From 353c1b3dd169ed58b9fe45246d46b6b25fe62557 Mon Sep 17 00:00:00 2001 From: Sebastian Fischmeister Date: Sat, 17 Dec 2011 12:56:39 -0500 Subject: [PATCH 001/134] updated the script --- doc/tracks_template_cli.rb | 105 +++++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 33 deletions(-) diff --git a/doc/tracks_template_cli.rb b/doc/tracks_template_cli.rb index fcf2a728..9be23092 100755 --- a/doc/tracks_template_cli.rb +++ b/doc/tracks_template_cli.rb @@ -1,6 +1,6 @@ #!/usr/bin/env ruby -# Version 0.2 (Sept 30, 2011) +# Version 0.4 (Dec 17, 2011) # # Based on the tracks_cli by Vitalie Lazu (https://gist.github.com/45537) @@ -20,19 +20,37 @@ # ENV['GTD_CONTEXT_URL_PREFIX'] --> 'http://localhost:3000/contexts/' # ENV['GTD_CONTEXT_URL'] --> 'http://localhost:3000/contexts.xml' +# project := +# dependent_action := ^|context|,..| +# independent_action := .|context|,..| +# to star an action add a tag 'starred' + # Format of input file: # - A token to be replaced in the subsequent lines starts with the string token # - New Projects start at the beginning of the line -# - New actions start with a '.' at the beginning of the line. To add a note to an action, separate the action from its note by using '|'. You have to stay in the same line. +# - New actions start with an '.' or an '^' at the beginning of the line. +# - To add a note to an action, separate the action from its note by using '|'. You have to stay in the same line. # - Comments start with '#' +# Simple test file. Remove the '# ' string at the beginning. +# token [A] +# token [BB] +# +# to [A] after [BB] +# .task 1 in [A], [BB]|computer|starred,blue|my notes here +# ^task 1.1 dependent on [A]|||only a note +# .task 2 +# +# project 2 with [A] +# .task in project 2 + # Example of an input file. Remove the '# ' string at the beginning and save it in a file. # token [location] # token [start] # token [end] # Book trip to [location] -# .Check visa requirements for [location]|instantiate template_visa, if visa required -# .Book flight to [location]|starting trip around [start], returning around [end] +# .Check visa requirements for [location]|starred|instantiate template_visa, if visa required +# .Book flight to [location]||starting trip around [start], returning around [end] # .Print flight details to [location] # .Book hotel in [location]|checking around [start], leaving around [end] # .Book rental car in [location]|starting [start], returning [end] @@ -51,8 +69,6 @@ # Instantiate this template: ./tracks_template_cli -c 1 -f template_file.txt -# Template can also be read from STDIN, however, then you have specify all tokens with -k - require 'net/https' require 'optparse' require 'cgi' @@ -80,7 +96,7 @@ module Gtd GTD_URI_CONTEXTS_PREFIX = ENV['GTD_CONTEXT_URL_PREFIX'] || 'http://localhost:3000/contexts/' GTD_URI_CONTEXTS = ENV['GTD_CONTEXT_URL'] || 'http://localhost:3000/contexts.xml' - def post(l, options = {}) + def postTodo(l, options = {}) uri = URI.parse(GTD_URI_TODOS) http = Net::HTTP.new(uri.host, uri.port) @@ -96,8 +112,7 @@ module Gtd description = CGI.escapeHTML(l) context_id = options[:context_id] ? options[:context_id].to_i : 1 project_id = options[:project_id] ? options[:project_id].to_i : 1 - starred = options[:starred] ? 1 : 0 - props = "#{description}#{project_id}#{context_id}" + props = "#{description}#{project_id}" if options[:show_from] props << "#{Time.at(options[:show_from]).xmlschema}" @@ -107,14 +122,38 @@ module Gtd props << "#{options[:note]}" end + if options[:taglist] + tags = options[:taglist].split(",") + if tags.length() > 0 + tags = tags.collect { |tag| "#{tag.strip}" unless tag.strip.empty?}.join('') + props << "#{tags}" + end + end + + if not (options[:context].nil? || options[:context].empty?) + props << "#{options[:context]}" + else + ## use the default context + props << "#{context_id}" + end + + if options[:depend] + props << "#{options[:last_todo_id]}" + end + req = Net::HTTP::Post.new(uri.path, "Content-Type" => "text/xml") req.basic_auth ENV['GTD_LOGIN'], ENV['GTD_PASSWORD'] req.body = "#{props}" + puts req.body + resp = http.request(req) if resp.code == '302' || resp.code == '201' puts resp['location'] + + # return the todo id + return resp['location'].split("/").last else p resp.body raise Gtd::Error @@ -193,7 +232,7 @@ module Gtd @keywords = {} @parser = OptionParser.new do |cmd| - cmd.banner = "Ruby Gtd CLI - takes todos input from STDIN" + cmd.banner = "Ruby Gtd Templates CLI" cmd.separator '' @@ -212,11 +251,6 @@ module Gtd cmd.on('-f [S]', "filename of the template") do |v| @filename = v - - if not File.exist?(@filename) - puts "ERROR: file #{@filename} doesn't exist" - exit 1 - end end cmd.on('-c [N]', Integer, 'default context id to set for new projects') do |v| @@ -238,6 +272,11 @@ module Gtd # lines = STDIN.read gtd = API.new + if @filename != nil and not File.exist?(@filename) + puts "ERROR: file #{@filename} doesn't exist" + exit 1 + end + if ENV['GTD_LOGIN'] == nil puts "ERROR: no GTD_LOGIN environment variable set" exit 1 @@ -247,18 +286,13 @@ module Gtd puts "ERROR: no GTD_PASSWORD environment variable set" exit 1 end - - if @filename.nil? + + if @filename == nil file = STDIN else file = File.open(@filename) end - # if lines.strip.empty? - # puts "Please pipe in some content to tracks on STDIN." - # exit 1 - # end - ## check for existence of the context if !@options[:context_id] puts "ERROR: need to specify a context_id with -c option. Go here to find one: #{API::GTD_URI_CONTEXTS}" @@ -280,11 +314,8 @@ module Gtd newtok=line.split(' ')[1] - if @keywords[newtok].nil? - print "Input required for "+newtok+": " - @keywords[newtok]=gets.chomp - end - + print "Input required for "+newtok+": " + @keywords[newtok]=gets.chomp next end @@ -294,26 +325,34 @@ module Gtd end # decide whether project or task - - if (line[0].chr == "." ) || (line[0].chr == "*") - @options[:starred]= line[0].chr == "*" ? true : false; + if (line[0].chr == "." ) || (line[0].chr == "^") + @options[:depend]= line[0].chr == "^" ? true : false; line = line[1..line.length] # find notes tmp= line.split("|") - if tmp.length > 3 + if tmp.length > 5 puts "Formatting error: found too many |" exit 1 end line=tmp[0] - @options[:note]=tmp[1] + + tmp.each_with_index do |t,idx| + t=t.strip.chomp + t=nil if t.empty? + tmp[idx]=t + end + + @options[:context]=tmp[1] + @options[:taglist]=tmp[2] + @options[:note]=tmp[3] if !@options[:project_id] puts "Warning: no project specified for task \"#{line}\". Using default project." end - gtd.post(line, @options) + @options[:last_todo_id]=gtd.postTodo(line, @options) else @options[:project_id]=gtd.postProject(line, @options) end From 2904bc953246278487cb3697361c061f8c79c4bc Mon Sep 17 00:00:00 2001 From: tim madden Date: Fri, 11 Mar 2011 13:50:33 -0600 Subject: [PATCH 002/134] Adding more options for deferring + shortening the one day so it stops wrapping --- app/views/todos/_todo.html.erb | 2 ++ config/locales/en.yml | 2 +- public/images/defer_2.png | Bin 0 -> 496 bytes public/images/defer_2_off.png | Bin 0 -> 425 bytes public/images/defer_3.png | Bin 0 -> 501 bytes public/images/defer_3_off.png | Bin 0 -> 441 bytes 6 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 public/images/defer_2.png create mode 100644 public/images/defer_2_off.png create mode 100644 public/images/defer_3.png create mode 100644 public/images/defer_3_off.png diff --git a/app/views/todos/_todo.html.erb b/app/views/todos/_todo.html.erb index 0f95e258..6f7edbc6 100644 --- a/app/views/todos/_todo.html.erb +++ b/app/views/todos/_todo.html.erb @@ -17,6 +17,8 @@ parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag'
  • <%= remote_delete_menu_item(todo) %>
  • <% unless todo.completed? || todo.deferred? -%>
  • <%= remote_defer_menu_item(1, todo) %>
  • +
  • <%= remote_defer_menu_item(2, todo) %>
  • +
  • <%= remote_defer_menu_item(3, todo) %>
  • <%= remote_defer_menu_item(7, todo) %>
  • <%= remote_promote_to_project_menu_item(todo) %>
  • <% end -%> diff --git a/config/locales/en.yml b/config/locales/en.yml index f356bfb3..14c8dcd6 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -426,7 +426,7 @@ en: completed_last_x_days: Completed in the last %{count} days no_actions_with: Currently there are no incomplete actions with the tag '%{tag_name}' defer_x_days: - one: Defer one day + one: Defer 1 day other: Defer %{count} days added_new_next_action_singular: Added new next action no_completed_actions: Currently there are no completed actions. diff --git a/public/images/defer_2.png b/public/images/defer_2.png new file mode 100644 index 0000000000000000000000000000000000000000..c27b735bfcb92eb0a594ab6d2153a2d8e8b391bc GIT binary patch literal 496 zcmVZ5EF*HHw!6!;X^b^~WtpY?ss(J%`pX=|TD>ww%xj_yJ?uI<)V=sY`tWP4YK zA9HZnecS<{Q}4ux8eCh~mWOg7b%q3Ro4O9Y|)Mvwp0#sg>=qZB|ZK zxU@2a31h$8e0ra?fv-=&9!~B}_F&AmX-QS&;=lj9){9VH#VtxVmN+ zG;LiF{1z()gGrOa^@Y8E@-a|!ioui4yPS78_rkrRl;WHC`>Gqzsy{^Jqqs^bxib_I zHJMC4N+lxdX4-lsuEQ`4hQlFMRdF~RsH*Bt^VST5Ai!}P27>`%7(UcIHS~R7bIY>W z@AvF>JGR>`0R4XdJwwwpHNRf3Y&IJJY}=;S>roWN-Jgdu48xFiyNzwz%w{vr=QGRY zQm67fkJV~LS(eQV<2VLjKA#gsk*+(A!+1Pqy@MeGO{dtsgwF~_{QqV&tIE=x!GmX TWP+-IH4nPNfaIru*CcwCoa8I~)yv@Iw1nLY|;fph(wlln1p5^>IYR%pJNuEX)*gtKR2 z^28I-K$Nvmg0tsSkKY3{^mhQVOIZS1fY5M=o!MQgA5}89833LeFBI(}@lc$@yCYh5 zt3Pn#aub03YM#W!IsgG}jERv+%K8=Mhbv<77}Kp8ZeDMC_t4M{SJd8WPTn%x>@V-p zG@AH7M+p1Flz!CIEPzhwu9sV=%_hY&NOa>m*6?<8SE< zvn(sT=XvycJzUqNR;!_u!Wi>f%U8{2v%((^2bRkvVHk2gpIIyxckMm}{#F!4L{U_l jk=x_&iPe*Te{H@2Qz3CU3n93s00000NkvXXu0mjfhX}h9 literal 0 HcmV?d00001 From e0f7eec17131d718dc73df63be8d4449846fb293 Mon Sep 17 00:00:00 2001 From: Sebastian Fischmeister Date: Tue, 20 Dec 2011 10:27:56 -0500 Subject: [PATCH 003/134] added verbose option --- doc/tracks_template_cli.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/doc/tracks_template_cli.rb b/doc/tracks_template_cli.rb index 9be23092..e02c8013 100755 --- a/doc/tracks_template_cli.rb +++ b/doc/tracks_template_cli.rb @@ -145,12 +145,12 @@ module Gtd req.basic_auth ENV['GTD_LOGIN'], ENV['GTD_PASSWORD'] req.body = "#{props}" - puts req.body + puts req.body if options[:verbose] resp = http.request(req) if resp.code == '302' || resp.code == '201' - puts resp['location'] + puts resp['location'] if options[:verbose] # return the todo id return resp['location'].split("/").last @@ -183,7 +183,7 @@ module Gtd resp = http.request(req) if resp.code == '302' || resp.code == '201' - puts resp['location'] + puts resp['location'] if options[:verbose] # return the project id return resp['location'].split("/").last @@ -249,6 +249,10 @@ module Gtd @keywords[v.split("=")[0]] = v.split("=")[1] end + cmd.on('-v', "verbose on") do |v| + @options[:verbose] = true + end + cmd.on('-f [S]', "filename of the template") do |v| @filename = v end From 1ced030681066b2854fa0bf45fc6b10190fc31d8 Mon Sep 17 00:00:00 2001 From: Matt Rogers Date: Tue, 10 Jan 2012 11:20:01 -0600 Subject: [PATCH 004/134] properly filter passwords in the users controller --- app/controllers/users_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 7b0eb8b7..77a9984a 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,4 +1,5 @@ class UsersController < ApplicationController + filter_parameter_logging "password" before_filter :admin_login_required, :only => [ :index, :show, :destroy ] skip_before_filter :login_required, :only => [ :new, :create ] skip_before_filter :check_for_deprecated_password_hash, From 99707d7a6959104c4151c8f971e15bbb69eceeba Mon Sep 17 00:00:00 2001 From: Matt Rogers Date: Tue, 10 Jan 2012 11:16:49 -0600 Subject: [PATCH 005/134] fix this test. the todo comparisons are case-sensitive. --- features/dependencies.feature | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/features/dependencies.feature b/features/dependencies.feature index c3e21b47..8e240f84 100644 --- a/features/dependencies.feature +++ b/features/dependencies.feature @@ -12,16 +12,16 @@ Feature: dependencies @selenium Scenario: Adding dependency to dependency by drag and drop Given I have a project "dependencies" with 3 todos - And "Todo 2" depends on "Todo 1" + And "todo 2" depends on "todo 1" When I go to the "dependencies" project - And I drag "Todo 3" to "Todo 2" - Then the successors of "Todo 1" should include "Todo 2" - And the successors of "Todo 2" should include "Todo 3" - When I expand the dependencies of "Todo 1" - Then I should see "Todo 2" within the dependencies of "Todo 1" - And I should see "Todo 3" within the dependencies of "Todo 1" - When I expand the dependencies of "Todo 2" - Then I should see "Todo 3" within the dependencies of "Todo 2" + And I drag "todo 3" to "todo 2" + Then the successors of "todo 1" should include "todo 2" + And the successors of "todo 2" should include "todo 3" + When I expand the dependencies of "todo 1" + Then I should see "todo 2" within the dependencies of "todo 1" + And I should see "todo 3" within the dependencies of "todo 1" + When I expand the dependencies of "todo 2" + Then I should see "todo 3" within the dependencies of "todo 2" @selenium Scenario: I can edit a todo to add the todo as a dependency to another From 27fb483485aea40f8da327f32f74542559a30efc Mon Sep 17 00:00:00 2001 From: Matt Rogers Date: Fri, 13 Jan 2012 21:26:22 -0600 Subject: [PATCH 006/134] Fix the failing mobile test after the updates The editing an action of the mobile page scenario failed because of the changes to the layout made by Tim Madden. --- features/mobile_edit_a_todo.feature | 6 +++--- features/step_definitions/todo_steps.rb | 10 +++++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/features/mobile_edit_a_todo.feature b/features/mobile_edit_a_todo.feature index 3589d072..46a6cf42 100644 --- a/features/mobile_edit_a_todo.feature +++ b/features/mobile_edit_a_todo.feature @@ -14,7 +14,7 @@ Feature: Edit a next action from the mobile view | context | description | | @mobile | test action | - @selenium + Scenario: I can edit an action on the mobile page When I am on the home page Then the badge should show 1 @@ -29,7 +29,7 @@ Feature: Edit a next action from the mobile view And I should not see "test action" When I follow "changed action" And I press "Mark complete" - Then I should see "changed action" in the completed container + Then I should see "changed action" in the completed section of the mobile site Scenario: Navigate from home page move this to separate features when other scenarios are created for these features @@ -48,4 +48,4 @@ Feature: Edit a next action from the mobile view And I press "Defer 1 day" Then I should see "There are no incomplete actions" When I follow "Tickler" - Then I should see "test action" \ No newline at end of file + Then I should see "test action" diff --git a/features/step_definitions/todo_steps.rb b/features/step_definitions/todo_steps.rb index 5ddda5b8..2aac79a4 100644 --- a/features/step_definitions/todo_steps.rb +++ b/features/step_definitions/todo_steps.rb @@ -168,4 +168,12 @@ Then /^the tags of "([^"]*)" should be "([^"]*)"$/ do |todo_description, tag_lis todo.should_not be_nil todo.tag_list.should == tag_list -end \ No newline at end of file +end + +Then /^I should see "([^"]*)" in the completed section of the mobile site$/ do |desc| + todo = @current_user.todos.find_by_description(desc) + todo.should_not be_nil + + xpath = "//div[@id='completed_container']//a[@href='/todos/#{todo.id}.m']" + response.should have_xpath xpath +end From 250e1d8fccb968400eb9e76a1988ecfbf2755e1e Mon Sep 17 00:00:00 2001 From: tim madden Date: Mon, 16 Jan 2012 11:37:29 -0600 Subject: [PATCH 007/134] folding mobile_done method into original toggle_check method the mobile_done method was created to test out a checkbox submit the mobile interface. In the interests of DRY, this brings the new mobile code into the original method, --- app/controllers/todos_controller.rb | 61 ++++++----------------------- app/helpers/todos_helper.rb | 2 +- 2 files changed, 12 insertions(+), 51 deletions(-) diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index ffce91b9..d654963a 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -348,62 +348,23 @@ class TodosController < ApplicationController end end format.m { - if cookies[:mobile_url] - old_path = cookies[:mobile_url] - cookies[:mobile_url] = {:value => nil, :secure => SITE_CONFIG['secure_cookies']} - notify(:notice, t("todos.action_marked_complete", :description => @todo.description, :completed => @todo.completed? ? 'complete' : 'incomplete')) - redirect_to old_path + if @saved + if cookies[:mobile_url] + old_path = cookies[:mobile_url] + cookies[:mobile_url] = {:value => nil, :secure => SITE_CONFIG['secure_cookies']} + notify(:notice, t("todos.action_marked_complete", :description => @todo.description, :completed => @todo.completed? ? 'complete' : 'incomplete')) + redirect_to old_path + else + notify(:notice, t("todos.action_marked_complete", :description => @todo.description, :completed => @todo.completed? ? 'complete' : 'incomplete')) + redirect_to todos_path(:format => 'm') + end else - notify(:notice, t("todos.action_marked_complete", :description => @todo.description, :completed => @todo.completed? ? 'complete' : 'incomplete')) - redirect_to todos_path(:format => 'm') + render :action => "edit", :format => :m end } end end - def mobile_done - # copied from toggle_check, left out other formats as they shouldn't come here - # ultimately would like to just use toggle_check - @todo = current_user.todos.find(params['id']) - @source_view = params['_source_view'] || 'todo' - @original_item_due = @todo.due - @original_item_was_deferred = @todo.deferred? - @original_item_was_pending = @todo.pending? - @original_item_was_hidden = @todo.hidden? - @original_item_context_id = @todo.context_id - @original_item_project_id = @todo.project_id - @todo_was_completed_from_deferred_or_blocked_state = @original_item_was_deferred || @original_item_was_pending - @saved = @todo.toggle_completion! - - @todo_was_blocked_from_completed_state = @todo.pending? # since we toggled_completion the previous state was completed - - # check if this todo has a related recurring_todo. If so, create next todo - @new_recurring_todo = check_for_next_todo(@todo) if @saved - - @predecessors = @todo.uncompleted_predecessors - if @saved - if @todo.completed? - @pending_to_activate = @todo.activate_pending_todos - else - @active_to_block = @todo.block_successors - end - end - - if @saved - if cookies[:mobile_url] - old_path = cookies[:mobile_url] - cookies[:mobile_url] = {:value => nil, :secure => SITE_CONFIG['secure_cookies']} - notify(:notice, t("todos.action_marked_complete", :description => @todo.description, :completed => @todo.completed? ? 'complete' : 'incomplete')) - redirect_to old_path - else - notify(:notice, t("todos.action_marked_complete", :description => @todo.description, :completed => @todo.completed? ? 'complete' : 'incomplete')) - redirect_to todos_path(:format => 'm') - end - else - render :action => "edit", :format => :m - end - end - def toggle_star @todo = current_user.todos.find(params['id']) @todo.toggle_star! diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index d6f3ed53..b1a8207d 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -90,7 +90,7 @@ module TodosHelper end def remote_mobile_checkbox(todo=@todo) - form_tag mobile_done_todo_path(@todo, :format => 'm'), :method => :put, :class => "mobile-done", :name => "mobile_complete_#{@todo.id}" do + form_tag toggle_check_todo_path(@todo, :format => 'm'), :method => :put, :class => "mobile-done", :name => "mobile_complete_#{@todo.id}" do check_box_tag('_source_view', 'todo', @todo && @todo.completed?, "onClick" => "document.mobile_complete_#{@todo.id}.submit()") end end From 01f283bc31dc2e4d16c408ace569a7acd1cab27e Mon Sep 17 00:00:00 2001 From: tim madden Date: Mon, 16 Jan 2012 11:46:49 -0600 Subject: [PATCH 008/134] Do not need this mobile_done in routes any longer. --- config/routes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index adf1fbca..ec0ed738 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -25,7 +25,7 @@ ActionController::Routing::Routes.draw do |map| map.resources :notes map.resources :todos, - :member => {:toggle_check => :put, :toggle_star => :put, :defer => :put, :mobile_done => :put}, + :member => {:toggle_check => :put, :toggle_star => :put, :defer => :put}, :collection => {:check_deferred => :post, :filter_to_context => :post, :filter_to_project => :post, :done => :get, :all_done => :get } From f74370aab51c569c46448d4dd868354854e89b4a Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Sat, 19 Nov 2011 02:41:06 +0100 Subject: [PATCH 009/134] first refactoring of stats controller --- app/controllers/application_controller.rb | 8 +- app/controllers/stats_controller.rb | 498 +++++++++------------- app/models/todo.rb | 6 +- config/locales/en.yml | 1 + test/functional/stats_controller_test.rb | 5 - test/unit/todo_test2.rb | 57 +++ 6 files changed, 260 insertions(+), 315 deletions(-) create mode 100644 test/unit/todo_test2.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f2c55bb3..9255fc3a 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -260,24 +260,26 @@ class ApplicationController < ActionController::Base self.class.prefered_auth? end + # all completed todos [today@00:00, today@now] def get_done_today(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES}) start_of_this_day = Time.zone.now.beginning_of_day completed_todos.completed_after(start_of_this_day).all(includes) end + # all completed todos [begin_of_week, start_of_today] def get_done_this_week(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES}) start_of_this_week = Time.zone.now.beginning_of_week start_of_this_day = Time.zone.now.beginning_of_day - completed_todos.completed_after(start_of_this_week).completed_before(start_of_this_day).all(includes) + completed_todos.completed_before(start_of_this_day).completed_after(start_of_this_week).all(includes) end + # all completed todos [begin_of_month, begin_of_week] def get_done_this_month(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES}) start_of_this_month = Time.zone.now.beginning_of_month start_of_this_week = Time.zone.now.beginning_of_week - completed_todos.completed_after(start_of_this_month).completed_before(start_of_this_week).all(includes) + completed_todos.completed_before(start_of_this_week).completed_after(start_of_this_month).all(includes) end - private def parse_date_per_user_prefs( s ) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index fac58ec2..41edf230 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -3,258 +3,124 @@ class StatsController < ApplicationController helper :todos, :projects, :recurring_todos append_before_filter :init, :exclude => [] - + def index - @page_title = 'TRACKS::Statistics' + @page_title = t('stats.index_title') @tags_count = get_total_number_of_tags_of_user @unique_tags_count = get_unique_tags_of_user.size - @hidden_contexts = @contexts.hidden - @first_action = @actions.find(:first, :order => "created_at ASC") - + @hidden_contexts = current_user.contexts.hidden + @first_action = current_user.todos.find(:first, :order => "created_at ASC") + get_stats_actions get_stats_contexts get_stats_projects - get_stats_tags - + get_stats_tags + render :layout => 'standard' - end - + end + def actions_done_last12months_data - @actions = @user.todos - # get actions created and completed in the past 12+3 months. +3 for running # average - @actions_done_last12months = @actions.find(:all, { - :select => "completed_at", - :conditions => ["completed_at > ? AND completed_at IS NOT NULL", @cut_off_year_plus3] - }) - @actions_created_last12months = @actions.find(:all, { - :select => "created_at", - :conditions => ["created_at > ?", @cut_off_year_plus3] - }) - - # convert to hash to be able to fill in non-existing days in - # @actions_done_last12months and count the total actions done in the past - # 12 months to be able to calculate percentage - - # use 0 to initialise action count to zero - @actions_done_last12months_hash = Hash.new(0) - @actions_done_last12months.each do |r| - months = (@today.year - r.completed_at.year)*12 + (@today.month - r.completed_at.month) + @actions_done_last12months = current_user.todos.completed_after(@cut_off_year_plus3).find(:all, { :select => "completed_at" }) + @actions_created_last12months = current_user.todos.created_after(@cut_off_year_plus3).find(:all, { :select => "created_at"}) - @actions_done_last12months_hash[months] += 1 - end - - # convert to hash to be able to fill in non-existing days in - # @actions_created_last12months and count the total actions done in the - # past 12 months to be able to calculate percentage - - # use 0 to initialise action count to zero - @actions_created_last12months_hash = Hash.new(0) - @actions_created_last12months.each do |r| - months = (@today.year - r.created_at.year)*12 + (@today.month - r.created_at.month) - - @actions_created_last12months_hash[months] += 1 - end - - @sum_actions_done_last12months=0 - @sum_actions_created_last12months=0 + # convert to hash to be able to fill in non-existing months + @actions_done_last12months_hash = convert_to_hash(@actions_done_last12months, :completed_at) + @actions_created_last12months_hash = convert_to_hash(@actions_created_last12months, :created_at) # find max for graph in both hashes - @max=0 - 0.upto 13 do |i| - @sum_actions_done_last12months += @actions_done_last12months_hash[i] - @max = @actions_done_last12months_hash[i] if @actions_done_last12months_hash[i] > @max - end - 0.upto 13 do |i| + @sum_actions_done_last12months, @sum_actions_created_last12months, @max = 0, 0, 0 + 0.upto 13 do |i| + @sum_actions_done_last12months += @actions_done_last12months_hash[i] @sum_actions_created_last12months += @actions_created_last12months_hash[i] - @max = @actions_created_last12months_hash[i] if @actions_created_last12months_hash[i] > @max + @max = [@actions_done_last12months_hash[i], @actions_created_last12months_hash[i], @max].max end - - # find running avg for month i by calculating avg of month i and the two - # after them. Ignore current month because you do not have full data for - # it - @actions_done_avg_last12months_hash = Hash.new("null") - 1.upto(12) { |i| - @actions_done_avg_last12months_hash[i] = (@actions_done_last12months_hash[i] + - @actions_done_last12months_hash[i+1] + - @actions_done_last12months_hash[i+2])/3.0 - } # find running avg for month i by calculating avg of month i and the two - # after them. Ignore current month because you do not have full data for - # it - @actions_created_avg_last12months_hash = Hash.new("null") - 1.upto(12) { |i| - @actions_created_avg_last12months_hash[i] = (@actions_created_last12months_hash[i] + - @actions_created_last12months_hash[i+1] + - @actions_created_last12months_hash[i+2])/3.0 - } - - # interpolate avg for this month. Assume 31 days in this month - days_passed_this_month = Time.new.day/1.0 - @interpolated_actions_created_this_month = ( - @actions_created_last12months_hash[0]/days_passed_this_month*31.0+ - @actions_created_last12months_hash[1]+ - @actions_created_last12months_hash[2]) / 3.0 - - @interpolated_actions_done_this_month = ( - @actions_done_last12months_hash[0]/days_passed_this_month*31.0 + - @actions_done_last12months_hash[1]+ - @actions_done_last12months_hash[2]) / 3.0 - + # after them. Ignore current month [0] because you do not have full data for it + @actions_done_avg_last12months_hash, @actions_created_avg_last12months_hash = Hash.new("null"), Hash.new("null") + 1.upto(12) do |i| + @actions_done_avg_last12months_hash[i] = three_month_avg(@actions_done_last12months_hash, i) + @actions_created_avg_last12months_hash[i] = three_month_avg(@actions_created_last12months_hash, i) + end + + # interpolate avg for current month. + percent_of_month = Time.zone.now.day.to_f / Time.zone.now.end_of_month.day.to_f + @interpolated_actions_created_this_month = interpolate_avg(@actions_created_last12months_hash, percent_of_month) + @interpolated_actions_done_this_month = interpolate_avg(@actions_done_last12months_hash, percent_of_month) + render :layout => false end - + def actions_done_last_years + @page_title = t('stats.index_title') @chart_width = 900 @chart_height = 400 end - + def actions_done_lastyears_data - @actions = @user.todos - - # get actions created and completed in the past 12+3 months. +3 for running - # average - @actions_done_last_months = @actions.find(:all, { - :select => "completed_at", - :conditions => ["completed_at IS NOT NULL"] - }) - @actions_created_last_months = @actions.find(:all, { - :select => "created_at", - }) - - @month_count = 0 - - # convert to hash to be able to fill in non-existing days in - # @actions_done_last12months and count the total actions done in the past - # 12 months to be able to calculate percentage - - # use 0 to initialise action count to zero - @actions_done_last_months_hash = Hash.new(0) - @actions_done_last_months.each do |r| - months = (@today.year - r.completed_at.year)*12 + (@today.month - r.completed_at.month) - @month_count = months if months > @month_count - @actions_done_last_months_hash[months] += 1 - end - - # convert to hash to be able to fill in non-existing days in - # @actions_created_last12months and count the total actions done in the - # past 12 months to be able to calculate percentage + @actions = current_user.todos - # use 0 to initialise action count to zero - @actions_created_last_months_hash = Hash.new(0) - @actions_created_last_months.each do |r| - months = (@today.year - r.created_at.year)*12 + (@today.month - r.created_at.month) - @month_count = months if months > @month_count - @actions_created_last_months_hash[months] += 1 - end + @actions_done_last_months = current_user.todos.completed.find(:all, { :select => "completed_at", :order => "completed_at DESC" }) + @actions_created_last_months = current_user.todos.find(:all, { :select => "created_at", :order => "created_at DESC" }) - @sum_actions_done_last_months=0 - @sum_actions_created_last_months=0 + @month_count = [difference_in_months(@today, @actions_created_last_months.last.created_at), + difference_in_months(@today, @actions_done_last_months.last.completed_at)].max + + # convert to hash to be able to fill in non-existing months + @actions_done_last_months_hash = convert_to_hash(@actions_done_last_months, :completed_at) + @actions_created_last_months_hash = convert_to_hash(@actions_created_last_months, :created_at) # find max for graph in both hashes - @max=0 + @sum_actions_done_last_months, @sum_actions_created_last_months, @max = 0, 0, 0 0.upto @month_count do |i| - @sum_actions_done_last_months += @actions_done_last_months_hash[i] - @max = @actions_done_last_months_hash[i] if @actions_done_last_months_hash[i] > @max - end - 0.upto @month_count do |i| + @sum_actions_done_last_months += @actions_done_last_months_hash[i] @sum_actions_created_last_months += @actions_created_last_months_hash[i] - @max = @actions_created_last_months_hash[i] if @actions_created_last_months_hash[i] > @max + @max = [@actions_done_last_months_hash[i], @actions_created_last_months_hash[i], @max].max end - - # find running avg for month i by calculating avg of month i and the two - # after them. Ignore current month because you do not have full data for - # it - @actions_done_avg_last_months_hash = Hash.new("null") - 1.upto(@month_count) { |i| - @actions_done_avg_last_months_hash[i] = (@actions_done_last_months_hash[i] + - @actions_done_last_months_hash[i+1] + - @actions_done_last_months_hash[i+2])/3.0 - } - # correct last two months - @actions_done_avg_last_months_hash[@month_count] = @actions_done_avg_last_months_hash[@month_count] * 3 - @actions_done_avg_last_months_hash[@month_count-1] = @actions_done_avg_last_months_hash[@month_count-1] * 3 / 2 if @month_count > 1 # find running avg for month i by calculating avg of month i and the two - # after them. Ignore current month because you do not have full data for - # it - @actions_created_avg_last_months_hash = Hash.new("null") - 1.upto(@month_count) { |i| - @actions_created_avg_last_months_hash[i] = (@actions_created_last_months_hash[i] + - @actions_created_last_months_hash[i+1] + - @actions_created_last_months_hash[i+2])/3.0 - } + # after them. Ignore current month because you do not have full data for it + @actions_done_avg_last_months_hash, @actions_created_avg_last_months_hash = Hash.new("null"), Hash.new("null") + 1.upto(@month_count) do |i| + @actions_done_avg_last_months_hash[i] = three_month_avg(@actions_done_last_months_hash, i) + @actions_created_avg_last_months_hash[i] = three_month_avg(@actions_created_last_months_hash, i) + end + # correct last two months - @actions_created_avg_last_months_hash[@month_count] = @actions_created_avg_last_months_hash[@month_count] * 3 - @actions_created_avg_last_months_hash[@month_count-1] = @actions_created_avg_last_months_hash[@month_count-1] * 3 / 2 if @month_count > 1 - - # interpolate avg for this month. Assume 31 days in this month - days_passed_this_month = Time.new.day/1.0 - @interpolated_actions_created_this_month = ( - @actions_created_last_months_hash[0]/days_passed_this_month*31.0+ - @actions_created_last_months_hash[1]+ - @actions_created_last_months_hash[2]) / 3.0 - - @interpolated_actions_done_this_month = ( - @actions_done_last_months_hash[0]/days_passed_this_month*31.0 + - @actions_done_last_months_hash[1]+ - @actions_done_last_months_hash[2]) / 3.0 - + correct_last_two_months(@actions_done_avg_last_months_hash, @month_count) + correct_last_two_months(@actions_created_avg_last_months_hash, @month_count) + + # interpolate avg for this month. + percent_of_month = Time.zone.now.day.to_f / Time.zone.now.end_of_month.day.to_f + @interpolated_actions_created_this_month = interpolate_avg(@actions_created_last_months_hash, percent_of_month) + @interpolated_actions_done_this_month = interpolate_avg(@actions_done_last_months_hash, percent_of_month) + render :layout => false end - + def actions_done_last30days_data # get actions created and completed in the past 30 days. - @actions_done_last30days = @actions.find(:all, { - :select => "completed_at", - :conditions => ["completed_at > ? AND completed_at IS NOT NULL", @cut_off_month] - }) - @actions_created_last30days = @actions.find(:all, { - :select => "created_at", - :conditions => ["created_at > ?", @cut_off_month] - }) - + @actions_done_last30days = current_user.todos.completed_after(@cut_off_month).find(:all, { :select => "completed_at" }) + @actions_created_last30days = current_user.todos.created_after(@cut_off_month).find(:all, { :select => "created_at" }) + # convert to hash to be able to fill in non-existing days in # @actions_done_last30days and count the total actions done in the past 30 # days to be able to calculate percentage - @sum_actions_done_last30days=0 - - # use 0 to initialise action count to zero - @actions_done_last30days_hash = Hash.new(0) - @actions_done_last30days.each do |r| - # only use date part of completed_at - action_date = Time.utc(r.completed_at.year, r.completed_at.month, r.completed_at.day, 0,0) - days = ((@today - action_date) / @seconds_per_day).to_i - - @actions_done_last30days_hash[days] += 1 - @sum_actions_done_last30days+=1 - end - - # convert to hash to be able to fill in non-existing days in - # @actions_done_last30days and count the total actions done in the past 30 - # days to be able to calculate percentage - @sum_actions_created_last30days=0 - - # use 0 to initialise action count to zero - @actions_created_last30days_hash = Hash.new(0) - @actions_created_last30days.each do |r| - # only use date part of created_at - action_date = Time.utc(r.created_at.year, r.created_at.month, r.created_at.day, 0,0) - days = ((@today - action_date) / @seconds_per_day).to_i - - @actions_created_last30days_hash[days] += 1 - @sum_actions_created_last30days += 1 - end + @actions_done_last30days_hash = convert_to_hash(@actions_done_last30days, :completed_at, :difference_in_days) + @actions_created_last30days_hash = convert_to_hash(@actions_created_last30days, :created_at, :difference_in_days) # find max for graph in both hashes - @max=0 - 0.upto(30) { |i| @max = @actions_done_last30days_hash[i] if @actions_done_last30days_hash[i] > @max } - 0.upto(30) { |i| @max = @actions_created_last30days_hash[i] if @actions_created_last30days_hash[i] > @max } - + @sum_actions_done_last30days, @sum_actions_created_last30days, @max = 0, 0, 0 + 0.upto(30) do |i| + @sum_actions_done_last30days += @actions_done_last30days_hash[i] + @sum_actions_created_last30days += @actions_created_last30days_hash[i] + @max = [ @actions_done_last30days_hash[i], @actions_created_last30days_hash[i], @max].max + end + render :layout => false end @@ -263,25 +129,25 @@ class StatsController < ApplicationController :select => "completed_at, created_at", :conditions => "completed_at IS NOT NULL" }) - + # convert to hash to be able to fill in non-existing days in # @actions_completion_time also convert days to weeks (/7) - + @max_days, @max_actions, @sum_actions=0,0,0 @actions_completion_time_hash = Hash.new(0) @actions_completion_time.each do |r| days = (r.completed_at - r.created_at) / @seconds_per_day weeks = (days/7).to_i - @actions_completion_time_hash[weeks] += 1 + @actions_completion_time_hash[weeks] += 1 @max_days=days if days > @max_days - @max_actions = @actions_completion_time_hash[weeks] if @actions_completion_time_hash[weeks] > @max_actions + @max_actions = @actions_completion_time_hash[weeks] if @actions_completion_time_hash[weeks] > @max_actions @sum_actions += 1 end - + # stop the chart after 10 weeks @cut_off = 10 - + render :layout => false end @@ -293,7 +159,7 @@ class StatsController < ApplicationController # convert to hash to be able to fill in non-existing days in # @actions_running_time also convert days to weeks (/7) - + @max_days, @max_actions, @sum_actions=0,0,0 @actions_running_time_hash = Hash.new(0) @actions_running_time.each do |r| @@ -301,15 +167,15 @@ class StatsController < ApplicationController weeks = (days/7).to_i @actions_running_time_hash[weeks] += 1 - + @max_days=days if days > @max_days @max_actions = @actions_running_time_hash[weeks] if @actions_running_time_hash[weeks] > @max_actions @sum_actions += 1 end - + # cut off chart at 52 weeks = one year @cut_off=52 - + render :layout => false end @@ -320,7 +186,7 @@ class StatsController < ApplicationController # - actions not part of a hidden context # - actions not deferred (show_from must be null) # - actions not pending/blocked - + @actions_running_time = @actions.find_by_sql([ "SELECT t.created_at "+ "FROM todos t LEFT OUTER JOIN projects p ON t.project_id = p.id LEFT OUTER JOIN contexts c ON t.context_id = c.id "+ @@ -330,10 +196,10 @@ class StatsController < ApplicationController "AND NOT (p.state='hidden' OR p.state='pending' OR c.hide=?) " + "ORDER BY t.created_at ASC", @user.id, true] ) - + # convert to hash to be able to fill in non-existing days in # @actions_running_time also convert days to weeks (/7) - + @max_days, @max_actions, @sum_actions=0,0,0 @actions_running_time_hash = Hash.new(0) @actions_running_time.each do |r| @@ -341,19 +207,19 @@ class StatsController < ApplicationController weeks = (days/7).to_i # RAILS_DEFAULT_LOGGER.error("\n" + total.to_s + " - " + days + "\n") @actions_running_time_hash[weeks] += 1 - + @max_days=days if days > @max_days @max_actions = @actions_running_time_hash[weeks] if @actions_running_time_hash[weeks] > @max_actions @sum_actions += 1 end - + # cut off chart at 52 weeks = one year @cut_off=52 - + render :layout => false end - + def context_total_actions_data # get total action count per context Went from GROUP BY c.id to c.name for # compatibility with postgresql. Since the name is forced to be unique, this @@ -383,14 +249,14 @@ class StatsController < ApplicationController @actions_per_context[size-1]['total']+=@all_actions_per_context[i]['total'].to_i end end - + @sum=0 0.upto @all_actions_per_context.size()-1 do |i| @sum += @all_actions_per_context[i]['total'].to_i end - - @truncate_chars = 15 - + + @truncate_chars = 15 + render :layout => false end @@ -407,7 +273,7 @@ class StatsController < ApplicationController "GROUP BY c.name, c.id "+ "ORDER BY total DESC" ) - + pie_cutoff=10 size = @all_actions_per_context.size() size = pie_cutoff if size > pie_cutoff @@ -424,27 +290,27 @@ class StatsController < ApplicationController @actions_per_context[size-1]['total']+=@all_actions_per_context[i]['total'].to_i end end - + @sum=0 0.upto @all_actions_per_context.size()-1 do |i| @sum += @all_actions_per_context[i]['total'].to_i end - + @truncate_chars = 15 - + render :layout => false end def actions_day_of_week_all_data @actions = @user.todos - + @actions_creation_day = @actions.find(:all, { :select => "created_at" }) - + @actions_completion_day = @actions.find(:all, { :select => "completed_at", - :conditions => "completed_at IS NOT NULL" + :conditions => "completed_at IS NOT NULL" }) # convert to hash to be able to fill in non-existing days @@ -457,7 +323,7 @@ class StatsController < ApplicationController # find max @max=0 0.upto(6) { |i| @max = @actions_creation_day_array[i] if @actions_creation_day_array[i] > @max} - + # convert to hash to be able to fill in non-existing days @actions_completion_day_array = Array.new(7) { |i| 0} @@ -467,7 +333,7 @@ class StatsController < ApplicationController @actions_completion_day_array[dayofweek] += 1 end 0.upto(6) { |i| @max = @actions_completion_day_array[i] if @actions_completion_day_array[i] > @max} - + render :layout => false end @@ -476,7 +342,7 @@ class StatsController < ApplicationController :select => "created_at", :conditions => ["created_at > ?", @cut_off_month] }) - + @actions_completion_day = @actions.find(:all, { :select => "completed_at", :conditions => ["completed_at IS NOT NULL AND completed_at > ?", @cut_off_month] @@ -500,17 +366,17 @@ class StatsController < ApplicationController @actions_completion_day_array[dayofweek] += 1 end 0.upto(6) { |i| @max = @actions_completion_day_array[i] if @actions_completion_day_array[i] > @max} - + render :layout => false end def actions_time_of_day_all_data @actions_creation_hour = @actions.find(:all, { :select => "created_at" - }) + }) @actions_completion_hour = @actions.find(:all, { - :select => "completed_at", - :conditions => "completed_at IS NOT NULL" + :select => "completed_at", + :conditions => "completed_at IS NOT NULL" }) # convert to hash to be able to fill in non-existing days @@ -524,12 +390,12 @@ class StatsController < ApplicationController # convert to hash to be able to fill in non-existing days @actions_completion_hour_array = Array.new(24) { |i| 0} - @actions_completion_hour.each do |r| + @actions_completion_hour.each do |r| hour = r.completed_at.hour @actions_completion_hour_array[hour] += 1 end 0.upto(23) { |i| @max = @actions_completion_hour_array[i] if @actions_completion_hour_array[i] > @max} - + render :layout => false end @@ -538,7 +404,7 @@ class StatsController < ApplicationController :select => "created_at", :conditions => ["created_at > ?", @cut_off_month] }) - + @actions_completion_hour = @actions.find(:all, { :select => "completed_at", :conditions => ["completed_at IS NOT NULL AND completed_at > ?", @cut_off_month] @@ -555,32 +421,32 @@ class StatsController < ApplicationController # convert to hash to be able to fill in non-existing days @actions_completion_hour_array = Array.new(24) { |i| 0} - @actions_completion_hour.each do |r| + @actions_completion_hour.each do |r| hour = r.completed_at.hour @actions_completion_hour_array[hour] += 1 end 0.upto(23) { |i| @max = @actions_completion_hour_array[i] if @actions_completion_hour_array[i] > @max} - + render :layout => false end - + def show_selected_actions_from_chart @page_title = t('stats.action_selection_title') @count = 99 @source_view = 'stats' - + case params['id'] when 'avrt', 'avrt_end' # actions_visible_running_time - + # HACK: because open flash chart uses & to denote the end of a parameter, # we cannot use URLs with multiple parameters (that would use &). So we # revert to using two id's for the same selection. avtr_end means that the # last bar of the chart is selected. avtr is used for all other bars - + week_from = params['index'].to_i week_to = week_from+1 - + @chart_name = "actions_visible_running_time_data" @page_title = t('stats.actions_selected_from_week') @further = false @@ -602,18 +468,18 @@ class StatsController < ApplicationController "ORDER BY t.created_at ASC", @user.id, true] ) - @selected_todo_ids, @count = get_ids_from(@actions_running_time, week_from, week_to, params['id']== 'avrt_end') - @actions = @user.todos + @selected_todo_ids, @count = get_ids_from(@actions_running_time, week_from, week_to, params['id']== 'avrt_end') + @actions = @user.todos @selected_actions = @actions.find(:all, { :conditions => "id in (" + @selected_todo_ids + ")" }) - + render :action => "show_selection_from_chart" - + when 'art', 'art_end' week_from = params['index'].to_i week_to = week_from+1 - + @chart_name = "actions_running_time_data" @page_title = "Actions selected from week " @further = false @@ -631,11 +497,11 @@ class StatsController < ApplicationController :conditions => "completed_at IS NULL" }) - @selected_todo_ids, @count = get_ids_from(@actions_running_time, week_from, week_to, params['id']=='art_end') + @selected_todo_ids, @count = get_ids_from(@actions_running_time, week_from, week_to, params['id']=='art_end') @selected_actions = @actions.find(:all, { :conditions => "id in (" + @selected_todo_ids + ")" }) - + render :action => "show_selection_from_chart" else # render error @@ -643,11 +509,11 @@ class StatsController < ApplicationController end end - def done + def done @source_view = 'done' - + init_not_done_counts - + @done_recently = current_user.todos.completed.all(:limit => 10, :order => 'completed_at DESC', :include => Todo::DEFAULT_INCLUDES) @last_completed_projects = current_user.projects.completed.all(:limit => 10, :order => 'completed_at DESC', :include => [:todos, :notes]) @last_completed_contexts = [] @@ -680,45 +546,37 @@ class StatsController < ApplicationController end def init - @actions = @user.todos - @projects = @user.projects - @contexts = @user.contexts + @me = self # for meta programming + @actions = current_user.todos + @projects = current_user.projects + @contexts = current_user.contexts # default chart dimensions @chart_width=460 @chart_height=250 @pie_width=@chart_width @pie_height=325 - + # get the current date wih time set to 0:0 - now = Time.new - @today = Time.utc(now.year, now.month, now.day, 0,0) + @today = Time.zone.now.beginning_of_day # define the number of seconds in a day @seconds_per_day = 60*60*24 # define cut_off date and discard the time for a month, 3 months and a year - cut_off_time = 13.months.ago() - @cut_off_year = Time.utc(cut_off_time.year, cut_off_time.month, cut_off_time.day,0,0) - - cut_off_time = 16.months.ago() - @cut_off_year_plus3 = Time.utc(cut_off_time.year, cut_off_time.month, cut_off_time.day,0,0) - - cut_off_time = 31.days.ago - @cut_off_month = Time.utc(cut_off_time.year, cut_off_time.month, cut_off_time.day,0,0) - - cut_off_time = 91.days.ago - @cut_off_3months = Time.utc(cut_off_time.year, cut_off_time.month, cut_off_time.day,0,0) - + @cut_off_year = 13.months.ago.beginning_of_day + @cut_off_year_plus3 = 16.months.ago.beginning_of_day + @cut_off_month = 1.month.ago.beginning_of_day + @cut_off_3months = 3.months.ago.beginning_of_day end - + def get_stats_actions # time to complete @completed_actions = @actions.find(:all, { :select => "completed_at, created_at", :conditions => "completed_at IS NOT NULL", }) - + actions_sum, actions_max, actions_min = 0,0,-1 @completed_actions.each do |r| actions_sum += (r.completed_at - r.created_at) @@ -727,34 +585,34 @@ class StatsController < ApplicationController actions_min = (r.completed_at - r.created_at) if actions_min == -1 actions_min = (r.completed_at - r.created_at) if (r.completed_at - r.created_at) < actions_min end - + sum_actions = @completed_actions.size sum_actions = 1 if sum_actions==0 - + @actions_avg_ttc = (actions_sum/sum_actions)/@seconds_per_day @actions_max_ttc = actions_max/@seconds_per_day @actions_min_ttc = actions_min/@seconds_per_day - + min_ttc_sec = Time.utc(2000,1,1,0,0)+actions_min @actions_min_ttc_sec = (min_ttc_sec).strftime("%H:%M:%S") @actions_min_ttc_sec = (actions_min / @seconds_per_day).round.to_s + " days " + @actions_min_ttc_sec if actions_min > @seconds_per_day - + # get count of actions created and actions done in the past 30 days. @sum_actions_done_last30days = @actions.count(:all, { - :conditions => ["completed_at > ? AND completed_at IS NOT NULL", @cut_off_month] + :conditions => ["completed_at > ? AND completed_at IS NOT NULL", @cut_off_month] }) @sum_actions_created_last30days = @actions.count(:all, { :conditions => ["created_at > ?", @cut_off_month] }) - + # get count of actions done in the past 12 months. @sum_actions_done_last12months = @actions.count(:all, { :conditions => ["completed_at > ? AND completed_at IS NOT NULL", @cut_off_year] }) @sum_actions_created_last12months = @actions.count(:all, { - :conditions => ["created_at > ?", @cut_off_year] - }) + :conditions => ["created_at > ?", @cut_off_year] + }) end def get_stats_contexts @@ -782,7 +640,7 @@ class StatsController < ApplicationController "AND t.user_id="+@user.id.to_s+" "+ "GROUP BY c.id, c.name ORDER BY total DESC " + "LIMIT 5" - ) + ) end def get_stats_projects @@ -799,10 +657,10 @@ class StatsController < ApplicationController "ORDER BY count DESC " + "LIMIT 10" ) - + # get the first 10 projects with their actions count of actions that have # been created or completed the past 30 days - + # using GROUP BY p.name (was: p.id) for compatibility with Postgresql. Since # you cannot create two contexts with the same name, this will work. @projects_and_actions_last30days = @projects.find_by_sql([ @@ -815,7 +673,7 @@ class StatsController < ApplicationController "ORDER BY count DESC " + "LIMIT 10", @cut_off_month, @cut_off_month, @user.id] ) - + # get the first 10 projects and their running time (creation date versus # now()) @projects_and_runtime_sql = @projects.find_by_sql( @@ -835,16 +693,16 @@ class StatsController < ApplicationController @projects_and_runtime[i]=[r.id, r.name, days.to_i+1] i += 1 end - + end - + def get_stats_tags # tag cloud code inspired by this article # http://www.juixe.com/techknow/index.php/2006/07/15/acts-as-taggable-tag-cloud/ levels=10 # TODO: parameterize limit - + # Get the tag cloud for all tags for actions query = "SELECT tags.id, name, count(*) AS count" query << " FROM taggings, tags, todos" @@ -856,7 +714,7 @@ class StatsController < ApplicationController query << " ORDER BY count DESC, name" query << " LIMIT 100" @tags_for_cloud = Tag.find_by_sql(query).sort_by { |tag| tag.name.downcase } - + max, @tags_min = 0, 0 @tags_for_cloud.each { |t| max = t.count.to_i if t.count.to_i > max @@ -888,20 +746,20 @@ class StatsController < ApplicationController } @tags_divisor_90days = ((max_90days - @tags_min_90days) / levels) + 1 - + end - + def get_ids_from (actions_running_time, week_from, week_to, at_end) count=0 selected_todo_ids = "" - + actions_running_time.each do |r| days = (@today - r.created_at) / @seconds_per_day weeks = (days/7).to_i if at_end if weeks >= week_from selected_todo_ids += r.id.to_s+"," - count+=1 + count+=1 end else if weeks.between?(week_from, week_to-1) @@ -910,11 +768,41 @@ class StatsController < ApplicationController end end end - + # strip trailing comma selected_todo_ids = selected_todo_ids[0..selected_todo_ids.length-2] - + return selected_todo_ids, count end - + + def convert_to_hash(records, date_method, difference_method=:difference_in_months) + # use 0 to initialise action count to zero + hash = Hash.new(0) + records.each { |t| hash[self.send(difference_method, @today, t.send(date_method))] += 1 } + return hash + end + + # assumes date1 > date2 + def difference_in_months(date1, date2) + return (date1.year - date2.year)*12 + (date1.month - date2.month) + end + + # assumes date1 > date2 + def difference_in_days(date1, date2) + return ((date1.at_midnight-date2.at_midnight)/@seconds_per_day).to_i + end + + def three_month_avg(hash, i) + return (hash[i] + hash[i+1] + hash[i+2])/3.0 + end + + def interpolate_avg(hash, percent) + return (hash[0]*percent + hash[1] + hash[2]) / 3.0 + end + + def correct_last_two_months(month_data, count) + month_data[count] = month_data[count] * 3 + month_data[count-1] = month_data[count-1] * 3 / 2 if count > 1 + end + end \ No newline at end of file diff --git a/app/models/todo.rb b/app/models/todo.rb index 9122afae..6f6cd1f4 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -41,8 +41,10 @@ class Todo < ActiveRecord::Base named_scope :with_tag, lambda { |tag_id| {:joins => :taggings, :conditions => ["taggings.tag_id = ? ", tag_id] } } named_scope :with_tags, lambda { |tag_ids| {:conditions => ["EXISTS(SELECT * from taggings t WHERE t.tag_id IN (?) AND t.taggable_id=todos.id AND t.taggable_type='Todo')", tag_ids] } } named_scope :of_user, lambda { |user_id| {:conditions => ["todos.user_id = ? ", user_id] } } - named_scope :completed_after, lambda { |date| {:conditions => ["todos.completed_at > ? ", date] } } - named_scope :completed_before, lambda { |date| {:conditions => ["todos.completed_at < ? ", date] } } + named_scope :completed_after, lambda { |date| {:conditions => ["todos.completed_at > ?", date] } } + named_scope :completed_before, lambda { |date| {:conditions => ["todos.completed_at < ?", date] } } + named_scope :created_after, lambda { |date| {:conditions => ["todos.created_at > ?", date] } } + named_scope :created_before, lambda { |date| {:conditions => ["todos.created_at < ?", date] } } STARRED_TAG_NAME = "starred" DEFAULT_INCLUDES = [ :project, :context, :tags, :taggings, :pending_successors, :uncompleted_predecessors, :recurring_todo ] diff --git a/config/locales/en.yml b/config/locales/en.yml index d9460627..2908cc27 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -233,6 +233,7 @@ en: one: 1 error prohibited this %{model} from being saved other: "%{count} errors prohibited this %{model} from being saved" stats: + index_title: TRACKS::Statistics tag_cloud_title: Tag cloud for all actions tag_cloud_description: This tag cloud includes tags of all actions (completed, not completed, visible and/or hidden) tag_cloud_90days_title: Tag cloud actions in past 90 days diff --git a/test/functional/stats_controller_test.rb b/test/functional/stats_controller_test.rb index 44ca1575..14ebec73 100755 --- a/test/functional/stats_controller_test.rb +++ b/test/functional/stats_controller_test.rb @@ -13,11 +13,6 @@ class StatsControllerTest < ActionController::TestCase @response = ActionController::TestResponse.new end - # Replace this with your real tests. - def test_truth - assert true - end - def test_get_index_when_not_logged_in get :index assert_redirected_to :controller => 'login', :action => 'login' diff --git a/test/unit/todo_test2.rb b/test/unit/todo_test2.rb new file mode 100644 index 00000000..323b7432 --- /dev/null +++ b/test/unit/todo_test2.rb @@ -0,0 +1,57 @@ +require File.expand_path(File.dirname(__FILE__) + '/../test_helper') +require 'date' + +class TodoTest < ActiveSupport::TestCase + fixtures :todos, :recurring_todos, :users, :contexts, :preferences, :tags, :taggings, :projects + + def setup + @not_completed1 = Todo.find(1).reload + @not_completed2 = Todo.find(2).reload + @completed = Todo.find(8).reload + end + + # test named_scopes + def test_find_completed + # Given 2 completed todos, one completed now and one completed 2 months ago + @not_completed1.toggle_completion! + @completed.completed_at = 2.months.ago + @completed.save! + + completed_old = @completed + completed_now = @not_completed1 + + # When I use the finders + recent_completed_todos = Todo.completed_after(1.month.ago).find(:all) + older_completed_todos = Todo.completed_before(1.month.ago).find(:all) + + # Then completed1 should be before and completed2 should be after a month ago + assert older_completed_todos.include?(completed_old) + assert recent_completed_todos.include?(completed_now) + + # And completed1 should not be after and completed2 should not be before a month ago + assert !older_completed_todos.include?(completed_now) + assert !recent_completed_todos.include?(completed_old) + end + + def test_find_created + # Given 2 created todos, one created now and one created 2 months ago + user = @completed.user + todo_old = user.todos.create!({:description => "created long long ago", :context => @completed.context}) + todo_old.created_at = 2.months.ago + todo_old.save! + todo_now = user.todos.create!({:description => "just created", :context => @completed.context}) + + # When I use the finders + recent_created_todos = Todo.created_after(1.month.ago).find(:all) + older_created_todos = Todo.created_before(1.month.ago).find(:all) + + # Then todo1 should be before and todo2 should be after a month ago + assert older_created_todos.include?(todo_old) + assert recent_created_todos.include?(todo_now) + + # And todo1 should not be after and todo2 should not be before a month ago + assert !older_created_todos.include?(todo_now) + assert !recent_created_todos.include?(todo_old) + end + +end \ No newline at end of file From 61624ed45554f773811ec28d6edf1232db69942f Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Sun, 20 Nov 2011 20:23:28 +0100 Subject: [PATCH 010/134] completed first pass of refactoring --- app/controllers/stats_controller.rb | 243 +++++++++------------------- app/views/stats/_totals.rhtml | 26 +-- app/views/stats/index.html.erb | 26 ++- 3 files changed, 96 insertions(+), 199 deletions(-) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index 41edf230..569a6e52 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -27,8 +27,8 @@ class StatsController < ApplicationController @actions_created_last12months = current_user.todos.created_after(@cut_off_year_plus3).find(:all, { :select => "created_at"}) # convert to hash to be able to fill in non-existing months - @actions_done_last12months_hash = convert_to_hash(@actions_done_last12months, :completed_at) - @actions_created_last12months_hash = convert_to_hash(@actions_created_last12months, :created_at) + @actions_done_last12months_hash = convert_to_hash(@actions_done_last12months, :difference_in_months, :completed_at) + @actions_created_last12months_hash = convert_to_hash(@actions_created_last12months, :difference_in_months, :created_at) # find max for graph in both hashes @sum_actions_done_last12months, @sum_actions_created_last12months, @max = 0, 0, 0 @@ -70,8 +70,8 @@ class StatsController < ApplicationController difference_in_months(@today, @actions_done_last_months.last.completed_at)].max # convert to hash to be able to fill in non-existing months - @actions_done_last_months_hash = convert_to_hash(@actions_done_last_months, :completed_at) - @actions_created_last_months_hash = convert_to_hash(@actions_created_last_months, :created_at) + @actions_done_last_months_hash = convert_to_hash(@actions_done_last_months, :difference_in_months, :completed_at) + @actions_created_last_months_hash = convert_to_hash(@actions_created_last_months, :difference_in_months, :created_at) # find max for graph in both hashes @sum_actions_done_last_months, @sum_actions_created_last_months, @max = 0, 0, 0 @@ -110,8 +110,8 @@ class StatsController < ApplicationController # convert to hash to be able to fill in non-existing days in # @actions_done_last30days and count the total actions done in the past 30 # days to be able to calculate percentage - @actions_done_last30days_hash = convert_to_hash(@actions_done_last30days, :completed_at, :difference_in_days) - @actions_created_last30days_hash = convert_to_hash(@actions_created_last30days, :created_at, :difference_in_days) + @actions_done_last30days_hash = convert_to_hash(@actions_done_last30days, :difference_in_days, :completed_at) + @actions_created_last30days_hash = convert_to_hash(@actions_created_last30days, :difference_in_days, :created_at) # find max for graph in both hashes @sum_actions_done_last30days, @sum_actions_created_last30days, @max = 0, 0, 0 @@ -125,23 +125,19 @@ class StatsController < ApplicationController end def actions_completion_time_data - @actions_completion_time = @actions.find(:all, { - :select => "completed_at, created_at", - :conditions => "completed_at IS NOT NULL" - }) + @actions_completion_time = current_user.todos.completed.find(:all, { :select => "completed_at, created_at" }) # convert to hash to be able to fill in non-existing days in # @actions_completion_time also convert days to weeks (/7) - @max_days, @max_actions, @sum_actions=0,0,0 - @actions_completion_time_hash = Hash.new(0) + @actions_completion_time_hash,@max_days, @max_actions, @sum_actions=Hash.new(0), 0,0,0 @actions_completion_time.each do |r| days = (r.completed_at - r.created_at) / @seconds_per_day weeks = (days/7).to_i @actions_completion_time_hash[weeks] += 1 - @max_days=days if days > @max_days - @max_actions = @actions_completion_time_hash[weeks] if @actions_completion_time_hash[weeks] > @max_actions + @max_days= [days, @max_days].max + @max_actions = [@actions_completion_time_hash[weeks], @max_actions].max @sum_actions += 1 end @@ -152,10 +148,7 @@ class StatsController < ApplicationController end def actions_running_time_data - @actions_running_time = @actions.find(:all, { - :select => "created_at", - :conditions => "completed_at IS NULL" - }) + @actions_running_time = current_user.todos.not_completed.find(:all, { :select => "created_at" }) # convert to hash to be able to fill in non-existing days in # @actions_running_time also convert days to weeks (/7) @@ -168,8 +161,8 @@ class StatsController < ApplicationController @actions_running_time_hash[weeks] += 1 - @max_days=days if days > @max_days - @max_actions = @actions_running_time_hash[weeks] if @actions_running_time_hash[weeks] > @max_actions + @max_days=[days,@max_days].max + @max_actions = [@actions_running_time_hash[weeks], @max_actions].max @sum_actions += 1 end @@ -181,21 +174,14 @@ class StatsController < ApplicationController def actions_visible_running_time_data # running means - # - not completed (completed_at must be null) visible means + # - not completed (completed_at must be null) + # visible means # - actions not part of a hidden project # - actions not part of a hidden context # - actions not deferred (show_from must be null) # - actions not pending/blocked - @actions_running_time = @actions.find_by_sql([ - "SELECT t.created_at "+ - "FROM todos t LEFT OUTER JOIN projects p ON t.project_id = p.id LEFT OUTER JOIN contexts c ON t.context_id = c.id "+ - "WHERE t.user_id=? "+ - "AND t.completed_at IS NULL " + - "AND t.show_from IS NULL " + - "AND NOT (p.state='hidden' OR p.state='pending' OR c.hide=?) " + - "ORDER BY t.created_at ASC", @user.id, true] - ) + @actions_running_time = current_user.todos.not_completed.not_hidden.not_deferred_or_blocked.find(:all, :select => "todos.created_at") # convert to hash to be able to fill in non-existing days in # @actions_running_time also convert days to weeks (/7) @@ -205,11 +191,10 @@ class StatsController < ApplicationController @actions_running_time.each do |r| days = (@today - r.created_at) / @seconds_per_day weeks = (days/7).to_i - # RAILS_DEFAULT_LOGGER.error("\n" + total.to_s + " - " + days + "\n") @actions_running_time_hash[weeks] += 1 - @max_days=days if days > @max_days - @max_actions = @actions_running_time_hash[weeks] if @actions_running_time_hash[weeks] > @max_actions + @max_days=[days, @max_days].max + @max_actions = [@actions_running_time_hash[weeks], @max_actions].max @sum_actions += 1 end @@ -224,11 +209,10 @@ class StatsController < ApplicationController # get total action count per context Went from GROUP BY c.id to c.name for # compatibility with postgresql. Since the name is forced to be unique, this # should work. - @all_actions_per_context = @contexts.find_by_sql( + @all_actions_per_context = current_user.contexts.find_by_sql( "SELECT c.name AS name, c.id as id, count(*) AS total "+ "FROM contexts c, todos t "+ "WHERE t.context_id=c.id "+ - "AND t.user_id="+@user.id.to_s+" "+ "GROUP BY c.name, c.id "+ "ORDER BY total DESC" ) @@ -250,10 +234,7 @@ class StatsController < ApplicationController end end - @sum=0 - 0.upto @all_actions_per_context.size()-1 do |i| - @sum += @all_actions_per_context[i]['total'].to_i - end + @sum = @all_actions_per_context.inject(0){|sum, apc| sum += apc['total'].to_i } @truncate_chars = 15 @@ -265,11 +246,10 @@ class StatsController < ApplicationController # # Went from GROUP BY c.id to c.name for compatibility with postgresql. Since # the name is forced to be unique, this should work. - @all_actions_per_context = @contexts.find_by_sql( + @all_actions_per_context = current_user.contexts.find_by_sql( "SELECT c.name AS name, c.id as id, count(*) AS total "+ "FROM contexts c, todos t "+ "WHERE t.context_id=c.id AND t.completed_at IS NULL AND NOT c.hide "+ - "AND t.user_id="+@user.id.to_s+" "+ "GROUP BY c.name, c.id "+ "ORDER BY total DESC" ) @@ -291,102 +271,57 @@ class StatsController < ApplicationController end end - @sum=0 - 0.upto @all_actions_per_context.size()-1 do |i| - @sum += @all_actions_per_context[i]['total'].to_i - end - + @sum = @all_actions_per_context.inject(0){|sum, apc| sum += apc['total'].to_i } @truncate_chars = 15 render :layout => false end def actions_day_of_week_all_data - @actions = @user.todos - - @actions_creation_day = @actions.find(:all, { - :select => "created_at" - }) - - @actions_completion_day = @actions.find(:all, { - :select => "completed_at", - :conditions => "completed_at IS NOT NULL" - }) + @actions_creation_day = current_user.todos.find(:all, { :select => "created_at" }) + @actions_completion_day = current_user.todos.completed.find(:all, { :select => "completed_at" }) # convert to hash to be able to fill in non-existing days @actions_creation_day_array = Array.new(7) { |i| 0} - @actions_creation_day.each do |t| - # dayofweek: sunday=0..saterday=6 - dayofweek = t.created_at.wday - @actions_creation_day_array[dayofweek] += 1 - end - # find max - @max=0 - 0.upto(6) { |i| @max = @actions_creation_day_array[i] if @actions_creation_day_array[i] > @max} - + @actions_creation_day.each { |t| @actions_creation_day_array[ t.created_at.wday ] += 1 } + @max = @actions_creation_day_array.max # convert to hash to be able to fill in non-existing days @actions_completion_day_array = Array.new(7) { |i| 0} - @actions_completion_day.each do |t| - # dayofweek: sunday=0..saterday=6 - dayofweek = t.completed_at.wday - @actions_completion_day_array[dayofweek] += 1 - end - 0.upto(6) { |i| @max = @actions_completion_day_array[i] if @actions_completion_day_array[i] > @max} + @actions_completion_day.each { |t| @actions_completion_day_array[ t.completed_at.wday ] += 1 } + @max = @actions_completion_day_array.max render :layout => false end def actions_day_of_week_30days_data - @actions_creation_day = @actions.find(:all, { - :select => "created_at", - :conditions => ["created_at > ?", @cut_off_month] - }) - - @actions_completion_day = @actions.find(:all, { - :select => "completed_at", - :conditions => ["completed_at IS NOT NULL AND completed_at > ?", @cut_off_month] - }) + @actions_creation_day = current_user.todos.created_after(@cut_off_month).find(:all, { :select => "created_at" }) + @actions_completion_day = current_user.todos.completed_after(@cut_off_month).find(:all, { :select => "completed_at" }) # convert to hash to be able to fill in non-existing days @max=0 @actions_creation_day_array = Array.new(7) { |i| 0} - @actions_creation_day.each do |r| - # dayofweek: sunday=1..saterday=8 - dayofweek = r.created_at.wday - @actions_creation_day_array[dayofweek] += 1 - end - 0.upto(6) { |i| @max = @actions_creation_day_array[i] if @actions_creation_day_array[i] > @max} + @actions_creation_day.each { |r| @actions_creation_day_array[ r.created_at.wday ] += 1 } # convert to hash to be able to fill in non-existing days @actions_completion_day_array = Array.new(7) { |i| 0} - @actions_completion_day.each do |r| - # dayofweek: sunday=1..saterday=7 - dayofweek = r.completed_at.wday - @actions_completion_day_array[dayofweek] += 1 - end - 0.upto(6) { |i| @max = @actions_completion_day_array[i] if @actions_completion_day_array[i] > @max} + @actions_completion_day.each { |r| @actions_completion_day_array[r.completed_at.wday] += 1 } + + @max = [@actions_creation_day_array.max, @actions_completion_day_array.max].max render :layout => false end def actions_time_of_day_all_data - @actions_creation_hour = @actions.find(:all, { - :select => "created_at" - }) - @actions_completion_hour = @actions.find(:all, { - :select => "completed_at", - :conditions => "completed_at IS NOT NULL" - }) + @actions_creation_hour = current_user.todos.find(:all, { :select => "created_at" }) + @actions_completion_hour = current_user.todos.completed.find(:all, { :select => "completed_at" }) # convert to hash to be able to fill in non-existing days - @max=0 @actions_creation_hour_array = Array.new(24) { |i| 0} @actions_creation_hour.each do |r| hour = r.created_at.hour @actions_creation_hour_array[hour] += 1 end - 0.upto(23) { |i| @max = @actions_creation_hour_array[i] if @actions_creation_hour_array[i] > @max} # convert to hash to be able to fill in non-existing days @actions_completion_hour_array = Array.new(24) { |i| 0} @@ -394,30 +329,22 @@ class StatsController < ApplicationController hour = r.completed_at.hour @actions_completion_hour_array[hour] += 1 end - 0.upto(23) { |i| @max = @actions_completion_hour_array[i] if @actions_completion_hour_array[i] > @max} + + @max = [@actions_creation_hour_array.max, @actions_completion_hour_array.max].max render :layout => false end def actions_time_of_day_30days_data - @actions_creation_hour = @actions.find(:all, { - :select => "created_at", - :conditions => ["created_at > ?", @cut_off_month] - }) - - @actions_completion_hour = @actions.find(:all, { - :select => "completed_at", - :conditions => ["completed_at IS NOT NULL AND completed_at > ?", @cut_off_month] - }) + @actions_creation_hour = current_user.todos.created_after(@cut_off_month).find(:all, { :select => "created_at" }) + @actions_completion_hour = current_user.todos.completed_after(@cut_off_month).find(:all, { :select => "completed_at" }) # convert to hash to be able to fill in non-existing days - @max=0 @actions_creation_hour_array = Array.new(24) { |i| 0} @actions_creation_hour.each do |r| hour = r.created_at.hour @actions_creation_hour_array[hour] += 1 end - 0.upto(23) { |i| @max = @actions_creation_hour_array[i] if @actions_creation_hour_array[i] > @max} # convert to hash to be able to fill in non-existing days @actions_completion_hour_array = Array.new(24) { |i| 0} @@ -425,7 +352,8 @@ class StatsController < ApplicationController hour = r.completed_at.hour @actions_completion_hour_array[hour] += 1 end - 0.upto(23) { |i| @max = @actions_completion_hour_array[i] if @actions_completion_hour_array[i] > @max} + + @max = [@actions_creation_hour_array.max, @max = @actions_completion_hour_array.max].max render :layout => false end @@ -458,19 +386,17 @@ class StatsController < ApplicationController end # get all running actions that are visible - @actions_running_time = @actions.find_by_sql([ + @actions_running_time = current_user.todos.find_by_sql([ "SELECT t.id, t.created_at "+ "FROM todos t LEFT OUTER JOIN projects p ON t.project_id = p.id LEFT OUTER JOIN contexts c ON t.context_id = c.id "+ - "WHERE t.user_id=? "+ - "AND t.completed_at IS NULL " + + "WHERE t.completed_at IS NULL " + "AND t.show_from IS NULL " + "AND NOT (p.state='hidden' OR c.hide=?) " + - "ORDER BY t.created_at ASC", @user.id, true] + "ORDER BY t.created_at ASC", true] ) @selected_todo_ids, @count = get_ids_from(@actions_running_time, week_from, week_to, params['id']== 'avrt_end') - @actions = @user.todos - @selected_actions = @actions.find(:all, { + @selected_actions = current_user.todos.find(:all, { :conditions => "id in (" + @selected_todo_ids + ")" }) @@ -490,12 +416,8 @@ class StatsController < ApplicationController @page_title += week_from.to_s + " - " + week_to.to_s + "" end - @actions = @user.todos # get all running actions - @actions_running_time = @actions.find(:all, { - :select => "id, created_at", - :conditions => "completed_at IS NULL" - }) + @actions_running_time = current_user.todos.not_completed.find(:all, { :select => "id, created_at" }) @selected_todo_ids, @count = get_ids_from(@actions_running_time, week_from, week_to, params['id']=='art_end') @selected_actions = @actions.find(:all, { @@ -524,12 +446,11 @@ class StatsController < ApplicationController private def get_unique_tags_of_user - tag_ids = @actions.find_by_sql([ + tag_ids = current_user.todos.find_by_sql([ "SELECT DISTINCT tags.id as id "+ "FROM tags, taggings, todos "+ - "WHERE todos.user_id=? "+ - "AND tags.id = taggings.tag_id " + - "AND taggings.taggable_id = todos.id ", current_user.id]) + "WHERE tags.id = taggings.tag_id " + + "AND taggings.taggable_id = todos.id "]) tags_ids_s = tag_ids.map(&:id).sort.join(",") return {} if tags_ids_s.blank? # return empty hash for .size to work return Tag.find(:all, :conditions => "id in (" + tags_ids_s + ")") @@ -537,19 +458,15 @@ class StatsController < ApplicationController def get_total_number_of_tags_of_user # same query as get_unique_tags_of_user except for the DISTINCT - return @actions.find_by_sql([ + return current_user.todos.find_by_sql([ "SELECT tags.id as id "+ "FROM tags, taggings, todos "+ - "WHERE todos.user_id=? "+ - "AND tags.id = taggings.tag_id " + - "AND taggings.taggable_id = todos.id ", current_user.id]).size + "WHERE tags.id = taggings.tag_id " + + "AND taggings.taggable_id = todos.id "]).size end def init @me = self # for meta programming - @actions = current_user.todos - @projects = current_user.projects - @contexts = current_user.contexts # default chart dimensions @chart_width=460 @@ -572,18 +489,15 @@ class StatsController < ApplicationController def get_stats_actions # time to complete - @completed_actions = @actions.find(:all, { - :select => "completed_at, created_at", - :conditions => "completed_at IS NOT NULL", - }) + @completed_actions = current_user.todos.completed.find(:all, { :select => "completed_at, created_at" }) actions_sum, actions_max, actions_min = 0,0,-1 @completed_actions.each do |r| actions_sum += (r.completed_at - r.created_at) - actions_max = (r.completed_at - r.created_at) if (r.completed_at - r.created_at) > actions_max + actions_max = [(r.completed_at - r.created_at), actions_max].max actions_min = (r.completed_at - r.created_at) if actions_min == -1 - actions_min = (r.completed_at - r.created_at) if (r.completed_at - r.created_at) < actions_min + actions_min = [(r.completed_at - r.created_at), actions_min].min end sum_actions = @completed_actions.size @@ -597,22 +511,13 @@ class StatsController < ApplicationController @actions_min_ttc_sec = (min_ttc_sec).strftime("%H:%M:%S") @actions_min_ttc_sec = (actions_min / @seconds_per_day).round.to_s + " days " + @actions_min_ttc_sec if actions_min > @seconds_per_day - # get count of actions created and actions done in the past 30 days. - @sum_actions_done_last30days = @actions.count(:all, { - :conditions => ["completed_at > ? AND completed_at IS NOT NULL", @cut_off_month] - }) - @sum_actions_created_last30days = @actions.count(:all, { - :conditions => ["created_at > ?", @cut_off_month] - }) + @sum_actions_done_last30days = current_user.todos.completed.completed_after(@cut_off_month).count(:all) + @sum_actions_created_last30days = current_user.todos.created_after(@cut_off_month).count(:all) # get count of actions done in the past 12 months. - @sum_actions_done_last12months = @actions.count(:all, { - :conditions => ["completed_at > ? AND completed_at IS NOT NULL", @cut_off_year] - }) - @sum_actions_created_last12months = @actions.count(:all, { - :conditions => ["created_at > ?", @cut_off_year] - }) + @sum_actions_done_last12months = current_user.todos.completed.completed_after(@cut_off_year).count(:all) + @sum_actions_created_last12months = current_user.todos.created_after(@cut_off_year).count(:all) end def get_stats_contexts @@ -620,11 +525,10 @@ class StatsController < ApplicationController # # Went from GROUP BY c.id to c.id, c.name for compatibility with postgresql. # Since the name is forced to be unique, this should work. - @actions_per_context = @contexts.find_by_sql( + @actions_per_context = current_user.contexts.find_by_sql( "SELECT c.id AS id, c.name AS name, count(*) AS total "+ "FROM contexts c, todos t "+ "WHERE t.context_id=c.id "+ - "AND t.user_id="+@user.id.to_s+" "+ "GROUP BY c.id, c.name ORDER BY total DESC " + "LIMIT 5" ) @@ -633,11 +537,10 @@ class StatsController < ApplicationController # # Went from GROUP BY c.id to c.id, c.name for compatibility with postgresql. # Since the name is forced to be unique, this should work. - @running_actions_per_context = @contexts.find_by_sql( + @running_actions_per_context = current_user.contexts.find_by_sql( "SELECT c.id AS id, c.name AS name, count(*) AS total "+ "FROM contexts c, todos t "+ "WHERE t.context_id=c.id AND t.completed_at IS NULL AND NOT c.hide "+ - "AND t.user_id="+@user.id.to_s+" "+ "GROUP BY c.id, c.name ORDER BY total DESC " + "LIMIT 5" ) @@ -648,11 +551,10 @@ class StatsController < ApplicationController # # Went from GROUP BY p.id to p.name for compatibility with postgresql. Since # the name is forced to be unique, this should work. - @projects_and_actions = @projects.find_by_sql( + @projects_and_actions = current_user.projects.find_by_sql( "SELECT p.id, p.name, count(*) AS count "+ "FROM projects p, todos t "+ "WHERE p.id = t.project_id "+ - "AND p.user_id="+@user.id.to_s+" "+ "GROUP BY p.id, p.name "+ "ORDER BY count DESC " + "LIMIT 10" @@ -663,20 +565,19 @@ class StatsController < ApplicationController # using GROUP BY p.name (was: p.id) for compatibility with Postgresql. Since # you cannot create two contexts with the same name, this will work. - @projects_and_actions_last30days = @projects.find_by_sql([ + @projects_and_actions_last30days = current_user.projects.find_by_sql([ "SELECT p.id, p.name, count(*) AS count "+ "FROM todos t, projects p "+ "WHERE t.project_id = p.id AND "+ " (t.created_at > ? OR t.completed_at > ?) "+ - "AND p.user_id=? "+ "GROUP BY p.id, p.name "+ "ORDER BY count DESC " + - "LIMIT 10", @cut_off_month, @cut_off_month, @user.id] + "LIMIT 10", @cut_off_month, @cut_off_month] ) # get the first 10 projects and their running time (creation date versus # now()) - @projects_and_runtime_sql = @projects.find_by_sql( + @projects_and_runtime_sql = current_user.projects.find_by_sql( "SELECT id, name, created_at "+ "FROM projects "+ "WHERE state='active' "+ @@ -717,8 +618,8 @@ class StatsController < ApplicationController max, @tags_min = 0, 0 @tags_for_cloud.each { |t| - max = t.count.to_i if t.count.to_i > max - @tags_min = t.count.to_i if t.count.to_i < @tags_min + max = [t.count.to_i, max].max + @tags_min = [t.count.to_i, @tags_min].min } @tags_divisor = ((max - @tags_min) / levels) + 1 @@ -741,8 +642,8 @@ class StatsController < ApplicationController max_90days, @tags_min_90days = 0, 0 @tags_for_cloud_90days.each { |t| - max_90days = t.count.to_i if t.count.to_i > max_90days - @tags_min_90days = t.count.to_i if t.count.to_i < @tags_min_90days + max_90days = [t.count.to_i, max_90days].max + @tags_min_90days = [t.count.to_i, @tags_min_90days].min } @tags_divisor_90days = ((max_90days - @tags_min_90days) / levels) + 1 @@ -775,10 +676,10 @@ class StatsController < ApplicationController return selected_todo_ids, count end - def convert_to_hash(records, date_method, difference_method=:difference_in_months) + def convert_to_hash(records, difference_method, date_method_on_todo) # use 0 to initialise action count to zero hash = Hash.new(0) - records.each { |t| hash[self.send(difference_method, @today, t.send(date_method))] += 1 } + records.each { |t| hash[self.send(difference_method, @today, t.send(date_method_on_todo))] += 1 } return hash end diff --git a/app/views/stats/_totals.rhtml b/app/views/stats/_totals.rhtml index 33db9cb5..4d2dac0c 100755 --- a/app/views/stats/_totals.rhtml +++ b/app/views/stats/_totals.rhtml @@ -1,20 +1,20 @@ -

    <%= t('stats.totals_project_count', :count => @projects.count) %> - <%= t('stats.totals_active_project_count', :count => @projects.active.count) %>, - <%= t('stats.totals_hidden_project_count', :count => @projects.hidden.count) %> - <%= t('stats.totals_completed_project_count', :count => @projects.completed.count) %>

    +

    <%= t('stats.totals_project_count', :count => current_user.projects.count) %> + <%= t('stats.totals_active_project_count', :count => current_user.projects.active.count) %>, + <%= t('stats.totals_hidden_project_count', :count => current_user.projects.hidden.count) %> + <%= t('stats.totals_completed_project_count', :count => current_user.projects.completed.count) %>

    -

    <%= t('stats.totals_context_count', :count => @contexts.count ) %> -<%= t('stats.totals_visible_context_count', :count => @contexts.active.count) %> -<%= t('stats.totals_hidden_context_count', :count => @contexts.hidden.count) %> +

    <%= t('stats.totals_context_count', :count => current_user.contexts.count ) %> +<%= t('stats.totals_visible_context_count', :count => current_user.contexts.active.count) %> +<%= t('stats.totals_hidden_context_count', :count => current_user.contexts.hidden.count) %> -<% unless @actions.empty? -%> +<% unless current_user.todos.empty? -%>

    <%= t('stats.totals_first_action', :date => format_date(@first_action.created_at)) %> -<%= t('stats.totals_action_count', :count => @actions.count) %>, -<%= t('stats.totals_actions_completed', :count => @actions.completed.count) %> +<%= t('stats.totals_action_count', :count => current_user.todos.count) %>, +<%= t('stats.totals_actions_completed', :count => current_user.todos.completed.count) %> -

    <%= t('stats.totals_incomplete_actions', :count => @actions.not_completed.count) %> -<%= t('stats.totals_deferred_actions', :count => @actions.deferred.count) %> -<%= t('stats.totals_blocked_actions', :count => @actions.blocked.count) %> +

    <%= t('stats.totals_incomplete_actions', :count => current_user.todos.not_completed.count) %> +<%= t('stats.totals_deferred_actions', :count => current_user.todos.deferred.count) %> +<%= t('stats.totals_blocked_actions', :count => current_user.todos.blocked.count) %>

    <%= t('stats.totals_tag_count', :count => @tags_count) %> diff --git a/app/views/stats/index.html.erb b/app/views/stats/index.html.erb index 46073cd9..7470731e 100755 --- a/app/views/stats/index.html.erb +++ b/app/views/stats/index.html.erb @@ -1,30 +1,26 @@

    <%= t('stats.totals') %>

    - + <%= render :partial => 'totals' -%> - - <% unless @actions.empty? -%> - + + <% unless current_user.todos.empty? -%> +

    <%= t('stats.actions') %>

    - <%= render :partial => 'actions' -%> - +

    <%= t('stats.contexts') %>

    - <%= render :partial => 'contexts' -%> - +

    <%= t('stats.projects') %>

    - <%= render :partial => 'projects' -%> - +

    <%= t('stats.tags') %>

    - <%= render :partial => 'tags' -%> - + <% else -%> - +

    <%= t('stats.more_stats_will_appear') %>

    - + <% end -%> - +
    \ No newline at end of file From 80d8d2b67ab99293d5b3372ed430f568dcca5791 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Fri, 25 Nov 2011 14:32:07 +0100 Subject: [PATCH 011/134] add tests --- app/controllers/stats_controller.rb | 4 +- test/functional/stats_controller_test.rb | 61 ++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index 569a6e52..975c254b 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -420,9 +420,7 @@ class StatsController < ApplicationController @actions_running_time = current_user.todos.not_completed.find(:all, { :select => "id, created_at" }) @selected_todo_ids, @count = get_ids_from(@actions_running_time, week_from, week_to, params['id']=='art_end') - @selected_actions = @actions.find(:all, { - :conditions => "id in (" + @selected_todo_ids + ")" - }) + @selected_actions = current_user.todos.find(:all, { :conditions => "id in (" + @selected_todo_ids + ")" }) render :action => "show_selection_from_chart" else diff --git a/test/functional/stats_controller_test.rb b/test/functional/stats_controller_test.rb index 14ebec73..94aac79b 100755 --- a/test/functional/stats_controller_test.rb +++ b/test/functional/stats_controller_test.rb @@ -48,10 +48,6 @@ class StatsControllerTest < ActionController::TestCase login_as(:admin_user) get :index assert_response :success - assert_equal 3, assigns['projects'].count - assert_equal 3, assigns['projects'].count(:conditions => "state = 'active'") - assert_equal 10, assigns['contexts'].count - assert_equal 17, assigns['actions'].count assert_equal 4, assigns['tags_count'] assert_equal 2, assigns['unique_tags_count'] assert_equal 2.week.ago.utc.at_midnight, assigns['first_action'].created_at.utc.at_midnight @@ -97,6 +93,61 @@ class StatsControllerTest < ActionController::TestCase Tagging.delete_all get :index assert_response :success - end + + def test_actions_done_last12months_data + login_as(:admin_user) + @current_user = User.find(users(:admin_user).id) + @current_user.todos.delete_all + + # Given two todos created today + todo_today1 = @current_user.todos.create!(:description => "created today1", :context => contexts(:office)) + todo_today2 = @current_user.todos.create!(:description => "created today2", :context => contexts(:office)) + # And a todo created a month ago + todo_month1 = create_todo_in_past(1.month+1.day) + # And a todo created two months ago + todo_month2 = create_completed_todo_in_past(2.months+1.day, 2.months+2.days) + # And a todo created three months ago + todo_month3 = create_todo_in_past(3.months+1.day) + # And a todo created over a year ago + todo_year = create_todo_in_past(2.years+1.day) + + # When I get the chart data + get :actions_done_last12months_data + assert_response :success + + # Then the todos for the chart should be retrieved + assert_not_nil assigns['actions_done_last12months'] + assert_not_nil assigns['actions_created_last12months'] + assert_equal 5, assigns['actions_created_last12months'].count, "very old todo should not be retrieved" + + # And they should be totalled in a hash + assert_equal 2, assigns['actions_created_last12months_hash'][0], "there should be two todos in current month" + assert_equal 1, assigns['actions_created_last12months_hash'][1], "there should be one todo in previous month" + assert_equal 1, assigns['actions_created_last12months_hash'][2], "there should be one todo in two month ago" + assert_equal 1, assigns['actions_created_last12months_hash'][3], "there should be one todo in three month ago" + + assert_equal 1, assigns['actions_done_last12months_hash'][2], "there should be one completed todo in two month ago" + + # And they should be averaged + # And the current month should be interpolated + # And totals should be calculated + end + + def create_todo_in_past(creation_time_in_past) + todo = @current_user.todos.create!(:description => "created #{creation_time_in_past} ago", :context => contexts(:office)) + todo.created_at = Time.zone.now - creation_time_in_past + todo.save! + return todo + end + + def create_completed_todo_in_past(creation_time_in_past, completed_time_in_past) + todo = @current_user.todos.create!(:description => "created #{creation_time_in_past} ago", :context => contexts(:office)) + todo.complete! + todo.completed_at = Time.zone.now - completed_time_in_past + todo.created_at = Time.zone.now - creation_time_in_past + todo.save! + return todo + end + end From 2349bee53553c6111f3a30d8f3259d34bd83f27e Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Mon, 28 Nov 2011 23:38:57 +0100 Subject: [PATCH 012/134] further refactorings and tests one test is failing, will fix that next time --- app/controllers/stats_controller.rb | 207 +++++++++--------- .../actions_completion_time_data.html.erb | 17 +- .../actions_done_last12months_data.html.erb | 33 +-- .../actions_done_last30days_data.html.erb | 14 +- .../actions_done_lastyears_data.html.erb | 28 +-- .../stats/actions_running_time_data.html.erb | 20 +- ...actions_visible_running_time_data.html.erb | 16 +- test/functional/stats_controller_test.rb | 136 ++++++++++-- 8 files changed, 289 insertions(+), 182 deletions(-) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index 975c254b..b55ab963 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -23,33 +23,28 @@ class StatsController < ApplicationController def actions_done_last12months_data # get actions created and completed in the past 12+3 months. +3 for running # average - @actions_done_last12months = current_user.todos.completed_after(@cut_off_year_plus3).find(:all, { :select => "completed_at" }) - @actions_created_last12months = current_user.todos.created_after(@cut_off_year_plus3).find(:all, { :select => "created_at"}) + @actions_done_last12months = current_user.todos.completed_after(@cut_off_year).find(:all, { :select => "completed_at" }) + @actions_created_last12months = current_user.todos.created_after(@cut_off_year).find(:all, { :select => "created_at"}) + @actions_done_last12monthsPlus3 = current_user.todos.completed_after(@cut_off_year_plus3).find(:all, { :select => "completed_at" }) + @actions_created_last12monthsPlus3 = current_user.todos.created_after(@cut_off_year_plus3).find(:all, { :select => "created_at"}) - # convert to hash to be able to fill in non-existing months - @actions_done_last12months_hash = convert_to_hash(@actions_done_last12months, :difference_in_months, :completed_at) - @actions_created_last12months_hash = convert_to_hash(@actions_created_last12months, :difference_in_months, :created_at) + # convert to array and fill in non-existing months + @actions_done_last12months_array = convert_to_array(convert_to_hash(@actions_done_last12months, :difference_in_months, :completed_at),13) + @actions_created_last12months_array = convert_to_array(convert_to_hash(@actions_created_last12months, :difference_in_months, :created_at),13) + @actions_done_last12monthsPlus3_array = convert_to_array(convert_to_hash(@actions_done_last12monthsPlus3, :difference_in_months, :completed_at),15) + @actions_created_last12monthsPlus3_array = convert_to_array(convert_to_hash(@actions_created_last12monthsPlus3, :difference_in_months, :created_at),15) + + # find max for graph in both arrays + @max = [@actions_done_last12months_array.max, @actions_created_last12months_array.max].max - # find max for graph in both hashes - @sum_actions_done_last12months, @sum_actions_created_last12months, @max = 0, 0, 0 - 0.upto 13 do |i| - @sum_actions_done_last12months += @actions_done_last12months_hash[i] - @sum_actions_created_last12months += @actions_created_last12months_hash[i] - @max = [@actions_done_last12months_hash[i], @actions_created_last12months_hash[i], @max].max - end - - # find running avg for month i by calculating avg of month i and the two - # after them. Ignore current month [0] because you do not have full data for it - @actions_done_avg_last12months_hash, @actions_created_avg_last12months_hash = Hash.new("null"), Hash.new("null") - 1.upto(12) do |i| - @actions_done_avg_last12months_hash[i] = three_month_avg(@actions_done_last12months_hash, i) - @actions_created_avg_last12months_hash[i] = three_month_avg(@actions_created_last12months_hash, i) - end + # find running avg + @actions_done_avg_last12months_array, @actions_created_avg_last12months_array = + find_running_avg_array(@actions_done_last12monthsPlus3_array, @actions_created_last12monthsPlus3_array, 13) # interpolate avg for current month. percent_of_month = Time.zone.now.day.to_f / Time.zone.now.end_of_month.day.to_f - @interpolated_actions_created_this_month = interpolate_avg(@actions_created_last12months_hash, percent_of_month) - @interpolated_actions_done_this_month = interpolate_avg(@actions_done_last12months_hash, percent_of_month) + @interpolated_actions_created_this_month = interpolate_avg(@actions_created_last12months_array, percent_of_month) + @interpolated_actions_done_this_month = interpolate_avg(@actions_done_last12months_array, percent_of_month) render :layout => false end @@ -61,47 +56,36 @@ class StatsController < ApplicationController end def actions_done_lastyears_data - @actions = current_user.todos - @actions_done_last_months = current_user.todos.completed.find(:all, { :select => "completed_at", :order => "completed_at DESC" }) @actions_created_last_months = current_user.todos.find(:all, { :select => "created_at", :order => "created_at DESC" }) + # query is sorted, so use last todo to calculate number of months @month_count = [difference_in_months(@today, @actions_created_last_months.last.created_at), - difference_in_months(@today, @actions_done_last_months.last.completed_at)].max + difference_in_months(@today, @actions_done_last_months.last.completed_at)].max + 1 - # convert to hash to be able to fill in non-existing months - @actions_done_last_months_hash = convert_to_hash(@actions_done_last_months, :difference_in_months, :completed_at) - @actions_created_last_months_hash = convert_to_hash(@actions_created_last_months, :difference_in_months, :created_at) + # convert to array and fill in non-existing months + @actions_done_last_months_array = convert_to_array(convert_to_hash(@actions_done_last_months, :difference_in_months, :completed_at), @month_count) + @actions_created_last_months_array = convert_to_array(convert_to_hash(@actions_created_last_months, :difference_in_months, :created_at), @month_count) # find max for graph in both hashes - @sum_actions_done_last_months, @sum_actions_created_last_months, @max = 0, 0, 0 - 0.upto @month_count do |i| - @sum_actions_done_last_months += @actions_done_last_months_hash[i] - @sum_actions_created_last_months += @actions_created_last_months_hash[i] - @max = [@actions_done_last_months_hash[i], @actions_created_last_months_hash[i], @max].max - end + @max = [@actions_done_last_months_array.max, @actions_created_last_months_array.max].max - # find running avg for month i by calculating avg of month i and the two - # after them. Ignore current month because you do not have full data for it - @actions_done_avg_last_months_hash, @actions_created_avg_last_months_hash = Hash.new("null"), Hash.new("null") - 1.upto(@month_count) do |i| - @actions_done_avg_last_months_hash[i] = three_month_avg(@actions_done_last_months_hash, i) - @actions_created_avg_last_months_hash[i] = three_month_avg(@actions_created_last_months_hash, i) - end + # find running avg + @actions_done_avg_last_months_array, @actions_created_avg_last_months_array = + find_running_avg_array(@actions_done_last_months_array, @actions_created_last_months_array, @month_count) - # correct last two months - correct_last_two_months(@actions_done_avg_last_months_hash, @month_count) - correct_last_two_months(@actions_created_avg_last_months_hash, @month_count) + # correct last two months since the data of last+1 and last+2 are not available for avg + correct_last_two_months(@actions_done_avg_last_months_array, @month_count-1) + correct_last_two_months(@actions_created_avg_last_months_array, @month_count-1) # interpolate avg for this month. percent_of_month = Time.zone.now.day.to_f / Time.zone.now.end_of_month.day.to_f - @interpolated_actions_created_this_month = interpolate_avg(@actions_created_last_months_hash, percent_of_month) - @interpolated_actions_done_this_month = interpolate_avg(@actions_done_last_months_hash, percent_of_month) + @interpolated_actions_created_this_month = interpolate_avg(@actions_created_last_months_array, percent_of_month) + @interpolated_actions_done_this_month = interpolate_avg(@actions_done_last_months_array, percent_of_month) render :layout => false end - def actions_done_last30days_data # get actions created and completed in the past 30 days. @actions_done_last30days = current_user.todos.completed_after(@cut_off_month).find(:all, { :select => "completed_at" }) @@ -114,33 +98,21 @@ class StatsController < ApplicationController @actions_created_last30days_hash = convert_to_hash(@actions_created_last30days, :difference_in_days, :created_at) # find max for graph in both hashes - @sum_actions_done_last30days, @sum_actions_created_last30days, @max = 0, 0, 0 - 0.upto(30) do |i| - @sum_actions_done_last30days += @actions_done_last30days_hash[i] - @sum_actions_created_last30days += @actions_created_last30days_hash[i] - @max = [ @actions_done_last30days_hash[i], @actions_created_last30days_hash[i], @max].max - end + @max = [find_max_in_hash(@actions_done_last30days_hash, 30), find_max_in_hash(@actions_created_last30days_hash, 30)].max render :layout => false end def actions_completion_time_data - @actions_completion_time = current_user.todos.completed.find(:all, { :select => "completed_at, created_at" }) + @actions_completion_time = current_user.todos.completed.find(:all, { :select => "completed_at, created_at", :order => "completed_at DESC" }) # convert to hash to be able to fill in non-existing days in # @actions_completion_time also convert days to weeks (/7) - @actions_completion_time_hash,@max_days, @max_actions, @sum_actions=Hash.new(0), 0,0,0 - @actions_completion_time.each do |r| - days = (r.completed_at - r.created_at) / @seconds_per_day - weeks = (days/7).to_i - @actions_completion_time_hash[weeks] += 1 - - @max_days= [days, @max_days].max - @max_actions = [@actions_completion_time_hash[weeks], @max_actions].max - @sum_actions += 1 - end - + @actions_completion_time_hash = convert_to_week_hash(@actions_completion_time) + @max_weeks = difference_in_weeks(@today, @actions_completion_time.last.completed_at) + @max_actions = find_max_in_hash(@actions_completion_time_hash, @max_weeks) + # stop the chart after 10 weeks @cut_off = 10 @@ -148,23 +120,11 @@ class StatsController < ApplicationController end def actions_running_time_data - @actions_running_time = current_user.todos.not_completed.find(:all, { :select => "created_at" }) + @actions_running_time = current_user.todos.not_completed.find(:all, { :select => "created_at", :order => "created_at DESC" }) - # convert to hash to be able to fill in non-existing days in - # @actions_running_time also convert days to weeks (/7) - - @max_days, @max_actions, @sum_actions=0,0,0 - @actions_running_time_hash = Hash.new(0) - @actions_running_time.each do |r| - days = (@today - r.created_at) / @seconds_per_day - weeks = (days/7).to_i - - @actions_running_time_hash[weeks] += 1 - - @max_days=[days,@max_days].max - @max_actions = [@actions_running_time_hash[weeks], @max_actions].max - @sum_actions += 1 - end + @actions_running_time_hash = convert_to_week_hash_today(@actions_running_time) + @max_weeks = difference_in_weeks(@today, @actions_running_time.last.created_at) + @max_actions = find_max_in_hash(@actions_running_time_hash, @max_weeks) # cut off chart at 52 weeks = one year @cut_off=52 @@ -181,22 +141,12 @@ class StatsController < ApplicationController # - actions not deferred (show_from must be null) # - actions not pending/blocked - @actions_running_time = current_user.todos.not_completed.not_hidden.not_deferred_or_blocked.find(:all, :select => "todos.created_at") + @actions_running_time = current_user.todos.not_completed.not_hidden.not_deferred_or_blocked.find( + :all, :select => "todos.created_at", :order => "todos.created_at DESC") - # convert to hash to be able to fill in non-existing days in - # @actions_running_time also convert days to weeks (/7) - - @max_days, @max_actions, @sum_actions=0,0,0 - @actions_running_time_hash = Hash.new(0) - @actions_running_time.each do |r| - days = (@today - r.created_at) / @seconds_per_day - weeks = (days/7).to_i - @actions_running_time_hash[weeks] += 1 - - @max_days=[days, @max_days].max - @max_actions = [@actions_running_time_hash[weeks], @max_actions].max - @sum_actions += 1 - end + @actions_running_time_hash = convert_to_week_hash_today(@actions_running_time) + @max_weeks = difference_in_weeks(@today, @actions_running_time.last.created_at) + @max_actions = find_max_in_hash(@actions_running_time_hash, @max_weeks) # cut off chart at 52 weeks = one year @cut_off=52 @@ -204,7 +154,6 @@ class StatsController < ApplicationController render :layout => false end - def context_total_actions_data # get total action count per context Went from GROUP BY c.id to c.name for # compatibility with postgresql. Since the name is forced to be unique, this @@ -674,6 +623,10 @@ class StatsController < ApplicationController return selected_todo_ids, count end + def convert_to_array(hash, upper_bound) + return Array.new(upper_bound){ |i| hash[i] } + end + def convert_to_hash(records, difference_method, date_method_on_todo) # use 0 to initialise action count to zero hash = Hash.new(0) @@ -681,6 +634,24 @@ class StatsController < ApplicationController return hash end + def convert_to_week_hash(records) + hash = Hash.new(0) + records.each do |r| + index = difference_in_weeks(r.completed_at, r.created_at) + hash[index] += 1 + end + return hash + end + + def convert_to_week_hash_today(records) + hash = Hash.new(0) + records.each do |r| + index = difference_in_weeks(@today, r.created_at) + hash[index] += 1 + end + return hash + end + # assumes date1 > date2 def difference_in_months(date1, date2) return (date1.year - date2.year)*12 + (date1.month - date2.month) @@ -690,18 +661,50 @@ class StatsController < ApplicationController def difference_in_days(date1, date2) return ((date1.at_midnight-date2.at_midnight)/@seconds_per_day).to_i end - - def three_month_avg(hash, i) - return (hash[i] + hash[i+1] + hash[i+2])/3.0 + + def difference_in_weeks(date1, date2) + return difference_in_days(date1, date2) / 7 end - def interpolate_avg(hash, percent) - return (hash[0]*percent + hash[1] + hash[2]) / 3.0 + def three_month_avg(set, i) + return ( (set[i]||0) + (set[i+1]||0) + (set[i+2]||0) )/3.0 + end + + def interpolate_avg(set, percent) + return (set[0]*percent + set[1] + set[2]) / 3.0 end def correct_last_two_months(month_data, count) month_data[count] = month_data[count] * 3 month_data[count-1] = month_data[count-1] * 3 / 2 if count > 1 end + + def find_max_in_hash(hash, upper_bound) + max = hash[0] + 1.upto(upper_bound){ |i| max = [hash[i], max].max } + return max + end + + def find_running_avg(done_hash, created_hash, upper_bound) + avg_done, avg_created = Hash.new("null"), Hash.new("null") + + # find running avg for month i by calculating avg of month i and the two + # after them. Ignore current month [0] because you do not have full data for it + 1.upto(upper_bound) do |i| + avg_done[i] = three_month_avg(done_hash, i) + avg_created[i] = three_month_avg(created_hash, i) + end + + return avg_done, avg_created + end + + def find_running_avg_array(done_array, created_array, upper_bound) + avg_done = Array.new(upper_bound){ |i| three_month_avg(done_array,i) } + avg_created = Array.new(upper_bound){ |i| three_month_avg(created_array,i) } + avg_done[0] = avg_created[0] = "null" + + return avg_done, avg_created + end + end \ No newline at end of file diff --git a/app/views/stats/actions_completion_time_data.html.erb b/app/views/stats/actions_completion_time_data.html.erb index be3a8237..3bcf0a35 100755 --- a/app/views/stats/actions_completion_time_data.html.erb +++ b/app/views/stats/actions_completion_time_data.html.erb @@ -5,33 +5,32 @@ &y_ticks=5,10,5& &filled_bar=50,0x9933CC,0x8010A0& &values= -<% @count = @max_days > @cut_off*7 ? @cut_off : @max_days/7 -@count = @count.to_i -0.upto @count-1 do |i| -%> +<% @count = @max_weeks > @cut_off ? @cut_off : @max_weeks +0.upto @count.to_i-1 do |i| -%> <%= @actions_completion_time_hash[i] -%>, <% end -%> -<% +<% @sum=0 -@count.upto @max_days/7 do |i| +@count.upto @max_weeks do |i| @sum += @actions_completion_time_hash[i] end -%> <%=@sum%>& &line_2=2,0xFF0000& &values_2= <% total=0 -@count = @max_days > @cut_off*7 ? @cut_off : @max_days/7 +@count = @max_weeks > @cut_off ? @cut_off : @max_weeks 0.upto @count-1 do |i| - total += @actions_completion_time_hash[i]*100.0/@sum_actions -%> + total += @actions_completion_time_hash[i]*100.0/@actions_completion_time.count -%> <%= total -%>, <% end -%> -<%= total+@sum*100.0/@sum_actions%>& +<%= total+@sum*100.0/@actions_completion_time.count%>& &x_labels=within 1, <% 1.upto @count-1 do |i| -%> <%= i %>-<%= i+1 %>, <% end -%> > <%= @count %>& &y_min=0& -<% # add one to @max for people who have no actions completed yet. +<% # add one to @max for people who have no actions completed yet. # OpenFlashChart cannot handle y_max=0 -%> &y_max=<%=1+@max_actions+@max_actions/10-%>& &show_y2=true& diff --git a/app/views/stats/actions_done_last12months_data.html.erb b/app/views/stats/actions_done_last12months_data.html.erb index 4d416e1c..605f9a5f 100755 --- a/app/views/stats/actions_done_last12months_data.html.erb +++ b/app/views/stats/actions_done_last12months_data.html.erb @@ -1,3 +1,9 @@ +<%- +url_array = Array.new(13){ |i| url_for :controller => 'stats', :action => 'actions_done_last_years'} +created_count_array = Array.new(13){ |i| @actions_created_last12months.count/12.0 } +done_count_array = Array.new(13){ |i| @actions_done_last12months.count/12.0 } +month_names = Array.new(13){ |i| Date::MONTHNAMES[ (Time.now.mon - i -1 ) % 12 + 1 ]} +-%> &title=<%= t('stats.actions_lastyear_title') %>,{font-size:16},& &y_legend=<%= t('stats.legend.number_of_actions') %>,12,0x736AFF& &x_legend=<%= t('stats.legend.months_ago') %>,12,0x736AFF& @@ -10,22 +16,19 @@ &line_6=2,0xAA0000, <%= t('stats.labels.month_avg_completed', :months => 3) %>, 9& &line_7=1,0xAA0000& &line_8=1,0x007700& -&values=<% 0.upto 11 do |i| -%><%= @actions_created_last12months_hash[i]%>,<% end -%><%= @actions_created_last12months_hash[12]%>& -&links=<% 0.upto 11 do |i| -%><%= url_for :controller => 'stats', :action => 'actions_done_last_years' %>,<% end -%><%= url_for :controller => 'stats', :action => 'actions_done_last_years' %>& -&links_2=<% 0.upto 11 do |i| -%><%= url_for :controller => 'stats', :action => 'actions_done_last_years' %>,<% end -%><%= url_for :controller => 'stats', :action => 'actions_done_last_years' %>& -&values_2=<% 0.upto 11 do |i| -%><%= @actions_done_last12months_hash[i]%>,<% end -%><%= @actions_done_last12months_hash[12]%>& -&values_3=<%0.upto 11 do |i| -%><%=@sum_actions_created_last12months/12.0-%>,<%end-%><%=@sum_actions_created_last12months/12.0-%>& -&values_4=<%0.upto 11 do |i| -%><%=@sum_actions_done_last12months/12.0-%>,<%end-%><%=@sum_actions_done_last12months/12.0-%>& -&values_5=<%0.upto 11 do |i| -%><%=@actions_created_avg_last12months_hash[i]-%>,<%end-%><%=@actions_created_avg_last12months_hash[12]-%>& -&values_6=<%0.upto 11 do |i| -%><%=@actions_done_avg_last12months_hash[i]-%>,<%end-%><%=@actions_done_avg_last12months_hash[12]-%>& -&values_7=<%=@interpolated_actions_created_this_month%>,<%=@actions_done_avg_last12months_hash[1]%>& -&values_8=<%=@interpolated_actions_done_this_month%>,<%=@actions_created_avg_last12months_hash[1]%>& -&x_labels=<%0.upto 11 do |i| -%> -<%= Date::MONTHNAMES[ (Time.now.mon - i -1 ) % 12 + 1 ] -%>, -<% end -%> -<%= Date::MONTHNAMES[(Time.now.mon - 12 -1 ) % 12 + 1] -%>& +&values=<%= @actions_created_last12months_array.join(",")%>& +&links=<%= url_array.join(",")%>& +&links_2=<%= url_array.join(",")%>& +&values_2=<%= @actions_done_last12months_array.join(",")%>& +&values_3=<%= created_count_array.join(",")%>& +&values_4=<%= done_count_array.join(",")%>& +&values_5=<%= @actions_created_avg_last12months_array.join(",")%>& +&values_6=<%= @actions_done_avg_last12months_array.join(",")%>& +&values_7=<%= @interpolated_actions_created_this_month%>,<%=@actions_done_avg_last12months_array[1]%>& +&values_8=<%= @interpolated_actions_done_this_month%>,<%=@actions_created_avg_last12months_array[1]%>& +&x_labels=<%= month_names.join(",")%>& &y_min=0& -<% # add one to @max for people who have no actions completed yet. +<% # add one to @max for people who have no actions completed yet. # OpenFlashChart cannot handle y_max=0 -%> &y_max=<%=@max+@max/10+1-%>& &x_label_style=9,,2,& \ No newline at end of file diff --git a/app/views/stats/actions_done_last30days_data.html.erb b/app/views/stats/actions_done_last30days_data.html.erb index 00efafc8..03bf323c 100755 --- a/app/views/stats/actions_done_last30days_data.html.erb +++ b/app/views/stats/actions_done_last30days_data.html.erb @@ -16,18 +16,18 @@ <% end -%><%= @actions_done_last30days_hash[30]%>& &values_3= <%0.upto 29 do |i| -%> -<%=@sum_actions_created_last30days/30.0-%>, +<%=@actions_created_last30days.count/30.0-%>, <%end-%> -<%=@sum_actions_created_last30days/30.0-%>& +<%=@actions_created_last30days.count/30.0-%>& &values_4= <%0.upto 29 do |i| -%> -<%=@sum_actions_done_last30days/30.0-%>, +<%=@actions_done_last30days.count/30.0-%>, <%end-%> -<%=@sum_actions_done_last30days/30.0-%>& +<%=@actions_done_last30days.count/30.0-%>& &x_labels= -<%0.upto 29 do |i| +<%0.upto 29 do |i| seconds = i * 24 * 60 * 60 - delta = Time.now-seconds + delta = Time.now-seconds -%> <%= delta.strftime("%a %d-%m") -%>, <% end @@ -36,7 +36,7 @@ <%= delta.strftime("%a %d-%m") -%>& &y_min=0& <% # max + 10% for some extra space at the top - # add one to @max for people who have no actions completed yet. + # add one to @max for people who have no actions completed yet. # OpenFlashChart cannot handle y_max=0 -%> &y_max=<%=@max+@max/10+1 -%>& &x_label_style=9,,2,3& \ No newline at end of file diff --git a/app/views/stats/actions_done_lastyears_data.html.erb b/app/views/stats/actions_done_lastyears_data.html.erb index 87245d13..d71c825d 100644 --- a/app/views/stats/actions_done_lastyears_data.html.erb +++ b/app/views/stats/actions_done_lastyears_data.html.erb @@ -1,3 +1,8 @@ +<%- +created_count_array = Array.new(@month_count){ |i| @actions_created_last_months.count/@month_count } +done_count_array = Array.new(@month_count){ |i| @actions_done_last_months.count/@month_count } +month_names = Array.new(@month_count){ |i| Date::MONTHNAMES[ (Time.now.mon - i -1 ) % 12 + 1 ]+ " " + (Time.now - i.months).year.to_s} +-%> &title=<%= t('stats.actions_last_year') %>,{font-size:16},& &y_legend=<%= t('stats.actions_last_year_legend.number_of_actions') %>,12,0x736AFF& &x_legend=<%= t('stats.actions_last_year_legend.months_ago') %>,12,0x736AFF& @@ -10,20 +15,17 @@ &line_6=2,0xAA0000, <%= t('stats.labels.month_avg_completed', :months => 3) %>, 9& &line_7=1,0xAA0000& &line_8=1,0x007700& -&values=<% 0.upto @month_count-1 do |i| -%><%= @actions_created_last_months_hash[i]%>,<% end -%><%= @actions_created_last_months_hash[@month_count]%>& -&values_2=<% 0.upto @month_count-1 do |i| -%><%= @actions_done_last_months_hash[i]%>,<% end -%><%= @actions_done_last_months_hash[@month_count]%>& -&values_3=<%0.upto @month_count-1 do |i| -%><%=@sum_actions_created_last_months/@month_count-%>,<%end-%><%=@sum_actions_created_last_months/@month_count-%>& -&values_4=<%0.upto @month_count-1 do |i| -%><%=@sum_actions_done_last_months/@month_count-%>,<%end-%><%=@sum_actions_done_last_months/@month_count-%>& -&values_5=<%0.upto @month_count-1 do |i| -%><%=@actions_created_avg_last_months_hash[i]-%>,<%end-%><%=@actions_created_avg_last_months_hash[@month_count]-%>& -&values_6=<%0.upto @month_count-1 do |i| -%><%=@actions_done_avg_last_months_hash[i]-%>,<%end-%><%=@actions_done_avg_last_months_hash[@month_count]-%>& -&values_7=<%=@interpolated_actions_created_this_month%>,<%=@actions_done_avg_last_months_hash[1]%>& -&values_8=<%=@interpolated_actions_done_this_month%>,<%=@actions_created_avg_last_months_hash[1]%>& -&x_labels=<%0.upto @month_count-1 do |i| -%> -<%= Date::MONTHNAMES[ (Time.now.mon - i -1 ) % 12 + 1 ] + " " + (Time.now - i.months).year.to_s -%>, -<% end -%> -<%= Date::MONTHNAMES[(Time.now.mon - @month_count -1 ) % 12 + 1] + " " + (Time.now - @month_count.months).year.to_s -%>& +&values=<%= @actions_created_last_months_array.join(",")%>& +&values_2=<%= @actions_done_last_months_array.join(",")%>& +&values_3=<%= created_count_array.join(",")%>& +&values_4=<%= done_count_array.join(",")%>& +&values_5=<%= @actions_created_avg_last_months_array.join(",")%>& +&values_6=<%= @actions_done_avg_last_months_array.join(",")%>& +&values_7=<%= @interpolated_actions_created_this_month%>,<%=@actions_done_avg_last_months_array[1]%>& +&values_8=<%= @interpolated_actions_done_this_month%>,<%=@actions_created_avg_last_months_array[1]%>& +&x_labels=<%= month_names.join(",")%>& &y_min=0& -<% # add one to @max for people who have no actions completed yet. +<% # add one to @max for people who have no actions completed yet. # OpenFlashChart cannot handle y_max=0 -%> &y_max=<%=@max+@max/10+1-%>& &x_label_style=9,,2,& \ No newline at end of file diff --git a/app/views/stats/actions_running_time_data.html.erb b/app/views/stats/actions_running_time_data.html.erb index a8a56300..923a0420 100755 --- a/app/views/stats/actions_running_time_data.html.erb +++ b/app/views/stats/actions_running_time_data.html.erb @@ -5,13 +5,13 @@ &y_ticks=5,10,5& &filled_bar=50,0x9933CC,0x8010A0& &values= -<% @count = @max_days > @cut_off*7 ? @cut_off : (@max_days/7).to_i - 0.upto @count-1 do |i| -%> +<% @count = @max_weeks > @cut_off ? @cut_off : @max_weeks + 0.upto @count.to_i-1 do |i| -%> <%= @actions_running_time_hash[i] -%>, <% end -%> -<% +<% @sum=0 - @count.upto((@max_days/7).to_i) {|i| @sum += @actions_running_time_hash[i]} -%> + @count.upto(@max_weeks.to_i) {|i| @sum += @actions_running_time_hash[i]} -%> <%=@sum%>& &links=<% 0.upto(@count-1) { |i| %><%= url_for :controller => 'stats', :action => 'show_selected_actions_from_chart', :index => i, :id=> "art" %>, <% } @@ -19,20 +19,20 @@ &line_2=2,0xFF0000& &values_2= <% total=0 - @count = @max_days > @cut_off*7 ? @cut_off : (@max_days/7).to_i - 0.upto @count-1 do |i| + @count = @max_weeks > @cut_off ? @cut_off : @max_weeks + 0.upto @count.to_i-1 do |i| total += @actions_running_time_hash[i] -%> - <%= total*100.0/@sum_actions -%>, + <%= total*100.0/@actions_running_time.count -%>, <% end -%> -<%= (total+@sum)*100.0/@sum_actions%>& +<%= (total+@sum)*100.0/@actions_running_time.count%>& &x_labels=< 1, <% 1.upto @count-1 do |i| -%> <%= i %>-<%= i+1 %>, <% end -%> ><%=@count-%>& &y_min=0& -<% @max_actions = @sum > @max_actions ? @sum : @max_actions -%> -<% # add one to @max for people who have no actions completed yet. +<% @max_actions = [@sum,@max_actions].max -%> +<% # add one to @max for people who have no actions completed yet. # OpenFlashChart cannot handle y_max=0 -%> &y_max=<%=1+@max_actions+@max_actions/10-%>& &x_label_style=9,,2,2& diff --git a/app/views/stats/actions_visible_running_time_data.html.erb b/app/views/stats/actions_visible_running_time_data.html.erb index c4c70505..9219e11c 100755 --- a/app/views/stats/actions_visible_running_time_data.html.erb +++ b/app/views/stats/actions_visible_running_time_data.html.erb @@ -5,11 +5,11 @@ &y_ticks=5,10,5& &filled_bar=50,0x9933CC,0x8010A0& &values= -<% @count = @max_days > @cut_off*7 ? @cut_off : (@max_days/7).to_i +<% @count = @max_weeks > @cut_off ? @cut_off : @max_weeks 0.upto(@count-1) { |i| -%><%= @actions_running_time_hash[i] -%>,<% } %> -<% +<% @sum=0 -@count.upto((@max_days/7).to_i) { |i| @sum += @actions_running_time_hash[i] } -%> +@count.upto(@max_weeks.to_i) { |i| @sum += @actions_running_time_hash[i] } -%> <%=@sum%>& &links=<% 0.upto(@count-1) { |i| %><%= url_for :controller => 'stats', :action => 'show_selected_actions_from_chart', :index => i, :id=> "avrt" %>, <% } @@ -17,12 +17,12 @@ &line_2=2,0xFF0000& &values_2= <% total=0 -@count = @max_days > @cut_off*7 ? @cut_off : (@max_days/7).to_i -0.upto @count-1 do |i| +@count = @max_weeks > @cut_off ? @cut_off : @max_weeks +0.upto @count-1 do |i| total += @actions_running_time_hash[i] -%> - <%= total*100.0/@sum_actions -%>, + <%= total*100.0/@actions_running_time.count -%>, <% end -%> -<%= (total+@sum)*100.0/@sum_actions%>& +<%= (total+@sum)*100.0/@actions_running_time.count%>& &x_labels=< 1, <% 1.upto @count-1 do |i| -%> <%= i %>-<%= i+1 %>, @@ -30,7 +30,7 @@ ><%=@count-%>& &y_min=0& <% @max_actions = @sum > @max_actions ? @sum : @max_actions -%> -<% # add one to @max for people who have no actions completed yet. +<% # add one to @max for people who have no actions completed yet. # OpenFlashChart cannot handle y_max=0 -%> &y_max=<%=1+@max_actions+@max_actions/10-%>& &x_label_style=9,,2,2& diff --git a/test/functional/stats_controller_test.rb b/test/functional/stats_controller_test.rb index 94aac79b..88ff2e27 100755 --- a/test/functional/stats_controller_test.rb +++ b/test/functional/stats_controller_test.rb @@ -100,17 +100,7 @@ class StatsControllerTest < ActionController::TestCase @current_user = User.find(users(:admin_user).id) @current_user.todos.delete_all - # Given two todos created today - todo_today1 = @current_user.todos.create!(:description => "created today1", :context => contexts(:office)) - todo_today2 = @current_user.todos.create!(:description => "created today2", :context => contexts(:office)) - # And a todo created a month ago - todo_month1 = create_todo_in_past(1.month+1.day) - # And a todo created two months ago - todo_month2 = create_completed_todo_in_past(2.months+1.day, 2.months+2.days) - # And a todo created three months ago - todo_month3 = create_todo_in_past(3.months+1.day) - # And a todo created over a year ago - todo_year = create_todo_in_past(2.years+1.day) + given_todos_for_stats # When I get the chart data get :actions_done_last12months_data @@ -119,19 +109,129 @@ class StatsControllerTest < ActionController::TestCase # Then the todos for the chart should be retrieved assert_not_nil assigns['actions_done_last12months'] assert_not_nil assigns['actions_created_last12months'] - assert_equal 5, assigns['actions_created_last12months'].count, "very old todo should not be retrieved" + assert_equal 7, assigns['actions_created_last12months'].count, "very old todo should not be retrieved" # And they should be totalled in a hash - assert_equal 2, assigns['actions_created_last12months_hash'][0], "there should be two todos in current month" - assert_equal 1, assigns['actions_created_last12months_hash'][1], "there should be one todo in previous month" - assert_equal 1, assigns['actions_created_last12months_hash'][2], "there should be one todo in two month ago" - assert_equal 1, assigns['actions_created_last12months_hash'][3], "there should be one todo in three month ago" + assert_equal 2, assigns['actions_created_last12months_array'][0], "there should be two todos in current month" + assert_equal 1, assigns['actions_created_last12months_array'][1], "there should be one todo in previous month" + assert_equal 1, assigns['actions_created_last12months_array'][2], "there should be one todo in two month ago" + assert_equal 1, assigns['actions_created_last12months_array'][3], "there should be one todo in three month ago" + assert_equal 2, assigns['actions_created_last12months_array'][4], "there should be two todos (1 created & 1 done) in four month ago" - assert_equal 1, assigns['actions_done_last12months_hash'][2], "there should be one completed todo in two month ago" + assert_equal 1, assigns['actions_done_last12months_array'][2], "there should be one completed todo in last three months" + assert_equal 1, assigns['actions_done_last12months_array'][4], "there should be one completed todo in last four months" - # And they should be averaged + # And they should be averaged over three months + assert_equal 1/3.0, assigns['actions_done_avg_last12months_array'][1], "fourth month should be excluded" + assert_equal 2/3.0, assigns['actions_done_avg_last12months_array'][2], "fourth month should be included" + + assert_equal 1.0, assigns['actions_created_avg_last12months_array'][1], "one every month" + assert_equal 4/3.0, assigns['actions_created_avg_last12months_array'][2], "two in fourth month" + # And the current month should be interpolated + fraction = Time.zone.now.day.to_f / Time.zone.now.end_of_month.day.to_f + assert_equal (2*fraction+2)/3.0, assigns['interpolated_actions_created_this_month'], "two this month and one in the last two months" + assert_equal 1/3.0, assigns['interpolated_actions_done_this_month'], "none this month and one in the last two months" + # And totals should be calculated + assert_equal 2, assigns['max'], "max of created or completed todos" + end + + def test_actions_done_lastyears_data + login_as(:admin_user) + @current_user = User.find(users(:admin_user).id) + @current_user.todos.delete_all + + given_todos_for_stats + + # When I get the chart data + get :actions_done_lastyears_data + assert_response :success + + # only tests difference with actions_done_last_12months_data + + # Then the count of months should be calculated + assert_equal 24, assigns['month_count'] + + # And the last two months are corrected + assert_equal 0.5, assigns['actions_done_avg_last_months_hash'][23] + assert_equal 1.0, assigns['actions_done_avg_last_months_hash'][24] + end + + def test_actions_completion_time_data + login_as(:admin_user) + @current_user = User.find(users(:admin_user).id) + @current_user.todos.delete_all + + given_todos_for_stats + + # When I get the chart data + get :actions_completion_time_data + assert_response :success + + # do not test stuff already implicitly tested in other tests + + assert_equal 104, assigns['max_weeks'], "two years is 104 weeks" + end + + def test_actions_running_time_data + login_as(:admin_user) + @current_user = User.find(users(:admin_user).id) + @current_user.todos.delete_all + + given_todos_for_stats + + # When I get the chart data + get :actions_running_time_data + assert_response :success + + # do not test stuff already implicitly tested in other tests + + assert_equal 17, assigns['max_weeks'], "there are action in the first 17 weeks of this year" + end + + def test_actions_visible_running_time_data + login_as(:admin_user) + @current_user = User.find(users(:admin_user).id) + @current_user.todos.delete_all + + given_todos_for_stats + + # When I get the chart data + get :actions_visible_running_time_data + login_as(:admin_user) + @current_user = User.find(users(:admin_user).id) + @current_user.todos.delete_all + + given_todos_for_stats + + # When I get the chart data + get :actions_running_time_data + assert_response :success + + # do not test stuff already implicitly tested in other tests + + assert_equal 17, assigns['max_weeks'], "there are action in the first 17 weeks of this year" + end + + private + + def given_todos_for_stats + # Given two todos created today + @todo_today1 = @current_user.todos.create!(:description => "created today1", :context => contexts(:office)) + @todo_today2 = @current_user.todos.create!(:description => "created today2", :context => contexts(:office)) + # And a todo created a month ago + @todo_month1 = create_todo_in_past(1.month+1.day) + # And a todo created two months ago + @todo_month2 = create_completed_todo_in_past(2.months+1.day, 2.months+2.days) + # And a todo created three months ago + @todo_month3 = create_todo_in_past(3.months+1.day) + # And a todo created four months ago + @todo_month4 = create_todo_in_past(4.months+1.day) + # And a todo created four months ago + @todo_month5 = create_completed_todo_in_past(4.months+1.day, 4.months+2.days) + # And a todo created over a year ago + @todo_year = create_completed_todo_in_past(2.years+1.day, 2.years+2.day) end def create_todo_in_past(creation_time_in_past) From b948cc48b29f7985c521c400e86d7533a341d2bf Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Fri, 9 Dec 2011 17:17:42 +0100 Subject: [PATCH 013/134] further refactoring and more tests --- app/controllers/stats_controller.rb | 137 +++++++++------- .../actions_completion_time_data.html.erb | 38 ++--- .../actions_done_last30days_data.html.erb | 41 ++--- .../actions_done_lastyears_data.html.erb | 8 +- .../stats/actions_running_time_data.html.erb | 50 +++--- ...actions_visible_running_time_data.html.erb | 48 +++--- test/functional/stats_controller_test.rb | 151 +++++++++++++----- 7 files changed, 256 insertions(+), 217 deletions(-) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index b55ab963..1adffe69 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -61,22 +61,22 @@ class StatsController < ApplicationController # query is sorted, so use last todo to calculate number of months @month_count = [difference_in_months(@today, @actions_created_last_months.last.created_at), - difference_in_months(@today, @actions_done_last_months.last.completed_at)].max + 1 + difference_in_months(@today, @actions_done_last_months.last.completed_at)].max # convert to array and fill in non-existing months - @actions_done_last_months_array = convert_to_array(convert_to_hash(@actions_done_last_months, :difference_in_months, :completed_at), @month_count) - @actions_created_last_months_array = convert_to_array(convert_to_hash(@actions_created_last_months, :difference_in_months, :created_at), @month_count) + @actions_done_last_months_array = convert_to_array(convert_to_hash(@actions_done_last_months, :difference_in_months, :completed_at), @month_count+1) + @actions_created_last_months_array = convert_to_array(convert_to_hash(@actions_created_last_months, :difference_in_months, :created_at), @month_count+1) # find max for graph in both hashes @max = [@actions_done_last_months_array.max, @actions_created_last_months_array.max].max # find running avg @actions_done_avg_last_months_array, @actions_created_avg_last_months_array = - find_running_avg_array(@actions_done_last_months_array, @actions_created_last_months_array, @month_count) + find_running_avg_array(@actions_done_last_months_array, @actions_created_last_months_array, @month_count+1) # correct last two months since the data of last+1 and last+2 are not available for avg - correct_last_two_months(@actions_done_avg_last_months_array, @month_count-1) - correct_last_two_months(@actions_created_avg_last_months_array, @month_count-1) + correct_last_two_months(@actions_done_avg_last_months_array, @month_count) + correct_last_two_months(@actions_created_avg_last_months_array, @month_count) # interpolate avg for this month. percent_of_month = Time.zone.now.day.to_f / Time.zone.now.end_of_month.day.to_f @@ -91,14 +91,12 @@ class StatsController < ApplicationController @actions_done_last30days = current_user.todos.completed_after(@cut_off_month).find(:all, { :select => "completed_at" }) @actions_created_last30days = current_user.todos.created_after(@cut_off_month).find(:all, { :select => "created_at" }) - # convert to hash to be able to fill in non-existing days in - # @actions_done_last30days and count the total actions done in the past 30 - # days to be able to calculate percentage - @actions_done_last30days_hash = convert_to_hash(@actions_done_last30days, :difference_in_days, :completed_at) - @actions_created_last30days_hash = convert_to_hash(@actions_created_last30days, :difference_in_days, :created_at) + # convert to array. 30+1 to have 30 complete days and one current day [0] + @actions_done_last30days_array = convert_to_array(convert_to_hash(@actions_done_last30days, :difference_in_days, :completed_at), 31) + @actions_created_last30days_array = convert_to_array(convert_to_hash(@actions_created_last30days, :difference_in_days, :created_at), 31) # find max for graph in both hashes - @max = [find_max_in_hash(@actions_done_last30days_hash, 30), find_max_in_hash(@actions_created_last30days_hash, 30)].max + @max = [@actions_done_last30days_array.max, @actions_created_last30days_array.max].max render :layout => false end @@ -106,15 +104,19 @@ class StatsController < ApplicationController def actions_completion_time_data @actions_completion_time = current_user.todos.completed.find(:all, { :select => "completed_at, created_at", :order => "completed_at DESC" }) - # convert to hash to be able to fill in non-existing days in - # @actions_completion_time also convert days to weeks (/7) - - @actions_completion_time_hash = convert_to_week_hash(@actions_completion_time) + # convert to array and fill in non-existing weeks with 0 @max_weeks = difference_in_weeks(@today, @actions_completion_time.last.completed_at) - @max_actions = find_max_in_hash(@actions_completion_time_hash, @max_weeks) + @actions_completed_per_week_array = convert_to_array(convert_to_week_hash(@actions_completion_time), @max_weeks+1) # stop the chart after 10 weeks - @cut_off = 10 + @count = [10, @max_weeks].min + + # convert to new array to hold max @cut_off elems + 1 for sum of actions after @cut_off + @actions_completion_time_array = cut_off_array(@actions_completed_per_week_array, @count) + @max_actions = @actions_completion_time_array.max + + # get percentage done cummulative + @cumm_percent_done = convert_to_cummulative_array(@actions_completion_time_array, @actions_completion_time.count) render :layout => false end @@ -122,13 +124,20 @@ class StatsController < ApplicationController def actions_running_time_data @actions_running_time = current_user.todos.not_completed.find(:all, { :select => "created_at", :order => "created_at DESC" }) - @actions_running_time_hash = convert_to_week_hash_today(@actions_running_time) + # convert to array and fill in non-existing weeks with 0 @max_weeks = difference_in_weeks(@today, @actions_running_time.last.created_at) - @max_actions = find_max_in_hash(@actions_running_time_hash, @max_weeks) + @actions_running_per_week_array = convert_to_array(convert_to_week_hash_today(@actions_running_time), @max_weeks+1) # cut off chart at 52 weeks = one year - @cut_off=52 + @count = [52, @max_weeks].min + + # convert to new array to hold max @cut_off elems + 1 for sum of actions after @cut_off + @actions_running_time_array = cut_off_array(@actions_running_per_week_array, @count) + @max_actions = @actions_running_time_array.max + # get percentage done cummulative + @cumm_percent_done = convert_to_cummulative_array(@actions_running_time_array, @actions_running_time.count ) + render :layout => false end @@ -144,12 +153,18 @@ class StatsController < ApplicationController @actions_running_time = current_user.todos.not_completed.not_hidden.not_deferred_or_blocked.find( :all, :select => "todos.created_at", :order => "todos.created_at DESC") - @actions_running_time_hash = convert_to_week_hash_today(@actions_running_time) @max_weeks = difference_in_weeks(@today, @actions_running_time.last.created_at) - @max_actions = find_max_in_hash(@actions_running_time_hash, @max_weeks) + @actions_running_per_week_array = convert_to_array(convert_to_week_hash_today(@actions_running_time), @max_weeks+1) # cut off chart at 52 weeks = one year - @cut_off=52 + @count = [52, @max_weeks].min + + # convert to new array to hold max @cut_off elems + 1 for sum of actions after @cut_off + @actions_running_time_array = cut_off_array(@actions_running_per_week_array, @count) + @max_actions = @actions_running_time_array.max + + # get percentage done cummulative + @cumm_percent_done = convert_to_cummulative_array(@actions_running_time_array, @actions_running_time.count ) render :layout => false end @@ -162,29 +177,29 @@ class StatsController < ApplicationController "SELECT c.name AS name, c.id as id, count(*) AS total "+ "FROM contexts c, todos t "+ "WHERE t.context_id=c.id "+ + "AND c.user_id = #{current_user.id} " + "GROUP BY c.name, c.id "+ "ORDER BY total DESC" ) - + @sum = @all_actions_per_context.inject(0){|sum, apc| sum += apc['total'].to_i } + pie_cutoff=10 - size = @all_actions_per_context.size() - size = pie_cutoff if size > pie_cutoff - @actions_per_context = Array.new(size) - 0.upto size-1 do |i| - @actions_per_context[i] = @all_actions_per_context[i] - end + size = [@all_actions_per_context.size, pie_cutoff].min + + # explicitely copy contents of hash to avoid ending up with two arrays pointing to same hashes + @actions_per_context = Array.new(size){|i| { + 'name' => @all_actions_per_context[i][:name], + 'total' => @all_actions_per_context[i][:total].to_i, + 'id' => @all_actions_per_context[i][:id] + } } if size==pie_cutoff @actions_per_context[size-1]['name']=t('stats.other_actions_label') - @actions_per_context[size-1]['total']=0 + @actions_per_context[size-1]['total']=@actions_per_context[size-1]['total'] @actions_per_context[size-1]['id']=-1 - (size-1).upto @all_actions_per_context.size()-1 do |i| - @actions_per_context[size-1]['total']+=@all_actions_per_context[i]['total'].to_i - end + size.upto(@all_actions_per_context.size-1){ |i| @actions_per_context[size-1]['total']+=(@all_actions_per_context[i]['total'].to_i) } end - - @sum = @all_actions_per_context.inject(0){|sum, apc| sum += apc['total'].to_i } - + @truncate_chars = 15 render :layout => false @@ -230,12 +245,12 @@ class StatsController < ApplicationController @actions_creation_day = current_user.todos.find(:all, { :select => "created_at" }) @actions_completion_day = current_user.todos.completed.find(:all, { :select => "completed_at" }) - # convert to hash to be able to fill in non-existing days + # convert to array and fill in non-existing days @actions_creation_day_array = Array.new(7) { |i| 0} @actions_creation_day.each { |t| @actions_creation_day_array[ t.created_at.wday ] += 1 } @max = @actions_creation_day_array.max - # convert to hash to be able to fill in non-existing days + # convert to array and fill in non-existing days @actions_completion_day_array = Array.new(7) { |i| 0} @actions_completion_day.each { |t| @actions_completion_day_array[ t.completed_at.wday ] += 1 } @max = @actions_completion_day_array.max @@ -652,7 +667,26 @@ class StatsController < ApplicationController return hash end + # returns a new array containing all elems of array up to cut_off and + # adds the sum of the rest of array to the last elem + def cut_off_array(array, cut_off) + # +1 to hold sum of rest + a = Array.new(cut_off+1){|i| array[i]||0} + # add rest of array to last elem + a[cut_off] += array.inject(:+) - a.inject(:+) + return a + end + + def convert_to_cummulative_array(array, max) + # calculate fractions + a = Array.new(array.size){|i| array[i]*100.0/max} + # make cummulative + 1.upto(array.size-1){ |i| a[i] += a[i-1] } + return a + end + # assumes date1 > date2 + # this results in the number of months before the month of date1, not taking days into account, so diff of 31-12 and 1-1 is 1 month! def difference_in_months(date1, date2) return (date1.year - date2.year)*12 + (date1.month - date2.month) end @@ -662,12 +696,13 @@ class StatsController < ApplicationController return ((date1.at_midnight-date2.at_midnight)/@seconds_per_day).to_i end + # assumes date1 > date2 def difference_in_weeks(date1, date2) return difference_in_days(date1, date2) / 7 end def three_month_avg(set, i) - return ( (set[i]||0) + (set[i+1]||0) + (set[i+2]||0) )/3.0 + return ( (set[i]||0) + (set[i+1]||0) + (set[i+2]||0) ) / 3.0 end def interpolate_avg(set, percent) @@ -678,25 +713,6 @@ class StatsController < ApplicationController month_data[count] = month_data[count] * 3 month_data[count-1] = month_data[count-1] * 3 / 2 if count > 1 end - - def find_max_in_hash(hash, upper_bound) - max = hash[0] - 1.upto(upper_bound){ |i| max = [hash[i], max].max } - return max - end - - def find_running_avg(done_hash, created_hash, upper_bound) - avg_done, avg_created = Hash.new("null"), Hash.new("null") - - # find running avg for month i by calculating avg of month i and the two - # after them. Ignore current month [0] because you do not have full data for it - 1.upto(upper_bound) do |i| - avg_done[i] = three_month_avg(done_hash, i) - avg_created[i] = three_month_avg(created_hash, i) - end - - return avg_done, avg_created - end def find_running_avg_array(done_array, created_array, upper_bound) avg_done = Array.new(upper_bound){ |i| three_month_avg(done_array,i) } @@ -706,5 +722,4 @@ class StatsController < ApplicationController return avg_done, avg_created end - end \ No newline at end of file diff --git a/app/views/stats/actions_completion_time_data.html.erb b/app/views/stats/actions_completion_time_data.html.erb index 3bcf0a35..b38a464a 100755 --- a/app/views/stats/actions_completion_time_data.html.erb +++ b/app/views/stats/actions_completion_time_data.html.erb @@ -1,37 +1,23 @@ +<%- +time_labels = Array.new(@count){ |i| "#{i}-#{i+1}" } +time_labels[0] = "within 1" +time_labels[@count] = "#{@count}" +-%> &title=<%= t('stats.action_completion_time_title') %>,{font-size:16},& &y_legend=<%= t('stats.legend.actions') %>,10,0x8010A0& &y2_legend=<%= t('stats.legend.percentage') %>,10,0xFF0000& &x_legend=<%= t('stats.legend.running_time') %>,12,0x736AFF& &y_ticks=5,10,5& &filled_bar=50,0x9933CC,0x8010A0& -&values= -<% @count = @max_weeks > @cut_off ? @cut_off : @max_weeks -0.upto @count.to_i-1 do |i| -%> - <%= @actions_completion_time_hash[i] -%>, -<% end -%> -<% -@sum=0 -@count.upto @max_weeks do |i| - @sum += @actions_completion_time_hash[i] -end -%> -<%=@sum%>& +&values=<%= @actions_completion_time_array.join(",")%>& &line_2=2,0xFF0000& -&values_2= -<% total=0 -@count = @max_weeks > @cut_off ? @cut_off : @max_weeks -0.upto @count-1 do |i| - total += @actions_completion_time_hash[i]*100.0/@actions_completion_time.count -%> - <%= total -%>, -<% end -%> -<%= total+@sum*100.0/@actions_completion_time.count%>& -&x_labels=within 1, -<% 1.upto @count-1 do |i| -%> - <%= i %>-<%= i+1 %>, -<% end -%> -> <%= @count %>& +&values_2=<%= @cumm_percent_done.join(",")%>& +&x_labels=<%= time_labels.join(",")%>& &y_min=0& -<% # add one to @max for people who have no actions completed yet. -# OpenFlashChart cannot handle y_max=0 -%> +<% +# add one to @max for people who have no actions completed yet. +# OpenFlashChart cannot handle y_max=0 +-%> &y_max=<%=1+@max_actions+@max_actions/10-%>& &show_y2=true& &y2_lines=2& diff --git a/app/views/stats/actions_done_last30days_data.html.erb b/app/views/stats/actions_done_last30days_data.html.erb index 03bf323c..28e2903c 100755 --- a/app/views/stats/actions_done_last30days_data.html.erb +++ b/app/views/stats/actions_done_last30days_data.html.erb @@ -1,3 +1,8 @@ +<%- +created_count_array = Array.new(30){ |i| @actions_created_last30days.count/30.0 } +done_count_array = Array.new(30){ |i| @actions_done_last30days.count/30.0 } +time_labels = Array.new(30){ |i| (Time.zone.now-i.days).strftime("%a %d-%m") } +-%> &title=<%= t('stats.actions_30days_title') %>,{font-size:16},& &y_legend=<%= t('stats.legend.number_of_actions') %>,12,0x736AFF& &x_legend=<%= t('stats.legend.number_of_days') %>,12,0x736AFF& @@ -6,37 +11,15 @@ &filled_bar_2=50,0x0066CC,0x0066CC,<%= t('stats.labels.completed') %>,9& &line_3=3,0x00FF00, <%= t('stats.labels.avg_created') %>, 9& &line_4=3,0xFF0000, <%= t('stats.labels.avg_completed') %>, 9& -&values= -<% 0.upto 29 do |i| -%> -<%= @actions_created_last30days_hash[i]%>, -<% end -%><%= @actions_created_last30days_hash[30]%>& -&values_2= -<% 0.upto 29 do |i| -%> -<%= @actions_done_last30days_hash[i]%>, -<% end -%><%= @actions_done_last30days_hash[30]%>& -&values_3= -<%0.upto 29 do |i| -%> -<%=@actions_created_last30days.count/30.0-%>, -<%end-%> -<%=@actions_created_last30days.count/30.0-%>& -&values_4= -<%0.upto 29 do |i| -%> -<%=@actions_done_last30days.count/30.0-%>, -<%end-%> -<%=@actions_done_last30days.count/30.0-%>& -&x_labels= -<%0.upto 29 do |i| - seconds = i * 24 * 60 * 60 - delta = Time.now-seconds --%> -<%= delta.strftime("%a %d-%m") -%>, -<% end - seconds = 29*25*60*60 - delta = Time.now-seconds-%> -<%= delta.strftime("%a %d-%m") -%>& +&values=<%= @actions_created_last30days_array.join(",")%>& +&values_2=<%= @actions_done_last30days_array.join(",")%>& +&values_3=<%= created_count_array.join(",")%>& +&values_4=<%= done_count_array.join(",")%>& +&x_labels=<%= time_labels.join(",")%>& &y_min=0& <% # max + 10% for some extra space at the top # add one to @max for people who have no actions completed yet. - # OpenFlashChart cannot handle y_max=0 -%> + # OpenFlashChart cannot handle y_max=0 +-%> &y_max=<%=@max+@max/10+1 -%>& &x_label_style=9,,2,3& \ No newline at end of file diff --git a/app/views/stats/actions_done_lastyears_data.html.erb b/app/views/stats/actions_done_lastyears_data.html.erb index d71c825d..03cfa025 100644 --- a/app/views/stats/actions_done_lastyears_data.html.erb +++ b/app/views/stats/actions_done_lastyears_data.html.erb @@ -1,9 +1,9 @@ <%- -created_count_array = Array.new(@month_count){ |i| @actions_created_last_months.count/@month_count } -done_count_array = Array.new(@month_count){ |i| @actions_done_last_months.count/@month_count } -month_names = Array.new(@month_count){ |i| Date::MONTHNAMES[ (Time.now.mon - i -1 ) % 12 + 1 ]+ " " + (Time.now - i.months).year.to_s} +created_count_array = Array.new(@month_count+1){ |i| @actions_created_last_months.count/@month_count } +done_count_array = Array.new(@month_count+1){ |i| @actions_done_last_months.count/@month_count } +month_names = Array.new(@month_count+1){ |i| Date::MONTHNAMES[ (Time.now.mon - i -1 ) % 12 + 1 ]+ " " + (Time.now - i.months).year.to_s} -%> -&title=<%= t('stats.actions_last_year') %>,{font-size:16},& +&title=<%= t('stats.actions_last_year') %>,{font-size:16},& &y_legend=<%= t('stats.actions_last_year_legend.number_of_actions') %>,12,0x736AFF& &x_legend=<%= t('stats.actions_last_year_legend.months_ago') %>,12,0x736AFF& &y_ticks=5,10,5& diff --git a/app/views/stats/actions_running_time_data.html.erb b/app/views/stats/actions_running_time_data.html.erb index 923a0420..6578a1cf 100755 --- a/app/views/stats/actions_running_time_data.html.erb +++ b/app/views/stats/actions_running_time_data.html.erb @@ -1,39 +1,27 @@ -&title=<%= t('stats.running_time_all') %>,{font-size:16},& -&y_legend=<%= t('stats.running_time_all_legend.actions') %>",10,0x736AFF& +<%- +url_labels = Array.new(@count){ |i| url_for(:controller => 'stats', :action => 'show_selected_actions_from_chart', :index => i, :id=> "art") } +url_labels[@count]=url_for(:controller => 'stats', :action => 'show_selected_actions_from_chart', :index => @count, :id=> "art_end") + +time_labels = Array.new(@count){ |i| "#{i}-#{i+1}" } +time_labels[0] = "< 1" +time_labels[@count] = "#{@count}" +-%> +&title=<%= t('stats.running_time_all') %>,{font-size:16},& +&y_legend=<%= t('stats.running_time_all_legend.actions') %>,10,0x736AFF& &y2_legend=<%= t('stats.running_time_all_legend.percentage') %>,10,0xFF0000& -&x_legend=<%= t('stats.running_time_all_legend.running_time') %>,11,0x736AFF& +&x_legend=<%= t('stats.running_time_all_legend.running_time') %>,11,0x736AFF& &y_ticks=5,10,5& &filled_bar=50,0x9933CC,0x8010A0& -&values= -<% @count = @max_weeks > @cut_off ? @cut_off : @max_weeks - 0.upto @count.to_i-1 do |i| -%> -<%= @actions_running_time_hash[i] -%>, -<% end -%> -<% - @sum=0 - @count.upto(@max_weeks.to_i) {|i| @sum += @actions_running_time_hash[i]} -%> -<%=@sum%>& -&links=<% -0.upto(@count-1) { |i| %><%= url_for :controller => 'stats', :action => 'show_selected_actions_from_chart', :index => i, :id=> "art" %>, <% } -%><%= url_for :controller => 'stats', :action => 'show_selected_actions_from_chart', :index => @count, :id=> "art_end" %>& +&values=<%= @actions_running_time_array.join(",") -%>& +&links=<%= url_labels.join(",") %>& &line_2=2,0xFF0000& -&values_2= -<% total=0 - @count = @max_weeks > @cut_off ? @cut_off : @max_weeks - 0.upto @count.to_i-1 do |i| - total += @actions_running_time_hash[i] -%> - <%= total*100.0/@actions_running_time.count -%>, -<% end -%> -<%= (total+@sum)*100.0/@actions_running_time.count%>& -&x_labels=< 1, -<% 1.upto @count-1 do |i| -%> -<%= i %>-<%= i+1 %>, -<% end -%> -><%=@count-%>& +&values_2=<%= @cumm_percent_done.join(",") %>& +&x_labels=<%= time_labels.join(",") %> & &y_min=0& -<% @max_actions = [@sum,@max_actions].max -%> -<% # add one to @max for people who have no actions completed yet. - # OpenFlashChart cannot handle y_max=0 -%> +<% + # add one to @max for people who have no actions completed yet. + # OpenFlashChart cannot handle y_max=0 +-%> &y_max=<%=1+@max_actions+@max_actions/10-%>& &x_label_style=9,,2,2& &show_y2=true& diff --git a/app/views/stats/actions_visible_running_time_data.html.erb b/app/views/stats/actions_visible_running_time_data.html.erb index 9219e11c..cd913eb4 100755 --- a/app/views/stats/actions_visible_running_time_data.html.erb +++ b/app/views/stats/actions_visible_running_time_data.html.erb @@ -1,37 +1,27 @@ -&title=<%= t('stats.current_running_time_of_incomplete_visible_actions') %>,{font-size:16},& -&y_legend=<%= t('stats.running_time_legend.actions') %>,10,0x736AFF& +<%- +url_labels = Array.new(@count){ |i| url_for(:controller => 'stats', :action => 'show_selected_actions_from_chart', :index => i, :id=> "avrt") } +url_labels[@count]=url_for(:controller => 'stats', :action => 'show_selected_actions_from_chart', :index => @count, :id=> "avrt_end") + +time_labels = Array.new(@count){ |i| "#{i}-#{i+1}" } +time_labels[0] = "< 1" +time_labels[@count] = "#{@count}" +-%> +&title=<%= t('stats.current_running_time_of_incomplete_visible_actions') %>,{font-size:16},& +&y_legend=<%= t('stats.running_time_legend.actions') %>,10,0x736AFF& &y2_legend=<%= t('stats.running_time_legend.percentage') %>,10,0xFF0000& -&x_legend=<%= t('stats.running_time_legend.weeks') %>,11,0x736AFF& +&x_legend=<%= t('stats.running_time_legend.weeks') %>,11,0x736AFF& &y_ticks=5,10,5& &filled_bar=50,0x9933CC,0x8010A0& -&values= -<% @count = @max_weeks > @cut_off ? @cut_off : @max_weeks -0.upto(@count-1) { |i| -%><%= @actions_running_time_hash[i] -%>,<% } %> -<% -@sum=0 -@count.upto(@max_weeks.to_i) { |i| @sum += @actions_running_time_hash[i] } -%> -<%=@sum%>& -&links=<% -0.upto(@count-1) { |i| %><%= url_for :controller => 'stats', :action => 'show_selected_actions_from_chart', :index => i, :id=> "avrt" %>, <% } -%><%= url_for :controller => 'stats', :action => 'show_selected_actions_from_chart', :index => @count, :id=> "avrt_end" %>& +&values=<%= @actions_running_time_array.join(",") -%>& +&links=<%= url_labels.join(",") %>& &line_2=2,0xFF0000& -&values_2= -<% total=0 -@count = @max_weeks > @cut_off ? @cut_off : @max_weeks -0.upto @count-1 do |i| - total += @actions_running_time_hash[i] -%> - <%= total*100.0/@actions_running_time.count -%>, -<% end -%> -<%= (total+@sum)*100.0/@actions_running_time.count%>& -&x_labels=< 1, -<% 1.upto @count-1 do |i| -%> - <%= i %>-<%= i+1 %>, -<% end -%> -><%=@count-%>& +&values_2=<%= @cumm_percent_done.join(",") -%>& +&x_labels=<%= time_labels.join(",")%>& &y_min=0& -<% @max_actions = @sum > @max_actions ? @sum : @max_actions -%> -<% # add one to @max for people who have no actions completed yet. -# OpenFlashChart cannot handle y_max=0 -%> +<% + # add one to @max for people who have no actions completed yet. + # OpenFlashChart cannot handle y_max=0 +-%> &y_max=<%=1+@max_actions+@max_actions/10-%>& &x_label_style=9,,2,2& &show_y2=true& diff --git a/test/functional/stats_controller_test.rb b/test/functional/stats_controller_test.rb index 88ff2e27..035a48f5 100755 --- a/test/functional/stats_controller_test.rb +++ b/test/functional/stats_controller_test.rb @@ -26,17 +26,18 @@ class StatsControllerTest < ActionController::TestCase def test_get_charts login_as(:admin_user) - %w{ actions_done_last30days_data - actions_done_last12months_data - actions_completion_time_data - actions_visible_running_time_data - actions_running_time_data - actions_day_of_week_all_data - actions_day_of_week_30days_data - actions_time_of_day_all_data - actions_time_of_day_30days_data - context_total_actions_data - context_running_actions_data + %w{ + actions_done_last30days_data + actions_done_last12months_data + actions_completion_time_data + actions_visible_running_time_data + actions_running_time_data + actions_day_of_week_all_data + actions_day_of_week_30days_data + actions_time_of_day_all_data + actions_time_of_day_30days_data + context_total_actions_data + context_running_actions_data }.each do |action| get action assert_response :success @@ -113,28 +114,51 @@ class StatsControllerTest < ActionController::TestCase # And they should be totalled in a hash assert_equal 2, assigns['actions_created_last12months_array'][0], "there should be two todos in current month" - assert_equal 1, assigns['actions_created_last12months_array'][1], "there should be one todo in previous month" - assert_equal 1, assigns['actions_created_last12months_array'][2], "there should be one todo in two month ago" + + # these test use relative dates. It will go wrong when the data is [1-8] of the month :-( + # FIXME: make testdata not relative of today to avoid crossing end_of_month + too_early = Time.zone.now.day <= 8 ? 1 : 0 + + assert_equal 1-too_early, assigns['actions_created_last12months_array'][1], "there should be one todo in previous month" + assert_equal 1+too_early, assigns['actions_created_last12months_array'][2], "there should be one todo in two month ago" assert_equal 1, assigns['actions_created_last12months_array'][3], "there should be one todo in three month ago" assert_equal 2, assigns['actions_created_last12months_array'][4], "there should be two todos (1 created & 1 done) in four month ago" - assert_equal 1, assigns['actions_done_last12months_array'][2], "there should be one completed todo in last three months" - assert_equal 1, assigns['actions_done_last12months_array'][4], "there should be one completed todo in last four months" + assert_equal 1, assigns['actions_done_last12months_array'][1], "there should be one completed todo one-two months ago" + assert_equal 1, assigns['actions_done_last12months_array'][2], "there should be one completed todo two-three months ago" + assert_equal 1, assigns['actions_done_last12months_array'][4], "there should be one completed todo four-five months ago" # And they should be averaged over three months - assert_equal 1/3.0, assigns['actions_done_avg_last12months_array'][1], "fourth month should be excluded" + assert_equal 2/3.0, assigns['actions_done_avg_last12months_array'][1], "fourth month should be excluded" assert_equal 2/3.0, assigns['actions_done_avg_last12months_array'][2], "fourth month should be included" - assert_equal 1.0, assigns['actions_created_avg_last12months_array'][1], "one every month" - assert_equal 4/3.0, assigns['actions_created_avg_last12months_array'][2], "two in fourth month" + assert_equal 3/3.0, assigns['actions_created_avg_last12months_array'][1], "one every month" + assert_equal (4+too_early)/3.0, assigns['actions_created_avg_last12months_array'][2], "two in fourth month" # And the current month should be interpolated fraction = Time.zone.now.day.to_f / Time.zone.now.end_of_month.day.to_f assert_equal (2*fraction+2)/3.0, assigns['interpolated_actions_created_this_month'], "two this month and one in the last two months" - assert_equal 1/3.0, assigns['interpolated_actions_done_this_month'], "none this month and one in the last two months" + assert_equal 2/3.0, assigns['interpolated_actions_done_this_month'], "none this month and one two the last two months" # And totals should be calculated - assert_equal 2, assigns['max'], "max of created or completed todos" + assert_equal 2, assigns['max'], "max of created or completed todos in one month" + end + + def test_actions_done_last30days_data + login_as(:admin_user) + @current_user = User.find(users(:admin_user).id) + @current_user.todos.delete_all + + given_todos_for_stats + + # When I get the chart data + get :actions_done_last30days_data + assert_response :success + + # only tests relevant differences with actions_done_last_12months_data + + assert_equal 31, assigns['actions_done_last30days_array'].size, "30 complete days plus 1 for the current day" + assert_equal 2, assigns['max'], "two actions created on one day is max" end def test_actions_done_lastyears_data @@ -151,11 +175,11 @@ class StatsControllerTest < ActionController::TestCase # only tests difference with actions_done_last_12months_data # Then the count of months should be calculated - assert_equal 24, assigns['month_count'] + assert_equal 27, assigns['month_count'], "two years and three months of last todo" # And the last two months are corrected - assert_equal 0.5, assigns['actions_done_avg_last_months_hash'][23] - assert_equal 1.0, assigns['actions_done_avg_last_months_hash'][24] + assert_equal 2/3.0, assigns['actions_done_avg_last_months_array'][23] + assert_equal 2/3.0, assigns['actions_done_avg_last_months_array'][24] end def test_actions_completion_time_data @@ -170,8 +194,11 @@ class StatsControllerTest < ActionController::TestCase assert_response :success # do not test stuff already implicitly tested in other tests - - assert_equal 104, assigns['max_weeks'], "two years is 104 weeks" + assert_equal 104, assigns['max_weeks'], "two years is 104 weeks (for completed_at)" + assert_equal 3, assigns['max_actions'], "3 completed within one week" + assert_equal 11, assigns['actions_completion_time_array'].size, "there should be 10 weeks of data + 1 for the rest" + assert_equal 1, assigns['actions_completion_time_array'][10], "there is one completed todo after the 10 weeks cut_off" + assert_equal 100.0, assigns['cumm_percent_done'][10], "cummulative percentage should add up to 100%" end def test_actions_running_time_data @@ -186,8 +213,11 @@ class StatsControllerTest < ActionController::TestCase assert_response :success # do not test stuff already implicitly tested in other tests - - assert_equal 17, assigns['max_weeks'], "there are action in the first 17 weeks of this year" + assert_equal 17, assigns['max_weeks'], "there are actions in the first 17 weeks of this year" + assert_equal 2, assigns['max_actions'], "2 actions running long together" + assert_equal 18, assigns['actions_running_time_array'].size, "there should be 17 weeks ( < cut_off) of data + 1 for the rest" + assert_equal 1, assigns['actions_running_time_array'][17], "there is one running todos in week 17 and zero after 17 weeks ( < cut off; ) " + assert_equal 100.0, assigns['cumm_percent_done'][17], "cummulative percentage should add up to 100%" end def test_actions_visible_running_time_data @@ -196,22 +226,51 @@ class StatsControllerTest < ActionController::TestCase @current_user.todos.delete_all given_todos_for_stats + # Given todo1 is deferred (i.e. not visible) + @todo_today1.show_from = Time.zone.now + 1.week + @todo_today1.save # When I get the chart data get :actions_visible_running_time_data + assert_response :success + + # do not test stuff already implicitly tested in other tests + assert_equal 17, assigns['max_weeks'], "there are actions in the first 17 weeks of this year" + assert_equal 1, assigns['max_actions'], "1 action running long; 1 is deferred" + assert_equal 1, assigns['actions_running_time_array'][0], "there is one running todos and one deferred todo created in week 1" + assert_equal 18, assigns['actions_running_time_array'].size, "there should be 17 weeks ( < cut_off) of data + 1 for the rest" + assert_equal 1, assigns['actions_running_time_array'][17], "there is one running todos in week 17 and zero after 17 weeks ( < cut off; ) " + assert_equal 100.0, assigns['cumm_percent_done'][17], "cummulative percentage should add up to 100%" + end + + def test_context_total_actions_data login_as(:admin_user) @current_user = User.find(users(:admin_user).id) @current_user.todos.delete_all given_todos_for_stats - + # When I get the chart data - get :actions_running_time_data + get :context_total_actions_data assert_response :success - - # do not test stuff already implicitly tested in other tests - - assert_equal 17, assigns['max_weeks'], "there are action in the first 17 weeks of this year" + + assert_equal 9, assigns['sum'], "Nine todos in 1 context" + assert_equal 1, assigns['actions_per_context'].size + + # Given 10 more todos in 10 different contexts + 1.upto(10) do |i| + context = @current_user.contexts.create!(:name => "context #{i}") + @current_user.todos.create!(:description => "created today with new context #{i}", :context => context) + end + + # When I get the chart data + get :context_total_actions_data + assert_response :success + + assert_equal 19, assigns['sum'], "added 10 todos" + assert_equal 10, assigns['actions_per_context'].size, "pie slices limited to max 10" + assert_equal 2, assigns['actions_per_context'][9]['total'], "pie slices limited to max 10; last pie contains sum of rest" + assert_equal "(others)", assigns['actions_per_context'][9]['name'], "pie slices limited to max 10; last slice contains label for others" end private @@ -221,17 +280,18 @@ class StatsControllerTest < ActionController::TestCase @todo_today1 = @current_user.todos.create!(:description => "created today1", :context => contexts(:office)) @todo_today2 = @current_user.todos.create!(:description => "created today2", :context => contexts(:office)) # And a todo created a month ago - @todo_month1 = create_todo_in_past(1.month+1.day) + @todo_month1 = create_completed_todo_in_past(1.month+1.weeks+1.day, 1.month+1.day) # And a todo created two months ago - @todo_month2 = create_completed_todo_in_past(2.months+1.day, 2.months+2.days) + @todo_month2 = create_completed_todo_in_past(2.months+2.days, 2.months+1.day) # And a todo created three months ago @todo_month3 = create_todo_in_past(3.months+1.day) # And a todo created four months ago @todo_month4 = create_todo_in_past(4.months+1.day) # And a todo created four months ago - @todo_month5 = create_completed_todo_in_past(4.months+1.day, 4.months+2.days) + @todo_month5 = create_completed_todo_in_past(4.months+2.days, 4.months+1.day) # And a todo created over a year ago - @todo_year = create_completed_todo_in_past(2.years+1.day, 2.years+2.day) + @todo_year1 = create_completed_todo_in_past(2.years+2.days, 2.years+1.day) + @todo_year2 = create_completed_todo_in_past(2.years+3.months, 2.years+1.day) end def create_todo_in_past(creation_time_in_past) @@ -250,4 +310,21 @@ class StatsControllerTest < ActionController::TestCase return todo end + # assumes date1 > date2 + def difference_in_days(date1, date2) + return ((date1.at_midnight-date2.at_midnight)/(60*60*24)).to_i + end + + # assumes date1 > date2 + def difference_in_weeks(date1, date2) + return difference_in_days(date1, date2) / 7 + end + + # assumes date1 > date2 + def difference_in_months(date1, date2) + diff = (date1.year - date2.year)*12 + (date1.month - date2.month) + return diff-1 if date1.day - date2.day < 0 # correct for incomplete months + return diff + end + end From 78a2bd7f49f66b40beb8552aa957a8c053a8485e Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Tue, 3 Jan 2012 22:08:50 +0100 Subject: [PATCH 014/134] further refactoring of stats controller and views --- app/controllers/stats_controller.rb | 119 ++++++-------- app/models/todo.rb | 2 +- .../actions_day_of_week_30days_data.html.erb | 25 ++- .../actions_day_of_week_all_data.html.erb | 27 ++-- .../context_running_actions_data.html.erb | 32 ++-- .../stats/context_total_actions_data.html.erb | 32 ++-- .../stats/show_selection_from_chart.html.erb | 17 +- config/locales/en.yml | 6 + test/functional/stats_controller_test.rb | 145 ++++++++++++++++++ 9 files changed, 258 insertions(+), 147 deletions(-) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index 1adffe69..1cc04251 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -214,28 +214,29 @@ class StatsController < ApplicationController "SELECT c.name AS name, c.id as id, count(*) AS total "+ "FROM contexts c, todos t "+ "WHERE t.context_id=c.id AND t.completed_at IS NULL AND NOT c.hide "+ + "AND c.user_id = #{current_user.id} " + "GROUP BY c.name, c.id "+ "ORDER BY total DESC" ) + @sum = @all_actions_per_context.inject(0){|sum, apc| sum += apc['total'].to_i } pie_cutoff=10 - size = @all_actions_per_context.size() - size = pie_cutoff if size > pie_cutoff - @actions_per_context = Array.new(size) - 0.upto size-1 do |i| - @actions_per_context[i] = @all_actions_per_context[i] - end + size = [@all_actions_per_context.size, pie_cutoff].min + + # explicitely copy contents of hash to avoid ending up with two arrays pointing to same hashes + @actions_per_context = Array.new(size){|i| { + 'name' => @all_actions_per_context[i][:name], + 'total' => @all_actions_per_context[i][:total].to_i, + 'id' => @all_actions_per_context[i][:id] + } } if size==pie_cutoff @actions_per_context[size-1]['name']=t('stats.other_actions_label') - @actions_per_context[size-1]['total']=0 + @actions_per_context[size-1]['total']=@actions_per_context[size-1]['total'] @actions_per_context[size-1]['id']=-1 - (size-1).upto @all_actions_per_context.size()-1 do |i| - @actions_per_context[size-1]['total']+=@all_actions_per_context[i]['total'].to_i - end + (size).upto(@all_actions_per_context.size()-1){|i| @actions_per_context[size-1]['total']+=@all_actions_per_context[i]['total'].to_i } end - @sum = @all_actions_per_context.inject(0){|sum, apc| sum += apc['total'].to_i } @truncate_chars = 15 render :layout => false @@ -282,17 +283,11 @@ class StatsController < ApplicationController # convert to hash to be able to fill in non-existing days @actions_creation_hour_array = Array.new(24) { |i| 0} - @actions_creation_hour.each do |r| - hour = r.created_at.hour - @actions_creation_hour_array[hour] += 1 - end + @actions_creation_hour.each{|r| @actions_creation_hour_array[r.created_at.hour] += 1 } # convert to hash to be able to fill in non-existing days @actions_completion_hour_array = Array.new(24) { |i| 0} - @actions_completion_hour.each do |r| - hour = r.completed_at.hour - @actions_completion_hour_array[hour] += 1 - end + @actions_completion_hour.each{|r| @actions_completion_hour_array[r.completed_at.hour] += 1 } @max = [@actions_creation_hour_array.max, @actions_completion_hour_array.max].max @@ -305,17 +300,11 @@ class StatsController < ApplicationController # convert to hash to be able to fill in non-existing days @actions_creation_hour_array = Array.new(24) { |i| 0} - @actions_creation_hour.each do |r| - hour = r.created_at.hour - @actions_creation_hour_array[hour] += 1 - end + @actions_creation_hour.each{|r| @actions_creation_hour_array[r.created_at.hour] += 1 } # convert to hash to be able to fill in non-existing days @actions_completion_hour_array = Array.new(24) { |i| 0} - @actions_completion_hour.each do |r| - hour = r.completed_at.hour - @actions_completion_hour_array[hour] += 1 - end + @actions_completion_hour.each{|r| @actions_completion_hour_array[r.completed_at.hour] += 1 } @max = [@actions_creation_hour_array.max, @max = @actions_completion_hour_array.max].max @@ -350,19 +339,12 @@ class StatsController < ApplicationController end # get all running actions that are visible - @actions_running_time = current_user.todos.find_by_sql([ - "SELECT t.id, t.created_at "+ - "FROM todos t LEFT OUTER JOIN projects p ON t.project_id = p.id LEFT OUTER JOIN contexts c ON t.context_id = c.id "+ - "WHERE t.completed_at IS NULL " + - "AND t.show_from IS NULL " + - "AND NOT (p.state='hidden' OR c.hide=?) " + - "ORDER BY t.created_at ASC", true] - ) + @actions_running_time = current_user.todos.not_completed.not_hidden.not_deferred_or_blocked.find( + :all, :select => "todos.id, todos.created_at", :order => "todos.created_at DESC") - @selected_todo_ids, @count = get_ids_from(@actions_running_time, week_from, week_to, params['id']== 'avrt_end') - @selected_actions = current_user.todos.find(:all, { - :conditions => "id in (" + @selected_todo_ids + ")" - }) + selected_todo_ids = get_ids_from(@actions_running_time, week_from, week_to, params['id']== 'avrt_end') + @selected_actions = selected_todo_ids.size == 0 ? [] : current_user.todos.find(:all, { :conditions => "id in (" + selected_todo_ids.join(",") + ")" }) + @count = @selected_actions.size render :action => "show_selection_from_chart" @@ -383,9 +365,10 @@ class StatsController < ApplicationController # get all running actions @actions_running_time = current_user.todos.not_completed.find(:all, { :select => "id, created_at" }) - @selected_todo_ids, @count = get_ids_from(@actions_running_time, week_from, week_to, params['id']=='art_end') - @selected_actions = current_user.todos.find(:all, { :conditions => "id in (" + @selected_todo_ids + ")" }) - + selected_todo_ids = get_ids_from(@actions_running_time, week_from, week_to, params['id']=='art_end') + @selected_actions = selected_todo_ids.size == 0 ? [] : current_user.todos.find(:all, { :conditions => "id in (" + selected_todo_ids.join(",") + ")" }) + @count = @selected_actions.size + render :action => "show_selection_from_chart" else # render error @@ -412,7 +395,8 @@ class StatsController < ApplicationController "SELECT DISTINCT tags.id as id "+ "FROM tags, taggings, todos "+ "WHERE tags.id = taggings.tag_id " + - "AND taggings.taggable_id = todos.id "]) + "AND taggings.taggable_id = todos.id "+ + "AND todos.user_id = #{current_user.id}"]) tags_ids_s = tag_ids.map(&:id).sort.join(",") return {} if tags_ids_s.blank? # return empty hash for .size to work return Tag.find(:all, :conditions => "id in (" + tags_ids_s + ")") @@ -424,7 +408,8 @@ class StatsController < ApplicationController "SELECT tags.id as id "+ "FROM tags, taggings, todos "+ "WHERE tags.id = taggings.tag_id " + - "AND taggings.taggable_id = todos.id "]).size + "AND taggings.taggable_id = todos.id " + + "AND todos.user_id = #{current_user.id}"]).size end def init @@ -453,23 +438,23 @@ class StatsController < ApplicationController # time to complete @completed_actions = current_user.todos.completed.find(:all, { :select => "completed_at, created_at" }) - actions_sum, actions_max, actions_min = 0,0,-1 + actions_sum, actions_max = 0,0 + actions_min = @completed_actions.first.completed_at - @completed_actions.first.created_at + @completed_actions.each do |r| actions_sum += (r.completed_at - r.created_at) actions_max = [(r.completed_at - r.created_at), actions_max].max - - actions_min = (r.completed_at - r.created_at) if actions_min == -1 actions_min = [(r.completed_at - r.created_at), actions_min].min end sum_actions = @completed_actions.size - sum_actions = 1 if sum_actions==0 + sum_actions = 1 if sum_actions==0 # to prevent dividing by zero @actions_avg_ttc = (actions_sum/sum_actions)/@seconds_per_day @actions_max_ttc = actions_max/@seconds_per_day @actions_min_ttc = actions_min/@seconds_per_day - min_ttc_sec = Time.utc(2000,1,1,0,0)+actions_min + min_ttc_sec = Time.utc(2000,1,1,0,0)+actions_min # convert to a datetime @actions_min_ttc_sec = (min_ttc_sec).strftime("%H:%M:%S") @actions_min_ttc_sec = (actions_min / @seconds_per_day).round.to_s + " days " + @actions_min_ttc_sec if actions_min > @seconds_per_day @@ -491,6 +476,7 @@ class StatsController < ApplicationController "SELECT c.id AS id, c.name AS name, count(*) AS total "+ "FROM contexts c, todos t "+ "WHERE t.context_id=c.id "+ + "AND t.user_id=#{current_user.id} " + "GROUP BY c.id, c.name ORDER BY total DESC " + "LIMIT 5" ) @@ -503,6 +489,7 @@ class StatsController < ApplicationController "SELECT c.id AS id, c.name AS name, count(*) AS total "+ "FROM contexts c, todos t "+ "WHERE t.context_id=c.id AND t.completed_at IS NULL AND NOT c.hide "+ + "AND t.user_id=#{current_user.id} " + "GROUP BY c.id, c.name ORDER BY total DESC " + "LIMIT 5" ) @@ -517,6 +504,7 @@ class StatsController < ApplicationController "SELECT p.id, p.name, count(*) AS count "+ "FROM projects p, todos t "+ "WHERE p.id = t.project_id "+ + "AND t.user_id=#{current_user.id} " + "GROUP BY p.id, p.name "+ "ORDER BY count DESC " + "LIMIT 10" @@ -532,6 +520,7 @@ class StatsController < ApplicationController "FROM todos t, projects p "+ "WHERE t.project_id = p.id AND "+ " (t.created_at > ? OR t.completed_at > ?) "+ + "AND t.user_id=#{current_user.id} " + "GROUP BY p.id, p.name "+ "ORDER BY count DESC " + "LIMIT 10", @cut_off_month, @cut_off_month] @@ -543,7 +532,7 @@ class StatsController < ApplicationController "SELECT id, name, created_at "+ "FROM projects "+ "WHERE state='active' "+ - "AND user_id="+@user.id.to_s+" "+ + "AND user_id=#{current_user.id} "+ "ORDER BY created_at ASC "+ "LIMIT 10" ) @@ -551,8 +540,8 @@ class StatsController < ApplicationController i=0 @projects_and_runtime = Array.new(10, [-1, "n/a", "n/a"]) @projects_and_runtime_sql.each do |r| - days = (@today - r.created_at) / @seconds_per_day - # add one so that a project that you just create returns 1 day + days = difference_in_days(@today, r.created_at) + # add one so that a project that you just created returns 1 day @projects_and_runtime[i]=[r.id, r.name, days.to_i+1] i += 1 end @@ -609,33 +598,21 @@ class StatsController < ApplicationController } @tags_divisor_90days = ((max_90days - @tags_min_90days) / levels) + 1 - end - def get_ids_from (actions_running_time, week_from, week_to, at_end) - count=0 - selected_todo_ids = "" + def get_ids_from (actions, week_from, week_to, at_end) + selected_todo_ids = [] - actions_running_time.each do |r| - days = (@today - r.created_at) / @seconds_per_day - weeks = (days/7).to_i + actions.each do |r| + weeks = difference_in_weeks(@today, r.created_at) if at_end - if weeks >= week_from - selected_todo_ids += r.id.to_s+"," - count+=1 - end + selected_todo_ids << r.id.to_s if weeks >= week_from else - if weeks.between?(week_from, week_to-1) - selected_todo_ids += r.id.to_s+"," - count+=1 - end + selected_todo_ids << r.id.to_s if weeks.between?(week_from, week_to-1) end end - # strip trailing comma - selected_todo_ids = selected_todo_ids[0..selected_todo_ids.length-2] - - return selected_todo_ids, count + return selected_todo_ids end def convert_to_array(hash, upper_bound) diff --git a/app/models/todo.rb b/app/models/todo.rb index 6f6cd1f4..a5bfd8d4 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -26,7 +26,7 @@ class Todo < ActiveRecord::Base named_scope :blocked, :conditions => ['todos.state = ?', 'pending'] named_scope :pending, :conditions => ['todos.state = ?', 'pending'] named_scope :deferred_or_blocked, :conditions => ["(todos.completed_at IS NULL AND NOT(todos.show_from IS NULL)) OR (todos.state = ?)", "pending"] - named_scope :not_deferred_or_blocked, :conditions => ["todos.completed_at IS NULL AND todos.show_from IS NULL AND NOT(todos.state = ?)", "pending"] + named_scope :not_deferred_or_blocked, :conditions => ["(todos.completed_at IS NULL) AND (todos.show_from IS NULL) AND (NOT todos.state = ?)", "pending"] named_scope :hidden, :joins => "INNER JOIN contexts c_hidden ON c_hidden.id = todos.context_id", :conditions => ["todos.state = ? OR (c_hidden.hide = ? AND (todos.state = ? OR todos.state = ? OR todos.state = ?))", diff --git a/app/views/stats/actions_day_of_week_30days_data.html.erb b/app/views/stats/actions_day_of_week_30days_data.html.erb index 5e884466..a61fe6a6 100755 --- a/app/views/stats/actions_day_of_week_30days_data.html.erb +++ b/app/views/stats/actions_day_of_week_30days_data.html.erb @@ -1,23 +1,16 @@ &title=<%= t('stats.actions_dow_30days_title') %>,{font-size:16},& -&y_legend=<%= t('stats.actions_dow_30days_legend.number_of_actions') %>,12,0x736AFF& -&x_legend=<%= t('stats.actions_dow_30days_legend.day_of_week') %>,12,0x736AFF& +&y_legend=<%= t('stats.actions_dow_30days_legend.number_of_actions') %>,10,0x736AFF& +&x_legend=<%= t('stats.actions_dow_30days_legend.day_of_week') %>,10,0x736AFF& &y_ticks=5,10,5& &filled_bar=50,0x9933CC,0x8010A0,<%= t('stats.labels.created') %>,8& &filled_bar_2=50,0x0066CC,0x0066CC,<%= t('stats.labels.completed') %>,8& -&values=<% -0.upto 5 do |i| -%> - <%=@actions_creation_day_array[i] -%>, -<% end -%><%=@actions_creation_day_array[6]%>& -&values_2=<% -0.upto 5 do |i| -%> - <%=@actions_completion_day_array[i] -%>, -<% end -%><%=@actions_completion_day_array[6]%>& -&x_labels= <% -0.upto 5 do |i| -%> - <%=Date::DAYNAMES[i] -%>, -<% end -%><%=Date::DAYNAMES[6]%>& +&values=<%= @actions_creation_day_array.join(",") %>& +&values_2=<%= @actions_completion_day_array.join(",") %>& +&x_labels=<%= Date::DAYNAMES.join(",") %>& &y_min=0& -<% # add one to @max for people who have no actions completed yet. - # OpenFlashChart cannot handle y_max=0 -%> +<% + # add one to @max for people who have no actions completed yet. + # OpenFlashChart cannot handle y_max=0 +-%> &y_max=<%=@max+1 -%>& &x_label_style=9,,2,1& \ No newline at end of file diff --git a/app/views/stats/actions_day_of_week_all_data.html.erb b/app/views/stats/actions_day_of_week_all_data.html.erb index 8accb729..1e8d23da 100755 --- a/app/views/stats/actions_day_of_week_all_data.html.erb +++ b/app/views/stats/actions_day_of_week_all_data.html.erb @@ -1,23 +1,16 @@ &title=<%= t('stats.actions_day_of_week_title') %>,{font-size:16},& -&y_legend=<%= t('stats.actions_day_of_week_legend.number_of_actions') %>,12,0x736AFF& -&x_legend=<%= t('stats.actions_day_of_week_legend.day_of_week') %>,12,0x736AFF& +&y_legend=<%= t('stats.actions_day_of_week_legend.number_of_actions') %>,10,0x736AFF& +&x_legend=<%= t('stats.actions_day_of_week_legend.day_of_week') %>,10,0x736AFF& &y_ticks=5,10,5& -&filled_bar=50,0x9933CC,0x8010A0,<%= t('stats.labels.created')%>,8& +&filled_bar=50,0x9933CC,0x8010A0,<%= t('stats.labels.created') %>,8& &filled_bar_2=50,0x0066CC,0x0066CC,<%= t('stats.labels.completed') %>,8& -&values=<% -0.upto 5 do |i| -%> - <%=@actions_creation_day_array[i] -%>, -<% end -%><%=@actions_creation_day_array[6]%>& -&values_2=<% -0.upto 5 do |i| -%> - <%=@actions_completion_day_array[i] -%>, -<% end -%><%=@actions_completion_day_array[6]%>& -&x_labels= <% -0.upto 5 do |i| -%> - <%=Date::DAYNAMES[i] -%>, -<% end -%><%=Date::DAYNAMES[6]%>& +&values=<%= @actions_creation_day_array.join(",") %>& +&values_2=<%= @actions_completion_day_array.join(",") %>& +&x_labels=<%= Date::DAYNAMES.join(",") %>& &y_min=0& -<% # add one to @max for people who have no actions completed yet. - # OpenFlashChart cannot handle y_max=0 -%> +<% + # add one to @max for people who have no actions completed yet. + # OpenFlashChart cannot handle y_max=0 +-%> &y_max=<%=@max+1 -%>& &x_label_style=9,,2,1& \ No newline at end of file diff --git a/app/views/stats/context_running_actions_data.html.erb b/app/views/stats/context_running_actions_data.html.erb index c856b71c..690a82f4 100755 --- a/app/views/stats/context_running_actions_data.html.erb +++ b/app/views/stats/context_running_actions_data.html.erb @@ -1,21 +1,15 @@ +<% + size = @actions_per_context.size() + pie_slices = Array.new(size){|i| @actions_per_context[i]['total'].to_i*100/@sum } + pie_labels = Array.new(size){|i| truncate(@actions_per_context[i]['name'], :length => @truncate_chars, :omission => '...') } + pie_links = Array.new(size){|i| url_for :controller => "contexts", :action => "show", :id=>@actions_per_context[i]['id']} +-%> &title=<%= t('stats.spread_of_running_actions_for_visible_contexts') %>,{font-size:16}& -&pie=60,#505050,{font-size: 12px; color: #404040;}& -&x_axis_steps=1& &y_ticks=5,10,5& &line=3,#87421F& &y_min=0& &y_max=20& -&values=<% -0.upto @actions_per_context.size()-2 do | i | - %><%=@actions_per_context[i]['total'].to_i*100/@sum%>,<% -end --%><%=@actions_per_context[@actions_per_context.size()-1]['total'].to_i*100/@sum%>& -&pie_labels=<% -0.upto @actions_per_context.size()-2 do | i | - %><%=truncate(@actions_per_context[i]['name'], :length => @truncate_chars, :omission => '...')%>,<% -end --%><%=truncate(@actions_per_context[@actions_per_context.size()-1]['name'], :length => @truncate_chars, :omission => '...') %>& -&links=<% -0.upto @actions_per_context.size()-2 do | i | - %><%=url_for :controller => "contexts", :action => "show", :id=>@actions_per_context[i]['id']%>,<% -end --%><%=url_for :controller => "contexts", :action => "show", :id=>@actions_per_context[@actions_per_context.size()-1]['id']%>& -&colours=#d01f3c,#356aa0,#C79810,#c61fd0,#1fc6d0,#1fd076,#72d01f,#c6d01f,#d0941f,#40941f& -&tool_tip=#x_label#: #val#%25& +&pie=60,#505050,{font-size: 12px; color: #404040;}& +&x_axis_steps=1& &y_ticks=5,10,5& &line=3,#87421F& &y_min=0& &y_max=20& +&values=<%= pie_slices.join(",") %>& +&pie_labels=<%= pie_labels.join(",") %>& +&links=<%= pie_links.join(",") %>& +&colours=#d01f3c,#356aa0,#C79810,#c61fd0,#1fc6d0,#1fd076,#72d01f,#c6d01f,#d0941f,#40941f& +&tool_tip=#x_label#: #val#%25& &x_label_style=9,,2,1& \ No newline at end of file diff --git a/app/views/stats/context_total_actions_data.html.erb b/app/views/stats/context_total_actions_data.html.erb index 4f9c7679..733bb5a7 100755 --- a/app/views/stats/context_total_actions_data.html.erb +++ b/app/views/stats/context_total_actions_data.html.erb @@ -1,21 +1,15 @@ +<% + size = @actions_per_context.size() + pie_slices = Array.new(size){|i| @actions_per_context[i]['total'].to_i*100/@sum } + pie_labels = Array.new(size){|i| truncate(@actions_per_context[i]['name'], :length => @truncate_chars, :omission => '...') } + pie_links = Array.new(size){|i| url_for :controller => "contexts", :action => "show", :id=>@actions_per_context[i]['id']} +-%> &title=<%= t('stats.spread_of_actions_for_all_context') %>,{font-size:16}& -&pie=70,#505050,{font-size: 12px; color: #404040;}& -&x_axis_steps=1& &y_ticks=5,10,5& &line=3,#87421F& &y_min=0& &y_max=20& -&values=<% -0.upto @actions_per_context.size()-2 do | i | - %><%=@actions_per_context[i]['total'].to_i*100/@sum%>,<% -end --%><%=@actions_per_context[@actions_per_context.size()-1]['total'].to_i*100/@sum%>& -&pie_labels=<% -0.upto @actions_per_context.size()-2 do | i | - %><%=truncate(@actions_per_context[i]['name'], :length => @truncate_chars, :omission => '...') %>,<% -end --%><%=truncate(@actions_per_context[@actions_per_context.size()-1]['name'], :length => @truncate_chars, :omission => '...') %>& -&links=<% -0.upto @actions_per_context.size()-2 do | i | - %><%=url_for :controller => "contexts", :action => "show", :id=>@actions_per_context[i]['id']%>,<% -end --%><%=url_for :controller => "contexts", :action => "show", :id=>@actions_per_context[@actions_per_context.size()-1]['id']%>& -&colours=#d01f3c,#356aa0,#C79810,#c61fd0,#1fc6d0,#1fd076,#72d01f,#c6d01f,#d0941f,#40941f& -&tool_tip=#x_label#: #val#%25& +&pie=70,#505050,{font-size: 12px; color: #404040;}& +&x_axis_steps=1& &y_ticks=5,10,5& &line=3,#87421F& &y_min=0& &y_max=20& +&values=<%= pie_slices.join(",") %>& +&pie_labels=<%= pie_labels.join(",") %>& +&links=<%= pie_links.join(",") %>& +&colours=#d01f3c,#356aa0,#C79810,#c61fd0,#1fc6d0,#1fd076,#72d01f,#c6d01f,#d0941f,#40941f& +&tool_tip=#x_label#: #val#%25& &x_label_style=9,,2,1& \ No newline at end of file diff --git a/app/views/stats/show_selection_from_chart.html.erb b/app/views/stats/show_selection_from_chart.html.erb index 28c13b18..15c3dc67 100644 --- a/app/views/stats/show_selection_from_chart.html.erb +++ b/app/views/stats/show_selection_from_chart.html.erb @@ -1,9 +1,18 @@ <%= render :partial => 'chart', :locals => {:width => @chart_width, :height => @chart_height, :data => url_for(:action => @chart_name)} -%>
    -

    <%= t('stats.click_to_update_actions') %> <%= t('stats.click_to_return', :link => link_to(t('stats.click_to_return_link'), {:controller => "stats", :action => "index"})) %> <% - unless @further -%> <%= - t('stats.click_to_show_actions_from_week', :link => link_to("here", {:controller => "stats", :action => "show_selected_actions_from_chart", :id=>"#{params[:id]}_end", :index => params[:index]}), :week => params[:index]) -%> - <% end %>

    +

    +<%= t('stats.click_to_update_actions') %> <%= t('stats.click_to_return', :link => link_to(t('stats.click_to_return_link'), {:controller => "stats", :action => "index"})) %> +<% + unless @further +-%> +<%= t('stats.click_to_show_actions_from_week', + :link => link_to("here", {:controller => "stats", :action => "show_selected_actions_from_chart", :id=>"#{params[:id]}_end", :index => params[:index]}), + :week => params[:index]) +-%> +<% + end +-%> +


    <%= @page_title -%>

    diff --git a/config/locales/en.yml b/config/locales/en.yml index 2908cc27..71142b67 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -321,6 +321,12 @@ en: click_to_update_actions: Click on a bar in the chart to update the actions below. no_actions_selected: There are no actions selected. actions_actions_avg_created_30days: In the last 30 days you created on average %{count} actions + actions_dow_30days_legend: + number_of_actions: Number of actions + day_of_week: Day of the week + actions_day_of_week_legend: + number_of_actions: Number of actions + day_of_week: Day of the week tod30_legend: number_of_actions: Number of actions time_of_day: Time of day diff --git a/test/functional/stats_controller_test.rb b/test/functional/stats_controller_test.rb index 035a48f5..d7844cb1 100755 --- a/test/functional/stats_controller_test.rb +++ b/test/functional/stats_controller_test.rb @@ -273,6 +273,151 @@ class StatsControllerTest < ActionController::TestCase assert_equal "(others)", assigns['actions_per_context'][9]['name'], "pie slices limited to max 10; last slice contains label for others" end + def test_context_running_actions_data + login_as(:admin_user) + @current_user = User.find(users(:admin_user).id) + @current_user.todos.delete_all + + given_todos_for_stats + + # When I get the chart data + get :context_running_actions_data + assert_response :success + + assert_equal 4, assigns['sum'], "Four running todos in 1 context" + assert_equal 1, assigns['actions_per_context'].size + + # Given 10 more todos in 10 different contexts + 1.upto(10) do |i| + context = @current_user.contexts.create!(:name => "context #{i}") + @current_user.todos.create!(:description => "created today with new context #{i}", :context => context) + end + + # When I get the chart data + get :context_running_actions_data + assert_response :success + + assert_equal 14, assigns['sum'], "added 10 todos" + assert_equal 10, assigns['actions_per_context'].size, "pie slices limited to max 10" + assert_equal 2, assigns['actions_per_context'][9]['total'], "pie slices limited to max 10; last pie contains sum of rest" + assert_equal "(others)", assigns['actions_per_context'][9]['name'], "pie slices limited to max 10; last slice contains label for others" + end + + def test_actions_day_of_week_all_data + login_as(:admin_user) + @current_user = User.find(users(:admin_user).id) + @current_user.todos.delete_all + + given_todos_for_stats + + # When I get the chart data + get :actions_day_of_week_all_data + assert_response :success + + # FIXME: testdata is relative from today, so not stable to test on day_of_week + # trivial not_nil tests + assert_not_nil assigns['max'] + assert_not_nil assigns['actions_creation_day_array'] + assert_not_nil assigns['actions_completion_day_array'] + end + + def test_actions_day_of_week_30days_data + login_as(:admin_user) + @current_user = User.find(users(:admin_user).id) + @current_user.todos.delete_all + + given_todos_for_stats + + # When I get the chart data + get :actions_day_of_week_30days_data + assert_response :success + + # FIXME: testdata is relative from today, so not stable to test on day_of_week + # trivial not_nil tests + assert_not_nil assigns['max'] + assert_not_nil assigns['actions_creation_day_array'] + assert_not_nil assigns['actions_completion_day_array'] + end + + def test_actions_time_of_day_all_data + login_as(:admin_user) + @current_user = User.find(users(:admin_user).id) + @current_user.todos.delete_all + + given_todos_for_stats + + # When I get the chart data + get :actions_time_of_day_all_data + assert_response :success + + # FIXME: testdata is relative from today, so not stable to test on day_of_week + # for now just trivial not_nil tests + assert_not_nil assigns['max'] + assert_not_nil assigns['actions_creation_hour_array'] + assert_not_nil assigns['actions_completion_hour_array'] + end + + def test_show_selected_actions_from_chart_avrt + login_as(:admin_user) + @current_user = User.find(users(:admin_user).id) + @current_user.todos.delete_all + + given_todos_for_stats + + # When I get the chart data + get :show_selected_actions_from_chart, {:id => "avrt", :index => 1} + assert_response :success + + assert_equal false, assigns['further'] # not at end + assert_equal 0, assigns['count'] + end + + def test_show_selected_actions_from_chart_avrt_end + login_as(:admin_user) + @current_user = User.find(users(:admin_user).id) + @current_user.todos.delete_all + + given_todos_for_stats + + # When I get the chart data + get :show_selected_actions_from_chart, {:id => "avrt_end", :index => 1} + assert_response :success + + assert assigns['further'] # at end + assert_equal 2, assigns['count'] + end + + def test_show_selected_actions_from_chart_art + login_as(:admin_user) + @current_user = User.find(users(:admin_user).id) + @current_user.todos.delete_all + + given_todos_for_stats + + # When I get the chart data + get :show_selected_actions_from_chart, {:id => "art", :index => 1} + assert_response :success + + assert_equal false, assigns['further'] # not at end + assert_equal 0, assigns['count'] + end + + def test_show_selected_actions_from_chart_art_end + login_as(:admin_user) + @current_user = User.find(users(:admin_user).id) + @current_user.todos.delete_all + + given_todos_for_stats + + # When I get the chart data + get :show_selected_actions_from_chart, {:id => "art_end", :index => 1} + assert_response :success + + assert assigns['further'] # at end + assert_equal 2, assigns['count'] + end + + private def given_todos_for_stats From 7af2211479f80b58541fcb69936fd5ece4c5398a Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Fri, 20 Jan 2012 23:22:21 +0100 Subject: [PATCH 015/134] finalize refactoring finally done, now for ticket 1030 :-) --- app/controllers/stats_controller.rb | 59 ++++++++++++++--------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index 1cc04251..fc4f1394 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -19,7 +19,7 @@ class StatsController < ApplicationController render :layout => 'standard' end - + def actions_done_last12months_data # get actions created and completed in the past 12+3 months. +3 for running # average @@ -29,10 +29,10 @@ class StatsController < ApplicationController @actions_created_last12monthsPlus3 = current_user.todos.created_after(@cut_off_year_plus3).find(:all, { :select => "created_at"}) # convert to array and fill in non-existing months - @actions_done_last12months_array = convert_to_array(convert_to_hash(@actions_done_last12months, :difference_in_months, :completed_at),13) - @actions_created_last12months_array = convert_to_array(convert_to_hash(@actions_created_last12months, :difference_in_months, :created_at),13) - @actions_done_last12monthsPlus3_array = convert_to_array(convert_to_hash(@actions_done_last12monthsPlus3, :difference_in_months, :completed_at),15) - @actions_created_last12monthsPlus3_array = convert_to_array(convert_to_hash(@actions_created_last12monthsPlus3, :difference_in_months, :created_at),15) + @actions_done_last12months_array = convert_to_months_from_today_array(@actions_done_last12months, 13, :completed_at) + @actions_created_last12months_array = convert_to_months_from_today_array(@actions_created_last12months, 13, :created_at) + @actions_done_last12monthsPlus3_array = convert_to_months_from_today_array(@actions_done_last12monthsPlus3, 13, :completed_at) + @actions_created_last12monthsPlus3_array = convert_to_months_from_today_array(@actions_created_last12monthsPlus3, 15, :created_at) # find max for graph in both arrays @max = [@actions_done_last12months_array.max, @actions_created_last12months_array.max].max @@ -64,8 +64,8 @@ class StatsController < ApplicationController difference_in_months(@today, @actions_done_last_months.last.completed_at)].max # convert to array and fill in non-existing months - @actions_done_last_months_array = convert_to_array(convert_to_hash(@actions_done_last_months, :difference_in_months, :completed_at), @month_count+1) - @actions_created_last_months_array = convert_to_array(convert_to_hash(@actions_created_last_months, :difference_in_months, :created_at), @month_count+1) + @actions_done_last_months_array = convert_to_months_from_today_array(@actions_done_last_months, @month_count+1, :completed_at) + @actions_created_last_months_array = convert_to_months_from_today_array(@actions_created_last_months, @month_count+1, :created_at) # find max for graph in both hashes @max = [@actions_done_last_months_array.max, @actions_created_last_months_array.max].max @@ -92,8 +92,8 @@ class StatsController < ApplicationController @actions_created_last30days = current_user.todos.created_after(@cut_off_month).find(:all, { :select => "created_at" }) # convert to array. 30+1 to have 30 complete days and one current day [0] - @actions_done_last30days_array = convert_to_array(convert_to_hash(@actions_done_last30days, :difference_in_days, :completed_at), 31) - @actions_created_last30days_array = convert_to_array(convert_to_hash(@actions_created_last30days, :difference_in_days, :created_at), 31) + @actions_done_last30days_array = convert_to_days_from_today_array(@actions_done_last30days, 31, :completed_at) + @actions_created_last30days_array = convert_to_days_from_today_array(@actions_created_last30days, 31, :created_at) # find max for graph in both hashes @max = [@actions_done_last30days_array.max, @actions_created_last30days_array.max].max @@ -106,7 +106,7 @@ class StatsController < ApplicationController # convert to array and fill in non-existing weeks with 0 @max_weeks = difference_in_weeks(@today, @actions_completion_time.last.completed_at) - @actions_completed_per_week_array = convert_to_array(convert_to_week_hash(@actions_completion_time), @max_weeks+1) + @actions_completed_per_week_array = convert_to_weeks_running_array(@actions_completion_time, @max_weeks+1) # stop the chart after 10 weeks @count = [10, @max_weeks].min @@ -126,7 +126,7 @@ class StatsController < ApplicationController # convert to array and fill in non-existing weeks with 0 @max_weeks = difference_in_weeks(@today, @actions_running_time.last.created_at) - @actions_running_per_week_array = convert_to_array(convert_to_week_hash_today(@actions_running_time), @max_weeks+1) + @actions_running_per_week_array = convert_to_weeks_from_today_array(@actions_running_time, @max_weeks+1, :created_at) # cut off chart at 52 weeks = one year @count = [52, @max_weeks].min @@ -154,7 +154,7 @@ class StatsController < ApplicationController :all, :select => "todos.created_at", :order => "todos.created_at DESC") @max_weeks = difference_in_weeks(@today, @actions_running_time.last.created_at) - @actions_running_per_week_array = convert_to_array(convert_to_week_hash_today(@actions_running_time), @max_weeks+1) + @actions_running_per_week_array = convert_to_weeks_from_today_array(@actions_running_time, @max_weeks+1, :created_at) # cut off chart at 52 weeks = one year @count = [52, @max_weeks].min @@ -619,31 +619,30 @@ class StatsController < ApplicationController return Array.new(upper_bound){ |i| hash[i] } end - def convert_to_hash(records, difference_method, date_method_on_todo) + # uses the supplied block to determine index in hash + def convert_to_hash(records) # use 0 to initialise action count to zero hash = Hash.new(0) - records.each { |t| hash[self.send(difference_method, @today, t.send(date_method_on_todo))] += 1 } - return hash - end - - def convert_to_week_hash(records) - hash = Hash.new(0) - records.each do |r| - index = difference_in_weeks(r.completed_at, r.created_at) - hash[index] += 1 - end + records.each { |r| hash[ yield r ] += 1 } return hash end - def convert_to_week_hash_today(records) - hash = Hash.new(0) - records.each do |r| - index = difference_in_weeks(@today, r.created_at) - hash[index] += 1 - end - return hash + def convert_to_months_from_today_array(records, array_size, date_method_on_todo) + return convert_to_array(convert_to_hash(records){ |r| difference_in_months(@today, r.send(date_method_on_todo))}, array_size) + end + + def convert_to_days_from_today_array(records, array_size, date_method_on_todo) + return convert_to_array(convert_to_hash(records){ |r| difference_in_days(@today, r.send(date_method_on_todo))}, array_size) end + def convert_to_weeks_from_today_array(records, array_size, date_method_on_todo) + return convert_to_array(convert_to_hash(records) { |r| difference_in_weeks(@today, r.send(date_method_on_todo))}, array_size) + end + + def convert_to_weeks_running_array(records, array_size) + return convert_to_array(convert_to_hash(records) { |r| difference_in_weeks(r.completed_at, r.created_at)}, array_size) + end + # returns a new array containing all elems of array up to cut_off and # adds the sum of the rest of array to the last elem def cut_off_array(array, cut_off) From bc7bf459dba2e77ac929187b1c87fc2998bbbbd6 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Fri, 20 Jan 2012 23:50:27 +0100 Subject: [PATCH 016/134] fix small regressions --- app/controllers/stats_controller.rb | 4 ++-- app/views/stats/actions_completion_time_data.html.erb | 4 ++-- app/views/stats/actions_running_time_data.html.erb | 2 +- app/views/stats/actions_visible_running_time_data.html.erb | 4 ++-- test/functional/stats_controller_test.rb | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index fc4f1394..ff9ecaf2 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -682,7 +682,7 @@ class StatsController < ApplicationController end def interpolate_avg(set, percent) - return (set[0]*percent + set[1] + set[2]) / 3.0 + return (set[0]*(1/percent) + set[1] + set[2]) / 3.0 end def correct_last_two_months(month_data, count) @@ -698,4 +698,4 @@ class StatsController < ApplicationController return avg_done, avg_created end -end \ No newline at end of file +end diff --git a/app/views/stats/actions_completion_time_data.html.erb b/app/views/stats/actions_completion_time_data.html.erb index b38a464a..d1830419 100755 --- a/app/views/stats/actions_completion_time_data.html.erb +++ b/app/views/stats/actions_completion_time_data.html.erb @@ -1,7 +1,7 @@ <%- time_labels = Array.new(@count){ |i| "#{i}-#{i+1}" } time_labels[0] = "within 1" -time_labels[@count] = "#{@count}" +time_labels[@count] = "> #{@count}" -%> &title=<%= t('stats.action_completion_time_title') %>,{font-size:16},& &y_legend=<%= t('stats.legend.actions') %>,10,0x8010A0& @@ -23,4 +23,4 @@ time_labels[@count] = "#{@count}" &y2_lines=2& &y2_min=0& &y2_max=100& -&x_label_style=9,,2,1& \ No newline at end of file +&x_label_style=9,,2,1& diff --git a/app/views/stats/actions_running_time_data.html.erb b/app/views/stats/actions_running_time_data.html.erb index 6578a1cf..37c7612d 100755 --- a/app/views/stats/actions_running_time_data.html.erb +++ b/app/views/stats/actions_running_time_data.html.erb @@ -4,7 +4,7 @@ url_labels[@count]=url_for(:controller => 'stats', :action => 'show_selected_act time_labels = Array.new(@count){ |i| "#{i}-#{i+1}" } time_labels[0] = "< 1" -time_labels[@count] = "#{@count}" +time_labels[@count] = "> #{@count}" -%> &title=<%= t('stats.running_time_all') %>,{font-size:16},& &y_legend=<%= t('stats.running_time_all_legend.actions') %>,10,0x736AFF& diff --git a/app/views/stats/actions_visible_running_time_data.html.erb b/app/views/stats/actions_visible_running_time_data.html.erb index cd913eb4..92ff5d5f 100755 --- a/app/views/stats/actions_visible_running_time_data.html.erb +++ b/app/views/stats/actions_visible_running_time_data.html.erb @@ -4,7 +4,7 @@ url_labels[@count]=url_for(:controller => 'stats', :action => 'show_selected_act time_labels = Array.new(@count){ |i| "#{i}-#{i+1}" } time_labels[0] = "< 1" -time_labels[@count] = "#{@count}" +time_labels[@count] = "> #{@count}" -%> &title=<%= t('stats.current_running_time_of_incomplete_visible_actions') %>,{font-size:16},& &y_legend=<%= t('stats.running_time_legend.actions') %>,10,0x736AFF& @@ -27,4 +27,4 @@ time_labels[@count] = "#{@count}" &show_y2=true& &y2_lines=2& &y2_min=0& -&y2_max=100& \ No newline at end of file +&y2_max=100& diff --git a/test/functional/stats_controller_test.rb b/test/functional/stats_controller_test.rb index d7844cb1..5aad0c4c 100755 --- a/test/functional/stats_controller_test.rb +++ b/test/functional/stats_controller_test.rb @@ -137,7 +137,7 @@ class StatsControllerTest < ActionController::TestCase # And the current month should be interpolated fraction = Time.zone.now.day.to_f / Time.zone.now.end_of_month.day.to_f - assert_equal (2*fraction+2)/3.0, assigns['interpolated_actions_created_this_month'], "two this month and one in the last two months" + assert_equal (2*(1/fraction)+2)/3.0, assigns['interpolated_actions_created_this_month'], "two this month and one in the last two months" assert_equal 2/3.0, assigns['interpolated_actions_done_this_month'], "none this month and one two the last two months" # And totals should be calculated From 1bce9a670d6aa14d447b95841f6e98e73f33d53f Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Sat, 21 Jan 2012 20:20:24 +0100 Subject: [PATCH 017/134] implement #1030. --- app/controllers/stats_controller.rb | 54 +++++++++++++++---- app/views/stats/_actions.rhtml | 19 ++++--- .../stats/actions_open_per_week_data.html.erb | 18 +++++++ config/locales/en.yml | 6 ++- 4 files changed, 79 insertions(+), 18 deletions(-) create mode 100644 app/views/stats/actions_open_per_week_data.html.erb diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index ff9ecaf2..1a2cfba2 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -112,7 +112,7 @@ class StatsController < ApplicationController @count = [10, @max_weeks].min # convert to new array to hold max @cut_off elems + 1 for sum of actions after @cut_off - @actions_completion_time_array = cut_off_array(@actions_completed_per_week_array, @count) + @actions_completion_time_array = cut_off_array_with_sum(@actions_completed_per_week_array, @count) @max_actions = @actions_completion_time_array.max # get percentage done cummulative @@ -132,7 +132,7 @@ class StatsController < ApplicationController @count = [52, @max_weeks].min # convert to new array to hold max @cut_off elems + 1 for sum of actions after @cut_off - @actions_running_time_array = cut_off_array(@actions_running_per_week_array, @count) + @actions_running_time_array = cut_off_array_with_sum(@actions_running_per_week_array, @count) @max_actions = @actions_running_time_array.max # get percentage done cummulative @@ -160,7 +160,7 @@ class StatsController < ApplicationController @count = [52, @max_weeks].min # convert to new array to hold max @cut_off elems + 1 for sum of actions after @cut_off - @actions_running_time_array = cut_off_array(@actions_running_per_week_array, @count) + @actions_running_time_array = cut_off_array_with_sum(@actions_running_per_week_array, @count) @max_actions = @actions_running_time_array.max # get percentage done cummulative @@ -168,6 +168,22 @@ class StatsController < ApplicationController render :layout => false end + + def actions_open_per_week_data + @actions_started = current_user.todos.created_after(@today-53.weeks).find(:all, + :select => "todos.created_at, todos.completed_at",:order => "todos.created_at DESC") + + @max_weeks = difference_in_weeks(@today, @actions_started.last.created_at) + + # cut off chart at 52 weeks = one year + @count = [52, @max_weeks].min + + @actions_open_per_week_array = convert_to_weeks_running_from_today_array(@actions_started, @max_weeks) + @actions_open_per_week_array = cut_off_array(@actions_open_per_week_array, @count) + @max_actions = @actions_open_per_week_array.max + + render :layout => false + end def context_total_actions_data # get total action count per context Went from GROUP BY c.id to c.name for @@ -619,39 +635,57 @@ class StatsController < ApplicationController return Array.new(upper_bound){ |i| hash[i] } end - # uses the supplied block to determine index in hash + # uses the supplied block to determine array of indexes in hash + # the block should return an array of indexes each is added to the hash and summed def convert_to_hash(records) # use 0 to initialise action count to zero hash = Hash.new(0) - records.each { |r| hash[ yield r ] += 1 } + records.each { |r| (yield r).each { |i| hash[i] += 1} } return hash end def convert_to_months_from_today_array(records, array_size, date_method_on_todo) - return convert_to_array(convert_to_hash(records){ |r| difference_in_months(@today, r.send(date_method_on_todo))}, array_size) + return convert_to_array(convert_to_hash(records){ |r| [difference_in_months(@today, r.send(date_method_on_todo))]}, array_size) end def convert_to_days_from_today_array(records, array_size, date_method_on_todo) - return convert_to_array(convert_to_hash(records){ |r| difference_in_days(@today, r.send(date_method_on_todo))}, array_size) + return convert_to_array(convert_to_hash(records){ |r| [difference_in_days(@today, r.send(date_method_on_todo))]}, array_size) end def convert_to_weeks_from_today_array(records, array_size, date_method_on_todo) - return convert_to_array(convert_to_hash(records) { |r| difference_in_weeks(@today, r.send(date_method_on_todo))}, array_size) + return convert_to_array(convert_to_hash(records) { |r| [difference_in_weeks(@today, r.send(date_method_on_todo))]}, array_size) end def convert_to_weeks_running_array(records, array_size) - return convert_to_array(convert_to_hash(records) { |r| difference_in_weeks(r.completed_at, r.created_at)}, array_size) + return convert_to_array(convert_to_hash(records) { |r| [difference_in_weeks(r.completed_at, r.created_at)]}, array_size) + end + + def convert_to_weeks_running_from_today_array(records, array_size) + hash = convert_to_hash(records) { |r| week_indexes_of(r) } + return convert_to_array(hash, array_size) + end + + def week_indexes_of(record) + a = [] + start_week = difference_in_weeks(@today, record.created_at) + end_week = record.completed_at ? difference_in_weeks(@today, record.completed_at) : 0 + end_week.upto(start_week) { |i| a << i }; + return a end # returns a new array containing all elems of array up to cut_off and # adds the sum of the rest of array to the last elem - def cut_off_array(array, cut_off) + def cut_off_array_with_sum(array, cut_off) # +1 to hold sum of rest a = Array.new(cut_off+1){|i| array[i]||0} # add rest of array to last elem a[cut_off] += array.inject(:+) - a.inject(:+) return a end + + def cut_off_array(array, cut_off) + return Array.new(cut_off){|i| array[i]||0} + end def convert_to_cummulative_array(array, max) # calculate fractions diff --git a/app/views/stats/_actions.rhtml b/app/views/stats/_actions.rhtml index 59d4c03c..705ebfcd 100755 --- a/app/views/stats/_actions.rhtml +++ b/app/views/stats/_actions.rhtml @@ -7,7 +7,9 @@ <%= t('stats.actions_avg_created', :count => (@sum_actions_created_last12months*10.0/12.0).round/10.0 )%> <%= t('stats.actions_avg_completed', :count => (@sum_actions_done_last12months*10.0/12.0).round/10.0 )%>

    -<% %w{ actions_done_last30days_data +<% + %w{ + actions_done_last30days_data actions_done_last12months_data actions_completion_time_data }.each do |action| @@ -17,12 +19,15 @@
    -<% %w{ actions_visible_running_time_data - actions_running_time_data - actions_day_of_week_all_data - actions_day_of_week_30days_data - actions_time_of_day_all_data - actions_time_of_day_30days_data +<% +%w{ + actions_visible_running_time_data + actions_running_time_data + actions_open_per_week_data + actions_day_of_week_all_data + actions_day_of_week_30days_data + actions_time_of_day_all_data + actions_time_of_day_30days_data }.each do |action| %><%= render :partial => 'chart', :locals => {:width => @chart_width, :height => @chart_height, :data => url_for(:action => action)} -%><% end diff --git a/app/views/stats/actions_open_per_week_data.html.erb b/app/views/stats/actions_open_per_week_data.html.erb new file mode 100644 index 00000000..e9e93bed --- /dev/null +++ b/app/views/stats/actions_open_per_week_data.html.erb @@ -0,0 +1,18 @@ +<%- +time_labels = Array.new(@count+1){ |i| "#{i}-#{i+1}" } +time_labels[0] = "< 1" +-%> +&title=<%= t('stats.open_per_week') %>,{font-size:16},& +&y_legend=<%= t('stats.open_per_week_legend.actions') %>,10,0x736AFF& +&x_legend=<%= t('stats.open_per_week_legend.weeks') %>,11,0x736AFF& +&y_ticks=5,10,5& +&filled_bar=50,0x9933CC,0x8010A0& +&values=<%= @actions_open_per_week_array.join(",") -%>& +&x_labels=<%= time_labels.join(",")%>& +&y_min=0& +<% + # add one to @max for people who have no actions completed yet. + # OpenFlashChart cannot handle y_max=0 +-%> +&y_max=<%=1+@max_actions+@max_actions/10-%>& +&x_label_style=9,,2,2& \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index 71142b67..09257013 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -255,7 +255,11 @@ en: running_time: Running time of an action (weeks) months_ago: Months ago current_running_time_of_incomplete_visible_actions: Current running time of incomplete visible actions - totals_deferred_actions: of which %{count} are deferred actions in the tickler + open_per_week: Active (visible and hidden) next actions per week + open_per_week_legend: + actions: Actions + weeks: Weeks ago + totals_deferred_actions: "of which %{count} are deferred actions in the tickler" running_time_legend: actions: Actions percentage: Percentage From b7ee2f79f5692fade4b724bfeef449370b1cd17b Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Sat, 21 Jan 2012 20:29:59 +0100 Subject: [PATCH 018/134] Fix #1030. add basic test for new chart. --- test/functional/stats_controller_test.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/functional/stats_controller_test.rb b/test/functional/stats_controller_test.rb index 5aad0c4c..0c965f90 100755 --- a/test/functional/stats_controller_test.rb +++ b/test/functional/stats_controller_test.rb @@ -32,6 +32,7 @@ class StatsControllerTest < ActionController::TestCase actions_completion_time_data actions_visible_running_time_data actions_running_time_data + actions_open_per_week_data actions_day_of_week_all_data actions_day_of_week_30days_data actions_time_of_day_all_data @@ -220,6 +221,23 @@ class StatsControllerTest < ActionController::TestCase assert_equal 100.0, assigns['cumm_percent_done'][17], "cummulative percentage should add up to 100%" end + def test_actions_open_per_week_data + login_as(:admin_user) + @current_user = User.find(users(:admin_user).id) + @current_user.todos.delete_all + + given_todos_for_stats + + # When I get the chart data + get :actions_open_per_week_data + assert_response :success + + # do not test stuff already implicitly tested in other tests + assert_equal 17, assigns['max_weeks'], "there are actions in the first 17 weeks of this year" + assert_equal 4, assigns['max_actions'], "4 actions running together" + assert_equal 17, assigns['actions_open_per_week_array'].size, "there should be 17 weeks ( < cut_off) of data" + end + def test_actions_visible_running_time_data login_as(:admin_user) @current_user = User.find(users(:admin_user).id) From 8b13ee88abc832fd8171127bc279588374f0a160 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Mon, 23 Jan 2012 12:27:49 +0100 Subject: [PATCH 019/134] fix #1234 by checking on :review source view --- app/controllers/projects_controller.rb | 3 ++- app/views/projects/update.js.erb | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 07f42df1..2110ee1d 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -34,6 +34,7 @@ class ProjectsController < ApplicationController end def review + @source_view = params['_source_view'] || 'review' @page_title = t('projects.list_reviews') @projects = current_user.projects.all @contexts = current_user.contexts.all @@ -107,7 +108,7 @@ class ProjectsController < ApplicationController respond_to do |format| format.html format.m &render_project_mobile - format.xml { + format.xml { render :xml => @project.to_xml(:except => :user_id) { |xml| xml.not_done { @not_done.each { |child| child.to_xml(:builder => xml, :skip_instruct => true) } } xml.deferred { @deferred.each { |child| child.to_xml(:builder => xml, :skip_instruct => true) } } diff --git a/app/views/projects/update.js.erb b/app/views/projects/update.js.erb index 270a38b0..a1b52dc7 100644 --- a/app/views/projects/update.js.erb +++ b/app/views/projects/update.js.erb @@ -1,6 +1,6 @@ <% if @saved -%> TracksPages.page_notify('notice', '<%=t('projects.project_saved_status')%>', 5); - <% if source_view_is :project_list -%> + <% if source_view_is_one_of(:project_list, :review) -%> update_project_list_page(); <% else # assume source_view :project -%> @@ -79,7 +79,7 @@ function remove_and_re_add_project() { # render it into the function. -%> function html_for_project_listing() { - return "<%= source_view_is(:project_list) ? escape_javascript(render(:partial => 'project_listing', :object => @project )) : "" %>"; + return "<%= source_view_is_one_of(:project_list, :review) ? escape_javascript(render(:partial => 'project_listing', :object => @project, :locals=>{:suppress_drag_handle => source_view_is(:review)} )) : "" %>"; } function html_for_sidebar() { From e935066c183e1f5156d33edc29cabe5b2ca049a8 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Fri, 27 Jan 2012 10:55:39 +0100 Subject: [PATCH 020/134] fix #1181. The project listing now had the small drag handle and all the controls to the left. --- app/controllers/stats_controller.rb | 2 +- app/helpers/application_helper.rb | 10 +++++----- app/helpers/projects_helper.rb | 2 +- app/views/projects/_project_listing.rhtml | 24 +++++++---------------- public/javascripts/application.js | 2 +- public/stylesheets/standard.css | 6 +++--- 6 files changed, 18 insertions(+), 28 deletions(-) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index 1a2cfba2..967e89bc 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -455,7 +455,7 @@ class StatsController < ApplicationController @completed_actions = current_user.todos.completed.find(:all, { :select => "completed_at, created_at" }) actions_sum, actions_max = 0,0 - actions_min = @completed_actions.first.completed_at - @completed_actions.first.created_at + actions_min = @completed_actions.first ? @completed_actions.first.completed_at - @completed_actions.first.created_at : 0 @completed_actions.each do |r| actions_sum += (r.completed_at - r.created_at) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index fbf0a0cf..21d6d868 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -13,7 +13,7 @@ module ApplicationHelper else tag_options = nil end - url = options.is_a?(String) ? options : self.url_for(options, *parameters_for_method_reference) + url = options.is_a?(String) ? options : self.url_for(options, *parameters_for_method_reference) id_tag = (request.request_uri == url) ? " id=\"current\"" : "" "#{name || url}" @@ -53,7 +53,7 @@ module ApplicationHelper else # overdue or due very soon! sound the alarm! if days == -1 - t('todos.next_actions_due_date.overdue_by', :days => days * -1) + t('todos.next_actions_due_date.overdue_by', :days => days * -1) elsif days < -1 t('todos.next_actions_due_date.overdue_by_plural', :days => days * -1) else @@ -123,7 +123,7 @@ module ApplicationHelper def link_to_edit_project (project, descriptor = sanitize(project.name)) link_to(descriptor, url_for({:controller => 'projects', :action => 'edit', :id => project.id}), - {:id => "link_edit_#{dom_id(project)}", :class => "project_edit_settings"}) + {:id => "link_edit_#{dom_id(project)}", :class => "project_edit_settings icon"}) end def link_to_edit_context (context, descriptor = sanitize(context.name)) @@ -155,7 +155,7 @@ module ApplicationHelper end def render_flash - render :partial => 'shared/flash', :object => flash + render :partial => 'shared/flash', :object => flash end def recurrence_time_span(rt) @@ -287,7 +287,7 @@ module ApplicationHelper done_tag_path(@tag_name) else done_todos_path - end + end else done_todos_path end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 50ea79e9..ddab5ba2 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -51,7 +51,7 @@ module ProjectsHelper project_path(project, :format => 'js'), { :id => "delete_project_#{project.id}", - :class => "delete_project_button", + :class => "delete_project_button icon", :x_confirm_message => t('projects.delete_project_confirmation', :name => project.name), :title => t('projects.delete_project_title') } diff --git a/app/views/projects/_project_listing.rhtml b/app/views/projects/_project_listing.rhtml index 8da4996d..22b1e37c 100644 --- a/app/views/projects/_project_listing.rhtml +++ b/app/views/projects/_project_listing.rhtml @@ -6,27 +6,17 @@ suppress_delete_button ||= false -%>
    " class="list">
    - - <% unless suppress_drag_handle -%> -
    - <%= t('common.drag_handle') %> -
    - <% end -%> - - -
    + <%= suppress_delete_button ? "" : link_to_delete_project(project, image_tag( "blank.png", :title => t('projects.delete_project_title'), :class=>"delete_item")) %> + <%= suppress_edit_button ? "" : link_to_edit_project(project, image_tag( "blank.png", :title => t('projects.edit_project_title'), :class=>"edit_item")) %> + <%= image_tag('grip.png', + :width => '7', :height => '16', :border => '0', + :title => t('common.drag_handle'), :class => 'grip') unless suppress_drag_handle -%> +
    <%= link_to_project( project ) %> <%= " (" + count_undone_todos_and_notes_phrase(project,"actions") + ")" %> - +
    - -
    - <%= project.aasm_current_state.to_s.upcase %> - <%= suppress_delete_button ? "" : link_to_delete_project(project, image_tag( "blank.png", :title => t('projects.delete_project_title'), :class=>"delete_item")) %> - <%= suppress_edit_button ? "" : link_to_edit_project(project, image_tag( "blank.png", :title => t('projects.edit_project_title'), :class=>"edit_item")) %> -
    -
    diff --git a/public/javascripts/application.js b/public/javascripts/application.js index 5c2302f8..700a7a7a 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -806,7 +806,7 @@ var ProjectListPage = { /* make the three lists of project sortable */ $(['active', 'hidden', 'completed']).each(function() { $("#list-"+this+"-projects").sortable({ - handle: '.handle', + handle: '.grip', update: update_order }); }); diff --git a/public/stylesheets/standard.css b/public/stylesheets/standard.css index 337c1370..88693a9f 100644 --- a/public/stylesheets/standard.css +++ b/public/stylesheets/standard.css @@ -426,13 +426,13 @@ input.item-checkbox { vertical-align: middle; } -.rec_description, .description { +.rec_description, .description, .project_description { margin-left: 80px; position:relative; } -.rec_description { - margin-left: 80px; +.project_description { + margin-left: 50px; } .stale_l1 { From d14a2a808dba4877fe7307901d246ba37cbd0143 Mon Sep 17 00:00:00 2001 From: Sebastian Fischmeister Date: Mon, 30 Jan 2012 09:56:58 -0500 Subject: [PATCH 021/134] cucumber tests for the review mode --- features/review.feature | 36 ++++++++++++++++++++++ features/step_definitions/project_steps.rb | 7 +++++ features/step_definitions/review_steps.rb | 9 ++++++ test/unit/project_test.rb | 12 +++++++- 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 features/review.feature create mode 100644 features/step_definitions/review_steps.rb diff --git a/features/review.feature b/features/review.feature new file mode 100644 index 00000000..6ba74cd4 --- /dev/null +++ b/features/review.feature @@ -0,0 +1,36 @@ +Feature: Reviewing projects + In order to keep the todos and projects up to date + As a Tracks user + I want to review my projects + + Background: + Given the following user record + | login | password | is_admin | + | testuser | secret | false | + And I have logged in as "testuser" with password "secret" + + Scenario: I see stalled projects + Given I have no projects + Given I have a project "stalled_project" with 0 todos + When I go to the review page + Then I see the project "stalled_project" in the "stalled" list + + Scenario: I see blocked projects + Given I have no projects + Given I have a project "blocked_project" with 1 deferred todos + When I go to the review page + Then I see the project "blocked_project" in the "blocked" list + + Scenario: I see dated projects + Given I have no projects + Given I have an outdated project "dated_project" with 1 todos + When I go to the review page + Then I see the project "dated_project" in the "review" list + + Scenario: The review list of projects contains all projects + Given I have no projects + Given I have a project "stalled_project" with 0 todos + Given I have a project "blocked_project" with 1 deferred todos + Given I have an outdated project "dated_project" with 1 todos + When I go to the review page + And the badge should show 5 ## note that stalled and blocked projects are also up-to-date listed diff --git a/features/step_definitions/project_steps.rb b/features/step_definitions/project_steps.rb index ffbf3aaa..132f7b92 100644 --- a/features/step_definitions/project_steps.rb +++ b/features/step_definitions/project_steps.rb @@ -1,3 +1,10 @@ +Given /^I have an outdated project "([^"]*)" with (\d+) todos$/ do |project_name, num_todos| + Given "I have a project \"#{project_name}\" with #{num_todos} todos" + @project = @current_user.projects.find_by_name(project_name) + @project.last_reviewed = @current_user.time - @current_user.prefs.review_period.days-1 + @project.save +end + Given /^I have a project "([^\"]*)" with ([0-9]+) todos$/ do |project_name, num_todos| @context = @current_user.contexts.find_or_create_by_name("Context A") @project = @current_user.projects.create!(:name => project_name) diff --git a/features/step_definitions/review_steps.rb b/features/step_definitions/review_steps.rb new file mode 100644 index 00000000..5b9fc699 --- /dev/null +++ b/features/step_definitions/review_steps.rb @@ -0,0 +1,9 @@ +Then /^I see the project "([^"]*)" in the "([^"]*)" list$/ do |name, state| + project = @current_user.projects.find_by_name(name) + project.should_not be_nil + + xpath = "//div[@id='list-#{state}-projects']//div[@id='project_#{project.id}']" + response.should have_xpath(xpath) +end + + diff --git a/test/unit/project_test.rb b/test/unit/project_test.rb index bafa5425..51179b31 100644 --- a/test/unit/project_test.rb +++ b/test/unit/project_test.rb @@ -68,7 +68,17 @@ class ProjectTest < ActiveSupport::TestCase assert_equal :active, @timemachine.aasm_current_state assert @timemachine.active? end - + + def test_review_project + assert_nil @timemachine.last_reviewed + assert @timemachine.needs_review?(nil) + end + + def test_review_completedprojects + @timemachine.complete! + assert !@timemachine.needs_review?(nil) + end + def test_complete_project assert_nil @timemachine.completed_at @timemachine.complete! From 71cd34a35ff6dbda1678153ff8e03c0343af4b8e Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Tue, 31 Jan 2012 12:11:14 +0100 Subject: [PATCH 022/134] fix #1239. Context helper was missing in search controller Conflicts: app/controllers/search_controller.rb --- app/controllers/search_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 44fa0d3f..6bb67311 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -1,7 +1,7 @@ class SearchController < ApplicationController - helper :todos, :application, :notes, :projects - + helper :todos, :application, :notes, :projects, :contexts + def results @source_view = params['_source_view'] || 'search' @page_title = "TRACKS::Search Results for #{params[:search]}" From e7268fbaa2aa0c99a6e6e4706deafa6e5d47fa2a Mon Sep 17 00:00:00 2001 From: Matt Rogers Date: Thu, 2 Feb 2012 22:27:18 -0600 Subject: [PATCH 023/134] Remove the double-quote custom validation Rails has had SQL injection prevention since at least 2009 so we don't need our version of it anymore. Fixes ticket #1237 --- app/models/todo.rb | 1 - test/functional/todos_controller_test.rb | 3 ++- test/unit/todo_test.rb | 7 +++++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/models/todo.rb b/app/models/todo.rb index a5bfd8d4..7d5b71d5 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -129,7 +129,6 @@ class Todo < ActiveRecord::Base if !show_from.blank? && show_from < user.date errors.add("show_from", I18n.t('models.todo.error_date_must_be_future')) end - errors.add(:description, "may not contain \" characters") if /\"/.match(self.description) unless @predecessor_array.nil? # Only validate predecessors if they changed @predecessor_array.each do |todo| errors.add("Depends on:", "Adding '#{h(todo.specification)}' would create a circular dependency") if is_successor?(todo) diff --git a/test/functional/todos_controller_test.rb b/test/functional/todos_controller_test.rb index e100ac1e..147255b7 100644 --- a/test/functional/todos_controller_test.rb +++ b/test/functional/todos_controller_test.rb @@ -220,11 +220,12 @@ class TodosControllerTest < ActionController::TestCase start_count = Todo.count put :create, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"Build a working time machine", "todo"=>{ - :multiple_todos=>"a\nb"} + :multiple_todos=>"a\nb\nmuch \"ado\" about \'nothing\'"} assert_equal start_count+2, Todo.count, "two todos should have been added" end + def test_add_multiple_dependent_todos login_as(:admin_user) diff --git a/test/unit/todo_test.rb b/test/unit/todo_test.rb index eb677699..2414a4a8 100644 --- a/test/unit/todo_test.rb +++ b/test/unit/todo_test.rb @@ -75,6 +75,13 @@ class TodoTest < ActiveSupport::TestCase assert_equal "must be a date in the future", t.errors.on(:show_from) end + def test_validate_description_can_contain_quote + t = @not_completed2 + t[:description] = "much \"ado\" about nothing" + assert t.save + assert_equal 0, t.errors.count + end + def test_defer_an_existing_todo @not_completed2 assert_equal :active, @not_completed2.aasm_current_state From 725ff5e0fad58c664e317fd0a2475f5829959887 Mon Sep 17 00:00:00 2001 From: Sebastian Fischmeister Date: Tue, 14 Feb 2012 10:16:29 -0500 Subject: [PATCH 024/134] don't execute a query when limit == 0 --- app/controllers/projects_controller.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 2110ee1d..2cfe530d 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -94,8 +94,12 @@ class ProjectsController < ApplicationController @not_done = @project.todos.active_or_hidden(:include => Todo::DEFAULT_INCLUDES) @deferred = @project.todos.deferred(:include => Todo::DEFAULT_INCLUDES) @pending = @project.todos.pending(:include => Todo::DEFAULT_INCLUDES) + + @done = {} @done = @project.todos.find_in_state(:all, :completed, - :order => "todos.completed_at DESC", :limit => current_user.prefs.show_number_completed, :include => Todo::DEFAULT_INCLUDES) + :order => "todos.completed_at DESC", + :limit => current_user.prefs.show_number_completed, + :include => Todo::DEFAULT_INCLUDES) if current_user.prefs.show_number_completed > 0 @count = @not_done.size @down_count = @count + @deferred.size + @pending.size From 00ddcbc9fabddc463f8c76afb5a674f570a30de6 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Fri, 3 Feb 2012 16:15:32 +0100 Subject: [PATCH 025/134] upgrade to jquery 1.7.1 and jquery-ui 1.8.17 --- app/views/layouts/login.html.erb | 2 +- app/views/layouts/standard.html.erb | 4 +- public/javascripts/jquery-1.6.2.min.js | 18 - public/javascripts/jquery-1.7.1.min.js | 4 + .../jquery-ui-1.8.15.custom.min.js | 790 ------------------ .../jquery-ui-1.8.17.custom.min.js | 356 ++++++++ .../ui-bg_gloss-wave_45_817865_500x100.png | Bin 4626 -> 3971 bytes .../ui-bg_gloss-wave_90_fff9e5_500x100.png | Bin 2720 -> 2257 bytes .../images/ui-icons_3d3d3d_256x240.png | Bin 4369 -> 5355 bytes .../images/ui-icons_ed9f26_256x240.png | Bin 4369 -> 5355 bytes .../images/ui-icons_fadc7a_256x240.png | Bin 5355 -> 4369 bytes ...custom.css => jquery-ui-1.8.17.custom.css} | 37 +- 12 files changed, 380 insertions(+), 831 deletions(-) delete mode 100644 public/javascripts/jquery-1.6.2.min.js create mode 100644 public/javascripts/jquery-1.7.1.min.js delete mode 100644 public/javascripts/jquery-ui-1.8.15.custom.min.js create mode 100644 public/javascripts/jquery-ui-1.8.17.custom.min.js rename public/stylesheets/{jquery-ui-1.8.15.custom.css => jquery-ui-1.8.17.custom.css} (97%) diff --git a/app/views/layouts/login.html.erb b/app/views/layouts/login.html.erb index 49099e2a..cade0e26 100644 --- a/app/views/layouts/login.html.erb +++ b/app/views/layouts/login.html.erb @@ -3,7 +3,7 @@ <%= stylesheet_link_tag "scaffold" %> - <%= javascript_include_tag 'jquery-1.6.2.min', 'jquery.cookie' %> + <%= javascript_include_tag 'jquery-1.7.1.min', 'jquery.cookie' %> <%= @page_title -%> diff --git a/app/views/layouts/standard.html.erb b/app/views/layouts/standard.html.erb index 611ccdc7..315bf324 100644 --- a/app/views/layouts/standard.html.erb +++ b/app/views/layouts/standard.html.erb @@ -2,9 +2,9 @@ - <%= stylesheet_link_tag 'standard','superfish','niftyCorners', 'jquery-ui-1.8.15.custom', :cache => 'tracks-cached' %> + <%= stylesheet_link_tag 'standard','superfish','niftyCorners', 'jquery-ui-1.8.17.custom', :cache => 'tracks-cached' %> <%= stylesheet_link_tag "print", :media => "print" %> - <%= javascript_include_tag 'jquery-1.6.2.min', 'jquery-ui-1.8.15.custom.min', + <%= javascript_include_tag 'jquery-1.7.1.min', 'jquery-ui-1.8.17.custom.min', 'jquery.truncator','jquery.jeditable.mini', 'jquery.cookie', 'jquery.blockUI', 'jquery.form', :cache => 'jquery-cached' %> diff --git a/public/javascripts/jquery-1.6.2.min.js b/public/javascripts/jquery-1.6.2.min.js deleted file mode 100644 index 8cdc80eb..00000000 --- a/public/javascripts/jquery-1.6.2.min.js +++ /dev/null @@ -1,18 +0,0 @@ -/*! - * jQuery JavaScript Library v1.6.2 - * http://jquery.com/ - * - * Copyright 2011, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Thu Jun 30 14:16:56 2011 -0400 - */ -(function(a,b){function cv(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cs(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cr(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cq(){cn=b}function cp(){setTimeout(cq,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bx(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bm(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(be,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bl(a){f.nodeName(a,"input")?bk(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bk)}function bk(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bj(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bi(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bh(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i=0===c})}function V(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function N(a,b){return(a&&a!=="*"?a+".":"")+b.replace(z,"`").replace(A,"&")}function M(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function K(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function E(){return!0}function D(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z])/ig,x=function(a,b){return b.toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!A){A=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a);return c===b||D.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(b,c,d){a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),d=c.documentElement,(!d||!d.nodeName||d.nodeName==="parsererror")&&e.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
    a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0},m&&f.extend(p,{position:"absolute",left:-1e3,top:-1e3});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
    ",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
    t
    ",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g=f.expando,h=typeof c=="string",i,j=a.nodeType,k=j?f.cache:a,l=j?a[f.expando]:a[f.expando]&&f.expando;if((!l||e&&l&&!k[l][g])&&h&&d===b)return;l||(j?a[f.expando]=l=++f.uuid:l=f.expando),k[l]||(k[l]={},j||(k[l].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?k[l][g]=f.extend(k[l][g],c):k[l]=f.extend(k[l],c);i=k[l],e&&(i[g]||(i[g]={}),i=i[g]),d!==b&&(i[f.camelCase(c)]=d);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[f.camelCase(c)]||i[c]:i}},removeData:function(b,c,d){if(!!f.acceptData(b)){var e=f.expando,g=b.nodeType,h=g?f.cache:b,i=g?b[f.expando]:f.expando;if(!h[i])return;if(c){var j=d?h[i][e]:h[i];if(j){delete j[c];if(!l(j))return}}if(d){delete h[i][e];if(!l(h[i]))return}var k=h[i][e];f.support.deleteExpando||h!=a?delete h[i]:h[i]=null,k?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=k):g&&(f.support.deleteExpando?delete b[f.expando]:b.removeAttribute?b.removeAttribute(f.expando):b[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=w:v&&c!=="className"&&(f.nodeName(a,"form")||u.test(c))&&(i=v)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.support.getSetAttribute?a.removeAttribute(b):(f.attr(a,b,""),a.removeAttributeNode(a.getAttributeNode(b))),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},tabIndex:{get:function(a){var c=a.getAttributeNode("tabIndex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}},value:{get:function(a,b){if(v&&f.nodeName(a,"button"))return v.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(v&&f.nodeName(a,"button"))return v.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==b?g:a[c]},propHooks:{}}),w={get:function(a,c){return f.prop(a,c)?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(f.attrFix=f.propFix,v=f.attrHooks.name=f.attrHooks.title=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,c){var d=a.getAttributeNode(c);if(d){d.nodeValue=b;return b}}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var x=/\.(.*)$/,y=/^(?:textarea|input|select)$/i,z=/\./g,A=/ /g,B=/[^\w\s.|`]/g,C=function(a){return a.replace(B,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=D;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=D);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),C).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i. -shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},J=function(c){var d=c.target,e,g;if(!!y.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=I(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:J,beforedeactivate:J,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&J.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&J.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",I(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in H)f.event.add(this,c+".specialChange",H[c]);return y.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return y.test(this.nodeName)}},H=f.event.special.change.filters,H.focus=H.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

    ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
    ";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=T.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a=="string")return f.inArray(this[0],a?f(a):this.parent().children());return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(V(c[0])||V(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=S.call(arguments);O.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!U[a]?f.unique(e):e,(this.length>1||Q.test(d))&&P.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var X=/ jQuery\d+="(?:\d+|null)"/g,Y=/^\s+/,Z=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,$=/<([\w:]+)/,_=/",""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]};bf.optgroup=bf.option,bf.tbody=bf.tfoot=bf.colgroup=bf.caption=bf.thead,bf.th=bf.td,f.support.htmlSerialize||(bf._default=[1,"div
    ","
    "]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(X,""):null;if(typeof a=="string"&&!bb.test(a)&&(f.support.leadingWhitespace||!Y.test(a))&&!bf[($.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Z,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j -)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bi(a,d),e=bj(a),g=bj(d);for(h=0;e[h];++h)bi(e[h],g[h])}if(b){bh(a,d);if(c){e=bj(a),g=bj(d);for(h=0;e[h];++h)bh(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!ba.test(k))k=b.createTextNode(k);else{k=k.replace(Z,"<$1>");var l=($.exec(k)||["",""])[1].toLowerCase(),m=bf[l]||bf._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=_.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&Y.test(k)&&o.insertBefore(b.createTextNode(Y.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bo.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle;c.zoom=1;var e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.filter=bn.test(g)?g.replace(bn,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bx(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(by=function(a,c){var d,e,g;c=c.replace(bp,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bz=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bq.test(d)&&br.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bx=by||bz,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bB=/%20/g,bC=/\[\]$/,bD=/\r?\n/g,bE=/#.*$/,bF=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bG=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bH=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,bI=/^(?:GET|HEAD)$/,bJ=/^\/\//,bK=/\?/,bL=/)<[^<]*)*<\/script>/gi,bM=/^(?:select|textarea)/i,bN=/\s+/,bO=/([?&])_=[^&]*/,bP=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bQ=f.fn.load,bR={},bS={},bT,bU;try{bT=e.href}catch(bV){bT=c.createElement("a"),bT.href="",bT=bT.href}bU=bP.exec(bT.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bQ)return bQ.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
    ").append(c.replace(bL,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bM.test(this.nodeName)||bG.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bD,"\r\n")}}):{name:b.name,value:c.replace(bD,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?f.extend(!0,a,f.ajaxSettings,b):(b=a,a=f.extend(!0,f.ajaxSettings,b));for(var c in{context:1,url:1})c in b?a[c]=b[c]:c in f.ajaxSettings&&(a[c]=f.ajaxSettings[c]);return a},ajaxSettings:{url:bT,isLocal:bH.test(bU[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML}},ajaxPrefilter:bW(bR),ajaxTransport:bW(bS),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a?4:0;var o,r,u,w=l?bZ(d,v,l):b,x,y;if(a>=200&&a<300||a===304){if(d.ifModified){if(x=v.getResponseHeader("Last-Modified"))f.lastModified[k]=x;if(y=v.getResponseHeader("Etag"))f.etag[k]=y}if(a===304)c="notmodified",o=!0;else try{r=b$(d,w),c="success",o=!0}catch(z){c="parsererror",u=z}}else{u=c;if(!c||a)c="error",a<0&&(a=0)}v.status=a,v.statusText=c,o?h.resolveWith(e,[r,c,v]):h.rejectWith(e,[v,c,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,c]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bF.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bE,"").replace(bJ,bU[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bN),d.crossDomain==null&&(r=bP.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bU[1]&&r[2]==bU[2]&&(r[3]||(r[1]==="http:"?80:443))==(bU[3]||(bU[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bX(bR,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bI.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bK.test(d.url)?"&":"?")+d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bO,"$1_="+x);d.url=y+(y===d.url?(bK.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", */*; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bX(bS,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){status<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bB,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn,co=a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cr("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
    ";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cu.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cu.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cv(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cv(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c];return e.document.compatMode==="CSS1Compat"&&g||e.document.body["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var h=f.css(e,d),i=parseFloat(h);return f.isNaN(i)?h:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/public/javascripts/jquery-1.7.1.min.js b/public/javascripts/jquery-1.7.1.min.js new file mode 100644 index 00000000..198b3ff0 --- /dev/null +++ b/public/javascripts/jquery-1.7.1.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.7.1 jquery.com | jquery.org/license */ +(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"":"")+""),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;g=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
    a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="
    "+""+"
    ",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="
    t
    ",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="
    ",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; +f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&i.push({elem:this,matches:d.slice(e)});for(j=0;j0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

    ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
    ";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
    ","
    "]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() +{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
    ").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file diff --git a/public/javascripts/jquery-ui-1.8.15.custom.min.js b/public/javascripts/jquery-ui-1.8.15.custom.min.js deleted file mode 100644 index 83de870c..00000000 --- a/public/javascripts/jquery-ui-1.8.15.custom.min.js +++ /dev/null @@ -1,790 +0,0 @@ -/*! - * jQuery UI 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI - */ -(function(c,j){function k(a,b){var d=a.nodeName.toLowerCase();if("area"===d){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&l(a)}return(/input|select|textarea|button|object/.test(d)?!a.disabled:"a"==d?a.href||b:b)&&l(a)}function l(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.15", -keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({propAttr:c.fn.prop||c.fn.attr,_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d= -this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this, -"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart": -"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,m,n){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(m)g-=parseFloat(c.curCSS(f,"border"+this+"Width",true))||0;if(n)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight, -outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h,d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){return k(a,!isNaN(c.attr(a,"tabindex")))},tabbable:function(a){var b=c.attr(a, -"tabindex"),d=isNaN(b);return(d||b>=0)&&k(a,!d)}});c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&& -a.element[0].parentNode)for(var e=0;e0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted= -false;a.target==this._mouseDownEvent.target&&b.data(a.target,this.widgetName+".preventClickEvent",true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery); -;/* - * jQuery UI Position 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Position - */ -(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY, -left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+= -k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+(parseInt(c.curCSS(this,"marginRight",true))||0),w=m+q+(parseInt(c.curCSS(this,"marginBottom",true))||0),i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-= -m/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left= -d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+= -a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b), -g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery); -;/* - * jQuery UI Draggable 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Draggables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper== -"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b= -this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;d(b.iframeFix===true?"iframe":b.iframeFix).each(function(){d('
    ').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")});return true},_mouseStart:function(a){var b=this.options;this.helper= -this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}); -this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);d.ui.ddmanager&&d.ui.ddmanager.dragStart(this,a);return true}, -_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b= -false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&this.options.revert.call(this.element,b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration, -10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},_mouseUp:function(a){this.options.iframeFix===true&&d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});d.ui.ddmanager&&d.ui.ddmanager.dragStop(this,a);return d.ui.mouse.prototype._mouseUp.call(this,a)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle|| -!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone().removeAttr("id"):this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&& -a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent= -this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"), -10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"), -10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[a.containment=="document"?0:d(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,a.containment=="document"?0:d(window).scrollTop()-this.offset.relative.top-this.offset.parent.top, -(a.containment=="document"?0:d(window).scrollLeft())+d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a.containment=="document"?0:d(window).scrollTop())+(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&a.containment.constructor!=Array){a=d(a.containment);var b=a[0];if(b){a.offset();var c=d(b).css("overflow")!= -"hidden";this.containment=[(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0),(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0),(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"), -10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=a}}else if(a.containment.constructor==Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+ -this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&& -!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,h=a.pageY;if(this.originalPosition){var g;if(this.containment){if(this.relative_container){g=this.relative_container.offset();g=[this.containment[0]+g.left,this.containment[1]+g.top,this.containment[2]+g.left,this.containment[3]+g.top]}else g=this.containment;if(a.pageX-this.offset.click.leftg[2])e=g[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>g[3])h=g[3]+this.offset.click.top}if(b.grid){h=b.grid[1]?this.originalPageY+Math.round((h-this.originalPageY)/b.grid[1])*b.grid[1]:this.originalPageY;h=g?!(h-this.offset.click.topg[3])?h:!(h-this.offset.click.topg[2])?e:!(e-this.offset.click.left=0;i--){var j=c.snapElements[i].left,l=j+c.snapElements[i].width,k=c.snapElements[i].top,m=k+c.snapElements[i].height;if(j-e=j&&f<=l||h>=j&&h<=l||fl)&&(e>= -i&&e<=k||g>=i&&g<=k||ek);default:return false}};d.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(a,b){var c=d.ui.ddmanager.droppables[a.options.scope]||[],e=b?b.type:null,g=(a.currentItem||a.element).find(":data(droppable)").andSelf(),f=0;a:for(;f
    ').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(), -top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle= -this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!e(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne", -nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var c=this.handles.split(",");this.handles={};for(var d=0;d');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});"se"==f&&g.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[f]=".ui-resizable-"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor== -String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),l=0;l=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,l);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection(); -this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){if(!a.disabled){e(this).removeClass("ui-resizable-autohide");b._handles.show()}},function(){if(!a.disabled)if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy(); -var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a= -false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"}); -this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff= -{width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis]; -if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);this._updateVirtualBoundaries(b.shiftKey);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false}, -_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height;f=f?0:c.sizeDiff.width;f={width:c.helper.width()-f,height:c.helper.height()-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f, -{top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",b);this._helper&&this.helper.remove();return false},_updateVirtualBoundaries:function(b){var a=this.options,c,d,f;a={minWidth:k(a.minWidth)?a.minWidth:0,maxWidth:k(a.maxWidth)?a.maxWidth:Infinity,minHeight:k(a.minHeight)?a.minHeight:0,maxHeight:k(a.maxHeight)?a.maxHeight: -Infinity};if(this._aspectRatio||b){b=a.minHeight*this.aspectRatio;d=a.minWidth/this.aspectRatio;c=a.maxHeight*this.aspectRatio;f=a.maxWidth/this.aspectRatio;if(b>a.minWidth)a.minWidth=b;if(d>a.minHeight)a.minHeight=d;if(cb.width,h=k(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,l=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&l)b.left=i-a.minWidth;if(d&&l)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left= -null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+ -a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+ -c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]); -b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});e.extend(e.ui.resizable,{version:"1.8.15"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(), -10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top- -f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var l=e(this),q=e(this).data("resizable-alsoresize"),p={},r=j&&j.length?j:l.parents(a.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(r,function(n,o){if((n=(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(l.css("position"))){c._revertToRelativePosition=true;l.css({position:"absolute",top:"auto",left:"auto"})}l.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType? -e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})};if(b._revertToRelativePosition){b._revertToRelativePosition=false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a= -e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-g};g=parseInt(a.element.css("left"),10)+(a.position.left-a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing, -step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize",b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement= -e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=e(a),f=[];e(["Top","Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset; -var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options,d=a.containerOffset,f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left: -a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?d.top:0}a.offset.left=a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top- -d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(d+a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition, -f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&/static/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25, -display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable");b.ghost&&b.ghost.css({position:"relative",height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b= -e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height= -d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},k=function(b){return!isNaN(parseInt(b,10))}})(jQuery); -;/* - * jQuery UI Selectable 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Selectables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function(e){e.widget("ui.selectable",e.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var c=this;this.element.addClass("ui-selectable");this.dragged=false;var f;this.refresh=function(){f=e(c.options.filter,c.element[0]);f.each(function(){var d=e(this),b=d.offset();e.data(this,"selectable-item",{element:this,$element:d,left:b.left,top:b.top,right:b.left+d.outerWidth(),bottom:b.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"), -selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=f.addClass("ui-selectee");this._mouseInit();this.helper=e("
    ")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},_mouseStart:function(c){var f=this;this.opos=[c.pageX, -c.pageY];if(!this.options.disabled){var d=this.options;this.selectees=e(d.filter,this.element[0]);this._trigger("start",c);e(d.appendTo).append(this.helper);this.helper.css({left:c.clientX,top:c.clientY,width:0,height:0});d.autoRefresh&&this.refresh();this.selectees.filter(".ui-selected").each(function(){var b=e.data(this,"selectable-item");b.startselected=true;if(!c.metaKey){b.$element.removeClass("ui-selected");b.selected=false;b.$element.addClass("ui-unselecting");b.unselecting=true;f._trigger("unselecting", -c,{unselecting:b.element})}});e(c.target).parents().andSelf().each(function(){var b=e.data(this,"selectable-item");if(b){var g=!c.metaKey||!b.$element.hasClass("ui-selected");b.$element.removeClass(g?"ui-unselecting":"ui-selected").addClass(g?"ui-selecting":"ui-unselecting");b.unselecting=!g;b.selecting=g;(b.selected=g)?f._trigger("selecting",c,{selecting:b.element}):f._trigger("unselecting",c,{unselecting:b.element});return false}})}},_mouseDrag:function(c){var f=this;this.dragged=true;if(!this.options.disabled){var d= -this.options,b=this.opos[0],g=this.opos[1],h=c.pageX,i=c.pageY;if(b>h){var j=h;h=b;b=j}if(g>i){j=i;i=g;g=j}this.helper.css({left:b,top:g,width:h-b,height:i-g});this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!(!a||a.element==f.element[0])){var k=false;if(d.tolerance=="touch")k=!(a.left>h||a.righti||a.bottomb&&a.rightg&&a.bottom *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){var a=this.options;this.containerCache={};this.element.addClass("ui-sortable"); -this.refresh();this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a=== -"disabled"){this.options[a]=b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&& -!b){var f=false;d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top, -left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]}; -this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!= -document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a); -return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0], -e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a,c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset(); -c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp({target:null});this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"): -this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--){this.containers[b]._trigger("deactivate",null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}if(this.placeholder){this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null, -dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):d(this.domPosition.parent).prepend(this.currentItem)}return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});!c.length&&a.key&&c.push(a.key+"=");return c.join("&")}, -toArray:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||"id")||"")});return c},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+jg&&b+la[this.floating?"width":"height"]?j:g0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith(); -if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=d.data(f[g],"sortable");if(h&&h!=this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), -this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});return d(b)},_removeCurrentsFromItems:function(){for(var a=this.currentItem.find(":data(sortable-item)"),b=0;b=0;f--)for(var g=d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h=0;b--){var c=this.items[b];if(!(c.instance!=this.currentContainer&&this.currentContainer&&c.item[0]!=this.currentItem[0])){var e=this.options.toleranceElement?d(this.options.toleranceElement,c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b= -this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top=e.top;this.containers[b].containerCache.width=this.containers[b].element.outerWidth();this.containers[b].containerCache.height=this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f= -d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!e)f.style.visibility="hidden";return f},update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")|| -0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out", -a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===1){this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h- -f)this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g- -this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.topthis.containment[3])?g:!(g-this.offset.click.topthis.containment[2])?f:!(f-this.offset.click.left=0;e--)if(d.ui.contains(this.containers[e].element[0],this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this, -this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out",g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop", -a,this._uiHash());for(e=0;e li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var a=this,b=a.options;a.running=0;a.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"); -a.headers=a.element.find(b.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){b.disabled||c(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){b.disabled||c(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){b.disabled||c(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){b.disabled||c(this).removeClass("ui-state-focus")});a.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom"); -if(b.navigation){var d=a.element.find("a").filter(b.navigationFilter).eq(0);if(d.length){var h=d.closest(".ui-accordion-header");a.active=h.length?h:d.closest(".ui-accordion-content").prev()}}a.active=a._findActive(a.active||b.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");a.active.next().addClass("ui-accordion-content-active");a._createIcons();a.resize();a.element.attr("role","tablist");a.headers.attr("role","tab").bind("keydown.accordion", -function(f){return a._keydown(f)}).next().attr("role","tabpanel");a.headers.not(a.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide();a.active.length?a.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):a.headers.eq(0).attr("tabIndex",0);c.browser.safari||a.headers.find("a").attr("tabIndex",-1);b.event&&a.headers.bind(b.event.split(" ").join(".accordion ")+".accordion",function(f){a._clickHandler.call(a,f,this);f.preventDefault()})},_createIcons:function(){var a= -this.options;if(a.icons){c("").addClass("ui-icon "+a.icons.header).prependTo(this.headers);this.active.children(".ui-icon").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var a=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"); -this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(a.autoHeight||a.fillHeight)b.css("height","");return c.Widget.prototype.destroy.call(this)},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a=="active"&&this.activate(b);if(a=="icons"){this._destroyIcons(); -b&&this._createIcons()}if(a=="disabled")this.headers.add(this.headers.next())[b?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(a){if(!(this.options.disabled||a.altKey||a.ctrlKey)){var b=c.ui.keyCode,d=this.headers.length,h=this.headers.index(a.target),f=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:f=this.headers[(h+1)%d];break;case b.LEFT:case b.UP:f=this.headers[(h-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},a.target); -a.preventDefault()}if(f){c(a.target).attr("tabIndex",-1);c(f).attr("tabIndex",0);f.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css("overflow",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,b-c(this).innerHeight()+ -c(this).height()))}).css("overflow","auto")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height("").height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a==="number"?this.headers.filter(":eq("+a+")"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(":eq(0)")},_clickHandler:function(a,b){var d=this.options; -if(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]===this.active[0];d.active=d.collapsible&&b?false:this.headers.index(a);if(!(this.running||!d.collapsible&&b)){var h=this.active;j=a.next();g=this.active.next();e={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):j,oldContent:g};var f=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(j,g,e,b,f);h.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header); -if(!b){a.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);a.next().addClass("ui-accordion-content-active")}}}else if(d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");var g=this.active.next(), -e={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:g},j=this.active=c([]);this._toggle(j,g,e)}},_toggle:function(a,b,d,h,f){var g=this,e=g.options;g.toShow=a;g.toHide=b;g.data=d;var j=function(){if(g)return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data);g.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&h?{toShow:c([]),toHide:b,complete:j,down:f,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:j,down:f,autoHeight:e.autoHeight|| -e.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;h=c.ui.accordion.animations;var i=e.duration,k=e.animated;if(k&&!h[k]&&!c.easing[k])k="slide";h[k]||(h[k]=function(l){this.slide(l,{easing:k,duration:i||700})});h[k](d)}else{if(e.collapsible&&h)a.toggle();else{b.hide();a.show()}j(true)}b.prev().attr({"aria-expanded":"false", -"aria-selected":"false",tabIndex:-1}).blur();a.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");if(this.toHide.length)this.toHide.parent()[0].className=this.toHide.parent()[0].className;this._trigger("change",null,this.data)}}});c.extend(c.ui.accordion,{version:"1.8.15", -animations:{slide:function(a,b){a=c.extend({easing:"swing",duration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css("overflow"),h=0,f={},g={},e;b=a.toShow;e=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css("paddingLeft"),10)-parseInt(b.css("paddingRight"),10)-(parseInt(b.css("borderLeftWidth"),10)||0)-(parseInt(b.css("borderRightWidth"),10)||0));c.each(["height","paddingTop","paddingBottom"],function(j,i){g[i]="hide";j=(""+c.css(a.toShow[0],i)).match(/^([\d+-.]+)(.*)$/); -f[i]={value:j[1],unit:j[2]||"px"}});a.toShow.css({height:0,overflow:"hidden"}).show();a.toHide.filter(":hidden").each(a.complete).end().filter(":visible").animate(g,{step:function(j,i){if(i.prop=="height")h=i.end-i.start===0?0:(i.now-i.start)/(i.end-i.start);a.toShow[0].style[i.prop]=h*f[i.prop].value+f[i.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css("height","");a.toShow.css({width:e,overflow:d});a.complete()}})}else a.toHide.animate({height:"hide", -paddingTop:"hide",paddingBottom:"hide"},a);else a.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1E3:200})}}})})(jQuery); -;/* - * jQuery UI Autocomplete 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Autocomplete - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.position.js - */ -(function(d){var e=0;d.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:false,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var a=this,b=this.element[0].ownerDocument,g;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!(a.options.disabled||a.element.propAttr("readOnly"))){g= -false;var f=d.ui.keyCode;switch(c.keyCode){case f.PAGE_UP:a._move("previousPage",c);break;case f.PAGE_DOWN:a._move("nextPage",c);break;case f.UP:a._move("previous",c);c.preventDefault();break;case f.DOWN:a._move("next",c);c.preventDefault();break;case f.ENTER:case f.NUMPAD_ENTER:if(a.menu.active){g=true;c.preventDefault()}case f.TAB:if(!a.menu.active)return;a.menu.select(c);break;case f.ESCAPE:a.element.val(a.term);a.close(c);break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){if(a.term!= -a.element.val()){a.selectedItem=null;a.search(null,c)}},a.options.delay);break}}}).bind("keypress.autocomplete",function(c){if(g){g=false;c.preventDefault()}}).bind("focus.autocomplete",function(){if(!a.options.disabled){a.selectedItem=null;a.previous=a.element.val()}}).bind("blur.autocomplete",function(c){if(!a.options.disabled){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)}});this._initSource();this.response=function(){return a._response.apply(a,arguments)}; -this.menu=d("
      ").addClass("ui-autocomplete").appendTo(d(this.options.appendTo||"body",b)[0]).mousedown(function(c){var f=a.menu.element[0];d(c.target).closest(".ui-menu-item").length||setTimeout(function(){d(document).one("mousedown",function(h){h.target!==a.element[0]&&h.target!==f&&!d.ui.contains(f,h.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,f){f=f.item.data("item.autocomplete");false!==a._trigger("focus",c,{item:f})&&/^key/.test(c.originalEvent.type)&& -a.element.val(f.value)},selected:function(c,f){var h=f.item.data("item.autocomplete"),i=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();a.previous=i;setTimeout(function(){a.previous=i;a.selectedItem=h},1)}false!==a._trigger("select",c,{item:h})&&a.element.val(h.value);a.term=a.element.val();a.close(c);a.selectedItem=h},blur:function(){a.menu.element.is(":visible")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu"); -d.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");this.menu.element.remove();d.Widget.prototype.destroy.call(this)},_setOption:function(a,b){d.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource();if(a==="appendTo")this.menu.element.appendTo(d(b||"body",this.element[0].ownerDocument)[0]);a==="disabled"&& -b&&this.xhr&&this.xhr.abort()},_initSource:function(){var a=this,b,g;if(d.isArray(this.options.source)){b=this.options.source;this.source=function(c,f){f(d.ui.autocomplete.filter(b,c.term))}}else if(typeof this.options.source==="string"){g=this.options.source;this.source=function(c,f){a.xhr&&a.xhr.abort();a.xhr=d.ajax({url:g,data:c,dataType:"json",autocompleteRequest:++e,success:function(h){this.autocompleteRequest===e&&f(h)},error:function(){this.autocompleteRequest===e&&f([])}})}}else this.source= -this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length").data("item.autocomplete",b).append(d("").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);else this.search(null,b)},widget:function(){return this.menu.element}});d.extend(d.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, -"\\$&")},filter:function(a,b){var g=new RegExp(d.ui.autocomplete.escapeRegex(b),"i");return d.grep(a,function(c){return g.test(c.label||c.value||c)})}})})(jQuery); -(function(d){d.widget("ui.menu",{_create:function(){var e=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(a){if(d(a.target).closest(".ui-menu-item a").length){a.preventDefault();e.select(a)}});this.refresh()},refresh:function(){var e=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex", --1).mouseenter(function(a){e.activate(a,d(this).parent())}).mouseleave(function(){e.deactivate()})},activate:function(e,a){this.deactivate();if(this.hasScroll()){var b=a.offset().top-this.element.offset().top,g=this.element.scrollTop(),c=this.element.height();if(b<0)this.element.scrollTop(g+b);else b>=c&&this.element.scrollTop(g+b-c+a.height())}this.active=a.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",e,{item:a})},deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id"); -this._trigger("blur");this.active=null}},next:function(e){this.move("next",".ui-menu-item:first",e)},previous:function(e){this.move("prev",".ui-menu-item:last",e)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(e,a,b){if(this.active){e=this.active[e+"All"](".ui-menu-item").eq(0);e.length?this.activate(b,e):this.activate(b,this.element.children(a))}else this.activate(b, -this.element.children(a))},nextPage:function(e){if(this.hasScroll())if(!this.active||this.last())this.activate(e,this.element.children(".ui-menu-item:first"));else{var a=this.active.offset().top,b=this.element.height(),g=this.element.children(".ui-menu-item").filter(function(){var c=d(this).offset().top-a-b+d(this).height();return c<10&&c>-10});g.length||(g=this.element.children(".ui-menu-item:last"));this.activate(e,g)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active|| -this.last()?":first":":last"))},previousPage:function(e){if(this.hasScroll())if(!this.active||this.first())this.activate(e,this.element.children(".ui-menu-item:last"));else{var a=this.active.offset().top,b=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var g=d(this).offset().top-a+b-d(this).height();return g<10&&g>-10});result.length||(result=this.element.children(".ui-menu-item:first"));this.activate(e,result)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active|| -this.first()?":last":":first"))},hasScroll:function(){return this.element.height()").addClass("ui-button-text").html(this.options.label).appendTo(a.empty()).text(),e=this.options.icons,f=e.primary&&e.secondary,d=[];if(e.primary||e.secondary){if(this.options.text)d.push("ui-button-text-icon"+(f?"s":e.primary?"-primary":"-secondary"));e.primary&&a.prepend("");e.secondary&&a.append("");if(!this.options.text){d.push(f?"ui-button-icons-only": -"ui-button-icon-only");this.hasTitle||a.attr("title",c)}}else d.push("ui-button-text-only");a.addClass(d.join(" "))}}});b.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(a,c){a==="disabled"&&this.buttons.button("option",a,c);b.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var a=this.element.css("direction")=== -"ltr";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return b(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(a?"ui-corner-left":"ui-corner-right").end().filter(":last").addClass(a?"ui-corner-right":"ui-corner-left").end().end()},destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return b(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy"); -b.Widget.prototype.destroy.call(this)}})})(jQuery); -;/* - * jQuery UI Dialog 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Dialog - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.button.js - * jquery.ui.draggable.js - * jquery.ui.mouse.js - * jquery.ui.position.js - * jquery.ui.resizable.js - */ -(function(c,l){var m={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},n={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true},o=c.attrFn||{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true,click:true};c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false, -position:{my:"center",at:"center",collision:"fit",using:function(a){var b=c(this).css(a).offset().top;b<0&&c(this).css("top",a.top-b)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||" ",e=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("
      ")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+ -b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var f=(a.uiDialogTitlebar=c("
      ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g), -h=c('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);return false}).appendTo(f);(a.uiDialogTitlebarCloseText=c("")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("").addClass("ui-dialog-title").attr("id", -e).html(d).prependTo(f);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=b.beforeclose;f.find("*").add(f).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"); -a.uiDialog.remove();a.originalTitle&&a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d,e;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!== -b.uiDialog[0]){e=c(this).css("z-index");isNaN(e)||(d=Math.max(d,e))}});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,e=d.options;if(e.modal&&!a||!e.stack&&!e.modal)return d._trigger("focus",b);if(e.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=e.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()};c.ui.dialog.maxZ+=1; -d.uiDialog.css("z-index",c.ui.dialog.maxZ);d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;a._size();a._position(b.position);d.show(b.show);a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(e){if(e.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),f=g.filter(":first");g=g.filter(":last");if(e.target===g[0]&&!e.shiftKey){f.focus(1);return false}else if(e.target=== -f[0]&&e.shiftKey){g.focus(1);return false}}});c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,e=c("
      ").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("
      ").addClass("ui-dialog-buttonset").appendTo(e);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a, -function(){return!(d=true)});if(d){c.each(a,function(f,h){h=c.isFunction(h)?{click:h,text:f}:h;var i=c('').click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.each(h,function(j,k){if(j!=="click")j in o?i[j](k):i.attr(j,k)});c.fn.button&&i.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close", -handle:".ui-dialog-titlebar",containment:"document",start:function(f,h){g=d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",f,a(h))},drag:function(f,h){b._trigger("drag",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);b._trigger("dragStop",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition, -originalSize:f.originalSize,position:f.position,size:f.size}}a=a===l?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",f,b(h))},resize:function(f,h){d._trigger("resize", -f,b(h))},stop:function(f,h){c(this).removeClass("ui-dialog-resizing");e.height=c(this).height();e.width=c(this).width();d._trigger("resizeStop",f,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0],e;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "): -[a[0],a[1]];if(b.length===1)b[1]=b[0];c.each(["left","top"],function(g,f){if(+b[g]===b[g]){d[g]=b[g];b[g]=f}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(e=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(c.extend({of:window},a));e||this.uiDialog.hide()},_setOptions:function(a){var b=this,d={},e=false;c.each(a,function(g,f){b._setOption(g,f); -if(g in m)e=true;if(g in n)d[g]=f});e&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",d)},_setOption:function(a,b){var d=this,e=d.uiDialog;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":e.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?e.addClass("ui-dialog-disabled"): -e.removeClass("ui-dialog-disabled");break;case "draggable":var g=e.is(":data(draggable)");g&&!b&&e.draggable("destroy");!g&&b&&d._makeDraggable();break;case "position":d._position(b);break;case "resizable":(g=e.is(":data(resizable)"))&&!b&&e.resizable("destroy");g&&typeof b==="string"&&e.resizable("option","handles",b);!g&&b!==false&&d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||" "));break}c.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var a= -this.options,b,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();d=Math.max(0,a.minHeight-b);if(a.height==="auto")if(c.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();a=this.element.css("height","auto").height();e||this.uiDialog.hide();this.element.height(Math.max(a,d))}else this.element.height(Math.max(a.height- -b,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.15",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "), -create:function(a){if(this.instances.length===0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(), -height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){var b=c.inArray(a,this.instances);b!=-1&&this.oldInstances.push(this.instances.splice(b,1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var d=0;c.each(this.instances,function(){d=Math.max(d,this.css("z-index"))});this.maxZ=d},height:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight); -b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(b.range==="min"||b.range==="max"?" ui-slider-range-"+b.range:""))}for(var j=c.length;j"); -this.handles=c.add(d(e.join("")).appendTo(a.element));this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(g){g.preventDefault()}).hover(function(){b.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(b.disabled)d(this).blur();else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(g){d(this).data("index.ui-slider-handle", -g)});this.handles.keydown(function(g){var k=true,l=d(this).data("index.ui-slider-handle"),i,h,m;if(!a.options.disabled){switch(g.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:k=false;if(!a._keySliding){a._keySliding=true;d(this).addClass("ui-state-active");i=a._start(g,l);if(i===false)return}break}m=a.options.step;i=a.options.values&&a.options.values.length? -(h=a.values(l)):(h=a.value());switch(g.keyCode){case d.ui.keyCode.HOME:h=a._valueMin();break;case d.ui.keyCode.END:h=a._valueMax();break;case d.ui.keyCode.PAGE_UP:h=a._trimAlignValue(i+(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:h=a._trimAlignValue(i-(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(i===a._valueMax())return;h=a._trimAlignValue(i+m);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(i===a._valueMin())return;h=a._trimAlignValue(i- -m);break}a._slide(g,l,h);return k}}).keyup(function(g){var k=d(this).data("index.ui-slider-handle");if(a._keySliding){a._keySliding=false;a._stop(g,k);a._change(g,k);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy(); -return this},_mouseCapture:function(a){var b=this.options,c,f,e,j,g;if(b.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:a.pageX,y:a.pageY});f=this._valueMax()-this._valueMin()+1;j=this;this.handles.each(function(k){var l=Math.abs(c-j.values(k));if(f>l){f=l;e=d(this);g=k}});if(b.range===true&&this.values(1)===b.min){g+=1;e=d(this.handles[g])}if(this._start(a,g)===false)return false; -this._mouseSliding=true;j._handleIndex=g;e.addClass("ui-state-active").focus();b=e.offset();this._clickOffset=!d(a.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:a.pageX-b.left-e.width()/2,top:a.pageY-b.top-e.height()/2-(parseInt(e.css("borderTopWidth"),10)||0)-(parseInt(e.css("borderBottomWidth"),10)||0)+(parseInt(e.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(a,g,c);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(a){var b= -this._normValueFromMouse({x:a.pageX,y:a.pageY});this._slide(a,this._handleIndex,b);return false},_mouseStop:function(a){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(a,this._handleIndex);this._change(a,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b;if(this.orientation==="horizontal"){b= -this.elementSize.width;a=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{b=this.elementSize.height;a=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}b=a/b;if(b>1)b=1;if(b<0)b=0;if(this.orientation==="vertical")b=1-b;a=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+b*a)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b); -c.values=this.values()}return this._trigger("start",a,c)},_slide:function(a,b,c){var f;if(this.options.values&&this.options.values.length){f=this.values(b?0:1);if(this.options.values.length===2&&this.options.range===true&&(b===0&&c>f||b===1&&c1){this.options.values[a]=this._trimAlignValue(b);this._refreshValue();this._change(null,a)}else if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;f=arguments[0];for(e=0;e=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b;a=a-c;if(Math.abs(c)*2>=b)a+=c>0?b:-b;return parseFloat(a.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var a= -this.options.range,b=this.options,c=this,f=!this._animateOff?b.animate:false,e,j={},g,k,l,i;if(this.options.values&&this.options.values.length)this.handles.each(function(h){e=(c.values(h)-c._valueMin())/(c._valueMax()-c._valueMin())*100;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";d(this).stop(1,1)[f?"animate":"css"](j,b.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(h===0)c.range.stop(1,1)[f?"animate":"css"]({left:e+"%"},b.animate);if(h===1)c.range[f?"animate":"css"]({width:e- -g+"%"},{queue:false,duration:b.animate})}else{if(h===0)c.range.stop(1,1)[f?"animate":"css"]({bottom:e+"%"},b.animate);if(h===1)c.range[f?"animate":"css"]({height:e-g+"%"},{queue:false,duration:b.animate})}g=e});else{k=this.value();l=this._valueMin();i=this._valueMax();e=i!==l?(k-l)/(i-l)*100:0;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";this.handle.stop(1,1)[f?"animate":"css"](j,b.animate);if(a==="min"&&this.orientation==="horizontal")this.range.stop(1,1)[f?"animate":"css"]({width:e+"%"}, -b.animate);if(a==="max"&&this.orientation==="horizontal")this.range[f?"animate":"css"]({width:100-e+"%"},{queue:false,duration:b.animate});if(a==="min"&&this.orientation==="vertical")this.range.stop(1,1)[f?"animate":"css"]({height:e+"%"},b.animate);if(a==="max"&&this.orientation==="vertical")this.range[f?"animate":"css"]({height:100-e+"%"},{queue:false,duration:b.animate})}}});d.extend(d.ui.slider,{version:"1.8.15"})})(jQuery); -;/* - * jQuery UI Tabs 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Tabs - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function(d,p){function u(){return++v}function w(){return++x}var v=0,x=0;d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"
      ",remove:null,select:null,show:null,spinner:"Loading…",tabTemplate:"
    • #{label}
    • "},_create:function(){this._tabify(true)},_setOption:function(b,e){if(b=="selected")this.options.collapsible&& -e==this.options.selected||this.select(e);else{this.options[b]=e;this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+u()},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+w());return d.cookie.apply(null,[b].concat(d.makeArray(arguments)))},_ui:function(b,e){return{tab:b,panel:e,index:this.anchors.index(b)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b= -d(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(b){function e(g,f){g.css("display","");!d.support.opacity&&f.opacity&&g[0].style.removeAttribute("filter")}var a=this,c=this.options,h=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=d(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);this.anchors.each(function(g,f){var i=d(f).attr("href"),l=i.split("#")[0],q;if(l&&(l===location.toString().split("#")[0]|| -(q=d("base")[0])&&l===q.href)){i=f.hash;f.href=i}if(h.test(i))a.panels=a.panels.add(a.element.find(a._sanitizeSelector(i)));else if(i&&i!=="#"){d.data(f,"href.tabs",i);d.data(f,"load.tabs",i.replace(/#.*$/,""));i=a._tabId(f);f.href="#"+i;f=a.element.find("#"+i);if(!f.length){f=d(c.panelTemplate).attr("id",i).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(a.panels[g-1]||a.list);f.data("destroy.tabs",true)}a.panels=a.panels.add(f)}else c.disabled.push(g)});if(b){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"); -this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(c.selected===p){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){c.selected=g;return false}});if(typeof c.selected!=="number"&&c.cookie)c.selected=parseInt(a._cookie(),10);if(typeof c.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)c.selected= -this.lis.index(this.lis.filter(".ui-tabs-selected"));c.selected=c.selected||(this.lis.length?0:-1)}else if(c.selected===null)c.selected=-1;c.selected=c.selected>=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return a.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active"); -if(c.selected>=0&&this.anchors.length){a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");a.element.queue("tabs",function(){a._trigger("show",null,a._ui(a.anchors[c.selected],a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash))[0]))});this.load(c.selected)}d(window).bind("unload",function(){a.lis.add(a.anchors).unbind(".tabs");a.lis=a.anchors=a.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")); -this.element[c.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");c.cookie&&this._cookie(c.selected,c.cookie);b=0;for(var j;j=this.lis[b];b++)d(j)[d.inArray(b,c.disabled)!=-1&&!d(j).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");c.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(c.event!=="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"+ -g)};this.lis.bind("mouseover.tabs",function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal", -function(){e(f,o);a._trigger("show",null,a._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");a._trigger("show",null,a._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||"normal",function(){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);a.element.dequeue("tabs")})}:function(g,f){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");a.element.dequeue("tabs")}; -this.anchors.bind(c.event+".tabs",function(){var g=this,f=d(g).closest("li"),i=a.panels.filter(":not(.ui-tabs-hide)"),l=a.element.find(a._sanitizeSelector(g.hash));if(f.hasClass("ui-tabs-selected")&&!c.collapsible||f.hasClass("ui-state-disabled")||f.hasClass("ui-state-processing")||a.panels.filter(":animated").length||a._trigger("select",null,a._ui(this,l[0]))===false){this.blur();return false}c.selected=a.anchors.index(this);a.abort();if(c.collapsible)if(f.hasClass("ui-tabs-selected")){c.selected= --1;c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){s(g,i)}).dequeue("tabs");this.blur();return false}else if(!i.length){c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this));this.blur();return false}c.cookie&&a._cookie(c.selected,c.cookie);if(l.length){i.length&&a.element.queue("tabs",function(){s(g,i)});a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier."; -d.browser.msie&&this.blur()});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(b){if(typeof b=="string")b=this.anchors.index(this.anchors.filter("[href$="+b+"]"));return b},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e= -d.data(this,"href.tabs");if(e)this.href=e;var a=d(this).unbind(".tabs");d.each(["href","load","cache"],function(c,h){a.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){d.data(this,"destroy.tabs")?d(this).remove():d(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});b.cookie&&this._cookie(null,b.cookie);return this},add:function(b, -e,a){if(a===p)a=this.anchors.length;var c=this,h=this.options;e=d(h.tabTemplate.replace(/#\{href\}/g,b).replace(/#\{label\}/g,e));b=!b.indexOf("#")?b.replace("#",""):this._tabId(d("a",e)[0]);e.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var j=c.element.find("#"+b);j.length||(j=d(h.panelTemplate).attr("id",b).data("destroy.tabs",true));j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(a>=this.lis.length){e.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[a]); -j.insertBefore(this.panels[a])}h.disabled=d.map(h.disabled,function(k){return k>=a?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass("ui-tabs-selected ui-state-active");j.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){c._trigger("show",null,c._ui(c.anchors[0],c.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[a],this.panels[a]));return this},remove:function(b){b=this._getIndex(b);var e=this.options,a=this.lis.eq(b).remove(),c=this.panels.eq(b).remove(); -if(a.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(b+(b+1=b?--h:h});this._tabify();this._trigger("remove",null,this._ui(a.find("a")[0],c[0]));return this},enable:function(b){b=this._getIndex(b);var e=this.options;if(d.inArray(b,e.disabled)!=-1){this.lis.eq(b).removeClass("ui-state-disabled");e.disabled=d.grep(e.disabled,function(a){return a!=b});this._trigger("enable",null, -this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(b){b=this._getIndex(b);var e=this.options;if(b!=e.selected){this.lis.eq(b).addClass("ui-state-disabled");e.disabled.push(b);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[b],this.panels[b]))}return this},select:function(b){b=this._getIndex(b);if(b==-1)if(this.options.collapsible&&this.options.selected!=-1)b=this.options.selected;else return this;this.anchors.eq(b).trigger(this.options.event+".tabs");return this}, -load:function(b){b=this._getIndex(b);var e=this,a=this.options,c=this.anchors.eq(b)[0],h=d.data(c,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(c,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(a.spinner){var j=d("span",c);j.data("label.tabs",j.html()).html(a.spinner)}this.xhr=d.ajax(d.extend({},a.ajaxOptions,{url:h,success:function(k,n){e.element.find(e._sanitizeSelector(c.hash)).html(k);e._cleanup();a.cache&&d.data(c, -"cache.tabs",true);e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.error(k,n,b,c)}catch(m){}}}));e.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this}, -url:function(b,e){this.anchors.eq(b).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.15"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(b,e){var a=this,c=this.options,h=a._rotate||(a._rotate=function(j){clearTimeout(a.rotation);a.rotation=setTimeout(function(){var k=c.selected;a.select(++k'))}function N(a){return a.bind("mouseout", -function(b){b=d(b.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");b.length&&b.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(b){b=d(b.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");if(!(d.datepicker._isDisabledDatepicker(J.inline?a.parent()[0]:J.input[0])||!b.length)){b.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"); -b.addClass("ui-state-hover");b.hasClass("ui-datepicker-prev")&&b.addClass("ui-datepicker-prev-hover");b.hasClass("ui-datepicker-next")&&b.addClass("ui-datepicker-next-hover")}})}function H(a,b){d.extend(a,b);for(var c in b)if(b[c]==null||b[c]==C)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:"1.8.15"}});var B=(new Date).getTime(),J;d.extend(M.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv}, -setDefaults:function(a){H(this._defaults,a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute("date:"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=f}}}e=a.nodeName.toLowerCase();f=e=="div"||e=="span";if(!a.id){this.uuid+=1;a.id="dp"+this.uuid}var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e=="input")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_-])/g, -"\\\\$1"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:N(d('
      '))}},_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker", -function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,"datepicker",b);b.settings.disabled&&this._disableDatepicker(a)}},_attachments:function(a,b){var c=this._get(b,"appendText"),e=this._get(b,"isRTL");b.append&&b.append.remove();if(c){b.append=d(''+c+"");a[e?"before":"after"](b.append)}a.unbind("focus",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,"showOn");if(c== -"focus"||c=="both")a.focus(this._showDatepicker);if(c=="button"||c=="both"){c=this._get(b,"buttonText");var f=this._get(b,"buttonImage");b.trigger=d(this._get(b,"buttonImageOnly")?d("").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('').addClass(this._triggerClass).html(f==""?c:d("").attr({src:f,alt:c,title:c})));a[e?"before":"after"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker(): -d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;gh){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort")));b.setDate(e(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a, -b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});d.data(a,"datepicker",b);this._setDate(b,this._getDefaultDate(b),true);this._updateDatepicker(b);this._updateAlternate(b);b.settings.disabled&&this._disableDatepicker(a);b.dpDiv.css("display","block")}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){this.uuid+= -1;this._dialogInput=d('');this._dialogInput.keydown(this._doKeyDown);d("body").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],"datepicker",a)}H(a.settings,e||{});b=b&&b.constructor==Date?this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/ -2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var b= -d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,"datepicker");if(e=="input"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)}else if(e=="div"||e=="span")b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e= -a.nodeName.toLowerCase();if(e=="input"){a.disabled=false;c.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(e=="div"||e=="span"){b=b.children("."+this._inlineClass);b.children().removeClass("ui-state-disabled");b.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=d(a),c=d.data(a, -"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=true;c.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(e=="div"||e=="span"){b=b.children("."+this._inlineClass);b.children().addClass("ui-state-disabled");b.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=d.map(this._disabledInputs,function(f){return f== -a?null:f});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;for(var b=0;b-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a);d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true},_showDatepicker:function(a){a=a.target||a;if(a.nodeName.toLowerCase()!="input")a=d("input", -a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);if(d.datepicker._curInst&&d.datepicker._curInst!=b){d.datepicker._datepickerShowing&&d.datepicker._triggerOnClose(d.datepicker._curInst);d.datepicker._curInst.dpDiv.stop(true,true)}var c=d.datepicker._get(b,"beforeShow");H(b.settings,c?c.apply(a,[a,b]):{});b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value="";if(!d.datepicker._pos){d.datepicker._pos= -d.datepicker._findPos(a);d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css("position")=="fixed";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c={left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.empty();b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});d.datepicker._updateDatepicker(b);c=d.datepicker._checkOffset(b, -c,e);b.dpDiv.css({position:d.datepicker._inDialog&&d.blockUI?"static":e?"fixed":"absolute",display:"none",left:c.left+"px",top:c.top+"px"});if(!b.inline){c=d.datepicker._get(b,"showAnim");var f=d.datepicker._get(b,"duration"),h=function(){var i=b.dpDiv.find("iframe.ui-datepicker-cover");if(i.length){var g=d.datepicker._getBorders(b.dpDiv);i.css({left:-g[0],top:-g[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex(d(a).zIndex()+1);d.datepicker._datepickerShowing=true;d.effects&& -d.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,"showOptions"),f,h):b.dpDiv[c||"show"](c?f:null,h);if(!c||!f)h();b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus();d.datepicker._curInst=b}}},_updateDatepicker:function(a){this.maxRows=4;var b=d.datepicker._getBorders(a.dpDiv);J=a;a.dpDiv.empty().append(this._generateHTML(a));var c=a.dpDiv.find("iframe.ui-datepicker-cover");c.length&&c.css({left:-b[0],top:-b[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()});a.dpDiv.find("."+ -this._dayOverClass+" a").mouseover();b=this._getNumberOfMonths(a);c=b[1];a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");c>1&&a.dpDiv.addClass("ui-datepicker-multi-"+c).css("width",17*c+"em");a.dpDiv[(b[0]!=1||b[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&& -a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var e=a.yearshtml;setTimeout(function(){e===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml);e=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]||c};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(),h=a.input?a.input.outerWidth(): -0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),j=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,"isRTL")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e-g):0);b.top-=Math.min(b.top,b.top+f>j&&j>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b=this._get(this._getInst(a), -"isRTL");a&&(a.type=="hidden"||a.nodeType!=1||d.expr.filters.hidden(a));)a=a[b?"previousSibling":"nextSibling"];a=d(a).offset();return[a.left,a.top]},_triggerOnClose:function(a){var b=this._get(a,"onClose");if(b)b.apply(a.input?a.input[0]:null,[a.input?a.input.val():"",a])},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=d.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(b,"showAnim");var c=this._get(b,"duration"),e=function(){d.datepicker._tidyDialog(b);this._curInst= -null};d.effects&&d.effects[a]?b.dpDiv.hide(a,d.datepicker._get(b,"showOptions"),c,e):b.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?"fadeOut":"hide"](a?c:null,e);a||e();d.datepicker._triggerOnClose(b);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(d.blockUI){d.unblockUI();d("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")}, -_checkExternalClick:function(a){if(d.datepicker._curInst){a=d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents("#"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&&d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"): -0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=d(a);var b=this._getInst(a[0]);if(this._get(b,"gotoCurrent")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth=b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e["selected"+(c=="M"? -"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay=d("a",e).html();f.selectedMonth=f.currentMonth=b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=d(a); -this._getInst(a[0]);this._selectDate(a,"")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a);a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,"onSelect");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a);else{this._hideDatepicker();this._lastInput=a.input[0];a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a, -"altFormat")||this._get(a,"dateFormat"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a));d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b=a.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b== -"")return null;var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;e=typeof e!="string"?e:(new Date).getFullYear()%100+parseInt(e,10);for(var f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,j=c=-1,l=-1,u=-1,k=false,o=function(p){(p=A+1-1){j=1;l=u;do{e=this._getDaysInMonth(c,j-1);if(l<=e)break;j++;l-=e}while(1)}v=this._daylightSavingAdjust(new Date(c,j-1,l));if(v.getFullYear()!=c||v.getMonth()+1!=j||v.getDate()!=l)throw"Invalid date";return v},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y", -RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1E7,formatDate:function(a,b,c){if(!b)return"";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames:null)||this._defaults.monthNames;var i=function(o){(o=k+112?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear; -b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?"":this._formatDate(a));if(c=this._get(a,"onSelect")){e=this._formatDate(a);c.apply(a.input?a.input[0]:null,[e,a])}},_getDate:function(a){return!a.currentYear||a.input&&a.input.val()== -""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),e=this._get(a,"showButtonPanel"),f=this._get(a,"hideIfNoPrevNext"),h=this._get(a,"navigationAsDateFormat"),i=this._getNumberOfMonths(a),g=this._get(a,"showCurrentAtPos"),j=this._get(a,"stepMonths"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay?new Date(9999, -9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),k=this._getMinMaxDate(a,"min"),o=this._getMinMaxDate(a,"max");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n=this._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=k&&nn;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,"prevText");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-j,1)),this._getFormatConfig(a)); -n=this._canAdjustMonth(a,-1,m,g)?''+n+"":f?"":''+n+"";var s=this._get(a,"nextText");s=!h?s:this.formatDate(s,this._daylightSavingAdjust(new Date(m, -g+j,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?''+s+"":f?"":''+s+"";j=this._get(a,"currentText");s=this._get(a,"gotoCurrent")&& -a.currentDay?u:b;j=!h?j:this.formatDate(j,s,this._getFormatConfig(a));h=!a.inline?'":"";e=e?'
      '+(c?h:"")+(this._isInRange(a,s)?'":"")+(c?"":h)+"
      ":"";h=parseInt(this._get(a,"firstDay"),10);h=isNaN(h)?0:h;j=this._get(a,"showWeek");s=this._get(a,"dayNames");this._get(a,"dayNamesShort");var q=this._get(a,"dayNamesMin"),A=this._get(a,"monthNames"),v=this._get(a,"monthNamesShort"),p=this._get(a,"beforeShowDay"),D=this._get(a,"showOtherMonths"),K=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var E=this._getDefaultDate(a),w="",x=0;x1)switch(G){case 0:y+=" ui-datepicker-group-first";t=" ui-corner-"+(c?"right":"left");break;case i[1]-1:y+=" ui-datepicker-group-last";t=" ui-corner-"+(c?"left":"right");break;default:y+=" ui-datepicker-group-middle";t="";break}y+='">'}y+='
      '+(/all|left/.test(t)&& -x==0?c?f:n:"")+(/all|right/.test(t)&&x==0?c?n:f:"")+this._generateMonthYearHeader(a,g,m,k,o,x>0||G>0,A,v)+'
      ';var z=j?'":"";for(t=0;t<7;t++){var r=(t+h)%7;z+="=5?' class="ui-datepicker-week-end"':"")+'>'+q[r]+""}y+=z+"";z=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay, -z);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;z=Math.ceil((t+z)/7);this.maxRows=z=l?this.maxRows>z?this.maxRows:z:z;r=this._daylightSavingAdjust(new Date(m,g,1-t));for(var Q=0;Q";var R=!j?"":'";for(t=0;t<7;t++){var I=p?p.apply(a.input?a.input[0]:null,[r]):[true,""],F=r.getMonth()!=g,L=F&&!K||!I[0]||k&&ro;R+='";r.setDate(r.getDate()+1);r=this._daylightSavingAdjust(r)}y+=R+""}g++;if(g>11){g=0;m++}y+="
      '+this._get(a,"weekHeader")+"
      '+this._get(a,"calculateWeek")(r)+""+(F&&!D?" ":L?''+ -r.getDate()+"":''+r.getDate()+"")+"
      "+(l?"
      "+(i[0]>0&&G==i[1]-1?'
      ':""):"");O+=y}w+=O}w+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'': -"");a._keyEvent=false;return w},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var j=this._get(a,"changeMonth"),l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),k='
      ',o="";if(h||!j)o+=''+i[b]+"";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='"}u||(k+=o+(h||!(j&&l)?" ":""));if(!a.yearshtml){a.yearshtml="";if(h||!l)k+=''+c+"";else{g=this._get(a,"yearRange").split(":");var s=(new Date).getFullYear();i=function(q){q=q.match(/c[+-].*/)?c+parseInt(q.substring(1),10):q.match(/[+-].*/)?s+parseInt(q,10):parseInt(q,10);return isNaN(q)?s:q};b=i(g[0]);g=Math.max(b,i(g[1]||""));b=e?Math.max(b, -e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(a.yearshtml+='";k+=a.yearshtml;a.yearshtml=null}}k+=this._get(a,"yearSuffix");if(u)k+=(h||!(j&&l)?" ":"")+o;k+="
      ";return k},_adjustInstDate:function(a,b,c){var e=a.drawYear+(c=="Y"?b:0),f=a.drawMonth+ -(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&ba?a:b},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");if(b)b.apply(a.input? -a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a);c=this._daylightSavingAdjust(new Date(c, -e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a, -"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker=function(a){if(!this.length)return this; -if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));return this.each(function(){typeof a== -"string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new M;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.15";window["DP_jQuery_"+B]=d})(jQuery); -;/* - * jQuery UI Progressbar 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Progressbar - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function(b,d){b.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()});this.valueDiv=b("
      ").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"); -this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===d)return this._value();this._setOption("value",a);return this},_setOption:function(a,c){if(a==="value"){this.options.value=c;this._refreshValue();this._value()===this.options.max&&this._trigger("complete")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;return Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100* -this._value()/this.options.max},_refreshValue:function(){var a=this.value(),c=this._percentage();if(this.oldValue!==a){this.oldValue=a;this._trigger("change")}this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(c.toFixed(0)+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.15"})})(jQuery); -;/* - * jQuery UI Effects 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/ - */ -jQuery.effects||function(f,j){function m(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1], -16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return n.transparent;return n[f.trim(c).toLowerCase()]}function s(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return m(b)}function o(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle, -a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function p(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in t||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function u(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d= -a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:b in f.fx.speeds?f.fx.speeds[b]:f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}function l(c){if(!c||typeof c==="number"||f.fx.speeds[c])return true;if(typeof c==="string"&&!f.effects[c])return true;return false}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor", -"borderTopColor","borderColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=s(b.elem,a);b.end=m(b.end);b.colorInit=true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var n={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0, -0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211, -211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},q=["add","remove","toggle"],t={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b, -d){if(f.isFunction(b)){d=b;b=null}return this.queue(function(){var e=f(this),g=e.attr("style")||" ",h=p(o.call(this)),r,v=e.attr("class");f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});r=p(o.call(this));e.attr("class",v);e.animate(u(h,r),{queue:false,duration:a,easing:b,complete:function(){f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments);f.dequeue(this)}})})}; -f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,a):f.effects.animateClass.apply(this, -[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.15",save:function(c,a){for(var b=0;b
      ").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}); -c.wrap(b);b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(d,e){a[e]=c.css(e);if(isNaN(parseInt(a[e],10)))a[e]="auto"});c.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return b.css(a).show()},removeWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent().replaceWith(c);return c},setTransition:function(c, -a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)});return d.call(this,b)},_show:f.fn.show,show:function(c){if(l(c))return this._show.apply(this,arguments);else{var a=k.apply(this,arguments); -a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(l(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(l(c)||typeof c==="boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),b=[];f.each(["em","px","%", -"pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,a,b,d,e){return d* -((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b,d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,a,b,d,e){if((a/= -e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c,a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==e)return b+d;if((a/= -e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h").css({position:"absolute",visibility:"visible",left:-f*(h/d),top:-e*(i/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode=="show"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode=="show"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode=="show"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode=="show"?0:(f-Math.floor(d/2))*(h/d)),top:g.top+ -e*(i/c)+(a.options.mode=="show"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode=="show"?1:0},a.duration||500);setTimeout(function(){a.options.mode=="show"?b.css({visibility:"visible"}):b.css({visibility:"visible"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j("div.ui-effects-explode").remove()},a.duration||500)})}})(jQuery); -;/* - * jQuery UI Effects Fade 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Fade - * - * Depends: - * jquery.effects.core.js - */ -(function(b){b.effects.fade=function(a){return this.queue(function(){var c=b(this),d=b.effects.setMode(c,a.options.mode||"hide");c.animate({opacity:d},{queue:false,duration:a.duration,easing:a.options.easing,complete:function(){a.callback&&a.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Fold 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Fold - * - * Depends: - * jquery.effects.core.js - */ -(function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=["position","top","bottom","left","right"],d=c.effects.setMode(b,a.options.mode||"hide"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:"hidden"}),f=d=="show"!=h,l=f?["width","height"]:["height","width"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1], -10)/100*f[d=="hide"?0:1];if(d=="show")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d=="show"?f[0]:g;i[l[1]]=d=="show"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d=="hide"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery); -;/* - * jQuery UI Effects Highlight 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Highlight - * - * Depends: - * jquery.effects.core.js - */ -(function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=["backgroundImage","backgroundColor","opacity"],d=b.effects.setMode(a,c.options.mode||"show"),f={backgroundColor:a.css("backgroundColor")};if(d=="hide")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d=="hide"&&a.hide();b.effects.restore(a,e);d=="show"&&!b.support.opacity&& -this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Pulsate 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Pulsate - * - * Depends: - * jquery.effects.core.js - */ -(function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||"show");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(":visible");animateTo=0;if(!isVisible){b.css("opacity",0).show();animateTo=1}if(c=="hide"&&isVisible||c=="show"&&!isVisible)times--;for(c=0;c').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:"absolute"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments); -b.dequeue()})})}})(jQuery); -; \ No newline at end of file diff --git a/public/javascripts/jquery-ui-1.8.17.custom.min.js b/public/javascripts/jquery-ui-1.8.17.custom.min.js new file mode 100644 index 00000000..991cb8d0 --- /dev/null +++ b/public/javascripts/jquery-ui-1.8.17.custom.min.js @@ -0,0 +1,356 @@ +/*! + * jQuery UI 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI + */(function(a,b){function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;if(!b.href||!g||f.nodeName.toLowerCase()!=="map")return!1;h=a("img[usemap=#"+g+"]")[0];return!!h&&d(h)}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}a.ui=a.ui||{};a.ui.version||(a.extend(a.ui,{version:"1.8.17",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(b,c){return typeof b=="number"?this.each(function(){var d=this;setTimeout(function(){a(d).focus(),c&&c.call(d)},b)}):this._focus.apply(this,arguments)},scrollParent:function(){var b;a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?b=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):b=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length){var d=a(this[0]),e,f;while(d.length&&d[0]!==document){e=d.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){f=parseInt(d.css("zIndex"),10);if(!isNaN(f)&&f!==0)return f}d=d.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a.each(["Width","Height"],function(c,d){function h(b,c,d,f){a.each(e,function(){c-=parseFloat(a.curCSS(b,"padding"+this,!0))||0,d&&(c-=parseFloat(a.curCSS(b,"border"+this+"Width",!0))||0),f&&(c-=parseFloat(a.curCSS(b,"margin"+this,!0))||0)});return c}var e=d==="Width"?["Left","Right"]:["Top","Bottom"],f=d.toLowerCase(),g={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){if(c===b)return g["inner"+d].call(this);return this.each(function(){a(this).css(f,h(this,c)+"px")})},a.fn["outer"+d]=function(b,c){if(typeof b!="number")return g["outer"+d].call(this,b);return this.each(function(){a(this).css(f,h(this,b,!0,c)+"px")})}}),a.extend(a.expr[":"],{data:function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a(function(){var b=document.body,c=b.appendChild(c=document.createElement("div"));a.extend(c.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),a.support.minHeight=c.offsetHeight===100,a.support.selectstart="onselectstart"in c,b.removeChild(c).style.display="none"}),a.extend(a.ui,{plugin:{add:function(b,c,d){var e=a.ui[b].prototype;for(var f in d)e.plugins[f]=e.plugins[f]||[],e.plugins[f].push([c,d[f]])},call:function(a,b,c){var d=a.plugins[b];if(!!d&&!!a.element[0].parentNode)for(var e=0;e0)return!0;b[d]=1,e=b[d]>0,b[d]=0;return e},isOverAxis:function(a,b,c){return a>b&&a=9)&&!b.button)return this._mouseUp(b);if(this._mouseStarted){this._mouseDrag(b);return b.preventDefault()}this._mouseDistanceMet(b)&&this._mouseDelayMet(b)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,b)!==!1,this._mouseStarted?this._mouseDrag(b):this._mouseUp(b));return!this._mouseStarted},_mouseUp:function(b){a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,b.target==this._mouseDownEvent.target&&a.data(b.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(b));return!1},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(a){return this.mouseDelayMet},_mouseStart:function(a){},_mouseDrag:function(a){},_mouseStop:function(a){},_mouseCapture:function(a){return!0}})})(jQuery);/* + * jQuery UI Position 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Position + */(function(a,b){a.ui=a.ui||{};var c=/left|center|right/,d=/top|center|bottom/,e="center",f={},g=a.fn.position,h=a.fn.offset;a.fn.position=function(b){if(!b||!b.of)return g.apply(this,arguments);b=a.extend({},b);var h=a(b.of),i=h[0],j=(b.collision||"flip").split(" "),k=b.offset?b.offset.split(" "):[0,0],l,m,n;i.nodeType===9?(l=h.width(),m=h.height(),n={top:0,left:0}):i.setTimeout?(l=h.width(),m=h.height(),n={top:h.scrollTop(),left:h.scrollLeft()}):i.preventDefault?(b.at="left top",l=m=0,n={top:b.of.pageY,left:b.of.pageX}):(l=h.outerWidth(),m=h.outerHeight(),n=h.offset()),a.each(["my","at"],function(){var a=(b[this]||"").split(" ");a.length===1&&(a=c.test(a[0])?a.concat([e]):d.test(a[0])?[e].concat(a):[e,e]),a[0]=c.test(a[0])?a[0]:e,a[1]=d.test(a[1])?a[1]:e,b[this]=a}),j.length===1&&(j[1]=j[0]),k[0]=parseInt(k[0],10)||0,k.length===1&&(k[1]=k[0]),k[1]=parseInt(k[1],10)||0,b.at[0]==="right"?n.left+=l:b.at[0]===e&&(n.left+=l/2),b.at[1]==="bottom"?n.top+=m:b.at[1]===e&&(n.top+=m/2),n.left+=k[0],n.top+=k[1];return this.each(function(){var c=a(this),d=c.outerWidth(),g=c.outerHeight(),h=parseInt(a.curCSS(this,"marginLeft",!0))||0,i=parseInt(a.curCSS(this,"marginTop",!0))||0,o=d+h+(parseInt(a.curCSS(this,"marginRight",!0))||0),p=g+i+(parseInt(a.curCSS(this,"marginBottom",!0))||0),q=a.extend({},n),r;b.my[0]==="right"?q.left-=d:b.my[0]===e&&(q.left-=d/2),b.my[1]==="bottom"?q.top-=g:b.my[1]===e&&(q.top-=g/2),f.fractions||(q.left=Math.round(q.left),q.top=Math.round(q.top)),r={left:q.left-h,top:q.top-i},a.each(["left","top"],function(c,e){a.ui.position[j[c]]&&a.ui.position[j[c]][e](q,{targetWidth:l,targetHeight:m,elemWidth:d,elemHeight:g,collisionPosition:r,collisionWidth:o,collisionHeight:p,offset:k,my:b.my,at:b.at})}),a.fn.bgiframe&&c.bgiframe(),c.offset(a.extend(q,{using:b.using}))})},a.ui.position={fit:{left:function(b,c){var d=a(window),e=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft();b.left=e>0?b.left-e:Math.max(b.left-c.collisionPosition.left,b.left)},top:function(b,c){var d=a(window),e=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop();b.top=e>0?b.top-e:Math.max(b.top-c.collisionPosition.top,b.top)}},flip:{left:function(b,c){if(c.at[0]!==e){var d=a(window),f=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft(),g=c.my[0]==="left"?-c.elemWidth:c.my[0]==="right"?c.elemWidth:0,h=c.at[0]==="left"?c.targetWidth:-c.targetWidth,i=-2*c.offset[0];b.left+=c.collisionPosition.left<0?g+h+i:f>0?g+h+i:0}},top:function(b,c){if(c.at[1]!==e){var d=a(window),f=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop(),g=c.my[1]==="top"?-c.elemHeight:c.my[1]==="bottom"?c.elemHeight:0,h=c.at[1]==="top"?c.targetHeight:-c.targetHeight,i=-2*c.offset[1];b.top+=c.collisionPosition.top<0?g+h+i:f>0?g+h+i:0}}}},a.offset.setOffset||(a.offset.setOffset=function(b,c){/static/.test(a.curCSS(b,"position"))&&(b.style.position="relative");var d=a(b),e=d.offset(),f=parseInt(a.curCSS(b,"top",!0),10)||0,g=parseInt(a.curCSS(b,"left",!0),10)||0,h={top:c.top-e.top+f,left:c.left-e.left+g};"using"in c?c.using.call(b,h):d.css(h)},a.fn.offset=function(b){var c=this[0];if(!c||!c.ownerDocument)return null;if(b)return this.each(function(){a.offset.setOffset(this,b)});return h.call(this)}),function(){var b=document.getElementsByTagName("body")[0],c=document.createElement("div"),d,e,g,h,i;d=document.createElement(b?"div":"body"),g={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},b&&jQuery.extend(g,{position:"absolute",left:"-1000px",top:"-1000px"});for(var j in g)d.style[j]=g[j];d.appendChild(c),e=b||document.documentElement,e.insertBefore(d,e.firstChild),c.style.cssText="position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;",h=a(c).offset(function(a,b){return b}).offset(),d.innerHTML="",e.removeChild(d),i=h.top+h.left+(b?2e3:0),f.fractions=i>21&&i<22}()})(jQuery);/* + * jQuery UI Draggable 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Draggables + * + * Depends: + * jquery.ui.core.js + * jquery.ui.mouse.js + * jquery.ui.widget.js + */(function(a,b){a.widget("ui.draggable",a.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1},_create:function(){this.options.helper=="original"&&!/^(?:r|a|f)/.test(this.element.css("position"))&&(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},destroy:function(){if(!!this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy();return this}},_mouseCapture:function(b){var c=this.options;if(this.helper||c.disabled||a(b.target).is(".ui-resizable-handle"))return!1;this.handle=this._getHandle(b);if(!this.handle)return!1;c.iframeFix&&a(c.iframeFix===!0?"iframe":c.iframeFix).each(function(){a('
      ').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(a(this).offset()).appendTo("body")});return!0},_mouseStart:function(b){var c=this.options;this.helper=this._createHelper(b),this._cacheHelperProportions(),a.ui.ddmanager&&(a.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,c.cursorAt&&this._adjustOffsetFromHelper(c.cursorAt),c.containment&&this._setContainment();if(this._trigger("start",b)===!1){this._clear();return!1}this._cacheHelperProportions(),a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this.helper.addClass("ui-draggable-dragging"),this._mouseDrag(b,!0),a.ui.ddmanager&&a.ui.ddmanager.dragStart(this,b);return!0},_mouseDrag:function(b,c){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute");if(!c){var d=this._uiHash();if(this._trigger("drag",b,d)===!1){this._mouseUp({});return!1}this.position=d.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";a.ui.ddmanager&&a.ui.ddmanager.drag(this,b);return!1},_mouseStop:function(b){var c=!1;a.ui.ddmanager&&!this.options.dropBehaviour&&(c=a.ui.ddmanager.drop(this,b)),this.dropped&&(c=this.dropped,this.dropped=!1);if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return!1;if(this.options.revert=="invalid"&&!c||this.options.revert=="valid"&&c||this.options.revert===!0||a.isFunction(this.options.revert)&&this.options.revert.call(this.element,c)){var d=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){d._trigger("stop",b)!==!1&&d._clear()})}else this._trigger("stop",b)!==!1&&this._clear();return!1},_mouseUp:function(b){this.options.iframeFix===!0&&a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),a.ui.ddmanager&&a.ui.ddmanager.dragStop(this,b);return a.ui.mouse.prototype._mouseUp.call(this,b)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?!0:!1;a(this.options.handle,this.element).find("*").andSelf().each(function(){this==b.target&&(c=!0)});return c},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b])):c.helper=="clone"?this.element.clone().removeAttr("id"):this.element;d.parents("body").length||d.appendTo(c.appendTo=="parent"?this.element[0].parentNode:c.appendTo),d[0]!=this.element[0]&&!/(fixed|absolute)/.test(d.css("position"))&&d.css("position","absolute");return d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[b.containment=="document"?0:a(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,b.containment=="document"?0:a(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,(b.containment=="document"?0:a(window).scrollLeft())+a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(b.containment=="document"?0:a(window).scrollTop())+(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)&&b.containment.constructor!=Array){var c=a(b.containment),d=c[0];if(!d)return;var e=c.offset(),f=a(d).css("overflow")!="hidden";this.containment=[(parseInt(a(d).css("borderLeftWidth"),10)||0)+(parseInt(a(d).css("paddingLeft"),10)||0),(parseInt(a(d).css("borderTopWidth"),10)||0)+(parseInt(a(d).css("paddingTop"),10)||0),(f?Math.max(d.scrollWidth,d.offsetWidth):d.offsetWidth)-(parseInt(a(d).css("borderLeftWidth"),10)||0)-(parseInt(a(d).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(f?Math.max(d.scrollHeight,d.offsetHeight):d.offsetHeight)-(parseInt(a(d).css("borderTopWidth"),10)||0)-(parseInt(a(d).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=c}else b.containment.constructor==Array&&(this.containment=b.containment)},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName),f=b.pageX,g=b.pageY;if(this.originalPosition){var h;if(this.containment){if(this.relative_container){var i=this.relative_container.offset();h=[this.containment[0]+i.left,this.containment[1]+i.top,this.containment[2]+i.left,this.containment[3]+i.top]}else h=this.containment;b.pageX-this.offset.click.lefth[2]&&(f=h[2]+this.offset.click.left),b.pageY-this.offset.click.top>h[3]&&(g=h[3]+this.offset.click.top)}if(c.grid){var j=c.grid[1]?this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1]:this.originalPageY;g=h?j-this.offset.click.toph[3]?j-this.offset.click.toph[2]?k-this.offset.click.left=0;k--){var l=d.snapElements[k].left,m=l+d.snapElements[k].width,n=d.snapElements[k].top,o=n+d.snapElements[k].height;if(!(l-f=k&&g<=l||h>=k&&h<=l||gl)&&(e>=i&&e<=j||f>=i&&f<=j||ej);default:return!1}},a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(b,c){var d=a.ui.ddmanager.droppables[b.options.scope]||[],e=c?c.type:null,f=(b.currentItem||b.element).find(":data(droppable)").andSelf();droppablesLoop:for(var g=0;g').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("resizable",this.element.data("resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=c.handles||(a(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se");if(this.handles.constructor==String){this.handles=="all"&&(this.handles="n,e,s,w,se,sw,ne,nw");var d=this.handles.split(",");this.handles={};for(var e=0;e');/sw|se|ne|nw/.test(f)&&h.css({zIndex:++c.zIndex}),"se"==f&&h.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[f]=".ui-resizable-"+f,this.element.append(h)}}this._renderAxis=function(b){b=b||this.element;for(var c in this.handles){this.handles[c].constructor==String&&(this.handles[c]=a(this.handles[c],this.element).show());if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var d=a(this.handles[c],this.element),e=0;e=/sw|ne|nw|se|n|s/.test(c)?d.outerHeight():d.outerWidth();var f=["padding",/ne|nw|n/.test(c)?"Top":/se|sw|s/.test(c)?"Bottom":/^e$/.test(c)?"Right":"Left"].join("");b.css(f,e),this._proportionallyResize()}if(!a(this.handles[c]).length)continue}},this._renderAxis(this.element),this._handles=a(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){if(!b.resizing){if(this.className)var a=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=a&&a[1]?a[1]:"se"}}),c.autoHide&&(this._handles.hide(),a(this.element).addClass("ui-resizable-autohide").hover(function(){c.disabled||(a(this).removeClass("ui-resizable-autohide"),b._handles.show())},function(){c.disabled||b.resizing||(a(this).addClass("ui-resizable-autohide"),b._handles.hide())})),this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(b){a(b).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var c=this.element;c.after(this.originalElement.css({position:c.css("position"),width:c.outerWidth(),height:c.outerHeight(),top:c.css("top"),left:c.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle),b(this.originalElement);return this},_mouseCapture:function(b){var c=!1;for(var d in this.handles)a(this.handles[d])[0]==b.target&&(c=!0);return!this.options.disabled&&c},_mouseStart:function(b){var d=this.options,e=this.element.position(),f=this.element;this.resizing=!0,this.documentScroll={top:a(document).scrollTop(),left:a(document).scrollLeft()},(f.is(".ui-draggable")||/absolute/.test(f.css("position")))&&f.css({position:"absolute",top:e.top,left:e.left}),a.browser.opera&&/relative/.test(f.css("position"))&&f.css({position:"relative",top:"auto",left:"auto"}),this._renderProxy();var g=c(this.helper.css("left")),h=c(this.helper.css("top"));d.containment&&(g+=a(d.containment).scrollLeft()||0,h+=a(d.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:g,top:h},this.size=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalSize=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalPosition={left:g,top:h},this.sizeDiff={width:f.outerWidth()-f.width(),height:f.outerHeight()-f.height()},this.originalMousePosition={left:b.pageX,top:b.pageY},this.aspectRatio=typeof d.aspectRatio=="number"?d.aspectRatio:this.originalSize.width/this.originalSize.height||1;var i=a(".ui-resizable-"+this.axis).css("cursor");a("body").css("cursor",i=="auto"?this.axis+"-resize":i),f.addClass("ui-resizable-resizing"),this._propagate("start",b);return!0},_mouseDrag:function(b){var c=this.helper,d=this.options,e={},f=this,g=this.originalMousePosition,h=this.axis,i=b.pageX-g.left||0,j=b.pageY-g.top||0,k=this._change[h];if(!k)return!1;var l=k.apply(this,[b,i,j]),m=a.browser.msie&&a.browser.version<7,n=this.sizeDiff;this._updateVirtualBoundaries(b.shiftKey);if(this._aspectRatio||b.shiftKey)l=this._updateRatio(l,b);l=this._respectSize(l,b),this._propagate("resize",b),c.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"}),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),this._updateCache(l),this._trigger("resize",b,this.ui());return!1},_mouseStop:function(b){this.resizing=!1;var c=this.options,d=this;if(this._helper){var e=this._proportionallyResizeElements,f=e.length&&/textarea/i.test(e[0].nodeName),g=f&&a.ui.hasScroll(e[0],"left")?0:d.sizeDiff.height,h=f?0:d.sizeDiff.width,i={width:d.helper.width()-h,height:d.helper.height()-g},j=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,k=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;c.animate||this.element.css(a.extend(i,{top:k,left:j})),d.helper.height(d.size.height),d.helper.width(d.size.width),this._helper&&!c.animate&&this._proportionallyResize()}a("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",b),this._helper&&this.helper.remove();return!1},_updateVirtualBoundaries:function(a){var b=this.options,c,e,f,g,h;h={minWidth:d(b.minWidth)?b.minWidth:0,maxWidth:d(b.maxWidth)?b.maxWidth:Infinity,minHeight:d(b.minHeight)?b.minHeight:0,maxHeight:d(b.maxHeight)?b.maxHeight:Infinity};if(this._aspectRatio||a)c=h.minHeight*this.aspectRatio,f=h.minWidth/this.aspectRatio,e=h.maxHeight*this.aspectRatio,g=h.maxWidth/this.aspectRatio,c>h.minWidth&&(h.minWidth=c),f>h.minHeight&&(h.minHeight=f),ea.width,k=d(a.height)&&e.minHeight&&e.minHeight>a.height;j&&(a.width=e.minWidth),k&&(a.height=e.minHeight),h&&(a.width=e.maxWidth),i&&(a.height=e.maxHeight);var l=this.originalPosition.left+this.originalSize.width,m=this.position.top+this.size.height,n=/sw|nw|w/.test(g),o=/nw|ne|n/.test(g);j&&n&&(a.left=l-e.minWidth),h&&n&&(a.left=l-e.maxWidth),k&&o&&(a.top=m-e.minHeight),i&&o&&(a.top=m-e.maxHeight);var p=!a.width&&!a.height;p&&!a.left&&a.top?a.top=null:p&&!a.top&&a.left&&(a.left=null);return a},_proportionallyResize:function(){var b=this.options;if(!!this._proportionallyResizeElements.length){var c=this.helper||this.element;for(var d=0;d');var d=a.browser.msie&&a.browser.version<7,e=d?1:0,f=d?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+f,height:this.element.outerHeight()+f,position:"absolute",left:this.elementOffset.left-e+"px",top:this.elementOffset.top-e+"px",zIndex:++c.zIndex}),this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(a,b,c){return{width:this.originalSize.width+b}},w:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{left:f.left+b,width:e.width-b}},n:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{top:f.top+c,height:e.height-c}},s:function(a,b,c){return{height:this.originalSize.height+c}},se:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},sw:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,c,d]))},ne:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},nw:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,c,d]))}},_propagate:function(b,c){a.ui.plugin.call(this,b,[c,this.ui()]),b!="resize"&&this._trigger(b,c,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),a.extend(a.ui.resizable,{version:"1.8.17"}),a.ui.plugin.add("resizable","alsoResize",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=function(b){a(b).each(function(){var b=a(this);b.data("resizable-alsoresize",{width:parseInt(b.width(),10),height:parseInt(b.height(),10),left:parseInt(b.css("left"),10),top:parseInt(b.css("top"),10),position:b.css("position")})})};typeof e.alsoResize=="object"&&!e.alsoResize.parentNode?e.alsoResize.length?(e.alsoResize=e.alsoResize[0],f(e.alsoResize)):a.each(e.alsoResize,function(a){f(a)}):f(e.alsoResize)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.originalSize,g=d.originalPosition,h={height:d.size.height-f.height||0,width:d.size.width-f.width||0,top:d.position.top-g.top||0,left:d.position.left-g.left||0},i=function(b,e){a(b).each(function(){var b=a(this),f=a(this).data("resizable-alsoresize"),g={},i=e&&e.length?e:b.parents(c.originalElement[0]).length?["width","height"]:["width","height","top","left"];a.each(i,function(a,b){var c=(f[b]||0)+(h[b]||0);c&&c>=0&&(g[b]=c||null)}),a.browser.opera&&/relative/.test(b.css("position"))&&(d._revertToRelativePosition=!0,b.css({position:"absolute",top:"auto",left:"auto"})),b.css(g)})};typeof e.alsoResize=="object"&&!e.alsoResize.nodeType?a.each(e.alsoResize,function(a,b){i(a,b)}):i(e.alsoResize)},stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=function(b){a(b).each(function(){var b=a(this);b.css({position:b.data("resizable-alsoresize").position})})};d._revertToRelativePosition&&(d._revertToRelativePosition=!1,typeof e.alsoResize=="object"&&!e.alsoResize.nodeType?a.each(e.alsoResize,function(a){f(a)}):f(e.alsoResize)),a(this).removeData("resizable-alsoresize")}}),a.ui.plugin.add("resizable","animate",{stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d._proportionallyResizeElements,g=f.length&&/textarea/i.test(f[0].nodeName),h=g&&a.ui.hasScroll(f[0],"left")?0:d.sizeDiff.height,i=g?0:d.sizeDiff.width,j={width:d.size.width-i,height:d.size.height-h},k=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,l=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;d.element.animate(a.extend(j,l&&k?{top:l,left:k}:{}),{duration:e.animateDuration,easing:e.animateEasing,step:function(){var c={width:parseInt(d.element.css("width"),10),height:parseInt(d.element.css("height"),10),top:parseInt(d.element.css("top"),10),left:parseInt(d.element.css("left"),10)};f&&f.length&&a(f[0]).css({width:c.width,height:c.height}),d._updateCache(c),d._propagate("resize",b)}})}}),a.ui.plugin.add("resizable","containment",{start:function(b,d){var e=a(this).data("resizable"),f=e.options,g=e.element,h=f.containment,i=h instanceof a?h.get(0):/parent/.test(h)?g.parent().get(0):h;if(!!i){e.containerElement=a(i);if(/document/.test(h)||h==document)e.containerOffset={left:0,top:0},e.containerPosition={left:0,top:0},e.parentData={element:a(document),left:0,top:0,width:a(document).width(),height:a(document).height()||document.body.parentNode.scrollHeight};else{var j=a(i),k=[];a(["Top","Right","Left","Bottom"]).each(function(a,b){k[a]=c(j.css("padding"+b))}),e.containerOffset=j.offset(),e.containerPosition=j.position(),e.containerSize={height:j.innerHeight()-k[3],width:j.innerWidth()-k[1]};var l=e.containerOffset,m=e.containerSize.height,n=e.containerSize.width,o=a.ui.hasScroll(i,"left")?i.scrollWidth:n,p=a.ui.hasScroll(i)?i.scrollHeight:m;e.parentData={element:i,left:l.left,top:l.top,width:o,height:p}}}},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.containerSize,g=d.containerOffset,h=d.size,i=d.position,j=d._aspectRatio||b.shiftKey,k={top:0,left:0},l=d.containerElement;l[0]!=document&&/static/.test(l.css("position"))&&(k=g),i.left<(d._helper?g.left:0)&&(d.size.width=d.size.width+(d._helper?d.position.left-g.left:d.position.left-k.left),j&&(d.size.height=d.size.width/e.aspectRatio),d.position.left=e.helper?g.left:0),i.top<(d._helper?g.top:0)&&(d.size.height=d.size.height+(d._helper?d.position.top-g.top:d.position.top),j&&(d.size.width=d.size.height*e.aspectRatio),d.position.top=d._helper?g.top:0),d.offset.left=d.parentData.left+d.position.left,d.offset.top=d.parentData.top+d.position.top;var m=Math.abs((d._helper?d.offset.left-k.left:d.offset.left-k.left)+d.sizeDiff.width),n=Math.abs((d._helper?d.offset.top-k.top:d.offset.top-g.top)+d.sizeDiff.height),o=d.containerElement.get(0)==d.element.parent().get(0),p=/relative|absolute/.test(d.containerElement.css("position"));o&&p&&(m-=d.parentData.left),m+d.size.width>=d.parentData.width&&(d.size.width=d.parentData.width-m,j&&(d.size.height=d.size.width/d.aspectRatio)),n+d.size.height>=d.parentData.height&&(d.size.height=d.parentData.height-n,j&&(d.size.width=d.size.height*d.aspectRatio))},stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.position,g=d.containerOffset,h=d.containerPosition,i=d.containerElement,j=a(d.helper),k=j.offset(),l=j.outerWidth()-d.sizeDiff.width,m=j.outerHeight()-d.sizeDiff.height;d._helper&&!e.animate&&/relative/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m}),d._helper&&!e.animate&&/static/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m})}}),a.ui.plugin.add("resizable","ghost",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size;d.ghost=d.originalElement.clone(),d.ghost.css({opacity:.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof e.ghost=="string"?e.ghost:""),d.ghost.appendTo(d.helper)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})},stop:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.helper&&d.helper.get(0).removeChild(d.ghost.get(0))}}),a.ui.plugin.add("resizable","grid",{resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size,g=d.originalSize,h=d.originalPosition,i=d.axis,j=e._aspectRatio||b.shiftKey;e.grid=typeof e.grid=="number"?[e.grid,e.grid]:e.grid;var k=Math.round((f.width-g.width)/(e.grid[0]||1))*(e.grid[0]||1),l=Math.round((f.height-g.height)/(e.grid[1]||1))*(e.grid[1]||1);/^(se|s|e)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l):/^(ne)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l):/^(sw)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.left=h.left-k):(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l,d.position.left=h.left-k)}});var c=function(a){return parseInt(a,10)||0},d=function(a){return!isNaN(parseInt(a,10))}})(jQuery);/* + * jQuery UI Selectable 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Selectables + * + * Depends: + * jquery.ui.core.js + * jquery.ui.mouse.js + * jquery.ui.widget.js + */(function(a,b){a.widget("ui.selectable",a.ui.mouse,{options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch"},_create:function(){var b=this;this.element.addClass("ui-selectable"),this.dragged=!1;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]),c.addClass("ui-selectee"),c.each(function(){var b=a(this),c=b.offset();a.data(this,"selectable-item",{element:this,$element:b,left:c.left,top:c.top,right:c.left+b.outerWidth(),bottom:c.top+b.outerHeight(),startselected:!1,selected:b.hasClass("ui-selected"),selecting:b.hasClass("ui-selecting"),unselecting:b.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=c.addClass("ui-selectee"),this._mouseInit(),this.helper=a("
      ")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable"),this._mouseDestroy();return this},_mouseStart:function(b){var c=this;this.opos=[b.pageX,b.pageY];if(!this.options.disabled){var d=this.options;this.selectees=a(d.filter,this.element[0]),this._trigger("start",b),a(d.appendTo).append(this.helper),this.helper.css({left:b.clientX,top:b.clientY,width:0,height:0}),d.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var d=a.data(this,"selectable-item");d.startselected=!0,!b.metaKey&&!b.ctrlKey&&(d.$element.removeClass("ui-selected"),d.selected=!1,d.$element.addClass("ui-unselecting"),d.unselecting=!0,c._trigger("unselecting",b,{unselecting:d.element}))}),a(b.target).parents().andSelf().each(function(){var d=a.data(this,"selectable-item");if(d){var e=!b.metaKey&&!b.ctrlKey||!d.$element.hasClass("ui-selected");d.$element.removeClass(e?"ui-unselecting":"ui-selected").addClass(e?"ui-selecting":"ui-unselecting"),d.unselecting=!e,d.selecting=e,d.selected=e,e?c._trigger("selecting",b,{selecting:d.element}):c._trigger("unselecting",b,{unselecting:d.element});return!1}})}},_mouseDrag:function(b){var c=this;this.dragged=!0;if(!this.options.disabled){var d=this.options,e=this.opos[0],f=this.opos[1],g=b.pageX,h=b.pageY;if(e>g){var i=g;g=e,e=i}if(f>h){var i=h;h=f,f=i}this.helper.css({left:e,top:f,width:g-e,height:h-f}),this.selectees.each(function(){var i=a.data(this,"selectable-item");if(!!i&&i.element!=c.element[0]){var j=!1;d.tolerance=="touch"?j=!(i.left>g||i.righth||i.bottome&&i.rightf&&i.bottom *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3},_create:function(){var a=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):!1,this.offset=this.element.offset(),this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData(this.widgetName+"-item");return this},_setOption:function(b,c){b==="disabled"?(this.options[b]=c,this.widget()[c?"addClass":"removeClass"]("ui-sortable-disabled")):a.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(b,c){var d=this;if(this.reverting)return!1;if(this.options.disabled||this.options.type=="static")return!1;this._refreshItems(b);var e=null,f=this,g=a(b.target).parents().each(function(){if(a.data(this,d.widgetName+"-item")==f){e=a(this);return!1}});a.data(b.target,d.widgetName+"-item")==f&&(e=a(b.target));if(!e)return!1;if(this.options.handle&&!c){var h=!1;a(this.options.handle,e).find("*").andSelf().each(function(){this==b.target&&(h=!0)});if(!h)return!1}this.currentItem=e,this._removeCurrentsFromItems();return!0},_mouseStart:function(b,c,d){var e=this.options,f=this;this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(b),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,e.cursorAt&&this._adjustOffsetFromHelper(e.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!=this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),e.containment&&this._setContainment(),e.cursor&&(a("body").css("cursor")&&(this._storedCursor=a("body").css("cursor")),a("body").css("cursor",e.cursor)),e.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",e.opacity)),e.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",e.zIndex)),this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",b,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions();if(!d)for(var g=this.containers.length-1;g>=0;g--)this.containers[g]._trigger("activate",b,f._uiHash(this));a.ui.ddmanager&&(a.ui.ddmanager.current=this),a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(b);return!0},_mouseDrag:function(b){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs);if(this.options.scroll){var c=this.options,d=!1;this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-b.pageY=0;e--){var f=this.items[e],g=f.item[0],h=this._intersectsWithPointer(f);if(!h)continue;if(g!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=g&&!a.ui.contains(this.placeholder[0],g)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],g):!0)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(f))this._rearrange(b,f);else break;this._trigger("change",b,this._uiHash());break}}this._contactContainers(b),a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),this._trigger("sort",b,this._uiHash()),this.lastPositionAbs=this.positionAbs;return!1},_mouseStop:function(b,c){if(!!b){a.ui.ddmanager&&!this.options.dropBehaviour&&a.ui.ddmanager.drop(this,b);if(this.options.revert){var d=this,e=d.placeholder.offset();d.reverting=!0,a(this.helper).animate({left:e.left-this.offset.parent.left-d.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-d.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){d._clear(b)})}else this._clear(b,c);return!1}},cancel:function(){var b=this;if(this.dragging){this._mouseUp({target:null}),this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("deactivate",null,b._uiHash(this)),this.containers[c].containerCache.over&&(this.containers[c]._trigger("out",null,b._uiHash(this)),this.containers[c].containerCache.over=0)}this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),a.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?a(this.domPosition.prev).after(this.currentItem):a(this.domPosition.parent).prepend(this.currentItem));return this},serialize:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];b=b||{},a(c).each(function(){var c=(a(b.item||this).attr(b.attribute||"id")||"").match(b.expression||/(.+)[-=_](.+)/);c&&d.push((b.key||c[1]+"[]")+"="+(b.key&&b.expression?c[1]:c[2]))}),!d.length&&b.key&&d.push(b.key+"=");return d.join("&")},toArray:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];b=b||{},c.each(function(){d.push(a(b.item||this).attr(b.attribute||"id")||"")});return d},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,d=this.positionAbs.top,e=d+this.helperProportions.height,f=a.left,g=f+a.width,h=a.top,i=h+a.height,j=this.offset.click.top,k=this.offset.click.left,l=d+j>h&&d+jf&&b+ka[this.floating?"width":"height"]?l:f0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a),this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(b){var c=this,d=[],e=[],f=this._connectWith();if(f&&b)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&e.push([a.isFunction(j.options.items)?j.options.items.call(j.element):a(j.options.items,j.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),j])}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(var g=e.length-1;g>=0;g--)e[g][0].each(function(){d.push(this)});return a(d)},_removeCurrentsFromItems:function(){var a=this.currentItem.find(":data("+this.widgetName+"-item)");for(var b=0;b=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&(e.push([a.isFunction(j.options.items)?j.options.items.call(j.element[0],b,{item:this.currentItem}):a(j.options.items,j.element),j]),this.containers.push(j))}}for(var g=e.length-1;g>=0;g--){var k=e[g][1],l=e[g][0];for(var i=0,m=l.length;i=0;c--){var d=this.items[c];if(d.instance!=this.currentContainer&&this.currentContainer&&d.item[0]!=this.currentItem[0])continue;var e=this.options.toleranceElement?a(this.options.toleranceElement,d.item):d.item;b||(d.width=e.outerWidth(),d.height=e.outerHeight());var f=e.offset();d.left=f.left,d.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(var c=this.containers.length-1;c>=0;c--){var f=this.containers[c].element.offset();this.containers[c].containerCache.left=f.left,this.containers[c].containerCache.top=f.top,this.containers[c].containerCache.width=this.containers[c].element.outerWidth(),this.containers[c].containerCache.height=this.containers[c].element.outerHeight()}return this},_createPlaceholder:function(b){var c=b||this,d=c.options;if(!d.placeholder||d.placeholder.constructor==String){var e=d.placeholder;d.placeholder={element:function(){var b=a(document.createElement(c.currentItem[0].nodeName)).addClass(e||c.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];e||(b.style.visibility="hidden");return b},update:function(a,b){if(!e||!!d.forcePlaceholderSize)b.height()||b.height(c.currentItem.innerHeight()-parseInt(c.currentItem.css("paddingTop")||0,10)-parseInt(c.currentItem.css("paddingBottom")||0,10)),b.width()||b.width(c.currentItem.innerWidth()-parseInt(c.currentItem.css("paddingLeft")||0,10)-parseInt(c.currentItem.css("paddingRight")||0,10))}}}c.placeholder=a(d.placeholder.element.call(c.element,c.currentItem)),c.currentItem.after(c.placeholder),d.placeholder.update(c,c.placeholder)},_contactContainers:function(b){var c=null,d=null;for(var e=this.containers.length-1;e>=0;e--){if(a.ui.contains(this.currentItem[0],this.containers[e].element[0]))continue;if(this._intersectsWith(this.containers[e].containerCache)){if(c&&a.ui.contains(this.containers[e].element[0],c.element[0]))continue;c=this.containers[e],d=e}else this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",b,this._uiHash(this)),this.containers[e].containerCache.over=0)}if(!!c)if(this.containers.length===1)this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1;else if(this.currentContainer!=this.containers[d]){var f=1e4,g=null,h=this.positionAbs[this.containers[d].floating?"left":"top"];for(var i=this.items.length-1;i>=0;i--){if(!a.ui.contains(this.containers[d].element[0],this.items[i].item[0]))continue;var j=this.items[i][this.containers[d].floating?"left":"top"];Math.abs(j-h)this.containment[2]&&(f=this.containment[2]+this.offset.click.left),b.pageY-this.offset.click.top>this.containment[3]&&(g=this.containment[3]+this.offset.click.top));if(c.grid){var h=this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1];g=this.containment?h-this.offset.click.topthis.containment[3]?h-this.offset.click.topthis.containment[2]?i-this.offset.click.left=0;f--)a.ui.contains(this.containers[f].element[0],this.currentItem[0])&&!c&&(d.push(function(a){return function(b){a._trigger("receive",b,this._uiHash(this))}}.call(this,this.containers[f])),d.push(function(a){return function(b){a._trigger("update",b,this._uiHash(this))}}.call(this,this.containers[f])))}for(var f=this.containers.length-1;f>=0;f--)c||d.push(function(a){return function(b){a._trigger("deactivate",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over&&(d.push(function(a){return function(b){a._trigger("out",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over=0);this._storedCursor&&a("body").css("cursor",this._storedCursor),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex),this.dragging=!1;if(this.cancelHelperRemoval){if(!c){this._trigger("beforeStop",b,this._uiHash());for(var f=0;f li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:!1,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var b=this,c=b.options;b.running=0,b.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"),b.headers=b.element.find(c.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){c.disabled||a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){c.disabled||a(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){c.disabled||a(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){c.disabled||a(this).removeClass("ui-state-focus")}),b.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");if(c.navigation){var d=b.element.find("a").filter(c.navigationFilter).eq(0);if(d.length){var e=d.closest(".ui-accordion-header");e.length?b.active=e:b.active=d.closest(".ui-accordion-content").prev()}}b.active=b._findActive(b.active||c.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top"),b.active.next().addClass("ui-accordion-content-active"),b._createIcons(),b.resize(),b.element.attr("role","tablist"),b.headers.attr("role","tab").bind("keydown.accordion",function(a){return b._keydown(a)}).next().attr("role","tabpanel"),b.headers.not(b.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide(),b.active.length?b.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):b.headers.eq(0).attr("tabIndex",0),a.browser.safari||b.headers.find("a").attr("tabIndex",-1),c.event&&b.headers.bind(c.event.split(" ").join(".accordion ")+".accordion",function(a){b._clickHandler.call(b,a,this),a.preventDefault()})},_createIcons:function(){var b=this.options;b.icons&&(a("").addClass("ui-icon "+b.icons.header).prependTo(this.headers),this.active.children(".ui-icon").toggleClass(b.icons.header).toggleClass(b.icons.headerSelected),this.element.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.children(".ui-icon").remove(),this.element.removeClass("ui-accordion-icons")},destroy:function(){var b=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"),this.headers.find("a").removeAttr("tabIndex"),this._destroyIcons();var c=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");(b.autoHeight||b.fillHeight)&&c.css("height","");return a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b=="active"&&this.activate(c),b=="icons"&&(this._destroyIcons(),c&&this._createIcons()),b=="disabled"&&this.headers.add(this.headers.next())[c?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(b){if(!(this.options.disabled||b.altKey||b.ctrlKey)){var c=a.ui.keyCode,d=this.headers.length,e=this.headers.index(b.target),f=!1;switch(b.keyCode){case c.RIGHT:case c.DOWN:f=this.headers[(e+1)%d];break;case c.LEFT:case c.UP:f=this.headers[(e-1+d)%d];break;case c.SPACE:case c.ENTER:this._clickHandler({target:b.target},b.target),b.preventDefault()}if(f){a(b.target).attr("tabIndex",-1),a(f).attr("tabIndex",0),f.focus();return!1}return!0}},resize:function(){var b=this.options,c;if(b.fillSpace){if(a.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}c=this.element.parent().height(),a.browser.msie&&this.element.parent().css("overflow",d),this.headers.each(function(){c-=a(this).outerHeight(!0)}),this.headers.next().each(function(){a(this).height(Math.max(0,c-a(this).innerHeight()+a(this).height()))}).css("overflow","auto")}else b.autoHeight&&(c=0,this.headers.next().each(function(){c=Math.max(c,a(this).height("").height())}).height(c));return this},activate:function(a){this.options.active=a;var b=this._findActive(a)[0];this._clickHandler({target:b},b);return this},_findActive:function(b){return b?typeof b=="number"?this.headers.filter(":eq("+b+")"):this.headers.not(this.headers.not(b)):b===!1?a([]):this.headers.filter(":eq(0)")},_clickHandler:function(b,c){var d=this.options;if(!d.disabled){if(!b.target){if(!d.collapsible)return;this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header),this.active.next().addClass("ui-accordion-content-active");var e=this.active.next(),f={options:d,newHeader:a([]),oldHeader:d.active,newContent:a([]),oldContent:e},g=this.active=a([]);this._toggle(g,e,f);return}var h=a(b.currentTarget||c),i=h[0]===this.active[0];d.active=d.collapsible&&i?!1:this.headers.index(h);if(this.running||!d.collapsible&&i)return;var j=this.active,g=h.next(),e=this.active.next(),f={options:d,newHeader:i&&d.collapsible?a([]):h,oldHeader:this.active,newContent:i&&d.collapsible?a([]):g,oldContent:e},k=this.headers.index(this.active[0])>this.headers.index(h[0]);this.active=i?a([]):h,this._toggle(g,e,f,i,k),j.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header),i||(h.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected),h.next().addClass("ui-accordion-content-active"));return}},_toggle:function(b,c,d,e,f){var g=this,h=g.options;g.toShow=b,g.toHide=c,g.data=d;var i=function(){if(!!g)return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data),g.running=c.size()===0?b.size():c.size();if(h.animated){var j={};h.collapsible&&e?j={toShow:a([]),toHide:c,complete:i,down:f,autoHeight:h.autoHeight||h.fillSpace}:j={toShow:b,toHide:c,complete:i,down:f,autoHeight:h.autoHeight||h.fillSpace},h.proxied||(h.proxied=h.animated),h.proxiedDuration||(h.proxiedDuration=h.duration),h.animated=a.isFunction(h.proxied)?h.proxied(j):h.proxied,h.duration=a.isFunction(h.proxiedDuration)?h.proxiedDuration(j):h.proxiedDuration;var k=a.ui.accordion.animations,l=h.duration,m=h.animated;m&&!k[m]&&!a.easing[m]&&(m="slide"),k[m]||(k[m]=function(a){this.slide(a,{easing:m,duration:l||700})}),k[m](j)}else h.collapsible&&e?b.toggle():(c.hide(),b.show()),i(!0);c.prev().attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).blur(),b.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;this.running||(this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""}),this.toHide.removeClass("ui-accordion-content-active"),this.toHide.length&&(this.toHide.parent()[0].className=this.toHide.parent()[0].className),this._trigger("change",null,this.data))}}),a.extend(a.ui.accordion,{version:"1.8.17",animations:{slide:function(b,c){b=a.extend({easing:"swing",duration:300},b,c);if(!b.toHide.size())b.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},b);else{if(!b.toShow.size()){b.toHide.animate({height:"hide",paddingTop:"hide",paddingBottom:"hide"},b);return}var d=b.toShow.css("overflow"),e=0,f={},g={},h=["height","paddingTop","paddingBottom"],i,j=b.toShow;i=j[0].style.width,j.width(j.parent().width()-parseFloat(j.css("paddingLeft"))-parseFloat(j.css("paddingRight"))-(parseFloat(j.css("borderLeftWidth"))||0)-(parseFloat(j.css("borderRightWidth"))||0)),a.each(h,function(c,d){g[d]="hide";var e=(""+a.css(b.toShow[0],d)).match(/^([\d+-.]+)(.*)$/);f[d]={value:e[1],unit:e[2]||"px"}}),b.toShow.css({height:0,overflow:"hidden"}).show(),b.toHide.filter(":hidden").each(b.complete).end().filter(":visible").animate(g,{step:function(a,c){c.prop=="height"&&(e=c.end-c.start===0?0:(c.now-c.start)/(c.end-c.start)),b.toShow[0].style[c.prop]=e*f[c.prop].value+f[c.prop].unit},duration:b.duration,easing:b.easing,complete:function(){b.autoHeight||b.toShow.css("height",""),b.toShow.css({width:i,overflow:d}),b.complete()}})}},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1e3:200})}}})})(jQuery);/* + * jQuery UI Autocomplete 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Autocomplete + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + * jquery.ui.position.js + */(function(a,b){var c=0;a.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var b=this,c=this.element[0].ownerDocument,d;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!b.options.disabled&&!b.element.propAttr("readOnly")){d=!1;var e=a.ui.keyCode;switch(c.keyCode){case e.PAGE_UP:b._move("previousPage",c);break;case e.PAGE_DOWN:b._move("nextPage",c);break;case e.UP:b._move("previous",c),c.preventDefault();break;case e.DOWN:b._move("next",c),c.preventDefault();break;case e.ENTER:case e.NUMPAD_ENTER:b.menu.active&&(d=!0,c.preventDefault());case e.TAB:if(!b.menu.active)return;b.menu.select(c);break;case e.ESCAPE:b.element.val(b.term),b.close(c);break;default:clearTimeout(b.searching),b.searching=setTimeout(function(){b.term!=b.element.val()&&(b.selectedItem=null,b.search(null,c))},b.options.delay)}}}).bind("keypress.autocomplete",function(a){d&&(d=!1,a.preventDefault())}).bind("focus.autocomplete",function(){b.options.disabled||(b.selectedItem=null,b.previous=b.element.val())}).bind("blur.autocomplete",function(a){b.options.disabled||(clearTimeout(b.searching),b.closing=setTimeout(function(){b.close(a),b._change(a)},150))}),this._initSource(),this.response=function(){return b._response.apply(b,arguments)},this.menu=a("
        ").addClass("ui-autocomplete").appendTo(a(this.options.appendTo||"body",c)[0]).mousedown(function(c){var d=b.menu.element[0];a(c.target).closest(".ui-menu-item").length||setTimeout(function(){a(document).one("mousedown",function(c){c.target!==b.element[0]&&c.target!==d&&!a.ui.contains(d,c.target)&&b.close()})},1),setTimeout(function(){clearTimeout(b.closing)},13)}).menu({focus:function(a,c){var d=c.item.data("item.autocomplete");!1!==b._trigger("focus",a,{item:d})&&/^key/.test(a.originalEvent.type)&&b.element.val(d.value)},selected:function(a,d){var e=d.item.data("item.autocomplete"),f=b.previous;b.element[0]!==c.activeElement&&(b.element.focus(),b.previous=f,setTimeout(function(){b.previous=f,b.selectedItem=e},1)),!1!==b._trigger("select",a,{item:e})&&b.element.val(e.value),b.term=b.element.val(),b.close(a),b.selectedItem=e},blur:function(a,c){b.menu.element.is(":visible")&&b.element.val()!==b.term&&b.element.val(b.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu"),a.fn.bgiframe&&this.menu.element.bgiframe(),b.beforeunloadHandler=function(){b.element.removeAttr("autocomplete")},a(window).bind("beforeunload",b.beforeunloadHandler)},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup"),this.menu.element.remove(),a(window).unbind("beforeunload",this.beforeunloadHandler),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b==="source"&&this._initSource(),b==="appendTo"&&this.menu.element.appendTo(a(c||"body",this.element[0].ownerDocument)[0]),b==="disabled"&&c&&this.xhr&&this.xhr.abort()},_initSource:function(){var b=this,d,e;a.isArray(this.options.source)?(d=this.options.source,this.source=function(b,c){c(a.ui.autocomplete.filter(d,b.term))}):typeof this.options.source=="string"?(e=this.options.source,this.source=function(d,f){b.xhr&&b.xhr.abort(),b.xhr=a.ajax({url:e,data:d,dataType:"json",autocompleteRequest:++c,success:function(a,b){this.autocompleteRequest===c&&f(a)},error:function(){this.autocompleteRequest===c&&f([])}})}):this.source=this.options.source},search:function(a,b){a=a!=null?a:this.element.val(),this.term=this.element.val();if(a.length").data("item.autocomplete",c).append(a("").text(c.label)).appendTo(b)},_move:function(a,b){if(!this.menu.element.is(":visible"))this.search(null,b);else{if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term),this.menu.deactivate();return}this.menu[a](b)}},widget:function(){return this.menu.element}}),a.extend(a.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")},filter:function(b,c){var d=new RegExp(a.ui.autocomplete.escapeRegex(c),"i");return a.grep(b,function(a){return d.test(a.label||a.value||a)})}})})(jQuery),function(a){a.widget("ui.menu",{_create:function(){var b=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(c){!a(c.target).closest(".ui-menu-item a").length||(c.preventDefault(),b.select(c))}),this.refresh()},refresh:function(){var b=this,c=this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem");c.children("a").addClass("ui-corner-all").attr("tabindex",-1).mouseenter(function(c){b.activate(c,a(this).parent())}).mouseleave(function(){b.deactivate()})},activate:function(a,b){this.deactivate();if(this.hasScroll()){var c=b.offset().top-this.element.offset().top,d=this.element.scrollTop(),e=this.element.height();c<0?this.element.scrollTop(d+c):c>=e&&this.element.scrollTop(d+c-e+b.height())}this.active=b.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end(),this._trigger("focus",a,{item:b})},deactivate:function(){!this.active||(this.active.children("a").removeClass("ui-state-hover").removeAttr("id"),this._trigger("blur"),this.active=null)},next:function(a){this.move("next",".ui-menu-item:first",a)},previous:function(a){this.move("prev",".ui-menu-item:last",a)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(a,b,c){if(!this.active)this.activate(c,this.element.children(b));else{var d=this.active[a+"All"](".ui-menu-item").eq(0);d.length?this.activate(c,d):this.activate(c,this.element.children(b))}},nextPage:function(b){if(this.hasScroll()){if(!this.active||this.last()){this.activate(b,this.element.children(".ui-menu-item:first"));return}var c=this.active.offset().top,d=this.element.height(),e=this.element.children(".ui-menu-item").filter(function(){var b=a(this).offset().top-c-d+a(this).height();return b<10&&b>-10});e.length||(e=this.element.children(".ui-menu-item:last")),this.activate(b,e)}else this.activate(b,this.element.children(".ui-menu-item").filter(!this.active||this.last()?":first":":last"))},previousPage:function(b){if(this.hasScroll()){if(!this.active||this.first()){this.activate(b,this.element.children(".ui-menu-item:last"));return}var c=this.active.offset().top,d=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var b=a(this).offset().top-c+d-a(this).height();return b<10&&b>-10}),result.length||(result=this.element.children(".ui-menu-item:first")),this.activate(b,result)}else this.activate(b,this.element.children(".ui-menu-item").filter(!this.active||this.first()?":last":":first"))},hasScroll:function(){return this.element.height()",this.element[0].ownerDocument).addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,e=d.primary&&d.secondary,f=[];d.primary||d.secondary?(this.options.text&&f.push("ui-button-text-icon"+(e?"s":d.primary?"-primary":"-secondary")),d.primary&&b.prepend(""),d.secondary&&b.append(""),this.options.text||(f.push(e?"ui-button-icons-only":"ui-button-icon-only"),this.hasTitle||b.attr("title",c))):f.push("ui-button-text-only"),b.addClass(f.join(" "))}}}),a.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c),a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var b=this.element.css("direction")==="rtl";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(b?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(b?"ui-corner-left":"ui-corner-right").end().end()},destroy:function(){this.element.removeClass("ui-buttonset"),this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy"),a.Widget.prototype.destroy.call(this)}})})(jQuery);/* + * jQuery UI Dialog 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Dialog + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + * jquery.ui.button.js + * jquery.ui.draggable.js + * jquery.ui.mouse.js + * jquery.ui.position.js + * jquery.ui.resizable.js + */(function(a,b){var c="ui-dialog ui-widget ui-widget-content ui-corner-all ",d={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},e={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0},f=a.attrFn||{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0,click:!0};a.widget("ui.dialog",{options:{autoOpen:!0,buttons:{},closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:!1,maxWidth:!1,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",collision:"fit",using:function(b){var c=a(this).css(b).offset().top;c<0&&a(this).css("top",b.top-c)}},resizable:!0,show:null,stack:!0,title:"",width:300,zIndex:1e3},_create:function(){this.originalTitle=this.element.attr("title"),typeof this.originalTitle!="string"&&(this.originalTitle=""),this.options.title=this.options.title||this.originalTitle;var b=this,d=b.options,e=d.title||" ",f=a.ui.dialog.getTitleId(b.element),g=(b.uiDialog=a("
        ")).appendTo(document.body).hide().addClass(c+d.dialogClass).css({zIndex:d.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(c){d.closeOnEscape&&!c.isDefaultPrevented()&&c.keyCode&&c.keyCode===a.ui.keyCode.ESCAPE&&(b.close(c),c.preventDefault())}).attr({role:"dialog","aria-labelledby":f}).mousedown(function(a){b.moveToTop(!1,a)}),h=b.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g),i=(b.uiDialogTitlebar=a("
        ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),j=a('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){j.addClass("ui-state-hover")},function(){j.removeClass("ui-state-hover")}).focus(function(){j.addClass("ui-state-focus")}).blur(function(){j.removeClass("ui-state-focus")}).click(function(a){b.close(a);return!1}).appendTo(i),k=(b.uiDialogTitlebarCloseText=a("")).addClass("ui-icon ui-icon-closethick").text(d.closeText).appendTo(j),l=a("").addClass("ui-dialog-title").attr("id",f).html(e).prependTo(i);a.isFunction(d.beforeclose)&&!a.isFunction(d.beforeClose)&&(d.beforeClose=d.beforeclose),i.find("*").add(i).disableSelection(),d.draggable&&a.fn.draggable&&b._makeDraggable(),d.resizable&&a.fn.resizable&&b._makeResizable(),b._createButtons(d.buttons),b._isOpen=!1,a.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy(),a.uiDialog.hide(),a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"),a.uiDialog.remove(),a.originalTitle&&a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(b){var c=this,d,e;if(!1!==c._trigger("beforeClose",b)){c.overlay&&c.overlay.destroy(),c.uiDialog.unbind("keypress.ui-dialog"),c._isOpen=!1,c.options.hide?c.uiDialog.hide(c.options.hide,function(){c._trigger("close",b)}):(c.uiDialog.hide(),c._trigger("close",b)),a.ui.dialog.overlay.resize(),c.options.modal&&(d=0,a(".ui-dialog").each(function(){this!==c.uiDialog[0]&&(e=a(this).css("z-index"),isNaN(e)||(d=Math.max(d,e)))}),a.ui.dialog.maxZ=d);return c}},isOpen:function(){return this._isOpen},moveToTop:function(b,c){var d=this,e=d.options,f;if(e.modal&&!b||!e.stack&&!e.modal)return d._trigger("focus",c);e.zIndex>a.ui.dialog.maxZ&&(a.ui.dialog.maxZ=e.zIndex),d.overlay&&(a.ui.dialog.maxZ+=1,d.overlay.$el.css("z-index",a.ui.dialog.overlay.maxZ=a.ui.dialog.maxZ)),f={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()},a.ui.dialog.maxZ+=1,d.uiDialog.css("z-index",a.ui.dialog.maxZ),d.element.attr(f),d._trigger("focus",c);return d},open:function(){if(!this._isOpen){var b=this,c=b.options,d=b.uiDialog;b.overlay=c.modal?new a.ui.dialog.overlay(b):null,b._size(),b._position(c.position),d.show(c.show),b.moveToTop(!0),c.modal&&d.bind("keydown.ui-dialog",function(b){if(b.keyCode===a.ui.keyCode.TAB){var c=a(":tabbable",this),d=c.filter(":first"),e=c.filter(":last");if(b.target===e[0]&&!b.shiftKey){d.focus(1);return!1}if(b.target===d[0]&&b.shiftKey){e.focus(1);return!1}}}),a(b.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus(),b._isOpen=!0,b._trigger("open");return b}},_createButtons:function(b){var c=this,d=!1,e=a("
        ").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=a("
        ").addClass("ui-dialog-buttonset").appendTo(e);c.uiDialog.find(".ui-dialog-buttonpane").remove(),typeof b=="object"&&b!==null&&a.each(b,function(){return!(d=!0)}),d&&(a.each(b,function(b,d){d=a.isFunction(d)?{click:d,text:b}:d;var e=a('').click(function(){d.click.apply(c.element[0],arguments)}).appendTo(g);a.each(d,function(a,b){a!=="click"&&(a in f?e[a](b):e.attr(a,b))}),a.fn.button&&e.button()}),e.appendTo(c.uiDialog))},_makeDraggable:function(){function f(a){return{position:a.position,offset:a.offset}}var b=this,c=b.options,d=a(document),e;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(d,g){e=c.height==="auto"?"auto":a(this).height(),a(this).height(a(this).height()).addClass("ui-dialog-dragging"),b._trigger("dragStart",d,f(g))},drag:function(a,c){b._trigger("drag",a,f(c))},stop:function(g,h){c.position=[h.position.left-d.scrollLeft(),h.position.top-d.scrollTop()],a(this).removeClass("ui-dialog-dragging").height(e),b._trigger("dragStop",g,f(h)),a.ui.dialog.overlay.resize()}})},_makeResizable:function(c){function h(a){return{originalPosition:a.originalPosition,originalSize:a.originalSize,position:a.position,size:a.size}}c=c===b?this.options.resizable:c;var d=this,e=d.options,f=d.uiDialog.css("position"),g=typeof c=="string"?c:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:g,start:function(b,c){a(this).addClass("ui-dialog-resizing"),d._trigger("resizeStart",b,h(c))},resize:function(a,b){d._trigger("resize",a,h(b))},stop:function(b,c){a(this).removeClass("ui-dialog-resizing"),e.height=a(this).height(),e.width=a(this).width(),d._trigger("resizeStop",b,h(c)),a.ui.dialog.overlay.resize()}}).css("position",f).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(b){var c=[],d=[0,0],e;if(b){if(typeof b=="string"||typeof b=="object"&&"0"in b)c=b.split?b.split(" "):[b[0],b[1]],c.length===1&&(c[1]=c[0]),a.each(["left","top"],function(a,b){+c[a]===c[a]&&(d[a]=c[a],c[a]=b)}),b={my:c.join(" "),at:c.join(" "),offset:d.join(" ")};b=a.extend({},a.ui.dialog.prototype.options.position,b)}else b=a.ui.dialog.prototype.options.position;e=this.uiDialog.is(":visible"),e||this.uiDialog.show(),this.uiDialog.css({top:0,left:0}).position(a.extend({of:window},b)),e||this.uiDialog.hide()},_setOptions:function(b){var c=this,f={},g=!1;a.each(b,function(a,b){c._setOption(a,b),a in d&&(g=!0),a in e&&(f[a]=b)}),g&&this._size(),this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",f)},_setOption:function(b,d){var e=this,f=e.uiDialog;switch(b){case"beforeclose":b="beforeClose";break;case"buttons":e._createButtons(d);break;case"closeText":e.uiDialogTitlebarCloseText.text(""+d);break;case"dialogClass":f.removeClass(e.options.dialogClass).addClass(c+d);break;case"disabled":d?f.addClass("ui-dialog-disabled"):f.removeClass("ui-dialog-disabled");break;case"draggable":var g=f.is(":data(draggable)");g&&!d&&f.draggable("destroy"),!g&&d&&e._makeDraggable();break;case"position":e._position(d);break;case"resizable":var h=f.is(":data(resizable)");h&&!d&&f.resizable("destroy"),h&&typeof d=="string"&&f.resizable("option","handles",d),!h&&d!==!1&&e._makeResizable(d);break;case"title":a(".ui-dialog-title",e.uiDialogTitlebar).html(""+(d||" "))}a.Widget.prototype._setOption.apply(e,arguments)},_size:function(){var b=this.options,c,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0}),b.minWidth>b.width&&(b.width=b.minWidth),c=this.uiDialog.css({height:"auto",width:b.width}).height(),d=Math.max(0,b.minHeight-c);if(b.height==="auto")if(a.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();var f=this.element.css("height","auto").height();e||this.uiDialog.hide(),this.element.height(Math.max(f,d))}else this.element.height(Math.max(b.height-c,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}}),a.extend(a.ui.dialog,{version:"1.8.17",uuid:0,maxZ:0,getTitleId:function(a){var b=a.attr("id");b||(this.uuid+=1,b=this.uuid);return"ui-dialog-title-"+b},overlay:function(b){this.$el=a.ui.dialog.overlay.create(b)}}),a.extend(a.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:a.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),create:function(b){this.instances.length===0&&(setTimeout(function(){a.ui.dialog.overlay.instances.length&&a(document).bind(a.ui.dialog.overlay.events,function(b){if(a(b.target).zIndex()").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});a.fn.bgiframe&&c.bgiframe(),this.instances.push(c);return c},destroy:function(b){var c=a.inArray(b,this.instances);c!=-1&&this.oldInstances.push(this.instances.splice(c,1)[0]),this.instances.length===0&&a([document,window]).unbind(".dialog-overlay"),b.remove();var d=0;a.each(this.instances,function(){d=Math.max(d,this.css("z-index"))}),this.maxZ=d},height:function(){var b,c;if(a.browser.msie&&a.browser.version<7){b=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight),c=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return b").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(d.range==="min"||d.range==="max"?" ui-slider-range-"+d.range:"")));for(var i=e.length;ic&&(f=c,g=a(this),i=b)}),c.range===!0&&this.values(1)===c.min&&(i+=1,g=a(this.handles[i])),j=this._start(b,i);if(j===!1)return!1;this._mouseSliding=!0,h._handleIndex=i,g.addClass("ui-state-active").focus(),k=g.offset(),l=!a(b.target).parents().andSelf().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:b.pageX-k.left-g.width()/2,top:b.pageY-k.top-g.height()/2-(parseInt(g.css("borderTopWidth"),10)||0)-(parseInt(g.css("borderBottomWidth"),10)||0)+(parseInt(g.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(b,i,e),this._animateOff=!0;return!0},_mouseStart:function(a){return!0},_mouseDrag:function(a){var b={x:a.pageX,y:a.pageY},c=this._normValueFromMouse(b);this._slide(a,this._handleIndex,c);return!1},_mouseStop:function(a){this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(a,this._handleIndex),this._change(a,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1;return!1},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b,c,d,e,f;this.orientation==="horizontal"?(b=this.elementSize.width,c=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(b=this.elementSize.height,c=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),d=c/b,d>1&&(d=1),d<0&&(d=0),this.orientation==="vertical"&&(d=1-d),e=this._valueMax()-this._valueMin(),f=this._valueMin()+d*e;return this._trimAlignValue(f)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values());return this._trigger("start",a,c)},_slide:function(a,b,c){var d,e,f;this.options.values&&this.options.values.length?(d=this.values(b?0:1),this.options.values.length===2&&this.options.range===!0&&(b===0&&c>d||b===1&&c1)this.options.values[b]=this._trimAlignValue(c),this._refreshValue(),this._change(null,b);else{if(!arguments.length)return this._values();if(!a.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(b):this.value();d=this.options.values,e=arguments[0];for(f=0;f=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b,d=a-c;Math.abs(c)*2>=b&&(d+=c>0?b:-b);return parseFloat(d.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var b=this.options.range,c=this.options,d=this,e=this._animateOff?!1:c.animate,f,g={},h,i,j,k;this.options.values&&this.options.values.length?this.handles.each(function(b,i){f=(d.values(b)-d._valueMin())/(d._valueMax()-d._valueMin())*100,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",a(this).stop(1,1)[e?"animate":"css"](g,c.animate),d.options.range===!0&&(d.orientation==="horizontal"?(b===0&&d.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({width:f-h+"%"},{queue:!1,duration:c.animate})):(b===0&&d.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({height:f-h+"%"},{queue:!1,duration:c.animate}))),h=f}):(i=this.value(),j=this._valueMin(),k=this._valueMax(),f=k!==j?(i-j)/(k-j)*100:0,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",this.handle.stop(1,1)[e?"animate":"css"](g,c.animate),b==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[e?"animate":"css"]({width:f+"%"},c.animate),b==="max"&&this.orientation==="horizontal"&&this.range[e?"animate":"css"]({width:100-f+"%"},{queue:!1,duration:c.animate}),b==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},c.animate),b==="max"&&this.orientation==="vertical"&&this.range[e?"animate":"css"]({height:100-f+"%"},{queue:!1,duration:c.animate}))}}),a.extend(a.ui.slider,{version:"1.8.17"})})(jQuery);/* + * jQuery UI Tabs 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Tabs + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + */(function(a,b){function f(){return++d}function e(){return++c}var c=0,d=0;a.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:!1,cookie:null,collapsible:!1,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"
        ",remove:null,select:null,show:null,spinner:"Loading…",tabTemplate:"
      • #{label}
      • "},_create:function(){this._tabify(!0)},_setOption:function(a,b){if(a=="selected"){if(this.options.collapsible&&b==this.options.selected)return;this.select(b)}else this.options[a]=b,this._tabify()},_tabId:function(a){return a.title&&a.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+e()},_sanitizeSelector:function(a){return a.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+f());return a.cookie.apply(null,[b].concat(a.makeArray(arguments)))},_ui:function(a,b){return{tab:a,panel:b,index:this.anchors.index(a)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=a(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(c){function m(b,c){b.css("display",""),!a.support.opacity&&c.opacity&&b[0].style.removeAttribute("filter")}var d=this,e=this.options,f=/^#.+/;this.list=this.element.find("ol,ul").eq(0),this.lis=a(" > li:has(a[href])",this.list),this.anchors=this.lis.map(function(){return a("a",this)[0]}),this.panels=a([]),this.anchors.each(function(b,c){var g=a(c).attr("href"),h=g.split("#")[0],i;h&&(h===location.toString().split("#")[0]||(i=a("base")[0])&&h===i.href)&&(g=c.hash,c.href=g);if(f.test(g))d.panels=d.panels.add(d.element.find(d._sanitizeSelector(g)));else if(g&&g!=="#"){a.data(c,"href.tabs",g),a.data(c,"load.tabs",g.replace(/#.*$/,""));var j=d._tabId(c);c.href="#"+j;var k=d.element.find("#"+j);k.length||(k=a(e.panelTemplate).attr("id",j).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(d.panels[b-1]||d.list),k.data("destroy.tabs",!0)),d.panels=d.panels.add(k)}else e.disabled.push(b)}),c?(this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"),this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.lis.addClass("ui-state-default ui-corner-top"),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom"),e.selected===b?(location.hash&&this.anchors.each(function(a,b){if(b.hash==location.hash){e.selected=a;return!1}}),typeof e.selected!="number"&&e.cookie&&(e.selected=parseInt(d._cookie(),10)),typeof e.selected!="number"&&this.lis.filter(".ui-tabs-selected").length&&(e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))),e.selected=e.selected||(this.lis.length?0:-1)):e.selected===null&&(e.selected=-1),e.selected=e.selected>=0&&this.anchors[e.selected]||e.selected<0?e.selected:0,e.disabled=a.unique(e.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(a,b){return d.lis.index(a)}))).sort(),a.inArray(e.selected,e.disabled)!=-1&&e.disabled.splice(a.inArray(e.selected,e.disabled),1),this.panels.addClass("ui-tabs-hide"),this.lis.removeClass("ui-tabs-selected ui-state-active"),e.selected>=0&&this.anchors.length&&(d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash)).removeClass("ui-tabs-hide"),this.lis.eq(e.selected).addClass("ui-tabs-selected ui-state-active"),d.element.queue("tabs",function(){d._trigger("show",null,d._ui(d.anchors[e.selected],d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash))[0]))}),this.load(e.selected)),a(window).bind("unload",function(){d.lis.add(d.anchors).unbind(".tabs"),d.lis=d.anchors=d.panels=null})):e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")),this.element[e.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible"),e.cookie&&this._cookie(e.selected,e.cookie);for(var g=0,h;h=this.lis[g];g++)a(h)[a.inArray(g,e.disabled)!=-1&&!a(h).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");e.cache===!1&&this.anchors.removeData("cache.tabs"),this.lis.add(this.anchors).unbind(".tabs");if(e.event!=="mouseover"){var i=function(a,b){b.is(":not(.ui-state-disabled)")&&b.addClass("ui-state-"+a)},j=function(a,b){b.removeClass("ui-state-"+a)};this.lis.bind("mouseover.tabs",function(){i("hover",a(this))}),this.lis.bind("mouseout.tabs",function(){j("hover",a(this))}),this.anchors.bind("focus.tabs",function(){i("focus",a(this).closest("li"))}),this.anchors.bind("blur.tabs",function(){j("focus",a(this).closest("li"))})}var k,l;e.fx&&(a.isArray(e.fx)?(k=e.fx[0],l=e.fx[1]):k=l=e.fx);var n=l?function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.hide().removeClass("ui-tabs-hide").animate(l,l.duration||"normal",function(){m(c,l),d._trigger("show",null,d._ui(b,c[0]))})}:function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.removeClass("ui-tabs-hide"),d._trigger("show",null,d._ui(b,c[0]))},o=k?function(a,b){b.animate(k,k.duration||"normal",function(){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),m(b,k),d.element.dequeue("tabs")})}:function(a,b,c){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),d.element.dequeue("tabs")};this.anchors.bind(e.event+".tabs",function(){var b=this,c=a(b).closest("li"),f=d.panels.filter(":not(.ui-tabs-hide)"),g=d.element.find(d._sanitizeSelector(b.hash));if(c.hasClass("ui-tabs-selected")&&!e.collapsible||c.hasClass("ui-state-disabled")||c.hasClass("ui-state-processing")||d.panels.filter(":animated").length||d._trigger("select",null,d._ui(this,g[0]))===!1){this.blur();return!1}e.selected=d.anchors.index(this),d.abort();if(e.collapsible){if(c.hasClass("ui-tabs-selected")){e.selected=-1,e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){o(b,f)}).dequeue("tabs"),this.blur();return!1}if(!f.length){e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this)),this.blur();return!1}}e.cookie&&d._cookie(e.selected,e.cookie);if(g.length)f.length&&d.element.queue("tabs",function(){o(b,f)}),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this));else throw"jQuery UI Tabs: Mismatching fragment identifier.";a.browser.msie&&this.blur()}),this.anchors.bind("click.tabs",function(){return!1})},_getIndex:function(a){typeof a=="string"&&(a=this.anchors.index(this.anchors.filter("[href$="+a+"]")));return a},destroy:function(){var b=this.options;this.abort(),this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs"),this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.anchors.each(function(){var b=a.data(this,"href.tabs");b&&(this.href=b);var c=a(this).unbind(".tabs");a.each(["href","load","cache"],function(a,b){c.removeData(b+".tabs")})}),this.lis.unbind(".tabs").add(this.panels).each(function(){a.data(this,"destroy.tabs")?a(this).remove():a(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}),b.cookie&&this._cookie(null,b.cookie);return this},add:function(c,d,e){e===b&&(e=this.anchors.length);var f=this,g=this.options,h=a(g.tabTemplate.replace(/#\{href\}/g,c).replace(/#\{label\}/g,d)),i=c.indexOf("#")?this._tabId(a("a",h)[0]):c.replace("#","");h.addClass("ui-state-default ui-corner-top").data("destroy.tabs",!0);var j=f.element.find("#"+i);j.length||(j=a(g.panelTemplate).attr("id",i).data("destroy.tabs",!0)),j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide"),e>=this.lis.length?(h.appendTo(this.list),j.appendTo(this.list[0].parentNode)):(h.insertBefore(this.lis[e]),j.insertBefore(this.panels[e])),g.disabled=a.map(g.disabled,function(a,b){return a>=e?++a:a}),this._tabify(),this.anchors.length==1&&(g.selected=0,h.addClass("ui-tabs-selected ui-state-active"),j.removeClass("ui-tabs-hide"),this.element.queue("tabs",function(){f._trigger("show",null,f._ui(f.anchors[0],f.panels[0]))}),this.load(0)),this._trigger("add",null,this._ui(this.anchors[e],this.panels[e]));return this},remove:function(b){b=this._getIndex(b);var c=this.options,d=this.lis.eq(b).remove(),e=this.panels.eq(b).remove();d.hasClass("ui-tabs-selected")&&this.anchors.length>1&&this.select(b+(b+1=b?--a:a}),this._tabify(),this._trigger("remove",null,this._ui(d.find("a")[0],e[0]));return this},enable:function(b){b=this._getIndex(b);var c=this.options;if(a.inArray(b,c.disabled)!=-1){this.lis.eq(b).removeClass("ui-state-disabled"),c.disabled=a.grep(c.disabled,function(a,c){return a!=b}),this._trigger("enable",null,this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(a){a=this._getIndex(a);var b=this,c=this.options;a!=c.selected&&(this.lis.eq(a).addClass("ui-state-disabled"),c.disabled.push(a),c.disabled.sort(),this._trigger("disable",null,this._ui(this.anchors[a],this.panels[a])));return this},select:function(a){a=this._getIndex(a);if(a==-1)if(this.options.collapsible&&this.options.selected!=-1)a=this.options.selected;else return this;this.anchors.eq(a).trigger(this.options.event+".tabs");return this},load:function(b){b=this._getIndex(b);var c=this,d=this.options,e=this.anchors.eq(b)[0],f=a.data(e,"load.tabs");this.abort();if(!f||this.element.queue("tabs").length!==0&&a.data(e,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(d.spinner){var g=a("span",e);g.data("label.tabs",g.html()).html(d.spinner)}this.xhr=a.ajax(a.extend({},d.ajaxOptions,{url:f,success:function(f,g){c.element.find(c._sanitizeSelector(e.hash)).html(f),c._cleanup(),d.cache&&a.data(e,"cache.tabs",!0),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.success(f,g)}catch(h){}},error:function(a,f,g){c._cleanup(),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.error(a,f,b,e)}catch(g){}}})),c.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]),this.panels.stop(!1,!0),this.element.queue("tabs",this.element.queue("tabs").splice(-2,2)),this.xhr&&(this.xhr.abort(),delete this.xhr),this._cleanup();return this},url:function(a,b){this.anchors.eq(a).removeData("cache.tabs").data("load.tabs",b);return this},length:function(){return this.anchors.length}}),a.extend(a.ui.tabs,{version:"1.8.17"}),a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(a,b){var c=this,d=this.options,e=c._rotate||(c._rotate=function(b){clearTimeout(c.rotation),c.rotation=setTimeout(function(){var a=d.selected;c.select(++a'))}$.extend($.ui,{datepicker:{version:"1.8.17"}});var PROP_NAME="datepicker",dpuuid=(new Date).getTime(),instActive;$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){extendRemove(this._defaults,a||{});return this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase(),inline=nodeName=="div"||nodeName=="span";target.id||(this.uuid+=1,target.id="dp"+this.uuid);var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{}),nodeName=="input"?this._connectDatepicker(target,inst):inline&&this._inlineDatepicker(target,inst)},_newInst:function(a,b){var c=a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1");return{id:c,input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:b?bindHover($('
        ')):this.dpDiv}},_connectDatepicker:function(a,b){var c=$(a);b.append=$([]),b.trigger=$([]);c.hasClass(this.markerClassName)||(this._attachments(c,b),c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),this._autoSize(b),$.data(a,PROP_NAME,b),b.settings.disabled&&this._disableDatepicker(a))},_attachments:function(a,b){var c=this._get(b,"appendText"),d=this._get(b,"isRTL");b.append&&b.append.remove(),c&&(b.append=$(''+c+""),a[d?"before":"after"](b.append)),a.unbind("focus",this._showDatepicker),b.trigger&&b.trigger.remove();var e=this._get(b,"showOn");(e=="focus"||e=="both")&&a.focus(this._showDatepicker);if(e=="button"||e=="both"){var f=this._get(b,"buttonText"),g=this._get(b,"buttonImage");b.trigger=$(this._get(b,"buttonImageOnly")?$("").addClass(this._triggerClass).attr({src:g,alt:f,title:f}):$('').addClass(this._triggerClass).html(g==""?f:$("").attr({src:g,alt:f,title:f}))),a[d?"before":"after"](b.trigger),b.trigger.click(function(){$.datepicker._datepickerShowing&&$.datepicker._lastInput==a[0]?$.datepicker._hideDatepicker():$.datepicker._showDatepicker(a[0]);return!1})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var d=function(a){var b=0,c=0;for(var d=0;db&&(b=a[d].length,c=d);return c};b.setMonth(d(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort"))),b.setDate(d(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=$(a);c.hasClass(this.markerClassName)||(c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),$.data(a,PROP_NAME,b),this._setDate(b,this._getDefaultDate(b),!0),this._updateDatepicker(b),this._updateAlternate(b),b.settings.disabled&&this._disableDatepicker(a),b.dpDiv.css("display","block"))},_dialogDatepicker:function(a,b,c,d,e){var f=this._dialogInst;if(!f){this.uuid+=1;var g="dp"+this.uuid;this._dialogInput=$(''),this._dialogInput.keydown(this._doKeyDown),$("body").append(this._dialogInput),f=this._dialogInst=this._newInst(this._dialogInput,!1),f.settings={},$.data(this._dialogInput[0],PROP_NAME,f)}extendRemove(f.settings,d||{}),b=b&&b.constructor==Date?this._formatDate(f,b):b,this._dialogInput.val(b),this._pos=e?e.length?e:[e.pageX,e.pageY]:null;if(!this._pos){var h=document.documentElement.clientWidth,i=document.documentElement.clientHeight,j=document.documentElement.scrollLeft||document.body.scrollLeft,k=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[h/2-100+j,i/2-150+k]}this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),f.settings.onSelect=c,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),$.blockUI&&$.blockUI(this.dpDiv),$.data(this._dialogInput[0],PROP_NAME,f);return this},_destroyDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!!b.hasClass(this.markerClassName)){var d=a.nodeName.toLowerCase();$.removeData(a,PROP_NAME),d=="input"?(c.append.remove(),c.trigger.remove(),b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):(d=="div"||d=="span")&&b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!!b.hasClass(this.markerClassName)){var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!1,c.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().removeClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b})}},_disableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!!b.hasClass(this.markerClassName)){var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!0,c.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().addClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b}),this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return!1;for(var b=0;b-1}},_doKeyUp:function(a){var b=$.datepicker._getInst(a.target);if(b.input.val()!=b.lastVal)try{var c=$.datepicker.parseDate($.datepicker._get(b,"dateFormat"),b.input?b.input.val():null,$.datepicker._getFormatConfig(b));c&&($.datepicker._setDateFromField(b),$.datepicker._updateAlternate(b),$.datepicker._updateDatepicker(b))}catch(a){$.datepicker.log(a)}return!0},_showDatepicker:function(a){a=a.target||a,a.nodeName.toLowerCase()!="input"&&(a=$("input",a.parentNode)[0]);if(!$.datepicker._isDisabledDatepicker(a)&&$.datepicker._lastInput!=a){var b=$.datepicker._getInst(a);$.datepicker._curInst&&$.datepicker._curInst!=b&&($.datepicker._curInst.dpDiv.stop(!0,!0),b&&$.datepicker._datepickerShowing&&$.datepicker._hideDatepicker($.datepicker._curInst.input[0]));var c=$.datepicker._get(b,"beforeShow"),d=c?c.apply(a,[a,b]):{};if(d===!1)return;extendRemove(b.settings,d),b.lastVal=null,$.datepicker._lastInput=a,$.datepicker._setDateFromField(b),$.datepicker._inDialog&&(a.value=""),$.datepicker._pos||($.datepicker._pos=$.datepicker._findPos(a),$.datepicker._pos[1]+=a.offsetHeight);var e=!1;$(a).parents().each(function(){e|=$(this).css("position")=="fixed";return!e}),e&&$.browser.opera&&($.datepicker._pos[0]-=document.documentElement.scrollLeft,$.datepicker._pos[1]-=document.documentElement.scrollTop);var f={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null,b.dpDiv.empty(),b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),$.datepicker._updateDatepicker(b),f=$.datepicker._checkOffset(b,f,e),b.dpDiv.css({position:$.datepicker._inDialog&&$.blockUI?"static":e?"fixed":"absolute",display:"none",left:f.left+"px",top:f.top+"px"});if(!b.inline){var g=$.datepicker._get(b,"showAnim"),h=$.datepicker._get(b,"duration"),i=function(){var a=b.dpDiv.find("iframe.ui-datepicker-cover");if(!!a.length){var c=$.datepicker._getBorders(b.dpDiv);a.css({left:-c[0],top:-c[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex($(a).zIndex()+1),$.datepicker._datepickerShowing=!0,$.effects&&$.effects[g]?b.dpDiv.show(g,$.datepicker._get(b,"showOptions"),h,i):b.dpDiv[g||"show"](g?h:null,i),(!g||!h)&&i(),b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus(),$.datepicker._curInst=b}}},_updateDatepicker:function(a){var b=this;b.maxRows=4;var c=$.datepicker._getBorders(a.dpDiv);instActive=a,a.dpDiv.empty().append(this._generateHTML(a));var d=a.dpDiv.find("iframe.ui-datepicker-cover");!d.length||d.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}),a.dpDiv.find("."+this._dayOverClass+" a").mouseover();var e=this._getNumberOfMonths(a),f=e[1],g=17;a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),f>1&&a.dpDiv.addClass("ui-datepicker-multi-"+f).css("width",g*f+"em"),a.dpDiv[(e[0]!=1||e[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi"),a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),a==$.datepicker._curInst&&$.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var h=a.yearshtml;setTimeout(function(){h===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml),h=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(a){return{thin:1,medium:2,thick:3}[a]||a};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var d=a.dpDiv.outerWidth(),e=a.dpDiv.outerHeight(),f=a.input?a.input.outerWidth():0,g=a.input?a.input.outerHeight():0,h=document.documentElement.clientWidth+$(document).scrollLeft(),i=document.documentElement.clientHeight+$(document).scrollTop();b.left-=this._get(a,"isRTL")?d-f:0,b.left-=c&&b.left==a.input.offset().left?$(document).scrollLeft():0,b.top-=c&&b.top==a.input.offset().top+g?$(document).scrollTop():0,b.left-=Math.min(b.left,b.left+d>h&&h>d?Math.abs(b.left+d-h):0),b.top-=Math.min(b.top,b.top+e>i&&i>e?Math.abs(e+g):0);return b},_findPos:function(a){var b=this._getInst(a),c=this._get(b,"isRTL");while(a&&(a.type=="hidden"||a.nodeType!=1||$.expr.filters.hidden(a)))a=a[c?"previousSibling":"nextSibling"];var d=$(a).offset();return[d.left,d.top]},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=$.data(a,PROP_NAME))&&this._datepickerShowing){var c=this._get(b,"showAnim"),d=this._get(b,"duration"),e=this,f=function(){$.datepicker._tidyDialog(b),e._curInst=null};$.effects&&$.effects[c]?b.dpDiv.hide(c,$.datepicker._get(b,"showOptions"),d,f):b.dpDiv[c=="slideDown"?"slideUp":c=="fadeIn"?"fadeOut":"hide"](c?d:null,f),c||f(),this._datepickerShowing=!1;var g=this._get(b,"onClose");g&&g.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),$.blockUI&&($.unblockUI(),$("body").append(this.dpDiv))),this._inDialog=!1}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(!!$.datepicker._curInst){var b=$(a.target),c=$.datepicker._getInst(b[0]);(b[0].id!=$.datepicker._mainDivId&&b.parents("#"+$.datepicker._mainDivId).length==0&&!b.hasClass($.datepicker.markerClassName)&&!b.hasClass($.datepicker._triggerClass)&&$.datepicker._datepickerShowing&&(!$.datepicker._inDialog||!$.blockUI)||b.hasClass($.datepicker.markerClassName)&&$.datepicker._curInst!=c)&&$.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){var d=$(a),e=this._getInst(d[0]);this._isDisabledDatepicker(d[0])||(this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c),this._updateDatepicker(e))},_gotoToday:function(a){var b=$(a),c=this._getInst(b[0]);if(this._get(c,"gotoCurrent")&&c.currentDay)c.selectedDay=c.currentDay,c.drawMonth=c.selectedMonth=c.currentMonth,c.drawYear=c.selectedYear=c.currentYear;else{var d=new Date;c.selectedDay=d.getDate(),c.drawMonth=c.selectedMonth=d.getMonth(),c.drawYear=c.selectedYear=d.getFullYear()}this._notifyChange(c),this._adjustDate(b)},_selectMonthYear:function(a,b,c){var d=$(a),e=this._getInst(d[0]);e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10),this._notifyChange(e),this._adjustDate(d)},_selectDay:function(a,b,c,d){var e=$(a);if(!$(d).hasClass(this._unselectableClass)&&!this._isDisabledDatepicker(e[0])){var f=this._getInst(e[0]);f.selectedDay=f.currentDay=$("a",d).html(),f.selectedMonth=f.currentMonth=b,f.selectedYear=f.currentYear=c,this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){var b=$(a),c=this._getInst(b[0]);this._selectDate(b,"")},_selectDate:function(a,b){var c=$(a),d=this._getInst(c[0]);b=b!=null?b:this._formatDate(d),d.input&&d.input.val(b),this._updateAlternate(d);var e=this._get(d,"onSelect");e?e.apply(d.input?d.input[0]:null,[b,d]):d.input&&d.input.trigger("change"),d.inline?this._updateDatepicker(d):(this._hideDatepicker(),this._lastInput=d.input[0],typeof d.input[0]!="object"&&d.input.focus(),this._lastInput=null)},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),d=this._getDate(a),e=this.formatDate(c,d,this._getFormatConfig(a));$(b).each(function(){$(this).val(e)})}},noWeekends:function(a){var b=a.getDay();return[b>0&&b<6,""]},iso8601Week:function(a){var b=new Date(a.getTime());b.setDate(b.getDate()+4-(b.getDay()||7));var c=b.getTime();b.setMonth(0),b.setDate(1);return Math.floor(Math.round((c-b)/864e5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;var d=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;d=typeof d!="string"?d:(new Date).getFullYear()%100+parseInt(d,10);var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,g=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,h=(c?c.monthNames:null)||this._defaults.monthNames,i=-1,j=-1,k=-1,l=-1,m=!1,n=function(b){var c=s+1-1){j=1,k=l;for(;;){var u=this._getDaysInMonth(i,j-1);if(k<=u)break;j++,k-=u}}var t=this._daylightSavingAdjust(new Date(i,j-1,k));if(t.getFullYear()!=i||t.getMonth()+1!=j||t.getDate()!=k)throw"Invalid date";return t},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1e7,formatDate:function(a,b,c){if(!b)return"";var d=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,e=(c?c.dayNames:null)||this._defaults.dayNames,f=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,h=function(b){var c=m+112?a.getHours()+2:0);return a},_setDate:function(a,b,c){var d=!b,e=a.selectedMonth,f=a.selectedYear,g=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=g.getDate(),a.drawMonth=a.selectedMonth=a.currentMonth=g.getMonth(),a.drawYear=a.selectedYear=a.currentYear=g.getFullYear(),(e!=a.selectedMonth||f!=a.selectedYear)&&!c&&this._notifyChange(a),this._adjustInstDate(a),a.input&&a.input.val(d?"":this._formatDate(a))},_getDate:function(a){var b=!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return b},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),d=this._get(a,"showButtonPanel"),e=this._get(a,"hideIfNoPrevNext"),f=this._get(a,"navigationAsDateFormat"),g=this._getNumberOfMonths(a),h=this._get(a,"showCurrentAtPos"),i=this._get(a,"stepMonths"),j=g[0]!=1||g[1]!=1,k=this._daylightSavingAdjust(a.currentDay?new Date(a.currentYear,a.currentMonth,a.currentDay):new Date(9999,9,9)),l=this._getMinMaxDate(a,"min"),m=this._getMinMaxDate(a,"max"),n=a.drawMonth-h,o=a.drawYear;n<0&&(n+=12,o--);if(m){var p=this._daylightSavingAdjust(new Date(m.getFullYear(),m.getMonth()-g[0]*g[1]+1,m.getDate()));p=l&&pp)n--,n<0&&(n=11,o--)}a.drawMonth=n,a.drawYear=o;var q=this._get(a,"prevText");q=f?this.formatDate(q,this._daylightSavingAdjust(new Date(o,n-i,1)),this._getFormatConfig(a)):q;var r=this._canAdjustMonth(a,-1,o,n)?''+q+"":e?"":''+q+"",s=this._get(a,"nextText");s=f?this.formatDate(s,this._daylightSavingAdjust(new Date(o,n+i,1)),this._getFormatConfig(a)):s;var t=this._canAdjustMonth(a,1,o,n)?''+s+"":e?"":''+s+"",u=this._get(a,"currentText"),v=this._get(a,"gotoCurrent")&&a.currentDay?k:b;u=f?this.formatDate(u,v,this._getFormatConfig(a)):u;var w=a.inline?"":'",x=d?'
        '+(c?w:"")+(this._isInRange(a,v)?'":"")+(c?"":w)+"
        ":"",y=parseInt(this._get(a,"firstDay"),10);y=isNaN(y)?0:y;var z=this._get(a,"showWeek"),A=this._get(a,"dayNames"),B=this._get(a,"dayNamesShort"),C=this._get(a,"dayNamesMin"),D=this._get(a,"monthNames"),E=this._get(a,"monthNamesShort"),F=this._get(a,"beforeShowDay"),G=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths"),I=this._get(a,"calculateWeek")||this.iso8601Week,J=this._getDefaultDate(a),K="";for(var L=0;L1)switch(N){case 0:Q+=" ui-datepicker-group-first",P=" ui-corner-"+(c?"right":"left");break;case g[1]-1:Q+=" ui-datepicker-group-last",P=" ui-corner-"+(c?"left":"right");break;default:Q+=" ui-datepicker-group-middle",P=""}Q+='">'}Q+='
        '+(/all|left/.test(P)&&L==0?c?t:r:"")+(/all|right/.test(P)&&L==0?c?r:t:"")+this._generateMonthYearHeader(a,n,o,l,m,L>0||N>0,D,E)+'
        '+"";var R=z?'":"";for(var S=0;S<7;S++){var T=(S+y)%7;R+="=5?' class="ui-datepicker-week-end"':"")+">"+''+C[T]+""}Q+=R+"";var U=this._getDaysInMonth(o,n);o==a.selectedYear&&n==a.selectedMonth&&(a.selectedDay=Math.min(a.selectedDay,U));var V=(this._getFirstDayOfMonth(o,n)-y+7)%7,W=Math.ceil((V+U)/7),X=j?this.maxRows>W?this.maxRows:W:W;this.maxRows=X;var Y=this._daylightSavingAdjust(new Date(o,n,1-V));for(var Z=0;Z";var _=z?'":"";for(var S=0;S<7;S++){var ba=F?F.apply(a.input?a.input[0]:null,[Y]):[!0,""],bb=Y.getMonth()!=n,bc=bb&&!H||!ba[0]||l&&Ym;_+='",Y.setDate(Y.getDate()+1),Y=this._daylightSavingAdjust(Y)}Q+=_+""}n++,n>11&&(n=0,o++),Q+="
        '+this._get(a,"weekHeader")+"
        '+this._get(a,"calculateWeek")(Y)+""+(bb&&!G?" ":bc?''+Y.getDate()+"":''+Y.getDate()+"")+"
        "+(j?""+(g[0]>0&&N==g[1]-1?'
        ':""):""),M+=Q}K+=M}K+=x+($.browser.msie&&parseInt($.browser.version,10)<7&&!a.inline?'':""),a._keyEvent=!1;return K},_generateMonthYearHeader:function(a,b,c,d,e,f,g,h){var i=this._get(a,"changeMonth"),j=this._get(a,"changeYear"),k=this +._get(a,"showMonthAfterYear"),l='
        ',m="";if(f||!i)m+=''+g[b]+"";else{var n=d&&d.getFullYear()==c,o=e&&e.getFullYear()==c;m+='"}k||(l+=m+(f||!i||!j?" ":""));if(!a.yearshtml){a.yearshtml="";if(f||!j)l+=''+c+"";else{var q=this._get(a,"yearRange").split(":"),r=(new Date).getFullYear(),s=function(a){var b=a.match(/c[+-].*/)?c+parseInt(a.substring(1),10):a.match(/[+-].*/)?r+parseInt(a,10):parseInt(a,10);return isNaN(b)?r:b},t=s(q[0]),u=Math.max(t,s(q[1]||""));t=d?Math.max(t,d.getFullYear()):t,u=e?Math.min(u,e.getFullYear()):u,a.yearshtml+='",l+=a.yearshtml,a.yearshtml=null}}l+=this._get(a,"yearSuffix"),k&&(l+=(f||!i||!j?" ":"")+m),l+="
        ";return l},_adjustInstDate:function(a,b,c){var d=a.drawYear+(c=="Y"?b:0),e=a.drawMonth+(c=="M"?b:0),f=Math.min(a.selectedDay,this._getDaysInMonth(d,e))+(c=="D"?b:0),g=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(d,e,f)));a.selectedDay=g.getDate(),a.drawMonth=a.selectedMonth=g.getMonth(),a.drawYear=a.selectedYear=g.getFullYear(),(c=="M"||c=="Y")&&this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max"),e=c&&bd?d:e;return e},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");b&&b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){var b=this._get(a,"numberOfMonths");return b==null?[1,1]:typeof b=="number"?[1,b]:b},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,d){var e=this._getNumberOfMonths(a),f=this._daylightSavingAdjust(new Date(c,d+(b<0?b:e[0]*e[1]),1));b<0&&f.setDate(this._getDaysInMonth(f.getFullYear(),f.getMonth()));return this._isInRange(a,f)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!d||b.getTime()<=d.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,d){b||(a.currentDay=a.selectedDay,a.currentMonth=a.selectedMonth,a.currentYear=a.selectedYear);var e=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(d,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),e,this._getFormatConfig(a))}}),$.fn.datepicker=function(a){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv),$.datepicker.initialized=!0);var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return $.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return $.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b));return this.each(function(){typeof a=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this].concat(b)):$.datepicker._attachDatepicker(this,a)})},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="1.8.17",window["DP_jQuery_"+dpuuid]=$})(jQuery);/* + * jQuery UI Progressbar 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Progressbar + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + */(function(a,b){a.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()}),this.valueDiv=a("
        ").appendTo(this.element),this.oldValue=this._value(),this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove(),a.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===b)return this._value();this._setOption("value",a);return this},_setOption:function(b,c){b==="value"&&(this.options.value=c,this._refreshValue(),this._value()===this.options.max&&this._trigger("complete")),a.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;typeof a!="number"&&(a=0);return Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100*this._value()/this.options.max},_refreshValue:function(){var a=this.value(),b=this._percentage();this.oldValue!==a&&(this.oldValue=a,this._trigger("change")),this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(b.toFixed(0)+"%"),this.element.attr("aria-valuenow",a)}}),a.extend(a.ui.progressbar,{version:"1.8.17"})})(jQuery);/* + * jQuery UI Effects 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Effects/ + */jQuery.effects||function(a,b){function l(b){if(!b||typeof b=="number"||a.fx.speeds[b])return!0;if(typeof b=="string"&&!a.effects[b])return!0;return!1}function k(b,c,d,e){typeof b=="object"&&(e=c,d=null,c=b,b=c.effect),a.isFunction(c)&&(e=c,d=null,c={});if(typeof c=="number"||a.fx.speeds[c])e=d,d=c,c={};a.isFunction(d)&&(e=d,d=null),c=c||{},d=d||c.duration,d=a.fx.off?0:typeof d=="number"?d:d in a.fx.speeds?a.fx.speeds[d]:a.fx.speeds._default,e=e||c.complete;return[b,c,d,e]}function j(a,b){var c={_:0},d;for(d in b)a[d]!=b[d]&&(c[d]=b[d]);return c}function i(b){var c,d;for(c in b)d=b[c],(d==null||a.isFunction(d)||c in g||/scrollbar/.test(c)||!/color/i.test(c)&&isNaN(parseFloat(d)))&&delete b[c];return b}function h(){var a=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,b={},c,d;if(a&&a.length&&a[0]&&a[a[0]]){var e=a.length;while(e--)c=a[e],typeof a[c]=="string"&&(d=c.replace(/\-(\w)/g,function(a,b){return b.toUpperCase()}),b[d]=a[c])}else for(c in a)typeof a[c]=="string"&&(b[c]=a[c]);return b}function d(b,d){var e;do{e=a.curCSS(b,d);if(e!=""&&e!="transparent"||a.nodeName(b,"body"))break;d="backgroundColor"}while(b=b.parentNode);return c(e)}function c(b){var c;if(b&&b.constructor==Array&&b.length==3)return b;if(c=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(b))return[parseInt(c[1],10),parseInt(c[2],10),parseInt(c[3],10)];if(c=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(b))return[parseFloat(c[1])*2.55,parseFloat(c[2])*2.55,parseFloat(c[3])*2.55];if(c=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(b))return[parseInt(c[1],16),parseInt(c[2],16),parseInt(c[3],16)];if(c=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(b))return[parseInt(c[1]+c[1],16),parseInt(c[2]+c[2],16),parseInt(c[3]+c[3],16)];if(c=/rgba\(0, 0, 0, 0\)/.exec(b))return e.transparent;return e[a.trim(b).toLowerCase()]}a.effects={},a.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","borderColor","color","outlineColor"],function(b,e){a.fx.step[e]=function(a){a.colorInit||(a.start=d(a.elem,e),a.end=c(a.end),a.colorInit=!0),a.elem.style[e]="rgb("+Math.max(Math.min(parseInt(a.pos*(a.end[0]-a.start[0])+a.start[0],10),255),0)+","+Math.max(Math.min(parseInt(a.pos*(a.end[1]-a.start[1])+a.start[1],10),255),0)+","+Math.max(Math.min(parseInt(a.pos*(a.end[2]-a.start[2])+a.start[2],10),255),0)+")"}});var e={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},f=["add","remove","toggle"],g={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};a.effects.animateClass=function(b,c,d,e){a.isFunction(d)&&(e=d,d=null);return this.queue(function(){var g=a(this),k=g.attr("style")||" ",l=i(h.call(this)),m,n=g.attr("class");a.each(f,function(a,c){b[c]&&g[c+"Class"](b[c])}),m=i(h.call(this)),g.attr("class",n),g.animate(j(l,m),{queue:!1,duration:c,easing:d,complete:function(){a.each(f,function(a,c){b[c]&&g[c+"Class"](b[c])}),typeof g.attr("style")=="object"?(g.attr("style").cssText="",g.attr("style").cssText=k):g.attr("style",k),e&&e.apply(this,arguments),a.dequeue(this)}})})},a.fn.extend({_addClass:a.fn.addClass,addClass:function(b,c,d,e){return c?a.effects.animateClass.apply(this,[{add:b},c,d,e]):this._addClass(b)},_removeClass:a.fn.removeClass,removeClass:function(b,c,d,e){return c?a.effects.animateClass.apply(this,[{remove:b},c,d,e]):this._removeClass(b)},_toggleClass:a.fn.toggleClass,toggleClass:function(c,d,e,f,g){return typeof d=="boolean"||d===b?e?a.effects.animateClass.apply(this,[d?{add:c}:{remove:c},e,f,g]):this._toggleClass(c,d):a.effects.animateClass.apply(this,[{toggle:c},d,e,f])},switchClass:function(b,c,d,e,f){return a.effects.animateClass.apply(this,[{add:c,remove:b},d,e,f])}}),a.extend(a.effects,{version:"1.8.17",save:function(a,b){for(var c=0;c").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),e=document.activeElement;b.wrap(d),(b[0]===e||a.contains(b[0],e))&&a(e).focus(),d=b.parent(),b.css("position")=="static"?(d.css({position:"relative"}),b.css({position:"relative"})):(a.extend(c,{position:b.css("position"),zIndex:b.css("z-index")}),a.each(["top","left","bottom","right"],function(a,d){c[d]=b.css(d),isNaN(parseInt(c[d],10))&&(c[d]="auto")}),b.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"}));return d.css(c).show()},removeWrapper:function(b){var c,d=document.activeElement;if(b.parent().is(".ui-effects-wrapper")){c=b.parent().replaceWith(b),(b[0]===d||a.contains(b[0],d))&&a(d).focus();return c}return b},setTransition:function(b,c,d,e){e=e||{},a.each(c,function(a,c){unit=b.cssUnit(c),unit[0]>0&&(e[c]=unit[0]*d+unit[1])});return e}}),a.fn.extend({effect:function(b,c,d,e){var f=k.apply(this,arguments),g={options:f[1],duration:f[2],callback:f[3]},h=g.options.mode,i=a.effects[b];if(a.fx.off||!i)return h?this[h](g.duration,g.callback):this.each(function(){g.callback&&g.callback.call(this)});return i.call(this,g)},_show:a.fn.show,show:function(a){if(l(a))return this._show.apply(this,arguments);var b=k.apply(this,arguments);b[1].mode="show";return this.effect.apply(this,b)},_hide:a.fn.hide,hide:function(a){if(l(a))return this._hide.apply(this,arguments);var b=k.apply(this,arguments);b[1].mode="hide";return this.effect.apply(this,b)},__toggle:a.fn.toggle,toggle:function(b){if(l(b)||typeof b=="boolean"||a.isFunction(b))return this.__toggle.apply(this,arguments);var c=k.apply(this,arguments);c[1].mode="toggle";return this.effect.apply(this,c)},cssUnit:function(b){var c=this.css(b),d=[];a.each(["em","px","%","pt"],function(a,b){c.indexOf(b)>0&&(d=[parseFloat(c),b])});return d}}),a.easing.jswing=a.easing.swing,a.extend(a.easing,{def:"easeOutQuad",swing:function(b,c,d,e,f){return a.easing[a.easing.def](b,c,d,e,f)},easeInQuad:function(a,b,c,d,e){return d*(b/=e)*b+c},easeOutQuad:function(a,b,c,d,e){return-d*(b/=e)*(b-2)+c},easeInOutQuad:function(a,b,c,d,e){if((b/=e/2)<1)return d/2*b*b+c;return-d/2*(--b*(b-2)-1)+c},easeInCubic:function(a,b,c,d,e){return d*(b/=e)*b*b+c},easeOutCubic:function(a,b,c,d,e){return d*((b=b/e-1)*b*b+1)+c},easeInOutCubic:function(a,b,c,d,e){if((b/=e/2)<1)return d/2*b*b*b+c;return d/2*((b-=2)*b*b+2)+c},easeInQuart:function(a,b,c,d,e){return d*(b/=e)*b*b*b+c},easeOutQuart:function(a,b,c,d,e){return-d*((b=b/e-1)*b*b*b-1)+c},easeInOutQuart:function(a,b,c,d,e){if((b/=e/2)<1)return d/2*b*b*b*b+c;return-d/2*((b-=2)*b*b*b-2)+c},easeInQuint:function(a,b,c,d,e){return d*(b/=e)*b*b*b*b+c},easeOutQuint:function(a,b,c,d,e){return d*((b=b/e-1)*b*b*b*b+1)+c},easeInOutQuint:function(a,b,c,d,e){if((b/=e/2)<1)return d/2*b*b*b*b*b+c;return d/2*((b-=2)*b*b*b*b+2)+c},easeInSine:function(a,b,c,d,e){return-d*Math.cos(b/e*(Math.PI/2))+d+c},easeOutSine:function(a,b,c,d,e){return d*Math.sin(b/e*(Math.PI/2))+c},easeInOutSine:function(a,b,c,d,e){return-d/2*(Math.cos(Math.PI*b/e)-1)+c},easeInExpo:function(a,b,c,d,e){return b==0?c:d*Math.pow(2,10*(b/e-1))+c},easeOutExpo:function(a,b,c,d,e){return b==e?c+d:d*(-Math.pow(2,-10*b/e)+1)+c},easeInOutExpo:function(a,b,c,d,e){if(b==0)return c;if(b==e)return c+d;if((b/=e/2)<1)return d/2*Math.pow(2,10*(b-1))+c;return d/2*(-Math.pow(2,-10*--b)+2)+c},easeInCirc:function(a,b,c,d,e){return-d*(Math.sqrt(1-(b/=e)*b)-1)+c},easeOutCirc:function(a,b,c,d,e){return d*Math.sqrt(1-(b=b/e-1)*b)+c},easeInOutCirc:function(a,b,c,d,e){if((b/=e/2)<1)return-d/2*(Math.sqrt(1-b*b)-1)+c;return d/2*(Math.sqrt(1-(b-=2)*b)+1)+c},easeInElastic:function(a,b,c,d,e){var f=1.70158,g=0,h=d;if(b==0)return c;if((b/=e)==1)return c+d;g||(g=e*.3);if(h").css({position:"absolute",visibility:"visible",left:-j*(g/d),top:-i*(h/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:g/d,height:h/c,left:f.left+j*(g/d)+(b.options.mode=="show"?(j-Math.floor(d/2))*(g/d):0),top:f.top+i*(h/c)+(b.options.mode=="show"?(i-Math.floor(c/2))*(h/c):0),opacity:b.options.mode=="show"?0:1}).animate({left:f.left+j*(g/d)+(b.options.mode=="show"?0:(j-Math.floor(d/2))*(g/d)),top:f.top+i*(h/c)+(b.options.mode=="show"?0:(i-Math.floor(c/2))*(h/c)),opacity:b.options.mode=="show"?1:0},b.duration||500);setTimeout(function(){b.options.mode=="show"?e.css({visibility:"visible"}):e.css({visibility:"visible"}).hide(),b.callback&&b.callback.apply(e[0]),e.dequeue(),a("div.ui-effects-explode").remove()},b.duration||500)})}})(jQuery);/* + * jQuery UI Effects Fade 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Effects/Fade + * + * Depends: + * jquery.effects.core.js + */(function(a,b){a.effects.fade=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"hide");c.animate({opacity:d},{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);/* + * jQuery UI Effects Fold 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Effects/Fold + * + * Depends: + * jquery.effects.core.js + */(function(a,b){a.effects.fold=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.size||15,g=!!b.options.horizFirst,h=b.duration?b.duration/2:a.fx.speeds._default/2;a.effects.save(c,d),c.show();var i=a.effects.createWrapper(c).css({overflow:"hidden"}),j=e=="show"!=g,k=j?["width","height"]:["height","width"],l=j?[i.width(),i.height()]:[i.height(),i.width()],m=/([0-9]+)%/.exec(f);m&&(f=parseInt(m[1],10)/100*l[e=="hide"?0:1]),e=="show"&&i.css(g?{height:0,width:f}:{height:f,width:0});var n={},p={};n[k[0]]=e=="show"?l[0]:f,p[k[1]]=e=="show"?l[1]:0,i.animate(n,h,b.options.easing).animate(p,h,b.options.easing,function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery);/* + * jQuery UI Effects Highlight 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Effects/Highlight + * + * Depends: + * jquery.effects.core.js + */(function(a,b){a.effects.highlight=function(b){return this.queue(function(){var c=a(this),d=["backgroundImage","backgroundColor","opacity"],e=a.effects.setMode(c,b.options.mode||"show"),f={backgroundColor:c.css("backgroundColor")};e=="hide"&&(f.opacity=0),a.effects.save(c,d),c.show().css({backgroundImage:"none",backgroundColor:b.options.color||"#ffff99"}).animate(f,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),e=="show"&&!a.support.opacity&&this.style.removeAttribute("filter"),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery);/* + * jQuery UI Effects Pulsate 1.8.17 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Effects/Pulsate + * + * Depends: + * jquery.effects.core.js + */(function(a,b){a.effects.pulsate=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"show");times=(b.options.times||5)*2-1,duration=b.duration?b.duration/2:a.fx.speeds._default/2,isVisible=c.is(":visible"),animateTo=0,isVisible||(c.css("opacity",0).show(),animateTo=1),(d=="hide"&&isVisible||d=="show"&&!isVisible)&×--;for(var e=0;e').appendTo(document.body).addClass(b.options.className).css({top:g.top,left:g.left,height:c.innerHeight(),width:c.innerWidth(),position:"absolute"}).animate(f,b.duration,b.options.easing,function(){h.remove(),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery); \ No newline at end of file diff --git a/public/stylesheets/images/ui-bg_gloss-wave_45_817865_500x100.png b/public/stylesheets/images/ui-bg_gloss-wave_45_817865_500x100.png index ccca7309240ddbea3e46db9593c595572c80d016..7662917a5dc5b2e54b324b49119bd4cccb72578b 100644 GIT binary patch literal 3971 zcmcInYgm%$x~68TS<`81raWa%p|u<|M@cPFoEa@oV~*NDf`?WZ2#98=DW00u8nsjy z%R^+sn(&Yz5+R}q+RQe|6p2(&JhenL!$X9KiqNK+`LXx4fA2rv``p*{zTb0w_xn8e zbAQ)=I1{k*Q|nIw0Km?mK>r8;VAHZWj{jt<`FTn7dkz4wJ2=Sy+p`&W7pjpIAY|X^ zg;ZnuFB#kZ_P4IQk7?)kYQK&w!09_4M+Ye|&e-EYLmk-@9S-GhYD`LY9&U^IH68AJ z_;&MpRr~PQj{pECfQ=Ub@MQDc1imW8V% z5g3&hzk^JUR7azC7A670>4o(Aa3E5`waGYc3PjphML~f%Z$>V@^C3p^`yI%{9$Nt5 z{HEa-n*f0Q=kbwjyUk{bL9cB8FVl&&ya=3e?R(PLW67{y3o)#X%WgQV={jf&;ePaX z%F(&f>(2kPSb3n44%bTmDS4+s}>h{j}uVcxFR%j&Q4eU zP~oI1oyqq&!aG?%H2wzcSWr+mgoHPz2d=X?|9DzP#-}{87Opv|tff}h*{so0S4Op5 zRvXJu5&M39TBg{Gg~#uHEBiQfHk<+rbFAn4W*TnSjE}(iF5mG)GLBO7y^~lzddZ-b zX`jv5N~fO|9i$}aaM(Q@?wbR1ory?bj$O|`hAuWcGuG~P>;<~hhR(RerjG@nFru*L zTnE7T#b>^)r!wcT@ZBpz}M=c~N-zSNRs zm@Kk5Ss^XelsEU!?{-e|p#M0~SXU^ab`*6VY(O3l=t}M$?w8q*Qbt-C38ufYq<4E) zZXDL2^|~FCQ3y;U7TDH|;@s{eyk_wt@XpQ|m19ZjwF44)+$2t^D(oto3cTZl3<;^* zzhCz@6x!Z`iggTQ`!awRl1CCqlsoR#H%rRGnBOjR=w8paa&XSPUYh~M>hpfv5N_pw zy1g*JH2t&`7kL9Z!_vGM)oBiEv0o6pafBD$R2a%-CLyuM6XGEt?qL}<5%1L3!QNSA)-pE`HVWroncvkyjt8)UKgrjY#!xgrgu>K z{!@w|p$%vvRxB-vNrvrmiL-Ax3v#Th>tQlsHsUjQ<~~1ML4~O3D7K#r z5sRL?%;{%JYDG4^u}EiIgwveBW0$wlO2C;J>cwNyJ8(wZo`#a3xx64cI(f+VrH6Ca z*`jHN?&p1Qe8_Zb1#py%z>*@3otaVVK+eYULA$D<2BBl_z^{3Y*F}!(AW<-t(#e zhoM4xJbT1nVO_#}I*?THR$)I9m3Cw7MVas)fw+(wwn0GatO(Ik#=PB>`DKZdnJW|8 z`Blzk5}`0b`!2*|V(j4*&Wk0Wwt}xXLdiz4chK zw|v=Ofxg1IJdJ%aALZk2Rf+Cz|xW2L}{(SY%y#00e|Ndo9)bCj3Ds zY_~brpy(G<<#8loytJEJ6K=B<5hF-H=V~9ClO;sKcHxVIwWD}ujp)Ho`SoHgngCRaf$whEUC6HI^?=y3o_cxYbfNxckTD;X-n$ zLVVCLBA$Psz$gO}fhp*&w`7XU$&DQ#6P31Eu;A#OT3JP*?0$!o*Hfh4P*}%fS>+;S zO89)hYe`=JyA1DOYT4|H#?^sr-8m5)lwAa8@y3$Iyfy>W93RxRXD<;T@$eVOtbfId zpo{unVzS2k9xv)|+a6e5Vs0tc{@P*LQ2Uk3r;QdncrusD!C=SQi6p-`=T8Bb{Id(1 zgnszihNaJRVs5!8X5y|L#n9;aPr$&MM(OVI3g@g!H*8#(N;hOX+^dkleb+6v3jzVF zMvl=C_dc7q6>#E(LeBga!`_vXJr;a2an<rEluk zY0Pg2=6GjYG+ovc-{y8=lHR8@lvhmwz6@f;#eG)xQuxgY>Z>D-sr=D^JxSmGo&Qyw zPixMq%YG>I+~!Ft-O~yJuSb9=1;&vDWr~I9Ojfo~dg7gN1>8C%UPexQu?^6PLV#ZG zH9fD2V8HkO?(!MVv7z&a&*ynIV9Gg9i`|^$@2V?g2jeDwk|F-fcVjd0mC6xt)o(d0 z+>Y`-y7A+03U)s<4z=oGg??3D%&f#JE~_8$B*d;%mLscjE2(LUDfI#H$i)$ZW#+UrF={eMU`s&+`u^ zFYIUY)qF4?+T1S>nu7_ui9gKVRZ=Cy472T4|D@;DO*4G5`EAVq;tbc&vCq6q;J)#v zW4ZLFpYfRZ_Xp|7`)l-O=l`J~{Fe%M-!A-G@y7jit|`_;wRZD;0=+&lV-1XYR;`=A;L9hWDduJS!<_bBqB(fGL`Cwa5SfjZaKamK z^C@LCr$G+|d!&Kt>WQ+tBy17xI_`PDv2+YG6L%bLp9`x(8*Dw&7NT2P!U-5p9ewf( zxL+GB1hmwEFSA;RVjTfz@b6@h$g^<`#_=~Ew}gZd5A=Fc8AfE;<4H^uc*&kCqhGDG zl;pr;7<~y6oICZm_MxtU$a0Zn=EDJnk*>4x@db+JErDxjatU07$h^CKBfDUt^Tx@J z--WiKb zcG0n5s0Bg(#iK)AFCPfoOUNe)J8e*v^4Hm2BTsbpvGe+Itw2!JN=_=_r zO4H<|yFGLt&znadn~DcLA9q@b{5lI_L!7~Ro<4hBs)#M!PMCMTepz&ei4=9^2)lL^ zf2(FTap!52KQDSD46YIc6I=2ouY+WCEB~3uvvO+NTA~}tO_|h9`kD(HX%)G9DHcO{ zC%$gi0yU3L#`%0Bna;~!fr^Un!gjcrxVpX?K((#OF9RmK^tr4YsLWTMeWksSRqle~ z+CgYb?on+%+Y!eOb_bMZqMIT zk!EgJsH3V#gPx>CNa7o*rA$C;Yd}J|9=g(1qjo{lI%;K>f>#S`cFO`()+dJ`ACv(Q Nbn1+M(|70p`QN(B1D5~* literal 4626 zcmYjTXIPWjw*ENIhy_8^Lkp0jAc!DHs7i?i4M-bN>4MUNga{~v(3$ayfI=oBL5iSM z5kjOTbeNGA14ddx2yLX3gb+%A0O7=O?sM;tZ@=qZYnS!yXTR%NNx#^^jvP`r1OUJh zD@zLp01#Uf***vMi!AZB6&3(UGpsBw-$v(f-Y_4P8OtPOoadU~*#&M5$==#c9%yU~ z@)OsWJ(%k30sD1IX)W$fX}mMs>fZT;l`d}U9fem5Lt;%Y-=*atlu&~M?(|>N)D?`k z!tQ!1eWJYH6YwUSx|SicVJ;pbE*CYd!|FDJu6!hfjo$aXZdNJJf4uuKNh%7W$4=_` zsIL1d_9civ?K^BAJSDk))84sLX|W*py+qVY2;@_4$%`J-d2#+bd48QCanlgjzoX+A_hW||cLkz*tPD2=I-Z!dm;-T2oTL#mg&?WgX0HfEzb9 z-z5>R#XJb%&mK>KF=fbBWtXpS%%2``)$D}|6<4z)r29Cif(KdisK%R_Y7JwvPS4g( z;AT=58~UrXYAQ5)Yf~d$+F7je4gHo@A@k{(Sb09P2%DKP!x_?z*YO+H`3l=l9~b}W z`}fBDKl5v1mrJA$w74q$UY}2Y=B<`fBGvW69E=%zqlX2l)PPPjWgpTS0Ua;QKAdl) z?HpTe1h%Zd_OQZ#YHhmO$YnXQrbR2RDfTfUUYvWHUSS=Xd(O6HXaHA@q$YL^tWGx% z7x@xePYHuLF_*qB?1SvBPf^Z` z5WfeU?-P@Y?@ID`y0@b>Zc;|5p|8^Pbp0ugTCUN!@>kV&#F5#mDnn1U$?g~WLd!Sv zW6hdTW*4>VT61;hQr`Gy)1+SJ&|^a@);!J)232fMoY z{qDxBg5csXDrsh3pVE@r72o{gX}~bp8#g43t>AfuWT7x>hyy#%DGXv3`f5|dh+(#! z13_U$zQT#*tIw}hbul44=L@x{&8pi{WD*VmdhSF0ta2>FkMg-XrT4>|Y0v(lKxc#H zX%+7zW*`y)Rervvg0cVbB)x=IJm?jBz~+#n8!_}0Dk}ORWhai{NlqP-!Pf5Z2O(Jq z)dY5xF9pFZEhq+I*S{?X!XH(SG!N(VHhR>rL4&hzpIj80{v};|j*LVyJv0N<&r)`Y z!n0}Ez{q-+3lX}`JRdLr8AH{rz?6ar@WS5vSkSgh%&~Pm85YRzF^RGHNlj3#7STym zbxJ|PcCA*jpuK+fcbkcprkQg2kKi|Qx{!7(JT_jHx~&b_-`ws) zH?RA9;B+VtRb}kQ5gR@#VXs2*?p5p5POMTKZnPBYI!*Aw1zPKffB4g+92S%Gm4j;3 z$tZQvepF~`m9WeI7Rdvd&$`nh&rL-A2fHO16Y(YE5G>>YTwLpJm%Uzb?1Q~sFL(ZL?tDL?9!I%jTkJ{EV+-2$<=@u5_fzbOb#m`abYsq)YRHwO z7L>#?IA#(4%v`gUBinV0lA;`n7@~Ai=S71@gSd$QEGaTuVE+gRun7hB1IPcrrvA^h znKPfs^b1&RJ%r5Cn$RZSFjUd4i5$)ScZPaNht}2{-_)(o*+3tRv)44VcUmc3FI$5% zYNBC}YoaZ6U70Gv!aY-&2NnL2j!}rKluwCqsfUv7Y9~`|P_|vqPxj9q`8ZA<2VpEw zRWM(S1baNvBDBdl5*3Tj%ECW%7bD|$;n?s~AyXKBEShNC^YXp}E zmC0@*_Ap)dUSb^0^QX*|t*Y=dXBK!0*I8$`rcvdun;Iis?4iZ|HD_M!EAk=_c(!#jfEb2R^rX*7t|SLs6-adD}$mooLpL< zCUy?*r6@%wMxcla^O|N)@aC(D=$c0ulxp5K-*)bnQ&q>5SeG}trp1~G2XxQA{-LjK1UKC5BovMNSLb3amx6*g&J zF2}z>-dYZ6_f7gRGQMcZI~r!L*dO(Wi6=%29s~2Z2(I*Iq|{vd_BHg&=MEL7r?iQq zWOGa)`TAmHd$_)2FU&B(X1Bnw2A!BVi^S{$>a^2p;0z%#?4WkRLM`%T#p$wz8<7q+ z4n6&bNCKM^h96m1ChLP-E3hL0tjvPK^t6qG*C@6isE1k8uqoJqon@v$>_(G1Nkd?d zJlDMclnbaM`|Yt5bR;fEJv)=_F`7vpuT~zDNl%%c8KSvT2hSXX`}Fv*-^h!K3j)(Q zXi{u20aM!^4GTF6EaTfSu7F(pfCu?DqNt&wS0MO!*d=3zCmX?9xrcC3W?r8}H5wqE ze%4Q7-q5&h-tzd|fJNQgL#DH>qLyJ%u1!2BNFcd1mlR8U)45iu!k|&~Z@#-S@bKBb z*syV_w|U|toJ;kFEIrBnQP*oj^24N7KoN2?HF9xX^GT9Ov>(B>08nutw)jvR z5N&>cKM?E^{7FJoOP+^_#H)4@*mqv`PbEFTT`8wv-+5p&^Q_22Zx95X#`^o7T9MD^ zkFXBA>@i;Jt+?ap$!GX#a;#p}W?|k_LuJ(oGhX1u%u0;~3!-nIK>yg3bSuu5W=^-g zRt=ztv1 z6m=wCtW8=}L|%uqN&s~6iSJp}=}C&bbc875-1Ga|fLGAiy(71jM19}p>}0IG2q*tF z880b9cR=y07y!f{j^B4tM1#eGFNup#8<3nALEF!5V&7NQ0mg6liBJ}hiu?KR@Rxs9 zkqkvtAQmjuc({-etvY+p!HJGiL*uT zlR123Cd*mCK~XY%(kM47or#6$W~8H?V|4$cL3>s8hxW>3-hx+GW}tgQS-ZaP*ApbE zUH{_(!hhgoY=X!8U$)&hu5jtI5lmtWGQ$U*?dKVp+C`8oji&~n$Q*4oMl@KLg^$+GBr9zIHDyVXUv z+uzP*PAv1|a_a9)Cm18M9ozh)9H9ukMV)*W;{lV_(BDu|Oz;S}yP(-}%7vc(B~o=c zwDFA>tkzR4zx{}H(TS|$uEV#+(LJe2dV!YSkP+H(7YA$AhmC*P*w%DBYBtk&gsLVnD1Q~gZ412R4}Vy^5zO~ z{>I6y;$87~4@TmGHEQ-g-oC+zY0w!M41*g2liQHJ)eTI>{`eS408`HLsyHs)N7Xr$ za8t7nxpDuu_pfF@z%)X$`K%Rct{N}kAkcb>tB(IOsUr9qO4=@YE1l`|D@~lI*F*v z>@&v8HErr=!`st&Tyg+0=^MWQB0pxi=eIrGQ`tYF`We%a%L8R1U~EfW7xO%`CAU2{ z35J5tl(7OyhD(f1@I;OxymeixdvZjrp|>l@6ULwFi}9oir?n>J3rBjg(upo^v}uDc zFDpY;ck!GaC4G`_$I;R}65godMVvjYTB#D8PM*ImFk-4x>w?o4#H|RhxijO@Q13vf zCaru7PKgrSjDmIkN)Lj0bt{6Jbdenlw~hH00zB>!j_Z-lT#23z$B5JjY#O}I3sL)* z$ciWUs^z@<{^lo?M`wPN3e)0)B3=jRRn+|*0RL}bJ^Z`;flc!sr`&H?8*=FXC$p30s&ol3GFU14^rU$-?z*J-vjgRZHgV&`B@YO5Pi;bh%>r zuqp^nW!gx%cU6DdeorFy2`mE9#Bu6Z5^3i|zD_GEChEA60l z*cT?c+%>wt@KvCtAWM-%4r4|`)&r5!3$b;%KDP#@DnlYlgK8BJOarY8rD~4l4&ZB@ zs`MFRZPpFL!cEnt27mAT)BPn_!&C!kol=l#05bOrZHePnu85C)&u%p;)(4F%KL66u zEsW0!qqNkdSXQKwCRP?%y$6*s)0DDXHOeowV8-aiE>LfUVGI5OWd^dHGtaYKy~*T$ zjkwnvS^9J-kFS5q!qz8tG<3Uju+PhPjO>+TTJg-NK zaokUSyLWrJamW~1qm7dFkjCbvse>I}(>q5o8J}Pvu!(CN`a))GA*Ww4&1*oyRlKUV zqL7=i5a06&4UY^MbymyuiI4TdmYU*=19frK4Q(JcW1uND{W5 zLM=^6f8X=f2e zDy_)8#BQ_V@NsM2TPIda3IWlO?QTI^$-vgfp+9WmB;GB&?$&x^;FL) zYeo+5d0Xw+t=mwC!w3dNFB^kmf9~n+7GA3Mt*sT#`nrVb{H;cr9k9{7!_6f-3jI5` Nx@Kolapm4`{{@BjK!pGR diff --git a/public/stylesheets/images/ui-bg_gloss-wave_90_fff9e5_500x100.png b/public/stylesheets/images/ui-bg_gloss-wave_90_fff9e5_500x100.png index ae00d7b27e2b9a68916ce75c53de9e498fd6fdf6..6e3ad2df76e3669cb737cdc3b36bca9c41fb353a 100644 GIT binary patch literal 2257 zcmb`JdsNbC8pnUFv(?mOXEvwIOxCFpM^o1{@4`;2m>sj&yde>-H#8wC!z)P5Y^OC9 zw^mJ3v%pCOg-Jrq`|2Vk2BCtXV^|E{h!7PN5Lu>k`eXjvKlY#ZyyrRRxxCNweLm+c zIujkSYlp)Q004GHo(TIZ0Bl*c-cz=3wVs#x10(?0UKJVkT}*C`dK!gSbbbk(x%k#% z@tT6PkyO0BV$umzE_J_cMsRi2n&Tf&9MLA9fYa(FH))VK13=l;o3_A#KRvSP-|9Ix z^S~sg_$880jV10Jd-+Qr*nIJs$W3t{JY1k@&9rd$uKlgTU$BQ~98uq?n6jX_DnFr{ zIuvKm^LJZ$@FZZYQnFc;)U+I$jAiRzxXQ89vQFtDB+B#q7Bn7g?;NVTlN zw93?ljA}S5V$Lj0I*H=H!j#;sNH%*J-V|;M$l@(Cyl2W!l|{`1Ki#-?97H;Q?Z{kt$-AbZs}d>P5rGgJv5qlXcH>Z@1RWb3 zzczs_5RFqyU(Dy&p(_i=Ej~EGBDM6J;eX+Z;m;7rv`P%2xlIv}7%a5ppLGPfgW7+# zju$#9o3xO>ZdbKFCEZ`l>BBxQf#A^OnDchY5~=JeXPMT@X^S-nEH*H9AqNA&5x;Su@_taLt~9tCDHmYI2Q+_u(4+N{flz@ifUdUBPUf}T4)U5 ztRnU!rs>93d(1M0;xEarmD$p>!Ql*!pJeR^UkiZMCR_|`M&2+ zH}YegJ1M97lG6EecQfQHe%yi}#~3(Ov~Ay{?6yJVHHLu%E$?r*Tc2LoH0kYj=ynqx z&&9^@(@TUQGs(XCG|;S1VxO_U3{!5JhagKI?Jo=YdA6;j@r^_gF2!(mr#MJJI&r#Z zlat+3<3pO*8>inA4k!8W2jIru4d&wdnzLm}ME=-|K;@M(-!+vLhbVM%OAQ-!C>tzJezoENnF=Flp0oT453FJGi^T?vou<86?2mKoCmGHp#cYa zdN{Hk+uj>fzH}mj#}2v^zzg7L*c)&&xO1=6Qam?!@L}dVzP$Y05ERb4Q{PoMP_WNR zkCUf2505N59xaG(Us=uUuNVH}^n#PwFvCP!b-i!y46tN8_YoKnS6hHB`pT-C{=Zvy zwPXGK?}1#>Z~1ds+jPuobQ1m!IB;3;8v@=N^cMjAf|bjAtt3Q#uXg+o3)9F5C~JpqYM(=P0YsZ=k2QAH6o%!@Sb6O#?;+?77?Br7n8#d& zKX60o@~;)_Zhj5}mE^DQM|AT30eUQts`k z$~7r8*7?lvP>Gr9bh$>5D$FhvbbQd2=-*4hqNQnL{q4DIbNtZev{6lE;gC4Ra9e?I zn>=9G7(qcmcelXA=5W!%Bo>>UW&ZMr3bhii!jFX!^r?>1MpqOF zoeh&V6fI*Gj7Lq~@Md@qfx%-R z(bozMFGkL|7u~yx2a?=VQe`f5@1DCZ$T;OQPd3Ga?kA-D+f|y52Jt4?2Y7Wqs#JBd zc9{9BZZI7=Qi)XWX;-owyDkZu^fwn1#`#V>DVs?V!+S{6v5riBjm+S|RABiF86F+RI)35%{{n&3p}qhB literal 2720 zcmai0e>~IqAOA={zRKxJza-O@NXV&9PHpK@!@0z1)@Z9aAw~{kwxPT3#Mtt?rMM8X zX4q!QhR(74TxPb6kR>u}el$PE_|Dy5_x3&9HL& zC-3myl%-n&>jO@a@6JCZ;eA|VriwASZOAeWpOOn11-#N zEC%CTmu9|EzO$C^^1xSTV9QFuuC3OJAVF$c{w1m5Y=HIV1CbZW~YYwmixC-qn@p{~li( zj4w0+ahxpvqRrpA|55Mq_43jtcaOXNao@F`d6!}6^M1P)fOE-+p(s(yREi99ACGhj@XZ5(tMa5f@KjP|Esx zVmz(Gv!839hMpRsCO;1URZP~Xnf+~u1i>8T!w`R^40Ft|E(hZEfr=YT)59e!k&JI7 zHWLSR>%c*#6km>e&zNP)Z2TfDKjy1jsM6gY4c6)bQfD~>g-YcUQJ<^gT|Q!BB8wA48ctFOP$1V0Co+j?hgsFw$N8Jek}uQoIB|ns(5!lFN_J`gp6J zkxdj->pK&z4_ux9B%B6WZY*b^8043Y!@Rye_Ko>hoIZ;b^{v%nc0cUd0(g&RLs&W% z-tbKwTd<`~FmR9HV6;^vN(v*dZ}JH7ulra&7PAfo)-h|esdQRLz-U<;I<vDx7t zx(Ejk-vgjp&eUmPv~^QvT;4{r#;p#3-qdBUzsb}wcl;O8*9vv@zV5!g{{BB)>(n1N za7jG)@0>EiOa03FJO)1JK+@1{scnxKI@2kQk2>mA!U;7WbXjDM2CG@=+(5O=9ZYe- z3$P6qWKR&oI>fjD(+*yA>rNmk2CFQT%Mi!P(_Pwb&#!NE8RowmCH8Bw(Fw*;1ubnH zRLQ7Hh`_N42zNw>)Dg2-7AD6HZQX|8Ax%{uS$hr$iijs}X70+%?%HdGtmD~zn`!al z2WZv#mb#PmJcXUK1ZE1CLtJG0OyHm~?KsO1j@)x1dY|=jt6l8f9o$kY9XD%5ahaU>^L=Gdoy{pfP=1ha>YjmS@p3D6>(GBS*0<; z!qdxsVrj&)R`jXtrf?&-A8){a1VLtB9oDu1xf(YXh%9+;rcSY@^H_}dOb6h!Cm5Hp zY52QXQ?07;Z*Q-6&@wG*>em5snzos^{852zT9pPIwd1v`;Fqe+U5hG^$&GK0l-mmNCW^_C+a!^z?R`e1E6u8 z!ymdpC15cA|H5U<=Gr0&-{^lz6A=s3-dbeJaV`F?OU9*IBtKB#8eZe+KS;|fq-R5* zdEAA92<0qvtaQ(F&G`vk*t0C^@ZI(34SMOS6RN_O^? zq3HEh!Yde6+iU6d-s49+NI2}k6&zR1UVzTFkOEKSKryP3$~K|cS9Wd3YHBy!SS2ZY z#GLJw4yHTO?Vf5RBTOM)V;Y=y+2h168w%To`!l`9Imb7;qvl-kj^Kuskq4&$U^oBj zr?u(lU+Vzy#)O#K@6)RrWLMjiq*+ZhQQdjC;Bq}SiO2SnWe2mNBwQB9LozmG%aoc1 z_qz`%dT`Mf{9orlCwkRG6BN&QtCD(sMZ+$pM4V=y&)!3yu28j?nIMf2?nFGao$JW8 zEALc#`m$rWkjhlF@n~J?0Df#TNdG)shHIf>>{FfyPR_zM9bd|U z5R3DJ)b-1qL8~#ZR#)Z{j=nfE5c$H}&5{mIh)m9!+0c9XZdRCqzE^u@jRC-g_3l17 zcK^M?AlpZO#N^H!cGp7r;ES%8%T3N)N$`UxfqM6Ww{hut3iCg=?B1VuL?MX`2^!QB zB@2E5EZI%X&sUzt3QYI9TJeQ}1-TTG)uisNFQmy&iGS|Bf+cJjL8{!wtN~;=9;y^4 zYhFFUg1b$^zkZZeI~Vd%*OVMiPxvaflwR2+ccteC9c0*jDT?PV{Wk00ALjS-CV-Ig zDfZWoH|AyCnT=gdjD$VW6DmKM6EDLpR~NWNRK>+O=>UmH@T^HQ01V^b<&6LU+-WpL zyDkZzFV;Fh?tpe(PNVq_08l{@JYG}r;JHn}H63o!ny$;II*+X>5vAFz_2RP%SHDE} zgXbPDMsQ)1j?V&Y?pFw8y=PLoQ@-`8+1apD8R}?Lzj5UH?zMK22NE~xvq z{~${%SeY)POZR*``|FjWpIH&X&7ZP~7m5vRDRT*^K`N1Q@&;=L8hw7wQ~ca0`(&MI z$|qgHq#=8TOY}SOI~6z4EVS)GrZ1DNI8?{?s2i>0u=H!OB^2Zri>wSL$CEIO3)JkVi(jjd7&hi*iF- zvCKZ>oFC#Xaj-s==D|M3T40Id+?Q19`;{Y-Hr7lkCmC|?+41eRY3$IfKwpTI6N?dX znrf8y@}i6Edb3`I%N*yV9e!DPZzii4e5`R&O~np+!RPz)(V!*CkRV7=hmploLA035 zk9W`@JY}2^%&ci2zc1l)P#-$`Aa6S$7I6gTM9_Ju;LHW4DF6^62|w=BKAH=f=3_;a zibt9t-vS1^KR^>{rOY{+A*O|!ch-b9)Kgk%_#N|QV8ozj0%H1e)lH0imMneJJdqq$ zM6I$nlz~Twm>O<1)L#$>Nx|6fvf;7AcKDc;;5)j`Vu-9E_Gj3mqWZh3y?qh(%QC=gNjesQq9w@{&yZ Q{{&pmUv#ec?%FT^1*WckbpQYW diff --git a/public/stylesheets/images/ui-icons_3d3d3d_256x240.png b/public/stylesheets/images/ui-icons_3d3d3d_256x240.png index 12b7518052c1fd0d317153b011d82781b08a90f6..c216ba1d591ed0381cf681ad70bd0f0c59574bb3 100644 GIT binary patch delta 5037 zcmV;e6H@GvBI_xT90dWdPI_;#Ayol?6JJS0K~#90?Oh9F+qMw~$x2$Nn4pts2rkicqs$`0#`RooLep(~$=Dh)P5Z%?UHqR&Q(6DAs zo2i7L)F=(Hpn)7PCAh>RawtSt6Ie?Yrcr}TvtCM@0~9J5v`du%z{CZO%CUM>n6g2^ zw6M16e*bx7EmR#$X=U>lQ>#;dC`*9q#fTgllsq8o>tccY+nmiFk0xM;t zjqt1(`8g^%#{U^g8Y<;hMEalMZ}XMTz)NcBWE( zQ<#bcNToJ+-(PmY4PzZu%YrqQd6z(b8TV4xsvnKbBhdy*Iqd8rfBp|4>W;qoO3MX0 z&SaG&hb|4oGeB-uWp|zAC7E~QJ|h#C0nm29v49Xw7ev4s@o%39j}Xv&`_f(^ZbuPHbYz#BobCFnnASABo5Nn(idW!4EEoTfEF{r zQZ$&?ZS&}F(B+p^=wY6u=X3paLtQt2JP>6!EWErl38&i9 z$=}Ma))`e54v*Eu99I{dr!ATK%|pKy^vHHMqQiAmdnGErv^n|GBG2W&R)p-+dj8>0 z#73NlRk;Wh1vuf+j41$Fe!MFg;3eW%tu*gbRAE;{-BS)%)5v9Nbq19YUenQ&Nf__V zO%G=;Um6Zgy>DfIBH1RYei>~bgD2t&bNWw{h|^b+H}oxqvwz^%JB2eI;du3C684e^ zH+iFSh#J%*L%E&gD>-9pO&47*^*C`^j2L7iQoZqDko^F^ui5vi=WAhAUTda=_9Of+ zP(Lblt|Z2Oj|j5QWeipgN@dox8~pofF0j|UVP@-8ytf91JLkd+k1Rr z!7M*(zJNt9cE!Mhg=+&$w#+}-1^}aPJv(IAcx)Tk9Rm*)z(vk`6TkRDIzM5MO)|eE zM{$NiE0t&y0f$2cK6H>}Urzxz!LjhbWcZD!Fn3UFwndO&zzy|5LCJ#0!&~VtpTL@t zdJ$x`VE|Tt#DLQyPvkTv^9L5{(`)oU)9C!hRs^wgfa~S*p9~QvkUT+lhRkLM9WnT}$o|QtOM$r4oO| zwhTcR4^;G1jM43v^lfK4EG|zT(0kbcDTL<%D{3tReK+VaqV`hYaOw^ zsErW<9q)@TzAzkuSKz`cKcnmC720vIB1c!tsG6GPV0X==`|DS~LF3`O=jTS|EzJ;M zVbklY0A;IPoo*t~7@1;CLS4LYD>bFwzX5-o{S7mmM_p6HjxI3+Sz&mo%PH~R!-EHi z)m!|3<-0thzN9PYKJv#4b8Wv7-{@40))&}@DzkIRw4L(AEKA$Auw1H$_1kG`U>{}R z-yH*TS-!#>5das;IeB5)(5VWjOrv}T&z>m;Ok1!FR5wSX2&U@)6~MRmQv4IZ^-#VL zP`ZvJ(yDt1%*+;mq)ro2N%!`lFV=DRNjGCI*2m1uPEOq7k#KN{6I8aqC0 zJW)4B;^=nX%|RJJY|X%f2Z$ey49lP!RRivh7{IyS^uil#Mg}O<{d9mffV)2cyz6sQ z>4sbm0Pn#I`TJH+!??et6Rz-fSAe+z2lBxplTXypqYbz-1>JR|yzTzM(8Lv#Ch1sz zdZY#T?x)vyb_O#C3|x0Vz;{1A1~LN4R$SE&jMw+XKqaBWaj2NvKt>!}s|P!##2@~? zRVWI7zEao(UO2dfYnDHBONHP3ig!vVw(q9C1Om;Abm22pnEMSIOJHk^-uaY~k%G4l zB0@cY-2uIs9w>nC!dbWcpnIjX(Zq2vf$oOzS zm7j~?HS@4h8!uiQPY*l;Yc2ixMPxbY6uP>+It^>Zgd zR)Fy>$YxZ=;GXorea%NQb_RO|*(`imK^UaW^4K;8L5EIR$+$wX{oZ=7*}8!h#qZ#9 z1|nA1Q$U-*Cc#Q7wCS1@4IO2^UcmGcY@*F7U;a}ZH%md6G zwF=n1EvP@!{(u`01##z~cdClVkJVWO(nkd}joMTzP8wT~J_HN&W?5tagx>rH;5Nyr z*c04+ds=Dt?2L75pwR{1M4y}TO4FYj{L%5FQ(Rtp3`_+qbw;}U5_G(O%S(A^f)Mo+ zeQM*`WO8OC<;^qPJV7xqhsU3L3=|k~KA-D|*E&OFpqeh1##Odov{Ef5M90p%~n*GpK%NTU)M(lmCEBez;i_; zT6eh50P|tj8qUp+7TZRDRf62JP@31uJ%N7Uvq{8|`yqTNn_e3Rt_=g%hJlv!`^HbNPG-HZy~9*+dSUtn@EQxofL1_HFE76q z^3YT5&s|f0-Or7ycX+>4Zrj>{52{*6<0A-8{vz21z`xC5U2}ndwTji8=(hG)Hww#O z#{HuX*75pBdv@&j!nB3yKfYG3>9kj0!Hv#FSa&1~R2fe=6Mx=SE6X1WbznCBbBw*X_#_TN38IHRRGI5Q8cxl1%^@OB2U?h*f{9C^SKX{CG_ zKz1-=P8EfN%=Y{5*#i%owW-E-E6k}e6^2)u(&f8yO54qUJUvmJoo%$^TRq{?7zXYr z1C~KEOc;>Brrk=_;7lIjg&9~02#?IjNCO+orpduJI@PTjp&xo_O8sM|4=0rWW+s7& zkLgU?-E^6p%?AL?c6~9!?lsd4%zTBz#wDBEwv8p=GSKnwZ$rSAZ6M>`@n3kVT!8J~ zW3(w&{{vxvMzb?KZVyI$cLtkb4fvpy9v>{1g?^a6(93fGOY?9&?DF+OV%Cawra3W- zwr(Y3(c|t8@8SJU^UGKpI3M8dJAfbh+*Gqz0x@#}=Ykw~$1*Yn@c3bWdWbS`BjQin<9t9>RJymF$DQ&2 zVEj|=9Zk<%0lo`2X5PVo^8xODH{hny4Y?T^A@KfS;Idio-WpL*5HcYA{XzR<;Jzi0 zkr5!>)(-SkS-=36d#I<{3>`tL>nlI!*P)D08t$K{`9T+>)oVX zsMpAU7GC6oN<{8pqUAv_@+cs9xRQl>5x5@V$-@GI$U%vFge;1m$=WM`n1FgK7z&_= zfx`=61oqnncoRH$7s$xS$mqx3mEirVJU$L^TbmJ)2t2xPC;bW)VRn6HwNOi(hm#3F zbmYULcxGzEIG_-I0zZ6c*ltdnaIn+XVdy@C|}q z8GSiGkRx!4$M4TQ@+>E?Ku83d3`2fc0!RhM${!JfRWN+ZVo&0TfP4mH$@{O+a0xwu zk@Rb0+YI)bzIO#GBO~LXqu`S_(SJ)m5)g^pZ^ymR1Op^o(D~R1g~rcDhv$a{(p3J8M3{1|`y3Putzj(Y_VM$Y4ajEs*Od+ou2nPOTg zEL^52Ji8KLfaAb0^XYG}jNTW%C5)ASO5VU$K|S~XBTCkv--ZnLnFUM>GysB#yOaQ) zY)=aTFWjqQ#Hxo3^@%80fQhsKCV;So?A)&T1DRl*p4}K3SjQh)@);U;^beadGBS=1 z;k(v8Dnw@%zTzo^2^*jP@#ipy72UDi5rx<)vTt=tC_S^}*-hz|UJf8QNd;DaAbl*Y zW`qEO`2GTgKCLSu0KPtfl|PyWAcnd?w7rw~W&CPFfJ}hv!we3S7nMVDdLN;pSjgF{$MP zg!RN@Km=xlPA`MWs>i=(o|lM!9#G1IR$VG+nxfRe47%&#mv=6a5&-CzqJw)kx@iGO z>ves?@wrNFGn~Nb#r)?$1t5=hW%cFt59}1NV!i-m^*?vvQ2G*uf_cbS;T6k*tN_8q z#YMUWz;fBOqN#aFyeha-e^vl8enkZERHlCV6g^Jm>3_92Wz``GDtqXEEJpAxx$mI_ z@C!OFS+tMA9cL2=ASmyd0+aZ}ULh`kYN>!61~kZCHU;mB)V1vbHI{D=7zr5qLVbLG z`da`E*Ilj=J402q3R}EV+9`mM(P696R6g@J0u$kCRe^4tLu6VTF=z%p}mb%QIek@ z4zPj#bHjk^0&+o#uP<08bKm?~&CoZ0Le{6wcm23ew zH{I-miZ?{J z2Rf^(ZQ0WGjqkgE-+K|xycCBOfU7Vqyq^a$+f-G5_e|T?0#L+;@9|h4Kp^SYj(klc zu|$OMt1ouY1$q`A4uK!!SQOsX~wpa2fs1^7Ve-n&3X z#)HRygML43+0AU>$A;W5tebaikyHZp(!xxY78}yXhEl$6@yABIqPLS*7h>k$K_!c- zlk-XUXV&loLk;li#Vgw8 z)i9uG$UUdXSyLGq8J`IFeSjhQ7U|o~=yl6~+m;>zzYp*MERa?&Lc2Beor2z%%*`;@ukZKw`#t}A{quf2-mk~&@qWJ+l%B{umS6)BEiUZT9K8$%_+l;0OzcBm zEIOySP1f^6d(F#cW1gyod(f|0p1QOC)bswBcSVlcn~^|^u}$)!9~8&xXN*Lit(BYH zcDFQQky|p7YBvC7JnQS}AwmRg=+|QNUV?}L&>s#}xVuLMv%r@^n`1QjSRrRWXkyJ9 zmDE;*DRaVsT=#K{K8I64nWZmZ2CJZxwB5j90TQ>YE)IWoHc6kou#GbZu9V5G>|hYN zVRMW8lgBiqT0nUXp=u}>7WWEfCP@4Ui-9jfUP?*4MKVF17iwB3mm$LqK*1}l_(_B`9~^*~GUu$qmn-^aeh}Y>05iSV908MyziiVl>p& zj6~f1+CKsSC#VDGYM*~fdr1-dUBzMNK#Lyw4WLYPoxcz})!ixTGcfkrhx_9t z?S~vP21SEgu)b_~6a8De8+J+{PiDHB1J0K@t`zPj_oVf;F!)uM^iS&fV0bX;WAZ;V zr>s4n?qP9_e?fMWA+IPgmPhPSzB#eyTyFX6!7n@*DlKK1Veq!gc+Hb5-d;~WPQE@vX$1JW2dd+>ea>3#CNb?R4k~RU!qW{HFL!Xx5c*m>p<;i za15`C5GqH-{Q~y|0+R9DnMzaWw{F0>zjW=J-ufAHZ->bT731?p zOD7gOc%3;Mu<5ZiZ__FhJu{2k%`iI&aQlp!2 zws3}z=_8(`W2Xf-GOVt1m3$_nZ>lF{S9H`*c^Dq)z<{V=TU3I3bk%zv&aXh6MQNwH zMfpOLCxKm*p9K!VI0aI!pGLCIpON+mEYvx{N7&KnRf9tO31IHjG!+7C|Lu1~`jZ-H zwCQ8q8B^quk#Eq8=209Tg2gfTBO9S0ZZI}0ZqkU*`_(_Bcr}5v{~6&M5w>k$N}zV9 z2^q||)dW=~`LiVN<8QK*0+vzrc;*qEzyheW_(mAviI!yC`ACU^+Jk9+Oln#jF{fh( zLbIgwA|g2YGmO}nt&@edRn~F@;^7K?J(7j9-o!^Kv54iBrf*mnXDb#Y;Q_7N&jRg^ z@M8>2%m|I+yL(e!C%jL!-@MH`VIqJE&~IuNSYeaGXIV+pwwi!65E&_PtpKW_u1;t! zUBS`rp7`!_AW-dZ3>M*;;ORVq?xvnhUez|87Z?_g^l>4Q!3r1xJLo4E;RD3rmVB+% zvcB+~VrhWcpBG*dDn)2F!a^0+U#M%7Eo!L0UmtxLWa zB|!K$Qks0`00}CNJr>CQdhNr~zzwZOKNPI}*8L$0gyS~lUkl4#3#)t%lTZz`xT2sC zaZAGc`@z3qH|&0QXLZf4-wTm-9lch6X(w>YGCY?#oZwYUnkA+?8F)wWQq9^%QTSQO;d%xhGZJU&9tTHxV z#U9_!QwzZ{)0^youAN0kuA4F{%6M+{W6upddRLJ3?#;GyfxPjj(JBUN*m+{IW8nBR zIRN*nqu|Dizr!A+#-%7PPDc_H&JtWGRZQJaP};Coy5Cx102Qo^w_}^ckgW%vGV)LI zZ$e~4bVem~K1GSwoSc^}SY&H?J9scn$-ZJfnHEPMmRfnnytYr`Q*zeiYrshPwx2F| zKb_YumV++);&U~8T4z{4FIq3VyAhHF7!f8jk5M{zMBh9J#M+zS59izMa|?Da)Om`Dvx zzol*neb#I_^7I2I4tZ5zW0z$*M*|$2gYWR&?%-RIwEN9Z1|p#vHwfcXy`HVH;@-Yg zp1gkjz+UmR+%8QqUKa$kp|zY}bF^Em$P=Lh;gU+hGkX?XpofgYdACwNO`+b4R|a0+ z8<+N4qbiPZKCP9z|F-yWXUGp;0_Ai~j4VDNqAkWJeB zsDyemKZfg`Zwo{2jLcF&A)7#5&v|z`x^HNH{{s{lj-FNeg zkhy>WFa^D`>3d=VqrhIrr^(Pb4e2__DJ}{qT7EMPU{~4I`5|+t?$XJChx!8_OROjH z4ogroCKKnXiyw4N6$L#IpW1MyG>T?zGFQHPX=QJNRY(vTepnmyt7AWOUTm%a>b>l{4NXv2z-nnXbomY24 zJ^x4mzV6f2fNrg2GVHcyhryl#yuVZk`WlgS_2AB*#N1Ee>8O(;+Z2xNp;3(M8O796 zLwPq^ln>>2f4`w*MI71t#agk}HpjgeK)jSG{;5xC>m@m1Z?PRJMK&)_=&M&chy=+J zWEy(BplP-vZuU(qmx!d0dJcw$NggLV8QAYW(iXAfyd0&Zok~BdeSD7d8t96=dIuw( zT`}PcF?P;5Y|?2ZB#ra-yK#n$vrqMyLXg1Fuk!bKfrLmX#a=2I|o2(d8vNfEf;U`~@5SZV&BHqANdeF(9+ubidb=Pzu4CHO}^oRf`AV5!>;=Kl3~k3a(E#?QOjkNRyKt zT>tj75Y5(uY|fT`+#qz=o(5R^+!r<&dwGP;JzkI5>=3qN$*D!(2@k6aZDBbI%Cuw& zsbzmz%m3jwn-|^KL|hU4V7ut@aAb1zfESw;K@o%S(Kzb8b_gr3_TqC)#HsyVZWolA zw*|ibkqd`(?+%VKBzRMC|DJ)}l&6162x;1B!J}P(kc+L2-Zs{@Akkg$6s?*fr;wk_wTMQ$?=^$HLA) z6(IW~YSVFurhHNlYBnmAhoRF_F%h($dBB}gf^nEkhXupIjPh@ZvRnIMHYnRH9<nvYnh8=^CXSVnqn%IVIv^OEyTR8~P^xXqk5pWH0HEVp(!h zI00>FYWYNp)RvgJWM?xeSvaBBwY<3#3aH?72LI`{j^cYexQu=g+Y05X338J^=f5)Z z+yCXAp&3unY>i^4%QxP)2F=QC1M6VvJ@AVNFSm{b2k+;@6KlbF+)fUyv(gbe@nnXO z*_W@0Xb1G{9Q+_O{s=)Ilt<@%IWbOIxPRKGjZxaX%6b@eIzECf{ z@;D2Y z0a}-6vBn5hu>2xvjIC{io;sP}HQn{2HKkIyq-GIyn}oV|`DBV$eCPYDg=VKf~M%DmHInYm5VrC|mvFLsd_w#VWx9wYm{82OabMS@_M%nwj&Diq{T=+C> zYO5LbPeuJ(QeWFn<(nfLIR(l_MVf@^hmb{W&SyhG94y;AA1^X|K0z8WLWT~>Qr?^Io)Lp;@!HxKxPZ0x4pxn qSjY#HREPziBU_jER_>FU-`mE$a{&_4r-N)jf3Y}=HmfwnME?hjxyfn( diff --git a/public/stylesheets/images/ui-icons_ed9f26_256x240.png b/public/stylesheets/images/ui-icons_ed9f26_256x240.png index 668e030c5e02e9b9851fb92c76610ecccdb6164b..50c74c159168b2537bede8ffc414a2d21a3b3c71 100644 GIT binary patch delta 5037 zcmV;e6H@GvBI_xT90dWdPI_;#Ayol?6JJS0K~#90?Oh9F+qMw~$x2$Nn4pts2rkicqs$`0#`RooLep(~$=Dh)P5Z%?UHqR&Q(6DAs zo2i7L)F=(Hpn)7PCAh>RawtSt6Ie?Yrcr}TvtCM@0~9J5v`du%z{CZO%CUM>n6g2^ zw6M16e*bx7EmR#$X=U>lQ>#;dC`*9q#fTgllsq8o>tccY+nmiFk0xM;t zjqt1(`8g^%#{U^g8Y<;hMEalMZ}XMTz)NcBWE( zQ<#bcNToJ+-(PmY4PzZu%YrqQd6z(b8TV4xsvnKbBhdy*Iqd8rfBp|4>W;qoO3MX0 z&SaG&hb|4oGeB-uWp|zAC7E~QJ|h#C0nm29v49Xw7ev4s@o%39j}Xv&`_f(^ZbuPHbYz#BobCFnnASABo5Nn(idW!4EEoTfEF{r zQZ$&?ZS&}F(B+p^=wY6u=X3paLtQt2JP>6!EWErl38&i9 z$=}Ma))`e54v*Eu99I{dr!ATK%|pKy^vHHMqQiAmdnGErv^n|GBG2W&R)p-+dj8>0 z#73NlRk;Wh1vuf+j41$Fe!MFg;3eW%tu*gbRAE;{-BS)%)5v9Nbq19YUenQ&Nf__V zO%G=;Um6Zgy>DfIBH1RYei>~bgD2t&bNWw{h|^b+H}oxqvwz^%JB2eI;du3C684e^ zH+iFSh#J%*L%E&gD>-9pO&47*^*C`^j2L7iQoZqDko^F^ui5vi=WAhAUTda=_9Of+ zP(Lblt|Z2Oj|j5QWeipgN@dox8~pofF0j|UVP@-8ytf91JLkd+k1Rr z!7M*(zJNt9cE!Mhg=+&$w#+}-1^}aPJv(IAcx)Tk9Rm*)z(vk`6TkRDIzM5MO)|eE zM{$NiE0t&y0f$2cK6H>}Urzxz!LjhbWcZD!Fn3UFwndO&zzy|5LCJ#0!&~VtpTL@t zdJ$x`VE|Tt#DLQyPvkTv^9L5{(`)oU)9C!hRs^wgfa~S*p9~QvkUT+lhRkLM9WnT}$o|QtOM$r4oO| zwhTcR4^;G1jM43v^lfK4EG|zT(0kbcDTL<%D{3tReK+VaqV`hYaOw^ zsErW<9q)@TzAzkuSKz`cKcnmC720vIB1c!tsG6GPV0X==`|DS~LF3`O=jTS|EzJ;M zVbklY0A;IPoo*t~7@1;CLS4LYD>bFwzX5-o{S7mmM_p6HjxI3+Sz&mo%PH~R!-EHi z)m!|3<-0thzN9PYKJv#4b8Wv7-{@40))&}@DzkIRw4L(AEKA$Auw1H$_1kG`U>{}R z-yH*TS-!#>5das;IeB5)(5VWjOrv}T&z>m;Ok1!FR5wSX2&U@)6~MRmQv4IZ^-#VL zP`ZvJ(yDt1%*+;mq)ro2N%!`lFV=DRNjGCI*2m1uPEOq7k#KN{6I8aqC0 zJW)4B;^=nX%|RJJY|X%f2Z$ey49lP!RRivh7{IyS^uil#Mg}O<{d9mffV)2cyz6sQ z>4sbm0Pn#I`TJH+!??et6Rz-fSAe+z2lBxplTXypqYbz-1>JR|yzTzM(8Lv#Ch1sz zdZY#T?x)vyb_O#C3|x0Vz;{1A1~LN4R$SE&jMw+XKqaBWaj2NvKt>!}s|P!##2@~? zRVWI7zEao(UO2dfYnDHBONHP3ig!vVw(q9C1Om;Abm22pnEMSIOJHk^-uaY~k%G4l zB0@cY-2uIs9w>nC!dbWcpnIjX(Zq2vf$oOzS zm7j~?HS@4h8!uiQPY*l;Yc2ixMPxbY6uP>+It^>Zgd zR)Fy>$YxZ=;GXorea%NQb_RO|*(`imK^UaW^4K;8L5EIR$+$wX{oZ=7*}8!h#qZ#9 z1|nA1Q$U-*Cc#Q7wCS1@4IO2^UcmGcY@*F7U;a}ZH%md6G zwF=n1EvP@!{(u`01##z~cdClVkJVWO(nkd}joMTzP8wT~J_HN&W?5tagx>rH;5Nyr z*c04+ds=Dt?2L75pwR{1M4y}TO4FYj{L%5FQ(Rtp3`_+qbw;}U5_G(O%S(A^f)Mo+ zeQM*`WO8OC<;^qPJV7xqhsU3L3=|k~KA-D|*E&OFpqeh1##Odov{Ef5M90p%~n*GpK%NTU)M(lmCEBez;i_; zT6eh50P|tj8qUp+7TZRDRf62JP@31uJ%N7Uvq{8|`yqTNn_e3Rt_=g%hJlv!`^HbNPG-HZy~9*+dSUtn@EQxofL1_HFE76q z^3YT5&s|f0-Or7ycX+>4Zrj>{52{*6<0A-8{vz21z`xC5U2}ndwTji8=(hG)Hww#O z#{HuX*75pBdv@&j!nB3yKfYG3>9kj0!Hv#FSa&1~R2fe=6Mx=SE6X1WbznCBbBw*X_#_TN38IHRRGI5Q8cxl1%^@OB2U?h*f{9C^SKX{CG_ zKz1-=P8EfN%=Y{5*#i%owW-E-E6k}e6^2)u(&f8yO54qUJUvmJoo%$^TRq{?7zXYr z1C~KEOc;>Brrk=_;7lIjg&9~02#?IjNCO+orpduJI@PTjp&xo_O8sM|4=0rWW+s7& zkLgU?-E^6p%?AL?c6~9!?lsd4%zTBz#wDBEwv8p=GSKnwZ$rSAZ6M>`@n3kVT!8J~ zW3(w&{{vxvMzb?KZVyI$cLtkb4fvpy9v>{1g?^a6(93fGOY?9&?DF+OV%Cawra3W- zwr(Y3(c|t8@8SJU^UGKpI3M8dJAfbh+*Gqz0x@#}=Ykw~$1*Yn@c3bWdWbS`BjQin<9t9>RJymF$DQ&2 zVEj|=9Zk<%0lo`2X5PVo^8xODH{hny4Y?T^A@KfS;Idio-WpL*5HcYA{XzR<;Jzi0 zkr5!>)(-SkS-=36d#I<{3>`tL>nlI!*P)D08t$K{`9T+>)oVX zsMpAU7GC6oN<{8pqUAv_@+cs9xRQl>5x5@V$-@GI$U%vFge;1m$=WM`n1FgK7z&_= zfx`=61oqnncoRH$7s$xS$mqx3mEirVJU$L^TbmJ)2t2xPC;bW)VRn6HwNOi(hm#3F zbmYULcxGzEIG_-I0zZ6c*ltdnaIn+XVdy@C|}q z8GSiGkRx!4$M4TQ@+>E?Ku83d3`2fc0!RhM${!JfRWN+ZVo&0TfP4mH$@{O+a0xwu zk@Rb0+YI)bzIO#GBO~LXqu`S_(SJ)m5)g^pZ^ymR1Op^o(D~R1g~rcDhv$a{(p3J8M3{1|`y3Putzj(Y_VM$Y4ajEs*Od+ou2nPOTg zEL^52Ji8KLfaAb0^XYG}jNTW%C5)ASO5VU$K|S~XBTCkv--ZnLnFUM>GysB#yOaQ) zY)=aTFWjqQ#Hxo3^@%80fQhsKCV;So?A)&T1DRl*p4}K3SjQh)@);U;^beadGBS=1 z;k(v8Dnw@%zTzo^2^*jP@#ipy72UDi5rx<)vTt=tC_S^}*-hz|UJf8QNd;DaAbl*Y zW`qEO`2GTgKCLSu0KPtfl|PyWAcnd?w7rw~W&CPFfJ}hv!we3S7nMVDdLN;pSjgF{$MP zg!RN@Km=xlPA`MWs>i=(o|lM!9#G1IR$VG+nxfRe47%&#mv=6a5&-CzqJw)kx@iGO z>ves?@wrNFGn~Nb#r)?$1t5=hW%cFt59}1NV!i-m^*?vvQ2G*uf_cbS;T6k*tN_8q z#YMUWz;fBOqN#aFyeha-e^vl8enkZERHlCV6g^Jm>3_92Wz``GDtqXEEJpAxx$mI_ z@C!OFS+tMA9cL2=ASmyd0+aZ}ULh`kYN>!61~kZCHU;mB)V1vbHI{D=7zr5qLVbLG z`da`E*Ilj=J402q3R}EV+9`mM(P696R6g@J0u$kCRe^4tLu6VTF=z%p}mb%QIek@ z4zPj#bHjk^0&+o#uP<08bKm?~&CoZ0Le{6wcm23ew zH{I-miZ?{J z2Rf^(ZQ0WGjqkgE-+K|xycCBOfU7Vqyq^a$+f-G5_e|T?0#L+;@9|h4Kp^SYj(klc zu|$OMt1ouY1$q`A4uK!!SQOsX~wpa2fs1^7Ve-n&3X z#)HRygML43+0AU>$A;W5tebaikyHZp(!xxY78}yXhEl$6@yABIqPLS*7h>k$K_!c- zlk-XUXV&loLk;li#Vgw8 z)i9uG$UUdXSyLGq8J`IFeSjhQ7U|o~=yl6~+m;>zzYp*MERa?&Lc2Beor2z%%*`;@ukZKw`#t}A{quf2-mk~&@qWJ+l%B{umS6)BEiUZT9K8$%_+l;0OzcBm zEIOySP1f^6d(F#cW1gyod(f|0p1QOC)bswBcSVlcn~^|^u}$)!9~8&xXN*Lit(BYH zcDFQQky|p7YBvC7JnQS}AwmRg=+|QNUV?}L&>s#}xVuLMv%r@^n`1QjSRrRWXkyJ9 zmDE;*DRaVsT=#K{K8I64nWZmZ2CJZxwB5j90TQ>YE)IWoHc6kou#GbZu9V5G>|hYN zVRMW8lgBiqT0nUXp=u}>7WWEfCP@4Ui-9jfUP?*4MKVF17iwB3mm$LqK*1}l_(_B`9~^*~GUu$qmn-^aeh}Y>05iSV908MyziiVl>p& zj6~f1+CKsSC#VDGYM*~fdr1-dUBzMNK#Lyw4WLYPoxcz})!ixTGcfkrhx_9t z?S~vP21SEgu)b_~6a8De8+J+{PiDHB1J0K@t`zPj_oVf;F!)uM^iS&fV0bX;WAZ;V zr>s4n?qP9_e?fMWA+IPgmPhPSzB#eyTyFX6!7n@*DlKK1Veq!gc+Hb5-d;~WPQE@vX$1JW2dd+>ea>3#CNb?R4k~RU!qW{HFL!Xx5c*m>p<;i za15`C5GqH-{Q~y|0+R9DnMzaWw{F0>zjW=J-ufAHZ->bT731?p zOD7gOc%3;Mu<5ZiZ__FhJu{2k%`iI&aQlp!2 zws3}z=_8(`W2Xf-GOVt1m3$_nZ>lF{S9H`*c^Dq)z<{V=TU3I3bk%zv&aXh6MQNwH zMfpOLCxKm*p9K!VI0aI!pGLCIpON+mEYvx{N7&KnRf9tO31IHjG!+7C|Lu1~`jZ-H zwCQ8q8B^quk#Eq8=209Tg2gfTBO9S0ZZI}0ZqkU*`_(_Bcr}5v{~6&M5w>k$N}zV9 z2^q||)dW=~`LiVN<8QK*0+vzrc;*qEzyheW_(mAviI!yC`ACU^+Jk9+Oln#jF{fh( zLbIgwA|g2YGmO}nt&@edRn~F@;^7K?J(7j9-o!^Kv54iBrf*mnXDb#Y;Q_7N&jRg^ z@M8>2%m|I+yL(e!C%jL!-@MH`VIqJE&~IuNSYeaGXIV+pwwi!65E&_PtpKW_u1;t! zUBS`rp7`!_AW-dZ3>M*;;ORVq?xvnhUez|87Z?_g^l>4Q!3r1xJLo4E;RD3rmVB+% zvcB+~VrhWcpBG*dDn)2F!a^0+U#M%7Eo!L0UmtxLWa zB|!K$Qks0`00}CNJr>CQdhNr~zzwZOKNPI}*8L$0gyS~lUkl4#3#)t%lTZz`xT2sC zaZAGc`@z3qH|&0QXLZf4-wTm-9lch6X(w>YGCY?#oZwYUnkA+?8F)wWQq9^%QTSQO;d%xhGZJU&9tTHxV z#U9_!QwzZ{)0^youAN0kuA4F{%6M+{W6upddRLJ3?#;GyfxPjj(JBUN*m+{IW8nBR zIRN*nqu|Dizr!A+#-%7PPDc_H&JtWGRZQJaP};Coy5Cx102Qo^w_}^ckgW%vGV)LI zZ$e~4bVem~K1GSwoSc^}SY&H?J9scn$-ZJfnHEPMmRfnnytYr`Q*zeiYrshPwx2F| zKb_YumV++);&U~8T4z{4FIq3VyAhHF7!f8jk5M{zMBh9J#M+zS59izMa|?Da)Om`Dvx zzol*neb#I_^7I2I4tZ5zW0z$*M*|$2gYWR&?%-RIwEN9Z1|p#vHwfcXy`HVH;@-Yg zp1gkjz+UmR+%8QqUKa$kp|zY}bF^Em$P=Lh;gU+hGkX?XpofgYdACwNO`+b4R|a0+ z8<+N4qbiPZKCP9z|F-yWXUGp;0_Ai~j4VDNqAkWJeB zsDyemKZfg`Zwo{2jLcF&A)7#5&v|z`x^HNH{{s{lj-FNeg zkhy>WFa^D`>3d=VqrhIrr^(Pb4e2__DJ}{qT7EMPU{~4I`5|+t?$XJChx!8_OROjH z4ogroCKKnXiyw4N6$L#IpW1MyG>T?zGFQHPX=QJNRY(vTepnmyt7AWOUTm%a>b>l{4NXv2z-nnXbomY24 zJ^x4mzV6f2fNrg2GVHcyhryl#yuVZk`WlgS_2AB*#N1Ee>8O(;+Z2xNp;3(M8O796 zLwPq^ln>>2f4`w*MI71t#agk}HpjgeK)jSG{;5xC>m@m1Z?PRJMK&)_=&M&chy=+J zWEy(BplP-vZuU(qmx!d0dJcw$NggLV8QAYW(iXAfyd0&Zok~BdeSD7d8t96=dIuw( zT`}PcF?P;5Y|?2ZB#ra-yK#n$vrqMyLXg1Fuk!bKfrLmX#a=2I|o2(d8vNfEf;U`~@5SZV&BHqANdeF(9+ubidb=Pzu4CHO}^oRf`AV5!>;=Kl3~k3a(E#?QOjkNRyKt zT>tj75Y5(uY|fT`+#qz=o(5R^+!r<&dwGP;JzkI5>=3qN$*D!(2@k6aZDBbI%Cuw& zsbzmz%m3jwn-|^KL|hU4V7ut@aAb1zfESw;K@o%S(Kzb8b_gr3_TqC)#HsyVZWolA zw*|ibkqd`(?+%VKBzRMC|DJ)}l&6162x;1B!J}P(kc+L2-Zs{@Akkg$6s?*fr;wk_wTMQ$?=^$HLA) z6(IW~YSVFurhHNlYBnmAhoRF_F%h($dBB}gf^nEkhXupIjPh@ZvRnIMHYnRH9<nvYnh8=^CXSVnqn%IVIv^OEyTR8~P^xXqk5pWH0HEVp(!h zI00>FYWYNp)RvgJWM?xeSvaBBwY<3#3aH?72LI`{j^cYexQu=g+Y05X338J^=f5)Z z+yCXAp&3unY>i^4%QxP)2F=QC1M6VvJ@AVNFSm{b2k+;@6KlbF+)fUyv(gbe@nnXO z*_W@0Xb1G{9Q+_O{s=)Ilt<@%IWbOIxPRKGjZxaX%6b@eIzECf{ z@;D2Y z0a}-6vBn5hu>2xvjIC{io;sP}HQn{2HKkIyq-GIyn}oV|`DBV$eCPYDg=VKf~M%DmHInYm5VrC|mvFLsd_w#VWx9wYm{82OabMS@_M%nwj&Diq{T=+C> zYO5LbPeuJ(QeWFn<(nfLIR(l_MVf@^hmb{W&SyhG94y;AA1^X|K0z8WLWT~>Qr?^Io)Lp;@!HxKxPZ0x4pxn qSjY#HREPziBU_jER_>FU-`mE$a{&_4r-N)jf3Y}=HmfwnME?hjxyfn( diff --git a/public/stylesheets/images/ui-icons_fadc7a_256x240.png b/public/stylesheets/images/ui-icons_fadc7a_256x240.png index f7a4dbfb00393bb7962889f8fa140f17cdd74c65..711a99d5fb4eaa3369028a81f32da49ea201f798 100644 GIT binary patch delta 4043 zcmXw*c|6mPAICRia~pHyUXI*Xu1XlGh~`LAk&zDNK61`y2z%%*`;@ukZKw`#t}A{quf2-mk~&@qWJ+l%B{umS6)BEiUZT9K8$%_+l;0OzcBm zEIOySP1f^6d(F#cW1gyod(f|0p1QOC)bswBcSVlcn~^|^u}$)!9~8&xXN*Lit(BYH zcDFQQky|p7YBvC7JnQS}AwmRg=+|QNUV?}L&>s#}xVuLMv%r@^n`1QjSRrRWXkyJ9 zmDE;*DRaVsT=#K{K8I64nWZmZ2CJZxwB5j90TQ>YE)IWoHc6kou#GbZu9V5G>|hYN zVRMW8lgBiqT0nUXp=u}>7WWEfCP@4Ui-9jfUP?*4MKVF17iwB3mm$LqK*1}l_(_B`9~^*~GUu$qmn-^aeh}Y>05iSV908MyziiVl>p& zj6~f1+CKsSC#VDGYM*~fdr1-dUBzMNK#Lyw4WLYPoxcz})!ixTGcfkrhx_9t z?S~vP21SEgu)b_~6a8De8+J+{PiDHB1J0K@t`zPj_oVf;F!)uM^iS&fV0bX;WAZ;V zr>s4n?qP9_e?fMWA+IPgmPhPSzB#eyTyFX6!7n@*DlKK1Veq!gc+Hb5-d;~WPQE@vX$1JW2dd+>ea>3#CNb?R4k~RU!qW{HFL!Xx5c*m>p<;i za15`C5GqH-{Q~y|0+R9DnMzaWw{F0>zjW=J-ufAHZ->bT731?p zOD7gOc%3;Mu<5ZiZ__FhJu{2k%`iI&aQlp!2 zws3}z=_8(`W2Xf-GOVt1m3$_nZ>lF{S9H`*c^Dq)z<{V=TU3I3bk%zv&aXh6MQNwH zMfpOLCxKm*p9K!VI0aI!pGLCIpON+mEYvx{N7&KnRf9tO31IHjG!+7C|Lu1~`jZ-H zwCQ8q8B^quk#Eq8=209Tg2gfTBO9S0ZZI}0ZqkU*`_(_Bcr}5v{~6&M5w>k$N}zV9 z2^q||)dW=~`LiVN<8QK*0+vzrc;*qEzyheW_(mAviI!yC`ACU^+Jk9+Oln#jF{fh( zLbIgwA|g2YGmO}nt&@edRn~F@;^7K?J(7j9-o!^Kv54iBrf*mnXDb#Y;Q_7N&jRg^ z@M8>2%m|I+yL(e!C%jL!-@MH`VIqJE&~IuNSYeaGXIV+pwwi!65E&_PtpKW_u1;t! zUBS`rp7`!_AW-dZ3>M*;;ORVq?xvnhUez|87Z?_g^l>4Q!3r1xJLo4E;RD3rmVB+% zvcB+~VrhWcpBG*dDn)2F!a^0+U#M%7Eo!L0UmtxLWa zB|!K$Qks0`00}CNJr>CQdhNr~zzwZOKNPI}*8L$0gyS~lUkl4#3#)t%lTZz`xT2sC zaZAGc`@z3qH|&0QXLZf4-wTm-9lch6X(w>YGCY?#oZwYUnkA+?8F)wWQq9^%QTSQO;d%xhGZJU&9tTHxV z#U9_!QwzZ{)0^youAN0kuA4F{%6M+{W6upddRLJ3?#;GyfxPjj(JBUN*m+{IW8nBR zIRN*nqu|Dizr!A+#-%7PPDc_H&JtWGRZQJaP};Coy5Cx102Qo^w_}^ckgW%vGV)LI zZ$e~4bVem~K1GSwoSc^}SY&H?J9scn$-ZJfnHEPMmRfnnytYr`Q*zeiYrshPwx2F| zKb_YumV++);&U~8T4z{4FIq3VyAhHF7!f8jk5M{zMBh9J#M+zS59izMa|?Da)Om`Dvx zzol*neb#I_^7I2I4tZ5zW0z$*M*|$2gYWR&?%-RIwEN9Z1|p#vHwfcXy`HVH;@-Yg zp1gkjz+UmR+%8QqUKa$kp|zY}bF^Em$P=Lh;gU+hGkX?XpofgYdACwNO`+b4R|a0+ z8<+N4qbiPZKCP9z|F-yWXUGp;0_Ai~j4VDNqAkWJeB zsDyemKZfg`Zwo{2jLcF&A)7#5&v|z`x^HNH{{s{lj-FNeg zkhy>WFa^D`>3d=VqrhIrr^(Pb4e2__DJ}{qT7EMPU{~4I`5|+t?$XJChx!8_OROjH z4ogroCKKnXiyw4N6$L#IpW1MyG>T?zGFQHPX=QJNRY(vTepnmyt7AWOUTm%a>b>l{4NXv2z-nnXbomY24 zJ^x4mzV6f2fNrg2GVHcyhryl#yuVZk`WlgS_2AB*#N1Ee>8O(;+Z2xNp;3(M8O796 zLwPq^ln>>2f4`w*MI71t#agk}HpjgeK)jSG{;5xC>m@m1Z?PRJMK&)_=&M&chy=+J zWEy(BplP-vZuU(qmx!d0dJcw$NggLV8QAYW(iXAfyd0&Zok~BdeSD7d8t96=dIuw( zT`}PcF?P;5Y|?2ZB#ra-yK#n$vrqMyLXg1Fuk!bKfrLmX#a=2I|o2(d8vNfEf;U`~@5SZV&BHqANdeF(9+ubidb=Pzu4CHO}^oRf`AV5!>;=Kl3~k3a(E#?QOjkNRyKt zT>tj75Y5(uY|fT`+#qz=o(5R^+!r<&dwGP;JzkI5>=3qN$*D!(2@k6aZDBbI%Cuw& zsbzmz%m3jwn-|^KL|hU4V7ut@aAb1zfESw;K@o%S(Kzb8b_gr3_TqC)#HsyVZWolA zw*|ibkqd`(?+%VKBzRMC|DJ)}l&6162x;1B!J}P(kc+L2-Zs{@Akkg$6s?*fr;wk_wTMQ$?=^$HLA) z6(IW~YSVFurhHNlYBnmAhoRF_F%h($dBB}gf^nEkhXupIjPh@ZvRnIMHYnRH9<nvYnh8=^CXSVnqn%IVIv^OEyTR8~P^xXqk5pWH0HEVp(!h zI00>FYWYNp)RvgJWM?xeSvaBBwY<3#3aH?72LI`{j^cYexQu=g+Y05X338J^=f5)Z z+yCXAp&3unY>i^4%QxP)2F=QC1M6VvJ@AVNFSm{b2k+;@6KlbF+)fUyv(gbe@nnXO z*_W@0Xb1G{9Q+_O{s=)Ilt<@%IWbOIxPRKGjZxaX%6b@eIzECf{ z@;D2Y z0a}-6vBn5hu>2xvjIC{io;sP}HQn{2HKkIyq-GIyn}oV|`DBV$eCPYDg=VKf~M%DmHInYm5VrC|mvFLsd_w#VWx9wYm{82OabMS@_M%nwj&Diq{T=+C> zYO5LbPeuJ(QeWFn<(nfLIR(l_MVf@^hmb{W&SyhG94y;AA1^X|K0z8WLWT~>Qr?^Io)Lp;@!HxKxPZ0x4pxn qSjY#HREPziBU_jER_>FU-`mE$a{&_4r-N)jf3Y}=HmfwnME?hjxyfn( delta 5037 zcmV;e6H@GvBI_xT90dWdPI_;#Ayol?6JJS0K~#90?Oh9F+qMw~$x2$Nn4pts2rkicqs$`0#`RooLep(~$=Dh)P5Z%?UHqR&Q(6DAs zo2i7L)F=(Hpn)7PCAh>RawtSt6Ie?Yrcr}TvtCM@0~9J5v`du%z{CZO%CUM>n6g2^ zw6M16e*bx7EmR#$X=U>lQ>#;dC`*9q#fTgllsq8o>tccY+nmiFk0xM;t zjqt1(`8g^%#{U^g8Y<;hMEalMZ}XMTz)NcBWE( zQ<#bcNToJ+-(PmY4PzZu%YrqQd6z(b8TV4xsvnKbBhdy*Iqd8rfBp|4>W;qoO3MX0 z&SaG&hb|4oGeB-uWp|zAC7E~QJ|h#C0nm29v49Xw7ev4s@o%39j}Xv&`_f(^ZbuPHbYz#BobCFnnASABo5Nn(idW!4EEoTfEF{r zQZ$&?ZS&}F(B+p^=wY6u=X3paLtQt2JP>6!EWErl38&i9 z$=}Ma))`e54v*Eu99I{dr!ATK%|pKy^vHHMqQiAmdnGErv^n|GBG2W&R)p-+dj8>0 z#73NlRk;Wh1vuf+j41$Fe!MFg;3eW%tu*gbRAE;{-BS)%)5v9Nbq19YUenQ&Nf__V zO%G=;Um6Zgy>DfIBH1RYei>~bgD2t&bNWw{h|^b+H}oxqvwz^%JB2eI;du3C684e^ zH+iFSh#J%*L%E&gD>-9pO&47*^*C`^j2L7iQoZqDko^F^ui5vi=WAhAUTda=_9Of+ zP(Lblt|Z2Oj|j5QWeipgN@dox8~pofF0j|UVP@-8ytf91JLkd+k1Rr z!7M*(zJNt9cE!Mhg=+&$w#+}-1^}aPJv(IAcx)Tk9Rm*)z(vk`6TkRDIzM5MO)|eE zM{$NiE0t&y0f$2cK6H>}Urzxz!LjhbWcZD!Fn3UFwndO&zzy|5LCJ#0!&~VtpTL@t zdJ$x`VE|Tt#DLQyPvkTv^9L5{(`)oU)9C!hRs^wgfa~S*p9~QvkUT+lhRkLM9WnT}$o|QtOM$r4oO| zwhTcR4^;G1jM43v^lfK4EG|zT(0kbcDTL<%D{3tReK+VaqV`hYaOw^ zsErW<9q)@TzAzkuSKz`cKcnmC720vIB1c!tsG6GPV0X==`|DS~LF3`O=jTS|EzJ;M zVbklY0A;IPoo*t~7@1;CLS4LYD>bFwzX5-o{S7mmM_p6HjxI3+Sz&mo%PH~R!-EHi z)m!|3<-0thzN9PYKJv#4b8Wv7-{@40))&}@DzkIRw4L(AEKA$Auw1H$_1kG`U>{}R z-yH*TS-!#>5das;IeB5)(5VWjOrv}T&z>m;Ok1!FR5wSX2&U@)6~MRmQv4IZ^-#VL zP`ZvJ(yDt1%*+;mq)ro2N%!`lFV=DRNjGCI*2m1uPEOq7k#KN{6I8aqC0 zJW)4B;^=nX%|RJJY|X%f2Z$ey49lP!RRivh7{IyS^uil#Mg}O<{d9mffV)2cyz6sQ z>4sbm0Pn#I`TJH+!??et6Rz-fSAe+z2lBxplTXypqYbz-1>JR|yzTzM(8Lv#Ch1sz zdZY#T?x)vyb_O#C3|x0Vz;{1A1~LN4R$SE&jMw+XKqaBWaj2NvKt>!}s|P!##2@~? zRVWI7zEao(UO2dfYnDHBONHP3ig!vVw(q9C1Om;Abm22pnEMSIOJHk^-uaY~k%G4l zB0@cY-2uIs9w>nC!dbWcpnIjX(Zq2vf$oOzS zm7j~?HS@4h8!uiQPY*l;Yc2ixMPxbY6uP>+It^>Zgd zR)Fy>$YxZ=;GXorea%NQb_RO|*(`imK^UaW^4K;8L5EIR$+$wX{oZ=7*}8!h#qZ#9 z1|nA1Q$U-*Cc#Q7wCS1@4IO2^UcmGcY@*F7U;a}ZH%md6G zwF=n1EvP@!{(u`01##z~cdClVkJVWO(nkd}joMTzP8wT~J_HN&W?5tagx>rH;5Nyr z*c04+ds=Dt?2L75pwR{1M4y}TO4FYj{L%5FQ(Rtp3`_+qbw;}U5_G(O%S(A^f)Mo+ zeQM*`WO8OC<;^qPJV7xqhsU3L3=|k~KA-D|*E&OFpqeh1##Odov{Ef5M90p%~n*GpK%NTU)M(lmCEBez;i_; zT6eh50P|tj8qUp+7TZRDRf62JP@31uJ%N7Uvq{8|`yqTNn_e3Rt_=g%hJlv!`^HbNPG-HZy~9*+dSUtn@EQxofL1_HFE76q z^3YT5&s|f0-Or7ycX+>4Zrj>{52{*6<0A-8{vz21z`xC5U2}ndwTji8=(hG)Hww#O z#{HuX*75pBdv@&j!nB3yKfYG3>9kj0!Hv#FSa&1~R2fe=6Mx=SE6X1WbznCBbBw*X_#_TN38IHRRGI5Q8cxl1%^@OB2U?h*f{9C^SKX{CG_ zKz1-=P8EfN%=Y{5*#i%owW-E-E6k}e6^2)u(&f8yO54qUJUvmJoo%$^TRq{?7zXYr z1C~KEOc;>Brrk=_;7lIjg&9~02#?IjNCO+orpduJI@PTjp&xo_O8sM|4=0rWW+s7& zkLgU?-E^6p%?AL?c6~9!?lsd4%zTBz#wDBEwv8p=GSKnwZ$rSAZ6M>`@n3kVT!8J~ zW3(w&{{vxvMzb?KZVyI$cLtkb4fvpy9v>{1g?^a6(93fGOY?9&?DF+OV%Cawra3W- zwr(Y3(c|t8@8SJU^UGKpI3M8dJAfbh+*Gqz0x@#}=Ykw~$1*Yn@c3bWdWbS`BjQin<9t9>RJymF$DQ&2 zVEj|=9Zk<%0lo`2X5PVo^8xODH{hny4Y?T^A@KfS;Idio-WpL*5HcYA{XzR<;Jzi0 zkr5!>)(-SkS-=36d#I<{3>`tL>nlI!*P)D08t$K{`9T+>)oVX zsMpAU7GC6oN<{8pqUAv_@+cs9xRQl>5x5@V$-@GI$U%vFge;1m$=WM`n1FgK7z&_= zfx`=61oqnncoRH$7s$xS$mqx3mEirVJU$L^TbmJ)2t2xPC;bW)VRn6HwNOi(hm#3F zbmYULcxGzEIG_-I0zZ6c*ltdnaIn+XVdy@C|}q z8GSiGkRx!4$M4TQ@+>E?Ku83d3`2fc0!RhM${!JfRWN+ZVo&0TfP4mH$@{O+a0xwu zk@Rb0+YI)bzIO#GBO~LXqu`S_(SJ)m5)g^pZ^ymR1Op^o(D~R1g~rcDhv$a{(p3J8M3{1|`y3Putzj(Y_VM$Y4ajEs*Od+ou2nPOTg zEL^52Ji8KLfaAb0^XYG}jNTW%C5)ASO5VU$K|S~XBTCkv--ZnLnFUM>GysB#yOaQ) zY)=aTFWjqQ#Hxo3^@%80fQhsKCV;So?A)&T1DRl*p4}K3SjQh)@);U;^beadGBS=1 z;k(v8Dnw@%zTzo^2^*jP@#ipy72UDi5rx<)vTt=tC_S^}*-hz|UJf8QNd;DaAbl*Y zW`qEO`2GTgKCLSu0KPtfl|PyWAcnd?w7rw~W&CPFfJ}hv!we3S7nMVDdLN;pSjgF{$MP zg!RN@Km=xlPA`MWs>i=(o|lM!9#G1IR$VG+nxfRe47%&#mv=6a5&-CzqJw)kx@iGO z>ves?@wrNFGn~Nb#r)?$1t5=hW%cFt59}1NV!i-m^*?vvQ2G*uf_cbS;T6k*tN_8q z#YMUWz;fBOqN#aFyeha-e^vl8enkZERHlCV6g^Jm>3_92Wz``GDtqXEEJpAxx$mI_ z@C!OFS+tMA9cL2=ASmyd0+aZ}ULh`kYN>!61~kZCHU;mB)V1vbHI{D=7zr5qLVbLG z`da`E*Ilj=J402q3R}EV+9`mM(P696R6g@J0u$kCRe^4tLu6VTF=z%p}mb%QIek@ z4zPj#bHjk^0&+o#uP<08bKm?~&CoZ0Le{6wcm23ew zH{I-miZ?{J z2Rf^(ZQ0WGjqkgE-+K|xycCBOfU7Vqyq^a$+f-G5_e|T?0#L+;@9|h4Kp^SYj(klc zu|$OMt1ouY1$q`A4uK!!SQOsX~wpa2fs1^7Ve-n&3X z#)HRygML43+0AU>$A;W5tebaikyHZp(!xxY78}yXhEl$6@yABIqPLS*7h>k$K_!c- zlk-XUXV&loLk;li#Vgw8 z)i9uG$UUdXSyLGq8J`IFeSjhQ7U|o~=yl6~+m;>zzYp*MERa?&Lc2Beor Date: Mon, 20 Feb 2012 21:56:36 -0500 Subject: [PATCH 026/134] Fix: the context view doesn't show pending or due todos --- app/controllers/contexts_controller.rb | 2 +- features/context_list.feature | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/controllers/contexts_controller.rb b/app/controllers/contexts_controller.rb index 7d8a14ea..fb2253f7 100644 --- a/app/controllers/contexts_controller.rb +++ b/app/controllers/contexts_controller.rb @@ -277,7 +277,7 @@ class ContextsController < ApplicationController # 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.active( + @not_done_todos = @context.todos.not_completed( :order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC", :include => Todo::DEFAULT_INCLUDES) diff --git a/features/context_list.feature b/features/context_list.feature index 140189b0..22f2ac7d 100644 --- a/features/context_list.feature +++ b/features/context_list.feature @@ -27,6 +27,15 @@ Feature: Manage the list of contexts And I follow "@computer" Then I should be on the context page for "@computer" + Scenario: The context view shows all todos + Given I have a todo "foo" in the context "@bar" which is due tomorrow + Given I have a deferred todo "foo2" in the context "@bar" + Given I have a todo "foo3" in the context "@bar" + When I go to the contexts page + And I follow "@bar" + Then I should be on the context page for "@bar" + And the badge should show 3 + @selenium Scenario: Delete context from context page should update badge Given I have a context called "@computer" From 0f39034986030e81355d212f8d72a32fd232dee9 Mon Sep 17 00:00:00 2001 From: Sebastian Fischmeister Date: Fri, 24 Feb 2012 16:46:11 -0500 Subject: [PATCH 027/134] removed whitespaces and matched the style with the todo_controller.rb (unless) --- app/controllers/projects_controller.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 2cfe530d..2adea3c9 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -97,9 +97,9 @@ class ProjectsController < ApplicationController @done = {} @done = @project.todos.find_in_state(:all, :completed, - :order => "todos.completed_at DESC", - :limit => current_user.prefs.show_number_completed, - :include => Todo::DEFAULT_INCLUDES) if current_user.prefs.show_number_completed > 0 + :order => "todos.completed_at DESC", + :limit => current_user.prefs.show_number_completed, + :include => Todo::DEFAULT_INCLUDES) unless current_user.prefs.show_number_completed == 0 @count = @not_done.size @down_count = @count + @deferred.size + @pending.size From 51b44a9ec9115821ff4987f5696162fcab6b99fd Mon Sep 17 00:00:00 2001 From: tim madden Date: Wed, 22 Feb 2012 10:53:48 -0600 Subject: [PATCH 028/134] Ticket #1241 - fix for layout of dependences on add / edit forms --- public/stylesheets/standard.css | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/public/stylesheets/standard.css b/public/stylesheets/standard.css index 88693a9f..41b82dd4 100644 --- a/public/stylesheets/standard.css +++ b/public/stylesheets/standard.css @@ -6,6 +6,10 @@ float:right; } +div.depends_on { + clear:both; +} + div.depends_on label { float: left; } @@ -361,7 +365,7 @@ div#input_box { } .selected_predecessors { - clear:right; + clear:both; } form.new_todo_form ul.predecessor_list, From 883296e70eb123b1c1bd2a6c2a76c834d1fa59c0 Mon Sep 17 00:00:00 2001 From: Tim Madden Date: Thu, 1 Mar 2012 11:55:48 -0600 Subject: [PATCH 029/134] test for tags prepop --- features/tagging_todos.feature | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/features/tagging_todos.feature b/features/tagging_todos.feature index e6d5ecaa..9e4847cf 100644 --- a/features/tagging_todos.feature +++ b/features/tagging_todos.feature @@ -75,4 +75,10 @@ Feature: Tagging todos Then the tag field in the new todo form should be "tests" # and the tag field should be prefilled after submitting a new todo When I submit a new action with description "are my tags prefilled" - Then the tags of "are my tags prefilled" should be "tests" \ No newline at end of file + Then the tags of "are my tags prefilled" should be "tests" + + @selenium + Scenario: If there are todos for a tag, when viewing the tag's page, the Tags field for new todos should be defaulted to that tag + Given I have a todo "migrate old scripts" in context "@pc" with tags "starred" + When I go to the tag page for "starred" + Then the tag field in the new todo form should be "starred" From 8c18c2888a9466aa4c0151e263fd8298dbe873cb Mon Sep 17 00:00:00 2001 From: tim madden Date: Thu, 16 Feb 2012 11:08:25 -0600 Subject: [PATCH 030/134] updates to mobile layout removing count and date as space is at a premium and not essential making menu padding larger to provide more space to click removing duplicated menus to stop wrapping Increasing the top margin above the content div to reduce fat fingers from clicking links in the content instead of the intended nav links Cleaning up some unused selectors and consistent spacing, etc... --- app/views/layouts/mobile.m.erb | 20 +++++++------------- public/stylesheets/mobile.css | 19 +++++++------------ 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/app/views/layouts/mobile.m.erb b/app/views/layouts/mobile.m.erb index e11432da..5bca2cc1 100644 --- a/app/views/layouts/mobile.m.erb +++ b/app/views/layouts/mobile.m.erb @@ -12,26 +12,20 @@ <%= @page_title %> <% if current_user && !current_user.prefs.nil? -%> -

        <% if @down_count -%><%= @down_count %><% end -%> <%= - l(Date.today, :format => current_user.prefs.title_date_format) -%>

        +
        <%= render_flash -%><%= yield -%>

        <% if current_user && !current_user.prefs.nil? -%> <% end -%> diff --git a/public/stylesheets/mobile.css b/public/stylesheets/mobile.css index f4795a55..03271345 100644 --- a/public/stylesheets/mobile.css +++ b/public/stylesheets/mobile.css @@ -4,7 +4,7 @@ body { } #content { - margin-top: 50px; + margin-top: 4em; } div.footer { @@ -178,9 +178,7 @@ span.r { background-color: #000000; clear: both; color: #EEEEEE; - height: 45px; left: 0; - margin-bottom: 5px; position: fixed; top: 0; width: 100%; @@ -190,19 +188,15 @@ span.r { .nav { color: #fff; background: #000; - padding-top: 0.2em; - padding-bottom: 0.2em; -} - -#topbar .nav { - padding-left:8px; - margin-bottom:0.3em; + padding-top: 0.75em; + padding-bottom: 0.75em; } .nav a, .nav a:link, .nav a:active, .nav a:visited { + background: #666; color: #fff; - padding-top: 1.0em; - padding-bottom: 0.5em; + padding: 0.5em; + margin-left:0.5em; } .nav a:focus, .nav a:hover, .nav a:active { @@ -221,6 +215,7 @@ span.r { table.c { margin-left: 5px; } + .mobile-done { display:inline; } From 6d50992dfb772dce22fea3748675a66f95a4619a Mon Sep 17 00:00:00 2001 From: tim madden Date: Wed, 22 Feb 2012 09:05:39 -0600 Subject: [PATCH 031/134] putting back the date and counter --- app/views/layouts/mobile.m.erb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/layouts/mobile.m.erb b/app/views/layouts/mobile.m.erb index 5bca2cc1..15d340b2 100644 --- a/app/views/layouts/mobile.m.erb +++ b/app/views/layouts/mobile.m.erb @@ -12,7 +12,8 @@ <%= @page_title %> <% if current_user && !current_user.prefs.nil? -%> -
        +

        <% if @down_count -%><%= @down_count %><% end -%> <%= + l(Date.today, :format => current_user.prefs.title_date_format) -%>

        + <% end -%> - - + \ No newline at end of file diff --git a/app/views/feedlist/_feed_for_project.html.erb b/app/views/feedlist/_feed_for_project.html.erb index 53d80462..0372e571 100644 --- a/app/views/feedlist/_feed_for_project.html.erb +++ b/app/views/feedlist/_feed_for_project.html.erb @@ -14,7 +14,7 @@
      • <%= t('common.numbered_step', :number => 2) %> - <%= t('feedlist.select_feed_for_project') %>
        -
      • <%= all_feed_links_for_project(project) %>
      • + <%= all_feed_links_for_project(project) %>
        diff --git a/app/views/todos/index.ics.erb b/app/views/todos/index.ics.erb index 7d90b64a..7fee3a19 100644 --- a/app/views/todos/index.ics.erb +++ b/app/views/todos/index.ics.erb @@ -1,6 +1,6 @@ BEGIN:VCALENDAR +PRODID:-//TRACKS//<%= TRACKS_VERSION %>//EN VERSION:2.0 -PRODID:-//rousette.org.uk//Tracks 1.04//EN CALSCALE:GREGORIAN METHOD:PUBLISH BEGIN:VTIMEZONE diff --git a/config/locales/en.yml b/config/locales/en.yml index a12d2dc8..da3e7b1c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -843,7 +843,7 @@ en: projects_and_actions: Active projects with their actions context_needed: There needs to be at least one context before you can request a feed actions_due_next_week: Actions due in 7 days or earlier - notice_incomplete_only: "Note: All feeds show only actions that have not been marked as done, unless stated otherwise." + notice_incomplete_only: "Note: All feeds show only actions that have not been marked as done, unless stated otherwise. These iCal feeds can be added to todo lists. If you want to show due todos in a calendar, use the iCal feed on the calendar page" all_actions: All actions actions_completed_last_week: Actions completed in the last 7 days context_centric_actions: Feeds for incomplete actions in a specific context From 04d2e47e23b1b0b961004c330a7f0c6aaa98af9f Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Sat, 24 Mar 2012 10:55:17 +0100 Subject: [PATCH 060/134] remove selenium environment. Not needed anymore. --- config/environments/selenium.rb | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 config/environments/selenium.rb diff --git a/config/environments/selenium.rb b/config/environments/selenium.rb deleted file mode 100644 index f7e812a6..00000000 --- a/config/environments/selenium.rb +++ /dev/null @@ -1,26 +0,0 @@ -# Edit at your own peril - it's recommended to regenerate this file -# in the future when you upgrade to a newer version of Cucumber. - -# IMPORTANT: Setting config.cache_classes to false is known to -# break Cucumber's use_transactional_fixtures method. -# For more information see https://rspec.lighthouseapp.com/projects/16211/tickets/165 -config.cache_classes = true - -# Log error messages when you accidentally call methods on nil. -config.whiny_nils = true - -# Show full error reports and disable caching -config.action_controller.consider_all_requests_local = true -config.action_controller.perform_caching = false - -# Disable request forgery protection in test environment -config.action_controller.allow_forgery_protection = false - -# Tell Action Mailer not to deliver emails to the real world. -# The :test delivery method accumulates sent emails in the -# ActionMailer::Base.deliveries array. -config.action_mailer.delivery_method = :test - -# Unique cookies -config.action_controller.session = { :key => 'TracksSelenium' } - From 923919e802b9e984cbaba84363bd7d0df12faaac Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Thu, 29 Mar 2012 15:17:36 +0200 Subject: [PATCH 061/134] update i18n using google translate for missing translations. Please check these translations! --- config/locales/cz.yml | 2082 +++++++++++++++++++++++++---------------- config/locales/de.yml | 812 ++++++++-------- config/locales/es.yml | 800 ++++++++-------- config/locales/fr.yml | 828 ++++++++-------- 4 files changed, 2489 insertions(+), 2033 deletions(-) diff --git a/config/locales/cz.yml b/config/locales/cz.yml index f99c46e2..96939e76 100755 --- a/config/locales/cz.yml +++ b/config/locales/cz.yml @@ -1,945 +1,1365 @@ ---- -cz: - layouts: - toggle_notes: Zobrazit/skrýt poznámky - toggle_contexts: "Přepnout sbalené kontexty" - toggle_contexts_title: "Zobrazí/skryje sbalené kontexty" - next_actions_rss_feed: RSS feed aktuálních úkolů - toggle_notes_title: Zobrazí/skryje všechny poznámky - mobile_navigation: - new_action: 0-Nový úkol - logout: Odhlásit - feeds: Feedy - starred: 4-Hvězdičky - projects: 3-Projekty - tickler: Tickler - contexts: 2-Kontexty - home: 1-Domů - navigation: - manage_users_title: Přidat nebo smazat uživatele - recurring_todos: Opakující se úkoly - api_docs: REST API Dokumenty - feeds: Feedy - starred: S hvězdou - notes_title: Zobrazit všechny poznámky - review_title: Provést revizi - stats: Statistiky - tickler_title: Tickler - manage_users: Správa uživatelů - export_title: Import a export dat - preferences: Nastavení - integrations_: Integrovat Tracks - feeds_title: Seznam dostupných feedů - calendar_title: Kalendář datovaných úkolů - completed_tasks: Hotové - stats_title: Zobrazí statistiky úkolů - tickler: Tickler - home_title: Domů - starred_title: Zobrazí úkoly s hvězdičkou - recurring_todos_title: Správa opakovaných úkolů - view: Ukázat - organize: Správa - completed_tasks_title: Hotové úkoly - home: Domů - export: Export - contexts_title: Kontexty - calendar: Kalendář - projects_title: Projekty - search: Hledat - preferences_title: Zobrazí možnosti nastavení - integrations: - opensearch_description: Prohledat Tracks - applescript_next_action_prompt: "Popis úkolu:" - gmail_description: Gadget pro Tracks do Gmailu - applescript_success_after_id: vytvořen - applescript_success_before_id: Nový úkol s ID - number: - format: +--- +cz: + common: + back: !binary | + WnDEm3Q= + + recurring_todos: "Opakovan\xC3\xA9 \xC3\xBAkoly" + actions: !binary | + w5prb2x5 + + third: !binary | + VMWZZXTDrQ== + + add: "P\xC5\x99idat" + previous: !binary | + UMWZZWRjaG96w60= + + go_back: !binary | + WnDEm3Q= + + logout: "Odhl\xC3\xA1sit" + second: !binary | + RHJ1aMO9 + + none: !binary | + xb3DoWRuw70= + + week: !binary | + dMO9ZGVu + + optional: "voliteln\xC3\xA9" + cancel: "Zru\xC5\xA1it" + month: !binary | + bcSbc8OtYw== + + forum: !binary | + RsOzcnVt + + server_error: Nastala chyba na serveru. + notes: "Pozn\xC3\xA1mky" + last: "Posledn\xC3\xAD" + projects: Projekty + review: Revize + action: !binary | + w5prb2w= + + project: Projekt + ok: Ok + contribute: !binary | + UMWZaXNwxJt0 + + first: !binary | + UHJ2bsOt + + website: "Webov\xC3\xA1 str\xC3\xA1nka" + numbered_step: Krok %{number} + errors_with_fields: !binary | + TmFzdGFseSBwb3TDrcW+ZSBzIG7DoXNsZWR1asOtY8OtbWkgcG9sw63EjWt5 + Og== + + create: "Vytvo\xC5\x99it" + sort: + by_task_count_title: "\xC5\x98adit podle po\xC4\x8Dtu \xC3\xBAkol\xC5\xAF" + by_task_count_title_confirm: "Ur\xC4\x8Dit\xC4\x9B chcete \xC5\x99adit tyto projekty podle po\xC4\x8Dtu \xC3\xBAkol\xC5\xAF? St\xC3\xA1vaj\xC3\xADc\xC3\xAD po\xC5\x99ad\xC3\xAD bude ztraceno." + alphabetically: "Abecedn\xC4\x9B" + sort: !binary | + xZhhZGl0 + + alphabetically_confirm: "Ur\xC4\x8Dit\xC4\x9B chcete \xC5\x99adit tyto projekty abecedn\xC4\x9B? St\xC3\xA1vaj\xC3\xADc\xC3\xAD po\xC5\x99ad\xC3\xAD bude ztraceno." + alphabetically_title: "Se\xC5\x99adit projekty abecedn\xC4\x9B" + by_task_count: "Podle po\xC4\x8Dtu \xC3\xBAkol\xC5\xAF" + drag_handle: !binary | + Q0hZxaQgTcSa + + months: !binary | + bcSbc8OtY2U= + + description: Popis + next: !binary | + RGFsxaHDrQ== + + fourth: !binary | + xIx0dnJ0w70= + + context: Kontext + todo: !binary | + w7prb2w= + + contexts: Kontexty + update: "Ulo\xC5\xBEit" + weeks: !binary | + dMO9ZG55 + + forth: !binary | + xIx0dnJ0w70= + + wiki: Wiki + bugs: Chyby + email: Email + ajaxError: "Chyba \xC4\x8Dten\xC3\xAD ze serveru" + search: Hledat + number: + format: separator: . precision: 3 delimiter: "," - human: - format: + human: + format: precision: 1 delimiter: "" - storage_units: + storage_units: format: "%n %u" - units: + units: kb: KB tb: TB gb: GB - byte: + byte: one: Byte - other: Bytů + other: !binary | + Qnl0xa8= + mb: MB - percentage: - format: + percentage: + format: delimiter: "" - currency: - format: + precision: + format: + delimiter: "" + currency: + format: format: "%u%n" unit: $ separator: . precision: 2 delimiter: "," - precision: - format: - delimiter: "" - common: - back: Zpět - third: Třetí - recurring_todos: Opakované úkoly - actions: Úkoly - add: Přidat - previous: Předchozí - logout: Odhlásit - go_back: Zpět - optional: volitelné - week: týden - cancel: Zrušit - none: Žádný - second: Druhý - month: měsíc - server_error: Nastala chyba na serveru. - forum: Fórum - notes: Poznámky - review: Revize - last: Poslední - projects: Projekty - action: Úkol - project: Projekt - ok: Ok - contribute: Přispět - website: Webová stránka - first: První - numbered_step: Krok %{number} - sort: - by_task_count_title: Řadit podle počtu úkolů - by_task_count_title_confirm: Určitě chcete řadit tyto projekty podle počtu úkolů? Stávající pořadí bude ztraceno. - alphabetically: Abecedně - alphabetically_confirm: Určitě chcete řadit tyto projekty abecedně? Stávající pořadí bude ztraceno. - alphabetically_title: Seřadit projekty abecedně - sort: Řadit - by_task_count: Podle počtu úkolů - fourth: Čtvrtý - create: Vytvořit - months: měsíce - contexts: Kontexty - errors_with_fields: "Nastaly potíže s následujícími políčky:" - next: Další - todo: úkol - context: Kontext - drag_handle: CHYŤ MĚ - description: Popis - bugs: Chyby - update: Uložit - forth: Čtvrtý - weeks: týdny - wiki: Wiki - email: Email - search: Hledat - ajaxError: Chyba čtení ze serveru - data: - import_successful: Import byl úspěšný. - import_errors: Při importu došlo k chybám - models: - project: - feed_title: Projekty - feed_description: Všechny projekty uživatele %{username} - todo: - error_date_must_be_future: datum musí být v budoucnosti - user: - error_context_not_associated: Kontext %{context} nepatří uživateli %{user}. - error_project_not_associated: Projekt %{project} nepatří uživateli %{user}. - preference: - due_on: Plánováno na %{date} - due_in: Plánováno za %{days} dní - due_styles: - - Plánováno za ___ dní - - Plánováno na _______ - activerecord: - attributes: - project: - name: Název - default_tags: Výchozí štítky - default_context_name: Výchozí kontext + layouts: + toggle_contexts_title: "Zobraz\xC3\xAD/skryje sbalen\xC3\xA9 kontexty" + toggle_contexts: "P\xC5\x99epnout sbalen\xC3\xA9 kontexty" + toggle_notes: "Zobrazit/skr\xC3\xBDt pozn\xC3\xA1mky" + next_actions_rss_feed: "RSS feed aktu\xC3\xA1ln\xC3\xADch \xC3\xBAkol\xC5\xAF" + toggle_notes_title: "Zobraz\xC3\xAD/skryje v\xC5\xA1echny pozn\xC3\xA1mky" + mobile_navigation: + new_action: !binary | + MC1Ob3bDvSDDumtvbA== + + logout: "Odhl\xC3\xA1sit" + feeds: Feedy + starred: !binary | + NC1IdsSbemRpxI1reQ== + + projects: 3-Projekty + tickler: Tickler + contexts: 2-Kontexty + home: "1-Dom\xC5\xAF" + navigation: + api_docs: REST API Dokumenty + manage_users_title: "P\xC5\x99idat nebo smazat u\xC5\xBEivatele" + recurring_todos: "Opakuj\xC3\xADc\xC3\xAD se \xC3\xBAkoly" + feeds: Feedy + stats: Statistiky + starred: "S hv\xC4\x9Bzdou" + notes_title: "Zobrazit v\xC5\xA1echny pozn\xC3\xA1mky" + manage_users: !binary | + U3Byw6F2YSB1xb5pdmF0ZWzFrw== + + tickler_title: Tickler + integrations_: Integrovat Tracks + export_title: Import a export dat + preferences: "Nastaven\xC3\xAD" + feeds_title: "Seznam dostupn\xC3\xBDch feed\xC5\xAF" + calendar_title: !binary | + S2FsZW5kw6HFmSBkYXRvdmFuw71jaCDDumtvbMWv + + home_title: !binary | + RG9txa8= + + tickler: Tickler + starred_title: "Zobraz\xC3\xAD \xC3\xBAkoly s hv\xC4\x9Bzdi\xC4\x8Dkou" + recurring_todos_title: "Spr\xC3\xA1va opakovan\xC3\xBDch \xC3\xBAkol\xC5\xAF" + completed_tasks: "Hotov\xC3\xA9" + stats_title: "Zobraz\xC3\xAD statistiky \xC3\xBAkol\xC5\xAF" + view: "Uk\xC3\xA1zat" + organize: "Spr\xC3\xA1va" + completed_tasks_title: "Hotov\xC3\xA9 \xC3\xBAkoly" + home: !binary | + RG9txa8= + + contexts_title: Kontexty + export: Export + preferences_title: "Zobraz\xC3\xAD mo\xC5\xBEnosti nastaven\xC3\xAD" + review_title: "Prov\xC3\xA9st revizi" + search: Hledat + projects_title: Projekty + calendar: !binary | + S2FsZW5kw6HFmQ== + + integrations: + opensearch_description: Prohledat Tracks + gmail_description: Gadget pro Tracks do Gmailu + applescript_next_action_prompt: "Popis \xC3\xBAkolu:" + applescript_success_after_id: "vytvo\xC5\x99en" + applescript_success_before_id: "Nov\xC3\xBD \xC3\xBAkol s ID" + activerecord: + attributes: + project: + name: !binary | + TsOhemV2 + + default_tags: !binary | + VsO9Y2hvesOtIMWhdMOtdGt5 + + default_context_name: "V\xC3\xBDchoz\xC3\xAD kontext" description: Popis - todo: - predecessors: Závisí na + todo: show_from: Zobrazovat od - notes: Poznámky + predecessors: !binary | + WsOhdmlzw60gbmE= + + notes: "Pozn\xC3\xA1mky" project: Projekt - context: Kontext description: Popis - due: Plánováno na - user: - last_name: Jméno - first_name: Příjmení - preference: - show_hidden_projects_in_sidebar: Zobrazovat skryté projekty v sidebaru - date_format: Formát data - show_hidden_contexts_in_sidebar: Zobrazovat skryté kontexty v sidebaru - mobile_todos_per_page: Úkolů na stránku (mobilní zobrazení) - verbose_action_descriptors: Ukecané popisovače úkolů - staleness_starts: Jako prošlé označit projekty starší než - review_period: Interval revize projektů - sms_context: Výchozí emailový kontext - title_date_format: Formát data nadpisu - show_number_completed: Počet hotových úkolů k zobrazení - refresh: Interval obnovení stránky (v minutách) - week_starts: Začátek týdne - last_name: Příjmení - locale: Lokále - due_style: Zobrazení datovaných úkolů - time_zone: Časové pásmo - show_project_on_todo_done: Po splnění úkolu přejít na projekt + context: Kontext + due: "Pl\xC3\xA1nov\xC3\xA1no na" + user: + last_name: !binary | + Sm3DqW5v + + first_name: !binary | + UMWZw61qbWVuw60= + + preference: + show_hidden_projects_in_sidebar: "Zobrazovat skryt\xC3\xA9 projekty v sidebaru" + date_format: "Form\xC3\xA1t data" + show_hidden_contexts_in_sidebar: "Zobrazovat skryt\xC3\xA9 kontexty v sidebaru" + mobile_todos_per_page: "\xC3\x9Akol\xC5\xAF na str\xC3\xA1nku (mobiln\xC3\xAD zobrazen\xC3\xAD)" + staleness_starts: "Jako pro\xC5\xA1l\xC3\xA9 ozna\xC4\x8Dit projekty star\xC5\xA1\xC3\xAD ne\xC5\xBE" + verbose_action_descriptors: "Ukecan\xC3\xA9 popisova\xC4\x8De \xC3\xBAkol\xC5\xAF" + sms_context: "V\xC3\xBDchoz\xC3\xAD emailov\xC3\xBD kontext" + show_number_completed: "Po\xC4\x8Det hotov\xC3\xBDch \xC3\xBAkol\xC5\xAF k zobrazen\xC3\xAD" + title_date_format: "Form\xC3\xA1t data nadpisu" + refresh: "Interval obnoven\xC3\xAD str\xC3\xA1nky (v minut\xC3\xA1ch)" + week_starts: !binary | + WmHEjcOhdGVrIHTDvWRuZQ== + + last_name: !binary | + UMWZw61qbWVuw60= + + locale: "Lok\xC3\xA1le" + due_style: "Zobrazen\xC3\xAD datovan\xC3\xBDch \xC3\xBAkol\xC5\xAF" + time_zone: !binary | + xIxhc292w6kgcMOhc21v + sms_email: SMS email - first_name: Jméno - show_completed_projects_in_sidebar: Zobrazovat hotové projekty v sidebaru - errors: - messages: - greater_than_or_equal_to: musí být větší nebo rovno %{count} - record_invalid: "Problém s daty: %{errors}" - confirmation: se neshoduje s ověřením - less_than_or_equal_to: musí být menší nebo rovno %{count} - blank: nesmí být prázdné - invalid: nesmí obsahovat čárku (',') - exclusion: je rezervované + show_project_on_todo_done: "Po spln\xC4\x9Bn\xC3\xAD \xC3\xBAkolu p\xC5\x99ej\xC3\xADt na projekt" + show_completed_projects_in_sidebar: "Zobrazovat hotov\xC3\xA9 projekty v sidebaru" + review_period: "Interval revize projekt\xC5\xAF" + first_name: !binary | + Sm3DqW5v + + errors: + models: + project: + attributes: + name: + blank: "projekt mus\xC3\xAD m\xC3\xADt n\xC3\xA1zev" + too_long: "n\xC3\xA1zev projektu mus\xC3\xAD b\xC3\xBDt krat\xC5\xA1\xC3\xAD ne\xC5\xBE 256 znak\xC5\xAF" + taken: "u\xC5\xBE existuje" + messages: + record_invalid: "Probl\xC3\xA9m s daty: %{errors}" + greater_than_or_equal_to: "mus\xC3\xAD b\xC3\xBDt v\xC4\x9Bt\xC5\xA1\xC3\xAD nebo rovno %{count}" + confirmation: "se neshoduje s ov\xC4\x9B\xC5\x99en\xC3\xADm" + less_than_or_equal_to: "mus\xC3\xAD b\xC3\xBDt men\xC5\xA1\xC3\xAD nebo rovno %{count}" + blank: !binary | + bmVzbcOtIGLDvXQgcHLDoXpkbsOp + + exclusion: "je rezervovan\xC3\xA9" + invalid: "nesm\xC3\xAD obsahovat \xC4\x8D\xC3\xA1rku (',')" odd: must be odd even: must be even - too_short: je příliš krátké (minimum je %{count} znaků) - empty: nesmí být prázdné - wrong_length: nemá správnou délku (má mít %{count} znaků) - less_than: musí být menší než %{count} - greater_than: musí být větší než %{count} - equal_to: se musí rovnat %{count} - accepted: musí být akceptováno - too_long: je příliš dlouhé (maximum je %{count} znaků) - taken: už bylo zabráno - inclusion: není na seznamu - not_a_number: není číslo - models: - project: - attributes: - name: - blank: projekt musí mít název - too_long: název projektu musí být kratší než 256 znaků - taken: už existuje - full_messages: + empty: !binary | + bmVzbcOtIGLDvXQgcHLDoXpkbsOp + + too_short: "je p\xC5\x99\xC3\xADli\xC5\xA1 kr\xC3\xA1tk\xC3\xA9 (minimum je %{count} znak\xC5\xAF)" + wrong_length: "nem\xC3\xA1 spr\xC3\xA1vnou d\xC3\xA9lku (m\xC3\xA1 m\xC3\xADt %{count} znak\xC5\xAF)" + less_than: !binary | + bXVzw60gYsO9dCBtZW7FocOtIG5lxb4gJXtjb3VudH0= + + greater_than: !binary | + bXVzw60gYsO9dCB2xJt0xaHDrSBuZcW+ICV7Y291bnR9 + + equal_to: "se mus\xC3\xAD rovnat %{count}" + accepted: "mus\xC3\xAD b\xC3\xBDt akceptov\xC3\xA1no" + too_long: "je p\xC5\x99\xC3\xADli\xC5\xA1 dlouh\xC3\xA9 (maximum je %{count} znak\xC5\xAF)" + taken: "u\xC5\xBE bylo zabr\xC3\xA1no" + inclusion: "nen\xC3\xAD na seznamu" + not_a_number: !binary | + bmVuw60gxI3DrXNsbw== + + template: + body: !binary | + TmFzdGFseSBwb3TDrcW+ZSBzIG7DoXNsZWR1asOtY8OtbWkgcG9sw63EjWt5 + Og== + + header: + one: "jedna chyba br\xC3\xA1n\xC3\xAD ulo\xC5\xBEen\xC3\xAD tohoto objektu %{model}" + other: "%{count} chyb br\xC3\xA1n\xC3\xAD ulo\xC5\xBEen\xC3\xAD tohoto objektu %{model}" + full_messages: format: "%{attribute} %{message}" - template: - body: "Nastaly potíže s následujícími políčky:" - header: - one: jedna chyba brání uložení tohoto objektu %{model} - other: "%{count} chyb brání uložení tohoto objektu %{model}" - stats: - tag_cloud_title: Mrak štítků pro všechny úkly - tag_cloud_description: Tento mrak zahrnuje štítky všech úkolů (hotových, nehotových, viditelných i skrytých) - tag_cloud_90days_title: Značky úkolů z posledních 90-ti dní - actions: Úkoly - totals_active_project_count: Znich %{count} je aktivních projeků - actions_last_year_legend: - number_of_actions: Počet úklolů - months_ago: měsíců zpět - totals_first_action: Od vašeho prvního úkolu %{date} - actions_avg_completion_time: Pro všechny vaše hotové úkoly je průměrný čas dokončení %{count} dní. - top10_longrunning: 10 nejdéle běžících projektů - actions_dow_30days_title: Dny v týdnu (posleních 30 dní) - legend: - actions: Úkoly - number_of_days: Před kolika dny - number_of_actions: Počet úkolů - day_of_week: Den v týdnu - percentage: Podíl - running_time: Čas k dokončení úkolu (týdny) - months_ago: měsíců zpět - current_running_time_of_incomplete_visible_actions: Aktuální čas běhu nedokončených viditelných úkolů - totals_deferred_actions: z nichž %{count} jsou odložené úkoly v Ticlkeru - running_time_legend: - actions: Úkoly - percentage: Podíl - weeks: Čas běhu úkolu (týdny). Klepněte na sloupec pro další info - totals_action_count: máte celkem %{count} úkolů - totals_incomplete_actions: Máte %{count} nehotových úkolů - totals_unique_tags: Z těchto štítků je %{count} unikátních. - actions_avg_completed_30days: a dokončeno průměrně %{count} úkolů za den. - top5_contexts: Top 5 kontextů - actions_lastyear_title: Úkoly za posledních 12 měsíců - totals_actions_completed: "%{count} z nich je hotových." - totals_context_count: Máte %{count} kontextů. - totals_visible_context_count: Z nich je %{count} viditelných kontextů - totals_blocked_actions: "%{count} je závislých na dokončení jiných akcí." + data: + import_successful: !binary | + SW1wb3J0IGJ5bCDDunNwxJvFoW7DvS4= + + import_errors: "P\xC5\x99i importu do\xC5\xA1lo k chyb\xC3\xA1m" + models: + project: + feed_title: Projekty + feed_description: "V\xC5\xA1echny projekty u\xC5\xBEivatele %{username}" + todo: + error_date_must_be_future: "datum mus\xC3\xAD b\xC3\xBDt v budoucnosti" + user: + error_context_not_associated: "Kontext %{context} nepat\xC5\x99\xC3\xAD u\xC5\xBEivateli %{user}." + error_project_not_associated: "Projekt %{project} nepat\xC5\x99\xC3\xAD u\xC5\xBEivateli %{user}." + preference: + due_on: "Pl\xC3\xA1nov\xC3\xA1no na %{date}" + due_in: "Pl\xC3\xA1nov\xC3\xA1no za %{days} dn\xC3\xAD" + due_styles: + - "Pl\xC3\xA1nov\xC3\xA1no za ___ dn\xC3\xAD" + - "Pl\xC3\xA1nov\xC3\xA1no na _______" + stats: + totals_hidden_context_count: "a %{count} skryt\xC3\xBDch kontext\xC5\xAF." + actions_avg_created: "Za posledn\xC3\xADch 12 m\xC4\x9Bs\xC3\xADc\xC5\xAF bylo vytvo\xC5\x99eno pr\xC5\xAFm\xC4\x9Brn\xC4\x9B %{count} \xC3\xBAkol\xC5\xAF" + actions_min_max_completion_days: "Maximum/minimum dn\xC3\xAD na dokon\xC4\x8Den\xC3\xAD je %{min}/%{max}." + totals_actions_completed: "%{count} z nich je hotov\xC3\xBDch." + tag_cloud_title: !binary | + TXJhayDFoXTDrXRrxa8gcHJvIHbFoWVjaG55IMO6a2x5 + + actions_actions_avg_created_30days: "Za posledn\xC3\xADch 30 dn\xC3\xAD bylo vytvo\xC5\x99eno pr\xC5\xAFm\xC4\x9Brn\xC4\x9B %{count} \xC3\xBAkol\xC5\xAF" + actions_avg_completed: !binary | + YSB1emF2xZllbm8gcHLFr23Em3JuxJsgJXtjb3VudH0gw7prb2zFryB6YSBt + xJtzw61jLg== + + top5_visible_contexts_with_incomplete_actions: "Top 5 viditeln\xC3\xBDch kontext\xC5\xAF s nehotov\xC3\xBDmi \xC3\xBAkoly" + actions: !binary | + w5prb2x5 + + totals_deferred_actions: "z nich\xC5\xBE %{count} jsou odlo\xC5\xBEen\xC3\xA9 \xC3\xBAkoly v Ticlkeru" + time_of_day_legend: + number_of_actions: !binary | + UG/EjWV0IMO6a29sxa8= + + time_of_day: "Denn\xC3\xAD doba" + totals_incomplete_actions: "M\xC3\xA1te %{count} nehotov\xC3\xBDch \xC3\xBAkol\xC5\xAF" + running_time_legend: + actions: !binary | + w5prb2x5 + + percentage: !binary | + UG9kw61s + + weeks: "\xC4\x8Cas b\xC4\x9Bhu \xC3\xBAkolu (t\xC3\xBDdny). Klepn\xC4\x9Bte na sloupec pro dal\xC5\xA1\xC3\xAD info" + totals_action_count: "m\xC3\xA1te celkem %{count} \xC3\xBAkol\xC5\xAF" + tag_cloud_90days_title: "Zna\xC4\x8Dky \xC3\xBAkol\xC5\xAF z posledn\xC3\xADch 90-ti dn\xC3\xAD" + tod30: "Denn\xC3\xAD doba (posledn\xC3\xADch 30 dn\xC3\xAD)" + tags: !binary | + xaB0w610a3k= + projects: Projekty - action_completion_time_title: Čas dokončení (všechny hotové úkoly) - actions_last_year: Úkoly v posledním roce - actions_min_max_completion_days: Maximum/minimum dní na dokončení je %{min}/%{max}. - tags: Štítky - actions_min_completion_time: Minimální čas k dokončení je %{time}. - no_tags_available: žádné štítky nejsou definovány - actions_day_of_week_title: Den v týdnu (všechny úkoly) - totals_project_count: Máte %{count} projektů. - running_time_all: Aktuální čas běhu všech nehotových úkolů - actions_30days_title: Úkoly za posledních 30 dní - time_of_day: Denní doba (všechny úkoly) - totals_hidden_project_count: "%{count} je skrytých" - tod30: Denní doba (posledních 30 dní) - tag_cloud_90days_description: Tento mrak zahrnuje štítky úkolů, které byly vytvořeny nebo dokončeny v posledních 90-ti dnech. - more_stats_will_appear: Další statistiky se zobrazí až přibyde více úkolů. - top5_visible_contexts_with_incomplete_actions: Top 5 viditelných kontextů s nehotovými úkoly - actions_further: " a dále" - totals_tag_count: Na akcích je umístěno %{count} štítků. - top10_projects_30days: Top 10 projektů za posledních 30 dní - spread_of_running_actions_for_visible_contexts: Distribuce běžících úkolů do viditelných kontextů - actions_selected_from_week: "Úkoly vybrané z týdne " - spread_of_actions_for_all_context: Distribuce všech úkolů do kontextů - click_to_show_actions_from_week: Klepněte %{link} pro zobrazení úkolů z týdne %{week} a dalších. - other_actions_label: (ostatní) - top10_projects: Top 10 projektů - totals_completed_project_count: a %{count} je hotových projektů. - actions_avg_created: Za posledních 12 měsíců bylo vytvořeno průměrně %{count} úkolů - click_to_return: Klepněte %{link} pro návrat ke statistikám. - actions_avg_completed: a uzavřeno průměrně %{count} úkolů za měsíc. - totals: Celkem - time_of_day_legend: - number_of_actions: Počet úkolů - time_of_day: Denní doba - contexts: Kontexty - click_to_return_link: zde - totals_hidden_context_count: a %{count} skrytých kontextů. - labels: - month_avg_completed: "%{months} měsíční průměr hotových" + actions_avg_completion_time: "Pro v\xC5\xA1echny va\xC5\xA1e hotov\xC3\xA9 \xC3\xBAkoly je pr\xC5\xAFm\xC4\x9Brn\xC3\xBD \xC4\x8Das dokon\xC4\x8Den\xC3\xAD %{count} dn\xC3\xAD." + labels: + month_avg_completed: !binary | + JXttb250aHN9IG3Em3PDrcSNbsOtIHByxa9txJtyIGhvdG92w71jaA== + completed: Completed - month_avg_created: "%{months} měsíční průměr vytvořených" - avg_created: průměrně vytvořeno - avg_completed: průměrně uzavřeno - created: Vytvořeno - running_time_all_legend: - actions: Úkoly - percentage: Podíl - running_time: Čas běhu úkolů (týdny). Klepněte na sloupec pro další info - click_to_update_actions: Klepněte na sloupec v grafu pro zobrazení detailů níže. - no_actions_selected: Nejsou vybrány žádné úkoly. - actions_actions_avg_created_30days: Za posledních 30 dní bylo vytvořeno průměrně %{count} úkolů - tod30_legend: - number_of_actions: Počet úkolů - time_of_day: Denní doba - action_selection_title: TRACKS::výběr úkolů - todos: + month_avg_created: !binary | + JXttb250aHN9IG3Em3PDrcSNbsOtIHByxa9txJtyIHZ5dHZvxZllbsO9Y2g= + + avg_created: !binary | + cHLFr23Em3JuxJsgdnl0dm/FmWVubw== + + avg_completed: !binary | + cHLFr23Em3JuxJsgdXphdsWZZW5v + + created: "Vytvo\xC5\x99eno" + actions_selected_from_week: "\xC3\x9Akoly vybran\xC3\xA9 z t\xC3\xBDdne " + totals_completed_project_count: "a %{count} je hotov\xC3\xBDch projekt\xC5\xAF." + actions_day_of_week_title: "Den v t\xC3\xBDdnu (v\xC5\xA1echny \xC3\xBAkoly)" + actions_lastyear_title: "\xC3\x9Akoly za posledn\xC3\xADch 12 m\xC4\x9Bs\xC3\xADc\xC5\xAF" + open_per_week: "Aktivn\xC3\xAD (viditeln\xC3\xA9 i skryt\xC3\xA9) dal\xC5\xA1\xC3\xAD akce za t\xC3\xBDden" + action_selection_title: !binary | + VFJBQ0tTOjp2w71ixJtyIMO6a29sxa8= + + totals_project_count: "M\xC3\xA1te %{count} projekt\xC5\xAF." + current_running_time_of_incomplete_visible_actions: !binary | + QWt0dcOhbG7DrSDEjWFzIGLEm2h1IG5lZG9rb27EjWVuw71jaCB2aWRpdGVs + bsO9Y2ggw7prb2zFrw== + + legend: + number_of_days: "P\xC5\x99ed kolika dny" + actions: !binary | + w5prb2x5 + + number_of_actions: !binary | + UG/EjWV0IMO6a29sxa8= + + day_of_week: "Den v t\xC3\xBDdnu" + percentage: !binary | + UG9kw61s + + running_time: "\xC4\x8Cas k dokon\xC4\x8Den\xC3\xAD \xC3\xBAkolu (t\xC3\xBDdny)" + months_ago: !binary | + bcSbc8OtY8WvIHpwxJt0 + + tod30_legend: + number_of_actions: !binary | + UG/EjWV0IMO6a29sxa8= + + time_of_day: "Denn\xC3\xAD doba" + totals_context_count: "M\xC3\xA1te %{count} kontext\xC5\xAF." + open_per_week_legend: + actions: !binary | + QWtjw60= + + weeks: !binary | + VMO9ZG55 + + actions_last_year_legend: + number_of_actions: !binary | + UG/EjWV0IMO6a2xvbMWv + + months_ago: !binary | + bcSbc8OtY8WvIHpwxJt0 + + top10_projects: "Top 10 projekt\xC5\xAF" + top5_contexts: "Top 5 kontext\xC5\xAF" + contexts: Kontexty + totals: Celkem + click_to_return: "Klepn\xC4\x9Bte %{link} pro n\xC3\xA1vrat ke statistik\xC3\xA1m." + tag_cloud_90days_description: "Tento mrak zahrnuje \xC5\xA1t\xC3\xADtky \xC3\xBAkol\xC5\xAF, kter\xC3\xA9 byly vytvo\xC5\x99eny nebo dokon\xC4\x8Deny v posledn\xC3\xADch 90-ti dnech." + totals_visible_context_count: "Z nich je %{count} viditeln\xC3\xBDch kontext\xC5\xAF" + top10_projects_30days: "Top 10 projekt\xC5\xAF za posledn\xC3\xADch 30 dn\xC3\xAD" + running_time_all: !binary | + QWt0dcOhbG7DrSDEjWFzIGLEm2h1IHbFoWVjaCBuZWhvdG92w71jaCDDumtv + bMWv + + actions_min_completion_time: "Minim\xC3\xA1ln\xC3\xAD \xC4\x8Das k dokon\xC4\x8Den\xC3\xAD je %{time}." + action_completion_time_title: "\xC4\x8Cas dokon\xC4\x8Den\xC3\xAD (v\xC5\xA1echny hotov\xC3\xA9 \xC3\xBAkoly)" + click_to_show_actions_from_week: "Klepn\xC4\x9Bte %{link} pro zobrazen\xC3\xAD \xC3\xBAkol\xC5\xAF z t\xC3\xBDdne %{week} a dal\xC5\xA1\xC3\xADch." + top10_longrunning: !binary | + MTAgbmVqZMOpbGUgYsSbxb7DrWPDrWNoIHByb2pla3TFrw== + + no_actions_selected: !binary | + TmVqc291IHZ5YnLDoW55IMW+w6FkbsOpIMO6a29seS4= + + totals_tag_count: "Na akc\xC3\xADch je um\xC3\xADst\xC4\x9Bno %{count} \xC5\xA1t\xC3\xADtk\xC5\xAF." + actions_further: " a d\xC3\xA1le" + actions_dow_30days_legend: + number_of_actions: !binary | + UG/EjWV0IGFrY8Ot + + day_of_week: "Den v t\xC3\xBDdnu" + totals_first_action: "Od va\xC5\xA1eho prvn\xC3\xADho \xC3\xBAkolu %{date}" + tag_cloud_description: "Tento mrak zahrnuje \xC5\xA1t\xC3\xADtky v\xC5\xA1ech \xC3\xBAkol\xC5\xAF (hotov\xC3\xBDch, nehotov\xC3\xBDch, viditeln\xC3\xBDch i skryt\xC3\xBDch)" + click_to_return_link: zde + click_to_update_actions: "Klepn\xC4\x9Bte na sloupec v grafu pro zobrazen\xC3\xAD detail\xC5\xAF n\xC3\xAD\xC5\xBEe." + spread_of_actions_for_all_context: "Distribuce v\xC5\xA1ech \xC3\xBAkol\xC5\xAF do kontext\xC5\xAF" + more_stats_will_appear: "Dal\xC5\xA1\xC3\xAD statistiky se zobraz\xC3\xAD a\xC5\xBE p\xC5\x99ibyde v\xC3\xADce \xC3\xBAkol\xC5\xAF." + actions_avg_completed_30days: "a dokon\xC4\x8Deno pr\xC5\xAFm\xC4\x9Brn\xC4\x9B %{count} \xC3\xBAkol\xC5\xAF za den." + no_tags_available: !binary | + xb7DoWRuw6kgxaF0w610a3kgbmVqc291IGRlZmlub3bDoW55 + + actions_30days_title: "\xC3\x9Akoly za posledn\xC3\xADch 30 dn\xC3\xAD" + index_title: TRACKS::Statistika + actions_dow_30days_title: "Dny v t\xC3\xBDdnu (poslen\xC3\xADch 30 dn\xC3\xAD)" + spread_of_running_actions_for_visible_contexts: "Distribuce b\xC4\x9B\xC5\xBE\xC3\xADc\xC3\xADch \xC3\xBAkol\xC5\xAF do viditeln\xC3\xBDch kontext\xC5\xAF" + actions_day_of_week_legend: + number_of_actions: !binary | + UG/EjWV0IGFrY8Ot + + day_of_week: "Den v t\xC3\xBDdnu" + actions_last_year: "\xC3\x9Akoly v posledn\xC3\xADm roce" + totals_blocked_actions: "%{count} je z\xC3\xA1visl\xC3\xBDch na dokon\xC4\x8Den\xC3\xAD jin\xC3\xBDch akc\xC3\xAD." + totals_unique_tags: "Z t\xC4\x9Bchto \xC5\xA1t\xC3\xADtk\xC5\xAF je %{count} unik\xC3\xA1tn\xC3\xADch." + totals_active_project_count: "Znich %{count} je aktivn\xC3\xADch projek\xC5\xAF" + running_time_all_legend: + actions: !binary | + w5prb2x5 + + percentage: !binary | + UG9kw61s + + running_time: "\xC4\x8Cas b\xC4\x9Bhu \xC3\xBAkol\xC5\xAF (t\xC3\xBDdny). Klepn\xC4\x9Bte na sloupec pro dal\xC5\xA1\xC3\xAD info" + other_actions_label: "(ostatn\xC3\xAD)" + time_of_day: "Denn\xC3\xAD doba (v\xC5\xA1echny \xC3\xBAkoly)" + totals_hidden_project_count: "%{count} je skryt\xC3\xBDch" + todos: show_from: Zobrazovat od - error_starring_recurring: Nebylo možno ohvězdičkovat opakovaný úkol \'%{description}\' - recurring_action_deleted: Úkol byl smazán. Protože jde o opakovaný úkol, byl vložen nový úkol - completed_actions: Hotové úkoly - completed_recurring: Hotové opakované úkoly - added_new_next_action: Přidán nový úkol - completed_rest_of_previous_month: Uzavřeno ve zbytku minulého měsíce - blocked_by: Čeká na %{predecessors} - star_action: Oznařit hvězdičkou - completed_recurrence_completed: Bylo smazáno poslední opakování opakovaného úkolu. Opakování dokončeno - defer_date_after_due_date: Datum zobrazení je až po plánovaném datu úkolu. Upravte datum úkolu před dalším pokusem o odpložení zobrazení. - unable_to_add_dependency: Nepodařilo se přidat závislost + error_starring_recurring: "Nebylo mo\xC5\xBEno ohv\xC4\x9Bzdi\xC4\x8Dkovat opakovan\xC3\xBD \xC3\xBAkol \\'%{description}\\'" + recurring_action_deleted: "\xC3\x9Akol byl smaz\xC3\xA1n. Proto\xC5\xBEe jde o opakovan\xC3\xBD \xC3\xBAkol, byl vlo\xC5\xBEen nov\xC3\xBD \xC3\xBAkol" + completed_actions: "Hotov\xC3\xA9 \xC3\xBAkoly" + blocked_by: "\xC4\x8Cek\xC3\xA1 na %{predecessors}" + completed_recurring: "Hotov\xC3\xA9 opakovan\xC3\xA9 \xC3\xBAkoly" + added_new_next_action: !binary | + UMWZaWTDoW4gbm92w70gw7prb2w= + + completed_rest_of_previous_month: "Uzav\xC5\x99eno ve zbytku minul\xC3\xA9ho m\xC4\x9Bs\xC3\xADce" + defer_date_after_due_date: "Datum zobrazen\xC3\xAD je a\xC5\xBE po pl\xC3\xA1novan\xC3\xA9m datu \xC3\xBAkolu. Upravte datum \xC3\xBAkolu p\xC5\x99ed dal\xC5\xA1\xC3\xADm pokusem o odplo\xC5\xBEen\xC3\xAD zobrazen\xC3\xAD." + star_action: "Ozna\xC5\x99it hv\xC4\x9Bzdi\xC4\x8Dkou" + completed_recurrence_completed: "Bylo smaz\xC3\xA1no posledn\xC3\xAD opakov\xC3\xA1n\xC3\xAD opakovan\xC3\xA9ho \xC3\xBAkolu. Opakov\xC3\xA1n\xC3\xAD dokon\xC4\x8Deno" + unable_to_add_dependency: "Nepoda\xC5\x99ilo se p\xC5\x99idat z\xC3\xA1vislost" done: Hotovo? - star_action_with_description: ohvězdičkovat úkol '%{description}' - tagged_with: označeno štítkem ‘%{tag_name}’ + star_action_with_description: "ohv\xC4\x9Bzdi\xC4\x8Dkovat \xC3\xBAkol '%{description}'" + tagged_with: "ozna\xC4\x8Deno \xC5\xA1t\xC3\xADtkem ‘%{tag_name}’" completed: Hotovo - no_deferred_actions_with: Žádné odložené úkoly se štítkem '%{tag_name}' - edit_action_with_description: Upravit úkol '%{description}' - no_hidden_actions: Žádné skryté úkoly - action_due_on: (úkol plánován na %{date}) - remove_dependency: Odstranit závislost (nesmaže úkol) - archived_tasks_title: TRACKS::Archiv hotových úkolů - list_incomplete_next_actions: Zabrazí nehotové úkoly - tags: Štítky (oddělené čárkami) - action_deleted_success: Úkol byl úspěšně smazán - new_related_todo_created: Byl vytvořen nový úkol patřící do tohoto opakovaného úkolu - context_changed: Kontext byl změněn na %{name} - add_another_dependency: Přidat další závislost - mobile_todos_page_title: Všechny úkoly - delete_recurring_action_title: Smazat opakovaný úkol - removed_predecessor: Byl odstraněn %{successor} jako závislost pro %{predecessor}. - recurring_actions_title: TRACKS::Opakované úkoly - next_action_needed: Je potřeba zadat aspoň jeden úkol - action_saved: Úkol uložen - scheduled_overdue: Naplánováno zobrazení před %{days} dny - action_deleted_error: Nepodařilo se smazat úkol - edit_action: Upravit úkol - added_new_context: Přidán nový kontext + no_deferred_actions_with: !binary | + xb3DoWRuw6kgb2Rsb8W+ZW7DqSDDumtvbHkgc2UgxaF0w610a2VtICcle3Rh + Z19uYW1lfSc= + + no_hidden_actions: !binary | + xb3DoWRuw6kgc2tyeXTDqSDDumtvbHk= + + action_due_on: "(\xC3\xBAkol pl\xC3\xA1nov\xC3\xA1n na %{date})" + edit_action_with_description: "Upravit \xC3\xBAkol '%{description}'" + archived_tasks_title: "TRACKS::Archiv hotov\xC3\xBDch \xC3\xBAkol\xC5\xAF" + remove_dependency: "Odstranit z\xC3\xA1vislost (nesma\xC5\xBEe \xC3\xBAkol)" + list_incomplete_next_actions: "Zabraz\xC3\xAD nehotov\xC3\xA9 \xC3\xBAkoly" + tags: !binary | + xaB0w610a3kgKG9kZMSbbGVuw6kgxI3DoXJrYW1pKQ== + + action_deleted_success: !binary | + w5prb2wgYnlsIMO6c3DEm8WhbsSbIHNtYXrDoW4= + + add_another_dependency: !binary | + UMWZaWRhdCBkYWzFocOtIHrDoXZpc2xvc3Q= + + new_related_todo_created: "Byl vytvo\xC5\x99en nov\xC3\xBD \xC3\xBAkol pat\xC5\x99\xC3\xADc\xC3\xAD do tohoto opakovan\xC3\xA9ho \xC3\xBAkolu" + context_changed: "Kontext byl zm\xC4\x9Bn\xC4\x9Bn na %{name}" + mobile_todos_page_title: "V\xC5\xA1echny \xC3\xBAkoly" + delete_recurring_action_title: "Smazat opakovan\xC3\xBD \xC3\xBAkol" + recurring_actions_title: "TRACKS::Opakovan\xC3\xA9 \xC3\xBAkoly" + removed_predecessor: "Byl odstran\xC4\x9Bn %{successor} jako z\xC3\xA1vislost pro %{predecessor}." + next_action_needed: "Je pot\xC5\x99eba zadat aspo\xC5\x88 jeden \xC3\xBAkol" + action_saved: !binary | + w5prb2wgdWxvxb5lbg== + + scheduled_overdue: "Napl\xC3\xA1nov\xC3\xA1no zobrazen\xC3\xAD p\xC5\x99ed %{days} dny" + action_deleted_error: "Nepoda\xC5\x99ilo se smazat \xC3\xBAkol" + edit_action: "Upravit \xC3\xBAkol" + added_new_context: "P\xC5\x99id\xC3\xA1n nov\xC3\xBD kontext" next_actions_description: "Filtr:" - list_incomplete_next_actions_with_limit: Zobrazuje posledních %{count} nedokončených úkolů - set_to_pending: "%{task} nastaven jako čekající" - added_new_project: Přidán nový projekt - next_actions_title_additions: - completed: hotové úkoly - due_today: dnes - due_within_a_week: během týdne older_completed_items: "" + list_incomplete_next_actions_with_limit: "Zobrazuje posledn\xC3\xADch %{count} nedokon\xC4\x8Den\xC3\xBDch \xC3\xBAkol\xC5\xAF" + set_to_pending: "%{task} nastaven jako \xC4\x8Dekaj\xC3\xADc\xC3\xAD" + added_new_project: "P\xC5\x99id\xC3\xA1n nov\xC3\xBD projekt" + next_actions_title_additions: + completed: "hotov\xC3\xA9 \xC3\xBAkoly" + due_today: dnes + due_within_a_week: !binary | + YsSbaGVtIHTDvWRuZQ== + + task_list_title: "TRACKS::\xC3\x9Akoly" + edit_recurring_todo: "Upravit opakovan\xC3\xBD \xC3\xBAkol" append_in_this_project: v tomto projektu - error_deleting_item: Nepodařilo se smazat položku %{description} - task_list_title: TRACKS::Úkoly - no_actions_due_this_week: Žádné úkoly plánovány na tento týden - no_deferred_pending_actions: Žádné odložené ani čekající úkoly - no_recurring_todos: Žádné opakované úkoly - error_completing_todo: Nepodařilo se ukončit / aktivovat opakovaný úkol %{description} - recurring_pattern_removed: Vzor opakování byl odstraněn z %{count} - convert_to_project: Vytvořit projekt - delete_recurring_action_confirm: Opravdu chcete smazat opakovaný úkol '%{description}'? - completed_last_day: Ukončené v posledních 24 hodinách + error_deleting_item: "Nepoda\xC5\x99ilo se smazat polo\xC5\xBEku %{description}" + no_actions_due_this_week: !binary | + xb3DoWRuw6kgw7prb2x5IHBsw6Fub3bDoW55IG5hIHRlbnRvIHTDvWRlbg== + + error_completing_todo: "Nepoda\xC5\x99ilo se ukon\xC4\x8Dit / aktivovat opakovan\xC3\xBD \xC3\xBAkol %{description}" + no_recurring_todos: !binary | + xb3DoWRuw6kgb3Bha292YW7DqSDDumtvbHk= + + recurring_pattern_removed: "Vzor opakov\xC3\xA1n\xC3\xAD byl odstran\xC4\x9Bn z %{count}" + convert_to_project: "Vytvo\xC5\x99it projekt" + no_deferred_pending_actions: !binary | + xb3DoWRuw6kgb2Rsb8W+ZW7DqSBhbmkgxI1la2Fqw61jw60gw7prb2x5 + + delete_recurring_action_confirm: "Opravdu chcete smazat opakovan\xC3\xBD \xC3\xBAkol '%{description}'?" + completed_last_day: "Ukon\xC4\x8Den\xC3\xA9 v posledn\xC3\xADch 24 hodin\xC3\xA1ch" + all_completed: "V\xC5\xA1echny hotov\xC3\xA9 \xC3\xBAkoly" + show_in_days: "Zobrazit za %{days} dn\xC3\xAD" + no_project: "--\xC5\xBD\xC3\xA1dn\xC3\xBD projekt--" + error_saving_recurring: "Nepoda\xC5\x99ilo se ulo\xC5\xBEit opakovan\xC3\xBD \xC3\xBAkol \\'%{description}\\'" completed_more_than_x_days_ago: "" - show_in_days: Zobrazit za %{days} dní - no_project: --Žádný projekt-- - error_saving_recurring: Nepodařilo se uložit opakovaný úkol \'%{description}\' - new_related_todo_created_short: vytvořen nový úkol - all_completed: Všechny hotové úkoly feed_title_in_context: v kontextu '%{context}' - older_than_days: "" - completed_tagged_page_title: TRACKS::Hotové úkoly se štítkem '%{tag_name}' + new_related_todo_created_short: "vytvo\xC5\x99en nov\xC3\xBD \xC3\xBAkol" edit: Upravit - pending: Čekající - completed_actions_with: Hotové úkoly se štítkem '%{tag_name}' - deleted_success: Úkol byl úspěšně smazán. - completed_tasks_title: TRACKS::Hotové úkoly + completed_tagged_page_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" + older_than_days: "" + pending: !binary | + xIxla2Fqw61jw60= + + completed_actions_with: "Hotov\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" feed_title_in_project: v projektu '%{project}' - clear_due_date: Smazat plánované datum úkolu - hidden_actions: Skryté úkoly - error_removing_dependency: Nepodařilo se odstranit závislost - was_due_on_date: bylo plánováno na %{date} - show_on_date: Ukázat %{date} - recurrence_period: Interval opakování - deferred_actions_with: Odložené úkoly se štítkem '%{tag_name}' - recurring_deleted_success: Opakovaný úkol byl úspěšně smazán. - confirm_delete: Opravdu chcete smazat úkol '%{description}'? + deleted_success: !binary | + w5prb2wgYnlsIMO6c3DEm8WhbsSbIHNtYXrDoW4u + + completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly" + clear_due_date: "Smazat pl\xC3\xA1novan\xC3\xA9 datum \xC3\xBAkolu" + error_removing_dependency: "Nepoda\xC5\x99ilo se odstranit z\xC3\xA1vislost" + hidden_actions: "Skryt\xC3\xA9 \xC3\xBAkoly" + was_due_on_date: "bylo pl\xC3\xA1nov\xC3\xA1no na %{date}" + show_on_date: "Uk\xC3\xA1zat %{date}" + recurrence_period: "Interval opakov\xC3\xA1n\xC3\xAD" + deferred_actions_with: "Odlo\xC5\xBEen\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" + confirm_delete: "Opravdu chcete smazat \xC3\xBAkol '%{description}'?" + recurring_deleted_success: !binary | + T3Bha292YW7DvSDDumtvbCBieWwgw7pzcMSbxaFuxJsgc21hesOhbi4= + + next_actions_title: "Tracks - \xC3\x9Akoly" + next_action_description: "Popis \xC3\xBAkolu" deferred_tasks_title: TRACKS::Tickler - next_actions_title: Tracks - Úkoly - next_action_description: Popis úkolu - no_completed_actions_with: Žádné hotové úkoly se štítkem '%{tag_name}' - clear_show_from_date: Odstranit datum zobrazení - calendar_page_title: TRACKS::Kalendář - unresolved_dependency: Hodnota v poli 'závisí na' neodpovídá žádnému existujícímu úkolu. Hodnota bude ignorována. Pokračovat? - in_hidden_state: (skrytý) + no_completed_actions_with: "\xC5\xBD\xC3\xA1dn\xC3\xA9 hotov\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" + clear_show_from_date: "Odstranit datum zobrazen\xC3\xAD" + calendar_page_title: "TRACKS::Kalend\xC3\xA1\xC5\x99" + unresolved_dependency: "Hodnota v poli 'z\xC3\xA1vis\xC3\xAD na' neodpov\xC3\xADd\xC3\xA1 \xC5\xBE\xC3\xA1dn\xC3\xA9mu existuj\xC3\xADc\xC3\xADmu \xC3\xBAkolu. Hodnota bude ignorov\xC3\xA1na. Pokra\xC4\x8Dovat?" + in_hidden_state: "(skryt\xC3\xBD)" show_today: Zobrazit Dnes - no_actions_found_title: Nenalezeny žádné úkoly - next_actions_due_date: - overdue_by: Prošlé %{days} den + no_actions_found_title: !binary | + TmVuYWxlemVueSDFvsOhZG7DqSDDumtvbHk= + + next_actions_due_date: + overdue_by: "Pro\xC5\xA1l\xC3\xA9 %{days} den" due_today: Dnes - due_in_x_days: Za %{days} dní - overdue_by_plural: Prošlé %{days} dní - due_tomorrow: Zítra - completed_last_x_days: Uzavřené za posledních %{count} dní - no_actions_with: Žádné úkoly se štítkem '%{tag_name}' - defer_x_days: - one: Ukázat zítra - other: Ukázat za %{count} dní - added_new_next_action_singular: Přidán nový úkol - no_completed_actions: Žádné hotové úkoly. - feeds: - completed: "Hotové: %{date}" - due: "Plánováno na: %{date}" - deferred_pending_actions: Odložené/čekající úkoly - has_x_pending: - one: Jeden čekající úkol - other: %{count} čekajících úkolů - delete_action: Smazat úkol - error_deleting_recurring: Nepodařilo se smazat opakovaný úkol \'%{description}\' - recurring_todos: Opakované úkoly + due_in_x_days: "Za %{days} dn\xC3\xAD" + overdue_by_plural: "Pro\xC5\xA1l\xC3\xA9 %{days} dn\xC3\xAD" + due_tomorrow: !binary | + WsOtdHJh + + completed_last_x_days: "Uzav\xC5\x99en\xC3\xA9 za posledn\xC3\xADch %{count} dn\xC3\xAD" + no_actions_with: "\xC5\xBD\xC3\xA1dn\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" + defer_x_days: + one: "Uk\xC3\xA1zat z\xC3\xADtra" + other: "Uk\xC3\xA1zat za %{count} dn\xC3\xAD" + added_new_next_action_singular: !binary | + UMWZaWTDoW4gbm92w70gw7prb2w= + + no_completed_actions: !binary | + xb3DoWRuw6kgaG90b3bDqSDDumtvbHku + + feeds: + completed: "Hotov\xC3\xA9: %{date}" + due: "Pl\xC3\xA1nov\xC3\xA1no na: %{date}" + deferred_pending_actions: !binary | + T2Rsb8W+ZW7DqS/EjWVrYWrDrWPDrSDDumtvbHk= + + has_x_pending: + one: !binary | + SmVkZW4gxI1la2Fqw61jw60gw7prb2w= + + other: !binary | + JXtjb3VudH0gxI1la2Fqw61jw61jaCDDumtvbMWv + + delete_action: "Smazat \xC3\xBAkol" + error_deleting_recurring: "Nepoda\xC5\x99ilo se smazat opakovan\xC3\xBD \xC3\xBAkol \\'%{description}\\'" + recurring_todos: "Opakovan\xC3\xA9 \xC3\xBAkoly" delete: Smazat - cannot_add_dependency_to_completed_todo: Nelze přidat úkol jako závislost k hotovému úkolu! - drag_action_title: Přetáhnout na jiný úkol pro vytvoření závislosti - no_last_completed_actions: Žádné hotové úkoly - depends_on: Závisí na - tickler_items_due: - one: Jeden úkol v Tickleru je plánován dnes - obnovte stránku pro zobrazení. - other: "%{count} položek v Tickleru je plánováno na dnes tickler items are now due - obnovte stránku pro zobrazení." - action_marked_complete: Úkol '%{description}' byl označen jako %{completed} - completed_today: Dokončené dnes - added_new_next_action_plural: Úkoly byly přidány - new_related_todo_not_created_short: úkol nebyl vytvořen - completed_rest_of_week: Dokončené ve zbytku týdne - error_starring: Nepodařilo se označit úkol hvězdičkou '%{description}' - calendar: - get_in_ical_format: Kalendář ve formátu iCal - due_next_week: Plánované příští týden - no_actions_due_next_week: Na příští týden nejsou plánované žádné úkoly - due_this_week: Plánované ve zbytku týdne - due_today: Plánované dnes - no_actions_due_today: Na dnešek nejsou plánované žádné úkoly - due_next_month_and_later: Plánováno na %{month} a dále - no_actions_due_after_this_month: Na příští měsíc a dále nejsou plánované žádné úkoly - due_this_month: Plánováno na %{month} - no_actions_due_this_month: Na zbytek tohoto měsíce nejsou žádné úkoly - show_tomorrow: Zobrazit zítra - tagged_page_title: TRACKS::Se štítkem '%{tag_name}' - action_deferred: Úkol '%{description}' byl oldožen - recurrence: - ends_on_number_times: Končí po %{number} opakováních - ends_on_date: Končí %{date} - every_work_day: Každý pracovní den - recurrence_on_due_date: datum na které je úkol plánován - weekly_options: Nastavení pro týdenní opakované úkoly - weekly: Týdně - monthly_options: Nastavení pro měsíční opakované úkoly - starts_on: Začíná - daily_options: Nastavení pro denní opakované úkoly - monthly: Měsíčně - pattern: - month_names: - - + cannot_add_dependency_to_completed_todo: "Nelze p\xC5\x99idat \xC3\xBAkol jako z\xC3\xA1vislost k hotov\xC3\xA9mu \xC3\xBAkolu!" + drag_action_title: "P\xC5\x99et\xC3\xA1hnout na jin\xC3\xBD \xC3\xBAkol pro vytvo\xC5\x99en\xC3\xAD z\xC3\xA1vislosti" + no_last_completed_actions: !binary | + xb3DoWRuw6kgaG90b3bDqSDDumtvbHk= + + tickler_items_due: + one: "Jeden \xC3\xBAkol v Tickleru je pl\xC3\xA1nov\xC3\xA1n dnes - obnovte str\xC3\xA1nku pro zobrazen\xC3\xAD." + other: "%{count} polo\xC5\xBEek v Tickleru je pl\xC3\xA1nov\xC3\xA1no na dnes tickler items are now due - obnovte str\xC3\xA1nku pro zobrazen\xC3\xAD." + depends_on: !binary | + WsOhdmlzw60gbmE= + + action_marked_complete: "\xC3\x9Akol '%{description}' byl ozna\xC4\x8Den jako %{completed}" + completed_today: "Dokon\xC4\x8Den\xC3\xA9 dnes" + added_new_next_action_plural: "\xC3\x9Akoly byly p\xC5\x99id\xC3\xA1ny" + new_related_todo_not_created_short: "\xC3\xBAkol nebyl vytvo\xC5\x99en" + completed_rest_of_week: "Dokon\xC4\x8Den\xC3\xA9 ve zbytku t\xC3\xBDdne" + error_starring: "Nepoda\xC5\x99ilo se ozna\xC4\x8Dit \xC3\xBAkol hv\xC4\x9Bzdi\xC4\x8Dkou '%{description}'" + show_tomorrow: "Zobrazit z\xC3\xADtra" + calendar: + get_in_ical_format: "Kalend\xC3\xA1\xC5\x99 ve form\xC3\xA1tu iCal" + due_next_week: !binary | + UGzDoW5vdmFuw6kgcMWZw63FoXTDrSB0w71kZW4= + + no_actions_due_next_week: !binary | + TmEgcMWZw63FoXTDrSB0w71kZW4gbmVqc291IHBsw6Fub3ZhbsOpIMW+w6Fk + bsOpIMO6a29seQ== + + due_this_week: "Pl\xC3\xA1novan\xC3\xA9 ve zbytku t\xC3\xBDdne" + due_today: "Pl\xC3\xA1novan\xC3\xA9 dnes" + no_actions_due_today: !binary | + TmEgZG5lxaFlayBuZWpzb3UgcGzDoW5vdmFuw6kgxb7DoWRuw6kgw7prb2x5 + + due_next_month_and_later: "Pl\xC3\xA1nov\xC3\xA1no na %{month} a d\xC3\xA1le" + no_actions_due_after_this_month: !binary | + TmEgcMWZw63FoXTDrSBtxJtzw61jIGEgZMOhbGUgbmVqc291IHBsw6Fub3Zh + bsOpIMW+w6FkbsOpIMO6a29seQ== + + no_actions_due_this_month: "Na zbytek tohoto m\xC4\x9Bs\xC3\xADce nejsou \xC5\xBE\xC3\xA1dn\xC3\xA9 \xC3\xBAkoly" + due_this_month: "Pl\xC3\xA1nov\xC3\xA1no na %{month}" + action_deferred: "\xC3\x9Akol '%{description}' byl oldo\xC5\xBEen" + added_dependency: "P\xC5\x99id\xC3\xA1no %{dependency} jako z\xC3\xA1vislost." + recurrence: + ends_on_number_times: "Kon\xC4\x8D\xC3\xAD po %{number} opakov\xC3\xA1n\xC3\xADch" + ends_on_date: "Kon\xC4\x8D\xC3\xAD %{date}" + every_work_day: "Ka\xC5\xBEd\xC3\xBD pracovn\xC3\xAD den" + recurrence_on_due_date: "datum na kter\xC3\xA9 je \xC3\xBAkol pl\xC3\xA1nov\xC3\xA1n" + weekly_options: "Nastaven\xC3\xAD pro t\xC3\xBDdenn\xC3\xAD opakovan\xC3\xA9 \xC3\xBAkoly" + weekly: !binary | + VMO9ZG7Emw== + + monthly_options: !binary | + TmFzdGF2ZW7DrSBwcm8gbcSbc8OtxI1uw60gb3Bha292YW7DqSDDumtvbHk= + + monthly: !binary | + TcSbc8OtxI1uxJs= + + starts_on: !binary | + WmHEjcOtbsOh + + daily_options: "Nastaven\xC3\xAD pro denn\xC3\xAD opakovan\xC3\xA9 \xC3\xBAkoly" + show_option_always: !binary | + c3TDoWxl + + daily: !binary | + RGVubsSb + + pattern: + third: !binary | + dMWZZXTDrQ== + + month_names: + - - Leden - - Únor - - Březen + - !binary | + w5pub3I= + + - "B\xC5\x99ezen" - Duben - - Květen - - Červen - - Červenec + - "Kv\xC4\x9Bten" + - "\xC4\x8Cerven" + - "\xC4\x8Cervenec" - Srpen - - Září - - Říjen + - !binary | + WsOhxZnDrQ== + + - !binary | + xZjDrWplbg== + - Listopad - Prosinec - third: třetí - every_n: každé %{n} - on_day_n: %{n}. den - second: druhý - every_xth_day_of_every_n_months: každý %{x} %{day} každých %{n_months} + every_n: !binary | + a2HFvmTDqSAle259 + + second: !binary | + ZHJ1aMO9 + + every_xth_day_of_every_n_months: "ka\xC5\xBEd\xC3\xBD %{x} %{day} ka\xC5\xBEd\xC3\xBDch %{n_months}" + on_day_n: "%{n}. den" from: od - weekly: každý týden - last: poslední - every_day: každý den - the_xth_day_of_month: %{x} %{day} měsíce %{month} - times: (%{number} opakování) - on_work_days: v pracovní dny - first: první - every_year_on: každý rok %{date} - day_names: - - neděle - - pondělí - - úterý - - středa - - čtvrtek - - pátek + weekly: !binary | + a2HFvmTDvSB0w71kZW4= + + every_day: !binary | + a2HFvmTDvSBkZW4= + + last: "posledn\xC3\xAD" + the_xth_day_of_month: "%{x} %{day} m\xC4\x9Bs\xC3\xADce %{month}" + times: "(%{number} opakov\xC3\xA1n\xC3\xAD)" + every_year_on: "ka\xC5\xBEd\xC3\xBD rok %{date}" + day_names: + - "ned\xC4\x9Ble" + - !binary | + cG9uZMSbbMOt + + - !binary | + w7p0ZXLDvQ== + + - "st\xC5\x99eda" + - "\xC4\x8Dtvrtek" + - !binary | + cMOhdGVr + - sobota - show: ukázat - fourth: čtvrtý - due: plánováno na + show: "uk\xC3\xA1zat" + first: !binary | + cHJ2bsOt + + on_work_days: "v pracovn\xC3\xAD dny" + fourth: !binary | + xI10dnJ0w70= + + due: "pl\xC3\xA1nov\xC3\xA1no na" + every_month: !binary | + a2HFvmTDvSBtxJtzw61j + until: do - every_month: každý měsíc - show_option_always: stále - daily: Denně - yearly_every_x_day: Každý %{month} %{day} - recurrence_on_options: Nastavit opakování na - daily_every_number_day: Každých %{number} dní - show_options: Úkázat úkol - weekly_every_number_week: Každých %{number} týdnů - ends_on: Končí - show_days_before: "%{days} dní před plánovaným datem" - from_tickler: datum kdy úkol vypadne z Tickleru (není nastaveno plánované datum) + recurrence_on_options: "Nastavit opakov\xC3\xA1n\xC3\xAD na" + yearly_every_x_day: "Ka\xC5\xBEd\xC3\xBD %{month} %{day}" + daily_every_number_day: "Ka\xC5\xBEd\xC3\xBDch %{number} dn\xC3\xAD" + ends_on: !binary | + S29uxI3DrQ== + + show_options: !binary | + w5prw6F6YXQgw7prb2w= + + weekly_every_number_week: "Ka\xC5\xBEd\xC3\xBDch %{number} t\xC3\xBDdn\xC5\xAF" + yearly_every_xth_day: "%{day} %{day_of_week} m\xC4\x9Bs\xC3\xADce %{month}" + show_days_before: "%{days} dn\xC3\xAD p\xC5\x99ed pl\xC3\xA1novan\xC3\xBDm datem" + from_tickler: "datum kdy \xC3\xBAkol vypadne z Tickleru (nen\xC3\xAD nastaveno pl\xC3\xA1novan\xC3\xA9 datum)" no_end_date: Nikdy - day_x_on_every_x_month: %{day}. den každý %{month}. měsíc - yearly_options: Nastavení pro roční opakované úkoly - yearly_every_xth_day: %{day} %{day_of_week} měsíce %{month} - monthly_every_xth_day: %{day} %{day_of_week} každý %{month}. měsíc - yearly: Ročně - no_completed_recurring: Žádné hotové opakované úkoly - added_dependency: Přidáno %{dependency} jako závislost. - no_deferred_actions: Žádné odložené úkoly. - all_completed_tagged_page_title: TRACKS::Hotové úkoly se štítkem %{tag_name} - completed_rest_of_month: Ukončené ve zbytku tohoto měsíce - recurrence_completed: Poslední opakování úkolu bylo označeno jako hotové. Opakovaný úkol je dokončený - error_toggle_complete: Nepodařilo se označit úkol jako hotový - no_actions_found: Žádné běžící úkoly. - in_pending_state: ve stavu čekající - due: Plánováno na - action_marked_complete_error: Úkol '%{description}' NEBYL označen jako %{completed} kvůli chybě na serveru. - depends_on_separate_with_commas: Závisí na (odděleno čárkami) - action_saved_to_tickler: Úkol byl uložen do Tickleru - recurring_action_saved: Opakovaný úkol byl uložen - completed_in_archive: - one: V archivu je hotový úkol. - other: V archivu je %{count} hotových úkolů. + day_x_on_every_x_month: "%{day}. den ka\xC5\xBEd\xC3\xBD %{month}. m\xC4\x9Bs\xC3\xADc" + yearly_options: "Nastaven\xC3\xAD pro ro\xC4\x8Dn\xC3\xAD opakovan\xC3\xA9 \xC3\xBAkoly" + monthly_every_xth_day: "%{day} %{day_of_week} ka\xC5\xBEd\xC3\xBD %{month}. m\xC4\x9Bs\xC3\xADc" + yearly: !binary | + Um/EjW7Emw== + + tagged_page_title: "TRACKS::Se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" + no_completed_recurring: !binary | + xb3DoWRuw6kgaG90b3bDqSBvcGFrb3ZhbsOpIMO6a29seQ== + + completed_rest_of_month: "Ukon\xC4\x8Den\xC3\xA9 ve zbytku tohoto m\xC4\x9Bs\xC3\xADce" + recurrence_completed: "Posledn\xC3\xAD opakov\xC3\xA1n\xC3\xAD \xC3\xBAkolu bylo ozna\xC4\x8Deno jako hotov\xC3\xA9. Opakovan\xC3\xBD \xC3\xBAkol je dokon\xC4\x8Den\xC3\xBD" + all_completed_tagged_page_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem %{tag_name}" + no_deferred_actions: !binary | + xb3DoWRuw6kgb2Rsb8W+ZW7DqSDDumtvbHku + + in_pending_state: "ve stavu \xC4\x8Dekaj\xC3\xADc\xC3\xAD" + no_actions_found: !binary | + xb3DoWRuw6kgYsSbxb7DrWPDrSDDumtvbHku + + error_toggle_complete: "Nepoda\xC5\x99ilo se ozna\xC4\x8Dit \xC3\xBAkol jako hotov\xC3\xBD" + due: "Pl\xC3\xA1nov\xC3\xA1no na" + action_marked_complete_error: "\xC3\x9Akol '%{description}' NEBYL ozna\xC4\x8Den jako %{completed} kv\xC5\xAFli chyb\xC4\x9B na serveru." + depends_on_separate_with_commas: !binary | + WsOhdmlzw60gbmEgKG9kZMSbbGVubyDEjcOhcmthbWkp + + recurring_action_saved: "Opakovan\xC3\xBD \xC3\xBAkol byl ulo\xC5\xBEen" + action_saved_to_tickler: "\xC3\x9Akol byl ulo\xC5\xBEen do Tickleru" + completed_in_archive: + one: "V archivu je hotov\xC3\xBD \xC3\xBAkol." + other: "V archivu je %{count} hotov\xC3\xBDch \xC3\xBAkol\xC5\xAF." to_tickler: do Tickleru - next_actions_description_additions: - completed: v posledních %{count} dnech - due_date: plánovano na %{due_date} nebo dříve - overdue: Spožděné úkoly - add_new_recurring: Vytvořit opakovaný úkol - edit_recurring_todo: Upravit opakovaný úkol - no_incomplete_actions: Žádné nehotové úkoly - notes: - delete_confirmation: Opravdu chcete smazat poznámku '%{id}'? - delete_item_title: Smazat položku - delete_note_title: Smazat poznámku '%{id}' - note_link_title: Zobrazit poznámku %{id} - show_note_title: Zobrazit poznámku - deleted_note: Smazat poznámku '%{id}' - edit_item_title: Upravit položku + next_actions_description_additions: + completed: "v posledn\xC3\xADch %{count} dnech" + due_date: "pl\xC3\xA1novano na %{due_date} nebo d\xC5\x99\xC3\xADve" + overdue: !binary | + U3Bvxb5kxJtuw6kgw7prb2x5 + + add_new_recurring: "Vytvo\xC5\x99it opakovan\xC3\xBD \xC3\xBAkol" + no_incomplete_actions: !binary | + xb3DoWRuw6kgbmVob3RvdsOpIMO6a29seQ== + + notes: + delete_note_title: "Smazat pozn\xC3\xA1mku '%{id}'" + delete_confirmation: "Opravdu chcete smazat pozn\xC3\xA1mku '%{id}'?" + delete_item_title: "Smazat polo\xC5\xBEku" + deleted_note: "Smazat pozn\xC3\xA1mku '%{id}'" + note_link_title: "Zobrazit pozn\xC3\xA1mku %{id}" + show_note_title: "Zobrazit pozn\xC3\xA1mku" + edit_item_title: "Upravit polo\xC5\xBEku" note_location_link: "V:" - no_notes_available: "Žádné poznámky: přidejte poznámky ze stránek jednotlivých projektů." - note_header: Poznámka %{id} - delete_note_confirm: Opravdu chcete smazat poznámku '%{id}'? - states: - hidden_plural: Skryté - completed: Hotový - completed_plural: Hotové - visible_plural: Viditelné - visible: Viditelný - active_plural: Aktivní - hidden: Skrytý - active: Aktivní - review_plural: Nerevidované - review: Nerevidovaný - stalled_plural: Opuštěné - stalled: Opuštěný - blocked_plural: Blokované - blocked: Blokovaný - current_plural: Aktuální - current: Aktuální - projects: - was_marked_hidden: byl označen jako skrytý + no_notes_available: "\xC5\xBD\xC3\xA1dn\xC3\xA9 pozn\xC3\xA1mky: p\xC5\x99idejte pozn\xC3\xA1mky ze str\xC3\xA1nek jednotliv\xC3\xBDch projekt\xC5\xAF." + note_header: "Pozn\xC3\xA1mka %{id}" + delete_note_confirm: "Opravdu chcete smazat pozn\xC3\xA1mku '%{id}'?" + states: + hidden_plural: "Skryt\xC3\xA9" + review_plural: "Nerevidovan\xC3\xA9" + stalled: !binary | + T3B1xaF0xJtuw70= + + completed: "Hotov\xC3\xBD" + current: !binary | + QWt0dcOhbG7DrQ== + + review: "Nerevidovan\xC3\xBD" + completed_plural: "Hotov\xC3\xA9" + blocked_plural: "Blokovan\xC3\xA9" + blocked: "Blokovan\xC3\xBD" + stalled_plural: !binary | + T3B1xaF0xJtuw6k= + + visible_plural: "Viditeln\xC3\xA9" + active_plural: "Aktivn\xC3\xAD" + visible: "Viditeln\xC3\xBD" + current_plural: !binary | + QWt0dcOhbG7DrQ== + + hidden: "Skryt\xC3\xBD" + active: "Aktivn\xC3\xAD" + errors: + user_unauthorized: "401 Neautorizov\xC3\xA1no: Jen administr\xC3\xA1to\xC5\x99i sm\xC3\xAD pou\xC5\xBE\xC3\xADvat tuto funkci." + projects: + no_actions_in_project: !binary | + xb3DoWRuw6kgYWt0aXZuw60gw7prb2x5 + + deferred_actions: "Odlo\xC5\xBEen\xC3\xA9 \xC3\xBAkoly projektu" + was_marked_hidden: "byl ozna\xC4\x8Den jako skryt\xC3\xBD" edit_project_title: Upravit projekt - default_tags_removed_notice: Výchozí štítky byly odstraněny - default_context_set: Výchozí kontext %{default_context} byl nastaven - no_actions_in_project: Žádné aktivní úkoly - deferred_actions: Odložené úkoly projektu - all_completed_tasks_title: TRACKS::Hotové úkoly projektu '%{project_name}' - hide_form: Skrýt formulář + default_tags_removed_notice: "V\xC3\xBDchoz\xC3\xAD \xC5\xA1t\xC3\xADtky byly odstran\xC4\x9Bny" + default_context_set: "V\xC3\xBDchoz\xC3\xAD kontext %{default_context} byl nastaven" + hide_form: !binary | + U2tyw710IGZvcm11bMOhxZk= + page_title: "TRACKS::Projekt: %{project}" - show_form_title: Nový projekt - list_completed_projects: TRACKS::Hotové projekty - to_new_project_page: přejít k novému projektu - no_notes_attached: Žádné poznámky - deferred_actions_empty: Žádné odložené úkoly - this_project: Tento projekt + all_completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly projektu '%{project_name}'" project_state: Projekt je %{state}. + list_completed_projects: "TRACKS::Hotov\xC3\xA9 projekty" + to_new_project_page: "p\xC5\x99ej\xC3\xADt k nov\xC3\xA9mu projektu" + no_notes_attached: !binary | + xb3DoWRuw6kgcG96bsOhbWt5 + + show_form_title: "Nov\xC3\xBD projekt" + deferred_actions_empty: !binary | + xb3DoWRuw6kgb2Rsb8W+ZW7DqSDDumtvbHk= + + this_project: Tento projekt + no_last_completed_recurring_todos: !binary | + xb3DoWRuw6kgaG90b3bDqSBvcGFrb3ZhbsOpIMO6a29seQ== + todos_append: v tomto projektu - no_last_completed_projects: Žádné hotové projekty - notes: Poznámky - no_last_completed_recurring_todos: Žádné hotové opakované úkoly - notes_empty: Žádné poznámky - no_projects: Žádné projekty - hide_form_title: Schovat formulář založení projektu - with_no_default_context: bez výchozího kontextu - delete_project: Smazat projekt - completed_actions_empty: V tomto projektu nejsou žádné hotové úkoly - show_form: Nový projekt - actions_in_project_title: Úkoly v tomto projetku - delete_project_confirmation: Opravdu chcete smazat projekt '%{name}'? - with_default_context: s výchozím kontextem '%{context_name}' - set_default_tags_notice: Nastavit výchozí šítky úkolů v tomto projektu %{default_tags} - is_active: je aktivní - settings: Nastavení - completed_projects: Hotové projetky - with_default_tags: a s '%{tags}' jako výchozí štítky - list_projects: TRACKS::Projekty + no_last_completed_projects: !binary | + xb3DoWRuw6kgaG90b3bDqSBwcm9qZWt0eQ== + + notes: "Pozn\xC3\xA1mky" + hide_form_title: "Schovat formul\xC3\xA1\xC5\x99 zalo\xC5\xBEen\xC3\xAD projektu" list_reviews: TRACKS::Revize - project_saved_status: Projekt byl uložen - add_project: Přidat projekt - add_note: Nová poznámka - completed_tasks_title: TRACKS::Hotové úkoly projektu '%{project_name}' - delete_project_title: Smaže projekt - hidden_projects: Skryté projekty - add_note_submit: Nová poznámka - was_marked_complete: byl označen jako hotový - completed_actions: Hotové úkoly tohoto projektu - default_context_removed: Výchozí kontext byl odstraněn - default_context: Výchozí kontext pro tento projekt je %{context} - status_project_name_changed: Jméno projektu bylo změněno - active_projects: Aktivní projekty - no_default_context: Tento projekt nemá výchozí kontext - with_no_default_tags: a nemá žádné výchozí značky + notes_empty: !binary | + xb3DoWRuw6kgcG96bsOhbWt5 + + no_projects: !binary | + xb3DoWRuw6kgcHJvamVrdHk= + + completed_actions_empty: "V tomto projektu nejsou \xC5\xBE\xC3\xA1dn\xC3\xA9 hotov\xC3\xA9 \xC3\xBAkoly" + with_no_default_context: "bez v\xC3\xBDchoz\xC3\xADho kontextu" + delete_project: Smazat projekt + show_form: "Nov\xC3\xBD projekt" + actions_in_project_title: "\xC3\x9Akoly v tomto projetku" + delete_project_confirmation: Opravdu chcete smazat projekt '%{name}'? + with_default_context: "s v\xC3\xBDchoz\xC3\xADm kontextem '%{context_name}'" + set_default_tags_notice: "Nastavit v\xC3\xBDchoz\xC3\xAD \xC5\xA1\xC3\xADtky \xC3\xBAkol\xC5\xAF v tomto projektu %{default_tags}" + completed_projects: "Hotov\xC3\xA9 projetky" + add_note: "Nov\xC3\xA1 pozn\xC3\xA1mka" + add_project: "P\xC5\x99idat projekt" + with_default_tags: "a s '%{tags}' jako v\xC3\xBDchoz\xC3\xAD \xC5\xA1t\xC3\xADtky" + settings: "Nastaven\xC3\xAD" + list_projects: TRACKS::Projekty + is_active: "je aktivn\xC3\xAD" + project_saved_status: "Projekt byl ulo\xC5\xBEen" + delete_project_title: "Sma\xC5\xBEe projekt" + hidden_projects: "Skryt\xC3\xA9 projekty" + completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly projektu '%{project_name}'" + default_context_removed: "V\xC3\xBDchoz\xC3\xAD kontext byl odstran\xC4\x9Bn" + completed_actions: "Hotov\xC3\xA9 \xC3\xBAkoly tohoto projektu" + add_note_submit: "Nov\xC3\xA1 pozn\xC3\xA1mka" + was_marked_complete: "byl ozna\xC4\x8Den jako hotov\xC3\xBD" + no_default_context: "Tento projekt nem\xC3\xA1 v\xC3\xBDchoz\xC3\xAD kontext" + with_no_default_tags: !binary | + YSBuZW3DoSDFvsOhZG7DqSB2w71jaG96w60gem5hxI1reQ== + edit_project_settings: Upravit vlastnosti projektu + status_project_name_changed: "Jm\xC3\xA9no projektu bylo zm\xC4\x9Bn\xC4\x9Bno" state: Tento projekt je %{state} - time: + default_context: "V\xC3\xBDchoz\xC3\xAD kontext pro tento projekt je %{context}" + active_projects: "Aktivn\xC3\xAD projekty" + preferences: + change_identity_url: "Zm\xC4\x9Bna URL identity" + open_id_url: "Va\xC5\xA1e OpenID URL je" + staleness_starts_after: "Zastar\xC3\xA1n\xC3\xAD nast\xC3\xA1v\xC3\xA1 po %{days} dnech" + page_title: "TRACKS::Nastaven\xC3\xAD" + change_password: "Zm\xC4\x9Bna hesla" + token_description: "Pe\xC5\xA1ek (feedy a pou\xC5\xBEit\xC3\xAD API)" + title: "Va\xC5\xA1e nastaven\xC3\xAD" + is_false: ne + show_number_completed: "Zobrazit %{number} hotov\xC3\xBDch polo\xC5\xBEek" + page_title_edit: "TRACKS::Editace nastaven\xC3\xAD" + is_true: ano + password_changed: "Heslo bylo zm\xC4\x9Bn\xC4\x9Bno. Pros\xC3\xADm znovu se p\xC5\x99ihla\xC5\xA1te." + edit_preferences: "Editace nastaven\xC3\xAD" + generate_new_token: "Generovat nov\xC3\xA9ho pe\xC5\xA1ka" + sms_context_none: !binary | + xb7DoWRuw70= + + token_header: !binary | + VsOhxaEgcGXFoWVr + + authentication_header: "Va\xC5\xA1e autentizace" + updated: "Nastaven\xC3\xAD bylo ulo\xC5\xBEeno" + current_authentication_type: "Pou\xC5\xBE\xC3\xADv\xC3\xA1te autentizaci %{auth_type}" + change_authentication_type: "Zm\xC4\x9Bna typu autentizace" + generate_new_token_confirm: "Opravdu? Nov\xC3\xBD pe\xC5\xA1ek nahrad\xC3\xAD ten p\xC5\xAFvodn\xC3\xAD a zp\xC5\xAFsob\xC3\xAD nefunk\xC4\x8Dnost ve v\xC5\xA1ech aplikac\xC3\xADch, kde jej pou\xC5\xBE\xC3\xADv\xC3\xA1te." + tabs: + tracks_behavior: "Chov\xC3\xA1n\xC3\xAD Tracks" + authentication: Autentizace + profile: Profil + date_and_time: "Datum a \xC4\x8Das" + time: am: am - formats: + formats: default: "%a, %d %b %Y %H:%M:%S %z" time: "" short: "%d %b %H:%M" month_day: "%B %d" long: "%B %d, %Y %H:%M" pm: pm - preferences: - open_id_url: Vaše OpenID URL je - staleness_starts_after: Zastarání nastává po %{days} dnech - change_identity_url: Změna URL identity - change_password: Změna hesla - password_changed: Heslo bylo změněno. Prosím znovu se přihlašte. - updated: Nastavení bylo uloženo - page_title: TRACKS::Nastavení - title: Vaše nastavení - token_description: Pešek (feedy a použití API) - is_false: "ne" - show_number_completed: Zobrazit %{number} hotových položek - page_title_edit: TRACKS::Editace nastavení - is_true: "ano" - edit_preferences: Editace nastavení - sms_context_none: žádný - generate_new_token: Generovat nového peška - token_header: Váš pešek - authentication_header: Vaše autentizace - current_authentication_type: Používáte autentizaci %{auth_type} - change_authentication_type: Změna typu autentizace - tabs: - authentication: Autentizace - tracks_behavior: Chování Tracks - profile: Profil - date_and_time: Datum a čas - generate_new_token_confirm: Opravdu? Nový pešek nahradí ten původní a způsobí nefunkčnost ve všech aplikacích, kde jej používáte. - errors: - user_unauthorized: "401 Neautorizováno: Jen administrátoři smí používat tuto funkci." - date: - month_names: - - + date: + month_names: + - - Leden - - Únor - - Březen + - !binary | + w5pub3I= + + - "B\xC5\x99ezen" - Duben - - Květen - - Červen - - Červenec + - "Kv\xC4\x9Bten" + - "\xC4\x8Cerven" + - "\xC4\x8Cervenec" - Srpen - - Září - - Říjen + - !binary | + WsOhxZnDrQ== + + - !binary | + xZjDrWplbg== + - Listopad - Prosinec - abbr_day_names: + abbr_day_names: - Ne - Po - - Út + - !binary | + w5p0 + - St - - Čt - - Pá + - !binary | + xIx0 + + - !binary | + UMOh + - So - order: + order: - :rok - - :měsíc + - ":m\xC4\x9Bs\xC3\xADc" - :den - formats: + formats: only_day: "" + longer: "%A %B %d, %Y" default: "%Y-%m-%d" short: "%b %d" month_day: "" long: "%B %d, %Y" - longer: "%A %B %d, %Y" - day_names: - - Neděle - - Ponělí - - Úterý - - Středa - - Čtvrtek - - Pátek + day_names: + - "Ned\xC4\x9Ble" + - !binary | + UG9uxJtsw60= + + - !binary | + w5p0ZXLDvQ== + + - "St\xC5\x99eda" + - "\xC4\x8Ctvrtek" + - !binary | + UMOhdGVr + - Sobota - abbr_month_names: - - + abbr_month_names: + - - Led - - Úno - - Bře + - !binary | + w5pubw== + + - !binary | + QsWZZQ== + - Dub - - Kvě - - Čer - - Čec + - !binary | + S3bEmw== + + - !binary | + xIxlcg== + + - !binary | + xIxlYw== + - Srp - - Zář - - Říj + - !binary | + WsOhxZk= + + - !binary | + xZjDrWo= + - Lis - Pro - support: - array: + will_paginate: + previous_label: "« p\xC5\x99edchoz\xC3\xAD" + page_entries_info: + multi_page: Zobrazuji %{model} %{from} - %{to} o %{count} celkem + single_page_html: + one: "Zobrazen\xC3\xAD 1 %{model}" + other: "Zobrazen\xC3\xAD v\xC5\xA1e %{count} %{model}" + zero: !binary | + xb3DoWRuw6kgJXttb2RlbH0gbmFsw6l6dA== + + single_page: + one: Zobrazuji 1 %{model} + other: "Zobrazen\xC3\xAD v\xC5\xA1ech %{count} %{model}" + zero: !binary | + xb3DoWRuw6kgJXttb2RlbH0gbmFsw6l6dA== + + multi_page_html: Zobrazuji %{model} %{from} - %{to} of %{count} celkem + page_gap: "…" + next_label: "dal\xC5\xA1\xC3\xAD »" + support: + array: words_connector: ", " last_word_connector: ", a " two_words_connector: " a " - select: - prompt: Prosím vyberte - footer: - send_feedback: Poslat zpětnou vazbu na %{version} - shared: - multiple_next_actions: Úkoly (jeden na každém řádku) - hide_form: Schovat formulář - toggle_single: Přidat úkol - add_action: Přidat úkol - add_actions: Přidat úkoly - tags_for_all_actions: Značky (oddělené čárkami) - toggle_single_title: Přidat jeden nový úkol - project_for_all_actions: Projekt (pro všechny) - context_for_all_actions: Kontext (pro všechny) - toggle_multi: Přidat více úkolů - separate_tags_with_commas: oddělené čárkami - toggle_multi_title: Přepnout formulář zakládání jedoho/více úkolů - hide_action_form_title: Skrýt formulář pro založení nového úkolu - make_actions_dependent: Akce budou vzájemně závislé - users: - successfully_deleted_user: Uživatel %{username} byl úspěšně smazán - failed_to_delete_user: Nepodařilo se smazat uživatele %{username} - total_contexts: Kontextů celkem - first_user_heading: "Vítejte v TRACKS. Nejdříve je nutné vytvořit administrátorský účet:" - openid_url_verified: Identitní url %{url} bylo úspěšně ověřeno a nastavena autentizace pomocí OpenID. - auth_type_update_error: "Nepodařilo se změnit typ autentizace: %{error_messages}" - destroy_successful: Uživatel %{login} byl úspěšně zničen - new_token_generated: Nový pešek byl úspěšně vygenerován - total_projects: Projektů celkem - signup_successful: Registrace uživatele %{username} byla úspěšná. - change_password_submit: Změnit heslo - no_signups_title: TRACKS::Registrace není povolena - user_created: Uživatel byl vytvořen. - manage_users: Správa uživatelů - account_signup: Registrace uživatele - password_updated: Heslo bylo změněno. - desired_login: Uživatelské jméno - signup: Registrace - confirm_password: Potvrzení hesla - new_user_heading: "Registrace nového uživatele:" - auth_type_updated: Typ autentizace byl změněn. - total_actions: Úkolů celkem - change_password_title: TRACKS::Změna hesla - change_auth_type_title: TRACKS::Změna zůsobu autentizace - change_password_prompt: Pro změnu hesla zadejte nové hestlo do polí níže a stiskněte 'Změna hesla'. - password_confirmation_label: Potvrzení hesla - destroy_error: Nepodařilo se smazat uživatele %{login} - choose_password: Zvolte heslo - register_with_cas: S vaším uživatelským jménem z CASu - label_auth_type: Způsob autentizace - new_password_label: Nové heslo - you_have_to_reset_your_password: "Je nutné změnit heslo" - new_user_title: TRACKS::Přihlášení jako administrátor - destroy_user: Zničit uživatele - total_users_count: Máte celkem %{count} uživatelů - destroy_confirmation: "Varování: tato akce smaže uživatele '%{login}', všechny jeho úkoly, kontexty, projekty i poznámky. Opravdu chcete pokračovat?" - signup_new_user: Registrace nového uživatele - openid_ok_pref_failed: Vaše identitní URL %{url} bylo úspěšně ověřeno, ale došlo k problému při ukládání nastavení. - identity_url: URL identity - auth_change_submit: Změnit způsob přihlašování - change_authentication_type: Změna způsobu přihlašování - total_notes: Poznámek celkem - select_authentication_type: Vyberte nový způsob autentizace a stiskněte 'Změnit způsob přihlašování'. - sidebar: - list_name_active_contexts: Aktivní kontexty - list_name_active_projects: Aktivní projekty - list_empty: Nic - list_name_completed_projects: Hotové projekty - list_name_hidden_projects: Skryté projekty - list_name_hidden_contexts: Skryté kontexty - feedlist: - choose_context: Vyberte kontext jehož feed si přejete - actions_due_today: Akce plánované na dnes + select: + prompt: "Pros\xC3\xADm vyberte" + shared: + multiple_next_actions: "\xC3\x9Akoly (jeden na ka\xC5\xBEd\xC3\xA9m \xC5\x99\xC3\xA1dku)" + make_actions_dependent: "Akce budou vz\xC3\xA1jemn\xC4\x9B z\xC3\xA1visl\xC3\xA9" + hide_form: "Schovat formul\xC3\xA1\xC5\x99" + toggle_single: !binary | + UMWZaWRhdCDDumtvbA== + + add_actions: "P\xC5\x99idat \xC3\xBAkoly" + add_action: !binary | + UMWZaWRhdCDDumtvbA== + + tags_for_all_actions: !binary | + Wm5hxI1reSAob2RkxJtsZW7DqSDEjcOhcmthbWkp + + toggle_multi: !binary | + UMWZaWRhdCB2w61jZSDDumtvbMWv + + toggle_single_title: "P\xC5\x99idat jeden nov\xC3\xBD \xC3\xBAkol" + project_for_all_actions: "Projekt (pro v\xC5\xA1echny)" + context_for_all_actions: "Kontext (pro v\xC5\xA1echny)" + separate_tags_with_commas: !binary | + b2RkxJtsZW7DqSDEjcOhcmthbWk= + + toggle_multi_title: !binary | + UMWZZXBub3V0IGZvcm11bMOhxZkgemFrbMOhZMOhbsOtIGplZG9oby92w61j + ZSDDumtvbMWv + + hide_action_form_title: "Skr\xC3\xBDt formul\xC3\xA1\xC5\x99 pro zalo\xC5\xBEen\xC3\xAD nov\xC3\xA9ho \xC3\xBAkolu" + footer: + send_feedback: "Poslat zp\xC4\x9Btnou vazbu na %{version}" + feedlist: + actions_due_today: "Akce pl\xC3\xA1novan\xC3\xA9 na dnes" + choose_context: "Vyberte kontext jeho\xC5\xBE feed si p\xC5\x99ejete" rss_feed: RSS Feed - ical_feed: iCal feed - all_contexts: Všechny kontexty legend: "Legenda:" - all_projects: Všechny projekty - choose_project: Vyberte projekt jehož feed si přejete + ical_feed: iCal feed + all_contexts: "V\xC5\xA1echny kontexty" + all_projects: "V\xC5\xA1echny projekty" + choose_project: "Vyberte projekt jeho\xC5\xBE feed si p\xC5\x99ejete" + project_needed: "Mus\xC3\xADte nejd\xC5\x99\xC3\xADve zalo\xC5\xBEit aspo\xC5\x88 jeden projekt" select_feed_for_project: Vyberte feed pro tento projekt - active_projects_wo_next: Aktivni projekty bez úkolů - project_needed: Musíte nejdříve založit aspoň jeden projekt - active_starred_actions: Všechny aktivní úkoly s hvězdičkou + active_projects_wo_next: "Aktivni projekty bez \xC3\xBAkol\xC5\xAF" + active_starred_actions: "V\xC5\xA1echny aktivn\xC3\xAD \xC3\xBAkoly s hv\xC4\x9Bzdi\xC4\x8Dkou" + context_needed: "Mus\xC3\xADte nejd\xC5\x99\xC3\xADve zalo\xC5\xBEit aspo\xC5\x88 jeden kontext" select_feed_for_context: Select the feed for this context - projects_and_actions: Aktivní projekty a jejich úkoly - context_needed: Musíte nejdříve založit aspoň jeden kontext - actions_due_next_week: Úkoly plánované na příštích sedm dní - notice_incomplete_only: "Poznámka: všechny feedy obsahují jen nehotové úkoly." - all_actions: Všechny úkoly - actions_completed_last_week: Úkoly dokončené v posledních sedmi dnech - context_centric_actions: Feedy s aktivními úkoly podle kontextů - plain_text_feed: Prostý text - last_fixed_number: Posledních %{number} úkolů - project_centric: Feedy s aktivními úkoly podle projektu - contexts: + projects_and_actions: "Aktivn\xC3\xAD projekty a jejich \xC3\xBAkoly" + actions_due_next_week: !binary | + w5prb2x5IHBsw6Fub3ZhbsOpIG5hIHDFmcOtxaF0w61jaCBzZWRtIGRuw60= + + notice_incomplete_only: "Pozn\xC3\xA1mka: v\xC5\xA1echny feedy obsahuj\xC3\xAD jen nehotov\xC3\xA9 \xC3\xBAkoly." + last_fixed_number: "Posledn\xC3\xADch %{number} \xC3\xBAkol\xC5\xAF" + all_actions: "V\xC5\xA1echny \xC3\xBAkoly" + actions_completed_last_week: "\xC3\x9Akoly dokon\xC4\x8Den\xC3\xA9 v posledn\xC3\xADch sedmi dnech" + context_centric_actions: "Feedy s aktivn\xC3\xADmi \xC3\xBAkoly podle kontext\xC5\xAF" + plain_text_feed: "Prost\xC3\xBD text" + project_centric: "Feedy s aktivn\xC3\xADmi \xC3\xBAkoly podle projektu" + users: + successfully_deleted_user: "U\xC5\xBEivatel %{username} byl \xC3\xBAsp\xC4\x9B\xC5\xA1n\xC4\x9B smaz\xC3\xA1n" + failed_to_delete_user: "Nepoda\xC5\x99ilo se smazat u\xC5\xBEivatele %{username}" + destroy_successful: "U\xC5\xBEivatel %{login} byl \xC3\xBAsp\xC4\x9B\xC5\xA1n\xC4\x9B zni\xC4\x8Den" + total_contexts: "Kontext\xC5\xAF celkem" + openid_url_verified: "Identitn\xC3\xAD url %{url} bylo \xC3\xBAsp\xC4\x9B\xC5\xA1n\xC4\x9B ov\xC4\x9B\xC5\x99eno a nastavena autentizace pomoc\xC3\xAD OpenID." + first_user_heading: "V\xC3\xADtejte v TRACKS. Nejd\xC5\x99\xC3\xADve je nutn\xC3\xA9 vytvo\xC5\x99it administr\xC3\xA1torsk\xC3\xBD \xC3\xBA\xC4\x8Det:" + auth_type_update_error: "Nepoda\xC5\x99ilo se zm\xC4\x9Bnit typ autentizace: %{error_messages}" + new_token_generated: !binary | + Tm92w70gcGXFoWVrIGJ5bCDDunNwxJvFoW7EmyB2eWdlbmVyb3bDoW4= + + total_projects: "Projekt\xC5\xAF celkem" + signup_successful: "Registrace u\xC5\xBEivatele %{username} byla \xC3\xBAsp\xC4\x9B\xC5\xA1n\xC3\xA1." + no_signups_title: "TRACKS::Registrace nen\xC3\xAD povolena" + user_created: "U\xC5\xBEivatel byl vytvo\xC5\x99en." + change_password_submit: "Zm\xC4\x9Bnit heslo" + account_signup: "Registrace u\xC5\xBEivatele" + manage_users: !binary | + U3Byw6F2YSB1xb5pdmF0ZWzFrw== + + password_updated: "Heslo bylo zm\xC4\x9Bn\xC4\x9Bno." + auth_type_updated: "Typ autentizace byl zm\xC4\x9Bn\xC4\x9Bn." + total_actions: "\xC3\x9Akol\xC5\xAF celkem" + desired_login: "U\xC5\xBEivatelsk\xC3\xA9 jm\xC3\xA9no" + signup: Registrace + confirm_password: "Potvrzen\xC3\xAD hesla" + new_user_heading: "Registrace nov\xC3\xA9ho u\xC5\xBEivatele:" + change_password_prompt: "Pro zm\xC4\x9Bnu hesla zadejte nov\xC3\xA9 hestlo do pol\xC3\xAD n\xC3\xAD\xC5\xBEe a stiskn\xC4\x9Bte 'Zm\xC4\x9Bna hesla'." + password_confirmation_label: "Potvrzen\xC3\xAD hesla" + destroy_error: "Nepoda\xC5\x99ilo se smazat u\xC5\xBEivatele %{login}" + choose_password: Zvolte heslo + change_password_title: "TRACKS::Zm\xC4\x9Bna hesla" + change_auth_type_title: "TRACKS::Zm\xC4\x9Bna z\xC5\xAFsobu autentizace" + new_password_label: "Nov\xC3\xA9 heslo" + register_with_cas: "S va\xC5\xA1\xC3\xADm u\xC5\xBEivatelsk\xC3\xBDm jm\xC3\xA9nem z CASu" + label_auth_type: "Zp\xC5\xAFsob autentizace" + new_user_title: "TRACKS::P\xC5\x99ihl\xC3\xA1\xC5\xA1en\xC3\xAD jako administr\xC3\xA1tor" + destroy_user: "Zni\xC4\x8Dit u\xC5\xBEivatele" + total_users_count: "M\xC3\xA1te celkem %{count} u\xC5\xBEivatel\xC5\xAF" + you_have_to_reset_your_password: "Je nutn\xC3\xA9 zm\xC4\x9Bnit heslo" + signup_new_user: "Registrace nov\xC3\xA9ho u\xC5\xBEivatele" + destroy_confirmation: "Varov\xC3\xA1n\xC3\xAD: tato akce sma\xC5\xBEe u\xC5\xBEivatele '%{login}', v\xC5\xA1echny jeho \xC3\xBAkoly, kontexty, projekty i pozn\xC3\xA1mky. Opravdu chcete pokra\xC4\x8Dovat?" + identity_url: URL identity + openid_ok_pref_failed: "Va\xC5\xA1e identitn\xC3\xAD URL %{url} bylo \xC3\xBAsp\xC4\x9B\xC5\xA1n\xC4\x9B ov\xC4\x9B\xC5\x99eno, ale do\xC5\xA1lo k probl\xC3\xA9mu p\xC5\x99i ukl\xC3\xA1d\xC3\xA1n\xC3\xAD nastaven\xC3\xAD." + change_authentication_type: !binary | + Wm3Em25hIHpwxa9zb2J1IHDFmWlobGHFoW92w6Fuw60= + + auth_change_submit: !binary | + Wm3Em25pdCB6cMWvc29iIHDFmWlobGHFoW92w6Fuw60= + + select_authentication_type: "Vyberte nov\xC3\xBD zp\xC5\xAFsob autentizace a stiskn\xC4\x9Bte 'Zm\xC4\x9Bnit zp\xC5\xAFsob p\xC5\x99ihla\xC5\xA1ov\xC3\xA1n\xC3\xAD'." + total_notes: "Pozn\xC3\xA1mek celkem" + contexts: delete_context_title: Smazat kontext - all_completed_tasks_title: TRACKS::Hotové úkoly v kontextu '%{context_name}' - hide_form: Schovat formulář - show_form_title: Nový kontext - delete_context_confirmation: Opravdu chcete smazat kontext '%{name}'? Dojde ke smazání všech (opakovaných) úkolů z daného kontextu! + hide_form: "Schovat formul\xC3\xA1\xC5\x99" + all_completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly v kontextu '%{context_name}'" + show_form_title: "Nov\xC3\xBD kontext" + delete_context_confirmation: "Opravdu chcete smazat kontext '%{name}'? Dojde ke smaz\xC3\xA1n\xC3\xAD v\xC5\xA1ech (opakovan\xC3\xBDch) \xC3\xBAkol\xC5\xAF z dan\xC3\xA9ho kontextu!" + todos_append: "v t\xC3\xA9to souvislosti" delete_context: Smazat kontext edit_context: Upravit kontext - hide_form_title: Schovat formulář - context_hide: Schovat z úvodní stránky? + hide_form_title: "Schovat formul\xC3\xA1\xC5\x99" + context_hide: "Schovat z \xC3\xBAvodn\xC3\xAD str\xC3\xA1nky?" hidden_contexts: Schovat kontexty - no_contexts_active: Žádné aktivní kontexty - show_form: Nový kontext - visible_contexts: Viditelné kontexty - save_status_message: Kontext uložen - add_context: Vytvořit kontext - context_name: Náev kontextu - update_status_message: Název kontextu byl změněn - completed_tasks_title: TRACKS::Hotové úkoly v kontextu '%{context_name}' - new_context_post: "' bude také vytvořen. Opravdu?" - status_active: Kontext je aktivní - no_actions: Žádné aktivní úkoly v tomto kontextu - last_completed_in_context: v tomto kontextu (posledních %{number}) - context_deleted: Kontext byl odstraněn '%{name}' - no_contexts_hidden: Žádné skryté kontexty - new_context_pre: Nový kontext ' - status_hidden: kontext je skrytý - login: - login_cas: přejít na CAS - sign_in: Přihlásit se - openid_identity_url_not_found: Je nám líto, neexistuje uživatel s touto identitou (%{identity_url}) - user_no_expiry: Neodhlšovat - cas_no_user_found: Nazdar, %{username}! Nemáte účet na Tracks. - cas_login: Přihlášení přes CAS - successful_with_session_info: "Přihlášení bylo úspěšné:" - please_login: Pro pokračování se prosím přihlšte do Tracks - cas_logged_in_greeting: Zdravíčko, %{username}! Byl jste autorizován. - cas_username_not_found: Bohužel neexistuje uživatel v CASu se jménem (%{username}) - mobile_use_openid: "\xE2\x80\xA6nebo přihlášení s OpenID" - cas_create_account: Pro vytvoření účtu v CASu prosím pokračujte sem %{signup_link} - account_login: Přihlášení uživatele - cas_signup_link: Vyžádat účet - session_will_not_expire: sezení bylo nastaveno jako trvalé. - successful: Přihlášení úspěšné. Vítejte zpět! + no_contexts_active: !binary | + xb3DoWRuw6kgYWt0aXZuw60ga29udGV4dHk= + + show_form: "Nov\xC3\xBD kontext" + visible_contexts: "Viditeln\xC3\xA9 kontexty" + save_status_message: "Kontext ulo\xC5\xBEen" + add_context: "Vytvo\xC5\x99it kontext" + update_status_message: "N\xC3\xA1zev kontextu byl zm\xC4\x9Bn\xC4\x9Bn" + context_name: "N\xC3\xA1ev kontextu" + status_active: "Kontext je aktivn\xC3\xAD" + completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly v kontextu '%{context_name}'" + new_context_post: "' bude tak\xC3\xA9 vytvo\xC5\x99en. Opravdu?" + no_actions: "\xC5\xBD\xC3\xA1dn\xC3\xA9 aktivn\xC3\xAD \xC3\xBAkoly v tomto kontextu" + last_completed_in_context: "v tomto kontextu (posledn\xC3\xADch %{number})" + context_deleted: "Kontext byl odstran\xC4\x9Bn '%{name}'" + no_contexts_hidden: !binary | + xb3DoWRuw6kgc2tyeXTDqSBrb250ZXh0eQ== + + new_context_pre: "Nov\xC3\xBD kontext '" + status_hidden: "kontext je skryt\xC3\xBD" + sidebar: + list_name_active_contexts: "Aktivn\xC3\xAD kontexty" + list_name_active_projects: "Aktivn\xC3\xAD projekty" + list_empty: Nic + list_name_completed_projects: "Hotov\xC3\xA9 projekty" + list_name_hidden_projects: "Skryt\xC3\xA9 projekty" + list_name_hidden_contexts: "Skryt\xC3\xA9 kontexty" + login: + sign_in: "P\xC5\x99ihl\xC3\xA1sit se" + openid_identity_url_not_found: "Je n\xC3\xA1m l\xC3\xADto, neexistuje u\xC5\xBEivatel s touto identitou (%{identity_url})" + user_no_expiry: "Neodhl\xC5\xA1ovat" + login_cas: "p\xC5\x99ej\xC3\xADt na CAS" + cas_logged_in_greeting: "Zdrav\xC3\xAD\xC4\x8Dko, %{username}! Byl jste autorizov\xC3\xA1n." + cas_no_user_found: "Nazdar, %{username}! Nem\xC3\xA1te \xC3\xBA\xC4\x8Det na Tracks." + cas_login: !binary | + UMWZaWhsw6HFoWVuw60gcMWZZXMgQ0FT + + successful_with_session_info: !binary | + UMWZaWhsw6HFoWVuw60gYnlsbyDDunNwxJvFoW7DqTo= + + please_login: "Pro pokra\xC4\x8Dov\xC3\xA1n\xC3\xAD se pros\xC3\xADm p\xC5\x99ihl\xC5\xA1te do Tracks" + cas_username_not_found: "Bohu\xC5\xBEel neexistuje u\xC5\xBEivatel v CASu se jm\xC3\xA9nem (%{username})" + cas_create_account: "Pro vytvo\xC5\x99en\xC3\xAD \xC3\xBA\xC4\x8Dtu v CASu pros\xC3\xADm pokra\xC4\x8Dujte sem %{signup_link}" + mobile_use_openid: !binary | + 4oCmbmVibyBwxZlpaGzDocWhZW7DrSBzIE9wZW5JRA== + + cas_signup_link: !binary | + VnnFvsOhZGF0IMO6xI1ldA== + + account_login: !binary | + UMWZaWhsw6HFoWVuw60gdcW+aXZhdGVsZQ== + + successful: !binary | + UMWZaWhsw6HFoWVuw60gw7pzcMSbxaFuw6kuIFbDrXRlanRlIHpwxJt0IQ== + + session_will_not_expire: "sezen\xC3\xAD bylo nastaveno jako trval\xC3\xA9." + session_will_expire: "sezen vypr\xC5\xA1\xC3\xAD za %{hours} hodin neaktivity." option_separator: nebo - session_time_out: Sezení vypršelo. Prosím %{link} - session_will_expire: sezen vyprší za %{hours} hodin neaktivity. - login_standard: vraťte se ke standardnímu přihlášení + session_time_out: "Sezen\xC3\xAD vypr\xC5\xA1elo. Pros\xC3\xADm %{link}" + login_standard: "vra\xC5\xA5te se ke standardn\xC3\xADmu p\xC5\x99ihl\xC3\xA1\xC5\xA1en\xC3\xAD" + log_in_again: "p\xC5\x99ihla\xC5\xA1te se znovu." logged_out: You have been logged out of Tracks. - login_with_openid: přihlašte se se svým OpenID - unsuccessful: Přihlášení bylo úspěšné. - log_in_again: přihlašte se znovu. - datetime: - prompts: + login_with_openid: "p\xC5\x99ihla\xC5\xA1te se se sv\xC3\xBDm OpenID" + unsuccessful: !binary | + UMWZaWhsw6HFoWVuw60gYnlsbyDDunNwxJvFoW7DqS4= + + datetime: + prompts: minute: Minuta second: Sekunda - month: Měsíc + month: !binary | + TcSbc8OtYw== + hour: Hodina day: Den year: Rok - distance_in_words: - less_than_x_minutes: - one: méně než minuta - other: méně než %{count} minut - zero: méně než minuta - x_days: - one: 1 den - other: "%{count} dní" - almost_x_years: + distance_in_words: + less_than_x_minutes: + one: !binary | + bcOpbsSbIG5lxb4gbWludXRh + + other: "m\xC3\xA9n\xC4\x9B ne\xC5\xBE %{count} minut" + zero: !binary | + bcOpbsSbIG5lxb4gbWludXRh + + almost_x_years: one: almost 1 rok other: skoro %{count} let - x_seconds: + x_days: + one: 1 den + other: "%{count} dn\xC3\xAD" + x_seconds: one: 1 sekunda other: "%{count} sekund" - about_x_hours: + about_x_hours: one: about 1 hodina - other: přibližně %{count} hodin - less_than_x_seconds: - one: méně než 1 sekunda - other: mén než %{count} sekund - zero: méně než 1 sekunda - x_months: - one: 1 měsíc - other: "%{count} měsíců" - x_minutes: + other: "p\xC5\x99ibli\xC5\xBEn\xC4\x9B %{count} hodin" + less_than_x_seconds: + one: "m\xC3\xA9n\xC4\x9B ne\xC5\xBE 1 sekunda" + other: "m\xC3\xA9n ne\xC5\xBE %{count} sekund" + zero: "m\xC3\xA9n\xC4\x9B ne\xC5\xBE 1 sekunda" + x_months: + one: !binary | + MSBtxJtzw61j + + other: !binary | + JXtjb3VudH0gbcSbc8OtY8Wv + + x_minutes: one: 1 minuta other: "%{count} minut" - about_x_years: + about_x_years: one: about 1 rok - other: přibližně %{count} let - about_x_months: - one: about 1 měsíc - other: přibližně %{count} měsíců - over_x_years: - one: přes rok - other: přes %{count} let - half_a_minute: půl minuty - search: - contexts_matching_query: Nalezené kontexty - tags_matching_query: Nalezené štítky - notes_matching_query: Nalezené poznámky - no_results: Na váš dotaz nebylo nic nalezeno. - todos_matching_query: Nalezené úkoly - projects_matching_query: Nalezené projekty + other: "p\xC5\x99ibli\xC5\xBEn\xC4\x9B %{count} let" + about_x_months: + one: "about 1 m\xC4\x9Bs\xC3\xADc" + other: !binary | + cMWZaWJsacW+bsSbICV7Y291bnR9IG3Em3PDrWPFrw== + + over_x_years: + one: "p\xC5\x99es rok" + other: "p\xC5\x99es %{count} let" + half_a_minute: "p\xC5\xAFl minuty" + search: + contexts_matching_query: "Nalezen\xC3\xA9 kontexty" + tags_matching_query: !binary | + TmFsZXplbsOpIMWhdMOtdGt5 + + no_results: "Na v\xC3\xA1\xC5\xA1 dotaz nebylo nic nalezeno." + todos_matching_query: "Nalezen\xC3\xA9 \xC3\xBAkoly" + projects_matching_query: "Nalezen\xC3\xA9 projekty" + notes_matching_query: "Nalezen\xC3\xA9 pozn\xC3\xA1mky" diff --git a/config/locales/de.yml b/config/locales/de.yml index 700c1684..fdc53b65 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1,61 +1,5 @@ --- de: - common: - back: "Zur\xC3\xBCck" - third: Dritte - actions: Aktionen - recurring_todos: Wiederholenden Aktionen - add: "Hinzuf\xC3\xBCgen" - go_back: "Zur\xC3\xBCck" - logout: Abmelden - previous: Vorherige - none: Keine - second: Zweite - week: Woche - cancel: Abbrechen - optional: optional - month: Monat - forum: Forum - notes: Notizen - server_error: Auf dem Server ist ein Fehler aufgetreten. - last: Letzte - action: Aktion - projects: Projekte - review: !binary | - w5xiZXJwcsO8ZnVuZw== - - project: Projekt - ok: Ok - contribute: Mitwirken - first: Erste - website: Website - numbered_step: Schritt %{number} - errors_with_fields: "Mit folgenden Feldern sind Probleme aufgetreten:" - sort: - by_task_count_title: Nach Anzahl der Aufgaben sortieren - by_task_count_title_confirm: Sollen diese Projekte wirklich nach Anzahl der Aufgaben sortiert werden? Die bisherige Sortier-Reihenfolge wird damit überschrieben. - alphabetically: Alphabetisch - alphabetically_confirm: Sollen diese Projekte wirklich alphabetisch sortiert werden? Die bisherige Sortier-Reihenfolge wird damit überschrieben. - sort: Sortieren - alphabetically_title: Projekte alphabetisch sortieren - by_task_count: Nach Anzahl der Aufgaben - create: Erstellen - drag_handle: Verschieben - description: Beschreibung - context: Kontext - todo: Aktione - months: Monate - next: "N\xC3\xA4chste" - fourth: Vierte - contexts: Kontexte - update: Aktualisieren - weeks: Woche - forth: Vierte - wiki: Wiki - bugs: Bugs - email: E-Mail - ajaxError: Fehler beim Empfangen vom Server - search: Suchen number: format: separator: "," @@ -78,6 +22,9 @@ de: percentage: format: delimiter: "" + precision: + format: + delimiter: "" currency: format: format: "%n%u" @@ -87,9 +34,62 @@ de: separator: . precision: delimiter: "," - precision: - format: - delimiter: "" + common: + back: "Zur\xC3\xBCck" + recurring_todos: Wiederholenden Aktionen + actions: Aktionen + third: Dritte + add: "Hinzuf\xC3\xBCgen" + previous: Vorherige + go_back: "Zur\xC3\xBCck" + logout: Abmelden + second: Zweite + optional: optional + week: Woche + none: Keine + cancel: Abbrechen + month: Monat + forum: Forum + server_error: Auf dem Server ist ein Fehler aufgetreten. + notes: Notizen + last: Letzte + review: !binary | + w5xiZXJwcsO8ZnVuZw== + + projects: Projekte + action: Aktion + project: Projekt + ok: Ok + contribute: Mitwirken + first: Erste + website: Website + numbered_step: Schritt %{number} + errors_with_fields: "Mit folgenden Feldern sind Probleme aufgetreten:" + create: Erstellen + sort: + by_task_count_title: Nach Anzahl der Aufgaben sortieren + by_task_count_title_confirm: Sollen diese Projekte wirklich nach Anzahl der Aufgaben sortiert werden? Die bisherige Sortier-Reihenfolge wird damit überschrieben. + alphabetically: Alphabetisch + sort: Sortieren + alphabetically_confirm: Sollen diese Projekte wirklich alphabetisch sortiert werden? Die bisherige Sortier-Reihenfolge wird damit überschrieben. + alphabetically_title: Projekte alphabetisch sortieren + by_task_count: Nach Anzahl der Aufgaben + months: Monate + drag_handle: Verschieben + description: Beschreibung + fourth: Vierte + next: "N\xC3\xA4chste" + contexts: Kontexte + todo: Aktione + context: Kontext + update: Aktualisieren + weeks: Woche + forth: Vierte + wiki: Wiki + bugs: Bugs + email: E-Mail + ajaxError: Fehler beim Empfangen vom Server + search: Suchen layouts: toggle_contexts_title: Machen Sie brach Kontexten (un)sichtbare toggle_contexts: Toggle zusammengebrochen Kontexten @@ -97,9 +97,9 @@ de: next_actions_rss_feed: RSS-Feed kommende Aufgaben toggle_notes_title: Alle Notizen umschalten mobile_navigation: + new_action: Neue Aufgabe logout: Abmelden feeds: Feeds - new_action: Neue Aufgabe starred: Markiert projects: Projekte tickler: Notizbuch @@ -107,8 +107,8 @@ de: home: Home navigation: api_docs: REST API Docs - recurring_todos: Sich wiederholende To-Dos manage_users_title: "Benutzer hinzuf\xC3\xBCgen oder entfernen" + recurring_todos: Sich wiederholende To-Dos feeds: Feeds stats: Statistiken starred: Markiert @@ -116,31 +116,31 @@ de: manage_users: Benutzer verwalten tickler_title: Notizbuch integrations_: Tracks integrieren - preferences: Einstellungen export_title: Daten importieren und exportieren - calendar_title: "Kalender mit \xC3\xBCberf\xC3\xA4lligen Aufgaben" + preferences: Einstellungen feeds_title: "Liste der verf\xC3\xBCgbaren Feeds anzeigen" - stats_title: Statistiken anzeigen + calendar_title: "Kalender mit \xC3\xBCberf\xC3\xA4lligen Aufgaben" home_title: Start tickler: Notizbuch starred_title: Markierte Aufgaben betrachten recurring_todos_title: Sich wiederholende To-Dos verwalten completed_tasks: Erledigt - organize: Organisieren + stats_title: Statistiken anzeigen view: Betrachten + organize: Organisieren completed_tasks_title: "Vollst\xC3\xA4ndig" home: Start contexts_title: Kontexte export: Export + preferences_title: Meine Einstellungen + review_title: "Machen Sie \xC3\xBCberpr\xC3\xBCfen" search: "Alle Eintr\xC3\xA4ge durchsuchen" projects_title: Projekte - preferences_title: Meine Einstellungen calendar: Kalender - review_title: "Machen Sie \xC3\xBCberpr\xC3\xBCfen" integrations: opensearch_description: In Tracks suchen - applescript_next_action_prompt: "Beschreibung der n\xC3\xA4chsten Aufgabe:" gmail_description: "Gadget, um Tracks als Gadget zu Googlemail hinzuzuf\xC3\xBCgen" + applescript_next_action_prompt: "Beschreibung der n\xC3\xA4chsten Aufgabe:" applescript_success_after_id: erstellt applescript_success_before_id: "N\xC3\xA4chste neue Aufgabe mit ID" activerecord: @@ -151,8 +151,8 @@ de: default_context_name: Standard Kontext description: Beschreibung todo: - predecessors: "H\xC3\xA4ngt ab von" show_from: Zeigen ab dem + predecessors: "H\xC3\xA4ngt ab von" notes: Notizen project: Projekt description: Beschreibung @@ -169,19 +169,19 @@ de: staleness_starts: Anfang des Abgestandenheit verbose_action_descriptors: "Ausf\xC3\xBChrlich Aktion Deskriptoren" sms_context: Standard-E-Mail-Kontext - show_number_completed: "Zeige Zahl der abgeschlossenen Ma\xC3\x9Fnahmen" title_date_format: Titel Datumsformat + show_number_completed: "Zeige Zahl der abgeschlossenen Ma\xC3\x9Fnahmen" refresh: Aktualisierungsintverall (in Minuten) week_starts: Woche startet am last_name: Nachname - time_zone: Zeit Zone - due_style: "F\xC3\xA4llig stijl" locale: Zahle + due_style: "F\xC3\xA4llig stijl" + time_zone: Zeit Zone sms_email: Per E-Mail show_project_on_todo_done: Zur Projektseite wechseln, wenn To-Do abgeschlossen - first_name: Name show_completed_projects_in_sidebar: Zeige abgeschlossene Projekte in der Sidebar review_period: Projekt-Review-Intervall + first_name: Name errors: models: project: @@ -193,31 +193,34 @@ de: messages: record_invalid: "Validierung fehlgeschlagen: %{Fehler}" greater_than_or_equal_to: "muss gr\xC3\xB6\xC3\x9Fer oder gleich %{count} sein" - less_than_or_equal_to: muss kleiner oder gleich %{count} sein confirmation: "stimmt nicht mit der Best\xC3\xA4tigung \xC3\xBCberein" + less_than_or_equal_to: muss kleiner oder gleich %{count} sein blank: "muss ausgef\xC3\xBCllt werden" exclusion: "ist nicht verf\xC3\xBCgbar" invalid: "ist nicht g\xC3\xBCltig" odd: muss ungerade sein + even: muss gerade sein + empty: "muss ausgef\xC3\xBCllt werden" too_short: ist zu kurz (nicht weniger als %{count} Zeichen) wrong_length: "hat die falsche L\xC3\xA4nge (muss genau %{count} Zeichen haben)" - empty: "muss ausgef\xC3\xBCllt werden" - even: muss gerade sein less_than: muss kleiner als %{count} sein - equal_to: muss genau %{count} sein greater_than: "muss gr\xC3\xB6\xC3\x9Fer als %{count} sein" + equal_to: muss genau %{count} sein + accepted: muss akzeptiert werden too_long: ist zu lang (nicht mehr als %{count} Zeichen) taken: ist bereits vergeben - accepted: muss akzeptiert werden - not_a_number: ist keine Zahl inclusion: "ist kein g\xC3\xBCltiger Wert" + not_a_number: ist keine Zahl + full_messages: + format: "%{attribute} %{message}" template: body: "Bitte \xC3\xBCberpr\xC3\xBCfen Sie die folgenden Felder:" header: one: "Konnte dieses %{model} Objekt nicht speichern: 1 Fehler." other: "Konnte dieses %{model} Objekt nicht speichern: %{count} Fehler." - full_messages: - format: "%{attribute} %{message}" + data: + import_successful: Import war erfolgreich. + import_errors: Beim Import sind Fehler aufgetreten. models: project: feed_title: Tracks-Projekte @@ -233,42 +236,142 @@ de: due_styles: - "F\xC3\xA4llig in ___ Tagen" - "F\xC3\xA4llig am _______" - data: - import_successful: Import war erfolgreich. - import_errors: Beim Import sind Fehler aufgetreten. + stats: + totals_hidden_context_count: und %{count} sind versteckte Kontexte. + actions_avg_created: In den letzten 12 Monaten hast du im Durchschnitt %{count} Aktionen erstellt + actions_min_max_completion_days: "Das Minimum/Maximum an Tagen einer Vervollst\xC3\xA4ndigung ist %{min}/%{max}." + totals_actions_completed: "%{count} davon sind abgeschlossen." + tag_cloud_title: Tag-Cloud aller Aktionen + actions_actions_avg_created_30days: In den letzten 30 Tagen hast du im Durchschnitt %{count} Aktionen erstellt + actions_avg_completed: und %{count} durchschnittlich davon monatlich erledigt + top5_visible_contexts_with_incomplete_actions: "Top 5 der sichtbaren Kontexte mit unvollst\xC3\xA4ndigen Aktionen" + actions: Aktionen + totals_deferred_actions: "von denen %{count} im Notizbuch zur\xC3\xBCckgestellt sind" + time_of_day_legend: + number_of_actions: Anzahl Aufgaben + time_of_day: Tageszeit + totals_incomplete_actions: "Du hast %{count} unvollst\xC3\xA4ndige Aktionen" + running_time_legend: + actions: Aufgaben + percentage: Prozentsatz + weeks: "Vergangene Zeit einer Aktion (Wochen). Klick auf eine Leiste f\xC3\xBCr mehr Informationen." + totals_action_count: hattest du insgesamt %{count} Aktionen + tag_cloud_90days_title: Tag-Cloud-Aktionen in den letzten 90 Tagen + tod30: Tageszeit (letzte 30 Tage) + tags: Tags + projects: Projekte + actions_avg_completion_time: Durchschnittlich hast du %{count} Tage gebraucht, um eine Aktion abzuschliessen. + labels: + month_avg_completed: "%{months} Monat durchschnittlich fertig gestellt" + completed: Erledigt + month_avg_created: "%{months} Monat durchschnittlich erstellt" + avg_created: Durchschnittlich erstellt + avg_completed: Durchschnittlich fertiggestellt + created: Erstellt + actions_selected_from_week: "Aktionen ausgew\xC3\xA4hlt ab Woche" + totals_completed_project_count: und %{count} sind abgeschlossene Projekte. + actions_day_of_week_title: Wochentag (alle Aktionen) + actions_lastyear_title: Aktionen der letzten 12 Monate + open_per_week: "Aktiv (sichtbar und unsichtbar) n\xC3\xA4chsten Aktionen pro Woche" + action_selection_title: TRACKS::Aktionsauswahl + totals_project_count: Du hast %{count} Projekte. + current_running_time_of_incomplete_visible_actions: "Aktuelle Laufzeit unvollst\xC3\xA4ndiger sichtbarer Aufgaben" + legend: + number_of_days: Anzahl vergangene Tage + actions: Aktionen + number_of_actions: Anzahl Aktionen + day_of_week: Wochentag + percentage: Prozentsatz + running_time: Laufzeit einer Aktion (Wochen) + months_ago: Monate zuvor + tod30_legend: + number_of_actions: Anzahl Aufgaben + time_of_day: Tageszeit + totals_context_count: Du hast %{count} Kontexte. + open_per_week_legend: + actions: Aktionen + weeks: Wochen her + actions_last_year_legend: + number_of_actions: Anzahl Aktionen + months_ago: Monate zuvor + top10_projects: Top 10 aller Projekte + top5_contexts: Top 5 aller Kontexte + contexts: Kontexte + totals: Ingesamt + click_to_return: "Klick auf %{link} um zur Statistikseite zur\xC3\xBCckzukehren." + tag_cloud_90days_description: Diese Tag-Cloud beinhaltet Tags der Aktionen, die in den letzten 90 Tagen erstellt oder abgeschlossen wurden. + totals_visible_context_count: Von diesen sind %{count} sichtbare Kontexte + top10_projects_30days: Top-10-Projekt der letzten 30 Tage + running_time_all: "Aktuelle Laufzeit aller unvollst\xC3\xA4ndigen Aktionen." + actions_min_completion_time: "Die minimale Zeit betr\xC3\xA4gt %{time}." + action_completion_time_title: Fertigstellungszeit (alle abgeschlossenen Aktionen) + click_to_show_actions_from_week: Klick auf %{link} um die Aktionen von Woche %{week} und danach anzuzeigen. + top10_longrunning: "Top 10 der am l\xC3\xA4ngsten laufenden Projekte" + no_actions_selected: "Es sind keine Aufgaben ausgew\xC3\xA4hlt." + totals_tag_count: Du hast %{count} Tags in Aktionen. + actions_further: und danach + actions_dow_30days_legend: + number_of_actions: Anzahl der Aktionen + day_of_week: Tag der Woche + totals_first_action: Seit deiner ersten Aktion am %{date} + tag_cloud_description: Diese Tag-Cloud beinhaltet Tags aller Aktionen (abgeschlossen, nicht abgeschlossen, sichtbar und/oder unsichtbar) + click_to_return_link: hier + click_to_update_actions: Klicke auf eine Leiste in der Grafik um die Aktionen unten zu aktualisieren. + spread_of_actions_for_all_context: Aufgabenverteilung aller Kontexte + more_stats_will_appear: "Weitere Statistiken werden verf\xC3\xBCgbar, wenn einige Aufgaben hinzugef\xC3\xBCgt wurden." + actions_avg_completed_30days: und %{count} durchschnittlich davon erledigt. + no_tags_available: "keine Tags verf\xC3\xBCgbar" + actions_30days_title: _Aktionen der letzten 30 Tage + index_title: TRACKS::Statistik + actions_dow_30days_title: Wochentag (letzte 30 Tage) + spread_of_running_actions_for_visible_contexts: Verteilung der laufenden Aufgaben aller sichtbaren Kontexte + actions_day_of_week_legend: + number_of_actions: Anzahl der Aktionen + day_of_week: Tag der Woche + actions_last_year: Aktionen im letzten Jahr + totals_blocked_actions: "%{count} h\xC3\xA4ngen vom Abschluss anderer Aktionen ab." + totals_unique_tags: Von diesen Tags sind %{count} einmalig.. + totals_active_project_count: Von diesen sind %{count} aktive Projekte + running_time_all_legend: + actions: Aktionen + percentage: Prozentsatz + running_time: "Laufzeit einer Aktion (Wochen). Klick auf eine Leiste f\xC3\xBCr mehr Informationen." + other_actions_label: (andere) + time_of_day: Tageszeit (alle Aktionen) + totals_hidden_project_count: "%{count} sind versteckt" todos: - recurring_action_deleted: Die Aktion wurde gelöscht. Da dies eine wiederkehrende Aktion ist, wurde eine neue erstellt. show_from: Anzeigen ab dem error_starring_recurring: Konnte die Hervorhebung der wiederkehrenden Aufgabe \'%{description}\' nicht durchführen + recurring_action_deleted: Die Aktion wurde gelöscht. Da dies eine wiederkehrende Aktion ist, wurde eine neue erstellt. completed_actions: Erledigte Aufgaben - added_new_next_action: Neue Aktion angelegt - completed_recurring: Abgeschlossene wiederkehrende To-Dos - completed_rest_of_previous_month: Fertiggestellt den Rest des Vormonats blocked_by: Blockiert durch %{predecessors} + completed_recurring: Abgeschlossene wiederkehrende To-Dos + added_new_next_action: Neue Aktion angelegt + completed_rest_of_previous_month: Fertiggestellt den Rest des Vormonats + defer_date_after_due_date: "Zur\xC3\xBCckstellungsdatum nach Ablaufdatum. Bitte passe das Ablaufdatum an, dass es vor dem Zur\xC3\xBCckstellungsdatum liegt." star_action: Aktion markieren completed_recurrence_completed: Es gibt keine weitere Aktion nach der soeben gelöschten. Die Wiederholung ist abgeschlossen. - defer_date_after_due_date: "Zur\xC3\xBCckstellungsdatum nach Ablaufdatum. Bitte passe das Ablaufdatum an, dass es vor dem Zur\xC3\xBCckstellungsdatum liegt." unable_to_add_dependency: Abhängigkeit nicht hinzufügbar done: Erledigt? star_action_with_description: Aktion '%{description}' markieren tagged_with: getagged mit ‘%{tag_name}’ completed: Erledigt no_deferred_actions_with: "Keine zur\xC3\xBCckgestellten Aktionen mit dem Tag '%{tag_name}'" - action_due_on: "(Aktion f\xC3\xA4llig am %{date})" no_hidden_actions: Momentan sind keine versteckten Aufgaben vorhanden + action_due_on: "(Aktion f\xC3\xA4llig am %{date})" edit_action_with_description: Aktion '%{description}' bearbeiten - list_incomplete_next_actions: Unerledigte Folge-Aufgaben anzeigen - tags: Tags (Komma-separiert) archived_tasks_title: TRACKS::Archivierte erledigte Aufgaben remove_dependency: Abhängigkeit löschen (löscht nicht die Aufgabe) + list_incomplete_next_actions: Unerledigte Folge-Aufgaben anzeigen + tags: Tags (Komma-separiert) action_deleted_success: Die nächste Aktion erfolgreich gelöscht - context_changed: Kontext zu %{name} gewechselt - new_related_todo_created: "Eine neue To-Do wurde hinzugef\xC3\xBCgt, die zu dieser wiederkehrenden To-Do geh\xC3\xB6rt" - mobile_todos_page_title: Alle Aufgaben add_another_dependency: "F\xC3\xBCgen Sie eine andere Abh\xC3\xA4ngigkeit" + new_related_todo_created: "Eine neue To-Do wurde hinzugef\xC3\xBCgt, die zu dieser wiederkehrenden To-Do geh\xC3\xB6rt" + context_changed: Kontext zu %{name} gewechselt + mobile_todos_page_title: Alle Aufgaben delete_recurring_action_title: "Wiederkehrende Aktion '%{description}' l\xC3\xB6schen" - removed_predecessor: "%{successor} entfernt als Abh\xC3\xA4ngigkeit von %{predecessor}." recurring_actions_title: TRACKS::Wiederkehrende Aktionen + removed_predecessor: "%{successor} entfernt als Abh\xC3\xA4ngigkeit von %{predecessor}." next_action_needed: Es muss mindestens eine folgende Aktion angelegt werden action_saved: Aktion gespeichert scheduled_overdue: "Planm\xC3\xA4\xC3\x9Fig angezeigt vor %{days} Tagen" @@ -276,41 +379,41 @@ de: edit_action: Aktion bearbeiten added_new_context: "Neuer Kontext hinzugef\xC3\xBCgt" next_actions_description: "Filter:" - set_to_pending: "%{task} als ausstehend markiert" + older_completed_items: "Ältere erledigte Aufgaben" list_incomplete_next_actions_with_limit: Zeige die letzten %{count} unerledigten Folge-Aufgaben + set_to_pending: "%{task} als ausstehend markiert" added_new_project: "Neues Projekt hinzugef\xC3\xBCgt" next_actions_title_additions: completed: Aufgaben erledigt due_today: heute fällig due_within_a_week: diese Woche fällig - older_completed_items: "Ältere erledigte Aufgaben" - append_in_this_project: in diesem Projekt - edit_recurring_todo: Bearbeiten Repetieren aktion - error_deleting_item: Beim Löschen von %{description} trat ein Fehler auf task_list_title: TRACKS::Aufgaben anzeigen + edit_recurring_todo: Bearbeiten Repetieren aktion + append_in_this_project: in diesem Projekt + error_deleting_item: Beim Löschen von %{description} trat ein Fehler auf no_actions_due_this_week: Keine zu erledigenden Aufgaben für den Rest der Woche - no_recurring_todos: Im Augenblick gibt es keine wiederkehrenden To-Dos error_completing_todo: Beim Abschliessen/Aktivieren der wiederkehrenden To-Do %{description} ist ein Fehler aufgetreten + no_recurring_todos: Im Augenblick gibt es keine wiederkehrenden To-Dos recurring_pattern_removed: Das Wiederauftreten Muster ist aus entfernt %{count} convert_to_project: In Projekt umwandeln no_deferred_pending_actions: Momentan sind keine aufgeschobenen oder ausstehenden Aufgaben vorhanden. delete_recurring_action_confirm: Soll die wiederkehrende Aktion '%{description}' wirklich gelöscht werden? completed_last_day: In den letzten 24 Stunden erledigt - feed_title_in_context: im Kontext '%{context}' - completed_more_than_x_days_ago: Vor mehr als %{count} Tagen erledigt + all_completed: Alle abgeschlossenen Aktionen show_in_days: Anzeigen in %{days} Tagen no_project: --Kein Projekt-- error_saving_recurring: Es gab einen Fehler beim Speichern der wiederkehrenden todo '%{description}' + completed_more_than_x_days_ago: Vor mehr als %{count} Tagen erledigt + feed_title_in_context: im Kontext '%{context}' new_related_todo_created_short: hat einen neuen todo - all_completed: Alle abgeschlossenen Aktionen - pending: Ausstehend - older_than_days: "Älter als %{count} Tage" - completed_tagged_page_title: "TRACKS:: Erledigte Aufgaben mit Tag %{tag_name}" edit: Bearbeiten + completed_tagged_page_title: "TRACKS:: Erledigte Aufgaben mit Tag %{tag_name}" + older_than_days: "Älter als %{count} Tage" + pending: Ausstehend completed_actions_with: Abgeschlossene Aktionen mit dem Tag %{tag_name} + feed_title_in_project: im Projekt '%{project}' deleted_success: "Die Aktion wurde erfolgreich gel\xC3\xB6scht." completed_tasks_title: TRACKS::Erledigte Aufgaben - feed_title_in_project: im Projekt '%{project}' clear_due_date: Fälligkeitsdatum leeren error_removing_dependency: "Beim Entfernen der Abh\xC3\xA4ngigkeit ist ein Fehler aufgetreten" hidden_actions: Verstecke Aufgaben @@ -320,13 +423,13 @@ de: deferred_actions_with: "Zur\xC3\xBCckgestellte Aktionen mit dem Tag '%{tag_name}'" confirm_delete: "Bist du sicher, dass du die Aktion '%{description}' l\xC3\xB6schen m\xC3\xB6chtest?" recurring_deleted_success: "Die wiederkehrende Aktion wurde erfolgreich gel\xC3\xB6scht." - no_completed_actions_with: Keine abgeschlossenen Aktionen mit dem Tag '%{tag_name}' next_actions_title: TRACKS::Weitere Aufgaben next_action_description: "Beschreibung der n\xC3\xA4chsten Aktion" deferred_tasks_title: TRACKS::Notizbuch + no_completed_actions_with: Keine abgeschlossenen Aktionen mit dem Tag '%{tag_name}' clear_show_from_date: Datum leeren - unresolved_dependency: "Der Wert, den Sie in die Abh\xC3\xA4ngigkeit Feld eingegeben nicht zu einer bestehenden Aktion zu l\xC3\xB6sen. Dieser Wert wird nicht mit dem Rest der Aktion gerettet werden. Weiter gehen?" calendar_page_title: TRACKS::Kalender + unresolved_dependency: "Der Wert, den Sie in die Abh\xC3\xA4ngigkeit Feld eingegeben nicht zu einer bestehenden Aktion zu l\xC3\xB6sen. Dieser Wert wird nicht mit dem Rest der Aktion gerettet werden. Weiter gehen?" in_hidden_state: als versteckt markiert show_today: Heute anzeigen no_actions_found_title: Keine Aktionen gefunden @@ -337,35 +440,37 @@ de: overdue_by_plural: "\xC3\x9Cberf\xC3\xA4llig mit %{days} Tagen" due_tomorrow: "F\xC3\xA4llig morgen" completed_last_x_days: In den letzten %{count} Tagen erledigt + no_actions_with: "Im Augenblick gibt es keine unvollst\xC3\xA4ndigen Aktionen mit dem Tag '%{tag_name}'" defer_x_days: one: "Einen Tag zur\xC3\xBCckstellen" other: "%{count} Tage zur\xC3\xBCckstellen" - no_actions_with: "Im Augenblick gibt es keine unvollst\xC3\xA4ndigen Aktionen mit dem Tag '%{tag_name}'" added_new_next_action_singular: Neue weiterführende Aufgabe angelegt no_completed_actions: Momentan sind keine erledigten Aufgaben vorhanden. + feeds: + completed: "Erledigt: %{date}" + due: "F&auuml;llig: %{date}" deferred_pending_actions: Aufgeschobene/ausstehende Aufgaben has_x_pending: one: Hat eine ausstehende Aktion other: Hat %{count} ausstehende Aktionen - feeds: - completed: "Erledigt: %{date}" - due: "F&auuml;llig: %{date}" - error_deleting_recurring: "Beim L\xC3\xB6schen der wiederkehrenden To-Do %{description} ist ein Fehler aufgetreten" delete_action: "Aktion l\xC3\xB6schen" + error_deleting_recurring: "Beim L\xC3\xB6schen der wiederkehrenden To-Do %{description} ist ein Fehler aufgetreten" recurring_todos: Wiederkehrende To-Dos delete: "L\xC3\xB6schen" - drag_action_title: "Auf andere Aktion ziehen, um sie als Abh\xC3\xA4ngigkeit zu definieren" cannot_add_dependency_to_completed_todo: "Kann nicht hinzugef\xC3\xBCgt werden diese Aktion als eine Abh\xC3\xA4ngigkeit zu einer abgeschlossenen Aktion!" + drag_action_title: "Auf andere Aktion ziehen, um sie als Abh\xC3\xA4ngigkeit zu definieren" no_last_completed_actions: Keine abgeschlossene Aktionen gefunden - depends_on: "H\xC3\xA4ngt ab von" tickler_items_due: one: Ein Notizbuch-Eintrag ist nun fällig - lade die Seite neu, um sie zu sehen. other: "%{count} Notizbuch-Einträge sind nun fällig - lade die Seite neu, um sie zu sehen." + depends_on: "H\xC3\xA4ngt ab von" action_marked_complete: Die Aktion '%{description}' wurde als %{completed} markiert. completed_today: Heute Fertiggestellt added_new_next_action_plural: Neue weiterführende Aufgaben angelegt new_related_todo_not_created_short: nicht schaffen todo completed_rest_of_week: Fertiggestellt den Rest dieser Woche + error_starring: Konnte die Hervorhebung von \'%{description}\' nicht durchführen + show_tomorrow: Morgen anzeigen calendar: get_in_ical_format: Diesen Kalender im iCal Format herunterladen due_next_week: Nächste Woche fällig @@ -377,8 +482,8 @@ de: no_actions_due_after_this_month: Nach diesem Monat sind keine Aufgaben fällig no_actions_due_this_month: Keine Aktionen für den Rest des Monats due_this_month: Im %{month} fällig - show_tomorrow: Morgen anzeigen - error_starring: Konnte die Hervorhebung von \'%{description}\' nicht durchführen + action_deferred: Die Aktion \'% {description}\' wurde vertagt + added_dependency: "%{dependency} als Abhängigkeit hinzugefügt." recurrence: ends_on_number_times: Endet nach %{number} Mal ends_on_date: Endet am %{date} @@ -391,8 +496,8 @@ de: starts_on: Beginnt am daily_options: "Einstellungen f\xC3\xBCr sich t\xC3\xA4glich wiederholenden Aktionen" show_option_always: immer + daily: "T\xC3\xA4glich" pattern: - third: Drittel month_names: - - Januar @@ -409,19 +514,18 @@ de: - Oktober - November - Dezember + third: Drittel every_n: jeden %{n} second: zweite every_xth_day_of_every_n_months: "jedes %{x} %{day} jedes %{n_months} \xE2\x80\x8B" on_day_n: am Tag %{n} - weekly: "w\xC3\xB6chentlich" from: von + weekly: "w\xC3\xB6chentlich" every_day: jeden Tag last: zuletzt the_xth_day_of_month: der %{x} %{day} von %{month} times: "f\xC3\xBCr %{number} Zeiten" - on_work_days: an Wochentagen every_year_on: jedes Jahr in %{date} - first: erste day_names: - Sonntag - Montag @@ -431,41 +535,40 @@ de: - Freitag - Samstag show: Show + first: erste + on_work_days: an Wochentagen fourth: vierte due: "F\xC3\xA4llig" - every_month: jeden Monat until: bis - daily: "T\xC3\xA4glich" - yearly_every_x_day: "Jeden %{day}. %{month} " + every_month: jeden Monat recurrence_on_options: Setze Wiederholung auf + yearly_every_x_day: "Jeden %{day}. %{month} " daily_every_number_day: Alle %{number} Tage - show_options: To-Do anzeigen ends_on: Endet am + show_options: To-Do anzeigen weekly_every_number_week: Kehrt jede %{number}. Woche wieder am - yearly_every_xth_day: Den %{day} %{day_of_week} des %{month} - yearly_options: "Einstellungen f\xC3\xBCr sich j\xC3\xA4hrlich wiederholende Aktionen" show_days_before: "%{days} Tage bevor die To-Do f\xC3\xA4llig ist" + yearly_every_xth_day: Den %{day} %{day_of_week} des %{month} from_tickler: the date todo comes from tickler (no due date set) no_end_date: Kein Enddatum day_x_on_every_x_month: Tag %{day} in jedem %{month}. Monat - yearly: "J\xC3\xA4hrlich" + yearly_options: "Einstellungen f\xC3\xBCr sich j\xC3\xA4hrlich wiederholende Aktionen" monthly_every_xth_day: Der %{day} %{day_of_week} eines jeden %{month}. Monats - action_deferred: Die Aktion \'% {description}\' wurde vertagt + yearly: "J\xC3\xA4hrlich" tagged_page_title: TRACKS::Als '%{tag_name}' markiert no_completed_recurring: Im Augenblick gibt es keine abgeschlossenen wiederkehrenden To-Dos - added_dependency: "%{dependency} als Abhängigkeit hinzugefügt." completed_rest_of_month: Fertiggestellt den Rest des Monats - no_deferred_actions: Zur Zeit sind keine zurückgestellten Aktionen vorhanden. - all_completed_tagged_page_title: "TRACKS:: Alle erledigten Aufgaben mit Tag %{tag_name}" recurrence_completed: Nach dieser wiederkehrenden Aktion, die du gerade abgeschlossen hast, folgt keine mehr. Die Wiederholung endet hiermit - no_actions_found: "Momentan gibt es keine unvollst\xC3\xA4ndigen Aktionen." + all_completed_tagged_page_title: "TRACKS:: Alle erledigten Aufgaben mit Tag %{tag_name}" + no_deferred_actions: Zur Zeit sind keine zurückgestellten Aktionen vorhanden. in_pending_state: und als ausstehend markiert + no_actions_found: "Momentan gibt es keine unvollst\xC3\xA4ndigen Aktionen." error_toggle_complete: "K\xC3\xB6nnte nicht diese Marke todo komplett" due: Fällig action_marked_complete_error: Die Aktion '%{description}' wurde aufgrund eines Fehlers NICHT als %{completed} markiert. - action_saved_to_tickler: Aktion im Notizbuch gespeichert depends_on_separate_with_commas: Hängt ab von (Komma-separiert) recurring_action_saved: Wiederkehrende Aktion gespeichert + action_saved_to_tickler: Aktion im Notizbuch gespeichert completed_in_archive: one: Es befindet sich eine erledigte Aufgabe im Archiv. other: Es befinden sich %{count} erledigte Aufgaben im Archiv. @@ -476,102 +579,10 @@ de: overdue: "Überfällig" add_new_recurring: "F\xC3\xBCge eine neue wiederkehrende Aktion hinzu" no_incomplete_actions: Es gibt keine unerledigten Aufgaben - stats: - tag_cloud_title: Tag-Cloud aller Aktionen - tag_cloud_description: Diese Tag-Cloud beinhaltet Tags aller Aktionen (abgeschlossen, nicht abgeschlossen, sichtbar und/oder unsichtbar) - actions: Aktionen - tag_cloud_90days_title: Tag-Cloud-Aktionen in den letzten 90 Tagen - totals_active_project_count: Von diesen sind %{count} aktive Projekte - actions_last_year_legend: - number_of_actions: Anzahl Aktionen - months_ago: Monate zuvor - totals_first_action: Seit deiner ersten Aktion am %{date} - actions_avg_completion_time: Durchschnittlich hast du %{count} Tage gebraucht, um eine Aktion abzuschliessen. - totals_deferred_actions: "von denen %{count} im Notizbuch zur\xC3\xBCckgestellt sind" - current_running_time_of_incomplete_visible_actions: "Aktuelle Laufzeit unvollst\xC3\xA4ndiger sichtbarer Aufgaben" - top10_longrunning: "Top 10 der am l\xC3\xA4ngsten laufenden Projekte" - totals_action_count: hattest du insgesamt %{count} Aktionen - actions_dow_30days_title: Wochentag (letzte 30 Tage) - legend: - actions: Aktionen - number_of_days: Anzahl vergangene Tage - number_of_actions: Anzahl Aktionen - day_of_week: Wochentag - percentage: Prozentsatz - running_time: Laufzeit einer Aktion (Wochen) - months_ago: Monate zuvor - running_time_legend: - actions: Aufgaben - percentage: Prozentsatz - weeks: "Vergangene Zeit einer Aktion (Wochen). Klick auf eine Leiste f\xC3\xBCr mehr Informationen." - top5_contexts: Top 5 aller Kontexte - actions_lastyear_title: Aktionen der letzten 12 Monate - totals_actions_completed: "%{count} davon sind abgeschlossen." - totals_incomplete_actions: "Du hast %{count} unvollst\xC3\xA4ndige Aktionen" - totals_unique_tags: Von diesen Tags sind %{count} einmalig.. - actions_avg_completed_30days: und %{count} durchschnittlich davon erledigt. - totals_blocked_actions: "%{count} h\xC3\xA4ngen vom Abschluss anderer Aktionen ab." - action_completion_time_title: Fertigstellungszeit (alle abgeschlossenen Aktionen) - projects: Projekte - actions_last_year: Aktionen im letzten Jahr - totals_context_count: Du hast %{count} Kontexte. - totals_visible_context_count: Von diesen sind %{count} sichtbare Kontexte - actions_min_max_completion_days: "Das Minimum/Maximum an Tagen einer Vervollst\xC3\xA4ndigung ist %{min}/%{max}." - actions_min_completion_time: "Die minimale Zeit betr\xC3\xA4gt %{time}." - tags: Tags - no_tags_available: "keine Tags verf\xC3\xBCgbar" - actions_day_of_week_title: Wochentag (alle Aktionen) - totals_project_count: Du hast %{count} Projekte. - totals_hidden_project_count: "%{count} sind versteckt" - tag_cloud_90days_description: Diese Tag-Cloud beinhaltet Tags der Aktionen, die in den letzten 90 Tagen erstellt oder abgeschlossen wurden. - top5_visible_contexts_with_incomplete_actions: "Top 5 der sichtbaren Kontexte mit unvollst\xC3\xA4ndigen Aktionen" - actions_30days_title: _Aktionen der letzten 30 Tage - time_of_day: Tageszeit (alle Aktionen) - more_stats_will_appear: "Weitere Statistiken werden verf\xC3\xBCgbar, wenn einige Aufgaben hinzugef\xC3\xBCgt wurden." - actions_further: und danach - tod30: Tageszeit (letzte 30 Tage) - running_time_all: "Aktuelle Laufzeit aller unvollst\xC3\xA4ndigen Aktionen." - totals_tag_count: Du hast %{count} Tags in Aktionen. - other_actions_label: (andere) - top10_projects_30days: Top-10-Projekt der letzten 30 Tage - spread_of_running_actions_for_visible_contexts: Verteilung der laufenden Aufgaben aller sichtbaren Kontexte - click_to_show_actions_from_week: Klick auf %{link} um die Aktionen von Woche %{week} und danach anzuzeigen. - actions_avg_created: In den letzten 12 Monaten hast du im Durchschnitt %{count} Aktionen erstellt - spread_of_actions_for_all_context: Aufgabenverteilung aller Kontexte - click_to_return: "Klick auf %{link} um zur Statistikseite zur\xC3\xBCckzukehren." - actions_selected_from_week: "Aktionen ausgew\xC3\xA4hlt ab Woche" - totals_completed_project_count: und %{count} sind abgeschlossene Projekte. - top10_projects: Top 10 aller Projekte - totals: Ingesamt - time_of_day_legend: - number_of_actions: Anzahl Aufgaben - time_of_day: Tageszeit - click_to_return_link: hier - totals_hidden_context_count: und %{count} sind versteckte Kontexte. - contexts: Kontexte - actions_avg_completed: und %{count} durchschnittlich davon monatlich erledigt - no_actions_selected: "Es sind keine Aufgaben ausgew\xC3\xA4hlt." - click_to_update_actions: Klicke auf eine Leiste in der Grafik um die Aktionen unten zu aktualisieren. - labels: - month_avg_completed: "%{months} Monat durchschnittlich fertig gestellt" - completed: Erledigt - month_avg_created: "%{months} Monat durchschnittlich erstellt" - avg_created: Durchschnittlich erstellt - avg_completed: Durchschnittlich fertiggestellt - created: Erstellt - running_time_all_legend: - actions: Aktionen - percentage: Prozentsatz - running_time: "Laufzeit einer Aktion (Wochen). Klick auf eine Leiste f\xC3\xBCr mehr Informationen." - tod30_legend: - number_of_actions: Anzahl Aufgaben - time_of_day: Tageszeit - action_selection_title: TRACKS::Aktionsauswahl - actions_actions_avg_created_30days: In den letzten 30 Tagen hast du im Durchschnitt %{count} Aktionen erstellt notes: + delete_note_title: Notiz '%{id}' löschen delete_confirmation: "Bist du sicher, dass du die Notiz '%{id}' l\xC3\xB6schen m\xC3\xB6chtest?" delete_item_title: Eintrag löschen - delete_note_title: Notiz '%{id}' löschen deleted_note: "Notiz '%{id}' l\xC3\xB6schen" note_link_title: Notiz %{id} anzeigen show_note_title: Notiz anzeigen @@ -583,87 +594,87 @@ de: states: hidden_plural: Versteckte review_plural: Datiert - completed: Erledigt stalled: Stalled + completed: Erledigt current: Auf dem neusten Stand - completed_plural: Erledigte review: Datiert - blocked: Verstopft + completed_plural: Erledigte blocked_plural: Verstopft + blocked: Verstopft stalled_plural: Stalled visible_plural: Sichtbare - visible: Sichtbar active_plural: Aktive + visible: Sichtbar current_plural: Auf dem neusten Stand - active: Aktiv hidden: Versteckt + active: Aktiv + errors: + user_unauthorized: "401 Unauthorized: Nur administrative Benutzer d\xC3\xBCrfen auf diese Funktion zugreifen." projects: + no_actions_in_project: "Momentan gibt es keine unvollst\xC3\xA4ndigen Aktionen in diesem Projekt" + deferred_actions: "Aufgeschobene Aufgaben f\xC3\xBCr dieses Projekt" was_marked_hidden: wurde als verborgen markiert edit_project_title: Projekt bearbeiten default_tags_removed_notice: Standard-Tags entfernt default_context_set: Standard-Kontext des Projekts auf %{default_context} gesetzt - no_actions_in_project: "Momentan gibt es keine unvollst\xC3\xA4ndigen Aktionen in diesem Projekt" - deferred_actions: "Aufgeschobene Aufgaben f\xC3\xBCr dieses Projekt" - all_completed_tasks_title: "TRACKS:: Alle auflisten Abgeschlossene Aktionen in Project '%{project_name}'" hide_form: Fomular verstecken page_title: "TRACKS::Projekt: %{project}" - show_form_title: Neues Projekt anlegen - this_project: Dieses Projekt + all_completed_tasks_title: "TRACKS:: Alle auflisten Abgeschlossene Aktionen in Project '%{project_name}'" project_state: Projekt ist %{state} list_completed_projects: "TRACKS:: Liste Abgeschlossene Projekte" to_new_project_page: Zu neuem Projekt weiterleiten no_notes_attached: "Im Augenblick sind keine Notizen mit diesem Projekt verkn\xC3\xBCpft." + show_form_title: Neues Projekt anlegen deferred_actions_empty: "Es gibt keine aufgeschobenen Aufgaben f\xC3\xBCr dieses Projekt" - notes: Notizen + this_project: Dieses Projekt no_last_completed_recurring_todos: Keine abgeschlossene sich wiederholende To-Dos gefunden todos_append: an dieses Projekt no_last_completed_projects: Keine abgeschlossene Projekte gefunden + notes: Notizen hide_form_title: Formular verstecken list_reviews: "TRACKS::R\xC3\xBCckblick" notes_empty: "Es gibt keine Notizen f\xC3\xBCr dieses Projekt" no_projects: Keine Projekte vorhanden - delete_project: Projekt löschen completed_actions_empty: "Es gibt keine erledigten Aufgaben f\xC3\xBCr dieses Projekt" with_no_default_context: hat keinen Standardwert Kontext + delete_project: Projekt löschen show_form: Projekt erstellen actions_in_project_title: Die Aktionen in diesem Projekt delete_project_confirmation: Soll das Projekt '%{name}' wirklich gelöscht werden? with_default_context: mit einem Standard-Rahmen von '%{context_name}' - with_default_tags: und mit '%{tags}' als Standard-Tags - is_active: ist aktiv set_default_tags_notice: Standard-Tags des Projekts auf %{default_tags} setzen completed_projects: Abgeschlossene Projekte add_note: "Notiz hinzuf\xC3\xBCgen" add_project: Projekt hinzufügen - list_projects: TRACKS::Projektliste settings: Einstellungen + with_default_tags: und mit '%{tags}' als Standard-Tags + list_projects: TRACKS::Projektliste + is_active: ist aktiv project_saved_status: Projekt gespeichert - completed_tasks_title: "TRACKS:: Liste Abgeschlossene Aktionen in Project '%{project_name}'" delete_project_title: Projekt löschen hidden_projects: Versteckte Projekte - add_note_submit: "Notiz hinzuf\xC3\xBCgen" - was_marked_complete: wurde als erledigt markiert + completed_tasks_title: "TRACKS:: Liste Abgeschlossene Aktionen in Project '%{project_name}'" default_context_removed: Standard-Kontext entfernt completed_actions: "Erledigte Aufgaben f\xC3\xBCr dieses Projekt" - default_context: Der Standard-Kontext dieses Projektes ist %{context} - active_projects: Aktive Projekte + add_note_submit: "Notiz hinzuf\xC3\xBCgen" + was_marked_complete: wurde als erledigt markiert no_default_context: Dieses Projekt hat keinen Standard-Kontext with_no_default_tags: und hat keinen Standardwert Tags - state: Dieses Projekt ist %{state} edit_project_settings: Edit Project Settings status_project_name_changed: "Projektname ge\xC3\xA4ndert" - errors: - user_unauthorized: "401 Unauthorized: Nur administrative Benutzer d\xC3\xBCrfen auf diese Funktion zugreifen." + state: Dieses Projekt ist %{state} + default_context: Der Standard-Kontext dieses Projektes ist %{context} + active_projects: Aktive Projekte preferences: + change_identity_url: "\xC3\x84ndere deine Identit\xC3\xA4ts-URL" open_id_url: "Deine OpenID-URL lautet:" staleness_starts_after: Abgestandenheit startet nach %{days} Tagen - change_identity_url: "\xC3\x84ndere deine Identit\xC3\xA4ts-URL" - page_title: TRACKS::Einstellungen change_password: "Passwort \xC3\xA4ndern" + page_title: TRACKS::Einstellungen token_description: "Token (f\xC3\xBCr die Verwendung in Feeds und der API)" title: Deine Einstellungen - show_number_completed: "Zeige %{number} erledigte Eintr\xC3\xA4ge" is_false: Nein + show_number_completed: "Zeige %{number} erledigte Eintr\xC3\xA4ge" page_title_edit: "TRACKS::Einstellungen \xC3\xA4ndern" is_true: Ja password_changed: "Ihr Passwort ge\xC3\xA4ndert wurde, melden Sie sich bitte wieder an." @@ -671,14 +682,14 @@ de: generate_new_token: Neues Token generieren sms_context_none: Keine token_header: Dein Token + authentication_header: Deine Authentifizierung updated: Einstellungen aktualisiert current_authentication_type: Dein Authentifizierungsart ist %{auth_type} change_authentication_type: "Authentifzierungsart \xC3\xA4ndern" - authentication_header: Deine Authentifizierung generate_new_token_confirm: "Bist du sicher? Wenn du ein neues Token generierst, wird dies das alte Token ersetzen und jegliche externe Nutzung st\xC3\xB6ren, die das alte Token verwendet." tabs: - authentication: Authentication tracks_behavior: Tracks Verhalten + authentication: Authentication profile: Profil date_and_time: Datum und Uhrzeit time: @@ -707,10 +718,6 @@ de: - Oktober - November - Dezember - order: - - :day - - :month - - :year abbr_day_names: - So - Mo @@ -719,6 +726,10 @@ de: - Do - Fr - Sa + order: + - :day + - :month + - :year formats: only_day: "%e" longer: "%A, %d. %B %Y" @@ -750,13 +761,6 @@ de: - Okt - Nov - Dez - support: - array: - words_connector: ", " - last_word_connector: " und " - two_words_connector: " und " - select: - prompt: "Bitte w\xC3\xA4hlen Sie" will_paginate: previous_label: !binary | wqsgWnVyw7xjaw== @@ -776,23 +780,126 @@ de: next_label: !binary | TsOkY2hzdGUgwrs= - footer: - send_feedback: Senden Sie Feedback zu %{version} + support: + array: + words_connector: ", " + last_word_connector: " und " + two_words_connector: " und " + select: + prompt: "Bitte w\xC3\xA4hlen Sie" shared: multiple_next_actions: Mehrere neue Aufgaben (eine pro Zeile) - hide_form: Formular verstecken make_actions_dependent: "Machen Sie Aktionen voneinander abh\xC3\xA4ngig" + hide_form: Formular verstecken toggle_single: Weitere Aktion erstellen add_actions: "Aufgaben hinzuf\xC3\xBCgen" add_action: "Aufgabe hinzuf\xC3\xBCgen" tags_for_all_actions: "Tags f\xC3\xBCr alle Aufgaben (mit Kommas trennen)" - context_for_all_actions: "Kontext f\xC3\xBCr alle Aufgaben" toggle_multi: "Mehrere neue Aufgabeneintr\xC3\xA4ge hinzuf\xC3\xBCgen" toggle_single_title: Eine weitere Aktion hinzufügen project_for_all_actions: "Projekt f\xC3\xBCr alle Aufgaben" + context_for_all_actions: "Kontext f\xC3\xBCr alle Aufgaben" separate_tags_with_commas: mit Kommas trennen toggle_multi_title: "Zwischen Einzel- und Mehrfachformular f\xC3\xBCr neue Aufgaben umschalten" hide_action_form_title: "Formular f\xC3\xBCr neue Aufgaben verstecken" + footer: + send_feedback: Senden Sie Feedback zu %{version} + feedlist: + actions_due_today: "Heute oder fr\xC3\xBCher f\xC3\xA4llig" + choose_context: "Kontext f\xC3\xBCr den Feed w\xC3\xA4hlen" + rss_feed: RSS-Feed + legend: "Legende:" + ical_feed: iCal-Feed + all_contexts: Alle Kontexte + all_projects: Alle Projekte + choose_project: "Projekt f\xC3\xBCr den Feed w\xC3\xA4hlen" + project_needed: Es muss mindestens ein Projekt existieren, bevor ein Feed abonniert werden kann. + select_feed_for_project: "Feed f\xC3\xBCr dieses Projekt ausw\xC3\xA4hlen" + active_projects_wo_next: Aktive Projekte ohne ausstehende Aufgaben + active_starred_actions: Alle markierten, aktiven Aufgaben + context_needed: Es muss mindestens ein Kontext existieren, bevor ein Feed abonniert werden kann. + select_feed_for_context: "Feed f\xC3\xBCr diesen Kontext ausw\xC3\xA4hlen" + projects_and_actions: Aktive Projekte und deren Aufgaben + actions_due_next_week: "In den n\xC3\xA4chsten 7 Tagen oder fr\xC3\xBCher f\xC3\xA4llige Aufgaben" + notice_incomplete_only: "Hinweis: Alle Feeds zeigen nur Aufgaben, die noch nicht als erledigt markiert wurden." + last_fixed_number: Die letzten %{number} Aufgaben + all_actions: Alle Aufgaben + actions_completed_last_week: In den letzten 7 Tagen abgeschlossene Aufgaben + context_centric_actions: "Feeds f\xC3\xBCr unvollst\xC3\xA4ndige Aufgaben in einem bestimmten Kontext" + plain_text_feed: Plain-Text-Feed + project_centric: "Feeds f\xC3\xBCr unvollst\xC3\xA4ndige Aufgaben in einem bestimmten Kontext" + users: + successfully_deleted_user: Benutzer %{username} erfolgreich gelöscht. + failed_to_delete_user: Löschen des Benutzers %{username} fehlgeschlagen + destroy_successful: "Benutzer %{login} wurde erfolgreich gel\xC3\xB6scht" + total_contexts: Alle Kontexte + openid_url_verified: Die URL %{url} wurde erfolgreich als Identität verifiziert und Deine Authentifizierung auf OpenID umgestellt. + first_user_heading: "Willkommen bei TRACKS. Als erstes legen Sie bitte einen Administrator-Zugang an:" + auth_type_update_error: "Beim Ändern der Authentifizierung trat ein Fehler auf: %{error_messages}" + new_token_generated: Neuer Token erfolgreich generiert + total_projects: Alle Projekte + signup_successful: Benutzer %{username} erfolgreich angelegt. + no_signups_title: TRACKS::Anmeldung nicht erlaubt + user_created: Benutzer angelegt. + change_password_submit: "Passwort \xC3\xA4ndern" + account_signup: Accounteinrichtung + manage_users: Benutzer verwalten + password_updated: Passwort aktualisiert. + auth_type_updated: Authentifizierungs-Art erfolgreich geändert. + total_actions: Alle Aufgaben + desired_login: "Gew\xC3\xBCnschter Benutzername" + signup: Registrieren + confirm_password: "Passwort best\xC3\xA4tigen" + new_user_heading: "Einen neuen Benutzer anlegen:" + change_password_prompt: "Gib dein neues Passwort in die unten stehenden Felder ein und klicke auf 'Passwort \xC3\xA4ndern' um dein altes Passwort durch das neue zu ersetzen." + password_confirmation_label: "Passwort best\xC3\xA4tigen" + destroy_error: "Beim L\xC3\xB6schen des Benutzers %{login} ist ein Fehler aufgetreten." + choose_password: "Passwort w\xC3\xA4hlen" + change_password_title: TRACKS::Passwort ändern + change_auth_type_title: TRACKS::Authentifizierungstyp ändern + new_password_label: Neues Passwort + register_with_cas: Mit deinem CAS-Benutzernamen + label_auth_type: Authentifizierungsart + new_user_title: TRACKS::Als Administrator anmelden + destroy_user: "Benutzer l\xC3\xB6schen" + total_users_count: Derzeit existieren %{count} Benutzer + you_have_to_reset_your_password: "Sie haben Ihr Passwort zur\xC3\xBCcksetzen" + signup_new_user: Neuen Benutzer anlegen + destroy_confirmation: "Achtung: der Benutzer '%{login}' wird mit all seinen Aufgaben, Kontexten, Projekten und Notizen gel\xC3\xB6scht. Bist du sicher, dass du fortfahren m\xC3\xB6chtest?" + identity_url: Identity-URL + openid_ok_pref_failed: Die URL %{url} wurde erfolgreich als Identität verifiziert, beim Speichern der Einstellungen trat jedoch ein Fehler auf. + change_authentication_type: "Authentifizierungsart \xC3\xA4ndern" + auth_change_submit: "Authentifizierungsart \xC3\xA4ndern" + select_authentication_type: "W\xC3\xA4hle deine neue Authentifizierungsart und klicke 'Authentifizierungsart \xC3\xA4ndern' an, um deine aktuellen Einstellungen zu \xC3\xBCberschreiben." + total_notes: Alle Notizen + contexts: + delete_context_title: Kontext löschen + hide_form: Formular verstecken + all_completed_tasks_title: "TRACKS:: Alle Abgeschlossene Ma\xC3\x9Fnahmen im context '%{context_name}'" + show_form_title: Neuen Kontext erstellen + delete_context_confirmation: Soll der Kontext '%{name}' wirklich gelöscht werden? Alle (wiederholenden) Aufgaben dieses Kontexts werden hierdurch ebenfalls gelöscht. + todos_append: In diesem Context + delete_context: Kontext löschen + edit_context: Kontext bearbeiten + hide_form_title: Formular für neuen Kontext verstecken + context_hide: Auf Startseite ausblenden? + hidden_contexts: Versteckte Kontexte + no_contexts_active: Derzeit gibt es keine aktiven Kontexte + show_form: Neuen Kontext erstellen + visible_contexts: Sichtbare Kontexte + save_status_message: Kontext gespeichert + add_context: "Kontext hinzuf\xC3\xBCgen" + update_status_message: "Kontextname wurde ge\xC3\xA4ndert" + context_name: Kontextname + status_active: Kontext ist aktiv + completed_tasks_title: "TRACKS:: Abgeschlossene Ma\xC3\x9Fnahmen im context '%{context_name}'" + new_context_post: "' wird ebenfalls angelegt. Fortfahren?" + no_actions: "Momentan gibt es keine unvollst\xC3\xA4ndigen Aufgaben in diesem Kontext" + last_completed_in_context: in diesem Kontext (letzte %{number}) + context_deleted: "Gel\xC3\xB6schter Kontext '%{name}'" + no_contexts_hidden: Derzeit gibt es keine versteckten Kontexte + new_context_pre: Der neue Kontext ' + status_hidden: Kontext ist versteckt sidebar: list_name_active_contexts: Aktive Kontexte list_name_active_projects: Aktive Projekte @@ -800,101 +907,31 @@ de: list_name_completed_projects: Abgeschlossene Projekte list_name_hidden_projects: Versteckte Projekte list_name_hidden_contexts: Versteckte Kontexte - users: - successfully_deleted_user: Benutzer %{username} erfolgreich gelöscht. - destroy_successful: "Benutzer %{login} wurde erfolgreich gel\xC3\xB6scht" - total_contexts: Alle Kontexte - openid_url_verified: Die URL %{url} wurde erfolgreich als Identität verifiziert und Deine Authentifizierung auf OpenID umgestellt. - first_user_heading: "Willkommen bei TRACKS. Als erstes legen Sie bitte einen Administrator-Zugang an:" - auth_type_update_error: "Beim Ändern der Authentifizierung trat ein Fehler auf: %{error_messages}" - failed_to_delete_user: Löschen des Benutzers %{username} fehlgeschlagen - new_token_generated: Neuer Token erfolgreich generiert - total_projects: Alle Projekte - signup_successful: Benutzer %{username} erfolgreich angelegt. - change_password_submit: "Passwort \xC3\xA4ndern" - no_signups_title: TRACKS::Anmeldung nicht erlaubt - user_created: Benutzer angelegt. - manage_users: Benutzer verwalten - account_signup: Accounteinrichtung - password_updated: Passwort aktualisiert. - confirm_password: "Passwort best\xC3\xA4tigen" - new_user_heading: "Einen neuen Benutzer anlegen:" - signup: Registrieren - auth_type_updated: Authentifizierungs-Art erfolgreich geändert. - total_actions: Alle Aufgaben - desired_login: "Gew\xC3\xBCnschter Benutzername" - choose_password: "Passwort w\xC3\xA4hlen" - change_password_title: TRACKS::Passwort ändern - change_auth_type_title: TRACKS::Authentifizierungstyp ändern - change_password_prompt: "Gib dein neues Passwort in die unten stehenden Felder ein und klicke auf 'Passwort \xC3\xA4ndern' um dein altes Passwort durch das neue zu ersetzen." - password_confirmation_label: "Passwort best\xC3\xA4tigen" - destroy_error: "Beim L\xC3\xB6schen des Benutzers %{login} ist ein Fehler aufgetreten." - new_password_label: Neues Passwort - register_with_cas: Mit deinem CAS-Benutzernamen - label_auth_type: Authentifizierungsart - new_user_title: TRACKS::Als Administrator anmelden - destroy_user: "Benutzer l\xC3\xB6schen" - total_users_count: Derzeit existieren %{count} Benutzer - destroy_confirmation: "Achtung: der Benutzer '%{login}' wird mit all seinen Aufgaben, Kontexten, Projekten und Notizen gel\xC3\xB6scht. Bist du sicher, dass du fortfahren m\xC3\xB6chtest?" - you_have_to_reset_your_password: "Sie haben Ihr Passwort zur\xC3\xBCcksetzen" - signup_new_user: Neuen Benutzer anlegen - openid_ok_pref_failed: Die URL %{url} wurde erfolgreich als Identität verifiziert, beim Speichern der Einstellungen trat jedoch ein Fehler auf. - change_authentication_type: "Authentifizierungsart \xC3\xA4ndern" - auth_change_submit: "Authentifizierungsart \xC3\xA4ndern" - identity_url: Identity-URL - select_authentication_type: "W\xC3\xA4hle deine neue Authentifizierungsart und klicke 'Authentifizierungsart \xC3\xA4ndern' an, um deine aktuellen Einstellungen zu \xC3\xBCberschreiben." - total_notes: Alle Notizen - contexts: - delete_context_title: Kontext löschen - all_completed_tasks_title: "TRACKS:: Alle Abgeschlossene Ma\xC3\x9Fnahmen im context '%{context_name}'" - hide_form: Formular verstecken - show_form_title: Neuen Kontext erstellen - delete_context_confirmation: Soll der Kontext '%{name}' wirklich gelöscht werden? Alle (wiederholenden) Aufgaben dieses Kontexts werden hierdurch ebenfalls gelöscht. - delete_context: Kontext löschen - hide_form_title: Formular für neuen Kontext verstecken - edit_context: Kontext bearbeiten - hidden_contexts: Versteckte Kontexte - no_contexts_active: Derzeit gibt es keine aktiven Kontexte - context_hide: Auf Startseite ausblenden? - show_form: Neuen Kontext erstellen - visible_contexts: Sichtbare Kontexte - save_status_message: Kontext gespeichert - add_context: "Kontext hinzuf\xC3\xBCgen" - update_status_message: "Kontextname wurde ge\xC3\xA4ndert" - context_name: Kontextname - completed_tasks_title: "TRACKS:: Abgeschlossene Ma\xC3\x9Fnahmen im context '%{context_name}'" - status_active: Kontext ist aktiv - new_context_post: "' wird ebenfalls angelegt. Fortfahren?" - context_deleted: "Gel\xC3\xB6schter Kontext '%{name}'" - no_contexts_hidden: Derzeit gibt es keine versteckten Kontexte - new_context_pre: Der neue Kontext ' - no_actions: "Momentan gibt es keine unvollst\xC3\xA4ndigen Aufgaben in diesem Kontext" - last_completed_in_context: in diesem Kontext (letzte %{number}) - status_hidden: Kontext ist versteckt - feedlist: - actions_due_today: "Heute oder fr\xC3\xBCher f\xC3\xA4llig" - choose_context: "Kontext f\xC3\xBCr den Feed w\xC3\xA4hlen" - all_contexts: Alle Kontexte - rss_feed: RSS-Feed - ical_feed: iCal-Feed - legend: "Legende:" - all_projects: Alle Projekte - choose_project: "Projekt f\xC3\xBCr den Feed w\xC3\xA4hlen" - active_projects_wo_next: Aktive Projekte ohne ausstehende Aufgaben - project_needed: Es muss mindestens ein Projekt existieren, bevor ein Feed abonniert werden kann. - select_feed_for_project: "Feed f\xC3\xBCr dieses Projekt ausw\xC3\xA4hlen" - active_starred_actions: Alle markierten, aktiven Aufgaben - context_needed: Es muss mindestens ein Kontext existieren, bevor ein Feed abonniert werden kann. - select_feed_for_context: "Feed f\xC3\xBCr diesen Kontext ausw\xC3\xA4hlen" - projects_and_actions: Aktive Projekte und deren Aufgaben - notice_incomplete_only: "Hinweis: Alle Feeds zeigen nur Aufgaben, die noch nicht als erledigt markiert wurden." - actions_due_next_week: "In den n\xC3\xA4chsten 7 Tagen oder fr\xC3\xBCher f\xC3\xA4llige Aufgaben" - plain_text_feed: Plain-Text-Feed - last_fixed_number: Die letzten %{number} Aufgaben - all_actions: Alle Aufgaben - actions_completed_last_week: In den letzten 7 Tagen abgeschlossene Aufgaben - context_centric_actions: "Feeds f\xC3\xBCr unvollst\xC3\xA4ndige Aufgaben in einem bestimmten Kontext" - project_centric: "Feeds f\xC3\xBCr unvollst\xC3\xA4ndige Aufgaben in einem bestimmten Kontext" + login: + sign_in: Anmeldung + openid_identity_url_not_found: "Sorry, aber es existiert kein Benutzer mit der Identit\xC3\xA4ts-URL (%{identity_url})" + user_no_expiry: Angemeldet bleiben + login_cas: zum CAS gehen + cas_logged_in_greeting: Hallo, %{username}! Du bist authentifiziert. + cas_no_user_found: Hallo, %{username}! Du hast leider keinen Tracks-Account. + cas_login: CAS-Anmeldung + successful_with_session_info: "Anmeldung erfolgreich:" + please_login: Bitte melde dich an, um Tracks zu nutzen + cas_username_not_found: Sorry, aber es existiert kein Benutzer mit dem CAS-Benutzernamen (%{username}) + cas_create_account: "Wenn du die Anfrage fortsetzen m\xC3\xB6chtest, klicke bitte hier: %{signup_link}" + mobile_use_openid: "\xE2\x80\xA6oder mit einer OpenID anmelden" + cas_signup_link: Account beantragen + account_login: Account-Anmeldung + successful: "Anmeldung erfolgreich. Willkommen zur\xC3\xBCck!" + session_will_not_expire: Sitzung wird nicht ablaufen. + session_will_expire: "Sitzung wird nach %{hours} Stunde(n) der Inaktivit\xC3\xA4t ablaufen." + option_separator: oder, + session_time_out: Sitzung abgelaufen. Bitte %{link} + login_standard: "zur\xC3\xBCck zum Standard-Login" + log_in_again: Erneut anmelden. + logged_out: Sie wurden von Tracks abgemeldet. + login_with_openid: Mit einer OpenID anmelden + unsuccessful: Anmeldung war nicht erfolgreich. datetime: prompts: minute: Minuten @@ -917,6 +954,9 @@ de: x_seconds: one: 1 Sekunde other: "%{count} Sekunden" + about_x_hours: + one: etwa 1 Stunde + other: etwa %{count} Stunden less_than_x_seconds: one: weniger als 1 Sekunde other: weniger als %{count} Sekunden @@ -927,48 +967,20 @@ de: x_minutes: one: 1 Minute other: "%{count} Minuten" - about_x_hours: - one: etwa 1 Stunde - other: etwa %{count} Stunden - about_x_months: - one: etwa 1 Monat - other: etwa %{count} Monate about_x_years: one: etwa 1 Jahr other: etwa %{count} Jahre + about_x_months: + one: etwa 1 Monat + other: etwa %{count} Monate over_x_years: one: mehr als 1 Jahr other: mehr als %{count} Jahre half_a_minute: eine halbe Minute - login: - sign_in: Anmeldung - openid_identity_url_not_found: "Sorry, aber es existiert kein Benutzer mit der Identit\xC3\xA4ts-URL (%{identity_url})" - login_cas: zum CAS gehen - user_no_expiry: Angemeldet bleiben - cas_login: CAS-Anmeldung - successful_with_session_info: "Anmeldung erfolgreich:" - please_login: Bitte melde dich an, um Tracks zu nutzen - cas_logged_in_greeting: Hallo, %{username}! Du bist authentifiziert. - cas_no_user_found: Hallo, %{username}! Du hast leider keinen Tracks-Account. - cas_username_not_found: Sorry, aber es existiert kein Benutzer mit dem CAS-Benutzernamen (%{username}) - mobile_use_openid: "\xE2\x80\xA6oder mit einer OpenID anmelden" - cas_create_account: "Wenn du die Anfrage fortsetzen m\xC3\xB6chtest, klicke bitte hier: %{signup_link}" - cas_signup_link: Account beantragen - account_login: Account-Anmeldung - successful: "Anmeldung erfolgreich. Willkommen zur\xC3\xBCck!" - session_will_not_expire: Sitzung wird nicht ablaufen. - session_time_out: Sitzung abgelaufen. Bitte %{link} - session_will_expire: "Sitzung wird nach %{hours} Stunde(n) der Inaktivit\xC3\xA4t ablaufen." - option_separator: oder, - login_standard: "zur\xC3\xBCck zum Standard-Login" - unsuccessful: Anmeldung war nicht erfolgreich. - log_in_again: Erneut anmelden. - logged_out: Sie wurden von Tracks abgemeldet. - login_with_openid: Mit einer OpenID anmelden search: contexts_matching_query: Kontexte entsprechen der Suche tags_matching_query: Tags entsprechen der Suche - notes_matching_query: Notizen entsprechen der Suche no_results: Die Suche ergab kein Ergebnis. todos_matching_query: Todos entsprechen der Suche projects_matching_query: Projekte entsprechen der Suche + notes_matching_query: Notizen entsprechen der Suche diff --git a/config/locales/es.yml b/config/locales/es.yml index 61933464..336ec97b 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1,61 +1,5 @@ --- es: - common: - back: !binary | - QXRyw6Fz - - third: Tercero - actions: Tareas - recurring_todos: "Repetici\xC3\xB3n de acciones" - add: "A\xC3\xB1adir" - go_back: "Volver atr\xC3\xA1s" - logout: Salir - previous: Anterior - none: Ninguno - second: Segundo - week: semana - cancel: Cancelar - month: mes - optional: opcional - forum: Foro - notes: Notas - server_error: Ha ocurrido un error en el servidor. - last: "\xC3\x9Altimo" - action: Tarea - projects: Proyectos - review: "Revisi\xC3\xB3n" - project: Proyecto - ok: Ok - contribute: Contribuir - first: Primero - website: Website - numbered_step: Paso %{number} - errors_with_fields: "Ha habido problemas con los siguientes campos:" - create: Crear - sort: - by_task_count_title: "Ordenar por n\xC3\xBAmero de tareas" - by_task_count_title_confirm: "\xC2\xBFEst\xC3\xA1 seguro que desea ordenar los proyectos por el n\xC3\xBAmero de tareas? Esto reemplazar\xC3\xA1 el orden existente." - alphabetically: "Alfab\xC3\xA9ticamente" - alphabetically_confirm: "\xC2\xBFEst\xC3\xA1 seguro que desea ordenar los proyectos por orden alfab\xC3\xA9tico? Esto reemplazar\xC3\xA1 el orden existente." - sort: Ordenar - alphabetically_title: "Proyectos de ordenar alfab\xC3\xA9ticamente" - by_task_count: "Por n\xC3\xBAmero de tareas" - drag_handle: ARRASTRAR - description: "Descripci\xC3\xB3n" - context: Contexto - todo: Todo - months: meses - next: "Pr\xC3\xB3ximo" - fourth: Cuarto - contexts: Contextos - update: Actualizar - weeks: semanas - forth: Siguiente - wiki: Wiki - bugs: Errores - email: Email - ajaxError: Hubo un error al recuperar desde el servidor - search: Buscar number: format: separator: . @@ -79,6 +23,62 @@ es: separator: . delimiter: "," + common: + back: !binary | + QXRyw6Fz + + recurring_todos: "Repetici\xC3\xB3n de acciones" + actions: Tareas + third: Tercero + add: "A\xC3\xB1adir" + previous: Anterior + go_back: "Volver atr\xC3\xA1s" + logout: Salir + second: Segundo + optional: opcional + week: semana + none: Ninguno + cancel: Cancelar + month: mes + forum: Foro + server_error: Ha ocurrido un error en el servidor. + notes: Notas + last: "\xC3\x9Altimo" + review: "Revisi\xC3\xB3n" + projects: Proyectos + action: Tarea + project: Proyecto + ok: Ok + contribute: Contribuir + first: Primero + website: Website + numbered_step: Paso %{number} + errors_with_fields: "Ha habido problemas con los siguientes campos:" + sort: + by_task_count_title: "Ordenar por n\xC3\xBAmero de tareas" + by_task_count_title_confirm: "\xC2\xBFEst\xC3\xA1 seguro que desea ordenar los proyectos por el n\xC3\xBAmero de tareas? Esto reemplazar\xC3\xA1 el orden existente." + alphabetically: "Alfab\xC3\xA9ticamente" + sort: Ordenar + alphabetically_confirm: "\xC2\xBFEst\xC3\xA1 seguro que desea ordenar los proyectos por orden alfab\xC3\xA9tico? Esto reemplazar\xC3\xA1 el orden existente." + alphabetically_title: "Proyectos de ordenar alfab\xC3\xA9ticamente" + by_task_count: "Por n\xC3\xBAmero de tareas" + create: Crear + months: meses + drag_handle: ARRASTRAR + description: "Descripci\xC3\xB3n" + fourth: Cuarto + next: "Pr\xC3\xB3ximo" + contexts: Contextos + todo: Todo + context: Contexto + update: Actualizar + weeks: semanas + forth: Siguiente + wiki: Wiki + bugs: Errores + email: Email + ajaxError: Hubo un error al recuperar desde el servidor + search: Buscar layouts: toggle_contexts_title: "Haga contextos se derrumb\xC3\xB3 (in)visible" toggle_contexts: "Cambiar los contextos se derrumb\xC3\xB3" @@ -86,9 +86,9 @@ es: next_actions_rss_feed: RSS feed of next actions toggle_notes_title: Activar/Desactivar todas las notas mobile_navigation: + new_action: Nueva tarea logout: "Cerrar sesi\xC3\xB3n" feeds: Feeds - new_action: Nueva tarea starred: avoritos projects: Proyectos tickler: Tickler @@ -96,8 +96,8 @@ es: home: Inicio navigation: api_docs: REST API Docs - recurring_todos: Tareas repetitivas manage_users_title: "A\xC3\xB1adir o eliminar usuarios" + recurring_todos: Tareas repetitivas feeds: Feeds stats: "Estad\xC3\xADsticas" starred: Estrellas @@ -105,31 +105,31 @@ es: manage_users: Administrar usuarios tickler_title: Tickler integrations_: Integrar Tracks - preferences: Preferencias export_title: Import and export data - calendar_title: Calendario de las acciones por + preferences: Preferencias feeds_title: See a list of available feeds - stats_title: See your statistics - tickler: Tickler + calendar_title: Calendario de las acciones por home_title: Inicio + tickler: Tickler starred_title: See your starred actions recurring_todos_title: Manage recurring actions completed_tasks: Hecho - organize: Organizar + stats_title: See your statistics view: Ver + organize: Organizar completed_tasks_title: Completed home: Inicio contexts_title: Contexts export: Export + preferences_title: Mostrar mis preferencias + review_title: "Posibilidad de una revisi\xC3\xB3n" search: Search All Items projects_title: Proyectos - preferences_title: Mostrar mis preferencias calendar: Calendario - review_title: "Posibilidad de una revisi\xC3\xB3n" integrations: opensearch_description: Buscar en las Tracks - applescript_next_action_prompt: "Descripci\xC3\xB3n de la pr\xC3\xB3xima tarea:" gmail_description: "Gadget para a\xC3\xB1adir pistas a Gmail como un gadget" + applescript_next_action_prompt: "Descripci\xC3\xB3n de la pr\xC3\xB3xima tarea:" applescript_success_after_id: creado applescript_success_before_id: "Nueva acci\xC3\xB3n junto con la identificaci\xC3\xB3n" activerecord: @@ -140,8 +140,8 @@ es: default_context_name: Default contexto description: "Descripci\xC3\xB3n" todo: - predecessors: Depende de la show_from: Mostrar + predecessors: Depende de la notes: Notas project: Proyecto description: "Descripci\xC3\xB3n" @@ -158,19 +158,19 @@ es: staleness_starts: Comienzo de estancamiento verbose_action_descriptors: "Descriptores detallado de acci\xC3\xB3n" sms_context: Contexto por defecto para el email - show_number_completed: "Mostrar n\xC3\xBAmero de tareas completadas" title_date_format: "T\xC3\xADtulo del formato de fecha" + show_number_completed: "Mostrar n\xC3\xBAmero de tareas completadas" refresh: "Intervalo de actualizaci\xC3\xB3n (en minutos)" week_starts: La semana comienza last_name: Apellido - time_zone: Zona horaria - due_style: Debido al estilo locale: Lugar + due_style: Debido al estilo + time_zone: Zona horaria sms_email: Email origen show_project_on_todo_done: "Ir a la p\xC3\xA1gina del proyecto al completar la tarea" - first_name: Nombre show_completed_projects_in_sidebar: Show completed projects in sidebar review_period: "Intervalo de revisi\xC3\xB3n del proyecto" + first_name: Nombre errors: models: project: @@ -182,31 +182,34 @@ es: messages: record_invalid: "La validaci\xC3\xB3n ha fallado: %{errores}" greater_than_or_equal_to: debe ser mayor que o igual a %{count} - less_than_or_equal_to: debe ser menor o igual a %{count} confirmation: "no coincide con la confirmaci\xC3\xB3n" + less_than_or_equal_to: debe ser menor o igual a %{count} blank: no puede estar en blanco exclusion: "est\xC3\xA1 reservado" invalid: "no puede contener el car\xC3\xA1cter de coma (',')" odd: tiene que ser impar - too_short: "es demasiado corto (m\xC3\xADnimo %{count} caracteres)" - wrong_length: es la longitud del mal (debe ser %{count} caracteres) even: "debe ser a\xC3\xBAn" empty: "no puede estar vac\xC3\xADo" + too_short: "es demasiado corto (m\xC3\xADnimo %{count} caracteres)" + wrong_length: es la longitud del mal (debe ser %{count} caracteres) less_than: debe ser menor que %{count} - equal_to: debe ser igual a %{count} greater_than: debe ser mayor que %{count} + equal_to: debe ser igual a %{count} + accepted: debe ser aceptada too_long: "es demasiado largo (el m\xC3\xA1ximo es %{count} caracteres)" taken: Ya se ha dado - accepted: debe ser aceptada - not_a_number: "no es un n\xC3\xBAmero" inclusion: "no est\xC3\xA1 incluido en la lista" - full_messages: - format: "%{attribute} %{message}" + not_a_number: "no es un n\xC3\xBAmero" template: body: "Hubo problemas con los campos siguientes:" header: one: Un error esta prohibido %{model} se guarden other: "%{count} errores proh\xC3\xADbe este %{model} que se guarden" + full_messages: + format: "%{attribute} %{message}" + data: + import_successful: "Importaci\xC3\xB3n se realiz\xC3\xB3 correctamente." + import_errors: "Han ocurrido algunos errores durante la importaci\xC3\xB3n" models: project: feed_title: Tracks Projects @@ -222,42 +225,142 @@ es: due_styles: - Due in ___ days - Due on _______ - data: - import_successful: "Importaci\xC3\xB3n se realiz\xC3\xB3 correctamente." - import_errors: "Han ocurrido algunos errores durante la importaci\xC3\xB3n" + stats: + totals_hidden_context_count: and %{count} are hidden contexts. + actions_avg_created: In the last 12 months you created on average %{count} actions + actions_min_max_completion_days: The Max-/minimum days to complete is %{min}/%{max}. + totals_actions_completed: "%{count} of these are completed." + tag_cloud_title: Tag cloud for all actions + actions_actions_avg_created_30days: In the last 30 days you created on average %{count} actions + actions_avg_completed: and completed an average of %{count} actions per month. + top5_visible_contexts_with_incomplete_actions: Top 5 visible contexts with incomplete actions + actions: Actions + totals_deferred_actions: of which %{count} are deferred actions in the tickler + time_of_day_legend: + number_of_actions: "N\xC3\xBAmero de tareas" + time_of_day: Time of day + totals_incomplete_actions: You have %{count} incomplete actions + running_time_legend: + actions: Tareas + percentage: Percentage + weeks: Running time of an action (weeks). Click on a bar for more info + totals_action_count: you have a total of %{count} actions + tag_cloud_90days_title: Tag cloud actions in past 90 days + tod30: Time of day (last 30 days) + tags: Tags + projects: Projects + actions_avg_completion_time: Of all your completed actions, the average time to complete is %{count} days. + labels: + month_avg_completed: "%{months} Month avg completed" + completed: Completed + month_avg_created: "%{months} Month avg created" + avg_created: Avg created + avg_completed: Avg completed + created: Created + actions_selected_from_week: "Actions selected from week " + totals_completed_project_count: and %{count} are completed projects. + actions_day_of_week_title: Day of week (all actions) + actions_lastyear_title: Actions in the last 12 months + open_per_week: "Pr\xC3\xB3ximas acciones activas (visibles y ocultas) a la semana" + action_selection_title: TRACKS::Action selection + totals_project_count: You have %{count} projects. + current_running_time_of_incomplete_visible_actions: Current running time of incomplete visible actions + legend: + number_of_days: Number of days ago + actions: Tareas + number_of_actions: "N\xC3\xBAmero de tareas" + day_of_week: Day of week + percentage: Percentage + running_time: Running time of an action (weeks) + months_ago: Months ago + tod30_legend: + number_of_actions: "N\xC3\xBAmero de tareas" + time_of_day: Time of day + totals_context_count: You have %{count} contexts. + open_per_week_legend: + actions: Acciones + weeks: "Semanas atr\xC3\xA1s" + actions_last_year_legend: + number_of_actions: Number of actions + months_ago: Months ago + top10_projects: Top 10 projects + top5_contexts: Top 5 contexts + contexts: Contexts + totals: Totals + click_to_return: Click %{link} to return to the statistics page. + tag_cloud_90days_description: This tag cloud includes tags of actions that were created or completed in the past 90 days. + totals_visible_context_count: Of those %{count} are visible contexts + top10_projects_30days: Top 10 project in past 30 days + running_time_all: Current running time of all incomplete actions + actions_min_completion_time: The minimum time to complete is %{time}. + action_completion_time_title: Completion time (all completed actions) + click_to_show_actions_from_week: Click %{link} to show the actions from week %{week} and further. + top10_longrunning: Top 10 longest running projects + no_actions_selected: No hay tareas seleccionadas. + totals_tag_count: You have %{count} tags placed on actions. + actions_further: " and further" + actions_dow_30days_legend: + number_of_actions: "N\xC3\xBAmero de acciones" + day_of_week: "D\xC3\xADa de la semana" + totals_first_action: Since your first action on %{date} + tag_cloud_description: This tag cloud includes tags of all actions (completed, not completed, visible and/or hidden) + click_to_return_link: here + click_to_update_actions: Click on a bar in the chart to update the actions below. + spread_of_actions_for_all_context: Spread of actions for all context + more_stats_will_appear: More statistics will appear here once you have added some actions. + actions_avg_completed_30days: and completed an average of %{count} actions per day. + no_tags_available: no tags available + actions_30days_title: Actions in the last 30 days + index_title: "TRACKS::Estad\xC3\xADstica" + actions_dow_30days_title: Day of week (past 30 days) + spread_of_running_actions_for_visible_contexts: Spread of running actions for visible contexts + actions_day_of_week_legend: + number_of_actions: "N\xC3\xBAmero de acciones" + day_of_week: "D\xC3\xADa de la semana" + actions_last_year: Actions in the last years + totals_blocked_actions: "%{count} are dependent on the completion of their actions." + totals_unique_tags: Of those tags, %{count} are unique. + totals_active_project_count: Of those %{count} are active projects + running_time_all_legend: + actions: Tareas + percentage: Percentage + running_time: Running time of an action (weeks). Click on a bar for more info + other_actions_label: (otros) + time_of_day: Time of day (all actions) + totals_hidden_project_count: "%{count} are hidden" todos: - recurring_action_deleted: Action was deleted. Because this action is recurring, a new action was added show_from: Show from error_starring_recurring: Could not toggle the star of recurring todo \'%{description}\' + recurring_action_deleted: Action was deleted. Because this action is recurring, a new action was added completed_actions: Completed actions - added_new_next_action: Added new next action - completed_recurring: Completed recurring todos - completed_rest_of_previous_month: Completado en el resto del mes anterior blocked_by: Blocked by %{predecessors} + completed_recurring: Completed recurring todos + added_new_next_action: Added new next action + completed_rest_of_previous_month: Completado en el resto del mes anterior + defer_date_after_due_date: Defer date is after due date. Please edit and adjust due date before deferring. star_action: Star this action completed_recurrence_completed: There is no next action after the recurring action you just deleted. The recurrence is completed - defer_date_after_due_date: Defer date is after due date. Please edit and adjust due date before deferring. unable_to_add_dependency: Unable to add dependency done: Done? star_action_with_description: star the action '%{description}' tagged_with: tagged with ‘%{tag_name}’ completed: Completed no_deferred_actions_with: No deferred actions with the tag '%{tag_name}' - action_due_on: (action due on %{date}) no_hidden_actions: Currently there are no hidden actions found + action_due_on: (action due on %{date}) edit_action_with_description: Edit the action '%{description}' - list_incomplete_next_actions: Lista las siguientes tareas incompletas - tags: Tags (separate with commas) archived_tasks_title: TRACKS::Archived completed tasks remove_dependency: Remove dependency (does not delete the action) + list_incomplete_next_actions: Lista las siguientes tareas incompletas + tags: Tags (separate with commas) action_deleted_success: Successfully deleted next action - context_changed: Context changed to %{name} - new_related_todo_created: "Una nueva tarea fue a\xC3\xB1adida y que pertenece a esta tarea recurrente" - mobile_todos_page_title: Todas las tareas add_another_dependency: Add another dependency + new_related_todo_created: "Una nueva tarea fue a\xC3\xB1adida y que pertenece a esta tarea recurrente" + context_changed: Context changed to %{name} + mobile_todos_page_title: Todas las tareas delete_recurring_action_title: Delete the recurring action - removed_predecessor: Removed %{successor} as dependency from %{predecessor}. recurring_actions_title: TRACKS::Recurring Actions + removed_predecessor: Removed %{successor} as dependency from %{predecessor}. next_action_needed: You need to submit at least one next action action_saved: Action saved scheduled_overdue: Scheduled to show %{days} days ago @@ -265,41 +368,41 @@ es: edit_action: Edit action added_new_context: Added new context next_actions_description: "Filter:" - set_to_pending: "%{task} set to pending" + older_completed_items: Older completed items list_incomplete_next_actions_with_limit: Lists the last %{count} incomplete next actions + set_to_pending: "%{task} set to pending" added_new_project: Added new project next_actions_title_additions: completed: actions completed due_today: due today due_within_a_week: due within a week - older_completed_items: Older completed items - append_in_this_project: in this project - edit_recurring_todo: "Editar la acci\xC3\xB3n de repetici\xC3\xB3n" - error_deleting_item: There was an error deleting the item %{description} task_list_title: TRACKS::List tasks + edit_recurring_todo: "Editar la acci\xC3\xB3n de repetici\xC3\xB3n" + append_in_this_project: in this project + error_deleting_item: There was an error deleting the item %{description} no_actions_due_this_week: No actions due in rest of this week - no_recurring_todos: Currently there are no recurring todos error_completing_todo: There was an error completing / activating the recurring todo %{description} + no_recurring_todos: Currently there are no recurring todos recurring_pattern_removed: "El patr\xC3\xB3n de repetici\xC3\xB3n se retira de %{count}" convert_to_project: Make project no_deferred_pending_actions: Currently there are no deferred or pending actions delete_recurring_action_confirm: Are you sure that you want to delete the recurring action '%{description}'? completed_last_day: Completed in the last 24 hours - feed_title_in_context: in context '%{context}' - completed_more_than_x_days_ago: Completed more than %{count} days ago + all_completed: Todas las acciones realizadas show_in_days: Show in %{days} days no_project: --No project-- error_saving_recurring: There was an error saving the recurring todo \'%{description}\' + completed_more_than_x_days_ago: Completed more than %{count} days ago + feed_title_in_context: in context '%{context}' new_related_todo_created_short: creada una nueva tarea - all_completed: Todas las acciones realizadas - pending: Pending - older_than_days: Older than %{count} days - completed_tagged_page_title: "TRACKS:: Las tareas completadas con etiqueta %{tag_name}" edit: Edit + completed_tagged_page_title: "TRACKS:: Las tareas completadas con etiqueta %{tag_name}" + older_than_days: Older than %{count} days + pending: Pending completed_actions_with: Completed actions with the tag %{tag_name} + feed_title_in_project: in project '%{project}' deleted_success: The action was deleted succesfully. completed_tasks_title: TRACKS::Completed tasks - feed_title_in_project: in project '%{project}' clear_due_date: Clear due date error_removing_dependency: There was an error removing the dependency hidden_actions: Tareas ocultas @@ -309,13 +412,13 @@ es: deferred_actions_with: Deferred actions with the tag '%{tag_name}' confirm_delete: Are you sure that you want to delete the action '%{description}'? recurring_deleted_success: The recurring action was deleted succesfully. - no_completed_actions_with: No completed actions with the tag '%{tag_name}' next_actions_title: Tracks - Next Actions next_action_description: "Descripci\xC3\xB3n de la nueva tarea" deferred_tasks_title: TRACKS::Tickler + no_completed_actions_with: No completed actions with the tag '%{tag_name}' clear_show_from_date: Clear show from date - unresolved_dependency: The value you entered in the dependency field did not resolve to an existing action. This value will not be saved with the rest of the action. Continue? calendar_page_title: TRACKS::Calendar + unresolved_dependency: The value you entered in the dependency field did not resolve to an existing action. This value will not be saved with the rest of the action. Continue? in_hidden_state: en estado oculto show_today: Show Today no_actions_found_title: No actions found @@ -326,35 +429,37 @@ es: overdue_by_plural: Overdue by %{days} days due_tomorrow: "Vence ma\xC3\xB1ana" completed_last_x_days: Completed in last %{count} days + no_actions_with: Currently there are no incomplete actions with the tag '%{tag_name}' defer_x_days: one: Defer one day other: Defer %{count} days - no_actions_with: Currently there are no incomplete actions with the tag '%{tag_name}' added_new_next_action_singular: Added new next action no_completed_actions: Currently there are no completed actions. + feeds: + completed: "Completed: %{date}" + due: "Due: %{date}" deferred_pending_actions: Deferred/pending actions has_x_pending: one: Tiene una tarea pendiente other: Tiene %{count} tareas pendientes - feeds: - completed: "Completed: %{date}" - due: "Due: %{date}" - error_deleting_recurring: There was an error deleting the recurring todo \'%{description}\' delete_action: Delete action + error_deleting_recurring: There was an error deleting the recurring todo \'%{description}\' recurring_todos: Recurring todos delete: Delete - drag_action_title: Drag onto another action to make it depend on that action cannot_add_dependency_to_completed_todo: Cannot add this action as a dependency to a completed action! + drag_action_title: Drag onto another action to make it depend on that action no_last_completed_actions: "No encontr\xC3\xB3 las acciones realizadas" - depends_on: Depends on tickler_items_due: one: One tickler item is now due - refresh the page to see it. other: "%{count} tickler items are now due - refresh the page to see them." + depends_on: Depends on action_marked_complete: The action '%{description}' was marked as %{completed} completed_today: Completed Today added_new_next_action_plural: Added new next actions new_related_todo_not_created_short: "no se cre\xC3\xB3 la tarea" completed_rest_of_week: Completado en el resto de esta semana + error_starring: Could not toggle the star of this todo \'%{description}\' + show_tomorrow: Show Tomorrow calendar: get_in_ical_format: Get this calendar in iCal format due_next_week: Due next week @@ -366,8 +471,8 @@ es: no_actions_due_after_this_month: No actions due after this month no_actions_due_this_month: No actions due in rest of this month due_this_month: Due in rest of %{month} - show_tomorrow: Show Tomorrow - error_starring: Could not toggle the star of this todo \'%{description}\' + action_deferred: "La acci\xC3\xB3n \\'%{description}\\' se aplaz\xC3\xB3" + added_dependency: Added %{dependency} as dependency. recurrence: ends_on_number_times: Ends after %{number} times ends_on_date: Ends on %{date} @@ -380,8 +485,8 @@ es: starts_on: Starts on daily_options: Settings for daily recurring actions show_option_always: always + daily: Daily pattern: - third: third month_names: - - January @@ -396,19 +501,18 @@ es: - October - November - December + third: third every_n: every %{n} second: second every_xth_day_of_every_n_months: every %{x} %{day} of every %{n_months} on_day_n: on day %{n} - weekly: weekly from: from + weekly: weekly every_day: every day last: last the_xth_day_of_month: the %{x} %{day} of %{month} times: for %{number} times - on_work_days: on work days every_year_on: every year on %{date} - first: first day_names: - sunday - monday @@ -418,41 +522,40 @@ es: - friday - saturday show: show + first: first + on_work_days: on work days fourth: fourth due: due - every_month: every month until: until - daily: Daily - yearly_every_x_day: Every %{month} %{day} + every_month: every month recurrence_on_options: Set recurrence on + yearly_every_x_day: Every %{month} %{day} daily_every_number_day: Every %{number} day(s) - show_options: Show the todo ends_on: Ends on + show_options: Show the todo weekly_every_number_week: Returns every %{number} week on - yearly_every_xth_day: The %{day} %{day_of_week} of %{month} - yearly_options: Settings for yearly recurring actions show_days_before: "%{days} days before the todo is due" + yearly_every_xth_day: The %{day} %{day_of_week} of %{month} from_tickler: the date todo comes from tickler (no due date set) no_end_date: No end date day_x_on_every_x_month: Day %{day} on every %{month} month - yearly: Yearly + yearly_options: Settings for yearly recurring actions monthly_every_xth_day: The %{day} %{day_of_week} of every %{month} month - action_deferred: "La acci\xC3\xB3n \\'%{description}\\' se aplaz\xC3\xB3" + yearly: Yearly tagged_page_title: TRACKS::Tagged with '%{tag_name}' no_completed_recurring: Currently there are no completed recurring todos - added_dependency: Added %{dependency} as dependency. completed_rest_of_month: Completado en el resto de este mes - no_deferred_actions: Currently there are no deferred actions. - all_completed_tagged_page_title: "TRACKS:: Todas las tareas realizadas con etiqueta %{tag_name}" recurrence_completed: There is no next action after the recurring action you just finished. The recurrence is completed - no_actions_found: Currently there are no incomplete actions. + all_completed_tagged_page_title: "TRACKS:: Todas las tareas realizadas con etiqueta %{tag_name}" + no_deferred_actions: Currently there are no deferred actions. in_pending_state: en estado pendiente + no_actions_found: Currently there are no incomplete actions. error_toggle_complete: Could not mark this todo complete due: "Fecha l\xC3\xADmite" action_marked_complete_error: The action '%{description}' was NOT marked as %{completed} due to an error on the server. - action_saved_to_tickler: Action saved to tickler depends_on_separate_with_commas: Depende de (separar con comas) recurring_action_saved: Recurring action saved + action_saved_to_tickler: Action saved to tickler completed_in_archive: one: There is one completed action in the archive. other: There are %{count} completed actions in the archive. @@ -463,102 +566,10 @@ es: overdue: Overdue add_new_recurring: Add a new recurring action no_incomplete_actions: There are no incomplete actions - stats: - tag_cloud_title: Tag cloud for all actions - tag_cloud_description: This tag cloud includes tags of all actions (completed, not completed, visible and/or hidden) - actions: Actions - tag_cloud_90days_title: Tag cloud actions in past 90 days - totals_active_project_count: Of those %{count} are active projects - actions_last_year_legend: - number_of_actions: Number of actions - months_ago: Months ago - totals_first_action: Since your first action on %{date} - actions_avg_completion_time: Of all your completed actions, the average time to complete is %{count} days. - totals_deferred_actions: of which %{count} are deferred actions in the tickler - current_running_time_of_incomplete_visible_actions: Current running time of incomplete visible actions - top10_longrunning: Top 10 longest running projects - totals_action_count: you have a total of %{count} actions - actions_dow_30days_title: Day of week (past 30 days) - legend: - actions: Tareas - number_of_days: Number of days ago - number_of_actions: "N\xC3\xBAmero de tareas" - day_of_week: Day of week - percentage: Percentage - running_time: Running time of an action (weeks) - months_ago: Months ago - running_time_legend: - actions: Tareas - percentage: Percentage - weeks: Running time of an action (weeks). Click on a bar for more info - top5_contexts: Top 5 contexts - actions_lastyear_title: Actions in the last 12 months - totals_actions_completed: "%{count} of these are completed." - totals_incomplete_actions: You have %{count} incomplete actions - totals_unique_tags: Of those tags, %{count} are unique. - actions_avg_completed_30days: and completed an average of %{count} actions per day. - totals_blocked_actions: "%{count} are dependent on the completion of their actions." - action_completion_time_title: Completion time (all completed actions) - projects: Projects - actions_last_year: Actions in the last years - totals_context_count: You have %{count} contexts. - totals_visible_context_count: Of those %{count} are visible contexts - actions_min_max_completion_days: The Max-/minimum days to complete is %{min}/%{max}. - actions_min_completion_time: The minimum time to complete is %{time}. - tags: Tags - no_tags_available: no tags available - actions_day_of_week_title: Day of week (all actions) - totals_project_count: You have %{count} projects. - totals_hidden_project_count: "%{count} are hidden" - tag_cloud_90days_description: This tag cloud includes tags of actions that were created or completed in the past 90 days. - top5_visible_contexts_with_incomplete_actions: Top 5 visible contexts with incomplete actions - actions_30days_title: Actions in the last 30 days - time_of_day: Time of day (all actions) - more_stats_will_appear: More statistics will appear here once you have added some actions. - actions_further: " and further" - tod30: Time of day (last 30 days) - running_time_all: Current running time of all incomplete actions - totals_tag_count: You have %{count} tags placed on actions. - other_actions_label: (otros) - top10_projects_30days: Top 10 project in past 30 days - spread_of_running_actions_for_visible_contexts: Spread of running actions for visible contexts - click_to_show_actions_from_week: Click %{link} to show the actions from week %{week} and further. - actions_avg_created: In the last 12 months you created on average %{count} actions - spread_of_actions_for_all_context: Spread of actions for all context - click_to_return: Click %{link} to return to the statistics page. - actions_selected_from_week: "Actions selected from week " - totals_completed_project_count: and %{count} are completed projects. - top10_projects: Top 10 projects - totals: Totals - time_of_day_legend: - number_of_actions: "N\xC3\xBAmero de tareas" - time_of_day: Time of day - click_to_return_link: here - totals_hidden_context_count: and %{count} are hidden contexts. - contexts: Contexts - actions_avg_completed: and completed an average of %{count} actions per month. - no_actions_selected: No hay tareas seleccionadas. - click_to_update_actions: Click on a bar in the chart to update the actions below. - labels: - month_avg_completed: "%{months} Month avg completed" - completed: Completed - month_avg_created: "%{months} Month avg created" - avg_created: Avg created - avg_completed: Avg completed - created: Created - running_time_all_legend: - actions: Tareas - percentage: Percentage - running_time: Running time of an action (weeks). Click on a bar for more info - tod30_legend: - number_of_actions: "N\xC3\xBAmero de tareas" - time_of_day: Time of day - action_selection_title: TRACKS::Action selection - actions_actions_avg_created_30days: In the last 30 days you created on average %{count} actions notes: + delete_note_title: Delete the note '%{id}' delete_confirmation: Are you sure that you want to delete the note '%{id}'? delete_item_title: Delete item - delete_note_title: Delete the note '%{id}' deleted_note: Deleted note '%{id}' note_link_title: Show note %{id} show_note_title: Show note @@ -570,87 +581,87 @@ es: states: hidden_plural: Hidden review_plural: Fechado - completed: Completed stalled: Estancado + completed: Completed current: "Hasta al d\xC3\xADa" - completed_plural: Completed review: Fechado - blocked: Bloqueado + completed_plural: Completed blocked_plural: Bloqueado + blocked: Bloqueado stalled_plural: Estancado visible_plural: Visible - visible: Visible active_plural: Active + visible: Visible current_plural: "Hasta al d\xC3\xADa" - active: Active hidden: Hidden + active: Active + errors: + user_unauthorized: "401 No autorizado: Solo los usuarios administrativos pueden acceder a esta funci\xC3\xB3n." projects: + no_actions_in_project: Currently there are no incomplete actions in this project + deferred_actions: Tareas pospuestas para este proyecto was_marked_hidden: has been marked as hidden edit_project_title: Editar proyecto default_tags_removed_notice: Removed the default tags default_context_set: Set project's default context to %{default_context} - no_actions_in_project: Currently there are no incomplete actions in this project - deferred_actions: Tareas pospuestas para este proyecto - all_completed_tasks_title: "TRACKS:: Lista de todas las acciones terminado en '%{project_name}' Proyecto" hide_form: Esconder formulario page_title: "TRACKS::Project: %{project}" - show_form_title: Create a new project - this_project: This project + all_completed_tasks_title: "TRACKS:: Lista de todas las acciones terminado en '%{project_name}' Proyecto" project_state: Project is %{state}. list_completed_projects: "TRACKS:: Lista de Proyectos Realizados" to_new_project_page: Take me to the new project page no_notes_attached: Currently there are no notes attached to this project + show_form_title: Create a new project deferred_actions_empty: There are no deferred actions for this project - notes: Notes + this_project: This project no_last_completed_recurring_todos: No se ha completado las acciones repetitivas que se encuentran todos_append: in this project no_last_completed_projects: No hay proyectos terminados encontrado + notes: Notes hide_form_title: Hide new project form list_reviews: "TRACKS::Revisi\xC3\xB3n" notes_empty: There are no notes for this project no_projects: Currently there are no projects - delete_project: Delete project completed_actions_empty: No hay tareas completadas para este proyecto with_no_default_context: with no default context + delete_project: Delete project show_form: Add a project actions_in_project_title: Actions in this project delete_project_confirmation: Are you sure that you want to delete the project '%{name}'? with_default_context: with a default context of '%{context_name}' - with_default_tags: and with '%{tags}' as the default tags - is_active: "est\xC3\xA1 activo" set_default_tags_notice: Set project's default tags to %{default_tags} completed_projects: Proyectos completados add_note: "A\xC3\xB1adir una nota" add_project: "A\xC3\xB1adir Proyecto" - list_projects: TRACKS::Lista de Proyectos settings: Settings + with_default_tags: and with '%{tags}' as the default tags + list_projects: TRACKS::Lista de Proyectos + is_active: "est\xC3\xA1 activo" project_saved_status: Project saved - completed_tasks_title: "TRACKS:: Lista de Acciones completadas en '%{project_name}' Proyecto" delete_project_title: Delete the project hidden_projects: Proyectos ocultos - add_note_submit: "A\xC3\xB1adir nota" - was_marked_complete: has been marked as completed + completed_tasks_title: "TRACKS:: Lista de Acciones completadas en '%{project_name}' Proyecto" default_context_removed: Eliminado el contexto por defecto completed_actions: Tareas completadas para este proyecto - default_context: The default context for this project is %{context} - active_projects: Active projects + add_note_submit: "A\xC3\xB1adir nota" + was_marked_complete: has been marked as completed no_default_context: Este proyecto no tiene un contexto por defecto with_no_default_tags: and with no default tags - state: This project is %{state} edit_project_settings: Edit Project Settings status_project_name_changed: Name of project was changed - errors: - user_unauthorized: "401 No autorizado: Solo los usuarios administrativos pueden acceder a esta funci\xC3\xB3n." + state: This project is %{state} + default_context: The default context for this project is %{context} + active_projects: Active projects preferences: + change_identity_url: Change Your Identity URL open_id_url: Your OpenID URL is staleness_starts_after: Staleness starts after %{days} days - change_identity_url: Change Your Identity URL - page_title: TRACKS::Preferences change_password: Change your password + page_title: TRACKS::Preferences token_description: Token (for feeds and API use) title: Your preferences - show_number_completed: Show %{number} completed items is_false: "false" + show_number_completed: Show %{number} completed items page_title_edit: TRACKS::Edit Preferences is_true: "true" password_changed: "Que ha cambiado la contrase\xC3\xB1a, por favor vuelve a iniciar sesi\xC3\xB3n." @@ -658,14 +669,14 @@ es: generate_new_token: Generate a new token sms_context_none: None token_header: Your token + authentication_header: Your authentication updated: "Las preferencias de actualizaci\xC3\xB3n" current_authentication_type: Your authentication type is %{auth_type} change_authentication_type: Change your authentication type - authentication_header: Your authentication generate_new_token_confirm: Are you sure? Generating a new token will replace the existing one and break any external usages of this token. tabs: - authentication: "Autenticaci\xC3\xB3n" tracks_behavior: Rastrea el comportamiento de + authentication: "Autenticaci\xC3\xB3n" profile: Perfil date_and_time: Fecha y hora time: @@ -729,13 +740,6 @@ es: - Oct - Nov - Dic - support: - array: - words_connector: "," - last_word_connector: ", y" - two_words_connector: y - select: - prompt: Por favor seleccione will_paginate: previous_label: "\xC2\xAB Anterior" page_entries_info: @@ -751,23 +755,126 @@ es: multi_page_html: Viendo %{model} %{from} - %{to} de %{count} en el total de page_gap: ... next_label: "Siguiente \xC2\xBB" - footer: - send_feedback: "Env\xC3\xADa comentarios sobre el %{version}" + support: + array: + words_connector: "," + last_word_connector: ", y" + two_words_connector: y + select: + prompt: Por favor seleccione shared: multiple_next_actions: Multiple next actions (one on each line) - hide_form: Esconder formulario make_actions_dependent: "Aseg\xC3\xBArese que las acciones dependen unos de otros" + hide_form: Esconder formulario toggle_single: Add a next action add_actions: "A\xC3\xB1adir tareas" add_action: "A\xC3\xB1adir tarea" tags_for_all_actions: Tags for all actions (sep. with commas) - context_for_all_actions: Context for all actions toggle_multi: Add multiple next actions toggle_single_title: Add a new next action project_for_all_actions: Project for all actions + context_for_all_actions: Context for all actions separate_tags_with_commas: separar con comas toggle_multi_title: Toggle single/multi new action form hide_action_form_title: Hide new action form + footer: + send_feedback: "Env\xC3\xADa comentarios sobre el %{version}" + feedlist: + actions_due_today: Acciones pendientes hoy o antes + choose_context: Elija el contexto en el que desea un canal de + rss_feed: RSS Feed + legend: "Leyenda:" + ical_feed: "iCal alimentaci\xC3\xB3n" + all_contexts: Todos los contextos + all_projects: Todos los proyectos + choose_project: Elegir el proyecto que quiere un canal de + project_needed: Es necesario que haya al menos un proyecto antes de poder solicitar un feed + select_feed_for_project: Seleccione la fuente para este proyecto + active_projects_wo_next: "Proyectos activos, sin las pr\xC3\xB3ximas acciones" + active_starred_actions: "Todas las acciones que protagoniz\xC3\xB3, activa" + context_needed: Es necesario que haya al menos un contexto antes de poder solicitar un feed + select_feed_for_context: "Seleccione la alimentaci\xC3\xB3n de este contexto" + projects_and_actions: Proyectos activos con sus acciones + actions_due_next_week: "Tareas pendientes en 7 d\xC3\xADas o menos" + notice_incomplete_only: "Nota: Todos los alimentos muestran s\xC3\xB3lo las acciones que no han sido marcadas como realizadas, a menos que se indique lo contrario." + last_fixed_number: "\xC3\x9Altima %{number} acciones" + all_actions: Todas las tareas + actions_completed_last_week: "Tareas completadas en los \xC3\xBAltimos 7 d\xC3\xADas" + context_centric_actions: "Feeds de acciones incompletas en un contexto espec\xC3\xADfico" + plain_text_feed: Canal Texto sin formato + project_centric: "Feeds de acciones incompletas en un proyecto espec\xC3\xADfico" + users: + successfully_deleted_user: Successfully deleted user %{username} + failed_to_delete_user: Failed to delete user %{username} + destroy_successful: User %{login} was successfully destroyed + total_contexts: Total contexts + openid_url_verified: You have successfully verified %{url} as your identity and set your authentication type to OpenID. + first_user_heading: "Welcome to TRACKS. To get started, please create an admin account:" + auth_type_update_error: "There was a problem updating your authentication type: %{error_messages}" + new_token_generated: New token successfully generated + total_projects: Total projects + signup_successful: Signup successful for user %{username}. + no_signups_title: TRACKS::No signups + user_created: User created. + change_password_submit: Change password + account_signup: Account signup + manage_users: Manage users + password_updated: Password updated. + auth_type_updated: Authentication type updated. + total_actions: Total actions + desired_login: Desired login + signup: Signup + confirm_password: Confirm password + new_user_heading: "Sign up a new user:" + change_password_prompt: Enter your new password in the fields below and click 'Change password' to replace your current password with your new one. + password_confirmation_label: Confirm password + destroy_error: There was an error deleting the user %{login} + choose_password: Choose password + change_password_title: TRACKS::Change password + change_auth_type_title: TRACKS::Change authentication type + new_password_label: New password + register_with_cas: With your CAS username + label_auth_type: Authentication type + new_user_title: TRACKS::Sign up as the admin user + destroy_user: Destroy user + total_users_count: You have a total of %{count} users + you_have_to_reset_your_password: "Usted tiene que restablecer su contrase\xC3\xB1a" + signup_new_user: Sign up new user + destroy_confirmation: "Warning: this will delete user '%{login}', all their actions, contexts, project and notes. Are you sure that you want to continue?" + identity_url: Identity URL + openid_ok_pref_failed: You have successfully verified %{url} as your identity but there was a problem saving your authentication preferences. + change_authentication_type: Change authentication type + auth_change_submit: Change authentication type + select_authentication_type: Select your new authentication type and click 'Change authentication type' to replace your current settings. + total_notes: Total notes + contexts: + delete_context_title: Eliminar contexto + hide_form: Esconder formulario + all_completed_tasks_title: "TRACKS:: Todas las acciones completadas en '%{context_name}' contexto" + show_form_title: "A\xC3\xB1adir un contexto" + delete_context_confirmation: "\xC2\xBFEst\xC3\xA1 seguro que desea eliminar '%{name}' el contexto? Tenga en cuenta que esto tambi\xC3\xA9n se eliminar\xC3\xA1n todas las acciones (la repetici\xC3\xB3n) en este contexto!" + todos_append: en este contexto + delete_context: Eliminar contexto + edit_context: Editar contexto + hide_form_title: Ocultar el formulario nuevo contexto + context_hide: "\xC2\xBFEsconder de la p\xC3\xA1gina principal?" + hidden_contexts: Contextos ocultos + no_contexts_active: Actualmente no hay contextos activos + show_form: Crear un nuevo contexto + visible_contexts: Contextos visible + save_status_message: Contexto guardado + add_context: "A\xC3\xB1adir contexto" + update_status_message: Nombre de contexto ha cambiado + context_name: Nombre del contexto + status_active: "El contexto est\xC3\xA1 activo" + completed_tasks_title: "TRACKS:: Las acciones completadas en '%{context_name}' el contexto" + new_context_post: "' Tambi\xC3\xA9n se ha creado. \xC2\xBFEst\xC3\xA1 seguro?" + no_actions: Actualmente no hay acciones incompletas en este contexto + last_completed_in_context: "en este contexto (\xC3\xBAltimos %{number})" + context_deleted: Contexto eliminado '%{name}' + no_contexts_hidden: Actualmente no hay contextos ocultos + new_context_pre: Nuevo contexto ' + status_hidden: Contexto se oculta sidebar: list_name_active_contexts: Active contexts list_name_active_projects: Active projects @@ -775,101 +882,31 @@ es: list_name_completed_projects: Completed projects list_name_hidden_projects: Hidden projects list_name_hidden_contexts: Hidden contexts - users: - successfully_deleted_user: Successfully deleted user %{username} - destroy_successful: User %{login} was successfully destroyed - total_contexts: Total contexts - openid_url_verified: You have successfully verified %{url} as your identity and set your authentication type to OpenID. - first_user_heading: "Welcome to TRACKS. To get started, please create an admin account:" - auth_type_update_error: "There was a problem updating your authentication type: %{error_messages}" - failed_to_delete_user: Failed to delete user %{username} - new_token_generated: New token successfully generated - total_projects: Total projects - signup_successful: Signup successful for user %{username}. - change_password_submit: Change password - no_signups_title: TRACKS::No signups - user_created: User created. - manage_users: Manage users - account_signup: Account signup - password_updated: Password updated. - confirm_password: Confirm password - new_user_heading: "Sign up a new user:" - signup: Signup - auth_type_updated: Authentication type updated. - total_actions: Total actions - desired_login: Desired login - choose_password: Choose password - change_password_title: TRACKS::Change password - change_auth_type_title: TRACKS::Change authentication type - change_password_prompt: Enter your new password in the fields below and click 'Change password' to replace your current password with your new one. - password_confirmation_label: Confirm password - destroy_error: There was an error deleting the user %{login} - new_password_label: New password - register_with_cas: With your CAS username - label_auth_type: Authentication type - new_user_title: TRACKS::Sign up as the admin user - destroy_user: Destroy user - total_users_count: You have a total of %{count} users - destroy_confirmation: "Warning: this will delete user '%{login}', all their actions, contexts, project and notes. Are you sure that you want to continue?" - you_have_to_reset_your_password: "Usted tiene que restablecer su contrase\xC3\xB1a" - signup_new_user: Sign up new user - openid_ok_pref_failed: You have successfully verified %{url} as your identity but there was a problem saving your authentication preferences. - change_authentication_type: Change authentication type - auth_change_submit: Change authentication type - identity_url: Identity URL - select_authentication_type: Select your new authentication type and click 'Change authentication type' to replace your current settings. - total_notes: Total notes - contexts: - delete_context_title: Eliminar contexto - all_completed_tasks_title: "TRACKS:: Todas las acciones completadas en '%{context_name}' contexto" - hide_form: Esconder formulario - show_form_title: "A\xC3\xB1adir un contexto" - delete_context_confirmation: "\xC2\xBFEst\xC3\xA1 seguro que desea eliminar '%{name}' el contexto? Tenga en cuenta que esto tambi\xC3\xA9n se eliminar\xC3\xA1n todas las acciones (la repetici\xC3\xB3n) en este contexto!" - delete_context: Eliminar contexto - hide_form_title: Ocultar el formulario nuevo contexto - edit_context: Editar contexto - hidden_contexts: Contextos ocultos - no_contexts_active: Actualmente no hay contextos activos - context_hide: "\xC2\xBFEsconder de la p\xC3\xA1gina principal?" - show_form: Crear un nuevo contexto - visible_contexts: Contextos visible - save_status_message: Contexto guardado - add_context: "A\xC3\xB1adir contexto" - update_status_message: Nombre de contexto ha cambiado - context_name: Nombre del contexto - completed_tasks_title: "TRACKS:: Las acciones completadas en '%{context_name}' el contexto" - status_active: "El contexto est\xC3\xA1 activo" - new_context_post: "' Tambi\xC3\xA9n se ha creado. \xC2\xBFEst\xC3\xA1 seguro?" - context_deleted: Contexto eliminado '%{name}' - no_contexts_hidden: Actualmente no hay contextos ocultos - new_context_pre: Nuevo contexto ' - no_actions: Actualmente no hay acciones incompletas en este contexto - last_completed_in_context: "en este contexto (\xC3\xBAltimos %{number})" - status_hidden: Contexto se oculta - feedlist: - actions_due_today: Acciones pendientes hoy o antes - choose_context: Elija el contexto en el que desea un canal de - all_contexts: Todos los contextos - rss_feed: RSS Feed - ical_feed: "iCal alimentaci\xC3\xB3n" - legend: "Leyenda:" - all_projects: Todos los proyectos - choose_project: Elegir el proyecto que quiere un canal de - active_projects_wo_next: "Proyectos activos, sin las pr\xC3\xB3ximas acciones" - project_needed: Es necesario que haya al menos un proyecto antes de poder solicitar un feed - select_feed_for_project: Seleccione la fuente para este proyecto - active_starred_actions: "Todas las acciones que protagoniz\xC3\xB3, activa" - context_needed: Es necesario que haya al menos un contexto antes de poder solicitar un feed - select_feed_for_context: "Seleccione la alimentaci\xC3\xB3n de este contexto" - projects_and_actions: Proyectos activos con sus acciones - notice_incomplete_only: "Nota: Todos los alimentos muestran s\xC3\xB3lo las acciones que no han sido marcadas como realizadas, a menos que se indique lo contrario." - actions_due_next_week: "Tareas pendientes en 7 d\xC3\xADas o menos" - plain_text_feed: Canal Texto sin formato - last_fixed_number: "\xC3\x9Altima %{number} acciones" - all_actions: Todas las tareas - actions_completed_last_week: "Tareas completadas en los \xC3\xBAltimos 7 d\xC3\xADas" - context_centric_actions: "Feeds de acciones incompletas en un contexto espec\xC3\xADfico" - project_centric: "Feeds de acciones incompletas en un proyecto espec\xC3\xADfico" + login: + sign_in: Entrar + openid_identity_url_not_found: Sorry, no user by that identity URL exists (%{identity_url}) + user_no_expiry: Stay logged in + login_cas: go to the CAS + cas_logged_in_greeting: Hello, %{username}! You are authenticated. + cas_no_user_found: Hello, %{username}! You do not have an account on Tracks. + cas_login: CAS Login + successful_with_session_info: "Login successful:" + please_login: Please log in to use Tracks + cas_username_not_found: Sorry, no user by that CAS username exists (%{username}) + cas_create_account: If you like to request on please go here to %{signup_link} + mobile_use_openid: "\xE2\x80\xA6or login with an OpenID" + cas_signup_link: Request account + account_login: Acceso a la cuenta + successful: "Has entrado con \xC3\xA9xito. Bienvenido!" + session_will_not_expire: session will not expire. + session_will_expire: session will expire after %{hours} hour(s) of inactivity. + option_separator: or, + session_time_out: Session has timed out. Please %{link} + login_standard: go back to the standard login + log_in_again: log in again. + logged_out: You have been logged out of Tracks. + login_with_openid: login with an OpenID + unsuccessful: Login unsuccessful. datetime: prompts: minute: Minuto @@ -898,6 +935,9 @@ es: x_seconds: one: Un segundo other: "%{count} segundos" + about_x_hours: + one: alrededor de 1 hora + other: Acerca de %{count} horas less_than_x_seconds: one: menos de 1 segundo other: menos de %{count} segundos @@ -908,48 +948,20 @@ es: x_minutes: one: 1 minuto other: "%{count} minutos" - about_x_hours: - one: alrededor de 1 hora - other: Acerca de %{count} horas - about_x_months: - one: alrededor de 1 mes - other: Acerca de %{count} meses about_x_years: one: "alrededor de 1 a\xC3\xB1o" other: "Acerca de %{count} a\xC3\xB1os" + about_x_months: + one: alrededor de 1 mes + other: Acerca de %{count} meses over_x_years: one: "m\xC3\xA1s de 1 a\xC3\xB1o" other: "en %{count} a\xC3\xB1os" half_a_minute: medio minuto - login: - sign_in: Entrar - openid_identity_url_not_found: Sorry, no user by that identity URL exists (%{identity_url}) - login_cas: go to the CAS - user_no_expiry: Stay logged in - cas_login: CAS Login - successful_with_session_info: "Login successful:" - please_login: Please log in to use Tracks - cas_logged_in_greeting: Hello, %{username}! You are authenticated. - cas_no_user_found: Hello, %{username}! You do not have an account on Tracks. - cas_username_not_found: Sorry, no user by that CAS username exists (%{username}) - mobile_use_openid: "\xE2\x80\xA6or login with an OpenID" - cas_create_account: If you like to request on please go here to %{signup_link} - cas_signup_link: Request account - account_login: Acceso a la cuenta - successful: "Has entrado con \xC3\xA9xito. Bienvenido!" - session_will_not_expire: session will not expire. - session_time_out: Session has timed out. Please %{link} - session_will_expire: session will expire after %{hours} hour(s) of inactivity. - option_separator: or, - login_standard: go back to the standard login - unsuccessful: Login unsuccessful. - log_in_again: log in again. - logged_out: You have been logged out of Tracks. - login_with_openid: login with an OpenID search: contexts_matching_query: Contexts matching query tags_matching_query: Tags matching query - notes_matching_query: Notes matching query no_results: Your search yielded no results. todos_matching_query: Todos matching query projects_matching_query: Projects matching query + notes_matching_query: Notes matching query diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 32aa6c92..214878b4 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -1,63 +1,5 @@ --- fr: - common: - back: Retour - third: "Troisi\xC3\xA8me" - actions: Actions - recurring_todos: "R\xC3\xA9p\xC3\xA9tition d'actions" - add: Ajouter - go_back: Retour - logout: "D\xC3\xA9connexion" - previous: !binary | - UHLDqWPDqWRlbnRl - - none: Aucun - second: Seconde - week: semaine - cancel: Annuler - optional: optionnel - month: mois - forum: Forum - notes: Notes - server_error: Une erreur s\'est produite sur le serveur - last: Dernier - action: Action - projects: Projets - review: Revue - project: Projet - ok: Ok - contribute: Contribuer - first: Premier - website: Site Web - numbered_step: Etape %{number} - errors_with_fields: "Il y a des probl\xC3\xA8me avec les champs suivants :" - sort: - by_task_count_title: "Trier par nombre de t\xC3\xA2ches" - by_task_count_title_confirm: "Etes vous s\xC3\xBBr de vouloir trier ces projets par nombre de t\xC3\xA2ches ? L\\'ordre actuel sera remplac\xC3\xA9." - alphabetically: "Par ordre alphab\xC3\xA9tique" - alphabetically_confirm: "Etes vous s\xC3\xBBr de vouloir trier ces projets par ordre alphab\xC3\xA9tique ? L\\'ordre actuel sera remplac\xC3\xA9." - sort: Trier - alphabetically_title: "Trier les projets par ordre alphab\xC3\xA9tique" - by_task_count: "Par nombre de t\xC3\xA2ches" - create: !binary | - Q3LDqWVy - - drag_handle: DRAG - description: Description - context: Contexte - todo: Action - months: Mois - next: Suivant - fourth: "Quatri\xC3\xA8me" - contexts: Contextes - update: "Mettre \xC3\xA0 jour" - weeks: semaines - forth: FORTH - wiki: Wiki - bugs: Bugs - email: Email - ajaxError: "Une erreur s'est produite en acc\xC3\xA9dant un serveur" - search: Rechercher number: format: separator: . @@ -80,15 +22,73 @@ fr: percentage: format: delimiter: "" + precision: + format: + delimiter: "" currency: format: format: "%u%n" unit: $ separator: . delimiter: "," - precision: - format: - delimiter: "" + common: + back: Retour + recurring_todos: "R\xC3\xA9p\xC3\xA9tition d'actions" + actions: Actions + third: "Troisi\xC3\xA8me" + add: Ajouter + previous: !binary | + UHLDqWPDqWRlbnRl + + go_back: Retour + logout: "D\xC3\xA9connexion" + second: Seconde + optional: optionnel + week: semaine + none: Aucun + cancel: Annuler + month: mois + forum: Forum + server_error: Une erreur s\'est produite sur le serveur + notes: Notes + last: Dernier + review: Revue + projects: Projets + action: Action + project: Projet + ok: Ok + contribute: Contribuer + first: Premier + website: Site Web + numbered_step: Etape %{number} + errors_with_fields: "Il y a des probl\xC3\xA8me avec les champs suivants :" + create: !binary | + Q3LDqWVy + + sort: + by_task_count_title: "Trier par nombre de t\xC3\xA2ches" + by_task_count_title_confirm: "Etes vous s\xC3\xBBr de vouloir trier ces projets par nombre de t\xC3\xA2ches ? L\\'ordre actuel sera remplac\xC3\xA9." + alphabetically: "Par ordre alphab\xC3\xA9tique" + sort: Trier + alphabetically_confirm: "Etes vous s\xC3\xBBr de vouloir trier ces projets par ordre alphab\xC3\xA9tique ? L\\'ordre actuel sera remplac\xC3\xA9." + alphabetically_title: "Trier les projets par ordre alphab\xC3\xA9tique" + by_task_count: "Par nombre de t\xC3\xA2ches" + months: Mois + drag_handle: DRAG + description: Description + fourth: "Quatri\xC3\xA8me" + next: Suivant + contexts: Contextes + todo: Action + context: Contexte + update: "Mettre \xC3\xA0 jour" + weeks: semaines + forth: FORTH + wiki: Wiki + bugs: Bugs + email: Email + ajaxError: "Une erreur s'est produite en acc\xC3\xA9dant un serveur" + search: Rechercher layouts: toggle_contexts_title: "Faire des contextes effondr\xC3\xA9 (in)visibles" toggle_contexts: "Basculer contextes effondr\xC3\xA9" @@ -96,9 +96,9 @@ fr: next_actions_rss_feed: Flux RSS des prochaines actions toggle_notes_title: Afficher/Cacher toutes les notes mobile_navigation: + new_action: 0-Nouvelle action logout: "D\xC3\xA9connexion" feeds: Flux - new_action: 0-Nouvelle action starred: "Marqu\xC3\xA9" projects: Projets tickler: Reporteur @@ -106,8 +106,8 @@ fr: home: Accueil navigation: api_docs: Doc REST API - recurring_todos: "T\xC3\xA2ches (todos) r\xC3\xA9p\xC3\xA9titives" manage_users_title: Ajouter ou supprimer des utilisateurs + recurring_todos: "T\xC3\xA2ches (todos) r\xC3\xA9p\xC3\xA9titives" feeds: Flux stats: Statistiques starred: "Marqu\xC3\xA9" @@ -115,33 +115,33 @@ fr: manage_users: Gestion des utilisateurs tickler_title: Reporteur integrations_: "Int\xC3\xA9grer Tracks" + export_title: "Importer et exporter des donn\xC3\xA9es" preferences: !binary | UHLDqWbDqXJlbmNlcw== - export_title: "Importer et exporter des donn\xC3\xA9es" - calendar_title: "Calendrier des actions \xC3\xA0 \xC3\xA9ch\xC3\xA9ance" feeds_title: Voir une liste des flux disponibles - stats_title: Voir vos statistiques + calendar_title: "Calendrier des actions \xC3\xA0 \xC3\xA9ch\xC3\xA9ance" home_title: Accueil tickler: Reporteur starred_title: "Voir vos actions pr\xC3\xA9f\xC3\xA9r\xC3\xA9es" recurring_todos_title: "Gerer les actions r\xC3\xA9currentes" completed_tasks: "Termin\xC3\xA9" - organize: Organiser + stats_title: Voir vos statistiques view: Vue + organize: Organiser completed_tasks_title: "Termin\xC3\xA9" home: Accueil contexts_title: Contextes export: Exporter + preferences_title: "Voir mes pr\xC3\xA9f\xC3\xA9rences" + review_title: Faire examiner search: Recherches tous les items projects_title: Projets - preferences_title: "Voir mes pr\xC3\xA9f\xC3\xA9rences" calendar: Calendrier - review_title: Faire examiner integrations: opensearch_description: Rechercher dans Tracks - applescript_next_action_prompt: "Description de l'action suivante:" gmail_description: "Gadget pour ajouter Tracks \xC3\xA0 Gmail" + applescript_next_action_prompt: "Description de l'action suivante:" applescript_success_after_id: !binary | Q3LDqcOp @@ -154,8 +154,8 @@ fr: default_context_name: Contexte par defaut description: Description todo: - predecessors: "D\xC3\xA9pend de" show_from: Afficher depuis + predecessors: "D\xC3\xA9pend de" notes: Note project: Projet description: Description @@ -172,19 +172,19 @@ fr: staleness_starts: "D\xC3\xA9but de d\xC3\xA9passement" verbose_action_descriptors: "Descripteurs d\\'action d\xC3\xA9taill\xC3\xA9s" sms_context: Contexte Email par default - show_number_completed: "Montrer le nombre d\\'action compl\xC3\xA9t\xC3\xA9es" title_date_format: Format de la date en titre + show_number_completed: "Montrer le nombre d\\'action compl\xC3\xA9t\xC3\xA9es" refresh: Intervalle de rafraichissement (en minutes) week_starts: Les semaines commencent un last_name: Nom - time_zone: Fuseau horaire - due_style: "Style Ech\xC3\xA9ance" locale: Langue + due_style: "Style Ech\xC3\xA9ance" + time_zone: Fuseau horaire sms_email: De l\'Email show_project_on_todo_done: "Aller au projet quand la t\xC3\xA2che est termin\xC3\xA9e" - first_name: Nom show_completed_projects_in_sidebar: "Montrer les projets compl\xC3\xA9t\xC3\xA9s dans le panneau lat\xC3\xA9ral" review_period: Intervalle de revue de projet + first_name: Nom errors: models: project: @@ -198,31 +198,34 @@ fr: messages: record_invalid: "La validation \xC3\xA0 \xC3\xA9chou\xC3\xA9 : %{errors}" greater_than_or_equal_to: "doit \xC3\xAAtre plus grand ou \xC3\xA9gal \xC3\xA0 %{count}" - less_than_or_equal_to: "doit \xC3\xAAtre inf\xC3\xA9rieur ou \xC3\xA9gal \xC3\xA0 %{count}" confirmation: "n\\'est pas identique \xC3\xA0 la confirmation" + less_than_or_equal_to: "doit \xC3\xAAtre inf\xC3\xA9rieur ou \xC3\xA9gal \xC3\xA0 %{count}" blank: "ne peux \xC3\xAAtre vide" exclusion: exclusion? invalid: "ne peut contenir le caract\xC3\xA8re virgule (\\',\\')" odd: "doit \xC3\xAAtre impair" + even: "doit \xC3\xAAtre pair" + empty: "ne peut \xC3\xAAtre vide" too_short: "est trop court (minimum de %{count} charact\xC3\xA8res)" wrong_length: "est de longueur incorrecte (doit \xC3\xAAtre de %{count} caract\xC3\xA8res)" - empty: "ne peut \xC3\xAAtre vide" - even: "doit \xC3\xAAtre pair" less_than: "doit \xC3\xAAtre inf\xC3\xA9rieur \xC3\xA0 %{count}" - equal_to: "doit \xC3\xAAtre \xC3\xA9gal \xC3\xA0 %{count}" greater_than: "doit \xC3\xAAtre plus grand que %{count}" + equal_to: "doit \xC3\xAAtre \xC3\xA9gal \xC3\xA0 %{count}" + accepted: "doit \xC3\xAAtre accept\xC3\xA9" too_long: "est trop long (maximum de %{count} caract\xC3\xA8res)" taken: "est d\xC3\xA9j\xC3\xA0 pris" - accepted: "doit \xC3\xAAtre accept\xC3\xA9" - not_a_number: n\'est pas un nombre inclusion: n\'est pas inclus dans la liste + not_a_number: n\'est pas un nombre + full_messages: + format: "%{attribute} %{message}" template: body: "Il y a des probl\xC3\xA8mes avec les champs suivants :" header: one: "1 erreur a emp\xC3\xA9ch\xC3\xA9 ce %{model} d\\'\xC3\xAAtre sauvegard\xC3\xA9" other: "%{count} erreurs ont emp\xC3\xA9ch\xC3\xA9 ce %{model} d\\'\xC3\xAAtre sauvegard\xC3\xA9" - full_messages: - format: "%{attribute} %{message}" + data: + import_successful: "L'import a r\xC3\xA9ussi." + import_errors: Des erreurs se sont produites durant l'import models: project: feed_title: Projets Tracks @@ -238,21 +241,127 @@ fr: due_styles: - "Ech\xC3\xA9ance dans ____ jours" - "Ech\xC3\xA9ance le ____" - data: - import_successful: "L'import a r\xC3\xA9ussi." - import_errors: Des erreurs se sont produites durant l'import + stats: + totals_hidden_context_count: "et %{count} sont des contextes cach\xC3\xA9s." + actions_avg_created: "Dans les 12 derniers mois vous avez cr\xC3\xA9\xC3\xA9 une moyenne de %{count} actions" + actions_min_max_completion_days: "Le nombre max/min de jours pour r\xC3\xA9aliser est %{min}/%{max}." + totals_actions_completed: "dont %{count} sont r\xC3\xA9alis\xC3\xA9es." + tag_cloud_title: Nuage de tag pour toutes les actions + actions_actions_avg_created_30days: "Dans les 30 jours vous avez cr\xC3\xA9er en moyenne %{count} actions" + actions_avg_completed: "et r\xC3\xA9alis\xC3\xA9 une moyenne de %{count} actions par mois." + top5_visible_contexts_with_incomplete_actions: Top 5 des contextes visible avec des actions en cours + actions: Actions + totals_deferred_actions: "desquels %{count} sont des actions report\xC3\xA9s dans le Reporteur" + time_of_day_legend: + number_of_actions: Nombre d'actions + time_of_day: Heure + totals_incomplete_actions: Vous avez %{count} actions en cours + running_time_legend: + actions: Actions + percentage: Pourcentage + weeks: Temps en cours d'une action (en semaines). Cliquer sur une barre pour plus d'info + totals_action_count: vous avez un total de %{count} actions + tag_cloud_90days_title: Nuage de tag des actions des 90 derniers jours + tod30: Heure (30 derniers jours) + tags: Tags + projects: Projets + actions_avg_completion_time: "Pour toutes vos actions r\xC3\xA9alis\xC3\xA9s, le temps moyen de r\xC3\xA9alisation est %{count} jours." + labels: + month_avg_completed: "%{month} mois moy. r\xC3\xA9alis\xC3\xA9" + completed: !binary | + Q29tcGzDqXTDqQ== + + month_avg_created: "%{month} mois moy. cr\xC3\xA9\xC3\xA9" + avg_created: !binary | + TW95LiBDcsOpw6k= + + avg_completed: "Moy. R\xC3\xA9alis\xC3\xA9" + created: !binary | + Q3LDqcOp + + actions_selected_from_week: "Actions selectionn\xC3\xA9es depuis la semaine" + totals_completed_project_count: "et %{count} sont des projets r\xC3\xA9alis\xC3\xA9s." + actions_day_of_week_title: Jour de la semaine (toutes les actions) + actions_lastyear_title: Actions des 12 derniers mois + open_per_week: "Actifs (visibles et cach\xC3\xA9s) prochaines actions par semaine" + action_selection_title: TRACKS::Selection action + totals_project_count: Vous avez %{count} projets + current_running_time_of_incomplete_visible_actions: "Dur\xC3\xA9e en cours des actions incompl\xC3\xA8tes visibles" + legend: + number_of_days: Il y a ... jours + actions: Actions + number_of_actions: Nombre d'actions + day_of_week: Jour de la semaine + percentage: Pourcentage + running_time: Temps en cours d'une action (en semaines) + months_ago: Il y a ... mois + tod30_legend: + number_of_actions: Nombre d'actions + time_of_day: Heure + totals_context_count: Vous avez %{count} contextes. + open_per_week_legend: + actions: Actions + weeks: Semaines Il ya + actions_last_year_legend: + number_of_actions: Nombre d'actions + months_ago: "Mois pr\xC3\xA9c\xC3\xA9dents" + top10_projects: Top 10 des projets + top5_contexts: Top 5 des contextes + contexts: Contextes + totals: Totaux + click_to_return: "Cliquer %{link} pour revenir \xC3\xA0 la page des statistiques" + tag_cloud_90days_description: "Ce nuage de tag contient les tags des actions cr\xC3\xA9\xC3\xA9es ou r\xC3\xA9alis\xC3\xA9es dans les 90 derniers jours." + totals_visible_context_count: De ceux-ci %{count} sont des contextes visibles + top10_projects_30days: Top 10 des projets des 30 derniers jours + running_time_all: "Temps en cours de toutes les actions incompl\xC3\xA8tes" + actions_min_completion_time: "Le temps minimum de r\xC3\xA9alisation est %{time}." + action_completion_time_title: "Temps de r\xC3\xA9alisation (toutes les actions r\xC3\xA9alis\xC3\xA9es)" + click_to_show_actions_from_week: Cliquer %{link} pour voir les actions depuis la semaine %{week}. + top10_longrunning: Top 10 des plus long projets en cours + no_actions_selected: "Il n'y a pas d'actions s\xC3\xA9lectionn\xC3\xA9es." + totals_tag_count: Vous avez %{count} tags sur des actions. + actions_further: et plus + actions_dow_30days_legend: + number_of_actions: Certain nombre d'actions + day_of_week: Jour de la semaine + totals_first_action: "Depuis votre premi\xC3\xA8re action du %{date}" + tag_cloud_description: "Ce nuage de tags contient les tags de toutes les actions (r\xC3\xA9alis\xC3\xA9es, en cours, visibles ou cach\xC3\xA9es)" + click_to_return_link: ici + click_to_update_actions: Cliquer sur une barre du graphique pour mettre a jour les actions ci-dessous. + spread_of_actions_for_all_context: Vue des actions pour tous les contextes + more_stats_will_appear: Plus de statistiques apparaitront quand vous aurez ajouter quelques actions. + actions_avg_completed_30days: "et r\xC3\xA9alis\xC3\xA9 une moyenne de %{count} actions par jour." + no_tags_available: pas de tags disponibles + actions_30days_title: Actions des 30 derniers jours + index_title: TRACKS::Statistiques + actions_dow_30days_title: Jour de la semaine (les 30 derniers jours) + spread_of_running_actions_for_visible_contexts: Vue des actions en cours pour tous les contextes + actions_day_of_week_legend: + number_of_actions: Certain nombre d'actions + day_of_week: Jour de la semaine + actions_last_year: "Actions des derni\xC3\xA8res ann\xC3\xA9es" + totals_blocked_actions: "%{count} d\xC3\xA9pendent de la r\xC3\xA9alisation de leurs actions" + totals_unique_tags: De ces tags, %{count} sont uniques. + totals_active_project_count: De ceux-ci %{count} sont des projets actifs + running_time_all_legend: + actions: Actions + percentage: Pourcentage + running_time: Temps en cours d'une action (en semaines). Cliquer sur une barre pour plus d'info + other_actions_label: (autres) + time_of_day: Heure (toutes les actions) + totals_hidden_project_count: "%{count} sont cach\xC3\xA9s" todos: - recurring_action_deleted: "L'action a \xC3\xA9t\xC3\xA9 supprim\xC3\xA9e. Parce que cette action est r\xC3\xA9currente, une nouvelle action \xC3\xA0 \xC3\xA9t\xC3\xA9 ajout\xC3\xA9e" show_from: Afficher depuis error_starring_recurring: "Impossible d'actionner l'\xC3\xA9toile de la tache r\xC3\xA9currente \\'%{description}\\'" + recurring_action_deleted: "L'action a \xC3\xA9t\xC3\xA9 supprim\xC3\xA9e. Parce que cette action est r\xC3\xA9currente, une nouvelle action \xC3\xA0 \xC3\xA9t\xC3\xA9 ajout\xC3\xA9e" completed_actions: "Action compl\xC3\xA9t\xC3\xA9es" - added_new_next_action: "Nouvelle action suivante ajout\xC3\xA9e" - completed_recurring: "T\xC3\xA2ches reccurents compl\xC3\xA9t\xC3\xA9s" - completed_rest_of_previous_month: "Compl\xC3\xA9t\xC3\xA9 dans le reste du mois pr\xC3\xA9c\xC3\xA9dent" blocked_by: "Bloqu\xC3\xA9 par %{predecessors}" + completed_recurring: "T\xC3\xA2ches reccurents compl\xC3\xA9t\xC3\xA9s" + added_new_next_action: "Nouvelle action suivante ajout\xC3\xA9e" + completed_rest_of_previous_month: "Compl\xC3\xA9t\xC3\xA9 dans le reste du mois pr\xC3\xA9c\xC3\xA9dent" + defer_date_after_due_date: "La date de report est apr\xC3\xA8s la date d'\xC3\xA9ch\xC3\xA9ance. Veuillez ajuster la date d'\xC3\xA9cheance avant de reporter." star_action: Elire cette action completed_recurrence_completed: "Il n'y pas d'action suivante apr\xC3\xA8s l'action r\xC3\xA9currente que vous avez supprim\xC3\xA9e. La r\xC3\xA9currence est termin\xC3\xA9e" - defer_date_after_due_date: "La date de report est apr\xC3\xA8s la date d'\xC3\xA9ch\xC3\xA9ance. Veuillez ajuster la date d'\xC3\xA9cheance avant de reporter." unable_to_add_dependency: "Impossible d'ajouter la d\xC3\xA9pendance" done: "Termin\xC3\xA9 ?" star_action_with_description: Elire l'action '%{description}' @@ -261,21 +370,21 @@ fr: Q29tcGzDqXTDqQ== no_deferred_actions_with: "Pas d'actions report\xC3\xA9es avec le tag '%{tag_name}'" - action_due_on: "(action \xC3\xA0 terminer avant le %{date})" no_hidden_actions: "Il n'y a pas d'actions cach\xC3\xA9es actuellement" + action_due_on: "(action \xC3\xA0 terminer avant le %{date})" edit_action_with_description: Modifier l'action '%{description}' - list_incomplete_next_actions: "Liste les prochaines actions incompl\xC3\xA8tes" - tags: "Tags (s\xC3\xA9par\xC3\xA9s par des virgules)" archived_tasks_title: "TRACKS::T\xC3\xA2ches r\xC3\xA9alis\xC3\xA9es archiv\xC3\xA9es" remove_dependency: "Enlever les d\xC3\xA9pendances (l'action n'est pas supprim\xC3\xA9e)" + list_incomplete_next_actions: "Liste les prochaines actions incompl\xC3\xA8tes" + tags: "Tags (s\xC3\xA9par\xC3\xA9s par des virgules)" action_deleted_success: "L'action suivante \xC3\xA0 \xC3\xA9t\xC3\xA9 supprim\xC3\xA9e avec succ\xC3\xA8s" - context_changed: "Contexte chang\xC3\xA9 en %{name}" - new_related_todo_created: "Une nouvelle t\xC3\xA2che a \xC3\xA9t\xC3\xA9 ajout\xC3\xA9e qui appartient \xC3\xA0 cette t\xC3\xA2che r\xC3\xA9currente" - mobile_todos_page_title: Toutes les actions add_another_dependency: "Ajouter une autre d\xC3\xA9pendance" + new_related_todo_created: "Une nouvelle t\xC3\xA2che a \xC3\xA9t\xC3\xA9 ajout\xC3\xA9e qui appartient \xC3\xA0 cette t\xC3\xA2che r\xC3\xA9currente" + context_changed: "Contexte chang\xC3\xA9 en %{name}" + mobile_todos_page_title: Toutes les actions delete_recurring_action_title: "Supprimer l'action r\xC3\xA9currente" - removed_predecessor: "Suppression de %{successor} comme d\xC3\xA9pendance de %{predecessor}" recurring_actions_title: "TRACKS::Actions r\xC3\xA9currentes" + removed_predecessor: "Suppression de %{successor} comme d\xC3\xA9pendance de %{predecessor}" next_action_needed: Vous devez soumettre au moins une prochaine action action_saved: "Action sauvegard\xC3\xA9e" scheduled_overdue: "Programm\xC3\xA9e pour apparaitre il y a %{days} jours" @@ -283,41 +392,41 @@ fr: edit_action: Modifier action added_new_context: "Nouveau context ajout\xC3\xA9" next_actions_description: "Filtre:" - set_to_pending: "%{task} mise en attente" + older_completed_items: "Anciens \xC3\xA9l\xC3\xA9ments compl\xC3\xA9t\xC3\xA9s" list_incomplete_next_actions_with_limit: "Liste les %{count} derni\xC3\xA8res actions suivantes incompl\xC3\xA8tes" + set_to_pending: "%{task} mise en attente" added_new_project: "Nouveau projet ajout\xC3\xA9" next_actions_title_additions: completed: "Actions compl\xC3\xA9t\xC3\xA9es" due_today: "\xC3\xA9ch\xC3\xA9ance aujourd'hui" due_within_a_week: "\xC3\xA9ch\xC3\xA9ance dans la semaine" - older_completed_items: "Anciens \xC3\xA9l\xC3\xA9ments compl\xC3\xA9t\xC3\xA9s" - append_in_this_project: dans ce projet - edit_recurring_todo: "Modifier l'action r\xC3\xA9p\xC3\xA9tant" - error_deleting_item: "Il s'est produit une erreur lors de la suppression de l'\xC3\xA9l\xC3\xA9ment %{description}" task_list_title: "TRACKS::Lister les t\xC3\xA2ches" + edit_recurring_todo: "Modifier l'action r\xC3\xA9p\xC3\xA9tant" + append_in_this_project: dans ce projet + error_deleting_item: "Il s'est produit une erreur lors de la suppression de l'\xC3\xA9l\xC3\xA9ment %{description}" no_actions_due_this_week: "Pas actions \xC3\xA0 faire cette semaine" - no_recurring_todos: "Il n'y a pas de t\xC3\xA2ches r\xC3\xA9currentes actuellement" error_completing_todo: "Il s'est produit une erreur lors de l'execution de l'action r\xC3\xA9currente %{description}" + no_recurring_todos: "Il n'y a pas de t\xC3\xA2ches r\xC3\xA9currentes actuellement" recurring_pattern_removed: "La p\xC3\xA9riodicit\xC3\xA9 est retir\xC3\xA9 de %{count}" convert_to_project: Faire projet no_deferred_pending_actions: "Il n'y pas d'actions report\xC3\xA9es ou en attente actuellement" delete_recurring_action_confirm: "Etes-vous s\xC3\xBBr de vouloir supprimer l'action r\xC3\xA9currente '%{description'}?" completed_last_day: "Compl\xC3\xA9t\xC3\xA9 ces derni\xC3\xA8res 24 heures" - feed_title_in_context: dans le contexte '%{context}' - completed_more_than_x_days_ago: "Compl\xC3\xA9t\xC3\xA9 il y a plus de %{count} jours" + all_completed: "Toutes les actions r\xC3\xA9alis\xC3\xA9es" show_in_days: Afficher dans %{days} jours no_project: --Pas de projet-- error_saving_recurring: "Il s'est produit une erreur lors de la sauvegarde de la t\xC3\xA2che r\xC3\xA9currente \\'%{description}\\'" + completed_more_than_x_days_ago: "Compl\xC3\xA9t\xC3\xA9 il y a plus de %{count} jours" + feed_title_in_context: dans le contexte '%{context}' new_related_todo_created_short: "\xC3\xA0 cr\xC3\xA9\xC3\xA9 une nouvelle t\xC3\xA2che" - all_completed: "Toutes les actions r\xC3\xA9alis\xC3\xA9es" - pending: En attente - older_than_days: Plus ancien que %{count} jours - completed_tagged_page_title: "TRACKS::Les t\xC3\xA2ches termin\xC3\xA9es avec marquer %{tag_name}" edit: Modifier + completed_tagged_page_title: "TRACKS::Les t\xC3\xA2ches termin\xC3\xA9es avec marquer %{tag_name}" + older_than_days: Plus ancien que %{count} jours + pending: En attente completed_actions_with: "Action compl\xC3\xA9t\xC3\xA9es avec le tag %{tag_name}" + feed_title_in_project: dans le projet '%{project}' deleted_success: "Action supprim\xC3\xA9e avec succ\xC3\xA8s." completed_tasks_title: "TRACKS::T\xC3\xA2ches compl\xC3\xA9t\xC3\xA9es" - feed_title_in_project: dans le projet '%{project}' clear_due_date: "Effacer la date d'\xC3\xA9ch\xC3\xA9ance" error_removing_dependency: "Il s'est produit une erreur lors de la suppression de la d\xC3\xA9pendance" hidden_actions: "Actions cach\xC3\xA9es" @@ -327,13 +436,13 @@ fr: deferred_actions_with: "Action report\xC3\xA9es avec le tag '%{tag_name}'" confirm_delete: "Etes-vous s\xC3\xBBr de vouloir supprimer l'action '%{description}' ?" recurring_deleted_success: "L'action r\xC3\xA9currente a \xC3\xA9t\xC3\xA9 supprim\xC3\xA9e avec succ\xC3\xA8s." - no_completed_actions_with: "Pas d'actions compl\xC3\xA9t\xC3\xA9es avec le tag '%{tag_name}'" next_actions_title: Tracks - Prochaines Actions next_action_description: Description de la prochaine action deferred_tasks_title: TRACKS::Reporteur + no_completed_actions_with: "Pas d'actions compl\xC3\xA9t\xC3\xA9es avec le tag '%{tag_name}'" clear_show_from_date: Effacer show from date - unresolved_dependency: "La valeur saisie dans le champ d\xC3\xA9pendance ne correspond pas \xC3\xA0 une action existante. Cette valeur ne sera pas sauvegard\xC3\xA9e avec le reste de l'action. Continuer ?" calendar_page_title: TRACKS::Calendrier + unresolved_dependency: "La valeur saisie dans le champ d\xC3\xA9pendance ne correspond pas \xC3\xA0 une action existante. Cette valeur ne sera pas sauvegard\xC3\xA9e avec le reste de l'action. Continuer ?" in_hidden_state: "a l\\'\xC3\xA9tat cach\xC3\xA9" show_today: Afficher aujourd'hui no_actions_found_title: "Aucune action trouv\xC3\xA9e" @@ -344,30 +453,30 @@ fr: overdue_by_plural: "D\xC3\xA9pass\xC3\xA9e de %{days} jours" due_tomorrow: "Ech\xC3\xA9ance demain" completed_last_x_days: "Compl\xC3\xA9t\xC3\xA9 ces %{count} jours" + no_actions_with: "Il n'y pas d'actions incompl\xC3\xA8tes avec le tag '%{tag_name}' actuellement" defer_x_days: one: Reporter d'un jour other: Report de %{count} jours - no_actions_with: "Il n'y pas d'actions incompl\xC3\xA8tes avec le tag '%{tag_name}' actuellement" added_new_next_action_singular: "Nouvelle action suivante ajout\xC3\xA9e" no_completed_actions: "Il n'y a pas d'actions compl\xC3\xA9t\xC3\xA9es actuellement." + feeds: + completed: "Compl\xC3\xA9t\xC3\xA9 : %{date}" + due: "Ech\xC3\xA9ance : %{date}" deferred_pending_actions: "Actions report\xC3\xA9es ou en attente" has_x_pending: one: A une action en attente other: A %{count} actions en attente - feeds: - completed: "Compl\xC3\xA9t\xC3\xA9 : %{date}" - due: "Ech\xC3\xA9ance : %{date}" - error_deleting_recurring: "Il s'est produit une erreur lors de la suppression de la t\xC3\xA2che r\xC3\xA9currente \\'%{description}\\'" delete_action: Supprimer action + error_deleting_recurring: "Il s'est produit une erreur lors de la suppression de la t\xC3\xA2che r\xC3\xA9currente \\'%{description}\\'" recurring_todos: "T\xC3\xA2ches r\xC3\xA9currentes" delete: Supprimer - drag_action_title: "D\xC3\xA9placer sur une autre action pour la rendre d\xC3\xA9pendante de cette action" cannot_add_dependency_to_completed_todo: "Impossible d'ajouter cette action comme d\xC3\xA9pendance d'une action compl\xC3\xA9t\xC3\xA9e !" + drag_action_title: "D\xC3\xA9placer sur une autre action pour la rendre d\xC3\xA9pendante de cette action" no_last_completed_actions: "Aucune action achev\xC3\xA9e trouve" - depends_on: "D\xC3\xA9pend de" tickler_items_due: one: "Un \xC3\xA9l\xC3\xA9ment du reporteur est arriv\xC3\xA9 \xC3\xA0 \xC3\xA9ch\xC3\xA9ance - rafraichir la page pour le voir." other: "%{count} \xC3\xA9l\xC3\xA9ments du reporteur sont arriv\xC3\xA9s \xC3\xA0 \xC3\xA9ch\xC3\xA9ance - rafraichir la page pour les voir." + depends_on: "D\xC3\xA9pend de" action_marked_complete: "L'action '%{description}' a \xC3\xA9t\xC3\xA9 marqu\xC3\xA9e comme %{completed}" completed_today: one: "Vous avez compl\xC3\xA9t\xC3\xA9 une action aujourd'hui" @@ -375,6 +484,8 @@ fr: added_new_next_action_plural: "Nouvelles actions suivantes ajout\xC3\xA9es" new_related_todo_not_created_short: "n'a pas cr\xC3\xA9\xC3\xA9 la t\xC3\xA2che" completed_rest_of_week: "Compl\xC3\xA9t\xC3\xA9 dans le reste de cette semaine" + error_starring: "Impossible d'actionner l'\xC3\xA9toile de cette tache \\'%{description}\\'" + show_tomorrow: Afficher demain calendar: get_in_ical_format: Obtenir ce calendrier au format iCal due_next_week: "A r\xC3\xA9aliser la semaine prochaine" @@ -386,8 +497,8 @@ fr: no_actions_due_after_this_month: "Pas d'actions \xC3\xA0 r\xC3\xA9aliser apr\xC3\xA8s ce mois" no_actions_due_this_month: "Pas d'actions \xC3\xA0 terminer pour ce mois" due_this_month: "A r\xC3\xA9aliser avant la fin de %{month}" - show_tomorrow: Afficher demain - error_starring: "Impossible d'actionner l'\xC3\xA9toile de cette tache \\'%{description}\\'" + action_deferred: "L'action '%{description}' a \xC3\xA9t\xC3\xA9 report\xC3\xA9" + added_dependency: "%{dependency} ajout\xC3\xA9e comme d\xC3\xA9pendance" recurrence: ends_on_number_times: Fini au bout de %{number} fois ends_on_date: Fini le %{date} @@ -400,8 +511,8 @@ fr: starts_on: "D\xC3\xA9marre le" daily_options: "Param\xC3\xA8tres des actions r\xC3\xA9currentes quotidiennes" show_option_always: toujours + daily: Quotidiennement pattern: - third: "troisi\xC3\xA8me" month_names: - - Janvier @@ -416,19 +527,18 @@ fr: - Octobre - Novembre - "D\xC3\xA9cembre" + third: "troisi\xC3\xA8me" every_n: tous les %{n} second: seconde every_xth_day_of_every_n_months: tous les %{x} %{day} tous les %{n_months} on_day_n: le %{n}e jour - weekly: Toutes les semaines from: de + weekly: Toutes les semaines every_day: chaque jour last: dernier the_xth_day_of_month: le %{x} %{day} de %{month} times: pour %{number} fois - on_work_days: "les jours ouvr\xC3\xA9s" every_year_on: "chaque ann\xC3\xA9e le %{date}" - first: premier day_names: - Dimanche - Lundi @@ -438,41 +548,40 @@ fr: - Vendredi - Samedi show: montrer + first: premier + on_work_days: "les jours ouvr\xC3\xA9s" fourth: "quatri\xC3\xA8me" due: "Ech\xC3\xA9ance" - every_month: chaque mois until: jusqu'a - daily: Quotidiennement - yearly_every_x_day: Chaque %{month} %{day} + every_month: chaque mois recurrence_on_options: "Activer la r\xC3\xA9currence" + yearly_every_x_day: Chaque %{month} %{day} daily_every_number_day: Tous les %{number} jour(s) - show_options: "Montrer la t\xC3\xA2che" ends_on: Fini le + show_options: "Montrer la t\xC3\xA2che" weekly_every_number_week: Returns every %{number} week on - yearly_every_xth_day: Chaque %{day} %{day_of_week} de %{month} - yearly_options: "Param\xC3\xA8tres pour les actions r\xC3\xA9currentes annuelles" show_days_before: "%{days} jours avant la date d'\xC3\xA9ch\xC3\xA9ance de la t\xC3\xA2che" + yearly_every_xth_day: Chaque %{day} %{day_of_week} de %{month} from_tickler: "la date de la t\xC3\xA2che provient du reporteur (pas de date d\\'\xC3\xA9ch\xC3\xA9ance d\xC3\xA9finie)" no_end_date: Pas de date de fin day_x_on_every_x_month: Le %{day} tous les %{month} mois - yearly: Tous les ans + yearly_options: "Param\xC3\xA8tres pour les actions r\xC3\xA9currentes annuelles" monthly_every_xth_day: Le %{day} %{day_of_week} tous les %{month} mois - action_deferred: "L'action '%{description}' a \xC3\xA9t\xC3\xA9 report\xC3\xA9" + yearly: Tous les ans tagged_page_title: "TRACKS::Tagg\xC3\xA9 avec %{tag_name}'" no_completed_recurring: "Il n'y a pas d'actions r\xC3\xA9currentes compl\xC3\xA9t\xC3\xA9es actuellement" - added_dependency: "%{dependency} ajout\xC3\xA9e comme d\xC3\xA9pendance" completed_rest_of_month: "Compl\xC3\xA9t\xC3\xA9 dans le reste de ce mois-ci" - no_deferred_actions: "Il n'y a pas d'actions report\xC3\xA9es actuellement" - all_completed_tagged_page_title: "TRACKS::Toutes les t\xC3\xA2ches accomplies par marquer %{tag_name}" recurrence_completed: "Il n'y a pas d'action suivante apr\xC3\xA8s l'action r\xC3\xA9currente que vous venez de terminer. Fin de la r\xC3\xA9currence" - no_actions_found: "Il n'y pas d'actions incompl\xC3\xA8tes actuellement." + all_completed_tagged_page_title: "TRACKS::Toutes les t\xC3\xA2ches accomplies par marquer %{tag_name}" + no_deferred_actions: "Il n'y a pas d'actions report\xC3\xA9es actuellement" in_pending_state: en attente + no_actions_found: "Il n'y pas d'actions incompl\xC3\xA8tes actuellement." error_toggle_complete: "Impossible de marquer cette tache comme compl\xC3\xA9t\xC3\xA9e" due: "Ech\xC3\xA9ance" action_marked_complete_error: "L'action '%{description}' n'a PAS \xC3\xA9t\xC3\xA9 marqu\xC3\xA9e comme %{completed} a cause d'une erreur sur le serveur " - action_saved_to_tickler: "Action sauvegard\xC3\xA9e dans le Reporteur" depends_on_separate_with_commas: "D\xC3\xA9pend de (s\xC3\xA9parer avec des virgules)" recurring_action_saved: "Action r\xC3\xA9currente sauv\xC3\xA9e" + action_saved_to_tickler: "Action sauvegard\xC3\xA9e dans le Reporteur" completed_in_archive: one: "Il n'y a pas d'action compl\xC3\xA9t\xC3\xA9e dans l'archive" other: "Il y a %{count} actions compl\xC3\xA9t\xC3\xA9es dans l'archive" @@ -483,108 +592,10 @@ fr: overdue: En retard add_new_recurring: "Ajouter une nouvelle action r\xC3\xA9currente" no_incomplete_actions: "Il n'y a pas d'actions incompl\xC3\xA8tes" - stats: - tag_cloud_title: Nuage de tag pour toutes les actions - tag_cloud_description: "Ce nuage de tags contient les tags de toutes les actions (r\xC3\xA9alis\xC3\xA9es, en cours, visibles ou cach\xC3\xA9es)" - actions: Actions - tag_cloud_90days_title: Nuage de tag des actions des 90 derniers jours - totals_active_project_count: De ceux-ci %{count} sont des projets actifs - actions_last_year_legend: - number_of_actions: Nombre d'actions - months_ago: "Mois pr\xC3\xA9c\xC3\xA9dents" - totals_first_action: "Depuis votre premi\xC3\xA8re action du %{date}" - actions_avg_completion_time: "Pour toutes vos actions r\xC3\xA9alis\xC3\xA9s, le temps moyen de r\xC3\xA9alisation est %{count} jours." - totals_deferred_actions: "desquels %{count} sont des actions report\xC3\xA9s dans le Reporteur" - current_running_time_of_incomplete_visible_actions: "Dur\xC3\xA9e en cours des actions incompl\xC3\xA8tes visibles" - top10_longrunning: Top 10 des plus long projets en cours - totals_action_count: vous avez un total de %{count} actions - actions_dow_30days_title: Jour de la semaine (les 30 derniers jours) - legend: - actions: Actions - number_of_days: Il y a ... jours - number_of_actions: Nombre d'actions - day_of_week: Jour de la semaine - percentage: Pourcentage - running_time: Temps en cours d'une action (en semaines) - months_ago: Il y a ... mois - running_time_legend: - actions: Actions - percentage: Pourcentage - weeks: Temps en cours d'une action (en semaines). Cliquer sur une barre pour plus d'info - top5_contexts: Top 5 des contextes - actions_lastyear_title: Actions des 12 derniers mois - totals_actions_completed: "dont %{count} sont r\xC3\xA9alis\xC3\xA9es." - totals_incomplete_actions: Vous avez %{count} actions en cours - totals_unique_tags: De ces tags, %{count} sont uniques. - actions_avg_completed_30days: "et r\xC3\xA9alis\xC3\xA9 une moyenne de %{count} actions par jour." - totals_blocked_actions: "%{count} d\xC3\xA9pendent de la r\xC3\xA9alisation de leurs actions" - action_completion_time_title: "Temps de r\xC3\xA9alisation (toutes les actions r\xC3\xA9alis\xC3\xA9es)" - projects: Projets - actions_last_year: "Actions des derni\xC3\xA8res ann\xC3\xA9es" - totals_context_count: Vous avez %{count} contextes. - totals_visible_context_count: De ceux-ci %{count} sont des contextes visibles - actions_min_max_completion_days: "Le nombre max/min de jours pour r\xC3\xA9aliser est %{min}/%{max}." - actions_min_completion_time: "Le temps minimum de r\xC3\xA9alisation est %{time}." - tags: Tags - no_tags_available: pas de tags disponibles - actions_day_of_week_title: Jour de la semaine (toutes les actions) - totals_project_count: Vous avez %{count} projets - totals_hidden_project_count: "%{count} sont cach\xC3\xA9s" - tag_cloud_90days_description: "Ce nuage de tag contient les tags des actions cr\xC3\xA9\xC3\xA9es ou r\xC3\xA9alis\xC3\xA9es dans les 90 derniers jours." - top5_visible_contexts_with_incomplete_actions: Top 5 des contextes visible avec des actions en cours - actions_30days_title: Actions des 30 derniers jours - time_of_day: Heure (toutes les actions) - more_stats_will_appear: Plus de statistiques apparaitront quand vous aurez ajouter quelques actions. - actions_further: et plus - tod30: Heure (30 derniers jours) - running_time_all: "Temps en cours de toutes les actions incompl\xC3\xA8tes" - totals_tag_count: Vous avez %{count} tags sur des actions. - other_actions_label: (autres) - top10_projects_30days: Top 10 des projets des 30 derniers jours - spread_of_running_actions_for_visible_contexts: Vue des actions en cours pour tous les contextes - click_to_show_actions_from_week: Cliquer %{link} pour voir les actions depuis la semaine %{week}. - actions_avg_created: "Dans les 12 derniers mois vous avez cr\xC3\xA9\xC3\xA9 une moyenne de %{count} actions" - spread_of_actions_for_all_context: Vue des actions pour tous les contextes - click_to_return: "Cliquer %{link} pour revenir \xC3\xA0 la page des statistiques" - actions_selected_from_week: "Actions selectionn\xC3\xA9es depuis la semaine" - totals_completed_project_count: "et %{count} sont des projets r\xC3\xA9alis\xC3\xA9s." - top10_projects: Top 10 des projets - totals: Totaux - time_of_day_legend: - number_of_actions: Nombre d'actions - time_of_day: Heure - click_to_return_link: ici - totals_hidden_context_count: "et %{count} sont des contextes cach\xC3\xA9s." - contexts: Contextes - actions_avg_completed: "et r\xC3\xA9alis\xC3\xA9 une moyenne de %{count} actions par mois." - no_actions_selected: "Il n'y a pas d'actions s\xC3\xA9lectionn\xC3\xA9es." - click_to_update_actions: Cliquer sur une barre du graphique pour mettre a jour les actions ci-dessous. - labels: - month_avg_completed: "%{month} mois moy. r\xC3\xA9alis\xC3\xA9" - completed: !binary | - Q29tcGzDqXTDqQ== - - month_avg_created: "%{month} mois moy. cr\xC3\xA9\xC3\xA9" - avg_created: !binary | - TW95LiBDcsOpw6k= - - avg_completed: "Moy. R\xC3\xA9alis\xC3\xA9" - created: !binary | - Q3LDqcOp - - running_time_all_legend: - actions: Actions - percentage: Pourcentage - running_time: Temps en cours d'une action (en semaines). Cliquer sur une barre pour plus d'info - tod30_legend: - number_of_actions: Nombre d'actions - time_of_day: Heure - action_selection_title: TRACKS::Selection action - actions_actions_avg_created_30days: "Dans les 30 jours vous avez cr\xC3\xA9er en moyenne %{count} actions" notes: + delete_note_title: Supprimer la note '%{id}' delete_confirmation: Etes-vous sur de vouloir supprimer la note '%{id}' ? delete_item_title: "Supprimer l'\xC3\xA9l\xC3\xA9ment" - delete_note_title: Supprimer la note '%{id}' deleted_note: Supprimer la note '%{id}' note_link_title: Voir note %{id} show_note_title: Voir note @@ -598,91 +609,91 @@ fr: review_plural: !binary | RGF0w6ll - completed: "Complet\xC3\xA9" stalled: "Bloqu\xC3\xA9s" + completed: "Complet\xC3\xA9" current: Up-to-date - completed_plural: "Complet\xC3\xA9s" review: !binary | RGF0w6ll - blocked: "Bloqu\xC3\xA9e" + completed_plural: "Complet\xC3\xA9s" blocked_plural: "Bloqu\xC3\xA9e" + blocked: "Bloqu\xC3\xA9e" stalled_plural: "Bloqu\xC3\xA9s" visible_plural: Visibles - visible: Visible active_plural: Actifs + visible: Visible current_plural: Up-to-date - active: Actif hidden: !binary | Q2FjaMOp + active: Actif + errors: + user_unauthorized: "401 Non autoris\xC3\xA9: Administrateur seulement." projects: + no_actions_in_project: "Il n'y pas d'action incompl\xC3\xA8tes pour ce projet" + deferred_actions: "Actions report\xC3\xA9es pour ce projet" was_marked_hidden: "est cach\xC3\xA9" edit_project_title: Editer le projet default_tags_removed_notice: Supprimer les tags par defaut default_context_set: "D\xC3\xA9finir le contexte par d\xC3\xA9faut du projet \xC3\xA0 %{default_context}" - no_actions_in_project: "Il n'y pas d'action incompl\xC3\xA8tes pour ce projet" - deferred_actions: "Actions report\xC3\xA9es pour ce projet" - all_completed_tasks_title: "TRACKS::Tous les Actions Achev\xC3\xA9 en Projet '%{project_name}'" hide_form: Cacher le formulaire page_title: "TRACKS::Projet: %{project}" - show_form_title: "Cr\xC3\xA9er un nouveau projet" - this_project: Ce projet + all_completed_tasks_title: "TRACKS::Tous les Actions Achev\xC3\xA9 en Projet '%{project_name}'" project_state: Le projet est %{state} list_completed_projects: "TRACKS::Liste des projets achev\xC3\xA9s" to_new_project_page: "Aller \xC3\xA0 la page du nouveau projet" no_notes_attached: "Il n'y a actuellement aucune note attach\xC3\xA9e \xC3\xA0 ce projet" + show_form_title: "Cr\xC3\xA9er un nouveau projet" deferred_actions_empty: "Il n'y a pas d'actions report\xC3\xA9es pour ce projet" - notes: Notes + this_project: Ce projet no_last_completed_recurring_todos: "Non termin\xC3\xA9 actions r\xC3\xA9p\xC3\xA9titives trouv\xC3\xA9es" todos_append: dans ce projet no_last_completed_projects: "Pas de projets termin\xC3\xA9s trouv\xC3\xA9s" + notes: Notes hide_form_title: Cacher le formulaire nouveau projet list_reviews: TRACKS::Revue notes_empty: Il n'y a pas de notes pour ce projet no_projects: Il n'y a actuellement aucun projet - delete_project: Supprimer projet completed_actions_empty: "Il n'y a pas d'actions r\xC3\xA9alis\xC3\xA9es pour ce projet" with_no_default_context: "sans contexte par d\xC3\xA9faut" + delete_project: Supprimer projet show_form: Ajouter un projet actions_in_project_title: Actions pour ce projet delete_project_confirmation: "Etes vous s\xC3\xBBr de vouloir supprimer le projet '%{name}' ?" with_default_context: "avec '%{context_name}' comme contexte par d\xC3\xA9faut" - with_default_tags: et avec '%{tags'} comme tags par defaut - is_active: est actif set_default_tags_notice: "D\xC3\xA9finir les tags par d\xC3\xA9faut du projet \xC3\xA0 %{default_tags}" completed_projects: "Projets r\xC3\xA9alis\xC3\xA9s" add_note: Ajouter une note add_project: Ajouter projet - list_projects: TRACKS::Liste des Projets settings: "Param\xC3\xA8tres" + with_default_tags: et avec '%{tags'} comme tags par defaut + list_projects: TRACKS::Liste des Projets + is_active: est actif project_saved_status: "Projet sauvegard\xC3\xA9" - completed_tasks_title: "TRACKS::Liste des actions men\xC3\xA9es \xC3\xA0 terme dans Projet '%{project_name}'" delete_project_title: Supprimer le projet hidden_projects: "Projets cach\xC3\xA9s" - add_note_submit: Ajouter note - was_marked_complete: "est compl\xC3\xA9t\xC3\xA9" + completed_tasks_title: "TRACKS::Liste des actions men\xC3\xA9es \xC3\xA0 terme dans Projet '%{project_name}'" default_context_removed: "Contexte par d\xC3\xA9faut supprim\xC3\xA9" completed_actions: "Actions r\xC3\xA9alis\xC3\xA9es pour ce projet" - default_context: "Le contexte par d\xC3\xA9faut pour ce projet est %{context}" - active_projects: Projets actifs + add_note_submit: Ajouter note + was_marked_complete: "est compl\xC3\xA9t\xC3\xA9" no_default_context: Ce projet n'a pas de contexte par defaut with_no_default_tags: "et sans tags par d\xC3\xA9faut" - state: Le projet est %{state} edit_project_settings: "Modifier les param\xC3\xA8tres du projet" status_project_name_changed: "Le nom du projet a \xC3\xA9t\xC3\xA9 modifi\xC3\xA9" - errors: - user_unauthorized: "401 Non autoris\xC3\xA9: Administrateur seulement." + state: Le projet est %{state} + default_context: "Le contexte par d\xC3\xA9faut pour ce projet est %{context}" + active_projects: Projets actifs preferences: + change_identity_url: "Modifier votre URL d'identit\xC3\xA9" open_id_url: Votre URL OpenID est staleness_starts_after: "\"date de fraicher\" d\xC3\xA9pass\xC3\xA9e \xC3\xA0 pr\xC3\xA8s %{days} days" - change_identity_url: "Modifier votre URL d'identit\xC3\xA9" - page_title: "TRACKS::Pr\xC3\xA9f\xC3\xA9rences" change_password: Modifier votre mot de passe + page_title: "TRACKS::Pr\xC3\xA9f\xC3\xA9rences" token_description: Jeton (pour flux et utilisation API) title: "Vos pr\xC3\xA9f\xC3\xA9rences" - show_number_completed: "Montrer %{number} items r\xC3\xA9alis\xC3\xA9s" is_false: faux + show_number_completed: "Montrer %{number} items r\xC3\xA9alis\xC3\xA9s" page_title_edit: "TRACKS::Editer les pr\xC3\xA9f\xC3\xA9rences" is_true: vrai password_changed: "Votre mot de passe a \xC3\xA9t\xC3\xA9 chang\xC3\xA9, s'il vous pla\xC3\xAEt vous connecter \xC3\xA0 nouveau." @@ -690,14 +701,14 @@ fr: generate_new_token: "G\xC3\xA9n\xC3\xA9rer un nouveau jeton" sms_context_none: Aucun token_header: Votre jeton + authentication_header: Votre authentification updated: "Pr\xC3\xA9f\xC3\xA9rences jour" current_authentication_type: Votre type d'authentification est %{auth_type} change_authentication_type: Modifier votre type d'authentification - authentication_header: Votre authentification generate_new_token_confirm: "Etes vous s\xC3\xBBr ? G\xC3\xA9n\xC3\xA9rer un nouveau jeton va remplacer le jeton existant et en interdire les utilisations externes." tabs: - authentication: Authentification tracks_behavior: Comportements Tracks + authentication: Authentification profile: Profil date_and_time: Date et heure time: @@ -724,10 +735,6 @@ fr: - octobre - novembre - "d\xC3\xA9cembre" - order: - - :day - - :month - - :year abbr_day_names: - dim - lun @@ -736,6 +743,10 @@ fr: - jeu - ven - sam + order: + - :day + - :month + - :year formats: only_day: "%e" longer: "%A, %d %b %Y" @@ -767,13 +778,6 @@ fr: - oct. - nov. - d\xC3\xA9c. - support: - array: - words_connector: "," - last_word_connector: ", et" - two_words_connector: et - select: - prompt: "Veuillez s\xC3\xA9lectionner" will_paginate: previous_label: !binary | wqtQcsOpY8OpZGVudA== @@ -791,23 +795,126 @@ fr: multi_page_html: "Affiche %{model} %{from} - %{to} \xC3\xA0 la %{count} au total" page_gap: ... next_label: "Suivant \xC2\xBB" - footer: - send_feedback: Envoyer un feedback sur %{version} + support: + array: + words_connector: "," + last_word_connector: ", et" + two_words_connector: et + select: + prompt: "Veuillez s\xC3\xA9lectionner" shared: multiple_next_actions: Actions suivante multiples (une sur chaque ligne) - hide_form: Cacher le formulaire make_actions_dependent: "Faire actions d\xC3\xA9pendantes les unes des autres" + hide_form: Cacher le formulaire toggle_single: Ajouter action suivante add_actions: Ajouter actions add_action: Ajouter action tags_for_all_actions: Tags pour toutes les actions (sep. avec des virgules) - context_for_all_actions: Contexte pour toutes les actions toggle_multi: Ajouter plusieurs actions suivantes toggle_single_title: Ajouter une nouvelle action suivante project_for_all_actions: Projet pour toutes les actions + context_for_all_actions: Contexte pour toutes les actions separate_tags_with_commas: "s\xC3\xA9parer avec des virgules" toggle_multi_title: Basculer formulaire action simple/multiple hide_action_form_title: Cacher le formulaire nouvelle action + footer: + send_feedback: Envoyer un feedback sur %{version} + feedlist: + actions_due_today: Actions devant se terminer aujourd'hui ou avant + choose_context: Choisir le contexte dont vous voulez un flux + rss_feed: Flux RSS + legend: "L\xC3\xA9gende" + ical_feed: Flux iCal + all_contexts: Tous les contextes + all_projects: Tous les projets + choose_project: Choisir le projet dont vous voulez un flux + project_needed: Il faut au moins un projet pour le flux + select_feed_for_project: Selectionner le flux pour ce projet + active_projects_wo_next: Projets actifs avec aucune action suivante + active_starred_actions: "Toutes les actions pr\xC3\xA9ferr\xC3\xA9es actives" + context_needed: Il faut au moins un contexte pour le flux + select_feed_for_context: Selectionner un flux pour ce contexte + projects_and_actions: Projets actifs et leurs actions + actions_due_next_week: Actions devant se terminer dans les 7 prochains jours ou moins + notice_incomplete_only: "NB: Les flux ne montrent que les actions incompl\xC3\xA8tes, sauf indication contraire" + last_fixed_number: "Derni\xC3\xA8res %{number} actions" + all_actions: Toutes les actions + actions_completed_last_week: "Actions r\xC3\xA9alis\xC3\xA9es dans les 7 derniers jours" + context_centric_actions: "Flux des actions dans un contexte sp\xC3\xA9cifique" + plain_text_feed: Flux texte + project_centric: "Flux des actions incompl\xC3\xA8tes d'un projet sp\xC3\xA9cifique" + users: + successfully_deleted_user: "Utilisateur %{username} supprim\xC3\xA9 avec succ\xC3\xA8s" + failed_to_delete_user: "La suppression de l'utilisateur {username} \xC3\xA0 \xC3\xA9chou\xC3\xA9" + destroy_successful: "Utilisateur %{login} supprim\xC3\xA9 avec succ\xC3\xA8s" + total_contexts: Total contextes + openid_url_verified: "Vous avez v\xC3\xA9rifi\xC3\xA9 avec succ\xC3\xA8s votre identit\xC3\xA9 comme %{url} et d\xC3\xA9fini votre type authentification comme OpenID" + first_user_heading: "Bienvenu \xC3\xA0 TRAKS. Pour commencer, veuillez cr\xC3\xA9er un compte administrateur" + auth_type_update_error: "Un probl\xC3\xA8me est survenu lors de la modification du type d'authentification : %{error_messages}" + new_token_generated: "Nouveau token g\xC3\xA9n\xC3\xA9r\xC3\xA9 avec succ\xC3\xA9s" + total_projects: Total projets + signup_successful: "Utilisateur %{username} cr\xC3\xA9\xC3\xA9 avec succ\xC3\xA8s." + no_signups_title: TRACKS::Pas de signups + user_created: "Utilisateur cr\xC3\xA9\xC3\xA9." + change_password_submit: Modifier mot de passe + account_signup: "Cr\xC3\xA9er un compte" + manage_users: "G\xC3\xA9rer utilisateurs" + password_updated: "Mot de passe modifi\xC3\xA9." + auth_type_updated: "Type d'authentification modifi\xC3\xA9." + total_actions: Total actions + desired_login: "Login souhait\xC3\xA9" + signup: "Cr\xC3\xA9ation" + confirm_password: Confirmer le mot de passe + new_user_heading: "Cr\xC3\xA9er un nouvel utilisateur:" + change_password_prompt: Entrer votre nouveau mot de passe dans les champs ci-dessous et cliquer sur 'Modifier mot de passe' pour remplacer votre mot de passe actuel par le nouveau. + password_confirmation_label: Confirmer mot de passe + destroy_error: Une erreur s'est produite lors de la suppression de l'utilisateur %{login} + choose_password: Choisir le mot de passe + change_password_title: TRACKS::Modifier mot de passe + change_auth_type_title: TRACKS::Modifier le type d'authentification + new_password_label: Nouveau mot de passe + register_with_cas: Avec votre nom d'utilisateur CAS + label_auth_type: Type d'authentification + new_user_title: "TRACKS::Cr\xC3\xA9er un administrateur" + destroy_user: Supprimer utilisateur + total_users_count: Vous avez %{count} utilisateurs + you_have_to_reset_your_password: "Vous devez r\xC3\xA9initialiser votre mot de passe" + signup_new_user: "Cr\xC3\xA9er un nouvel utilisateur" + destroy_confirmation: "Attention : cela va supprimer l'utilisateur '%{login}', toutes ses actions, contextes, projets et notes. Etes-vous s\xC3\xBBr de vouloir continuer ?" + identity_url: "URL Identit\xC3\xA9" + openid_ok_pref_failed: "Vous avez v\xC3\xA9rifi\xC3\xA9 avec succ\xC3\xA8s votre identit\xC3\xA9 comme %{url} mais un probl\xC3\xA8me est survenu lors de la sauvegarde de vos pr\xC3\xA9f\xC3\xA9rences d'authentification." + change_authentication_type: Modifier le type d'authentification + auth_change_submit: Modifier le type d'authenfication + select_authentication_type: "S\xC3\xA9lectionner votre nouveau type d'authentification et cliquer sur 'Modifier type d'authenfication' pour remplacer les param\xC3\xA8tres actuels." + total_notes: Total notes + contexts: + delete_context_title: Supprimer contexte + hide_form: Cacher le formulaire + all_completed_tasks_title: "TRACKS::Toutes les actions Achev\xC3\xA9 en le contexte '%{context_name}'" + show_form_title: Ajouter un contexte + delete_context_confirmation: "Etes vous s\xC3\xBBr de vouloir supprimer le contexte %{name}? Toutes les actions (r\xC3\xA9p\xC3\xA9titives) de ce contexte seront \xC3\xA9galement supprim\xC3\xA9es !" + todos_append: dans ce contexte + delete_context: Supprimer contexte + edit_context: Modifier contexte + hide_form_title: Cacher le formulaire nouveau contexte + context_hide: "Cach\xC3\xA9 de la premi\xC3\xA8re page ?" + hidden_contexts: "Contextes cach\xC3\xA9s" + no_contexts_active: Actuellement, il n'y a pas de contextes actifs + show_form: "Cr\xC3\xA9er un nouveau contexte" + visible_contexts: Contextes visibles + save_status_message: "Contexte sauvegard\xC3\xA9" + add_context: Ajouter un contexte + update_status_message: "Le nom du contexte \xC3\xA0 \xC3\xA9t\xC3\xA9 modifi\xC3\xA9" + context_name: Nom du Contexte + status_active: Le Contexte est actif + completed_tasks_title: "TRACKS::actions Achev\xC3\xA9 en le contexte '%{context_name}'" + new_context_post: "'sera aussi cr\xC3\xA9\xC3\xA9. Etes-vous s\xC3\xBBr ?" + no_actions: "Actuellement, il n'y pas d'actions incompl\xC3\xA8tes dans ce contexte" + last_completed_in_context: dans ce contexte (dernier %{number}) + context_deleted: "Contexte \\'%{name}\\' supprim\xC3\xA9" + no_contexts_hidden: "Actuellement, il n'y a pas de contextes cach\xC3\xA9s" + new_context_pre: Nouveau contexte ' + status_hidden: "Le Contexte est cach\xC3\xA9" sidebar: list_name_active_contexts: Contextes actifs list_name_active_projects: Projets actifs @@ -815,101 +922,31 @@ fr: list_name_completed_projects: "Projets r\xC3\xA9alis\xC3\xA9s" list_name_hidden_projects: "Projets cach\xC3\xA9s" list_name_hidden_contexts: "Contextes cach\xC3\xA9s" - users: - successfully_deleted_user: "Utilisateur %{username} supprim\xC3\xA9 avec succ\xC3\xA8s" - destroy_successful: "Utilisateur %{login} supprim\xC3\xA9 avec succ\xC3\xA8s" - total_contexts: Total contextes - openid_url_verified: "Vous avez v\xC3\xA9rifi\xC3\xA9 avec succ\xC3\xA8s votre identit\xC3\xA9 comme %{url} et d\xC3\xA9fini votre type authentification comme OpenID" - first_user_heading: "Bienvenu \xC3\xA0 TRAKS. Pour commencer, veuillez cr\xC3\xA9er un compte administrateur" - auth_type_update_error: "Un probl\xC3\xA8me est survenu lors de la modification du type d'authentification : %{error_messages}" - failed_to_delete_user: "La suppression de l'utilisateur {username} \xC3\xA0 \xC3\xA9chou\xC3\xA9" - new_token_generated: "Nouveau token g\xC3\xA9n\xC3\xA9r\xC3\xA9 avec succ\xC3\xA9s" - total_projects: Total projets - signup_successful: "Utilisateur %{username} cr\xC3\xA9\xC3\xA9 avec succ\xC3\xA8s." - change_password_submit: Modifier mot de passe - no_signups_title: TRACKS::Pas de signups - user_created: "Utilisateur cr\xC3\xA9\xC3\xA9." - manage_users: "G\xC3\xA9rer utilisateurs" - account_signup: "Cr\xC3\xA9er un compte" - password_updated: "Mot de passe modifi\xC3\xA9." - confirm_password: Confirmer le mot de passe - new_user_heading: "Cr\xC3\xA9er un nouvel utilisateur:" - signup: "Cr\xC3\xA9ation" - auth_type_updated: "Type d'authentification modifi\xC3\xA9." - total_actions: Total actions - desired_login: "Login souhait\xC3\xA9" - choose_password: Choisir le mot de passe - change_password_title: TRACKS::Modifier mot de passe - change_auth_type_title: TRACKS::Modifier le type d'authentification - change_password_prompt: Entrer votre nouveau mot de passe dans les champs ci-dessous et cliquer sur 'Modifier mot de passe' pour remplacer votre mot de passe actuel par le nouveau. - password_confirmation_label: Confirmer mot de passe - destroy_error: Une erreur s'est produite lors de la suppression de l'utilisateur %{login} - new_password_label: Nouveau mot de passe - register_with_cas: Avec votre nom d'utilisateur CAS - label_auth_type: Type d'authentification - new_user_title: "TRACKS::Cr\xC3\xA9er un administrateur" - destroy_user: Supprimer utilisateur - total_users_count: Vous avez %{count} utilisateurs - destroy_confirmation: "Attention : cela va supprimer l'utilisateur '%{login}', toutes ses actions, contextes, projets et notes. Etes-vous s\xC3\xBBr de vouloir continuer ?" - you_have_to_reset_your_password: "Vous devez r\xC3\xA9initialiser votre mot de passe" - signup_new_user: "Cr\xC3\xA9er un nouvel utilisateur" - openid_ok_pref_failed: "Vous avez v\xC3\xA9rifi\xC3\xA9 avec succ\xC3\xA8s votre identit\xC3\xA9 comme %{url} mais un probl\xC3\xA8me est survenu lors de la sauvegarde de vos pr\xC3\xA9f\xC3\xA9rences d'authentification." - change_authentication_type: Modifier le type d'authentification - auth_change_submit: Modifier le type d'authenfication - identity_url: "URL Identit\xC3\xA9" - select_authentication_type: "S\xC3\xA9lectionner votre nouveau type d'authentification et cliquer sur 'Modifier type d'authenfication' pour remplacer les param\xC3\xA8tres actuels." - total_notes: Total notes - contexts: - delete_context_title: Supprimer contexte - all_completed_tasks_title: "TRACKS::Toutes les actions Achev\xC3\xA9 en le contexte '%{context_name}'" - hide_form: Cacher le formulaire - show_form_title: Ajouter un contexte - delete_context_confirmation: "Etes vous s\xC3\xBBr de vouloir supprimer le contexte %{name}? Toutes les actions (r\xC3\xA9p\xC3\xA9titives) de ce contexte seront \xC3\xA9galement supprim\xC3\xA9es !" - delete_context: Supprimer contexte - hide_form_title: Cacher le formulaire nouveau contexte - edit_context: Modifier contexte - hidden_contexts: "Contextes cach\xC3\xA9s" - no_contexts_active: Actuellement, il n'y a pas de contextes actifs - context_hide: "Cach\xC3\xA9 de la premi\xC3\xA8re page ?" - show_form: "Cr\xC3\xA9er un nouveau contexte" - visible_contexts: Contextes visibles - save_status_message: "Contexte sauvegard\xC3\xA9" - add_context: Ajouter un contexte - update_status_message: "Le nom du contexte \xC3\xA0 \xC3\xA9t\xC3\xA9 modifi\xC3\xA9" - context_name: Nom du Contexte - completed_tasks_title: "TRACKS::actions Achev\xC3\xA9 en le contexte '%{context_name}'" - status_active: Le Contexte est actif - new_context_post: "'sera aussi cr\xC3\xA9\xC3\xA9. Etes-vous s\xC3\xBBr ?" - context_deleted: "Contexte \\'%{name}\\' supprim\xC3\xA9" - no_contexts_hidden: "Actuellement, il n'y a pas de contextes cach\xC3\xA9s" - new_context_pre: Nouveau contexte ' - no_actions: "Actuellement, il n'y pas d'actions incompl\xC3\xA8tes dans ce contexte" - last_completed_in_context: dans ce contexte (dernier %{number}) - status_hidden: "Le Contexte est cach\xC3\xA9" - feedlist: - actions_due_today: Actions devant se terminer aujourd'hui ou avant - choose_context: Choisir le contexte dont vous voulez un flux - all_contexts: Tous les contextes - rss_feed: Flux RSS - ical_feed: Flux iCal - legend: "L\xC3\xA9gende" - all_projects: Tous les projets - choose_project: Choisir le projet dont vous voulez un flux - active_projects_wo_next: Projets actifs avec aucune action suivante - project_needed: Il faut au moins un projet pour le flux - select_feed_for_project: Selectionner le flux pour ce projet - active_starred_actions: "Toutes les actions pr\xC3\xA9ferr\xC3\xA9es actives" - context_needed: Il faut au moins un contexte pour le flux - select_feed_for_context: Selectionner un flux pour ce contexte - projects_and_actions: Projets actifs et leurs actions - notice_incomplete_only: "NB: Les flux ne montrent que les actions incompl\xC3\xA8tes, sauf indication contraire" - actions_due_next_week: Actions devant se terminer dans les 7 prochains jours ou moins - plain_text_feed: Flux texte - last_fixed_number: "Derni\xC3\xA8res %{number} actions" - all_actions: Toutes les actions - actions_completed_last_week: "Actions r\xC3\xA9alis\xC3\xA9es dans les 7 derniers jours" - context_centric_actions: "Flux des actions dans un contexte sp\xC3\xA9cifique" - project_centric: "Flux des actions incompl\xC3\xA8tes d'un projet sp\xC3\xA9cifique" + login: + sign_in: Se connecter + openid_identity_url_not_found: "D\xC3\xA9sol\xC3\xA9, aucun utilisateur avec cette identit\xC3\xA9 URL n'existe (%{identity_url})" + user_no_expiry: "Rester connect\xC3\xA9" + login_cas: Aller au CAS + cas_logged_in_greeting: "Bonjour, %{username}! Vous \xC3\xAAtes authentifi\xC3\xA9." + cas_no_user_found: Bonjour, %{username}! Vous n'avez pas de compte sur Tracks. + cas_login: Login CAS + successful_with_session_info: "La connexion \xC3\xA0 r\xC3\xA9ussi:" + please_login: Veuillez vous connecter pour utiliser Tracks + cas_username_not_found: "D\xC3\xA9sol\xC3\xA9, aucun utilisateur avec ce nom CAS n'existe (%{username})" + cas_create_account: "Si vous voulez vous inscrire aller \xC3\xA0 %{signup_link}" + mobile_use_openid: ... ou ce connecter avec un OpenID + cas_signup_link: Demander un compte + account_login: Identifiant du compte + successful: "La connexion \xC3\xA0 r\xC3\xA9ussi. Bienvenue !" + session_will_not_expire: la session n'expire jamais. + session_will_expire: "la session expire apr\xC3\xA8s %{hours} heure(s) d'inactivit\xC3\xA9." + option_separator: ou, + session_time_out: "La session \xC3\xA0 expir\xC3\xA9. Merci de %{link}" + login_standard: "retourner \xC3\xA0 l'\xC3\xA9cran de connexion standard" + log_in_again: Se reconnecter + logged_out: "Vous avez \xC3\xA9t\xC3\xA9 d\xC3\xA9connect\xC3\xA9 de Tracks." + login_with_openid: se connecter avec un OpenID + unsuccessful: "La connexion \xC3\xA0 \xC3\xA9chou\xC3\xA9." datetime: prompts: minute: Minute @@ -934,6 +971,9 @@ fr: x_seconds: one: 1 seconde other: "%{count} secondes" + about_x_hours: + one: environ 1 heure + other: environ %{count} heures less_than_x_seconds: one: moins d'1 seconde other: moins de %{count} secondes @@ -944,48 +984,20 @@ fr: x_minutes: one: 1 minute other: "%{count} minutes" - about_x_hours: - one: environ 1 heure - other: environ %{count} heures - about_x_months: - one: environ 1 mois - other: environ %{count} mois about_x_years: one: environ 1 an other: environ %{count} ans + about_x_months: + one: environ 1 mois + other: environ %{count} mois over_x_years: one: plus d'1 an other: plus de %{count} ans half_a_minute: une demi-minute - login: - sign_in: Se connecter - openid_identity_url_not_found: "D\xC3\xA9sol\xC3\xA9, aucun utilisateur avec cette identit\xC3\xA9 URL n'existe (%{identity_url})" - login_cas: Aller au CAS - user_no_expiry: "Rester connect\xC3\xA9" - cas_login: Login CAS - successful_with_session_info: "La connexion \xC3\xA0 r\xC3\xA9ussi:" - please_login: Veuillez vous connecter pour utiliser Tracks - cas_logged_in_greeting: "Bonjour, %{username}! Vous \xC3\xAAtes authentifi\xC3\xA9." - cas_no_user_found: Bonjour, %{username}! Vous n'avez pas de compte sur Tracks. - cas_username_not_found: "D\xC3\xA9sol\xC3\xA9, aucun utilisateur avec ce nom CAS n'existe (%{username})" - mobile_use_openid: ... ou ce connecter avec un OpenID - cas_create_account: "Si vous voulez vous inscrire aller \xC3\xA0 %{signup_link}" - cas_signup_link: Demander un compte - account_login: Identifiant du compte - successful: "La connexion \xC3\xA0 r\xC3\xA9ussi. Bienvenue !" - session_will_not_expire: la session n'expire jamais. - session_time_out: "La session \xC3\xA0 expir\xC3\xA9. Merci de %{link}" - session_will_expire: "la session expire apr\xC3\xA8s %{hours} heure(s) d'inactivit\xC3\xA9." - option_separator: ou, - login_standard: "retourner \xC3\xA0 l'\xC3\xA9cran de connexion standard" - unsuccessful: "La connexion \xC3\xA0 \xC3\xA9chou\xC3\xA9." - log_in_again: Se reconnecter - logged_out: "Vous avez \xC3\xA9t\xC3\xA9 d\xC3\xA9connect\xC3\xA9 de Tracks." - login_with_openid: se connecter avec un OpenID search: contexts_matching_query: "Contextes correspondant \xC3\xA0 la requ\xC3\xAAte" tags_matching_query: "Tags correspondant \xC3\xA0 la requ\xC3\xAAte" - notes_matching_query: "Notes correspondant \xC3\xA0 la requ\xC3\xAAte" no_results: "Aucun r\xC3\xA9sultat \xC3\xA0 votre recherche." todos_matching_query: "AFaire (todos) correspondant \xC3\xA0 la requ\xC3\xAAte" projects_matching_query: "Projets correspondant \xC3\xA0 la requ\xC3\xAAte" + notes_matching_query: "Notes correspondant \xC3\xA0 la requ\xC3\xAAte" From af10e740176348c87bc5102e224043e3cc51bfaf Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Thu, 29 Mar 2012 16:05:17 +0200 Subject: [PATCH 062/134] fix #1242 by fixing all the routing from the review button --- app/controllers/projects_controller.rb | 12 ++++++++++- app/views/projects/_project_form.rhtml | 2 +- features/review.feature | 24 ++++++++++++++++++++++ features/step_definitions/project_steps.rb | 14 ++++++++++++- 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 2adea3c9..381ba8bf 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -74,7 +74,17 @@ class ProjectsController < ApplicationController def set_reviewed @project.last_reviewed = Time.zone.now @project.save - redirect_to :action => 'show' + + case @source_view + when "project" + redirect_to :action => 'show' + when "project_list" + redirect_to :action => 'index' + when "review" + redirect_to :action => 'review' + else + redirect_to :action => 'index' + end end def projects_and_actions diff --git a/app/views/projects/_project_form.rhtml b/app/views/projects/_project_form.rhtml index 8aa86ee1..b349f9f5 100644 --- a/app/views/projects/_project_form.rhtml +++ b/app/views/projects/_project_form.rhtml @@ -40,7 +40,7 @@ project = project_form <%=image_tag("cancel.png", :alt => "") %> Cancel - + " id="<%= dom_id(project, 'reviewed') %>" class="reviewed"> <%=image_tag("reviewed.png", :alt => "") %> Reviewed diff --git a/features/review.feature b/features/review.feature index 6ba74cd4..c41a4aa6 100644 --- a/features/review.feature +++ b/features/review.feature @@ -34,3 +34,27 @@ Feature: Reviewing projects Given I have an outdated project "dated_project" with 1 todos When I go to the review page And the badge should show 5 ## note that stalled and blocked projects are also up-to-date listed + + @javascript + Scenario: I can mark a project as reviewed from the projects list page + Given I have a project called "review me" + When I go to the projects page + Then I should see "review me" + When I edit project "review me" and mark the project as reviewed + Then I should be on the projects page + And I should see "review me" + + @javascript + Scenario: I can mark a project as reviewed from the project page + Given I have a project called "review me" + When I go to the "review me" project + When I edit project settings and mark the project as reviewed + Then I should be on the "review me" project + + @javascript + Scenario: I can mark a project as reviewed from the review page + Given I have an outdated project "review me" with 1 todos + When I go to the review page + Then I should see "review me" + When I edit project "review me" and mark the project as reviewed + Then I should be on the review page \ No newline at end of file diff --git a/features/step_definitions/project_steps.rb b/features/step_definitions/project_steps.rb index c948343e..812c068f 100644 --- a/features/step_definitions/project_steps.rb +++ b/features/step_definitions/project_steps.rb @@ -164,7 +164,6 @@ When /^I edit the project settings$/ do page.should have_xpath("//div[@id='edit_project_#{@project.id}']/form//button[@id='submit_project_#{@project.id}']") end - When /^I close the project settings$/ do @project.should_not be_nil click_link "Cancel" @@ -181,6 +180,19 @@ When /^I edit the project state of "([^"]*)" to "([^"]*)"$/ do |project_name, st end end +When /^I edit project "([^"]*)" and mark the project as reviewed$/ do |project_name| + project = @current_user.projects.find_by_name(project_name) + project.should_not be_nil + + open_project_edit_form(project) + click_link "reviewed_project_#{project.id}" +end + +When /^I edit project settings and mark the project as reviewed$/ do + open_project_edit_form(@project) + click_link "reviewed_project_#{@project.id}" +end + When /^I add a note "([^"]*)" to the project$/ do |note_body| click_link "Add a note" fill_in "note[body]", :with => note_body From ff4a376ee92965c11c75d23aa7052a0c579a94df Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Thu, 29 Mar 2012 21:14:48 +0200 Subject: [PATCH 063/134] fix #1245 by managing pages with more than one project in a list Update still looks ugly. I'd like to see things more seperated for project list page and review page. Todo! --- app/views/projects/edit.js.erb | 8 +++----- app/views/projects/update.js.erb | 18 +++++++++++------- public/javascripts/application.js | 6 ++++-- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/app/views/projects/edit.js.erb b/app/views/projects/edit.js.erb index a5dee7a5..1f986496 100644 --- a/app/views/projects/edit.js.erb +++ b/app/views/projects/edit.js.erb @@ -3,8 +3,8 @@ function html_for_edit_form() { } function show_edit_form() { - $('div#<%=dom_id(@project, 'edit')%>').html(html_for_edit_form()); - $('div#<%=dom_id(@project, 'edit')%>').fadeIn(500); + $('div.project-edit-current div#<%=dom_id(@project, 'edit')%>').html(html_for_edit_form()); + $('div.project-edit-current div#<%=dom_id(@project, 'edit')%>').fadeIn(500); $('div#project_name').editable('disable'); } @@ -12,12 +12,10 @@ function set_focus() { $('input.project-name').focus(); } - function replace_project_with_edit_form() { - $('div#<%=dom_id(@project)%>').fadeOut(250, function() { + $('div.project-edit-current div#<%=dom_id(@project)%>').fadeOut(250, function() { show_edit_form(); set_focus(); - enable_rich_interaction(); }); } diff --git a/app/views/projects/update.js.erb b/app/views/projects/update.js.erb index a1b52dc7..7cc6c484 100644 --- a/app/views/projects/update.js.erb +++ b/app/views/projects/update.js.erb @@ -24,6 +24,7 @@ function update_project_list_page() { ProjectListPage.update_all_states_count(<%=@active_projects_count%>, <%=@hidden_projects_count%>, <%=@completed_projects_count%>); ProjectListPage.show_or_hide_all_state_containers(<%= @show_active_projects %>, <%= @show_hidden_projects %>, <%= @show_completed_projects %>); TracksForm.set_project_name_and_default_project_name("<%= escape_javascript(@project.name)%>"); + $('div.project-edit-current').removeClass('project-edit-current'); } function update_project_page() { @@ -44,7 +45,9 @@ function remove_project_edit_form() { <%- # do not remove() edit form as this will remove the DIV that is needed to replace with the new form, so only empty the DIV -%> - $('#<%=dom_id(@project, 'edit')%>').hide(500, function() {$('#<%=dom_id(@project, 'edit')%>').html("");} ); + $('#<%=dom_id(@project, 'edit')%>').hide(500, function() { + $('#<%=dom_id(@project, 'edit')%>').html(""); + }); } function update_and_show_project_settings() { @@ -53,17 +56,18 @@ function update_and_show_project_settings() { } function replace_project_form_with_updated_project() { - $('#<%=dom_id(@project, 'container')%>').fadeOut(250, function() { + $('div#<%=dom_id(@project, 'container')%>').each(function(index, elem) { + $(this).fadeOut(250, function() { <% - # first add the updated project after the old one, then remove old one - # using html() does not work, because it will replace the _content_ of + # first add the updated project after the old one, then remove old one. + # Using html() does not work, because it will replace the _content_ of # the container instead of the container itself, i.e. you will get # a container within a container which will break drag-and-drop sorting -%> - $('#<%=dom_id(@project, 'container')%>').after(html_for_project_listing()); - $('#<%=dom_id(@project, 'container')%>').remove(); + $(this).after(html_for_project_listing()); + $(this).remove(); $('#<%=dom_id(@project, 'container')%>').fadeIn(500); - }); + })}); } function remove_and_re_add_project() { diff --git a/public/javascripts/application.js b/public/javascripts/application.js index 364c1e28..65c25b72 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -770,8 +770,9 @@ var ProjectListPage = { /* set behavior for edit project settings link in both projects list page and project page */ $("a.project_edit_settings").live('click', function (evt) { - get_with_ajax_and_block_element(this.href, $(this).parent().parent()); - return false; + $(this).parent().parent().addClass('project-edit-current'); /* mark project in list */ + get_with_ajax_and_block_element(this.href, $(this).parent().parent()); + return false; }); /* submit project form after edit */ @@ -785,6 +786,7 @@ var ProjectListPage = { $('form.edit-project-form a.negative').live('click', function(){ $('div#project_name').editable('enable'); $(this).parents('.edit-form').fadeOut(200, function () { + $(this).parents('.project-edit-current').removeClass('project-edit-current'); $(this).parents('.list').find('.project').fadeIn(500); $(this).parents('.container').find('.item-show').fadeIn(500); }) From bb998ba3fa6b6a69253ee3aeb018f09035d588a0 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Thu, 29 Mar 2012 21:48:34 +0200 Subject: [PATCH 064/134] fix #1265. The validations were not checked when making a project out of a todo. Thanks popsch for spotting this one! --- app/controllers/todos_controller.rb | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 0219373e..79947c80 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -846,9 +846,16 @@ class TodosController < ApplicationController @todo = current_user.todos.find(params[:id]) @project = current_user.projects.new(:name => @todo.description, :description => @todo.notes, :default_context => @todo.context) - @todo.destroy - @project.save! - redirect_to project_url(@project) + + + unless @project.invalid? + @todo.destroy + @project.save! + redirect_to project_url(@project) + else + flash[:error] = "Could not create project from todo: #{@project.errors.full_messages[0]}" + redirect_to request.env["HTTP_REFERER"] || root_url + end end def show_notes From 0012a56ecbdcf8702db350fc84b25849234ddcdb Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Thu, 29 Mar 2012 21:51:33 +0200 Subject: [PATCH 065/134] fix #1266. Please test and reopen if necessary. I think I prefixed all queries with the right table --- app/controllers/todos_controller.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 79947c80..793b753c 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -809,7 +809,7 @@ class TodosController < ApplicationController @items = current_user.todos.find(:all, :include => [:context, :project], :conditions => [ '(todos.state = ? OR todos.state = ? OR todos.state = ?) AND ' + - 'NOT (id = ?) AND lower(description) LIKE ? AND project_id = ?', + 'NOT (todos.id = ?) AND lower(todos.description) LIKE ? AND todos.project_id = ?', 'active', 'pending', 'deferred', @todo.id, '%' + params[:predecessor_list].downcase + '%', @@ -821,7 +821,7 @@ class TodosController < ApplicationController @items = current_user.todos.find(:all, :include => [:context, :project], :conditions => [ '(todos.state = ? OR todos.state = ? OR todos.state = ?) AND ' + - 'NOT (id = ?) AND lower(description) LIKE ?', + 'NOT (todos.id = ?) AND lower(todos.description) LIKE ?', 'active', 'pending', 'deferred', params[:id], '%' + params[:term].downcase + '%' ], :order => 'description ASC', @@ -832,7 +832,7 @@ class TodosController < ApplicationController # New todo - TODO: Filter on project @items = current_user.todos.find(:all, :include => [:context, :project], - :conditions => [ '(todos.state = ? OR todos.state = ? OR todos.state = ?) AND lower(description) LIKE ?', + :conditions => [ '(todos.state = ? OR todos.state = ? OR todos.state = ?) AND lower(todos.description) LIKE ?', 'active', 'pending', 'deferred', '%' + params[:term].downcase + '%' ], :order => 'description ASC', From 2aef2b56227a93a183c7614fbaf289019ba6ec31 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Tue, 3 Apr 2012 13:41:09 +0200 Subject: [PATCH 066/134] fix regression for editing project settings from project page --- app/views/projects/edit.js.erb | 16 +++++++++++----- config/cucumber.yml | 2 +- features/context_edit.feature | 2 +- features/dependencies.feature | 2 +- features/edit_a_todo.feature | 4 ++-- features/step_definitions/todo_edit_steps.rb | 4 +++- features/view_done.feature | 2 +- 7 files changed, 20 insertions(+), 12 deletions(-) diff --git a/app/views/projects/edit.js.erb b/app/views/projects/edit.js.erb index 1f986496..c13641d2 100644 --- a/app/views/projects/edit.js.erb +++ b/app/views/projects/edit.js.erb @@ -1,10 +1,17 @@ +<% + selector_edit = "div##{dom_id(@project, 'edit')}" + selector_edit = "div.project-edit-current " + selector unless @source_view="project" + selector_project = "div##{dom_id(@project)}" + selector_project = "div.project-edit-current " + selector unless @source_view="project" +-%> + function html_for_edit_form() { return "<%= escape_javascript(render(:partial => 'project_form', :object => @project)) %>"; } function show_edit_form() { - $('div.project-edit-current div#<%=dom_id(@project, 'edit')%>').html(html_for_edit_form()); - $('div.project-edit-current div#<%=dom_id(@project, 'edit')%>').fadeIn(500); + $('<%= selector_edit %>').html(html_for_edit_form()); + $('<%= selector_edit %>').fadeIn(500); $('div#project_name').editable('disable'); } @@ -13,11 +20,10 @@ function set_focus() { } function replace_project_with_edit_form() { - $('div.project-edit-current div#<%=dom_id(@project)%>').fadeOut(250, function() { + $('<%= selector_project %>').fadeOut(250, function() { show_edit_form(); set_focus(); }); } - -replace_project_with_edit_form(); +replace_project_with_edit_form(); \ No newline at end of file diff --git a/config/cucumber.yml b/config/cucumber.yml index 199cb582..0ccd3618 100644 --- a/config/cucumber.yml +++ b/config/cucumber.yml @@ -4,5 +4,5 @@ rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'pr std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} --strict --tags ~@wip" %> default: <%= std_opts %> features -wip: --tags @wip:10 --wip features +wip: --tags @wip:15 --wip features rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip diff --git a/features/context_edit.feature b/features/context_edit.feature index 073d197c..18aad0fe 100644 --- a/features/context_edit.feature +++ b/features/context_edit.feature @@ -12,7 +12,7 @@ Feature: Edit a context And I have a project called "test project" And I have 2 todos in project "test project" in context "@pc" with tags "starred" prefixed by "test_project " - @javascript @wip + @javascript Scenario: In place edit of context name Given I have a context called "Errands" When I go to the context page for "Errands" diff --git a/features/dependencies.feature b/features/dependencies.feature index 7513bdd0..28537faa 100644 --- a/features/dependencies.feature +++ b/features/dependencies.feature @@ -160,7 +160,7 @@ Feature: dependencies When I mark "test 1" as complete And I should see "test 1" in the completed container And I should see that "test 2" does not have dependencies - When I mark the complete todo "test 1" active + When I mark the completed todo "test 1" active Then I should not see "test 1" in the completed container And I should see "test 1" in the deferred container And I should see "test 1" within the dependencies of "test 2" diff --git a/features/edit_a_todo.feature b/features/edit_a_todo.feature index 8f2df123..b68bcdaf 100644 --- a/features/edit_a_todo.feature +++ b/features/edit_a_todo.feature @@ -116,7 +116,7 @@ Feature: Edit a next action from every page Then I should see empty message for todos of And I should not see the container for context "visible context" And I should not see empty message for completed todos of - When I mark the complete todo "visible todo" active + When I mark the completed todo "visible todo" active Then I should see the container for context "visible context" And I should see empty message for completed todos of And I should see "visible todo" in the context container for "visible context" @@ -133,7 +133,7 @@ Feature: Edit a next action from every page When I go to the Then I should see empty message for todos of And I should not see empty message for completed todos of - When I mark the complete todo "visible todo" active + When I mark the completed todo "visible todo" active And I should see empty message for completed todos of And I should not see empty message for todos of diff --git a/features/step_definitions/todo_edit_steps.rb b/features/step_definitions/todo_edit_steps.rb index 425732bc..e52614dd 100644 --- a/features/step_definitions/todo_edit_steps.rb +++ b/features/step_definitions/todo_edit_steps.rb @@ -18,8 +18,10 @@ When /^I mark "([^"]*)" as uncompleted$/ do |action_description| wait_for_ajax end -When /^I mark the complete todo "([^"]*)" active$/ do |action_description| +When /^I mark the completed todo "([^"]*)" active$/ do |action_description| step "I mark \"#{action_description}\" as uncompleted" + wait_for_ajax + wait_for_animations_to_end end ####### (UN)STARRING ####### diff --git a/features/view_done.feature b/features/view_done.feature index ba4ff8db..cac54a20 100644 --- a/features/view_done.feature +++ b/features/view_done.feature @@ -137,7 +137,7 @@ Feature: Show done Scenario Outline: I can toggle a todo active from the done pages When I go to the Then I should see "todo 1" - When I mark the complete todo "todo 1" active + When I mark the completed todo "todo 1" active Then I should not see "todo 1" When I go to the Then I should see "todo 1" From 90c80c43305c7aa4d4cb6bdb82083ba1678fefb7 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Tue, 3 Apr 2012 15:49:24 +0200 Subject: [PATCH 067/134] update versioning for master --- README | 20 +++++++------------- config/environment.rb | 2 +- doc/CHANGELOG | 35 ++++++++++++++++++++++++----------- doc/README_DEVELOPERS | 41 +++++++++-------------------------------- 4 files changed, 41 insertions(+), 57 deletions(-) diff --git a/README b/README index 3b9a58bc..3def6b36 100644 --- a/README +++ b/README @@ -1,26 +1,20 @@ # Tracks: a GTD(TM) web application, built with Ruby on Rails -**IMPORTANT: Tracks is moving to a GitHub Organization to make it easier to continue administering the project. Development will soon cease at bsag/tracks and move to TracksApp/tracks. If you are currently pulling from bsag/tracks, please pull from TracksApp instead.** - -`git clone git://github.com/TracksApp/tracks.git` - -**The new home for Tracks is https://github.com/TracksApp/tracks** - * Project homepage: http://getontracks.org/ * Manual: http://TracksApp.github.com/tracks/ * Source at GitHub: http://github.com/TracksApp/tracks/ * Assembla space (for bug reports and feature requests): http://www.assembla.com/spaces/tracks-tickets/tickets * Wiki (community contributed information): https://github.com/TracksApp/tracks/wiki -* Forum: http://getontracks.org/forums/ +* Forum (read-only): http://getontracks.org/forums/ * Mailing list: http://lists.rousette.org.uk/mailman/listinfo/tracks-discuss * Original developer: bsag (http://www.rousette.org.uk/) * Contributors: https://github.com/TracksApp/tracks/wiki/Contributors -* Version: 2.1devel -* Copyright: (cc) 2004-2011 rousette.org.uk. +* Version: 2.2devel +* Copyright: (cc) 2004-2012 rousette.org.uk. * License: GNU GPL All the documentation for Tracks can be found within the /doc directory and at -http://bsag.github.com/tracks/ +http://tracksapp.github.com/tracks/ The latter includes full instructions for both new installations and upgrades from older installations of Tracks. @@ -37,12 +31,12 @@ you cannot find a solution to your problem. The wiki has a lot of user contributed installation HOWTOs for various webhosts, specific OS's and more. If you are thinking about contributing towards the development of Tracks, -please read /doc/README_DEVELOPERS for general information, or -/doc/tracks_api_wrapper.rb for information on Tracks' API. Also you can find -some information on development on the wiki. +please read /doc/README_DEVELOPERS for general information. Also you can find +some information on development, testing and contributing on the wiki. While fully usable for everyday use, Tracks is still a work in progress. Make sure that you take sensible precautions and back up all your data frequently, taking particular care when you are upgrading. Enjoy being productive! + diff --git a/config/environment.rb b/config/environment.rb index 61db438c..390f585b 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -110,7 +110,7 @@ end # changed in development.rb to show under_construction bar NOTIFY_BAR = "" unless defined?(NOTIFY_BAR) -tracks_version='2.1devel' +tracks_version='2.2devel' # comment out next two lines if you do not want (or can not) the date of the # last git commit in the footer info=`git log --pretty=format:"%ai" -1` diff --git a/doc/CHANGELOG b/doc/CHANGELOG index ae0944eb..cca33e2c 100644 --- a/doc/CHANGELOG +++ b/doc/CHANGELOG @@ -1,43 +1,56 @@ -= Tracks: a GTD web application, built with Ruby on Rails += Tracks: a GTD(TM) web application, built with Ruby on Rails * Project homepage: http://getontracks.org/ * Manual: http://TracksApp.github.com/tracks/ * Source at GitHub: http://github.com/TracksApp/tracks/ * Assembla space (for bug reports and feature requests): http://www.assembla.com/spaces/tracks-tickets/tickets * Wiki (community contributed information): https://github.com/TracksApp/tracks/wiki -* Forum: http://getontracks.org/forums/ +* Forum (read-only): http://getontracks.org/forums/ * Mailing list: http://lists.rousette.org.uk/mailman/listinfo/tracks-discuss * Original developer: bsag (http://www.rousette.org.uk/) * Contributors: https://github.com/TracksApp/tracks/wiki/Contributors -* Version: 2.1devel -* Copyright: (cc) 2004-2011 rousette.org.uk. +* Version: 2.1RC1 +* Copyright: (cc) 2004-2012 rousette.org.uk. * License: GNU GPL -== Version 2.1devel +== Version 2.1RC1 -NOTE: To use this version you need to migrate your database. Not migrating will +NOTE 1: To use this version you need to migrate your database. Not migrating will cause new actions not to appear! -This version of tracks has moved to a new place on GitHub. Also the wiki moved +NOTE 2: This version of tracks has moved to a new place on GitHub. Also the wiki moved to GitHub, see the changed URLs above. New and changed features: 1. Redesign of the completed todos: a new overview page. Also all context and project pages have a link to their completed actions 2. New locales (es and fr) and updated locales (de, nl) -3. You can star an action right from the form to add a new action -4. Redesign of preferences page. +3. You can star an action right from the form for adding a new action +4. Redesign of preferences page 5. You can now mark an action complete from the tickler 6. Project names can now contain comma (',') in it name -7. There are two example ruby scripts in /doc to use the REST API to add a todo +7. Context view now shows hidden and pending actions +8. Mobile improvements by Tim Madden (we now require some javascript support on the mobile) +9. Two extra defer periods in the context menu of an action +10.There is a review page where you can see stalled or neglected projects. + There is a reviewed button on the project edit page. +11.You need to change your password: migrated to better BCrypt hash algoritm for storing passwords by Jan Stępień + +New features (technical) +1. There are two example ruby scripts in /doc to use the REST API to add a todo or a project template with todos from the command line +2. The tag page can now select actions from mulitple tags using AND and OR. + There is no gui for this. + Syntax is /todos/tag/tagA,tagB?and=tagC to select all todos with (tagA or tagB) AND tagC Under the hood: -1. Upgraded rails to 2.3.12, jquery to 1.6.2 and jquery-ui to 1.8.14 +1. Upgraded rails to 2.3.12, jquery to 1.7.1 and jquery-ui to 1.8.17 2. Fixed several issues with the REST API 3. Upgraded the act_as_statemachine plugin. This change requires a migration. See note above! 4. Migated to bundler for gem dependencies +5. Migrated to cucumber and capybara for integration testing +6. Development mode shows a work-in-progress banner on top of the screen See https://github.com/tracksapp/tracks/compare/v2.0...master for all detailed changes diff --git a/doc/README_DEVELOPERS b/doc/README_DEVELOPERS index e63c7e44..7570c9ce 100644 --- a/doc/README_DEVELOPERS +++ b/doc/README_DEVELOPERS @@ -1,13 +1,13 @@ 1. Resources Tracks is using -* github to host the git repository. +* github to host the git repository and manage git pull requests. * Assembla to manage bugs and enhancement request. * the mailing list to discuss features and development and interact with users See README for links to the respective sites -Also see the Development pages on the wiki for details on installing, upgrading, etc. +Also see the Development pages on the wiki for details on installing, testing, upgrading, etc. 2. Dependencies @@ -15,13 +15,11 @@ The dependencies for Tracks are maintained using bundler. Before starting your tracks instance, you'll need to run 'bundle install' to fetch all the dependencies -3. Wiki +3. Testing There are some pointers for setting up your Tracks copy for testing at https://github.com/TracksApp/tracks/wiki/Testing/ -4. SQLITE3 FOR TESTING - By default, tests are configured to run using sqlite3 in memory mode to increase speed. You will need the sqlite3-ruby gem for this. @@ -33,33 +31,12 @@ database.yml below 'database: ":memory:"': If you want to run tests using another database, that's fine, too. Just change your database.yml accordingly. -5. Test::Unit tests +Running cucumber/selenium tests in :memory mode does not seem to work. -To run the Test::Unit tests run - - rake test - -Running the above command will run through the unit, functional, and -integration tests for Tracks. Use 'rake -T' to see a list of all rake tasks to -determine how to run each section of tests separately. - -6. RSpec tests - -To run the RSpec tests run - - rake spec - -7. Cucumber tests - -To run the cucumber test run - - rake cucumber - -and for those using javascript/ajax use - - rake cucumber:selenium - -In order to run the selenium tests, you'll need to have Firefox 3.x installed. -Newer versions won't work. +The rspec tests are not actively maintained. See the wiki for more information on testing: https://github.com/TracksApp/tracks/wiki/Testing + +4. Contributing + +See https://github.com/TracksApp/tracks/wiki/How-to-contribute \ No newline at end of file From c7637053e1e182b11de35fc70fe22f01a7bc370f Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Tue, 3 Apr 2012 20:29:58 +0200 Subject: [PATCH 068/134] fix #1268. The default context in the new todo form on the home page is now the first active context Instead of the first context that could be hidden and thus appear random. Also fix setting the default context based on the project you select. --- app/controllers/todos_controller.rb | 4 ++-- app/helpers/todos_helper.rb | 3 ++- app/views/shared/_add_new_item_form.rhtml | 5 +++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 793b753c..2bdb06c5 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -18,8 +18,8 @@ class TodosController < ApplicationController extend ActionView::Helpers::SanitizeHelper::ClassMethods def index - @projects = current_user.projects.find(:all, :include => [:default_context]) - @contexts = current_user.contexts.find(:all) + @projects = current_user.projects.all(:include => [:default_context]) + @contexts = current_user.contexts @contexts_to_show = current_user.contexts.active diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index eb31f8e7..3f616b86 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -1,4 +1,5 @@ module TodosHelper + def remote_star_icon(todo=@todo) link_to( image_tag_for_star(todo), @@ -272,7 +273,7 @@ module TodosHelper end def default_contexts_for_autocomplete - projects = current_user.uncompleted.projects.find(:all, :include => [:context], :conditions => ['default_context_id is not null']) + projects = current_user.projects.uncompleted.find(:all, :include => [:default_context], :conditions => ['NOT(default_context_id IS NULL)']) Hash[*projects.map{ |p| [escape_javascript(p.name), escape_javascript(p.default_context.name)] }.flatten].to_json end diff --git a/app/views/shared/_add_new_item_form.rhtml b/app/views/shared/_add_new_item_form.rhtml index 940dedb5..d8e3b9a7 100644 --- a/app/views/shared/_add_new_item_form.rhtml +++ b/app/views/shared/_add_new_item_form.rhtml @@ -1,6 +1,7 @@ <% -@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 = @context.name if @context +@initial_context_name ||= @project.default_context.name unless @project.nil? || @project.default_context.nil? +@initial_context_name ||= @contexts.active.first.name unless @contexts.active.first.nil? @initial_context_name ||= @contexts.first.name unless @contexts.first.nil? @initial_project_name = @project.name unless @project.nil? @initial_tags ||= @default_tags From 8d6b9b5dbde76ba975c547805fdc4d05f45b4596 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Wed, 4 Apr 2012 20:03:40 +0200 Subject: [PATCH 069/134] fix regressions --- app/controllers/todos_controller.rb | 2 +- app/views/projects/edit.js.erb | 4 +-- .../step_definitions/recurring_todo_steps.rb | 2 ++ features/view_done.feature | 36 +++++++++++-------- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 2bdb06c5..df7df3cd 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -573,7 +573,7 @@ class TodosController < ApplicationController @source_view = 'deferred' @page_title = t('todos.deferred_tasks_title') - @contexts_to_show = @contexts = current_user.contexts.find(:all) + @contexts_to_show = @contexts = current_user.contexts includes = params[:format]=='xml' ? [:context, :project] : Todo::DEFAULT_INCLUDES diff --git a/app/views/projects/edit.js.erb b/app/views/projects/edit.js.erb index c13641d2..3df90048 100644 --- a/app/views/projects/edit.js.erb +++ b/app/views/projects/edit.js.erb @@ -1,8 +1,8 @@ <% selector_edit = "div##{dom_id(@project, 'edit')}" - selector_edit = "div.project-edit-current " + selector unless @source_view="project" + selector_edit = "div.project-edit-current " + selector_edit unless @source_view=="project" selector_project = "div##{dom_id(@project)}" - selector_project = "div.project-edit-current " + selector unless @source_view="project" + selector_project = "div.project-edit-current " + selector_project unless @source_view=="project" -%> function html_for_edit_form() { diff --git a/features/step_definitions/recurring_todo_steps.rb b/features/step_definitions/recurring_todo_steps.rb index 46739fba..8d37ec71 100644 --- a/features/step_definitions/recurring_todo_steps.rb +++ b/features/step_definitions/recurring_todo_steps.rb @@ -73,6 +73,8 @@ When /^I mark the pattern "([^"]*)" as (complete|active)$/ do |pattern_name, sta pattern.should_not be_nil pattern.completed?.should(state=="complete" ? be_false : be_true) page.find("#check_#{pattern.id}").click + wait_for_ajax + wait_for_animations_to_end end When /^I follow the recurring todo link of "([^"]*)"$/ do |action_description| diff --git a/features/view_done.feature b/features/view_done.feature index cac54a20..bda393be 100644 --- a/features/view_done.feature +++ b/features/view_done.feature @@ -113,7 +113,7 @@ Feature: Show done Then I should be on the done recurring todos page And the page should be "2" - @selenium + @javascript @wip Scenario: I can toggle a done recurring todo active from done page Given I have a completed repeat pattern "test pattern" When I go to the done recurring todos page @@ -123,7 +123,7 @@ Feature: Show done When I go to the recurring todos page Then I should see "test pattern" in the active recurring todos container - @selenium + @javascript Scenario: I can delete a recurring todo from the done page Given I have a completed repeat pattern "test pattern" When I go to the done recurring todos page @@ -133,7 +133,7 @@ Feature: Show done When I go to the recurring todos page Then I should not see "test pattern" in the active recurring todos container - @selenium + @javascript Scenario Outline: I can toggle a todo active from the done pages When I go to the Then I should see "todo 1" @@ -153,7 +153,7 @@ Feature: Show done | all done actions page for project "test project"| "test project" project | | | all done actions page for tag "starred" | home page | in the context container for "@pc" | - @selenium + @javascript Scenario Outline: I can toggle the star of a todo from the done pages When I go to the Then I should see a starred "todo 1" @@ -171,7 +171,7 @@ Feature: Show done | all done actions page for project "test project"| | all done actions page for tag "starred" | - @selenium + @javascript Scenario: I can edit a project to active from the project done page Given I have a completed project called "completed project" When I go to the done projects page @@ -181,7 +181,6 @@ Feature: Show done When I go to the projects page Then I should see "completed project" - Scenario Outline: All pages are internationalized Given I set the locale to "" When I go to the @@ -221,12 +220,19 @@ Feature: Show done | all done actions page for context "@pc" | es | | all done actions page for project "test project"| es | | all done actions page for tag "starred" | es | -# fr locale needs changes from preference branch -# | done actions page | fr | -# | all done actions page | fr | -# | done actions page for context "@pc" | fr | -# | done actions page for project "test project" | fr | -# | done actions page for tag "starred" | fr | -# | all done actions page for context "@pc" | fr | -# | all done actions page for project "test project"| fr | -# | all done actions page for tag "starred" | fr | + | done actions page | fr | + | all done actions page | fr | + | done actions page for context "@pc" | fr | + | done actions page for project "test project" | fr | + | done actions page for tag "starred" | fr | + | all done actions page for context "@pc" | fr | + | all done actions page for project "test project"| fr | + | all done actions page for tag "starred" | fr | + | done actions page | cz | + | all done actions page | cz | + | done actions page for context "@pc" | cz | + | done actions page for project "test project" | cz | + | done actions page for tag "starred" | cz | + | all done actions page for context "@pc" | cz | + | all done actions page for project "test project"| cz | + | all done actions page for tag "starred" | cz | From 0dad59df4c242229516bbe52709a2c691b9f7a7a Mon Sep 17 00:00:00 2001 From: tim madden Date: Thu, 5 Apr 2012 10:02:31 -0500 Subject: [PATCH 070/134] Fix for days calculation being shown as rational number in ruby 1.9.2 --- app/helpers/application_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 39c591e4..8e8a2848 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -20,7 +20,7 @@ module ApplicationHelper end def days_from_today(date) - date.in_time_zone.to_date - current_user.time.to_date + Integer (date.in_time_zone.to_date - current_user.time.to_date) end # Check due date in comparison to today's date Flag up date appropriately with From 2bdecb583a8018e91705ba64bf9e7ed977f6faae Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Sun, 8 Apr 2012 15:17:29 +0200 Subject: [PATCH 071/134] Fix deprecation warning of has_many_polymorphs. Needed to vendor this gem. --- Gemfile | 2 +- Gemfile.lock | 10 +- .../has_many_polymorphs-2.13/.specification | 288 ++ .../gems/has_many_polymorphs-2.13/CHANGELOG | 84 + vendor/gems/has_many_polymorphs-2.13/LICENSE | 184 ++ vendor/gems/has_many_polymorphs-2.13/Manifest | 173 ++ vendor/gems/has_many_polymorphs-2.13/README | 205 ++ vendor/gems/has_many_polymorphs-2.13/Rakefile | 28 + vendor/gems/has_many_polymorphs-2.13/TODO | 2 + .../has_many_polymorphs-2.13/examples/hmph.rb | 69 + .../generators/tagging/tagging_generator.rb | 97 + .../generators/tagging/templates/migration.rb | 28 + .../generators/tagging/templates/tag.rb | 39 + .../generators/tagging/templates/tag_test.rb | 15 + .../generators/tagging/templates/tagging.rb | 16 + .../tagging/templates/tagging_extensions.rb | 203 ++ .../tagging/templates/tagging_test.rb | 85 + .../generators/tagging/templates/taggings.yml | 23 + .../generators/tagging/templates/tags.yml | 7 + .../has_many_polymorphs.gemspec | 40 + vendor/gems/has_many_polymorphs-2.13/init.rb | 2 + .../lib/has_many_polymorphs.rb | 27 + .../lib/has_many_polymorphs/association.rb | 159 ++ .../lib/has_many_polymorphs/autoload.rb | 69 + .../lib/has_many_polymorphs/base.rb | 60 + .../lib/has_many_polymorphs/class_methods.rb | 600 ++++ .../lib/has_many_polymorphs/configuration.rb | 19 + .../has_many_polymorphs/debugging_tools.rb | 103 + .../rake_task_redefine_task.rb | 35 + .../lib/has_many_polymorphs/reflection.rb | 58 + .../has_many_polymorphs/support_methods.rb | 84 + .../test/fixtures/bow_wows.yml | 10 + .../test/fixtures/cats.yml | 18 + .../test/fixtures/eaters_foodstuffs.yml | 0 .../test/fixtures/fish.yml | 12 + .../test/fixtures/frogs.yml | 5 + .../test/fixtures/keep_your_enemies_close.yml | 0 .../test/fixtures/little_whale_pupils.yml | 0 .../test/fixtures/people.yml | 7 + .../test/fixtures/petfoods.yml | 11 + .../test/fixtures/whales.yml | 5 + .../test/fixtures/wild_boars.yml | 10 + .../test/generator/tagging_generator_test.rb | 42 + .../test/integration/app/README | 182 ++ .../test/integration/app/Rakefile | 19 + .../app/app/controllers/application.rb | 7 + .../app/app/controllers/bones_controller.rb | 5 + .../app/app/helpers/addresses_helper.rb | 2 + .../app/app/helpers/application_helper.rb | 3 + .../app/app/helpers/bones_helper.rb | 2 + .../app/app/helpers/sellers_helper.rb | 28 + .../app/app/helpers/states_helper.rb | 2 + .../app/app/helpers/users_helper.rb | 2 + .../test/integration/app/app/models/bone.rb | 2 + .../app/app/models/double_sti_parent.rb | 2 + .../models/double_sti_parent_relationship.rb | 2 + .../app/app/models/organic_substance.rb | 2 + .../app/app/models/single_sti_parent.rb | 4 + .../models/single_sti_parent_relationship.rb | 4 + .../test/integration/app/app/models/stick.rb | 2 + .../test/integration/app/app/models/stone.rb | 2 + .../app/app/views/addresses/edit.html.erb | 12 + .../app/app/views/addresses/index.html.erb | 18 + .../app/app/views/addresses/new.html.erb | 11 + .../app/app/views/addresses/show.html.erb | 3 + .../app/app/views/bones/index.rhtml | 5 + .../app/app/views/layouts/addresses.html.erb | 17 + .../app/app/views/layouts/sellers.html.erb | 17 + .../app/app/views/layouts/states.html.erb | 17 + .../app/app/views/layouts/users.html.erb | 17 + .../app/app/views/sellers/edit.html.erb | 12 + .../app/app/views/sellers/index.html.erb | 20 + .../app/app/views/sellers/new.html.erb | 11 + .../app/app/views/sellers/show.html.erb | 3 + .../app/app/views/states/edit.html.erb | 12 + .../app/app/views/states/index.html.erb | 19 + .../app/app/views/states/new.html.erb | 11 + .../app/app/views/states/show.html.erb | 3 + .../app/app/views/users/edit.html.erb | 12 + .../app/app/views/users/index.html.erb | 22 + .../app/app/views/users/new.html.erb | 11 + .../app/app/views/users/show.html.erb | 3 + .../test/integration/app/config/boot.rb | 110 + .../test/integration/app/config/database.yml | 17 + .../integration/app/config/environment.rb | 19 + .../app/config/environment.rb.canonical | 19 + .../app/config/environments/development.rb | 9 + .../app/config/environments/production.rb | 18 + .../app/config/environments/test.rb | 19 + .../integration/app/config/locomotive.yml | 6 + .../test/integration/app/config/routes.rb | 33 + .../app/config/ultrasphinx/default.base | 56 + .../ultrasphinx/development.conf.canonical | 155 + .../app/db/migrate/001_create_sticks.rb | 11 + .../app/db/migrate/002_create_stones.rb | 11 + .../migrate/003_create_organic_substances.rb | 11 + .../app/db/migrate/004_create_bones.rb | 8 + .../migrate/005_create_single_sti_parents.rb | 11 + .../migrate/006_create_double_sti_parents.rb | 11 + ..._create_single_sti_parent_relationships.rb | 13 + ..._create_double_sti_parent_relationships.rb | 14 + .../db/migrate/009_create_library_model.rb | 11 + .../test/integration/app/doc/README_FOR_APP | 2 + .../generators/commenting_generator_test.rb | 83 + .../test/integration/app/lib/library_model.rb | 2 + .../test/integration/app/public/404.html | 30 + .../test/integration/app/public/500.html | 30 + .../test/integration/app/public/dispatch.cgi | 10 + .../test/integration/app/public/dispatch.fcgi | 24 + .../test/integration/app/public/dispatch.rb | 10 + .../test/integration/app/public/favicon.ico | 0 .../integration/app/public/images/rails.png | Bin 0 -> 1787 bytes .../test/integration/app/public/index.html | 277 ++ .../app/public/javascripts/application.js | 2 + .../app/public/javascripts/controls.js | 833 ++++++ .../app/public/javascripts/dragdrop.js | 942 ++++++ .../app/public/javascripts/effects.js | 1088 +++++++ .../app/public/javascripts/prototype.js | 2515 +++++++++++++++++ .../test/integration/app/public/robots.txt | 1 + .../app/public/stylesheets/scaffold.css | 74 + .../test/integration/app/script/about | 3 + .../test/integration/app/script/breakpointer | 3 + .../test/integration/app/script/console | 3 + .../test/integration/app/script/destroy | 3 + .../test/integration/app/script/generate | 3 + .../app/script/performance/benchmarker | 3 + .../app/script/performance/profiler | 3 + .../test/integration/app/script/plugin | 3 + .../integration/app/script/process/inspector | 3 + .../integration/app/script/process/reaper | 3 + .../integration/app/script/process/spawner | 3 + .../test/integration/app/script/runner | 3 + .../test/integration/app/script/server | 3 + .../double_sti_parent_relationships.yml | 7 + .../app/test/fixtures/double_sti_parents.yml | 7 + .../app/test/fixtures/organic_substances.yml | 5 + .../single_sti_parent_relationships.yml | 7 + .../app/test/fixtures/single_sti_parents.yml | 7 + .../integration/app/test/fixtures/sticks.yml | 7 + .../integration/app/test/fixtures/stones.yml | 7 + .../functional/addresses_controller_test.rb | 57 + .../test/functional/bones_controller_test.rb | 8 + .../functional/sellers_controller_test.rb | 57 + .../test/functional/states_controller_test.rb | 57 + .../test/functional/users_controller_test.rb | 57 + .../test/integration/app/test/test_helper.rb | 8 + .../integration/app/test/unit/bone_test.rb | 8 + .../double_sti_parent_relationship_test.rb | 8 + .../app/test/unit/double_sti_parent_test.rb | 8 + .../app/test/unit/organic_substance_test.rb | 8 + .../single_sti_parent_relationship_test.rb | 8 + .../app/test/unit/single_sti_parent_test.rb | 8 + .../integration/app/test/unit/stick_test.rb | 8 + .../integration/app/test/unit/stone_test.rb | 8 + .../test/integration/server_test.rb | 43 + .../test/models/aquatic/fish.rb | 5 + .../test/models/aquatic/pupils_whale.rb | 7 + .../test/models/aquatic/whale.rb | 15 + .../models/beautiful_fight_relationship.rb | 26 + .../test/models/canine.rb | 9 + .../test/models/cat.rb | 5 + .../test/models/dog.rb | 18 + .../test/models/eaters_foodstuff.rb | 10 + .../test/models/frog.rb | 4 + .../test/models/kitten.rb | 3 + .../test/models/parentship.rb | 4 + .../test/models/person.rb | 9 + .../test/models/petfood.rb | 39 + .../test/models/tabby.rb | 2 + .../test/models/wild_boar.rb | 3 + .../test/modules/extension_module.rb | 9 + .../test/modules/other_extension_module.rb | 9 + .../test/patches/symlinked_plugins_1.2.6.diff | 46 + .../has_many_polymorphs-2.13/test/schema.rb | 87 + .../has_many_polymorphs-2.13/test/setup.rb | 14 + .../test/test_helper.rb | 51 + .../test/unit/has_many_polymorphs_test.rb | 714 +++++ 177 files changed, 11469 insertions(+), 4 deletions(-) create mode 100644 vendor/gems/has_many_polymorphs-2.13/.specification create mode 100644 vendor/gems/has_many_polymorphs-2.13/CHANGELOG create mode 100644 vendor/gems/has_many_polymorphs-2.13/LICENSE create mode 100644 vendor/gems/has_many_polymorphs-2.13/Manifest create mode 100644 vendor/gems/has_many_polymorphs-2.13/README create mode 100644 vendor/gems/has_many_polymorphs-2.13/Rakefile create mode 100644 vendor/gems/has_many_polymorphs-2.13/TODO create mode 100644 vendor/gems/has_many_polymorphs-2.13/examples/hmph.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/generators/tagging/tagging_generator.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/migration.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tag.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tag_test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging_extensions.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging_test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/taggings.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tags.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/has_many_polymorphs.gemspec create mode 100644 vendor/gems/has_many_polymorphs-2.13/init.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/association.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/autoload.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/base.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/class_methods.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/configuration.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/debugging_tools.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/rake_task_redefine_task.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/reflection.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/support_methods.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/bow_wows.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/cats.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/eaters_foodstuffs.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/fish.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/frogs.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/keep_your_enemies_close.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/little_whale_pupils.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/people.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/petfoods.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/whales.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/wild_boars.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/generator/tagging_generator_test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/README create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/Rakefile create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/controllers/application.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/controllers/bones_controller.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/addresses_helper.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/application_helper.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/bones_helper.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/sellers_helper.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/states_helper.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/users_helper.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/bone.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/double_sti_parent.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/double_sti_parent_relationship.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/organic_substance.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/single_sti_parent.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/single_sti_parent_relationship.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/stick.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/stone.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/edit.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/index.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/new.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/show.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/bones/index.rhtml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/addresses.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/sellers.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/states.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/users.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/edit.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/index.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/new.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/show.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/edit.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/index.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/new.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/show.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/edit.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/index.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/new.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/show.html.erb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/boot.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/database.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environment.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environment.rb.canonical create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/development.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/production.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/locomotive.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/routes.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/ultrasphinx/default.base create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/ultrasphinx/development.conf.canonical create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/001_create_sticks.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/002_create_stones.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/003_create_organic_substances.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/004_create_bones.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/005_create_single_sti_parents.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/006_create_double_sti_parents.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/009_create_library_model.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/doc/README_FOR_APP create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/generators/commenting_generator_test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/lib/library_model.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/404.html create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/500.html create mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.cgi create mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.fcgi create mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/favicon.ico create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/images/rails.png create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/index.html create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/application.js create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/controls.js create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/dragdrop.js create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/effects.js create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/prototype.js create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/robots.txt create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/stylesheets/scaffold.css create mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/about create mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/breakpointer create mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/console create mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/destroy create mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/generate create mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/performance/benchmarker create mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/performance/profiler create mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/plugin create mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/inspector create mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/reaper create mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/spawner create mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/runner create mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/server create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/double_sti_parent_relationships.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/double_sti_parents.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/organic_substances.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/single_sti_parent_relationships.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/single_sti_parents.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/sticks.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/stones.yml create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/addresses_controller_test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/bones_controller_test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/sellers_controller_test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/states_controller_test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/users_controller_test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/test_helper.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/bone_test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/double_sti_parent_relationship_test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/double_sti_parent_test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/organic_substance_test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/single_sti_parent_relationship_test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/single_sti_parent_test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/stick_test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/stone_test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/server_test.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/fish.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/pupils_whale.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/whale.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/beautiful_fight_relationship.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/canine.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/cat.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/dog.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/eaters_foodstuff.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/frog.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/kitten.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/parentship.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/person.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/petfood.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/tabby.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/wild_boar.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/modules/extension_module.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/modules/other_extension_module.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/patches/symlinked_plugins_1.2.6.diff create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/schema.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/setup.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/test_helper.rb create mode 100644 vendor/gems/has_many_polymorphs-2.13/test/unit/has_many_polymorphs_test.rb diff --git a/Gemfile b/Gemfile index dc3af876..03b4cda4 100644 --- a/Gemfile +++ b/Gemfile @@ -8,7 +8,7 @@ gem "RedCloth", "4.2.8" gem "sanitize", "~>1.2.1" gem "rack", "1.1.0" gem "will_paginate", "~> 2.3.15" -gem "has_many_polymorphs", "~> 2.13" +gem "has_many_polymorphs", "~> 2.13", :path => "vendor/gems/has_many_polymorphs-2.13" # vendorred to get rid of some deprecation warnings gem "acts_as_list", "~>0.1.4" gem "aasm", "~>2.2.0" gem "rubyjedi-actionwebservice", :require => "actionwebservice" diff --git a/Gemfile.lock b/Gemfile.lock index 34569fc6..0c888954 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,6 +3,12 @@ PATH specs: aruba (0.2.2) +PATH + remote: vendor/gems/has_many_polymorphs-2.13 + specs: + has_many_polymorphs (2.13) + activerecord + GEM remote: http://rubygems.org/ remote: http://gems.github.com/ @@ -51,8 +57,6 @@ GEM gem_plugin (0.2.3) gherkin (2.7.7) json (>= 1.4.6) - has_many_polymorphs (2.13) - activerecord highline (1.5.2) hoe (2.13.1) rake (~> 0.8) @@ -143,7 +147,7 @@ DEPENDENCIES cucumber-rails (~> 0.3.2) database_cleaner (>= 0.5.0) flexmock - has_many_polymorphs (~> 2.13) + has_many_polymorphs (~> 2.13)! highline (~> 1.5.0) hoe hpricot diff --git a/vendor/gems/has_many_polymorphs-2.13/.specification b/vendor/gems/has_many_polymorphs-2.13/.specification new file mode 100644 index 00000000..8cec7bbd --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/.specification @@ -0,0 +1,288 @@ +--- !ruby/object:Gem::Specification +name: has_many_polymorphs +version: !ruby/object:Gem::Version + hash: 25 + prerelease: + segments: + - 2 + - 13 + version: "2.13" +platform: ruby +authors: +- "" +autorequire: +bindir: bin +cert_chain: +- /Users/eweaver/p/configuration/gem_certificates/evan_weaver-original-public_cert.pem +date: 2009-02-02 00:00:00 Z +dependencies: +- !ruby/object:Gem::Dependency + type: :runtime + requirement: &id001 !ruby/object:Gem::Requirement + none: false + requirements: + - - ">=" + - !ruby/object:Gem::Version + hash: 3 + segments: + - 0 + version: "0" + prerelease: false + name: activerecord + version_requirements: *id001 +- !ruby/object:Gem::Dependency + type: :development + requirement: &id002 !ruby/object:Gem::Requirement + none: false + requirements: + - - ">=" + - !ruby/object:Gem::Version + hash: 3 + segments: + - 0 + version: "0" + prerelease: false + name: echoe + version_requirements: *id002 +description: An ActiveRecord plugin for self-referential and double-sided polymorphic associations. +email: "" +executables: [] + +extensions: [] + +extra_rdoc_files: +- CHANGELOG +- generators/tagging/templates/migration.rb +- generators/tagging/templates/tag.rb +- generators/tagging/templates/tagging.rb +- generators/tagging/templates/tagging_extensions.rb +- lib/has_many_polymorphs/association.rb +- lib/has_many_polymorphs/autoload.rb +- lib/has_many_polymorphs/class_methods.rb +- lib/has_many_polymorphs/configuration.rb +- lib/has_many_polymorphs/reflection.rb +- LICENSE +- README +- test/integration/app/doc/README_FOR_APP +- test/integration/app/README +- TODO +files: +- CHANGELOG +- examples/hmph.rb +- generators/tagging/tagging_generator.rb +- generators/tagging/templates/migration.rb +- generators/tagging/templates/tag.rb +- generators/tagging/templates/tag_test.rb +- generators/tagging/templates/tagging.rb +- generators/tagging/templates/tagging_extensions.rb +- generators/tagging/templates/tagging_test.rb +- generators/tagging/templates/taggings.yml +- generators/tagging/templates/tags.yml +- init.rb +- lib/has_many_polymorphs/association.rb +- lib/has_many_polymorphs/autoload.rb +- lib/has_many_polymorphs/base.rb +- lib/has_many_polymorphs/class_methods.rb +- lib/has_many_polymorphs/configuration.rb +- lib/has_many_polymorphs/debugging_tools.rb +- lib/has_many_polymorphs/rake_task_redefine_task.rb +- lib/has_many_polymorphs/reflection.rb +- lib/has_many_polymorphs/support_methods.rb +- lib/has_many_polymorphs.rb +- LICENSE +- Manifest +- Rakefile +- README +- test/fixtures/bow_wows.yml +- test/fixtures/cats.yml +- test/fixtures/eaters_foodstuffs.yml +- test/fixtures/fish.yml +- test/fixtures/frogs.yml +- test/fixtures/keep_your_enemies_close.yml +- test/fixtures/little_whale_pupils.yml +- test/fixtures/people.yml +- test/fixtures/petfoods.yml +- test/fixtures/whales.yml +- test/fixtures/wild_boars.yml +- test/generator/tagging_generator_test.rb +- test/integration/app/app/controllers/application.rb +- test/integration/app/app/controllers/bones_controller.rb +- test/integration/app/app/helpers/addresses_helper.rb +- test/integration/app/app/helpers/application_helper.rb +- test/integration/app/app/helpers/bones_helper.rb +- test/integration/app/app/helpers/sellers_helper.rb +- test/integration/app/app/helpers/states_helper.rb +- test/integration/app/app/helpers/users_helper.rb +- test/integration/app/app/models/bone.rb +- test/integration/app/app/models/double_sti_parent.rb +- test/integration/app/app/models/double_sti_parent_relationship.rb +- test/integration/app/app/models/organic_substance.rb +- test/integration/app/app/models/single_sti_parent.rb +- test/integration/app/app/models/single_sti_parent_relationship.rb +- test/integration/app/app/models/stick.rb +- test/integration/app/app/models/stone.rb +- test/integration/app/app/views/addresses/edit.html.erb +- test/integration/app/app/views/addresses/index.html.erb +- test/integration/app/app/views/addresses/new.html.erb +- test/integration/app/app/views/addresses/show.html.erb +- test/integration/app/app/views/bones/index.rhtml +- test/integration/app/app/views/layouts/addresses.html.erb +- test/integration/app/app/views/layouts/sellers.html.erb +- test/integration/app/app/views/layouts/states.html.erb +- test/integration/app/app/views/layouts/users.html.erb +- test/integration/app/app/views/sellers/edit.html.erb +- test/integration/app/app/views/sellers/index.html.erb +- test/integration/app/app/views/sellers/new.html.erb +- test/integration/app/app/views/sellers/show.html.erb +- test/integration/app/app/views/states/edit.html.erb +- test/integration/app/app/views/states/index.html.erb +- test/integration/app/app/views/states/new.html.erb +- test/integration/app/app/views/states/show.html.erb +- test/integration/app/app/views/users/edit.html.erb +- test/integration/app/app/views/users/index.html.erb +- test/integration/app/app/views/users/new.html.erb +- test/integration/app/app/views/users/show.html.erb +- test/integration/app/config/boot.rb +- test/integration/app/config/database.yml +- test/integration/app/config/environment.rb +- test/integration/app/config/environment.rb.canonical +- test/integration/app/config/environments/development.rb +- test/integration/app/config/environments/production.rb +- test/integration/app/config/environments/test.rb +- test/integration/app/config/locomotive.yml +- test/integration/app/config/routes.rb +- test/integration/app/config/ultrasphinx/default.base +- test/integration/app/config/ultrasphinx/development.conf.canonical +- test/integration/app/db/migrate/001_create_sticks.rb +- test/integration/app/db/migrate/002_create_stones.rb +- test/integration/app/db/migrate/003_create_organic_substances.rb +- test/integration/app/db/migrate/004_create_bones.rb +- test/integration/app/db/migrate/005_create_single_sti_parents.rb +- test/integration/app/db/migrate/006_create_double_sti_parents.rb +- test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb +- test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb +- test/integration/app/db/migrate/009_create_library_model.rb +- test/integration/app/doc/README_FOR_APP +- test/integration/app/generators/commenting_generator_test.rb +- test/integration/app/lib/library_model.rb +- test/integration/app/public/404.html +- test/integration/app/public/500.html +- test/integration/app/public/dispatch.cgi +- test/integration/app/public/dispatch.fcgi +- test/integration/app/public/dispatch.rb +- test/integration/app/public/favicon.ico +- test/integration/app/public/images/rails.png +- test/integration/app/public/index.html +- test/integration/app/public/javascripts/application.js +- test/integration/app/public/javascripts/controls.js +- test/integration/app/public/javascripts/dragdrop.js +- test/integration/app/public/javascripts/effects.js +- test/integration/app/public/javascripts/prototype.js +- test/integration/app/public/robots.txt +- test/integration/app/public/stylesheets/scaffold.css +- test/integration/app/Rakefile +- test/integration/app/README +- test/integration/app/script/about +- test/integration/app/script/breakpointer +- test/integration/app/script/console +- test/integration/app/script/destroy +- test/integration/app/script/generate +- test/integration/app/script/performance/benchmarker +- test/integration/app/script/performance/profiler +- test/integration/app/script/plugin +- test/integration/app/script/process/inspector +- test/integration/app/script/process/reaper +- test/integration/app/script/process/spawner +- test/integration/app/script/runner +- test/integration/app/script/server +- test/integration/app/test/fixtures/double_sti_parent_relationships.yml +- test/integration/app/test/fixtures/double_sti_parents.yml +- test/integration/app/test/fixtures/organic_substances.yml +- test/integration/app/test/fixtures/single_sti_parent_relationships.yml +- test/integration/app/test/fixtures/single_sti_parents.yml +- test/integration/app/test/fixtures/sticks.yml +- test/integration/app/test/fixtures/stones.yml +- test/integration/app/test/functional/addresses_controller_test.rb +- test/integration/app/test/functional/bones_controller_test.rb +- test/integration/app/test/functional/sellers_controller_test.rb +- test/integration/app/test/functional/states_controller_test.rb +- test/integration/app/test/functional/users_controller_test.rb +- test/integration/app/test/test_helper.rb +- test/integration/app/test/unit/bone_test.rb +- test/integration/app/test/unit/double_sti_parent_relationship_test.rb +- test/integration/app/test/unit/double_sti_parent_test.rb +- test/integration/app/test/unit/organic_substance_test.rb +- test/integration/app/test/unit/single_sti_parent_relationship_test.rb +- test/integration/app/test/unit/single_sti_parent_test.rb +- test/integration/app/test/unit/stick_test.rb +- test/integration/app/test/unit/stone_test.rb +- test/integration/server_test.rb +- test/models/aquatic/fish.rb +- test/models/aquatic/pupils_whale.rb +- test/models/aquatic/whale.rb +- test/models/beautiful_fight_relationship.rb +- test/models/canine.rb +- test/models/cat.rb +- test/models/dog.rb +- test/models/eaters_foodstuff.rb +- test/models/frog.rb +- test/models/kitten.rb +- test/models/parentship.rb +- test/models/person.rb +- test/models/petfood.rb +- test/models/tabby.rb +- test/models/wild_boar.rb +- test/modules/extension_module.rb +- test/modules/other_extension_module.rb +- test/patches/symlinked_plugins_1.2.6.diff +- test/schema.rb +- test/setup.rb +- test/test_helper.rb +- test/unit/has_many_polymorphs_test.rb +- TODO +- has_many_polymorphs.gemspec +homepage: http://blog.evanweaver.com/files/doc/fauna/has_many_polymorphs/ +licenses: [] + +post_install_message: +rdoc_options: +- --line-numbers +- --inline-source +- --title +- Has_many_polymorphs +- --main +- README +require_paths: +- lib +required_ruby_version: !ruby/object:Gem::Requirement + none: false + requirements: + - - ">=" + - !ruby/object:Gem::Version + hash: 3 + segments: + - 0 + version: "0" +required_rubygems_version: !ruby/object:Gem::Requirement + none: false + requirements: + - - ">=" + - !ruby/object:Gem::Version + hash: 11 + segments: + - 1 + - 2 + version: "1.2" +requirements: [] + +rubyforge_project: fauna +rubygems_version: 1.8.10 +signing_key: /Users/eweaver/p/configuration/gem_certificates/evan_weaver-original-private_key.pem +specification_version: 2 +summary: An ActiveRecord plugin for self-referential and double-sided polymorphic associations. +test_files: +- test/generator/tagging_generator_test.rb +- test/integration/server_test.rb +- test/unit/has_many_polymorphs_test.rb +has_rdoc: true + diff --git a/vendor/gems/has_many_polymorphs-2.13/CHANGELOG b/vendor/gems/has_many_polymorphs-2.13/CHANGELOG new file mode 100644 index 00000000..ec8ef45f --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/CHANGELOG @@ -0,0 +1,84 @@ +v2.13. Merge various fixes for Rails 2.2.2. + +v2.12. Improvements to the test suite; bugfixes for STI children (rsl). Remove fancy dependency system in favor of using Dispatcher::to_prepare every time. + +v2.11. Rails 1.2.6 tagging generator compatibility; change test suite to use included integration app. + +v2.10. Add :parent_conditions option; bugfix for nullified conditions; bugfix for self-referential tagging generator; allow setting of has_many_polymorphs_options hash in Configuration's after_initialize if you need to adjust the autoload behavior; clear error message on missing or improperly namespaced models; fix .build on double-sided relationships; add :namespace key for easier set up of Camping apps or other unusual class structures. + +v2.9. Gem version renumbering; my apologies if this messes anyone up. + +v2.8. RDoc documentation; repository relocation; Rakefile cleanup; remove deprecated plugin-specific class caching. + +v2.7.5. Various bugfixes; Postgres problems may remain on edge. + +v2.7.3. Use new :source and :source_type options in 1.2.3 (David Lemstra); fix pluralization bug; add some tests; experimental tagging generator. + +v2.7.2. Deprecate has_many_polymorphs_cache_classes= option because it doesn't really work. Use config.cache_classes= instead to cache all reloadable items. + +v2.7.1. Dispatcher.to_prepare didn't fire in the console; now using a config.after_initialize wrapper instead. + +v2.7. Dependency injection framework elimates having to care about load order. + +v2.6. Make the logger act sane for the gem version. + +v2.5.2. Allow :skip_duplicates on double relationships. + +v2.5.1. Renamed :ignore_duplicates to :skip_duplicates to better express its non-passive behavior; made sure not to load target set on push unless necessary. + +v2.5. Activerecord compatibility branch becomes trunk: extra options now supported for double polymorphism; conditions nulled-out and propogated to child relationships; more tests; new :ignore_duplicates option on macro can be set to false if you want << to push duplicate associations. + +v2.4.1. Code split into multiple files; tests added for pluralization check; Rails 1.1.6 no longer supported. + +v2.4. Unlimited mixed class association extensions for both single and double targets and joins. + +v2.3. Gem version + +v2.2. API change; prefix on methods is now singular when using :rename_individual_collections. + +v2.1. Add configuration option to cache polymorphic classes in development mode. + +v2.0. Collection methods (push, delete, clear) now on individual collections. + +v1.9.2. Disjoint collection sides bugfix, don't raise on new records. + +v1.9.1. Double classify bugfix. + +v1.9. Large changes to properly support double polymorphism. + +v1.8.2. Bugfix to make sure the type gets checked on doubly polymorphic parents. + +v1.8.1. Bugfix for sqlite3 child attribute retrieval. + +v1.8. Bugfix for instantiating attributes of namespaced models. + +v1.7.1. Bugfix for double polymorphic relationships. + +v1.7. Double polymorphic relationships (includes new API method). + +v1.6. Namespaced model support. + +v1.5. Bugfix for Postgres and Mysql under 1.1.6; refactored tests (hildofur); properly handles legacy table names set with set_table_name(). + +v1.4. STI support added (use the child class names, not the base class). + +v1.3. Bug regarding table names with underscores in SQL query fixed. + +v1.2. License change, again. + +v1.1. File_column bug fixed. + +v1.0. Tests written; after_find and after_initialize now correctly called. + +v0.5. SQL performance enhancements added. + +v0.4. Rewrote singletons as full-fledged proxy class so that marshalling works (e.g. in the session). + +v0.3. Caching added. + +v0.2. Fixed dependency reloading problem in development mode. + +v0.1. License change. + +v0. Added :dependent support on the join table; no changelog before this version. + diff --git a/vendor/gems/has_many_polymorphs-2.13/LICENSE b/vendor/gems/has_many_polymorphs-2.13/LICENSE new file mode 100644 index 00000000..90eec26b --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/LICENSE @@ -0,0 +1,184 @@ +Academic Free License (AFL) v. 3.0 + +This Academic Free License (the "License") applies to any original work +of authorship (the "Original Work") whose owner (the "Licensor") has +placed the following licensing notice adjacent to the copyright notice +for the Original Work: + +Licensed under the Academic Free License version 3.0 + +1) Grant of Copyright License. Licensor grants You a worldwide, +royalty-free, non-exclusive, sublicensable license, for the duration of +the copyright, to do the following: + +a) to reproduce the Original Work in copies, either alone or as part of +a collective work; + +b) to translate, adapt, alter, transform, modify, or arrange the +Original Work, thereby creating derivative works ("Derivative Works") +based upon the Original Work; + +c) to distribute or communicate copies of the Original Work and +Derivative Works to the public, under any license of your choice that +does not contradict the terms and conditions, including Licensor's +reserved rights and remedies, in this Academic Free License; + +d) to perform the Original Work publicly; and + +e) to display the Original Work publicly. + +2) Grant of Patent License. Licensor grants You a worldwide, +royalty-free, non-exclusive, sublicensable license, under patent claims +owned or controlled by the Licensor that are embodied in the Original +Work as furnished by the Licensor, for the duration of the patents, to +make, use, sell, offer for sale, have made, and import the Original Work +and Derivative Works. + +3) Grant of Source Code License. The term "Source Code" means the +preferred form of the Original Work for making modifications to it and +all available documentation describing how to modify the Original Work. +Licensor agrees to provide a machine-readable copy of the Source Code of +the Original Work along with each copy of the Original Work that +Licensor distributes. Licensor reserves the right to satisfy this +obligation by placing a machine-readable copy of the Source Code in an +information repository reasonably calculated to permit inexpensive and +convenient access by You for as long as Licensor continues to distribute +the Original Work. + +4) Exclusions From License Grant. Neither the names of Licensor, nor the +names of any contributors to the Original Work, nor any of their +trademarks or service marks, may be used to endorse or promote products +derived from this Original Work without express prior permission of the +Licensor. Except as expressly stated herein, nothing in this License +grants any license to Licensor's trademarks, copyrights, patents, trade +secrets or any other intellectual property. No patent license is granted +to make, use, sell, offer for sale, have made, or import embodiments of +any patent claims other than the licensed claims defined in Section 2. +No license is granted to the trademarks of Licensor even if such marks +are included in the Original Work. Nothing in this License shall be +interpreted to prohibit Licensor from licensing under terms different +from this License any Original Work that Licensor otherwise would have a +right to license. + +5) External Deployment. The term "External Deployment" means the use, +distribution, or communication of the Original Work or Derivative Works +in any way such that the Original Work or Derivative Works may be used +by anyone other than You, whether those works are distributed or +communicated to those persons or made available as an application +intended for use over a network. As an express condition for the grants +of license hereunder, You must treat any External Deployment by You of +the Original Work or a Derivative Work as a distribution under section +1(c). + +6) Attribution Rights. You must retain, in the Source Code of any +Derivative Works that You create, all copyright, patent, or trademark +notices from the Source Code of the Original Work, as well as any +notices of licensing and any descriptive text identified therein as an +"Attribution Notice." You must cause the Source Code for any Derivative +Works that You create to carry a prominent Attribution Notice reasonably +calculated to inform recipients that You have modified the Original +Work. + +7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants +that the copyright in and to the Original Work and the patent rights +granted herein by Licensor are owned by the Licensor or are sublicensed +to You under the terms of this License with the permission of the +contributor(s) of those copyrights and patent rights. Except as +expressly stated in the immediately preceding sentence, the Original +Work is provided under this License on an "AS IS" BASIS and WITHOUT +WARRANTY, either express or implied, including, without limitation, the +warranties of non-infringement, merchantability or fitness for a +particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL +WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential +part of this License. No license to the Original Work is granted by this +License except under this disclaimer. + +8) Limitation of Liability. Under no circumstances and under no legal +theory, whether in tort (including negligence), contract, or otherwise, +shall the Licensor be liable to anyone for any indirect, special, +incidental, or consequential damages of any character arising as a +result of this License or the use of the Original Work including, +without limitation, damages for loss of goodwill, work stoppage, +computer failure or malfunction, or any and all other commercial damages +or losses. This limitation of liability shall not apply to the extent +applicable law prohibits such limitation. + +9) Acceptance and Termination. If, at any time, You expressly assented +to this License, that assent indicates your clear and irrevocable +acceptance of this License and all of its terms and conditions. If You +distribute or communicate copies of the Original Work or a Derivative +Work, You must make a reasonable effort under the circumstances to +obtain the express assent of recipients to the terms of this License. +This License conditions your rights to undertake the activities listed +in Section 1, including your right to create Derivative Works based upon +the Original Work, and doing so without honoring these terms and +conditions is prohibited by copyright law and international treaty. +Nothing in this License is intended to affect copyright exceptions and +limitations (including "fair use" or "fair dealing"). This License shall +terminate immediately and You may no longer exercise any of the rights +granted to You by this License upon your failure to honor the conditions +in Section 1(c). + +10) Termination for Patent Action. This License shall terminate +automatically and You may no longer exercise any of the rights granted +to You by this License as of the date You commence an action, including +a cross-claim or counterclaim, against Licensor or any licensee alleging +that the Original Work infringes a patent. This termination provision +shall not apply for an action alleging patent infringement by +combinations of the Original Work with other software or hardware. + +11) Jurisdiction, Venue and Governing Law. Any action or suit relating +to this License may be brought only in the courts of a jurisdiction +wherein the Licensor resides or in which Licensor conducts its primary +business, and under the laws of that jurisdiction excluding its +conflict-of-law provisions. The application of the United Nations +Convention on Contracts for the International Sale of Goods is expressly +excluded. Any use of the Original Work outside the scope of this License +or after its termination shall be subject to the requirements and +penalties of copyright or patent law in the appropriate jurisdiction. +This section shall survive the termination of this License. + +12) Attorneys' Fees. In any action to enforce the terms of this License +or seeking damages relating thereto, the prevailing party shall be +entitled to recover its costs and expenses, including, without +limitation, reasonable attorneys' fees and costs incurred in connection +with such action, including any appeal of such action. This section +shall survive the termination of this License. + +13) Miscellaneous. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. + +14) Definition of "You" in This License. "You" throughout this License, +whether in upper or lower case, means an individual or a legal entity +exercising rights under, and complying with all of the terms of, this +License. For legal entities, "You" includes any entity that controls, is +controlled by, or is under common control with you. For purposes of this +definition, "control" means (i) the power, direct or indirect, to cause +the direction or management of such entity, whether by contract or +otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +15) Right to Use. You may use the Original Work in all ways not +otherwise restricted or conditioned by this License or by law, and +Licensor promises not to interfere with or be responsible for such uses +by You. + +16) Modification of This License. This License is Copyright (c) 2005 +Lawrence Rosen. Permission is granted to copy, distribute, or +communicate this License without modification. Nothing in this License +permits You to modify this License as applied to the Original Work or to +Derivative Works. However, You may modify the text of this License and +copy, distribute or communicate your modified version (the "Modified +License") and apply it to other original works of authorship subject to +the following conditions: (i) You may not indicate in any way that your +Modified License is the "Academic Free License" or "AFL" and you may not +use those names in the name of your Modified License; (ii) You must +replace the notice specified in the first paragraph above with the +notice "Licensed under " or with a notice +of your own that is not confusingly similar to the notice in this +License; and (iii) You may not claim that your original works are open +source software unless your Modified License has been approved by Open +Source Initiative (OSI) and You comply with its license review and +certification process. + diff --git a/vendor/gems/has_many_polymorphs-2.13/Manifest b/vendor/gems/has_many_polymorphs-2.13/Manifest new file mode 100644 index 00000000..c0555eff --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/Manifest @@ -0,0 +1,173 @@ +CHANGELOG +examples/hmph.rb +generators/tagging/tagging_generator.rb +generators/tagging/templates/migration.rb +generators/tagging/templates/tag.rb +generators/tagging/templates/tag_test.rb +generators/tagging/templates/tagging.rb +generators/tagging/templates/tagging_extensions.rb +generators/tagging/templates/tagging_test.rb +generators/tagging/templates/taggings.yml +generators/tagging/templates/tags.yml +init.rb +lib/has_many_polymorphs/association.rb +lib/has_many_polymorphs/autoload.rb +lib/has_many_polymorphs/base.rb +lib/has_many_polymorphs/class_methods.rb +lib/has_many_polymorphs/configuration.rb +lib/has_many_polymorphs/debugging_tools.rb +lib/has_many_polymorphs/rake_task_redefine_task.rb +lib/has_many_polymorphs/reflection.rb +lib/has_many_polymorphs/support_methods.rb +lib/has_many_polymorphs.rb +LICENSE +Manifest +Rakefile +README +test/fixtures/bow_wows.yml +test/fixtures/cats.yml +test/fixtures/eaters_foodstuffs.yml +test/fixtures/fish.yml +test/fixtures/frogs.yml +test/fixtures/keep_your_enemies_close.yml +test/fixtures/little_whale_pupils.yml +test/fixtures/people.yml +test/fixtures/petfoods.yml +test/fixtures/whales.yml +test/fixtures/wild_boars.yml +test/generator/tagging_generator_test.rb +test/integration/app/app/controllers/application.rb +test/integration/app/app/controllers/bones_controller.rb +test/integration/app/app/helpers/addresses_helper.rb +test/integration/app/app/helpers/application_helper.rb +test/integration/app/app/helpers/bones_helper.rb +test/integration/app/app/helpers/sellers_helper.rb +test/integration/app/app/helpers/states_helper.rb +test/integration/app/app/helpers/users_helper.rb +test/integration/app/app/models/bone.rb +test/integration/app/app/models/double_sti_parent.rb +test/integration/app/app/models/double_sti_parent_relationship.rb +test/integration/app/app/models/organic_substance.rb +test/integration/app/app/models/single_sti_parent.rb +test/integration/app/app/models/single_sti_parent_relationship.rb +test/integration/app/app/models/stick.rb +test/integration/app/app/models/stone.rb +test/integration/app/app/views/addresses/edit.html.erb +test/integration/app/app/views/addresses/index.html.erb +test/integration/app/app/views/addresses/new.html.erb +test/integration/app/app/views/addresses/show.html.erb +test/integration/app/app/views/bones/index.rhtml +test/integration/app/app/views/layouts/addresses.html.erb +test/integration/app/app/views/layouts/sellers.html.erb +test/integration/app/app/views/layouts/states.html.erb +test/integration/app/app/views/layouts/users.html.erb +test/integration/app/app/views/sellers/edit.html.erb +test/integration/app/app/views/sellers/index.html.erb +test/integration/app/app/views/sellers/new.html.erb +test/integration/app/app/views/sellers/show.html.erb +test/integration/app/app/views/states/edit.html.erb +test/integration/app/app/views/states/index.html.erb +test/integration/app/app/views/states/new.html.erb +test/integration/app/app/views/states/show.html.erb +test/integration/app/app/views/users/edit.html.erb +test/integration/app/app/views/users/index.html.erb +test/integration/app/app/views/users/new.html.erb +test/integration/app/app/views/users/show.html.erb +test/integration/app/config/boot.rb +test/integration/app/config/database.yml +test/integration/app/config/environment.rb +test/integration/app/config/environment.rb.canonical +test/integration/app/config/environments/development.rb +test/integration/app/config/environments/production.rb +test/integration/app/config/environments/test.rb +test/integration/app/config/locomotive.yml +test/integration/app/config/routes.rb +test/integration/app/config/ultrasphinx/default.base +test/integration/app/config/ultrasphinx/development.conf.canonical +test/integration/app/db/migrate/001_create_sticks.rb +test/integration/app/db/migrate/002_create_stones.rb +test/integration/app/db/migrate/003_create_organic_substances.rb +test/integration/app/db/migrate/004_create_bones.rb +test/integration/app/db/migrate/005_create_single_sti_parents.rb +test/integration/app/db/migrate/006_create_double_sti_parents.rb +test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb +test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb +test/integration/app/db/migrate/009_create_library_model.rb +test/integration/app/doc/README_FOR_APP +test/integration/app/generators/commenting_generator_test.rb +test/integration/app/lib/library_model.rb +test/integration/app/public/404.html +test/integration/app/public/500.html +test/integration/app/public/dispatch.cgi +test/integration/app/public/dispatch.fcgi +test/integration/app/public/dispatch.rb +test/integration/app/public/favicon.ico +test/integration/app/public/images/rails.png +test/integration/app/public/index.html +test/integration/app/public/javascripts/application.js +test/integration/app/public/javascripts/controls.js +test/integration/app/public/javascripts/dragdrop.js +test/integration/app/public/javascripts/effects.js +test/integration/app/public/javascripts/prototype.js +test/integration/app/public/robots.txt +test/integration/app/public/stylesheets/scaffold.css +test/integration/app/Rakefile +test/integration/app/README +test/integration/app/script/about +test/integration/app/script/breakpointer +test/integration/app/script/console +test/integration/app/script/destroy +test/integration/app/script/generate +test/integration/app/script/performance/benchmarker +test/integration/app/script/performance/profiler +test/integration/app/script/plugin +test/integration/app/script/process/inspector +test/integration/app/script/process/reaper +test/integration/app/script/process/spawner +test/integration/app/script/runner +test/integration/app/script/server +test/integration/app/test/fixtures/double_sti_parent_relationships.yml +test/integration/app/test/fixtures/double_sti_parents.yml +test/integration/app/test/fixtures/organic_substances.yml +test/integration/app/test/fixtures/single_sti_parent_relationships.yml +test/integration/app/test/fixtures/single_sti_parents.yml +test/integration/app/test/fixtures/sticks.yml +test/integration/app/test/fixtures/stones.yml +test/integration/app/test/functional/addresses_controller_test.rb +test/integration/app/test/functional/bones_controller_test.rb +test/integration/app/test/functional/sellers_controller_test.rb +test/integration/app/test/functional/states_controller_test.rb +test/integration/app/test/functional/users_controller_test.rb +test/integration/app/test/test_helper.rb +test/integration/app/test/unit/bone_test.rb +test/integration/app/test/unit/double_sti_parent_relationship_test.rb +test/integration/app/test/unit/double_sti_parent_test.rb +test/integration/app/test/unit/organic_substance_test.rb +test/integration/app/test/unit/single_sti_parent_relationship_test.rb +test/integration/app/test/unit/single_sti_parent_test.rb +test/integration/app/test/unit/stick_test.rb +test/integration/app/test/unit/stone_test.rb +test/integration/server_test.rb +test/models/aquatic/fish.rb +test/models/aquatic/pupils_whale.rb +test/models/aquatic/whale.rb +test/models/beautiful_fight_relationship.rb +test/models/canine.rb +test/models/cat.rb +test/models/dog.rb +test/models/eaters_foodstuff.rb +test/models/frog.rb +test/models/kitten.rb +test/models/parentship.rb +test/models/person.rb +test/models/petfood.rb +test/models/tabby.rb +test/models/wild_boar.rb +test/modules/extension_module.rb +test/modules/other_extension_module.rb +test/patches/symlinked_plugins_1.2.6.diff +test/schema.rb +test/setup.rb +test/test_helper.rb +test/unit/has_many_polymorphs_test.rb +TODO diff --git a/vendor/gems/has_many_polymorphs-2.13/README b/vendor/gems/has_many_polymorphs-2.13/README new file mode 100644 index 00000000..2f3f73f9 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/README @@ -0,0 +1,205 @@ +Has_many_polymorphs + +An ActiveRecord plugin for self-referential and double-sided polymorphic associations. + +== License + +Copyright 2006-2008 Cloudburst, LLC. Licensed under the AFL 3. See the included LICENSE file. + +The public certificate for the gem is here[http://rubyforge.org/frs/download.php/25331/evan_weaver-original-public_cert.pem]. + +If you use this software, please {make a donation}[http://blog.evanweaver.com/donate/], or {recommend Evan}[http://www.workingwithrails.com/person/7739-evan-weaver] at Working with Rails. + +== Description + +This plugin lets you define self-referential and double-sided polymorphic associations in your models. It is an extension of has_many :through. + +“Polymorphic” means an association can freely point to any of several unrelated model classes, instead of being tied to one particular class. + +== Features + +* self-references +* double-sided polymorphism +* efficient database usage +* STI support +* namespace support +* automatic individual and reverse associations + +The plugin also includes a generator for a tagging system, a common use case (see below). + +== Requirements + +* Rails 2.2.2 or greater + += Usage + +== Installation + +To install the Rails plugin, run: + script/plugin install git://github.com/fauna/has_many_polymorphs.git + +There's also a gem version. To install it instead, run: + sudo gem install has_many_polymorphs + +If you are using the gem, make sure to add require 'has_many_polymorphs' to environment.rb, before Rails::Initializer block. + +== Configuration + +Setup the parent model as so: + + class Kennel < ActiveRecord::Base + has_many_polymorphs :guests, :from => [:dogs, :cats, :birds] + end + +The join model: + + class GuestsKennel < ActiveRecord::Base + belongs_to :kennel + belongs_to :guest, :polymorphic => true + end + +One of the child models: + + class Dog < ActiveRecord::Base + # nothing + end + +For your parent and child models, you don't need any special fields in your migration. For the join model (GuestsKennel), use a migration like so: + + class CreateGuestsKennels < ActiveRecord::Migration + def self.up + create_table :guests_kennels do |t| + t.references :guest, :polymorphic => true + t.references :kennel + end + end + + def self.down + drop_table :guests_kennels + end + end + +See ActiveRecord::Associations::PolymorphicClassMethods for more configuration options. + +== Helper methods example + + >> k = Kennel.find(1) + # + >> k.guests.map(&:class) + [Dog, Cat, Cat, Bird] + + >> k.guests.push(Cat.create); k.cats.size + 3 + >> k.guests << Cat.create; k.cats.size + 4 + >> k.guests.size + 6 + + >> d = k.dogs.first + # + >> d.kennels + [#] + + >> k.guests.delete(d); k.dogs.size + 0 + >> k.guests.size + 5 + +Note that the parent method is always plural, even if there is only one parent (Dog#kennels, not Dog#kennel). + +See ActiveRecord::Associations::PolymorphicAssociation for more helper method details. + += Extras + +== Double-sided polymorphism + +Double-sided relationships are defined on the join model: + + class Devouring < ActiveRecord::Base + belongs_to :guest, :polymorphic => true + belongs_to :eaten, :polymorphic => true + + acts_as_double_polymorphic_join( + :guests =>[:dogs, :cats], + :eatens => [:cats, :birds] + ) + end + +Now, dogs and cats can eat birds and cats. Birds can't eat anything (they aren't guests) and dogs can't be eaten by anything (since they aren't eatens). The keys stand for what the models are, not what they do. + +In this case, each guest/eaten relationship is called a Devouring. + +In your migration, you need to declare both sides as polymorphic: + + class CreateDevourings < ActiveRecord::Migration + def self.up + create_table :devourings do |t| + t.references :guest, :polymorphic => true + t.references :eaten, :polymorphic => true + end + end + + def self.down + drop_table :devourings + end + end + +See ActiveRecord::Associations::PolymorphicClassMethods for more. + +== Tagging generator + +Has_many_polymorphs includes a tagging system generator. Run: + script/generate tagging Dog Cat [...MoreModels...] + +This adds a migration and new Tag and Tagging models in app/models. It configures Tag with an appropriate has_many_polymorphs call against the models you list at the command line. It also adds the file lib/tagging_extensions.rb and requires it in environment.rb. + +Tests will also be generated. + +Once you've run the generator, you can tag records as follows: + + >> d = Dog.create(:name => "Rover") + # + >> d.tag_list + "" + >> d.tag_with "fierce loud" + # + >> d.tag_list + "fierce loud" + >> c = Cat.create(:name => "Chloe") + # + >> c.tag_with "fierce cute" + # + >> c.tag_list + "cute fierce" + >> Tag.find_by_name("fierce").taggables + [#, #] + +The generator accepts the optional flag --skip-migration to skip generating a migration (for example, if you are converting from acts_as_taggable). It also accepts the flag --self-referential if you want to be able to tag tags. + +See ActiveRecord::Base::TaggingExtensions, Tag, and Tagging for more. + +== Troubleshooting + +Some debugging tools are available in lib/has_many_polymorphs/debugging_tools.rb. + +If you are having trouble, think very carefully about how your model classes, key columns, and table names relate. You may have to explicitly specify options on your join model such as :class_name, :foreign_key, or :as. The included tests are a good place to look for examples. + +Note that because of the way Rails reloads model classes, the plugin can sometimes bog down your development server. Set config.cache_classes = true in config/environments/development.rb to avoid this. + +== Reporting problems + +The support forum is here[http://rubyforge.org/forum/forum.php?forum_id=16450]. + +Patches and contributions are very welcome. Please note that contributors are required to assign copyright for their additions to Cloudburst, LLC. + +== Further resources + +* http://blog.evanweaver.com/articles/2007/08/15/polymorphs-tutorial +* http://blog.evanweaver.com/articles/2007/02/22/polymorphs-25-total-insanity-branch +* http://blog.evanweaver.com/articles/2007/02/09/how-to-find-the-most-popular-tags +* http://blog.evanweaver.com/articles/2007/01/13/growing-up-your-acts_as_taggable +* http://blog.evanweaver.com/articles/2006/12/02/polymorphs-19 +* http://blog.evanweaver.com/articles/2006/11/05/directed-double-polymorphic-associations +* http://blog.evanweaver.com/articles/2006/11/04/namespaced-model-support-in-has_many_polymorphs +* http://blog.evanweaver.com/articles/2006/09/26/sti-support-in-has_many_polymorphs +* http://blog.evanweaver.com/articles/2006/09/11/make-polymorphic-children-belong-to-only-one-parent diff --git a/vendor/gems/has_many_polymorphs-2.13/Rakefile b/vendor/gems/has_many_polymorphs-2.13/Rakefile new file mode 100644 index 00000000..b93a94f5 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/Rakefile @@ -0,0 +1,28 @@ + +require 'echoe' + +Echoe.new("has_many_polymorphs") do |p| + p.project = "fauna" + p.summary = "An ActiveRecord plugin for self-referential and double-sided polymorphic associations." + p.url = "http://blog.evanweaver.com/files/doc/fauna/has_many_polymorphs/" + p.docs_host = "blog.evanweaver.com:~/www/bax/public/files/doc/" + p.dependencies = ["activerecord"] + p.rdoc_pattern = /polymorphs\/association|polymorphs\/class_methods|polymorphs\/reflection|polymorphs\/autoload|polymorphs\/configuration|README|CHANGELOG|TODO|LICENSE|templates\/migration\.rb|templates\/tag\.rb|templates\/tagging\.rb|templates\/tagging_extensions\.rb/ + p.require_signed = true + p.clean_pattern += ["**/ruby_sess*", "**/generated_models/**"] + p.test_pattern = ["test/unit/*_test.rb", "test/integration/*_test.rb", "test/generator/*_test.rb"] +end + +desc "Run all the tests for every database adapter" +task "test_all" do + ['mysql', 'postgresql', 'sqlite3'].each do |adapter| + ENV['DB'] = adapter + ENV['PRODUCTION'] = nil + STDERR.puts "#{'='*80}\nDevelopment mode for #{adapter}\n#{'='*80}" + system("rake test:multi_rails:all") + + ENV['PRODUCTION'] = '1' + STDERR.puts "#{'='*80}\nProduction mode for #{adapter}\n#{'='*80}" + system("rake test:multi_rails:all") + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/TODO b/vendor/gems/has_many_polymorphs-2.13/TODO new file mode 100644 index 00000000..b06e28f2 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/TODO @@ -0,0 +1,2 @@ + +* Tag cloud method diff --git a/vendor/gems/has_many_polymorphs-2.13/examples/hmph.rb b/vendor/gems/has_many_polymorphs-2.13/examples/hmph.rb new file mode 100644 index 00000000..67017505 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/examples/hmph.rb @@ -0,0 +1,69 @@ +require 'camping' +require 'has_many_polymorphs' + +Camping.goes :Hmph + +module Hmph::Models + class GuestsKennel < Base + belongs_to :kennel + belongs_to :guest, :polymorphic => true + end + + class Dog < Base + end + + class Cat < Base + end + + class Bird < Base + end + + class Kennel < Base + has_many_polymorphs :guests, + :from => [:dogs, :cats, :birds], + :through => :guests_kennels, + :namespace => :"hmph/models/" + end + + class InitialSchema < V 1.0 + def self.up + create_table :hmph_kennels do |t| + t.column :created_at, :datetime + t.column :modified_at, :datetime + t.column :name, :string, :default => 'Anonymous Kennel' + end + + create_table :hmph_guests_kennels do |t| + t.column :guest_id, :integer + t.column :guest_type, :string + t.column :kennel_id, :integer + end + + create_table :hmph_dogs do |t| + t.column :name, :string, :default => 'Fido' + end + + create_table :hmph_cats do |t| + t.column :name, :string, :default => 'Morris' + end + + create_table :hmph_birds do |t| + t.column :name, :string, :default => 'Polly' + end + end + + def self.down + drop_table :hmph_kennels + drop_table :hmph_guests_kennels + drop_table :hmph_dogs + drop_table :hmph_cats + drop_table :hmph_birds + end + end +end + +module Hmph::Controllers +end + +module Hmph::Views +end diff --git a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/tagging_generator.rb b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/tagging_generator.rb new file mode 100644 index 00000000..d99b10f8 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/tagging_generator.rb @@ -0,0 +1,97 @@ +require 'ruby-debug' and Debugger.start if ENV['USER'] == 'eweaver' + +class TaggingGenerator < Rails::Generator::NamedBase + default_options :skip_migration => false + default_options :self_referential => false + attr_reader :parent_association_name + attr_reader :taggable_models + + def initialize(runtime_args, runtime_options = {}) + parse!(runtime_args, runtime_options) + + @parent_association_name = (runtime_args.include?("--self-referential") ? "tagger" : "tag") + @taggable_models = runtime_args.reject{|opt| opt =~ /^--/}.map do |taggable| + ":" + taggable.underscore.pluralize + end + @taggable_models += [":tags"] if runtime_args.include?("--self-referential") + @taggable_models.uniq! + + verify @taggable_models + hacks + runtime_args.unshift("placeholder") + super + end + + def verify models + puts "** Warning: only one taggable model specified; tests may not run properly." if models.size < 2 + models.each do |model| + model = model[1..-1].classify + next if model == "Tag" # don't load ourselves when --self-referential is used + self.class.const_get(model) rescue puts "** Error: model #{model[1..-1].classify} could not be loaded." or exit + end + end + + def hacks + # add the extension require in environment.rb + phrase = "require 'tagging_extensions'" + filename = "#{RAILS_ROOT}/config/environment.rb" + unless (open(filename) do |file| + file.grep(/#{Regexp.escape phrase}/).any? + end) + open(filename, 'a+') do |file| + file.puts "\n" + phrase + "\n" + end + end + end + + def manifest + record do |m| + m.class_collisions class_path, class_name, "#{class_name}Test" + + m.directory File.join('app/models', class_path) + m.directory File.join('test/unit', class_path) + m.directory File.join('test/fixtures', class_path) + m.directory File.join('test/fixtures', class_path) + m.directory File.join('lib') + + m.template 'tag.rb', File.join('app/models', class_path, "tag.rb") + m.template 'tag_test.rb', File.join('test/unit', class_path, "tag_test.rb") + m.template 'tags.yml', File.join('test/fixtures', class_path, "tags.yml") + + m.template 'tagging.rb', File.join('app/models', class_path, "tagging.rb") + m.template 'tagging_test.rb', File.join('test/unit', class_path, "tagging_test.rb") + m.template 'taggings.yml', File.join('test/fixtures', class_path, "taggings.yml") + + m.template 'tagging_extensions.rb', File.join('lib', 'tagging_extensions.rb') + + unless options[:skip_migration] + m.migration_template 'migration.rb', 'db/migrate', + :migration_file_name => "create_tags_and_taggings" + end + + end + end + + protected + def banner + "Usage: #{$0} generate tagging [TaggableModelA TaggableModelB ...]" + end + + def add_options!(opt) + opt.separator '' + opt.separator 'Options:' + opt.on("--skip-migration", + "Don't generate a migration file for this model") { |v| options[:skip_migration] = v } + opt.on("--self-referential", + "Allow tags to tag themselves.") { |v| options[:self_referential] = v } + end + + # Useful for generating tests/fixtures + def model_one + taggable_models[0][1..-1].classify + end + + def model_two + taggable_models[1][1..-1].classify rescue model_one + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/migration.rb b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/migration.rb new file mode 100644 index 00000000..582b54c6 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/migration.rb @@ -0,0 +1,28 @@ + +# A migration to add tables for Tag and Tagging. This file is automatically generated and added to your app if you run the tagging generator included with has_many_polymorphs. + +class CreateTagsAndTaggings < ActiveRecord::Migration + + # Add the new tables. + def self.up + create_table :tags do |t| + t.column :name, :string, :null => false + end + add_index :tags, :name, :unique => true + + create_table :taggings do |t| + t.column :<%= parent_association_name -%>_id, :integer, :null => false + t.column :taggable_id, :integer, :null => false + t.column :taggable_type, :string, :null => false + # t.column :position, :integer # Uncomment this if you need to use acts_as_list. + end + add_index :taggings, [:<%= parent_association_name -%>_id, :taggable_id, :taggable_type], :unique => true + end + + # Remove the tables. + def self.down + drop_table :tags + drop_table :taggings + end + +end diff --git a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tag.rb b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tag.rb new file mode 100644 index 00000000..1966a76b --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tag.rb @@ -0,0 +1,39 @@ + +# The Tag model. This model is automatically generated and added to your app if you run the tagging generator included with has_many_polymorphs. + +class Tag < ActiveRecord::Base + + DELIMITER = " " # Controls how to split and join tagnames from strings. You may need to change the validates_format_of parameters if you change this. + + # If database speed becomes an issue, you could remove these validations and rescue the ActiveRecord database constraint errors instead. + validates_presence_of :name + validates_uniqueness_of :name, :case_sensitive => false + + # Change this validation if you need more complex tag names. + validates_format_of :name, :with => /^[a-zA-Z0-9\_\-]+$/, :message => "can not contain special characters" + + # Set up the polymorphic relationship. + has_many_polymorphs :taggables, + :from => [<%= taggable_models.join(", ") %>], + :through => :taggings, + :dependent => :destroy, +<% if options[:self_referential] -%> :as => :<%= parent_association_name -%>, +<% end -%> + :skip_duplicates => false, + :parent_extend => proc { + # Defined on the taggable models, not on Tag itself. Return the tagnames associated with this record as a string. + def to_s + self.map(&:name).sort.join(Tag::DELIMITER) + end + } + + # Callback to strip extra spaces from the tagname before saving it. If you allow tags to be renamed later, you might want to use the before_save callback instead. + def before_create + self.name = name.downcase.strip.squeeze(" ") + end + + # Tag::Error class. Raised by ActiveRecord::Base::TaggingExtensions if something goes wrong. + class Error < StandardError + end + +end diff --git a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tag_test.rb b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tag_test.rb new file mode 100644 index 00000000..f4ab543a --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tag_test.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class TagTest < Test::Unit::TestCase + fixtures <%= taggable_models[0..1].join(", ") -%> + + def setup + @obj = <%= model_two %>.find(:first) + @obj.tag_with "pale imperial" + end + + def test_to_s + assert_equal "imperial pale", <%= model_two -%>.find(:first).tags.to_s + end + +end diff --git a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging.rb b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging.rb new file mode 100644 index 00000000..bb5ea28f --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging.rb @@ -0,0 +1,16 @@ + +# The Tagging join model. This model is automatically generated and added to your app if you run the tagging generator included with has_many_polymorphs. + +class Tagging < ActiveRecord::Base + + belongs_to :<%= parent_association_name -%><%= ", :foreign_key => \"#{parent_association_name}_id\", :class_name => \"Tag\"" if options[:self_referential] %> + belongs_to :taggable, :polymorphic => true + + # If you also need to use acts_as_list, you will have to manage the tagging positions manually by creating decorated join records when you associate Tags with taggables. + # acts_as_list :scope => :taggable + + # This callback makes sure that an orphaned Tag is deleted if it no longer tags anything. + def after_destroy + <%= parent_association_name -%>.destroy_without_callbacks if <%= parent_association_name -%> and <%= parent_association_name -%>.taggings.count == 0 + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging_extensions.rb b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging_extensions.rb new file mode 100644 index 00000000..ca7e6add --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging_extensions.rb @@ -0,0 +1,203 @@ +class ActiveRecord::Base #:nodoc: + + # These extensions make models taggable. This file is automatically generated and required by your app if you run the tagging generator included with has_many_polymorphs. + module TaggingExtensions + + # Add tags to self. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags. + # + # We need to avoid name conflicts with the built-in ActiveRecord association methods, thus the underscores. + def _add_tags incoming + taggable?(true) + tag_cast_to_string(incoming).each do |tag_name| + begin + tag = Tag.find_or_create_by_name(tag_name) + raise Tag::Error, "tag could not be saved: #{tag_name}" if tag.new_record? + tags << tag + rescue ActiveRecord::StatementInvalid => e + raise unless e.to_s =~ /duplicate/i + end + end + end + + # Removes tags from self. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags. + def _remove_tags outgoing + taggable?(true) + outgoing = tag_cast_to_string(outgoing) + <% if options[:self_referential] %> + # because of http://dev.rubyonrails.org/ticket/6466 + taggings.destroy(*(taggings.find(:all, :include => :<%= parent_association_name -%>).select do |tagging| + outgoing.include? tagging.<%= parent_association_name -%>.name + end)) + <% else -%> + <%= parent_association_name -%>s.delete(*(<%= parent_association_name -%>s.select do |tag| + outgoing.include? tag.name + end)) + <% end -%> + end + + # Returns the tags on self as a string. + def tag_list + # Redefined later to avoid an RDoc parse error. + end + + # Replace the existing tags on self. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags. + def tag_with list + #:stopdoc: + taggable?(true) + list = tag_cast_to_string(list) + + # Transactions may not be ideal for you here; be aware. + Tag.transaction do + current = <%= parent_association_name -%>s.map(&:name) + _add_tags(list - current) + _remove_tags(current - list) + end + + self + #:startdoc: + end + + # Returns the tags on self as a string. + def tag_list #:nodoc: + #:stopdoc: + taggable?(true) + <%= parent_association_name -%>s.reload + <%= parent_association_name -%>s.to_s + #:startdoc: + end + + def tag_list=(value) + tag_with(value) + end + + private + + def tag_cast_to_string obj #:nodoc: + case obj + when Array + obj.map! do |item| + case item + when /^\d+$/, Fixnum then Tag.find(item).name # This will be slow if you use ids a lot. + when Tag then item.name + when String then item + else + raise "Invalid type" + end + end + when String + obj = obj.split(Tag::DELIMITER).map do |tag_name| + tag_name.strip.squeeze(" ") + end + else + raise "Invalid object of class #{obj.class} as tagging method parameter" + end.flatten.compact.map(&:downcase).uniq + end + + # Check if a model is in the :taggables target list. The alternative to this check is to explicitly include a TaggingMethods module (which you would create) in each target model. + def taggable?(should_raise = false) #:nodoc: + unless flag = respond_to?(:<%= parent_association_name -%>s) + raise "#{self.class} is not a taggable model" if should_raise + end + flag + end + + end + + module TaggingFinders + # Find all the objects tagged with the supplied list of tags + # + # Usage : Model.tagged_with("ruby") + # Model.tagged_with("hello", "world") + # Model.tagged_with("hello", "world", :limit => 10) + # + # XXX This query strategy is not performant, and needs to be rewritten as an inverted join or a series of unions + # + def tagged_with(*tag_list) + options = tag_list.last.is_a?(Hash) ? tag_list.pop : {} + tag_list = parse_tags(tag_list) + + scope = scope(:find) + options[:select] ||= "#{table_name}.*" + options[:from] ||= "#{table_name}, tags, taggings" + + sql = "SELECT #{(scope && scope[:select]) || options[:select]} " + sql << "FROM #{(scope && scope[:from]) || options[:from]} " + + add_joins!(sql, options[:joins], scope) + + sql << "WHERE #{table_name}.#{primary_key} = taggings.taggable_id " + sql << "AND taggings.taggable_type = '#{ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s}' " + sql << "AND taggings.tag_id = tags.id " + + tag_list_condition = tag_list.map {|name| "'#{name}'"}.join(", ") + + sql << "AND (tags.name IN (#{sanitize_sql(tag_list_condition)})) " + sql << "AND #{sanitize_sql(options[:conditions])} " if options[:conditions] + + columns = column_names.map do |column| + "#{table_name}.#{column}" + end.join(", ") + + sql << "GROUP BY #{columns} " + sql << "HAVING COUNT(taggings.tag_id) = #{tag_list.size}" + + add_order!(sql, options[:order], scope) + add_limit!(sql, options, scope) + add_lock!(sql, options, scope) + + find_by_sql(sql) + end + + def self.tagged_with_any(*tag_list) + options = tag_list.last.is_a?(Hash) ? tag_list.pop : {} + tag_list = parse_tags(tag_list) + + scope = scope(:find) + options[:select] ||= "#{table_name}.*" + options[:from] ||= "#{table_name}, meta_tags, taggings" + + sql = "SELECT #{(scope && scope[:select]) || options[:select]} " + sql << "FROM #{(scope && scope[:from]) || options[:from]} " + + add_joins!(sql, options, scope) + + sql << "WHERE #{table_name}.#{primary_key} = taggings.taggable_id " + sql << "AND taggings.taggable_type = '#{ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s}' " + sql << "AND taggings.meta_tag_id = meta_tags.id " + + sql << "AND (" + or_options = [] + tag_list.each do |name| + or_options << "meta_tags.name = '#{name}'" + end + or_options_joined = or_options.join(" OR ") + sql << "#{or_options_joined}) " + + + sql << "AND #{sanitize_sql(options[:conditions])} " if options[:conditions] + + columns = column_names.map do |column| + "#{table_name}.#{column}" + end.join(", ") + + sql << "GROUP BY #{columns} " + + add_order!(sql, options[:order], scope) + add_limit!(sql, options, scope) + add_lock!(sql, options, scope) + + find_by_sql(sql) + end + + def parse_tags(tags) + return [] if tags.blank? + tags = Array(tags).first + tags = tags.respond_to?(:flatten) ? tags.flatten : tags.split(Tag::DELIMITER) + tags.map { |tag| tag.strip.squeeze(" ") }.flatten.compact.map(&:downcase).uniq + end + + end + + include TaggingExtensions + extend TaggingFinders +end diff --git a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging_test.rb b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging_test.rb new file mode 100644 index 00000000..f055d381 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging_test.rb @@ -0,0 +1,85 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class TaggingTest < Test::Unit::TestCase + fixtures :tags, :taggings, <%= taggable_models[0..1].join(", ") -%> + + def setup + @objs = <%= model_two %>.find(:all, :limit => 2) + + @obj1 = @objs[0] + @obj1.tag_with("pale") + @obj1.reload + + @obj2 = @objs[1] + @obj2.tag_with("pale imperial") + @obj2.reload + +<% if taggable_models.size > 1 -%> + @obj3 = <%= model_one -%>.find(:first) +<% end -%> + @tag1 = Tag.find(1) + @tag2 = Tag.find(2) + @tagging1 = Tagging.find(1) + end + + def test_tag_with + @obj2.tag_with "hoppy pilsner" + assert_equal "hoppy pilsner", @obj2.tag_list + end + + def test_find_tagged_with + @obj1.tag_with "seasonal lager ipa" + @obj2.tag_with ["lager", "stout", "fruity", "seasonal"] + + result1 = [@obj1] + assert_equal <%= model_two %>.tagged_with("ipa"), result1 + assert_equal <%= model_two %>.tagged_with("ipa lager"), result1 + assert_equal <%= model_two %>.tagged_with("ipa", "lager"), result1 + + result2 = [@obj1.id, @obj2.id].sort + assert_equal <%= model_two %>.tagged_with("seasonal").map(&:id).sort, result2 + assert_equal <%= model_two %>.tagged_with("seasonal lager").map(&:id).sort, result2 + assert_equal <%= model_two %>.tagged_with("seasonal", "lager").map(&:id).sort, result2 + end + +<% if options[:self_referential] -%> + def test_self_referential_tag_with + @tag1.tag_with [1, 2] + assert @tag1.tags.include?(@tag1) + assert !@tag2.tags.include?(@tag1) + end + +<% end -%> + def test__add_tags + @obj1._add_tags "porter longneck" + assert Tag.find_by_name("porter").taggables.include?(@obj1) + assert Tag.find_by_name("longneck").taggables.include?(@obj1) + assert_equal "longneck pale porter", @obj1.tag_list + + @obj1._add_tags [2] + assert_equal "imperial longneck pale porter", @obj1.tag_list + end + + def test__remove_tags + @obj2._remove_tags ["2", @tag1] + assert @obj2.tags.empty? + end + + def test_tag_list + assert_equal "imperial pale", @obj2.tag_list + end + + def test_taggable + assert_raises(RuntimeError) do + @tagging1.send(:taggable?, true) + end + assert !@tagging1.send(:taggable?) +<% if taggable_models.size > 1 -%> + assert @obj3.send(:taggable?) +<% end -%> +<% if options[:self_referential] -%> + assert @tag1.send(:taggable?) +<% end -%> + end + +end diff --git a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/taggings.yml b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/taggings.yml new file mode 100644 index 00000000..0cf13b9d --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/taggings.yml @@ -0,0 +1,23 @@ +--- +<% if taggable_models.size > 1 -%> +taggings_003: + <%= parent_association_name -%>_id: "2" + id: "3" + taggable_type: <%= model_one %> + taggable_id: "1" +<% end -%> +taggings_004: + <%= parent_association_name -%>_id: "2" + id: "4" + taggable_type: <%= model_two %> + taggable_id: "2" +taggings_001: + <%= parent_association_name -%>_id: "1" + id: "1" + taggable_type: <%= model_two %> + taggable_id: "1" +taggings_002: + <%= parent_association_name -%>_id: "1" + id: "2" + taggable_type: <%= model_two %> + taggable_id: "2" diff --git a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tags.yml b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tags.yml new file mode 100644 index 00000000..517a8ce5 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tags.yml @@ -0,0 +1,7 @@ +--- +tags_001: + name: pale + id: "1" +tags_002: + name: imperial + id: "2" diff --git a/vendor/gems/has_many_polymorphs-2.13/has_many_polymorphs.gemspec b/vendor/gems/has_many_polymorphs-2.13/has_many_polymorphs.gemspec new file mode 100644 index 00000000..3e1a69b7 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/has_many_polymorphs.gemspec @@ -0,0 +1,40 @@ +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = %q{has_many_polymorphs} + s.version = "2.13" + + s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version= + s.authors = [""] + s.cert_chain = ["/Users/eweaver/p/configuration/gem_certificates/evan_weaver-original-public_cert.pem"] + s.date = %q{2009-02-02} + s.description = %q{An ActiveRecord plugin for self-referential and double-sided polymorphic associations.} + s.email = %q{} + s.extra_rdoc_files = ["CHANGELOG", "generators/tagging/templates/migration.rb", "generators/tagging/templates/tag.rb", "generators/tagging/templates/tagging.rb", "generators/tagging/templates/tagging_extensions.rb", "lib/has_many_polymorphs/association.rb", "lib/has_many_polymorphs/autoload.rb", "lib/has_many_polymorphs/class_methods.rb", "lib/has_many_polymorphs/configuration.rb", "lib/has_many_polymorphs/reflection.rb", "LICENSE", "README", "test/integration/app/doc/README_FOR_APP", "test/integration/app/README", "TODO"] + s.files = ["CHANGELOG", "examples/hmph.rb", "generators/tagging/tagging_generator.rb", "generators/tagging/templates/migration.rb", "generators/tagging/templates/tag.rb", "generators/tagging/templates/tag_test.rb", "generators/tagging/templates/tagging.rb", "generators/tagging/templates/tagging_extensions.rb", "generators/tagging/templates/tagging_test.rb", "generators/tagging/templates/taggings.yml", "generators/tagging/templates/tags.yml", "init.rb", "lib/has_many_polymorphs/association.rb", "lib/has_many_polymorphs/autoload.rb", "lib/has_many_polymorphs/base.rb", "lib/has_many_polymorphs/class_methods.rb", "lib/has_many_polymorphs/configuration.rb", "lib/has_many_polymorphs/debugging_tools.rb", "lib/has_many_polymorphs/rake_task_redefine_task.rb", "lib/has_many_polymorphs/reflection.rb", "lib/has_many_polymorphs/support_methods.rb", "lib/has_many_polymorphs.rb", "LICENSE", "Manifest", "Rakefile", "README", "test/fixtures/bow_wows.yml", "test/fixtures/cats.yml", "test/fixtures/eaters_foodstuffs.yml", "test/fixtures/fish.yml", "test/fixtures/frogs.yml", "test/fixtures/keep_your_enemies_close.yml", "test/fixtures/little_whale_pupils.yml", "test/fixtures/people.yml", "test/fixtures/petfoods.yml", "test/fixtures/whales.yml", "test/fixtures/wild_boars.yml", "test/generator/tagging_generator_test.rb", "test/integration/app/app/controllers/application.rb", "test/integration/app/app/controllers/bones_controller.rb", "test/integration/app/app/helpers/addresses_helper.rb", "test/integration/app/app/helpers/application_helper.rb", "test/integration/app/app/helpers/bones_helper.rb", "test/integration/app/app/helpers/sellers_helper.rb", "test/integration/app/app/helpers/states_helper.rb", "test/integration/app/app/helpers/users_helper.rb", "test/integration/app/app/models/bone.rb", "test/integration/app/app/models/double_sti_parent.rb", "test/integration/app/app/models/double_sti_parent_relationship.rb", "test/integration/app/app/models/organic_substance.rb", "test/integration/app/app/models/single_sti_parent.rb", "test/integration/app/app/models/single_sti_parent_relationship.rb", "test/integration/app/app/models/stick.rb", "test/integration/app/app/models/stone.rb", "test/integration/app/app/views/addresses/edit.html.erb", "test/integration/app/app/views/addresses/index.html.erb", "test/integration/app/app/views/addresses/new.html.erb", "test/integration/app/app/views/addresses/show.html.erb", "test/integration/app/app/views/bones/index.rhtml", "test/integration/app/app/views/layouts/addresses.html.erb", "test/integration/app/app/views/layouts/sellers.html.erb", "test/integration/app/app/views/layouts/states.html.erb", "test/integration/app/app/views/layouts/users.html.erb", "test/integration/app/app/views/sellers/edit.html.erb", "test/integration/app/app/views/sellers/index.html.erb", "test/integration/app/app/views/sellers/new.html.erb", "test/integration/app/app/views/sellers/show.html.erb", "test/integration/app/app/views/states/edit.html.erb", "test/integration/app/app/views/states/index.html.erb", "test/integration/app/app/views/states/new.html.erb", "test/integration/app/app/views/states/show.html.erb", "test/integration/app/app/views/users/edit.html.erb", "test/integration/app/app/views/users/index.html.erb", "test/integration/app/app/views/users/new.html.erb", "test/integration/app/app/views/users/show.html.erb", "test/integration/app/config/boot.rb", "test/integration/app/config/database.yml", "test/integration/app/config/environment.rb", "test/integration/app/config/environment.rb.canonical", "test/integration/app/config/environments/development.rb", "test/integration/app/config/environments/production.rb", "test/integration/app/config/environments/test.rb", "test/integration/app/config/locomotive.yml", "test/integration/app/config/routes.rb", "test/integration/app/config/ultrasphinx/default.base", "test/integration/app/config/ultrasphinx/development.conf.canonical", "test/integration/app/db/migrate/001_create_sticks.rb", "test/integration/app/db/migrate/002_create_stones.rb", "test/integration/app/db/migrate/003_create_organic_substances.rb", "test/integration/app/db/migrate/004_create_bones.rb", "test/integration/app/db/migrate/005_create_single_sti_parents.rb", "test/integration/app/db/migrate/006_create_double_sti_parents.rb", "test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb", "test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb", "test/integration/app/db/migrate/009_create_library_model.rb", "test/integration/app/doc/README_FOR_APP", "test/integration/app/generators/commenting_generator_test.rb", "test/integration/app/lib/library_model.rb", "test/integration/app/public/404.html", "test/integration/app/public/500.html", "test/integration/app/public/dispatch.cgi", "test/integration/app/public/dispatch.fcgi", "test/integration/app/public/dispatch.rb", "test/integration/app/public/favicon.ico", "test/integration/app/public/images/rails.png", "test/integration/app/public/index.html", "test/integration/app/public/javascripts/application.js", "test/integration/app/public/javascripts/controls.js", "test/integration/app/public/javascripts/dragdrop.js", "test/integration/app/public/javascripts/effects.js", "test/integration/app/public/javascripts/prototype.js", "test/integration/app/public/robots.txt", "test/integration/app/public/stylesheets/scaffold.css", "test/integration/app/Rakefile", "test/integration/app/README", "test/integration/app/script/about", "test/integration/app/script/breakpointer", "test/integration/app/script/console", "test/integration/app/script/destroy", "test/integration/app/script/generate", "test/integration/app/script/performance/benchmarker", "test/integration/app/script/performance/profiler", "test/integration/app/script/plugin", "test/integration/app/script/process/inspector", "test/integration/app/script/process/reaper", "test/integration/app/script/process/spawner", "test/integration/app/script/runner", "test/integration/app/script/server", "test/integration/app/test/fixtures/double_sti_parent_relationships.yml", "test/integration/app/test/fixtures/double_sti_parents.yml", "test/integration/app/test/fixtures/organic_substances.yml", "test/integration/app/test/fixtures/single_sti_parent_relationships.yml", "test/integration/app/test/fixtures/single_sti_parents.yml", "test/integration/app/test/fixtures/sticks.yml", "test/integration/app/test/fixtures/stones.yml", "test/integration/app/test/functional/addresses_controller_test.rb", "test/integration/app/test/functional/bones_controller_test.rb", "test/integration/app/test/functional/sellers_controller_test.rb", "test/integration/app/test/functional/states_controller_test.rb", "test/integration/app/test/functional/users_controller_test.rb", "test/integration/app/test/test_helper.rb", "test/integration/app/test/unit/bone_test.rb", "test/integration/app/test/unit/double_sti_parent_relationship_test.rb", "test/integration/app/test/unit/double_sti_parent_test.rb", "test/integration/app/test/unit/organic_substance_test.rb", "test/integration/app/test/unit/single_sti_parent_relationship_test.rb", "test/integration/app/test/unit/single_sti_parent_test.rb", "test/integration/app/test/unit/stick_test.rb", "test/integration/app/test/unit/stone_test.rb", "test/integration/server_test.rb", "test/models/aquatic/fish.rb", "test/models/aquatic/pupils_whale.rb", "test/models/aquatic/whale.rb", "test/models/beautiful_fight_relationship.rb", "test/models/canine.rb", "test/models/cat.rb", "test/models/dog.rb", "test/models/eaters_foodstuff.rb", "test/models/frog.rb", "test/models/kitten.rb", "test/models/parentship.rb", "test/models/person.rb", "test/models/petfood.rb", "test/models/tabby.rb", "test/models/wild_boar.rb", "test/modules/extension_module.rb", "test/modules/other_extension_module.rb", "test/patches/symlinked_plugins_1.2.6.diff", "test/schema.rb", "test/setup.rb", "test/test_helper.rb", "test/unit/has_many_polymorphs_test.rb", "TODO", "has_many_polymorphs.gemspec"] + s.has_rdoc = true + s.homepage = %q{http://blog.evanweaver.com/files/doc/fauna/has_many_polymorphs/} + s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Has_many_polymorphs", "--main", "README"] + s.require_paths = ["lib"] + s.rubyforge_project = %q{fauna} + s.rubygems_version = %q{1.3.1} + s.signing_key = %q{/Users/eweaver/p/configuration/gem_certificates/evan_weaver-original-private_key.pem} + s.summary = %q{An ActiveRecord plugin for self-referential and double-sided polymorphic associations.} + s.test_files = ["test/generator/tagging_generator_test.rb", "test/integration/server_test.rb", "test/unit/has_many_polymorphs_test.rb"] + + if s.respond_to? :specification_version then + current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION + s.specification_version = 2 + + if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then + s.add_runtime_dependency(%q, [">= 0"]) + s.add_development_dependency(%q, [">= 0"]) + else + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) + end + else + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/init.rb b/vendor/gems/has_many_polymorphs-2.13/init.rb new file mode 100644 index 00000000..3939a253 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/init.rb @@ -0,0 +1,2 @@ + +require 'has_many_polymorphs' diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs.rb new file mode 100644 index 00000000..03c600cc --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs.rb @@ -0,0 +1,27 @@ + +require 'active_record' + +RAILS_DEFAULT_LOGGER = nil unless defined? RAILS_DEFAULT_LOGGER + +require 'has_many_polymorphs/reflection' +require 'has_many_polymorphs/association' +require 'has_many_polymorphs/class_methods' + +require 'has_many_polymorphs/support_methods' +require 'has_many_polymorphs/base' + +class ActiveRecord::Base + extend ActiveRecord::Associations::PolymorphicClassMethods +end + +if ENV['HMP_DEBUG'] || ENV['RAILS_ENV'] =~ /development|test/ && ENV['USER'] == 'eweaver' + require 'has_many_polymorphs/debugging_tools' +end + +if defined? Rails and RAILS_ENV and RAILS_ROOT + _logger_warn "rails environment detected" + require 'has_many_polymorphs/configuration' + require 'has_many_polymorphs/autoload' +end + +_logger_debug "loaded ok" diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/association.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/association.rb new file mode 100644 index 00000000..a2b2d81a --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/association.rb @@ -0,0 +1,159 @@ +module ActiveRecord #:nodoc: + module Associations #:nodoc: + + class PolymorphicError < ActiveRecordError #:nodoc: + end + + class PolymorphicMethodNotSupportedError < ActiveRecordError #:nodoc: + end + + # The association class for a has_many_polymorphs association. + class PolymorphicAssociation < HasManyThroughAssociation + + # Push a record onto the association. Triggers a database load for a uniqueness check only if :skip_duplicates is true. Return value is undefined. + def <<(*records) + return if records.empty? + + if @reflection.options[:skip_duplicates] + _logger_debug "Loading instances for polymorphic duplicate push check; use :skip_duplicates => false and perhaps a database constraint to avoid this possible performance issue" + load_target + end + + @reflection.klass.transaction do + flatten_deeper(records).each do |record| + if @owner.new_record? or not record.respond_to?(:new_record?) or record.new_record? + raise PolymorphicError, "You can't associate unsaved records." + end + next if @reflection.options[:skip_duplicates] and @target.include? record + @owner.send(@reflection.through_reflection.name).proxy_target << @reflection.klass.create!(construct_join_attributes(record)) + @target << record if loaded? + end + end + + self + end + + alias :push :<< + alias :concat :<< + + # Runs a find against the association contents, returning the matched records. All regular find options except :include are supported. + def find(*args) + opts = args._extract_options! + opts.delete :include + super(*(args + [opts])) + end + + def construct_scope + _logger_warn "Warning; not all usage scenarios for polymorphic scopes are supported yet." + super + end + + # Deletes a record from the association. Return value is undefined. + def delete(*records) + records = flatten_deeper(records) + records.reject! {|record| @target.delete(record) if record.new_record?} + return if records.empty? + + @reflection.klass.transaction do + records.each do |record| + joins = @reflection.through_reflection.name + @owner.send(joins).delete(@owner.send(joins).select do |join| + join.send(@reflection.options[:polymorphic_key]) == record.id and + join.send(@reflection.options[:polymorphic_type_key]) == "#{record.class.base_class}" + end) + @target.delete(record) + end + end + end + + # Clears all records from the association. Returns an empty array. + def clear(klass = nil) + load_target + return if @target.empty? + + if klass + delete(@target.select {|r| r.is_a? klass }) + else + @owner.send(@reflection.through_reflection.name).clear + @target.clear + end + [] + end + + protected + +# undef :sum +# undef :create! + + def construct_quoted_owner_attributes(*args) #:nodoc: + # no access to returning() here? why not? + type_key = @reflection.options[:foreign_type_key] + {@reflection.primary_key_name => @owner.id, + type_key=> (@owner.class.base_class.name if type_key)} + end + + def construct_from #:nodoc: + # build the FROM part of the query, in this case, the polymorphic join table + @reflection.klass.table_name + end + + def construct_owner #:nodoc: + # the table name for the owner object's class + @owner.class.table_name + end + + def construct_owner_key #:nodoc: + # the primary key field for the owner object + @owner.class.primary_key + end + + def construct_select(custom_select = nil) #:nodoc: + # build the select query + selected = custom_select || @reflection.options[:select] + end + + def construct_joins(custom_joins = nil) #:nodoc: + # build the string of default joins + "JOIN #{construct_owner} polymorphic_parent ON #{construct_from}.#{@reflection.options[:foreign_key]} = polymorphic_parent.#{construct_owner_key} " + + @reflection.options[:from].map do |plural| + klass = plural._as_class + "LEFT JOIN #{klass.table_name} ON #{construct_from}.#{@reflection.options[:polymorphic_key]} = #{klass.table_name}.#{klass.primary_key} AND #{construct_from}.#{@reflection.options[:polymorphic_type_key]} = #{@reflection.klass.quote_value(klass.base_class.name)}" + end.uniq.join(" ") + " #{custom_joins}" + end + + def construct_conditions #:nodoc: + # build the fully realized condition string + conditions = construct_quoted_owner_attributes.map do |field, value| + "#{construct_from}.#{field} = #{@reflection.klass.quote_value(value)}" if value + end + conditions << custom_conditions if custom_conditions + "(" + conditions.compact.join(') AND (') + ")" + end + + def custom_conditions #:nodoc: + # custom conditions... not as messy as has_many :through because our joins are a little smarter + if @reflection.options[:conditions] + "(" + interpolate_sql(@reflection.klass.send(:sanitize_sql, @reflection.options[:conditions])) + ")" + end + end + + alias :construct_owner_attributes :construct_quoted_owner_attributes + alias :conditions :custom_conditions # XXX possibly not necessary + alias :sql_conditions :custom_conditions # XXX ditto + + # construct attributes for join for a particular record + def construct_join_attributes(record) #:nodoc: + {@reflection.options[:polymorphic_key] => record.id, + @reflection.options[:polymorphic_type_key] => "#{record.class.base_class}", + @reflection.options[:foreign_key] => @owner.id}.merge(@reflection.options[:foreign_type_key] ? + {@reflection.options[:foreign_type_key] => "#{@owner.class.base_class}"} : {}) # for double-sided relationships + end + + def build(attrs = nil) #:nodoc: + raise PolymorphicMethodNotSupportedError, "You can't associate new records." + end + + end + + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/autoload.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/autoload.rb new file mode 100644 index 00000000..f05c9dc8 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/autoload.rb @@ -0,0 +1,69 @@ +require 'initializer' unless defined? ::Rails::Initializer +require 'action_controller/dispatcher' unless defined? ::ActionController::Dispatcher + +module HasManyPolymorphs + +=begin rdoc +Searches for models that use has_many_polymorphs or acts_as_double_polymorphic_join and makes sure that they get loaded during app initialization. This ensures that helper methods are injected into the target classes. + +Note that you can override DEFAULT_OPTIONS via Rails::Configuration#has_many_polymorphs_options. For example, if you need an application extension to be required before has_many_polymorphs loads your models, add an after_initialize block in config/environment.rb that appends to the 'requirements' key: + Rails::Initializer.run do |config| + # your other configuration here + + config.after_initialize do + config.has_many_polymorphs_options['requirements'] << 'lib/my_extension' + end + end + +=end + + DEFAULT_OPTIONS = { + :file_pattern => "#{RAILS_ROOT}/app/models/**/*.rb", + :file_exclusions => ['svn', 'CVS', 'bzr'], + :methods => ['has_many_polymorphs', 'acts_as_double_polymorphic_join'], + :requirements => []} + + mattr_accessor :options + @@options = HashWithIndifferentAccess.new(DEFAULT_OPTIONS) + + # Dispatcher callback to load polymorphic relationships from the top down. + def self.autoload + + _logger_debug "autoload hook invoked" + + options[:requirements].each do |requirement| + _logger_warn "forcing requirement load of #{requirement}" + require requirement + end + + Dir.glob(options[:file_pattern]).each do |filename| + next if filename =~ /#{options[:file_exclusions].join("|")}/ + open filename do |file| + if file.grep(/#{options[:methods].join("|")}/).any? + begin + model = File.basename(filename)[0..-4].camelize + _logger_warn "preloading parent model #{model}" + model.constantize + rescue Object => e + _logger_warn "#{model} could not be preloaded: #{e.inspect}" + end + end + end + end + end + +end + +class Rails::Initializer #:nodoc: + # Make sure it gets loaded in the console, tests, and migrations + def after_initialize_with_autoload + after_initialize_without_autoload + HasManyPolymorphs.autoload + end + alias_method_chain :after_initialize, :autoload +end + +ActionController::Dispatcher.to_prepare(:has_many_polymorphs_autoload) do + # Make sure it gets loaded in the app + HasManyPolymorphs.autoload +end diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/base.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/base.rb new file mode 100644 index 00000000..9513039c --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/base.rb @@ -0,0 +1,60 @@ + +module ActiveRecord + class Base + + class << self + + # Interprets a polymorphic row from a unified SELECT, returning the appropriate ActiveRecord instance. Overrides ActiveRecord::Base.instantiate_without_callbacks. + def instantiate_with_polymorphic_checks(record) + if record['polymorphic_parent_class'] + reflection = record['polymorphic_parent_class'].constantize.reflect_on_association(record['polymorphic_association_id'].to_sym) +# _logger_debug "Instantiating a polymorphic row for #{record['polymorphic_parent_class']}.reflect_on_association(:#{record['polymorphic_association_id']})" + + # rewrite the record with the right column names + table_aliases = reflection.options[:table_aliases].dup + record = Hash[*table_aliases.keys.map {|key| [key, record[table_aliases[key]]] }.flatten] + + # find the real child class + klass = record["#{self.table_name}.#{reflection.options[:polymorphic_type_key]}"].constantize + if sti_klass = record["#{klass.table_name}.#{klass.inheritance_column}"] + klass = klass.class_eval do compute_type(sti_klass) end # in case of namespaced STI models + end + + # check that the join actually joined to something + unless (child_id = record["#{self.table_name}.#{reflection.options[:polymorphic_key]}"]) == record["#{klass.table_name}.#{klass.primary_key}"] + raise ActiveRecord::Associations::PolymorphicError, + "Referential integrity violation; child <#{klass.name}:#{child_id}> was not found for #{reflection.name.inspect}" + end + + # eject the join keys + # XXX not very readable + record = Hash[*record._select do |column, value| + column[/^#{klass.table_name}/] + end.map do |column, value| + [column[/\.(.*)/, 1], value] + end.flatten] + + # allocate and assign values + returning(klass.allocate) do |obj| + obj.instance_variable_set("@attributes", record) + obj.instance_variable_set("@attributes_cache", Hash.new) + + if obj.respond_to_without_attributes?(:after_find) + obj.send(:callback, :after_find) + end + + if obj.respond_to_without_attributes?(:after_initialize) + obj.send(:callback, :after_initialize) + end + + end + else + instantiate_without_polymorphic_checks(record) + end + end + + alias_method_chain :instantiate, :polymorphic_checks + end + + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/class_methods.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/class_methods.rb new file mode 100644 index 00000000..536a49d4 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/class_methods.rb @@ -0,0 +1,600 @@ + +module ActiveRecord #:nodoc: + module Associations #:nodoc: + +=begin rdoc + +Class methods added to ActiveRecord::Base for setting up polymorphic associations. + +== Notes + +STI association targets must enumerated and named. For example, if Dog and Cat both inherit from Animal, you still need to say [:dogs, :cats], and not [:animals]. + +Namespaced models follow the Rails underscore convention. ZooAnimal::Lion becomes :'zoo_animal/lion'. + +You do not need to set up any other associations other than for either the regular method or the double. The join associations and all individual and reverse associations are generated for you. However, a join model and table are required. + +There is a tentative report that you can make the parent model be its own join model, but this is untested. + +=end + + module PolymorphicClassMethods + + RESERVED_DOUBLES_KEYS = [:conditions, :order, :limit, :offset, :extend, :skip_duplicates, + :join_extend, :dependent, :rename_individual_collections, + :namespace] #:nodoc: + +=begin rdoc + +This method creates a doubled-sided polymorphic relationship. It must be called on the join model: + + class Devouring < ActiveRecord::Base + belongs_to :eater, :polymorphic => true + belongs_to :eaten, :polymorphic => true + + acts_as_double_polymorphic_join( + :eaters => [:dogs, :cats], + :eatens => [:cats, :birds] + ) + end + +The method works by defining one or more special has_many_polymorphs association on every model in the target lists, depending on which side of the association it is on. Double self-references will work. + +The two association names and their value arrays are the only required parameters. + +== Available options + +These options are passed through to targets on both sides of the association. If you want to affect only one side, prepend the key with the name of that side. For example, :eaters_extend. + +:dependent:: Accepts :destroy, :nullify, or :delete_all. Controls how the join record gets treated on any association delete (whether from the polymorph or from an individual collection); defaults to :destroy. +:skip_duplicates:: If true, will check to avoid pushing already associated records (but also triggering a database load). Defaults to true. +:rename_individual_collections:: If true, all individual collections are prepended with the polymorph name, and the children's parent collection is appended with "\_of_#{association_name}". +:extend:: One or an array of mixed modules and procs, which are applied to the polymorphic association (usually to define custom methods). +:join_extend:: One or an array of mixed modules and procs, which are applied to the join association. +:conditions:: An array or string of conditions for the SQL WHERE clause. +:order:: A string for the SQL ORDER BY clause. +:limit:: An integer. Affects the polymorphic and individual associations. +:offset:: An integer. Only affects the polymorphic association. +:namespace:: A symbol. Prepended to all the models in the :from and :through keys. This is especially useful for Camping, which namespaces models by default. + +=end + + def acts_as_double_polymorphic_join options={}, &extension + + collections, options = extract_double_collections(options) + + # handle the block + options[:extend] = (if options[:extend] + Array(options[:extend]) + [extension] + else + extension + end) if extension + + collection_option_keys = make_general_option_keys_specific!(options, collections) + + join_name = self.name.tableize.to_sym + collections.each do |association_id, children| + parent_hash_key = (collections.keys - [association_id]).first # parents are the entries in the _other_ children array + + begin + parent_foreign_key = self.reflect_on_association(parent_hash_key._singularize).primary_key_name + rescue NoMethodError + raise PolymorphicError, "Couldn't find 'belongs_to' association for :#{parent_hash_key._singularize} in #{self.name}." unless parent_foreign_key + end + + parents = collections[parent_hash_key] + conflicts = (children & parents) # set intersection + parents.each do |plural_parent_name| + + parent_class = plural_parent_name._as_class + singular_reverse_association_id = parent_hash_key._singularize + + internal_options = { + :is_double => true, + :from => children, + :as => singular_reverse_association_id, + :through => join_name.to_sym, + :foreign_key => parent_foreign_key, + :foreign_type_key => parent_foreign_key.to_s.sub(/_id$/, '_type'), + :singular_reverse_association_id => singular_reverse_association_id, + :conflicts => conflicts + } + + general_options = Hash[*options._select do |key, value| + collection_option_keys[association_id].include? key and !value.nil? + end.map do |key, value| + [key.to_s[association_id.to_s.length+1..-1].to_sym, value] + end._flatten_once] # rename side-specific options to general names + + general_options.each do |key, value| + # avoid clobbering keys that appear in both option sets + if internal_options[key] + general_options[key] = Array(value) + Array(internal_options[key]) + end + end + + parent_class.send(:has_many_polymorphs, association_id, internal_options.merge(general_options)) + + if conflicts.include? plural_parent_name + # unify the alternate sides of the conflicting children + (conflicts).each do |method_name| + unless parent_class.instance_methods.include?(method_name) + parent_class.send(:define_method, method_name) do + (self.send("#{singular_reverse_association_id}_#{method_name}") + + self.send("#{association_id._singularize}_#{method_name}")).freeze + end + end + end + + # unify the join model... join model is always renamed for doubles, unlike child associations + unless parent_class.instance_methods.include?(join_name) + parent_class.send(:define_method, join_name) do + (self.send("#{join_name}_as_#{singular_reverse_association_id}") + + self.send("#{join_name}_as_#{association_id._singularize}")).freeze + end + end + else + unless parent_class.instance_methods.include?(join_name) + parent_class.send(:alias_method, join_name, "#{join_name}_as_#{singular_reverse_association_id}") + end + end + + end + end + end + + private + + def extract_double_collections(options) + collections = options._select do |key, value| + value.is_a? Array and key.to_s !~ /(#{RESERVED_DOUBLES_KEYS.map(&:to_s).join('|')})$/ + end + + raise PolymorphicError, "Couldn't understand options in acts_as_double_polymorphic_join. Valid parameters are your two class collections, and then #{RESERVED_DOUBLES_KEYS.inspect[1..-2]}, with optionally your collection names prepended and joined with an underscore." unless collections.size == 2 + + options = options._select do |key, value| + !collections[key] + end + + [collections, options] + end + + def make_general_option_keys_specific!(options, collections) + collection_option_keys = Hash[*collections.keys.map do |key| + [key, RESERVED_DOUBLES_KEYS.map{|option| "#{key}_#{option}".to_sym}] + end._flatten_once] + + collections.keys.each do |collection| + options.each do |key, value| + next if collection_option_keys.values.flatten.include? key + # shift the general options to the individual sides + collection_key = "#{collection}_#{key}".to_sym + collection_value = options[collection_key] + case key + when :conditions + collection_value, value = sanitize_sql(collection_value), sanitize_sql(value) + options[collection_key] = (collection_value ? "(#{collection_value}) AND (#{value})" : value) + when :order + options[collection_key] = (collection_value ? "#{collection_value}, #{value}" : value) + when :extend, :join_extend + options[collection_key] = Array(collection_value) + Array(value) + else + options[collection_key] ||= value + end + end + end + + collection_option_keys + end + + + + public + +=begin rdoc + +This method createds a single-sided polymorphic relationship. + + class Petfood < ActiveRecord::Base + has_many_polymorphs :eaters, :from => [:dogs, :cats, :birds] + end + +The only required parameter, aside from the association name, is :from. + +The method generates a number of associations aside from the polymorphic one. In this example Petfood also gets dogs, cats, and birds, and Dog, Cat, and Bird get petfoods. (The reverse association to the parents is always plural.) + +== Available options + +:from:: An array of symbols representing the target models. Required. +:as:: A symbol for the parent's interface in the join--what the parent 'acts as'. +:through:: A symbol representing the class of the join model. Follows Rails defaults if not supplied (the parent and the association names, alphabetized, concatenated with an underscore, and singularized). +:dependent:: Accepts :destroy, :nullify, :delete_all. Controls how the join record gets treated on any associate delete (whether from the polymorph or from an individual collection); defaults to :destroy. +:skip_duplicates:: If true, will check to avoid pushing already associated records (but also triggering a database load). Defaults to true. +:rename_individual_collections:: If true, all individual collections are prepended with the polymorph name, and the children's parent collection is appended with "_of_#{association_name}". For example, zoos becomes zoos_of_animals. This is to help avoid method name collisions in crowded classes. +:extend:: One or an array of mixed modules and procs, which are applied to the polymorphic association (usually to define custom methods). +:join_extend:: One or an array of mixed modules and procs, which are applied to the join association. +:parent_extend:: One or an array of mixed modules and procs, which are applied to the target models' association to the parents. +:conditions:: An array or string of conditions for the SQL WHERE clause. +:parent_conditions:: An array or string of conditions which are applied to the target models' association to the parents. +:order:: A string for the SQL ORDER BY clause. +:parent_order:: A string for the SQL ORDER BY which is applied to the target models' association to the parents. +:group:: An array or string of conditions for the SQL GROUP BY clause. Affects the polymorphic and individual associations. +:limit:: An integer. Affects the polymorphic and individual associations. +:offset:: An integer. Only affects the polymorphic association. +:namespace:: A symbol. Prepended to all the models in the :from and :through keys. This is especially useful for Camping, which namespaces models by default. +:uniq:: If true, the records returned are passed through a pure-Ruby uniq before they are returned. Rarely needed. +:foreign_key:: The column name for the parent's id in the join. +:foreign_type_key:: The column name for the parent's class name in the join, if the parent itself is polymorphic. Rarely needed--if you're thinking about using this, you almost certainly want to use acts_as_double_polymorphic_join() instead. +:polymorphic_key:: The column name for the child's id in the join. +:polymorphic_type_key:: The column name for the child's class name in the join. + +If you pass a block, it gets converted to a Proc and added to :extend. + +== On condition nullification + +When you request an individual association, non-applicable but fully-qualified fields in the polymorphic association's :conditions, :order, and :group options get changed to NULL. For example, if you set :conditions => "dogs.name != 'Spot'", when you request .cats, the conditions string is changed to NULL != 'Spot'. + +Be aware, however, that NULL != 'Spot' returns false due to SQL's 3-value logic. Instead, you need to use the :conditions string "dogs.name IS NULL OR dogs.name != 'Spot'" to get the behavior you probably expect for negative matches. + +=end + + def has_many_polymorphs (association_id, options = {}, &extension) + _logger_debug "associating #{self}.#{association_id}" + reflection = create_has_many_polymorphs_reflection(association_id, options, &extension) + # puts "Created reflection #{reflection.inspect}" + # configure_dependency_for_has_many(reflection) + collection_reader_method(reflection, PolymorphicAssociation) + end + + # Composed method that assigns option defaults, builds the reflection object, and sets up all the related associations on the parent, join, and targets. + def create_has_many_polymorphs_reflection(association_id, options, &extension) #:nodoc: + options.assert_valid_keys( + :from, + :as, + :through, + :foreign_key, + :foreign_type_key, + :polymorphic_key, # same as :association_foreign_key + :polymorphic_type_key, + :dependent, # default :destroy, only affects the join table + :skip_duplicates, # default true, only affects the polymorphic collection + :ignore_duplicates, # deprecated + :is_double, + :rename_individual_collections, + :reverse_association_id, # not used + :singular_reverse_association_id, + :conflicts, + :extend, + :join_class_name, + :join_extend, + :parent_extend, + :table_aliases, + :select, # applies to the polymorphic relationship + :conditions, # applies to the polymorphic relationship, the children, and the join + # :include, + :parent_conditions, + :parent_order, + :order, # applies to the polymorphic relationship, the children, and the join + :group, # only applies to the polymorphic relationship and the children + :limit, # only applies to the polymorphic relationship and the children + :offset, # only applies to the polymorphic relationship + :parent_order, + :parent_group, + :parent_limit, + :parent_offset, + # :source, + :namespace, + :uniq, # XXX untested, only applies to the polymorphic relationship + # :finder_sql, + # :counter_sql, + # :before_add, + # :after_add, + # :before_remove, + # :after_remove + :dummy) + + # validate against the most frequent configuration mistakes + verify_pluralization_of(association_id) + raise PolymorphicError, ":from option must be an array" unless options[:from].is_a? Array + options[:from].each{|plural| verify_pluralization_of(plural)} + + options[:as] ||= self.name.demodulize.underscore.to_sym + options[:conflicts] = Array(options[:conflicts]) + options[:foreign_key] ||= "#{options[:as]}_id" + + options[:association_foreign_key] = + options[:polymorphic_key] ||= "#{association_id._singularize}_id" + options[:polymorphic_type_key] ||= "#{association_id._singularize}_type" + + if options.has_key? :ignore_duplicates + _logger_warn "DEPRECATION WARNING: please use :skip_duplicates instead of :ignore_duplicates" + options[:skip_duplicates] = options[:ignore_duplicates] + end + options[:skip_duplicates] = true unless options.has_key? :skip_duplicates + options[:dependent] = :destroy unless options.has_key? :dependent + options[:conditions] = sanitize_sql(options[:conditions]) + + # options[:finder_sql] ||= "(options[:polymorphic_key] + + options[:through] ||= build_join_table_symbol(association_id, (options[:as]._pluralize or self.table_name)) + + # set up namespaces if we have a namespace key + # XXX needs test coverage + if options[:namespace] + namespace = options[:namespace].to_s.chomp("/") + "/" + options[:from].map! do |child| + "#{namespace}#{child}".to_sym + end + options[:through] = "#{namespace}#{options[:through]}".to_sym + end + + options[:join_class_name] ||= options[:through]._classify + options[:table_aliases] ||= build_table_aliases([options[:through]] + options[:from]) + options[:select] ||= build_select(association_id, options[:table_aliases]) + + options[:through] = "#{options[:through]}_as_#{options[:singular_reverse_association_id]}" if options[:singular_reverse_association_id] + options[:through] = demodulate(options[:through]).to_sym + + options[:extend] = spiked_create_extension_module(association_id, Array(options[:extend]) + Array(extension)) + options[:join_extend] = spiked_create_extension_module(association_id, Array(options[:join_extend]), "Join") + options[:parent_extend] = spiked_create_extension_module(association_id, Array(options[:parent_extend]), "Parent") + + # create the reflection object + create_reflection(:has_many_polymorphs, association_id, options, self).tap do |reflection| + # set up the other related associations + create_join_association(association_id, reflection) + create_has_many_through_associations_for_parent_to_children(association_id, reflection) + create_has_many_through_associations_for_children_to_parent(association_id, reflection) + end + end + + private + + + # table mapping for use at the instantiation point + + def build_table_aliases(from) + # for the targets + {}.tap do |aliases| + from.map(&:to_s).sort.map(&:to_sym).each_with_index do |plural, t_index| + begin + table = plural._as_class.table_name + rescue NameError => e + raise PolymorphicError, "Could not find a valid class for #{plural.inspect} (tried #{plural.to_s._classify}). If it's namespaced, be sure to specify it as :\"module/#{plural}\" instead." + end + begin + plural._as_class.columns.map(&:name).each_with_index do |field, f_index| + aliases["#{table}.#{field}"] = "t#{t_index}_r#{f_index}" + end + rescue ActiveRecord::StatementInvalid => e + _logger_warn "Looks like your table doesn't exist for #{plural.to_s._classify}.\nError #{e}\nSkipping..." + end + end + end + end + + def build_select(association_id, aliases) + # instantiate has to know which reflection the results are coming from + (["\'#{self.name}\' AS polymorphic_parent_class", + "\'#{association_id}\' AS polymorphic_association_id"] + + aliases.map do |table, _alias| + "#{table} AS #{_alias}" + end.sort).join(", ") + end + + # method sub-builders + + def create_join_association(association_id, reflection) + + options = { + :foreign_key => reflection.options[:foreign_key], + :dependent => reflection.options[:dependent], + :class_name => reflection.klass.name, + :extend => reflection.options[:join_extend] + # :limit => reflection.options[:limit], + # :offset => reflection.options[:offset], + # :order => devolve(association_id, reflection, reflection.options[:order], reflection.klass, true), + # :conditions => devolve(association_id, reflection, reflection.options[:conditions], reflection.klass, true) + } + + if reflection.options[:foreign_type_key] + type_check = "#{reflection.options[:foreign_type_key]} = #{quote_value(self.base_class.name)}" + conjunction = options[:conditions] ? " AND " : nil + options[:conditions] = "#{options[:conditions]}#{conjunction}#{type_check}" + options[:as] = reflection.options[:as] + end + + has_many(reflection.options[:through], options) + + inject_before_save_into_join_table(association_id, reflection) + end + + def inject_before_save_into_join_table(association_id, reflection) + sti_hook = "sti_class_rewrite" + rewrite_procedure = %[self.send(:#{reflection.options[:polymorphic_type_key]}=, self.#{reflection.options[:polymorphic_type_key]}.constantize.base_class.name)] + + # XXX should be abstracted? + reflection.klass.class_eval %[ + unless instance_methods.include? "before_save_with_#{sti_hook}" + if instance_methods.include? "before_save" + alias_method :before_save_without_#{sti_hook}, :before_save + def before_save_with_#{sti_hook} + before_save_without_#{sti_hook} + #{rewrite_procedure} + end + else + def before_save_with_#{sti_hook} + #{rewrite_procedure} + end + end + alias_method :before_save, :before_save_with_#{sti_hook} + end + ] + end + + def create_has_many_through_associations_for_children_to_parent(association_id, reflection) + + child_pluralization_map(association_id, reflection).each do |plural, singular| + if singular == reflection.options[:as] + raise PolymorphicError, if reflection.options[:is_double] + "You can't give either of the sides in a double-polymorphic join the same name as any of the individual target classes." + else + "You can't have a self-referential polymorphic has_many :through without renaming the non-polymorphic foreign key in the join model." + end + end + + parent = self + plural._as_class.instance_eval do + # this shouldn't be called at all during doubles; there is no way to traverse to a double polymorphic parent (XXX is that right?) + unless reflection.options[:is_double] or reflection.options[:conflicts].include? self.name.tableize.to_sym + + # the join table + through = "#{reflection.options[:through]}#{'_as_child' if parent == self}".to_sym + has_many(through, + :as => association_id._singularize, +# :source => association_id._singularize, +# :source_type => reflection.options[:polymorphic_type_key], + :class_name => reflection.klass.name, + :dependent => reflection.options[:dependent], + :extend => reflection.options[:join_extend], + # :limit => reflection.options[:limit], + # :offset => reflection.options[:offset], + :order => devolve(association_id, reflection, reflection.options[:parent_order], reflection.klass), + :conditions => devolve(association_id, reflection, reflection.options[:parent_conditions], reflection.klass) + ) + + # the association to the target's parents + association = "#{reflection.options[:as]._pluralize}#{"_of_#{association_id}" if reflection.options[:rename_individual_collections]}".to_sym + has_many(association, + :through => through, + :class_name => parent.name, + :source => reflection.options[:as], + :foreign_key => reflection.options[:foreign_key], + :extend => reflection.options[:parent_extend], + :conditions => reflection.options[:parent_conditions], + :order => reflection.options[:parent_order], + :offset => reflection.options[:parent_offset], + :limit => reflection.options[:parent_limit], + :group => reflection.options[:parent_group]) + +# debugger if association == :parents +# +# nil + + end + end + end + end + + def create_has_many_through_associations_for_parent_to_children(association_id, reflection) + child_pluralization_map(association_id, reflection).each do |plural, singular| + #puts ":source => #{child}" + current_association = demodulate(child_association_map(association_id, reflection)[plural]) + source = demodulate(singular) + + if reflection.options[:conflicts].include? plural + # XXX check this + current_association = "#{association_id._singularize}_#{current_association}" if reflection.options[:conflicts].include? self.name.tableize.to_sym + source = "#{source}_as_#{association_id._singularize}".to_sym + end + + # make push/delete accessible from the individual collections but still operate via the general collection + extension_module = self.class_eval %[ + module #{self.name + current_association._classify + "PolymorphicChildAssociationExtension"} + def push *args; proxy_owner.send(:#{association_id}).send(:push, *args); self; end + alias :<< :push + def delete *args; proxy_owner.send(:#{association_id}).send(:delete, *args); end + def clear; proxy_owner.send(:#{association_id}).send(:clear, #{singular._classify}); end + self + end] + + has_many(current_association.to_sym, + :through => reflection.options[:through], + :source => association_id._singularize, + :source_type => plural._as_class.base_class.name, + :class_name => plural._as_class.name, # make STI not conflate subtypes + :extend => (Array(extension_module) + reflection.options[:extend]), + :limit => reflection.options[:limit], + # :offset => reflection.options[:offset], + :order => devolve(association_id, reflection, reflection.options[:order], plural._as_class), + :conditions => devolve(association_id, reflection, reflection.options[:conditions], plural._as_class), + :group => devolve(association_id, reflection, reflection.options[:group], plural._as_class) + ) + + end + end + + # some support methods + + def child_pluralization_map(association_id, reflection) + Hash[*reflection.options[:from].map do |plural| + [plural, plural._singularize] + end.flatten] + end + + def child_association_map(association_id, reflection) + Hash[*reflection.options[:from].map do |plural| + [plural, "#{association_id._singularize.to_s + "_" if reflection.options[:rename_individual_collections]}#{plural}".to_sym] + end.flatten] + end + + def demodulate(s) + s.to_s.gsub('/', '_').to_sym + end + + def build_join_table_symbol(association_id, name) + [name.to_s, association_id.to_s].sort.join("_").to_sym + end + + def all_classes_for(association_id, reflection) + klasses = [self, reflection.klass, *child_pluralization_map(association_id, reflection).keys.map(&:_as_class)] + klasses += klasses.map(&:base_class) + klasses.uniq + end + + def devolve(association_id, reflection, string, klass, remove_inappropriate_clauses = false) + # XXX remove_inappropriate_clauses is not implemented; we'll wait until someone actually needs it + return unless string + string = string.dup + # _logger_debug "devolving #{string} for #{klass}" + inappropriate_classes = (all_classes_for(association_id, reflection) - # the join class must always be preserved + [klass, klass.base_class, reflection.klass, reflection.klass.base_class]) + inappropriate_classes.map do |klass| + klass.columns.map do |column| + [klass.table_name, column.name] + end.map do |table, column| + ["#{table}.#{column}", "`#{table}`.#{column}", "#{table}.`#{column}`", "`#{table}`.`#{column}`"] + end + end.flatten.sort_by(&:size).reverse.each do |quoted_reference| + # _logger_debug "devolved #{quoted_reference} to NULL" + # XXX clause removal would go here + string.gsub!(quoted_reference, "NULL") + end + # _logger_debug "altered to #{string}" + string + end + + def verify_pluralization_of(sym) + sym = sym.to_s + singular = sym.singularize + plural = singular.pluralize + raise PolymorphicError, "Pluralization rules not set up correctly. You passed :#{sym}, which singularizes to :#{singular}, but that pluralizes to :#{plural}, which is different. Maybe you meant :#{plural} to begin with?" unless sym == plural + end + + def spiked_create_extension_module(association_id, extensions, identifier = nil) + module_extensions = extensions.select{|e| e.is_a? Module} + proc_extensions = extensions.select{|e| e.is_a? Proc } + + # support namespaced anonymous blocks as well as multiple procs + proc_extensions.each_with_index do |proc_extension, index| + module_name = "#{self.to_s}#{association_id._classify}Polymorphic#{identifier}AssociationExtension#{index}" + the_module = self.class_eval "module #{module_name}; self; end" # XXX hrm + the_module.class_eval &proc_extension + module_extensions << the_module + end + module_extensions + end + + end + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/configuration.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/configuration.rb new file mode 100644 index 00000000..9de21617 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/configuration.rb @@ -0,0 +1,19 @@ + +=begin rdoc +Access the has_many_polymorphs_options hash in your Rails::Initializer.run#after_initialize block if you need to modify the behavior of Rails::Initializer::HasManyPolymorphsAutoload. +=end + +module Rails #:nodoc: + class Configuration + + def has_many_polymorphs_options + ::HasManyPolymorphs.options + end + + def has_many_polymorphs_options=(hash) + ::HasManyPolymorphs.options = HashWithIndifferentAccess.new(hash) + end + + end +end + diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/debugging_tools.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/debugging_tools.rb new file mode 100644 index 00000000..22c9af38 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/debugging_tools.rb @@ -0,0 +1,103 @@ + +=begin rdoc + +Debugging tools for Has_many_polymorphs. + +Enable the different tools by setting the environment variable HMP_DEBUG. Settings with special meaning are "ruby-debug", "trace", and "dependencies". + +== Code generation + +Enabled by default when HMP_DEBUG is set. + +Ouputs a folder generated_models/ in RAILS_ROOT containing valid Ruby files explaining all the ActiveRecord relationships set up by the plugin, as well as listing the line in the plugin that called each particular association method. + +== Ruby-debug + +Enable by setting HMP_DEBUG to "ruby-debug". + +Starts ruby-debug for the life of the process. + +== Trace + +Enable by setting HMP_DEBUG to "ruby-debug". + +Outputs an indented trace of relevant method calls as they occur. + +== Dependencies + +Enable by setting HMP_DEBUG to "dependencies". + +Turns on Rails' default dependency logging. + +=end + +_logger_warn "debug mode enabled" + +class << ActiveRecord::Base + COLLECTION_METHODS = [:belongs_to, :has_many, :has_and_belongs_to_many, :has_one, + :has_many_polymorphs, :acts_as_double_polymorphic_join].each do |method_name| + alias_method "original_#{method_name}".to_sym, method_name + undef_method method_name + end + + unless defined? GENERATED_CODE_DIR + GENERATED_CODE_DIR = "#{RAILS_ROOT}/generated_models" + + begin + system "rm -rf #{GENERATED_CODE_DIR}" + Dir.mkdir GENERATED_CODE_DIR + rescue Errno::EACCES + _logger_warn "no permissions for generated code dir: #{GENERATED_CODE_DIR}" + end + + if File.exist? GENERATED_CODE_DIR + alias :original_method_missing :method_missing + def method_missing(method_name, *args, &block) + if COLLECTION_METHODS.include? method_name.to_sym + Dir.chdir GENERATED_CODE_DIR do + filename = "#{demodulate(self.name.underscore)}.rb" + contents = File.open(filename).read rescue "\nclass #{self.name}\n\nend\n" + line = caller[1][/\:(\d+)\:/, 1] + contents[-5..-5] = "\n #{method_name} #{args[0..-2].inspect[1..-2]},\n #{args[-1].inspect[1..-2].gsub(" :", "\n :").gsub("=>", " => ")}\n#{ block ? " #{block.inspect.sub(/\@.*\//, '@')}\n" : ""} # called from line #{line}\n\n" + File.open(filename, "w") do |file| + file.puts contents + end + end + # doesn't actually display block contents + self.send("original_#{method_name}", *args, &block) + else + self.send(:original_method_missing, method_name, *args, &block) + end + end + end + + end +end + +case ENV['HMP_DEBUG'] + + when "ruby-debug" + require 'rubygems' + require 'ruby-debug' + Debugger.start + _logger_warn "ruby-debug enabled." + + when "trace" + _logger_warn "method tracing enabled" + $debug_trace_indent = 0 + set_trace_func (proc do |event, file, line, id, binding, classname| + if id.to_s =~ /instantiate/ #/IRB|Wirble|RubyLex|RubyToken|Logger|ConnectionAdapters|SQLite3|MonitorMixin|Benchmark|Inflector|Inflections/ + if event == 'call' + puts (" " * $debug_trace_indent) + "#{event}ed #{classname}\##{id} from #{file.split('/').last}::#{line}" + $debug_trace_indent += 1 + elsif event == 'return' + $debug_trace_indent -= 1 unless $debug_trace_indent == 0 + puts (" " * $debug_trace_indent) + "#{event}ed #{classname}\##{id}" + end + end + end) + + when "dependencies" + _logger_warn "dependency activity being logged" + (::Dependencies.log_activity = true) rescue nil +end diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/rake_task_redefine_task.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/rake_task_redefine_task.rb new file mode 100644 index 00000000..217d2590 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/rake_task_redefine_task.rb @@ -0,0 +1,35 @@ + +# Redefine instead of chain a Rake task +# http://www.bigbold.com/snippets/posts/show/2032 + +module Rake + module TaskManager + def redefine_task(task_class, args, &block) + task_name, deps = resolve_args(args) + task_name = task_class.scope_name(@scope, task_name) + deps = [deps] unless deps.respond_to?(:to_ary) + deps = deps.collect {|d| d.to_s } + task = @tasks[task_name.to_s] = task_class.new(task_name, self) + task.application = self + task.add_comment(@last_comment) + @last_comment = nil + task.enhance(deps, &block) + task + end + end + class Task + class << self + def redefine_task(args, &block) + Rake.application.redefine_task(self, args, &block) + end + end + end +end + +class Object + def silently + stderr, stdout, $stderr, $stdout = $stderr, $stdout, StringIO.new, StringIO.new + yield + $stderr, $stdout = stderr, stdout + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/reflection.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/reflection.rb new file mode 100644 index 00000000..0091397d --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/reflection.rb @@ -0,0 +1,58 @@ +module ActiveRecord #:nodoc: + module Reflection #:nodoc: + + module ClassMethods #:nodoc: + + # Update the default reflection switch so that :has_many_polymorphs types get instantiated. + # It's not a composed method so we have to override the whole thing. + def create_reflection(macro, name, options, active_record) + case macro + when :has_many, :belongs_to, :has_one, :has_and_belongs_to_many + klass = options[:through] ? ThroughReflection : AssociationReflection + reflection = klass.new(macro, name, options, active_record) + when :composed_of + reflection = AggregateReflection.new(macro, name, options, active_record) + # added by has_many_polymorphs # + when :has_many_polymorphs + reflection = PolymorphicReflection.new(macro, name, options, active_record) + end + write_inheritable_hash :reflections, name => reflection + reflection + end + + end + + class PolymorphicError < ActiveRecordError #:nodoc: + end + +=begin rdoc + +The reflection built by the has_many_polymorphs method. + +Inherits from ActiveRecord::Reflection::AssociationReflection. + +=end + + class PolymorphicReflection < ThroughReflection + # Stub out the validity check. Has_many_polymorphs checks validity on macro creation, not on reflection. + def check_validity! + # nothing + end + + # Return the source reflection. + def source_reflection + # normally is the has_many to the through model, but we return ourselves, + # since there isn't a real source class for a polymorphic target + self + end + + # Set the classname of the target. Uses the join class name. + def class_name + # normally is the classname of the association target + @class_name ||= options[:join_class_name] + end + + end + + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/support_methods.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/support_methods.rb new file mode 100644 index 00000000..89ca52a4 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/support_methods.rb @@ -0,0 +1,84 @@ + +class String + + # Changes an underscored string into a class reference. + def _as_class + # classify expects self to be plural + self.classify.constantize + end + + # For compatibility with the Symbol extensions. + alias :_singularize :singularize + alias :_pluralize :pluralize + alias :_classify :classify +end + +class Symbol + + # Changes an underscored symbol into a class reference. + def _as_class; self.to_s._as_class; end + + # Changes a plural symbol into a singular symbol. + def _singularize; self.to_s.singularize.to_sym; end + + # Changes a singular symbol into a plural symbol. + def _pluralize; self.to_s.pluralize.to_sym; end + + # Changes a symbol into a class name string. + def _classify; self.to_s.classify; end +end + +class Array + + # Flattens the first level of self. + def _flatten_once + self.inject([]){|r, el| r + Array(el)} + end + + # Rails 1.2.3 compatibility method. Copied from http://dev.rubyonrails.org/browser/trunk/activesupport/lib/active_support/core_ext/array/extract_options.rb?rev=7217 + def _extract_options! + last.is_a?(::Hash) ? pop : {} + end +end + +class Hash + + # An implementation of select that returns a Hash. + def _select + Hash[*self.select do |key, value| + yield key, value + end._flatten_once] + end +end + +class Object + + # Returns the metaclass of self. + def _metaclass; (class << self; self; end); end + + # Logger shortcut. + def _logger_debug s + s = "** has_many_polymorphs: #{s}" + RAILS_DEFAULT_LOGGER.debug(s) if RAILS_DEFAULT_LOGGER + end + + # Logger shortcut. + def _logger_warn s + s = "** has_many_polymorphs: #{s}" + if RAILS_DEFAULT_LOGGER + RAILS_DEFAULT_LOGGER.warn(s) + else + $stderr.puts(s) + end + end + +end + +class ActiveRecord::Base + + # Return the base class name as a string. + def _base_class_name + self.class.base_class.name.to_s + end + +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/bow_wows.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/bow_wows.yml new file mode 100644 index 00000000..00be9d88 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/bow_wows.yml @@ -0,0 +1,10 @@ +rover: + id: 1 + name: Rover + created_at: "2007-01-01 12:00:00" + updated_at: "2007-01-04 10:00:00" +spot: + id: 2 + name: Spot + created_at: "2007-01-02 12:00:00" + updated_at: "2007-01-03 10:00:00" diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/cats.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/cats.yml new file mode 100644 index 00000000..aed894f9 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/cats.yml @@ -0,0 +1,18 @@ +chloe: + id: 1 + cat_type: Kitten + name: Chloe + created_at: "2007-04-01 12:00:00" + updated_at: "2007-04-04 10:00:00" +alice: + id: 2 + cat_type: Kitten + name: Alice + created_at: "2007-04-02 12:00:00" + updated_at: "2007-04-03 10:00:00" +toby: + id: 3 + cat_type: Tabby + name: Toby + created_at: "2007-04-02 12:00:00" + updated_at: "2007-04-03 10:00:00" diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/eaters_foodstuffs.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/eaters_foodstuffs.yml new file mode 100644 index 00000000..e69de29b diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/fish.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/fish.yml new file mode 100644 index 00000000..3974a672 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/fish.yml @@ -0,0 +1,12 @@ +swimmy: + id: 1 + name: Swimmy + speed: 10 + created_at: "2007-02-01 12:00:00" + updated_at: "2007-02-04 10:00:00" +jaws: + id: 2 + name: Jaws + speed: 20 + created_at: "2007-02-02 12:00:00" + updated_at: "2007-02-03 10:00:00" diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/frogs.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/frogs.yml new file mode 100644 index 00000000..e9d37d7c --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/frogs.yml @@ -0,0 +1,5 @@ +froggy: + id: 1 + name: Froggy + created_at: "2007-05-01 12:00:00" + updated_at: "2007-05-04 10:00:00" diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/keep_your_enemies_close.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/keep_your_enemies_close.yml new file mode 100644 index 00000000..e69de29b diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/little_whale_pupils.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/little_whale_pupils.yml new file mode 100644 index 00000000..e69de29b diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/people.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/people.yml new file mode 100644 index 00000000..085d2172 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/people.yml @@ -0,0 +1,7 @@ +bob: + id: 1 + name: Bob + age: 45 + created_at: "2007-04-01 12:00:00" + updated_at: "2007-04-04 10:00:00" + \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/petfoods.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/petfoods.yml new file mode 100644 index 00000000..a117d294 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/petfoods.yml @@ -0,0 +1,11 @@ +kibbles: + the_petfood_primary_key: 1 + name: Kibbles + created_at: "2007-06-01 12:00:00" + updated_at: "2007-06-04 10:00:00" +bits: + the_petfood_primary_key: 2 + name: Bits + created_at: "2007-06-02 12:00:00" + updated_at: "2007-06-03 10:00:00" + \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/whales.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/whales.yml new file mode 100644 index 00000000..bded734e --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/whales.yml @@ -0,0 +1,5 @@ +shamu: + id: 1 + name: Shamu + created_at: "2007-03-01 12:00:00" + updated_at: "2007-03-04 10:00:00" diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/wild_boars.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/wild_boars.yml new file mode 100644 index 00000000..73fd3e2e --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/wild_boars.yml @@ -0,0 +1,10 @@ +puma: + id: 1 + name: Puma + created_at: "2007-07-01 12:00:00" + updated_at: "2007-07-04 10:00:00" +jacrazy: + id: 2 + name: Jacrazy + created_at: "2007-07-02 12:00:00" + updated_at: "2007-07-03 10:00:00" diff --git a/vendor/gems/has_many_polymorphs-2.13/test/generator/tagging_generator_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/generator/tagging_generator_test.rb new file mode 100644 index 00000000..34e20c4f --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/generator/tagging_generator_test.rb @@ -0,0 +1,42 @@ +require 'fileutils' +require File.dirname(__FILE__) + '/../test_helper' + +class TaggingGeneratorTest < Test::Unit::TestCase + + def setup + Dir.chdir RAILS_ROOT do + truncate + + # Revert environment lib requires + FileUtils.cp "config/environment.rb.canonical", "config/environment.rb" + + # Delete generator output + ["app/models/tag.rb", "app/models/tagging.rb", + "test/unit/tag_test.rb", "test/unit/tagging_test.rb", + "test/fixtures/tags.yml", "test/fixtures/taggings.yml", + "lib/tagging_extensions.rb", + "db/migrate/010_create_tags_and_taggings.rb"].each do |file| + File.delete file if File.exist? file + end + + # Rebuild database + Echoe.silence do + system("ruby #{HERE}/setup.rb") + end + end + end + + alias :teardown :setup + + def test_generator + Dir.chdir RAILS_ROOT do + Echoe.silence do + assert system("script/generate tagging Stick Stone -q -f") + assert system("rake db:migrate") + assert system("rake db:fixtures:load") + assert system("rake test:units") + end + end + end + +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/README b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/README new file mode 100644 index 00000000..0d6affdd --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/README @@ -0,0 +1,182 @@ +== Welcome to Rails + +Rails is a web-application and persistence 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-built 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 an 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 are 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. + + +== Getting started + +1. At the command prompt, start a new rails application using the rails command + and your application name. Ex: rails myapp + (If you've downloaded rails in a complete tgz or zip, this step is already done) +2. Change directory into myapp and start the web server: script/server (run with --help for options) +3. Go to http://localhost:3000/ and get "Welcome aboard: You’re riding the Rails!" +4. Follow the guidelines to start developing your application + + +== Web Servers + +By default, Rails will try to use Mongrel and lighttpd if they are installed, otherwise +Rails will use the WEBrick, the webserver that ships with Ruby. When you run script/server, +Rails will check if Mongrel exists, then lighttpd and finally fall back to WEBrick. This ensures +that you can always get up and running quickly. + +Mongrel is a Ruby-based webserver with a C-component (which requires compilation) that is +suitable for development and deployment of Rails applications. If you have Ruby Gems installed, +getting up and running with mongrel is as easy as: gem install mongrel. +More info at: http://mongrel.rubyforge.org + +If Mongrel is not installed, Rails will look for lighttpd. It's considerably faster than +Mongrel and WEBrick and also suited for production use, but requires additional +installation and currently only works well on OS X/Unix (Windows users are encouraged +to start with Mongrel). We recommend version 1.4.11 and higher. You can download it from +http://www.lighttpd.net. + +And finally, if neither Mongrel or lighttpd are installed, Rails will use the built-in Ruby +web server, WEBrick. WEBrick is a small Ruby web server suitable for development, but not +for production. + +But of course its also possible to run Rails on any platform that supports FCGI. +Apache, LiteSpeed, IIS are just a few. For more information on FCGI, +please visit: http://wiki.rubyonrails.com/rails/pages/FastCGI + + +== Debugging Rails + +Have "tail -f" commands running on the server.log and development.log. 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 + => "[#nil, \"body\"=>nil, \"id\"=>\"1\"}>, + #\"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 + => #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. Starting the script without arguments will launch it in the development environment. +Passing an argument will specify a different environment, like script/console production. + +To reload your controllers and models after launching the console run reload! + +To reload your controllers and models after launching the console run reload! + + + +== Description of contents + +app + Holds all the code that's specific to this particular application. + +app/controllers + Holds controllers that should be named like weblogs_controller.rb for + automated URL mapping. All controllers should descend from ApplicationController + which itself descends from ActionController::Base. + +app/models + Holds models that should be named like post.rb. + Most models will descend from ActiveRecord::Base. + +app/views + Holds the template files for the view that should be named like + weblogs/index.rhtml for the WeblogsController#index action. All views use eRuby + syntax. + +app/views/layouts + Holds the template files for layouts to be used with views. This models the common + header/footer method of wrapping views. In your views, define a layout using the + layout :default and create a file named default.rhtml. Inside default.rhtml, + call <% yield %> to render the view using this layout. + +app/helpers + Holds view helpers that should be named like weblogs_helper.rb. These are generated + for you automatically when using script/generate for controllers. Helpers can be used to + wrap functionality for your views into methods. + +config + Configuration files for the Rails environment, the routing map, the database, and other dependencies. + +components + Self-contained mini-applications that can bundle together controllers, models, and views. + +db + Contains the database schema in schema.rb. db/migrate contains all + the sequence of Migrations for your schema. + +doc + This directory is where your application documentation will be stored when generated + using rake doc:app + +lib + Application specific libraries. Basically, any kind of custom code that doesn't + belong under controllers, models, or helpers. This directory is in the load path. + +public + The directory available for the web server. Contains subdirectories for images, stylesheets, + and javascripts. Also contains the dispatchers and the default HTML files. This should be + set as the DOCUMENT_ROOT of your web server. + +script + Helper scripts for automation and generation. + +test + Unit and functional tests along with fixtures. When using the script/generate scripts, template + test files will be generated for you and placed in this directory. + +vendor + External libraries that the application depends on. Also includes the plugins subdirectory. + This directory is in the load path. diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/Rakefile b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/Rakefile new file mode 100644 index 00000000..2573c13c --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/Rakefile @@ -0,0 +1,19 @@ +# 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' + +namespace :test do + desc "a new rake task to include generators" + Rake::TestTask.new(:generators) do |t| + t.libs << 'lib' + t.test_files = FileList['test/generators/*_test.rb'] + t.verbose = true + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/controllers/application.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/controllers/application.rb new file mode 100644 index 00000000..057f4f7e --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/controllers/application.rb @@ -0,0 +1,7 @@ +# Filters added to this controller apply to all controllers in the application. +# Likewise, all the methods added will be available for all controllers. + +class ApplicationController < ActionController::Base + # Pick a unique cookie name to distinguish our session data from others' + session :session_key => '_testapp_session_id' +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/controllers/bones_controller.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/controllers/bones_controller.rb new file mode 100644 index 00000000..29bfe0c0 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/controllers/bones_controller.rb @@ -0,0 +1,5 @@ +class BonesController < ApplicationController + def index + @bones = Bone.find(:all) + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/addresses_helper.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/addresses_helper.rb new file mode 100644 index 00000000..5f4dc138 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/addresses_helper.rb @@ -0,0 +1,2 @@ +module AddressesHelper +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/application_helper.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/application_helper.rb new file mode 100644 index 00000000..22a7940e --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/application_helper.rb @@ -0,0 +1,3 @@ +# Methods added to this helper will be available to all templates in the application. +module ApplicationHelper +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/bones_helper.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/bones_helper.rb new file mode 100644 index 00000000..c188f669 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/bones_helper.rb @@ -0,0 +1,2 @@ +module BonesHelper +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/sellers_helper.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/sellers_helper.rb new file mode 100644 index 00000000..4bdecd54 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/sellers_helper.rb @@ -0,0 +1,28 @@ +module SellersHelper + + def display_address(seller) + logger.info "Seller Data ====================" + logger.info seller.inspect + logger.info "Seller responds to address " + seller.respond_to?("address").to_s + logger.info "Seller responds to address= " + seller.respond_to?("address=").to_s + # logger.info seller.methods.sort.inspect + logger.info "User Data ====================" + logger.info seller.user.inspect + logger.info "User responds to address " + seller.user.respond_to?("address").to_s + logger.info "User responds to address= " + seller.user.respond_to?("address=").to_s + # logger.info seller.user.methods.sort.inspect + display_address = Array.new + if seller.address + display_address << seller.address.city if seller.address.city + display_address << seller.address.state.abbreviation if seller.address.state && seller.address.state.abbreviation + display_address << seller.address.zip_postal_code if seller.address.zip_postal_code + end + + unless display_address.empty? + "Location: " + display_address.join(", ") + else + "Location: unknown" + end + end + +end \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/states_helper.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/states_helper.rb new file mode 100644 index 00000000..f98bdc7c --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/states_helper.rb @@ -0,0 +1,2 @@ +module StatesHelper +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/users_helper.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/users_helper.rb new file mode 100644 index 00000000..2310a240 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/users_helper.rb @@ -0,0 +1,2 @@ +module UsersHelper +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/bone.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/bone.rb new file mode 100644 index 00000000..f9268612 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/bone.rb @@ -0,0 +1,2 @@ +class Bone < OrganicSubstance +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/double_sti_parent.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/double_sti_parent.rb new file mode 100644 index 00000000..5bc344f7 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/double_sti_parent.rb @@ -0,0 +1,2 @@ +class DoubleStiParent < ActiveRecord::Base +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/double_sti_parent_relationship.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/double_sti_parent_relationship.rb new file mode 100644 index 00000000..10b6255b --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/double_sti_parent_relationship.rb @@ -0,0 +1,2 @@ +class DoubleStiParentRelationship < ActiveRecord::Base +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/organic_substance.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/organic_substance.rb new file mode 100644 index 00000000..e9a080d9 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/organic_substance.rb @@ -0,0 +1,2 @@ +class OrganicSubstance < ActiveRecord::Base +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/single_sti_parent.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/single_sti_parent.rb new file mode 100644 index 00000000..5e4410bb --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/single_sti_parent.rb @@ -0,0 +1,4 @@ + +class SingleStiParent < ActiveRecord::Base + has_many_polymorphs :the_bones, :from => [:bones], :through => :single_sti_parent_relationship +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/single_sti_parent_relationship.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/single_sti_parent_relationship.rb new file mode 100644 index 00000000..7f783c15 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/single_sti_parent_relationship.rb @@ -0,0 +1,4 @@ +class SingleStiParentRelationship < ActiveRecord::Base + belongs_to :single_sti_parent + belongs_to :the_bone, :polymorphic => true +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/stick.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/stick.rb new file mode 100644 index 00000000..4992506a --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/stick.rb @@ -0,0 +1,2 @@ +class Stick < ActiveRecord::Base +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/stone.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/stone.rb new file mode 100644 index 00000000..8617396e --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/stone.rb @@ -0,0 +1,2 @@ +class Stone < ActiveRecord::Base +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/edit.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/edit.html.erb new file mode 100644 index 00000000..6b6a3894 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/edit.html.erb @@ -0,0 +1,12 @@ +

        Editing address

        + +<%= error_messages_for :address %> + +<% form_for(@address) do |f| %> +

        + <%= f.submit "Update" %> +

        +<% end %> + +<%= link_to 'Show', @address %> | +<%= link_to 'Back', addresses_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/index.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/index.html.erb new file mode 100644 index 00000000..86d0d387 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/index.html.erb @@ -0,0 +1,18 @@ +

        Listing addresses

        + + + + + +<% for address in @addresses %> + + + + + +<% end %> +
        <%= link_to 'Show', address %><%= link_to 'Edit', edit_address_path(address) %><%= link_to 'Destroy', address, :confirm => 'Are you sure?', :method => :delete %>
        + +
        + +<%= link_to 'New address', new_address_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/new.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/new.html.erb new file mode 100644 index 00000000..1fae44cf --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/new.html.erb @@ -0,0 +1,11 @@ +

        New address

        + +<%= error_messages_for :address %> + +<% form_for(@address) do |f| %> +

        + <%= f.submit "Create" %> +

        +<% end %> + +<%= link_to 'Back', addresses_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/show.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/show.html.erb new file mode 100644 index 00000000..a75ddbd5 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/show.html.erb @@ -0,0 +1,3 @@ + +<%= link_to 'Edit', edit_address_path(@address) %> | +<%= link_to 'Back', addresses_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/bones/index.rhtml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/bones/index.rhtml new file mode 100644 index 00000000..06f1dad3 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/bones/index.rhtml @@ -0,0 +1,5 @@ + +

        Bones: index

        +<% @bones.each do |bone| %> +

        ID: <%= bone.id %>

        +<% end %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/addresses.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/addresses.html.erb new file mode 100644 index 00000000..84583552 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/addresses.html.erb @@ -0,0 +1,17 @@ + + + + + + Addresses: <%= controller.action_name %> + <%= stylesheet_link_tag 'scaffold' %> + + + +

        <%= flash[:notice] %>

        + +<%= yield %> + + + diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/sellers.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/sellers.html.erb new file mode 100644 index 00000000..bc08e9be --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/sellers.html.erb @@ -0,0 +1,17 @@ + + + + + + Sellers: <%= controller.action_name %> + <%= stylesheet_link_tag 'scaffold' %> + + + +

        <%= flash[:notice] %>

        + +<%= yield %> + + + diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/states.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/states.html.erb new file mode 100644 index 00000000..b2b086fd --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/states.html.erb @@ -0,0 +1,17 @@ + + + + + + States: <%= controller.action_name %> + <%= stylesheet_link_tag 'scaffold' %> + + + +

        <%= flash[:notice] %>

        + +<%= yield %> + + + diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/users.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/users.html.erb new file mode 100644 index 00000000..23757aa6 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/users.html.erb @@ -0,0 +1,17 @@ + + + + + + Users: <%= controller.action_name %> + <%= stylesheet_link_tag 'scaffold' %> + + + +

        <%= flash[:notice] %>

        + +<%= yield %> + + + diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/edit.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/edit.html.erb new file mode 100644 index 00000000..14c41036 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/edit.html.erb @@ -0,0 +1,12 @@ +

        Editing seller

        + +<%= error_messages_for :seller %> + +<% form_for(@seller) do |f| %> +

        + <%= f.submit "Update" %> +

        +<% end %> + +<%= link_to 'Show', @seller %> | +<%= link_to 'Back', sellers_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/index.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/index.html.erb new file mode 100644 index 00000000..97ef0457 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/index.html.erb @@ -0,0 +1,20 @@ +

        Listing sellers

        + + + + + +<% for seller in @sellers %> + + + + + + + +<% end %> +
        <%= h(seller.company_name) %><%= h(display_address(seller)) %><%= link_to 'Show', seller %><%= link_to 'Edit', edit_seller_path(seller) %><%= link_to 'Destroy', seller, :confirm => 'Are you sure?', :method => :delete %>
        + +
        + +<%= link_to 'New seller', new_seller_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/new.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/new.html.erb new file mode 100644 index 00000000..6814338d --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/new.html.erb @@ -0,0 +1,11 @@ +

        New seller

        + +<%= error_messages_for :seller %> + +<% form_for(@seller) do |f| %> +

        + <%= f.submit "Create" %> +

        +<% end %> + +<%= link_to 'Back', sellers_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/show.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/show.html.erb new file mode 100644 index 00000000..f21dcfa7 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/show.html.erb @@ -0,0 +1,3 @@ + +<%= link_to 'Edit', edit_seller_path(@seller) %> | +<%= link_to 'Back', sellers_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/edit.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/edit.html.erb new file mode 100644 index 00000000..dc59d08b --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/edit.html.erb @@ -0,0 +1,12 @@ +

        Editing state

        + +<%= error_messages_for :state %> + +<% form_for(@state) do |f| %> +

        + <%= f.submit "Update" %> +

        +<% end %> + +<%= link_to 'Show', @state %> | +<%= link_to 'Back', states_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/index.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/index.html.erb new file mode 100644 index 00000000..07c11ae1 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/index.html.erb @@ -0,0 +1,19 @@ +

        Listing states

        + + + + + +<% for state in @states %> + + + + + + +<% end %> +
        <%= state.name %><%= link_to 'Show', state %><%= link_to 'Edit', edit_state_path(state) %><%= link_to 'Destroy', state, :confirm => 'Are you sure?', :method => :delete %>
        + +
        + +<%= link_to 'New state', new_state_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/new.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/new.html.erb new file mode 100644 index 00000000..5caacd5d --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/new.html.erb @@ -0,0 +1,11 @@ +

        New state

        + +<%= error_messages_for :state %> + +<% form_for(@state) do |f| %> +

        + <%= f.submit "Create" %> +

        +<% end %> + +<%= link_to 'Back', states_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/show.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/show.html.erb new file mode 100644 index 00000000..ba5c32fb --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/show.html.erb @@ -0,0 +1,3 @@ + +<%= link_to 'Edit', edit_state_path(@state) %> | +<%= link_to 'Back', states_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/edit.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/edit.html.erb new file mode 100644 index 00000000..b497ec93 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/edit.html.erb @@ -0,0 +1,12 @@ +

        Editing user

        + +<%= error_messages_for :user %> + +<% form_for(@user) do |f| %> +

        + <%= f.submit "Update" %> +

        +<% end %> + +<%= link_to 'Show', @user %> | +<%= link_to 'Back', users_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/index.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/index.html.erb new file mode 100644 index 00000000..6397e64e --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/index.html.erb @@ -0,0 +1,22 @@ +

        Listing users

        + + + + + +<% for user in @users %> + + + + + + + + + +<% end %> +
        <%= h(user.login) %><%= h(user.address.line_1) %><%= h(user.address.city) %><%= h(user.address.state.name) %><%= link_to 'Show', user %><%= link_to 'Edit', edit_user_path(user) %><%= link_to 'Destroy', user, :confirm => 'Are you sure?', :method => :delete %>
        + +
        + +<%= link_to 'New user', new_user_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/new.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/new.html.erb new file mode 100644 index 00000000..bc76aa6b --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/new.html.erb @@ -0,0 +1,11 @@ +

        New user

        + +<%= error_messages_for :user %> + +<% form_for(@user) do |f| %> +

        + <%= f.submit "Create" %> +

        +<% end %> + +<%= link_to 'Back', users_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/show.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/show.html.erb new file mode 100644 index 00000000..3109a37d --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/show.html.erb @@ -0,0 +1,3 @@ + +<%= link_to 'Edit', edit_user_path(@user) %> | +<%= link_to 'Back', users_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/boot.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/boot.rb new file mode 100644 index 00000000..cb9a72da --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/boot.rb @@ -0,0 +1,110 @@ +# Don't change this file! +# Configure your app in config/environment.rb and config/environments/*.rb + +RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT) + +module Rails + class << self + def boot! + unless booted? + preinitialize + pick_boot.run + end + end + + def booted? + defined? Rails::Initializer + end + + def pick_boot + (vendor_rails? ? VendorBoot : GemBoot).new + end + + def vendor_rails? + File.exist?("#{RAILS_ROOT}/vendor/rails") + end + + def preinitialize + load(preinitializer_path) if File.exists?(preinitializer_path) + end + + def preinitializer_path + "#{RAILS_ROOT}/config/preinitializer.rb" + end + end + + class Boot + def run + load_initializer + Rails::Initializer.run(:set_load_path) + end + end + + class VendorBoot < Boot + def load_initializer + require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer" + end + end + + class GemBoot < Boot + def load_initializer + self.class.load_rubygems + load_rails_gem + require 'initializer' + end + + def load_rails_gem + if version = self.class.gem_version + STDERR.puts "Boot.rb loading version #{version}" + gem 'rails', version + else + STDERR.puts "Boot.rb loading latest available version" + gem 'rails' + end + rescue Gem::LoadError => load_error + $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.) + exit 1 + end + + class << self + def rubygems_version + Gem::RubyGemsVersion if defined? Gem::RubyGemsVersion + end + + def gem_version + if defined? RAILS_GEM_VERSION + RAILS_GEM_VERSION + elsif ENV.include?('RAILS_GEM_VERSION') + ENV['RAILS_GEM_VERSION'] + else + parse_gem_version(read_environment_rb) + end + end + + def load_rubygems + require 'rubygems' + + unless rubygems_version >= '0.9.4' + $stderr.puts %(Rails requires RubyGems >= 0.9.4 (you have #{rubygems_version}). Please `gem update --system` and try again.) + exit 1 + end + + rescue LoadError + $stderr.puts %(Rails requires RubyGems >= 0.9.4. Please install RubyGems and try again: http://rubygems.rubyforge.org) + exit 1 + end + + def parse_gem_version(text) + $1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*'([!~<>=]*\s*[\d.]+)'/ + end + + private + def read_environment_rb + File.read("#{RAILS_ROOT}/config/environment.rb") + end + end + end +end + +# All that for this: +Rails.boot! diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/database.yml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/database.yml new file mode 100644 index 00000000..c64a5d89 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/database.yml @@ -0,0 +1,17 @@ + +defaults: &defaults + adapter: <%= ENV['DB'] || 'mysql' %> + host: localhost + database: hmp_development + username: root + password: + +development: + <<: *defaults + +test: + <<: *defaults + +production: + <<: *defaults + \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environment.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environment.rb new file mode 100644 index 00000000..39f34dee --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environment.rb @@ -0,0 +1,19 @@ +require File.join(File.dirname(__FILE__), 'boot') +require 'action_controller' + +Rails::Initializer.run do |config| + + if ActionController::Base.respond_to? 'session=' + config.action_controller.session = {:session_key => '_app_session', :secret => '22cde4d5c1a61ba69a81795322cde4d5c1a61ba69a817953'} + end + + config.load_paths << "#{RAILS_ROOT}/app/models/person" # moduleless model path + + config.after_initialize do + config.has_many_polymorphs_options['requirements'] << "#{RAILS_ROOT}/lib/library_model" + end +end + +# Dependencies.log_activity = true + +ENV['RAILS_ASSET_ID'] = Time.now.to_i.to_s diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environment.rb.canonical b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environment.rb.canonical new file mode 100644 index 00000000..39f34dee --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environment.rb.canonical @@ -0,0 +1,19 @@ +require File.join(File.dirname(__FILE__), 'boot') +require 'action_controller' + +Rails::Initializer.run do |config| + + if ActionController::Base.respond_to? 'session=' + config.action_controller.session = {:session_key => '_app_session', :secret => '22cde4d5c1a61ba69a81795322cde4d5c1a61ba69a817953'} + end + + config.load_paths << "#{RAILS_ROOT}/app/models/person" # moduleless model path + + config.after_initialize do + config.has_many_polymorphs_options['requirements'] << "#{RAILS_ROOT}/lib/library_model" + end +end + +# Dependencies.log_activity = true + +ENV['RAILS_ASSET_ID'] = Time.now.to_i.to_s diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/development.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/development.rb new file mode 100644 index 00000000..54ae4ed2 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/development.rb @@ -0,0 +1,9 @@ + +config.cache_classes = ENV['PRODUCTION'] +config.whiny_nils = true +config.action_controller.consider_all_requests_local = !ENV['PRODUCTION'] +config.action_controller.perform_caching = ENV['PRODUCTION'] +# The following has been deprecated in Rails 2.1 and removed in 2.2 +config.action_view.cache_template_extensions = ENV['PRODUCTION'] if Rails::VERSION::MAJOR < 2 or Rails::VERSION::MAJOR == 2 && Rails::VERSION::MINOR < 1 +config.action_view.debug_rjs = !ENV['PRODUCTION'] +config.action_mailer.raise_delivery_errors = false diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/production.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/production.rb new file mode 100644 index 00000000..cb295b83 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/production.rb @@ -0,0 +1,18 @@ +# Settings specified here will take precedence over those in config/environment.rb + +# The production environment is meant for finished, "live" apps. +# Code is not reloaded between requests +config.cache_classes = true + +# Use a different logger for distributed setups +# config.logger = SyslogLogger.new + +# Full error reports are disabled and caching is turned on +config.action_controller.consider_all_requests_local = false +config.action_controller.perform_caching = true + +# Enable serving of images, stylesheets, and javascripts from an asset server +# config.action_controller.asset_host = "http://assets.example.com" + +# Disable delivery errors, bad email addresses will be ignored +# config.action_mailer.raise_delivery_errors = false diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/test.rb new file mode 100644 index 00000000..f0689b92 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/test.rb @@ -0,0 +1,19 @@ +# Settings specified here will take precedence over those in config/environment.rb + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! +config.cache_classes = true + +# Log error messages when you accidentally call methods on nil. +config.whiny_nils = true + +# Show full error reports and disable caching +config.action_controller.consider_all_requests_local = true +config.action_controller.perform_caching = false + +# Tell ActionMailer not to deliver emails to the real world. +# The :test delivery method accumulates sent emails in the +# ActionMailer::Base.deliveries array. +config.action_mailer.delivery_method = :test \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/locomotive.yml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/locomotive.yml new file mode 100644 index 00000000..01d79773 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/locomotive.yml @@ -0,0 +1,6 @@ +--- +mode: development +runs_at_launch: 0 +identifier: testapp +port: 3005 +bundle: /Applications/Locomotive2/Bundles/rmagickRailsMar2007_i386.locobundle \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/routes.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/routes.rb new file mode 100644 index 00000000..b83b6f4d --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/routes.rb @@ -0,0 +1,33 @@ +ActionController::Routing::Routes.draw do |map| + map.resources :states + + map.resources :states + + map.resources :addresses + + map.resources :sellers + + map.resources :users + + # The priority is based upon order of creation: first created -> highest priority. + + # Sample of regular route: + # map.connect 'products/:id', :controller => 'catalog', :action => 'view' + # Keep in mind you can assign values other than :controller and :action + + # Sample of named route: + # map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase' + # This route can be invoked with purchase_url(:id => product.id) + + # You can have the root of your site routed by hooking up '' + # -- just remember to delete public/index.html. + # map.connect '', :controller => "welcome" + + # Allow downloading Web Service WSDL as a file with an extension + # instead of a file named 'wsdl' + map.connect ':controller/service.wsdl', :action => 'wsdl' + + # Install the default route as the lowest priority. + map.connect ':controller/:action/:id.:format' + map.connect ':controller/:action/:id' +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/ultrasphinx/default.base b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/ultrasphinx/default.base new file mode 100644 index 00000000..2886ccdc --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/ultrasphinx/default.base @@ -0,0 +1,56 @@ +# +# Sphinx/Ultrasphinx user-configurable options. +# +# Copy this file to RAILS_ROOT/config/ultrasphinx. +# You can use individual namespaces if you want (e.g. "development.base"). +# + +indexer +{ + # Indexer running options + mem_limit = 256M +} + +searchd +{ + # Daemon options + # What interface the search daemon should listen on and where to store its logs + address = 0.0.0.0 + port = 3313 + log = /tmp/sphinx/searchd.log + query_log = /tmp/sphinx/query.log + read_timeout = 5 + max_children = 300 + pid_file = /tmp/sphinx/searchd.pid + max_matches = 100000 +} + +client +{ + # Client options + dictionary_name = ts + # How your application connects to the search daemon (not necessarily the same as above) + server_host = localhost + server_port = 3313 +} + +source +{ + # Individual SQL source options + sql_range_step = 20000 + strip_html = 0 + index_html_attrs = + sql_query_post = +} + +index +{ + # Index building options + path = /tmp/sphinx/ + docinfo = extern # just leave this alone + morphology = stem_en + stopwords = # /path/to/stopwords.txt + min_word_len = 1 + charset_type = utf-8 # or sbcs (Single Byte Character Set) + charset_table = 0..9, A..Z->a..z, -, _, ., &, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F,U+C5->U+E5, U+E5, U+C4->U+E4, U+E4, U+D6->U+F6, U+F6, U+16B, U+0c1->a, U+0c4->a, U+0c9->e, U+0cd->i, U+0d3->o, U+0d4->o, U+0da->u, U+0dd->y, U+0e1->a, U+0e4->a, U+0e9->e, U+0ed->i, U+0f3->o, U+0f4->o, U+0fa->u, U+0fd->y, U+104->U+105, U+105, U+106->U+107, U+10c->c, U+10d->c, U+10e->d, U+10f->d, U+116->U+117, U+117, U+118->U+119, U+11a->e, U+11b->e, U+12E->U+12F, U+12F, U+139->l, U+13a->l, U+13d->l, U+13e->l, U+141->U+142, U+142, U+143->U+144, U+144,U+147->n, U+148->n, U+154->r, U+155->r, U+158->r, U+159->r, U+15A->U+15B, U+15B, U+160->s, U+160->U+161, U+161->s, U+164->t, U+165->t, U+16A->U+16B, U+16B, U+16e->u, U+16f->u, U+172->U+173, U+173, U+179->U+17A, U+17A, U+17B->U+17C, U+17C, U+17d->z, U+17e->z, +} diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/ultrasphinx/development.conf.canonical b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/ultrasphinx/development.conf.canonical new file mode 100644 index 00000000..f08e8ed4 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/ultrasphinx/development.conf.canonical @@ -0,0 +1,155 @@ + +# Auto-generated at Wed Oct 03 03:57:12 -0400 2007. +# Hand modifications will be overwritten. +# /Users/eweaver/Desktop/projects/chow/vendor/plugins/ultrasphinx/test/integration/app/config/ultrasphinx/default.base +indexer { + mem_limit = 256M +} +searchd { + read_timeout = 5 + max_children = 300 + log = /tmp/sphinx/searchd.log + port = 3313 + max_matches = 100000 + query_log = /tmp/sphinx/query.log + pid_file = /tmp/sphinx/searchd.pid + address = 0.0.0.0 +} + +# Source configuration + +source geo__states +{ + strip_html = 0 + sql_range_step = 20000 + index_html_attrs = + sql_query_post = + +type = mysql +sql_query_pre = SET SESSION group_concat_max_len = 65535 +sql_query_pre = SET NAMES utf8 + +sql_db = app_development +sql_host = localhost +sql_pass = +sql_user = root +sql_query_range = SELECT MIN(id), MAX(id) FROM states +sql_query = SELECT (states.id * 4 + 0) AS id, CAST(GROUP_CONCAT(addresses.name SEPARATOR ' ') AS CHAR) AS address_name, 0 AS capitalization, 'Geo::State' AS class, 0 AS class_id, '' AS company, '' AS company_name, 0 AS company_name_facet, '' AS content, UNIX_TIMESTAMP('1970-01-01 00:00:00') AS created_at, 0 AS deleted, '' AS email, '__empty_searchable__' AS empty_searchable, '' AS login, '' AS name, '' AS state, 0 AS user_id FROM states LEFT OUTER JOIN addresses ON states.id = addresses.state_id WHERE states.id >= $start AND states.id <= $end GROUP BY id + +sql_group_column = capitalization +sql_group_column = class_id +sql_group_column = company_name_facet +sql_date_column = created_at +sql_group_column = deleted +sql_group_column = user_id +sql_query_info = SELECT * FROM states WHERE states.id = (($id - 0) / 4) +} + + +# Source configuration + +source sellers +{ + strip_html = 0 + sql_range_step = 20000 + index_html_attrs = + sql_query_post = + +type = mysql +sql_query_pre = SET SESSION group_concat_max_len = 65535 +sql_query_pre = SET NAMES utf8 + +sql_db = app_development +sql_host = localhost +sql_pass = +sql_user = root +sql_query_range = SELECT MIN(id), MAX(id) FROM sellers +sql_query = SELECT (sellers.id * 4 + 1) AS id, '' AS address_name, sellers.capitalization AS capitalization, 'Seller' AS class, 1 AS class_id, '' AS company, sellers.company_name AS company_name, CRC32(sellers.company_name) AS company_name_facet, '' AS content, UNIX_TIMESTAMP(sellers.created_at) AS created_at, 0 AS deleted, '' AS email, '__empty_searchable__' AS empty_searchable, '' AS login, '' AS name, '' AS state, sellers.user_id AS user_id FROM sellers WHERE sellers.id >= $start AND sellers.id <= $end GROUP BY id + +sql_group_column = capitalization +sql_group_column = class_id +sql_group_column = company_name_facet +sql_date_column = created_at +sql_group_column = deleted +sql_group_column = user_id +sql_query_info = SELECT * FROM sellers WHERE sellers.id = (($id - 1) / 4) +} + + +# Source configuration + +source geo__addresses +{ + strip_html = 0 + sql_range_step = 20000 + index_html_attrs = + sql_query_post = + +type = mysql +sql_query_pre = SET SESSION group_concat_max_len = 65535 +sql_query_pre = SET NAMES utf8 + +sql_db = app_development +sql_host = localhost +sql_pass = +sql_user = root +sql_query_range = SELECT MIN(id), MAX(id) FROM addresses +sql_query = SELECT (addresses.id * 4 + 2) AS id, '' AS address_name, 0 AS capitalization, 'Geo::Address' AS class, 2 AS class_id, '' AS company, '' AS company_name, 0 AS company_name_facet, CONCAT_WS(' ', addresses.line_1, addresses.line_2, addresses.city, addresses.province_region, addresses.zip_postal_code) AS content, UNIX_TIMESTAMP('1970-01-01 00:00:00') AS created_at, 0 AS deleted, '' AS email, '__empty_searchable__' AS empty_searchable, '' AS login, addresses.name AS name, states.name AS state, 0 AS user_id FROM addresses LEFT OUTER JOIN states ON states.id = addresses.state_id WHERE addresses.id >= $start AND addresses.id <= $end GROUP BY id + +sql_group_column = capitalization +sql_group_column = class_id +sql_group_column = company_name_facet +sql_date_column = created_at +sql_group_column = deleted +sql_group_column = user_id +sql_query_info = SELECT * FROM addresses WHERE addresses.id = (($id - 2) / 4) +} + + +# Source configuration + +source users +{ + strip_html = 0 + sql_range_step = 20000 + index_html_attrs = + sql_query_post = + +type = mysql +sql_query_pre = SET SESSION group_concat_max_len = 65535 +sql_query_pre = SET NAMES utf8 + +sql_db = app_development +sql_host = localhost +sql_pass = +sql_user = root +sql_query_range = SELECT MIN(id), MAX(id) FROM users +sql_query = SELECT (users.id * 4 + 3) AS id, '' AS address_name, 0 AS capitalization, 'User' AS class, 3 AS class_id, sellers.company_name AS company, '' AS company_name, 0 AS company_name_facet, '' AS content, UNIX_TIMESTAMP('1970-01-01 00:00:00') AS created_at, users.deleted AS deleted, users.email AS email, '__empty_searchable__' AS empty_searchable, users.login AS login, '' AS name, '' AS state, 0 AS user_id FROM users LEFT OUTER JOIN sellers ON users.id = sellers.user_id WHERE users.id >= $start AND users.id <= $end AND (deleted = 0) GROUP BY id + +sql_group_column = capitalization +sql_group_column = class_id +sql_group_column = company_name_facet +sql_date_column = created_at +sql_group_column = deleted +sql_group_column = user_id +sql_query_info = SELECT * FROM users WHERE users.id = (($id - 3) / 4) +} + + +# Index configuration + +index complete +{ + source = geo__addresses + source = geo__states + source = sellers + source = users + charset_type = utf-8 + charset_table = 0..9, A..Z->a..z, -, _, ., &, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F,U+C5->U+E5, U+E5, U+C4->U+E4, U+E4, U+D6->U+F6, U+F6, U+16B, U+0c1->a, U+0c4->a, U+0c9->e, U+0cd->i, U+0d3->o, U+0d4->o, U+0da->u, U+0dd->y, U+0e1->a, U+0e4->a, U+0e9->e, U+0ed->i, U+0f3->o, U+0f4->o, U+0fa->u, U+0fd->y, U+104->U+105, U+105, U+106->U+107, U+10c->c, U+10d->c, U+10e->d, U+10f->d, U+116->U+117, U+117, U+118->U+119, U+11a->e, U+11b->e, U+12E->U+12F, U+12F, U+139->l, U+13a->l, U+13d->l, U+13e->l, U+141->U+142, U+142, U+143->U+144, U+144,U+147->n, U+148->n, U+154->r, U+155->r, U+158->r, U+159->r, U+15A->U+15B, U+15B, U+160->s, U+160->U+161, U+161->s, U+164->t, U+165->t, U+16A->U+16B, U+16B, U+16e->u, U+16f->u, U+172->U+173, U+173, U+179->U+17A, U+17A, U+17B->U+17C, U+17C, U+17d->z, U+17e->z, + min_word_len = 1 + stopwords = + path = /tmp/sphinx//sphinx_index_complete + docinfo = extern + morphology = stem_en +} + diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/001_create_sticks.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/001_create_sticks.rb new file mode 100644 index 00000000..6193c313 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/001_create_sticks.rb @@ -0,0 +1,11 @@ +class CreateSticks < ActiveRecord::Migration + def self.up + create_table :sticks do |t| + t.column :name, :string + end + end + + def self.down + drop_table :sticks + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/002_create_stones.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/002_create_stones.rb new file mode 100644 index 00000000..4c1ec154 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/002_create_stones.rb @@ -0,0 +1,11 @@ +class CreateStones < ActiveRecord::Migration + def self.up + create_table :stones do |t| + t.column :name, :string + end + end + + def self.down + drop_table :stones + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/003_create_organic_substances.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/003_create_organic_substances.rb new file mode 100644 index 00000000..1bf82da6 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/003_create_organic_substances.rb @@ -0,0 +1,11 @@ +class CreateOrganicSubstances < ActiveRecord::Migration + def self.up + create_table :organic_substances do |t| + t.column :type, :string + end + end + + def self.down + drop_table :organic_substances + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/004_create_bones.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/004_create_bones.rb new file mode 100644 index 00000000..6faa0aa1 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/004_create_bones.rb @@ -0,0 +1,8 @@ +class CreateBones < ActiveRecord::Migration + def self.up + # Using STI + end + + def self.down + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/005_create_single_sti_parents.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/005_create_single_sti_parents.rb new file mode 100644 index 00000000..eef14621 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/005_create_single_sti_parents.rb @@ -0,0 +1,11 @@ +class CreateSingleStiParents < ActiveRecord::Migration + def self.up + create_table :single_sti_parents do |t| + t.column :name, :string + end + end + + def self.down + drop_table :single_sti_parents + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/006_create_double_sti_parents.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/006_create_double_sti_parents.rb new file mode 100644 index 00000000..2a28f4ab --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/006_create_double_sti_parents.rb @@ -0,0 +1,11 @@ +class CreateDoubleStiParents < ActiveRecord::Migration + def self.up + create_table :double_sti_parents do |t| + t.column :name, :string + end + end + + def self.down + drop_table :double_sti_parents + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb new file mode 100644 index 00000000..deceeec7 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb @@ -0,0 +1,13 @@ +class CreateSingleStiParentRelationships < ActiveRecord::Migration + def self.up + create_table :single_sti_parent_relationships do |t| + t.column :the_bone_type, :string, :null => false + t.column :the_bone_id, :integer, :null => false + t.column :single_sti_parent_id, :integer, :null => false + end + end + + def self.down + drop_table :single_sti_parent_relationships + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb new file mode 100644 index 00000000..46605d9b --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb @@ -0,0 +1,14 @@ +class CreateDoubleStiParentRelationships < ActiveRecord::Migration + def self.up + create_table :double_sti_parent_relationships do |t| + t.column :the_bone_type, :string, :null => false + t.column :the_bone_id, :integer, :null => false + t.column :parent_type, :string, :null => false + t.column :parent_id, :integer, :null => false + end + end + + def self.down + drop_table :double_sti_parent_relationships + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/009_create_library_model.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/009_create_library_model.rb new file mode 100644 index 00000000..bdf7cf46 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/009_create_library_model.rb @@ -0,0 +1,11 @@ +class CreateLibraryModel < ActiveRecord::Migration + def self.up + create_table :library_models do |t| + t.column :name, :string + end + end + + def self.down + drop_table :library_models + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/doc/README_FOR_APP b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/doc/README_FOR_APP new file mode 100644 index 00000000..ac6c1491 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/doc/README_FOR_APP @@ -0,0 +1,2 @@ +Use this README file to introduce your application and point to useful places in the API for learning more. +Run "rake appdoc" to generate API documentation for your models and controllers. \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/generators/commenting_generator_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/generators/commenting_generator_test.rb new file mode 100644 index 00000000..96c6a799 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/generators/commenting_generator_test.rb @@ -0,0 +1,83 @@ +require File.dirname(__FILE__) + '/../test_helper' +require 'fileutils' + +class CommentingGeneratorTest < Test::Unit::TestCase + + def test_ensure_comments_dont_exist + # make sure the comments are already defined + assert_equal false, Object.send(:const_defined?, :Comment) + assert_equal false, Object.send(:const_defined?, :Commenting) + end + + def test_ensure_files_exist_after_generator_runs + run_generator + + # make sure the files are there + for generated_file in generated_files do + assert File.exists?(File.expand_path(generated_file)) + end + end + + def test_classes_exist_with_associations + run_generator + assert_nothing_raised { Commenting } + assert_nothing_raised { Comment } + citation = Citation.find(:first) + assert !citation.nil? + assert citation.respond_to?(:comments) + user = User.find(:first) + assert !user.nil? + assert user.respond_to?(:comments) + end + + def teardown + Object.send(:remove_const, :Comment) if Object.send(:const_defined?, :Comment) + Object.send(:remove_const, :Commenting) if Object.send(:const_defined?, :Commenting) + remove_all_generated_files + remove_require_for_commenting_extensions + end + + def generated_files + generated_files = [File.join(File.dirname(__FILE__), '..', '..', 'app', 'models', 'comment.rb')] + generated_files << File.join(File.dirname(__FILE__), '..', '..', 'app', 'models', 'commenting.rb') + generated_files << File.join(File.dirname(__FILE__), '..', '..', 'test', 'unit', 'commenting_test.rb') + generated_files << File.join(File.dirname(__FILE__), '..', '..', 'test', 'unit', 'comment_test.rb') + generated_files << File.join(File.dirname(__FILE__), '..', '..', 'lib', 'commenting_extensions.rb') + generated_files << File.join(File.dirname(__FILE__), '..', '..', 'test', 'fixtures', 'comments.yml') + generated_files << File.join(File.dirname(__FILE__), '..', '..', 'test', 'fixtures', 'commentings.yml') + end + + def remove_all_generated_files + for generated_file in generated_files do + if File.exists?(generated_file) + assert FileUtils.rm(generated_file) + end + end + end + + def run_migrate + `rake db:migrate RAILS_ENV=test` + end + + def run_generator + command = File.join(File.dirname(__FILE__), '..', '..', 'script', 'generate') + `#{command} commenting Citation User` + run_migrate + end + + def remove_require_for_commenting_extensions + environment = File.join(File.dirname(__FILE__), '..', '..', 'config', 'environment.rb') + new_environment = '' + if File.exists?(environment) + if (open(environment) { |file| file.grep(/Rails/).any? }) + IO.readlines(environment).each do |line| + new_environment += line unless line.match(/commenting_extensions/i) + end + File.open(environment, "w+") do |f| + f.pos = 0 + f.print new_environment + end + end + end + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/lib/library_model.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/lib/library_model.rb new file mode 100644 index 00000000..e27106fa --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/lib/library_model.rb @@ -0,0 +1,2 @@ +class LibraryModel < ActiveRecord::Base +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/404.html b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/404.html new file mode 100644 index 00000000..eff660b9 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/404.html @@ -0,0 +1,30 @@ + + + + + + + The page you were looking for doesn't exist (404) + + + + + +
        +

        The page you were looking for doesn't exist.

        +

        You may have mistyped the address or the page may have moved.

        +
        + + \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/500.html b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/500.html new file mode 100644 index 00000000..f0aee0e9 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/500.html @@ -0,0 +1,30 @@ + + + + + + + We're sorry, but something went wrong + + + + + +
        +

        We're sorry, but something went wrong.

        +

        We've been notified about this issue and we'll take a look at it shortly.

        +
        + + \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.cgi b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.cgi new file mode 100755 index 00000000..9b5ae760 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.cgi @@ -0,0 +1,10 @@ +#!/usr/local/bin/ruby + +require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT) + +# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like: +# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired +require "dispatcher" + +ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun) +Dispatcher.dispatch \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.fcgi b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.fcgi new file mode 100755 index 00000000..664dbbbe --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.fcgi @@ -0,0 +1,24 @@ +#!/usr/bin/env ruby +# +# You may specify the path to the FastCGI crash log (a log of unhandled +# exceptions which forced the FastCGI instance to exit, great for debugging) +# and the number of requests to process before running garbage collection. +# +# By default, the FastCGI crash log is RAILS_ROOT/log/fastcgi.crash.log +# and the GC period is nil (turned off). A reasonable number of requests +# could range from 10-100 depending on the memory footprint of your app. +# +# Example: +# # Default log path, normal GC behavior. +# RailsFCGIHandler.process! +# +# # Default log path, 50 requests between GC. +# RailsFCGIHandler.process! nil, 50 +# +# # Custom log path, normal GC behavior. +# RailsFCGIHandler.process! '/var/log/myapp_fcgi_crash.log' +# +require File.dirname(__FILE__) + "/../config/environment" +require 'fcgi_handler' + +RailsFCGIHandler.process! diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.rb new file mode 100755 index 00000000..9b5ae760 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.rb @@ -0,0 +1,10 @@ +#!/usr/local/bin/ruby + +require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT) + +# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like: +# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired +require "dispatcher" + +ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun) +Dispatcher.dispatch \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/favicon.ico b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/favicon.ico new file mode 100644 index 00000000..e69de29b diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/images/rails.png b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/images/rails.png new file mode 100644 index 0000000000000000000000000000000000000000..b8441f182e06974083cf08f0acaf0e2fd612bd40 GIT binary patch literal 1787 zcmVCLdthj)A!BBmWB&y|X`RY;f`BJ<_ju%@N||NoLFD~mQl$aHGjq>;5dG_D{h(5s}0 z6&=HANU$m__3PuddU(lvR_xWj`}Oho@9EyQt-n!E*P(KhM@X_VFV2l&>deNZJT%y8iwA zoG>u1B`p2=_u9k4v1Mud`1+qvOZoHg#bITJ9U`qBAek?40RR96!AV3xRCwBy*IQ$v zN(=yC9IhRft9V64L`77pqF_Cx@c;kSNoGK)`?Ps*cP(EtGlYZ{D5cxspMQvjKH)Oh6X(pa|J{ zGy1J$Ej7=Z{uvmMfRRsE;v`p;45B~6*ep#hM^ji zl$+7qoWq~}ewG=61uFw0He{tJurMU&4Iv?=B^eR(wAHk!miA)O7p_+YR>lbmU3rmn ze?+ze(+sEd6foB&*l9+?zkr_a-5*v&p*?c}HOGtyHg6r{WFYpQ=#z0Hc7VWLx$>M3|b0|Gn z+5t#z6*ffSVc6DjpmB2?AAR@@vB!wCK?9Yl;33;Q7^%(401QW|k=R8b!OwtLJPjjm zO9Ia;qCq)rOq!1Ia*6#A%#xb}yDx1P*pWla>9j$bnMn3CBqe4`TRll_Iy29kmG?4fbKuF=XqU|?3b@B zA`&a?KIgZ|KJx5eND_c3Em=WZn@xW8hRJ^G&sY^b(FW?WC9W_sb;+lAPdLTdBaKIK;-f}*h4|1aTjw7qX_k~e{TWO7jqcekERN;Jyh%67)q4rKpL*CEYL;|#GY{B@5 zi52XoC?xsoorJKxsliugF#z38MJqrYCWV(t<=G&f;^Me13&AiI9{3jUZ$ zFM`*L(9qc^VMxkz1oaDH!1pcD^IXp>Z0Jb=_qs?Vsrs{mp<^{$N!EC9o+`CO-(o}E zJ`y{*;9s|wr22-QoJ87y^~;)Q@b%P4UgSSsx>2$o@Vd{%Pk0@4qZ^fhB(vt$c1TG> z*{Ad;foraENbld`=MCNm4?9kvlgK~&J>ialpJ7nua zx0oRzwG5;}Qne)Fg(N3kf?JVmB;}y&5(0+~r*aL$0Zof8fe!AtHWH>A^1Y)@G@GsA zup`R{Qg?{+MaxTq#2n{6w|)c&yaJ7{U4ngAH5v6I)*;@rEBE*ehIPBwKBQU)YKE8F0lR!Sm?sE4Xk-sj&E$|A-9n dP56HS1^^A-61FoN)nxzx002ovPDHLkV1kw_Sd9Px literal 0 HcmV?d00001 diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/index.html b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/index.html new file mode 100644 index 00000000..a2daab72 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/index.html @@ -0,0 +1,277 @@ + + + + + Ruby on Rails: Welcome aboard + + + + + + +
        + + +
        + + + + +
        +

        Getting started

        +

        Here’s how to get rolling:

        + +
          +
        1. +

          Create your databases and edit config/database.yml

          +

          Rails needs to know your login and password.

          +
        2. + +
        3. +

          Use script/generate to create your models and controllers

          +

          To see all available options, run it without parameters.

          +
        4. + +
        5. +

          Set up a default route and remove or rename this file

          +

          Routes are setup in config/routes.rb.

          +
        6. +
        +
        +
        + + +
        + + \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/application.js b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/application.js new file mode 100644 index 00000000..fe457769 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/application.js @@ -0,0 +1,2 @@ +// Place your application-specific JavaScript functions and classes here +// This file is automatically included by javascript_include_tag :defaults diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/controls.js b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/controls.js new file mode 100644 index 00000000..8c273f87 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/controls.js @@ -0,0 +1,833 @@ +// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005, 2006 Ivan Krstic (http://blogs.law.harvard.edu/ivan) +// (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com) +// Contributors: +// Richard Livsey +// Rahul Bhargava +// Rob Wills +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +// Autocompleter.Base handles all the autocompletion functionality +// that's independent of the data source for autocompletion. This +// includes drawing the autocompletion menu, observing keyboard +// and mouse events, and similar. +// +// Specific autocompleters need to provide, at the very least, +// a getUpdatedChoices function that will be invoked every time +// the text inside the monitored textbox changes. This method +// should get the text for which to provide autocompletion by +// invoking this.getToken(), NOT by directly accessing +// this.element.value. This is to allow incremental tokenized +// autocompletion. Specific auto-completion logic (AJAX, etc) +// belongs in getUpdatedChoices. +// +// Tokenized incremental autocompletion is enabled automatically +// when an autocompleter is instantiated with the 'tokens' option +// in the options parameter, e.g.: +// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); +// will incrementally autocomplete with a comma as the token. +// Additionally, ',' in the above example can be replaced with +// a token array, e.g. { tokens: [',', '\n'] } which +// enables autocompletion on multiple tokens. This is most +// useful when one of the tokens is \n (a newline), as it +// allows smart autocompletion after linebreaks. + +if(typeof Effect == 'undefined') + throw("controls.js requires including script.aculo.us' effects.js library"); + +var Autocompleter = {} +Autocompleter.Base = function() {}; +Autocompleter.Base.prototype = { + baseInitialize: function(element, update, options) { + this.element = $(element); + this.update = $(update); + this.hasFocus = false; + this.changed = false; + this.active = false; + this.index = 0; + this.entryCount = 0; + + if(this.setOptions) + this.setOptions(options); + else + this.options = options || {}; + + this.options.paramName = this.options.paramName || this.element.name; + this.options.tokens = this.options.tokens || []; + this.options.frequency = this.options.frequency || 0.4; + this.options.minChars = this.options.minChars || 1; + this.options.onShow = this.options.onShow || + function(element, update){ + if(!update.style.position || update.style.position=='absolute') { + update.style.position = 'absolute'; + Position.clone(element, update, { + setHeight: false, + offsetTop: element.offsetHeight + }); + } + Effect.Appear(update,{duration:0.15}); + }; + this.options.onHide = this.options.onHide || + function(element, update){ new Effect.Fade(update,{duration:0.15}) }; + + if(typeof(this.options.tokens) == 'string') + this.options.tokens = new Array(this.options.tokens); + + this.observer = null; + + this.element.setAttribute('autocomplete','off'); + + Element.hide(this.update); + + Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this)); + Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this)); + }, + + show: function() { + if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); + if(!this.iefix && + (navigator.appVersion.indexOf('MSIE')>0) && + (navigator.userAgent.indexOf('Opera')<0) && + (Element.getStyle(this.update, 'position')=='absolute')) { + new Insertion.After(this.update, + ''); + this.iefix = $(this.update.id+'_iefix'); + } + if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); + }, + + fixIEOverlapping: function() { + Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)}); + this.iefix.style.zIndex = 1; + this.update.style.zIndex = 2; + Element.show(this.iefix); + }, + + hide: function() { + this.stopIndicator(); + if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); + if(this.iefix) Element.hide(this.iefix); + }, + + startIndicator: function() { + if(this.options.indicator) Element.show(this.options.indicator); + }, + + stopIndicator: function() { + if(this.options.indicator) Element.hide(this.options.indicator); + }, + + onKeyPress: function(event) { + if(this.active) + switch(event.keyCode) { + case Event.KEY_TAB: + case Event.KEY_RETURN: + this.selectEntry(); + Event.stop(event); + case Event.KEY_ESC: + this.hide(); + this.active = false; + Event.stop(event); + return; + case Event.KEY_LEFT: + case Event.KEY_RIGHT: + return; + case Event.KEY_UP: + this.markPrevious(); + this.render(); + if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event); + return; + case Event.KEY_DOWN: + this.markNext(); + this.render(); + if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event); + return; + } + else + if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || + (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return; + + this.changed = true; + this.hasFocus = true; + + if(this.observer) clearTimeout(this.observer); + this.observer = + setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); + }, + + activate: function() { + this.changed = false; + this.hasFocus = true; + this.getUpdatedChoices(); + }, + + onHover: function(event) { + var element = Event.findElement(event, 'LI'); + if(this.index != element.autocompleteIndex) + { + this.index = element.autocompleteIndex; + this.render(); + } + Event.stop(event); + }, + + onClick: function(event) { + var element = Event.findElement(event, 'LI'); + this.index = element.autocompleteIndex; + this.selectEntry(); + this.hide(); + }, + + onBlur: function(event) { + // needed to make click events working + setTimeout(this.hide.bind(this), 250); + this.hasFocus = false; + this.active = false; + }, + + render: function() { + if(this.entryCount > 0) { + for (var i = 0; i < this.entryCount; i++) + this.index==i ? + Element.addClassName(this.getEntry(i),"selected") : + Element.removeClassName(this.getEntry(i),"selected"); + + if(this.hasFocus) { + this.show(); + this.active = true; + } + } else { + this.active = false; + this.hide(); + } + }, + + markPrevious: function() { + if(this.index > 0) this.index-- + else this.index = this.entryCount-1; + this.getEntry(this.index).scrollIntoView(true); + }, + + markNext: function() { + if(this.index < this.entryCount-1) this.index++ + else this.index = 0; + this.getEntry(this.index).scrollIntoView(false); + }, + + getEntry: function(index) { + return this.update.firstChild.childNodes[index]; + }, + + getCurrentEntry: function() { + return this.getEntry(this.index); + }, + + selectEntry: function() { + this.active = false; + this.updateElement(this.getCurrentEntry()); + }, + + updateElement: function(selectedElement) { + if (this.options.updateElement) { + this.options.updateElement(selectedElement); + return; + } + var value = ''; + if (this.options.select) { + var nodes = document.getElementsByClassName(this.options.select, selectedElement) || []; + if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); + } else + value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); + + var lastTokenPos = this.findLastToken(); + if (lastTokenPos != -1) { + var newValue = this.element.value.substr(0, lastTokenPos + 1); + var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/); + if (whitespace) + newValue += whitespace[0]; + this.element.value = newValue + value; + } else { + this.element.value = value; + } + this.element.focus(); + + if (this.options.afterUpdateElement) + this.options.afterUpdateElement(this.element, selectedElement); + }, + + updateChoices: function(choices) { + if(!this.changed && this.hasFocus) { + this.update.innerHTML = choices; + Element.cleanWhitespace(this.update); + Element.cleanWhitespace(this.update.down()); + + if(this.update.firstChild && this.update.down().childNodes) { + this.entryCount = + this.update.down().childNodes.length; + for (var i = 0; i < this.entryCount; i++) { + var entry = this.getEntry(i); + entry.autocompleteIndex = i; + this.addObservers(entry); + } + } else { + this.entryCount = 0; + } + + this.stopIndicator(); + this.index = 0; + + if(this.entryCount==1 && this.options.autoSelect) { + this.selectEntry(); + this.hide(); + } else { + this.render(); + } + } + }, + + addObservers: function(element) { + Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); + Event.observe(element, "click", this.onClick.bindAsEventListener(this)); + }, + + onObserverEvent: function() { + this.changed = false; + if(this.getToken().length>=this.options.minChars) { + this.startIndicator(); + this.getUpdatedChoices(); + } else { + this.active = false; + this.hide(); + } + }, + + getToken: function() { + var tokenPos = this.findLastToken(); + if (tokenPos != -1) + var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,''); + else + var ret = this.element.value; + + return /\n/.test(ret) ? '' : ret; + }, + + findLastToken: function() { + var lastTokenPos = -1; + + for (var i=0; i lastTokenPos) + lastTokenPos = thisTokenPos; + } + return lastTokenPos; + } +} + +Ajax.Autocompleter = Class.create(); +Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), { + initialize: function(element, update, url, options) { + this.baseInitialize(element, update, options); + this.options.asynchronous = true; + this.options.onComplete = this.onComplete.bind(this); + this.options.defaultParams = this.options.parameters || null; + this.url = url; + }, + + getUpdatedChoices: function() { + entry = encodeURIComponent(this.options.paramName) + '=' + + encodeURIComponent(this.getToken()); + + this.options.parameters = this.options.callback ? + this.options.callback(this.element, entry) : entry; + + if(this.options.defaultParams) + this.options.parameters += '&' + this.options.defaultParams; + + new Ajax.Request(this.url, this.options); + }, + + onComplete: function(request) { + this.updateChoices(request.responseText); + } + +}); + +// The local array autocompleter. Used when you'd prefer to +// inject an array of autocompletion options into the page, rather +// than sending out Ajax queries, which can be quite slow sometimes. +// +// The constructor takes four parameters. The first two are, as usual, +// the id of the monitored textbox, and id of the autocompletion menu. +// The third is the array you want to autocomplete from, and the fourth +// is the options block. +// +// Extra local autocompletion options: +// - choices - How many autocompletion choices to offer +// +// - partialSearch - If false, the autocompleter will match entered +// text only at the beginning of strings in the +// autocomplete array. Defaults to true, which will +// match text at the beginning of any *word* in the +// strings in the autocomplete array. If you want to +// search anywhere in the string, additionally set +// the option fullSearch to true (default: off). +// +// - fullSsearch - Search anywhere in autocomplete array strings. +// +// - partialChars - How many characters to enter before triggering +// a partial match (unlike minChars, which defines +// how many characters are required to do any match +// at all). Defaults to 2. +// +// - ignoreCase - Whether to ignore case when autocompleting. +// Defaults to true. +// +// It's possible to pass in a custom function as the 'selector' +// option, if you prefer to write your own autocompletion logic. +// In that case, the other options above will not apply unless +// you support them. + +Autocompleter.Local = Class.create(); +Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), { + initialize: function(element, update, array, options) { + this.baseInitialize(element, update, options); + this.options.array = array; + }, + + getUpdatedChoices: function() { + this.updateChoices(this.options.selector(this)); + }, + + setOptions: function(options) { + this.options = Object.extend({ + choices: 10, + partialSearch: true, + partialChars: 2, + ignoreCase: true, + fullSearch: false, + selector: function(instance) { + var ret = []; // Beginning matches + var partial = []; // Inside matches + var entry = instance.getToken(); + var count = 0; + + for (var i = 0; i < instance.options.array.length && + ret.length < instance.options.choices ; i++) { + + var elem = instance.options.array[i]; + var foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase()) : + elem.indexOf(entry); + + while (foundPos != -1) { + if (foundPos == 0 && elem.length != entry.length) { + ret.push("
      • " + elem.substr(0, entry.length) + "" + + elem.substr(entry.length) + "
      • "); + break; + } else if (entry.length >= instance.options.partialChars && + instance.options.partialSearch && foundPos != -1) { + if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { + partial.push("
      • " + elem.substr(0, foundPos) + "" + + elem.substr(foundPos, entry.length) + "" + elem.substr( + foundPos + entry.length) + "
      • "); + break; + } + } + + foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : + elem.indexOf(entry, foundPos + 1); + + } + } + if (partial.length) + ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)) + return "
          " + ret.join('') + "
        "; + } + }, options || {}); + } +}); + +// AJAX in-place editor +// +// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor + +// Use this if you notice weird scrolling problems on some browsers, +// the DOM might be a bit confused when this gets called so do this +// waits 1 ms (with setTimeout) until it does the activation +Field.scrollFreeActivate = function(field) { + setTimeout(function() { + Field.activate(field); + }, 1); +} + +Ajax.InPlaceEditor = Class.create(); +Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99"; +Ajax.InPlaceEditor.prototype = { + initialize: function(element, url, options) { + this.url = url; + this.element = $(element); + + this.options = Object.extend({ + paramName: "value", + okButton: true, + okText: "ok", + cancelLink: true, + cancelText: "cancel", + savingText: "Saving...", + clickToEditText: "Click to edit", + okText: "ok", + rows: 1, + onComplete: function(transport, element) { + new Effect.Highlight(element, {startcolor: this.options.highlightcolor}); + }, + onFailure: function(transport) { + alert("Error communicating with the server: " + transport.responseText.stripTags()); + }, + callback: function(form) { + return Form.serialize(form); + }, + handleLineBreaks: true, + loadingText: 'Loading...', + savingClassName: 'inplaceeditor-saving', + loadingClassName: 'inplaceeditor-loading', + formClassName: 'inplaceeditor-form', + highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor, + highlightendcolor: "#FFFFFF", + externalControl: null, + submitOnBlur: false, + ajaxOptions: {}, + evalScripts: false + }, options || {}); + + if(!this.options.formId && this.element.id) { + this.options.formId = this.element.id + "-inplaceeditor"; + if ($(this.options.formId)) { + // there's already a form with that name, don't specify an id + this.options.formId = null; + } + } + + if (this.options.externalControl) { + this.options.externalControl = $(this.options.externalControl); + } + + this.originalBackground = Element.getStyle(this.element, 'background-color'); + if (!this.originalBackground) { + this.originalBackground = "transparent"; + } + + this.element.title = this.options.clickToEditText; + + this.onclickListener = this.enterEditMode.bindAsEventListener(this); + this.mouseoverListener = this.enterHover.bindAsEventListener(this); + this.mouseoutListener = this.leaveHover.bindAsEventListener(this); + Event.observe(this.element, 'click', this.onclickListener); + Event.observe(this.element, 'mouseover', this.mouseoverListener); + Event.observe(this.element, 'mouseout', this.mouseoutListener); + if (this.options.externalControl) { + Event.observe(this.options.externalControl, 'click', this.onclickListener); + Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener); + Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener); + } + }, + enterEditMode: function(evt) { + if (this.saving) return; + if (this.editing) return; + this.editing = true; + this.onEnterEditMode(); + if (this.options.externalControl) { + Element.hide(this.options.externalControl); + } + Element.hide(this.element); + this.createForm(); + this.element.parentNode.insertBefore(this.form, this.element); + if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField); + // stop the event to avoid a page refresh in Safari + if (evt) { + Event.stop(evt); + } + return false; + }, + createForm: function() { + this.form = document.createElement("form"); + this.form.id = this.options.formId; + Element.addClassName(this.form, this.options.formClassName) + this.form.onsubmit = this.onSubmit.bind(this); + + this.createEditField(); + + if (this.options.textarea) { + var br = document.createElement("br"); + this.form.appendChild(br); + } + + if (this.options.okButton) { + okButton = document.createElement("input"); + okButton.type = "submit"; + okButton.value = this.options.okText; + okButton.className = 'editor_ok_button'; + this.form.appendChild(okButton); + } + + if (this.options.cancelLink) { + cancelLink = document.createElement("a"); + cancelLink.href = "#"; + cancelLink.appendChild(document.createTextNode(this.options.cancelText)); + cancelLink.onclick = this.onclickCancel.bind(this); + cancelLink.className = 'editor_cancel'; + this.form.appendChild(cancelLink); + } + }, + hasHTMLLineBreaks: function(string) { + if (!this.options.handleLineBreaks) return false; + return string.match(/
        /i); + }, + convertHTMLLineBreaks: function(string) { + return string.replace(/
        /gi, "\n").replace(//gi, "\n").replace(/<\/p>/gi, "\n").replace(/

        /gi, ""); + }, + createEditField: function() { + var text; + if(this.options.loadTextURL) { + text = this.options.loadingText; + } else { + text = this.getText(); + } + + var obj = this; + + if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) { + this.options.textarea = false; + var textField = document.createElement("input"); + textField.obj = this; + textField.type = "text"; + textField.name = this.options.paramName; + textField.value = text; + textField.style.backgroundColor = this.options.highlightcolor; + textField.className = 'editor_field'; + var size = this.options.size || this.options.cols || 0; + if (size != 0) textField.size = size; + if (this.options.submitOnBlur) + textField.onblur = this.onSubmit.bind(this); + this.editField = textField; + } else { + this.options.textarea = true; + var textArea = document.createElement("textarea"); + textArea.obj = this; + textArea.name = this.options.paramName; + textArea.value = this.convertHTMLLineBreaks(text); + textArea.rows = this.options.rows; + textArea.cols = this.options.cols || 40; + textArea.className = 'editor_field'; + if (this.options.submitOnBlur) + textArea.onblur = this.onSubmit.bind(this); + this.editField = textArea; + } + + if(this.options.loadTextURL) { + this.loadExternalText(); + } + this.form.appendChild(this.editField); + }, + getText: function() { + return this.element.innerHTML; + }, + loadExternalText: function() { + Element.addClassName(this.form, this.options.loadingClassName); + this.editField.disabled = true; + new Ajax.Request( + this.options.loadTextURL, + Object.extend({ + asynchronous: true, + onComplete: this.onLoadedExternalText.bind(this) + }, this.options.ajaxOptions) + ); + }, + onLoadedExternalText: function(transport) { + Element.removeClassName(this.form, this.options.loadingClassName); + this.editField.disabled = false; + this.editField.value = transport.responseText.stripTags(); + Field.scrollFreeActivate(this.editField); + }, + onclickCancel: function() { + this.onComplete(); + this.leaveEditMode(); + return false; + }, + onFailure: function(transport) { + this.options.onFailure(transport); + if (this.oldInnerHTML) { + this.element.innerHTML = this.oldInnerHTML; + this.oldInnerHTML = null; + } + return false; + }, + onSubmit: function() { + // onLoading resets these so we need to save them away for the Ajax call + var form = this.form; + var value = this.editField.value; + + // do this first, sometimes the ajax call returns before we get a chance to switch on Saving... + // which means this will actually switch on Saving... *after* we've left edit mode causing Saving... + // to be displayed indefinitely + this.onLoading(); + + if (this.options.evalScripts) { + new Ajax.Request( + this.url, Object.extend({ + parameters: this.options.callback(form, value), + onComplete: this.onComplete.bind(this), + onFailure: this.onFailure.bind(this), + asynchronous:true, + evalScripts:true + }, this.options.ajaxOptions)); + } else { + new Ajax.Updater( + { success: this.element, + // don't update on failure (this could be an option) + failure: null }, + this.url, Object.extend({ + parameters: this.options.callback(form, value), + onComplete: this.onComplete.bind(this), + onFailure: this.onFailure.bind(this) + }, this.options.ajaxOptions)); + } + // stop the event to avoid a page refresh in Safari + if (arguments.length > 1) { + Event.stop(arguments[0]); + } + return false; + }, + onLoading: function() { + this.saving = true; + this.removeForm(); + this.leaveHover(); + this.showSaving(); + }, + showSaving: function() { + this.oldInnerHTML = this.element.innerHTML; + this.element.innerHTML = this.options.savingText; + Element.addClassName(this.element, this.options.savingClassName); + this.element.style.backgroundColor = this.originalBackground; + Element.show(this.element); + }, + removeForm: function() { + if(this.form) { + if (this.form.parentNode) Element.remove(this.form); + this.form = null; + } + }, + enterHover: function() { + if (this.saving) return; + this.element.style.backgroundColor = this.options.highlightcolor; + if (this.effect) { + this.effect.cancel(); + } + Element.addClassName(this.element, this.options.hoverClassName) + }, + leaveHover: function() { + if (this.options.backgroundColor) { + this.element.style.backgroundColor = this.oldBackground; + } + Element.removeClassName(this.element, this.options.hoverClassName) + if (this.saving) return; + this.effect = new Effect.Highlight(this.element, { + startcolor: this.options.highlightcolor, + endcolor: this.options.highlightendcolor, + restorecolor: this.originalBackground + }); + }, + leaveEditMode: function() { + Element.removeClassName(this.element, this.options.savingClassName); + this.removeForm(); + this.leaveHover(); + this.element.style.backgroundColor = this.originalBackground; + Element.show(this.element); + if (this.options.externalControl) { + Element.show(this.options.externalControl); + } + this.editing = false; + this.saving = false; + this.oldInnerHTML = null; + this.onLeaveEditMode(); + }, + onComplete: function(transport) { + this.leaveEditMode(); + this.options.onComplete.bind(this)(transport, this.element); + }, + onEnterEditMode: function() {}, + onLeaveEditMode: function() {}, + dispose: function() { + if (this.oldInnerHTML) { + this.element.innerHTML = this.oldInnerHTML; + } + this.leaveEditMode(); + Event.stopObserving(this.element, 'click', this.onclickListener); + Event.stopObserving(this.element, 'mouseover', this.mouseoverListener); + Event.stopObserving(this.element, 'mouseout', this.mouseoutListener); + if (this.options.externalControl) { + Event.stopObserving(this.options.externalControl, 'click', this.onclickListener); + Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener); + Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener); + } + } +}; + +Ajax.InPlaceCollectionEditor = Class.create(); +Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype); +Object.extend(Ajax.InPlaceCollectionEditor.prototype, { + createEditField: function() { + if (!this.cached_selectTag) { + var selectTag = document.createElement("select"); + var collection = this.options.collection || []; + var optionTag; + collection.each(function(e,i) { + optionTag = document.createElement("option"); + optionTag.value = (e instanceof Array) ? e[0] : e; + if((typeof this.options.value == 'undefined') && + ((e instanceof Array) ? this.element.innerHTML == e[1] : e == optionTag.value)) optionTag.selected = true; + if(this.options.value==optionTag.value) optionTag.selected = true; + optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e)); + selectTag.appendChild(optionTag); + }.bind(this)); + this.cached_selectTag = selectTag; + } + + this.editField = this.cached_selectTag; + if(this.options.loadTextURL) this.loadExternalText(); + this.form.appendChild(this.editField); + this.options.callback = function(form, value) { + return "value=" + encodeURIComponent(value); + } + } +}); + +// Delayed observer, like Form.Element.Observer, +// but waits for delay after last key input +// Ideal for live-search fields + +Form.Element.DelayedObserver = Class.create(); +Form.Element.DelayedObserver.prototype = { + initialize: function(element, delay, callback) { + this.delay = delay || 0.5; + this.element = $(element); + this.callback = callback; + this.timer = null; + this.lastValue = $F(this.element); + Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this)); + }, + delayedListener: function(event) { + if(this.lastValue == $F(this.element)) return; + if(this.timer) clearTimeout(this.timer); + this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000); + this.lastValue = $F(this.element); + }, + onTimerEvent: function() { + this.timer = null; + this.callback(this.element, $F(this.element)); + } +}; diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/dragdrop.js b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/dragdrop.js new file mode 100644 index 00000000..c71ddb82 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/dragdrop.js @@ -0,0 +1,942 @@ +// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005, 2006 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +if(typeof Effect == 'undefined') + throw("dragdrop.js requires including script.aculo.us' effects.js library"); + +var Droppables = { + drops: [], + + remove: function(element) { + this.drops = this.drops.reject(function(d) { return d.element==$(element) }); + }, + + add: function(element) { + element = $(element); + var options = Object.extend({ + greedy: true, + hoverclass: null, + tree: false + }, arguments[1] || {}); + + // cache containers + if(options.containment) { + options._containers = []; + var containment = options.containment; + if((typeof containment == 'object') && + (containment.constructor == Array)) { + containment.each( function(c) { options._containers.push($(c)) }); + } else { + options._containers.push($(containment)); + } + } + + if(options.accept) options.accept = [options.accept].flatten(); + + Element.makePositioned(element); // fix IE + options.element = element; + + this.drops.push(options); + }, + + findDeepestChild: function(drops) { + deepest = drops[0]; + + for (i = 1; i < drops.length; ++i) + if (Element.isParent(drops[i].element, deepest.element)) + deepest = drops[i]; + + return deepest; + }, + + isContained: function(element, drop) { + var containmentNode; + if(drop.tree) { + containmentNode = element.treeNode; + } else { + containmentNode = element.parentNode; + } + return drop._containers.detect(function(c) { return containmentNode == c }); + }, + + isAffected: function(point, element, drop) { + return ( + (drop.element!=element) && + ((!drop._containers) || + this.isContained(element, drop)) && + ((!drop.accept) || + (Element.classNames(element).detect( + function(v) { return drop.accept.include(v) } ) )) && + Position.within(drop.element, point[0], point[1]) ); + }, + + deactivate: function(drop) { + if(drop.hoverclass) + Element.removeClassName(drop.element, drop.hoverclass); + this.last_active = null; + }, + + activate: function(drop) { + if(drop.hoverclass) + Element.addClassName(drop.element, drop.hoverclass); + this.last_active = drop; + }, + + show: function(point, element) { + if(!this.drops.length) return; + var affected = []; + + if(this.last_active) this.deactivate(this.last_active); + this.drops.each( function(drop) { + if(Droppables.isAffected(point, element, drop)) + affected.push(drop); + }); + + if(affected.length>0) { + drop = Droppables.findDeepestChild(affected); + Position.within(drop.element, point[0], point[1]); + if(drop.onHover) + drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); + + Droppables.activate(drop); + } + }, + + fire: function(event, element) { + if(!this.last_active) return; + Position.prepare(); + + if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active)) + if (this.last_active.onDrop) + this.last_active.onDrop(element, this.last_active.element, event); + }, + + reset: function() { + if(this.last_active) + this.deactivate(this.last_active); + } +} + +var Draggables = { + drags: [], + observers: [], + + register: function(draggable) { + if(this.drags.length == 0) { + this.eventMouseUp = this.endDrag.bindAsEventListener(this); + this.eventMouseMove = this.updateDrag.bindAsEventListener(this); + this.eventKeypress = this.keyPress.bindAsEventListener(this); + + Event.observe(document, "mouseup", this.eventMouseUp); + Event.observe(document, "mousemove", this.eventMouseMove); + Event.observe(document, "keypress", this.eventKeypress); + } + this.drags.push(draggable); + }, + + unregister: function(draggable) { + this.drags = this.drags.reject(function(d) { return d==draggable }); + if(this.drags.length == 0) { + Event.stopObserving(document, "mouseup", this.eventMouseUp); + Event.stopObserving(document, "mousemove", this.eventMouseMove); + Event.stopObserving(document, "keypress", this.eventKeypress); + } + }, + + activate: function(draggable) { + if(draggable.options.delay) { + this._timeout = setTimeout(function() { + Draggables._timeout = null; + window.focus(); + Draggables.activeDraggable = draggable; + }.bind(this), draggable.options.delay); + } else { + window.focus(); // allows keypress events if window isn't currently focused, fails for Safari + this.activeDraggable = draggable; + } + }, + + deactivate: function() { + this.activeDraggable = null; + }, + + updateDrag: function(event) { + if(!this.activeDraggable) return; + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + // Mozilla-based browsers fire successive mousemove events with + // the same coordinates, prevent needless redrawing (moz bug?) + if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; + this._lastPointer = pointer; + + this.activeDraggable.updateDrag(event, pointer); + }, + + endDrag: function(event) { + if(this._timeout) { + clearTimeout(this._timeout); + this._timeout = null; + } + if(!this.activeDraggable) return; + this._lastPointer = null; + this.activeDraggable.endDrag(event); + this.activeDraggable = null; + }, + + keyPress: function(event) { + if(this.activeDraggable) + this.activeDraggable.keyPress(event); + }, + + addObserver: function(observer) { + this.observers.push(observer); + this._cacheObserverCallbacks(); + }, + + removeObserver: function(element) { // element instead of observer fixes mem leaks + this.observers = this.observers.reject( function(o) { return o.element==element }); + this._cacheObserverCallbacks(); + }, + + notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' + if(this[eventName+'Count'] > 0) + this.observers.each( function(o) { + if(o[eventName]) o[eventName](eventName, draggable, event); + }); + if(draggable.options[eventName]) draggable.options[eventName](draggable, event); + }, + + _cacheObserverCallbacks: function() { + ['onStart','onEnd','onDrag'].each( function(eventName) { + Draggables[eventName+'Count'] = Draggables.observers.select( + function(o) { return o[eventName]; } + ).length; + }); + } +} + +/*--------------------------------------------------------------------------*/ + +var Draggable = Class.create(); +Draggable._dragging = {}; + +Draggable.prototype = { + initialize: function(element) { + var defaults = { + handle: false, + reverteffect: function(element, top_offset, left_offset) { + var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; + new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur, + queue: {scope:'_draggable', position:'end'} + }); + }, + endeffect: function(element) { + var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0; + new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, + queue: {scope:'_draggable', position:'end'}, + afterFinish: function(){ + Draggable._dragging[element] = false + } + }); + }, + zindex: 1000, + revert: false, + scroll: false, + scrollSensitivity: 20, + scrollSpeed: 15, + snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] } + delay: 0 + }; + + if(!arguments[1] || typeof arguments[1].endeffect == 'undefined') + Object.extend(defaults, { + starteffect: function(element) { + element._opacity = Element.getOpacity(element); + Draggable._dragging[element] = true; + new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); + } + }); + + var options = Object.extend(defaults, arguments[1] || {}); + + this.element = $(element); + + if(options.handle && (typeof options.handle == 'string')) + this.handle = this.element.down('.'+options.handle, 0); + + if(!this.handle) this.handle = $(options.handle); + if(!this.handle) this.handle = this.element; + + if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) { + options.scroll = $(options.scroll); + this._isScrollChild = Element.childOf(this.element, options.scroll); + } + + Element.makePositioned(this.element); // fix IE + + this.delta = this.currentDelta(); + this.options = options; + this.dragging = false; + + this.eventMouseDown = this.initDrag.bindAsEventListener(this); + Event.observe(this.handle, "mousedown", this.eventMouseDown); + + Draggables.register(this); + }, + + destroy: function() { + Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); + Draggables.unregister(this); + }, + + currentDelta: function() { + return([ + parseInt(Element.getStyle(this.element,'left') || '0'), + parseInt(Element.getStyle(this.element,'top') || '0')]); + }, + + initDrag: function(event) { + if(typeof Draggable._dragging[this.element] != 'undefined' && + Draggable._dragging[this.element]) return; + if(Event.isLeftClick(event)) { + // abort on form elements, fixes a Firefox issue + var src = Event.element(event); + if(src.tagName && ( + src.tagName=='INPUT' || + src.tagName=='SELECT' || + src.tagName=='OPTION' || + src.tagName=='BUTTON' || + src.tagName=='TEXTAREA')) return; + + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + var pos = Position.cumulativeOffset(this.element); + this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); + + Draggables.activate(this); + Event.stop(event); + } + }, + + startDrag: function(event) { + this.dragging = true; + + if(this.options.zindex) { + this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); + this.element.style.zIndex = this.options.zindex; + } + + if(this.options.ghosting) { + this._clone = this.element.cloneNode(true); + Position.absolutize(this.element); + this.element.parentNode.insertBefore(this._clone, this.element); + } + + if(this.options.scroll) { + if (this.options.scroll == window) { + var where = this._getWindowScroll(this.options.scroll); + this.originalScrollLeft = where.left; + this.originalScrollTop = where.top; + } else { + this.originalScrollLeft = this.options.scroll.scrollLeft; + this.originalScrollTop = this.options.scroll.scrollTop; + } + } + + Draggables.notify('onStart', this, event); + + if(this.options.starteffect) this.options.starteffect(this.element); + }, + + updateDrag: function(event, pointer) { + if(!this.dragging) this.startDrag(event); + Position.prepare(); + Droppables.show(pointer, this.element); + Draggables.notify('onDrag', this, event); + + this.draw(pointer); + if(this.options.change) this.options.change(this); + + if(this.options.scroll) { + this.stopScrolling(); + + var p; + if (this.options.scroll == window) { + with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; } + } else { + p = Position.page(this.options.scroll); + p[0] += this.options.scroll.scrollLeft + Position.deltaX; + p[1] += this.options.scroll.scrollTop + Position.deltaY; + p.push(p[0]+this.options.scroll.offsetWidth); + p.push(p[1]+this.options.scroll.offsetHeight); + } + var speed = [0,0]; + if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity); + if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity); + if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity); + if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity); + this.startScrolling(speed); + } + + // fix AppleWebKit rendering + if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); + + Event.stop(event); + }, + + finishDrag: function(event, success) { + this.dragging = false; + + if(this.options.ghosting) { + Position.relativize(this.element); + Element.remove(this._clone); + this._clone = null; + } + + if(success) Droppables.fire(event, this.element); + Draggables.notify('onEnd', this, event); + + var revert = this.options.revert; + if(revert && typeof revert == 'function') revert = revert(this.element); + + var d = this.currentDelta(); + if(revert && this.options.reverteffect) { + this.options.reverteffect(this.element, + d[1]-this.delta[1], d[0]-this.delta[0]); + } else { + this.delta = d; + } + + if(this.options.zindex) + this.element.style.zIndex = this.originalZ; + + if(this.options.endeffect) + this.options.endeffect(this.element); + + Draggables.deactivate(this); + Droppables.reset(); + }, + + keyPress: function(event) { + if(event.keyCode!=Event.KEY_ESC) return; + this.finishDrag(event, false); + Event.stop(event); + }, + + endDrag: function(event) { + if(!this.dragging) return; + this.stopScrolling(); + this.finishDrag(event, true); + Event.stop(event); + }, + + draw: function(point) { + var pos = Position.cumulativeOffset(this.element); + if(this.options.ghosting) { + var r = Position.realOffset(this.element); + pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY; + } + + var d = this.currentDelta(); + pos[0] -= d[0]; pos[1] -= d[1]; + + if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) { + pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft; + pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop; + } + + var p = [0,1].map(function(i){ + return (point[i]-pos[i]-this.offset[i]) + }.bind(this)); + + if(this.options.snap) { + if(typeof this.options.snap == 'function') { + p = this.options.snap(p[0],p[1],this); + } else { + if(this.options.snap instanceof Array) { + p = p.map( function(v, i) { + return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this)) + } else { + p = p.map( function(v) { + return Math.round(v/this.options.snap)*this.options.snap }.bind(this)) + } + }} + + var style = this.element.style; + if((!this.options.constraint) || (this.options.constraint=='horizontal')) + style.left = p[0] + "px"; + if((!this.options.constraint) || (this.options.constraint=='vertical')) + style.top = p[1] + "px"; + + if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering + }, + + stopScrolling: function() { + if(this.scrollInterval) { + clearInterval(this.scrollInterval); + this.scrollInterval = null; + Draggables._lastScrollPointer = null; + } + }, + + startScrolling: function(speed) { + if(!(speed[0] || speed[1])) return; + this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed]; + this.lastScrolled = new Date(); + this.scrollInterval = setInterval(this.scroll.bind(this), 10); + }, + + scroll: function() { + var current = new Date(); + var delta = current - this.lastScrolled; + this.lastScrolled = current; + if(this.options.scroll == window) { + with (this._getWindowScroll(this.options.scroll)) { + if (this.scrollSpeed[0] || this.scrollSpeed[1]) { + var d = delta / 1000; + this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] ); + } + } + } else { + this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000; + this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000; + } + + Position.prepare(); + Droppables.show(Draggables._lastPointer, this.element); + Draggables.notify('onDrag', this); + if (this._isScrollChild) { + Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); + Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; + Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; + if (Draggables._lastScrollPointer[0] < 0) + Draggables._lastScrollPointer[0] = 0; + if (Draggables._lastScrollPointer[1] < 0) + Draggables._lastScrollPointer[1] = 0; + this.draw(Draggables._lastScrollPointer); + } + + if(this.options.change) this.options.change(this); + }, + + _getWindowScroll: function(w) { + var T, L, W, H; + with (w.document) { + if (w.document.documentElement && documentElement.scrollTop) { + T = documentElement.scrollTop; + L = documentElement.scrollLeft; + } else if (w.document.body) { + T = body.scrollTop; + L = body.scrollLeft; + } + if (w.innerWidth) { + W = w.innerWidth; + H = w.innerHeight; + } else if (w.document.documentElement && documentElement.clientWidth) { + W = documentElement.clientWidth; + H = documentElement.clientHeight; + } else { + W = body.offsetWidth; + H = body.offsetHeight + } + } + return { top: T, left: L, width: W, height: H }; + } +} + +/*--------------------------------------------------------------------------*/ + +var SortableObserver = Class.create(); +SortableObserver.prototype = { + initialize: function(element, observer) { + this.element = $(element); + this.observer = observer; + this.lastValue = Sortable.serialize(this.element); + }, + + onStart: function() { + this.lastValue = Sortable.serialize(this.element); + }, + + onEnd: function() { + Sortable.unmark(); + if(this.lastValue != Sortable.serialize(this.element)) + this.observer(this.element) + } +} + +var Sortable = { + SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/, + + sortables: {}, + + _findRootElement: function(element) { + while (element.tagName != "BODY") { + if(element.id && Sortable.sortables[element.id]) return element; + element = element.parentNode; + } + }, + + options: function(element) { + element = Sortable._findRootElement($(element)); + if(!element) return; + return Sortable.sortables[element.id]; + }, + + destroy: function(element){ + var s = Sortable.options(element); + + if(s) { + Draggables.removeObserver(s.element); + s.droppables.each(function(d){ Droppables.remove(d) }); + s.draggables.invoke('destroy'); + + delete Sortable.sortables[s.element.id]; + } + }, + + create: function(element) { + element = $(element); + var options = Object.extend({ + element: element, + tag: 'li', // assumes li children, override with tag: 'tagname' + dropOnEmpty: false, + tree: false, + treeTag: 'ul', + overlap: 'vertical', // one of 'vertical', 'horizontal' + constraint: 'vertical', // one of 'vertical', 'horizontal', false + containment: element, // also takes array of elements (or id's); or false + handle: false, // or a CSS class + only: false, + delay: 0, + hoverclass: null, + ghosting: false, + scroll: false, + scrollSensitivity: 20, + scrollSpeed: 15, + format: this.SERIALIZE_RULE, + onChange: Prototype.emptyFunction, + onUpdate: Prototype.emptyFunction + }, arguments[1] || {}); + + // clear any old sortable with same element + this.destroy(element); + + // build options for the draggables + var options_for_draggable = { + revert: true, + scroll: options.scroll, + scrollSpeed: options.scrollSpeed, + scrollSensitivity: options.scrollSensitivity, + delay: options.delay, + ghosting: options.ghosting, + constraint: options.constraint, + handle: options.handle }; + + if(options.starteffect) + options_for_draggable.starteffect = options.starteffect; + + if(options.reverteffect) + options_for_draggable.reverteffect = options.reverteffect; + else + if(options.ghosting) options_for_draggable.reverteffect = function(element) { + element.style.top = 0; + element.style.left = 0; + }; + + if(options.endeffect) + options_for_draggable.endeffect = options.endeffect; + + if(options.zindex) + options_for_draggable.zindex = options.zindex; + + // build options for the droppables + var options_for_droppable = { + overlap: options.overlap, + containment: options.containment, + tree: options.tree, + hoverclass: options.hoverclass, + onHover: Sortable.onHover + } + + var options_for_tree = { + onHover: Sortable.onEmptyHover, + overlap: options.overlap, + containment: options.containment, + hoverclass: options.hoverclass + } + + // fix for gecko engine + Element.cleanWhitespace(element); + + options.draggables = []; + options.droppables = []; + + // drop on empty handling + if(options.dropOnEmpty || options.tree) { + Droppables.add(element, options_for_tree); + options.droppables.push(element); + } + + (this.findElements(element, options) || []).each( function(e) { + // handles are per-draggable + var handle = options.handle ? + $(e).down('.'+options.handle,0) : e; + options.draggables.push( + new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); + Droppables.add(e, options_for_droppable); + if(options.tree) e.treeNode = element; + options.droppables.push(e); + }); + + if(options.tree) { + (Sortable.findTreeElements(element, options) || []).each( function(e) { + Droppables.add(e, options_for_tree); + e.treeNode = element; + options.droppables.push(e); + }); + } + + // keep reference + this.sortables[element.id] = options; + + // for onupdate + Draggables.addObserver(new SortableObserver(element, options.onUpdate)); + + }, + + // return all suitable-for-sortable elements in a guaranteed order + findElements: function(element, options) { + return Element.findChildren( + element, options.only, options.tree ? true : false, options.tag); + }, + + findTreeElements: function(element, options) { + return Element.findChildren( + element, options.only, options.tree ? true : false, options.treeTag); + }, + + onHover: function(element, dropon, overlap) { + if(Element.isParent(dropon, element)) return; + + if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) { + return; + } else if(overlap>0.5) { + Sortable.mark(dropon, 'before'); + if(dropon.previousSibling != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, dropon); + if(dropon.parentNode!=oldParentNode) + Sortable.options(oldParentNode).onChange(element); + Sortable.options(dropon.parentNode).onChange(element); + } + } else { + Sortable.mark(dropon, 'after'); + var nextElement = dropon.nextSibling || null; + if(nextElement != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, nextElement); + if(dropon.parentNode!=oldParentNode) + Sortable.options(oldParentNode).onChange(element); + Sortable.options(dropon.parentNode).onChange(element); + } + } + }, + + onEmptyHover: function(element, dropon, overlap) { + var oldParentNode = element.parentNode; + var droponOptions = Sortable.options(dropon); + + if(!Element.isParent(dropon, element)) { + var index; + + var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only}); + var child = null; + + if(children) { + var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); + + for (index = 0; index < children.length; index += 1) { + if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) { + offset -= Element.offsetSize (children[index], droponOptions.overlap); + } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) { + child = index + 1 < children.length ? children[index + 1] : null; + break; + } else { + child = children[index]; + break; + } + } + } + + dropon.insertBefore(element, child); + + Sortable.options(oldParentNode).onChange(element); + droponOptions.onChange(element); + } + }, + + unmark: function() { + if(Sortable._marker) Sortable._marker.hide(); + }, + + mark: function(dropon, position) { + // mark on ghosting only + var sortable = Sortable.options(dropon.parentNode); + if(sortable && !sortable.ghosting) return; + + if(!Sortable._marker) { + Sortable._marker = + ($('dropmarker') || Element.extend(document.createElement('DIV'))). + hide().addClassName('dropmarker').setStyle({position:'absolute'}); + document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); + } + var offsets = Position.cumulativeOffset(dropon); + Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'}); + + if(position=='after') + if(sortable.overlap == 'horizontal') + Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'}); + else + Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'}); + + Sortable._marker.show(); + }, + + _tree: function(element, options, parent) { + var children = Sortable.findElements(element, options) || []; + + for (var i = 0; i < children.length; ++i) { + var match = children[i].id.match(options.format); + + if (!match) continue; + + var child = { + id: encodeURIComponent(match ? match[1] : null), + element: element, + parent: parent, + children: [], + position: parent.children.length, + container: $(children[i]).down(options.treeTag) + } + + /* Get the element containing the children and recurse over it */ + if (child.container) + this._tree(child.container, options, child) + + parent.children.push (child); + } + + return parent; + }, + + tree: function(element) { + element = $(element); + var sortableOptions = this.options(element); + var options = Object.extend({ + tag: sortableOptions.tag, + treeTag: sortableOptions.treeTag, + only: sortableOptions.only, + name: element.id, + format: sortableOptions.format + }, arguments[1] || {}); + + var root = { + id: null, + parent: null, + children: [], + container: element, + position: 0 + } + + return Sortable._tree(element, options, root); + }, + + /* Construct a [i] index for a particular node */ + _constructIndex: function(node) { + var index = ''; + do { + if (node.id) index = '[' + node.position + ']' + index; + } while ((node = node.parent) != null); + return index; + }, + + sequence: function(element) { + element = $(element); + var options = Object.extend(this.options(element), arguments[1] || {}); + + return $(this.findElements(element, options) || []).map( function(item) { + return item.id.match(options.format) ? item.id.match(options.format)[1] : ''; + }); + }, + + setSequence: function(element, new_sequence) { + element = $(element); + var options = Object.extend(this.options(element), arguments[2] || {}); + + var nodeMap = {}; + this.findElements(element, options).each( function(n) { + if (n.id.match(options.format)) + nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode]; + n.parentNode.removeChild(n); + }); + + new_sequence.each(function(ident) { + var n = nodeMap[ident]; + if (n) { + n[1].appendChild(n[0]); + delete nodeMap[ident]; + } + }); + }, + + serialize: function(element) { + element = $(element); + var options = Object.extend(Sortable.options(element), arguments[1] || {}); + var name = encodeURIComponent( + (arguments[1] && arguments[1].name) ? arguments[1].name : element.id); + + if (options.tree) { + return Sortable.tree(element, arguments[1]).children.map( function (item) { + return [name + Sortable._constructIndex(item) + "[id]=" + + encodeURIComponent(item.id)].concat(item.children.map(arguments.callee)); + }).flatten().join('&'); + } else { + return Sortable.sequence(element, arguments[1]).map( function(item) { + return name + "[]=" + encodeURIComponent(item); + }).join('&'); + } + } +} + +// Returns true if child is contained within element +Element.isParent = function(child, element) { + if (!child.parentNode || child == element) return false; + if (child.parentNode == element) return true; + return Element.isParent(child.parentNode, element); +} + +Element.findChildren = function(element, only, recursive, tagName) { + if(!element.hasChildNodes()) return null; + tagName = tagName.toUpperCase(); + if(only) only = [only].flatten(); + var elements = []; + $A(element.childNodes).each( function(e) { + if(e.tagName && e.tagName.toUpperCase()==tagName && + (!only || (Element.classNames(e).detect(function(v) { return only.include(v) })))) + elements.push(e); + if(recursive) { + var grandchildren = Element.findChildren(e, only, recursive, tagName); + if(grandchildren) elements.push(grandchildren); + } + }); + + return (elements.length>0 ? elements.flatten() : []); +} + +Element.offsetSize = function (element, type) { + return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')]; +} diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/effects.js b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/effects.js new file mode 100644 index 00000000..3b02eda2 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/effects.js @@ -0,0 +1,1088 @@ +// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// Contributors: +// Justin Palmer (http://encytemedia.com/) +// Mark Pilgrim (http://diveintomark.org/) +// Martin Bialasinki +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +// converts rgb() and #xxx to #xxxxxx format, +// returns self (or first argument) if not convertable +String.prototype.parseColor = function() { + var color = '#'; + if(this.slice(0,4) == 'rgb(') { + var cols = this.slice(4,this.length-1).split(','); + var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); + } else { + if(this.slice(0,1) == '#') { + if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); + if(this.length==7) color = this.toLowerCase(); + } + } + return(color.length==7 ? color : (arguments[0] || this)); +} + +/*--------------------------------------------------------------------------*/ + +Element.collectTextNodes = function(element) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); + }).flatten().join(''); +} + +Element.collectTextNodesIgnoreClass = function(element, className) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? + Element.collectTextNodesIgnoreClass(node, className) : '')); + }).flatten().join(''); +} + +Element.setContentZoom = function(element, percent) { + element = $(element); + element.setStyle({fontSize: (percent/100) + 'em'}); + if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); + return element; +} + +Element.getOpacity = function(element){ + element = $(element); + var opacity; + if (opacity = element.getStyle('opacity')) + return parseFloat(opacity); + if (opacity = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) + if(opacity[1]) return parseFloat(opacity[1]) / 100; + return 1.0; +} + +Element.setOpacity = function(element, value){ + element= $(element); + if (value == 1){ + element.setStyle({ opacity: + (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? + 0.999999 : 1.0 }); + if(/MSIE/.test(navigator.userAgent) && !window.opera) + element.setStyle({filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')}); + } else { + if(value < 0.00001) value = 0; + element.setStyle({opacity: value}); + if(/MSIE/.test(navigator.userAgent) && !window.opera) + element.setStyle( + { filter: element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') + + 'alpha(opacity='+value*100+')' }); + } + return element; +} + +Element.getInlineOpacity = function(element){ + return $(element).style.opacity || ''; +} + +Element.forceRerendering = function(element) { + try { + element = $(element); + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch(e) { } +}; + +/*--------------------------------------------------------------------------*/ + +Array.prototype.call = function() { + var args = arguments; + this.each(function(f){ f.apply(this, args) }); +} + +/*--------------------------------------------------------------------------*/ + +var Effect = { + _elementDoesNotExistError: { + name: 'ElementDoesNotExistError', + message: 'The specified DOM element does not exist, but is required for this effect to operate' + }, + tagifyText: function(element) { + if(typeof Builder == 'undefined') + throw("Effect.tagifyText requires including script.aculo.us' builder.js library"); + + var tagifyStyle = 'position:relative'; + if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1'; + + element = $(element); + $A(element.childNodes).each( function(child) { + if(child.nodeType==3) { + child.nodeValue.toArray().each( function(character) { + element.insertBefore( + Builder.node('span',{style: tagifyStyle}, + character == ' ' ? String.fromCharCode(160) : character), + child); + }); + Element.remove(child); + } + }); + }, + multiple: function(element, effect) { + var elements; + if(((typeof element == 'object') || + (typeof element == 'function')) && + (element.length)) + elements = element; + else + elements = $(element).childNodes; + + var options = Object.extend({ + speed: 0.1, + delay: 0.0 + }, arguments[2] || {}); + var masterDelay = options.delay; + + $A(elements).each( function(element, index) { + new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); + }); + }, + PAIRS: { + 'slide': ['SlideDown','SlideUp'], + 'blind': ['BlindDown','BlindUp'], + 'appear': ['Appear','Fade'] + }, + toggle: function(element, effect) { + element = $(element); + effect = (effect || 'appear').toLowerCase(); + var options = Object.extend({ + queue: { position:'end', scope:(element.id || 'global'), limit: 1 } + }, arguments[2] || {}); + Effect[element.visible() ? + Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); + } +}; + +var Effect2 = Effect; // deprecated + +/* ------------- transitions ------------- */ + +Effect.Transitions = { + linear: Prototype.K, + sinoidal: function(pos) { + return (-Math.cos(pos*Math.PI)/2) + 0.5; + }, + reverse: function(pos) { + return 1-pos; + }, + flicker: function(pos) { + return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4; + }, + wobble: function(pos) { + return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5; + }, + pulse: function(pos, pulses) { + pulses = pulses || 5; + return ( + Math.round((pos % (1/pulses)) * pulses) == 0 ? + ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) : + 1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) + ); + }, + none: function(pos) { + return 0; + }, + full: function(pos) { + return 1; + } +}; + +/* ------------- core effects ------------- */ + +Effect.ScopedQueue = Class.create(); +Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), { + initialize: function() { + this.effects = []; + this.interval = null; + }, + _each: function(iterator) { + this.effects._each(iterator); + }, + add: function(effect) { + var timestamp = new Date().getTime(); + + var position = (typeof effect.options.queue == 'string') ? + effect.options.queue : effect.options.queue.position; + + switch(position) { + case 'front': + // move unstarted effects after this effect + this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { + e.startOn += effect.finishOn; + e.finishOn += effect.finishOn; + }); + break; + case 'with-last': + timestamp = this.effects.pluck('startOn').max() || timestamp; + break; + case 'end': + // start effect after last queued effect has finished + timestamp = this.effects.pluck('finishOn').max() || timestamp; + break; + } + + effect.startOn += timestamp; + effect.finishOn += timestamp; + + if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) + this.effects.push(effect); + + if(!this.interval) + this.interval = setInterval(this.loop.bind(this), 40); + }, + remove: function(effect) { + this.effects = this.effects.reject(function(e) { return e==effect }); + if(this.effects.length == 0) { + clearInterval(this.interval); + this.interval = null; + } + }, + loop: function() { + var timePos = new Date().getTime(); + this.effects.invoke('loop', timePos); + } +}); + +Effect.Queues = { + instances: $H(), + get: function(queueName) { + if(typeof queueName != 'string') return queueName; + + if(!this.instances[queueName]) + this.instances[queueName] = new Effect.ScopedQueue(); + + return this.instances[queueName]; + } +} +Effect.Queue = Effect.Queues.get('global'); + +Effect.DefaultOptions = { + transition: Effect.Transitions.sinoidal, + duration: 1.0, // seconds + fps: 25.0, // max. 25fps due to Effect.Queue implementation + sync: false, // true for combining + from: 0.0, + to: 1.0, + delay: 0.0, + queue: 'parallel' +} + +Effect.Base = function() {}; +Effect.Base.prototype = { + position: null, + start: function(options) { + this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {}); + this.currentFrame = 0; + this.state = 'idle'; + this.startOn = this.options.delay*1000; + this.finishOn = this.startOn + (this.options.duration*1000); + this.event('beforeStart'); + if(!this.options.sync) + Effect.Queues.get(typeof this.options.queue == 'string' ? + 'global' : this.options.queue.scope).add(this); + }, + loop: function(timePos) { + if(timePos >= this.startOn) { + if(timePos >= this.finishOn) { + this.render(1.0); + this.cancel(); + this.event('beforeFinish'); + if(this.finish) this.finish(); + this.event('afterFinish'); + return; + } + var pos = (timePos - this.startOn) / (this.finishOn - this.startOn); + var frame = Math.round(pos * this.options.fps * this.options.duration); + if(frame > this.currentFrame) { + this.render(pos); + this.currentFrame = frame; + } + } + }, + render: function(pos) { + if(this.state == 'idle') { + this.state = 'running'; + this.event('beforeSetup'); + if(this.setup) this.setup(); + this.event('afterSetup'); + } + if(this.state == 'running') { + if(this.options.transition) pos = this.options.transition(pos); + pos *= (this.options.to-this.options.from); + pos += this.options.from; + this.position = pos; + this.event('beforeUpdate'); + if(this.update) this.update(pos); + this.event('afterUpdate'); + } + }, + cancel: function() { + if(!this.options.sync) + Effect.Queues.get(typeof this.options.queue == 'string' ? + 'global' : this.options.queue.scope).remove(this); + this.state = 'finished'; + }, + event: function(eventName) { + if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); + if(this.options[eventName]) this.options[eventName](this); + }, + inspect: function() { + return '#'; + } +} + +Effect.Parallel = Class.create(); +Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), { + initialize: function(effects) { + this.effects = effects || []; + this.start(arguments[1]); + }, + update: function(position) { + this.effects.invoke('render', position); + }, + finish: function(position) { + this.effects.each( function(effect) { + effect.render(1.0); + effect.cancel(); + effect.event('beforeFinish'); + if(effect.finish) effect.finish(position); + effect.event('afterFinish'); + }); + } +}); + +Effect.Event = Class.create(); +Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), { + initialize: function() { + var options = Object.extend({ + duration: 0 + }, arguments[0] || {}); + this.start(options); + }, + update: Prototype.emptyFunction +}); + +Effect.Opacity = Class.create(); +Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + if(!this.element) throw(Effect._elementDoesNotExistError); + // make this work on IE on elements without 'layout' + if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout)) + this.element.setStyle({zoom: 1}); + var options = Object.extend({ + from: this.element.getOpacity() || 0.0, + to: 1.0 + }, arguments[1] || {}); + this.start(options); + }, + update: function(position) { + this.element.setOpacity(position); + } +}); + +Effect.Move = Class.create(); +Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + if(!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + x: 0, + y: 0, + mode: 'relative' + }, arguments[1] || {}); + this.start(options); + }, + setup: function() { + // Bug in Opera: Opera returns the "real" position of a static element or + // relative element that does not have top/left explicitly set. + // ==> Always set top and left for position relative elements in your stylesheets + // (to 0 if you do not need them) + this.element.makePositioned(); + this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); + this.originalTop = parseFloat(this.element.getStyle('top') || '0'); + if(this.options.mode == 'absolute') { + // absolute movement, so we need to calc deltaX and deltaY + this.options.x = this.options.x - this.originalLeft; + this.options.y = this.options.y - this.originalTop; + } + }, + update: function(position) { + this.element.setStyle({ + left: Math.round(this.options.x * position + this.originalLeft) + 'px', + top: Math.round(this.options.y * position + this.originalTop) + 'px' + }); + } +}); + +// for backwards compatibility +Effect.MoveBy = function(element, toTop, toLeft) { + return new Effect.Move(element, + Object.extend({ x: toLeft, y: toTop }, arguments[3] || {})); +}; + +Effect.Scale = Class.create(); +Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), { + initialize: function(element, percent) { + this.element = $(element); + if(!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + scaleX: true, + scaleY: true, + scaleContent: true, + scaleFromCenter: false, + scaleMode: 'box', // 'box' or 'contents' or {} with provided values + scaleFrom: 100.0, + scaleTo: percent + }, arguments[2] || {}); + this.start(options); + }, + setup: function() { + this.restoreAfterFinish = this.options.restoreAfterFinish || false; + this.elementPositioning = this.element.getStyle('position'); + + this.originalStyle = {}; + ['top','left','width','height','fontSize'].each( function(k) { + this.originalStyle[k] = this.element.style[k]; + }.bind(this)); + + this.originalTop = this.element.offsetTop; + this.originalLeft = this.element.offsetLeft; + + var fontSize = this.element.getStyle('font-size') || '100%'; + ['em','px','%','pt'].each( function(fontSizeType) { + if(fontSize.indexOf(fontSizeType)>0) { + this.fontSize = parseFloat(fontSize); + this.fontSizeType = fontSizeType; + } + }.bind(this)); + + this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; + + this.dims = null; + if(this.options.scaleMode=='box') + this.dims = [this.element.offsetHeight, this.element.offsetWidth]; + if(/^content/.test(this.options.scaleMode)) + this.dims = [this.element.scrollHeight, this.element.scrollWidth]; + if(!this.dims) + this.dims = [this.options.scaleMode.originalHeight, + this.options.scaleMode.originalWidth]; + }, + update: function(position) { + var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); + if(this.options.scaleContent && this.fontSize) + this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); + this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); + }, + finish: function(position) { + if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle); + }, + setDimensions: function(height, width) { + var d = {}; + if(this.options.scaleX) d.width = Math.round(width) + 'px'; + if(this.options.scaleY) d.height = Math.round(height) + 'px'; + if(this.options.scaleFromCenter) { + var topd = (height - this.dims[0])/2; + var leftd = (width - this.dims[1])/2; + if(this.elementPositioning == 'absolute') { + if(this.options.scaleY) d.top = this.originalTop-topd + 'px'; + if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; + } else { + if(this.options.scaleY) d.top = -topd + 'px'; + if(this.options.scaleX) d.left = -leftd + 'px'; + } + } + this.element.setStyle(d); + } +}); + +Effect.Highlight = Class.create(); +Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + if(!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {}); + this.start(options); + }, + setup: function() { + // Prevent executing on elements not in the layout flow + if(this.element.getStyle('display')=='none') { this.cancel(); return; } + // Disable background image during the effect + this.oldStyle = { + backgroundImage: this.element.getStyle('background-image') }; + this.element.setStyle({backgroundImage: 'none'}); + if(!this.options.endcolor) + this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); + if(!this.options.restorecolor) + this.options.restorecolor = this.element.getStyle('background-color'); + // init color calculations + this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); + this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); + }, + update: function(position) { + this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ + return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) }); + }, + finish: function() { + this.element.setStyle(Object.extend(this.oldStyle, { + backgroundColor: this.options.restorecolor + })); + } +}); + +Effect.ScrollTo = Class.create(); +Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + this.start(arguments[1] || {}); + }, + setup: function() { + Position.prepare(); + var offsets = Position.cumulativeOffset(this.element); + if(this.options.offset) offsets[1] += this.options.offset; + var max = window.innerHeight ? + window.height - window.innerHeight : + document.body.scrollHeight - + (document.documentElement.clientHeight ? + document.documentElement.clientHeight : document.body.clientHeight); + this.scrollStart = Position.deltaY; + this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart; + }, + update: function(position) { + Position.prepare(); + window.scrollTo(Position.deltaX, + this.scrollStart + (position*this.delta)); + } +}); + +/* ------------- combination effects ------------- */ + +Effect.Fade = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + var options = Object.extend({ + from: element.getOpacity() || 1.0, + to: 0.0, + afterFinishInternal: function(effect) { + if(effect.options.to!=0) return; + effect.element.hide().setStyle({opacity: oldOpacity}); + }}, arguments[1] || {}); + return new Effect.Opacity(element,options); +} + +Effect.Appear = function(element) { + element = $(element); + var options = Object.extend({ + from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), + to: 1.0, + // force Safari to render floated elements properly + afterFinishInternal: function(effect) { + effect.element.forceRerendering(); + }, + beforeSetup: function(effect) { + effect.element.setOpacity(effect.options.from).show(); + }}, arguments[1] || {}); + return new Effect.Opacity(element,options); +} + +Effect.Puff = function(element) { + element = $(element); + var oldStyle = { + opacity: element.getInlineOpacity(), + position: element.getStyle('position'), + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height + }; + return new Effect.Parallel( + [ new Effect.Scale(element, 200, + { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], + Object.extend({ duration: 1.0, + beforeSetupInternal: function(effect) { + Position.absolutize(effect.effects[0].element) + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().setStyle(oldStyle); } + }, arguments[1] || {}) + ); +} + +Effect.BlindUp = function(element) { + element = $(element); + element.makeClipping(); + return new Effect.Scale(element, 0, + Object.extend({ scaleContent: false, + scaleX: false, + restoreAfterFinish: true, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping(); + } + }, arguments[1] || {}) + ); +} + +Effect.BlindDown = function(element) { + element = $(element); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: 0, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makeClipping().setStyle({height: '0px'}).show(); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping(); + } + }, arguments[1] || {})); +} + +Effect.SwitchOff = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + return new Effect.Appear(element, Object.extend({ + duration: 0.4, + from: 0, + transition: Effect.Transitions.flicker, + afterFinishInternal: function(effect) { + new Effect.Scale(effect.element, 1, { + duration: 0.3, scaleFromCenter: true, + scaleX: false, scaleContent: false, restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makePositioned().makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity}); + } + }) + } + }, arguments[1] || {})); +} + +Effect.DropOut = function(element) { + element = $(element); + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left'), + opacity: element.getInlineOpacity() }; + return new Effect.Parallel( + [ new Effect.Move(element, {x: 0, y: 100, sync: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 }) ], + Object.extend( + { duration: 0.5, + beforeSetup: function(effect) { + effect.effects[0].element.makePositioned(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); + } + }, arguments[1] || {})); +} + +Effect.Shake = function(element) { + element = $(element); + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left') }; + return new Effect.Move(element, + { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { + effect.element.undoPositioned().setStyle(oldStyle); + }}) }}) }}) }}) }}) }}); +} + +Effect.SlideDown = function(element) { + element = $(element).cleanWhitespace(); + // SlideDown need to have the content of the element wrapped in a container element with fixed height! + var oldInnerBottom = element.down().getStyle('bottom'); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: window.opera ? 0 : 1, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makePositioned(); + effect.element.down().makePositioned(); + if(window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping().setStyle({height: '0px'}).show(); + }, + afterUpdateInternal: function(effect) { + effect.element.down().setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping().undoPositioned(); + effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } + }, arguments[1] || {}) + ); +} + +Effect.SlideUp = function(element) { + element = $(element).cleanWhitespace(); + var oldInnerBottom = element.down().getStyle('bottom'); + return new Effect.Scale(element, window.opera ? 0 : 1, + Object.extend({ scaleContent: false, + scaleX: false, + scaleMode: 'box', + scaleFrom: 100, + restoreAfterFinish: true, + beforeStartInternal: function(effect) { + effect.element.makePositioned(); + effect.element.down().makePositioned(); + if(window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping().show(); + }, + afterUpdateInternal: function(effect) { + effect.element.down().setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom}); + effect.element.down().undoPositioned(); + } + }, arguments[1] || {}) + ); +} + +// Bug in opera makes the TD containing this element expand for a instance after finish +Effect.Squish = function(element) { + return new Effect.Scale(element, window.opera ? 1 : 0, { + restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping(); + } + }); +} + +Effect.Grow = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.full + }, arguments[1] || {}); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var initialMoveX, initialMoveY; + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + initialMoveX = initialMoveY = moveX = moveY = 0; + break; + case 'top-right': + initialMoveX = dims.width; + initialMoveY = moveY = 0; + moveX = -dims.width; + break; + case 'bottom-left': + initialMoveX = moveX = 0; + initialMoveY = dims.height; + moveY = -dims.height; + break; + case 'bottom-right': + initialMoveX = dims.width; + initialMoveY = dims.height; + moveX = -dims.width; + moveY = -dims.height; + break; + case 'center': + initialMoveX = dims.width / 2; + initialMoveY = dims.height / 2; + moveX = -dims.width / 2; + moveY = -dims.height / 2; + break; + } + + return new Effect.Move(element, { + x: initialMoveX, + y: initialMoveY, + duration: 0.01, + beforeSetup: function(effect) { + effect.element.hide().makeClipping().makePositioned(); + }, + afterFinishInternal: function(effect) { + new Effect.Parallel( + [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), + new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), + new Effect.Scale(effect.element, 100, { + scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, + sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) + ], Object.extend({ + beforeSetup: function(effect) { + effect.effects[0].element.setStyle({height: '0px'}).show(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); + } + }, options) + ) + } + }); +} + +Effect.Shrink = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.none + }, arguments[1] || {}); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + moveX = moveY = 0; + break; + case 'top-right': + moveX = dims.width; + moveY = 0; + break; + case 'bottom-left': + moveX = 0; + moveY = dims.height; + break; + case 'bottom-right': + moveX = dims.width; + moveY = dims.height; + break; + case 'center': + moveX = dims.width / 2; + moveY = dims.height / 2; + break; + } + + return new Effect.Parallel( + [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), + new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), + new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) + ], Object.extend({ + beforeStartInternal: function(effect) { + effect.effects[0].element.makePositioned().makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } + }, options) + ); +} + +Effect.Pulsate = function(element) { + element = $(element); + var options = arguments[1] || {}; + var oldOpacity = element.getInlineOpacity(); + var transition = options.transition || Effect.Transitions.sinoidal; + var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) }; + reverser.bind(transition); + return new Effect.Opacity(element, + Object.extend(Object.extend({ duration: 2.0, from: 0, + afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } + }, options), {transition: reverser})); +} + +Effect.Fold = function(element) { + element = $(element); + var oldStyle = { + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height }; + element.makeClipping(); + return new Effect.Scale(element, 5, Object.extend({ + scaleContent: false, + scaleX: false, + afterFinishInternal: function(effect) { + new Effect.Scale(element, 1, { + scaleContent: false, + scaleY: false, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().setStyle(oldStyle); + } }); + }}, arguments[1] || {})); +}; + +Effect.Morph = Class.create(); +Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + if(!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + style: '' + }, arguments[1] || {}); + this.start(options); + }, + setup: function(){ + function parseColor(color){ + if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff'; + color = color.parseColor(); + return $R(0,2).map(function(i){ + return parseInt( color.slice(i*2+1,i*2+3), 16 ) + }); + } + this.transforms = this.options.style.parseStyle().map(function(property){ + var originalValue = this.element.getStyle(property[0]); + return $H({ + style: property[0], + originalValue: property[1].unit=='color' ? + parseColor(originalValue) : parseFloat(originalValue || 0), + targetValue: property[1].unit=='color' ? + parseColor(property[1].value) : property[1].value, + unit: property[1].unit + }); + }.bind(this)).reject(function(transform){ + return ( + (transform.originalValue == transform.targetValue) || + ( + transform.unit != 'color' && + (isNaN(transform.originalValue) || isNaN(transform.targetValue)) + ) + ) + }); + }, + update: function(position) { + var style = $H(), value = null; + this.transforms.each(function(transform){ + value = transform.unit=='color' ? + $R(0,2).inject('#',function(m,v,i){ + return m+(Math.round(transform.originalValue[i]+ + (transform.targetValue[i] - transform.originalValue[i])*position)).toColorPart() }) : + transform.originalValue + Math.round( + ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit; + style[transform.style] = value; + }); + this.element.setStyle(style); + } +}); + +Effect.Transform = Class.create(); +Object.extend(Effect.Transform.prototype, { + initialize: function(tracks){ + this.tracks = []; + this.options = arguments[1] || {}; + this.addTracks(tracks); + }, + addTracks: function(tracks){ + tracks.each(function(track){ + var data = $H(track).values().first(); + this.tracks.push($H({ + ids: $H(track).keys().first(), + effect: Effect.Morph, + options: { style: data } + })); + }.bind(this)); + return this; + }, + play: function(){ + return new Effect.Parallel( + this.tracks.map(function(track){ + var elements = [$(track.ids) || $$(track.ids)].flatten(); + return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) }); + }).flatten(), + this.options + ); + } +}); + +Element.CSS_PROPERTIES = ['azimuth', 'backgroundAttachment', 'backgroundColor', 'backgroundImage', + 'backgroundPosition', 'backgroundRepeat', 'borderBottomColor', 'borderBottomStyle', + 'borderBottomWidth', 'borderCollapse', 'borderLeftColor', 'borderLeftStyle', 'borderLeftWidth', + 'borderRightColor', 'borderRightStyle', 'borderRightWidth', 'borderSpacing', 'borderTopColor', + 'borderTopStyle', 'borderTopWidth', 'bottom', 'captionSide', 'clear', 'clip', 'color', 'content', + 'counterIncrement', 'counterReset', 'cssFloat', 'cueAfter', 'cueBefore', 'cursor', 'direction', + 'display', 'elevation', 'emptyCells', 'fontFamily', 'fontSize', 'fontSizeAdjust', 'fontStretch', + 'fontStyle', 'fontVariant', 'fontWeight', 'height', 'left', 'letterSpacing', 'lineHeight', + 'listStyleImage', 'listStylePosition', 'listStyleType', 'marginBottom', 'marginLeft', 'marginRight', + 'marginTop', 'markerOffset', 'marks', 'maxHeight', 'maxWidth', 'minHeight', 'minWidth', 'opacity', + 'orphans', 'outlineColor', 'outlineOffset', 'outlineStyle', 'outlineWidth', 'overflowX', 'overflowY', + 'paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop', 'page', 'pageBreakAfter', 'pageBreakBefore', + 'pageBreakInside', 'pauseAfter', 'pauseBefore', 'pitch', 'pitchRange', 'position', 'quotes', + 'richness', 'right', 'size', 'speakHeader', 'speakNumeral', 'speakPunctuation', 'speechRate', 'stress', + 'tableLayout', 'textAlign', 'textDecoration', 'textIndent', 'textShadow', 'textTransform', 'top', + 'unicodeBidi', 'verticalAlign', 'visibility', 'voiceFamily', 'volume', 'whiteSpace', 'widows', + 'width', 'wordSpacing', 'zIndex']; + +Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/; + +String.prototype.parseStyle = function(){ + var element = Element.extend(document.createElement('div')); + element.innerHTML = '

        '; + var style = element.down().style, styleRules = $H(); + + Element.CSS_PROPERTIES.each(function(property){ + if(style[property]) styleRules[property] = style[property]; + }); + + var result = $H(); + + styleRules.each(function(pair){ + var property = pair[0], value = pair[1], unit = null; + + if(value.parseColor('#zzzzzz') != '#zzzzzz') { + value = value.parseColor(); + unit = 'color'; + } else if(Element.CSS_LENGTH.test(value)) + var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/), + value = parseFloat(components[1]), unit = (components.length == 3) ? components[2] : null; + + result[property.underscore().dasherize()] = $H({ value:value, unit:unit }); + }.bind(this)); + + return result; +}; + +Element.morph = function(element, style) { + new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {})); + return element; +}; + +['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom', + 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each( + function(f) { Element.Methods[f] = Element[f]; } +); + +Element.Methods.visualEffect = function(element, effect, options) { + s = effect.gsub(/_/, '-').camelize(); + effect_class = s.charAt(0).toUpperCase() + s.substring(1); + new Effect[effect_class](element, options); + return $(element); +}; + +Element.addMethods(); \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/prototype.js b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/prototype.js new file mode 100644 index 00000000..50582217 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/prototype.js @@ -0,0 +1,2515 @@ +/* Prototype JavaScript framework, version 1.5.0 + * (c) 2005-2007 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://prototype.conio.net/ + * +/*--------------------------------------------------------------------------*/ + +var Prototype = { + Version: '1.5.0', + BrowserFeatures: { + XPath: !!document.evaluate + }, + + ScriptFragment: '(?:)((\n|\r|.)*?)(?:<\/script>)', + emptyFunction: function() {}, + K: function(x) { return x } +} + +var Class = { + create: function() { + return function() { + this.initialize.apply(this, arguments); + } + } +} + +var Abstract = new Object(); + +Object.extend = function(destination, source) { + for (var property in source) { + destination[property] = source[property]; + } + return destination; +} + +Object.extend(Object, { + inspect: function(object) { + try { + if (object === undefined) return 'undefined'; + if (object === null) return 'null'; + return object.inspect ? object.inspect() : object.toString(); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } + }, + + keys: function(object) { + var keys = []; + for (var property in object) + keys.push(property); + return keys; + }, + + values: function(object) { + var values = []; + for (var property in object) + values.push(object[property]); + return values; + }, + + clone: function(object) { + return Object.extend({}, object); + } +}); + +Function.prototype.bind = function() { + var __method = this, args = $A(arguments), object = args.shift(); + return function() { + return __method.apply(object, args.concat($A(arguments))); + } +} + +Function.prototype.bindAsEventListener = function(object) { + var __method = this, args = $A(arguments), object = args.shift(); + return function(event) { + return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments))); + } +} + +Object.extend(Number.prototype, { + toColorPart: function() { + var digits = this.toString(16); + if (this < 16) return '0' + digits; + return digits; + }, + + succ: function() { + return this + 1; + }, + + times: function(iterator) { + $R(0, this, true).each(iterator); + return this; + } +}); + +var Try = { + these: function() { + var returnValue; + + for (var i = 0, length = arguments.length; i < length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) {} + } + + return returnValue; + } +} + +/*--------------------------------------------------------------------------*/ + +var PeriodicalExecuter = Class.create(); +PeriodicalExecuter.prototype = { + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + stop: function() { + if (!this.timer) return; + clearInterval(this.timer); + this.timer = null; + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.callback(this); + } finally { + this.currentlyExecuting = false; + } + } + } +} +String.interpret = function(value){ + return value == null ? '' : String(value); +} + +Object.extend(String.prototype, { + gsub: function(pattern, replacement) { + var result = '', source = this, match; + replacement = arguments.callee.prepareReplacement(replacement); + + while (source.length > 0) { + if (match = source.match(pattern)) { + result += source.slice(0, match.index); + result += String.interpret(replacement(match)); + source = source.slice(match.index + match[0].length); + } else { + result += source, source = ''; + } + } + return result; + }, + + sub: function(pattern, replacement, count) { + replacement = this.gsub.prepareReplacement(replacement); + count = count === undefined ? 1 : count; + + return this.gsub(pattern, function(match) { + if (--count < 0) return match[0]; + return replacement(match); + }); + }, + + scan: function(pattern, iterator) { + this.gsub(pattern, iterator); + return this; + }, + + truncate: function(length, truncation) { + length = length || 30; + truncation = truncation === undefined ? '...' : truncation; + return this.length > length ? + this.slice(0, length - truncation.length) + truncation : this; + }, + + strip: function() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + }, + + stripTags: function() { + return this.replace(/<\/?[^>]+>/gi, ''); + }, + + stripScripts: function() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + }, + + extractScripts: function() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); + var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + }, + + evalScripts: function() { + return this.extractScripts().map(function(script) { return eval(script) }); + }, + + escapeHTML: function() { + var div = document.createElement('div'); + var text = document.createTextNode(this); + div.appendChild(text); + return div.innerHTML; + }, + + unescapeHTML: function() { + var div = document.createElement('div'); + div.innerHTML = this.stripTags(); + return div.childNodes[0] ? (div.childNodes.length > 1 ? + $A(div.childNodes).inject('',function(memo,node){ return memo+node.nodeValue }) : + div.childNodes[0].nodeValue) : ''; + }, + + toQueryParams: function(separator) { + var match = this.strip().match(/([^?#]*)(#.*)?$/); + if (!match) return {}; + + return match[1].split(separator || '&').inject({}, function(hash, pair) { + if ((pair = pair.split('='))[0]) { + var name = decodeURIComponent(pair[0]); + var value = pair[1] ? decodeURIComponent(pair[1]) : undefined; + + if (hash[name] !== undefined) { + if (hash[name].constructor != Array) + hash[name] = [hash[name]]; + if (value) hash[name].push(value); + } + else hash[name] = value; + } + return hash; + }); + }, + + toArray: function() { + return this.split(''); + }, + + succ: function() { + return this.slice(0, this.length - 1) + + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); + }, + + camelize: function() { + var parts = this.split('-'), len = parts.length; + if (len == 1) return parts[0]; + + var camelized = this.charAt(0) == '-' + ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) + : parts[0]; + + for (var i = 1; i < len; i++) + camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); + + return camelized; + }, + + capitalize: function(){ + return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); + }, + + underscore: function() { + return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); + }, + + dasherize: function() { + return this.gsub(/_/,'-'); + }, + + inspect: function(useDoubleQuotes) { + var escapedString = this.replace(/\\/g, '\\\\'); + if (useDoubleQuotes) + return '"' + escapedString.replace(/"/g, '\\"') + '"'; + else + return "'" + escapedString.replace(/'/g, '\\\'') + "'"; + } +}); + +String.prototype.gsub.prepareReplacement = function(replacement) { + if (typeof replacement == 'function') return replacement; + var template = new Template(replacement); + return function(match) { return template.evaluate(match) }; +} + +String.prototype.parseQuery = String.prototype.toQueryParams; + +var Template = Class.create(); +Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; +Template.prototype = { + initialize: function(template, pattern) { + this.template = template.toString(); + this.pattern = pattern || Template.Pattern; + }, + + evaluate: function(object) { + return this.template.gsub(this.pattern, function(match) { + var before = match[1]; + if (before == '\\') return match[2]; + return before + String.interpret(object[match[3]]); + }); + } +} + +var $break = new Object(); +var $continue = new Object(); + +var Enumerable = { + each: function(iterator) { + var index = 0; + try { + this._each(function(value) { + try { + iterator(value, index++); + } catch (e) { + if (e != $continue) throw e; + } + }); + } catch (e) { + if (e != $break) throw e; + } + return this; + }, + + eachSlice: function(number, iterator) { + var index = -number, slices = [], array = this.toArray(); + while ((index += number) < array.length) + slices.push(array.slice(index, index+number)); + return slices.map(iterator); + }, + + all: function(iterator) { + var result = true; + this.each(function(value, index) { + result = result && !!(iterator || Prototype.K)(value, index); + if (!result) throw $break; + }); + return result; + }, + + any: function(iterator) { + var result = false; + this.each(function(value, index) { + if (result = !!(iterator || Prototype.K)(value, index)) + throw $break; + }); + return result; + }, + + collect: function(iterator) { + var results = []; + this.each(function(value, index) { + results.push((iterator || Prototype.K)(value, index)); + }); + return results; + }, + + detect: function(iterator) { + var result; + this.each(function(value, index) { + if (iterator(value, index)) { + result = value; + throw $break; + } + }); + return result; + }, + + findAll: function(iterator) { + var results = []; + this.each(function(value, index) { + if (iterator(value, index)) + results.push(value); + }); + return results; + }, + + grep: function(pattern, iterator) { + var results = []; + this.each(function(value, index) { + var stringValue = value.toString(); + if (stringValue.match(pattern)) + results.push((iterator || Prototype.K)(value, index)); + }) + return results; + }, + + include: function(object) { + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + }, + + inGroupsOf: function(number, fillWith) { + fillWith = fillWith === undefined ? null : fillWith; + return this.eachSlice(number, function(slice) { + while(slice.length < number) slice.push(fillWith); + return slice; + }); + }, + + inject: function(memo, iterator) { + this.each(function(value, index) { + memo = iterator(memo, value, index); + }); + return memo; + }, + + invoke: function(method) { + var args = $A(arguments).slice(1); + return this.map(function(value) { + return value[method].apply(value, args); + }); + }, + + max: function(iterator) { + var result; + this.each(function(value, index) { + value = (iterator || Prototype.K)(value, index); + if (result == undefined || value >= result) + result = value; + }); + return result; + }, + + min: function(iterator) { + var result; + this.each(function(value, index) { + value = (iterator || Prototype.K)(value, index); + if (result == undefined || value < result) + result = value; + }); + return result; + }, + + partition: function(iterator) { + var trues = [], falses = []; + this.each(function(value, index) { + ((iterator || Prototype.K)(value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + }, + + pluck: function(property) { + var results = []; + this.each(function(value, index) { + results.push(value[property]); + }); + return results; + }, + + reject: function(iterator) { + var results = []; + this.each(function(value, index) { + if (!iterator(value, index)) + results.push(value); + }); + return results; + }, + + sortBy: function(iterator) { + return this.map(function(value, index) { + return {value: value, criteria: iterator(value, index)}; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + }, + + toArray: function() { + return this.map(); + }, + + zip: function() { + var iterator = Prototype.K, args = $A(arguments); + if (typeof args.last() == 'function') + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + return iterator(collections.pluck(index)); + }); + }, + + size: function() { + return this.toArray().length; + }, + + inspect: function() { + return '#'; + } +} + +Object.extend(Enumerable, { + map: Enumerable.collect, + find: Enumerable.detect, + select: Enumerable.findAll, + member: Enumerable.include, + entries: Enumerable.toArray +}); +var $A = Array.from = function(iterable) { + if (!iterable) return []; + if (iterable.toArray) { + return iterable.toArray(); + } else { + var results = []; + for (var i = 0, length = iterable.length; i < length; i++) + results.push(iterable[i]); + return results; + } +} + +Object.extend(Array.prototype, Enumerable); + +if (!Array.prototype._reverse) + Array.prototype._reverse = Array.prototype.reverse; + +Object.extend(Array.prototype, { + _each: function(iterator) { + for (var i = 0, length = this.length; i < length; i++) + iterator(this[i]); + }, + + clear: function() { + this.length = 0; + return this; + }, + + first: function() { + return this[0]; + }, + + last: function() { + return this[this.length - 1]; + }, + + compact: function() { + return this.select(function(value) { + return value != null; + }); + }, + + flatten: function() { + return this.inject([], function(array, value) { + return array.concat(value && value.constructor == Array ? + value.flatten() : [value]); + }); + }, + + without: function() { + var values = $A(arguments); + return this.select(function(value) { + return !values.include(value); + }); + }, + + indexOf: function(object) { + for (var i = 0, length = this.length; i < length; i++) + if (this[i] == object) return i; + return -1; + }, + + reverse: function(inline) { + return (inline !== false ? this : this.toArray())._reverse(); + }, + + reduce: function() { + return this.length > 1 ? this : this[0]; + }, + + uniq: function() { + return this.inject([], function(array, value) { + return array.include(value) ? array : array.concat([value]); + }); + }, + + clone: function() { + return [].concat(this); + }, + + size: function() { + return this.length; + }, + + inspect: function() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + } +}); + +Array.prototype.toArray = Array.prototype.clone; + +function $w(string){ + string = string.strip(); + return string ? string.split(/\s+/) : []; +} + +if(window.opera){ + Array.prototype.concat = function(){ + var array = []; + for(var i = 0, length = this.length; i < length; i++) array.push(this[i]); + for(var i = 0, length = arguments.length; i < length; i++) { + if(arguments[i].constructor == Array) { + for(var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) + array.push(arguments[i][j]); + } else { + array.push(arguments[i]); + } + } + return array; + } +} +var Hash = function(obj) { + Object.extend(this, obj || {}); +}; + +Object.extend(Hash, { + toQueryString: function(obj) { + var parts = []; + + this.prototype._each.call(obj, function(pair) { + if (!pair.key) return; + + if (pair.value && pair.value.constructor == Array) { + var values = pair.value.compact(); + if (values.length < 2) pair.value = values.reduce(); + else { + key = encodeURIComponent(pair.key); + values.each(function(value) { + value = value != undefined ? encodeURIComponent(value) : ''; + parts.push(key + '=' + encodeURIComponent(value)); + }); + return; + } + } + if (pair.value == undefined) pair[1] = ''; + parts.push(pair.map(encodeURIComponent).join('=')); + }); + + return parts.join('&'); + } +}); + +Object.extend(Hash.prototype, Enumerable); +Object.extend(Hash.prototype, { + _each: function(iterator) { + for (var key in this) { + var value = this[key]; + if (value && value == Hash.prototype[key]) continue; + + var pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + }, + + keys: function() { + return this.pluck('key'); + }, + + values: function() { + return this.pluck('value'); + }, + + merge: function(hash) { + return $H(hash).inject(this, function(mergedHash, pair) { + mergedHash[pair.key] = pair.value; + return mergedHash; + }); + }, + + remove: function() { + var result; + for(var i = 0, length = arguments.length; i < length; i++) { + var value = this[arguments[i]]; + if (value !== undefined){ + if (result === undefined) result = value; + else { + if (result.constructor != Array) result = [result]; + result.push(value) + } + } + delete this[arguments[i]]; + } + return result; + }, + + toQueryString: function() { + return Hash.toQueryString(this); + }, + + inspect: function() { + return '#'; + } +}); + +function $H(object) { + if (object && object.constructor == Hash) return object; + return new Hash(object); +}; +ObjectRange = Class.create(); +Object.extend(ObjectRange.prototype, Enumerable); +Object.extend(ObjectRange.prototype, { + initialize: function(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + }, + + _each: function(iterator) { + var value = this.start; + while (this.include(value)) { + iterator(value); + value = value.succ(); + } + }, + + include: function(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } +}); + +var $R = function(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +} + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +} + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responder) { + if (!this.include(responder)) + this.responders.push(responder); + }, + + unregister: function(responder) { + this.responders = this.responders.without(responder); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (typeof responder[callback] == 'function') { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) {} + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { + Ajax.activeRequestCount++; + }, + onComplete: function() { + Ajax.activeRequestCount--; + } +}); + +Ajax.Base = function() {}; +Ajax.Base.prototype = { + setOptions: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + encoding: 'UTF-8', + parameters: '' + } + Object.extend(this.options, options || {}); + + this.options.method = this.options.method.toLowerCase(); + if (typeof this.options.parameters == 'string') + this.options.parameters = this.options.parameters.toQueryParams(); + } +} + +Ajax.Request = Class.create(); +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + +Ajax.Request.prototype = Object.extend(new Ajax.Base(), { + _complete: false, + + initialize: function(url, options) { + this.transport = Ajax.getTransport(); + this.setOptions(options); + this.request(url); + }, + + request: function(url) { + this.url = url; + this.method = this.options.method; + var params = this.options.parameters; + + if (!['get', 'post'].include(this.method)) { + // simulate other verbs over post + params['_method'] = this.method; + this.method = 'post'; + } + + params = Hash.toQueryString(params); + if (params && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_=' + + // when GET, append parameters to URL + if (this.method == 'get' && params) + this.url += (this.url.indexOf('?') > -1 ? '&' : '?') + params; + + try { + Ajax.Responders.dispatch('onCreate', this, this.transport); + + this.transport.open(this.method.toUpperCase(), this.url, + this.options.asynchronous); + + if (this.options.asynchronous) + setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10); + + this.transport.onreadystatechange = this.onStateChange.bind(this); + this.setRequestHeaders(); + + var body = this.method == 'post' ? (this.options.postBody || params) : null; + + this.transport.send(body); + + /* Force Firefox to handle ready state 4 for synchronous requests */ + if (!this.options.asynchronous && this.transport.overrideMimeType) + this.onStateChange(); + + } + catch (e) { + this.dispatchException(e); + } + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState > 1 && !((readyState == 4) && this._complete)) + this.respondToReadyState(this.transport.readyState); + }, + + setRequestHeaders: function() { + var headers = { + 'X-Requested-With': 'XMLHttpRequest', + 'X-Prototype-Version': Prototype.Version, + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }; + + if (this.method == 'post') { + headers['Content-type'] = this.options.contentType + + (this.options.encoding ? '; charset=' + this.options.encoding : ''); + + /* Force "Connection: close" for older Mozilla browsers to work + * around a bug where XMLHttpRequest sends an incorrect + * Content-length header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType && + (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) + headers['Connection'] = 'close'; + } + + // user-defined headers + if (typeof this.options.requestHeaders == 'object') { + var extras = this.options.requestHeaders; + + if (typeof extras.push == 'function') + for (var i = 0, length = extras.length; i < length; i += 2) + headers[extras[i]] = extras[i+1]; + else + $H(extras).each(function(pair) { headers[pair.key] = pair.value }); + } + + for (var name in headers) + this.transport.setRequestHeader(name, headers[name]); + }, + + success: function() { + return !this.transport.status + || (this.transport.status >= 200 && this.transport.status < 300); + }, + + respondToReadyState: function(readyState) { + var state = Ajax.Request.Events[readyState]; + var transport = this.transport, json = this.evalJSON(); + + if (state == 'Complete') { + try { + this._complete = true; + (this.options['on' + this.transport.status] + || this.options['on' + (this.success() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(transport, json); + } catch (e) { + this.dispatchException(e); + } + + if ((this.getHeader('Content-type') || 'text/javascript').strip(). + match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i)) + this.evalResponse(); + } + + try { + (this.options['on' + state] || Prototype.emptyFunction)(transport, json); + Ajax.Responders.dispatch('on' + state, this, transport, json); + } catch (e) { + this.dispatchException(e); + } + + if (state == 'Complete') { + // avoid memory leak in MSIE: clean up + this.transport.onreadystatechange = Prototype.emptyFunction; + } + }, + + getHeader: function(name) { + try { + return this.transport.getResponseHeader(name); + } catch (e) { return null } + }, + + evalJSON: function() { + try { + var json = this.getHeader('X-JSON'); + return json ? eval('(' + json + ')') : null; + } catch (e) { return null } + }, + + evalResponse: function() { + try { + return eval(this.transport.responseText); + } catch (e) { + this.dispatchException(e); + } + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Updater = Class.create(); + +Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { + initialize: function(container, url, options) { + this.container = { + success: (container.success || container), + failure: (container.failure || (container.success ? null : container)) + } + + this.transport = Ajax.getTransport(); + this.setOptions(options); + + var onComplete = this.options.onComplete || Prototype.emptyFunction; + this.options.onComplete = (function(transport, param) { + this.updateContent(); + onComplete(transport, param); + }).bind(this); + + this.request(url); + }, + + updateContent: function() { + var receiver = this.container[this.success() ? 'success' : 'failure']; + var response = this.transport.responseText; + + if (!this.options.evalScripts) response = response.stripScripts(); + + if (receiver = $(receiver)) { + if (this.options.insertion) + new this.options.insertion(receiver, response); + else + receiver.update(response); + } + + if (this.success()) { + if (this.onComplete) + setTimeout(this.onComplete.bind(this), 10); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(); +Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { + initialize: function(container, url, options) { + this.setOptions(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = {}; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.options.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(request) { + if (this.options.decay) { + this.decay = (request.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = request.responseText; + } + this.timer = setTimeout(this.onTimerEvent.bind(this), + this.decay * this.frequency * 1000); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); +function $(element) { + if (arguments.length > 1) { + for (var i = 0, elements = [], length = arguments.length; i < length; i++) + elements.push($(arguments[i])); + return elements; + } + if (typeof element == 'string') + element = document.getElementById(element); + return Element.extend(element); +} + +if (Prototype.BrowserFeatures.XPath) { + document._getElementsByXPath = function(expression, parentElement) { + var results = []; + var query = document.evaluate(expression, $(parentElement) || document, + null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + for (var i = 0, length = query.snapshotLength; i < length; i++) + results.push(query.snapshotItem(i)); + return results; + }; +} + +document.getElementsByClassName = function(className, parentElement) { + if (Prototype.BrowserFeatures.XPath) { + var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]"; + return document._getElementsByXPath(q, parentElement); + } else { + var children = ($(parentElement) || document.body).getElementsByTagName('*'); + var elements = [], child; + for (var i = 0, length = children.length; i < length; i++) { + child = children[i]; + if (Element.hasClassName(child, className)) + elements.push(Element.extend(child)); + } + return elements; + } +}; + +/*--------------------------------------------------------------------------*/ + +if (!window.Element) + var Element = new Object(); + +Element.extend = function(element) { + if (!element || _nativeExtensions || element.nodeType == 3) return element; + + if (!element._extended && element.tagName && element != window) { + var methods = Object.clone(Element.Methods), cache = Element.extend.cache; + + if (element.tagName == 'FORM') + Object.extend(methods, Form.Methods); + if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName)) + Object.extend(methods, Form.Element.Methods); + + Object.extend(methods, Element.Methods.Simulated); + + for (var property in methods) { + var value = methods[property]; + if (typeof value == 'function' && !(property in element)) + element[property] = cache.findOrStore(value); + } + } + + element._extended = true; + return element; +}; + +Element.extend.cache = { + findOrStore: function(value) { + return this[value] = this[value] || function() { + return value.apply(null, [this].concat($A(arguments))); + } + } +}; + +Element.Methods = { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function(element) { + element = $(element); + Element[Element.visible(element) ? 'hide' : 'show'](element); + return element; + }, + + hide: function(element) { + $(element).style.display = 'none'; + return element; + }, + + show: function(element) { + $(element).style.display = ''; + return element; + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + return element; + }, + + update: function(element, html) { + html = typeof html == 'undefined' ? '' : html.toString(); + $(element).innerHTML = html.stripScripts(); + setTimeout(function() {html.evalScripts()}, 10); + return element; + }, + + replace: function(element, html) { + element = $(element); + html = typeof html == 'undefined' ? '' : html.toString(); + if (element.outerHTML) { + element.outerHTML = html.stripScripts(); + } else { + var range = element.ownerDocument.createRange(); + range.selectNodeContents(element); + element.parentNode.replaceChild( + range.createContextualFragment(html.stripScripts()), element); + } + setTimeout(function() {html.evalScripts()}, 10); + return element; + }, + + inspect: function(element) { + element = $(element); + var result = '<' + element.tagName.toLowerCase(); + $H({'id': 'id', 'className': 'class'}).each(function(pair) { + var property = pair.first(), attribute = pair.last(); + var value = (element[property] || '').toString(); + if (value) result += ' ' + attribute + '=' + value.inspect(true); + }); + return result + '>'; + }, + + recursivelyCollect: function(element, property) { + element = $(element); + var elements = []; + while (element = element[property]) + if (element.nodeType == 1) + elements.push(Element.extend(element)); + return elements; + }, + + ancestors: function(element) { + return $(element).recursivelyCollect('parentNode'); + }, + + descendants: function(element) { + return $A($(element).getElementsByTagName('*')); + }, + + immediateDescendants: function(element) { + if (!(element = $(element).firstChild)) return []; + while (element && element.nodeType != 1) element = element.nextSibling; + if (element) return [element].concat($(element).nextSiblings()); + return []; + }, + + previousSiblings: function(element) { + return $(element).recursivelyCollect('previousSibling'); + }, + + nextSiblings: function(element) { + return $(element).recursivelyCollect('nextSibling'); + }, + + siblings: function(element) { + element = $(element); + return element.previousSiblings().reverse().concat(element.nextSiblings()); + }, + + match: function(element, selector) { + if (typeof selector == 'string') + selector = new Selector(selector); + return selector.match($(element)); + }, + + up: function(element, expression, index) { + return Selector.findElement($(element).ancestors(), expression, index); + }, + + down: function(element, expression, index) { + return Selector.findElement($(element).descendants(), expression, index); + }, + + previous: function(element, expression, index) { + return Selector.findElement($(element).previousSiblings(), expression, index); + }, + + next: function(element, expression, index) { + return Selector.findElement($(element).nextSiblings(), expression, index); + }, + + getElementsBySelector: function() { + var args = $A(arguments), element = $(args.shift()); + return Selector.findChildElements(element, args); + }, + + getElementsByClassName: function(element, className) { + return document.getElementsByClassName(className, element); + }, + + readAttribute: function(element, name) { + element = $(element); + if (document.all && !window.opera) { + var t = Element._attributeTranslations; + if (t.values[name]) return t.values[name](element, name); + if (t.names[name]) name = t.names[name]; + var attribute = element.attributes[name]; + if(attribute) return attribute.nodeValue; + } + return element.getAttribute(name); + }, + + getHeight: function(element) { + return $(element).getDimensions().height; + }, + + getWidth: function(element) { + return $(element).getDimensions().width; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + var elementClassName = element.className; + if (elementClassName.length == 0) return false; + if (elementClassName == className || + elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) + return true; + return false; + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + Element.classNames(element).add(className); + return element; + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + Element.classNames(element).remove(className); + return element; + }, + + toggleClassName: function(element, className) { + if (!(element = $(element))) return; + Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className); + return element; + }, + + observe: function() { + Event.observe.apply(Event, arguments); + return $A(arguments).first(); + }, + + stopObserving: function() { + Event.stopObserving.apply(Event, arguments); + return $A(arguments).first(); + }, + + // removes whitespace-only text node children + cleanWhitespace: function(element) { + element = $(element); + var node = element.firstChild; + while (node) { + var nextNode = node.nextSibling; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + element.removeChild(node); + node = nextNode; + } + return element; + }, + + empty: function(element) { + return $(element).innerHTML.match(/^\s*$/); + }, + + descendantOf: function(element, ancestor) { + element = $(element), ancestor = $(ancestor); + while (element = element.parentNode) + if (element == ancestor) return true; + return false; + }, + + scrollTo: function(element) { + element = $(element); + var pos = Position.cumulativeOffset(element); + window.scrollTo(pos[0], pos[1]); + return element; + }, + + getStyle: function(element, style) { + element = $(element); + if (['float','cssFloat'].include(style)) + style = (typeof element.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat'); + style = style.camelize(); + var value = element.style[style]; + if (!value) { + if (document.defaultView && document.defaultView.getComputedStyle) { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css[style] : null; + } else if (element.currentStyle) { + value = element.currentStyle[style]; + } + } + + if((value == 'auto') && ['width','height'].include(style) && (element.getStyle('display') != 'none')) + value = element['offset'+style.capitalize()] + 'px'; + + if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) + if (Element.getStyle(element, 'position') == 'static') value = 'auto'; + if(style == 'opacity') { + if(value) return parseFloat(value); + if(value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) + if(value[1]) return parseFloat(value[1]) / 100; + return 1.0; + } + return value == 'auto' ? null : value; + }, + + setStyle: function(element, style) { + element = $(element); + for (var name in style) { + var value = style[name]; + if(name == 'opacity') { + if (value == 1) { + value = (/Gecko/.test(navigator.userAgent) && + !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0; + if(/MSIE/.test(navigator.userAgent) && !window.opera) + element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,''); + } else if(value == '') { + if(/MSIE/.test(navigator.userAgent) && !window.opera) + element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,''); + } else { + if(value < 0.00001) value = 0; + if(/MSIE/.test(navigator.userAgent) && !window.opera) + element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') + + 'alpha(opacity='+value*100+')'; + } + } else if(['float','cssFloat'].include(name)) name = (typeof element.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat'; + element.style[name.camelize()] = value; + } + return element; + }, + + getDimensions: function(element) { + element = $(element); + var display = $(element).getStyle('display'); + if (display != 'none' && display != null) // Safari bug + return {width: element.offsetWidth, height: element.offsetHeight}; + + // All *Width and *Height properties give 0 on elements with display none, + // so enable the element temporarily + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + var originalDisplay = els.display; + els.visibility = 'hidden'; + els.position = 'absolute'; + els.display = 'block'; + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + els.display = originalDisplay; + els.position = originalPosition; + els.visibility = originalVisibility; + return {width: originalWidth, height: originalHeight}; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + // Opera returns the offset relative to the positioning context, when an + // element is position relative but top and left have not been defined + if (window.opera) { + element.style.top = 0; + element.style.left = 0; + } + } + return element; + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + return element; + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return element; + element._overflow = element.style.overflow || 'auto'; + if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') + element.style.overflow = 'hidden'; + return element; + }, + + undoClipping: function(element) { + element = $(element); + if (!element._overflow) return element; + element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; + element._overflow = null; + return element; + } +}; + +Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf}); + +Element._attributeTranslations = {}; + +Element._attributeTranslations.names = { + colspan: "colSpan", + rowspan: "rowSpan", + valign: "vAlign", + datetime: "dateTime", + accesskey: "accessKey", + tabindex: "tabIndex", + enctype: "encType", + maxlength: "maxLength", + readonly: "readOnly", + longdesc: "longDesc" +}; + +Element._attributeTranslations.values = { + _getAttr: function(element, attribute) { + return element.getAttribute(attribute, 2); + }, + + _flag: function(element, attribute) { + return $(element).hasAttribute(attribute) ? attribute : null; + }, + + style: function(element) { + return element.style.cssText.toLowerCase(); + }, + + title: function(element) { + var node = element.getAttributeNode('title'); + return node.specified ? node.nodeValue : null; + } +}; + +Object.extend(Element._attributeTranslations.values, { + href: Element._attributeTranslations.values._getAttr, + src: Element._attributeTranslations.values._getAttr, + disabled: Element._attributeTranslations.values._flag, + checked: Element._attributeTranslations.values._flag, + readonly: Element._attributeTranslations.values._flag, + multiple: Element._attributeTranslations.values._flag +}); + +Element.Methods.Simulated = { + hasAttribute: function(element, attribute) { + var t = Element._attributeTranslations; + attribute = t.names[attribute] || attribute; + return $(element).getAttributeNode(attribute).specified; + } +}; + +// IE is missing .innerHTML support for TABLE-related elements +if (document.all && !window.opera){ + Element.Methods.update = function(element, html) { + element = $(element); + html = typeof html == 'undefined' ? '' : html.toString(); + var tagName = element.tagName.toUpperCase(); + if (['THEAD','TBODY','TR','TD'].include(tagName)) { + var div = document.createElement('div'); + switch (tagName) { + case 'THEAD': + case 'TBODY': + div.innerHTML = '' + html.stripScripts() + '
        '; + depth = 2; + break; + case 'TR': + div.innerHTML = '' + html.stripScripts() + '
        '; + depth = 3; + break; + case 'TD': + div.innerHTML = '
        ' + html.stripScripts() + '
        '; + depth = 4; + } + $A(element.childNodes).each(function(node){ + element.removeChild(node) + }); + depth.times(function(){ div = div.firstChild }); + + $A(div.childNodes).each( + function(node){ element.appendChild(node) }); + } else { + element.innerHTML = html.stripScripts(); + } + setTimeout(function() {html.evalScripts()}, 10); + return element; + } +}; + +Object.extend(Element, Element.Methods); + +var _nativeExtensions = false; + +if(/Konqueror|Safari|KHTML/.test(navigator.userAgent)) + ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) { + var className = 'HTML' + tag + 'Element'; + if(window[className]) return; + var klass = window[className] = {}; + klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__; + }); + +Element.addMethods = function(methods) { + Object.extend(Element.Methods, methods || {}); + + function copy(methods, destination, onlyIfAbsent) { + onlyIfAbsent = onlyIfAbsent || false; + var cache = Element.extend.cache; + for (var property in methods) { + var value = methods[property]; + if (!onlyIfAbsent || !(property in destination)) + destination[property] = cache.findOrStore(value); + } + } + + if (typeof HTMLElement != 'undefined') { + copy(Element.Methods, HTMLElement.prototype); + copy(Element.Methods.Simulated, HTMLElement.prototype, true); + copy(Form.Methods, HTMLFormElement.prototype); + [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) { + copy(Form.Element.Methods, klass.prototype); + }); + _nativeExtensions = true; + } +} + +var Toggle = new Object(); +Toggle.display = Element.toggle; + +/*--------------------------------------------------------------------------*/ + +Abstract.Insertion = function(adjacency) { + this.adjacency = adjacency; +} + +Abstract.Insertion.prototype = { + initialize: function(element, content) { + this.element = $(element); + this.content = content.stripScripts(); + + if (this.adjacency && this.element.insertAdjacentHTML) { + try { + this.element.insertAdjacentHTML(this.adjacency, this.content); + } catch (e) { + var tagName = this.element.tagName.toUpperCase(); + if (['TBODY', 'TR'].include(tagName)) { + this.insertContent(this.contentFromAnonymousTable()); + } else { + throw e; + } + } + } else { + this.range = this.element.ownerDocument.createRange(); + if (this.initializeRange) this.initializeRange(); + this.insertContent([this.range.createContextualFragment(this.content)]); + } + + setTimeout(function() {content.evalScripts()}, 10); + }, + + contentFromAnonymousTable: function() { + var div = document.createElement('div'); + div.innerHTML = '' + this.content + '
        '; + return $A(div.childNodes[0].childNodes[0].childNodes); + } +} + +var Insertion = new Object(); + +Insertion.Before = Class.create(); +Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { + initializeRange: function() { + this.range.setStartBefore(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.parentNode.insertBefore(fragment, this.element); + }).bind(this)); + } +}); + +Insertion.Top = Class.create(); +Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { + initializeRange: function() { + this.range.selectNodeContents(this.element); + this.range.collapse(true); + }, + + insertContent: function(fragments) { + fragments.reverse(false).each((function(fragment) { + this.element.insertBefore(fragment, this.element.firstChild); + }).bind(this)); + } +}); + +Insertion.Bottom = Class.create(); +Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { + initializeRange: function() { + this.range.selectNodeContents(this.element); + this.range.collapse(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.appendChild(fragment); + }).bind(this)); + } +}); + +Insertion.After = Class.create(); +Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { + initializeRange: function() { + this.range.setStartAfter(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.parentNode.insertBefore(fragment, + this.element.nextSibling); + }).bind(this)); + } +}); + +/*--------------------------------------------------------------------------*/ + +Element.ClassNames = Class.create(); +Element.ClassNames.prototype = { + initialize: function(element) { + this.element = $(element); + }, + + _each: function(iterator) { + this.element.className.split(/\s+/).select(function(name) { + return name.length > 0; + })._each(iterator); + }, + + set: function(className) { + this.element.className = className; + }, + + add: function(classNameToAdd) { + if (this.include(classNameToAdd)) return; + this.set($A(this).concat(classNameToAdd).join(' ')); + }, + + remove: function(classNameToRemove) { + if (!this.include(classNameToRemove)) return; + this.set($A(this).without(classNameToRemove).join(' ')); + }, + + toString: function() { + return $A(this).join(' '); + } +}; + +Object.extend(Element.ClassNames.prototype, Enumerable); +var Selector = Class.create(); +Selector.prototype = { + initialize: function(expression) { + this.params = {classNames: []}; + this.expression = expression.toString().strip(); + this.parseExpression(); + this.compileMatcher(); + }, + + parseExpression: function() { + function abort(message) { throw 'Parse error in selector: ' + message; } + + if (this.expression == '') abort('empty expression'); + + var params = this.params, expr = this.expression, match, modifier, clause, rest; + while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) { + params.attributes = params.attributes || []; + params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''}); + expr = match[1]; + } + + if (expr == '*') return this.params.wildcard = true; + + while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) { + modifier = match[1], clause = match[2], rest = match[3]; + switch (modifier) { + case '#': params.id = clause; break; + case '.': params.classNames.push(clause); break; + case '': + case undefined: params.tagName = clause.toUpperCase(); break; + default: abort(expr.inspect()); + } + expr = rest; + } + + if (expr.length > 0) abort(expr.inspect()); + }, + + buildMatchExpression: function() { + var params = this.params, conditions = [], clause; + + if (params.wildcard) + conditions.push('true'); + if (clause = params.id) + conditions.push('element.readAttribute("id") == ' + clause.inspect()); + if (clause = params.tagName) + conditions.push('element.tagName.toUpperCase() == ' + clause.inspect()); + if ((clause = params.classNames).length > 0) + for (var i = 0, length = clause.length; i < length; i++) + conditions.push('element.hasClassName(' + clause[i].inspect() + ')'); + if (clause = params.attributes) { + clause.each(function(attribute) { + var value = 'element.readAttribute(' + attribute.name.inspect() + ')'; + var splitValueBy = function(delimiter) { + return value + ' && ' + value + '.split(' + delimiter.inspect() + ')'; + } + + switch (attribute.operator) { + case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break; + case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break; + case '|=': conditions.push( + splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect() + ); break; + case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break; + case '': + case undefined: conditions.push('element.hasAttribute(' + attribute.name.inspect() + ')'); break; + default: throw 'Unknown operator ' + attribute.operator + ' in selector'; + } + }); + } + + return conditions.join(' && '); + }, + + compileMatcher: function() { + this.match = new Function('element', 'if (!element.tagName) return false; \ + element = $(element); \ + return ' + this.buildMatchExpression()); + }, + + findElements: function(scope) { + var element; + + if (element = $(this.params.id)) + if (this.match(element)) + if (!scope || Element.childOf(element, scope)) + return [element]; + + scope = (scope || document).getElementsByTagName(this.params.tagName || '*'); + + var results = []; + for (var i = 0, length = scope.length; i < length; i++) + if (this.match(element = scope[i])) + results.push(Element.extend(element)); + + return results; + }, + + toString: function() { + return this.expression; + } +} + +Object.extend(Selector, { + matchElements: function(elements, expression) { + var selector = new Selector(expression); + return elements.select(selector.match.bind(selector)).map(Element.extend); + }, + + findElement: function(elements, expression, index) { + if (typeof expression == 'number') index = expression, expression = false; + return Selector.matchElements(elements, expression || '*')[index || 0]; + }, + + findChildElements: function(element, expressions) { + return expressions.map(function(expression) { + return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null], function(results, expr) { + var selector = new Selector(expr); + return results.inject([], function(elements, result) { + return elements.concat(selector.findElements(result || element)); + }); + }); + }).flatten(); + } +}); + +function $$() { + return Selector.findChildElements(document, $A(arguments)); +} +var Form = { + reset: function(form) { + $(form).reset(); + return form; + }, + + serializeElements: function(elements, getHash) { + var data = elements.inject({}, function(result, element) { + if (!element.disabled && element.name) { + var key = element.name, value = $(element).getValue(); + if (value != undefined) { + if (result[key]) { + if (result[key].constructor != Array) result[key] = [result[key]]; + result[key].push(value); + } + else result[key] = value; + } + } + return result; + }); + + return getHash ? data : Hash.toQueryString(data); + } +}; + +Form.Methods = { + serialize: function(form, getHash) { + return Form.serializeElements(Form.getElements(form), getHash); + }, + + getElements: function(form) { + return $A($(form).getElementsByTagName('*')).inject([], + function(elements, child) { + if (Form.Element.Serializers[child.tagName.toLowerCase()]) + elements.push(Element.extend(child)); + return elements; + } + ); + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) return $A(inputs).map(Element.extend); + + for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || (name && input.name != name)) + continue; + matchingInputs.push(Element.extend(input)); + } + + return matchingInputs; + }, + + disable: function(form) { + form = $(form); + form.getElements().each(function(element) { + element.blur(); + element.disabled = 'true'; + }); + return form; + }, + + enable: function(form) { + form = $(form); + form.getElements().each(function(element) { + element.disabled = ''; + }); + return form; + }, + + findFirstElement: function(form) { + return $(form).getElements().find(function(element) { + return element.type != 'hidden' && !element.disabled && + ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); + }); + }, + + focusFirstElement: function(form) { + form = $(form); + form.findFirstElement().activate(); + return form; + } +} + +Object.extend(Form, Form.Methods); + +/*--------------------------------------------------------------------------*/ + +Form.Element = { + focus: function(element) { + $(element).focus(); + return element; + }, + + select: function(element) { + $(element).select(); + return element; + } +} + +Form.Element.Methods = { + serialize: function(element) { + element = $(element); + if (!element.disabled && element.name) { + var value = element.getValue(); + if (value != undefined) { + var pair = {}; + pair[element.name] = value; + return Hash.toQueryString(pair); + } + } + return ''; + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + return Form.Element.Serializers[method](element); + }, + + clear: function(element) { + $(element).value = ''; + return element; + }, + + present: function(element) { + return $(element).value != ''; + }, + + activate: function(element) { + element = $(element); + element.focus(); + if (element.select && ( element.tagName.toLowerCase() != 'input' || + !['button', 'reset', 'submit'].include(element.type) ) ) + element.select(); + return element; + }, + + disable: function(element) { + element = $(element); + element.disabled = true; + return element; + }, + + enable: function(element) { + element = $(element); + element.blur(); + element.disabled = false; + return element; + } +} + +Object.extend(Form.Element, Form.Element.Methods); +var Field = Form.Element; +var $F = Form.Element.getValue; + +/*--------------------------------------------------------------------------*/ + +Form.Element.Serializers = { + input: function(element) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element); + default: + return Form.Element.Serializers.textarea(element); + } + }, + + inputSelector: function(element) { + return element.checked ? element.value : null; + }, + + textarea: function(element) { + return element.value; + }, + + select: function(element) { + return this[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + }, + + selectOne: function(element) { + var index = element.selectedIndex; + return index >= 0 ? this.optionValue(element.options[index]) : null; + }, + + selectMany: function(element) { + var values, length = element.length; + if (!length) return null; + + for (var i = 0, values = []; i < length; i++) { + var opt = element.options[i]; + if (opt.selected) values.push(this.optionValue(opt)); + } + return values; + }, + + optionValue: function(opt) { + // extend element because hasAttribute may not be native + return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; + } +} + +/*--------------------------------------------------------------------------*/ + +Abstract.TimedObserver = function() {} +Abstract.TimedObserver.prototype = { + initialize: function(element, frequency, callback) { + this.frequency = frequency; + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + this.registerCallback(); + }, + + registerCallback: function() { + setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + onTimerEvent: function() { + var value = this.getValue(); + var changed = ('string' == typeof this.lastValue && 'string' == typeof value + ? this.lastValue != value : String(this.lastValue) != String(value)); + if (changed) { + this.callback(this.element, value); + this.lastValue = value; + } + } +} + +Form.Element.Observer = Class.create(); +Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(); +Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = function() {} +Abstract.EventObserver.prototype = { + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + Form.getElements(this.element).each(this.registerCallback.bind(this)); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + default: + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +} + +Form.Element.EventObserver = Class.create(); +Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(); +Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); +if (!window.Event) { + var Event = new Object(); +} + +Object.extend(Event, { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + KEY_HOME: 36, + KEY_END: 35, + KEY_PAGEUP: 33, + KEY_PAGEDOWN: 34, + + element: function(event) { + return event.target || event.srcElement; + }, + + isLeftClick: function(event) { + return (((event.which) && (event.which == 1)) || + ((event.button) && (event.button == 1))); + }, + + pointerX: function(event) { + return event.pageX || (event.clientX + + (document.documentElement.scrollLeft || document.body.scrollLeft)); + }, + + pointerY: function(event) { + return event.pageY || (event.clientY + + (document.documentElement.scrollTop || document.body.scrollTop)); + }, + + stop: function(event) { + if (event.preventDefault) { + event.preventDefault(); + event.stopPropagation(); + } else { + event.returnValue = false; + event.cancelBubble = true; + } + }, + + // find the first node with the given tagName, starting from the + // node the event was triggered on; traverses the DOM upwards + findElement: function(event, tagName) { + var element = Event.element(event); + while (element.parentNode && (!element.tagName || + (element.tagName.toUpperCase() != tagName.toUpperCase()))) + element = element.parentNode; + return element; + }, + + observers: false, + + _observeAndCache: function(element, name, observer, useCapture) { + if (!this.observers) this.observers = []; + if (element.addEventListener) { + this.observers.push([element, name, observer, useCapture]); + element.addEventListener(name, observer, useCapture); + } else if (element.attachEvent) { + this.observers.push([element, name, observer, useCapture]); + element.attachEvent('on' + name, observer); + } + }, + + unloadCache: function() { + if (!Event.observers) return; + for (var i = 0, length = Event.observers.length; i < length; i++) { + Event.stopObserving.apply(this, Event.observers[i]); + Event.observers[i][0] = null; + } + Event.observers = false; + }, + + observe: function(element, name, observer, useCapture) { + element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) + || element.attachEvent)) + name = 'keydown'; + + Event._observeAndCache(element, name, observer, useCapture); + }, + + stopObserving: function(element, name, observer, useCapture) { + element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) + || element.detachEvent)) + name = 'keydown'; + + if (element.removeEventListener) { + element.removeEventListener(name, observer, useCapture); + } else if (element.detachEvent) { + try { + element.detachEvent('on' + name, observer); + } catch (e) {} + } + } +}); + +/* prevent memory leaks in IE */ +if (navigator.appVersion.match(/\bMSIE\b/)) + Event.observe(window, 'unload', Event.unloadCache, false); +var Position = { + // set to true if needed, warning: firefox performance problems + // NOT neeeded for page scrolling, only if draggable contained in + // scrollable elements + includeScrollOffsets: false, + + // must be called before calling withinIncludingScrolloffset, every time the + // page is scrolled + prepare: function() { + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft + || 0; + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop + || 0; + }, + + realOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return [valueL, valueT]; + }, + + cumulativeOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return [valueL, valueT]; + }, + + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + if(element.tagName=='BODY') break; + var p = Element.getStyle(element, 'position'); + if (p == 'relative' || p == 'absolute') break; + } + } while (element); + return [valueL, valueT]; + }, + + offsetParent: function(element) { + if (element.offsetParent) return element.offsetParent; + if (element == document.body) return element; + + while ((element = element.parentNode) && element != document.body) + if (Element.getStyle(element, 'position') != 'static') + return element; + + return document.body; + }, + + // caches x/y coordinate pair to use with overlap + within: function(element, x, y) { + if (this.includeScrollOffsets) + return this.withinIncludingScrolloffsets(element, x, y); + this.xcomp = x; + this.ycomp = y; + this.offset = this.cumulativeOffset(element); + + return (y >= this.offset[1] && + y < this.offset[1] + element.offsetHeight && + x >= this.offset[0] && + x < this.offset[0] + element.offsetWidth); + }, + + withinIncludingScrolloffsets: function(element, x, y) { + var offsetcache = this.realOffset(element); + + this.xcomp = x + offsetcache[0] - this.deltaX; + this.ycomp = y + offsetcache[1] - this.deltaY; + this.offset = this.cumulativeOffset(element); + + return (this.ycomp >= this.offset[1] && + this.ycomp < this.offset[1] + element.offsetHeight && + this.xcomp >= this.offset[0] && + this.xcomp < this.offset[0] + element.offsetWidth); + }, + + // within must be called directly before + overlap: function(mode, element) { + if (!mode) return 0; + if (mode == 'vertical') + return ((this.offset[1] + element.offsetHeight) - this.ycomp) / + element.offsetHeight; + if (mode == 'horizontal') + return ((this.offset[0] + element.offsetWidth) - this.xcomp) / + element.offsetWidth; + }, + + page: function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + // Safari fix + if (element.offsetParent==document.body) + if (Element.getStyle(element,'position')=='absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + if (!window.opera || element.tagName=='BODY') { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } + } while (element = element.parentNode); + + return [valueL, valueT]; + }, + + clone: function(source, target) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || {}) + + // find page position of source + source = $(source); + var p = Position.page(source); + + // find coordinate system to use + target = $(target); + var delta = [0, 0]; + var parent = null; + // delta [0,0] will do fine with position: fixed elements, + // position:absolute needs offsetParent deltas + if (Element.getStyle(target,'position') == 'absolute') { + parent = Position.offsetParent(target); + delta = Position.page(parent); + } + + // correct by body offsets (fixes Safari) + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + // set position + if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if(options.setWidth) target.style.width = source.offsetWidth + 'px'; + if(options.setHeight) target.style.height = source.offsetHeight + 'px'; + }, + + absolutize: function(element) { + element = $(element); + if (element.style.position == 'absolute') return; + Position.prepare(); + + var offsets = Position.positionedOffset(element); + var top = offsets[1]; + var left = offsets[0]; + var width = element.clientWidth; + var height = element.clientHeight; + + element._originalLeft = left - parseFloat(element.style.left || 0); + element._originalTop = top - parseFloat(element.style.top || 0); + element._originalWidth = element.style.width; + element._originalHeight = element.style.height; + + element.style.position = 'absolute'; + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.width = width + 'px'; + element.style.height = height + 'px'; + }, + + relativize: function(element) { + element = $(element); + if (element.style.position == 'relative') return; + Position.prepare(); + + element.style.position = 'relative'; + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); + var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.height = element._originalHeight; + element.style.width = element._originalWidth; + } +} + +// Safari returns margins on body which is incorrect if the child is absolutely +// positioned. For performance reasons, redefine Position.cumulativeOffset for +// KHTML/WebKit only. +if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { + Position.cumulativeOffset = function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return [valueL, valueT]; + } +} + +Element.addMethods(); \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/robots.txt b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/robots.txt new file mode 100644 index 00000000..4ab9e89f --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/robots.txt @@ -0,0 +1 @@ +# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/stylesheets/scaffold.css b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/stylesheets/scaffold.css new file mode 100644 index 00000000..8f239a35 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/stylesheets/scaffold.css @@ -0,0 +1,74 @@ +body { background-color: #fff; color: #333; } + +body, p, ol, ul, td { + font-family: verdana, arial, helvetica, sans-serif; + font-size: 13px; + line-height: 18px; +} + +pre { + background-color: #eee; + padding: 10px; + font-size: 11px; +} + +a { color: #000; } +a:visited { color: #666; } +a:hover { color: #fff; background-color:#000; } + +.fieldWithErrors { + padding: 2px; + background-color: red; + display: table; +} + +#errorExplanation { + width: 400px; + border: 2px solid red; + padding: 7px; + padding-bottom: 12px; + margin-bottom: 20px; + background-color: #f0f0f0; +} + +#errorExplanation h2 { + text-align: left; + font-weight: bold; + padding: 5px 5px 5px 15px; + font-size: 12px; + margin: -7px; + background-color: #c00; + color: #fff; +} + +#errorExplanation p { + color: #333; + margin-bottom: 0; + padding: 5px; +} + +#errorExplanation ul li { + font-size: 12px; + list-style: square; +} + +div.uploadStatus { + margin: 5px; +} + +div.progressBar { + margin: 5px; +} + +div.progressBar div.border { + background-color: #fff; + border: 1px solid grey; + width: 100%; +} + +div.progressBar div.background { + background-color: #333; + height: 18px; + width: 0%; +} + diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/about b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/about new file mode 100755 index 00000000..7b07d46a --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/about @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../config/boot' +require 'commands/about' \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/breakpointer b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/breakpointer new file mode 100755 index 00000000..64af76ed --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/breakpointer @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../config/boot' +require 'commands/breakpointer' \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/console b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/console new file mode 100755 index 00000000..42f28f7d --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/console @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../config/boot' +require 'commands/console' \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/destroy b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/destroy new file mode 100755 index 00000000..fa0e6fcd --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/destroy @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../config/boot' +require 'commands/destroy' \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/generate b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/generate new file mode 100755 index 00000000..ef976e09 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/generate @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../config/boot' +require 'commands/generate' \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/performance/benchmarker b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/performance/benchmarker new file mode 100755 index 00000000..c842d35d --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/performance/benchmarker @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../../config/boot' +require 'commands/performance/benchmarker' diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/performance/profiler b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/performance/profiler new file mode 100755 index 00000000..d855ac8b --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/performance/profiler @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../../config/boot' +require 'commands/performance/profiler' diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/plugin b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/plugin new file mode 100755 index 00000000..26ca64c0 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/plugin @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../config/boot' +require 'commands/plugin' \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/inspector b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/inspector new file mode 100755 index 00000000..bf25ad86 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/inspector @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../../config/boot' +require 'commands/process/inspector' diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/reaper b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/reaper new file mode 100755 index 00000000..c77f0453 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/reaper @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../../config/boot' +require 'commands/process/reaper' diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/spawner b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/spawner new file mode 100755 index 00000000..7118f398 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/spawner @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../../config/boot' +require 'commands/process/spawner' diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/runner b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/runner new file mode 100755 index 00000000..ccc30f9d --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/runner @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../config/boot' +require 'commands/runner' \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/server b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/server new file mode 100755 index 00000000..dfabcb88 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/server @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../config/boot' +require 'commands/server' \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/double_sti_parent_relationships.yml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/double_sti_parent_relationships.yml new file mode 100644 index 00000000..5bf02933 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/double_sti_parent_relationships.yml @@ -0,0 +1,7 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html + +# one: +# column: value +# +# two: +# column: value diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/double_sti_parents.yml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/double_sti_parents.yml new file mode 100644 index 00000000..5bf02933 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/double_sti_parents.yml @@ -0,0 +1,7 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html + +# one: +# column: value +# +# two: +# column: value diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/organic_substances.yml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/organic_substances.yml new file mode 100644 index 00000000..123ef537 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/organic_substances.yml @@ -0,0 +1,5 @@ +one: + type: Bone + +two: + type: Bone diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/single_sti_parent_relationships.yml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/single_sti_parent_relationships.yml new file mode 100644 index 00000000..5bf02933 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/single_sti_parent_relationships.yml @@ -0,0 +1,7 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html + +# one: +# column: value +# +# two: +# column: value diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/single_sti_parents.yml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/single_sti_parents.yml new file mode 100644 index 00000000..5bf02933 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/single_sti_parents.yml @@ -0,0 +1,7 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html + +# one: +# column: value +# +# two: +# column: value diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/sticks.yml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/sticks.yml new file mode 100644 index 00000000..157d7472 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/sticks.yml @@ -0,0 +1,7 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html + +one: + name: MyString + +two: + name: MyString diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/stones.yml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/stones.yml new file mode 100644 index 00000000..157d7472 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/stones.yml @@ -0,0 +1,7 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html + +one: + name: MyString + +two: + name: MyString diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/addresses_controller_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/addresses_controller_test.rb new file mode 100644 index 00000000..65284b5b --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/addresses_controller_test.rb @@ -0,0 +1,57 @@ +require File.dirname(__FILE__) + '/../test_helper' +require 'addresses_controller' + +# Re-raise errors caught by the controller. +class AddressesController; def rescue_action(e) raise e end; end + +class AddressesControllerTest < Test::Unit::TestCase + fixtures :addresses + + def setup + @controller = AddressesController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + def test_should_get_index + get :index + assert_response :success + assert assigns(:addresses) + end + + def test_should_get_new + get :new + assert_response :success + end + + def test_should_create_address + assert_difference('Address.count') do + post :create, :address => { :country_id => 1, :user_id => 1, :state_id => 1} + end + + assert_redirected_to address_path(assigns(:address)) + end + + def test_should_show_address + get :show, :id => 1 + assert_response :success + end + + def test_should_get_edit + get :edit, :id => 1 + assert_response :success + end + + def test_should_update_address + put :update, :id => 1, :address => { } + assert_redirected_to address_path(assigns(:address)) + end + + def test_should_destroy_address + assert_difference('Address.count', -1) do + delete :destroy, :id => 1 + end + + assert_redirected_to addresses_path + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/bones_controller_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/bones_controller_test.rb new file mode 100644 index 00000000..fc0c7bd8 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/bones_controller_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class BonesControllerTest < ActionController::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/sellers_controller_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/sellers_controller_test.rb new file mode 100644 index 00000000..fb992e5d --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/sellers_controller_test.rb @@ -0,0 +1,57 @@ +require File.dirname(__FILE__) + '/../test_helper' +require 'sellers_controller' + +# Re-raise errors caught by the controller. +class SellersController; def rescue_action(e) raise e end; end + +class SellersControllerTest < Test::Unit::TestCase + fixtures :sellers + + def setup + @controller = SellersController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + def test_should_get_index + get :index + assert_response :success + assert assigns(:sellers) + end + + def test_should_get_new + get :new + assert_response :success + end + + def test_should_create_seller + assert_difference('Seller.count') do + post :create, :seller => { } + end + + assert_redirected_to seller_path(assigns(:seller)) + end + + def test_should_show_seller + get :show, :id => 1 + assert_response :success + end + + def test_should_get_edit + get :edit, :id => 1 + assert_response :success + end + + def test_should_update_seller + put :update, :id => 1, :seller => { } + assert_redirected_to seller_path(assigns(:seller)) + end + + def test_should_destroy_seller + assert_difference('Seller.count', -1) do + delete :destroy, :id => 1 + end + + assert_redirected_to sellers_path + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/states_controller_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/states_controller_test.rb new file mode 100644 index 00000000..2e93453b --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/states_controller_test.rb @@ -0,0 +1,57 @@ +require File.dirname(__FILE__) + '/../test_helper' +require 'states_controller' + +# Re-raise errors caught by the controller. +class StatesController; def rescue_action(e) raise e end; end + +class StatesControllerTest < Test::Unit::TestCase + fixtures :states + + def setup + @controller = StatesController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + def test_should_get_index + get :index + assert_response :success + assert assigns(:states) + end + + def test_should_get_new + get :new + assert_response :success + end + + def test_should_create_state + assert_difference('State.count') do + post :create, :state => { } + end + + assert_redirected_to state_path(assigns(:state)) + end + + def test_should_show_state + get :show, :id => 1 + assert_response :success + end + + def test_should_get_edit + get :edit, :id => 1 + assert_response :success + end + + def test_should_update_state + put :update, :id => 1, :state => { } + assert_redirected_to state_path(assigns(:state)) + end + + def test_should_destroy_state + assert_difference('State.count', -1) do + delete :destroy, :id => 1 + end + + assert_redirected_to states_path + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/users_controller_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/users_controller_test.rb new file mode 100644 index 00000000..bc36751f --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/users_controller_test.rb @@ -0,0 +1,57 @@ +require File.dirname(__FILE__) + '/../test_helper' +require 'users_controller' + +# Re-raise errors caught by the controller. +class UsersController; def rescue_action(e) raise e end; end + +class UsersControllerTest < Test::Unit::TestCase + fixtures :users + + def setup + @controller = UsersController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + def test_should_get_index + get :index + assert_response :success + assert assigns(:users) + end + + def test_should_get_new + get :new + assert_response :success + end + + def test_should_create_user + assert_difference('User.count') do + post :create, :user => { } + end + + assert_redirected_to user_path(assigns(:user)) + end + + def test_should_show_user + get :show, :id => 1 + assert_response :success + end + + def test_should_get_edit + get :edit, :id => 1 + assert_response :success + end + + def test_should_update_user + put :update, :id => 1, :user => { } + assert_redirected_to user_path(assigns(:user)) + end + + def test_should_destroy_user + assert_difference('User.count', -1) do + delete :destroy, :id => 1 + end + + assert_redirected_to users_path + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/test_helper.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/test_helper.rb new file mode 100644 index 00000000..773c49de --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/test_helper.rb @@ -0,0 +1,8 @@ +ENV["RAILS_ENV"] = "development" +require File.expand_path(File.dirname(__FILE__) + "/../config/environment") +require 'test_help' + +class Test::Unit::TestCase + self.use_transactional_fixtures = true + self.use_instantiated_fixtures = false +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/bone_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/bone_test.rb new file mode 100644 index 00000000..8afcb87b --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/bone_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class BoneTest < Test::Unit::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/double_sti_parent_relationship_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/double_sti_parent_relationship_test.rb new file mode 100644 index 00000000..dc20e74d --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/double_sti_parent_relationship_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class DoubleStiParentRelationshipTest < Test::Unit::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/double_sti_parent_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/double_sti_parent_test.rb new file mode 100644 index 00000000..154383a2 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/double_sti_parent_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class DoubleStiParentTest < Test::Unit::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/organic_substance_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/organic_substance_test.rb new file mode 100644 index 00000000..af328b95 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/organic_substance_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class OrganicSubstanceTest < Test::Unit::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/single_sti_parent_relationship_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/single_sti_parent_relationship_test.rb new file mode 100644 index 00000000..d5563fd8 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/single_sti_parent_relationship_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class SingleStiParentRelationshipTest < Test::Unit::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/single_sti_parent_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/single_sti_parent_test.rb new file mode 100644 index 00000000..70a00ecb --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/single_sti_parent_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class SingleStiParentTest < Test::Unit::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/stick_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/stick_test.rb new file mode 100644 index 00000000..6729e0d6 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/stick_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class StickTest < Test::Unit::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/stone_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/stone_test.rb new file mode 100644 index 00000000..76b518d7 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/stone_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class StoneTest < Test::Unit::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/server_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/server_test.rb new file mode 100644 index 00000000..e53ea1aa --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/integration/server_test.rb @@ -0,0 +1,43 @@ + +require "#{File.dirname(__FILE__)}/../test_helper" +require 'open-uri' + +# Start the server + +class ServerTest < Test::Unit::TestCase + + PORT = 43040 + URL = "http://localhost:#{PORT}/" + + def setup + @pid = Process.fork do + Dir.chdir RAILS_ROOT do + # print "S" + exec("script/server -p #{PORT} &> #{LOG}") + end + end + sleep(5) + end + + def teardown + # Process.kill(9, @pid) doesn't work because Mongrel has double-forked itself away + `ps awx | grep #{PORT} | grep -v grep | awk '{print $1}'`.split("\n").each do |pid| + system("kill -9 #{pid}") + # print "K" + end + sleep(2) + @pid = nil + end + + def test_association_reloading + assert_match(/Bones: index/, open(URL + 'bones').read) + assert_match(/Bones: index/, open(URL + 'bones').read) + assert_match(/Bones: index/, open(URL + 'bones').read) + assert_match(/Bones: index/, open(URL + 'bones').read) + end + + def test_verify_autoload_gets_invoked_in_console + # XXX Probably can use script/runner to test this + end + +end \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/fish.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/fish.rb new file mode 100644 index 00000000..204642e9 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/fish.rb @@ -0,0 +1,5 @@ +class Aquatic::Fish < ActiveRecord::Base + # set_table_name "fish" + # attr_accessor :after_find_test, :after_initialize_test +end + diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/pupils_whale.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/pupils_whale.rb new file mode 100644 index 00000000..ae4cbc18 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/pupils_whale.rb @@ -0,0 +1,7 @@ + +class Aquatic::PupilsWhale < ActiveRecord::Base + set_table_name "little_whale_pupils" + belongs_to :whale, :class_name => "Aquatic::Whale", :foreign_key => "whale_id" + belongs_to :aquatic_pupil, :polymorphic => true +end + diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/whale.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/whale.rb new file mode 100644 index 00000000..0ca1b7fb --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/whale.rb @@ -0,0 +1,15 @@ +# see http://dev.rubyonrails.org/ticket/5935 +module Aquatic; end +require 'aquatic/fish' +require 'aquatic/pupils_whale' + +class Aquatic::Whale < ActiveRecord::Base + # set_table_name "whales" + + has_many_polymorphs(:aquatic_pupils, :from => [:dogs, :"aquatic/fish"], + :through => "aquatic/pupils_whales") do + def a_method + :correct_block_result + end + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/beautiful_fight_relationship.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/beautiful_fight_relationship.rb new file mode 100644 index 00000000..b678c982 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/models/beautiful_fight_relationship.rb @@ -0,0 +1,26 @@ + +require 'extension_module' + +class BeautifulFightRelationship < ActiveRecord::Base + set_table_name 'keep_your_enemies_close' + + belongs_to :enemy, :polymorphic => true + belongs_to :protector, :polymorphic => true + # polymorphic relationships with column names different from the relationship name + # are not supported by Rails + + acts_as_double_polymorphic_join :enemies => [:dogs, :kittens, :frogs], + :protectors => [:wild_boars, :kittens, :"aquatic/fish", :dogs], + :enemies_extend => [ExtensionModule, proc {}], + :protectors_extend => proc { + def a_method + :correct_proc_result + end + }, + :join_extend => proc { + def a_method + :correct_join_result + end + } +end + diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/canine.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/canine.rb new file mode 100644 index 00000000..b0010160 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/models/canine.rb @@ -0,0 +1,9 @@ +class Canine < ActiveRecord::Base + self.abstract_class = true + + def an_abstract_method + :correct_abstract_method_response + end + +end + diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/cat.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/cat.rb new file mode 100644 index 00000000..0c99ff08 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/models/cat.rb @@ -0,0 +1,5 @@ +class Cat < ActiveRecord::Base + # STI base class + self.inheritance_column = 'cat_type' +end + diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/dog.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/dog.rb new file mode 100644 index 00000000..7f027237 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/models/dog.rb @@ -0,0 +1,18 @@ + +require 'canine' + +class Dog < Canine + attr_accessor :after_find_test, :after_initialize_test + set_table_name "bow_wows" + + def after_find + @after_find_test = true +# puts "After find called on #{name}." + end + + def after_initialize + @after_initialize_test = true + end + +end + diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/eaters_foodstuff.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/eaters_foodstuff.rb new file mode 100644 index 00000000..d904bb16 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/models/eaters_foodstuff.rb @@ -0,0 +1,10 @@ + +class EatersFoodstuff < ActiveRecord::Base + belongs_to :foodstuff, :class_name => "Petfood", :foreign_key => "foodstuff_id" + belongs_to :eater, :polymorphic => true + + def before_save + self.some_attribute = 3 + end +end + diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/frog.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/frog.rb new file mode 100644 index 00000000..5a0f4658 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/models/frog.rb @@ -0,0 +1,4 @@ +class Frog < ActiveRecord::Base + +end + diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/kitten.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/kitten.rb new file mode 100644 index 00000000..2a244c03 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/models/kitten.rb @@ -0,0 +1,3 @@ +class Kitten < Cat +# has_many :eaters_parents, :dependent => true, :as => 'eater' +end \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/parentship.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/parentship.rb new file mode 100644 index 00000000..e87b759b --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/models/parentship.rb @@ -0,0 +1,4 @@ +class Parentship < ActiveRecord::Base + belongs_to :parent, :class_name => "Person", :foreign_key => "parent_id" + belongs_to :kid, :polymorphic => true, :foreign_type => "child_type" +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/person.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/person.rb new file mode 100644 index 00000000..5d019829 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/models/person.rb @@ -0,0 +1,9 @@ +require 'parentship' +class Person < ActiveRecord::Base + has_many_polymorphs :kids, + :through => :parentships, + :from => [:people], + :as => :parent, + :polymorphic_type_key => "child_type", + :conditions => "people.age < 10" +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/petfood.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/petfood.rb new file mode 100644 index 00000000..df420ea8 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/models/petfood.rb @@ -0,0 +1,39 @@ +# see http://dev.rubyonrails.org/ticket/5935 +require 'eaters_foodstuff' +require 'petfood' +require 'cat' +module Aquatic; end +require 'aquatic/fish' +require 'dog' +require 'wild_boar' +require 'kitten' +require 'tabby' +require 'extension_module' +require 'other_extension_module' + +class Petfood < ActiveRecord::Base + set_primary_key 'the_petfood_primary_key' + has_many_polymorphs :eaters, + :from => [:dogs, :petfoods, :wild_boars, :kittens, + :tabbies, :"aquatic/fish"], +# :dependent => :destroy, :destroy is now the default + :rename_individual_collections => true, + :as => :foodstuff, + :foreign_key => "foodstuff_id", + :ignore_duplicates => false, + :conditions => "NULL IS NULL", + :order => "eaters_foodstuffs.updated_at ASC", + :parent_order => "petfoods.the_petfood_primary_key DESC", + :parent_conditions => "petfoods.name IS NULL OR petfoods.name != 'Snausages'", + :extend => [ExtensionModule, OtherExtensionModule, proc {}], + :join_extend => proc { + def a_method + :correct_join_result + end + }, + :parent_extend => proc { + def a_method + :correct_parent_proc_result + end + } + end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/tabby.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/tabby.rb new file mode 100644 index 00000000..3cd0f994 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/models/tabby.rb @@ -0,0 +1,2 @@ +class Tabby < Cat +end \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/wild_boar.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/wild_boar.rb new file mode 100644 index 00000000..27d36a53 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/models/wild_boar.rb @@ -0,0 +1,3 @@ +class WildBoar < ActiveRecord::Base +end + diff --git a/vendor/gems/has_many_polymorphs-2.13/test/modules/extension_module.rb b/vendor/gems/has_many_polymorphs-2.13/test/modules/extension_module.rb new file mode 100644 index 00000000..7cb4eff4 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/modules/extension_module.rb @@ -0,0 +1,9 @@ + +module ExtensionModule + def a_method + :correct_module_result + end + def self.a_method + :incorrect_module_result + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/modules/other_extension_module.rb b/vendor/gems/has_many_polymorphs-2.13/test/modules/other_extension_module.rb new file mode 100644 index 00000000..16313bd8 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/modules/other_extension_module.rb @@ -0,0 +1,9 @@ + +module OtherExtensionModule + def another_method + :correct_other_module_result + end + def self.another_method + :incorrect_other_module_result + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/patches/symlinked_plugins_1.2.6.diff b/vendor/gems/has_many_polymorphs-2.13/test/patches/symlinked_plugins_1.2.6.diff new file mode 100644 index 00000000..99e0df3e --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/patches/symlinked_plugins_1.2.6.diff @@ -0,0 +1,46 @@ +Index: /trunk/railties/lib/rails_generator/lookup.rb +=================================================================== +--- /trunk/railties/lib/rails_generator/lookup.rb (revision 4310) ++++ /trunk/railties/lib/rails_generator/lookup.rb (revision 6101) +@@ -101,5 +101,5 @@ + sources << PathSource.new(:lib, "#{::RAILS_ROOT}/lib/generators") + sources << PathSource.new(:vendor, "#{::RAILS_ROOT}/vendor/generators") +- sources << PathSource.new(:plugins, "#{::RAILS_ROOT}/vendor/plugins/**/generators") ++ sources << PathSource.new(:plugins, "#{::RAILS_ROOT}/vendor/plugins/*/**/generators") + end + sources << PathSource.new(:user, "#{Dir.user_home}/.rails/generators") +Index: /trunk/railties/lib/tasks/rails.rb +=================================================================== +--- /trunk/railties/lib/tasks/rails.rb (revision 5469) ++++ /trunk/railties/lib/tasks/rails.rb (revision 6101) +@@ -6,3 +6,3 @@ + # Load any custom rakefile extensions + Dir["#{RAILS_ROOT}/lib/tasks/**/*.rake"].sort.each { |ext| load ext } +-Dir["#{RAILS_ROOT}/vendor/plugins/**/tasks/**/*.rake"].sort.each { |ext| load ext } ++Dir["#{RAILS_ROOT}/vendor/plugins/*/**/tasks/**/*.rake"].sort.each { |ext| load ext } +Index: /trunk/railties/lib/tasks/testing.rake +=================================================================== +--- /trunk/railties/lib/tasks/testing.rake (revision 5263) ++++ /trunk/railties/lib/tasks/testing.rake (revision 6101) +@@ -109,9 +109,9 @@ + t.pattern = "vendor/plugins/#{ENV['PLUGIN']}/test/**/*_test.rb" + else +- t.pattern = 'vendor/plugins/**/test/**/*_test.rb' ++ t.pattern = 'vendor/plugins/*/**/test/**/*_test.rb' + end + + t.verbose = true + end +- Rake::Task['test:plugins'].comment = "Run the plugin tests in vendor/plugins/**/test (or specify with PLUGIN=name)" ++ Rake::Task['test:plugins'].comment = "Run the plugin tests in vendor/plugins/*/**/test (or specify with PLUGIN=name)" + end +Index: /trunk/railties/CHANGELOG +=================================================================== +--- /trunk/railties/CHANGELOG (revision 6069) ++++ /trunk/railties/CHANGELOG (revision 6101) +@@ -1,3 +1,5 @@ + *SVN* ++ ++* Plugins may be symlinked in vendor/plugins. #4245 [brandon, progrium@gmail.com] + + * Resource generator depends on the model generator rather than duplicating it. #7269 [bscofield] diff --git a/vendor/gems/has_many_polymorphs-2.13/test/schema.rb b/vendor/gems/has_many_polymorphs-2.13/test/schema.rb new file mode 100644 index 00000000..39d869dc --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/schema.rb @@ -0,0 +1,87 @@ +ActiveRecord::Schema.define(:version => 0) do + create_table :petfoods, :force => true, :primary_key => :the_petfood_primary_key do |t| + t.column :name, :string + t.column :created_at, :datetime, :null => false + t.column :updated_at, :datetime, :null => false + end + + create_table :bow_wows, :force => true do |t| + t.column :name, :string + t.column :created_at, :datetime, :null => false + t.column :updated_at, :datetime, :null => false + end + + create_table :cats, :force => true do |t| + t.column :name, :string + t.column :cat_type, :string + t.column :created_at, :datetime, :null => false + t.column :updated_at, :datetime, :null => false + end + + create_table :frogs, :force => true do |t| + t.column :name, :string + t.column :created_at, :datetime, :null => false + t.column :updated_at, :datetime, :null => false + end + + create_table :wild_boars, :force => true do |t| + t.column :name, :string + t.column :created_at, :datetime, :null => false + t.column :updated_at, :datetime, :null => false + end + + create_table :eaters_foodstuffs, :force => true do |t| + t.column :foodstuff_id, :integer + t.column :eater_id, :integer + t.column :some_attribute, :integer, :default => 0 + t.column :eater_type, :string + t.column :created_at, :datetime, :null => false + t.column :updated_at, :datetime, :null => false + end + + create_table :fish, :force => true do |t| + t.column :name, :string + t.column :speed, :integer + t.column :created_at, :datetime, :null => false + t.column :updated_at, :datetime, :null => false + end + + create_table :whales, :force => true do |t| + t.column :name, :string + t.column :created_at, :datetime, :null => false + t.column :updated_at, :datetime, :null => false + end + + create_table :little_whale_pupils, :force => true do |t| + t.column :whale_id, :integer + t.column :aquatic_pupil_id, :integer + t.column :aquatic_pupil_type, :string + t.column :created_at, :datetime, :null => false + t.column :updated_at, :datetime, :null => false + end + + create_table :keep_your_enemies_close, :force => true do |t| + t.column :enemy_id, :integer + t.column :enemy_type, :string + t.column :protector_id, :integer + t.column :protector_type, :string + t.column :created_at, :datetime, :null => false + t.column :updated_at, :datetime, :null => false + end + + create_table :parentships, :force => true do |t| + t.column :parent_id, :integer + t.column :child_type, :string + t.column :kid_id, :integer + t.column :created_at, :datetime, :null => false + t.column :updated_at, :datetime, :null => false + end + + create_table :people, :force => true do |t| + t.column :name, :string + t.column :age, :integer + t.column :created_at, :datetime, :null => false + t.column :updated_at, :datetime, :null => false + end + +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/setup.rb b/vendor/gems/has_many_polymorphs-2.13/test/setup.rb new file mode 100644 index 00000000..52535798 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/setup.rb @@ -0,0 +1,14 @@ + +# Setup integration system for the integration suite + +Dir.chdir "#{File.dirname(__FILE__)}/integration/app/" do + Dir.chdir "vendor/plugins" do + system("rm has_many_polymorphs; ln -s ../../../../../ has_many_polymorphs") + end + + system "rake db:drop --trace RAILS_GEM_VERSION=2.2.2 " + system "rake db:create --trace RAILS_GEM_VERSION=2.2.2 " + system "rake db:migrate --trace" + system "rake db:fixtures:load --trace" +end + diff --git a/vendor/gems/has_many_polymorphs-2.13/test/test_helper.rb b/vendor/gems/has_many_polymorphs-2.13/test/test_helper.rb new file mode 100644 index 00000000..363a6607 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/test_helper.rb @@ -0,0 +1,51 @@ + +$VERBOSE = nil +require 'rubygems' +require 'echoe' +require 'test/unit' +require 'multi_rails_init' +require 'ruby-debug' + +if defined? ENV['MULTIRAILS_RAILS_VERSION'] + ENV['RAILS_GEM_VERSION'] = ENV['MULTIRAILS_RAILS_VERSION'] +end + +Echoe.silence do + HERE = File.expand_path(File.dirname(__FILE__)) + $LOAD_PATH << HERE + # $LOAD_PATH << "#{HERE}/integration/app" +end + +LOG = "#{HERE}/integration/app/log/development.log" + +### For unit tests + +require 'integration/app/config/environment' +require 'test_help' + +ActiveSupport::Inflector.inflections {|i| i.irregular 'fish', 'fish' } + +$LOAD_PATH.unshift(Test::Unit::TestCase.fixture_path = HERE + "/fixtures") +$LOAD_PATH.unshift(HERE + "/models") +$LOAD_PATH.unshift(HERE + "/modules") + +class Test::Unit::TestCase + self.use_transactional_fixtures = !(ActiveRecord::Base.connection.is_a? ActiveRecord::ConnectionAdapters::MysqlAdapter rescue false) + self.use_instantiated_fixtures = false +end + +Echoe.silence do + load(HERE + "/schema.rb") +end + +### For integration tests + +def truncate + system("> #{LOG}") +end + +def log + File.open(LOG, 'r') do |f| + f.read + end +end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/unit/has_many_polymorphs_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/unit/has_many_polymorphs_test.rb new file mode 100644 index 00000000..7f4b05a4 --- /dev/null +++ b/vendor/gems/has_many_polymorphs-2.13/test/unit/has_many_polymorphs_test.rb @@ -0,0 +1,714 @@ +require File.dirname(__FILE__) + '/../test_helper' + +require 'dog' +require 'wild_boar' +require 'frog' +require 'cat' +require 'kitten' +require 'aquatic/whale' +require 'aquatic/fish' +require 'aquatic/pupils_whale' +require 'beautiful_fight_relationship' + +class PolymorphTest < Test::Unit::TestCase + + set_fixture_class :bow_wows => Dog + set_fixture_class :keep_your_enemies_close => BeautifulFightRelationship + set_fixture_class :whales => Aquatic::Whale + set_fixture_class :fish => Aquatic::Fish + set_fixture_class :little_whale_pupils => Aquatic::PupilsWhale + + fixtures :cats, :bow_wows, :frogs, :wild_boars, :eaters_foodstuffs, :petfoods, + :fish, :whales, :little_whale_pupils, :keep_your_enemies_close, :people + + def setup + @association_error = ActiveRecord::Associations::PolymorphicError + @kibbles = Petfood.find(1) + @bits = Petfood.find(2) + @shamu = Aquatic::Whale.find(1) + @swimmy = Aquatic::Fish.find(1) + @rover = Dog.find(1) + @spot = Dog.find(2) + @puma = WildBoar.find(1) + @chloe = Kitten.find(1) + @alice = Kitten.find(2) + @toby = Tabby.find(3) + @froggy = Frog.find(1) + + @join_count = EatersFoodstuff.count + @kibbles_eaters_count = @kibbles.eaters.size + @bits_eaters_count = @bits.eaters.size + + @double_join_count = BeautifulFightRelationship.count + @alice_enemies_count = @alice.enemies.size + end + + def test_all_relationship_validities + # q = [] + # ObjectSpace.each_object(Class){|c| q << c if c.ancestors.include? ActiveRecord::Base } + # q.each{|c| puts "#{c.name}.reflect_on_all_associations.map(&:check_validity!)"} + Petfood.reflect_on_all_associations.map(&:check_validity!) + Tabby.reflect_on_all_associations.map(&:check_validity!) + Kitten.reflect_on_all_associations.map(&:check_validity!) + Dog.reflect_on_all_associations.map(&:check_validity!) + Canine.reflect_on_all_associations.map(&:check_validity!) + Aquatic::Fish.reflect_on_all_associations.map(&:check_validity!) + EatersFoodstuff.reflect_on_all_associations.map(&:check_validity!) + WildBoar.reflect_on_all_associations.map(&:check_validity!) + Frog.reflect_on_all_associations.map(&:check_validity!) + Cat.reflect_on_all_associations.map(&:check_validity!) + BeautifulFightRelationship.reflect_on_all_associations.map(&:check_validity!) + Person.reflect_on_all_associations.map(&:check_validity!) + Parentship.reflect_on_all_associations.map(&:check_validity!) + Aquatic::Whale.reflect_on_all_associations.map(&:check_validity!) + Aquatic::PupilsWhale.reflect_on_all_associations.map(&:check_validity!) + end + + def test_assignment + assert @kibbles.eaters.blank? + assert @kibbles.eaters.push(Cat.find_by_name('Chloe')) + assert_equal @kibbles_eaters_count += 1, @kibbles.eaters.count + + @kibbles.reload + assert_equal @kibbles_eaters_count, @kibbles.eaters.count + end + + def test_duplicate_assignment + # try to add a duplicate item when :ignore_duplicates is false + @kibbles.eaters.push(@alice) + assert @kibbles.eaters.include?(@alice) + @kibbles.eaters.push(@alice) + assert_equal @kibbles_eaters_count + 2, @kibbles.eaters.count + assert_equal @join_count + 2, EatersFoodstuff.count + end + + def test_create_and_push + assert @kibbles.eaters.push(@spot) + assert_equal @kibbles_eaters_count += 1, @kibbles.eaters.count + assert @kibbles.eaters << @rover + assert @kibbles.eaters << Kitten.create(:name => "Miranda") + assert_equal @kibbles_eaters_count += 2, @kibbles.eaters.length + + @kibbles.reload + assert_equal @kibbles_eaters_count, @kibbles.eaters.length + + # test that ids and new flags were set appropriately + assert_not_nil @kibbles.eaters[0].id + assert !@kibbles.eaters[1].new_record? + end + + def test_reload + assert @kibbles.reload + assert @kibbles.eaters.reload + end + + def test_add_join_record + assert_equal Kitten, @chloe.class + assert join = EatersFoodstuff.new(:foodstuff_id => @bits.id, :eater_id => @chloe.id, :eater_type => @chloe.class.name ) + assert join.save! + assert join.id + assert_equal @join_count + 1, EatersFoodstuff.count + + #assert_equal @bits_eaters_count, @bits.eaters.size # Doesn't behave this way on latest edge anymore + assert_equal @bits_eaters_count + 1, @bits.eaters.count # SQL + + # reload; is the new association there? + assert @bits.eaters.reload + assert @bits.eaters.include?(@chloe) + end + + def test_build_join_record_on_association + assert_equal Kitten, @chloe.class + assert join = @chloe.eaters_foodstuffs.build(:foodstuff => @bits) + # assert_equal join.eater_type, @chloe.class.name # will be STI parent type + assert join.save! + assert join.id + assert_equal @join_count + 1, EatersFoodstuff.count + + assert @bits.eaters.reload + assert @bits.eaters.include?(@chloe) + end + +# not supporting this, since has_many :through doesn't support it either +# def test_add_unsaved +# # add an unsaved item +# assert @bits.eaters << Kitten.new(:name => "Bridget") +# assert_nil Kitten.find_by_name("Bridget") +# assert_equal @bits_eaters_count + 1, @bits.eaters.count +# +# assert @bits.save +# @bits.reload +# assert_equal @bits_eaters_count + 1, @bits.eaters.count +# +# end + + def test_self_reference + assert @kibbles.eaters << @bits + assert_equal @kibbles_eaters_count += 1, @kibbles.eaters.count + assert @kibbles.eaters.include?(@bits) + @kibbles.reload + assert @kibbles.foodstuffs_of_eaters.blank? + + @bits.reload + assert @bits.foodstuffs_of_eaters.include?(@kibbles) + assert_equal [@kibbles], @bits.foodstuffs_of_eaters + end + + def test_remove + assert @kibbles.eaters << @chloe + @kibbles.reload + assert @kibbles.eaters.delete(@kibbles.eaters[0]) + assert_equal @kibbles_eaters_count, @kibbles.eaters.count + end + + def test_destroy + assert @kibbles.eaters.push(@chloe) + @kibbles.reload + assert @kibbles.eaters.length > 0 + assert @kibbles.eaters[0].destroy + @kibbles.reload + assert_equal @kibbles_eaters_count, @kibbles.eaters.count + end + + def test_clear + @kibbles.eaters << [@chloe, @spot, @rover] + @kibbles.reload + assert @kibbles.eaters.clear.blank? + assert @kibbles.eaters.blank? + @kibbles.reload + assert @kibbles.eaters.blank? + end + + def test_individual_collections + assert @kibbles.eaters.push(@chloe) + # check if individual collections work + assert_equal @kibbles.eater_kittens.length, 1 + assert @kibbles.eater_dogs + assert 1, @rover.eaters_foodstuffs.count + end + + def test_individual_collections_push + assert_equal [@chloe], (@kibbles.eater_kittens << @chloe) + @kibbles.reload + assert @kibbles.eaters.include?(@chloe) + assert @kibbles.eater_kittens.include?(@chloe) + assert !@kibbles.eater_dogs.include?(@chloe) + end + + def test_individual_collections_delete + @kibbles.eaters << [@chloe, @spot, @rover] + @kibbles.reload + assert_equal [@chloe], @kibbles.eater_kittens.delete(@chloe) + assert @kibbles.eater_kittens.empty? + @kibbles.eater_kittens.delete(@chloe) # what should this return? + + @kibbles.reload + assert @kibbles.eater_kittens.empty? + assert @kibbles.eater_dogs.include?(@spot) + end + + def test_individual_collections_clear + @kibbles.eaters << [@chloe, @spot, @rover] + @kibbles.reload + + assert_equal [], @kibbles.eater_kittens.clear + assert @kibbles.eater_kittens.empty? + assert_equal 2, @kibbles.eaters.size + + assert @kibbles.eater_kittens.empty? + assert_equal 2, @kibbles.eaters.size + assert !@kibbles.eater_kittens.include?(@chloe) + assert !@kibbles.eaters.include?(@chloe) + + @kibbles.reload + assert @kibbles.eater_kittens.empty? + assert_equal 2, @kibbles.eaters.size + assert !@kibbles.eater_kittens.include?(@chloe) + assert !@kibbles.eaters.include?(@chloe) + end + + def test_childrens_individual_collections + assert Cat.find_by_name('Chloe').eaters_foodstuffs + assert @kibbles.eaters_foodstuffs + end + + def test_self_referential_join_tables + # check that the self-reference join tables go the right ways + assert_equal @kibbles_eaters_count, @kibbles.eaters_foodstuffs.count + assert_equal @kibbles.eaters_foodstuffs.count, @kibbles.eaters_foodstuffs_as_child.count + end + + def test_dependent + assert @kibbles.eaters << @chloe + @kibbles.reload + + # delete ourself and see if :dependent was obeyed + dependent_rows = @kibbles.eaters_foodstuffs + assert_equal dependent_rows.length, @kibbles.eaters.count + @join_count = EatersFoodstuff.count + + @kibbles.destroy + assert_equal @join_count - dependent_rows.length, EatersFoodstuff.count + assert_equal 0, EatersFoodstuff.find(:all, :conditions => ['foodstuff_id = ?', 1] ).length + end + + def test_normal_callbacks + assert @rover.respond_to?(:after_initialize) + assert @rover.respond_to?(:after_find) + assert @rover.after_initialize_test + assert @rover.after_find_test + end + + def test_model_callbacks_not_overridden_by_plugin_callbacks + assert 0, @bits.eaters.count + assert @bits.eaters.push(@rover) + @bits.save + @bits2 = Petfood.find_by_name("Bits") + @bits.reload + assert rover = @bits2.eaters.select { |x| x.name == "Rover" }[0] + assert rover.after_initialize_test + assert rover.after_find_test + end + + def test_number_of_join_records + assert EatersFoodstuff.create(:foodstuff_id => 1, :eater_id => 1, :eater_type => "Cat") + @join_count = EatersFoodstuff.count + assert @join_count > 0 + end + + def test_number_of_regular_records + dogs = Dog.count + assert Dog.new(:name => "Auggie").save! + assert dogs + 1, Dog.count + end + + def test_attributes_come_through_when_child_has_underscore_in_table_name + join = EatersFoodstuff.new(:foodstuff_id => @bits.id, :eater_id => @puma.id, :eater_type => @puma.class.name) + join.save! + + @bits.eaters.reload + + assert_equal "Puma", @puma.name + assert_equal "Puma", @bits.eaters.first.name + end + + + def test_before_save_on_join_table_is_not_clobbered_by_sti_base_class_fix + assert @kibbles.eaters << @chloe + assert_equal 3, @kibbles.eaters_foodstuffs.first.some_attribute + end + + def test_sti_type_counts_are_correct + @kibbles.eaters << [@chloe, @alice, @toby] + assert_equal 2, @kibbles.eater_kittens.count + assert_equal 1, @kibbles.eater_tabbies.count + assert !@kibbles.respond_to?(:eater_cats) + end + + + def test_creating_namespaced_relationship + assert @shamu.aquatic_pupils.empty? + @shamu.aquatic_pupils << @swimmy + assert_equal 1, @shamu.aquatic_pupils.length + @shamu.reload + assert_equal 1, @shamu.aquatic_pupils.length + end + + def test_namespaced_polymorphic_collection + @shamu.aquatic_pupils << @swimmy + assert @shamu.aquatic_pupils.include?(@swimmy) + @shamu.reload + assert @shamu.aquatic_pupils.include?(@swimmy) + + @shamu.aquatic_pupils << @spot + assert @shamu.dogs.include?(@spot) + assert @shamu.aquatic_pupils.include?(@swimmy) + assert_equal @swimmy, @shamu.aquatic_fish.first + assert_equal 10, @shamu.aquatic_fish.first.speed + end + + def test_deleting_namespaced_relationship + @shamu.aquatic_pupils << @swimmy + @shamu.aquatic_pupils << @spot + + @shamu.reload + @shamu.aquatic_pupils.delete @spot + assert !@shamu.dogs.include?(@spot) + assert !@shamu.aquatic_pupils.include?(@spot) + assert_equal 1, @shamu.aquatic_pupils.length + end + + def test_unrenamed_parent_of_namespaced_child + @shamu.aquatic_pupils << @swimmy + assert_equal [@shamu], @swimmy.whales + end + + def test_empty_double_collections + assert @puma.enemies.empty? + assert @froggy.protectors.empty? + assert @alice.enemies.empty? + assert @spot.protectors.empty? + assert @alice.beautiful_fight_relationships_as_enemy.empty? + assert @alice.beautiful_fight_relationships_as_protector.empty? + assert @alice.beautiful_fight_relationships.empty? + end + + def test_double_collection_assignment + @alice.enemies << @spot + @alice.reload + @spot.reload + assert @spot.protectors.include?(@alice) + assert @alice.enemies.include?(@spot) + assert !@alice.protectors.include?(@alice) + assert_equal 1, @alice.beautiful_fight_relationships_as_protector.size + assert_equal 0, @alice.beautiful_fight_relationships_as_enemy.size + assert_equal 1, @alice.beautiful_fight_relationships.size + + # self reference + assert_equal 1, @alice.enemies.length + @alice.enemies.push @alice + assert @alice.enemies.include?(@alice) + assert_equal 2, @alice.enemies.length + @alice.reload + assert_equal 2, @alice.beautiful_fight_relationships_as_protector.size + assert_equal 1, @alice.beautiful_fight_relationships_as_enemy.size + assert_equal 3, @alice.beautiful_fight_relationships.size + end + + def test_double_collection_build_join_record_on_association + + join = @alice.beautiful_fight_relationships_as_protector.build(:enemy => @spot) + + assert_equal @alice.class.base_class.name, join.protector_type + assert_nothing_raised { join.save! } + + assert join.id + assert_equal @double_join_count + 1, BeautifulFightRelationship.count + + assert @alice.enemies.reload + assert @alice.enemies.include?(@spot) + end + + def test_double_dependency_injection +# breakpoint + end + + def test_double_collection_deletion + @alice.enemies << @spot + @alice.reload + assert @alice.enemies.include?(@spot) + @alice.enemies.delete(@spot) + assert !@alice.enemies.include?(@spot) + assert @alice.enemies.empty? + @alice.reload + assert !@alice.enemies.include?(@spot) + assert @alice.enemies.empty? + assert_equal 0, @alice.beautiful_fight_relationships.size + end + + def test_double_collection_deletion_from_opposite_side + @alice.protectors << @puma + @alice.reload + assert @alice.protectors.include?(@puma) + @alice.protectors.delete(@puma) + assert !@alice.protectors.include?(@puma) + assert @alice.protectors.empty? + @alice.reload + assert !@alice.protectors.include?(@puma) + assert @alice.protectors.empty? + assert_equal 0, @alice.beautiful_fight_relationships.size + end + + def test_individual_collections_created_for_double_relationship + assert @alice.dogs.empty? + @alice.enemies << @spot + + assert @alice.enemies.include?(@spot) + assert !@alice.kittens.include?(@alice) + + assert !@alice.dogs.include?(@spot) + @alice.reload + assert @alice.dogs.include?(@spot) + assert !WildBoar.find(@alice.id).dogs.include?(@spot) # make sure the parent type is checked + end + + def test_individual_collections_created_for_double_relationship_from_opposite_side + assert @alice.wild_boars.empty? + @alice.protectors << @puma + + assert @alice.protectors.include?(@puma) + assert !@alice.wild_boars.include?(@puma) + @alice.reload + assert @alice.wild_boars.include?(@puma) + + assert !Dog.find(@alice.id).wild_boars.include?(@puma) # make sure the parent type is checked + end + + def test_self_referential_individual_collections_created_for_double_relationship + @alice.enemies << @alice + @alice.reload + assert @alice.enemy_kittens.include?(@alice) + assert @alice.protector_kittens.include?(@alice) + assert @alice.kittens.include?(@alice) + assert_equal 2, @alice.kittens.size + + @alice.enemies << (@chloe = Kitten.find_by_name('Chloe')) + @alice.reload + assert @alice.enemy_kittens.include?(@chloe) + assert !@alice.protector_kittens.include?(@chloe) + assert @alice.kittens.include?(@chloe) + assert_equal 3, @alice.kittens.size + end + + def test_child_of_polymorphic_join_can_reach_parent + @alice.enemies << @spot + @alice.reload + assert @spot.protectors.include?(@alice) + end + + def test_double_collection_deletion_from_child_polymorphic_join + @alice.enemies << @spot + @spot.protectors.delete(@alice) + assert !@spot.protectors.include?(@alice) + @alice.reload + assert !@alice.enemies.include?(@spot) + BeautifulFightRelationship.create(:protector_id => 2, :protector_type => "Dog", :enemy_id => @spot.id, :enemy_type => @spot.class.name) + @alice.enemies << @spot + @spot.protectors.delete(@alice) + assert !@spot.protectors.include?(@alice) + end + + def test_collection_query_on_unsaved_record + assert Dog.new.enemies.empty? + assert Dog.new.foodstuffs_of_eaters.empty? + end + + def test_double_individual_collections_push + assert_equal [@chloe], (@spot.protector_kittens << @chloe) + @spot.reload + assert @spot.protectors.include?(@chloe) + assert @spot.protector_kittens.include?(@chloe) + assert !@spot.protector_dogs.include?(@chloe) + + assert_equal [@froggy], (@spot.frogs << @froggy) + @spot.reload + assert @spot.enemies.include?(@froggy) + assert @spot.frogs.include?(@froggy) + assert !@spot.enemy_dogs.include?(@froggy) + end + + def test_double_individual_collections_delete + @spot.protectors << [@chloe, @puma] + @spot.reload + assert_equal [@chloe], @spot.protector_kittens.delete(@chloe) + assert @spot.protector_kittens.empty? + @spot.protector_kittens.delete(@chloe) # again, unclear what .delete should return + + @spot.reload + assert @spot.protector_kittens.empty? + assert @spot.wild_boars.include?(@puma) + end + + def test_double_individual_collections_clear + @spot.protectors << [@chloe, @puma, @alice] + @spot.reload + assert_equal [], @spot.protector_kittens.clear + assert @spot.protector_kittens.empty? + assert_equal 1, @spot.protectors.size + @spot.reload + assert @spot.protector_kittens.empty? + assert_equal 1, @spot.protectors.size + assert !@spot.protector_kittens.include?(@chloe) + assert !@spot.protectors.include?(@chloe) + assert !@spot.protector_kittens.include?(@alice) + assert !@spot.protectors.include?(@alice) + assert @spot.protectors.include?(@puma) + assert @spot.wild_boars.include?(@puma) + end + + def test_single_extensions + assert_equal :correct_block_result, @shamu.aquatic_pupils.a_method + @kibbles.eaters.push(@alice) + @kibbles.eaters.push(@spot) + assert_equal :correct_join_result, @kibbles.eaters_foodstuffs.a_method + assert_equal :correct_module_result, @kibbles.eaters.a_method + assert_equal :correct_other_module_result, @kibbles.eaters.another_method + @kibbles.eaters.each do |eater| + assert_equal :correct_join_result, eater.eaters_foodstuffs.a_method + end + assert_equal :correct_parent_proc_result, @kibbles.foodstuffs_of_eaters.a_method + assert_equal :correct_parent_proc_result, @kibbles.eaters.first.foodstuffs_of_eaters.a_method + end + + def test_double_extensions + assert_equal :correct_proc_result, @spot.protectors.a_method + assert_equal :correct_module_result, @spot.enemies.a_method + assert_equal :correct_join_result, @spot.beautiful_fight_relationships_as_enemy.a_method + assert_equal :correct_join_result, @spot.beautiful_fight_relationships_as_protector.a_method + assert_equal :correct_join_result, @froggy.beautiful_fight_relationships.a_method + assert_equal :correct_join_result, @froggy.beautiful_fight_relationships_as_enemy.a_method + assert_raises(NoMethodError) {@froggy.beautiful_fight_relationships_as_protector.a_method} + end + + def test_pluralization_checks + assert_raises(@association_error) { + eval "class SomeModel < ActiveRecord::Base + has_many_polymorphs :polymorphs, :from => [:dog, :cats] + end" } + assert_raises(@association_error) { + eval "class SomeModel < ActiveRecord::Base + has_many_polymorphs :polymorph, :from => [:dogs, :cats] + end" } + assert_raises(@association_error) { + eval "class SomeModel < ActiveRecord::Base + acts_as_double_polymorphic_join :polymorph => [:dogs, :cats], :unimorphs => [:dogs, :cats] + end" } + end + + def test_error_message_on_namespaced_targets + assert_raises(@association_error) { + eval "class SomeModel < ActiveRecord::Base + has_many_polymorphs :polymorphs, :from => [:fish] + end" } + end + + def test_single_custom_finders + [@kibbles, @alice, @puma, @spot, @bits].each {|record| @kibbles.eaters << record; sleep 1} # XXX yeah i know + assert_equal @kibbles.eaters, @kibbles.eaters.find(:all, :order => "eaters_foodstuffs.created_at ASC") + assert_equal @kibbles.eaters.reverse, @kibbles.eaters.find(:all, :order => "eaters_foodstuffs.created_at DESC") + if (ActiveRecord::Base.connection.is_a? ActiveRecord::ConnectionAdapters::MysqlAdapter rescue false) + assert_equal @kibbles.eaters.sort_by(&:created_at), @kibbles.eaters.find(:all, :order => "IFNULL(bow_wows.created_at,(IFNULL(petfoods.created_at,(IFNULL(wild_boars.created_at,(IFNULL(cats.created_at,fish.created_at))))))) ASC") + end + assert_equal @kibbles.eaters.select{|x| x.is_a? Petfood}, @kibbles.eater_petfoods.find(:all, :order => "eaters_foodstuffs.created_at ASC") + end + + def test_double_custom_finders + @spot.protectors << [@chloe, @puma, @alice] + assert_equal [@chloe], @spot.protectors.find(:all, :conditions => ["cats.name = ?", @chloe.name], :limit => 1) + assert_equal [], @spot.protectors.find(:all, :conditions => ["cats.name = ?", @chloe.name], :limit => 1, :offset => 1) + assert_equal 2, @spot.protectors.find(:all, :limit => 100, :offset => 1).size + end + + def test_single_custom_finder_parameters_carry_to_individual_relationships + # XXX test nullout here + end + + def test_double_custom_finder_parameters_carry_to_individual_relationships + # XXX test nullout here + end + + def test_include_doesnt_fail + assert_nothing_raised do + @spot.protectors.find(:all, :include => :wild_boars) + end + end + + def test_abstract_method + assert_equal :correct_abstract_method_response, @spot.an_abstract_method + end + + def test_missing_target_should_raise + @kibbles.eaters << [@kibbles, @alice, @puma, @spot, @bits] + @spot.destroy_without_callbacks + assert_raises(@association_error) { @kibbles.eaters.reload } +# assert_raises(@association_error) { @kibbles.eater_dogs.reload } # bah AR + end + + def test_lazy_loading_is_lazy + # XXX + end + + def test_push_with_skip_duplicates_false_doesnt_load_target + # Loading kibbles locally again because setup calls .size which loads target + kibbles = Petfood.find(1) + assert !kibbles.eaters.loaded? + assert !(kibbles.eater_dogs << Dog.create!(:name => "Mongy")).loaded? + assert !kibbles.eaters.loaded? + end + + def test_association_foreign_key_is_sane + assert_equal "eater_id", Petfood.reflect_on_association(:eaters).association_foreign_key + end + + def test_reflection_instance_methods_are_sane + assert_equal EatersFoodstuff, Petfood.reflect_on_association(:eaters).klass + assert_equal EatersFoodstuff.name, Petfood.reflect_on_association(:eaters).class_name + end + + def test_parent_order + @alice.foodstuffs_of_eaters << Petfood.find(:all, :order => "the_petfood_primary_key ASC") + @alice.reload #not necessary + assert_equal [2,1], @alice.foodstuffs_of_eaters.map(&:id) + end + + def test_parent_conditions + @kibbles.eaters << @alice + assert_equal [@alice], @kibbles.eaters + + @snausages = Petfood.create(:name => 'Snausages') + @snausages.eaters << @alice + assert_equal [@alice], @snausages.eaters + + assert_equal [@kibbles], @alice.foodstuffs_of_eaters + end + + def test_self_referential_hmp_with_conditions + p = Person.find(:first) + kid = Person.create(:name => "Tim", :age => 3) + p.kids << kid + + kid.reload; p.reload + + # assert_equal [p], kid.parents + # assert Rails.has_one? Bug + # non-standard foreign_type key is not set properly when you are the polymorphic interface of a has_many going to a :through + + assert_equal [kid], p.kids + assert_equal [kid], p.people + end + +# def test_polymorphic_include +# @kibbles.eaters << [@kibbles, @alice, @puma, @spot, @bits] +# assert @kibbles.eaters.include?(@kibbles.eaters_foodstuffs.find(:all, :include => :eater).first.eater) +# end +# +# def test_double_polymorphic_include +# end +# +# def test_single_child_include +# end +# +# def test_double_child_include +# end +# +# def test_single_include_from_parent +# end +# +# def test_double_include_from_parent +# end +# +# def test_meta_referential_single_include +# end +# +# def test_meta_referential_double_include +# end +# +# def test_meta_referential_single_include +# end +# +# def test_meta_referential_single_double_multi_include +# end +# +# def test_dont_ignore_duplicates +# end +# +# def test_ignore_duplicates +# end +# +# def test_tagging_system_generator +# end +# +# def test_tagging_system_library +# end + +end From 4db90386a838ea229a716f910739baee13f8577e Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Fri, 6 Apr 2012 16:10:26 +0200 Subject: [PATCH 072/134] fix waring about missing spec file for aruba --- vendor/gems/aruba-0.2.2/.specification | 89 ++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 vendor/gems/aruba-0.2.2/.specification diff --git a/vendor/gems/aruba-0.2.2/.specification b/vendor/gems/aruba-0.2.2/.specification new file mode 100644 index 00000000..e696110a --- /dev/null +++ b/vendor/gems/aruba-0.2.2/.specification @@ -0,0 +1,89 @@ +--- !ruby/object:Gem::Specification +name: aruba +version: !ruby/object:Gem::Version + hash: 19 + prerelease: + segments: + - 0 + - 2 + - 2 + version: 0.2.2 +platform: ruby +authors: +- "Aslak Helles\xC3\xB8y" +- David Chelimsky +autorequire: +bindir: bin +cert_chain: [] + +date: 2010-09-28 00:00:00 Z +dependencies: +- !ruby/object:Gem::Dependency + name: rspec + prerelease: false + requirement: &id001 !ruby/object:Gem::Requirement + none: false + requirements: + - - ~> + - !ruby/object:Gem::Version + hash: 62196431 + segments: + - 2 + - 0 + - 0 + - beta + - 22 + version: 2.0.0.beta.22 + type: :development + version_requirements: *id001 +description: CLI Steps for Cucumber, hand-crafted for you in Aruba +email: cukes@googlegroups.com +executables: [] + +extensions: [] + +extra_rdoc_files: +- LICENSE +- README.rdoc +- History.txt +files: +- LICENSE +- README.rdoc +- History.txt +homepage: http://github.com/aslakhellesoy/aruba +licenses: [] + +post_install_message: +rdoc_options: +- --charset=UTF-8 +require_paths: +- lib +required_ruby_version: !ruby/object:Gem::Requirement + none: false + requirements: + - - ">=" + - !ruby/object:Gem::Version + hash: 3 + segments: + - 0 + version: "0" +required_rubygems_version: !ruby/object:Gem::Requirement + none: false + requirements: + - - ">=" + - !ruby/object:Gem::Version + hash: 3 + segments: + - 0 + version: "0" +requirements: [] + +rubyforge_project: +rubygems_version: 1.8.10 +signing_key: +specification_version: 3 +summary: aruba-0.2.2 +test_files: [] + +has_rdoc: + From dcb155d90d09a6652fa6a8744e8dfe33281eadf2 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Sun, 8 Apr 2012 14:52:44 +0200 Subject: [PATCH 073/134] fix #1271. Don't block an already blocked todo. Create tests for this case --- app/controllers/todos_controller.rb | 2 +- app/models/todo.rb | 8 +- lib/tracks/source_view.rb | 2 +- test/functional/todos_controller_test.rb | 106 +++++++++++++++++++++++ test/unit/todo_test.rb | 44 ++++++++++ test/unit/todo_test2.rb | 57 ------------ 6 files changed, 158 insertions(+), 61 deletions(-) delete mode 100644 test/unit/todo_test2.rb diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index df7df3cd..c6361b22 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -286,7 +286,7 @@ class TodosController < ApplicationController @original_state = @todo.state unless @predecessor.completed? @todo.add_predecessor(@predecessor) - @todo.block! + @todo.block! unless @todo.pending? @saved = @todo.save @status_message = t('todos.added_dependency', :dependency => @predecessor.description) diff --git a/app/models/todo.rb b/app/models/todo.rb index f1164e1f..7c712abb 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -164,10 +164,14 @@ class Todo < ActiveRecord::Base return @removed_predecessors end + # remove predecessor and activate myself if it was the last predecessor def remove_predecessor(predecessor) - # remove predecessor and activate myself self.predecessors.delete(predecessor) - self.activate! + if self.predecessors.empty? + self.activate! + else + save! + end end # Returns true if t is equal to self or a successor of self diff --git a/lib/tracks/source_view.rb b/lib/tracks/source_view.rb index 8cb17ca8..3e6ae371 100644 --- a/lib/tracks/source_view.rb +++ b/lib/tracks/source_view.rb @@ -56,7 +56,7 @@ module Tracks end def source_view_is_one_of( *s ) - s.include?(params[:_source_view].to_sym) + s.include?((params[:_source_view] || @source_view).to_sym) end end diff --git a/test/functional/todos_controller_test.rb b/test/functional/todos_controller_test.rb index 9ee46863..fcdc20bc 100644 --- a/test/functional/todos_controller_test.rb +++ b/test/functional/todos_controller_test.rb @@ -722,5 +722,111 @@ class TodosControllerTest < ActionController::TestCase get :tag, {:name => "foo", :format => "txt" } assert_response 401 end + + def test_make_todo_dependent + login_as(:admin_user) + predecessor = todos(:call_bill) + successor = todos(:call_dino_ext) + + # no predecessors yet + assert_equal 0, successor.predecessors.size + + # add predecessor + put :add_predecessor, :predecessor=>predecessor.id, :successor=>successor.id + + assert_equal 1, successor.predecessors.count + assert_equal predecessor.id, successor.predecessors.first.id + end + + def test_make_todo_with_dependencies_dependent + login_as(:admin_user) + + predecessor = todos(:call_bill) + successor = todos(:call_dino_ext) + other_todo = todos(:phone_grandfather) + + # predecessor -> successor + put :add_predecessor, :predecessor=>predecessor.id, :successor=>successor.id + + # other_todo -> predecessor -> successor + put :add_predecessor, :predecessor=>other_todo.id, :successor=>predecessor.id + + assert_equal 1, successor.predecessors(true).count + assert_equal 0, other_todo.predecessors(true).count + assert_equal 1, predecessor.predecessors(true).count + assert_equal predecessor.id, successor.predecessors.first.id + assert_equal other_todo.id, predecessor.predecessors.first.id + end + + def test_mingle_dependent_todos_leave + # based on #1271 + login_as(:admin_user) + + t1 = todos(:call_bill) + t2 = todos(:call_dino_ext) + t3 = todos(:phone_grandfather) + t4 = todos(:construct_dilation_device) + + # t1 -> t2 + put :add_predecessor, :predecessor=>t1.id, :successor=>t2.id + # t3 -> t4 + put :add_predecessor, :predecessor=>t3.id, :successor=>t4.id + + # t2 -> t4 + put :add_predecessor, :predecessor=>t2.id, :successor=>t4.id + + # should be: t1 -> t2 -> t4 and t3 -> t4 + assert t4.predecessors.map(&:id).include?(t2.id) + assert t4.predecessors.map(&:id).include?(t3.id) + assert t2.predecessors.map(&:id).include?(t1.id) + end + + def test_mingle_dependent_todos_root + # based on #1271 + login_as(:admin_user) + + t1 = todos(:call_bill) + t2 = todos(:call_dino_ext) + t3 = todos(:phone_grandfather) + t4 = todos(:construct_dilation_device) + + # t1 -> t2 + put :add_predecessor, :predecessor=>t1.id, :successor=>t2.id + # t3 -> t4 + put :add_predecessor, :predecessor=>t3.id, :successor=>t4.id + + # t3 -> t2 + put :add_predecessor, :predecessor=>t3.id, :successor=>t2.id + + # should be: t1 -> t2 and t3 -> t4 & t2 + assert t3.successors.map(&:id).include?(t4.id) + assert t3.successors.map(&:id).include?(t2.id) + assert t2.predecessors.map(&:id).include?(t1.id) + assert t2.predecessors.map(&:id).include?(t3.id) + end + + def test_unmingle_dependent_todos + # based on #1271 + login_as(:admin_user) + + t1 = todos(:call_bill) + t2 = todos(:call_dino_ext) + t3 = todos(:phone_grandfather) + t4 = todos(:construct_dilation_device) + + # create same dependency tree as previous test + # should be: t1 -> t2 -> t4 and t3 -> t4 + put :add_predecessor, :predecessor=>t1.id, :successor=>t2.id + put :add_predecessor, :predecessor=>t3.id, :successor=>t4.id + put :add_predecessor, :predecessor=>t2.id, :successor=>t4.id + + # removing t4 as successor of t2 should leave t4 blocked with t3 as predecessor + put :remove_predecessor, :predecessor=>t2.id, :id=>t4.id + + t4.reload + assert t4.pending?, "t4 should remain pending" + assert t4.predecessors.map(&:id).include?(t3.id) + end + end diff --git a/test/unit/todo_test.rb b/test/unit/todo_test.rb index 2414a4a8..481c4894 100644 --- a/test/unit/todo_test.rb +++ b/test/unit/todo_test.rb @@ -342,5 +342,49 @@ class TodoTest < ActiveSupport::TestCase assert 2, todos_with_aORc_and_b.count end + # test named_scopes + def test_find_completed + # Given 2 completed todos, one completed now and one completed 2 months ago + @not_completed1.toggle_completion! + @completed.completed_at = 2.months.ago + @completed.save! + completed_old = @completed + completed_now = @not_completed1 + + # When I use the finders + recent_completed_todos = Todo.completed_after(1.month.ago).find(:all) + older_completed_todos = Todo.completed_before(1.month.ago).find(:all) + + # Then completed1 should be before and completed2 should be after a month ago + assert older_completed_todos.include?(completed_old) + assert recent_completed_todos.include?(completed_now) + + # And completed1 should not be after and completed2 should not be before a month ago + assert !older_completed_todos.include?(completed_now) + assert !recent_completed_todos.include?(completed_old) + end + + def test_find_created + # Given 2 created todos, one created now and one created 2 months ago + user = @completed.user + todo_old = user.todos.create!({:description => "created long long ago", :context => @completed.context}) + todo_old.created_at = 2.months.ago + todo_old.save! + todo_now = user.todos.create!({:description => "just created", :context => @completed.context}) + + # When I use the finders + recent_created_todos = Todo.created_after(1.month.ago).find(:all) + older_created_todos = Todo.created_before(1.month.ago).find(:all) + + # Then todo1 should be before and todo2 should be after a month ago + assert older_created_todos.include?(todo_old) + assert recent_created_todos.include?(todo_now) + + # And todo1 should not be after and todo2 should not be before a month ago + assert !older_created_todos.include?(todo_now) + assert !recent_created_todos.include?(todo_old) + end + + end diff --git a/test/unit/todo_test2.rb b/test/unit/todo_test2.rb deleted file mode 100644 index 323b7432..00000000 --- a/test/unit/todo_test2.rb +++ /dev/null @@ -1,57 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/../test_helper') -require 'date' - -class TodoTest < ActiveSupport::TestCase - fixtures :todos, :recurring_todos, :users, :contexts, :preferences, :tags, :taggings, :projects - - def setup - @not_completed1 = Todo.find(1).reload - @not_completed2 = Todo.find(2).reload - @completed = Todo.find(8).reload - end - - # test named_scopes - def test_find_completed - # Given 2 completed todos, one completed now and one completed 2 months ago - @not_completed1.toggle_completion! - @completed.completed_at = 2.months.ago - @completed.save! - - completed_old = @completed - completed_now = @not_completed1 - - # When I use the finders - recent_completed_todos = Todo.completed_after(1.month.ago).find(:all) - older_completed_todos = Todo.completed_before(1.month.ago).find(:all) - - # Then completed1 should be before and completed2 should be after a month ago - assert older_completed_todos.include?(completed_old) - assert recent_completed_todos.include?(completed_now) - - # And completed1 should not be after and completed2 should not be before a month ago - assert !older_completed_todos.include?(completed_now) - assert !recent_completed_todos.include?(completed_old) - end - - def test_find_created - # Given 2 created todos, one created now and one created 2 months ago - user = @completed.user - todo_old = user.todos.create!({:description => "created long long ago", :context => @completed.context}) - todo_old.created_at = 2.months.ago - todo_old.save! - todo_now = user.todos.create!({:description => "just created", :context => @completed.context}) - - # When I use the finders - recent_created_todos = Todo.created_after(1.month.ago).find(:all) - older_created_todos = Todo.created_before(1.month.ago).find(:all) - - # Then todo1 should be before and todo2 should be after a month ago - assert older_created_todos.include?(todo_old) - assert recent_created_todos.include?(todo_now) - - # And todo1 should not be after and todo2 should not be before a month ago - assert !older_created_todos.include?(todo_now) - assert !recent_created_todos.include?(todo_old) - end - -end \ No newline at end of file From d2d229c23a612b5ee316017d3a3d0c3ce06552cd Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Sun, 8 Apr 2012 16:01:29 +0200 Subject: [PATCH 074/134] cleanup and hopefully fix #1222 --- app/models/todo.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/todo.rb b/app/models/todo.rb index 7c712abb..c056ff58 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -303,14 +303,14 @@ class Todo < ActiveRecord::Base # XML API fixups def predecessor_dependencies=(params) - value = params[:predecessor] - return if value.nil? + deps = params[:predecessor] + return if deps.nil? # for multiple dependencies, value will be an array of id's, but for a single dependency, # value will be a string. In that case convert to array - value = [value] unless value.class == Array + deps = [deps] unless deps.class == Array - value.each { |ele| add_predecessor(self.user.todos.find_by_id(ele.to_i)) unless ele.blank? } + deps.each { |dep| self.add_predecessor(self.user.todos.find(dep.to_i)) unless dep.blank? } end alias_method :original_context=, :context= From 033afda0e1058060a900503f5cc83723b4ddb1d7 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Mon, 9 Apr 2012 12:48:40 +0200 Subject: [PATCH 075/134] fix #1195. Update all autocompleters for more sane order of returned items --- app/controllers/contexts_controller.rb | 11 ++++- app/controllers/projects_controller.rb | 9 +++- app/controllers/todos_controller.rb | 57 +++++++++++++------------- 3 files changed, 46 insertions(+), 31 deletions(-) diff --git a/app/controllers/contexts_controller.rb b/app/controllers/contexts_controller.rb index b738fdcf..aff19c89 100644 --- a/app/controllers/contexts_controller.rb +++ b/app/controllers/contexts_controller.rb @@ -31,7 +31,7 @@ class ContextsController < ApplicationController @all_contexts = current_user.contexts.all render :action => 'index', :layout => false, :content_type => Mime::TEXT end - format.autocomplete { render :text => for_autocomplete(@active_contexts + @hidden_contexts, params[:term])} + format.autocomplete &render_autocomplete end end @@ -248,6 +248,15 @@ class ContextsController < ApplicationController :author => lambda { |c| nil } } end end + + def render_autocomplete + lambda do + # first get active contexts with todos then those without + filled_contexts = @active_contexts.reject { |ctx| ctx.todos.count == 0 } + @hidden_contexts.reject { |ctx| ctx.todos.count == 0 } + empty_contexts = @active_contexts.find_all { |ctx| ctx.todos.count == 0 } + @hidden_contexts.find_all { |ctx| ctx.todos.count == 0 } + render :text => for_autocomplete(filled_contexts + empty_contexts, params[:term]) + end + end def feed_options Context.feed_options(current_user) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 381ba8bf..b9766f89 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -28,7 +28,7 @@ class ProjectsController < ApplicationController format.rss &render_rss_feed format.atom &render_atom_feed format.text &render_text_feed - format.autocomplete { render :text => for_autocomplete(current_user.projects.uncompleted, params[:term]) } + format.autocomplete &render_autocomplete end end end @@ -385,6 +385,13 @@ class ProjectsController < ApplicationController render :action => 'index', :layout => false, :content_type => Mime::TEXT end end + + def render_autocomplete + lambda do + projects = current_user.projects.active + current_user.projects.hidden + render :text => for_autocomplete(projects, params[:term]) + end + end def set_project_from_params @project = current_user.projects.find_by_params(params) diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index c6361b22..fc6491a2 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -694,9 +694,13 @@ class TodosController < ApplicationController end def tags - @tags = Tag.find(:all, :conditions =>['name like ?', '%'+params[:term]+'%']) + # TODO: limit to current_user + tags_beginning = Tag.find(:all, :conditions => ['name like ?', params[:term]+'%']) + tags_all = Tag.find(:all, :conditions =>['name like ?', '%'+params[:term]+'%']) + tags_all= tags_all - tags_beginning + respond_to do |format| - format.autocomplete { render :text => for_autocomplete(@tags, params[:term]) } + format.autocomplete { render :text => for_autocomplete(tags_beginning+tags_all, params[:term]) } end end @@ -805,36 +809,32 @@ class TodosController < ApplicationController def auto_complete_for_predecessor unless params['id'].nil? get_todo_from_params - # Begin matching todos in current project - @items = current_user.todos.find(:all, + # Begin matching todos in current project, excluding @todo itself + @items = @todo.project.todos.not_completed.find(:all, :include => [:context, :project], - :conditions => [ '(todos.state = ? OR todos.state = ? OR todos.state = ?) AND ' + - 'NOT (todos.id = ?) AND lower(todos.description) LIKE ? AND todos.project_id = ?', - 'active', 'pending', 'deferred', - @todo.id, - '%' + params[:predecessor_list].downcase + '%', - @todo.project_id ], + :conditions => ['(LOWER(todos.description) LIKE ?) AND NOT(todos.id=?)', "%#{params[:term].downcase}%", @todo.id], :order => 'description ASC', :limit => 10 - ) - if @items.empty? # Match todos in other projects - @items = current_user.todos.find(:all, - :include => [:context, :project], - :conditions => [ '(todos.state = ? OR todos.state = ? OR todos.state = ?) AND ' + - 'NOT (todos.id = ?) AND lower(todos.description) LIKE ?', - 'active', 'pending', 'deferred', - params[:id], '%' + params[:term].downcase + '%' ], - :order => 'description ASC', - :limit => 10 - ) - end - else - # New todo - TODO: Filter on project - @items = current_user.todos.find(:all, + ) unless @todo.project.nil? + # Then look in the current context, excluding @todo itself + @items = @todo.context.todos.not_completed.find(:all, :include => [:context, :project], - :conditions => [ '(todos.state = ? OR todos.state = ? OR todos.state = ?) AND lower(todos.description) LIKE ?', - 'active', 'pending', 'deferred', - '%' + params[:term].downcase + '%' ], + :conditions => ['(LOWER(todos.description) LIKE ?) AND NOT(todos.id=?)', "%#{params[:term].downcase}%", @todo.id], + :order => 'description ASC', + :limit => 10 + ) unless !@items.empty? || @todo.context.nil? + # Match todos in other projects, excluding @todo itself + @items = current_user.todos.not_completed.find(:all, + :include => [:context, :project], + :conditions => ['(LOWER(todos.description) LIKE ?) AND NOT(todos.id=?)', "%#{params[:term].downcase}%", @todo.id], + :order => 'description ASC', + :limit => 10 + ) unless !@items.empty? + else + # New todo - TODO: Filter on current project in project view + @items = current_user.todos.not_completed.find(:all, + :include => [:context, :project], + :conditions => ['(LOWER(todos.description) LIKE ?)', "%#{params[:term].downcase}%"], :order => 'description ASC', :limit => 10 ) @@ -847,7 +847,6 @@ class TodosController < ApplicationController @project = current_user.projects.new(:name => @todo.description, :description => @todo.notes, :default_context => @todo.context) - unless @project.invalid? @todo.destroy @project.save! From 98bb405f69b5fd847ae8520585e3c56c11b3f2f2 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Mon, 9 Apr 2012 12:58:29 +0200 Subject: [PATCH 076/134] fix #1274 by adding indeces for dependency and project tables --- ...20409105058_add_indices_to_dependency_table.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 db/migrate/20120409105058_add_indices_to_dependency_table.rb diff --git a/db/migrate/20120409105058_add_indices_to_dependency_table.rb b/db/migrate/20120409105058_add_indices_to_dependency_table.rb new file mode 100644 index 00000000..74418b25 --- /dev/null +++ b/db/migrate/20120409105058_add_indices_to_dependency_table.rb @@ -0,0 +1,15 @@ +class AddIndicesToDependencyTable < ActiveRecord::Migration + def self.up + add_index :dependencies, :successor_id + add_index :dependencies, :predecessor_id + add_index :projects, :state + add_index :projects, [:user_id, :state] + end + + def self.down + remove_index :dependencies, :successor_id + remove_index :dependencies, :predecessor_id + remove_index :projects, :state + remove_index :projects, [:user_id, :state] + end +end From 784b7434f6cf2ac757c2051012414bdf3ff4772b Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Tue, 10 Apr 2012 20:28:58 +0200 Subject: [PATCH 077/134] add some missing translations for #1276 --- app/helpers/application_helper.rb | 2 +- app/views/projects/_project_state_group.rhtml | 2 +- config/locales/cz.yml | 338 ++++----- config/locales/de.yml | 388 +++++----- config/locales/en.yml | 2 + config/locales/es.yml | 388 +++++----- config/locales/fr.yml | 392 +++++----- config/locales/nl.yml | 682 +++++++++--------- 8 files changed, 1104 insertions(+), 1090 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 8e8a2848..6a5776e3 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -231,7 +231,7 @@ module ApplicationHelper else return list.inject("") do |html, item| link = (item.class == "Project") ? link_to_project( item ) : link_to_context(item) - html << content_tag(:li, link + " (" + count_undone_todos_phrase(item,"actions")+")") + html << content_tag(:li, link + " (" + count_undone_todos_phrase(item, I18n.t("common.actions_midsentence"))+")") end end end diff --git a/app/views/projects/_project_state_group.rhtml b/app/views/projects/_project_state_group.rhtml index f052d125..b90371b2 100644 --- a/app/views/projects/_project_state_group.rhtml +++ b/app/views/projects/_project_state_group.rhtml @@ -10,7 +10,7 @@ <%= t('common.last' ) unless ( ['review','stalled','blocked','current'].include?(state) )%> <%= t('states.'+state+'_plural' )%> - <%= t('common.projects') %><%= total_count==-1 ? "" : " ("+link_to("Show all", done_projects_path)+")"%> + <%= t('common.projects') %><%= total_count==-1 ? "" : " ("+link_to(t('common.show_all'), done_projects_path)+")"%> <% unless suppress_sort_menu %> diff --git a/config/locales/cz.yml b/config/locales/cz.yml index 96939e76..47a3e068 100755 --- a/config/locales/cz.yml +++ b/config/locales/cz.yml @@ -22,6 +22,7 @@ cz: second: !binary | RHJ1aMO9 + actions_midsentence: akce none: !binary | xb3DoWRuw70= @@ -29,15 +30,16 @@ cz: dMO9ZGVu optional: "voliteln\xC3\xA9" + show_all: "Zobrazit v\xC5\xA1echny" cancel: "Zru\xC5\xA1it" month: !binary | bcSbc8OtYw== + server_error: Nastala chyba na serveru. + notes: "Pozn\xC3\xA1mky" forum: !binary | RsOzcnVt - server_error: Nastala chyba na serveru. - notes: "Pozn\xC3\xA1mky" last: "Posledn\xC3\xAD" projects: Projekty review: Revize @@ -45,19 +47,15 @@ cz: w5prb2w= project: Projekt - ok: Ok contribute: !binary | UMWZaXNwxJt0 + ok: Ok first: !binary | UHJ2bsOt website: "Webov\xC3\xA1 str\xC3\xA1nka" numbered_step: Krok %{number} - errors_with_fields: !binary | - TmFzdGFseSBwb3TDrcW+ZSBzIG7DoXNsZWR1asOtY8OtbWkgcG9sw63EjWt5 - Og== - create: "Vytvo\xC5\x99it" sort: by_task_count_title: "\xC5\x98adit podle po\xC4\x8Dtu \xC3\xBAkol\xC5\xAF" @@ -87,6 +85,10 @@ cz: w7prb2w= contexts: Kontexty + errors_with_fields: !binary | + TmFzdGFseSBwb3TDrcW+ZSBzIG7DoXNsZWR1asOtY8OtbWkgcG9sw63EjWt5 + Og== + update: "Ulo\xC5\xBEit" weeks: !binary | dMO9ZG55 @@ -96,8 +98,8 @@ cz: wiki: Wiki bugs: Chyby - email: Email ajaxError: "Chyba \xC4\x8Dten\xC3\xAD ze serveru" + email: Email search: Hledat number: format: @@ -135,8 +137,8 @@ cz: delimiter: "," layouts: toggle_contexts_title: "Zobraz\xC3\xAD/skryje sbalen\xC3\xA9 kontexty" - toggle_contexts: "P\xC5\x99epnout sbalen\xC3\xA9 kontexty" toggle_notes: "Zobrazit/skr\xC3\xBDt pozn\xC3\xA1mky" + toggle_contexts: "P\xC5\x99epnout sbalen\xC3\xA9 kontexty" next_actions_rss_feed: "RSS feed aktu\xC3\xA1ln\xC3\xADch \xC3\xBAkol\xC5\xAF" toggle_notes_title: "Zobraz\xC3\xAD/skryje v\xC5\xA1echny pozn\xC3\xA1mky" mobile_navigation: @@ -153,13 +155,13 @@ cz: contexts: 2-Kontexty home: "1-Dom\xC5\xAF" navigation: - api_docs: REST API Dokumenty manage_users_title: "P\xC5\x99idat nebo smazat u\xC5\xBEivatele" recurring_todos: "Opakuj\xC3\xADc\xC3\xAD se \xC3\xBAkoly" + api_docs: REST API Dokumenty feeds: Feedy stats: Statistiky - starred: "S hv\xC4\x9Bzdou" notes_title: "Zobrazit v\xC5\xA1echny pozn\xC3\xA1mky" + starred: "S hv\xC4\x9Bzdou" manage_users: !binary | U3Byw6F2YSB1xb5pdmF0ZWzFrw== @@ -171,14 +173,14 @@ cz: calendar_title: !binary | S2FsZW5kw6HFmSBkYXRvdmFuw71jaCDDumtvbMWv + recurring_todos_title: "Spr\xC3\xA1va opakovan\xC3\xBDch \xC3\xBAkol\xC5\xAF" + tickler: Tickler + completed_tasks: "Hotov\xC3\xA9" + stats_title: "Zobraz\xC3\xAD statistiky \xC3\xBAkol\xC5\xAF" home_title: !binary | RG9txa8= - tickler: Tickler starred_title: "Zobraz\xC3\xAD \xC3\xBAkoly s hv\xC4\x9Bzdi\xC4\x8Dkou" - recurring_todos_title: "Spr\xC3\xA1va opakovan\xC3\xBDch \xC3\xBAkol\xC5\xAF" - completed_tasks: "Hotov\xC3\xA9" - stats_title: "Zobraz\xC3\xAD statistiky \xC3\xBAkol\xC5\xAF" view: "Uk\xC3\xA1zat" organize: "Spr\xC3\xA1va" completed_tasks_title: "Hotov\xC3\xA9 \xC3\xBAkoly" @@ -187,10 +189,10 @@ cz: contexts_title: Kontexty export: Export + projects_title: Projekty + search: Hledat preferences_title: "Zobraz\xC3\xAD mo\xC5\xBEnosti nastaven\xC3\xAD" review_title: "Prov\xC3\xA9st revizi" - search: Hledat - projects_title: Projekty calendar: !binary | S2FsZW5kw6HFmQ== @@ -232,9 +234,9 @@ cz: show_hidden_projects_in_sidebar: "Zobrazovat skryt\xC3\xA9 projekty v sidebaru" date_format: "Form\xC3\xA1t data" show_hidden_contexts_in_sidebar: "Zobrazovat skryt\xC3\xA9 kontexty v sidebaru" + verbose_action_descriptors: "Ukecan\xC3\xA9 popisova\xC4\x8De \xC3\xBAkol\xC5\xAF" mobile_todos_per_page: "\xC3\x9Akol\xC5\xAF na str\xC3\xA1nku (mobiln\xC3\xAD zobrazen\xC3\xAD)" staleness_starts: "Jako pro\xC5\xA1l\xC3\xA9 ozna\xC4\x8Dit projekty star\xC5\xA1\xC3\xAD ne\xC5\xBE" - verbose_action_descriptors: "Ukecan\xC3\xA9 popisova\xC4\x8De \xC3\xBAkol\xC5\xAF" sms_context: "V\xC3\xBDchoz\xC3\xAD emailov\xC3\xBD kontext" show_number_completed: "Po\xC4\x8Det hotov\xC3\xBDch \xC3\xBAkol\xC5\xAF k zobrazen\xC3\xAD" title_date_format: "Form\xC3\xA1t data nadpisu" @@ -246,17 +248,17 @@ cz: UMWZw61qbWVuw60= locale: "Lok\xC3\xA1le" - due_style: "Zobrazen\xC3\xAD datovan\xC3\xBDch \xC3\xBAkol\xC5\xAF" time_zone: !binary | xIxhc292w6kgcMOhc21v + due_style: "Zobrazen\xC3\xAD datovan\xC3\xBDch \xC3\xBAkol\xC5\xAF" sms_email: SMS email show_project_on_todo_done: "Po spln\xC4\x9Bn\xC3\xAD \xC3\xBAkolu p\xC5\x99ej\xC3\xADt na projekt" show_completed_projects_in_sidebar: "Zobrazovat hotov\xC3\xA9 projekty v sidebaru" - review_period: "Interval revize projekt\xC5\xAF" first_name: !binary | Sm3DqW5v + review_period: "Interval revize projekt\xC5\xAF" errors: models: project: @@ -296,6 +298,8 @@ cz: not_a_number: !binary | bmVuw60gxI3DrXNsbw== + full_messages: + format: "%{attribute} %{message}" template: body: !binary | TmFzdGFseSBwb3TDrcW+ZSBzIG7DoXNsZWR1asOtY8OtbWkgcG9sw63EjWt5 @@ -304,8 +308,6 @@ cz: header: one: "jedna chyba br\xC3\xA1n\xC3\xAD ulo\xC5\xBEen\xC3\xAD tohoto objektu %{model}" other: "%{count} chyb br\xC3\xA1n\xC3\xAD ulo\xC5\xBEen\xC3\xAD tohoto objektu %{model}" - full_messages: - format: "%{attribute} %{message}" data: import_successful: !binary | SW1wb3J0IGJ5bCDDunNwxJvFoW7DvS4= @@ -327,13 +329,13 @@ cz: - "Pl\xC3\xA1nov\xC3\xA1no za ___ dn\xC3\xAD" - "Pl\xC3\xA1nov\xC3\xA1no na _______" stats: + tag_cloud_title: !binary | + TXJhayDFoXTDrXRrxa8gcHJvIHbFoWVjaG55IMO6a2x5 + totals_hidden_context_count: "a %{count} skryt\xC3\xBDch kontext\xC5\xAF." actions_avg_created: "Za posledn\xC3\xADch 12 m\xC4\x9Bs\xC3\xADc\xC5\xAF bylo vytvo\xC5\x99eno pr\xC5\xAFm\xC4\x9Brn\xC4\x9B %{count} \xC3\xBAkol\xC5\xAF" actions_min_max_completion_days: "Maximum/minimum dn\xC3\xAD na dokon\xC4\x8Den\xC3\xAD je %{min}/%{max}." totals_actions_completed: "%{count} z nich je hotov\xC3\xBDch." - tag_cloud_title: !binary | - TXJhayDFoXTDrXRrxa8gcHJvIHbFoWVjaG55IMO6a2x5 - actions_actions_avg_created_30days: "Za posledn\xC3\xADch 30 dn\xC3\xAD bylo vytvo\xC5\x99eno pr\xC5\xAFm\xC4\x9Brn\xC4\x9B %{count} \xC3\xBAkol\xC5\xAF" actions_avg_completed: !binary | YSB1emF2xZllbm8gcHLFr23Em3JuxJsgJXtjb3VudH0gw7prb2zFryB6YSBt @@ -343,13 +345,13 @@ cz: actions: !binary | w5prb2x5 - totals_deferred_actions: "z nich\xC5\xBE %{count} jsou odlo\xC5\xBEen\xC3\xA9 \xC3\xBAkoly v Ticlkeru" time_of_day_legend: number_of_actions: !binary | UG/EjWV0IMO6a29sxa8= time_of_day: "Denn\xC3\xAD doba" totals_incomplete_actions: "M\xC3\xA1te %{count} nehotov\xC3\xBDch \xC3\xBAkol\xC5\xAF" + totals_action_count: "m\xC3\xA1te celkem %{count} \xC3\xBAkol\xC5\xAF" running_time_legend: actions: !binary | w5prb2x5 @@ -358,7 +360,7 @@ cz: UG9kw61s weeks: "\xC4\x8Cas b\xC4\x9Bhu \xC3\xBAkolu (t\xC3\xBDdny). Klepn\xC4\x9Bte na sloupec pro dal\xC5\xA1\xC3\xAD info" - totals_action_count: "m\xC3\xA1te celkem %{count} \xC3\xBAkol\xC5\xAF" + totals_deferred_actions: "z nich\xC5\xBE %{count} jsou odlo\xC5\xBEen\xC3\xA9 \xC3\xBAkoly v Ticlkeru" tag_cloud_90days_title: "Zna\xC4\x8Dky \xC3\xBAkol\xC5\xAF z posledn\xC3\xADch 90-ti dn\xC3\xAD" tod30: "Denn\xC3\xAD doba (posledn\xC3\xADch 30 dn\xC3\xAD)" tags: !binary | @@ -366,6 +368,7 @@ cz: projects: Projekty actions_avg_completion_time: "Pro v\xC5\xA1echny va\xC5\xA1e hotov\xC3\xA9 \xC3\xBAkoly je pr\xC5\xAFm\xC4\x9Brn\xC3\xBD \xC4\x8Das dokon\xC4\x8Den\xC3\xAD %{count} dn\xC3\xAD." + actions_day_of_week_title: "Den v t\xC3\xBDdnu (v\xC5\xA1echny \xC3\xBAkoly)" labels: month_avg_completed: !binary | JXttb250aHN9IG3Em3PDrcSNbsOtIHByxa9txJtyIGhvdG92w71jaA== @@ -381,19 +384,14 @@ cz: cHLFr23Em3JuxJsgdXphdsWZZW5v created: "Vytvo\xC5\x99eno" - actions_selected_from_week: "\xC3\x9Akoly vybran\xC3\xA9 z t\xC3\xBDdne " totals_completed_project_count: "a %{count} je hotov\xC3\xBDch projekt\xC5\xAF." - actions_day_of_week_title: "Den v t\xC3\xBDdnu (v\xC5\xA1echny \xC3\xBAkoly)" + actions_selected_from_week: "\xC3\x9Akoly vybran\xC3\xA9 z t\xC3\xBDdne " actions_lastyear_title: "\xC3\x9Akoly za posledn\xC3\xADch 12 m\xC4\x9Bs\xC3\xADc\xC5\xAF" open_per_week: "Aktivn\xC3\xAD (viditeln\xC3\xA9 i skryt\xC3\xA9) dal\xC5\xA1\xC3\xAD akce za t\xC3\xBDden" action_selection_title: !binary | VFJBQ0tTOjp2w71ixJtyIMO6a29sxa8= totals_project_count: "M\xC3\xA1te %{count} projekt\xC5\xAF." - current_running_time_of_incomplete_visible_actions: !binary | - QWt0dcOhbG7DrSDEjWFzIGLEm2h1IG5lZG9rb27EjWVuw71jaCB2aWRpdGVs - bsO9Y2ggw7prb2zFrw== - legend: number_of_days: "P\xC5\x99ed kolika dny" actions: !binary | @@ -403,13 +401,17 @@ cz: UG/EjWV0IMO6a29sxa8= day_of_week: "Den v t\xC3\xBDdnu" + running_time: "\xC4\x8Cas k dokon\xC4\x8Den\xC3\xAD \xC3\xBAkolu (t\xC3\xBDdny)" percentage: !binary | UG9kw61s - running_time: "\xC4\x8Cas k dokon\xC4\x8Den\xC3\xAD \xC3\xBAkolu (t\xC3\xBDdny)" months_ago: !binary | bcSbc8OtY8WvIHpwxJt0 + current_running_time_of_incomplete_visible_actions: !binary | + QWt0dcOhbG7DrSDEjWFzIGLEm2h1IG5lZG9rb27EjWVuw71jaCB2aWRpdGVs + bsO9Y2ggw7prb2zFrw== + tod30_legend: number_of_actions: !binary | UG/EjWV0IMO6a29sxa8= @@ -432,16 +434,16 @@ cz: top10_projects: "Top 10 projekt\xC5\xAF" top5_contexts: "Top 5 kontext\xC5\xAF" - contexts: Kontexty totals: Celkem + contexts: Kontexty click_to_return: "Klepn\xC4\x9Bte %{link} pro n\xC3\xA1vrat ke statistik\xC3\xA1m." tag_cloud_90days_description: "Tento mrak zahrnuje \xC5\xA1t\xC3\xADtky \xC3\xBAkol\xC5\xAF, kter\xC3\xA9 byly vytvo\xC5\x99eny nebo dokon\xC4\x8Deny v posledn\xC3\xADch 90-ti dnech." totals_visible_context_count: "Z nich je %{count} viditeln\xC3\xBDch kontext\xC5\xAF" - top10_projects_30days: "Top 10 projekt\xC5\xAF za posledn\xC3\xADch 30 dn\xC3\xAD" running_time_all: !binary | QWt0dcOhbG7DrSDEjWFzIGLEm2h1IHbFoWVjaCBuZWhvdG92w71jaCDDumtv bMWv + top10_projects_30days: "Top 10 projekt\xC5\xAF za posledn\xC3\xADch 30 dn\xC3\xAD" actions_min_completion_time: "Minim\xC3\xA1ln\xC3\xAD \xC4\x8Das k dokon\xC4\x8Den\xC3\xAD je %{time}." action_completion_time_title: "\xC4\x8Cas dokon\xC4\x8Den\xC3\xAD (v\xC5\xA1echny hotov\xC3\xA9 \xC3\xBAkoly)" click_to_show_actions_from_week: "Klepn\xC4\x9Bte %{link} pro zobrazen\xC3\xAD \xC3\xBAkol\xC5\xAF z t\xC3\xBDdne %{week} a dal\xC5\xA1\xC3\xADch." @@ -451,8 +453,8 @@ cz: no_actions_selected: !binary | TmVqc291IHZ5YnLDoW55IMW+w6FkbsOpIMO6a29seS4= - totals_tag_count: "Na akc\xC3\xADch je um\xC3\xADst\xC4\x9Bno %{count} \xC5\xA1t\xC3\xADtk\xC5\xAF." actions_further: " a d\xC3\xA1le" + totals_tag_count: "Na akc\xC3\xADch je um\xC3\xADst\xC4\x9Bno %{count} \xC5\xA1t\xC3\xADtk\xC5\xAF." actions_dow_30days_legend: number_of_actions: !binary | UG/EjWV0IGFrY8Ot @@ -460,52 +462,52 @@ cz: day_of_week: "Den v t\xC3\xBDdnu" totals_first_action: "Od va\xC5\xA1eho prvn\xC3\xADho \xC3\xBAkolu %{date}" tag_cloud_description: "Tento mrak zahrnuje \xC5\xA1t\xC3\xADtky v\xC5\xA1ech \xC3\xBAkol\xC5\xAF (hotov\xC3\xBDch, nehotov\xC3\xBDch, viditeln\xC3\xBDch i skryt\xC3\xBDch)" - click_to_return_link: zde click_to_update_actions: "Klepn\xC4\x9Bte na sloupec v grafu pro zobrazen\xC3\xAD detail\xC5\xAF n\xC3\xAD\xC5\xBEe." + click_to_return_link: zde spread_of_actions_for_all_context: "Distribuce v\xC5\xA1ech \xC3\xBAkol\xC5\xAF do kontext\xC5\xAF" more_stats_will_appear: "Dal\xC5\xA1\xC3\xAD statistiky se zobraz\xC3\xAD a\xC5\xBE p\xC5\x99ibyde v\xC3\xADce \xC3\xBAkol\xC5\xAF." actions_avg_completed_30days: "a dokon\xC4\x8Deno pr\xC5\xAFm\xC4\x9Brn\xC4\x9B %{count} \xC3\xBAkol\xC5\xAF za den." + actions_dow_30days_title: "Dny v t\xC3\xBDdnu (poslen\xC3\xADch 30 dn\xC3\xAD)" + actions_30days_title: "\xC3\x9Akoly za posledn\xC3\xADch 30 dn\xC3\xAD" no_tags_available: !binary | xb7DoWRuw6kgxaF0w610a3kgbmVqc291IGRlZmlub3bDoW55 - actions_30days_title: "\xC3\x9Akoly za posledn\xC3\xADch 30 dn\xC3\xAD" index_title: TRACKS::Statistika - actions_dow_30days_title: "Dny v t\xC3\xBDdnu (poslen\xC3\xADch 30 dn\xC3\xAD)" - spread_of_running_actions_for_visible_contexts: "Distribuce b\xC4\x9B\xC5\xBE\xC3\xADc\xC3\xADch \xC3\xBAkol\xC5\xAF do viditeln\xC3\xBDch kontext\xC5\xAF" actions_day_of_week_legend: number_of_actions: !binary | UG/EjWV0IGFrY8Ot day_of_week: "Den v t\xC3\xBDdnu" - actions_last_year: "\xC3\x9Akoly v posledn\xC3\xADm roce" + spread_of_running_actions_for_visible_contexts: "Distribuce b\xC4\x9B\xC5\xBE\xC3\xADc\xC3\xADch \xC3\xBAkol\xC5\xAF do viditeln\xC3\xBDch kontext\xC5\xAF" totals_blocked_actions: "%{count} je z\xC3\xA1visl\xC3\xBDch na dokon\xC4\x8Den\xC3\xAD jin\xC3\xBDch akc\xC3\xAD." + actions_last_year: "\xC3\x9Akoly v posledn\xC3\xADm roce" totals_unique_tags: "Z t\xC4\x9Bchto \xC5\xA1t\xC3\xADtk\xC5\xAF je %{count} unik\xC3\xA1tn\xC3\xADch." totals_active_project_count: "Znich %{count} je aktivn\xC3\xADch projek\xC5\xAF" running_time_all_legend: actions: !binary | w5prb2x5 + running_time: "\xC4\x8Cas b\xC4\x9Bhu \xC3\xBAkol\xC5\xAF (t\xC3\xBDdny). Klepn\xC4\x9Bte na sloupec pro dal\xC5\xA1\xC3\xAD info" percentage: !binary | UG9kw61s - running_time: "\xC4\x8Cas b\xC4\x9Bhu \xC3\xBAkol\xC5\xAF (t\xC3\xBDdny). Klepn\xC4\x9Bte na sloupec pro dal\xC5\xA1\xC3\xAD info" other_actions_label: "(ostatn\xC3\xAD)" - time_of_day: "Denn\xC3\xAD doba (v\xC5\xA1echny \xC3\xBAkoly)" totals_hidden_project_count: "%{count} je skryt\xC3\xBDch" + time_of_day: "Denn\xC3\xAD doba (v\xC5\xA1echny \xC3\xBAkoly)" todos: show_from: Zobrazovat od error_starring_recurring: "Nebylo mo\xC5\xBEno ohv\xC4\x9Bzdi\xC4\x8Dkovat opakovan\xC3\xBD \xC3\xBAkol \\'%{description}\\'" recurring_action_deleted: "\xC3\x9Akol byl smaz\xC3\xA1n. Proto\xC5\xBEe jde o opakovan\xC3\xBD \xC3\xBAkol, byl vlo\xC5\xBEen nov\xC3\xBD \xC3\xBAkol" completed_actions: "Hotov\xC3\xA9 \xC3\xBAkoly" - blocked_by: "\xC4\x8Cek\xC3\xA1 na %{predecessors}" + completed_rest_of_previous_month: "Uzav\xC5\x99eno ve zbytku minul\xC3\xA9ho m\xC4\x9Bs\xC3\xADce" completed_recurring: "Hotov\xC3\xA9 opakovan\xC3\xA9 \xC3\xBAkoly" added_new_next_action: !binary | UMWZaWTDoW4gbm92w70gw7prb2w= - completed_rest_of_previous_month: "Uzav\xC5\x99eno ve zbytku minul\xC3\xA9ho m\xC4\x9Bs\xC3\xADce" - defer_date_after_due_date: "Datum zobrazen\xC3\xAD je a\xC5\xBE po pl\xC3\xA1novan\xC3\xA9m datu \xC3\xBAkolu. Upravte datum \xC3\xBAkolu p\xC5\x99ed dal\xC5\xA1\xC3\xADm pokusem o odplo\xC5\xBEen\xC3\xAD zobrazen\xC3\xAD." - star_action: "Ozna\xC5\x99it hv\xC4\x9Bzdi\xC4\x8Dkou" + blocked_by: "\xC4\x8Cek\xC3\xA1 na %{predecessors}" completed_recurrence_completed: "Bylo smaz\xC3\xA1no posledn\xC3\xAD opakov\xC3\xA1n\xC3\xAD opakovan\xC3\xA9ho \xC3\xBAkolu. Opakov\xC3\xA1n\xC3\xAD dokon\xC4\x8Deno" + star_action: "Ozna\xC5\x99it hv\xC4\x9Bzdi\xC4\x8Dkou" + defer_date_after_due_date: "Datum zobrazen\xC3\xAD je a\xC5\xBE po pl\xC3\xA1novan\xC3\xA9m datu \xC3\xBAkolu. Upravte datum \xC3\xBAkolu p\xC5\x99ed dal\xC5\xA1\xC3\xADm pokusem o odplo\xC5\xBEen\xC3\xAD zobrazen\xC3\xAD." unable_to_add_dependency: "Nepoda\xC5\x99ilo se p\xC5\x99idat z\xC3\xA1vislost" done: Hotovo? star_action_with_description: "ohv\xC4\x9Bzdi\xC4\x8Dkovat \xC3\xBAkol '%{description}'" @@ -515,11 +517,11 @@ cz: xb3DoWRuw6kgb2Rsb8W+ZW7DqSDDumtvbHkgc2UgxaF0w610a2VtICcle3Rh Z19uYW1lfSc= + edit_action_with_description: "Upravit \xC3\xBAkol '%{description}'" no_hidden_actions: !binary | xb3DoWRuw6kgc2tyeXTDqSDDumtvbHk= action_due_on: "(\xC3\xBAkol pl\xC3\xA1nov\xC3\xA1n na %{date})" - edit_action_with_description: "Upravit \xC3\xBAkol '%{description}'" archived_tasks_title: "TRACKS::Archiv hotov\xC3\xBDch \xC3\xBAkol\xC5\xAF" remove_dependency: "Odstranit z\xC3\xA1vislost (nesma\xC5\xBEe \xC3\xBAkol)" list_incomplete_next_actions: "Zabraz\xC3\xAD nehotov\xC3\xA9 \xC3\xBAkoly" @@ -529,15 +531,15 @@ cz: action_deleted_success: !binary | w5prb2wgYnlsIMO6c3DEm8WhbsSbIHNtYXrDoW4= + new_related_todo_created: "Byl vytvo\xC5\x99en nov\xC3\xBD \xC3\xBAkol pat\xC5\x99\xC3\xADc\xC3\xAD do tohoto opakovan\xC3\xA9ho \xC3\xBAkolu" + context_changed: "Kontext byl zm\xC4\x9Bn\xC4\x9Bn na %{name}" add_another_dependency: !binary | UMWZaWRhdCBkYWzFocOtIHrDoXZpc2xvc3Q= - new_related_todo_created: "Byl vytvo\xC5\x99en nov\xC3\xBD \xC3\xBAkol pat\xC5\x99\xC3\xADc\xC3\xAD do tohoto opakovan\xC3\xA9ho \xC3\xBAkolu" - context_changed: "Kontext byl zm\xC4\x9Bn\xC4\x9Bn na %{name}" mobile_todos_page_title: "V\xC5\xA1echny \xC3\xBAkoly" delete_recurring_action_title: "Smazat opakovan\xC3\xBD \xC3\xBAkol" - recurring_actions_title: "TRACKS::Opakovan\xC3\xA9 \xC3\xBAkoly" removed_predecessor: "Byl odstran\xC4\x9Bn %{successor} jako z\xC3\xA1vislost pro %{predecessor}." + recurring_actions_title: "TRACKS::Opakovan\xC3\xA9 \xC3\xBAkoly" next_action_needed: "Je pot\xC5\x99eba zadat aspo\xC5\x88 jeden \xC3\xBAkol" action_saved: !binary | w5prb2wgdWxvxb5lbg== @@ -547,7 +549,6 @@ cz: edit_action: "Upravit \xC3\xBAkol" added_new_context: "P\xC5\x99id\xC3\xA1n nov\xC3\xBD kontext" next_actions_description: "Filtr:" - older_completed_items: "" list_incomplete_next_actions_with_limit: "Zobrazuje posledn\xC3\xADch %{count} nedokon\xC4\x8Den\xC3\xBDch \xC3\xBAkol\xC5\xAF" set_to_pending: "%{task} nastaven jako \xC4\x8Dekaj\xC3\xADc\xC3\xAD" added_new_project: "P\xC5\x99id\xC3\xA1n nov\xC3\xBD projekt" @@ -557,34 +558,35 @@ cz: due_within_a_week: !binary | YsSbaGVtIHTDvWRuZQ== - task_list_title: "TRACKS::\xC3\x9Akoly" + older_completed_items: "" + error_deleting_item: "Nepoda\xC5\x99ilo se smazat polo\xC5\xBEku %{description}" edit_recurring_todo: "Upravit opakovan\xC3\xBD \xC3\xBAkol" append_in_this_project: v tomto projektu - error_deleting_item: "Nepoda\xC5\x99ilo se smazat polo\xC5\xBEku %{description}" + task_list_title: "TRACKS::\xC3\x9Akoly" no_actions_due_this_week: !binary | xb3DoWRuw6kgw7prb2x5IHBsw6Fub3bDoW55IG5hIHRlbnRvIHTDvWRlbg== - error_completing_todo: "Nepoda\xC5\x99ilo se ukon\xC4\x8Dit / aktivovat opakovan\xC3\xBD \xC3\xBAkol %{description}" - no_recurring_todos: !binary | - xb3DoWRuw6kgb3Bha292YW7DqSDDumtvbHk= - - recurring_pattern_removed: "Vzor opakov\xC3\xA1n\xC3\xAD byl odstran\xC4\x9Bn z %{count}" - convert_to_project: "Vytvo\xC5\x99it projekt" no_deferred_pending_actions: !binary | xb3DoWRuw6kgb2Rsb8W+ZW7DqSBhbmkgxI1la2Fqw61jw60gw7prb2x5 + no_recurring_todos: !binary | + xb3DoWRuw6kgb3Bha292YW7DqSDDumtvbHk= + + error_completing_todo: "Nepoda\xC5\x99ilo se ukon\xC4\x8Dit / aktivovat opakovan\xC3\xBD \xC3\xBAkol %{description}" + recurring_pattern_removed: "Vzor opakov\xC3\xA1n\xC3\xAD byl odstran\xC4\x9Bn z %{count}" + convert_to_project: "Vytvo\xC5\x99it projekt" delete_recurring_action_confirm: "Opravdu chcete smazat opakovan\xC3\xBD \xC3\xBAkol '%{description}'?" completed_last_day: "Ukon\xC4\x8Den\xC3\xA9 v posledn\xC3\xADch 24 hodin\xC3\xA1ch" - all_completed: "V\xC5\xA1echny hotov\xC3\xA9 \xC3\xBAkoly" show_in_days: "Zobrazit za %{days} dn\xC3\xAD" no_project: "--\xC5\xBD\xC3\xA1dn\xC3\xBD projekt--" error_saving_recurring: "Nepoda\xC5\x99ilo se ulo\xC5\xBEit opakovan\xC3\xBD \xC3\xBAkol \\'%{description}\\'" completed_more_than_x_days_ago: "" - feed_title_in_context: v kontextu '%{context}' new_related_todo_created_short: "vytvo\xC5\x99en nov\xC3\xBD \xC3\xBAkol" + feed_title_in_context: v kontextu '%{context}' + all_completed: "V\xC5\xA1echny hotov\xC3\xA9 \xC3\xBAkoly" edit: Upravit - completed_tagged_page_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" older_than_days: "" + completed_tagged_page_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" pending: !binary | xIxla2Fqw61jw60= @@ -597,10 +599,10 @@ cz: clear_due_date: "Smazat pl\xC3\xA1novan\xC3\xA9 datum \xC3\xBAkolu" error_removing_dependency: "Nepoda\xC5\x99ilo se odstranit z\xC3\xA1vislost" hidden_actions: "Skryt\xC3\xA9 \xC3\xBAkoly" + deferred_actions_with: "Odlo\xC5\xBEen\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" was_due_on_date: "bylo pl\xC3\xA1nov\xC3\xA1no na %{date}" show_on_date: "Uk\xC3\xA1zat %{date}" recurrence_period: "Interval opakov\xC3\xA1n\xC3\xAD" - deferred_actions_with: "Odlo\xC5\xBEen\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" confirm_delete: "Opravdu chcete smazat \xC3\xBAkol '%{description}'?" recurring_deleted_success: !binary | T3Bha292YW7DvSDDumtvbCBieWwgw7pzcMSbxaFuxJsgc21hesOhbi4= @@ -611,25 +613,25 @@ cz: no_completed_actions_with: "\xC5\xBD\xC3\xA1dn\xC3\xA9 hotov\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" clear_show_from_date: "Odstranit datum zobrazen\xC3\xAD" calendar_page_title: "TRACKS::Kalend\xC3\xA1\xC5\x99" - unresolved_dependency: "Hodnota v poli 'z\xC3\xA1vis\xC3\xAD na' neodpov\xC3\xADd\xC3\xA1 \xC5\xBE\xC3\xA1dn\xC3\xA9mu existuj\xC3\xADc\xC3\xADmu \xC3\xBAkolu. Hodnota bude ignorov\xC3\xA1na. Pokra\xC4\x8Dovat?" in_hidden_state: "(skryt\xC3\xBD)" - show_today: Zobrazit Dnes - no_actions_found_title: !binary | - TmVuYWxlemVueSDFvsOhZG7DqSDDumtvbHk= - + unresolved_dependency: "Hodnota v poli 'z\xC3\xA1vis\xC3\xAD na' neodpov\xC3\xADd\xC3\xA1 \xC5\xBE\xC3\xA1dn\xC3\xA9mu existuj\xC3\xADc\xC3\xADmu \xC3\xBAkolu. Hodnota bude ignorov\xC3\xA1na. Pokra\xC4\x8Dovat?" next_actions_due_date: overdue_by: "Pro\xC5\xA1l\xC3\xA9 %{days} den" - due_today: Dnes due_in_x_days: "Za %{days} dn\xC3\xAD" + due_today: Dnes overdue_by_plural: "Pro\xC5\xA1l\xC3\xA9 %{days} dn\xC3\xAD" due_tomorrow: !binary | WsOtdHJh + show_today: Zobrazit Dnes + no_actions_found_title: !binary | + TmVuYWxlemVueSDFvsOhZG7DqSDDumtvbHk= + completed_last_x_days: "Uzav\xC5\x99en\xC3\xA9 za posledn\xC3\xADch %{count} dn\xC3\xAD" - no_actions_with: "\xC5\xBD\xC3\xA1dn\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" defer_x_days: one: "Uk\xC3\xA1zat z\xC3\xADtra" other: "Uk\xC3\xA1zat za %{count} dn\xC3\xAD" + no_actions_with: "\xC5\xBD\xC3\xA1dn\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" added_new_next_action_singular: !binary | UMWZaWTDoW4gbm92w70gw7prb2w= @@ -653,8 +655,8 @@ cz: error_deleting_recurring: "Nepoda\xC5\x99ilo se smazat opakovan\xC3\xBD \xC3\xBAkol \\'%{description}\\'" recurring_todos: "Opakovan\xC3\xA9 \xC3\xBAkoly" delete: Smazat - cannot_add_dependency_to_completed_todo: "Nelze p\xC5\x99idat \xC3\xBAkol jako z\xC3\xA1vislost k hotov\xC3\xA9mu \xC3\xBAkolu!" drag_action_title: "P\xC5\x99et\xC3\xA1hnout na jin\xC3\xBD \xC3\xBAkol pro vytvo\xC5\x99en\xC3\xAD z\xC3\xA1vislosti" + cannot_add_dependency_to_completed_todo: "Nelze p\xC5\x99idat \xC3\xBAkol jako z\xC3\xA1vislost k hotov\xC3\xA9mu \xC3\xBAkolu!" no_last_completed_actions: !binary | xb3DoWRuw6kgaG90b3bDqSDDumtvbHk= @@ -665,8 +667,8 @@ cz: WsOhdmlzw60gbmE= action_marked_complete: "\xC3\x9Akol '%{description}' byl ozna\xC4\x8Den jako %{completed}" - completed_today: "Dokon\xC4\x8Den\xC3\xA9 dnes" added_new_next_action_plural: "\xC3\x9Akoly byly p\xC5\x99id\xC3\xA1ny" + completed_today: "Dokon\xC4\x8Den\xC3\xA9 dnes" new_related_todo_not_created_short: "\xC3\xBAkol nebyl vytvo\xC5\x99en" completed_rest_of_week: "Dokon\xC4\x8Den\xC3\xA9 ve zbytku t\xC3\xBDdne" error_starring: "Nepoda\xC5\x99ilo se ozna\xC4\x8Dit \xC3\xBAkol hv\xC4\x9Bzdi\xC4\x8Dkou '%{description}'" @@ -681,10 +683,10 @@ cz: bsOpIMO6a29seQ== due_this_week: "Pl\xC3\xA1novan\xC3\xA9 ve zbytku t\xC3\xBDdne" - due_today: "Pl\xC3\xA1novan\xC3\xA9 dnes" no_actions_due_today: !binary | TmEgZG5lxaFlayBuZWpzb3UgcGzDoW5vdmFuw6kgxb7DoWRuw6kgw7prb2x5 + due_today: "Pl\xC3\xA1novan\xC3\xA9 dnes" due_next_month_and_later: "Pl\xC3\xA1nov\xC3\xA1no na %{month} a d\xC3\xA1le" no_actions_due_after_this_month: !binary | TmEgcMWZw63FoXTDrSBtxJtzw61jIGEgZMOhbGUgbmVqc291IHBsw6Fub3Zh @@ -693,7 +695,6 @@ cz: no_actions_due_this_month: "Na zbytek tohoto m\xC4\x9Bs\xC3\xADce nejsou \xC5\xBE\xC3\xA1dn\xC3\xA9 \xC3\xBAkoly" due_this_month: "Pl\xC3\xA1nov\xC3\xA1no na %{month}" action_deferred: "\xC3\x9Akol '%{description}' byl oldo\xC5\xBEen" - added_dependency: "P\xC5\x99id\xC3\xA1no %{dependency} jako z\xC3\xA1vislost." recurrence: ends_on_number_times: "Kon\xC4\x8D\xC3\xAD po %{number} opakov\xC3\xA1n\xC3\xADch" ends_on_date: "Kon\xC4\x8D\xC3\xAD %{date}" @@ -720,9 +721,6 @@ cz: RGVubsSb pattern: - third: !binary | - dMWZZXTDrQ== - month_names: - - Leden @@ -743,6 +741,9 @@ cz: - Listopad - Prosinec + third: !binary | + dMWZZXTDrQ== + every_n: !binary | a2HFvmTDqSAle259 @@ -762,6 +763,11 @@ cz: the_xth_day_of_month: "%{x} %{day} m\xC4\x9Bs\xC3\xADce %{month}" times: "(%{number} opakov\xC3\xA1n\xC3\xAD)" every_year_on: "ka\xC5\xBEd\xC3\xBD rok %{date}" + on_work_days: "v pracovn\xC3\xAD dny" + first: !binary | + cHJ2bsOt + + show: "uk\xC3\xA1zat" day_names: - "ned\xC4\x9Ble" - !binary | @@ -776,19 +782,14 @@ cz: cMOhdGVr - sobota - show: "uk\xC3\xA1zat" - first: !binary | - cHJ2bsOt - - on_work_days: "v pracovn\xC3\xAD dny" fourth: !binary | xI10dnJ0w70= due: "pl\xC3\xA1nov\xC3\xA1no na" + until: do every_month: !binary | a2HFvmTDvSBtxJtzw61j - until: do recurrence_on_options: "Nastavit opakov\xC3\xA1n\xC3\xAD na" yearly_every_x_day: "Ka\xC5\xBEd\xC3\xBD %{month} %{day}" daily_every_number_day: "Ka\xC5\xBEd\xC3\xBDch %{number} dn\xC3\xAD" @@ -799,12 +800,12 @@ cz: w5prw6F6YXQgw7prb2w= weekly_every_number_week: "Ka\xC5\xBEd\xC3\xBDch %{number} t\xC3\xBDdn\xC5\xAF" - yearly_every_xth_day: "%{day} %{day_of_week} m\xC4\x9Bs\xC3\xADce %{month}" - show_days_before: "%{days} dn\xC3\xAD p\xC5\x99ed pl\xC3\xA1novan\xC3\xBDm datem" from_tickler: "datum kdy \xC3\xBAkol vypadne z Tickleru (nen\xC3\xAD nastaveno pl\xC3\xA1novan\xC3\xA9 datum)" + yearly_every_xth_day: "%{day} %{day_of_week} m\xC4\x9Bs\xC3\xADce %{month}" no_end_date: Nikdy day_x_on_every_x_month: "%{day}. den ka\xC5\xBEd\xC3\xBD %{month}. m\xC4\x9Bs\xC3\xADc" yearly_options: "Nastaven\xC3\xAD pro ro\xC4\x8Dn\xC3\xAD opakovan\xC3\xA9 \xC3\xBAkoly" + show_days_before: "%{days} dn\xC3\xAD p\xC5\x99ed pl\xC3\xA1novan\xC3\xBDm datem" monthly_every_xth_day: "%{day} %{day_of_week} ka\xC5\xBEd\xC3\xBD %{month}. m\xC4\x9Bs\xC3\xADc" yearly: !binary | Um/EjW7Emw== @@ -813,19 +814,22 @@ cz: no_completed_recurring: !binary | xb3DoWRuw6kgaG90b3bDqSBvcGFrb3ZhbsOpIMO6a29seQ== - completed_rest_of_month: "Ukon\xC4\x8Den\xC3\xA9 ve zbytku tohoto m\xC4\x9Bs\xC3\xADce" - recurrence_completed: "Posledn\xC3\xAD opakov\xC3\xA1n\xC3\xAD \xC3\xBAkolu bylo ozna\xC4\x8Deno jako hotov\xC3\xA9. Opakovan\xC3\xBD \xC3\xBAkol je dokon\xC4\x8Den\xC3\xBD" + added_dependency: "P\xC5\x99id\xC3\xA1no %{dependency} jako z\xC3\xA1vislost." all_completed_tagged_page_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem %{tag_name}" no_deferred_actions: !binary | xb3DoWRuw6kgb2Rsb8W+ZW7DqSDDumtvbHku - in_pending_state: "ve stavu \xC4\x8Dekaj\xC3\xADc\xC3\xAD" + completed_rest_of_month: "Ukon\xC4\x8Den\xC3\xA9 ve zbytku tohoto m\xC4\x9Bs\xC3\xADce" + recurrence_completed: "Posledn\xC3\xAD opakov\xC3\xA1n\xC3\xAD \xC3\xBAkolu bylo ozna\xC4\x8Deno jako hotov\xC3\xA9. Opakovan\xC3\xBD \xC3\xBAkol je dokon\xC4\x8Den\xC3\xBD" no_actions_found: !binary | xb3DoWRuw6kgYsSbxb7DrWPDrSDDumtvbHku + in_pending_state: "ve stavu \xC4\x8Dekaj\xC3\xADc\xC3\xAD" error_toggle_complete: "Nepoda\xC5\x99ilo se ozna\xC4\x8Dit \xC3\xBAkol jako hotov\xC3\xBD" due: "Pl\xC3\xA1nov\xC3\xA1no na" action_marked_complete_error: "\xC3\x9Akol '%{description}' NEBYL ozna\xC4\x8Den jako %{completed} kv\xC5\xAFli chyb\xC4\x9B na serveru." + to_tickler: do Tickleru + add_new_recurring: "Vytvo\xC5\x99it opakovan\xC3\xBD \xC3\xBAkol" depends_on_separate_with_commas: !binary | WsOhdmlzw60gbmEgKG9kZMSbbGVubyDEjcOhcmthbWkp @@ -834,14 +838,12 @@ cz: completed_in_archive: one: "V archivu je hotov\xC3\xBD \xC3\xBAkol." other: "V archivu je %{count} hotov\xC3\xBDch \xC3\xBAkol\xC5\xAF." - to_tickler: do Tickleru next_actions_description_additions: completed: "v posledn\xC3\xADch %{count} dnech" due_date: "pl\xC3\xA1novano na %{due_date} nebo d\xC5\x99\xC3\xADve" overdue: !binary | U3Bvxb5kxJtuw6kgw7prb2x5 - add_new_recurring: "Vytvo\xC5\x99it opakovan\xC3\xBD \xC3\xBAkol" no_incomplete_actions: !binary | xb3DoWRuw6kgbmVob3RvdsOpIMO6a29seQ== @@ -867,8 +869,8 @@ cz: current: !binary | QWt0dcOhbG7DrQ== - review: "Nerevidovan\xC3\xBD" completed_plural: "Hotov\xC3\xA9" + review: "Nerevidovan\xC3\xBD" blocked_plural: "Blokovan\xC3\xA9" blocked: "Blokovan\xC3\xBD" stalled_plural: !binary | @@ -877,28 +879,26 @@ cz: visible_plural: "Viditeln\xC3\xA9" active_plural: "Aktivn\xC3\xAD" visible: "Viditeln\xC3\xBD" + hidden: "Skryt\xC3\xBD" current_plural: !binary | QWt0dcOhbG7DrQ== - hidden: "Skryt\xC3\xBD" active: "Aktivn\xC3\xAD" - errors: - user_unauthorized: "401 Neautorizov\xC3\xA1no: Jen administr\xC3\xA1to\xC5\x99i sm\xC3\xAD pou\xC5\xBE\xC3\xADvat tuto funkci." projects: + edit_project_title: Upravit projekt + default_tags_removed_notice: "V\xC3\xBDchoz\xC3\xAD \xC5\xA1t\xC3\xADtky byly odstran\xC4\x9Bny" + default_context_set: "V\xC3\xBDchoz\xC3\xAD kontext %{default_context} byl nastaven" no_actions_in_project: !binary | xb3DoWRuw6kgYWt0aXZuw60gw7prb2x5 deferred_actions: "Odlo\xC5\xBEen\xC3\xA9 \xC3\xBAkoly projektu" was_marked_hidden: "byl ozna\xC4\x8Den jako skryt\xC3\xBD" - edit_project_title: Upravit projekt - default_tags_removed_notice: "V\xC3\xBDchoz\xC3\xAD \xC5\xA1t\xC3\xADtky byly odstran\xC4\x9Bny" - default_context_set: "V\xC3\xBDchoz\xC3\xAD kontext %{default_context} byl nastaven" hide_form: !binary | U2tyw710IGZvcm11bMOhxZk= - page_title: "TRACKS::Projekt: %{project}" all_completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly projektu '%{project_name}'" - project_state: Projekt je %{state}. + page_title: "TRACKS::Projekt: %{project}" + this_project: Tento projekt list_completed_projects: "TRACKS::Hotov\xC3\xA9 projekty" to_new_project_page: "p\xC5\x99ej\xC3\xADt k nov\xC3\xA9mu projektu" no_notes_attached: !binary | @@ -908,7 +908,7 @@ cz: deferred_actions_empty: !binary | xb3DoWRuw6kgb2Rsb8W+ZW7DqSDDumtvbHk= - this_project: Tento projekt + project_state: Projekt je %{state}. no_last_completed_recurring_todos: !binary | xb3DoWRuw6kgaG90b3bDqSBvcGFrb3ZhbsOpIMO6a29seQ== @@ -917,14 +917,14 @@ cz: xb3DoWRuw6kgaG90b3bDqSBwcm9qZWt0eQ== notes: "Pozn\xC3\xA1mky" - hide_form_title: "Schovat formul\xC3\xA1\xC5\x99 zalo\xC5\xBEen\xC3\xAD projektu" - list_reviews: TRACKS::Revize notes_empty: !binary | xb3DoWRuw6kgcG96bsOhbWt5 no_projects: !binary | xb3DoWRuw6kgcHJvamVrdHk= + hide_form_title: "Schovat formul\xC3\xA1\xC5\x99 zalo\xC5\xBEen\xC3\xAD projektu" + list_reviews: TRACKS::Revize completed_actions_empty: "V tomto projektu nejsou \xC5\xBE\xC3\xA1dn\xC3\xA9 hotov\xC3\xA9 \xC3\xBAkoly" with_no_default_context: "bez v\xC3\xBDchoz\xC3\xADho kontextu" delete_project: Smazat projekt @@ -932,45 +932,47 @@ cz: actions_in_project_title: "\xC3\x9Akoly v tomto projetku" delete_project_confirmation: Opravdu chcete smazat projekt '%{name}'? with_default_context: "s v\xC3\xBDchoz\xC3\xADm kontextem '%{context_name}'" - set_default_tags_notice: "Nastavit v\xC3\xBDchoz\xC3\xAD \xC5\xA1\xC3\xADtky \xC3\xBAkol\xC5\xAF v tomto projektu %{default_tags}" + is_active: "je aktivn\xC3\xAD" completed_projects: "Hotov\xC3\xA9 projetky" + project_saved_status: "Projekt byl ulo\xC5\xBEen" add_note: "Nov\xC3\xA1 pozn\xC3\xA1mka" add_project: "P\xC5\x99idat projekt" - with_default_tags: "a s '%{tags}' jako v\xC3\xBDchoz\xC3\xAD \xC5\xA1t\xC3\xADtky" settings: "Nastaven\xC3\xAD" + with_default_tags: "a s '%{tags}' jako v\xC3\xBDchoz\xC3\xAD \xC5\xA1t\xC3\xADtky" list_projects: TRACKS::Projekty - is_active: "je aktivn\xC3\xAD" - project_saved_status: "Projekt byl ulo\xC5\xBEen" + set_default_tags_notice: "Nastavit v\xC3\xBDchoz\xC3\xAD \xC5\xA1\xC3\xADtky \xC3\xBAkol\xC5\xAF v tomto projektu %{default_tags}" + completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly projektu '%{project_name}'" delete_project_title: "Sma\xC5\xBEe projekt" hidden_projects: "Skryt\xC3\xA9 projekty" - completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly projektu '%{project_name}'" default_context_removed: "V\xC3\xBDchoz\xC3\xAD kontext byl odstran\xC4\x9Bn" - completed_actions: "Hotov\xC3\xA9 \xC3\xBAkoly tohoto projektu" add_note_submit: "Nov\xC3\xA1 pozn\xC3\xA1mka" was_marked_complete: "byl ozna\xC4\x8Den jako hotov\xC3\xBD" + completed_actions: "Hotov\xC3\xA9 \xC3\xBAkoly tohoto projektu" no_default_context: "Tento projekt nem\xC3\xA1 v\xC3\xBDchoz\xC3\xAD kontext" with_no_default_tags: !binary | YSBuZW3DoSDFvsOhZG7DqSB2w71jaG96w60gem5hxI1reQ== edit_project_settings: Upravit vlastnosti projektu - status_project_name_changed: "Jm\xC3\xA9no projektu bylo zm\xC4\x9Bn\xC4\x9Bno" state: Tento projekt je %{state} + status_project_name_changed: "Jm\xC3\xA9no projektu bylo zm\xC4\x9Bn\xC4\x9Bno" default_context: "V\xC3\xBDchoz\xC3\xAD kontext pro tento projekt je %{context}" active_projects: "Aktivn\xC3\xAD projekty" + errors: + user_unauthorized: "401 Neautorizov\xC3\xA1no: Jen administr\xC3\xA1to\xC5\x99i sm\xC3\xAD pou\xC5\xBE\xC3\xADvat tuto funkci." preferences: change_identity_url: "Zm\xC4\x9Bna URL identity" - open_id_url: "Va\xC5\xA1e OpenID URL je" staleness_starts_after: "Zastar\xC3\xA1n\xC3\xAD nast\xC3\xA1v\xC3\xA1 po %{days} dnech" - page_title: "TRACKS::Nastaven\xC3\xAD" + open_id_url: "Va\xC5\xA1e OpenID URL je" change_password: "Zm\xC4\x9Bna hesla" + page_title: "TRACKS::Nastaven\xC3\xAD" token_description: "Pe\xC5\xA1ek (feedy a pou\xC5\xBEit\xC3\xAD API)" title: "Va\xC5\xA1e nastaven\xC3\xAD" - is_false: ne show_number_completed: "Zobrazit %{number} hotov\xC3\xBDch polo\xC5\xBEek" + is_false: ne + edit_preferences: "Editace nastaven\xC3\xAD" page_title_edit: "TRACKS::Editace nastaven\xC3\xAD" is_true: ano password_changed: "Heslo bylo zm\xC4\x9Bn\xC4\x9Bno. Pros\xC3\xADm znovu se p\xC5\x99ihla\xC5\xA1te." - edit_preferences: "Editace nastaven\xC3\xAD" generate_new_token: "Generovat nov\xC3\xA9ho pe\xC5\xA1ka" sms_context_none: !binary | xb7DoWRuw70= @@ -1034,7 +1036,9 @@ cz: - So order: - :rok - - ":m\xC4\x9Bs\xC3\xADc" + - !binary | + Om3Em3PDrWM= + - :den formats: only_day: "" @@ -1114,10 +1118,10 @@ cz: shared: multiple_next_actions: "\xC3\x9Akoly (jeden na ka\xC5\xBEd\xC3\xA9m \xC5\x99\xC3\xA1dku)" make_actions_dependent: "Akce budou vz\xC3\xA1jemn\xC4\x9B z\xC3\xA1visl\xC3\xA9" - hide_form: "Schovat formul\xC3\xA1\xC5\x99" toggle_single: !binary | UMWZaWRhdCDDumtvbA== + hide_form: "Schovat formul\xC3\xA1\xC5\x99" add_actions: "P\xC5\x99idat \xC3\xBAkoly" add_action: !binary | UMWZaWRhdCDDumtvbA== @@ -1125,12 +1129,12 @@ cz: tags_for_all_actions: !binary | Wm5hxI1reSAob2RkxJtsZW7DqSDEjcOhcmthbWkp + project_for_all_actions: "Projekt (pro v\xC5\xA1echny)" + context_for_all_actions: "Kontext (pro v\xC5\xA1echny)" toggle_multi: !binary | UMWZaWRhdCB2w61jZSDDumtvbMWv toggle_single_title: "P\xC5\x99idat jeden nov\xC3\xBD \xC3\xBAkol" - project_for_all_actions: "Projekt (pro v\xC5\xA1echny)" - context_for_all_actions: "Kontext (pro v\xC5\xA1echny)" separate_tags_with_commas: !binary | b2RkxJtsZW7DqSDEjcOhcmthbWk= @@ -1144,8 +1148,8 @@ cz: feedlist: actions_due_today: "Akce pl\xC3\xA1novan\xC3\xA9 na dnes" choose_context: "Vyberte kontext jeho\xC5\xBE feed si p\xC5\x99ejete" - rss_feed: RSS Feed legend: "Legenda:" + rss_feed: RSS Feed ical_feed: iCal feed all_contexts: "V\xC5\xA1echny kontexty" all_projects: "V\xC5\xA1echny projekty" @@ -1154,103 +1158,71 @@ cz: select_feed_for_project: Vyberte feed pro tento projekt active_projects_wo_next: "Aktivni projekty bez \xC3\xBAkol\xC5\xAF" active_starred_actions: "V\xC5\xA1echny aktivn\xC3\xAD \xC3\xBAkoly s hv\xC4\x9Bzdi\xC4\x8Dkou" - context_needed: "Mus\xC3\xADte nejd\xC5\x99\xC3\xADve zalo\xC5\xBEit aspo\xC5\x88 jeden kontext" select_feed_for_context: Select the feed for this context projects_and_actions: "Aktivn\xC3\xAD projekty a jejich \xC3\xBAkoly" + context_needed: "Mus\xC3\xADte nejd\xC5\x99\xC3\xADve zalo\xC5\xBEit aspo\xC5\x88 jeden kontext" actions_due_next_week: !binary | w5prb2x5IHBsw6Fub3ZhbsOpIG5hIHDFmcOtxaF0w61jaCBzZWRtIGRuw60= notice_incomplete_only: "Pozn\xC3\xA1mka: v\xC5\xA1echny feedy obsahuj\xC3\xAD jen nehotov\xC3\xA9 \xC3\xBAkoly." + context_centric_actions: "Feedy s aktivn\xC3\xADmi \xC3\xBAkoly podle kontext\xC5\xAF" + plain_text_feed: "Prost\xC3\xBD text" last_fixed_number: "Posledn\xC3\xADch %{number} \xC3\xBAkol\xC5\xAF" all_actions: "V\xC5\xA1echny \xC3\xBAkoly" actions_completed_last_week: "\xC3\x9Akoly dokon\xC4\x8Den\xC3\xA9 v posledn\xC3\xADch sedmi dnech" - context_centric_actions: "Feedy s aktivn\xC3\xADmi \xC3\xBAkoly podle kontext\xC5\xAF" - plain_text_feed: "Prost\xC3\xBD text" project_centric: "Feedy s aktivn\xC3\xADmi \xC3\xBAkoly podle projektu" users: + first_user_heading: "V\xC3\xADtejte v TRACKS. Nejd\xC5\x99\xC3\xADve je nutn\xC3\xA9 vytvo\xC5\x99it administr\xC3\xA1torsk\xC3\xBD \xC3\xBA\xC4\x8Det:" successfully_deleted_user: "U\xC5\xBEivatel %{username} byl \xC3\xBAsp\xC4\x9B\xC5\xA1n\xC4\x9B smaz\xC3\xA1n" + auth_type_update_error: "Nepoda\xC5\x99ilo se zm\xC4\x9Bnit typ autentizace: %{error_messages}" failed_to_delete_user: "Nepoda\xC5\x99ilo se smazat u\xC5\xBEivatele %{username}" destroy_successful: "U\xC5\xBEivatel %{login} byl \xC3\xBAsp\xC4\x9B\xC5\xA1n\xC4\x9B zni\xC4\x8Den" total_contexts: "Kontext\xC5\xAF celkem" openid_url_verified: "Identitn\xC3\xAD url %{url} bylo \xC3\xBAsp\xC4\x9B\xC5\xA1n\xC4\x9B ov\xC4\x9B\xC5\x99eno a nastavena autentizace pomoc\xC3\xAD OpenID." - first_user_heading: "V\xC3\xADtejte v TRACKS. Nejd\xC5\x99\xC3\xADve je nutn\xC3\xA9 vytvo\xC5\x99it administr\xC3\xA1torsk\xC3\xBD \xC3\xBA\xC4\x8Det:" - auth_type_update_error: "Nepoda\xC5\x99ilo se zm\xC4\x9Bnit typ autentizace: %{error_messages}" + signup_successful: "Registrace u\xC5\xBEivatele %{username} byla \xC3\xBAsp\xC4\x9B\xC5\xA1n\xC3\xA1." new_token_generated: !binary | Tm92w70gcGXFoWVrIGJ5bCDDunNwxJvFoW7EmyB2eWdlbmVyb3bDoW4= total_projects: "Projekt\xC5\xAF celkem" - signup_successful: "Registrace u\xC5\xBEivatele %{username} byla \xC3\xBAsp\xC4\x9B\xC5\xA1n\xC3\xA1." no_signups_title: "TRACKS::Registrace nen\xC3\xAD povolena" user_created: "U\xC5\xBEivatel byl vytvo\xC5\x99en." change_password_submit: "Zm\xC4\x9Bnit heslo" - account_signup: "Registrace u\xC5\xBEivatele" manage_users: !binary | U3Byw6F2YSB1xb5pdmF0ZWzFrw== + account_signup: "Registrace u\xC5\xBEivatele" password_updated: "Heslo bylo zm\xC4\x9Bn\xC4\x9Bno." - auth_type_updated: "Typ autentizace byl zm\xC4\x9Bn\xC4\x9Bn." total_actions: "\xC3\x9Akol\xC5\xAF celkem" desired_login: "U\xC5\xBEivatelsk\xC3\xA9 jm\xC3\xA9no" - signup: Registrace confirm_password: "Potvrzen\xC3\xAD hesla" new_user_heading: "Registrace nov\xC3\xA9ho u\xC5\xBEivatele:" - change_password_prompt: "Pro zm\xC4\x9Bnu hesla zadejte nov\xC3\xA9 hestlo do pol\xC3\xAD n\xC3\xAD\xC5\xBEe a stiskn\xC4\x9Bte 'Zm\xC4\x9Bna hesla'." - password_confirmation_label: "Potvrzen\xC3\xAD hesla" + signup: Registrace + auth_type_updated: "Typ autentizace byl zm\xC4\x9Bn\xC4\x9Bn." destroy_error: "Nepoda\xC5\x99ilo se smazat u\xC5\xBEivatele %{login}" choose_password: Zvolte heslo change_password_title: "TRACKS::Zm\xC4\x9Bna hesla" change_auth_type_title: "TRACKS::Zm\xC4\x9Bna z\xC5\xAFsobu autentizace" + change_password_prompt: "Pro zm\xC4\x9Bnu hesla zadejte nov\xC3\xA9 hestlo do pol\xC3\xAD n\xC3\xAD\xC5\xBEe a stiskn\xC4\x9Bte 'Zm\xC4\x9Bna hesla'." + password_confirmation_label: "Potvrzen\xC3\xAD hesla" new_password_label: "Nov\xC3\xA9 heslo" register_with_cas: "S va\xC5\xA1\xC3\xADm u\xC5\xBEivatelsk\xC3\xBDm jm\xC3\xA9nem z CASu" label_auth_type: "Zp\xC5\xAFsob autentizace" + total_users_count: "M\xC3\xA1te celkem %{count} u\xC5\xBEivatel\xC5\xAF" new_user_title: "TRACKS::P\xC5\x99ihl\xC3\xA1\xC5\xA1en\xC3\xAD jako administr\xC3\xA1tor" destroy_user: "Zni\xC4\x8Dit u\xC5\xBEivatele" - total_users_count: "M\xC3\xA1te celkem %{count} u\xC5\xBEivatel\xC5\xAF" you_have_to_reset_your_password: "Je nutn\xC3\xA9 zm\xC4\x9Bnit heslo" signup_new_user: "Registrace nov\xC3\xA9ho u\xC5\xBEivatele" destroy_confirmation: "Varov\xC3\xA1n\xC3\xAD: tato akce sma\xC5\xBEe u\xC5\xBEivatele '%{login}', v\xC5\xA1echny jeho \xC3\xBAkoly, kontexty, projekty i pozn\xC3\xA1mky. Opravdu chcete pokra\xC4\x8Dovat?" identity_url: URL identity - openid_ok_pref_failed: "Va\xC5\xA1e identitn\xC3\xAD URL %{url} bylo \xC3\xBAsp\xC4\x9B\xC5\xA1n\xC4\x9B ov\xC4\x9B\xC5\x99eno, ale do\xC5\xA1lo k probl\xC3\xA9mu p\xC5\x99i ukl\xC3\xA1d\xC3\xA1n\xC3\xAD nastaven\xC3\xAD." change_authentication_type: !binary | Wm3Em25hIHpwxa9zb2J1IHDFmWlobGHFoW92w6Fuw60= + openid_ok_pref_failed: "Va\xC5\xA1e identitn\xC3\xAD URL %{url} bylo \xC3\xBAsp\xC4\x9B\xC5\xA1n\xC4\x9B ov\xC4\x9B\xC5\x99eno, ale do\xC5\xA1lo k probl\xC3\xA9mu p\xC5\x99i ukl\xC3\xA1d\xC3\xA1n\xC3\xAD nastaven\xC3\xAD." auth_change_submit: !binary | Wm3Em25pdCB6cMWvc29iIHDFmWlobGHFoW92w6Fuw60= select_authentication_type: "Vyberte nov\xC3\xBD zp\xC5\xAFsob autentizace a stiskn\xC4\x9Bte 'Zm\xC4\x9Bnit zp\xC5\xAFsob p\xC5\x99ihla\xC5\xA1ov\xC3\xA1n\xC3\xAD'." total_notes: "Pozn\xC3\xA1mek celkem" - contexts: - delete_context_title: Smazat kontext - hide_form: "Schovat formul\xC3\xA1\xC5\x99" - all_completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly v kontextu '%{context_name}'" - show_form_title: "Nov\xC3\xBD kontext" - delete_context_confirmation: "Opravdu chcete smazat kontext '%{name}'? Dojde ke smaz\xC3\xA1n\xC3\xAD v\xC5\xA1ech (opakovan\xC3\xBDch) \xC3\xBAkol\xC5\xAF z dan\xC3\xA9ho kontextu!" - todos_append: "v t\xC3\xA9to souvislosti" - delete_context: Smazat kontext - edit_context: Upravit kontext - hide_form_title: "Schovat formul\xC3\xA1\xC5\x99" - context_hide: "Schovat z \xC3\xBAvodn\xC3\xAD str\xC3\xA1nky?" - hidden_contexts: Schovat kontexty - no_contexts_active: !binary | - xb3DoWRuw6kgYWt0aXZuw60ga29udGV4dHk= - - show_form: "Nov\xC3\xBD kontext" - visible_contexts: "Viditeln\xC3\xA9 kontexty" - save_status_message: "Kontext ulo\xC5\xBEen" - add_context: "Vytvo\xC5\x99it kontext" - update_status_message: "N\xC3\xA1zev kontextu byl zm\xC4\x9Bn\xC4\x9Bn" - context_name: "N\xC3\xA1ev kontextu" - status_active: "Kontext je aktivn\xC3\xAD" - completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly v kontextu '%{context_name}'" - new_context_post: "' bude tak\xC3\xA9 vytvo\xC5\x99en. Opravdu?" - no_actions: "\xC5\xBD\xC3\xA1dn\xC3\xA9 aktivn\xC3\xAD \xC3\xBAkoly v tomto kontextu" - last_completed_in_context: "v tomto kontextu (posledn\xC3\xADch %{number})" - context_deleted: "Kontext byl odstran\xC4\x9Bn '%{name}'" - no_contexts_hidden: !binary | - xb3DoWRuw6kgc2tyeXTDqSBrb250ZXh0eQ== - - new_context_pre: "Nov\xC3\xBD kontext '" - status_hidden: "kontext je skryt\xC3\xBD" sidebar: list_name_active_contexts: "Aktivn\xC3\xAD kontexty" list_name_active_projects: "Aktivn\xC3\xAD projekty" @@ -1258,12 +1230,43 @@ cz: list_name_completed_projects: "Hotov\xC3\xA9 projekty" list_name_hidden_projects: "Skryt\xC3\xA9 projekty" list_name_hidden_contexts: "Skryt\xC3\xA9 kontexty" + contexts: + delete_context_title: Smazat kontext + hide_form: "Schovat formul\xC3\xA1\xC5\x99" + all_completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly v kontextu '%{context_name}'" + show_form_title: "Nov\xC3\xBD kontext" + delete_context_confirmation: "Opravdu chcete smazat kontext '%{name}'? Dojde ke smaz\xC3\xA1n\xC3\xAD v\xC5\xA1ech (opakovan\xC3\xBDch) \xC3\xBAkol\xC5\xAF z dan\xC3\xA9ho kontextu!" + delete_context: Smazat kontext + todos_append: "v t\xC3\xA9to souvislosti" + edit_context: Upravit kontext + hide_form_title: "Schovat formul\xC3\xA1\xC5\x99" + no_contexts_active: !binary | + xb3DoWRuw6kgYWt0aXZuw60ga29udGV4dHk= + + context_hide: "Schovat z \xC3\xBAvodn\xC3\xAD str\xC3\xA1nky?" + hidden_contexts: Schovat kontexty + visible_contexts: "Viditeln\xC3\xA9 kontexty" + save_status_message: "Kontext ulo\xC5\xBEen" + show_form: "Nov\xC3\xBD kontext" + add_context: "Vytvo\xC5\x99it kontext" + context_name: "N\xC3\xA1ev kontextu" + update_status_message: "N\xC3\xA1zev kontextu byl zm\xC4\x9Bn\xC4\x9Bn" + completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly v kontextu '%{context_name}'" + status_active: "Kontext je aktivn\xC3\xAD" + new_context_post: "' bude tak\xC3\xA9 vytvo\xC5\x99en. Opravdu?" + context_deleted: "Kontext byl odstran\xC4\x9Bn '%{name}'" + no_contexts_hidden: !binary | + xb3DoWRuw6kgc2tyeXTDqSBrb250ZXh0eQ== + + new_context_pre: "Nov\xC3\xBD kontext '" + no_actions: "\xC5\xBD\xC3\xA1dn\xC3\xA9 aktivn\xC3\xAD \xC3\xBAkoly v tomto kontextu" + last_completed_in_context: "v tomto kontextu (posledn\xC3\xADch %{number})" + status_hidden: "kontext je skryt\xC3\xBD" login: - sign_in: "P\xC5\x99ihl\xC3\xA1sit se" openid_identity_url_not_found: "Je n\xC3\xA1m l\xC3\xADto, neexistuje u\xC5\xBEivatel s touto identitou (%{identity_url})" user_no_expiry: "Neodhl\xC5\xA1ovat" login_cas: "p\xC5\x99ej\xC3\xADt na CAS" - cas_logged_in_greeting: "Zdrav\xC3\xAD\xC4\x8Dko, %{username}! Byl jste autorizov\xC3\xA1n." + sign_in: "P\xC5\x99ihl\xC3\xA1sit se" cas_no_user_found: "Nazdar, %{username}! Nem\xC3\xA1te \xC3\xBA\xC4\x8Det na Tracks." cas_login: !binary | UMWZaWhsw6HFoWVuw60gcMWZZXMgQ0FT @@ -1272,6 +1275,7 @@ cz: UMWZaWhsw6HFoWVuw60gYnlsbyDDunNwxJvFoW7DqTo= please_login: "Pro pokra\xC4\x8Dov\xC3\xA1n\xC3\xAD se pros\xC3\xADm p\xC5\x99ihl\xC5\xA1te do Tracks" + cas_logged_in_greeting: "Zdrav\xC3\xAD\xC4\x8Dko, %{username}! Byl jste autorizov\xC3\xA1n." cas_username_not_found: "Bohu\xC5\xBEel neexistuje u\xC5\xBEivatel v CASu se jm\xC3\xA9nem (%{username})" cas_create_account: "Pro vytvo\xC5\x99en\xC3\xAD \xC3\xBA\xC4\x8Dtu v CASu pros\xC3\xADm pokra\xC4\x8Dujte sem %{signup_link}" mobile_use_openid: !binary | diff --git a/config/locales/de.yml b/config/locales/de.yml index fdc53b65..b52875d3 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1,5 +1,63 @@ --- de: + common: + back: "Zur\xC3\xBCck" + recurring_todos: Wiederholenden Aktionen + actions: Aktionen + third: Dritte + add: "Hinzuf\xC3\xBCgen" + previous: Vorherige + go_back: "Zur\xC3\xBCck" + logout: Abmelden + second: Zweite + actions_midsentence: Aktionen + optional: optional + week: Woche + none: Keine + show_all: Alle einzeigen + cancel: Abbrechen + month: Monat + server_error: Auf dem Server ist ein Fehler aufgetreten. + notes: Notizen + forum: Forum + last: Letzte + review: !binary | + w5xiZXJwcsO8ZnVuZw== + + projects: Projekte + action: Aktion + project: Projekt + contribute: Mitwirken + ok: Ok + first: Erste + website: Website + numbered_step: Schritt %{number} + create: Erstellen + sort: + by_task_count_title: Nach Anzahl der Aufgaben sortieren + by_task_count_title_confirm: Sollen diese Projekte wirklich nach Anzahl der Aufgaben sortiert werden? Die bisherige Sortier-Reihenfolge wird damit überschrieben. + alphabetically: Alphabetisch + sort: Sortieren + alphabetically_confirm: Sollen diese Projekte wirklich alphabetisch sortiert werden? Die bisherige Sortier-Reihenfolge wird damit überschrieben. + alphabetically_title: Projekte alphabetisch sortieren + by_task_count: Nach Anzahl der Aufgaben + drag_handle: Verschieben + months: Monate + description: Beschreibung + fourth: Vierte + next: "N\xC3\xA4chste" + contexts: Kontexte + todo: Aktione + context: Kontext + errors_with_fields: "Mit folgenden Feldern sind Probleme aufgetreten:" + update: Aktualisieren + weeks: Woche + forth: Vierte + wiki: Wiki + bugs: Bugs + ajaxError: Fehler beim Empfangen vom Server + email: E-Mail + search: Suchen number: format: separator: "," @@ -34,66 +92,10 @@ de: separator: . precision: delimiter: "," - common: - back: "Zur\xC3\xBCck" - recurring_todos: Wiederholenden Aktionen - actions: Aktionen - third: Dritte - add: "Hinzuf\xC3\xBCgen" - previous: Vorherige - go_back: "Zur\xC3\xBCck" - logout: Abmelden - second: Zweite - optional: optional - week: Woche - none: Keine - cancel: Abbrechen - month: Monat - forum: Forum - server_error: Auf dem Server ist ein Fehler aufgetreten. - notes: Notizen - last: Letzte - review: !binary | - w5xiZXJwcsO8ZnVuZw== - - projects: Projekte - action: Aktion - project: Projekt - ok: Ok - contribute: Mitwirken - first: Erste - website: Website - numbered_step: Schritt %{number} - errors_with_fields: "Mit folgenden Feldern sind Probleme aufgetreten:" - create: Erstellen - sort: - by_task_count_title: Nach Anzahl der Aufgaben sortieren - by_task_count_title_confirm: Sollen diese Projekte wirklich nach Anzahl der Aufgaben sortiert werden? Die bisherige Sortier-Reihenfolge wird damit überschrieben. - alphabetically: Alphabetisch - sort: Sortieren - alphabetically_confirm: Sollen diese Projekte wirklich alphabetisch sortiert werden? Die bisherige Sortier-Reihenfolge wird damit überschrieben. - alphabetically_title: Projekte alphabetisch sortieren - by_task_count: Nach Anzahl der Aufgaben - months: Monate - drag_handle: Verschieben - description: Beschreibung - fourth: Vierte - next: "N\xC3\xA4chste" - contexts: Kontexte - todo: Aktione - context: Kontext - update: Aktualisieren - weeks: Woche - forth: Vierte - wiki: Wiki - bugs: Bugs - email: E-Mail - ajaxError: Fehler beim Empfangen vom Server - search: Suchen layouts: toggle_contexts_title: Machen Sie brach Kontexten (un)sichtbare - toggle_contexts: Toggle zusammengebrochen Kontexten toggle_notes: Notizen umschalten + toggle_contexts: Toggle zusammengebrochen Kontexten next_actions_rss_feed: RSS-Feed kommende Aufgaben toggle_notes_title: Alle Notizen umschalten mobile_navigation: @@ -106,13 +108,13 @@ de: contexts: Kontexte home: Home navigation: - api_docs: REST API Docs manage_users_title: "Benutzer hinzuf\xC3\xBCgen oder entfernen" recurring_todos: Sich wiederholende To-Dos + api_docs: REST API Docs feeds: Feeds stats: Statistiken - starred: Markiert notes_title: Alle Notizen anzeigen + starred: Markiert manage_users: Benutzer verwalten tickler_title: Notizbuch integrations_: Tracks integrieren @@ -120,22 +122,22 @@ de: preferences: Einstellungen feeds_title: "Liste der verf\xC3\xBCgbaren Feeds anzeigen" calendar_title: "Kalender mit \xC3\xBCberf\xC3\xA4lligen Aufgaben" - home_title: Start - tickler: Notizbuch - starred_title: Markierte Aufgaben betrachten recurring_todos_title: Sich wiederholende To-Dos verwalten + tickler: Notizbuch completed_tasks: Erledigt stats_title: Statistiken anzeigen + home_title: Start + starred_title: Markierte Aufgaben betrachten view: Betrachten organize: Organisieren completed_tasks_title: "Vollst\xC3\xA4ndig" home: Start contexts_title: Kontexte export: Export + projects_title: Projekte + search: "Alle Eintr\xC3\xA4ge durchsuchen" preferences_title: Meine Einstellungen review_title: "Machen Sie \xC3\xBCberpr\xC3\xBCfen" - search: "Alle Eintr\xC3\xA4ge durchsuchen" - projects_title: Projekte calendar: Kalender integrations: opensearch_description: In Tracks suchen @@ -165,23 +167,23 @@ de: show_hidden_projects_in_sidebar: Zeige Versteckte Projekte in der Sidebar date_format: Datum Format show_hidden_contexts_in_sidebar: "Zeige Versteckte Zusammenh\xC3\xA4nge in der Sidebar" + verbose_action_descriptors: "Ausf\xC3\xBChrlich Aktion Deskriptoren" mobile_todos_per_page: Aufgaben pro Seite (Mobile Version) staleness_starts: Anfang des Abgestandenheit - verbose_action_descriptors: "Ausf\xC3\xBChrlich Aktion Deskriptoren" sms_context: Standard-E-Mail-Kontext - title_date_format: Titel Datumsformat show_number_completed: "Zeige Zahl der abgeschlossenen Ma\xC3\x9Fnahmen" + title_date_format: Titel Datumsformat refresh: Aktualisierungsintverall (in Minuten) week_starts: Woche startet am last_name: Nachname locale: Zahle - due_style: "F\xC3\xA4llig stijl" time_zone: Zeit Zone + due_style: "F\xC3\xA4llig stijl" sms_email: Per E-Mail show_project_on_todo_done: Zur Projektseite wechseln, wenn To-Do abgeschlossen show_completed_projects_in_sidebar: Zeige abgeschlossene Projekte in der Sidebar - review_period: Projekt-Review-Intervall first_name: Name + review_period: Projekt-Review-Intervall errors: models: project: @@ -211,13 +213,13 @@ de: taken: ist bereits vergeben inclusion: "ist kein g\xC3\xBCltiger Wert" not_a_number: ist keine Zahl - full_messages: - format: "%{attribute} %{message}" template: body: "Bitte \xC3\xBCberpr\xC3\xBCfen Sie die folgenden Felder:" header: one: "Konnte dieses %{model} Objekt nicht speichern: 1 Fehler." other: "Konnte dieses %{model} Objekt nicht speichern: %{count} Fehler." + full_messages: + format: "%{attribute} %{message}" data: import_successful: Import war erfolgreich. import_errors: Beim Import sind Fehler aufgetreten. @@ -237,30 +239,31 @@ de: - "F\xC3\xA4llig in ___ Tagen" - "F\xC3\xA4llig am _______" stats: + tag_cloud_title: Tag-Cloud aller Aktionen totals_hidden_context_count: und %{count} sind versteckte Kontexte. actions_avg_created: In den letzten 12 Monaten hast du im Durchschnitt %{count} Aktionen erstellt actions_min_max_completion_days: "Das Minimum/Maximum an Tagen einer Vervollst\xC3\xA4ndigung ist %{min}/%{max}." totals_actions_completed: "%{count} davon sind abgeschlossen." - tag_cloud_title: Tag-Cloud aller Aktionen actions_actions_avg_created_30days: In den letzten 30 Tagen hast du im Durchschnitt %{count} Aktionen erstellt actions_avg_completed: und %{count} durchschnittlich davon monatlich erledigt top5_visible_contexts_with_incomplete_actions: "Top 5 der sichtbaren Kontexte mit unvollst\xC3\xA4ndigen Aktionen" actions: Aktionen - totals_deferred_actions: "von denen %{count} im Notizbuch zur\xC3\xBCckgestellt sind" time_of_day_legend: number_of_actions: Anzahl Aufgaben time_of_day: Tageszeit totals_incomplete_actions: "Du hast %{count} unvollst\xC3\xA4ndige Aktionen" + totals_action_count: hattest du insgesamt %{count} Aktionen running_time_legend: actions: Aufgaben percentage: Prozentsatz weeks: "Vergangene Zeit einer Aktion (Wochen). Klick auf eine Leiste f\xC3\xBCr mehr Informationen." - totals_action_count: hattest du insgesamt %{count} Aktionen + totals_deferred_actions: "von denen %{count} im Notizbuch zur\xC3\xBCckgestellt sind" tag_cloud_90days_title: Tag-Cloud-Aktionen in den letzten 90 Tagen tod30: Tageszeit (letzte 30 Tage) tags: Tags projects: Projekte actions_avg_completion_time: Durchschnittlich hast du %{count} Tage gebraucht, um eine Aktion abzuschliessen. + actions_day_of_week_title: Wochentag (alle Aktionen) labels: month_avg_completed: "%{months} Monat durchschnittlich fertig gestellt" completed: Erledigt @@ -268,22 +271,21 @@ de: avg_created: Durchschnittlich erstellt avg_completed: Durchschnittlich fertiggestellt created: Erstellt - actions_selected_from_week: "Aktionen ausgew\xC3\xA4hlt ab Woche" totals_completed_project_count: und %{count} sind abgeschlossene Projekte. - actions_day_of_week_title: Wochentag (alle Aktionen) + actions_selected_from_week: "Aktionen ausgew\xC3\xA4hlt ab Woche" actions_lastyear_title: Aktionen der letzten 12 Monate open_per_week: "Aktiv (sichtbar und unsichtbar) n\xC3\xA4chsten Aktionen pro Woche" action_selection_title: TRACKS::Aktionsauswahl totals_project_count: Du hast %{count} Projekte. - current_running_time_of_incomplete_visible_actions: "Aktuelle Laufzeit unvollst\xC3\xA4ndiger sichtbarer Aufgaben" legend: number_of_days: Anzahl vergangene Tage actions: Aktionen number_of_actions: Anzahl Aktionen day_of_week: Wochentag - percentage: Prozentsatz running_time: Laufzeit einer Aktion (Wochen) + percentage: Prozentsatz months_ago: Monate zuvor + current_running_time_of_incomplete_visible_actions: "Aktuelle Laufzeit unvollst\xC3\xA4ndiger sichtbarer Aufgaben" tod30_legend: number_of_actions: Anzahl Aufgaben time_of_day: Tageszeit @@ -296,82 +298,82 @@ de: months_ago: Monate zuvor top10_projects: Top 10 aller Projekte top5_contexts: Top 5 aller Kontexte - contexts: Kontexte totals: Ingesamt + contexts: Kontexte click_to_return: "Klick auf %{link} um zur Statistikseite zur\xC3\xBCckzukehren." tag_cloud_90days_description: Diese Tag-Cloud beinhaltet Tags der Aktionen, die in den letzten 90 Tagen erstellt oder abgeschlossen wurden. totals_visible_context_count: Von diesen sind %{count} sichtbare Kontexte - top10_projects_30days: Top-10-Projekt der letzten 30 Tage running_time_all: "Aktuelle Laufzeit aller unvollst\xC3\xA4ndigen Aktionen." + top10_projects_30days: Top-10-Projekt der letzten 30 Tage actions_min_completion_time: "Die minimale Zeit betr\xC3\xA4gt %{time}." action_completion_time_title: Fertigstellungszeit (alle abgeschlossenen Aktionen) click_to_show_actions_from_week: Klick auf %{link} um die Aktionen von Woche %{week} und danach anzuzeigen. top10_longrunning: "Top 10 der am l\xC3\xA4ngsten laufenden Projekte" no_actions_selected: "Es sind keine Aufgaben ausgew\xC3\xA4hlt." - totals_tag_count: Du hast %{count} Tags in Aktionen. actions_further: und danach + totals_tag_count: Du hast %{count} Tags in Aktionen. actions_dow_30days_legend: number_of_actions: Anzahl der Aktionen day_of_week: Tag der Woche totals_first_action: Seit deiner ersten Aktion am %{date} tag_cloud_description: Diese Tag-Cloud beinhaltet Tags aller Aktionen (abgeschlossen, nicht abgeschlossen, sichtbar und/oder unsichtbar) - click_to_return_link: hier click_to_update_actions: Klicke auf eine Leiste in der Grafik um die Aktionen unten zu aktualisieren. + click_to_return_link: hier spread_of_actions_for_all_context: Aufgabenverteilung aller Kontexte more_stats_will_appear: "Weitere Statistiken werden verf\xC3\xBCgbar, wenn einige Aufgaben hinzugef\xC3\xBCgt wurden." actions_avg_completed_30days: und %{count} durchschnittlich davon erledigt. - no_tags_available: "keine Tags verf\xC3\xBCgbar" - actions_30days_title: _Aktionen der letzten 30 Tage - index_title: TRACKS::Statistik actions_dow_30days_title: Wochentag (letzte 30 Tage) - spread_of_running_actions_for_visible_contexts: Verteilung der laufenden Aufgaben aller sichtbaren Kontexte + actions_30days_title: _Aktionen der letzten 30 Tage + no_tags_available: "keine Tags verf\xC3\xBCgbar" + index_title: TRACKS::Statistik actions_day_of_week_legend: number_of_actions: Anzahl der Aktionen day_of_week: Tag der Woche - actions_last_year: Aktionen im letzten Jahr + spread_of_running_actions_for_visible_contexts: Verteilung der laufenden Aufgaben aller sichtbaren Kontexte totals_blocked_actions: "%{count} h\xC3\xA4ngen vom Abschluss anderer Aktionen ab." + actions_last_year: Aktionen im letzten Jahr totals_unique_tags: Von diesen Tags sind %{count} einmalig.. totals_active_project_count: Von diesen sind %{count} aktive Projekte running_time_all_legend: actions: Aktionen - percentage: Prozentsatz running_time: "Laufzeit einer Aktion (Wochen). Klick auf eine Leiste f\xC3\xBCr mehr Informationen." + percentage: Prozentsatz other_actions_label: (andere) - time_of_day: Tageszeit (alle Aktionen) totals_hidden_project_count: "%{count} sind versteckt" + time_of_day: Tageszeit (alle Aktionen) todos: show_from: Anzeigen ab dem error_starring_recurring: Konnte die Hervorhebung der wiederkehrenden Aufgabe \'%{description}\' nicht durchführen recurring_action_deleted: Die Aktion wurde gelöscht. Da dies eine wiederkehrende Aktion ist, wurde eine neue erstellt. completed_actions: Erledigte Aufgaben - blocked_by: Blockiert durch %{predecessors} + completed_rest_of_previous_month: Fertiggestellt den Rest des Vormonats completed_recurring: Abgeschlossene wiederkehrende To-Dos added_new_next_action: Neue Aktion angelegt - completed_rest_of_previous_month: Fertiggestellt den Rest des Vormonats - defer_date_after_due_date: "Zur\xC3\xBCckstellungsdatum nach Ablaufdatum. Bitte passe das Ablaufdatum an, dass es vor dem Zur\xC3\xBCckstellungsdatum liegt." - star_action: Aktion markieren + blocked_by: Blockiert durch %{predecessors} completed_recurrence_completed: Es gibt keine weitere Aktion nach der soeben gelöschten. Die Wiederholung ist abgeschlossen. + star_action: Aktion markieren + defer_date_after_due_date: "Zur\xC3\xBCckstellungsdatum nach Ablaufdatum. Bitte passe das Ablaufdatum an, dass es vor dem Zur\xC3\xBCckstellungsdatum liegt." unable_to_add_dependency: Abhängigkeit nicht hinzufügbar done: Erledigt? star_action_with_description: Aktion '%{description}' markieren tagged_with: getagged mit ‘%{tag_name}’ completed: Erledigt no_deferred_actions_with: "Keine zur\xC3\xBCckgestellten Aktionen mit dem Tag '%{tag_name}'" + edit_action_with_description: Aktion '%{description}' bearbeiten no_hidden_actions: Momentan sind keine versteckten Aufgaben vorhanden action_due_on: "(Aktion f\xC3\xA4llig am %{date})" - edit_action_with_description: Aktion '%{description}' bearbeiten archived_tasks_title: TRACKS::Archivierte erledigte Aufgaben remove_dependency: Abhängigkeit löschen (löscht nicht die Aufgabe) list_incomplete_next_actions: Unerledigte Folge-Aufgaben anzeigen tags: Tags (Komma-separiert) action_deleted_success: Die nächste Aktion erfolgreich gelöscht - add_another_dependency: "F\xC3\xBCgen Sie eine andere Abh\xC3\xA4ngigkeit" new_related_todo_created: "Eine neue To-Do wurde hinzugef\xC3\xBCgt, die zu dieser wiederkehrenden To-Do geh\xC3\xB6rt" context_changed: Kontext zu %{name} gewechselt + add_another_dependency: "F\xC3\xBCgen Sie eine andere Abh\xC3\xA4ngigkeit" mobile_todos_page_title: Alle Aufgaben delete_recurring_action_title: "Wiederkehrende Aktion '%{description}' l\xC3\xB6schen" - recurring_actions_title: TRACKS::Wiederkehrende Aktionen removed_predecessor: "%{successor} entfernt als Abh\xC3\xA4ngigkeit von %{predecessor}." + recurring_actions_title: TRACKS::Wiederkehrende Aktionen next_action_needed: Es muss mindestens eine folgende Aktion angelegt werden action_saved: Aktion gespeichert scheduled_overdue: "Planm\xC3\xA4\xC3\x9Fig angezeigt vor %{days} Tagen" @@ -379,7 +381,6 @@ de: edit_action: Aktion bearbeiten added_new_context: "Neuer Kontext hinzugef\xC3\xBCgt" next_actions_description: "Filter:" - older_completed_items: "Ältere erledigte Aufgaben" list_incomplete_next_actions_with_limit: Zeige die letzten %{count} unerledigten Folge-Aufgaben set_to_pending: "%{task} als ausstehend markiert" added_new_project: "Neues Projekt hinzugef\xC3\xBCgt" @@ -387,28 +388,29 @@ de: completed: Aufgaben erledigt due_today: heute fällig due_within_a_week: diese Woche fällig - task_list_title: TRACKS::Aufgaben anzeigen + older_completed_items: "Ältere erledigte Aufgaben" + error_deleting_item: Beim Löschen von %{description} trat ein Fehler auf edit_recurring_todo: Bearbeiten Repetieren aktion append_in_this_project: in diesem Projekt - error_deleting_item: Beim Löschen von %{description} trat ein Fehler auf + task_list_title: TRACKS::Aufgaben anzeigen no_actions_due_this_week: Keine zu erledigenden Aufgaben für den Rest der Woche - error_completing_todo: Beim Abschliessen/Aktivieren der wiederkehrenden To-Do %{description} ist ein Fehler aufgetreten + no_deferred_pending_actions: Momentan sind keine aufgeschobenen oder ausstehenden Aufgaben vorhanden. no_recurring_todos: Im Augenblick gibt es keine wiederkehrenden To-Dos + error_completing_todo: Beim Abschliessen/Aktivieren der wiederkehrenden To-Do %{description} ist ein Fehler aufgetreten recurring_pattern_removed: Das Wiederauftreten Muster ist aus entfernt %{count} convert_to_project: In Projekt umwandeln - no_deferred_pending_actions: Momentan sind keine aufgeschobenen oder ausstehenden Aufgaben vorhanden. delete_recurring_action_confirm: Soll die wiederkehrende Aktion '%{description}' wirklich gelöscht werden? completed_last_day: In den letzten 24 Stunden erledigt - all_completed: Alle abgeschlossenen Aktionen show_in_days: Anzeigen in %{days} Tagen no_project: --Kein Projekt-- error_saving_recurring: Es gab einen Fehler beim Speichern der wiederkehrenden todo '%{description}' completed_more_than_x_days_ago: Vor mehr als %{count} Tagen erledigt - feed_title_in_context: im Kontext '%{context}' new_related_todo_created_short: hat einen neuen todo + feed_title_in_context: im Kontext '%{context}' + all_completed: Alle abgeschlossenen Aktionen edit: Bearbeiten - completed_tagged_page_title: "TRACKS:: Erledigte Aufgaben mit Tag %{tag_name}" older_than_days: "Älter als %{count} Tage" + completed_tagged_page_title: "TRACKS:: Erledigte Aufgaben mit Tag %{tag_name}" pending: Ausstehend completed_actions_with: Abgeschlossene Aktionen mit dem Tag %{tag_name} feed_title_in_project: im Projekt '%{project}' @@ -417,10 +419,10 @@ de: clear_due_date: Fälligkeitsdatum leeren error_removing_dependency: "Beim Entfernen der Abh\xC3\xA4ngigkeit ist ein Fehler aufgetreten" hidden_actions: Verstecke Aufgaben + deferred_actions_with: "Zur\xC3\xBCckgestellte Aktionen mit dem Tag '%{tag_name}'" was_due_on_date: war am %{date} fällig show_on_date: Anzeigen am %{date} recurrence_period: Wiederholungszeitraum - deferred_actions_with: "Zur\xC3\xBCckgestellte Aktionen mit dem Tag '%{tag_name}'" confirm_delete: "Bist du sicher, dass du die Aktion '%{description}' l\xC3\xB6schen m\xC3\xB6chtest?" recurring_deleted_success: "Die wiederkehrende Aktion wurde erfolgreich gel\xC3\xB6scht." next_actions_title: TRACKS::Weitere Aufgaben @@ -429,21 +431,21 @@ de: no_completed_actions_with: Keine abgeschlossenen Aktionen mit dem Tag '%{tag_name}' clear_show_from_date: Datum leeren calendar_page_title: TRACKS::Kalender - unresolved_dependency: "Der Wert, den Sie in die Abh\xC3\xA4ngigkeit Feld eingegeben nicht zu einer bestehenden Aktion zu l\xC3\xB6sen. Dieser Wert wird nicht mit dem Rest der Aktion gerettet werden. Weiter gehen?" in_hidden_state: als versteckt markiert - show_today: Heute anzeigen - no_actions_found_title: Keine Aktionen gefunden + unresolved_dependency: "Der Wert, den Sie in die Abh\xC3\xA4ngigkeit Feld eingegeben nicht zu einer bestehenden Aktion zu l\xC3\xB6sen. Dieser Wert wird nicht mit dem Rest der Aktion gerettet werden. Weiter gehen?" next_actions_due_date: overdue_by: "\xC3\x9Cberf\xC3\xA4llig mit %{days} Tag" - due_today: "Heute f\xC3\xA4llig" due_in_x_days: "F\xC3\xA4llig in %{days} Tagen" + due_today: "Heute f\xC3\xA4llig" overdue_by_plural: "\xC3\x9Cberf\xC3\xA4llig mit %{days} Tagen" due_tomorrow: "F\xC3\xA4llig morgen" + show_today: Heute anzeigen + no_actions_found_title: Keine Aktionen gefunden completed_last_x_days: In den letzten %{count} Tagen erledigt - no_actions_with: "Im Augenblick gibt es keine unvollst\xC3\xA4ndigen Aktionen mit dem Tag '%{tag_name}'" defer_x_days: one: "Einen Tag zur\xC3\xBCckstellen" other: "%{count} Tage zur\xC3\xBCckstellen" + no_actions_with: "Im Augenblick gibt es keine unvollst\xC3\xA4ndigen Aktionen mit dem Tag '%{tag_name}'" added_new_next_action_singular: Neue weiterführende Aufgabe angelegt no_completed_actions: Momentan sind keine erledigten Aufgaben vorhanden. feeds: @@ -457,16 +459,16 @@ de: error_deleting_recurring: "Beim L\xC3\xB6schen der wiederkehrenden To-Do %{description} ist ein Fehler aufgetreten" recurring_todos: Wiederkehrende To-Dos delete: "L\xC3\xB6schen" - cannot_add_dependency_to_completed_todo: "Kann nicht hinzugef\xC3\xBCgt werden diese Aktion als eine Abh\xC3\xA4ngigkeit zu einer abgeschlossenen Aktion!" drag_action_title: "Auf andere Aktion ziehen, um sie als Abh\xC3\xA4ngigkeit zu definieren" + cannot_add_dependency_to_completed_todo: "Kann nicht hinzugef\xC3\xBCgt werden diese Aktion als eine Abh\xC3\xA4ngigkeit zu einer abgeschlossenen Aktion!" no_last_completed_actions: Keine abgeschlossene Aktionen gefunden tickler_items_due: one: Ein Notizbuch-Eintrag ist nun fällig - lade die Seite neu, um sie zu sehen. other: "%{count} Notizbuch-Einträge sind nun fällig - lade die Seite neu, um sie zu sehen." depends_on: "H\xC3\xA4ngt ab von" action_marked_complete: Die Aktion '%{description}' wurde als %{completed} markiert. - completed_today: Heute Fertiggestellt added_new_next_action_plural: Neue weiterführende Aufgaben angelegt + completed_today: Heute Fertiggestellt new_related_todo_not_created_short: nicht schaffen todo completed_rest_of_week: Fertiggestellt den Rest dieser Woche error_starring: Konnte die Hervorhebung von \'%{description}\' nicht durchführen @@ -476,14 +478,13 @@ de: due_next_week: Nächste Woche fällig no_actions_due_next_week: Keine Aufgaben für die kommende Woche due_this_week: Die restliche Woche zu erledigen - due_today: Heute zu erledigen no_actions_due_today: Heute sind keine Aufgaben fällig + due_today: Heute zu erledigen due_next_month_and_later: Im %{month} und später fällig no_actions_due_after_this_month: Nach diesem Monat sind keine Aufgaben fällig no_actions_due_this_month: Keine Aktionen für den Rest des Monats due_this_month: Im %{month} fällig action_deferred: Die Aktion \'% {description}\' wurde vertagt - added_dependency: "%{dependency} als Abhängigkeit hinzugefügt." recurrence: ends_on_number_times: Endet nach %{number} Mal ends_on_date: Endet am %{date} @@ -498,6 +499,7 @@ de: show_option_always: immer daily: "T\xC3\xA4glich" pattern: + third: Drittel month_names: - - Januar @@ -514,7 +516,6 @@ de: - Oktober - November - Dezember - third: Drittel every_n: jeden %{n} second: zweite every_xth_day_of_every_n_months: "jedes %{x} %{day} jedes %{n_months} \xE2\x80\x8B" @@ -526,6 +527,9 @@ de: the_xth_day_of_month: der %{x} %{day} von %{month} times: "f\xC3\xBCr %{number} Zeiten" every_year_on: jedes Jahr in %{date} + on_work_days: an Wochentagen + first: erste + show: Show day_names: - Sonntag - Montag @@ -534,9 +538,6 @@ de: - Donnerstag - Freitag - Samstag - show: Show - first: erste - on_work_days: an Wochentagen fourth: vierte due: "F\xC3\xA4llig" until: bis @@ -547,37 +548,38 @@ de: ends_on: Endet am show_options: To-Do anzeigen weekly_every_number_week: Kehrt jede %{number}. Woche wieder am - show_days_before: "%{days} Tage bevor die To-Do f\xC3\xA4llig ist" - yearly_every_xth_day: Den %{day} %{day_of_week} des %{month} from_tickler: the date todo comes from tickler (no due date set) + yearly_every_xth_day: Den %{day} %{day_of_week} des %{month} no_end_date: Kein Enddatum day_x_on_every_x_month: Tag %{day} in jedem %{month}. Monat yearly_options: "Einstellungen f\xC3\xBCr sich j\xC3\xA4hrlich wiederholende Aktionen" + show_days_before: "%{days} Tage bevor die To-Do f\xC3\xA4llig ist" monthly_every_xth_day: Der %{day} %{day_of_week} eines jeden %{month}. Monats yearly: "J\xC3\xA4hrlich" tagged_page_title: TRACKS::Als '%{tag_name}' markiert no_completed_recurring: Im Augenblick gibt es keine abgeschlossenen wiederkehrenden To-Dos - completed_rest_of_month: Fertiggestellt den Rest des Monats - recurrence_completed: Nach dieser wiederkehrenden Aktion, die du gerade abgeschlossen hast, folgt keine mehr. Die Wiederholung endet hiermit + added_dependency: "%{dependency} als Abhängigkeit hinzugefügt." all_completed_tagged_page_title: "TRACKS:: Alle erledigten Aufgaben mit Tag %{tag_name}" no_deferred_actions: Zur Zeit sind keine zurückgestellten Aktionen vorhanden. - in_pending_state: und als ausstehend markiert + completed_rest_of_month: Fertiggestellt den Rest des Monats + recurrence_completed: Nach dieser wiederkehrenden Aktion, die du gerade abgeschlossen hast, folgt keine mehr. Die Wiederholung endet hiermit no_actions_found: "Momentan gibt es keine unvollst\xC3\xA4ndigen Aktionen." + in_pending_state: und als ausstehend markiert error_toggle_complete: "K\xC3\xB6nnte nicht diese Marke todo komplett" due: Fällig action_marked_complete_error: Die Aktion '%{description}' wurde aufgrund eines Fehlers NICHT als %{completed} markiert. + to_tickler: ", im Notizbuch hinterlegt" + add_new_recurring: "F\xC3\xBCge eine neue wiederkehrende Aktion hinzu" depends_on_separate_with_commas: Hängt ab von (Komma-separiert) recurring_action_saved: Wiederkehrende Aktion gespeichert action_saved_to_tickler: Aktion im Notizbuch gespeichert completed_in_archive: one: Es befindet sich eine erledigte Aufgabe im Archiv. other: Es befinden sich %{count} erledigte Aufgaben im Archiv. - to_tickler: ", im Notizbuch hinterlegt" next_actions_description_additions: completed: In den letzten %{count} Tagen due_date: mit einem Datum %{due_date} oder früher overdue: "Überfällig" - add_new_recurring: "F\xC3\xBCge eine neue wiederkehrende Aktion hinzu" no_incomplete_actions: Es gibt keine unerledigten Aufgaben notes: delete_note_title: Notiz '%{id}' löschen @@ -597,44 +599,42 @@ de: stalled: Stalled completed: Erledigt current: Auf dem neusten Stand - review: Datiert completed_plural: Erledigte + review: Datiert blocked_plural: Verstopft blocked: Verstopft stalled_plural: Stalled visible_plural: Sichtbare active_plural: Aktive visible: Sichtbar - current_plural: Auf dem neusten Stand hidden: Versteckt + current_plural: Auf dem neusten Stand active: Aktiv - errors: - user_unauthorized: "401 Unauthorized: Nur administrative Benutzer d\xC3\xBCrfen auf diese Funktion zugreifen." projects: - no_actions_in_project: "Momentan gibt es keine unvollst\xC3\xA4ndigen Aktionen in diesem Projekt" - deferred_actions: "Aufgeschobene Aufgaben f\xC3\xBCr dieses Projekt" - was_marked_hidden: wurde als verborgen markiert edit_project_title: Projekt bearbeiten default_tags_removed_notice: Standard-Tags entfernt default_context_set: Standard-Kontext des Projekts auf %{default_context} gesetzt + no_actions_in_project: "Momentan gibt es keine unvollst\xC3\xA4ndigen Aktionen in diesem Projekt" + deferred_actions: "Aufgeschobene Aufgaben f\xC3\xBCr dieses Projekt" + was_marked_hidden: wurde als verborgen markiert hide_form: Fomular verstecken - page_title: "TRACKS::Projekt: %{project}" all_completed_tasks_title: "TRACKS:: Alle auflisten Abgeschlossene Aktionen in Project '%{project_name}'" - project_state: Projekt ist %{state} + page_title: "TRACKS::Projekt: %{project}" + this_project: Dieses Projekt list_completed_projects: "TRACKS:: Liste Abgeschlossene Projekte" to_new_project_page: Zu neuem Projekt weiterleiten no_notes_attached: "Im Augenblick sind keine Notizen mit diesem Projekt verkn\xC3\xBCpft." show_form_title: Neues Projekt anlegen deferred_actions_empty: "Es gibt keine aufgeschobenen Aufgaben f\xC3\xBCr dieses Projekt" - this_project: Dieses Projekt + project_state: Projekt ist %{state} no_last_completed_recurring_todos: Keine abgeschlossene sich wiederholende To-Dos gefunden todos_append: an dieses Projekt no_last_completed_projects: Keine abgeschlossene Projekte gefunden notes: Notizen - hide_form_title: Formular verstecken - list_reviews: "TRACKS::R\xC3\xBCckblick" notes_empty: "Es gibt keine Notizen f\xC3\xBCr dieses Projekt" no_projects: Keine Projekte vorhanden + hide_form_title: Formular verstecken + list_reviews: "TRACKS::R\xC3\xBCckblick" completed_actions_empty: "Es gibt keine erledigten Aufgaben f\xC3\xBCr dieses Projekt" with_no_default_context: hat keinen Standardwert Kontext delete_project: Projekt löschen @@ -642,43 +642,45 @@ de: actions_in_project_title: Die Aktionen in diesem Projekt delete_project_confirmation: Soll das Projekt '%{name}' wirklich gelöscht werden? with_default_context: mit einem Standard-Rahmen von '%{context_name}' - set_default_tags_notice: Standard-Tags des Projekts auf %{default_tags} setzen + is_active: ist aktiv completed_projects: Abgeschlossene Projekte + project_saved_status: Projekt gespeichert add_note: "Notiz hinzuf\xC3\xBCgen" add_project: Projekt hinzufügen - settings: Einstellungen with_default_tags: und mit '%{tags}' als Standard-Tags + settings: Einstellungen list_projects: TRACKS::Projektliste - is_active: ist aktiv - project_saved_status: Projekt gespeichert + set_default_tags_notice: Standard-Tags des Projekts auf %{default_tags} setzen + completed_tasks_title: "TRACKS:: Liste Abgeschlossene Aktionen in Project '%{project_name}'" delete_project_title: Projekt löschen hidden_projects: Versteckte Projekte - completed_tasks_title: "TRACKS:: Liste Abgeschlossene Aktionen in Project '%{project_name}'" default_context_removed: Standard-Kontext entfernt - completed_actions: "Erledigte Aufgaben f\xC3\xBCr dieses Projekt" add_note_submit: "Notiz hinzuf\xC3\xBCgen" was_marked_complete: wurde als erledigt markiert + completed_actions: "Erledigte Aufgaben f\xC3\xBCr dieses Projekt" no_default_context: Dieses Projekt hat keinen Standard-Kontext with_no_default_tags: und hat keinen Standardwert Tags edit_project_settings: Edit Project Settings - status_project_name_changed: "Projektname ge\xC3\xA4ndert" state: Dieses Projekt ist %{state} + status_project_name_changed: "Projektname ge\xC3\xA4ndert" default_context: Der Standard-Kontext dieses Projektes ist %{context} active_projects: Aktive Projekte + errors: + user_unauthorized: "401 Unauthorized: Nur administrative Benutzer d\xC3\xBCrfen auf diese Funktion zugreifen." preferences: change_identity_url: "\xC3\x84ndere deine Identit\xC3\xA4ts-URL" - open_id_url: "Deine OpenID-URL lautet:" staleness_starts_after: Abgestandenheit startet nach %{days} Tagen + open_id_url: "Deine OpenID-URL lautet:" change_password: "Passwort \xC3\xA4ndern" page_title: TRACKS::Einstellungen token_description: "Token (f\xC3\xBCr die Verwendung in Feeds und der API)" title: Deine Einstellungen - is_false: Nein show_number_completed: "Zeige %{number} erledigte Eintr\xC3\xA4ge" + is_false: Nein + edit_preferences: Einstellungen bearbeiten page_title_edit: "TRACKS::Einstellungen \xC3\xA4ndern" is_true: Ja password_changed: "Ihr Passwort ge\xC3\xA4ndert wurde, melden Sie sich bitte wieder an." - edit_preferences: Einstellungen bearbeiten generate_new_token: Neues Token generieren sms_context_none: Keine token_header: Dein Token @@ -790,15 +792,15 @@ de: shared: multiple_next_actions: Mehrere neue Aufgaben (eine pro Zeile) make_actions_dependent: "Machen Sie Aktionen voneinander abh\xC3\xA4ngig" - hide_form: Formular verstecken toggle_single: Weitere Aktion erstellen + hide_form: Formular verstecken add_actions: "Aufgaben hinzuf\xC3\xBCgen" add_action: "Aufgabe hinzuf\xC3\xBCgen" tags_for_all_actions: "Tags f\xC3\xBCr alle Aufgaben (mit Kommas trennen)" - toggle_multi: "Mehrere neue Aufgabeneintr\xC3\xA4ge hinzuf\xC3\xBCgen" - toggle_single_title: Eine weitere Aktion hinzufügen project_for_all_actions: "Projekt f\xC3\xBCr alle Aufgaben" context_for_all_actions: "Kontext f\xC3\xBCr alle Aufgaben" + toggle_multi: "Mehrere neue Aufgabeneintr\xC3\xA4ge hinzuf\xC3\xBCgen" + toggle_single_title: Eine weitere Aktion hinzufügen separate_tags_with_commas: mit Kommas trennen toggle_multi_title: "Zwischen Einzel- und Mehrfachformular f\xC3\xBCr neue Aufgaben umschalten" hide_action_form_title: "Formular f\xC3\xBCr neue Aufgaben verstecken" @@ -807,8 +809,8 @@ de: feedlist: actions_due_today: "Heute oder fr\xC3\xBCher f\xC3\xA4llig" choose_context: "Kontext f\xC3\xBCr den Feed w\xC3\xA4hlen" - rss_feed: RSS-Feed legend: "Legende:" + rss_feed: RSS-Feed ical_feed: iCal-Feed all_contexts: Alle Kontexte all_projects: Alle Projekte @@ -817,89 +819,61 @@ de: select_feed_for_project: "Feed f\xC3\xBCr dieses Projekt ausw\xC3\xA4hlen" active_projects_wo_next: Aktive Projekte ohne ausstehende Aufgaben active_starred_actions: Alle markierten, aktiven Aufgaben - context_needed: Es muss mindestens ein Kontext existieren, bevor ein Feed abonniert werden kann. select_feed_for_context: "Feed f\xC3\xBCr diesen Kontext ausw\xC3\xA4hlen" projects_and_actions: Aktive Projekte und deren Aufgaben + context_needed: Es muss mindestens ein Kontext existieren, bevor ein Feed abonniert werden kann. actions_due_next_week: "In den n\xC3\xA4chsten 7 Tagen oder fr\xC3\xBCher f\xC3\xA4llige Aufgaben" notice_incomplete_only: "Hinweis: Alle Feeds zeigen nur Aufgaben, die noch nicht als erledigt markiert wurden." + context_centric_actions: "Feeds f\xC3\xBCr unvollst\xC3\xA4ndige Aufgaben in einem bestimmten Kontext" + plain_text_feed: Plain-Text-Feed last_fixed_number: Die letzten %{number} Aufgaben all_actions: Alle Aufgaben actions_completed_last_week: In den letzten 7 Tagen abgeschlossene Aufgaben - context_centric_actions: "Feeds f\xC3\xBCr unvollst\xC3\xA4ndige Aufgaben in einem bestimmten Kontext" - plain_text_feed: Plain-Text-Feed project_centric: "Feeds f\xC3\xBCr unvollst\xC3\xA4ndige Aufgaben in einem bestimmten Kontext" users: + first_user_heading: "Willkommen bei TRACKS. Als erstes legen Sie bitte einen Administrator-Zugang an:" successfully_deleted_user: Benutzer %{username} erfolgreich gelöscht. + auth_type_update_error: "Beim Ändern der Authentifizierung trat ein Fehler auf: %{error_messages}" failed_to_delete_user: Löschen des Benutzers %{username} fehlgeschlagen destroy_successful: "Benutzer %{login} wurde erfolgreich gel\xC3\xB6scht" total_contexts: Alle Kontexte openid_url_verified: Die URL %{url} wurde erfolgreich als Identität verifiziert und Deine Authentifizierung auf OpenID umgestellt. - first_user_heading: "Willkommen bei TRACKS. Als erstes legen Sie bitte einen Administrator-Zugang an:" - auth_type_update_error: "Beim Ändern der Authentifizierung trat ein Fehler auf: %{error_messages}" + signup_successful: Benutzer %{username} erfolgreich angelegt. new_token_generated: Neuer Token erfolgreich generiert total_projects: Alle Projekte - signup_successful: Benutzer %{username} erfolgreich angelegt. no_signups_title: TRACKS::Anmeldung nicht erlaubt user_created: Benutzer angelegt. change_password_submit: "Passwort \xC3\xA4ndern" - account_signup: Accounteinrichtung manage_users: Benutzer verwalten + account_signup: Accounteinrichtung password_updated: Passwort aktualisiert. - auth_type_updated: Authentifizierungs-Art erfolgreich geändert. total_actions: Alle Aufgaben desired_login: "Gew\xC3\xBCnschter Benutzername" - signup: Registrieren confirm_password: "Passwort best\xC3\xA4tigen" new_user_heading: "Einen neuen Benutzer anlegen:" - change_password_prompt: "Gib dein neues Passwort in die unten stehenden Felder ein und klicke auf 'Passwort \xC3\xA4ndern' um dein altes Passwort durch das neue zu ersetzen." - password_confirmation_label: "Passwort best\xC3\xA4tigen" + signup: Registrieren + auth_type_updated: Authentifizierungs-Art erfolgreich geändert. destroy_error: "Beim L\xC3\xB6schen des Benutzers %{login} ist ein Fehler aufgetreten." choose_password: "Passwort w\xC3\xA4hlen" change_password_title: TRACKS::Passwort ändern change_auth_type_title: TRACKS::Authentifizierungstyp ändern + change_password_prompt: "Gib dein neues Passwort in die unten stehenden Felder ein und klicke auf 'Passwort \xC3\xA4ndern' um dein altes Passwort durch das neue zu ersetzen." + password_confirmation_label: "Passwort best\xC3\xA4tigen" new_password_label: Neues Passwort register_with_cas: Mit deinem CAS-Benutzernamen label_auth_type: Authentifizierungsart + total_users_count: Derzeit existieren %{count} Benutzer new_user_title: TRACKS::Als Administrator anmelden destroy_user: "Benutzer l\xC3\xB6schen" - total_users_count: Derzeit existieren %{count} Benutzer you_have_to_reset_your_password: "Sie haben Ihr Passwort zur\xC3\xBCcksetzen" signup_new_user: Neuen Benutzer anlegen destroy_confirmation: "Achtung: der Benutzer '%{login}' wird mit all seinen Aufgaben, Kontexten, Projekten und Notizen gel\xC3\xB6scht. Bist du sicher, dass du fortfahren m\xC3\xB6chtest?" identity_url: Identity-URL - openid_ok_pref_failed: Die URL %{url} wurde erfolgreich als Identität verifiziert, beim Speichern der Einstellungen trat jedoch ein Fehler auf. change_authentication_type: "Authentifizierungsart \xC3\xA4ndern" + openid_ok_pref_failed: Die URL %{url} wurde erfolgreich als Identität verifiziert, beim Speichern der Einstellungen trat jedoch ein Fehler auf. auth_change_submit: "Authentifizierungsart \xC3\xA4ndern" select_authentication_type: "W\xC3\xA4hle deine neue Authentifizierungsart und klicke 'Authentifizierungsart \xC3\xA4ndern' an, um deine aktuellen Einstellungen zu \xC3\xBCberschreiben." total_notes: Alle Notizen - contexts: - delete_context_title: Kontext löschen - hide_form: Formular verstecken - all_completed_tasks_title: "TRACKS:: Alle Abgeschlossene Ma\xC3\x9Fnahmen im context '%{context_name}'" - show_form_title: Neuen Kontext erstellen - delete_context_confirmation: Soll der Kontext '%{name}' wirklich gelöscht werden? Alle (wiederholenden) Aufgaben dieses Kontexts werden hierdurch ebenfalls gelöscht. - todos_append: In diesem Context - delete_context: Kontext löschen - edit_context: Kontext bearbeiten - hide_form_title: Formular für neuen Kontext verstecken - context_hide: Auf Startseite ausblenden? - hidden_contexts: Versteckte Kontexte - no_contexts_active: Derzeit gibt es keine aktiven Kontexte - show_form: Neuen Kontext erstellen - visible_contexts: Sichtbare Kontexte - save_status_message: Kontext gespeichert - add_context: "Kontext hinzuf\xC3\xBCgen" - update_status_message: "Kontextname wurde ge\xC3\xA4ndert" - context_name: Kontextname - status_active: Kontext ist aktiv - completed_tasks_title: "TRACKS:: Abgeschlossene Ma\xC3\x9Fnahmen im context '%{context_name}'" - new_context_post: "' wird ebenfalls angelegt. Fortfahren?" - no_actions: "Momentan gibt es keine unvollst\xC3\xA4ndigen Aufgaben in diesem Kontext" - last_completed_in_context: in diesem Kontext (letzte %{number}) - context_deleted: "Gel\xC3\xB6schter Kontext '%{name}'" - no_contexts_hidden: Derzeit gibt es keine versteckten Kontexte - new_context_pre: Der neue Kontext ' - status_hidden: Kontext ist versteckt sidebar: list_name_active_contexts: Aktive Kontexte list_name_active_projects: Aktive Projekte @@ -907,16 +881,44 @@ de: list_name_completed_projects: Abgeschlossene Projekte list_name_hidden_projects: Versteckte Projekte list_name_hidden_contexts: Versteckte Kontexte + contexts: + delete_context_title: Kontext löschen + hide_form: Formular verstecken + all_completed_tasks_title: "TRACKS:: Alle Abgeschlossene Ma\xC3\x9Fnahmen im context '%{context_name}'" + show_form_title: Neuen Kontext erstellen + delete_context_confirmation: Soll der Kontext '%{name}' wirklich gelöscht werden? Alle (wiederholenden) Aufgaben dieses Kontexts werden hierdurch ebenfalls gelöscht. + delete_context: Kontext löschen + todos_append: In diesem Context + edit_context: Kontext bearbeiten + hide_form_title: Formular für neuen Kontext verstecken + no_contexts_active: Derzeit gibt es keine aktiven Kontexte + context_hide: Auf Startseite ausblenden? + hidden_contexts: Versteckte Kontexte + visible_contexts: Sichtbare Kontexte + save_status_message: Kontext gespeichert + show_form: Neuen Kontext erstellen + add_context: "Kontext hinzuf\xC3\xBCgen" + context_name: Kontextname + update_status_message: "Kontextname wurde ge\xC3\xA4ndert" + completed_tasks_title: "TRACKS:: Abgeschlossene Ma\xC3\x9Fnahmen im context '%{context_name}'" + status_active: Kontext ist aktiv + new_context_post: "' wird ebenfalls angelegt. Fortfahren?" + context_deleted: "Gel\xC3\xB6schter Kontext '%{name}'" + no_contexts_hidden: Derzeit gibt es keine versteckten Kontexte + new_context_pre: Der neue Kontext ' + no_actions: "Momentan gibt es keine unvollst\xC3\xA4ndigen Aufgaben in diesem Kontext" + last_completed_in_context: in diesem Kontext (letzte %{number}) + status_hidden: Kontext ist versteckt login: - sign_in: Anmeldung openid_identity_url_not_found: "Sorry, aber es existiert kein Benutzer mit der Identit\xC3\xA4ts-URL (%{identity_url})" user_no_expiry: Angemeldet bleiben login_cas: zum CAS gehen - cas_logged_in_greeting: Hallo, %{username}! Du bist authentifiziert. + sign_in: Anmeldung cas_no_user_found: Hallo, %{username}! Du hast leider keinen Tracks-Account. cas_login: CAS-Anmeldung successful_with_session_info: "Anmeldung erfolgreich:" please_login: Bitte melde dich an, um Tracks zu nutzen + cas_logged_in_greeting: Hallo, %{username}! Du bist authentifiziert. cas_username_not_found: Sorry, aber es existiert kein Benutzer mit dem CAS-Benutzernamen (%{username}) cas_create_account: "Wenn du die Anfrage fortsetzen m\xC3\xB6chtest, klicke bitte hier: %{signup_link}" mobile_use_openid: "\xE2\x80\xA6oder mit einer OpenID anmelden" diff --git a/config/locales/en.yml b/config/locales/en.yml index da3e7b1c..56590447 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -90,8 +90,10 @@ en: third: Third recurring_todos: Repeating Actions actions: Actions + actions_midsentence: actions add: Add previous: Previous + show_all: Show all logout: Logout go_back: Go back optional: optional diff --git a/config/locales/es.yml b/config/locales/es.yml index 336ec97b..b4f67bd4 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1,5 +1,63 @@ --- es: + common: + back: !binary | + QXRyw6Fz + + recurring_todos: "Repetici\xC3\xB3n de acciones" + actions: Tareas + third: Tercero + add: "A\xC3\xB1adir" + previous: Anterior + go_back: "Volver atr\xC3\xA1s" + logout: Salir + second: Segundo + actions_midsentence: acciones + optional: opcional + week: semana + none: Ninguno + show_all: Mostrar todo + cancel: Cancelar + month: mes + server_error: Ha ocurrido un error en el servidor. + notes: Notas + forum: Foro + last: "\xC3\x9Altimo" + review: "Revisi\xC3\xB3n" + projects: Proyectos + action: Tarea + project: Proyecto + contribute: Contribuir + ok: Ok + first: Primero + website: Website + numbered_step: Paso %{number} + sort: + by_task_count_title: "Ordenar por n\xC3\xBAmero de tareas" + by_task_count_title_confirm: "\xC2\xBFEst\xC3\xA1 seguro que desea ordenar los proyectos por el n\xC3\xBAmero de tareas? Esto reemplazar\xC3\xA1 el orden existente." + alphabetically: "Alfab\xC3\xA9ticamente" + sort: Ordenar + alphabetically_confirm: "\xC2\xBFEst\xC3\xA1 seguro que desea ordenar los proyectos por orden alfab\xC3\xA9tico? Esto reemplazar\xC3\xA1 el orden existente." + alphabetically_title: "Proyectos de ordenar alfab\xC3\xA9ticamente" + by_task_count: "Por n\xC3\xBAmero de tareas" + create: Crear + drag_handle: ARRASTRAR + months: meses + description: "Descripci\xC3\xB3n" + fourth: Cuarto + next: "Pr\xC3\xB3ximo" + contexts: Contextos + todo: Todo + context: Contexto + errors_with_fields: "Ha habido problemas con los siguientes campos:" + update: Actualizar + weeks: semanas + forth: Siguiente + wiki: Wiki + bugs: Errores + ajaxError: Hubo un error al recuperar desde el servidor + email: Email + search: Buscar number: format: separator: . @@ -23,66 +81,10 @@ es: separator: . delimiter: "," - common: - back: !binary | - QXRyw6Fz - - recurring_todos: "Repetici\xC3\xB3n de acciones" - actions: Tareas - third: Tercero - add: "A\xC3\xB1adir" - previous: Anterior - go_back: "Volver atr\xC3\xA1s" - logout: Salir - second: Segundo - optional: opcional - week: semana - none: Ninguno - cancel: Cancelar - month: mes - forum: Foro - server_error: Ha ocurrido un error en el servidor. - notes: Notas - last: "\xC3\x9Altimo" - review: "Revisi\xC3\xB3n" - projects: Proyectos - action: Tarea - project: Proyecto - ok: Ok - contribute: Contribuir - first: Primero - website: Website - numbered_step: Paso %{number} - errors_with_fields: "Ha habido problemas con los siguientes campos:" - sort: - by_task_count_title: "Ordenar por n\xC3\xBAmero de tareas" - by_task_count_title_confirm: "\xC2\xBFEst\xC3\xA1 seguro que desea ordenar los proyectos por el n\xC3\xBAmero de tareas? Esto reemplazar\xC3\xA1 el orden existente." - alphabetically: "Alfab\xC3\xA9ticamente" - sort: Ordenar - alphabetically_confirm: "\xC2\xBFEst\xC3\xA1 seguro que desea ordenar los proyectos por orden alfab\xC3\xA9tico? Esto reemplazar\xC3\xA1 el orden existente." - alphabetically_title: "Proyectos de ordenar alfab\xC3\xA9ticamente" - by_task_count: "Por n\xC3\xBAmero de tareas" - create: Crear - months: meses - drag_handle: ARRASTRAR - description: "Descripci\xC3\xB3n" - fourth: Cuarto - next: "Pr\xC3\xB3ximo" - contexts: Contextos - todo: Todo - context: Contexto - update: Actualizar - weeks: semanas - forth: Siguiente - wiki: Wiki - bugs: Errores - email: Email - ajaxError: Hubo un error al recuperar desde el servidor - search: Buscar layouts: toggle_contexts_title: "Haga contextos se derrumb\xC3\xB3 (in)visible" - toggle_contexts: "Cambiar los contextos se derrumb\xC3\xB3" toggle_notes: Activar/Desactivar notas + toggle_contexts: "Cambiar los contextos se derrumb\xC3\xB3" next_actions_rss_feed: RSS feed of next actions toggle_notes_title: Activar/Desactivar todas las notas mobile_navigation: @@ -95,13 +97,13 @@ es: contexts: Contextos home: Inicio navigation: - api_docs: REST API Docs manage_users_title: "A\xC3\xB1adir o eliminar usuarios" recurring_todos: Tareas repetitivas + api_docs: REST API Docs feeds: Feeds stats: "Estad\xC3\xADsticas" - starred: Estrellas notes_title: Mostrar todas las notas + starred: Estrellas manage_users: Administrar usuarios tickler_title: Tickler integrations_: Integrar Tracks @@ -109,22 +111,22 @@ es: preferences: Preferencias feeds_title: See a list of available feeds calendar_title: Calendario de las acciones por - home_title: Inicio - tickler: Tickler - starred_title: See your starred actions recurring_todos_title: Manage recurring actions + tickler: Tickler completed_tasks: Hecho stats_title: See your statistics + home_title: Inicio + starred_title: See your starred actions view: Ver organize: Organizar completed_tasks_title: Completed home: Inicio contexts_title: Contexts export: Export + projects_title: Proyectos + search: Search All Items preferences_title: Mostrar mis preferencias review_title: "Posibilidad de una revisi\xC3\xB3n" - search: Search All Items - projects_title: Proyectos calendar: Calendario integrations: opensearch_description: Buscar en las Tracks @@ -154,23 +156,23 @@ es: show_hidden_projects_in_sidebar: Mostrar proyectos ocultos en el lateral date_format: Formato de fecha show_hidden_contexts_in_sidebar: Mostrar los contextos ocultos en el lateral + verbose_action_descriptors: "Descriptores detallado de acci\xC3\xB3n" mobile_todos_per_page: "Tareas por p\xC3\xA1gina (Vista M\xC3\xB3vil)" staleness_starts: Comienzo de estancamiento - verbose_action_descriptors: "Descriptores detallado de acci\xC3\xB3n" sms_context: Contexto por defecto para el email - title_date_format: "T\xC3\xADtulo del formato de fecha" show_number_completed: "Mostrar n\xC3\xBAmero de tareas completadas" + title_date_format: "T\xC3\xADtulo del formato de fecha" refresh: "Intervalo de actualizaci\xC3\xB3n (en minutos)" week_starts: La semana comienza last_name: Apellido locale: Lugar - due_style: Debido al estilo time_zone: Zona horaria + due_style: Debido al estilo sms_email: Email origen show_project_on_todo_done: "Ir a la p\xC3\xA1gina del proyecto al completar la tarea" show_completed_projects_in_sidebar: Show completed projects in sidebar - review_period: "Intervalo de revisi\xC3\xB3n del proyecto" first_name: Nombre + review_period: "Intervalo de revisi\xC3\xB3n del proyecto" errors: models: project: @@ -200,13 +202,13 @@ es: taken: Ya se ha dado inclusion: "no est\xC3\xA1 incluido en la lista" not_a_number: "no es un n\xC3\xBAmero" + full_messages: + format: "%{attribute} %{message}" template: body: "Hubo problemas con los campos siguientes:" header: one: Un error esta prohibido %{model} se guarden other: "%{count} errores proh\xC3\xADbe este %{model} que se guarden" - full_messages: - format: "%{attribute} %{message}" data: import_successful: "Importaci\xC3\xB3n se realiz\xC3\xB3 correctamente." import_errors: "Han ocurrido algunos errores durante la importaci\xC3\xB3n" @@ -226,30 +228,31 @@ es: - Due in ___ days - Due on _______ stats: + tag_cloud_title: Tag cloud for all actions totals_hidden_context_count: and %{count} are hidden contexts. actions_avg_created: In the last 12 months you created on average %{count} actions actions_min_max_completion_days: The Max-/minimum days to complete is %{min}/%{max}. totals_actions_completed: "%{count} of these are completed." - tag_cloud_title: Tag cloud for all actions actions_actions_avg_created_30days: In the last 30 days you created on average %{count} actions actions_avg_completed: and completed an average of %{count} actions per month. top5_visible_contexts_with_incomplete_actions: Top 5 visible contexts with incomplete actions actions: Actions - totals_deferred_actions: of which %{count} are deferred actions in the tickler time_of_day_legend: number_of_actions: "N\xC3\xBAmero de tareas" time_of_day: Time of day totals_incomplete_actions: You have %{count} incomplete actions + totals_action_count: you have a total of %{count} actions running_time_legend: actions: Tareas percentage: Percentage weeks: Running time of an action (weeks). Click on a bar for more info - totals_action_count: you have a total of %{count} actions + totals_deferred_actions: of which %{count} are deferred actions in the tickler tag_cloud_90days_title: Tag cloud actions in past 90 days tod30: Time of day (last 30 days) tags: Tags projects: Projects actions_avg_completion_time: Of all your completed actions, the average time to complete is %{count} days. + actions_day_of_week_title: Day of week (all actions) labels: month_avg_completed: "%{months} Month avg completed" completed: Completed @@ -257,22 +260,21 @@ es: avg_created: Avg created avg_completed: Avg completed created: Created - actions_selected_from_week: "Actions selected from week " totals_completed_project_count: and %{count} are completed projects. - actions_day_of_week_title: Day of week (all actions) + actions_selected_from_week: "Actions selected from week " actions_lastyear_title: Actions in the last 12 months open_per_week: "Pr\xC3\xB3ximas acciones activas (visibles y ocultas) a la semana" action_selection_title: TRACKS::Action selection totals_project_count: You have %{count} projects. - current_running_time_of_incomplete_visible_actions: Current running time of incomplete visible actions legend: number_of_days: Number of days ago actions: Tareas number_of_actions: "N\xC3\xBAmero de tareas" day_of_week: Day of week - percentage: Percentage running_time: Running time of an action (weeks) + percentage: Percentage months_ago: Months ago + current_running_time_of_incomplete_visible_actions: Current running time of incomplete visible actions tod30_legend: number_of_actions: "N\xC3\xBAmero de tareas" time_of_day: Time of day @@ -285,82 +287,82 @@ es: months_ago: Months ago top10_projects: Top 10 projects top5_contexts: Top 5 contexts - contexts: Contexts totals: Totals + contexts: Contexts click_to_return: Click %{link} to return to the statistics page. tag_cloud_90days_description: This tag cloud includes tags of actions that were created or completed in the past 90 days. totals_visible_context_count: Of those %{count} are visible contexts - top10_projects_30days: Top 10 project in past 30 days running_time_all: Current running time of all incomplete actions + top10_projects_30days: Top 10 project in past 30 days actions_min_completion_time: The minimum time to complete is %{time}. action_completion_time_title: Completion time (all completed actions) click_to_show_actions_from_week: Click %{link} to show the actions from week %{week} and further. top10_longrunning: Top 10 longest running projects no_actions_selected: No hay tareas seleccionadas. - totals_tag_count: You have %{count} tags placed on actions. actions_further: " and further" + totals_tag_count: You have %{count} tags placed on actions. actions_dow_30days_legend: number_of_actions: "N\xC3\xBAmero de acciones" day_of_week: "D\xC3\xADa de la semana" totals_first_action: Since your first action on %{date} tag_cloud_description: This tag cloud includes tags of all actions (completed, not completed, visible and/or hidden) - click_to_return_link: here click_to_update_actions: Click on a bar in the chart to update the actions below. + click_to_return_link: here spread_of_actions_for_all_context: Spread of actions for all context more_stats_will_appear: More statistics will appear here once you have added some actions. actions_avg_completed_30days: and completed an average of %{count} actions per day. - no_tags_available: no tags available - actions_30days_title: Actions in the last 30 days - index_title: "TRACKS::Estad\xC3\xADstica" actions_dow_30days_title: Day of week (past 30 days) - spread_of_running_actions_for_visible_contexts: Spread of running actions for visible contexts + actions_30days_title: Actions in the last 30 days + no_tags_available: no tags available + index_title: "TRACKS::Estad\xC3\xADstica" actions_day_of_week_legend: number_of_actions: "N\xC3\xBAmero de acciones" day_of_week: "D\xC3\xADa de la semana" - actions_last_year: Actions in the last years + spread_of_running_actions_for_visible_contexts: Spread of running actions for visible contexts totals_blocked_actions: "%{count} are dependent on the completion of their actions." + actions_last_year: Actions in the last years totals_unique_tags: Of those tags, %{count} are unique. totals_active_project_count: Of those %{count} are active projects running_time_all_legend: actions: Tareas - percentage: Percentage running_time: Running time of an action (weeks). Click on a bar for more info + percentage: Percentage other_actions_label: (otros) - time_of_day: Time of day (all actions) totals_hidden_project_count: "%{count} are hidden" + time_of_day: Time of day (all actions) todos: show_from: Show from error_starring_recurring: Could not toggle the star of recurring todo \'%{description}\' recurring_action_deleted: Action was deleted. Because this action is recurring, a new action was added completed_actions: Completed actions - blocked_by: Blocked by %{predecessors} + completed_rest_of_previous_month: Completado en el resto del mes anterior completed_recurring: Completed recurring todos added_new_next_action: Added new next action - completed_rest_of_previous_month: Completado en el resto del mes anterior - defer_date_after_due_date: Defer date is after due date. Please edit and adjust due date before deferring. - star_action: Star this action + blocked_by: Blocked by %{predecessors} completed_recurrence_completed: There is no next action after the recurring action you just deleted. The recurrence is completed + star_action: Star this action + defer_date_after_due_date: Defer date is after due date. Please edit and adjust due date before deferring. unable_to_add_dependency: Unable to add dependency done: Done? star_action_with_description: star the action '%{description}' tagged_with: tagged with ‘%{tag_name}’ completed: Completed no_deferred_actions_with: No deferred actions with the tag '%{tag_name}' + edit_action_with_description: Edit the action '%{description}' no_hidden_actions: Currently there are no hidden actions found action_due_on: (action due on %{date}) - edit_action_with_description: Edit the action '%{description}' archived_tasks_title: TRACKS::Archived completed tasks remove_dependency: Remove dependency (does not delete the action) list_incomplete_next_actions: Lista las siguientes tareas incompletas tags: Tags (separate with commas) action_deleted_success: Successfully deleted next action - add_another_dependency: Add another dependency new_related_todo_created: "Una nueva tarea fue a\xC3\xB1adida y que pertenece a esta tarea recurrente" context_changed: Context changed to %{name} + add_another_dependency: Add another dependency mobile_todos_page_title: Todas las tareas delete_recurring_action_title: Delete the recurring action - recurring_actions_title: TRACKS::Recurring Actions removed_predecessor: Removed %{successor} as dependency from %{predecessor}. + recurring_actions_title: TRACKS::Recurring Actions next_action_needed: You need to submit at least one next action action_saved: Action saved scheduled_overdue: Scheduled to show %{days} days ago @@ -368,7 +370,6 @@ es: edit_action: Edit action added_new_context: Added new context next_actions_description: "Filter:" - older_completed_items: Older completed items list_incomplete_next_actions_with_limit: Lists the last %{count} incomplete next actions set_to_pending: "%{task} set to pending" added_new_project: Added new project @@ -376,28 +377,29 @@ es: completed: actions completed due_today: due today due_within_a_week: due within a week - task_list_title: TRACKS::List tasks + older_completed_items: Older completed items + error_deleting_item: There was an error deleting the item %{description} edit_recurring_todo: "Editar la acci\xC3\xB3n de repetici\xC3\xB3n" append_in_this_project: in this project - error_deleting_item: There was an error deleting the item %{description} + task_list_title: TRACKS::List tasks no_actions_due_this_week: No actions due in rest of this week - error_completing_todo: There was an error completing / activating the recurring todo %{description} + no_deferred_pending_actions: Currently there are no deferred or pending actions no_recurring_todos: Currently there are no recurring todos + error_completing_todo: There was an error completing / activating the recurring todo %{description} recurring_pattern_removed: "El patr\xC3\xB3n de repetici\xC3\xB3n se retira de %{count}" convert_to_project: Make project - no_deferred_pending_actions: Currently there are no deferred or pending actions delete_recurring_action_confirm: Are you sure that you want to delete the recurring action '%{description}'? completed_last_day: Completed in the last 24 hours - all_completed: Todas las acciones realizadas show_in_days: Show in %{days} days no_project: --No project-- error_saving_recurring: There was an error saving the recurring todo \'%{description}\' completed_more_than_x_days_ago: Completed more than %{count} days ago - feed_title_in_context: in context '%{context}' new_related_todo_created_short: creada una nueva tarea + feed_title_in_context: in context '%{context}' + all_completed: Todas las acciones realizadas edit: Edit - completed_tagged_page_title: "TRACKS:: Las tareas completadas con etiqueta %{tag_name}" older_than_days: Older than %{count} days + completed_tagged_page_title: "TRACKS:: Las tareas completadas con etiqueta %{tag_name}" pending: Pending completed_actions_with: Completed actions with the tag %{tag_name} feed_title_in_project: in project '%{project}' @@ -406,10 +408,10 @@ es: clear_due_date: Clear due date error_removing_dependency: There was an error removing the dependency hidden_actions: Tareas ocultas + deferred_actions_with: Deferred actions with the tag '%{tag_name}' was_due_on_date: was due on %{date} show_on_date: Show on %{date} recurrence_period: Recurrence period - deferred_actions_with: Deferred actions with the tag '%{tag_name}' confirm_delete: Are you sure that you want to delete the action '%{description}'? recurring_deleted_success: The recurring action was deleted succesfully. next_actions_title: Tracks - Next Actions @@ -418,21 +420,21 @@ es: no_completed_actions_with: No completed actions with the tag '%{tag_name}' clear_show_from_date: Clear show from date calendar_page_title: TRACKS::Calendar - unresolved_dependency: The value you entered in the dependency field did not resolve to an existing action. This value will not be saved with the rest of the action. Continue? in_hidden_state: en estado oculto - show_today: Show Today - no_actions_found_title: No actions found + unresolved_dependency: The value you entered in the dependency field did not resolve to an existing action. This value will not be saved with the rest of the action. Continue? next_actions_due_date: overdue_by: Overdue by %{days} day - due_today: Vence hoy due_in_x_days: "Vence en %{days} d\xC3\xADas" + due_today: Vence hoy overdue_by_plural: Overdue by %{days} days due_tomorrow: "Vence ma\xC3\xB1ana" + show_today: Show Today + no_actions_found_title: No actions found completed_last_x_days: Completed in last %{count} days - no_actions_with: Currently there are no incomplete actions with the tag '%{tag_name}' defer_x_days: one: Defer one day other: Defer %{count} days + no_actions_with: Currently there are no incomplete actions with the tag '%{tag_name}' added_new_next_action_singular: Added new next action no_completed_actions: Currently there are no completed actions. feeds: @@ -446,16 +448,16 @@ es: error_deleting_recurring: There was an error deleting the recurring todo \'%{description}\' recurring_todos: Recurring todos delete: Delete - cannot_add_dependency_to_completed_todo: Cannot add this action as a dependency to a completed action! drag_action_title: Drag onto another action to make it depend on that action + cannot_add_dependency_to_completed_todo: Cannot add this action as a dependency to a completed action! no_last_completed_actions: "No encontr\xC3\xB3 las acciones realizadas" tickler_items_due: one: One tickler item is now due - refresh the page to see it. other: "%{count} tickler items are now due - refresh the page to see them." depends_on: Depends on action_marked_complete: The action '%{description}' was marked as %{completed} - completed_today: Completed Today added_new_next_action_plural: Added new next actions + completed_today: Completed Today new_related_todo_not_created_short: "no se cre\xC3\xB3 la tarea" completed_rest_of_week: Completado en el resto de esta semana error_starring: Could not toggle the star of this todo \'%{description}\' @@ -465,14 +467,13 @@ es: due_next_week: Due next week no_actions_due_next_week: No actions due in next week due_this_week: Due in rest of this week - due_today: Due today no_actions_due_today: No actions due today + due_today: Due today due_next_month_and_later: Due in %{month} and later no_actions_due_after_this_month: No actions due after this month no_actions_due_this_month: No actions due in rest of this month due_this_month: Due in rest of %{month} action_deferred: "La acci\xC3\xB3n \\'%{description}\\' se aplaz\xC3\xB3" - added_dependency: Added %{dependency} as dependency. recurrence: ends_on_number_times: Ends after %{number} times ends_on_date: Ends on %{date} @@ -487,6 +488,7 @@ es: show_option_always: always daily: Daily pattern: + third: third month_names: - - January @@ -501,7 +503,6 @@ es: - October - November - December - third: third every_n: every %{n} second: second every_xth_day_of_every_n_months: every %{x} %{day} of every %{n_months} @@ -513,6 +514,9 @@ es: the_xth_day_of_month: the %{x} %{day} of %{month} times: for %{number} times every_year_on: every year on %{date} + on_work_days: on work days + first: first + show: show day_names: - sunday - monday @@ -521,9 +525,6 @@ es: - thursday - friday - saturday - show: show - first: first - on_work_days: on work days fourth: fourth due: due until: until @@ -534,37 +535,38 @@ es: ends_on: Ends on show_options: Show the todo weekly_every_number_week: Returns every %{number} week on - show_days_before: "%{days} days before the todo is due" - yearly_every_xth_day: The %{day} %{day_of_week} of %{month} from_tickler: the date todo comes from tickler (no due date set) + yearly_every_xth_day: The %{day} %{day_of_week} of %{month} no_end_date: No end date day_x_on_every_x_month: Day %{day} on every %{month} month yearly_options: Settings for yearly recurring actions + show_days_before: "%{days} days before the todo is due" monthly_every_xth_day: The %{day} %{day_of_week} of every %{month} month yearly: Yearly tagged_page_title: TRACKS::Tagged with '%{tag_name}' no_completed_recurring: Currently there are no completed recurring todos - completed_rest_of_month: Completado en el resto de este mes - recurrence_completed: There is no next action after the recurring action you just finished. The recurrence is completed + added_dependency: Added %{dependency} as dependency. all_completed_tagged_page_title: "TRACKS:: Todas las tareas realizadas con etiqueta %{tag_name}" no_deferred_actions: Currently there are no deferred actions. - in_pending_state: en estado pendiente + completed_rest_of_month: Completado en el resto de este mes + recurrence_completed: There is no next action after the recurring action you just finished. The recurrence is completed no_actions_found: Currently there are no incomplete actions. + in_pending_state: en estado pendiente error_toggle_complete: Could not mark this todo complete due: "Fecha l\xC3\xADmite" action_marked_complete_error: The action '%{description}' was NOT marked as %{completed} due to an error on the server. + to_tickler: to tickler + add_new_recurring: Add a new recurring action depends_on_separate_with_commas: Depende de (separar con comas) recurring_action_saved: Recurring action saved action_saved_to_tickler: Action saved to tickler completed_in_archive: one: There is one completed action in the archive. other: There are %{count} completed actions in the archive. - to_tickler: to tickler next_actions_description_additions: completed: in the last %{count} days due_date: with a due date %{due_date} or earlier overdue: Overdue - add_new_recurring: Add a new recurring action no_incomplete_actions: There are no incomplete actions notes: delete_note_title: Delete the note '%{id}' @@ -584,44 +586,42 @@ es: stalled: Estancado completed: Completed current: "Hasta al d\xC3\xADa" - review: Fechado completed_plural: Completed + review: Fechado blocked_plural: Bloqueado blocked: Bloqueado stalled_plural: Estancado visible_plural: Visible active_plural: Active visible: Visible - current_plural: "Hasta al d\xC3\xADa" hidden: Hidden + current_plural: "Hasta al d\xC3\xADa" active: Active - errors: - user_unauthorized: "401 No autorizado: Solo los usuarios administrativos pueden acceder a esta funci\xC3\xB3n." projects: - no_actions_in_project: Currently there are no incomplete actions in this project - deferred_actions: Tareas pospuestas para este proyecto - was_marked_hidden: has been marked as hidden edit_project_title: Editar proyecto default_tags_removed_notice: Removed the default tags default_context_set: Set project's default context to %{default_context} + no_actions_in_project: Currently there are no incomplete actions in this project + deferred_actions: Tareas pospuestas para este proyecto + was_marked_hidden: has been marked as hidden hide_form: Esconder formulario - page_title: "TRACKS::Project: %{project}" all_completed_tasks_title: "TRACKS:: Lista de todas las acciones terminado en '%{project_name}' Proyecto" - project_state: Project is %{state}. + page_title: "TRACKS::Project: %{project}" + this_project: This project list_completed_projects: "TRACKS:: Lista de Proyectos Realizados" to_new_project_page: Take me to the new project page no_notes_attached: Currently there are no notes attached to this project show_form_title: Create a new project deferred_actions_empty: There are no deferred actions for this project - this_project: This project + project_state: Project is %{state}. no_last_completed_recurring_todos: No se ha completado las acciones repetitivas que se encuentran todos_append: in this project no_last_completed_projects: No hay proyectos terminados encontrado notes: Notes - hide_form_title: Hide new project form - list_reviews: "TRACKS::Revisi\xC3\xB3n" notes_empty: There are no notes for this project no_projects: Currently there are no projects + hide_form_title: Hide new project form + list_reviews: "TRACKS::Revisi\xC3\xB3n" completed_actions_empty: No hay tareas completadas para este proyecto with_no_default_context: with no default context delete_project: Delete project @@ -629,43 +629,45 @@ es: actions_in_project_title: Actions in this project delete_project_confirmation: Are you sure that you want to delete the project '%{name}'? with_default_context: with a default context of '%{context_name}' - set_default_tags_notice: Set project's default tags to %{default_tags} + is_active: "est\xC3\xA1 activo" completed_projects: Proyectos completados + project_saved_status: Project saved add_note: "A\xC3\xB1adir una nota" add_project: "A\xC3\xB1adir Proyecto" - settings: Settings with_default_tags: and with '%{tags}' as the default tags + settings: Settings list_projects: TRACKS::Lista de Proyectos - is_active: "est\xC3\xA1 activo" - project_saved_status: Project saved + set_default_tags_notice: Set project's default tags to %{default_tags} + completed_tasks_title: "TRACKS:: Lista de Acciones completadas en '%{project_name}' Proyecto" delete_project_title: Delete the project hidden_projects: Proyectos ocultos - completed_tasks_title: "TRACKS:: Lista de Acciones completadas en '%{project_name}' Proyecto" default_context_removed: Eliminado el contexto por defecto - completed_actions: Tareas completadas para este proyecto add_note_submit: "A\xC3\xB1adir nota" was_marked_complete: has been marked as completed + completed_actions: Tareas completadas para este proyecto no_default_context: Este proyecto no tiene un contexto por defecto with_no_default_tags: and with no default tags edit_project_settings: Edit Project Settings - status_project_name_changed: Name of project was changed state: This project is %{state} + status_project_name_changed: Name of project was changed default_context: The default context for this project is %{context} active_projects: Active projects + errors: + user_unauthorized: "401 No autorizado: Solo los usuarios administrativos pueden acceder a esta funci\xC3\xB3n." preferences: change_identity_url: Change Your Identity URL - open_id_url: Your OpenID URL is staleness_starts_after: Staleness starts after %{days} days + open_id_url: Your OpenID URL is change_password: Change your password page_title: TRACKS::Preferences token_description: Token (for feeds and API use) title: Your preferences - is_false: "false" show_number_completed: Show %{number} completed items + is_false: "false" + edit_preferences: Edit preferences page_title_edit: TRACKS::Edit Preferences is_true: "true" password_changed: "Que ha cambiado la contrase\xC3\xB1a, por favor vuelve a iniciar sesi\xC3\xB3n." - edit_preferences: Edit preferences generate_new_token: Generate a new token sms_context_none: None token_header: Your token @@ -765,15 +767,15 @@ es: shared: multiple_next_actions: Multiple next actions (one on each line) make_actions_dependent: "Aseg\xC3\xBArese que las acciones dependen unos de otros" - hide_form: Esconder formulario toggle_single: Add a next action + hide_form: Esconder formulario add_actions: "A\xC3\xB1adir tareas" add_action: "A\xC3\xB1adir tarea" tags_for_all_actions: Tags for all actions (sep. with commas) - toggle_multi: Add multiple next actions - toggle_single_title: Add a new next action project_for_all_actions: Project for all actions context_for_all_actions: Context for all actions + toggle_multi: Add multiple next actions + toggle_single_title: Add a new next action separate_tags_with_commas: separar con comas toggle_multi_title: Toggle single/multi new action form hide_action_form_title: Hide new action form @@ -782,8 +784,8 @@ es: feedlist: actions_due_today: Acciones pendientes hoy o antes choose_context: Elija el contexto en el que desea un canal de - rss_feed: RSS Feed legend: "Leyenda:" + rss_feed: RSS Feed ical_feed: "iCal alimentaci\xC3\xB3n" all_contexts: Todos los contextos all_projects: Todos los proyectos @@ -792,89 +794,61 @@ es: select_feed_for_project: Seleccione la fuente para este proyecto active_projects_wo_next: "Proyectos activos, sin las pr\xC3\xB3ximas acciones" active_starred_actions: "Todas las acciones que protagoniz\xC3\xB3, activa" - context_needed: Es necesario que haya al menos un contexto antes de poder solicitar un feed select_feed_for_context: "Seleccione la alimentaci\xC3\xB3n de este contexto" projects_and_actions: Proyectos activos con sus acciones + context_needed: Es necesario que haya al menos un contexto antes de poder solicitar un feed actions_due_next_week: "Tareas pendientes en 7 d\xC3\xADas o menos" notice_incomplete_only: "Nota: Todos los alimentos muestran s\xC3\xB3lo las acciones que no han sido marcadas como realizadas, a menos que se indique lo contrario." + context_centric_actions: "Feeds de acciones incompletas en un contexto espec\xC3\xADfico" + plain_text_feed: Canal Texto sin formato last_fixed_number: "\xC3\x9Altima %{number} acciones" all_actions: Todas las tareas actions_completed_last_week: "Tareas completadas en los \xC3\xBAltimos 7 d\xC3\xADas" - context_centric_actions: "Feeds de acciones incompletas en un contexto espec\xC3\xADfico" - plain_text_feed: Canal Texto sin formato project_centric: "Feeds de acciones incompletas en un proyecto espec\xC3\xADfico" users: + first_user_heading: "Welcome to TRACKS. To get started, please create an admin account:" successfully_deleted_user: Successfully deleted user %{username} + auth_type_update_error: "There was a problem updating your authentication type: %{error_messages}" failed_to_delete_user: Failed to delete user %{username} destroy_successful: User %{login} was successfully destroyed total_contexts: Total contexts openid_url_verified: You have successfully verified %{url} as your identity and set your authentication type to OpenID. - first_user_heading: "Welcome to TRACKS. To get started, please create an admin account:" - auth_type_update_error: "There was a problem updating your authentication type: %{error_messages}" + signup_successful: Signup successful for user %{username}. new_token_generated: New token successfully generated total_projects: Total projects - signup_successful: Signup successful for user %{username}. no_signups_title: TRACKS::No signups user_created: User created. change_password_submit: Change password - account_signup: Account signup manage_users: Manage users + account_signup: Account signup password_updated: Password updated. - auth_type_updated: Authentication type updated. total_actions: Total actions desired_login: Desired login - signup: Signup confirm_password: Confirm password new_user_heading: "Sign up a new user:" - change_password_prompt: Enter your new password in the fields below and click 'Change password' to replace your current password with your new one. - password_confirmation_label: Confirm password + signup: Signup + auth_type_updated: Authentication type updated. destroy_error: There was an error deleting the user %{login} choose_password: Choose password change_password_title: TRACKS::Change password change_auth_type_title: TRACKS::Change authentication type + change_password_prompt: Enter your new password in the fields below and click 'Change password' to replace your current password with your new one. + password_confirmation_label: Confirm password new_password_label: New password register_with_cas: With your CAS username label_auth_type: Authentication type + total_users_count: You have a total of %{count} users new_user_title: TRACKS::Sign up as the admin user destroy_user: Destroy user - total_users_count: You have a total of %{count} users you_have_to_reset_your_password: "Usted tiene que restablecer su contrase\xC3\xB1a" signup_new_user: Sign up new user destroy_confirmation: "Warning: this will delete user '%{login}', all their actions, contexts, project and notes. Are you sure that you want to continue?" identity_url: Identity URL - openid_ok_pref_failed: You have successfully verified %{url} as your identity but there was a problem saving your authentication preferences. change_authentication_type: Change authentication type + openid_ok_pref_failed: You have successfully verified %{url} as your identity but there was a problem saving your authentication preferences. auth_change_submit: Change authentication type select_authentication_type: Select your new authentication type and click 'Change authentication type' to replace your current settings. total_notes: Total notes - contexts: - delete_context_title: Eliminar contexto - hide_form: Esconder formulario - all_completed_tasks_title: "TRACKS:: Todas las acciones completadas en '%{context_name}' contexto" - show_form_title: "A\xC3\xB1adir un contexto" - delete_context_confirmation: "\xC2\xBFEst\xC3\xA1 seguro que desea eliminar '%{name}' el contexto? Tenga en cuenta que esto tambi\xC3\xA9n se eliminar\xC3\xA1n todas las acciones (la repetici\xC3\xB3n) en este contexto!" - todos_append: en este contexto - delete_context: Eliminar contexto - edit_context: Editar contexto - hide_form_title: Ocultar el formulario nuevo contexto - context_hide: "\xC2\xBFEsconder de la p\xC3\xA1gina principal?" - hidden_contexts: Contextos ocultos - no_contexts_active: Actualmente no hay contextos activos - show_form: Crear un nuevo contexto - visible_contexts: Contextos visible - save_status_message: Contexto guardado - add_context: "A\xC3\xB1adir contexto" - update_status_message: Nombre de contexto ha cambiado - context_name: Nombre del contexto - status_active: "El contexto est\xC3\xA1 activo" - completed_tasks_title: "TRACKS:: Las acciones completadas en '%{context_name}' el contexto" - new_context_post: "' Tambi\xC3\xA9n se ha creado. \xC2\xBFEst\xC3\xA1 seguro?" - no_actions: Actualmente no hay acciones incompletas en este contexto - last_completed_in_context: "en este contexto (\xC3\xBAltimos %{number})" - context_deleted: Contexto eliminado '%{name}' - no_contexts_hidden: Actualmente no hay contextos ocultos - new_context_pre: Nuevo contexto ' - status_hidden: Contexto se oculta sidebar: list_name_active_contexts: Active contexts list_name_active_projects: Active projects @@ -882,16 +856,44 @@ es: list_name_completed_projects: Completed projects list_name_hidden_projects: Hidden projects list_name_hidden_contexts: Hidden contexts + contexts: + delete_context_title: Eliminar contexto + hide_form: Esconder formulario + all_completed_tasks_title: "TRACKS:: Todas las acciones completadas en '%{context_name}' contexto" + show_form_title: "A\xC3\xB1adir un contexto" + delete_context_confirmation: "\xC2\xBFEst\xC3\xA1 seguro que desea eliminar '%{name}' el contexto? Tenga en cuenta que esto tambi\xC3\xA9n se eliminar\xC3\xA1n todas las acciones (la repetici\xC3\xB3n) en este contexto!" + delete_context: Eliminar contexto + todos_append: en este contexto + edit_context: Editar contexto + hide_form_title: Ocultar el formulario nuevo contexto + no_contexts_active: Actualmente no hay contextos activos + context_hide: "\xC2\xBFEsconder de la p\xC3\xA1gina principal?" + hidden_contexts: Contextos ocultos + visible_contexts: Contextos visible + save_status_message: Contexto guardado + show_form: Crear un nuevo contexto + add_context: "A\xC3\xB1adir contexto" + context_name: Nombre del contexto + update_status_message: Nombre de contexto ha cambiado + completed_tasks_title: "TRACKS:: Las acciones completadas en '%{context_name}' el contexto" + status_active: "El contexto est\xC3\xA1 activo" + new_context_post: "' Tambi\xC3\xA9n se ha creado. \xC2\xBFEst\xC3\xA1 seguro?" + context_deleted: Contexto eliminado '%{name}' + no_contexts_hidden: Actualmente no hay contextos ocultos + new_context_pre: Nuevo contexto ' + no_actions: Actualmente no hay acciones incompletas en este contexto + last_completed_in_context: "en este contexto (\xC3\xBAltimos %{number})" + status_hidden: Contexto se oculta login: - sign_in: Entrar openid_identity_url_not_found: Sorry, no user by that identity URL exists (%{identity_url}) user_no_expiry: Stay logged in login_cas: go to the CAS - cas_logged_in_greeting: Hello, %{username}! You are authenticated. + sign_in: Entrar cas_no_user_found: Hello, %{username}! You do not have an account on Tracks. cas_login: CAS Login successful_with_session_info: "Login successful:" please_login: Please log in to use Tracks + cas_logged_in_greeting: Hello, %{username}! You are authenticated. cas_username_not_found: Sorry, no user by that CAS username exists (%{username}) cas_create_account: If you like to request on please go here to %{signup_link} mobile_use_openid: "\xE2\x80\xA6or login with an OpenID" diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 214878b4..8b005323 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -1,5 +1,65 @@ --- fr: + common: + back: Retour + recurring_todos: "R\xC3\xA9p\xC3\xA9tition d'actions" + actions: Actions + third: "Troisi\xC3\xA8me" + add: Ajouter + previous: !binary | + UHLDqWPDqWRlbnRl + + go_back: Retour + logout: "D\xC3\xA9connexion" + second: Seconde + actions_midsentence: actes + optional: optionnel + week: semaine + none: Aucun + show_all: Voir tous + cancel: Annuler + month: mois + server_error: Une erreur s\'est produite sur le serveur + notes: Notes + forum: Forum + last: Dernier + review: Revue + projects: Projets + action: Action + project: Projet + contribute: Contribuer + ok: Ok + first: Premier + website: Site Web + numbered_step: Etape %{number} + create: !binary | + Q3LDqWVy + + sort: + by_task_count_title: "Trier par nombre de t\xC3\xA2ches" + by_task_count_title_confirm: "Etes vous s\xC3\xBBr de vouloir trier ces projets par nombre de t\xC3\xA2ches ? L\\'ordre actuel sera remplac\xC3\xA9." + alphabetically: "Par ordre alphab\xC3\xA9tique" + sort: Trier + alphabetically_confirm: "Etes vous s\xC3\xBBr de vouloir trier ces projets par ordre alphab\xC3\xA9tique ? L\\'ordre actuel sera remplac\xC3\xA9." + alphabetically_title: "Trier les projets par ordre alphab\xC3\xA9tique" + by_task_count: "Par nombre de t\xC3\xA2ches" + drag_handle: DRAG + months: Mois + description: Description + fourth: "Quatri\xC3\xA8me" + next: Suivant + contexts: Contextes + todo: Action + context: Contexte + errors_with_fields: "Il y a des probl\xC3\xA8me avec les champs suivants :" + update: "Mettre \xC3\xA0 jour" + weeks: semaines + forth: FORTH + wiki: Wiki + bugs: Bugs + ajaxError: "Une erreur s'est produite en acc\xC3\xA9dant un serveur" + email: Email + search: Rechercher number: format: separator: . @@ -31,68 +91,10 @@ fr: unit: $ separator: . delimiter: "," - common: - back: Retour - recurring_todos: "R\xC3\xA9p\xC3\xA9tition d'actions" - actions: Actions - third: "Troisi\xC3\xA8me" - add: Ajouter - previous: !binary | - UHLDqWPDqWRlbnRl - - go_back: Retour - logout: "D\xC3\xA9connexion" - second: Seconde - optional: optionnel - week: semaine - none: Aucun - cancel: Annuler - month: mois - forum: Forum - server_error: Une erreur s\'est produite sur le serveur - notes: Notes - last: Dernier - review: Revue - projects: Projets - action: Action - project: Projet - ok: Ok - contribute: Contribuer - first: Premier - website: Site Web - numbered_step: Etape %{number} - errors_with_fields: "Il y a des probl\xC3\xA8me avec les champs suivants :" - create: !binary | - Q3LDqWVy - - sort: - by_task_count_title: "Trier par nombre de t\xC3\xA2ches" - by_task_count_title_confirm: "Etes vous s\xC3\xBBr de vouloir trier ces projets par nombre de t\xC3\xA2ches ? L\\'ordre actuel sera remplac\xC3\xA9." - alphabetically: "Par ordre alphab\xC3\xA9tique" - sort: Trier - alphabetically_confirm: "Etes vous s\xC3\xBBr de vouloir trier ces projets par ordre alphab\xC3\xA9tique ? L\\'ordre actuel sera remplac\xC3\xA9." - alphabetically_title: "Trier les projets par ordre alphab\xC3\xA9tique" - by_task_count: "Par nombre de t\xC3\xA2ches" - months: Mois - drag_handle: DRAG - description: Description - fourth: "Quatri\xC3\xA8me" - next: Suivant - contexts: Contextes - todo: Action - context: Contexte - update: "Mettre \xC3\xA0 jour" - weeks: semaines - forth: FORTH - wiki: Wiki - bugs: Bugs - email: Email - ajaxError: "Une erreur s'est produite en acc\xC3\xA9dant un serveur" - search: Rechercher layouts: toggle_contexts_title: "Faire des contextes effondr\xC3\xA9 (in)visibles" - toggle_contexts: "Basculer contextes effondr\xC3\xA9" toggle_notes: Afficher/Cacher notes + toggle_contexts: "Basculer contextes effondr\xC3\xA9" next_actions_rss_feed: Flux RSS des prochaines actions toggle_notes_title: Afficher/Cacher toutes les notes mobile_navigation: @@ -105,13 +107,13 @@ fr: contexts: Contextes home: Accueil navigation: - api_docs: Doc REST API manage_users_title: Ajouter ou supprimer des utilisateurs recurring_todos: "T\xC3\xA2ches (todos) r\xC3\xA9p\xC3\xA9titives" + api_docs: Doc REST API feeds: Flux stats: Statistiques - starred: "Marqu\xC3\xA9" notes_title: Voir toutes les notes + starred: "Marqu\xC3\xA9" manage_users: Gestion des utilisateurs tickler_title: Reporteur integrations_: "Int\xC3\xA9grer Tracks" @@ -121,22 +123,22 @@ fr: feeds_title: Voir une liste des flux disponibles calendar_title: "Calendrier des actions \xC3\xA0 \xC3\xA9ch\xC3\xA9ance" - home_title: Accueil - tickler: Reporteur - starred_title: "Voir vos actions pr\xC3\xA9f\xC3\xA9r\xC3\xA9es" recurring_todos_title: "Gerer les actions r\xC3\xA9currentes" + tickler: Reporteur completed_tasks: "Termin\xC3\xA9" stats_title: Voir vos statistiques + home_title: Accueil + starred_title: "Voir vos actions pr\xC3\xA9f\xC3\xA9r\xC3\xA9es" view: Vue organize: Organiser completed_tasks_title: "Termin\xC3\xA9" home: Accueil contexts_title: Contextes export: Exporter + projects_title: Projets + search: Recherches tous les items preferences_title: "Voir mes pr\xC3\xA9f\xC3\xA9rences" review_title: Faire examiner - search: Recherches tous les items - projects_title: Projets calendar: Calendrier integrations: opensearch_description: Rechercher dans Tracks @@ -168,23 +170,23 @@ fr: show_hidden_projects_in_sidebar: "Montrer les projets cach\xC3\xA9s dans le panneau lat\xC3\xA9ral" date_format: Format date show_hidden_contexts_in_sidebar: "Montrer les contextes cach\xC3\xA9s dans le panneau lat\xC3\xA9ral" + verbose_action_descriptors: "Descripteurs d\\'action d\xC3\xA9taill\xC3\xA9s" mobile_todos_per_page: Actions par page (Vue Mobile) staleness_starts: "D\xC3\xA9but de d\xC3\xA9passement" - verbose_action_descriptors: "Descripteurs d\\'action d\xC3\xA9taill\xC3\xA9s" sms_context: Contexte Email par default - title_date_format: Format de la date en titre show_number_completed: "Montrer le nombre d\\'action compl\xC3\xA9t\xC3\xA9es" + title_date_format: Format de la date en titre refresh: Intervalle de rafraichissement (en minutes) week_starts: Les semaines commencent un last_name: Nom locale: Langue - due_style: "Style Ech\xC3\xA9ance" time_zone: Fuseau horaire + due_style: "Style Ech\xC3\xA9ance" sms_email: De l\'Email show_project_on_todo_done: "Aller au projet quand la t\xC3\xA2che est termin\xC3\xA9e" show_completed_projects_in_sidebar: "Montrer les projets compl\xC3\xA9t\xC3\xA9s dans le panneau lat\xC3\xA9ral" - review_period: Intervalle de revue de projet first_name: Nom + review_period: Intervalle de revue de projet errors: models: project: @@ -216,13 +218,13 @@ fr: taken: "est d\xC3\xA9j\xC3\xA0 pris" inclusion: n\'est pas inclus dans la liste not_a_number: n\'est pas un nombre - full_messages: - format: "%{attribute} %{message}" template: body: "Il y a des probl\xC3\xA8mes avec les champs suivants :" header: one: "1 erreur a emp\xC3\xA9ch\xC3\xA9 ce %{model} d\\'\xC3\xAAtre sauvegard\xC3\xA9" other: "%{count} erreurs ont emp\xC3\xA9ch\xC3\xA9 ce %{model} d\\'\xC3\xAAtre sauvegard\xC3\xA9" + full_messages: + format: "%{attribute} %{message}" data: import_successful: "L'import a r\xC3\xA9ussi." import_errors: Des erreurs se sont produites durant l'import @@ -242,30 +244,31 @@ fr: - "Ech\xC3\xA9ance dans ____ jours" - "Ech\xC3\xA9ance le ____" stats: + tag_cloud_title: Nuage de tag pour toutes les actions totals_hidden_context_count: "et %{count} sont des contextes cach\xC3\xA9s." actions_avg_created: "Dans les 12 derniers mois vous avez cr\xC3\xA9\xC3\xA9 une moyenne de %{count} actions" actions_min_max_completion_days: "Le nombre max/min de jours pour r\xC3\xA9aliser est %{min}/%{max}." totals_actions_completed: "dont %{count} sont r\xC3\xA9alis\xC3\xA9es." - tag_cloud_title: Nuage de tag pour toutes les actions actions_actions_avg_created_30days: "Dans les 30 jours vous avez cr\xC3\xA9er en moyenne %{count} actions" actions_avg_completed: "et r\xC3\xA9alis\xC3\xA9 une moyenne de %{count} actions par mois." top5_visible_contexts_with_incomplete_actions: Top 5 des contextes visible avec des actions en cours actions: Actions - totals_deferred_actions: "desquels %{count} sont des actions report\xC3\xA9s dans le Reporteur" time_of_day_legend: number_of_actions: Nombre d'actions time_of_day: Heure totals_incomplete_actions: Vous avez %{count} actions en cours + totals_action_count: vous avez un total de %{count} actions running_time_legend: actions: Actions percentage: Pourcentage weeks: Temps en cours d'une action (en semaines). Cliquer sur une barre pour plus d'info - totals_action_count: vous avez un total de %{count} actions + totals_deferred_actions: "desquels %{count} sont des actions report\xC3\xA9s dans le Reporteur" tag_cloud_90days_title: Nuage de tag des actions des 90 derniers jours tod30: Heure (30 derniers jours) tags: Tags projects: Projets actions_avg_completion_time: "Pour toutes vos actions r\xC3\xA9alis\xC3\xA9s, le temps moyen de r\xC3\xA9alisation est %{count} jours." + actions_day_of_week_title: Jour de la semaine (toutes les actions) labels: month_avg_completed: "%{month} mois moy. r\xC3\xA9alis\xC3\xA9" completed: !binary | @@ -279,22 +282,21 @@ fr: created: !binary | Q3LDqcOp - actions_selected_from_week: "Actions selectionn\xC3\xA9es depuis la semaine" totals_completed_project_count: "et %{count} sont des projets r\xC3\xA9alis\xC3\xA9s." - actions_day_of_week_title: Jour de la semaine (toutes les actions) + actions_selected_from_week: "Actions selectionn\xC3\xA9es depuis la semaine" actions_lastyear_title: Actions des 12 derniers mois open_per_week: "Actifs (visibles et cach\xC3\xA9s) prochaines actions par semaine" action_selection_title: TRACKS::Selection action totals_project_count: Vous avez %{count} projets - current_running_time_of_incomplete_visible_actions: "Dur\xC3\xA9e en cours des actions incompl\xC3\xA8tes visibles" legend: number_of_days: Il y a ... jours actions: Actions number_of_actions: Nombre d'actions day_of_week: Jour de la semaine - percentage: Pourcentage running_time: Temps en cours d'une action (en semaines) + percentage: Pourcentage months_ago: Il y a ... mois + current_running_time_of_incomplete_visible_actions: "Dur\xC3\xA9e en cours des actions incompl\xC3\xA8tes visibles" tod30_legend: number_of_actions: Nombre d'actions time_of_day: Heure @@ -307,61 +309,61 @@ fr: months_ago: "Mois pr\xC3\xA9c\xC3\xA9dents" top10_projects: Top 10 des projets top5_contexts: Top 5 des contextes - contexts: Contextes totals: Totaux + contexts: Contextes click_to_return: "Cliquer %{link} pour revenir \xC3\xA0 la page des statistiques" tag_cloud_90days_description: "Ce nuage de tag contient les tags des actions cr\xC3\xA9\xC3\xA9es ou r\xC3\xA9alis\xC3\xA9es dans les 90 derniers jours." totals_visible_context_count: De ceux-ci %{count} sont des contextes visibles - top10_projects_30days: Top 10 des projets des 30 derniers jours running_time_all: "Temps en cours de toutes les actions incompl\xC3\xA8tes" + top10_projects_30days: Top 10 des projets des 30 derniers jours actions_min_completion_time: "Le temps minimum de r\xC3\xA9alisation est %{time}." action_completion_time_title: "Temps de r\xC3\xA9alisation (toutes les actions r\xC3\xA9alis\xC3\xA9es)" click_to_show_actions_from_week: Cliquer %{link} pour voir les actions depuis la semaine %{week}. top10_longrunning: Top 10 des plus long projets en cours no_actions_selected: "Il n'y a pas d'actions s\xC3\xA9lectionn\xC3\xA9es." - totals_tag_count: Vous avez %{count} tags sur des actions. actions_further: et plus + totals_tag_count: Vous avez %{count} tags sur des actions. actions_dow_30days_legend: number_of_actions: Certain nombre d'actions day_of_week: Jour de la semaine totals_first_action: "Depuis votre premi\xC3\xA8re action du %{date}" tag_cloud_description: "Ce nuage de tags contient les tags de toutes les actions (r\xC3\xA9alis\xC3\xA9es, en cours, visibles ou cach\xC3\xA9es)" - click_to_return_link: ici click_to_update_actions: Cliquer sur une barre du graphique pour mettre a jour les actions ci-dessous. + click_to_return_link: ici spread_of_actions_for_all_context: Vue des actions pour tous les contextes more_stats_will_appear: Plus de statistiques apparaitront quand vous aurez ajouter quelques actions. actions_avg_completed_30days: "et r\xC3\xA9alis\xC3\xA9 une moyenne de %{count} actions par jour." - no_tags_available: pas de tags disponibles - actions_30days_title: Actions des 30 derniers jours - index_title: TRACKS::Statistiques actions_dow_30days_title: Jour de la semaine (les 30 derniers jours) - spread_of_running_actions_for_visible_contexts: Vue des actions en cours pour tous les contextes + actions_30days_title: Actions des 30 derniers jours + no_tags_available: pas de tags disponibles + index_title: TRACKS::Statistiques actions_day_of_week_legend: number_of_actions: Certain nombre d'actions day_of_week: Jour de la semaine - actions_last_year: "Actions des derni\xC3\xA8res ann\xC3\xA9es" + spread_of_running_actions_for_visible_contexts: Vue des actions en cours pour tous les contextes totals_blocked_actions: "%{count} d\xC3\xA9pendent de la r\xC3\xA9alisation de leurs actions" + actions_last_year: "Actions des derni\xC3\xA8res ann\xC3\xA9es" totals_unique_tags: De ces tags, %{count} sont uniques. totals_active_project_count: De ceux-ci %{count} sont des projets actifs running_time_all_legend: actions: Actions - percentage: Pourcentage running_time: Temps en cours d'une action (en semaines). Cliquer sur une barre pour plus d'info + percentage: Pourcentage other_actions_label: (autres) - time_of_day: Heure (toutes les actions) totals_hidden_project_count: "%{count} sont cach\xC3\xA9s" + time_of_day: Heure (toutes les actions) todos: show_from: Afficher depuis error_starring_recurring: "Impossible d'actionner l'\xC3\xA9toile de la tache r\xC3\xA9currente \\'%{description}\\'" recurring_action_deleted: "L'action a \xC3\xA9t\xC3\xA9 supprim\xC3\xA9e. Parce que cette action est r\xC3\xA9currente, une nouvelle action \xC3\xA0 \xC3\xA9t\xC3\xA9 ajout\xC3\xA9e" completed_actions: "Action compl\xC3\xA9t\xC3\xA9es" - blocked_by: "Bloqu\xC3\xA9 par %{predecessors}" + completed_rest_of_previous_month: "Compl\xC3\xA9t\xC3\xA9 dans le reste du mois pr\xC3\xA9c\xC3\xA9dent" completed_recurring: "T\xC3\xA2ches reccurents compl\xC3\xA9t\xC3\xA9s" added_new_next_action: "Nouvelle action suivante ajout\xC3\xA9e" - completed_rest_of_previous_month: "Compl\xC3\xA9t\xC3\xA9 dans le reste du mois pr\xC3\xA9c\xC3\xA9dent" - defer_date_after_due_date: "La date de report est apr\xC3\xA8s la date d'\xC3\xA9ch\xC3\xA9ance. Veuillez ajuster la date d'\xC3\xA9cheance avant de reporter." - star_action: Elire cette action + blocked_by: "Bloqu\xC3\xA9 par %{predecessors}" completed_recurrence_completed: "Il n'y pas d'action suivante apr\xC3\xA8s l'action r\xC3\xA9currente que vous avez supprim\xC3\xA9e. La r\xC3\xA9currence est termin\xC3\xA9e" + star_action: Elire cette action + defer_date_after_due_date: "La date de report est apr\xC3\xA8s la date d'\xC3\xA9ch\xC3\xA9ance. Veuillez ajuster la date d'\xC3\xA9cheance avant de reporter." unable_to_add_dependency: "Impossible d'ajouter la d\xC3\xA9pendance" done: "Termin\xC3\xA9 ?" star_action_with_description: Elire l'action '%{description}' @@ -370,21 +372,21 @@ fr: Q29tcGzDqXTDqQ== no_deferred_actions_with: "Pas d'actions report\xC3\xA9es avec le tag '%{tag_name}'" + edit_action_with_description: Modifier l'action '%{description}' no_hidden_actions: "Il n'y a pas d'actions cach\xC3\xA9es actuellement" action_due_on: "(action \xC3\xA0 terminer avant le %{date})" - edit_action_with_description: Modifier l'action '%{description}' archived_tasks_title: "TRACKS::T\xC3\xA2ches r\xC3\xA9alis\xC3\xA9es archiv\xC3\xA9es" remove_dependency: "Enlever les d\xC3\xA9pendances (l'action n'est pas supprim\xC3\xA9e)" list_incomplete_next_actions: "Liste les prochaines actions incompl\xC3\xA8tes" tags: "Tags (s\xC3\xA9par\xC3\xA9s par des virgules)" action_deleted_success: "L'action suivante \xC3\xA0 \xC3\xA9t\xC3\xA9 supprim\xC3\xA9e avec succ\xC3\xA8s" - add_another_dependency: "Ajouter une autre d\xC3\xA9pendance" new_related_todo_created: "Une nouvelle t\xC3\xA2che a \xC3\xA9t\xC3\xA9 ajout\xC3\xA9e qui appartient \xC3\xA0 cette t\xC3\xA2che r\xC3\xA9currente" context_changed: "Contexte chang\xC3\xA9 en %{name}" + add_another_dependency: "Ajouter une autre d\xC3\xA9pendance" mobile_todos_page_title: Toutes les actions delete_recurring_action_title: "Supprimer l'action r\xC3\xA9currente" - recurring_actions_title: "TRACKS::Actions r\xC3\xA9currentes" removed_predecessor: "Suppression de %{successor} comme d\xC3\xA9pendance de %{predecessor}" + recurring_actions_title: "TRACKS::Actions r\xC3\xA9currentes" next_action_needed: Vous devez soumettre au moins une prochaine action action_saved: "Action sauvegard\xC3\xA9e" scheduled_overdue: "Programm\xC3\xA9e pour apparaitre il y a %{days} jours" @@ -392,7 +394,6 @@ fr: edit_action: Modifier action added_new_context: "Nouveau context ajout\xC3\xA9" next_actions_description: "Filtre:" - older_completed_items: "Anciens \xC3\xA9l\xC3\xA9ments compl\xC3\xA9t\xC3\xA9s" list_incomplete_next_actions_with_limit: "Liste les %{count} derni\xC3\xA8res actions suivantes incompl\xC3\xA8tes" set_to_pending: "%{task} mise en attente" added_new_project: "Nouveau projet ajout\xC3\xA9" @@ -400,28 +401,29 @@ fr: completed: "Actions compl\xC3\xA9t\xC3\xA9es" due_today: "\xC3\xA9ch\xC3\xA9ance aujourd'hui" due_within_a_week: "\xC3\xA9ch\xC3\xA9ance dans la semaine" - task_list_title: "TRACKS::Lister les t\xC3\xA2ches" + older_completed_items: "Anciens \xC3\xA9l\xC3\xA9ments compl\xC3\xA9t\xC3\xA9s" + error_deleting_item: "Il s'est produit une erreur lors de la suppression de l'\xC3\xA9l\xC3\xA9ment %{description}" edit_recurring_todo: "Modifier l'action r\xC3\xA9p\xC3\xA9tant" append_in_this_project: dans ce projet - error_deleting_item: "Il s'est produit une erreur lors de la suppression de l'\xC3\xA9l\xC3\xA9ment %{description}" + task_list_title: "TRACKS::Lister les t\xC3\xA2ches" no_actions_due_this_week: "Pas actions \xC3\xA0 faire cette semaine" - error_completing_todo: "Il s'est produit une erreur lors de l'execution de l'action r\xC3\xA9currente %{description}" + no_deferred_pending_actions: "Il n'y pas d'actions report\xC3\xA9es ou en attente actuellement" no_recurring_todos: "Il n'y a pas de t\xC3\xA2ches r\xC3\xA9currentes actuellement" + error_completing_todo: "Il s'est produit une erreur lors de l'execution de l'action r\xC3\xA9currente %{description}" recurring_pattern_removed: "La p\xC3\xA9riodicit\xC3\xA9 est retir\xC3\xA9 de %{count}" convert_to_project: Faire projet - no_deferred_pending_actions: "Il n'y pas d'actions report\xC3\xA9es ou en attente actuellement" delete_recurring_action_confirm: "Etes-vous s\xC3\xBBr de vouloir supprimer l'action r\xC3\xA9currente '%{description'}?" completed_last_day: "Compl\xC3\xA9t\xC3\xA9 ces derni\xC3\xA8res 24 heures" - all_completed: "Toutes les actions r\xC3\xA9alis\xC3\xA9es" show_in_days: Afficher dans %{days} jours no_project: --Pas de projet-- error_saving_recurring: "Il s'est produit une erreur lors de la sauvegarde de la t\xC3\xA2che r\xC3\xA9currente \\'%{description}\\'" completed_more_than_x_days_ago: "Compl\xC3\xA9t\xC3\xA9 il y a plus de %{count} jours" - feed_title_in_context: dans le contexte '%{context}' new_related_todo_created_short: "\xC3\xA0 cr\xC3\xA9\xC3\xA9 une nouvelle t\xC3\xA2che" + feed_title_in_context: dans le contexte '%{context}' + all_completed: "Toutes les actions r\xC3\xA9alis\xC3\xA9es" edit: Modifier - completed_tagged_page_title: "TRACKS::Les t\xC3\xA2ches termin\xC3\xA9es avec marquer %{tag_name}" older_than_days: Plus ancien que %{count} jours + completed_tagged_page_title: "TRACKS::Les t\xC3\xA2ches termin\xC3\xA9es avec marquer %{tag_name}" pending: En attente completed_actions_with: "Action compl\xC3\xA9t\xC3\xA9es avec le tag %{tag_name}" feed_title_in_project: dans le projet '%{project}' @@ -430,10 +432,10 @@ fr: clear_due_date: "Effacer la date d'\xC3\xA9ch\xC3\xA9ance" error_removing_dependency: "Il s'est produit une erreur lors de la suppression de la d\xC3\xA9pendance" hidden_actions: "Actions cach\xC3\xA9es" + deferred_actions_with: "Action report\xC3\xA9es avec le tag '%{tag_name}'" was_due_on_date: "arriv\xC3\xA9e \xC3\xA0 \xC3\xA9ch\xC3\xA9ance le %{date}" show_on_date: Afficher le %{date} recurrence_period: "Periode de r\xC3\xA9currence" - deferred_actions_with: "Action report\xC3\xA9es avec le tag '%{tag_name}'" confirm_delete: "Etes-vous s\xC3\xBBr de vouloir supprimer l'action '%{description}' ?" recurring_deleted_success: "L'action r\xC3\xA9currente a \xC3\xA9t\xC3\xA9 supprim\xC3\xA9e avec succ\xC3\xA8s." next_actions_title: Tracks - Prochaines Actions @@ -442,21 +444,21 @@ fr: no_completed_actions_with: "Pas d'actions compl\xC3\xA9t\xC3\xA9es avec le tag '%{tag_name}'" clear_show_from_date: Effacer show from date calendar_page_title: TRACKS::Calendrier - unresolved_dependency: "La valeur saisie dans le champ d\xC3\xA9pendance ne correspond pas \xC3\xA0 une action existante. Cette valeur ne sera pas sauvegard\xC3\xA9e avec le reste de l'action. Continuer ?" in_hidden_state: "a l\\'\xC3\xA9tat cach\xC3\xA9" - show_today: Afficher aujourd'hui - no_actions_found_title: "Aucune action trouv\xC3\xA9e" + unresolved_dependency: "La valeur saisie dans le champ d\xC3\xA9pendance ne correspond pas \xC3\xA0 une action existante. Cette valeur ne sera pas sauvegard\xC3\xA9e avec le reste de l'action. Continuer ?" next_actions_due_date: overdue_by: "D\xC3\xA9pass\xC3\xA9e de %{days} jour" - due_today: "Ech\xC3\xA9ance aujourd'hui" due_in_x_days: "Ech\xC3\xA9ance dans %{days} days" + due_today: "Ech\xC3\xA9ance aujourd'hui" overdue_by_plural: "D\xC3\xA9pass\xC3\xA9e de %{days} jours" due_tomorrow: "Ech\xC3\xA9ance demain" + show_today: Afficher aujourd'hui + no_actions_found_title: "Aucune action trouv\xC3\xA9e" completed_last_x_days: "Compl\xC3\xA9t\xC3\xA9 ces %{count} jours" - no_actions_with: "Il n'y pas d'actions incompl\xC3\xA8tes avec le tag '%{tag_name}' actuellement" defer_x_days: one: Reporter d'un jour other: Report de %{count} jours + no_actions_with: "Il n'y pas d'actions incompl\xC3\xA8tes avec le tag '%{tag_name}' actuellement" added_new_next_action_singular: "Nouvelle action suivante ajout\xC3\xA9e" no_completed_actions: "Il n'y a pas d'actions compl\xC3\xA9t\xC3\xA9es actuellement." feeds: @@ -470,18 +472,18 @@ fr: error_deleting_recurring: "Il s'est produit une erreur lors de la suppression de la t\xC3\xA2che r\xC3\xA9currente \\'%{description}\\'" recurring_todos: "T\xC3\xA2ches r\xC3\xA9currentes" delete: Supprimer - cannot_add_dependency_to_completed_todo: "Impossible d'ajouter cette action comme d\xC3\xA9pendance d'une action compl\xC3\xA9t\xC3\xA9e !" drag_action_title: "D\xC3\xA9placer sur une autre action pour la rendre d\xC3\xA9pendante de cette action" + cannot_add_dependency_to_completed_todo: "Impossible d'ajouter cette action comme d\xC3\xA9pendance d'une action compl\xC3\xA9t\xC3\xA9e !" no_last_completed_actions: "Aucune action achev\xC3\xA9e trouve" tickler_items_due: one: "Un \xC3\xA9l\xC3\xA9ment du reporteur est arriv\xC3\xA9 \xC3\xA0 \xC3\xA9ch\xC3\xA9ance - rafraichir la page pour le voir." other: "%{count} \xC3\xA9l\xC3\xA9ments du reporteur sont arriv\xC3\xA9s \xC3\xA0 \xC3\xA9ch\xC3\xA9ance - rafraichir la page pour les voir." depends_on: "D\xC3\xA9pend de" action_marked_complete: "L'action '%{description}' a \xC3\xA9t\xC3\xA9 marqu\xC3\xA9e comme %{completed}" + added_new_next_action_plural: "Nouvelles actions suivantes ajout\xC3\xA9es" completed_today: one: "Vous avez compl\xC3\xA9t\xC3\xA9 une action aujourd'hui" other: "Vous avez compl\xC3\xA9t\xC3\xA9 %{count} action aujourd'hui" - added_new_next_action_plural: "Nouvelles actions suivantes ajout\xC3\xA9es" new_related_todo_not_created_short: "n'a pas cr\xC3\xA9\xC3\xA9 la t\xC3\xA2che" completed_rest_of_week: "Compl\xC3\xA9t\xC3\xA9 dans le reste de cette semaine" error_starring: "Impossible d'actionner l'\xC3\xA9toile de cette tache \\'%{description}\\'" @@ -491,14 +493,13 @@ fr: due_next_week: "A r\xC3\xA9aliser la semaine prochaine" no_actions_due_next_week: "Pas d'actions \xC3\xA0 terminer la semaine prochaine" due_this_week: "A r\xC3\xA9aliser avant la fin de cette semaine" - due_today: "A r\xC3\xA9aliser aujourd'hui" no_actions_due_today: "Pas d'action \xC3\xA0 terminer aujourd'hui" + due_today: "A r\xC3\xA9aliser aujourd'hui" due_next_month_and_later: "A r\xC3\xA9aliser dans %{month} et plus" no_actions_due_after_this_month: "Pas d'actions \xC3\xA0 r\xC3\xA9aliser apr\xC3\xA8s ce mois" no_actions_due_this_month: "Pas d'actions \xC3\xA0 terminer pour ce mois" due_this_month: "A r\xC3\xA9aliser avant la fin de %{month}" action_deferred: "L'action '%{description}' a \xC3\xA9t\xC3\xA9 report\xC3\xA9" - added_dependency: "%{dependency} ajout\xC3\xA9e comme d\xC3\xA9pendance" recurrence: ends_on_number_times: Fini au bout de %{number} fois ends_on_date: Fini le %{date} @@ -513,6 +514,7 @@ fr: show_option_always: toujours daily: Quotidiennement pattern: + third: "troisi\xC3\xA8me" month_names: - - Janvier @@ -527,7 +529,6 @@ fr: - Octobre - Novembre - "D\xC3\xA9cembre" - third: "troisi\xC3\xA8me" every_n: tous les %{n} second: seconde every_xth_day_of_every_n_months: tous les %{x} %{day} tous les %{n_months} @@ -539,6 +540,9 @@ fr: the_xth_day_of_month: le %{x} %{day} de %{month} times: pour %{number} fois every_year_on: "chaque ann\xC3\xA9e le %{date}" + on_work_days: "les jours ouvr\xC3\xA9s" + first: premier + show: montrer day_names: - Dimanche - Lundi @@ -547,9 +551,6 @@ fr: - Jeudi - Vendredi - Samedi - show: montrer - first: premier - on_work_days: "les jours ouvr\xC3\xA9s" fourth: "quatri\xC3\xA8me" due: "Ech\xC3\xA9ance" until: jusqu'a @@ -560,37 +561,38 @@ fr: ends_on: Fini le show_options: "Montrer la t\xC3\xA2che" weekly_every_number_week: Returns every %{number} week on - show_days_before: "%{days} jours avant la date d'\xC3\xA9ch\xC3\xA9ance de la t\xC3\xA2che" - yearly_every_xth_day: Chaque %{day} %{day_of_week} de %{month} from_tickler: "la date de la t\xC3\xA2che provient du reporteur (pas de date d\\'\xC3\xA9ch\xC3\xA9ance d\xC3\xA9finie)" + yearly_every_xth_day: Chaque %{day} %{day_of_week} de %{month} no_end_date: Pas de date de fin day_x_on_every_x_month: Le %{day} tous les %{month} mois yearly_options: "Param\xC3\xA8tres pour les actions r\xC3\xA9currentes annuelles" + show_days_before: "%{days} jours avant la date d'\xC3\xA9ch\xC3\xA9ance de la t\xC3\xA2che" monthly_every_xth_day: Le %{day} %{day_of_week} tous les %{month} mois yearly: Tous les ans tagged_page_title: "TRACKS::Tagg\xC3\xA9 avec %{tag_name}'" no_completed_recurring: "Il n'y a pas d'actions r\xC3\xA9currentes compl\xC3\xA9t\xC3\xA9es actuellement" - completed_rest_of_month: "Compl\xC3\xA9t\xC3\xA9 dans le reste de ce mois-ci" - recurrence_completed: "Il n'y a pas d'action suivante apr\xC3\xA8s l'action r\xC3\xA9currente que vous venez de terminer. Fin de la r\xC3\xA9currence" + added_dependency: "%{dependency} ajout\xC3\xA9e comme d\xC3\xA9pendance" all_completed_tagged_page_title: "TRACKS::Toutes les t\xC3\xA2ches accomplies par marquer %{tag_name}" no_deferred_actions: "Il n'y a pas d'actions report\xC3\xA9es actuellement" - in_pending_state: en attente + completed_rest_of_month: "Compl\xC3\xA9t\xC3\xA9 dans le reste de ce mois-ci" + recurrence_completed: "Il n'y a pas d'action suivante apr\xC3\xA8s l'action r\xC3\xA9currente que vous venez de terminer. Fin de la r\xC3\xA9currence" no_actions_found: "Il n'y pas d'actions incompl\xC3\xA8tes actuellement." + in_pending_state: en attente error_toggle_complete: "Impossible de marquer cette tache comme compl\xC3\xA9t\xC3\xA9e" due: "Ech\xC3\xA9ance" action_marked_complete_error: "L'action '%{description}' n'a PAS \xC3\xA9t\xC3\xA9 marqu\xC3\xA9e comme %{completed} a cause d'une erreur sur le serveur " + to_tickler: Vers le reporteur + add_new_recurring: "Ajouter une nouvelle action r\xC3\xA9currente" depends_on_separate_with_commas: "D\xC3\xA9pend de (s\xC3\xA9parer avec des virgules)" recurring_action_saved: "Action r\xC3\xA9currente sauv\xC3\xA9e" action_saved_to_tickler: "Action sauvegard\xC3\xA9e dans le Reporteur" completed_in_archive: one: "Il n'y a pas d'action compl\xC3\xA9t\xC3\xA9e dans l'archive" other: "Il y a %{count} actions compl\xC3\xA9t\xC3\xA9es dans l'archive" - to_tickler: Vers le reporteur next_actions_description_additions: completed: dans les %{count} derniers jours due_date: "avec au plus la date d'\xC3\xA9ch\xC3\xA9ance %{due_date}" overdue: En retard - add_new_recurring: "Ajouter une nouvelle action r\xC3\xA9currente" no_incomplete_actions: "Il n'y a pas d'actions incompl\xC3\xA8tes" notes: delete_note_title: Supprimer la note '%{id}' @@ -612,48 +614,46 @@ fr: stalled: "Bloqu\xC3\xA9s" completed: "Complet\xC3\xA9" current: Up-to-date + completed_plural: "Complet\xC3\xA9s" review: !binary | RGF0w6ll - completed_plural: "Complet\xC3\xA9s" blocked_plural: "Bloqu\xC3\xA9e" blocked: "Bloqu\xC3\xA9e" stalled_plural: "Bloqu\xC3\xA9s" visible_plural: Visibles active_plural: Actifs visible: Visible - current_plural: Up-to-date hidden: !binary | Q2FjaMOp + current_plural: Up-to-date active: Actif - errors: - user_unauthorized: "401 Non autoris\xC3\xA9: Administrateur seulement." projects: - no_actions_in_project: "Il n'y pas d'action incompl\xC3\xA8tes pour ce projet" - deferred_actions: "Actions report\xC3\xA9es pour ce projet" - was_marked_hidden: "est cach\xC3\xA9" edit_project_title: Editer le projet default_tags_removed_notice: Supprimer les tags par defaut default_context_set: "D\xC3\xA9finir le contexte par d\xC3\xA9faut du projet \xC3\xA0 %{default_context}" + no_actions_in_project: "Il n'y pas d'action incompl\xC3\xA8tes pour ce projet" + deferred_actions: "Actions report\xC3\xA9es pour ce projet" + was_marked_hidden: "est cach\xC3\xA9" hide_form: Cacher le formulaire - page_title: "TRACKS::Projet: %{project}" all_completed_tasks_title: "TRACKS::Tous les Actions Achev\xC3\xA9 en Projet '%{project_name}'" - project_state: Le projet est %{state} + page_title: "TRACKS::Projet: %{project}" + this_project: Ce projet list_completed_projects: "TRACKS::Liste des projets achev\xC3\xA9s" to_new_project_page: "Aller \xC3\xA0 la page du nouveau projet" no_notes_attached: "Il n'y a actuellement aucune note attach\xC3\xA9e \xC3\xA0 ce projet" show_form_title: "Cr\xC3\xA9er un nouveau projet" deferred_actions_empty: "Il n'y a pas d'actions report\xC3\xA9es pour ce projet" - this_project: Ce projet + project_state: Le projet est %{state} no_last_completed_recurring_todos: "Non termin\xC3\xA9 actions r\xC3\xA9p\xC3\xA9titives trouv\xC3\xA9es" todos_append: dans ce projet no_last_completed_projects: "Pas de projets termin\xC3\xA9s trouv\xC3\xA9s" notes: Notes - hide_form_title: Cacher le formulaire nouveau projet - list_reviews: TRACKS::Revue notes_empty: Il n'y a pas de notes pour ce projet no_projects: Il n'y a actuellement aucun projet + hide_form_title: Cacher le formulaire nouveau projet + list_reviews: TRACKS::Revue completed_actions_empty: "Il n'y a pas d'actions r\xC3\xA9alis\xC3\xA9es pour ce projet" with_no_default_context: "sans contexte par d\xC3\xA9faut" delete_project: Supprimer projet @@ -661,43 +661,45 @@ fr: actions_in_project_title: Actions pour ce projet delete_project_confirmation: "Etes vous s\xC3\xBBr de vouloir supprimer le projet '%{name}' ?" with_default_context: "avec '%{context_name}' comme contexte par d\xC3\xA9faut" - set_default_tags_notice: "D\xC3\xA9finir les tags par d\xC3\xA9faut du projet \xC3\xA0 %{default_tags}" + is_active: est actif completed_projects: "Projets r\xC3\xA9alis\xC3\xA9s" + project_saved_status: "Projet sauvegard\xC3\xA9" add_note: Ajouter une note add_project: Ajouter projet - settings: "Param\xC3\xA8tres" with_default_tags: et avec '%{tags'} comme tags par defaut + settings: "Param\xC3\xA8tres" list_projects: TRACKS::Liste des Projets - is_active: est actif - project_saved_status: "Projet sauvegard\xC3\xA9" + set_default_tags_notice: "D\xC3\xA9finir les tags par d\xC3\xA9faut du projet \xC3\xA0 %{default_tags}" + completed_tasks_title: "TRACKS::Liste des actions men\xC3\xA9es \xC3\xA0 terme dans Projet '%{project_name}'" delete_project_title: Supprimer le projet hidden_projects: "Projets cach\xC3\xA9s" - completed_tasks_title: "TRACKS::Liste des actions men\xC3\xA9es \xC3\xA0 terme dans Projet '%{project_name}'" default_context_removed: "Contexte par d\xC3\xA9faut supprim\xC3\xA9" - completed_actions: "Actions r\xC3\xA9alis\xC3\xA9es pour ce projet" add_note_submit: Ajouter note was_marked_complete: "est compl\xC3\xA9t\xC3\xA9" + completed_actions: "Actions r\xC3\xA9alis\xC3\xA9es pour ce projet" no_default_context: Ce projet n'a pas de contexte par defaut with_no_default_tags: "et sans tags par d\xC3\xA9faut" edit_project_settings: "Modifier les param\xC3\xA8tres du projet" - status_project_name_changed: "Le nom du projet a \xC3\xA9t\xC3\xA9 modifi\xC3\xA9" state: Le projet est %{state} + status_project_name_changed: "Le nom du projet a \xC3\xA9t\xC3\xA9 modifi\xC3\xA9" default_context: "Le contexte par d\xC3\xA9faut pour ce projet est %{context}" active_projects: Projets actifs + errors: + user_unauthorized: "401 Non autoris\xC3\xA9: Administrateur seulement." preferences: change_identity_url: "Modifier votre URL d'identit\xC3\xA9" - open_id_url: Votre URL OpenID est staleness_starts_after: "\"date de fraicher\" d\xC3\xA9pass\xC3\xA9e \xC3\xA0 pr\xC3\xA8s %{days} days" + open_id_url: Votre URL OpenID est change_password: Modifier votre mot de passe page_title: "TRACKS::Pr\xC3\xA9f\xC3\xA9rences" token_description: Jeton (pour flux et utilisation API) title: "Vos pr\xC3\xA9f\xC3\xA9rences" - is_false: faux show_number_completed: "Montrer %{number} items r\xC3\xA9alis\xC3\xA9s" + is_false: faux + edit_preferences: "Editer les pr\xC3\xA9f\xC3\xA9rences" page_title_edit: "TRACKS::Editer les pr\xC3\xA9f\xC3\xA9rences" is_true: vrai password_changed: "Votre mot de passe a \xC3\xA9t\xC3\xA9 chang\xC3\xA9, s'il vous pla\xC3\xAEt vous connecter \xC3\xA0 nouveau." - edit_preferences: "Editer les pr\xC3\xA9f\xC3\xA9rences" generate_new_token: "G\xC3\xA9n\xC3\xA9rer un nouveau jeton" sms_context_none: Aucun token_header: Votre jeton @@ -805,15 +807,15 @@ fr: shared: multiple_next_actions: Actions suivante multiples (une sur chaque ligne) make_actions_dependent: "Faire actions d\xC3\xA9pendantes les unes des autres" - hide_form: Cacher le formulaire toggle_single: Ajouter action suivante + hide_form: Cacher le formulaire add_actions: Ajouter actions add_action: Ajouter action tags_for_all_actions: Tags pour toutes les actions (sep. avec des virgules) - toggle_multi: Ajouter plusieurs actions suivantes - toggle_single_title: Ajouter une nouvelle action suivante project_for_all_actions: Projet pour toutes les actions context_for_all_actions: Contexte pour toutes les actions + toggle_multi: Ajouter plusieurs actions suivantes + toggle_single_title: Ajouter une nouvelle action suivante separate_tags_with_commas: "s\xC3\xA9parer avec des virgules" toggle_multi_title: Basculer formulaire action simple/multiple hide_action_form_title: Cacher le formulaire nouvelle action @@ -822,8 +824,8 @@ fr: feedlist: actions_due_today: Actions devant se terminer aujourd'hui ou avant choose_context: Choisir le contexte dont vous voulez un flux - rss_feed: Flux RSS legend: "L\xC3\xA9gende" + rss_feed: Flux RSS ical_feed: Flux iCal all_contexts: Tous les contextes all_projects: Tous les projets @@ -832,89 +834,61 @@ fr: select_feed_for_project: Selectionner le flux pour ce projet active_projects_wo_next: Projets actifs avec aucune action suivante active_starred_actions: "Toutes les actions pr\xC3\xA9ferr\xC3\xA9es actives" - context_needed: Il faut au moins un contexte pour le flux select_feed_for_context: Selectionner un flux pour ce contexte projects_and_actions: Projets actifs et leurs actions + context_needed: Il faut au moins un contexte pour le flux actions_due_next_week: Actions devant se terminer dans les 7 prochains jours ou moins notice_incomplete_only: "NB: Les flux ne montrent que les actions incompl\xC3\xA8tes, sauf indication contraire" + context_centric_actions: "Flux des actions dans un contexte sp\xC3\xA9cifique" + plain_text_feed: Flux texte last_fixed_number: "Derni\xC3\xA8res %{number} actions" all_actions: Toutes les actions actions_completed_last_week: "Actions r\xC3\xA9alis\xC3\xA9es dans les 7 derniers jours" - context_centric_actions: "Flux des actions dans un contexte sp\xC3\xA9cifique" - plain_text_feed: Flux texte project_centric: "Flux des actions incompl\xC3\xA8tes d'un projet sp\xC3\xA9cifique" users: + first_user_heading: "Bienvenu \xC3\xA0 TRAKS. Pour commencer, veuillez cr\xC3\xA9er un compte administrateur" successfully_deleted_user: "Utilisateur %{username} supprim\xC3\xA9 avec succ\xC3\xA8s" + auth_type_update_error: "Un probl\xC3\xA8me est survenu lors de la modification du type d'authentification : %{error_messages}" failed_to_delete_user: "La suppression de l'utilisateur {username} \xC3\xA0 \xC3\xA9chou\xC3\xA9" destroy_successful: "Utilisateur %{login} supprim\xC3\xA9 avec succ\xC3\xA8s" total_contexts: Total contextes openid_url_verified: "Vous avez v\xC3\xA9rifi\xC3\xA9 avec succ\xC3\xA8s votre identit\xC3\xA9 comme %{url} et d\xC3\xA9fini votre type authentification comme OpenID" - first_user_heading: "Bienvenu \xC3\xA0 TRAKS. Pour commencer, veuillez cr\xC3\xA9er un compte administrateur" - auth_type_update_error: "Un probl\xC3\xA8me est survenu lors de la modification du type d'authentification : %{error_messages}" + signup_successful: "Utilisateur %{username} cr\xC3\xA9\xC3\xA9 avec succ\xC3\xA8s." new_token_generated: "Nouveau token g\xC3\xA9n\xC3\xA9r\xC3\xA9 avec succ\xC3\xA9s" total_projects: Total projets - signup_successful: "Utilisateur %{username} cr\xC3\xA9\xC3\xA9 avec succ\xC3\xA8s." no_signups_title: TRACKS::Pas de signups user_created: "Utilisateur cr\xC3\xA9\xC3\xA9." change_password_submit: Modifier mot de passe - account_signup: "Cr\xC3\xA9er un compte" manage_users: "G\xC3\xA9rer utilisateurs" + account_signup: "Cr\xC3\xA9er un compte" password_updated: "Mot de passe modifi\xC3\xA9." - auth_type_updated: "Type d'authentification modifi\xC3\xA9." total_actions: Total actions desired_login: "Login souhait\xC3\xA9" - signup: "Cr\xC3\xA9ation" confirm_password: Confirmer le mot de passe new_user_heading: "Cr\xC3\xA9er un nouvel utilisateur:" - change_password_prompt: Entrer votre nouveau mot de passe dans les champs ci-dessous et cliquer sur 'Modifier mot de passe' pour remplacer votre mot de passe actuel par le nouveau. - password_confirmation_label: Confirmer mot de passe + signup: "Cr\xC3\xA9ation" + auth_type_updated: "Type d'authentification modifi\xC3\xA9." destroy_error: Une erreur s'est produite lors de la suppression de l'utilisateur %{login} choose_password: Choisir le mot de passe change_password_title: TRACKS::Modifier mot de passe change_auth_type_title: TRACKS::Modifier le type d'authentification + change_password_prompt: Entrer votre nouveau mot de passe dans les champs ci-dessous et cliquer sur 'Modifier mot de passe' pour remplacer votre mot de passe actuel par le nouveau. + password_confirmation_label: Confirmer mot de passe new_password_label: Nouveau mot de passe register_with_cas: Avec votre nom d'utilisateur CAS label_auth_type: Type d'authentification + total_users_count: Vous avez %{count} utilisateurs new_user_title: "TRACKS::Cr\xC3\xA9er un administrateur" destroy_user: Supprimer utilisateur - total_users_count: Vous avez %{count} utilisateurs you_have_to_reset_your_password: "Vous devez r\xC3\xA9initialiser votre mot de passe" signup_new_user: "Cr\xC3\xA9er un nouvel utilisateur" destroy_confirmation: "Attention : cela va supprimer l'utilisateur '%{login}', toutes ses actions, contextes, projets et notes. Etes-vous s\xC3\xBBr de vouloir continuer ?" identity_url: "URL Identit\xC3\xA9" - openid_ok_pref_failed: "Vous avez v\xC3\xA9rifi\xC3\xA9 avec succ\xC3\xA8s votre identit\xC3\xA9 comme %{url} mais un probl\xC3\xA8me est survenu lors de la sauvegarde de vos pr\xC3\xA9f\xC3\xA9rences d'authentification." change_authentication_type: Modifier le type d'authentification + openid_ok_pref_failed: "Vous avez v\xC3\xA9rifi\xC3\xA9 avec succ\xC3\xA8s votre identit\xC3\xA9 comme %{url} mais un probl\xC3\xA8me est survenu lors de la sauvegarde de vos pr\xC3\xA9f\xC3\xA9rences d'authentification." auth_change_submit: Modifier le type d'authenfication select_authentication_type: "S\xC3\xA9lectionner votre nouveau type d'authentification et cliquer sur 'Modifier type d'authenfication' pour remplacer les param\xC3\xA8tres actuels." total_notes: Total notes - contexts: - delete_context_title: Supprimer contexte - hide_form: Cacher le formulaire - all_completed_tasks_title: "TRACKS::Toutes les actions Achev\xC3\xA9 en le contexte '%{context_name}'" - show_form_title: Ajouter un contexte - delete_context_confirmation: "Etes vous s\xC3\xBBr de vouloir supprimer le contexte %{name}? Toutes les actions (r\xC3\xA9p\xC3\xA9titives) de ce contexte seront \xC3\xA9galement supprim\xC3\xA9es !" - todos_append: dans ce contexte - delete_context: Supprimer contexte - edit_context: Modifier contexte - hide_form_title: Cacher le formulaire nouveau contexte - context_hide: "Cach\xC3\xA9 de la premi\xC3\xA8re page ?" - hidden_contexts: "Contextes cach\xC3\xA9s" - no_contexts_active: Actuellement, il n'y a pas de contextes actifs - show_form: "Cr\xC3\xA9er un nouveau contexte" - visible_contexts: Contextes visibles - save_status_message: "Contexte sauvegard\xC3\xA9" - add_context: Ajouter un contexte - update_status_message: "Le nom du contexte \xC3\xA0 \xC3\xA9t\xC3\xA9 modifi\xC3\xA9" - context_name: Nom du Contexte - status_active: Le Contexte est actif - completed_tasks_title: "TRACKS::actions Achev\xC3\xA9 en le contexte '%{context_name}'" - new_context_post: "'sera aussi cr\xC3\xA9\xC3\xA9. Etes-vous s\xC3\xBBr ?" - no_actions: "Actuellement, il n'y pas d'actions incompl\xC3\xA8tes dans ce contexte" - last_completed_in_context: dans ce contexte (dernier %{number}) - context_deleted: "Contexte \\'%{name}\\' supprim\xC3\xA9" - no_contexts_hidden: "Actuellement, il n'y a pas de contextes cach\xC3\xA9s" - new_context_pre: Nouveau contexte ' - status_hidden: "Le Contexte est cach\xC3\xA9" sidebar: list_name_active_contexts: Contextes actifs list_name_active_projects: Projets actifs @@ -922,16 +896,44 @@ fr: list_name_completed_projects: "Projets r\xC3\xA9alis\xC3\xA9s" list_name_hidden_projects: "Projets cach\xC3\xA9s" list_name_hidden_contexts: "Contextes cach\xC3\xA9s" + contexts: + delete_context_title: Supprimer contexte + hide_form: Cacher le formulaire + all_completed_tasks_title: "TRACKS::Toutes les actions Achev\xC3\xA9 en le contexte '%{context_name}'" + show_form_title: Ajouter un contexte + delete_context_confirmation: "Etes vous s\xC3\xBBr de vouloir supprimer le contexte %{name}? Toutes les actions (r\xC3\xA9p\xC3\xA9titives) de ce contexte seront \xC3\xA9galement supprim\xC3\xA9es !" + delete_context: Supprimer contexte + todos_append: dans ce contexte + edit_context: Modifier contexte + hide_form_title: Cacher le formulaire nouveau contexte + no_contexts_active: Actuellement, il n'y a pas de contextes actifs + context_hide: "Cach\xC3\xA9 de la premi\xC3\xA8re page ?" + hidden_contexts: "Contextes cach\xC3\xA9s" + visible_contexts: Contextes visibles + save_status_message: "Contexte sauvegard\xC3\xA9" + show_form: "Cr\xC3\xA9er un nouveau contexte" + add_context: Ajouter un contexte + context_name: Nom du Contexte + update_status_message: "Le nom du contexte \xC3\xA0 \xC3\xA9t\xC3\xA9 modifi\xC3\xA9" + completed_tasks_title: "TRACKS::actions Achev\xC3\xA9 en le contexte '%{context_name}'" + status_active: Le Contexte est actif + new_context_post: "'sera aussi cr\xC3\xA9\xC3\xA9. Etes-vous s\xC3\xBBr ?" + context_deleted: "Contexte \\'%{name}\\' supprim\xC3\xA9" + no_contexts_hidden: "Actuellement, il n'y a pas de contextes cach\xC3\xA9s" + new_context_pre: Nouveau contexte ' + no_actions: "Actuellement, il n'y pas d'actions incompl\xC3\xA8tes dans ce contexte" + last_completed_in_context: dans ce contexte (dernier %{number}) + status_hidden: "Le Contexte est cach\xC3\xA9" login: - sign_in: Se connecter openid_identity_url_not_found: "D\xC3\xA9sol\xC3\xA9, aucun utilisateur avec cette identit\xC3\xA9 URL n'existe (%{identity_url})" user_no_expiry: "Rester connect\xC3\xA9" login_cas: Aller au CAS - cas_logged_in_greeting: "Bonjour, %{username}! Vous \xC3\xAAtes authentifi\xC3\xA9." + sign_in: Se connecter cas_no_user_found: Bonjour, %{username}! Vous n'avez pas de compte sur Tracks. cas_login: Login CAS successful_with_session_info: "La connexion \xC3\xA0 r\xC3\xA9ussi:" please_login: Veuillez vous connecter pour utiliser Tracks + cas_logged_in_greeting: "Bonjour, %{username}! Vous \xC3\xAAtes authentifi\xC3\xA9." cas_username_not_found: "D\xC3\xA9sol\xC3\xA9, aucun utilisateur avec ce nom CAS n'existe (%{username})" cas_create_account: "Si vous voulez vous inscrire aller \xC3\xA0 %{signup_link}" mobile_use_openid: ... ou ce connecter avec un OpenID diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 83e60a2a..e8823318 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -1,5 +1,61 @@ --- nl: + common: + back: Terug + recurring_todos: Herhalende acties + actions: Acties + third: Derde + add: Toevoegen + previous: Vorige + go_back: Ga terug + logout: Log uit + second: Tweede + actions_midsentence: acties + optional: optioneel + week: week + none: Geen + show_all: Toon alle + cancel: Annuleer + month: maand + server_error: Een fout heeft op de server plaatsgevonden + notes: Notities + forum: Forum + last: Laatste + review: Evaluatie + projects: Projecten + action: Actie + project: Project + contribute: Bijdragen + ok: Ok + first: Eerste + website: Website + numbered_step: Stap %{number} + sort: + by_task_count_title: Sorteer op aantal acties + by_task_count_title_confirm: Weet u zeker dat u deze op aantal acties wilt sorteren? Dat zal de huidige sorteervolgorde aanpassen. + alphabetically: Alfabetisch + sort: Sorteer + alphabetically_confirm: Weet u zeker dat u deze projecten alfabetisch wilt sorteren? Dat zal de huidige sorteervolgorde aanpassen. + alphabetically_title: Sorteer projecten alfabetisch + by_task_count: Op aantal acties + drag_handle: SLEEP + create: Maken + months: maanden + description: Beschrijving + fourth: Vierde + next: Volgende + contexts: Contexten + todo: actie + context: Context + errors_with_fields: Er waren problemen met de volgende velden + update: Bijwerken + weeks: weken + forth: Vierde + wiki: Wiki + bugs: Fouten + ajaxError: Er is een fout opgetreden bij het ophalen van gegevens van de server + email: E-mail + search: Zoeken number: format: separator: "," @@ -23,71 +79,12 @@ nl: separator: "," delimiter: . - integrations: - opensearch_description: Zoek in Tracks - applescript_next_action_prompt: "Omschrijving van de actie:" - gmail_description: Gadget om Tracks toe te voegen aan Gmail als een gadget - applescript_success_before_id: Nieuwe actie met ID - applescript_success_after_id: gemaakt - common: - back: Terug - recurring_todos: Herhalende acties - actions: Acties - third: Derde - add: Toevoegen - previous: Vorige - logout: Log uit - go_back: Ga terug - optional: optioneel - week: week - none: Geen - cancel: Annuleer - month: maand - second: Tweede - server_error: Een fout heeft op de server plaatsgevonden - forum: Forum - notes: Notities - review: Evaluatie - projects: Projecten - last: Laatste - action: Actie - project: Project - contribute: Bijdragen - ok: Ok - numbered_step: Stap %{number} - first: Eerste - website: Website - months: maanden - sort: - by_task_count_title: Sorteer op aantal acties - by_task_count_title_confirm: Weet u zeker dat u deze op aantal acties wilt sorteren? Dat zal de huidige sorteervolgorde aanpassen. - alphabetically: Alfabetisch - alphabetically_title: Sorteer projecten alfabetisch - sort: Sorteer - alphabetically_confirm: Weet u zeker dat u deze projecten alfabetisch wilt sorteren? Dat zal de huidige sorteervolgorde aanpassen. - by_task_count: Op aantal acties - fourth: Vierde - errors_with_fields: Er waren problemen met de volgende velden - contexts: Contexten - todo: actie - context: Context - next: Volgende - description: Beschrijving - drag_handle: SLEEP - create: Maken - weeks: weken - wiki: Wiki - update: Bijwerken - bugs: Fouten - forth: Vierde - search: Zoeken - email: E-mail - ajaxError: Er is een fout opgetreden bij het ophalen van gegevens van de server layouts: toggle_contexts_title: Maak ingeklapte contexten (on)zichtbaar - toggle_contexts: Toggle ingeklapte contexten toggle_notes: Toggle notities + toggle_contexts: Toggle ingeklapte contexten next_actions_rss_feed: RSS-feed van de acties + toggle_notes_title: Toggle alle notities mobile_navigation: new_action: Nieuwe actie logout: Afmelden @@ -97,57 +94,44 @@ nl: tickler: Tickler contexts: Contexten home: Start - toggle_notes_title: Toggle alle notities navigation: + manage_users_title: Toevoegen of verwijderen gebruikers recurring_todos: Terugkerende acties api_docs: REST API Docs - manage_users_title: Toevoegen of verwijderen gebruikers feeds: Feeds stats: Statistieken - notes_title: Toon alle notities starred: Ster - tickler_title: Tickler + notes_title: Toon alle notities manage_users: Beheren gebruikers - preferences: Voorkeuren + tickler_title: Tickler integrations_: Integreer Tracks export_title: Import en export van gegevens - calendar_title: Kalender met acties met deadline + preferences: Voorkeuren feeds_title: Zie een lijst met beschikbare feeds - completed_tasks: Gereed + calendar_title: Kalender met acties met deadline + recurring_todos_title: Beheren terugkerende acties tickler: Tickler + completed_tasks: Gereed stats_title: Zie je statistieken home_title: Start starred_title: Zie je ster acties - recurring_todos_title: Beheren terugkerende acties view: Bekijk organize: Organiseer completed_tasks_title: Afgerond - export: Export - contexts_title: Contexten home: Start + contexts_title: Contexten + export: Export projects_title: Projecten - preferences_title: Toon mijn voorkeuren search: Zoeken in alle items + preferences_title: Toon mijn voorkeuren review_title: Evaluatie uitvoeren calendar: Agenda - models: - project: - feed_title: Tracks Projecten - feed_description: Een overzicht van alle projecten voor %{username} - todo: - error_date_must_be_future: moet een datum in de toekomst zijn - preference: - due_on: Deadline op %{date} - due_in: Deadline over %{days} dagen - due_styles: - - Deadline over ____ dagen - - Deadline op ____ - user: - error_context_not_associated: Context %{context} niet geassocieerd met gebruikers %{user}. - error_project_not_associated: Project %{project} niet geassocieerd met gebruikers %{user}. - data: - import_successful: De import was succesvol - import_errors: Er hebben zich fouten voorgedaan bij de import + integrations: + opensearch_description: Zoek in Tracks + gmail_description: Gadget om Tracks toe te voegen aan Gmail als een gadget + applescript_next_action_prompt: "Omschrijving van de actie:" + applescript_success_after_id: gemaakt + applescript_success_before_id: Nieuwe actie met ID activerecord: attributes: project: @@ -156,37 +140,37 @@ nl: default_context_name: Standaard context description: Beschrijving todo: - predecessors: Afhankelijkheden show_from: Tonen vanaf + predecessors: Afhankelijkheden notes: Notities project: Project - context: Context description: Beschrijving + context: Context due: Deadline + user: + last_name: Achternaam + first_name: Voornaam preference: show_hidden_projects_in_sidebar: Toon verborgen projecten in sidebar date_format: Datum formaat show_hidden_contexts_in_sidebar: Toon verborgen contexten in sidebar - staleness_starts: Begin van markeren openstaande actie - sms_context: Standaard context voor email verbose_action_descriptors: Context en project uitschrijven in actielijst mobile_todos_per_page: Acties per pagina (mobiel) + staleness_starts: Begin van markeren openstaande actie + sms_context: Standaard context voor email show_number_completed: Aantal te tonen afgeronde acties title_date_format: Datum formaat in titel refresh: Ververs interval (in minuten) week_starts: Week start op last_name: Achternaam - due_style: Deadline stijl locale: Taal time_zone: Tijdzone - show_project_on_todo_done: Ga naar project pagina wanneer actie gereed is + due_style: Deadline stijl sms_email: Van email - review_period: Project evaluatie interval + show_project_on_todo_done: Ga naar project pagina wanneer actie gereed is show_completed_projects_in_sidebar: Toon afgeronde projecten in sidebar first_name: Voornaam - user: - last_name: Achternaam - first_name: Voornaam + review_period: Project evaluatie interval errors: models: project: @@ -198,31 +182,49 @@ nl: messages: record_invalid: "Validatie mislukt: %{errors}" greater_than_or_equal_to: moet groter of gelijk zijn aan %{count} - less_than_or_equal_to: moet kleiner of gelijk zijn aan %{count} confirmation: komt niet overeen met de configuratie + less_than_or_equal_to: moet kleiner of gelijk zijn aan %{count} blank: mag niet leeg zijn exclusion: is gereserveerd invalid: mag niet een komma (',') karakter bevatten odd: moet oneven zijn + even: moet even zijn + empty: mag niet leeg zijn too_short: is te kort (minimum is %{count} karakters) wrong_length: heeft de verkeerde lengte (moet %{count} karakters lang zijn) - empty: mag niet leeg zijn - even: moet even zijn less_than: moet kleiner zijn dan %{count} - equal_to: moet gelijk zijn aan %{count} greater_than: moet groter zijn dan %{count} + equal_to: moet gelijk zijn aan %{count} + accepted: moet geaccepteerd worden too_long: is te lang (maximum is %{count} karakters) taken: is al gepakt - accepted: moet geaccepteerd worden - not_a_number: is niet een getal inclusion: is niet opgenomen in de lijst - full_messages: - format: "%{attribute} %{message}" + not_a_number: is niet een getal template: body: Er waren problemen met de volgende velden header: one: 1 fout voorkomt het kunnen bewaren van deze %{model} other: "%{count} fouten voorkomen dat dit %{model} bewaard kan worden" + full_messages: + format: "%{attribute} %{message}" + data: + import_successful: De import was succesvol + import_errors: Er hebben zich fouten voorgedaan bij de import + models: + project: + feed_title: Tracks Projecten + feed_description: Een overzicht van alle projecten voor %{username} + todo: + error_date_must_be_future: moet een datum in de toekomst zijn + user: + error_context_not_associated: Context %{context} niet geassocieerd met gebruikers %{user}. + error_project_not_associated: Project %{project} niet geassocieerd met gebruikers %{user}. + preference: + due_on: Deadline op %{date} + due_in: Deadline over %{days} dagen + due_styles: + - Deadline over ____ dagen + - Deadline op ____ stats: tag_cloud_title: Tag Cloud voor alle acties totals_hidden_context_count: en %{count} zijn verborgen contexten. @@ -238,16 +240,17 @@ nl: time_of_day: Tijd van de dag totals_incomplete_actions: U heeft %{count} onvolledige acties totals_action_count: u heeft een totaal van %{count} acties - totals_deferred_actions: waarvan %{count} uitgestelde acties in de tickler zijn running_time_legend: actions: Acties percentage: Percentage weeks: Looptijd van een actie (weken). Klik op een balk voor meer info + totals_deferred_actions: waarvan %{count} uitgestelde acties in de tickler zijn tag_cloud_90days_title: Tag cloud met acties in afgelopen 90 dagen tod30: Tijd van de dag (laatste 30 dagen) tags: Tags projects: Projecten actions_avg_completion_time: Van al uw afgeronde acties, de gemiddelde tijd dat dit in beslag nam is %{count} dagen. + actions_day_of_week_title: Dag van de week (alle acties) labels: month_avg_completed: "%{months} gem afgerond per maand" completed: Afgerond @@ -255,9 +258,8 @@ nl: avg_created: Gem gemaakt avg_completed: Gem afgerond created: Gemaakt - actions_selected_from_week: Gekozen acties van week totals_completed_project_count: en %{count} zijn afgeronde projecten. - actions_day_of_week_title: Dag van de week (alle acties) + actions_selected_from_week: Gekozen acties van week actions_lastyear_title: Acties in de afgelopen 12 maanden open_per_week: Active (zichtbare en verborgen) volgende acties per week action_selection_title: "TRACKS:: Actie selectie" @@ -267,8 +269,8 @@ nl: actions: Acties number_of_actions: Aantal acties day_of_week: Dag van de week - percentage: Percentage running_time: Looptijd van een actie (weken) + percentage: Percentage months_ago: Maanden geleden current_running_time_of_incomplete_visible_actions: Huidige looptijd van onvolledige zichtbare acties tod30_legend: @@ -283,13 +285,13 @@ nl: months_ago: Maanden geleden top10_projects: Top 10 projecten top5_contexts: Top 5 contexten - totals_visible_context_count: Van deze zijn %{count} zichtbare contexten totals: Totalen contexts: Contexten click_to_return: Klik %{link} om terug te keren naar de statistieken pagina. tag_cloud_90days_description: Deze tag cloud bevat tags van acties die zijn gemaakt of voltooid in de afgelopen 90 dagen. - top10_projects_30days: Top 10 project in de laatste 30 dagen + totals_visible_context_count: Van deze zijn %{count} zichtbare contexten running_time_all: Huidige looptijd van alle onvolledige acties + top10_projects_30days: Top 10 project in de laatste 30 dagen actions_min_completion_time: De minimale tijd tot afronding is %{time}. action_completion_time_title: Doorlooptijd (alle voltooide acties) click_to_show_actions_from_week: Klik %{link} om de acties van week %{week} en verder te zien. @@ -307,10 +309,10 @@ nl: spread_of_actions_for_all_context: Verdeling van acties voor alle contexten more_stats_will_appear: Meer statistieken zullen hier verschijnen zodra u acties hebt toegevoegd. actions_avg_completed_30days: en voltooide een gemiddelde van %{count} acties per dag. + actions_dow_30days_title: Dag van de week (laatste 30 dagen) actions_30days_title: Acties in de afgelopen 30 dagen no_tags_available: geen tags beschikbaar index_title: TRACKS::Statistiek - actions_dow_30days_title: Dag van de week (laatste 30 dagen) actions_day_of_week_legend: number_of_actions: Aantal acties day_of_week: Dag van de week @@ -321,41 +323,41 @@ nl: totals_active_project_count: Van deze zijn %{count} actieve projecten running_time_all_legend: actions: Acties - percentage: Percentage running_time: Looptijd van een actie (weken). Klik op een balk voor meer info + percentage: Percentage other_actions_label: (anderen) totals_hidden_project_count: "%{count} zijn verborgen" time_of_day: Tijd van de dag (alle acties) todos: - completed_actions: Voltooide acties show_from: Toon vanaf error_starring_recurring: Kon niet de ster van deze terugkerende actie niet omzetten \'%{description}\' recurring_action_deleted: Actie werd verwijderd. Omdat deze actie herhalend is. werd een nieuwe actie toegevoegd + completed_actions: Voltooide acties completed_rest_of_previous_month: Afgerond in de rest van de vorige maand completed_recurring: Afgesloten terugkerende todos added_new_next_action: Nieuwe actie toegevoegd blocked_by: Geblokkeerd door %{predecessors} - done: Voltooid? - star_action: Markeer deze actie met een ster completed_recurrence_completed: Er is geen actie na de terugkerende actie die u new verwijderd heeft. De herhaling is voltooid + star_action: Markeer deze actie met een ster defer_date_after_due_date: Uitsteldatum is na de vervaldag. Gelieve vervaldag bewerken alvorens uitsteldatum aan te passen. unable_to_add_dependency: Niet in staat om de afhankelijkheid toe te voegen + done: Voltooid? star_action_with_description: markeer de actie '%{description}' met een ster tagged_with: gelabeld met ‘%{tag_name}’ completed: Afgerond no_deferred_actions_with: Geen uitgestelde acties met de tag '%{tag_name}' - no_hidden_actions: Momenteel zijn er geen verborgen acties gevonden edit_action_with_description: Bewerk de actie '%{description}' + no_hidden_actions: Momenteel zijn er geen verborgen acties gevonden action_due_on: (deadline actie op %{date}) - action_deleted_success: Actie succesvol verwijderd archived_tasks_title: "TRACKS:: Gearchiveerde voltooide taken" remove_dependency: Verwijder afhankelijkheid (zal niet de actie zelf verwijderen) list_incomplete_next_actions: Toon onvoltooide acties tags: Tags (gescheiden door komma's) - mobile_todos_page_title: Alle acties + action_deleted_success: Actie succesvol verwijderd new_related_todo_created: Een nieuwe actie is toegevoegd, die behoort bij deze terugkerende todo context_changed: Context veranderd in '%{name}' add_another_dependency: Nog een afhankelijkheid toevoegen + mobile_todos_page_title: Alle acties delete_recurring_action_title: Verwijder de terugkerende actie removed_predecessor: "'%{successor}' is verwijderd als afhankelijkheid van '%{predecessor}'." recurring_actions_title: TRACKS::Terugkerende acties @@ -366,36 +368,36 @@ nl: edit_action: Actie bewerken added_new_context: Nieuwe context toegevoegd next_actions_description: "Filter:" + list_incomplete_next_actions_with_limit: Toont de laatste %{count} onvoltooide acties + set_to_pending: "'%{task}' als wachtend ingesteld" + added_new_project: Nieuw project toegevoegd next_actions_title_additions: completed: acties voltooid due_today: deadline vandaag due_within_a_week: deadline binnen een week - added_new_project: Nieuw project toegevoegd - list_incomplete_next_actions_with_limit: Toont de laatste %{count} onvoltooide acties - set_to_pending: "'%{task}' als wachtend ingesteld" older_completed_items: Oudere voltooide items error_deleting_item: Er is een fout opgetreden bij het verwijderen van het item '%{description}' edit_recurring_todo: Bewerk herhalende actie append_in_this_project: in dit project task_list_title: TRACKS::Toon acties no_actions_due_this_week: Geen acties met deadline in rest van deze week + no_deferred_pending_actions: Momenteel zijn er geen uitgestelde of wachtende acties no_recurring_todos: Momenteel zijn er geen terugkerende acties error_completing_todo: Er was een fout bij het voltooien / activeren van de terugkerende actie '%{description}' recurring_pattern_removed: Het herhalingspatroon is verwijderd van %{count} convert_to_project: Maak project - no_deferred_pending_actions: Momenteel zijn er geen uitgestelde of wachtende acties delete_recurring_action_confirm: Weet u zeker dat u wilt de terugkerende actie '%{description}' wilt verwijderen? completed_last_day: Voltooid in de laatste 24 uur - all_completed: Alle afgeronde acties - error_saving_recurring: Er is een fout opgetreden het opslaan van de terugkerende actie '%{description}' show_in_days: Toon over %{days} dagen no_project: -- Geen project -- + error_saving_recurring: Er is een fout opgetreden het opslaan van de terugkerende actie '%{description}' completed_more_than_x_days_ago: Voltooid meer dan %{count} dagen geleden - feed_title_in_context: in context '%{context}' new_related_todo_created_short: een nieuwe actie gemaakt - completed_tagged_page_title: "TRACKS:: Afgeronde acties met tag %{tag_name}" - older_than_days: Ouder dan %{count} dagen + feed_title_in_context: in context '%{context}' + all_completed: Alle afgeronde acties edit: Bewerken + older_than_days: Ouder dan %{count} dagen + completed_tagged_page_title: "TRACKS:: Afgeronde acties met tag %{tag_name}" pending: Wachtend completed_actions_with: Afgeronde acties met de tag %{tag_name} feed_title_in_project: In het project '%{project}' @@ -404,56 +406,56 @@ nl: clear_due_date: Maak deadline leeg error_removing_dependency: Er is een fout opgetreden het verwijderen van de afhankelijke actie hidden_actions: Verborgen acties + deferred_actions_with: Uitgestelde acties met de tag '%{tag_name}' was_due_on_date: had deadline op %{date} show_on_date: Toon op %{date} recurrence_period: Herhaling periode - deferred_actions_with: Uitgestelde acties met de tag '%{tag_name}' confirm_delete: Weet u zeker dat u de actie '%{description}' wilt verwijderen? recurring_deleted_success: De recurrente actie is succesvol verwijderd. - deferred_tasks_title: TRACKS::Tickler next_actions_title: Tracks - Acties next_action_description: Actie beschrijving + deferred_tasks_title: TRACKS::Tickler no_completed_actions_with: Geen voltooide acties met de tag '%{tag_name}' clear_show_from_date: Maak de datum Tonen Vanaf leeg calendar_page_title: TRACKS::Agenda - unresolved_dependency: De waarde die u ingevoerd heeft in het afhankelijkheden veld is niet herleidbaar naar een bestaande actie. Deze waarde wordt niet bewaard met de rest van de actie. Doorgaan? in_hidden_state: in verborgen toestand - show_today: Toon vandaag - no_actions_found_title: Geen acties gevonden + unresolved_dependency: De waarde die u ingevoerd heeft in het afhankelijkheden veld is niet herleidbaar naar een bestaande actie. Deze waarde wordt niet bewaard met de rest van de actie. Doorgaan? next_actions_due_date: overdue_by: Over deadline met %{days} dag - due_today: Deadline vandaag due_in_x_days: Deadline over %{days} dagen + due_today: Deadline vandaag overdue_by_plural: Over deadline met %{days} dagen due_tomorrow: Deadline morgen + show_today: Toon vandaag + no_actions_found_title: Geen acties gevonden completed_last_x_days: Voltooid in de laatste %{count} dagen - no_actions_with: Momenteel zijn er geen onvoltooide acties met de tag '%{tag_name}' defer_x_days: one: Een dag uitstellen other: "%{count} dagen uitstellen" + no_actions_with: Momenteel zijn er geen onvoltooide acties met de tag '%{tag_name}' added_new_next_action_singular: Nieuwe actie toegevoegd no_completed_actions: Momenteel zijn er geen voltooide acties. + feeds: + completed: "Voltooid: %{date}" + due: "Deadline: %{date}" deferred_pending_actions: Uitgestelde/wachtende acties has_x_pending: one: Heeft een wachtende actie other: Heeft %{count} wachtende acties - feeds: - completed: "Voltooid: %{date}" - due: "Deadline: %{date}" - recurring_todos: Terugkerende acties delete_action: Verwijder actie error_deleting_recurring: Er is een fout opgetreden bij het verwijderen van het item \'%{description}\' + recurring_todos: Terugkerende acties delete: Verwijder - cannot_add_dependency_to_completed_todo: Kan deze actie niet als een afhankelijkheid van een voltooide actie toevoegen! drag_action_title: Sleep naar een andere actie om deze afhankelijk te maken van die actie + cannot_add_dependency_to_completed_todo: Kan deze actie niet als een afhankelijkheid van een voltooide actie toevoegen! no_last_completed_actions: Geen afgeronde acties gevonden tickler_items_due: one: Een tickler item wordt nu zichtbaar - vernieuw de pagina om het te zien. other: "%{count} tickerl items zijn nu zichtbaar - vernieuw de pagina om ze te zien." depends_on: Hangt af van action_marked_complete: De actie '%{description}' werd gemarkeerd als %{completed} - completed_today: Vandaag afgerond added_new_next_action_plural: Nieuwe acties toegevoegd + completed_today: Vandaag afgerond new_related_todo_not_created_short: een nieuwe actie is niet gemaakt completed_rest_of_week: Afgerond in de rest van deze week error_starring: Kon niet de ster van deze actie niet omzetten \'%{description}\' @@ -463,13 +465,12 @@ nl: due_next_week: Deadline volgende week no_actions_due_next_week: Geen acties met deadline in volgende week due_this_week: Deadline in rest van deze week - due_today: Deadline vandaag no_actions_due_today: Geen acties met deadline vandaag + due_today: Deadline vandaag due_next_month_and_later: Deadline in %{month} en later no_actions_due_after_this_month: Geen acties met deadline na deze maand - due_this_month: Deadline in rest van %{month} no_actions_due_this_month: Geen acties met deadline in de rest van deze maand - added_dependency: "%{dependency} als afhankelijkheid toegevoegd." + due_this_month: Deadline in rest van %{month} action_deferred: De actie '%{description}' is uitgesteld recurrence: ends_on_number_times: Eindigt na %{number} keer @@ -477,14 +478,15 @@ nl: every_work_day: Elke werkdag recurrence_on_due_date: de datum dat deadline van de actie is weekly_options: Instellingen voor de wekelijkse terugkerende acties - monthly_options: Instellingen voor maandelijks terugkerende acties weekly: Wekelijks + monthly_options: Instellingen voor maandelijks terugkerende acties monthly: Maandelijks starts_on: Begint op daily_options: Instellingen voor dagelijks terugkerende acties - daily: Dagelijks show_option_always: altijd + daily: Dagelijks pattern: + third: derde month_names: - - januari @@ -499,21 +501,20 @@ nl: - oktober - november - december - third: derde every_n: elke %{n} + second: tweede every_xth_day_of_every_n_months: elke %{x} %{day} van elke %{n_months} on_day_n: op dag %{n} - second: tweede from: vanaf weekly: wekelijks - last: laatste every_day: elke dag + last: laatste the_xth_day_of_month: de %{x} %{day} van %{month} times: voor %{number} keer - on_work_days: op werkdagen - show: Tonen every_year_on: elk jaar op %{date} + on_work_days: op werkdagen first: eerste + show: Tonen day_names: - zondag - maandag @@ -526,48 +527,49 @@ nl: due: Deadline until: tot every_month: elke maand - yearly_every_x_day: Elke %{month} %{day} recurrence_on_options: Stel herhaling in op + yearly_every_x_day: Elke %{month} %{day} daily_every_number_day: Elke %{number} dag(en) - weekly_every_number_week: Herhaalt elke %{number} weken op ends_on: Eindigt op show_options: Toon de actie - yearly_options: Instellingen voor jaarlijks terugkerende acties - show_days_before: "%{days} dagen v\xC3\xB3\xC3\xB3r de deadline van actie" + weekly_every_number_week: Herhaalt elke %{number} weken op + yearly_every_xth_day: De %{day} %{day_of_week} van %{month} from_tickler: de datum dat de actie uit de tickler komt (geen deadline ingesteld) no_end_date: Geen einddatum day_x_on_every_x_month: Dag %{day} op elke %{month} maand - yearly_every_xth_day: De %{day} %{day_of_week} van %{month} - yearly: Jaarlijks + yearly_options: Instellingen voor jaarlijks terugkerende acties + show_days_before: "%{days} dagen v\xC3\xB3\xC3\xB3r de deadline van actie" monthly_every_xth_day: De %{day} %{day_of_week} van elke %{month} maand + yearly: Jaarlijks tagged_page_title: TRACKS::Tagged met '%{tag_name}' no_completed_recurring: Momenteel zijn er geen voltooide terugkerende acties - completed_rest_of_month: Afgerond in de rest van deze maand - recurrence_completed: Er is geen volgende actie na de terugkerende actie die u zojuist hebt voltooid. De herhaling is voltooid + added_dependency: "%{dependency} als afhankelijkheid toegevoegd." all_completed_tagged_page_title: "TRACKS:: Alle afgeronde acties met tag %{tag_name}" no_deferred_actions: Momenteel zijn er geen uitgestelde acties. + completed_rest_of_month: Afgerond in de rest van deze maand + recurrence_completed: Er is geen volgende actie na de terugkerende actie die u zojuist hebt voltooid. De herhaling is voltooid no_actions_found: Momenteel zijn er geen onafgeronde acties. in_pending_state: in wachtende toestand error_toggle_complete: Kon deze actie niet als afgerond markeren due: Deadline action_marked_complete_error: De actie '%{description}' is niet gemarkeerd als %{completed} vanwege een fout op de server. + to_tickler: naar tickler + add_new_recurring: Voeg een nieuwe terugkerende actie toe depends_on_separate_with_commas: Afhankelijk van (gescheiden door komma's) - action_saved_to_tickler: Actie opgeslagen in tickler recurring_action_saved: Terugkerende actie opgeslagen + action_saved_to_tickler: Actie opgeslagen in tickler completed_in_archive: one: Er is een voltooide actie in het archief. other: Er zijn %{count} afgeronde acties in het archief. - to_tickler: naar tickler next_actions_description_additions: completed: in de afgelopen %{count} dagen due_date: met een deadline %{due_date} of eerder overdue: Achterstallig - add_new_recurring: Voeg een nieuwe terugkerende actie toe no_incomplete_actions: Er zijn geen onvoltooide acties notes: + delete_note_title: Verwijder de notitie '%{id}' delete_confirmation: Weet u zeker dat u de notitie '%{id}' wilt verwijderen? delete_item_title: Verwijder item - delete_note_title: Verwijder de notitie '%{id}' deleted_note: Verwijder notitie '%{id}' note_link_title: Toon notitie %{id} show_note_title: Toon notitie @@ -578,21 +580,105 @@ nl: delete_note_confirm: Weet u zeker dat u de notitie '%{id}' wilt verwijderen? states: hidden_plural: Verborgen + review_plural: Gedateerde stalled: Vastgelopen completed: Afgerond - review_plural: Gedateerde current: Bijgewerkt - review: Gedateerde completed_plural: Afgeronde + review: Gedateerde blocked_plural: Geblokkeerde blocked: Geblokkeerd stalled_plural: Vastgelopen visible_plural: Zichtbare - visible: Zichtbaar active_plural: Actieve - active: Actief - current_plural: Bijgewerkte + visible: Zichtbaar hidden: Verborgen + current_plural: Bijgewerkte + active: Actief + errors: + user_unauthorized: "401 Unauthorized: Alleen administratieve gebruikers mogen deze functie gebruiken." + projects: + edit_project_title: Bewerk project + default_tags_removed_notice: De standaard tags zijn verwijderd + default_context_set: Stel project standaard context in op %{default_context} + no_actions_in_project: Momenteel zijn er geen onafgeronde acties in dit project + deferred_actions: Uitgestelde acties voor dit project + was_marked_hidden: is gemarkeerd als verborgen + hide_form: Verberg formulier + all_completed_tasks_title: TRACKS::Toon alle afgeronde acties in het project '{project_name}' + page_title: "TRACKS:: Project: %{project}" + this_project: Dit project + list_completed_projects: TRACKS::Toon afgeronde projecten + to_new_project_page: Ga naar de nieuwe projectpagina + no_notes_attached: Momenteel zijn er geen notities toegevoegd aan dit project + show_form_title: Maak een nieuw project + deferred_actions_empty: Er zijn geen uitgestelde acties voor dit project + project_state: Project is %{state}. + no_last_completed_recurring_todos: Geen afgeronde herhalende acties gevonden + todos_append: in dit project + no_last_completed_projects: Geen afgeronde projecten gevonden + notes: Notities + notes_empty: Er zijn geen notities voor dit project + no_projects: Momenteel zijn er geen projecten + hide_form_title: Verberg nieuw project formulier + list_reviews: TRACKS::Evaluatie + completed_actions_empty: Er zijn nog geen afgeronde acties voor dit project + with_no_default_context: zonder standaard context + delete_project: Project verwijderen + show_form: Toevoegen van een project + actions_in_project_title: Acties in dit project + delete_project_confirmation: Weet u zeker dat u wilt het project '%{name} wilt verwijderen? + with_default_context: met een standaard context '%{context_name}' + is_active: is actief + completed_projects: Voltooide projecten + project_saved_status: Project opgeslagen + add_note: Een notitie toevoegen + add_project: Voeg project toe + settings: Instellingen + with_default_tags: en met '%{tags}' als de standaard tags + list_projects: "TRACKS:: Overzicht van projecten" + set_default_tags_notice: Stel project standaard tags in op %{default_tags} + completed_tasks_title: TRACKS::Toon afgeronde acties in het project '%{project_name}' + delete_project_title: Verwijder het project + hidden_projects: Verborgen projecten + default_context_removed: Standaard context verwijderd + add_note_submit: Notitie toevoegen + was_marked_complete: is gemarkeerd als voltooid + completed_actions: Afgeronde acties voor dit project + no_default_context: Dit project heeft geen standaard context + with_no_default_tags: en zonder standaard tags + edit_project_settings: Bewerk project instellingen + state: Dit project is %{state} + status_project_name_changed: Naam van het project werd gewijzigd + default_context: De standaard context voor dit project is %{context} + active_projects: Actieve projecten + preferences: + change_identity_url: Verander uw Identity URL + open_id_url: Uw OpenID URL is + staleness_starts_after: Markeren openstaande acties begint na %{days} dagen + change_password: Wijzig uw wachtwoord + page_title: "TRACKS:: Voorkeuren" + token_description: Token (voor feeds en API gebruik) + title: Uw voorkeuren + is_false: Nee + show_number_completed: Toon %{number} voltooide items + edit_preferences: Voorkeuren bewerken + page_title_edit: "TRACKS:: Voorkeuren bewerken" + is_true: Ja + password_changed: Je wachtwoord is gewijzigd, meld je opnieuw aan. + generate_new_token: Genereer een nieuwe token + sms_context_none: Geen + token_header: Uw token + authentication_header: Uw authenticatie + updated: Voorkeuren bijgewerkt + current_authentication_type: Uw authenticatietype is %{auth_type} + change_authentication_type: Verander uw authenticatietype + generate_new_token_confirm: Weet u dit zeker? Het genereren van een nieuw token zal de bestaande te vervangen en dit zal het extern gebruiken van de oude token laten mislukken. + tabs: + tracks_behavior: Tracks gedrag + authentication: Authenticatie + profile: Profiel + date_and_time: Datum en tijd time: am: ochtend formats: @@ -602,90 +688,6 @@ nl: month_day: "%d %B" long: "%A, %d. %B %Y, %H:%M" pm: middag - projects: - edit_project_title: Bewerk project - default_tags_removed_notice: De standaard tags zijn verwijderd - default_context_set: Stel project standaard context in op %{default_context} - no_actions_in_project: Momenteel zijn er geen onafgeronde acties in dit project - deferred_actions: Uitgestelde acties voor dit project - was_marked_hidden: is gemarkeerd als verborgen - page_title: "TRACKS:: Project: %{project}" - all_completed_tasks_title: TRACKS::Toon alle afgeronde acties in het project '{project_name}' - hide_form: Verberg formulier - no_notes_attached: Momenteel zijn er geen notities toegevoegd aan dit project - show_form_title: Maak een nieuw project - deferred_actions_empty: Er zijn geen uitgestelde acties voor dit project - this_project: Dit project - project_state: Project is %{state}. - list_completed_projects: TRACKS::Toon afgeronde projecten - to_new_project_page: Ga naar de nieuwe projectpagina - no_last_completed_projects: Geen afgeronde projecten gevonden - no_last_completed_recurring_todos: Geen afgeronde herhalende acties gevonden - notes: Notities - todos_append: in dit project - list_reviews: TRACKS::Evaluatie - notes_empty: Er zijn geen notities voor dit project - no_projects: Momenteel zijn er geen projecten - hide_form_title: Verberg nieuw project formulier - delete_project: Project verwijderen - completed_actions_empty: Er zijn nog geen afgeronde acties voor dit project - with_no_default_context: zonder standaard context - delete_project_confirmation: Weet u zeker dat u wilt het project '%{name} wilt verwijderen? - with_default_context: met een standaard context '%{context_name}' - show_form: Toevoegen van een project - actions_in_project_title: Acties in dit project - add_project: Voeg project toe - with_default_tags: en met '%{tags}' als de standaard tags - list_projects: "TRACKS:: Overzicht van projecten" - settings: Instellingen - is_active: is actief - project_saved_status: Project opgeslagen - set_default_tags_notice: Stel project standaard tags in op %{default_tags} - completed_projects: Voltooide projecten - add_note: Een notitie toevoegen - hidden_projects: Verborgen projecten - delete_project_title: Verwijder het project - completed_tasks_title: TRACKS::Toon afgeronde acties in het project '%{project_name}' - add_note_submit: Notitie toevoegen - completed_actions: Afgeronde acties voor dit project - was_marked_complete: is gemarkeerd als voltooid - default_context_removed: Standaard context verwijderd - status_project_name_changed: Naam van het project werd gewijzigd - active_projects: Actieve projecten - state: Dit project is %{state} - no_default_context: Dit project heeft geen standaard context - default_context: De standaard context voor dit project is %{context} - with_no_default_tags: en zonder standaard tags - edit_project_settings: Bewerk project instellingen - preferences: - staleness_starts_after: Markeren openstaande acties begint na %{days} dagen - open_id_url: Uw OpenID URL is - change_identity_url: Verander uw Identity URL - page_title: "TRACKS:: Voorkeuren" - change_password: Wijzig uw wachtwoord - title: Uw voorkeuren - token_description: Token (voor feeds en API gebruik) - show_number_completed: Toon %{number} voltooide items - is_false: Nee - is_true: Ja - password_changed: Je wachtwoord is gewijzigd, meld je opnieuw aan. - edit_preferences: Voorkeuren bewerken - page_title_edit: "TRACKS:: Voorkeuren bewerken" - generate_new_token: Genereer een nieuwe token - sms_context_none: Geen - token_header: Uw token - authentication_header: Uw authenticatie - current_authentication_type: Uw authenticatietype is %{auth_type} - change_authentication_type: Verander uw authenticatietype - updated: Voorkeuren bijgewerkt - generate_new_token_confirm: Weet u dit zeker? Het genereren van een nieuw token zal de bestaande te vervangen en dit zal het extern gebruiken van de oude token laten mislukken. - tabs: - authentication: Authenticatie - tracks_behavior: Tracks gedrag - profile: Profiel - date_and_time: Datum en tijd - errors: - user_unauthorized: "401 Unauthorized: Alleen administratieve gebruikers mogen deze functie gebruiken." date: month_names: - @@ -701,10 +703,6 @@ nl: - Oktober - November - December - order: - - :day - - :month - - :year abbr_day_names: - Zo - Ma @@ -713,6 +711,10 @@ nl: - Do - Vr - Za + order: + - :day + - :month + - :year formats: only_day: "%e" longer: "%A %d %B %Y" @@ -750,11 +752,11 @@ nl: one: Toon 1 %{model} other: Toon alle %{count} %{model} zero: Geen %{model} gevonden - multi_page_html: Toon %{model} %{from} - %{to} van %{count} in totaal single_page: one: Toon 1 %{model} other: Toon alle %{count} %{model} zero: Geen %{model} gevonden + multi_page_html: Toon %{model} %{from} - %{to} van %{count} in totaal page_gap: "…" next_label: "Volgende \xC2\xBB" support: @@ -764,13 +766,11 @@ nl: two_words_connector: en select: prompt: Selecteer - footer: - send_feedback: Stuur reactie op %{version} shared: multiple_next_actions: Meerdere acties (een op elke regel) - toggle_single: Voeg een actie toe - hide_form: Verberg formulier make_actions_dependent: Maak acties afhankelijk van elkaar + hide_form: Verberg formulier + toggle_single: Voeg een actie toe add_actions: Toevoegen acties add_action: Actie toevoegen tags_for_all_actions: Tags voor alle acties (scheiden met een komma) @@ -803,78 +803,76 @@ nl: - Donderdag - Vrijdag - Zaterdag + footer: + send_feedback: Stuur reactie op %{version} + feedlist: + actions_due_today: Acties die vandaag of eerder af moeten + choose_context: Kies de context waar je een feed van wilt + legend: Legenda + rss_feed: RSS Feed + ical_feed: iCal feed + all_contexts: Alle contexten + all_projects: Alle projecten + choose_project: Kies het project waar je een feed van wilt + project_needed: "Er moet ten minste \xC3\xA9\xC3\xA9n project zijn voor een feed opgevraagd kan worden" + select_feed_for_project: Kies de feed voor dit project + active_projects_wo_next: Actieve projecten zonder acties + active_starred_actions: Alle gesterde, actieve acties + select_feed_for_context: Kies de feed voor deze context + projects_and_actions: Actieve projecten met hun acties + context_needed: "Er moet eerst ten minste \xC3\xA9\xC3\xA9n context zijn voor je een feed kan opvragen" + actions_due_next_week: Acties die binnen 7 dagen afgerond moeten + notice_incomplete_only: "Merk op: alle feeds laten alleen acties zien die niet afgerond zijn, tenzij anders vermeld." + context_centric_actions: Feeds voor onafgeronde acties in een specifieke context + plain_text_feed: Reguliere tekst feed + last_fixed_number: Laatste %{number} acties + all_actions: Alle acties + actions_completed_last_week: Acties afgerond in de afgelopen 7 dagen + project_centric: Feeds voor onafgeronde acties in een specifiek project users: + first_user_heading: "Welkom bij TRACKS. Om te beginnen, maak dan een admin account:" + successfully_deleted_user: Succesvol gebruiker %{username} verwijderd + auth_type_update_error: "Er was een probleem met het bijwerken van uw authenticatietype: %{error_messages}" failed_to_delete_user: Mislukt de gebruiker %{username} te verwijderen destroy_successful: Gebruiker %{login} met succes verwijderd total_contexts: Totaal aantal contexten openid_url_verified: Je hebt %{url} met succes geverifieerd als je identiteit en uw authenticatie type OpenID opgeslagen. - first_user_heading: "Welkom bij TRACKS. Om te beginnen, maak dan een admin account:" - auth_type_update_error: "Er was een probleem met het bijwerken van uw authenticatietype: %{error_messages}" - successfully_deleted_user: Succesvol gebruiker %{username} verwijderd + signup_successful: Aanmelding succesvol voor gebruiker %{username}. new_token_generated: Nieuwe token met succes gegenereerd total_projects: Totaal aantal projecten - signup_successful: Aanmelding succesvol voor gebruiker %{username}. no_signups_title: "TRACKS:: Geen nieuwe aanmeldingen" user_created: Gebruiker aangemaakt. change_password_submit: Wachtwoord wijzigen + manage_users: Beheren gebruikers account_signup: Aanmelden voor een account password_updated: Wachtwoord bijgewerkt. - manage_users: Beheren gebruikers total_actions: Totaal aanal acties desired_login: Gewenste login - signup: Aanmelden confirm_password: Bevestig wachtwoord new_user_heading: "Registreer een nieuwe gebruiker:" + signup: Aanmelden auth_type_updated: Authenticatietype bijgewerkt. - change_password_prompt: Voer uw nieuwe wachtwoord in de onderstaande velden in en kies 'Wachtwoord wijzigen' om uw huidige wachtwoord met uw nieuwe te vervangen. - password_confirmation_label: Bevestig wachtwoord destroy_error: Er is een fout opgetreden bij het verwijderen van de gebruiker '%{login}' choose_password: Kies een wachtwoord change_password_title: TRACKS::Wachtwoord wijzigen change_auth_type_title: TRACKS::Wijzig authenticatietype + change_password_prompt: Voer uw nieuwe wachtwoord in de onderstaande velden in en kies 'Wachtwoord wijzigen' om uw huidige wachtwoord met uw nieuwe te vervangen. + password_confirmation_label: Bevestig wachtwoord + new_password_label: Nieuw wachtwoord register_with_cas: Met uw CAS gebruikersnaam label_auth_type: Authenticatietype - new_password_label: Nieuw wachtwoord + total_users_count: Je hebt een totaal van %{count} gebruikers new_user_title: "TRACKS:: Aanmelden als de admin gebruiker" destroy_user: Verwijder de gebruiker - total_users_count: Je hebt een totaal van %{count} gebruikers you_have_to_reset_your_password: Je moet je wachtwoord opnieuw instellen signup_new_user: Registreer nieuwe gebruiker destroy_confirmation: "Waarschuwing: dit zal de gebruiker '%{login} verwijderen met al zijn acties, contexten, projecten en notities. Weet u zeker dat u wilt doorgaan?" - change_authentication_type: Wijzigen authenticatietype - openid_ok_pref_failed: Je hebt succesvol de %{url} geverifieerd als je identiteit, maar er was een probleem met het opslaan van uw authenticatie voorkeuren. - auth_change_submit: Wijzigen authenticatietype identity_url: Identiteit URL + openid_ok_pref_failed: Je hebt succesvol de %{url} geverifieerd als je identiteit, maar er was een probleem met het opslaan van uw authenticatie voorkeuren. + change_authentication_type: Wijzigen authenticatietype + auth_change_submit: Wijzigen authenticatietype select_authentication_type: Selecteer uw nieuwe authenticatie type en klik op 'Wijzigen authenticatietype' om uw huidige instellingen te vervangen. total_notes: Totaal aantal notities - contexts: - delete_context_title: Verwijder context - all_completed_tasks_title: "TRACKS:: Alle voltooide acties in context '%{context_name}'" - hide_form: Verberg formulier - show_form_title: Voeg een context toe - delete_context: Verwijder context - todos_append: in deze context - delete_context_confirmation: Weet u zeker dat u de context '%{name}' wilt verwijderen? Merk op dat dit ook alle (herhalende) acties in deze context zal verwijderen! - edit_context: Bewerk context - hide_form_title: "Verberg formulier voor nieuwe context " - hidden_contexts: Verborgen contexten - no_contexts_active: Momenteel zijn er geen actieve contexten - context_hide: Verberg van de start pagina? - save_status_message: Context bewaard - add_context: Context toevoegen - show_form: Maak een nieuwe context - visible_contexts: Zichtbare contexten - update_status_message: Naam van de context was veranderd - context_name: Context naam - status_active: Context is actief - new_context_post: "' zal ook gemaakt worden. Weet u dit zeker?" - completed_tasks_title: "TRACKS:: Voltooid acties in de context '%{context_name}'" - last_completed_in_context: in deze context (laatste %{number}) - context_deleted: De context '%{name}' is verwijderd - no_contexts_hidden: Momenteel zijn er geen verborgen contexten - new_context_pre: Nieuwe context ' - no_actions: Momenteel zijn er geen onafgeronde acties in deze context - status_hidden: Context is verborgen sidebar: list_name_active_contexts: Actieve contexten list_name_active_projects: Actieve projecten @@ -882,35 +880,39 @@ nl: list_name_completed_projects: Voltooide projecten list_name_hidden_projects: Verborgen projecten list_name_hidden_contexts: Verborgen contexten - feedlist: - actions_due_today: Acties die vandaag of eerder af moeten - choose_context: Kies de context waar je een feed van wilt - legend: Legenda - all_contexts: Alle contexten - rss_feed: RSS Feed - ical_feed: iCal feed - all_projects: Alle projecten - choose_project: Kies het project waar je een feed van wilt - select_feed_for_project: Kies de feed voor dit project - active_projects_wo_next: Actieve projecten zonder acties - project_needed: "Er moet ten minste \xC3\xA9\xC3\xA9n project zijn voor een feed opgevraagd kan worden" - active_starred_actions: Alle gesterde, actieve acties - select_feed_for_context: Kies de feed voor deze context - projects_and_actions: Actieve projecten met hun acties - context_needed: "Er moet eerst ten minste \xC3\xA9\xC3\xA9n context zijn voor je een feed kan opvragen" - notice_incomplete_only: "Merk op: alle feeds laten alleen acties zien die niet afgerond zijn, tenzij anders vermeld." - actions_due_next_week: Acties die binnen 7 dagen afgerond moeten - all_actions: Alle acties - actions_completed_last_week: Acties afgerond in de afgelopen 7 dagen - context_centric_actions: Feeds voor onafgeronde acties in een specifieke context - plain_text_feed: Reguliere tekst feed - last_fixed_number: Laatste %{number} acties - project_centric: Feeds voor onafgeronde acties in een specifiek project + contexts: + delete_context_title: Verwijder context + hide_form: Verberg formulier + all_completed_tasks_title: "TRACKS:: Alle voltooide acties in context '%{context_name}'" + show_form_title: Voeg een context toe + delete_context_confirmation: Weet u zeker dat u de context '%{name}' wilt verwijderen? Merk op dat dit ook alle (herhalende) acties in deze context zal verwijderen! + delete_context: Verwijder context + todos_append: in deze context + edit_context: Bewerk context + hide_form_title: "Verberg formulier voor nieuwe context " + no_contexts_active: Momenteel zijn er geen actieve contexten + context_hide: Verberg van de start pagina? + hidden_contexts: Verborgen contexten + visible_contexts: Zichtbare contexten + save_status_message: Context bewaard + show_form: Maak een nieuwe context + add_context: Context toevoegen + context_name: Context naam + update_status_message: Naam van de context was veranderd + completed_tasks_title: "TRACKS:: Voltooid acties in de context '%{context_name}'" + status_active: Context is actief + new_context_post: "' zal ook gemaakt worden. Weet u dit zeker?" + context_deleted: De context '%{name}' is verwijderd + no_contexts_hidden: Momenteel zijn er geen verborgen contexten + new_context_pre: Nieuwe context ' + no_actions: Momenteel zijn er geen onafgeronde acties in deze context + last_completed_in_context: in deze context (laatste %{number}) + status_hidden: Context is verborgen login: - sign_in: Meld aan openid_identity_url_not_found: Sorry, geen gebruiker met die identiteit URL bestaat (%{identity_url}) user_no_expiry: Blijf ingelogd login_cas: Ga naar het CAS + sign_in: Meld aan cas_no_user_found: Hallo,%{username}! Je hebt nog geen account op Tracks. cas_login: CAS Inloggen successful_with_session_info: "Login succesvol:" @@ -921,11 +923,11 @@ nl: mobile_use_openid: ... if inloggen met een OpenID cas_signup_link: Aanvragen account account_login: Account login - session_will_not_expire: sessie zal niet verlopen. successful: Succesvol aangemeld. Welkom terug! + session_will_not_expire: sessie zal niet verlopen. + session_will_expire: sessie zal verlopen na %{hours} u(u)r(en) van inactiviteit. option_separator: of, session_time_out: Sessie is verlopen. Gelieve %{link} - session_will_expire: sessie zal verlopen na %{hours} u(u)r(en) van inactiviteit. login_standard: Ga terug naar de standaard login log_in_again: opnieuw in te loggen. logged_out: Je bent afgemeld bij Tracks. @@ -934,8 +936,8 @@ nl: datetime: prompts: minute: Minuut - month: Maand second: Seconden + month: Maand hour: Uur day: Dag year: Jaar @@ -953,6 +955,9 @@ nl: x_seconds: one: 1 seconde other: "%{count} seconden" + about_x_hours: + one: ongeveer 1 uur + other: ongeveer %{count} uren less_than_x_seconds: one: minder dan 1 seconde other: minder dan %{count} seconden @@ -963,15 +968,12 @@ nl: x_minutes: one: 1 minuut other: "%{count} minuten" - about_x_hours: - one: ongeveer 1 uur - other: ongeveer %{count} uren - about_x_months: - one: ongeveer 1 maand - other: ongeveer %{count} maanden about_x_years: one: ongeveer 1 jaar other: ongeveer %{count} jaren + about_x_months: + one: ongeveer 1 maand + other: ongeveer %{count} maanden over_x_years: one: over 1 jaar other: over %{count} jaren @@ -979,7 +981,7 @@ nl: search: contexts_matching_query: Contexten passend bij zoekopdracht tags_matching_query: Tags passend bij zoekopdracht + no_results: Uw zoekopdracht heeft geen resultaten opgeleverd. todos_matching_query: Todos passend bij zoekopdracht projects_matching_query: Projecten passend bij zoekopdracht notes_matching_query: Notities passend bij zoekopdracht - no_results: Uw zoekopdracht heeft geen resultaten opgeleverd. From 8093fce7d3fe553d3ee4f56d289b65359c483035 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Tue, 10 Apr 2012 20:37:45 +0200 Subject: [PATCH 078/134] update links in README and CHANGELOG --- README | 10 ++++------ doc/CHANGELOG | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/README b/README index 3def6b36..a701b3de 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ # Tracks: a GTD(TM) web application, built with Ruby on Rails * Project homepage: http://getontracks.org/ -* Manual: http://TracksApp.github.com/tracks/ +* Manual: http://getontracks.org/manual/ * Source at GitHub: http://github.com/TracksApp/tracks/ * Assembla space (for bug reports and feature requests): http://www.assembla.com/spaces/tracks-tickets/tickets * Wiki (community contributed information): https://github.com/TracksApp/tracks/wiki @@ -13,10 +13,9 @@ * Copyright: (cc) 2004-2012 rousette.org.uk. * License: GNU GPL -All the documentation for Tracks can be found within the /doc directory and at -http://tracksapp.github.com/tracks/ +More documentation for Tracks can be found within the /doc directory. -The latter includes full instructions for both new installations and upgrades +The manual includes full instructions for both new installations and upgrades from older installations of Tracks. The instructions might appear long and intimidatingly complex, but that is @@ -38,5 +37,4 @@ While fully usable for everyday use, Tracks is still a work in progress. Make sure that you take sensible precautions and back up all your data frequently, taking particular care when you are upgrading. -Enjoy being productive! - +Enjoy being productive! \ No newline at end of file diff --git a/doc/CHANGELOG b/doc/CHANGELOG index cca33e2c..7095f83c 100644 --- a/doc/CHANGELOG +++ b/doc/CHANGELOG @@ -1,7 +1,7 @@ = Tracks: a GTD(TM) web application, built with Ruby on Rails * Project homepage: http://getontracks.org/ -* Manual: http://TracksApp.github.com/tracks/ +* Manual: http://getontracks.org/manual/ * Source at GitHub: http://github.com/TracksApp/tracks/ * Assembla space (for bug reports and feature requests): http://www.assembla.com/spaces/tracks-tickets/tickets * Wiki (community contributed information): https://github.com/TracksApp/tracks/wiki @@ -9,7 +9,7 @@ * Mailing list: http://lists.rousette.org.uk/mailman/listinfo/tracks-discuss * Original developer: bsag (http://www.rousette.org.uk/) * Contributors: https://github.com/TracksApp/tracks/wiki/Contributors -* Version: 2.1RC1 +* Version: 2.2devel * Copyright: (cc) 2004-2012 rousette.org.uk. * License: GNU GPL From b2e34d469494c0a779ac6623d80cc7170cb4e9c8 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Sun, 8 Apr 2012 16:17:34 +0200 Subject: [PATCH 079/134] remove has_many_polymorphs --- Gemfile | 1 - Gemfile.lock | 7 - lib/tagging_extensions.rb | 200 -- .../has_many_polymorphs-2.13/.specification | 288 -- .../gems/has_many_polymorphs-2.13/CHANGELOG | 84 - vendor/gems/has_many_polymorphs-2.13/LICENSE | 184 -- vendor/gems/has_many_polymorphs-2.13/Manifest | 173 -- vendor/gems/has_many_polymorphs-2.13/README | 205 -- vendor/gems/has_many_polymorphs-2.13/Rakefile | 28 - vendor/gems/has_many_polymorphs-2.13/TODO | 2 - .../has_many_polymorphs-2.13/examples/hmph.rb | 69 - .../generators/tagging/tagging_generator.rb | 97 - .../generators/tagging/templates/migration.rb | 28 - .../generators/tagging/templates/tag.rb | 39 - .../generators/tagging/templates/tag_test.rb | 15 - .../generators/tagging/templates/tagging.rb | 16 - .../tagging/templates/tagging_extensions.rb | 203 -- .../tagging/templates/tagging_test.rb | 85 - .../generators/tagging/templates/taggings.yml | 23 - .../generators/tagging/templates/tags.yml | 7 - .../has_many_polymorphs.gemspec | 40 - vendor/gems/has_many_polymorphs-2.13/init.rb | 2 - .../lib/has_many_polymorphs.rb | 27 - .../lib/has_many_polymorphs/association.rb | 159 -- .../lib/has_many_polymorphs/autoload.rb | 69 - .../lib/has_many_polymorphs/base.rb | 60 - .../lib/has_many_polymorphs/class_methods.rb | 600 ---- .../lib/has_many_polymorphs/configuration.rb | 19 - .../has_many_polymorphs/debugging_tools.rb | 103 - .../rake_task_redefine_task.rb | 35 - .../lib/has_many_polymorphs/reflection.rb | 58 - .../has_many_polymorphs/support_methods.rb | 84 - .../test/fixtures/bow_wows.yml | 10 - .../test/fixtures/cats.yml | 18 - .../test/fixtures/eaters_foodstuffs.yml | 0 .../test/fixtures/fish.yml | 12 - .../test/fixtures/frogs.yml | 5 - .../test/fixtures/keep_your_enemies_close.yml | 0 .../test/fixtures/little_whale_pupils.yml | 0 .../test/fixtures/people.yml | 7 - .../test/fixtures/petfoods.yml | 11 - .../test/fixtures/whales.yml | 5 - .../test/fixtures/wild_boars.yml | 10 - .../test/generator/tagging_generator_test.rb | 42 - .../test/integration/app/README | 182 -- .../test/integration/app/Rakefile | 19 - .../app/app/controllers/application.rb | 7 - .../app/app/controllers/bones_controller.rb | 5 - .../app/app/helpers/addresses_helper.rb | 2 - .../app/app/helpers/application_helper.rb | 3 - .../app/app/helpers/bones_helper.rb | 2 - .../app/app/helpers/sellers_helper.rb | 28 - .../app/app/helpers/states_helper.rb | 2 - .../app/app/helpers/users_helper.rb | 2 - .../test/integration/app/app/models/bone.rb | 2 - .../app/app/models/double_sti_parent.rb | 2 - .../models/double_sti_parent_relationship.rb | 2 - .../app/app/models/organic_substance.rb | 2 - .../app/app/models/single_sti_parent.rb | 4 - .../models/single_sti_parent_relationship.rb | 4 - .../test/integration/app/app/models/stick.rb | 2 - .../test/integration/app/app/models/stone.rb | 2 - .../app/app/views/addresses/edit.html.erb | 12 - .../app/app/views/addresses/index.html.erb | 18 - .../app/app/views/addresses/new.html.erb | 11 - .../app/app/views/addresses/show.html.erb | 3 - .../app/app/views/bones/index.rhtml | 5 - .../app/app/views/layouts/addresses.html.erb | 17 - .../app/app/views/layouts/sellers.html.erb | 17 - .../app/app/views/layouts/states.html.erb | 17 - .../app/app/views/layouts/users.html.erb | 17 - .../app/app/views/sellers/edit.html.erb | 12 - .../app/app/views/sellers/index.html.erb | 20 - .../app/app/views/sellers/new.html.erb | 11 - .../app/app/views/sellers/show.html.erb | 3 - .../app/app/views/states/edit.html.erb | 12 - .../app/app/views/states/index.html.erb | 19 - .../app/app/views/states/new.html.erb | 11 - .../app/app/views/states/show.html.erb | 3 - .../app/app/views/users/edit.html.erb | 12 - .../app/app/views/users/index.html.erb | 22 - .../app/app/views/users/new.html.erb | 11 - .../app/app/views/users/show.html.erb | 3 - .../test/integration/app/config/boot.rb | 110 - .../test/integration/app/config/database.yml | 17 - .../integration/app/config/environment.rb | 19 - .../app/config/environment.rb.canonical | 19 - .../app/config/environments/development.rb | 9 - .../app/config/environments/production.rb | 18 - .../app/config/environments/test.rb | 19 - .../integration/app/config/locomotive.yml | 6 - .../test/integration/app/config/routes.rb | 33 - .../app/config/ultrasphinx/default.base | 56 - .../ultrasphinx/development.conf.canonical | 155 - .../app/db/migrate/001_create_sticks.rb | 11 - .../app/db/migrate/002_create_stones.rb | 11 - .../migrate/003_create_organic_substances.rb | 11 - .../app/db/migrate/004_create_bones.rb | 8 - .../migrate/005_create_single_sti_parents.rb | 11 - .../migrate/006_create_double_sti_parents.rb | 11 - ..._create_single_sti_parent_relationships.rb | 13 - ..._create_double_sti_parent_relationships.rb | 14 - .../db/migrate/009_create_library_model.rb | 11 - .../test/integration/app/doc/README_FOR_APP | 2 - .../generators/commenting_generator_test.rb | 83 - .../test/integration/app/lib/library_model.rb | 2 - .../test/integration/app/public/404.html | 30 - .../test/integration/app/public/500.html | 30 - .../test/integration/app/public/dispatch.cgi | 10 - .../test/integration/app/public/dispatch.fcgi | 24 - .../test/integration/app/public/dispatch.rb | 10 - .../test/integration/app/public/favicon.ico | 0 .../integration/app/public/images/rails.png | Bin 1787 -> 0 bytes .../test/integration/app/public/index.html | 277 -- .../app/public/javascripts/application.js | 2 - .../app/public/javascripts/controls.js | 833 ------ .../app/public/javascripts/dragdrop.js | 942 ------ .../app/public/javascripts/effects.js | 1088 ------- .../app/public/javascripts/prototype.js | 2515 ----------------- .../test/integration/app/public/robots.txt | 1 - .../app/public/stylesheets/scaffold.css | 74 - .../test/integration/app/script/about | 3 - .../test/integration/app/script/breakpointer | 3 - .../test/integration/app/script/console | 3 - .../test/integration/app/script/destroy | 3 - .../test/integration/app/script/generate | 3 - .../app/script/performance/benchmarker | 3 - .../app/script/performance/profiler | 3 - .../test/integration/app/script/plugin | 3 - .../integration/app/script/process/inspector | 3 - .../integration/app/script/process/reaper | 3 - .../integration/app/script/process/spawner | 3 - .../test/integration/app/script/runner | 3 - .../test/integration/app/script/server | 3 - .../double_sti_parent_relationships.yml | 7 - .../app/test/fixtures/double_sti_parents.yml | 7 - .../app/test/fixtures/organic_substances.yml | 5 - .../single_sti_parent_relationships.yml | 7 - .../app/test/fixtures/single_sti_parents.yml | 7 - .../integration/app/test/fixtures/sticks.yml | 7 - .../integration/app/test/fixtures/stones.yml | 7 - .../functional/addresses_controller_test.rb | 57 - .../test/functional/bones_controller_test.rb | 8 - .../functional/sellers_controller_test.rb | 57 - .../test/functional/states_controller_test.rb | 57 - .../test/functional/users_controller_test.rb | 57 - .../test/integration/app/test/test_helper.rb | 8 - .../integration/app/test/unit/bone_test.rb | 8 - .../double_sti_parent_relationship_test.rb | 8 - .../app/test/unit/double_sti_parent_test.rb | 8 - .../app/test/unit/organic_substance_test.rb | 8 - .../single_sti_parent_relationship_test.rb | 8 - .../app/test/unit/single_sti_parent_test.rb | 8 - .../integration/app/test/unit/stick_test.rb | 8 - .../integration/app/test/unit/stone_test.rb | 8 - .../test/integration/server_test.rb | 43 - .../test/models/aquatic/fish.rb | 5 - .../test/models/aquatic/pupils_whale.rb | 7 - .../test/models/aquatic/whale.rb | 15 - .../models/beautiful_fight_relationship.rb | 26 - .../test/models/canine.rb | 9 - .../test/models/cat.rb | 5 - .../test/models/dog.rb | 18 - .../test/models/eaters_foodstuff.rb | 10 - .../test/models/frog.rb | 4 - .../test/models/kitten.rb | 3 - .../test/models/parentship.rb | 4 - .../test/models/person.rb | 9 - .../test/models/petfood.rb | 39 - .../test/models/tabby.rb | 2 - .../test/models/wild_boar.rb | 3 - .../test/modules/extension_module.rb | 9 - .../test/modules/other_extension_module.rb | 9 - .../test/patches/symlinked_plugins_1.2.6.diff | 46 - .../has_many_polymorphs-2.13/test/schema.rb | 87 - .../has_many_polymorphs-2.13/test/setup.rb | 14 - .../test/test_helper.rb | 51 - .../test/unit/has_many_polymorphs_test.rb | 714 ----- 178 files changed, 11669 deletions(-) delete mode 100644 lib/tagging_extensions.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/.specification delete mode 100644 vendor/gems/has_many_polymorphs-2.13/CHANGELOG delete mode 100644 vendor/gems/has_many_polymorphs-2.13/LICENSE delete mode 100644 vendor/gems/has_many_polymorphs-2.13/Manifest delete mode 100644 vendor/gems/has_many_polymorphs-2.13/README delete mode 100644 vendor/gems/has_many_polymorphs-2.13/Rakefile delete mode 100644 vendor/gems/has_many_polymorphs-2.13/TODO delete mode 100644 vendor/gems/has_many_polymorphs-2.13/examples/hmph.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/generators/tagging/tagging_generator.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/migration.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tag.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tag_test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging_extensions.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging_test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/taggings.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tags.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/has_many_polymorphs.gemspec delete mode 100644 vendor/gems/has_many_polymorphs-2.13/init.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/association.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/autoload.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/base.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/class_methods.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/configuration.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/debugging_tools.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/rake_task_redefine_task.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/reflection.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/support_methods.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/bow_wows.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/cats.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/eaters_foodstuffs.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/fish.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/frogs.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/keep_your_enemies_close.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/little_whale_pupils.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/people.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/petfoods.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/whales.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/fixtures/wild_boars.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/generator/tagging_generator_test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/README delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/Rakefile delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/controllers/application.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/controllers/bones_controller.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/addresses_helper.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/application_helper.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/bones_helper.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/sellers_helper.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/states_helper.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/users_helper.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/bone.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/double_sti_parent.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/double_sti_parent_relationship.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/organic_substance.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/single_sti_parent.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/single_sti_parent_relationship.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/stick.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/stone.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/edit.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/index.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/new.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/show.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/bones/index.rhtml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/addresses.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/sellers.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/states.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/users.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/edit.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/index.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/new.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/show.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/edit.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/index.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/new.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/show.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/edit.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/index.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/new.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/show.html.erb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/boot.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/database.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environment.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environment.rb.canonical delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/development.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/production.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/locomotive.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/routes.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/ultrasphinx/default.base delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/ultrasphinx/development.conf.canonical delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/001_create_sticks.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/002_create_stones.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/003_create_organic_substances.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/004_create_bones.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/005_create_single_sti_parents.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/006_create_double_sti_parents.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/009_create_library_model.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/doc/README_FOR_APP delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/generators/commenting_generator_test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/lib/library_model.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/404.html delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/500.html delete mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.cgi delete mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.fcgi delete mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/favicon.ico delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/images/rails.png delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/index.html delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/application.js delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/controls.js delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/dragdrop.js delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/effects.js delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/prototype.js delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/robots.txt delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/stylesheets/scaffold.css delete mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/about delete mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/breakpointer delete mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/console delete mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/destroy delete mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/generate delete mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/performance/benchmarker delete mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/performance/profiler delete mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/plugin delete mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/inspector delete mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/reaper delete mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/spawner delete mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/runner delete mode 100755 vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/server delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/double_sti_parent_relationships.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/double_sti_parents.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/organic_substances.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/single_sti_parent_relationships.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/single_sti_parents.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/sticks.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/stones.yml delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/addresses_controller_test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/bones_controller_test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/sellers_controller_test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/states_controller_test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/users_controller_test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/test_helper.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/bone_test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/double_sti_parent_relationship_test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/double_sti_parent_test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/organic_substance_test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/single_sti_parent_relationship_test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/single_sti_parent_test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/stick_test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/stone_test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/integration/server_test.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/fish.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/pupils_whale.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/whale.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/beautiful_fight_relationship.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/canine.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/cat.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/dog.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/eaters_foodstuff.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/frog.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/kitten.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/parentship.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/person.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/petfood.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/tabby.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/models/wild_boar.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/modules/extension_module.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/modules/other_extension_module.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/patches/symlinked_plugins_1.2.6.diff delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/schema.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/setup.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/test_helper.rb delete mode 100644 vendor/gems/has_many_polymorphs-2.13/test/unit/has_many_polymorphs_test.rb diff --git a/Gemfile b/Gemfile index 03b4cda4..87eca690 100644 --- a/Gemfile +++ b/Gemfile @@ -8,7 +8,6 @@ gem "RedCloth", "4.2.8" gem "sanitize", "~>1.2.1" gem "rack", "1.1.0" gem "will_paginate", "~> 2.3.15" -gem "has_many_polymorphs", "~> 2.13", :path => "vendor/gems/has_many_polymorphs-2.13" # vendorred to get rid of some deprecation warnings gem "acts_as_list", "~>0.1.4" gem "aasm", "~>2.2.0" gem "rubyjedi-actionwebservice", :require => "actionwebservice" diff --git a/Gemfile.lock b/Gemfile.lock index 0c888954..783cfdf0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,12 +3,6 @@ PATH specs: aruba (0.2.2) -PATH - remote: vendor/gems/has_many_polymorphs-2.13 - specs: - has_many_polymorphs (2.13) - activerecord - GEM remote: http://rubygems.org/ remote: http://gems.github.com/ @@ -147,7 +141,6 @@ DEPENDENCIES cucumber-rails (~> 0.3.2) database_cleaner (>= 0.5.0) flexmock - has_many_polymorphs (~> 2.13)! highline (~> 1.5.0) hoe hpricot diff --git a/lib/tagging_extensions.rb b/lib/tagging_extensions.rb deleted file mode 100644 index 2808f42a..00000000 --- a/lib/tagging_extensions.rb +++ /dev/null @@ -1,200 +0,0 @@ -class ActiveRecord::Base #:nodoc: - - # These extensions make models taggable. This file is automatically generated and required by your app if you run the tagging generator included with has_many_polymorphs. - module TaggingExtensions - - # Add tags to self. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags. - # - # We need to avoid name conflicts with the built-in ActiveRecord association methods, thus the underscores. - def _add_tags incoming - taggable?(true) - tag_cast_to_string(incoming).each do |tag_name| - # added following check to prevent empty tags from being saved (which will fail) - unless tag_name.blank? - begin - tag = Tag.find_or_create_by_name(tag_name) - raise Tag::Error, "tag could not be saved: #{tag_name}" if tag.new_record? - tags << tag - rescue ActiveRecord::StatementInvalid => e - raise unless e.to_s =~ /duplicate/i - end - end - end - end - - # Removes tags from self. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags. - def _remove_tags outgoing - taggable?(true) - outgoing = tag_cast_to_string(outgoing) - tags.delete(*(tags.select do |tag| - outgoing.include? tag.name - end)) - end - - # Returns the tags on self as a string. - def tag_list - # Redefined later to avoid an RDoc parse error. - end - - # Replace the existing tags on self. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags. - def tag_with list - #:stopdoc: - taggable?(true) - list = tag_cast_to_string(list) - - # Transactions may not be ideal for you here; be aware. - Tag.transaction do - current = tags.map(&:name) - _add_tags(list - current) - _remove_tags(current - list) - end - - self - #:startdoc: - end - - # Returns the tags on self as a string. - def tag_list #:nodoc: - #:stopdoc: - taggable?(true) - tags.reload - tags.to_s - #:startdoc: - end - - def tag_list=(value) - tag_with(value) - end - - private - - def tag_cast_to_string obj #:nodoc: - case obj - when Array - obj.map! do |item| - case item - # removed next line as it prevents using numbers as tags - # when /^\d+$/, Fixnum then Tag.find(item).name # This will be slow if you use ids a lot. - when Tag then item.name - when String then item - else - raise "Invalid type" - end - end - when String - obj = obj.split(Tag::DELIMITER).map do |tag_name| - tag_name.strip.squeeze(" ") - end - else - raise "Invalid object of class #{obj.class} as tagging method parameter" - end.flatten.compact.map(&:downcase).uniq - end - - # Check if a model is in the :taggables target list. The alternative to this check is to explicitly include a TaggingMethods module (which you would create) in each target model. - def taggable?(should_raise = false) #:nodoc: - unless flag = respond_to?(:tags) - raise "#{self.class} is not a taggable model" if should_raise - end - flag - end - - end - - module TaggingFinders - # Find all the objects tagged with the supplied list of tags - # - # Usage : Model.tagged_with("ruby") - # Model.tagged_with("hello", "world") - # Model.tagged_with("hello", "world", :limit => 10) - # - # XXX This query strategy is not performant, and needs to be rewritten as an inverted join or a series of unions - # - def tagged_with(*tag_list) - options = tag_list.last.is_a?(Hash) ? tag_list.pop : {} - tag_list = parse_tags(tag_list) - - scope = scope(:find) - options[:select] ||= "#{table_name}.*" - options[:from] ||= "#{table_name}, tags, taggings" - - sql = "SELECT #{(scope && scope[:select]) || options[:select]} " - sql << "FROM #{(scope && scope[:from]) || options[:from]} " - - add_joins!(sql, options[:joins], scope) - - sql << "WHERE #{table_name}.#{primary_key} = taggings.taggable_id " - sql << "AND taggings.taggable_type = '#{ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s}' " - sql << "AND taggings.tag_id = tags.id " - - tag_list_condition = tag_list.map {|name| "'#{name}'"}.join(", ") - - sql << "AND (tags.name IN (#{sanitize_sql(tag_list_condition)})) " - sql << "AND #{sanitize_sql(options[:conditions])} " if options[:conditions] - - columns = column_names.map do |column| - "#{table_name}.#{column}" - end.join(", ") - - sql << "GROUP BY #{columns} " - sql << "HAVING COUNT(taggings.tag_id) = #{tag_list.size}" - - add_order!(sql, options[:order], scope) - add_limit!(sql, options, scope) - add_lock!(sql, options, scope) - - find_by_sql(sql) - end - - def self.tagged_with_any(*tag_list) - options = tag_list.last.is_a?(Hash) ? tag_list.pop : {} - tag_list = parse_tags(tag_list) - - scope = scope(:find) - options[:select] ||= "#{table_name}.*" - options[:from] ||= "#{table_name}, meta_tags, taggings" - - sql = "SELECT #{(scope && scope[:select]) || options[:select]} " - sql << "FROM #{(scope && scope[:from]) || options[:from]} " - - add_joins!(sql, options, scope) - - sql << "WHERE #{table_name}.#{primary_key} = taggings.taggable_id " - sql << "AND taggings.taggable_type = '#{ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s}' " - sql << "AND taggings.meta_tag_id = meta_tags.id " - - sql << "AND (" - or_options = [] - tag_list.each do |name| - or_options << "meta_tags.name = '#{name}'" - end - or_options_joined = or_options.join(" OR ") - sql << "#{or_options_joined}) " - - - sql << "AND #{sanitize_sql(options[:conditions])} " if options[:conditions] - - columns = column_names.map do |column| - "#{table_name}.#{column}" - end.join(", ") - - sql << "GROUP BY #{columns} " - - add_order!(sql, options[:order], scope) - add_limit!(sql, options, scope) - add_lock!(sql, options, scope) - - find_by_sql(sql) - end - - def parse_tags(tags) - return [] if tags.blank? - tags = Array(tags).first - tags = tags.respond_to?(:flatten) ? tags.flatten : tags.split(Tag::DELIMITER) - tags.map { |tag| tag.strip.squeeze(" ") }.flatten.compact.map(&:downcase).uniq - end - - end - - include TaggingExtensions - extend TaggingFinders -end diff --git a/vendor/gems/has_many_polymorphs-2.13/.specification b/vendor/gems/has_many_polymorphs-2.13/.specification deleted file mode 100644 index 8cec7bbd..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/.specification +++ /dev/null @@ -1,288 +0,0 @@ ---- !ruby/object:Gem::Specification -name: has_many_polymorphs -version: !ruby/object:Gem::Version - hash: 25 - prerelease: - segments: - - 2 - - 13 - version: "2.13" -platform: ruby -authors: -- "" -autorequire: -bindir: bin -cert_chain: -- /Users/eweaver/p/configuration/gem_certificates/evan_weaver-original-public_cert.pem -date: 2009-02-02 00:00:00 Z -dependencies: -- !ruby/object:Gem::Dependency - type: :runtime - requirement: &id001 !ruby/object:Gem::Requirement - none: false - requirements: - - - ">=" - - !ruby/object:Gem::Version - hash: 3 - segments: - - 0 - version: "0" - prerelease: false - name: activerecord - version_requirements: *id001 -- !ruby/object:Gem::Dependency - type: :development - requirement: &id002 !ruby/object:Gem::Requirement - none: false - requirements: - - - ">=" - - !ruby/object:Gem::Version - hash: 3 - segments: - - 0 - version: "0" - prerelease: false - name: echoe - version_requirements: *id002 -description: An ActiveRecord plugin for self-referential and double-sided polymorphic associations. -email: "" -executables: [] - -extensions: [] - -extra_rdoc_files: -- CHANGELOG -- generators/tagging/templates/migration.rb -- generators/tagging/templates/tag.rb -- generators/tagging/templates/tagging.rb -- generators/tagging/templates/tagging_extensions.rb -- lib/has_many_polymorphs/association.rb -- lib/has_many_polymorphs/autoload.rb -- lib/has_many_polymorphs/class_methods.rb -- lib/has_many_polymorphs/configuration.rb -- lib/has_many_polymorphs/reflection.rb -- LICENSE -- README -- test/integration/app/doc/README_FOR_APP -- test/integration/app/README -- TODO -files: -- CHANGELOG -- examples/hmph.rb -- generators/tagging/tagging_generator.rb -- generators/tagging/templates/migration.rb -- generators/tagging/templates/tag.rb -- generators/tagging/templates/tag_test.rb -- generators/tagging/templates/tagging.rb -- generators/tagging/templates/tagging_extensions.rb -- generators/tagging/templates/tagging_test.rb -- generators/tagging/templates/taggings.yml -- generators/tagging/templates/tags.yml -- init.rb -- lib/has_many_polymorphs/association.rb -- lib/has_many_polymorphs/autoload.rb -- lib/has_many_polymorphs/base.rb -- lib/has_many_polymorphs/class_methods.rb -- lib/has_many_polymorphs/configuration.rb -- lib/has_many_polymorphs/debugging_tools.rb -- lib/has_many_polymorphs/rake_task_redefine_task.rb -- lib/has_many_polymorphs/reflection.rb -- lib/has_many_polymorphs/support_methods.rb -- lib/has_many_polymorphs.rb -- LICENSE -- Manifest -- Rakefile -- README -- test/fixtures/bow_wows.yml -- test/fixtures/cats.yml -- test/fixtures/eaters_foodstuffs.yml -- test/fixtures/fish.yml -- test/fixtures/frogs.yml -- test/fixtures/keep_your_enemies_close.yml -- test/fixtures/little_whale_pupils.yml -- test/fixtures/people.yml -- test/fixtures/petfoods.yml -- test/fixtures/whales.yml -- test/fixtures/wild_boars.yml -- test/generator/tagging_generator_test.rb -- test/integration/app/app/controllers/application.rb -- test/integration/app/app/controllers/bones_controller.rb -- test/integration/app/app/helpers/addresses_helper.rb -- test/integration/app/app/helpers/application_helper.rb -- test/integration/app/app/helpers/bones_helper.rb -- test/integration/app/app/helpers/sellers_helper.rb -- test/integration/app/app/helpers/states_helper.rb -- test/integration/app/app/helpers/users_helper.rb -- test/integration/app/app/models/bone.rb -- test/integration/app/app/models/double_sti_parent.rb -- test/integration/app/app/models/double_sti_parent_relationship.rb -- test/integration/app/app/models/organic_substance.rb -- test/integration/app/app/models/single_sti_parent.rb -- test/integration/app/app/models/single_sti_parent_relationship.rb -- test/integration/app/app/models/stick.rb -- test/integration/app/app/models/stone.rb -- test/integration/app/app/views/addresses/edit.html.erb -- test/integration/app/app/views/addresses/index.html.erb -- test/integration/app/app/views/addresses/new.html.erb -- test/integration/app/app/views/addresses/show.html.erb -- test/integration/app/app/views/bones/index.rhtml -- test/integration/app/app/views/layouts/addresses.html.erb -- test/integration/app/app/views/layouts/sellers.html.erb -- test/integration/app/app/views/layouts/states.html.erb -- test/integration/app/app/views/layouts/users.html.erb -- test/integration/app/app/views/sellers/edit.html.erb -- test/integration/app/app/views/sellers/index.html.erb -- test/integration/app/app/views/sellers/new.html.erb -- test/integration/app/app/views/sellers/show.html.erb -- test/integration/app/app/views/states/edit.html.erb -- test/integration/app/app/views/states/index.html.erb -- test/integration/app/app/views/states/new.html.erb -- test/integration/app/app/views/states/show.html.erb -- test/integration/app/app/views/users/edit.html.erb -- test/integration/app/app/views/users/index.html.erb -- test/integration/app/app/views/users/new.html.erb -- test/integration/app/app/views/users/show.html.erb -- test/integration/app/config/boot.rb -- test/integration/app/config/database.yml -- test/integration/app/config/environment.rb -- test/integration/app/config/environment.rb.canonical -- test/integration/app/config/environments/development.rb -- test/integration/app/config/environments/production.rb -- test/integration/app/config/environments/test.rb -- test/integration/app/config/locomotive.yml -- test/integration/app/config/routes.rb -- test/integration/app/config/ultrasphinx/default.base -- test/integration/app/config/ultrasphinx/development.conf.canonical -- test/integration/app/db/migrate/001_create_sticks.rb -- test/integration/app/db/migrate/002_create_stones.rb -- test/integration/app/db/migrate/003_create_organic_substances.rb -- test/integration/app/db/migrate/004_create_bones.rb -- test/integration/app/db/migrate/005_create_single_sti_parents.rb -- test/integration/app/db/migrate/006_create_double_sti_parents.rb -- test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb -- test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb -- test/integration/app/db/migrate/009_create_library_model.rb -- test/integration/app/doc/README_FOR_APP -- test/integration/app/generators/commenting_generator_test.rb -- test/integration/app/lib/library_model.rb -- test/integration/app/public/404.html -- test/integration/app/public/500.html -- test/integration/app/public/dispatch.cgi -- test/integration/app/public/dispatch.fcgi -- test/integration/app/public/dispatch.rb -- test/integration/app/public/favicon.ico -- test/integration/app/public/images/rails.png -- test/integration/app/public/index.html -- test/integration/app/public/javascripts/application.js -- test/integration/app/public/javascripts/controls.js -- test/integration/app/public/javascripts/dragdrop.js -- test/integration/app/public/javascripts/effects.js -- test/integration/app/public/javascripts/prototype.js -- test/integration/app/public/robots.txt -- test/integration/app/public/stylesheets/scaffold.css -- test/integration/app/Rakefile -- test/integration/app/README -- test/integration/app/script/about -- test/integration/app/script/breakpointer -- test/integration/app/script/console -- test/integration/app/script/destroy -- test/integration/app/script/generate -- test/integration/app/script/performance/benchmarker -- test/integration/app/script/performance/profiler -- test/integration/app/script/plugin -- test/integration/app/script/process/inspector -- test/integration/app/script/process/reaper -- test/integration/app/script/process/spawner -- test/integration/app/script/runner -- test/integration/app/script/server -- test/integration/app/test/fixtures/double_sti_parent_relationships.yml -- test/integration/app/test/fixtures/double_sti_parents.yml -- test/integration/app/test/fixtures/organic_substances.yml -- test/integration/app/test/fixtures/single_sti_parent_relationships.yml -- test/integration/app/test/fixtures/single_sti_parents.yml -- test/integration/app/test/fixtures/sticks.yml -- test/integration/app/test/fixtures/stones.yml -- test/integration/app/test/functional/addresses_controller_test.rb -- test/integration/app/test/functional/bones_controller_test.rb -- test/integration/app/test/functional/sellers_controller_test.rb -- test/integration/app/test/functional/states_controller_test.rb -- test/integration/app/test/functional/users_controller_test.rb -- test/integration/app/test/test_helper.rb -- test/integration/app/test/unit/bone_test.rb -- test/integration/app/test/unit/double_sti_parent_relationship_test.rb -- test/integration/app/test/unit/double_sti_parent_test.rb -- test/integration/app/test/unit/organic_substance_test.rb -- test/integration/app/test/unit/single_sti_parent_relationship_test.rb -- test/integration/app/test/unit/single_sti_parent_test.rb -- test/integration/app/test/unit/stick_test.rb -- test/integration/app/test/unit/stone_test.rb -- test/integration/server_test.rb -- test/models/aquatic/fish.rb -- test/models/aquatic/pupils_whale.rb -- test/models/aquatic/whale.rb -- test/models/beautiful_fight_relationship.rb -- test/models/canine.rb -- test/models/cat.rb -- test/models/dog.rb -- test/models/eaters_foodstuff.rb -- test/models/frog.rb -- test/models/kitten.rb -- test/models/parentship.rb -- test/models/person.rb -- test/models/petfood.rb -- test/models/tabby.rb -- test/models/wild_boar.rb -- test/modules/extension_module.rb -- test/modules/other_extension_module.rb -- test/patches/symlinked_plugins_1.2.6.diff -- test/schema.rb -- test/setup.rb -- test/test_helper.rb -- test/unit/has_many_polymorphs_test.rb -- TODO -- has_many_polymorphs.gemspec -homepage: http://blog.evanweaver.com/files/doc/fauna/has_many_polymorphs/ -licenses: [] - -post_install_message: -rdoc_options: -- --line-numbers -- --inline-source -- --title -- Has_many_polymorphs -- --main -- README -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - none: false - requirements: - - - ">=" - - !ruby/object:Gem::Version - hash: 3 - segments: - - 0 - version: "0" -required_rubygems_version: !ruby/object:Gem::Requirement - none: false - requirements: - - - ">=" - - !ruby/object:Gem::Version - hash: 11 - segments: - - 1 - - 2 - version: "1.2" -requirements: [] - -rubyforge_project: fauna -rubygems_version: 1.8.10 -signing_key: /Users/eweaver/p/configuration/gem_certificates/evan_weaver-original-private_key.pem -specification_version: 2 -summary: An ActiveRecord plugin for self-referential and double-sided polymorphic associations. -test_files: -- test/generator/tagging_generator_test.rb -- test/integration/server_test.rb -- test/unit/has_many_polymorphs_test.rb -has_rdoc: true - diff --git a/vendor/gems/has_many_polymorphs-2.13/CHANGELOG b/vendor/gems/has_many_polymorphs-2.13/CHANGELOG deleted file mode 100644 index ec8ef45f..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/CHANGELOG +++ /dev/null @@ -1,84 +0,0 @@ -v2.13. Merge various fixes for Rails 2.2.2. - -v2.12. Improvements to the test suite; bugfixes for STI children (rsl). Remove fancy dependency system in favor of using Dispatcher::to_prepare every time. - -v2.11. Rails 1.2.6 tagging generator compatibility; change test suite to use included integration app. - -v2.10. Add :parent_conditions option; bugfix for nullified conditions; bugfix for self-referential tagging generator; allow setting of has_many_polymorphs_options hash in Configuration's after_initialize if you need to adjust the autoload behavior; clear error message on missing or improperly namespaced models; fix .build on double-sided relationships; add :namespace key for easier set up of Camping apps or other unusual class structures. - -v2.9. Gem version renumbering; my apologies if this messes anyone up. - -v2.8. RDoc documentation; repository relocation; Rakefile cleanup; remove deprecated plugin-specific class caching. - -v2.7.5. Various bugfixes; Postgres problems may remain on edge. - -v2.7.3. Use new :source and :source_type options in 1.2.3 (David Lemstra); fix pluralization bug; add some tests; experimental tagging generator. - -v2.7.2. Deprecate has_many_polymorphs_cache_classes= option because it doesn't really work. Use config.cache_classes= instead to cache all reloadable items. - -v2.7.1. Dispatcher.to_prepare didn't fire in the console; now using a config.after_initialize wrapper instead. - -v2.7. Dependency injection framework elimates having to care about load order. - -v2.6. Make the logger act sane for the gem version. - -v2.5.2. Allow :skip_duplicates on double relationships. - -v2.5.1. Renamed :ignore_duplicates to :skip_duplicates to better express its non-passive behavior; made sure not to load target set on push unless necessary. - -v2.5. Activerecord compatibility branch becomes trunk: extra options now supported for double polymorphism; conditions nulled-out and propogated to child relationships; more tests; new :ignore_duplicates option on macro can be set to false if you want << to push duplicate associations. - -v2.4.1. Code split into multiple files; tests added for pluralization check; Rails 1.1.6 no longer supported. - -v2.4. Unlimited mixed class association extensions for both single and double targets and joins. - -v2.3. Gem version - -v2.2. API change; prefix on methods is now singular when using :rename_individual_collections. - -v2.1. Add configuration option to cache polymorphic classes in development mode. - -v2.0. Collection methods (push, delete, clear) now on individual collections. - -v1.9.2. Disjoint collection sides bugfix, don't raise on new records. - -v1.9.1. Double classify bugfix. - -v1.9. Large changes to properly support double polymorphism. - -v1.8.2. Bugfix to make sure the type gets checked on doubly polymorphic parents. - -v1.8.1. Bugfix for sqlite3 child attribute retrieval. - -v1.8. Bugfix for instantiating attributes of namespaced models. - -v1.7.1. Bugfix for double polymorphic relationships. - -v1.7. Double polymorphic relationships (includes new API method). - -v1.6. Namespaced model support. - -v1.5. Bugfix for Postgres and Mysql under 1.1.6; refactored tests (hildofur); properly handles legacy table names set with set_table_name(). - -v1.4. STI support added (use the child class names, not the base class). - -v1.3. Bug regarding table names with underscores in SQL query fixed. - -v1.2. License change, again. - -v1.1. File_column bug fixed. - -v1.0. Tests written; after_find and after_initialize now correctly called. - -v0.5. SQL performance enhancements added. - -v0.4. Rewrote singletons as full-fledged proxy class so that marshalling works (e.g. in the session). - -v0.3. Caching added. - -v0.2. Fixed dependency reloading problem in development mode. - -v0.1. License change. - -v0. Added :dependent support on the join table; no changelog before this version. - diff --git a/vendor/gems/has_many_polymorphs-2.13/LICENSE b/vendor/gems/has_many_polymorphs-2.13/LICENSE deleted file mode 100644 index 90eec26b..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/LICENSE +++ /dev/null @@ -1,184 +0,0 @@ -Academic Free License (AFL) v. 3.0 - -This Academic Free License (the "License") applies to any original work -of authorship (the "Original Work") whose owner (the "Licensor") has -placed the following licensing notice adjacent to the copyright notice -for the Original Work: - -Licensed under the Academic Free License version 3.0 - -1) Grant of Copyright License. Licensor grants You a worldwide, -royalty-free, non-exclusive, sublicensable license, for the duration of -the copyright, to do the following: - -a) to reproduce the Original Work in copies, either alone or as part of -a collective work; - -b) to translate, adapt, alter, transform, modify, or arrange the -Original Work, thereby creating derivative works ("Derivative Works") -based upon the Original Work; - -c) to distribute or communicate copies of the Original Work and -Derivative Works to the public, under any license of your choice that -does not contradict the terms and conditions, including Licensor's -reserved rights and remedies, in this Academic Free License; - -d) to perform the Original Work publicly; and - -e) to display the Original Work publicly. - -2) Grant of Patent License. Licensor grants You a worldwide, -royalty-free, non-exclusive, sublicensable license, under patent claims -owned or controlled by the Licensor that are embodied in the Original -Work as furnished by the Licensor, for the duration of the patents, to -make, use, sell, offer for sale, have made, and import the Original Work -and Derivative Works. - -3) Grant of Source Code License. The term "Source Code" means the -preferred form of the Original Work for making modifications to it and -all available documentation describing how to modify the Original Work. -Licensor agrees to provide a machine-readable copy of the Source Code of -the Original Work along with each copy of the Original Work that -Licensor distributes. Licensor reserves the right to satisfy this -obligation by placing a machine-readable copy of the Source Code in an -information repository reasonably calculated to permit inexpensive and -convenient access by You for as long as Licensor continues to distribute -the Original Work. - -4) Exclusions From License Grant. Neither the names of Licensor, nor the -names of any contributors to the Original Work, nor any of their -trademarks or service marks, may be used to endorse or promote products -derived from this Original Work without express prior permission of the -Licensor. Except as expressly stated herein, nothing in this License -grants any license to Licensor's trademarks, copyrights, patents, trade -secrets or any other intellectual property. No patent license is granted -to make, use, sell, offer for sale, have made, or import embodiments of -any patent claims other than the licensed claims defined in Section 2. -No license is granted to the trademarks of Licensor even if such marks -are included in the Original Work. Nothing in this License shall be -interpreted to prohibit Licensor from licensing under terms different -from this License any Original Work that Licensor otherwise would have a -right to license. - -5) External Deployment. The term "External Deployment" means the use, -distribution, or communication of the Original Work or Derivative Works -in any way such that the Original Work or Derivative Works may be used -by anyone other than You, whether those works are distributed or -communicated to those persons or made available as an application -intended for use over a network. As an express condition for the grants -of license hereunder, You must treat any External Deployment by You of -the Original Work or a Derivative Work as a distribution under section -1(c). - -6) Attribution Rights. You must retain, in the Source Code of any -Derivative Works that You create, all copyright, patent, or trademark -notices from the Source Code of the Original Work, as well as any -notices of licensing and any descriptive text identified therein as an -"Attribution Notice." You must cause the Source Code for any Derivative -Works that You create to carry a prominent Attribution Notice reasonably -calculated to inform recipients that You have modified the Original -Work. - -7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants -that the copyright in and to the Original Work and the patent rights -granted herein by Licensor are owned by the Licensor or are sublicensed -to You under the terms of this License with the permission of the -contributor(s) of those copyrights and patent rights. Except as -expressly stated in the immediately preceding sentence, the Original -Work is provided under this License on an "AS IS" BASIS and WITHOUT -WARRANTY, either express or implied, including, without limitation, the -warranties of non-infringement, merchantability or fitness for a -particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL -WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential -part of this License. No license to the Original Work is granted by this -License except under this disclaimer. - -8) Limitation of Liability. Under no circumstances and under no legal -theory, whether in tort (including negligence), contract, or otherwise, -shall the Licensor be liable to anyone for any indirect, special, -incidental, or consequential damages of any character arising as a -result of this License or the use of the Original Work including, -without limitation, damages for loss of goodwill, work stoppage, -computer failure or malfunction, or any and all other commercial damages -or losses. This limitation of liability shall not apply to the extent -applicable law prohibits such limitation. - -9) Acceptance and Termination. If, at any time, You expressly assented -to this License, that assent indicates your clear and irrevocable -acceptance of this License and all of its terms and conditions. If You -distribute or communicate copies of the Original Work or a Derivative -Work, You must make a reasonable effort under the circumstances to -obtain the express assent of recipients to the terms of this License. -This License conditions your rights to undertake the activities listed -in Section 1, including your right to create Derivative Works based upon -the Original Work, and doing so without honoring these terms and -conditions is prohibited by copyright law and international treaty. -Nothing in this License is intended to affect copyright exceptions and -limitations (including "fair use" or "fair dealing"). This License shall -terminate immediately and You may no longer exercise any of the rights -granted to You by this License upon your failure to honor the conditions -in Section 1(c). - -10) Termination for Patent Action. This License shall terminate -automatically and You may no longer exercise any of the rights granted -to You by this License as of the date You commence an action, including -a cross-claim or counterclaim, against Licensor or any licensee alleging -that the Original Work infringes a patent. This termination provision -shall not apply for an action alleging patent infringement by -combinations of the Original Work with other software or hardware. - -11) Jurisdiction, Venue and Governing Law. Any action or suit relating -to this License may be brought only in the courts of a jurisdiction -wherein the Licensor resides or in which Licensor conducts its primary -business, and under the laws of that jurisdiction excluding its -conflict-of-law provisions. The application of the United Nations -Convention on Contracts for the International Sale of Goods is expressly -excluded. Any use of the Original Work outside the scope of this License -or after its termination shall be subject to the requirements and -penalties of copyright or patent law in the appropriate jurisdiction. -This section shall survive the termination of this License. - -12) Attorneys' Fees. In any action to enforce the terms of this License -or seeking damages relating thereto, the prevailing party shall be -entitled to recover its costs and expenses, including, without -limitation, reasonable attorneys' fees and costs incurred in connection -with such action, including any appeal of such action. This section -shall survive the termination of this License. - -13) Miscellaneous. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. - -14) Definition of "You" in This License. "You" throughout this License, -whether in upper or lower case, means an individual or a legal entity -exercising rights under, and complying with all of the terms of, this -License. For legal entities, "You" includes any entity that controls, is -controlled by, or is under common control with you. For purposes of this -definition, "control" means (i) the power, direct or indirect, to cause -the direction or management of such entity, whether by contract or -otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -15) Right to Use. You may use the Original Work in all ways not -otherwise restricted or conditioned by this License or by law, and -Licensor promises not to interfere with or be responsible for such uses -by You. - -16) Modification of This License. This License is Copyright (c) 2005 -Lawrence Rosen. Permission is granted to copy, distribute, or -communicate this License without modification. Nothing in this License -permits You to modify this License as applied to the Original Work or to -Derivative Works. However, You may modify the text of this License and -copy, distribute or communicate your modified version (the "Modified -License") and apply it to other original works of authorship subject to -the following conditions: (i) You may not indicate in any way that your -Modified License is the "Academic Free License" or "AFL" and you may not -use those names in the name of your Modified License; (ii) You must -replace the notice specified in the first paragraph above with the -notice "Licensed under " or with a notice -of your own that is not confusingly similar to the notice in this -License; and (iii) You may not claim that your original works are open -source software unless your Modified License has been approved by Open -Source Initiative (OSI) and You comply with its license review and -certification process. - diff --git a/vendor/gems/has_many_polymorphs-2.13/Manifest b/vendor/gems/has_many_polymorphs-2.13/Manifest deleted file mode 100644 index c0555eff..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/Manifest +++ /dev/null @@ -1,173 +0,0 @@ -CHANGELOG -examples/hmph.rb -generators/tagging/tagging_generator.rb -generators/tagging/templates/migration.rb -generators/tagging/templates/tag.rb -generators/tagging/templates/tag_test.rb -generators/tagging/templates/tagging.rb -generators/tagging/templates/tagging_extensions.rb -generators/tagging/templates/tagging_test.rb -generators/tagging/templates/taggings.yml -generators/tagging/templates/tags.yml -init.rb -lib/has_many_polymorphs/association.rb -lib/has_many_polymorphs/autoload.rb -lib/has_many_polymorphs/base.rb -lib/has_many_polymorphs/class_methods.rb -lib/has_many_polymorphs/configuration.rb -lib/has_many_polymorphs/debugging_tools.rb -lib/has_many_polymorphs/rake_task_redefine_task.rb -lib/has_many_polymorphs/reflection.rb -lib/has_many_polymorphs/support_methods.rb -lib/has_many_polymorphs.rb -LICENSE -Manifest -Rakefile -README -test/fixtures/bow_wows.yml -test/fixtures/cats.yml -test/fixtures/eaters_foodstuffs.yml -test/fixtures/fish.yml -test/fixtures/frogs.yml -test/fixtures/keep_your_enemies_close.yml -test/fixtures/little_whale_pupils.yml -test/fixtures/people.yml -test/fixtures/petfoods.yml -test/fixtures/whales.yml -test/fixtures/wild_boars.yml -test/generator/tagging_generator_test.rb -test/integration/app/app/controllers/application.rb -test/integration/app/app/controllers/bones_controller.rb -test/integration/app/app/helpers/addresses_helper.rb -test/integration/app/app/helpers/application_helper.rb -test/integration/app/app/helpers/bones_helper.rb -test/integration/app/app/helpers/sellers_helper.rb -test/integration/app/app/helpers/states_helper.rb -test/integration/app/app/helpers/users_helper.rb -test/integration/app/app/models/bone.rb -test/integration/app/app/models/double_sti_parent.rb -test/integration/app/app/models/double_sti_parent_relationship.rb -test/integration/app/app/models/organic_substance.rb -test/integration/app/app/models/single_sti_parent.rb -test/integration/app/app/models/single_sti_parent_relationship.rb -test/integration/app/app/models/stick.rb -test/integration/app/app/models/stone.rb -test/integration/app/app/views/addresses/edit.html.erb -test/integration/app/app/views/addresses/index.html.erb -test/integration/app/app/views/addresses/new.html.erb -test/integration/app/app/views/addresses/show.html.erb -test/integration/app/app/views/bones/index.rhtml -test/integration/app/app/views/layouts/addresses.html.erb -test/integration/app/app/views/layouts/sellers.html.erb -test/integration/app/app/views/layouts/states.html.erb -test/integration/app/app/views/layouts/users.html.erb -test/integration/app/app/views/sellers/edit.html.erb -test/integration/app/app/views/sellers/index.html.erb -test/integration/app/app/views/sellers/new.html.erb -test/integration/app/app/views/sellers/show.html.erb -test/integration/app/app/views/states/edit.html.erb -test/integration/app/app/views/states/index.html.erb -test/integration/app/app/views/states/new.html.erb -test/integration/app/app/views/states/show.html.erb -test/integration/app/app/views/users/edit.html.erb -test/integration/app/app/views/users/index.html.erb -test/integration/app/app/views/users/new.html.erb -test/integration/app/app/views/users/show.html.erb -test/integration/app/config/boot.rb -test/integration/app/config/database.yml -test/integration/app/config/environment.rb -test/integration/app/config/environment.rb.canonical -test/integration/app/config/environments/development.rb -test/integration/app/config/environments/production.rb -test/integration/app/config/environments/test.rb -test/integration/app/config/locomotive.yml -test/integration/app/config/routes.rb -test/integration/app/config/ultrasphinx/default.base -test/integration/app/config/ultrasphinx/development.conf.canonical -test/integration/app/db/migrate/001_create_sticks.rb -test/integration/app/db/migrate/002_create_stones.rb -test/integration/app/db/migrate/003_create_organic_substances.rb -test/integration/app/db/migrate/004_create_bones.rb -test/integration/app/db/migrate/005_create_single_sti_parents.rb -test/integration/app/db/migrate/006_create_double_sti_parents.rb -test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb -test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb -test/integration/app/db/migrate/009_create_library_model.rb -test/integration/app/doc/README_FOR_APP -test/integration/app/generators/commenting_generator_test.rb -test/integration/app/lib/library_model.rb -test/integration/app/public/404.html -test/integration/app/public/500.html -test/integration/app/public/dispatch.cgi -test/integration/app/public/dispatch.fcgi -test/integration/app/public/dispatch.rb -test/integration/app/public/favicon.ico -test/integration/app/public/images/rails.png -test/integration/app/public/index.html -test/integration/app/public/javascripts/application.js -test/integration/app/public/javascripts/controls.js -test/integration/app/public/javascripts/dragdrop.js -test/integration/app/public/javascripts/effects.js -test/integration/app/public/javascripts/prototype.js -test/integration/app/public/robots.txt -test/integration/app/public/stylesheets/scaffold.css -test/integration/app/Rakefile -test/integration/app/README -test/integration/app/script/about -test/integration/app/script/breakpointer -test/integration/app/script/console -test/integration/app/script/destroy -test/integration/app/script/generate -test/integration/app/script/performance/benchmarker -test/integration/app/script/performance/profiler -test/integration/app/script/plugin -test/integration/app/script/process/inspector -test/integration/app/script/process/reaper -test/integration/app/script/process/spawner -test/integration/app/script/runner -test/integration/app/script/server -test/integration/app/test/fixtures/double_sti_parent_relationships.yml -test/integration/app/test/fixtures/double_sti_parents.yml -test/integration/app/test/fixtures/organic_substances.yml -test/integration/app/test/fixtures/single_sti_parent_relationships.yml -test/integration/app/test/fixtures/single_sti_parents.yml -test/integration/app/test/fixtures/sticks.yml -test/integration/app/test/fixtures/stones.yml -test/integration/app/test/functional/addresses_controller_test.rb -test/integration/app/test/functional/bones_controller_test.rb -test/integration/app/test/functional/sellers_controller_test.rb -test/integration/app/test/functional/states_controller_test.rb -test/integration/app/test/functional/users_controller_test.rb -test/integration/app/test/test_helper.rb -test/integration/app/test/unit/bone_test.rb -test/integration/app/test/unit/double_sti_parent_relationship_test.rb -test/integration/app/test/unit/double_sti_parent_test.rb -test/integration/app/test/unit/organic_substance_test.rb -test/integration/app/test/unit/single_sti_parent_relationship_test.rb -test/integration/app/test/unit/single_sti_parent_test.rb -test/integration/app/test/unit/stick_test.rb -test/integration/app/test/unit/stone_test.rb -test/integration/server_test.rb -test/models/aquatic/fish.rb -test/models/aquatic/pupils_whale.rb -test/models/aquatic/whale.rb -test/models/beautiful_fight_relationship.rb -test/models/canine.rb -test/models/cat.rb -test/models/dog.rb -test/models/eaters_foodstuff.rb -test/models/frog.rb -test/models/kitten.rb -test/models/parentship.rb -test/models/person.rb -test/models/petfood.rb -test/models/tabby.rb -test/models/wild_boar.rb -test/modules/extension_module.rb -test/modules/other_extension_module.rb -test/patches/symlinked_plugins_1.2.6.diff -test/schema.rb -test/setup.rb -test/test_helper.rb -test/unit/has_many_polymorphs_test.rb -TODO diff --git a/vendor/gems/has_many_polymorphs-2.13/README b/vendor/gems/has_many_polymorphs-2.13/README deleted file mode 100644 index 2f3f73f9..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/README +++ /dev/null @@ -1,205 +0,0 @@ -Has_many_polymorphs - -An ActiveRecord plugin for self-referential and double-sided polymorphic associations. - -== License - -Copyright 2006-2008 Cloudburst, LLC. Licensed under the AFL 3. See the included LICENSE file. - -The public certificate for the gem is here[http://rubyforge.org/frs/download.php/25331/evan_weaver-original-public_cert.pem]. - -If you use this software, please {make a donation}[http://blog.evanweaver.com/donate/], or {recommend Evan}[http://www.workingwithrails.com/person/7739-evan-weaver] at Working with Rails. - -== Description - -This plugin lets you define self-referential and double-sided polymorphic associations in your models. It is an extension of has_many :through. - -“Polymorphic” means an association can freely point to any of several unrelated model classes, instead of being tied to one particular class. - -== Features - -* self-references -* double-sided polymorphism -* efficient database usage -* STI support -* namespace support -* automatic individual and reverse associations - -The plugin also includes a generator for a tagging system, a common use case (see below). - -== Requirements - -* Rails 2.2.2 or greater - -= Usage - -== Installation - -To install the Rails plugin, run: - script/plugin install git://github.com/fauna/has_many_polymorphs.git - -There's also a gem version. To install it instead, run: - sudo gem install has_many_polymorphs - -If you are using the gem, make sure to add require 'has_many_polymorphs' to environment.rb, before Rails::Initializer block. - -== Configuration - -Setup the parent model as so: - - class Kennel < ActiveRecord::Base - has_many_polymorphs :guests, :from => [:dogs, :cats, :birds] - end - -The join model: - - class GuestsKennel < ActiveRecord::Base - belongs_to :kennel - belongs_to :guest, :polymorphic => true - end - -One of the child models: - - class Dog < ActiveRecord::Base - # nothing - end - -For your parent and child models, you don't need any special fields in your migration. For the join model (GuestsKennel), use a migration like so: - - class CreateGuestsKennels < ActiveRecord::Migration - def self.up - create_table :guests_kennels do |t| - t.references :guest, :polymorphic => true - t.references :kennel - end - end - - def self.down - drop_table :guests_kennels - end - end - -See ActiveRecord::Associations::PolymorphicClassMethods for more configuration options. - -== Helper methods example - - >> k = Kennel.find(1) - # - >> k.guests.map(&:class) - [Dog, Cat, Cat, Bird] - - >> k.guests.push(Cat.create); k.cats.size - 3 - >> k.guests << Cat.create; k.cats.size - 4 - >> k.guests.size - 6 - - >> d = k.dogs.first - # - >> d.kennels - [#] - - >> k.guests.delete(d); k.dogs.size - 0 - >> k.guests.size - 5 - -Note that the parent method is always plural, even if there is only one parent (Dog#kennels, not Dog#kennel). - -See ActiveRecord::Associations::PolymorphicAssociation for more helper method details. - -= Extras - -== Double-sided polymorphism - -Double-sided relationships are defined on the join model: - - class Devouring < ActiveRecord::Base - belongs_to :guest, :polymorphic => true - belongs_to :eaten, :polymorphic => true - - acts_as_double_polymorphic_join( - :guests =>[:dogs, :cats], - :eatens => [:cats, :birds] - ) - end - -Now, dogs and cats can eat birds and cats. Birds can't eat anything (they aren't guests) and dogs can't be eaten by anything (since they aren't eatens). The keys stand for what the models are, not what they do. - -In this case, each guest/eaten relationship is called a Devouring. - -In your migration, you need to declare both sides as polymorphic: - - class CreateDevourings < ActiveRecord::Migration - def self.up - create_table :devourings do |t| - t.references :guest, :polymorphic => true - t.references :eaten, :polymorphic => true - end - end - - def self.down - drop_table :devourings - end - end - -See ActiveRecord::Associations::PolymorphicClassMethods for more. - -== Tagging generator - -Has_many_polymorphs includes a tagging system generator. Run: - script/generate tagging Dog Cat [...MoreModels...] - -This adds a migration and new Tag and Tagging models in app/models. It configures Tag with an appropriate has_many_polymorphs call against the models you list at the command line. It also adds the file lib/tagging_extensions.rb and requires it in environment.rb. - -Tests will also be generated. - -Once you've run the generator, you can tag records as follows: - - >> d = Dog.create(:name => "Rover") - # - >> d.tag_list - "" - >> d.tag_with "fierce loud" - # - >> d.tag_list - "fierce loud" - >> c = Cat.create(:name => "Chloe") - # - >> c.tag_with "fierce cute" - # - >> c.tag_list - "cute fierce" - >> Tag.find_by_name("fierce").taggables - [#, #] - -The generator accepts the optional flag --skip-migration to skip generating a migration (for example, if you are converting from acts_as_taggable). It also accepts the flag --self-referential if you want to be able to tag tags. - -See ActiveRecord::Base::TaggingExtensions, Tag, and Tagging for more. - -== Troubleshooting - -Some debugging tools are available in lib/has_many_polymorphs/debugging_tools.rb. - -If you are having trouble, think very carefully about how your model classes, key columns, and table names relate. You may have to explicitly specify options on your join model such as :class_name, :foreign_key, or :as. The included tests are a good place to look for examples. - -Note that because of the way Rails reloads model classes, the plugin can sometimes bog down your development server. Set config.cache_classes = true in config/environments/development.rb to avoid this. - -== Reporting problems - -The support forum is here[http://rubyforge.org/forum/forum.php?forum_id=16450]. - -Patches and contributions are very welcome. Please note that contributors are required to assign copyright for their additions to Cloudburst, LLC. - -== Further resources - -* http://blog.evanweaver.com/articles/2007/08/15/polymorphs-tutorial -* http://blog.evanweaver.com/articles/2007/02/22/polymorphs-25-total-insanity-branch -* http://blog.evanweaver.com/articles/2007/02/09/how-to-find-the-most-popular-tags -* http://blog.evanweaver.com/articles/2007/01/13/growing-up-your-acts_as_taggable -* http://blog.evanweaver.com/articles/2006/12/02/polymorphs-19 -* http://blog.evanweaver.com/articles/2006/11/05/directed-double-polymorphic-associations -* http://blog.evanweaver.com/articles/2006/11/04/namespaced-model-support-in-has_many_polymorphs -* http://blog.evanweaver.com/articles/2006/09/26/sti-support-in-has_many_polymorphs -* http://blog.evanweaver.com/articles/2006/09/11/make-polymorphic-children-belong-to-only-one-parent diff --git a/vendor/gems/has_many_polymorphs-2.13/Rakefile b/vendor/gems/has_many_polymorphs-2.13/Rakefile deleted file mode 100644 index b93a94f5..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/Rakefile +++ /dev/null @@ -1,28 +0,0 @@ - -require 'echoe' - -Echoe.new("has_many_polymorphs") do |p| - p.project = "fauna" - p.summary = "An ActiveRecord plugin for self-referential and double-sided polymorphic associations." - p.url = "http://blog.evanweaver.com/files/doc/fauna/has_many_polymorphs/" - p.docs_host = "blog.evanweaver.com:~/www/bax/public/files/doc/" - p.dependencies = ["activerecord"] - p.rdoc_pattern = /polymorphs\/association|polymorphs\/class_methods|polymorphs\/reflection|polymorphs\/autoload|polymorphs\/configuration|README|CHANGELOG|TODO|LICENSE|templates\/migration\.rb|templates\/tag\.rb|templates\/tagging\.rb|templates\/tagging_extensions\.rb/ - p.require_signed = true - p.clean_pattern += ["**/ruby_sess*", "**/generated_models/**"] - p.test_pattern = ["test/unit/*_test.rb", "test/integration/*_test.rb", "test/generator/*_test.rb"] -end - -desc "Run all the tests for every database adapter" -task "test_all" do - ['mysql', 'postgresql', 'sqlite3'].each do |adapter| - ENV['DB'] = adapter - ENV['PRODUCTION'] = nil - STDERR.puts "#{'='*80}\nDevelopment mode for #{adapter}\n#{'='*80}" - system("rake test:multi_rails:all") - - ENV['PRODUCTION'] = '1' - STDERR.puts "#{'='*80}\nProduction mode for #{adapter}\n#{'='*80}" - system("rake test:multi_rails:all") - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/TODO b/vendor/gems/has_many_polymorphs-2.13/TODO deleted file mode 100644 index b06e28f2..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/TODO +++ /dev/null @@ -1,2 +0,0 @@ - -* Tag cloud method diff --git a/vendor/gems/has_many_polymorphs-2.13/examples/hmph.rb b/vendor/gems/has_many_polymorphs-2.13/examples/hmph.rb deleted file mode 100644 index 67017505..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/examples/hmph.rb +++ /dev/null @@ -1,69 +0,0 @@ -require 'camping' -require 'has_many_polymorphs' - -Camping.goes :Hmph - -module Hmph::Models - class GuestsKennel < Base - belongs_to :kennel - belongs_to :guest, :polymorphic => true - end - - class Dog < Base - end - - class Cat < Base - end - - class Bird < Base - end - - class Kennel < Base - has_many_polymorphs :guests, - :from => [:dogs, :cats, :birds], - :through => :guests_kennels, - :namespace => :"hmph/models/" - end - - class InitialSchema < V 1.0 - def self.up - create_table :hmph_kennels do |t| - t.column :created_at, :datetime - t.column :modified_at, :datetime - t.column :name, :string, :default => 'Anonymous Kennel' - end - - create_table :hmph_guests_kennels do |t| - t.column :guest_id, :integer - t.column :guest_type, :string - t.column :kennel_id, :integer - end - - create_table :hmph_dogs do |t| - t.column :name, :string, :default => 'Fido' - end - - create_table :hmph_cats do |t| - t.column :name, :string, :default => 'Morris' - end - - create_table :hmph_birds do |t| - t.column :name, :string, :default => 'Polly' - end - end - - def self.down - drop_table :hmph_kennels - drop_table :hmph_guests_kennels - drop_table :hmph_dogs - drop_table :hmph_cats - drop_table :hmph_birds - end - end -end - -module Hmph::Controllers -end - -module Hmph::Views -end diff --git a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/tagging_generator.rb b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/tagging_generator.rb deleted file mode 100644 index d99b10f8..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/tagging_generator.rb +++ /dev/null @@ -1,97 +0,0 @@ -require 'ruby-debug' and Debugger.start if ENV['USER'] == 'eweaver' - -class TaggingGenerator < Rails::Generator::NamedBase - default_options :skip_migration => false - default_options :self_referential => false - attr_reader :parent_association_name - attr_reader :taggable_models - - def initialize(runtime_args, runtime_options = {}) - parse!(runtime_args, runtime_options) - - @parent_association_name = (runtime_args.include?("--self-referential") ? "tagger" : "tag") - @taggable_models = runtime_args.reject{|opt| opt =~ /^--/}.map do |taggable| - ":" + taggable.underscore.pluralize - end - @taggable_models += [":tags"] if runtime_args.include?("--self-referential") - @taggable_models.uniq! - - verify @taggable_models - hacks - runtime_args.unshift("placeholder") - super - end - - def verify models - puts "** Warning: only one taggable model specified; tests may not run properly." if models.size < 2 - models.each do |model| - model = model[1..-1].classify - next if model == "Tag" # don't load ourselves when --self-referential is used - self.class.const_get(model) rescue puts "** Error: model #{model[1..-1].classify} could not be loaded." or exit - end - end - - def hacks - # add the extension require in environment.rb - phrase = "require 'tagging_extensions'" - filename = "#{RAILS_ROOT}/config/environment.rb" - unless (open(filename) do |file| - file.grep(/#{Regexp.escape phrase}/).any? - end) - open(filename, 'a+') do |file| - file.puts "\n" + phrase + "\n" - end - end - end - - def manifest - record do |m| - m.class_collisions class_path, class_name, "#{class_name}Test" - - m.directory File.join('app/models', class_path) - m.directory File.join('test/unit', class_path) - m.directory File.join('test/fixtures', class_path) - m.directory File.join('test/fixtures', class_path) - m.directory File.join('lib') - - m.template 'tag.rb', File.join('app/models', class_path, "tag.rb") - m.template 'tag_test.rb', File.join('test/unit', class_path, "tag_test.rb") - m.template 'tags.yml', File.join('test/fixtures', class_path, "tags.yml") - - m.template 'tagging.rb', File.join('app/models', class_path, "tagging.rb") - m.template 'tagging_test.rb', File.join('test/unit', class_path, "tagging_test.rb") - m.template 'taggings.yml', File.join('test/fixtures', class_path, "taggings.yml") - - m.template 'tagging_extensions.rb', File.join('lib', 'tagging_extensions.rb') - - unless options[:skip_migration] - m.migration_template 'migration.rb', 'db/migrate', - :migration_file_name => "create_tags_and_taggings" - end - - end - end - - protected - def banner - "Usage: #{$0} generate tagging [TaggableModelA TaggableModelB ...]" - end - - def add_options!(opt) - opt.separator '' - opt.separator 'Options:' - opt.on("--skip-migration", - "Don't generate a migration file for this model") { |v| options[:skip_migration] = v } - opt.on("--self-referential", - "Allow tags to tag themselves.") { |v| options[:self_referential] = v } - end - - # Useful for generating tests/fixtures - def model_one - taggable_models[0][1..-1].classify - end - - def model_two - taggable_models[1][1..-1].classify rescue model_one - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/migration.rb b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/migration.rb deleted file mode 100644 index 582b54c6..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/migration.rb +++ /dev/null @@ -1,28 +0,0 @@ - -# A migration to add tables for Tag and Tagging. This file is automatically generated and added to your app if you run the tagging generator included with has_many_polymorphs. - -class CreateTagsAndTaggings < ActiveRecord::Migration - - # Add the new tables. - def self.up - create_table :tags do |t| - t.column :name, :string, :null => false - end - add_index :tags, :name, :unique => true - - create_table :taggings do |t| - t.column :<%= parent_association_name -%>_id, :integer, :null => false - t.column :taggable_id, :integer, :null => false - t.column :taggable_type, :string, :null => false - # t.column :position, :integer # Uncomment this if you need to use acts_as_list. - end - add_index :taggings, [:<%= parent_association_name -%>_id, :taggable_id, :taggable_type], :unique => true - end - - # Remove the tables. - def self.down - drop_table :tags - drop_table :taggings - end - -end diff --git a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tag.rb b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tag.rb deleted file mode 100644 index 1966a76b..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tag.rb +++ /dev/null @@ -1,39 +0,0 @@ - -# The Tag model. This model is automatically generated and added to your app if you run the tagging generator included with has_many_polymorphs. - -class Tag < ActiveRecord::Base - - DELIMITER = " " # Controls how to split and join tagnames from strings. You may need to change the validates_format_of parameters if you change this. - - # If database speed becomes an issue, you could remove these validations and rescue the ActiveRecord database constraint errors instead. - validates_presence_of :name - validates_uniqueness_of :name, :case_sensitive => false - - # Change this validation if you need more complex tag names. - validates_format_of :name, :with => /^[a-zA-Z0-9\_\-]+$/, :message => "can not contain special characters" - - # Set up the polymorphic relationship. - has_many_polymorphs :taggables, - :from => [<%= taggable_models.join(", ") %>], - :through => :taggings, - :dependent => :destroy, -<% if options[:self_referential] -%> :as => :<%= parent_association_name -%>, -<% end -%> - :skip_duplicates => false, - :parent_extend => proc { - # Defined on the taggable models, not on Tag itself. Return the tagnames associated with this record as a string. - def to_s - self.map(&:name).sort.join(Tag::DELIMITER) - end - } - - # Callback to strip extra spaces from the tagname before saving it. If you allow tags to be renamed later, you might want to use the before_save callback instead. - def before_create - self.name = name.downcase.strip.squeeze(" ") - end - - # Tag::Error class. Raised by ActiveRecord::Base::TaggingExtensions if something goes wrong. - class Error < StandardError - end - -end diff --git a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tag_test.rb b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tag_test.rb deleted file mode 100644 index f4ab543a..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tag_test.rb +++ /dev/null @@ -1,15 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class TagTest < Test::Unit::TestCase - fixtures <%= taggable_models[0..1].join(", ") -%> - - def setup - @obj = <%= model_two %>.find(:first) - @obj.tag_with "pale imperial" - end - - def test_to_s - assert_equal "imperial pale", <%= model_two -%>.find(:first).tags.to_s - end - -end diff --git a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging.rb b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging.rb deleted file mode 100644 index bb5ea28f..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging.rb +++ /dev/null @@ -1,16 +0,0 @@ - -# The Tagging join model. This model is automatically generated and added to your app if you run the tagging generator included with has_many_polymorphs. - -class Tagging < ActiveRecord::Base - - belongs_to :<%= parent_association_name -%><%= ", :foreign_key => \"#{parent_association_name}_id\", :class_name => \"Tag\"" if options[:self_referential] %> - belongs_to :taggable, :polymorphic => true - - # If you also need to use acts_as_list, you will have to manage the tagging positions manually by creating decorated join records when you associate Tags with taggables. - # acts_as_list :scope => :taggable - - # This callback makes sure that an orphaned Tag is deleted if it no longer tags anything. - def after_destroy - <%= parent_association_name -%>.destroy_without_callbacks if <%= parent_association_name -%> and <%= parent_association_name -%>.taggings.count == 0 - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging_extensions.rb b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging_extensions.rb deleted file mode 100644 index ca7e6add..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging_extensions.rb +++ /dev/null @@ -1,203 +0,0 @@ -class ActiveRecord::Base #:nodoc: - - # These extensions make models taggable. This file is automatically generated and required by your app if you run the tagging generator included with has_many_polymorphs. - module TaggingExtensions - - # Add tags to self. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags. - # - # We need to avoid name conflicts with the built-in ActiveRecord association methods, thus the underscores. - def _add_tags incoming - taggable?(true) - tag_cast_to_string(incoming).each do |tag_name| - begin - tag = Tag.find_or_create_by_name(tag_name) - raise Tag::Error, "tag could not be saved: #{tag_name}" if tag.new_record? - tags << tag - rescue ActiveRecord::StatementInvalid => e - raise unless e.to_s =~ /duplicate/i - end - end - end - - # Removes tags from self. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags. - def _remove_tags outgoing - taggable?(true) - outgoing = tag_cast_to_string(outgoing) - <% if options[:self_referential] %> - # because of http://dev.rubyonrails.org/ticket/6466 - taggings.destroy(*(taggings.find(:all, :include => :<%= parent_association_name -%>).select do |tagging| - outgoing.include? tagging.<%= parent_association_name -%>.name - end)) - <% else -%> - <%= parent_association_name -%>s.delete(*(<%= parent_association_name -%>s.select do |tag| - outgoing.include? tag.name - end)) - <% end -%> - end - - # Returns the tags on self as a string. - def tag_list - # Redefined later to avoid an RDoc parse error. - end - - # Replace the existing tags on self. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags. - def tag_with list - #:stopdoc: - taggable?(true) - list = tag_cast_to_string(list) - - # Transactions may not be ideal for you here; be aware. - Tag.transaction do - current = <%= parent_association_name -%>s.map(&:name) - _add_tags(list - current) - _remove_tags(current - list) - end - - self - #:startdoc: - end - - # Returns the tags on self as a string. - def tag_list #:nodoc: - #:stopdoc: - taggable?(true) - <%= parent_association_name -%>s.reload - <%= parent_association_name -%>s.to_s - #:startdoc: - end - - def tag_list=(value) - tag_with(value) - end - - private - - def tag_cast_to_string obj #:nodoc: - case obj - when Array - obj.map! do |item| - case item - when /^\d+$/, Fixnum then Tag.find(item).name # This will be slow if you use ids a lot. - when Tag then item.name - when String then item - else - raise "Invalid type" - end - end - when String - obj = obj.split(Tag::DELIMITER).map do |tag_name| - tag_name.strip.squeeze(" ") - end - else - raise "Invalid object of class #{obj.class} as tagging method parameter" - end.flatten.compact.map(&:downcase).uniq - end - - # Check if a model is in the :taggables target list. The alternative to this check is to explicitly include a TaggingMethods module (which you would create) in each target model. - def taggable?(should_raise = false) #:nodoc: - unless flag = respond_to?(:<%= parent_association_name -%>s) - raise "#{self.class} is not a taggable model" if should_raise - end - flag - end - - end - - module TaggingFinders - # Find all the objects tagged with the supplied list of tags - # - # Usage : Model.tagged_with("ruby") - # Model.tagged_with("hello", "world") - # Model.tagged_with("hello", "world", :limit => 10) - # - # XXX This query strategy is not performant, and needs to be rewritten as an inverted join or a series of unions - # - def tagged_with(*tag_list) - options = tag_list.last.is_a?(Hash) ? tag_list.pop : {} - tag_list = parse_tags(tag_list) - - scope = scope(:find) - options[:select] ||= "#{table_name}.*" - options[:from] ||= "#{table_name}, tags, taggings" - - sql = "SELECT #{(scope && scope[:select]) || options[:select]} " - sql << "FROM #{(scope && scope[:from]) || options[:from]} " - - add_joins!(sql, options[:joins], scope) - - sql << "WHERE #{table_name}.#{primary_key} = taggings.taggable_id " - sql << "AND taggings.taggable_type = '#{ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s}' " - sql << "AND taggings.tag_id = tags.id " - - tag_list_condition = tag_list.map {|name| "'#{name}'"}.join(", ") - - sql << "AND (tags.name IN (#{sanitize_sql(tag_list_condition)})) " - sql << "AND #{sanitize_sql(options[:conditions])} " if options[:conditions] - - columns = column_names.map do |column| - "#{table_name}.#{column}" - end.join(", ") - - sql << "GROUP BY #{columns} " - sql << "HAVING COUNT(taggings.tag_id) = #{tag_list.size}" - - add_order!(sql, options[:order], scope) - add_limit!(sql, options, scope) - add_lock!(sql, options, scope) - - find_by_sql(sql) - end - - def self.tagged_with_any(*tag_list) - options = tag_list.last.is_a?(Hash) ? tag_list.pop : {} - tag_list = parse_tags(tag_list) - - scope = scope(:find) - options[:select] ||= "#{table_name}.*" - options[:from] ||= "#{table_name}, meta_tags, taggings" - - sql = "SELECT #{(scope && scope[:select]) || options[:select]} " - sql << "FROM #{(scope && scope[:from]) || options[:from]} " - - add_joins!(sql, options, scope) - - sql << "WHERE #{table_name}.#{primary_key} = taggings.taggable_id " - sql << "AND taggings.taggable_type = '#{ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s}' " - sql << "AND taggings.meta_tag_id = meta_tags.id " - - sql << "AND (" - or_options = [] - tag_list.each do |name| - or_options << "meta_tags.name = '#{name}'" - end - or_options_joined = or_options.join(" OR ") - sql << "#{or_options_joined}) " - - - sql << "AND #{sanitize_sql(options[:conditions])} " if options[:conditions] - - columns = column_names.map do |column| - "#{table_name}.#{column}" - end.join(", ") - - sql << "GROUP BY #{columns} " - - add_order!(sql, options[:order], scope) - add_limit!(sql, options, scope) - add_lock!(sql, options, scope) - - find_by_sql(sql) - end - - def parse_tags(tags) - return [] if tags.blank? - tags = Array(tags).first - tags = tags.respond_to?(:flatten) ? tags.flatten : tags.split(Tag::DELIMITER) - tags.map { |tag| tag.strip.squeeze(" ") }.flatten.compact.map(&:downcase).uniq - end - - end - - include TaggingExtensions - extend TaggingFinders -end diff --git a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging_test.rb b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging_test.rb deleted file mode 100644 index f055d381..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tagging_test.rb +++ /dev/null @@ -1,85 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class TaggingTest < Test::Unit::TestCase - fixtures :tags, :taggings, <%= taggable_models[0..1].join(", ") -%> - - def setup - @objs = <%= model_two %>.find(:all, :limit => 2) - - @obj1 = @objs[0] - @obj1.tag_with("pale") - @obj1.reload - - @obj2 = @objs[1] - @obj2.tag_with("pale imperial") - @obj2.reload - -<% if taggable_models.size > 1 -%> - @obj3 = <%= model_one -%>.find(:first) -<% end -%> - @tag1 = Tag.find(1) - @tag2 = Tag.find(2) - @tagging1 = Tagging.find(1) - end - - def test_tag_with - @obj2.tag_with "hoppy pilsner" - assert_equal "hoppy pilsner", @obj2.tag_list - end - - def test_find_tagged_with - @obj1.tag_with "seasonal lager ipa" - @obj2.tag_with ["lager", "stout", "fruity", "seasonal"] - - result1 = [@obj1] - assert_equal <%= model_two %>.tagged_with("ipa"), result1 - assert_equal <%= model_two %>.tagged_with("ipa lager"), result1 - assert_equal <%= model_two %>.tagged_with("ipa", "lager"), result1 - - result2 = [@obj1.id, @obj2.id].sort - assert_equal <%= model_two %>.tagged_with("seasonal").map(&:id).sort, result2 - assert_equal <%= model_two %>.tagged_with("seasonal lager").map(&:id).sort, result2 - assert_equal <%= model_two %>.tagged_with("seasonal", "lager").map(&:id).sort, result2 - end - -<% if options[:self_referential] -%> - def test_self_referential_tag_with - @tag1.tag_with [1, 2] - assert @tag1.tags.include?(@tag1) - assert !@tag2.tags.include?(@tag1) - end - -<% end -%> - def test__add_tags - @obj1._add_tags "porter longneck" - assert Tag.find_by_name("porter").taggables.include?(@obj1) - assert Tag.find_by_name("longneck").taggables.include?(@obj1) - assert_equal "longneck pale porter", @obj1.tag_list - - @obj1._add_tags [2] - assert_equal "imperial longneck pale porter", @obj1.tag_list - end - - def test__remove_tags - @obj2._remove_tags ["2", @tag1] - assert @obj2.tags.empty? - end - - def test_tag_list - assert_equal "imperial pale", @obj2.tag_list - end - - def test_taggable - assert_raises(RuntimeError) do - @tagging1.send(:taggable?, true) - end - assert !@tagging1.send(:taggable?) -<% if taggable_models.size > 1 -%> - assert @obj3.send(:taggable?) -<% end -%> -<% if options[:self_referential] -%> - assert @tag1.send(:taggable?) -<% end -%> - end - -end diff --git a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/taggings.yml b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/taggings.yml deleted file mode 100644 index 0cf13b9d..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/taggings.yml +++ /dev/null @@ -1,23 +0,0 @@ ---- -<% if taggable_models.size > 1 -%> -taggings_003: - <%= parent_association_name -%>_id: "2" - id: "3" - taggable_type: <%= model_one %> - taggable_id: "1" -<% end -%> -taggings_004: - <%= parent_association_name -%>_id: "2" - id: "4" - taggable_type: <%= model_two %> - taggable_id: "2" -taggings_001: - <%= parent_association_name -%>_id: "1" - id: "1" - taggable_type: <%= model_two %> - taggable_id: "1" -taggings_002: - <%= parent_association_name -%>_id: "1" - id: "2" - taggable_type: <%= model_two %> - taggable_id: "2" diff --git a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tags.yml b/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tags.yml deleted file mode 100644 index 517a8ce5..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/generators/tagging/templates/tags.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -tags_001: - name: pale - id: "1" -tags_002: - name: imperial - id: "2" diff --git a/vendor/gems/has_many_polymorphs-2.13/has_many_polymorphs.gemspec b/vendor/gems/has_many_polymorphs-2.13/has_many_polymorphs.gemspec deleted file mode 100644 index 3e1a69b7..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/has_many_polymorphs.gemspec +++ /dev/null @@ -1,40 +0,0 @@ -# -*- encoding: utf-8 -*- - -Gem::Specification.new do |s| - s.name = %q{has_many_polymorphs} - s.version = "2.13" - - s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version= - s.authors = [""] - s.cert_chain = ["/Users/eweaver/p/configuration/gem_certificates/evan_weaver-original-public_cert.pem"] - s.date = %q{2009-02-02} - s.description = %q{An ActiveRecord plugin for self-referential and double-sided polymorphic associations.} - s.email = %q{} - s.extra_rdoc_files = ["CHANGELOG", "generators/tagging/templates/migration.rb", "generators/tagging/templates/tag.rb", "generators/tagging/templates/tagging.rb", "generators/tagging/templates/tagging_extensions.rb", "lib/has_many_polymorphs/association.rb", "lib/has_many_polymorphs/autoload.rb", "lib/has_many_polymorphs/class_methods.rb", "lib/has_many_polymorphs/configuration.rb", "lib/has_many_polymorphs/reflection.rb", "LICENSE", "README", "test/integration/app/doc/README_FOR_APP", "test/integration/app/README", "TODO"] - s.files = ["CHANGELOG", "examples/hmph.rb", "generators/tagging/tagging_generator.rb", "generators/tagging/templates/migration.rb", "generators/tagging/templates/tag.rb", "generators/tagging/templates/tag_test.rb", "generators/tagging/templates/tagging.rb", "generators/tagging/templates/tagging_extensions.rb", "generators/tagging/templates/tagging_test.rb", "generators/tagging/templates/taggings.yml", "generators/tagging/templates/tags.yml", "init.rb", "lib/has_many_polymorphs/association.rb", "lib/has_many_polymorphs/autoload.rb", "lib/has_many_polymorphs/base.rb", "lib/has_many_polymorphs/class_methods.rb", "lib/has_many_polymorphs/configuration.rb", "lib/has_many_polymorphs/debugging_tools.rb", "lib/has_many_polymorphs/rake_task_redefine_task.rb", "lib/has_many_polymorphs/reflection.rb", "lib/has_many_polymorphs/support_methods.rb", "lib/has_many_polymorphs.rb", "LICENSE", "Manifest", "Rakefile", "README", "test/fixtures/bow_wows.yml", "test/fixtures/cats.yml", "test/fixtures/eaters_foodstuffs.yml", "test/fixtures/fish.yml", "test/fixtures/frogs.yml", "test/fixtures/keep_your_enemies_close.yml", "test/fixtures/little_whale_pupils.yml", "test/fixtures/people.yml", "test/fixtures/petfoods.yml", "test/fixtures/whales.yml", "test/fixtures/wild_boars.yml", "test/generator/tagging_generator_test.rb", "test/integration/app/app/controllers/application.rb", "test/integration/app/app/controllers/bones_controller.rb", "test/integration/app/app/helpers/addresses_helper.rb", "test/integration/app/app/helpers/application_helper.rb", "test/integration/app/app/helpers/bones_helper.rb", "test/integration/app/app/helpers/sellers_helper.rb", "test/integration/app/app/helpers/states_helper.rb", "test/integration/app/app/helpers/users_helper.rb", "test/integration/app/app/models/bone.rb", "test/integration/app/app/models/double_sti_parent.rb", "test/integration/app/app/models/double_sti_parent_relationship.rb", "test/integration/app/app/models/organic_substance.rb", "test/integration/app/app/models/single_sti_parent.rb", "test/integration/app/app/models/single_sti_parent_relationship.rb", "test/integration/app/app/models/stick.rb", "test/integration/app/app/models/stone.rb", "test/integration/app/app/views/addresses/edit.html.erb", "test/integration/app/app/views/addresses/index.html.erb", "test/integration/app/app/views/addresses/new.html.erb", "test/integration/app/app/views/addresses/show.html.erb", "test/integration/app/app/views/bones/index.rhtml", "test/integration/app/app/views/layouts/addresses.html.erb", "test/integration/app/app/views/layouts/sellers.html.erb", "test/integration/app/app/views/layouts/states.html.erb", "test/integration/app/app/views/layouts/users.html.erb", "test/integration/app/app/views/sellers/edit.html.erb", "test/integration/app/app/views/sellers/index.html.erb", "test/integration/app/app/views/sellers/new.html.erb", "test/integration/app/app/views/sellers/show.html.erb", "test/integration/app/app/views/states/edit.html.erb", "test/integration/app/app/views/states/index.html.erb", "test/integration/app/app/views/states/new.html.erb", "test/integration/app/app/views/states/show.html.erb", "test/integration/app/app/views/users/edit.html.erb", "test/integration/app/app/views/users/index.html.erb", "test/integration/app/app/views/users/new.html.erb", "test/integration/app/app/views/users/show.html.erb", "test/integration/app/config/boot.rb", "test/integration/app/config/database.yml", "test/integration/app/config/environment.rb", "test/integration/app/config/environment.rb.canonical", "test/integration/app/config/environments/development.rb", "test/integration/app/config/environments/production.rb", "test/integration/app/config/environments/test.rb", "test/integration/app/config/locomotive.yml", "test/integration/app/config/routes.rb", "test/integration/app/config/ultrasphinx/default.base", "test/integration/app/config/ultrasphinx/development.conf.canonical", "test/integration/app/db/migrate/001_create_sticks.rb", "test/integration/app/db/migrate/002_create_stones.rb", "test/integration/app/db/migrate/003_create_organic_substances.rb", "test/integration/app/db/migrate/004_create_bones.rb", "test/integration/app/db/migrate/005_create_single_sti_parents.rb", "test/integration/app/db/migrate/006_create_double_sti_parents.rb", "test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb", "test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb", "test/integration/app/db/migrate/009_create_library_model.rb", "test/integration/app/doc/README_FOR_APP", "test/integration/app/generators/commenting_generator_test.rb", "test/integration/app/lib/library_model.rb", "test/integration/app/public/404.html", "test/integration/app/public/500.html", "test/integration/app/public/dispatch.cgi", "test/integration/app/public/dispatch.fcgi", "test/integration/app/public/dispatch.rb", "test/integration/app/public/favicon.ico", "test/integration/app/public/images/rails.png", "test/integration/app/public/index.html", "test/integration/app/public/javascripts/application.js", "test/integration/app/public/javascripts/controls.js", "test/integration/app/public/javascripts/dragdrop.js", "test/integration/app/public/javascripts/effects.js", "test/integration/app/public/javascripts/prototype.js", "test/integration/app/public/robots.txt", "test/integration/app/public/stylesheets/scaffold.css", "test/integration/app/Rakefile", "test/integration/app/README", "test/integration/app/script/about", "test/integration/app/script/breakpointer", "test/integration/app/script/console", "test/integration/app/script/destroy", "test/integration/app/script/generate", "test/integration/app/script/performance/benchmarker", "test/integration/app/script/performance/profiler", "test/integration/app/script/plugin", "test/integration/app/script/process/inspector", "test/integration/app/script/process/reaper", "test/integration/app/script/process/spawner", "test/integration/app/script/runner", "test/integration/app/script/server", "test/integration/app/test/fixtures/double_sti_parent_relationships.yml", "test/integration/app/test/fixtures/double_sti_parents.yml", "test/integration/app/test/fixtures/organic_substances.yml", "test/integration/app/test/fixtures/single_sti_parent_relationships.yml", "test/integration/app/test/fixtures/single_sti_parents.yml", "test/integration/app/test/fixtures/sticks.yml", "test/integration/app/test/fixtures/stones.yml", "test/integration/app/test/functional/addresses_controller_test.rb", "test/integration/app/test/functional/bones_controller_test.rb", "test/integration/app/test/functional/sellers_controller_test.rb", "test/integration/app/test/functional/states_controller_test.rb", "test/integration/app/test/functional/users_controller_test.rb", "test/integration/app/test/test_helper.rb", "test/integration/app/test/unit/bone_test.rb", "test/integration/app/test/unit/double_sti_parent_relationship_test.rb", "test/integration/app/test/unit/double_sti_parent_test.rb", "test/integration/app/test/unit/organic_substance_test.rb", "test/integration/app/test/unit/single_sti_parent_relationship_test.rb", "test/integration/app/test/unit/single_sti_parent_test.rb", "test/integration/app/test/unit/stick_test.rb", "test/integration/app/test/unit/stone_test.rb", "test/integration/server_test.rb", "test/models/aquatic/fish.rb", "test/models/aquatic/pupils_whale.rb", "test/models/aquatic/whale.rb", "test/models/beautiful_fight_relationship.rb", "test/models/canine.rb", "test/models/cat.rb", "test/models/dog.rb", "test/models/eaters_foodstuff.rb", "test/models/frog.rb", "test/models/kitten.rb", "test/models/parentship.rb", "test/models/person.rb", "test/models/petfood.rb", "test/models/tabby.rb", "test/models/wild_boar.rb", "test/modules/extension_module.rb", "test/modules/other_extension_module.rb", "test/patches/symlinked_plugins_1.2.6.diff", "test/schema.rb", "test/setup.rb", "test/test_helper.rb", "test/unit/has_many_polymorphs_test.rb", "TODO", "has_many_polymorphs.gemspec"] - s.has_rdoc = true - s.homepage = %q{http://blog.evanweaver.com/files/doc/fauna/has_many_polymorphs/} - s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Has_many_polymorphs", "--main", "README"] - s.require_paths = ["lib"] - s.rubyforge_project = %q{fauna} - s.rubygems_version = %q{1.3.1} - s.signing_key = %q{/Users/eweaver/p/configuration/gem_certificates/evan_weaver-original-private_key.pem} - s.summary = %q{An ActiveRecord plugin for self-referential and double-sided polymorphic associations.} - s.test_files = ["test/generator/tagging_generator_test.rb", "test/integration/server_test.rb", "test/unit/has_many_polymorphs_test.rb"] - - if s.respond_to? :specification_version then - current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION - s.specification_version = 2 - - if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then - s.add_runtime_dependency(%q, [">= 0"]) - s.add_development_dependency(%q, [">= 0"]) - else - s.add_dependency(%q, [">= 0"]) - s.add_dependency(%q, [">= 0"]) - end - else - s.add_dependency(%q, [">= 0"]) - s.add_dependency(%q, [">= 0"]) - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/init.rb b/vendor/gems/has_many_polymorphs-2.13/init.rb deleted file mode 100644 index 3939a253..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/init.rb +++ /dev/null @@ -1,2 +0,0 @@ - -require 'has_many_polymorphs' diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs.rb deleted file mode 100644 index 03c600cc..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs.rb +++ /dev/null @@ -1,27 +0,0 @@ - -require 'active_record' - -RAILS_DEFAULT_LOGGER = nil unless defined? RAILS_DEFAULT_LOGGER - -require 'has_many_polymorphs/reflection' -require 'has_many_polymorphs/association' -require 'has_many_polymorphs/class_methods' - -require 'has_many_polymorphs/support_methods' -require 'has_many_polymorphs/base' - -class ActiveRecord::Base - extend ActiveRecord::Associations::PolymorphicClassMethods -end - -if ENV['HMP_DEBUG'] || ENV['RAILS_ENV'] =~ /development|test/ && ENV['USER'] == 'eweaver' - require 'has_many_polymorphs/debugging_tools' -end - -if defined? Rails and RAILS_ENV and RAILS_ROOT - _logger_warn "rails environment detected" - require 'has_many_polymorphs/configuration' - require 'has_many_polymorphs/autoload' -end - -_logger_debug "loaded ok" diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/association.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/association.rb deleted file mode 100644 index a2b2d81a..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/association.rb +++ /dev/null @@ -1,159 +0,0 @@ -module ActiveRecord #:nodoc: - module Associations #:nodoc: - - class PolymorphicError < ActiveRecordError #:nodoc: - end - - class PolymorphicMethodNotSupportedError < ActiveRecordError #:nodoc: - end - - # The association class for a has_many_polymorphs association. - class PolymorphicAssociation < HasManyThroughAssociation - - # Push a record onto the association. Triggers a database load for a uniqueness check only if :skip_duplicates is true. Return value is undefined. - def <<(*records) - return if records.empty? - - if @reflection.options[:skip_duplicates] - _logger_debug "Loading instances for polymorphic duplicate push check; use :skip_duplicates => false and perhaps a database constraint to avoid this possible performance issue" - load_target - end - - @reflection.klass.transaction do - flatten_deeper(records).each do |record| - if @owner.new_record? or not record.respond_to?(:new_record?) or record.new_record? - raise PolymorphicError, "You can't associate unsaved records." - end - next if @reflection.options[:skip_duplicates] and @target.include? record - @owner.send(@reflection.through_reflection.name).proxy_target << @reflection.klass.create!(construct_join_attributes(record)) - @target << record if loaded? - end - end - - self - end - - alias :push :<< - alias :concat :<< - - # Runs a find against the association contents, returning the matched records. All regular find options except :include are supported. - def find(*args) - opts = args._extract_options! - opts.delete :include - super(*(args + [opts])) - end - - def construct_scope - _logger_warn "Warning; not all usage scenarios for polymorphic scopes are supported yet." - super - end - - # Deletes a record from the association. Return value is undefined. - def delete(*records) - records = flatten_deeper(records) - records.reject! {|record| @target.delete(record) if record.new_record?} - return if records.empty? - - @reflection.klass.transaction do - records.each do |record| - joins = @reflection.through_reflection.name - @owner.send(joins).delete(@owner.send(joins).select do |join| - join.send(@reflection.options[:polymorphic_key]) == record.id and - join.send(@reflection.options[:polymorphic_type_key]) == "#{record.class.base_class}" - end) - @target.delete(record) - end - end - end - - # Clears all records from the association. Returns an empty array. - def clear(klass = nil) - load_target - return if @target.empty? - - if klass - delete(@target.select {|r| r.is_a? klass }) - else - @owner.send(@reflection.through_reflection.name).clear - @target.clear - end - [] - end - - protected - -# undef :sum -# undef :create! - - def construct_quoted_owner_attributes(*args) #:nodoc: - # no access to returning() here? why not? - type_key = @reflection.options[:foreign_type_key] - {@reflection.primary_key_name => @owner.id, - type_key=> (@owner.class.base_class.name if type_key)} - end - - def construct_from #:nodoc: - # build the FROM part of the query, in this case, the polymorphic join table - @reflection.klass.table_name - end - - def construct_owner #:nodoc: - # the table name for the owner object's class - @owner.class.table_name - end - - def construct_owner_key #:nodoc: - # the primary key field for the owner object - @owner.class.primary_key - end - - def construct_select(custom_select = nil) #:nodoc: - # build the select query - selected = custom_select || @reflection.options[:select] - end - - def construct_joins(custom_joins = nil) #:nodoc: - # build the string of default joins - "JOIN #{construct_owner} polymorphic_parent ON #{construct_from}.#{@reflection.options[:foreign_key]} = polymorphic_parent.#{construct_owner_key} " + - @reflection.options[:from].map do |plural| - klass = plural._as_class - "LEFT JOIN #{klass.table_name} ON #{construct_from}.#{@reflection.options[:polymorphic_key]} = #{klass.table_name}.#{klass.primary_key} AND #{construct_from}.#{@reflection.options[:polymorphic_type_key]} = #{@reflection.klass.quote_value(klass.base_class.name)}" - end.uniq.join(" ") + " #{custom_joins}" - end - - def construct_conditions #:nodoc: - # build the fully realized condition string - conditions = construct_quoted_owner_attributes.map do |field, value| - "#{construct_from}.#{field} = #{@reflection.klass.quote_value(value)}" if value - end - conditions << custom_conditions if custom_conditions - "(" + conditions.compact.join(') AND (') + ")" - end - - def custom_conditions #:nodoc: - # custom conditions... not as messy as has_many :through because our joins are a little smarter - if @reflection.options[:conditions] - "(" + interpolate_sql(@reflection.klass.send(:sanitize_sql, @reflection.options[:conditions])) + ")" - end - end - - alias :construct_owner_attributes :construct_quoted_owner_attributes - alias :conditions :custom_conditions # XXX possibly not necessary - alias :sql_conditions :custom_conditions # XXX ditto - - # construct attributes for join for a particular record - def construct_join_attributes(record) #:nodoc: - {@reflection.options[:polymorphic_key] => record.id, - @reflection.options[:polymorphic_type_key] => "#{record.class.base_class}", - @reflection.options[:foreign_key] => @owner.id}.merge(@reflection.options[:foreign_type_key] ? - {@reflection.options[:foreign_type_key] => "#{@owner.class.base_class}"} : {}) # for double-sided relationships - end - - def build(attrs = nil) #:nodoc: - raise PolymorphicMethodNotSupportedError, "You can't associate new records." - end - - end - - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/autoload.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/autoload.rb deleted file mode 100644 index f05c9dc8..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/autoload.rb +++ /dev/null @@ -1,69 +0,0 @@ -require 'initializer' unless defined? ::Rails::Initializer -require 'action_controller/dispatcher' unless defined? ::ActionController::Dispatcher - -module HasManyPolymorphs - -=begin rdoc -Searches for models that use has_many_polymorphs or acts_as_double_polymorphic_join and makes sure that they get loaded during app initialization. This ensures that helper methods are injected into the target classes. - -Note that you can override DEFAULT_OPTIONS via Rails::Configuration#has_many_polymorphs_options. For example, if you need an application extension to be required before has_many_polymorphs loads your models, add an after_initialize block in config/environment.rb that appends to the 'requirements' key: - Rails::Initializer.run do |config| - # your other configuration here - - config.after_initialize do - config.has_many_polymorphs_options['requirements'] << 'lib/my_extension' - end - end - -=end - - DEFAULT_OPTIONS = { - :file_pattern => "#{RAILS_ROOT}/app/models/**/*.rb", - :file_exclusions => ['svn', 'CVS', 'bzr'], - :methods => ['has_many_polymorphs', 'acts_as_double_polymorphic_join'], - :requirements => []} - - mattr_accessor :options - @@options = HashWithIndifferentAccess.new(DEFAULT_OPTIONS) - - # Dispatcher callback to load polymorphic relationships from the top down. - def self.autoload - - _logger_debug "autoload hook invoked" - - options[:requirements].each do |requirement| - _logger_warn "forcing requirement load of #{requirement}" - require requirement - end - - Dir.glob(options[:file_pattern]).each do |filename| - next if filename =~ /#{options[:file_exclusions].join("|")}/ - open filename do |file| - if file.grep(/#{options[:methods].join("|")}/).any? - begin - model = File.basename(filename)[0..-4].camelize - _logger_warn "preloading parent model #{model}" - model.constantize - rescue Object => e - _logger_warn "#{model} could not be preloaded: #{e.inspect}" - end - end - end - end - end - -end - -class Rails::Initializer #:nodoc: - # Make sure it gets loaded in the console, tests, and migrations - def after_initialize_with_autoload - after_initialize_without_autoload - HasManyPolymorphs.autoload - end - alias_method_chain :after_initialize, :autoload -end - -ActionController::Dispatcher.to_prepare(:has_many_polymorphs_autoload) do - # Make sure it gets loaded in the app - HasManyPolymorphs.autoload -end diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/base.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/base.rb deleted file mode 100644 index 9513039c..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/base.rb +++ /dev/null @@ -1,60 +0,0 @@ - -module ActiveRecord - class Base - - class << self - - # Interprets a polymorphic row from a unified SELECT, returning the appropriate ActiveRecord instance. Overrides ActiveRecord::Base.instantiate_without_callbacks. - def instantiate_with_polymorphic_checks(record) - if record['polymorphic_parent_class'] - reflection = record['polymorphic_parent_class'].constantize.reflect_on_association(record['polymorphic_association_id'].to_sym) -# _logger_debug "Instantiating a polymorphic row for #{record['polymorphic_parent_class']}.reflect_on_association(:#{record['polymorphic_association_id']})" - - # rewrite the record with the right column names - table_aliases = reflection.options[:table_aliases].dup - record = Hash[*table_aliases.keys.map {|key| [key, record[table_aliases[key]]] }.flatten] - - # find the real child class - klass = record["#{self.table_name}.#{reflection.options[:polymorphic_type_key]}"].constantize - if sti_klass = record["#{klass.table_name}.#{klass.inheritance_column}"] - klass = klass.class_eval do compute_type(sti_klass) end # in case of namespaced STI models - end - - # check that the join actually joined to something - unless (child_id = record["#{self.table_name}.#{reflection.options[:polymorphic_key]}"]) == record["#{klass.table_name}.#{klass.primary_key}"] - raise ActiveRecord::Associations::PolymorphicError, - "Referential integrity violation; child <#{klass.name}:#{child_id}> was not found for #{reflection.name.inspect}" - end - - # eject the join keys - # XXX not very readable - record = Hash[*record._select do |column, value| - column[/^#{klass.table_name}/] - end.map do |column, value| - [column[/\.(.*)/, 1], value] - end.flatten] - - # allocate and assign values - returning(klass.allocate) do |obj| - obj.instance_variable_set("@attributes", record) - obj.instance_variable_set("@attributes_cache", Hash.new) - - if obj.respond_to_without_attributes?(:after_find) - obj.send(:callback, :after_find) - end - - if obj.respond_to_without_attributes?(:after_initialize) - obj.send(:callback, :after_initialize) - end - - end - else - instantiate_without_polymorphic_checks(record) - end - end - - alias_method_chain :instantiate, :polymorphic_checks - end - - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/class_methods.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/class_methods.rb deleted file mode 100644 index 536a49d4..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/class_methods.rb +++ /dev/null @@ -1,600 +0,0 @@ - -module ActiveRecord #:nodoc: - module Associations #:nodoc: - -=begin rdoc - -Class methods added to ActiveRecord::Base for setting up polymorphic associations. - -== Notes - -STI association targets must enumerated and named. For example, if Dog and Cat both inherit from Animal, you still need to say [:dogs, :cats], and not [:animals]. - -Namespaced models follow the Rails underscore convention. ZooAnimal::Lion becomes :'zoo_animal/lion'. - -You do not need to set up any other associations other than for either the regular method or the double. The join associations and all individual and reverse associations are generated for you. However, a join model and table are required. - -There is a tentative report that you can make the parent model be its own join model, but this is untested. - -=end - - module PolymorphicClassMethods - - RESERVED_DOUBLES_KEYS = [:conditions, :order, :limit, :offset, :extend, :skip_duplicates, - :join_extend, :dependent, :rename_individual_collections, - :namespace] #:nodoc: - -=begin rdoc - -This method creates a doubled-sided polymorphic relationship. It must be called on the join model: - - class Devouring < ActiveRecord::Base - belongs_to :eater, :polymorphic => true - belongs_to :eaten, :polymorphic => true - - acts_as_double_polymorphic_join( - :eaters => [:dogs, :cats], - :eatens => [:cats, :birds] - ) - end - -The method works by defining one or more special has_many_polymorphs association on every model in the target lists, depending on which side of the association it is on. Double self-references will work. - -The two association names and their value arrays are the only required parameters. - -== Available options - -These options are passed through to targets on both sides of the association. If you want to affect only one side, prepend the key with the name of that side. For example, :eaters_extend. - -:dependent:: Accepts :destroy, :nullify, or :delete_all. Controls how the join record gets treated on any association delete (whether from the polymorph or from an individual collection); defaults to :destroy. -:skip_duplicates:: If true, will check to avoid pushing already associated records (but also triggering a database load). Defaults to true. -:rename_individual_collections:: If true, all individual collections are prepended with the polymorph name, and the children's parent collection is appended with "\_of_#{association_name}". -:extend:: One or an array of mixed modules and procs, which are applied to the polymorphic association (usually to define custom methods). -:join_extend:: One or an array of mixed modules and procs, which are applied to the join association. -:conditions:: An array or string of conditions for the SQL WHERE clause. -:order:: A string for the SQL ORDER BY clause. -:limit:: An integer. Affects the polymorphic and individual associations. -:offset:: An integer. Only affects the polymorphic association. -:namespace:: A symbol. Prepended to all the models in the :from and :through keys. This is especially useful for Camping, which namespaces models by default. - -=end - - def acts_as_double_polymorphic_join options={}, &extension - - collections, options = extract_double_collections(options) - - # handle the block - options[:extend] = (if options[:extend] - Array(options[:extend]) + [extension] - else - extension - end) if extension - - collection_option_keys = make_general_option_keys_specific!(options, collections) - - join_name = self.name.tableize.to_sym - collections.each do |association_id, children| - parent_hash_key = (collections.keys - [association_id]).first # parents are the entries in the _other_ children array - - begin - parent_foreign_key = self.reflect_on_association(parent_hash_key._singularize).primary_key_name - rescue NoMethodError - raise PolymorphicError, "Couldn't find 'belongs_to' association for :#{parent_hash_key._singularize} in #{self.name}." unless parent_foreign_key - end - - parents = collections[parent_hash_key] - conflicts = (children & parents) # set intersection - parents.each do |plural_parent_name| - - parent_class = plural_parent_name._as_class - singular_reverse_association_id = parent_hash_key._singularize - - internal_options = { - :is_double => true, - :from => children, - :as => singular_reverse_association_id, - :through => join_name.to_sym, - :foreign_key => parent_foreign_key, - :foreign_type_key => parent_foreign_key.to_s.sub(/_id$/, '_type'), - :singular_reverse_association_id => singular_reverse_association_id, - :conflicts => conflicts - } - - general_options = Hash[*options._select do |key, value| - collection_option_keys[association_id].include? key and !value.nil? - end.map do |key, value| - [key.to_s[association_id.to_s.length+1..-1].to_sym, value] - end._flatten_once] # rename side-specific options to general names - - general_options.each do |key, value| - # avoid clobbering keys that appear in both option sets - if internal_options[key] - general_options[key] = Array(value) + Array(internal_options[key]) - end - end - - parent_class.send(:has_many_polymorphs, association_id, internal_options.merge(general_options)) - - if conflicts.include? plural_parent_name - # unify the alternate sides of the conflicting children - (conflicts).each do |method_name| - unless parent_class.instance_methods.include?(method_name) - parent_class.send(:define_method, method_name) do - (self.send("#{singular_reverse_association_id}_#{method_name}") + - self.send("#{association_id._singularize}_#{method_name}")).freeze - end - end - end - - # unify the join model... join model is always renamed for doubles, unlike child associations - unless parent_class.instance_methods.include?(join_name) - parent_class.send(:define_method, join_name) do - (self.send("#{join_name}_as_#{singular_reverse_association_id}") + - self.send("#{join_name}_as_#{association_id._singularize}")).freeze - end - end - else - unless parent_class.instance_methods.include?(join_name) - parent_class.send(:alias_method, join_name, "#{join_name}_as_#{singular_reverse_association_id}") - end - end - - end - end - end - - private - - def extract_double_collections(options) - collections = options._select do |key, value| - value.is_a? Array and key.to_s !~ /(#{RESERVED_DOUBLES_KEYS.map(&:to_s).join('|')})$/ - end - - raise PolymorphicError, "Couldn't understand options in acts_as_double_polymorphic_join. Valid parameters are your two class collections, and then #{RESERVED_DOUBLES_KEYS.inspect[1..-2]}, with optionally your collection names prepended and joined with an underscore." unless collections.size == 2 - - options = options._select do |key, value| - !collections[key] - end - - [collections, options] - end - - def make_general_option_keys_specific!(options, collections) - collection_option_keys = Hash[*collections.keys.map do |key| - [key, RESERVED_DOUBLES_KEYS.map{|option| "#{key}_#{option}".to_sym}] - end._flatten_once] - - collections.keys.each do |collection| - options.each do |key, value| - next if collection_option_keys.values.flatten.include? key - # shift the general options to the individual sides - collection_key = "#{collection}_#{key}".to_sym - collection_value = options[collection_key] - case key - when :conditions - collection_value, value = sanitize_sql(collection_value), sanitize_sql(value) - options[collection_key] = (collection_value ? "(#{collection_value}) AND (#{value})" : value) - when :order - options[collection_key] = (collection_value ? "#{collection_value}, #{value}" : value) - when :extend, :join_extend - options[collection_key] = Array(collection_value) + Array(value) - else - options[collection_key] ||= value - end - end - end - - collection_option_keys - end - - - - public - -=begin rdoc - -This method createds a single-sided polymorphic relationship. - - class Petfood < ActiveRecord::Base - has_many_polymorphs :eaters, :from => [:dogs, :cats, :birds] - end - -The only required parameter, aside from the association name, is :from. - -The method generates a number of associations aside from the polymorphic one. In this example Petfood also gets dogs, cats, and birds, and Dog, Cat, and Bird get petfoods. (The reverse association to the parents is always plural.) - -== Available options - -:from:: An array of symbols representing the target models. Required. -:as:: A symbol for the parent's interface in the join--what the parent 'acts as'. -:through:: A symbol representing the class of the join model. Follows Rails defaults if not supplied (the parent and the association names, alphabetized, concatenated with an underscore, and singularized). -:dependent:: Accepts :destroy, :nullify, :delete_all. Controls how the join record gets treated on any associate delete (whether from the polymorph or from an individual collection); defaults to :destroy. -:skip_duplicates:: If true, will check to avoid pushing already associated records (but also triggering a database load). Defaults to true. -:rename_individual_collections:: If true, all individual collections are prepended with the polymorph name, and the children's parent collection is appended with "_of_#{association_name}". For example, zoos becomes zoos_of_animals. This is to help avoid method name collisions in crowded classes. -:extend:: One or an array of mixed modules and procs, which are applied to the polymorphic association (usually to define custom methods). -:join_extend:: One or an array of mixed modules and procs, which are applied to the join association. -:parent_extend:: One or an array of mixed modules and procs, which are applied to the target models' association to the parents. -:conditions:: An array or string of conditions for the SQL WHERE clause. -:parent_conditions:: An array or string of conditions which are applied to the target models' association to the parents. -:order:: A string for the SQL ORDER BY clause. -:parent_order:: A string for the SQL ORDER BY which is applied to the target models' association to the parents. -:group:: An array or string of conditions for the SQL GROUP BY clause. Affects the polymorphic and individual associations. -:limit:: An integer. Affects the polymorphic and individual associations. -:offset:: An integer. Only affects the polymorphic association. -:namespace:: A symbol. Prepended to all the models in the :from and :through keys. This is especially useful for Camping, which namespaces models by default. -:uniq:: If true, the records returned are passed through a pure-Ruby uniq before they are returned. Rarely needed. -:foreign_key:: The column name for the parent's id in the join. -:foreign_type_key:: The column name for the parent's class name in the join, if the parent itself is polymorphic. Rarely needed--if you're thinking about using this, you almost certainly want to use acts_as_double_polymorphic_join() instead. -:polymorphic_key:: The column name for the child's id in the join. -:polymorphic_type_key:: The column name for the child's class name in the join. - -If you pass a block, it gets converted to a Proc and added to :extend. - -== On condition nullification - -When you request an individual association, non-applicable but fully-qualified fields in the polymorphic association's :conditions, :order, and :group options get changed to NULL. For example, if you set :conditions => "dogs.name != 'Spot'", when you request .cats, the conditions string is changed to NULL != 'Spot'. - -Be aware, however, that NULL != 'Spot' returns false due to SQL's 3-value logic. Instead, you need to use the :conditions string "dogs.name IS NULL OR dogs.name != 'Spot'" to get the behavior you probably expect for negative matches. - -=end - - def has_many_polymorphs (association_id, options = {}, &extension) - _logger_debug "associating #{self}.#{association_id}" - reflection = create_has_many_polymorphs_reflection(association_id, options, &extension) - # puts "Created reflection #{reflection.inspect}" - # configure_dependency_for_has_many(reflection) - collection_reader_method(reflection, PolymorphicAssociation) - end - - # Composed method that assigns option defaults, builds the reflection object, and sets up all the related associations on the parent, join, and targets. - def create_has_many_polymorphs_reflection(association_id, options, &extension) #:nodoc: - options.assert_valid_keys( - :from, - :as, - :through, - :foreign_key, - :foreign_type_key, - :polymorphic_key, # same as :association_foreign_key - :polymorphic_type_key, - :dependent, # default :destroy, only affects the join table - :skip_duplicates, # default true, only affects the polymorphic collection - :ignore_duplicates, # deprecated - :is_double, - :rename_individual_collections, - :reverse_association_id, # not used - :singular_reverse_association_id, - :conflicts, - :extend, - :join_class_name, - :join_extend, - :parent_extend, - :table_aliases, - :select, # applies to the polymorphic relationship - :conditions, # applies to the polymorphic relationship, the children, and the join - # :include, - :parent_conditions, - :parent_order, - :order, # applies to the polymorphic relationship, the children, and the join - :group, # only applies to the polymorphic relationship and the children - :limit, # only applies to the polymorphic relationship and the children - :offset, # only applies to the polymorphic relationship - :parent_order, - :parent_group, - :parent_limit, - :parent_offset, - # :source, - :namespace, - :uniq, # XXX untested, only applies to the polymorphic relationship - # :finder_sql, - # :counter_sql, - # :before_add, - # :after_add, - # :before_remove, - # :after_remove - :dummy) - - # validate against the most frequent configuration mistakes - verify_pluralization_of(association_id) - raise PolymorphicError, ":from option must be an array" unless options[:from].is_a? Array - options[:from].each{|plural| verify_pluralization_of(plural)} - - options[:as] ||= self.name.demodulize.underscore.to_sym - options[:conflicts] = Array(options[:conflicts]) - options[:foreign_key] ||= "#{options[:as]}_id" - - options[:association_foreign_key] = - options[:polymorphic_key] ||= "#{association_id._singularize}_id" - options[:polymorphic_type_key] ||= "#{association_id._singularize}_type" - - if options.has_key? :ignore_duplicates - _logger_warn "DEPRECATION WARNING: please use :skip_duplicates instead of :ignore_duplicates" - options[:skip_duplicates] = options[:ignore_duplicates] - end - options[:skip_duplicates] = true unless options.has_key? :skip_duplicates - options[:dependent] = :destroy unless options.has_key? :dependent - options[:conditions] = sanitize_sql(options[:conditions]) - - # options[:finder_sql] ||= "(options[:polymorphic_key] - - options[:through] ||= build_join_table_symbol(association_id, (options[:as]._pluralize or self.table_name)) - - # set up namespaces if we have a namespace key - # XXX needs test coverage - if options[:namespace] - namespace = options[:namespace].to_s.chomp("/") + "/" - options[:from].map! do |child| - "#{namespace}#{child}".to_sym - end - options[:through] = "#{namespace}#{options[:through]}".to_sym - end - - options[:join_class_name] ||= options[:through]._classify - options[:table_aliases] ||= build_table_aliases([options[:through]] + options[:from]) - options[:select] ||= build_select(association_id, options[:table_aliases]) - - options[:through] = "#{options[:through]}_as_#{options[:singular_reverse_association_id]}" if options[:singular_reverse_association_id] - options[:through] = demodulate(options[:through]).to_sym - - options[:extend] = spiked_create_extension_module(association_id, Array(options[:extend]) + Array(extension)) - options[:join_extend] = spiked_create_extension_module(association_id, Array(options[:join_extend]), "Join") - options[:parent_extend] = spiked_create_extension_module(association_id, Array(options[:parent_extend]), "Parent") - - # create the reflection object - create_reflection(:has_many_polymorphs, association_id, options, self).tap do |reflection| - # set up the other related associations - create_join_association(association_id, reflection) - create_has_many_through_associations_for_parent_to_children(association_id, reflection) - create_has_many_through_associations_for_children_to_parent(association_id, reflection) - end - end - - private - - - # table mapping for use at the instantiation point - - def build_table_aliases(from) - # for the targets - {}.tap do |aliases| - from.map(&:to_s).sort.map(&:to_sym).each_with_index do |plural, t_index| - begin - table = plural._as_class.table_name - rescue NameError => e - raise PolymorphicError, "Could not find a valid class for #{plural.inspect} (tried #{plural.to_s._classify}). If it's namespaced, be sure to specify it as :\"module/#{plural}\" instead." - end - begin - plural._as_class.columns.map(&:name).each_with_index do |field, f_index| - aliases["#{table}.#{field}"] = "t#{t_index}_r#{f_index}" - end - rescue ActiveRecord::StatementInvalid => e - _logger_warn "Looks like your table doesn't exist for #{plural.to_s._classify}.\nError #{e}\nSkipping..." - end - end - end - end - - def build_select(association_id, aliases) - # instantiate has to know which reflection the results are coming from - (["\'#{self.name}\' AS polymorphic_parent_class", - "\'#{association_id}\' AS polymorphic_association_id"] + - aliases.map do |table, _alias| - "#{table} AS #{_alias}" - end.sort).join(", ") - end - - # method sub-builders - - def create_join_association(association_id, reflection) - - options = { - :foreign_key => reflection.options[:foreign_key], - :dependent => reflection.options[:dependent], - :class_name => reflection.klass.name, - :extend => reflection.options[:join_extend] - # :limit => reflection.options[:limit], - # :offset => reflection.options[:offset], - # :order => devolve(association_id, reflection, reflection.options[:order], reflection.klass, true), - # :conditions => devolve(association_id, reflection, reflection.options[:conditions], reflection.klass, true) - } - - if reflection.options[:foreign_type_key] - type_check = "#{reflection.options[:foreign_type_key]} = #{quote_value(self.base_class.name)}" - conjunction = options[:conditions] ? " AND " : nil - options[:conditions] = "#{options[:conditions]}#{conjunction}#{type_check}" - options[:as] = reflection.options[:as] - end - - has_many(reflection.options[:through], options) - - inject_before_save_into_join_table(association_id, reflection) - end - - def inject_before_save_into_join_table(association_id, reflection) - sti_hook = "sti_class_rewrite" - rewrite_procedure = %[self.send(:#{reflection.options[:polymorphic_type_key]}=, self.#{reflection.options[:polymorphic_type_key]}.constantize.base_class.name)] - - # XXX should be abstracted? - reflection.klass.class_eval %[ - unless instance_methods.include? "before_save_with_#{sti_hook}" - if instance_methods.include? "before_save" - alias_method :before_save_without_#{sti_hook}, :before_save - def before_save_with_#{sti_hook} - before_save_without_#{sti_hook} - #{rewrite_procedure} - end - else - def before_save_with_#{sti_hook} - #{rewrite_procedure} - end - end - alias_method :before_save, :before_save_with_#{sti_hook} - end - ] - end - - def create_has_many_through_associations_for_children_to_parent(association_id, reflection) - - child_pluralization_map(association_id, reflection).each do |plural, singular| - if singular == reflection.options[:as] - raise PolymorphicError, if reflection.options[:is_double] - "You can't give either of the sides in a double-polymorphic join the same name as any of the individual target classes." - else - "You can't have a self-referential polymorphic has_many :through without renaming the non-polymorphic foreign key in the join model." - end - end - - parent = self - plural._as_class.instance_eval do - # this shouldn't be called at all during doubles; there is no way to traverse to a double polymorphic parent (XXX is that right?) - unless reflection.options[:is_double] or reflection.options[:conflicts].include? self.name.tableize.to_sym - - # the join table - through = "#{reflection.options[:through]}#{'_as_child' if parent == self}".to_sym - has_many(through, - :as => association_id._singularize, -# :source => association_id._singularize, -# :source_type => reflection.options[:polymorphic_type_key], - :class_name => reflection.klass.name, - :dependent => reflection.options[:dependent], - :extend => reflection.options[:join_extend], - # :limit => reflection.options[:limit], - # :offset => reflection.options[:offset], - :order => devolve(association_id, reflection, reflection.options[:parent_order], reflection.klass), - :conditions => devolve(association_id, reflection, reflection.options[:parent_conditions], reflection.klass) - ) - - # the association to the target's parents - association = "#{reflection.options[:as]._pluralize}#{"_of_#{association_id}" if reflection.options[:rename_individual_collections]}".to_sym - has_many(association, - :through => through, - :class_name => parent.name, - :source => reflection.options[:as], - :foreign_key => reflection.options[:foreign_key], - :extend => reflection.options[:parent_extend], - :conditions => reflection.options[:parent_conditions], - :order => reflection.options[:parent_order], - :offset => reflection.options[:parent_offset], - :limit => reflection.options[:parent_limit], - :group => reflection.options[:parent_group]) - -# debugger if association == :parents -# -# nil - - end - end - end - end - - def create_has_many_through_associations_for_parent_to_children(association_id, reflection) - child_pluralization_map(association_id, reflection).each do |plural, singular| - #puts ":source => #{child}" - current_association = demodulate(child_association_map(association_id, reflection)[plural]) - source = demodulate(singular) - - if reflection.options[:conflicts].include? plural - # XXX check this - current_association = "#{association_id._singularize}_#{current_association}" if reflection.options[:conflicts].include? self.name.tableize.to_sym - source = "#{source}_as_#{association_id._singularize}".to_sym - end - - # make push/delete accessible from the individual collections but still operate via the general collection - extension_module = self.class_eval %[ - module #{self.name + current_association._classify + "PolymorphicChildAssociationExtension"} - def push *args; proxy_owner.send(:#{association_id}).send(:push, *args); self; end - alias :<< :push - def delete *args; proxy_owner.send(:#{association_id}).send(:delete, *args); end - def clear; proxy_owner.send(:#{association_id}).send(:clear, #{singular._classify}); end - self - end] - - has_many(current_association.to_sym, - :through => reflection.options[:through], - :source => association_id._singularize, - :source_type => plural._as_class.base_class.name, - :class_name => plural._as_class.name, # make STI not conflate subtypes - :extend => (Array(extension_module) + reflection.options[:extend]), - :limit => reflection.options[:limit], - # :offset => reflection.options[:offset], - :order => devolve(association_id, reflection, reflection.options[:order], plural._as_class), - :conditions => devolve(association_id, reflection, reflection.options[:conditions], plural._as_class), - :group => devolve(association_id, reflection, reflection.options[:group], plural._as_class) - ) - - end - end - - # some support methods - - def child_pluralization_map(association_id, reflection) - Hash[*reflection.options[:from].map do |plural| - [plural, plural._singularize] - end.flatten] - end - - def child_association_map(association_id, reflection) - Hash[*reflection.options[:from].map do |plural| - [plural, "#{association_id._singularize.to_s + "_" if reflection.options[:rename_individual_collections]}#{plural}".to_sym] - end.flatten] - end - - def demodulate(s) - s.to_s.gsub('/', '_').to_sym - end - - def build_join_table_symbol(association_id, name) - [name.to_s, association_id.to_s].sort.join("_").to_sym - end - - def all_classes_for(association_id, reflection) - klasses = [self, reflection.klass, *child_pluralization_map(association_id, reflection).keys.map(&:_as_class)] - klasses += klasses.map(&:base_class) - klasses.uniq - end - - def devolve(association_id, reflection, string, klass, remove_inappropriate_clauses = false) - # XXX remove_inappropriate_clauses is not implemented; we'll wait until someone actually needs it - return unless string - string = string.dup - # _logger_debug "devolving #{string} for #{klass}" - inappropriate_classes = (all_classes_for(association_id, reflection) - # the join class must always be preserved - [klass, klass.base_class, reflection.klass, reflection.klass.base_class]) - inappropriate_classes.map do |klass| - klass.columns.map do |column| - [klass.table_name, column.name] - end.map do |table, column| - ["#{table}.#{column}", "`#{table}`.#{column}", "#{table}.`#{column}`", "`#{table}`.`#{column}`"] - end - end.flatten.sort_by(&:size).reverse.each do |quoted_reference| - # _logger_debug "devolved #{quoted_reference} to NULL" - # XXX clause removal would go here - string.gsub!(quoted_reference, "NULL") - end - # _logger_debug "altered to #{string}" - string - end - - def verify_pluralization_of(sym) - sym = sym.to_s - singular = sym.singularize - plural = singular.pluralize - raise PolymorphicError, "Pluralization rules not set up correctly. You passed :#{sym}, which singularizes to :#{singular}, but that pluralizes to :#{plural}, which is different. Maybe you meant :#{plural} to begin with?" unless sym == plural - end - - def spiked_create_extension_module(association_id, extensions, identifier = nil) - module_extensions = extensions.select{|e| e.is_a? Module} - proc_extensions = extensions.select{|e| e.is_a? Proc } - - # support namespaced anonymous blocks as well as multiple procs - proc_extensions.each_with_index do |proc_extension, index| - module_name = "#{self.to_s}#{association_id._classify}Polymorphic#{identifier}AssociationExtension#{index}" - the_module = self.class_eval "module #{module_name}; self; end" # XXX hrm - the_module.class_eval &proc_extension - module_extensions << the_module - end - module_extensions - end - - end - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/configuration.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/configuration.rb deleted file mode 100644 index 9de21617..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/configuration.rb +++ /dev/null @@ -1,19 +0,0 @@ - -=begin rdoc -Access the has_many_polymorphs_options hash in your Rails::Initializer.run#after_initialize block if you need to modify the behavior of Rails::Initializer::HasManyPolymorphsAutoload. -=end - -module Rails #:nodoc: - class Configuration - - def has_many_polymorphs_options - ::HasManyPolymorphs.options - end - - def has_many_polymorphs_options=(hash) - ::HasManyPolymorphs.options = HashWithIndifferentAccess.new(hash) - end - - end -end - diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/debugging_tools.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/debugging_tools.rb deleted file mode 100644 index 22c9af38..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/debugging_tools.rb +++ /dev/null @@ -1,103 +0,0 @@ - -=begin rdoc - -Debugging tools for Has_many_polymorphs. - -Enable the different tools by setting the environment variable HMP_DEBUG. Settings with special meaning are "ruby-debug", "trace", and "dependencies". - -== Code generation - -Enabled by default when HMP_DEBUG is set. - -Ouputs a folder generated_models/ in RAILS_ROOT containing valid Ruby files explaining all the ActiveRecord relationships set up by the plugin, as well as listing the line in the plugin that called each particular association method. - -== Ruby-debug - -Enable by setting HMP_DEBUG to "ruby-debug". - -Starts ruby-debug for the life of the process. - -== Trace - -Enable by setting HMP_DEBUG to "ruby-debug". - -Outputs an indented trace of relevant method calls as they occur. - -== Dependencies - -Enable by setting HMP_DEBUG to "dependencies". - -Turns on Rails' default dependency logging. - -=end - -_logger_warn "debug mode enabled" - -class << ActiveRecord::Base - COLLECTION_METHODS = [:belongs_to, :has_many, :has_and_belongs_to_many, :has_one, - :has_many_polymorphs, :acts_as_double_polymorphic_join].each do |method_name| - alias_method "original_#{method_name}".to_sym, method_name - undef_method method_name - end - - unless defined? GENERATED_CODE_DIR - GENERATED_CODE_DIR = "#{RAILS_ROOT}/generated_models" - - begin - system "rm -rf #{GENERATED_CODE_DIR}" - Dir.mkdir GENERATED_CODE_DIR - rescue Errno::EACCES - _logger_warn "no permissions for generated code dir: #{GENERATED_CODE_DIR}" - end - - if File.exist? GENERATED_CODE_DIR - alias :original_method_missing :method_missing - def method_missing(method_name, *args, &block) - if COLLECTION_METHODS.include? method_name.to_sym - Dir.chdir GENERATED_CODE_DIR do - filename = "#{demodulate(self.name.underscore)}.rb" - contents = File.open(filename).read rescue "\nclass #{self.name}\n\nend\n" - line = caller[1][/\:(\d+)\:/, 1] - contents[-5..-5] = "\n #{method_name} #{args[0..-2].inspect[1..-2]},\n #{args[-1].inspect[1..-2].gsub(" :", "\n :").gsub("=>", " => ")}\n#{ block ? " #{block.inspect.sub(/\@.*\//, '@')}\n" : ""} # called from line #{line}\n\n" - File.open(filename, "w") do |file| - file.puts contents - end - end - # doesn't actually display block contents - self.send("original_#{method_name}", *args, &block) - else - self.send(:original_method_missing, method_name, *args, &block) - end - end - end - - end -end - -case ENV['HMP_DEBUG'] - - when "ruby-debug" - require 'rubygems' - require 'ruby-debug' - Debugger.start - _logger_warn "ruby-debug enabled." - - when "trace" - _logger_warn "method tracing enabled" - $debug_trace_indent = 0 - set_trace_func (proc do |event, file, line, id, binding, classname| - if id.to_s =~ /instantiate/ #/IRB|Wirble|RubyLex|RubyToken|Logger|ConnectionAdapters|SQLite3|MonitorMixin|Benchmark|Inflector|Inflections/ - if event == 'call' - puts (" " * $debug_trace_indent) + "#{event}ed #{classname}\##{id} from #{file.split('/').last}::#{line}" - $debug_trace_indent += 1 - elsif event == 'return' - $debug_trace_indent -= 1 unless $debug_trace_indent == 0 - puts (" " * $debug_trace_indent) + "#{event}ed #{classname}\##{id}" - end - end - end) - - when "dependencies" - _logger_warn "dependency activity being logged" - (::Dependencies.log_activity = true) rescue nil -end diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/rake_task_redefine_task.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/rake_task_redefine_task.rb deleted file mode 100644 index 217d2590..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/rake_task_redefine_task.rb +++ /dev/null @@ -1,35 +0,0 @@ - -# Redefine instead of chain a Rake task -# http://www.bigbold.com/snippets/posts/show/2032 - -module Rake - module TaskManager - def redefine_task(task_class, args, &block) - task_name, deps = resolve_args(args) - task_name = task_class.scope_name(@scope, task_name) - deps = [deps] unless deps.respond_to?(:to_ary) - deps = deps.collect {|d| d.to_s } - task = @tasks[task_name.to_s] = task_class.new(task_name, self) - task.application = self - task.add_comment(@last_comment) - @last_comment = nil - task.enhance(deps, &block) - task - end - end - class Task - class << self - def redefine_task(args, &block) - Rake.application.redefine_task(self, args, &block) - end - end - end -end - -class Object - def silently - stderr, stdout, $stderr, $stdout = $stderr, $stdout, StringIO.new, StringIO.new - yield - $stderr, $stdout = stderr, stdout - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/reflection.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/reflection.rb deleted file mode 100644 index 0091397d..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/reflection.rb +++ /dev/null @@ -1,58 +0,0 @@ -module ActiveRecord #:nodoc: - module Reflection #:nodoc: - - module ClassMethods #:nodoc: - - # Update the default reflection switch so that :has_many_polymorphs types get instantiated. - # It's not a composed method so we have to override the whole thing. - def create_reflection(macro, name, options, active_record) - case macro - when :has_many, :belongs_to, :has_one, :has_and_belongs_to_many - klass = options[:through] ? ThroughReflection : AssociationReflection - reflection = klass.new(macro, name, options, active_record) - when :composed_of - reflection = AggregateReflection.new(macro, name, options, active_record) - # added by has_many_polymorphs # - when :has_many_polymorphs - reflection = PolymorphicReflection.new(macro, name, options, active_record) - end - write_inheritable_hash :reflections, name => reflection - reflection - end - - end - - class PolymorphicError < ActiveRecordError #:nodoc: - end - -=begin rdoc - -The reflection built by the has_many_polymorphs method. - -Inherits from ActiveRecord::Reflection::AssociationReflection. - -=end - - class PolymorphicReflection < ThroughReflection - # Stub out the validity check. Has_many_polymorphs checks validity on macro creation, not on reflection. - def check_validity! - # nothing - end - - # Return the source reflection. - def source_reflection - # normally is the has_many to the through model, but we return ourselves, - # since there isn't a real source class for a polymorphic target - self - end - - # Set the classname of the target. Uses the join class name. - def class_name - # normally is the classname of the association target - @class_name ||= options[:join_class_name] - end - - end - - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/support_methods.rb b/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/support_methods.rb deleted file mode 100644 index 89ca52a4..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/lib/has_many_polymorphs/support_methods.rb +++ /dev/null @@ -1,84 +0,0 @@ - -class String - - # Changes an underscored string into a class reference. - def _as_class - # classify expects self to be plural - self.classify.constantize - end - - # For compatibility with the Symbol extensions. - alias :_singularize :singularize - alias :_pluralize :pluralize - alias :_classify :classify -end - -class Symbol - - # Changes an underscored symbol into a class reference. - def _as_class; self.to_s._as_class; end - - # Changes a plural symbol into a singular symbol. - def _singularize; self.to_s.singularize.to_sym; end - - # Changes a singular symbol into a plural symbol. - def _pluralize; self.to_s.pluralize.to_sym; end - - # Changes a symbol into a class name string. - def _classify; self.to_s.classify; end -end - -class Array - - # Flattens the first level of self. - def _flatten_once - self.inject([]){|r, el| r + Array(el)} - end - - # Rails 1.2.3 compatibility method. Copied from http://dev.rubyonrails.org/browser/trunk/activesupport/lib/active_support/core_ext/array/extract_options.rb?rev=7217 - def _extract_options! - last.is_a?(::Hash) ? pop : {} - end -end - -class Hash - - # An implementation of select that returns a Hash. - def _select - Hash[*self.select do |key, value| - yield key, value - end._flatten_once] - end -end - -class Object - - # Returns the metaclass of self. - def _metaclass; (class << self; self; end); end - - # Logger shortcut. - def _logger_debug s - s = "** has_many_polymorphs: #{s}" - RAILS_DEFAULT_LOGGER.debug(s) if RAILS_DEFAULT_LOGGER - end - - # Logger shortcut. - def _logger_warn s - s = "** has_many_polymorphs: #{s}" - if RAILS_DEFAULT_LOGGER - RAILS_DEFAULT_LOGGER.warn(s) - else - $stderr.puts(s) - end - end - -end - -class ActiveRecord::Base - - # Return the base class name as a string. - def _base_class_name - self.class.base_class.name.to_s - end - -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/bow_wows.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/bow_wows.yml deleted file mode 100644 index 00be9d88..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/bow_wows.yml +++ /dev/null @@ -1,10 +0,0 @@ -rover: - id: 1 - name: Rover - created_at: "2007-01-01 12:00:00" - updated_at: "2007-01-04 10:00:00" -spot: - id: 2 - name: Spot - created_at: "2007-01-02 12:00:00" - updated_at: "2007-01-03 10:00:00" diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/cats.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/cats.yml deleted file mode 100644 index aed894f9..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/cats.yml +++ /dev/null @@ -1,18 +0,0 @@ -chloe: - id: 1 - cat_type: Kitten - name: Chloe - created_at: "2007-04-01 12:00:00" - updated_at: "2007-04-04 10:00:00" -alice: - id: 2 - cat_type: Kitten - name: Alice - created_at: "2007-04-02 12:00:00" - updated_at: "2007-04-03 10:00:00" -toby: - id: 3 - cat_type: Tabby - name: Toby - created_at: "2007-04-02 12:00:00" - updated_at: "2007-04-03 10:00:00" diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/eaters_foodstuffs.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/eaters_foodstuffs.yml deleted file mode 100644 index e69de29b..00000000 diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/fish.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/fish.yml deleted file mode 100644 index 3974a672..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/fish.yml +++ /dev/null @@ -1,12 +0,0 @@ -swimmy: - id: 1 - name: Swimmy - speed: 10 - created_at: "2007-02-01 12:00:00" - updated_at: "2007-02-04 10:00:00" -jaws: - id: 2 - name: Jaws - speed: 20 - created_at: "2007-02-02 12:00:00" - updated_at: "2007-02-03 10:00:00" diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/frogs.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/frogs.yml deleted file mode 100644 index e9d37d7c..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/frogs.yml +++ /dev/null @@ -1,5 +0,0 @@ -froggy: - id: 1 - name: Froggy - created_at: "2007-05-01 12:00:00" - updated_at: "2007-05-04 10:00:00" diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/keep_your_enemies_close.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/keep_your_enemies_close.yml deleted file mode 100644 index e69de29b..00000000 diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/little_whale_pupils.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/little_whale_pupils.yml deleted file mode 100644 index e69de29b..00000000 diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/people.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/people.yml deleted file mode 100644 index 085d2172..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/people.yml +++ /dev/null @@ -1,7 +0,0 @@ -bob: - id: 1 - name: Bob - age: 45 - created_at: "2007-04-01 12:00:00" - updated_at: "2007-04-04 10:00:00" - \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/petfoods.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/petfoods.yml deleted file mode 100644 index a117d294..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/petfoods.yml +++ /dev/null @@ -1,11 +0,0 @@ -kibbles: - the_petfood_primary_key: 1 - name: Kibbles - created_at: "2007-06-01 12:00:00" - updated_at: "2007-06-04 10:00:00" -bits: - the_petfood_primary_key: 2 - name: Bits - created_at: "2007-06-02 12:00:00" - updated_at: "2007-06-03 10:00:00" - \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/whales.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/whales.yml deleted file mode 100644 index bded734e..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/whales.yml +++ /dev/null @@ -1,5 +0,0 @@ -shamu: - id: 1 - name: Shamu - created_at: "2007-03-01 12:00:00" - updated_at: "2007-03-04 10:00:00" diff --git a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/wild_boars.yml b/vendor/gems/has_many_polymorphs-2.13/test/fixtures/wild_boars.yml deleted file mode 100644 index 73fd3e2e..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/fixtures/wild_boars.yml +++ /dev/null @@ -1,10 +0,0 @@ -puma: - id: 1 - name: Puma - created_at: "2007-07-01 12:00:00" - updated_at: "2007-07-04 10:00:00" -jacrazy: - id: 2 - name: Jacrazy - created_at: "2007-07-02 12:00:00" - updated_at: "2007-07-03 10:00:00" diff --git a/vendor/gems/has_many_polymorphs-2.13/test/generator/tagging_generator_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/generator/tagging_generator_test.rb deleted file mode 100644 index 34e20c4f..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/generator/tagging_generator_test.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'fileutils' -require File.dirname(__FILE__) + '/../test_helper' - -class TaggingGeneratorTest < Test::Unit::TestCase - - def setup - Dir.chdir RAILS_ROOT do - truncate - - # Revert environment lib requires - FileUtils.cp "config/environment.rb.canonical", "config/environment.rb" - - # Delete generator output - ["app/models/tag.rb", "app/models/tagging.rb", - "test/unit/tag_test.rb", "test/unit/tagging_test.rb", - "test/fixtures/tags.yml", "test/fixtures/taggings.yml", - "lib/tagging_extensions.rb", - "db/migrate/010_create_tags_and_taggings.rb"].each do |file| - File.delete file if File.exist? file - end - - # Rebuild database - Echoe.silence do - system("ruby #{HERE}/setup.rb") - end - end - end - - alias :teardown :setup - - def test_generator - Dir.chdir RAILS_ROOT do - Echoe.silence do - assert system("script/generate tagging Stick Stone -q -f") - assert system("rake db:migrate") - assert system("rake db:fixtures:load") - assert system("rake test:units") - end - end - end - -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/README b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/README deleted file mode 100644 index 0d6affdd..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/README +++ /dev/null @@ -1,182 +0,0 @@ -== Welcome to Rails - -Rails is a web-application and persistence 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-built 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 an 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 are 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. - - -== Getting started - -1. At the command prompt, start a new rails application using the rails command - and your application name. Ex: rails myapp - (If you've downloaded rails in a complete tgz or zip, this step is already done) -2. Change directory into myapp and start the web server: script/server (run with --help for options) -3. Go to http://localhost:3000/ and get "Welcome aboard: You’re riding the Rails!" -4. Follow the guidelines to start developing your application - - -== Web Servers - -By default, Rails will try to use Mongrel and lighttpd if they are installed, otherwise -Rails will use the WEBrick, the webserver that ships with Ruby. When you run script/server, -Rails will check if Mongrel exists, then lighttpd and finally fall back to WEBrick. This ensures -that you can always get up and running quickly. - -Mongrel is a Ruby-based webserver with a C-component (which requires compilation) that is -suitable for development and deployment of Rails applications. If you have Ruby Gems installed, -getting up and running with mongrel is as easy as: gem install mongrel. -More info at: http://mongrel.rubyforge.org - -If Mongrel is not installed, Rails will look for lighttpd. It's considerably faster than -Mongrel and WEBrick and also suited for production use, but requires additional -installation and currently only works well on OS X/Unix (Windows users are encouraged -to start with Mongrel). We recommend version 1.4.11 and higher. You can download it from -http://www.lighttpd.net. - -And finally, if neither Mongrel or lighttpd are installed, Rails will use the built-in Ruby -web server, WEBrick. WEBrick is a small Ruby web server suitable for development, but not -for production. - -But of course its also possible to run Rails on any platform that supports FCGI. -Apache, LiteSpeed, IIS are just a few. For more information on FCGI, -please visit: http://wiki.rubyonrails.com/rails/pages/FastCGI - - -== Debugging Rails - -Have "tail -f" commands running on the server.log and development.log. 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 - => "[#nil, \"body\"=>nil, \"id\"=>\"1\"}>, - #\"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 - => #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. Starting the script without arguments will launch it in the development environment. -Passing an argument will specify a different environment, like script/console production. - -To reload your controllers and models after launching the console run reload! - -To reload your controllers and models after launching the console run reload! - - - -== Description of contents - -app - Holds all the code that's specific to this particular application. - -app/controllers - Holds controllers that should be named like weblogs_controller.rb for - automated URL mapping. All controllers should descend from ApplicationController - which itself descends from ActionController::Base. - -app/models - Holds models that should be named like post.rb. - Most models will descend from ActiveRecord::Base. - -app/views - Holds the template files for the view that should be named like - weblogs/index.rhtml for the WeblogsController#index action. All views use eRuby - syntax. - -app/views/layouts - Holds the template files for layouts to be used with views. This models the common - header/footer method of wrapping views. In your views, define a layout using the - layout :default and create a file named default.rhtml. Inside default.rhtml, - call <% yield %> to render the view using this layout. - -app/helpers - Holds view helpers that should be named like weblogs_helper.rb. These are generated - for you automatically when using script/generate for controllers. Helpers can be used to - wrap functionality for your views into methods. - -config - Configuration files for the Rails environment, the routing map, the database, and other dependencies. - -components - Self-contained mini-applications that can bundle together controllers, models, and views. - -db - Contains the database schema in schema.rb. db/migrate contains all - the sequence of Migrations for your schema. - -doc - This directory is where your application documentation will be stored when generated - using rake doc:app - -lib - Application specific libraries. Basically, any kind of custom code that doesn't - belong under controllers, models, or helpers. This directory is in the load path. - -public - The directory available for the web server. Contains subdirectories for images, stylesheets, - and javascripts. Also contains the dispatchers and the default HTML files. This should be - set as the DOCUMENT_ROOT of your web server. - -script - Helper scripts for automation and generation. - -test - Unit and functional tests along with fixtures. When using the script/generate scripts, template - test files will be generated for you and placed in this directory. - -vendor - External libraries that the application depends on. Also includes the plugins subdirectory. - This directory is in the load path. diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/Rakefile b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/Rakefile deleted file mode 100644 index 2573c13c..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/Rakefile +++ /dev/null @@ -1,19 +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' - -namespace :test do - desc "a new rake task to include generators" - Rake::TestTask.new(:generators) do |t| - t.libs << 'lib' - t.test_files = FileList['test/generators/*_test.rb'] - t.verbose = true - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/controllers/application.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/controllers/application.rb deleted file mode 100644 index 057f4f7e..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/controllers/application.rb +++ /dev/null @@ -1,7 +0,0 @@ -# Filters added to this controller apply to all controllers in the application. -# Likewise, all the methods added will be available for all controllers. - -class ApplicationController < ActionController::Base - # Pick a unique cookie name to distinguish our session data from others' - session :session_key => '_testapp_session_id' -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/controllers/bones_controller.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/controllers/bones_controller.rb deleted file mode 100644 index 29bfe0c0..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/controllers/bones_controller.rb +++ /dev/null @@ -1,5 +0,0 @@ -class BonesController < ApplicationController - def index - @bones = Bone.find(:all) - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/addresses_helper.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/addresses_helper.rb deleted file mode 100644 index 5f4dc138..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/addresses_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module AddressesHelper -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/application_helper.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/application_helper.rb deleted file mode 100644 index 22a7940e..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/application_helper.rb +++ /dev/null @@ -1,3 +0,0 @@ -# Methods added to this helper will be available to all templates in the application. -module ApplicationHelper -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/bones_helper.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/bones_helper.rb deleted file mode 100644 index c188f669..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/bones_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module BonesHelper -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/sellers_helper.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/sellers_helper.rb deleted file mode 100644 index 4bdecd54..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/sellers_helper.rb +++ /dev/null @@ -1,28 +0,0 @@ -module SellersHelper - - def display_address(seller) - logger.info "Seller Data ====================" - logger.info seller.inspect - logger.info "Seller responds to address " + seller.respond_to?("address").to_s - logger.info "Seller responds to address= " + seller.respond_to?("address=").to_s - # logger.info seller.methods.sort.inspect - logger.info "User Data ====================" - logger.info seller.user.inspect - logger.info "User responds to address " + seller.user.respond_to?("address").to_s - logger.info "User responds to address= " + seller.user.respond_to?("address=").to_s - # logger.info seller.user.methods.sort.inspect - display_address = Array.new - if seller.address - display_address << seller.address.city if seller.address.city - display_address << seller.address.state.abbreviation if seller.address.state && seller.address.state.abbreviation - display_address << seller.address.zip_postal_code if seller.address.zip_postal_code - end - - unless display_address.empty? - "Location: " + display_address.join(", ") - else - "Location: unknown" - end - end - -end \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/states_helper.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/states_helper.rb deleted file mode 100644 index f98bdc7c..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/states_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module StatesHelper -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/users_helper.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/users_helper.rb deleted file mode 100644 index 2310a240..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/helpers/users_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module UsersHelper -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/bone.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/bone.rb deleted file mode 100644 index f9268612..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/bone.rb +++ /dev/null @@ -1,2 +0,0 @@ -class Bone < OrganicSubstance -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/double_sti_parent.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/double_sti_parent.rb deleted file mode 100644 index 5bc344f7..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/double_sti_parent.rb +++ /dev/null @@ -1,2 +0,0 @@ -class DoubleStiParent < ActiveRecord::Base -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/double_sti_parent_relationship.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/double_sti_parent_relationship.rb deleted file mode 100644 index 10b6255b..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/double_sti_parent_relationship.rb +++ /dev/null @@ -1,2 +0,0 @@ -class DoubleStiParentRelationship < ActiveRecord::Base -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/organic_substance.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/organic_substance.rb deleted file mode 100644 index e9a080d9..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/organic_substance.rb +++ /dev/null @@ -1,2 +0,0 @@ -class OrganicSubstance < ActiveRecord::Base -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/single_sti_parent.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/single_sti_parent.rb deleted file mode 100644 index 5e4410bb..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/single_sti_parent.rb +++ /dev/null @@ -1,4 +0,0 @@ - -class SingleStiParent < ActiveRecord::Base - has_many_polymorphs :the_bones, :from => [:bones], :through => :single_sti_parent_relationship -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/single_sti_parent_relationship.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/single_sti_parent_relationship.rb deleted file mode 100644 index 7f783c15..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/single_sti_parent_relationship.rb +++ /dev/null @@ -1,4 +0,0 @@ -class SingleStiParentRelationship < ActiveRecord::Base - belongs_to :single_sti_parent - belongs_to :the_bone, :polymorphic => true -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/stick.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/stick.rb deleted file mode 100644 index 4992506a..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/stick.rb +++ /dev/null @@ -1,2 +0,0 @@ -class Stick < ActiveRecord::Base -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/stone.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/stone.rb deleted file mode 100644 index 8617396e..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/models/stone.rb +++ /dev/null @@ -1,2 +0,0 @@ -class Stone < ActiveRecord::Base -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/edit.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/edit.html.erb deleted file mode 100644 index 6b6a3894..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/edit.html.erb +++ /dev/null @@ -1,12 +0,0 @@ -

        Editing address

        - -<%= error_messages_for :address %> - -<% form_for(@address) do |f| %> -

        - <%= f.submit "Update" %> -

        -<% end %> - -<%= link_to 'Show', @address %> | -<%= link_to 'Back', addresses_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/index.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/index.html.erb deleted file mode 100644 index 86d0d387..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/index.html.erb +++ /dev/null @@ -1,18 +0,0 @@ -

        Listing addresses

        - - - - - -<% for address in @addresses %> - - - - - -<% end %> -
        <%= link_to 'Show', address %><%= link_to 'Edit', edit_address_path(address) %><%= link_to 'Destroy', address, :confirm => 'Are you sure?', :method => :delete %>
        - -
        - -<%= link_to 'New address', new_address_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/new.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/new.html.erb deleted file mode 100644 index 1fae44cf..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/new.html.erb +++ /dev/null @@ -1,11 +0,0 @@ -

        New address

        - -<%= error_messages_for :address %> - -<% form_for(@address) do |f| %> -

        - <%= f.submit "Create" %> -

        -<% end %> - -<%= link_to 'Back', addresses_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/show.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/show.html.erb deleted file mode 100644 index a75ddbd5..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/addresses/show.html.erb +++ /dev/null @@ -1,3 +0,0 @@ - -<%= link_to 'Edit', edit_address_path(@address) %> | -<%= link_to 'Back', addresses_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/bones/index.rhtml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/bones/index.rhtml deleted file mode 100644 index 06f1dad3..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/bones/index.rhtml +++ /dev/null @@ -1,5 +0,0 @@ - -

        Bones: index

        -<% @bones.each do |bone| %> -

        ID: <%= bone.id %>

        -<% end %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/addresses.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/addresses.html.erb deleted file mode 100644 index 84583552..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/addresses.html.erb +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - Addresses: <%= controller.action_name %> - <%= stylesheet_link_tag 'scaffold' %> - - - -

        <%= flash[:notice] %>

        - -<%= yield %> - - - diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/sellers.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/sellers.html.erb deleted file mode 100644 index bc08e9be..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/sellers.html.erb +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - Sellers: <%= controller.action_name %> - <%= stylesheet_link_tag 'scaffold' %> - - - -

        <%= flash[:notice] %>

        - -<%= yield %> - - - diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/states.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/states.html.erb deleted file mode 100644 index b2b086fd..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/states.html.erb +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - States: <%= controller.action_name %> - <%= stylesheet_link_tag 'scaffold' %> - - - -

        <%= flash[:notice] %>

        - -<%= yield %> - - - diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/users.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/users.html.erb deleted file mode 100644 index 23757aa6..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/layouts/users.html.erb +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - Users: <%= controller.action_name %> - <%= stylesheet_link_tag 'scaffold' %> - - - -

        <%= flash[:notice] %>

        - -<%= yield %> - - - diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/edit.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/edit.html.erb deleted file mode 100644 index 14c41036..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/edit.html.erb +++ /dev/null @@ -1,12 +0,0 @@ -

        Editing seller

        - -<%= error_messages_for :seller %> - -<% form_for(@seller) do |f| %> -

        - <%= f.submit "Update" %> -

        -<% end %> - -<%= link_to 'Show', @seller %> | -<%= link_to 'Back', sellers_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/index.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/index.html.erb deleted file mode 100644 index 97ef0457..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/index.html.erb +++ /dev/null @@ -1,20 +0,0 @@ -

        Listing sellers

        - - - - - -<% for seller in @sellers %> - - - - - - - -<% end %> -
        <%= h(seller.company_name) %><%= h(display_address(seller)) %><%= link_to 'Show', seller %><%= link_to 'Edit', edit_seller_path(seller) %><%= link_to 'Destroy', seller, :confirm => 'Are you sure?', :method => :delete %>
        - -
        - -<%= link_to 'New seller', new_seller_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/new.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/new.html.erb deleted file mode 100644 index 6814338d..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/new.html.erb +++ /dev/null @@ -1,11 +0,0 @@ -

        New seller

        - -<%= error_messages_for :seller %> - -<% form_for(@seller) do |f| %> -

        - <%= f.submit "Create" %> -

        -<% end %> - -<%= link_to 'Back', sellers_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/show.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/show.html.erb deleted file mode 100644 index f21dcfa7..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/sellers/show.html.erb +++ /dev/null @@ -1,3 +0,0 @@ - -<%= link_to 'Edit', edit_seller_path(@seller) %> | -<%= link_to 'Back', sellers_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/edit.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/edit.html.erb deleted file mode 100644 index dc59d08b..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/edit.html.erb +++ /dev/null @@ -1,12 +0,0 @@ -

        Editing state

        - -<%= error_messages_for :state %> - -<% form_for(@state) do |f| %> -

        - <%= f.submit "Update" %> -

        -<% end %> - -<%= link_to 'Show', @state %> | -<%= link_to 'Back', states_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/index.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/index.html.erb deleted file mode 100644 index 07c11ae1..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/index.html.erb +++ /dev/null @@ -1,19 +0,0 @@ -

        Listing states

        - - - - - -<% for state in @states %> - - - - - - -<% end %> -
        <%= state.name %><%= link_to 'Show', state %><%= link_to 'Edit', edit_state_path(state) %><%= link_to 'Destroy', state, :confirm => 'Are you sure?', :method => :delete %>
        - -
        - -<%= link_to 'New state', new_state_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/new.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/new.html.erb deleted file mode 100644 index 5caacd5d..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/new.html.erb +++ /dev/null @@ -1,11 +0,0 @@ -

        New state

        - -<%= error_messages_for :state %> - -<% form_for(@state) do |f| %> -

        - <%= f.submit "Create" %> -

        -<% end %> - -<%= link_to 'Back', states_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/show.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/show.html.erb deleted file mode 100644 index ba5c32fb..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/states/show.html.erb +++ /dev/null @@ -1,3 +0,0 @@ - -<%= link_to 'Edit', edit_state_path(@state) %> | -<%= link_to 'Back', states_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/edit.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/edit.html.erb deleted file mode 100644 index b497ec93..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/edit.html.erb +++ /dev/null @@ -1,12 +0,0 @@ -

        Editing user

        - -<%= error_messages_for :user %> - -<% form_for(@user) do |f| %> -

        - <%= f.submit "Update" %> -

        -<% end %> - -<%= link_to 'Show', @user %> | -<%= link_to 'Back', users_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/index.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/index.html.erb deleted file mode 100644 index 6397e64e..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/index.html.erb +++ /dev/null @@ -1,22 +0,0 @@ -

        Listing users

        - - - - - -<% for user in @users %> - - - - - - - - - -<% end %> -
        <%= h(user.login) %><%= h(user.address.line_1) %><%= h(user.address.city) %><%= h(user.address.state.name) %><%= link_to 'Show', user %><%= link_to 'Edit', edit_user_path(user) %><%= link_to 'Destroy', user, :confirm => 'Are you sure?', :method => :delete %>
        - -
        - -<%= link_to 'New user', new_user_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/new.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/new.html.erb deleted file mode 100644 index bc76aa6b..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/new.html.erb +++ /dev/null @@ -1,11 +0,0 @@ -

        New user

        - -<%= error_messages_for :user %> - -<% form_for(@user) do |f| %> -

        - <%= f.submit "Create" %> -

        -<% end %> - -<%= link_to 'Back', users_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/show.html.erb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/show.html.erb deleted file mode 100644 index 3109a37d..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/app/views/users/show.html.erb +++ /dev/null @@ -1,3 +0,0 @@ - -<%= link_to 'Edit', edit_user_path(@user) %> | -<%= link_to 'Back', users_path %> diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/boot.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/boot.rb deleted file mode 100644 index cb9a72da..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/boot.rb +++ /dev/null @@ -1,110 +0,0 @@ -# Don't change this file! -# Configure your app in config/environment.rb and config/environments/*.rb - -RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT) - -module Rails - class << self - def boot! - unless booted? - preinitialize - pick_boot.run - end - end - - def booted? - defined? Rails::Initializer - end - - def pick_boot - (vendor_rails? ? VendorBoot : GemBoot).new - end - - def vendor_rails? - File.exist?("#{RAILS_ROOT}/vendor/rails") - end - - def preinitialize - load(preinitializer_path) if File.exists?(preinitializer_path) - end - - def preinitializer_path - "#{RAILS_ROOT}/config/preinitializer.rb" - end - end - - class Boot - def run - load_initializer - Rails::Initializer.run(:set_load_path) - end - end - - class VendorBoot < Boot - def load_initializer - require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer" - end - end - - class GemBoot < Boot - def load_initializer - self.class.load_rubygems - load_rails_gem - require 'initializer' - end - - def load_rails_gem - if version = self.class.gem_version - STDERR.puts "Boot.rb loading version #{version}" - gem 'rails', version - else - STDERR.puts "Boot.rb loading latest available version" - gem 'rails' - end - rescue Gem::LoadError => load_error - $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.) - exit 1 - end - - class << self - def rubygems_version - Gem::RubyGemsVersion if defined? Gem::RubyGemsVersion - end - - def gem_version - if defined? RAILS_GEM_VERSION - RAILS_GEM_VERSION - elsif ENV.include?('RAILS_GEM_VERSION') - ENV['RAILS_GEM_VERSION'] - else - parse_gem_version(read_environment_rb) - end - end - - def load_rubygems - require 'rubygems' - - unless rubygems_version >= '0.9.4' - $stderr.puts %(Rails requires RubyGems >= 0.9.4 (you have #{rubygems_version}). Please `gem update --system` and try again.) - exit 1 - end - - rescue LoadError - $stderr.puts %(Rails requires RubyGems >= 0.9.4. Please install RubyGems and try again: http://rubygems.rubyforge.org) - exit 1 - end - - def parse_gem_version(text) - $1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*'([!~<>=]*\s*[\d.]+)'/ - end - - private - def read_environment_rb - File.read("#{RAILS_ROOT}/config/environment.rb") - end - end - end -end - -# All that for this: -Rails.boot! diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/database.yml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/database.yml deleted file mode 100644 index c64a5d89..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/database.yml +++ /dev/null @@ -1,17 +0,0 @@ - -defaults: &defaults - adapter: <%= ENV['DB'] || 'mysql' %> - host: localhost - database: hmp_development - username: root - password: - -development: - <<: *defaults - -test: - <<: *defaults - -production: - <<: *defaults - \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environment.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environment.rb deleted file mode 100644 index 39f34dee..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environment.rb +++ /dev/null @@ -1,19 +0,0 @@ -require File.join(File.dirname(__FILE__), 'boot') -require 'action_controller' - -Rails::Initializer.run do |config| - - if ActionController::Base.respond_to? 'session=' - config.action_controller.session = {:session_key => '_app_session', :secret => '22cde4d5c1a61ba69a81795322cde4d5c1a61ba69a817953'} - end - - config.load_paths << "#{RAILS_ROOT}/app/models/person" # moduleless model path - - config.after_initialize do - config.has_many_polymorphs_options['requirements'] << "#{RAILS_ROOT}/lib/library_model" - end -end - -# Dependencies.log_activity = true - -ENV['RAILS_ASSET_ID'] = Time.now.to_i.to_s diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environment.rb.canonical b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environment.rb.canonical deleted file mode 100644 index 39f34dee..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environment.rb.canonical +++ /dev/null @@ -1,19 +0,0 @@ -require File.join(File.dirname(__FILE__), 'boot') -require 'action_controller' - -Rails::Initializer.run do |config| - - if ActionController::Base.respond_to? 'session=' - config.action_controller.session = {:session_key => '_app_session', :secret => '22cde4d5c1a61ba69a81795322cde4d5c1a61ba69a817953'} - end - - config.load_paths << "#{RAILS_ROOT}/app/models/person" # moduleless model path - - config.after_initialize do - config.has_many_polymorphs_options['requirements'] << "#{RAILS_ROOT}/lib/library_model" - end -end - -# Dependencies.log_activity = true - -ENV['RAILS_ASSET_ID'] = Time.now.to_i.to_s diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/development.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/development.rb deleted file mode 100644 index 54ae4ed2..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/development.rb +++ /dev/null @@ -1,9 +0,0 @@ - -config.cache_classes = ENV['PRODUCTION'] -config.whiny_nils = true -config.action_controller.consider_all_requests_local = !ENV['PRODUCTION'] -config.action_controller.perform_caching = ENV['PRODUCTION'] -# The following has been deprecated in Rails 2.1 and removed in 2.2 -config.action_view.cache_template_extensions = ENV['PRODUCTION'] if Rails::VERSION::MAJOR < 2 or Rails::VERSION::MAJOR == 2 && Rails::VERSION::MINOR < 1 -config.action_view.debug_rjs = !ENV['PRODUCTION'] -config.action_mailer.raise_delivery_errors = false diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/production.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/production.rb deleted file mode 100644 index cb295b83..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/production.rb +++ /dev/null @@ -1,18 +0,0 @@ -# Settings specified here will take precedence over those in config/environment.rb - -# The production environment is meant for finished, "live" apps. -# Code is not reloaded between requests -config.cache_classes = true - -# Use a different logger for distributed setups -# config.logger = SyslogLogger.new - -# Full error reports are disabled and caching is turned on -config.action_controller.consider_all_requests_local = false -config.action_controller.perform_caching = true - -# Enable serving of images, stylesheets, and javascripts from an asset server -# config.action_controller.asset_host = "http://assets.example.com" - -# Disable delivery errors, bad email addresses will be ignored -# config.action_mailer.raise_delivery_errors = false diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/test.rb deleted file mode 100644 index f0689b92..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/environments/test.rb +++ /dev/null @@ -1,19 +0,0 @@ -# Settings specified here will take precedence over those in config/environment.rb - -# The test environment is used exclusively to run your application's -# test suite. You never need to work with it otherwise. Remember that -# your test database is "scratch space" for the test suite and is wiped -# and recreated between test runs. Don't rely on the data there! -config.cache_classes = true - -# Log error messages when you accidentally call methods on nil. -config.whiny_nils = true - -# Show full error reports and disable caching -config.action_controller.consider_all_requests_local = true -config.action_controller.perform_caching = false - -# Tell ActionMailer not to deliver emails to the real world. -# The :test delivery method accumulates sent emails in the -# ActionMailer::Base.deliveries array. -config.action_mailer.delivery_method = :test \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/locomotive.yml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/locomotive.yml deleted file mode 100644 index 01d79773..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/locomotive.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -mode: development -runs_at_launch: 0 -identifier: testapp -port: 3005 -bundle: /Applications/Locomotive2/Bundles/rmagickRailsMar2007_i386.locobundle \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/routes.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/routes.rb deleted file mode 100644 index b83b6f4d..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/routes.rb +++ /dev/null @@ -1,33 +0,0 @@ -ActionController::Routing::Routes.draw do |map| - map.resources :states - - map.resources :states - - map.resources :addresses - - map.resources :sellers - - map.resources :users - - # The priority is based upon order of creation: first created -> highest priority. - - # Sample of regular route: - # map.connect 'products/:id', :controller => 'catalog', :action => 'view' - # Keep in mind you can assign values other than :controller and :action - - # Sample of named route: - # map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase' - # This route can be invoked with purchase_url(:id => product.id) - - # You can have the root of your site routed by hooking up '' - # -- just remember to delete public/index.html. - # map.connect '', :controller => "welcome" - - # Allow downloading Web Service WSDL as a file with an extension - # instead of a file named 'wsdl' - map.connect ':controller/service.wsdl', :action => 'wsdl' - - # Install the default route as the lowest priority. - map.connect ':controller/:action/:id.:format' - map.connect ':controller/:action/:id' -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/ultrasphinx/default.base b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/ultrasphinx/default.base deleted file mode 100644 index 2886ccdc..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/ultrasphinx/default.base +++ /dev/null @@ -1,56 +0,0 @@ -# -# Sphinx/Ultrasphinx user-configurable options. -# -# Copy this file to RAILS_ROOT/config/ultrasphinx. -# You can use individual namespaces if you want (e.g. "development.base"). -# - -indexer -{ - # Indexer running options - mem_limit = 256M -} - -searchd -{ - # Daemon options - # What interface the search daemon should listen on and where to store its logs - address = 0.0.0.0 - port = 3313 - log = /tmp/sphinx/searchd.log - query_log = /tmp/sphinx/query.log - read_timeout = 5 - max_children = 300 - pid_file = /tmp/sphinx/searchd.pid - max_matches = 100000 -} - -client -{ - # Client options - dictionary_name = ts - # How your application connects to the search daemon (not necessarily the same as above) - server_host = localhost - server_port = 3313 -} - -source -{ - # Individual SQL source options - sql_range_step = 20000 - strip_html = 0 - index_html_attrs = - sql_query_post = -} - -index -{ - # Index building options - path = /tmp/sphinx/ - docinfo = extern # just leave this alone - morphology = stem_en - stopwords = # /path/to/stopwords.txt - min_word_len = 1 - charset_type = utf-8 # or sbcs (Single Byte Character Set) - charset_table = 0..9, A..Z->a..z, -, _, ., &, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F,U+C5->U+E5, U+E5, U+C4->U+E4, U+E4, U+D6->U+F6, U+F6, U+16B, U+0c1->a, U+0c4->a, U+0c9->e, U+0cd->i, U+0d3->o, U+0d4->o, U+0da->u, U+0dd->y, U+0e1->a, U+0e4->a, U+0e9->e, U+0ed->i, U+0f3->o, U+0f4->o, U+0fa->u, U+0fd->y, U+104->U+105, U+105, U+106->U+107, U+10c->c, U+10d->c, U+10e->d, U+10f->d, U+116->U+117, U+117, U+118->U+119, U+11a->e, U+11b->e, U+12E->U+12F, U+12F, U+139->l, U+13a->l, U+13d->l, U+13e->l, U+141->U+142, U+142, U+143->U+144, U+144,U+147->n, U+148->n, U+154->r, U+155->r, U+158->r, U+159->r, U+15A->U+15B, U+15B, U+160->s, U+160->U+161, U+161->s, U+164->t, U+165->t, U+16A->U+16B, U+16B, U+16e->u, U+16f->u, U+172->U+173, U+173, U+179->U+17A, U+17A, U+17B->U+17C, U+17C, U+17d->z, U+17e->z, -} diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/ultrasphinx/development.conf.canonical b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/ultrasphinx/development.conf.canonical deleted file mode 100644 index f08e8ed4..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/config/ultrasphinx/development.conf.canonical +++ /dev/null @@ -1,155 +0,0 @@ - -# Auto-generated at Wed Oct 03 03:57:12 -0400 2007. -# Hand modifications will be overwritten. -# /Users/eweaver/Desktop/projects/chow/vendor/plugins/ultrasphinx/test/integration/app/config/ultrasphinx/default.base -indexer { - mem_limit = 256M -} -searchd { - read_timeout = 5 - max_children = 300 - log = /tmp/sphinx/searchd.log - port = 3313 - max_matches = 100000 - query_log = /tmp/sphinx/query.log - pid_file = /tmp/sphinx/searchd.pid - address = 0.0.0.0 -} - -# Source configuration - -source geo__states -{ - strip_html = 0 - sql_range_step = 20000 - index_html_attrs = - sql_query_post = - -type = mysql -sql_query_pre = SET SESSION group_concat_max_len = 65535 -sql_query_pre = SET NAMES utf8 - -sql_db = app_development -sql_host = localhost -sql_pass = -sql_user = root -sql_query_range = SELECT MIN(id), MAX(id) FROM states -sql_query = SELECT (states.id * 4 + 0) AS id, CAST(GROUP_CONCAT(addresses.name SEPARATOR ' ') AS CHAR) AS address_name, 0 AS capitalization, 'Geo::State' AS class, 0 AS class_id, '' AS company, '' AS company_name, 0 AS company_name_facet, '' AS content, UNIX_TIMESTAMP('1970-01-01 00:00:00') AS created_at, 0 AS deleted, '' AS email, '__empty_searchable__' AS empty_searchable, '' AS login, '' AS name, '' AS state, 0 AS user_id FROM states LEFT OUTER JOIN addresses ON states.id = addresses.state_id WHERE states.id >= $start AND states.id <= $end GROUP BY id - -sql_group_column = capitalization -sql_group_column = class_id -sql_group_column = company_name_facet -sql_date_column = created_at -sql_group_column = deleted -sql_group_column = user_id -sql_query_info = SELECT * FROM states WHERE states.id = (($id - 0) / 4) -} - - -# Source configuration - -source sellers -{ - strip_html = 0 - sql_range_step = 20000 - index_html_attrs = - sql_query_post = - -type = mysql -sql_query_pre = SET SESSION group_concat_max_len = 65535 -sql_query_pre = SET NAMES utf8 - -sql_db = app_development -sql_host = localhost -sql_pass = -sql_user = root -sql_query_range = SELECT MIN(id), MAX(id) FROM sellers -sql_query = SELECT (sellers.id * 4 + 1) AS id, '' AS address_name, sellers.capitalization AS capitalization, 'Seller' AS class, 1 AS class_id, '' AS company, sellers.company_name AS company_name, CRC32(sellers.company_name) AS company_name_facet, '' AS content, UNIX_TIMESTAMP(sellers.created_at) AS created_at, 0 AS deleted, '' AS email, '__empty_searchable__' AS empty_searchable, '' AS login, '' AS name, '' AS state, sellers.user_id AS user_id FROM sellers WHERE sellers.id >= $start AND sellers.id <= $end GROUP BY id - -sql_group_column = capitalization -sql_group_column = class_id -sql_group_column = company_name_facet -sql_date_column = created_at -sql_group_column = deleted -sql_group_column = user_id -sql_query_info = SELECT * FROM sellers WHERE sellers.id = (($id - 1) / 4) -} - - -# Source configuration - -source geo__addresses -{ - strip_html = 0 - sql_range_step = 20000 - index_html_attrs = - sql_query_post = - -type = mysql -sql_query_pre = SET SESSION group_concat_max_len = 65535 -sql_query_pre = SET NAMES utf8 - -sql_db = app_development -sql_host = localhost -sql_pass = -sql_user = root -sql_query_range = SELECT MIN(id), MAX(id) FROM addresses -sql_query = SELECT (addresses.id * 4 + 2) AS id, '' AS address_name, 0 AS capitalization, 'Geo::Address' AS class, 2 AS class_id, '' AS company, '' AS company_name, 0 AS company_name_facet, CONCAT_WS(' ', addresses.line_1, addresses.line_2, addresses.city, addresses.province_region, addresses.zip_postal_code) AS content, UNIX_TIMESTAMP('1970-01-01 00:00:00') AS created_at, 0 AS deleted, '' AS email, '__empty_searchable__' AS empty_searchable, '' AS login, addresses.name AS name, states.name AS state, 0 AS user_id FROM addresses LEFT OUTER JOIN states ON states.id = addresses.state_id WHERE addresses.id >= $start AND addresses.id <= $end GROUP BY id - -sql_group_column = capitalization -sql_group_column = class_id -sql_group_column = company_name_facet -sql_date_column = created_at -sql_group_column = deleted -sql_group_column = user_id -sql_query_info = SELECT * FROM addresses WHERE addresses.id = (($id - 2) / 4) -} - - -# Source configuration - -source users -{ - strip_html = 0 - sql_range_step = 20000 - index_html_attrs = - sql_query_post = - -type = mysql -sql_query_pre = SET SESSION group_concat_max_len = 65535 -sql_query_pre = SET NAMES utf8 - -sql_db = app_development -sql_host = localhost -sql_pass = -sql_user = root -sql_query_range = SELECT MIN(id), MAX(id) FROM users -sql_query = SELECT (users.id * 4 + 3) AS id, '' AS address_name, 0 AS capitalization, 'User' AS class, 3 AS class_id, sellers.company_name AS company, '' AS company_name, 0 AS company_name_facet, '' AS content, UNIX_TIMESTAMP('1970-01-01 00:00:00') AS created_at, users.deleted AS deleted, users.email AS email, '__empty_searchable__' AS empty_searchable, users.login AS login, '' AS name, '' AS state, 0 AS user_id FROM users LEFT OUTER JOIN sellers ON users.id = sellers.user_id WHERE users.id >= $start AND users.id <= $end AND (deleted = 0) GROUP BY id - -sql_group_column = capitalization -sql_group_column = class_id -sql_group_column = company_name_facet -sql_date_column = created_at -sql_group_column = deleted -sql_group_column = user_id -sql_query_info = SELECT * FROM users WHERE users.id = (($id - 3) / 4) -} - - -# Index configuration - -index complete -{ - source = geo__addresses - source = geo__states - source = sellers - source = users - charset_type = utf-8 - charset_table = 0..9, A..Z->a..z, -, _, ., &, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F,U+C5->U+E5, U+E5, U+C4->U+E4, U+E4, U+D6->U+F6, U+F6, U+16B, U+0c1->a, U+0c4->a, U+0c9->e, U+0cd->i, U+0d3->o, U+0d4->o, U+0da->u, U+0dd->y, U+0e1->a, U+0e4->a, U+0e9->e, U+0ed->i, U+0f3->o, U+0f4->o, U+0fa->u, U+0fd->y, U+104->U+105, U+105, U+106->U+107, U+10c->c, U+10d->c, U+10e->d, U+10f->d, U+116->U+117, U+117, U+118->U+119, U+11a->e, U+11b->e, U+12E->U+12F, U+12F, U+139->l, U+13a->l, U+13d->l, U+13e->l, U+141->U+142, U+142, U+143->U+144, U+144,U+147->n, U+148->n, U+154->r, U+155->r, U+158->r, U+159->r, U+15A->U+15B, U+15B, U+160->s, U+160->U+161, U+161->s, U+164->t, U+165->t, U+16A->U+16B, U+16B, U+16e->u, U+16f->u, U+172->U+173, U+173, U+179->U+17A, U+17A, U+17B->U+17C, U+17C, U+17d->z, U+17e->z, - min_word_len = 1 - stopwords = - path = /tmp/sphinx//sphinx_index_complete - docinfo = extern - morphology = stem_en -} - diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/001_create_sticks.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/001_create_sticks.rb deleted file mode 100644 index 6193c313..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/001_create_sticks.rb +++ /dev/null @@ -1,11 +0,0 @@ -class CreateSticks < ActiveRecord::Migration - def self.up - create_table :sticks do |t| - t.column :name, :string - end - end - - def self.down - drop_table :sticks - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/002_create_stones.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/002_create_stones.rb deleted file mode 100644 index 4c1ec154..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/002_create_stones.rb +++ /dev/null @@ -1,11 +0,0 @@ -class CreateStones < ActiveRecord::Migration - def self.up - create_table :stones do |t| - t.column :name, :string - end - end - - def self.down - drop_table :stones - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/003_create_organic_substances.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/003_create_organic_substances.rb deleted file mode 100644 index 1bf82da6..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/003_create_organic_substances.rb +++ /dev/null @@ -1,11 +0,0 @@ -class CreateOrganicSubstances < ActiveRecord::Migration - def self.up - create_table :organic_substances do |t| - t.column :type, :string - end - end - - def self.down - drop_table :organic_substances - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/004_create_bones.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/004_create_bones.rb deleted file mode 100644 index 6faa0aa1..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/004_create_bones.rb +++ /dev/null @@ -1,8 +0,0 @@ -class CreateBones < ActiveRecord::Migration - def self.up - # Using STI - end - - def self.down - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/005_create_single_sti_parents.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/005_create_single_sti_parents.rb deleted file mode 100644 index eef14621..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/005_create_single_sti_parents.rb +++ /dev/null @@ -1,11 +0,0 @@ -class CreateSingleStiParents < ActiveRecord::Migration - def self.up - create_table :single_sti_parents do |t| - t.column :name, :string - end - end - - def self.down - drop_table :single_sti_parents - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/006_create_double_sti_parents.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/006_create_double_sti_parents.rb deleted file mode 100644 index 2a28f4ab..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/006_create_double_sti_parents.rb +++ /dev/null @@ -1,11 +0,0 @@ -class CreateDoubleStiParents < ActiveRecord::Migration - def self.up - create_table :double_sti_parents do |t| - t.column :name, :string - end - end - - def self.down - drop_table :double_sti_parents - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb deleted file mode 100644 index deceeec7..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb +++ /dev/null @@ -1,13 +0,0 @@ -class CreateSingleStiParentRelationships < ActiveRecord::Migration - def self.up - create_table :single_sti_parent_relationships do |t| - t.column :the_bone_type, :string, :null => false - t.column :the_bone_id, :integer, :null => false - t.column :single_sti_parent_id, :integer, :null => false - end - end - - def self.down - drop_table :single_sti_parent_relationships - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb deleted file mode 100644 index 46605d9b..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb +++ /dev/null @@ -1,14 +0,0 @@ -class CreateDoubleStiParentRelationships < ActiveRecord::Migration - def self.up - create_table :double_sti_parent_relationships do |t| - t.column :the_bone_type, :string, :null => false - t.column :the_bone_id, :integer, :null => false - t.column :parent_type, :string, :null => false - t.column :parent_id, :integer, :null => false - end - end - - def self.down - drop_table :double_sti_parent_relationships - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/009_create_library_model.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/009_create_library_model.rb deleted file mode 100644 index bdf7cf46..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/db/migrate/009_create_library_model.rb +++ /dev/null @@ -1,11 +0,0 @@ -class CreateLibraryModel < ActiveRecord::Migration - def self.up - create_table :library_models do |t| - t.column :name, :string - end - end - - def self.down - drop_table :library_models - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/doc/README_FOR_APP b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/doc/README_FOR_APP deleted file mode 100644 index ac6c1491..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/doc/README_FOR_APP +++ /dev/null @@ -1,2 +0,0 @@ -Use this README file to introduce your application and point to useful places in the API for learning more. -Run "rake appdoc" to generate API documentation for your models and controllers. \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/generators/commenting_generator_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/generators/commenting_generator_test.rb deleted file mode 100644 index 96c6a799..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/generators/commenting_generator_test.rb +++ /dev/null @@ -1,83 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' -require 'fileutils' - -class CommentingGeneratorTest < Test::Unit::TestCase - - def test_ensure_comments_dont_exist - # make sure the comments are already defined - assert_equal false, Object.send(:const_defined?, :Comment) - assert_equal false, Object.send(:const_defined?, :Commenting) - end - - def test_ensure_files_exist_after_generator_runs - run_generator - - # make sure the files are there - for generated_file in generated_files do - assert File.exists?(File.expand_path(generated_file)) - end - end - - def test_classes_exist_with_associations - run_generator - assert_nothing_raised { Commenting } - assert_nothing_raised { Comment } - citation = Citation.find(:first) - assert !citation.nil? - assert citation.respond_to?(:comments) - user = User.find(:first) - assert !user.nil? - assert user.respond_to?(:comments) - end - - def teardown - Object.send(:remove_const, :Comment) if Object.send(:const_defined?, :Comment) - Object.send(:remove_const, :Commenting) if Object.send(:const_defined?, :Commenting) - remove_all_generated_files - remove_require_for_commenting_extensions - end - - def generated_files - generated_files = [File.join(File.dirname(__FILE__), '..', '..', 'app', 'models', 'comment.rb')] - generated_files << File.join(File.dirname(__FILE__), '..', '..', 'app', 'models', 'commenting.rb') - generated_files << File.join(File.dirname(__FILE__), '..', '..', 'test', 'unit', 'commenting_test.rb') - generated_files << File.join(File.dirname(__FILE__), '..', '..', 'test', 'unit', 'comment_test.rb') - generated_files << File.join(File.dirname(__FILE__), '..', '..', 'lib', 'commenting_extensions.rb') - generated_files << File.join(File.dirname(__FILE__), '..', '..', 'test', 'fixtures', 'comments.yml') - generated_files << File.join(File.dirname(__FILE__), '..', '..', 'test', 'fixtures', 'commentings.yml') - end - - def remove_all_generated_files - for generated_file in generated_files do - if File.exists?(generated_file) - assert FileUtils.rm(generated_file) - end - end - end - - def run_migrate - `rake db:migrate RAILS_ENV=test` - end - - def run_generator - command = File.join(File.dirname(__FILE__), '..', '..', 'script', 'generate') - `#{command} commenting Citation User` - run_migrate - end - - def remove_require_for_commenting_extensions - environment = File.join(File.dirname(__FILE__), '..', '..', 'config', 'environment.rb') - new_environment = '' - if File.exists?(environment) - if (open(environment) { |file| file.grep(/Rails/).any? }) - IO.readlines(environment).each do |line| - new_environment += line unless line.match(/commenting_extensions/i) - end - File.open(environment, "w+") do |f| - f.pos = 0 - f.print new_environment - end - end - end - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/lib/library_model.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/lib/library_model.rb deleted file mode 100644 index e27106fa..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/lib/library_model.rb +++ /dev/null @@ -1,2 +0,0 @@ -class LibraryModel < ActiveRecord::Base -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/404.html b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/404.html deleted file mode 100644 index eff660b9..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/404.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - The page you were looking for doesn't exist (404) - - - - - -
        -

        The page you were looking for doesn't exist.

        -

        You may have mistyped the address or the page may have moved.

        -
        - - \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/500.html b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/500.html deleted file mode 100644 index f0aee0e9..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/500.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - We're sorry, but something went wrong - - - - - -
        -

        We're sorry, but something went wrong.

        -

        We've been notified about this issue and we'll take a look at it shortly.

        -
        - - \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.cgi b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.cgi deleted file mode 100755 index 9b5ae760..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.cgi +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/local/bin/ruby - -require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT) - -# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like: -# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired -require "dispatcher" - -ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun) -Dispatcher.dispatch \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.fcgi b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.fcgi deleted file mode 100755 index 664dbbbe..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.fcgi +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env ruby -# -# You may specify the path to the FastCGI crash log (a log of unhandled -# exceptions which forced the FastCGI instance to exit, great for debugging) -# and the number of requests to process before running garbage collection. -# -# By default, the FastCGI crash log is RAILS_ROOT/log/fastcgi.crash.log -# and the GC period is nil (turned off). A reasonable number of requests -# could range from 10-100 depending on the memory footprint of your app. -# -# Example: -# # Default log path, normal GC behavior. -# RailsFCGIHandler.process! -# -# # Default log path, 50 requests between GC. -# RailsFCGIHandler.process! nil, 50 -# -# # Custom log path, normal GC behavior. -# RailsFCGIHandler.process! '/var/log/myapp_fcgi_crash.log' -# -require File.dirname(__FILE__) + "/../config/environment" -require 'fcgi_handler' - -RailsFCGIHandler.process! diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.rb deleted file mode 100755 index 9b5ae760..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/dispatch.rb +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/local/bin/ruby - -require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT) - -# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like: -# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired -require "dispatcher" - -ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun) -Dispatcher.dispatch \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/favicon.ico b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/favicon.ico deleted file mode 100644 index e69de29b..00000000 diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/images/rails.png b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/images/rails.png deleted file mode 100644 index b8441f182e06974083cf08f0acaf0e2fd612bd40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1787 zcmVCLdthj)A!BBmWB&y|X`RY;f`BJ<_ju%@N||NoLFD~mQl$aHGjq>;5dG_D{h(5s}0 z6&=HANU$m__3PuddU(lvR_xWj`}Oho@9EyQt-n!E*P(KhM@X_VFV2l&>deNZJT%y8iwA zoG>u1B`p2=_u9k4v1Mud`1+qvOZoHg#bITJ9U`qBAek?40RR96!AV3xRCwBy*IQ$v zN(=yC9IhRft9V64L`77pqF_Cx@c;kSNoGK)`?Ps*cP(EtGlYZ{D5cxspMQvjKH)Oh6X(pa|J{ zGy1J$Ej7=Z{uvmMfRRsE;v`p;45B~6*ep#hM^ji zl$+7qoWq~}ewG=61uFw0He{tJurMU&4Iv?=B^eR(wAHk!miA)O7p_+YR>lbmU3rmn ze?+ze(+sEd6foB&*l9+?zkr_a-5*v&p*?c}HOGtyHg6r{WFYpQ=#z0Hc7VWLx$>M3|b0|Gn z+5t#z6*ffSVc6DjpmB2?AAR@@vB!wCK?9Yl;33;Q7^%(401QW|k=R8b!OwtLJPjjm zO9Ia;qCq)rOq!1Ia*6#A%#xb}yDx1P*pWla>9j$bnMn3CBqe4`TRll_Iy29kmG?4fbKuF=XqU|?3b@B zA`&a?KIgZ|KJx5eND_c3Em=WZn@xW8hRJ^G&sY^b(FW?WC9W_sb;+lAPdLTdBaKIK;-f}*h4|1aTjw7qX_k~e{TWO7jqcekERN;Jyh%67)q4rKpL*CEYL;|#GY{B@5 zi52XoC?xsoorJKxsliugF#z38MJqrYCWV(t<=G&f;^Me13&AiI9{3jUZ$ zFM`*L(9qc^VMxkz1oaDH!1pcD^IXp>Z0Jb=_qs?Vsrs{mp<^{$N!EC9o+`CO-(o}E zJ`y{*;9s|wr22-QoJ87y^~;)Q@b%P4UgSSsx>2$o@Vd{%Pk0@4qZ^fhB(vt$c1TG> z*{Ad;foraENbld`=MCNm4?9kvlgK~&J>ialpJ7nua zx0oRzwG5;}Qne)Fg(N3kf?JVmB;}y&5(0+~r*aL$0Zof8fe!AtHWH>A^1Y)@G@GsA zup`R{Qg?{+MaxTq#2n{6w|)c&yaJ7{U4ngAH5v6I)*;@rEBE*ehIPBwKBQU)YKE8F0lR!Sm?sE4Xk-sj&E$|A-9n dP56HS1^^A-61FoN)nxzx002ovPDHLkV1kw_Sd9Px diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/index.html b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/index.html deleted file mode 100644 index a2daab72..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/index.html +++ /dev/null @@ -1,277 +0,0 @@ - - - - - Ruby on Rails: Welcome aboard - - - - - - -
        - - -
        - - - - -
        -

        Getting started

        -

        Here’s how to get rolling:

        - -
          -
        1. -

          Create your databases and edit config/database.yml

          -

          Rails needs to know your login and password.

          -
        2. - -
        3. -

          Use script/generate to create your models and controllers

          -

          To see all available options, run it without parameters.

          -
        4. - -
        5. -

          Set up a default route and remove or rename this file

          -

          Routes are setup in config/routes.rb.

          -
        6. -
        -
        -
        - - -
        - - \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/application.js b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/application.js deleted file mode 100644 index fe457769..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/application.js +++ /dev/null @@ -1,2 +0,0 @@ -// Place your application-specific JavaScript functions and classes here -// This file is automatically included by javascript_include_tag :defaults diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/controls.js b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/controls.js deleted file mode 100644 index 8c273f87..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/controls.js +++ /dev/null @@ -1,833 +0,0 @@ -// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// (c) 2005, 2006 Ivan Krstic (http://blogs.law.harvard.edu/ivan) -// (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com) -// Contributors: -// Richard Livsey -// Rahul Bhargava -// Rob Wills -// -// script.aculo.us is freely distributable under the terms of an MIT-style license. -// For details, see the script.aculo.us web site: http://script.aculo.us/ - -// Autocompleter.Base handles all the autocompletion functionality -// that's independent of the data source for autocompletion. This -// includes drawing the autocompletion menu, observing keyboard -// and mouse events, and similar. -// -// Specific autocompleters need to provide, at the very least, -// a getUpdatedChoices function that will be invoked every time -// the text inside the monitored textbox changes. This method -// should get the text for which to provide autocompletion by -// invoking this.getToken(), NOT by directly accessing -// this.element.value. This is to allow incremental tokenized -// autocompletion. Specific auto-completion logic (AJAX, etc) -// belongs in getUpdatedChoices. -// -// Tokenized incremental autocompletion is enabled automatically -// when an autocompleter is instantiated with the 'tokens' option -// in the options parameter, e.g.: -// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); -// will incrementally autocomplete with a comma as the token. -// Additionally, ',' in the above example can be replaced with -// a token array, e.g. { tokens: [',', '\n'] } which -// enables autocompletion on multiple tokens. This is most -// useful when one of the tokens is \n (a newline), as it -// allows smart autocompletion after linebreaks. - -if(typeof Effect == 'undefined') - throw("controls.js requires including script.aculo.us' effects.js library"); - -var Autocompleter = {} -Autocompleter.Base = function() {}; -Autocompleter.Base.prototype = { - baseInitialize: function(element, update, options) { - this.element = $(element); - this.update = $(update); - this.hasFocus = false; - this.changed = false; - this.active = false; - this.index = 0; - this.entryCount = 0; - - if(this.setOptions) - this.setOptions(options); - else - this.options = options || {}; - - this.options.paramName = this.options.paramName || this.element.name; - this.options.tokens = this.options.tokens || []; - this.options.frequency = this.options.frequency || 0.4; - this.options.minChars = this.options.minChars || 1; - this.options.onShow = this.options.onShow || - function(element, update){ - if(!update.style.position || update.style.position=='absolute') { - update.style.position = 'absolute'; - Position.clone(element, update, { - setHeight: false, - offsetTop: element.offsetHeight - }); - } - Effect.Appear(update,{duration:0.15}); - }; - this.options.onHide = this.options.onHide || - function(element, update){ new Effect.Fade(update,{duration:0.15}) }; - - if(typeof(this.options.tokens) == 'string') - this.options.tokens = new Array(this.options.tokens); - - this.observer = null; - - this.element.setAttribute('autocomplete','off'); - - Element.hide(this.update); - - Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this)); - Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this)); - }, - - show: function() { - if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); - if(!this.iefix && - (navigator.appVersion.indexOf('MSIE')>0) && - (navigator.userAgent.indexOf('Opera')<0) && - (Element.getStyle(this.update, 'position')=='absolute')) { - new Insertion.After(this.update, - ''); - this.iefix = $(this.update.id+'_iefix'); - } - if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); - }, - - fixIEOverlapping: function() { - Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)}); - this.iefix.style.zIndex = 1; - this.update.style.zIndex = 2; - Element.show(this.iefix); - }, - - hide: function() { - this.stopIndicator(); - if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); - if(this.iefix) Element.hide(this.iefix); - }, - - startIndicator: function() { - if(this.options.indicator) Element.show(this.options.indicator); - }, - - stopIndicator: function() { - if(this.options.indicator) Element.hide(this.options.indicator); - }, - - onKeyPress: function(event) { - if(this.active) - switch(event.keyCode) { - case Event.KEY_TAB: - case Event.KEY_RETURN: - this.selectEntry(); - Event.stop(event); - case Event.KEY_ESC: - this.hide(); - this.active = false; - Event.stop(event); - return; - case Event.KEY_LEFT: - case Event.KEY_RIGHT: - return; - case Event.KEY_UP: - this.markPrevious(); - this.render(); - if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event); - return; - case Event.KEY_DOWN: - this.markNext(); - this.render(); - if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event); - return; - } - else - if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || - (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return; - - this.changed = true; - this.hasFocus = true; - - if(this.observer) clearTimeout(this.observer); - this.observer = - setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); - }, - - activate: function() { - this.changed = false; - this.hasFocus = true; - this.getUpdatedChoices(); - }, - - onHover: function(event) { - var element = Event.findElement(event, 'LI'); - if(this.index != element.autocompleteIndex) - { - this.index = element.autocompleteIndex; - this.render(); - } - Event.stop(event); - }, - - onClick: function(event) { - var element = Event.findElement(event, 'LI'); - this.index = element.autocompleteIndex; - this.selectEntry(); - this.hide(); - }, - - onBlur: function(event) { - // needed to make click events working - setTimeout(this.hide.bind(this), 250); - this.hasFocus = false; - this.active = false; - }, - - render: function() { - if(this.entryCount > 0) { - for (var i = 0; i < this.entryCount; i++) - this.index==i ? - Element.addClassName(this.getEntry(i),"selected") : - Element.removeClassName(this.getEntry(i),"selected"); - - if(this.hasFocus) { - this.show(); - this.active = true; - } - } else { - this.active = false; - this.hide(); - } - }, - - markPrevious: function() { - if(this.index > 0) this.index-- - else this.index = this.entryCount-1; - this.getEntry(this.index).scrollIntoView(true); - }, - - markNext: function() { - if(this.index < this.entryCount-1) this.index++ - else this.index = 0; - this.getEntry(this.index).scrollIntoView(false); - }, - - getEntry: function(index) { - return this.update.firstChild.childNodes[index]; - }, - - getCurrentEntry: function() { - return this.getEntry(this.index); - }, - - selectEntry: function() { - this.active = false; - this.updateElement(this.getCurrentEntry()); - }, - - updateElement: function(selectedElement) { - if (this.options.updateElement) { - this.options.updateElement(selectedElement); - return; - } - var value = ''; - if (this.options.select) { - var nodes = document.getElementsByClassName(this.options.select, selectedElement) || []; - if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); - } else - value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); - - var lastTokenPos = this.findLastToken(); - if (lastTokenPos != -1) { - var newValue = this.element.value.substr(0, lastTokenPos + 1); - var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/); - if (whitespace) - newValue += whitespace[0]; - this.element.value = newValue + value; - } else { - this.element.value = value; - } - this.element.focus(); - - if (this.options.afterUpdateElement) - this.options.afterUpdateElement(this.element, selectedElement); - }, - - updateChoices: function(choices) { - if(!this.changed && this.hasFocus) { - this.update.innerHTML = choices; - Element.cleanWhitespace(this.update); - Element.cleanWhitespace(this.update.down()); - - if(this.update.firstChild && this.update.down().childNodes) { - this.entryCount = - this.update.down().childNodes.length; - for (var i = 0; i < this.entryCount; i++) { - var entry = this.getEntry(i); - entry.autocompleteIndex = i; - this.addObservers(entry); - } - } else { - this.entryCount = 0; - } - - this.stopIndicator(); - this.index = 0; - - if(this.entryCount==1 && this.options.autoSelect) { - this.selectEntry(); - this.hide(); - } else { - this.render(); - } - } - }, - - addObservers: function(element) { - Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); - Event.observe(element, "click", this.onClick.bindAsEventListener(this)); - }, - - onObserverEvent: function() { - this.changed = false; - if(this.getToken().length>=this.options.minChars) { - this.startIndicator(); - this.getUpdatedChoices(); - } else { - this.active = false; - this.hide(); - } - }, - - getToken: function() { - var tokenPos = this.findLastToken(); - if (tokenPos != -1) - var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,''); - else - var ret = this.element.value; - - return /\n/.test(ret) ? '' : ret; - }, - - findLastToken: function() { - var lastTokenPos = -1; - - for (var i=0; i lastTokenPos) - lastTokenPos = thisTokenPos; - } - return lastTokenPos; - } -} - -Ajax.Autocompleter = Class.create(); -Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), { - initialize: function(element, update, url, options) { - this.baseInitialize(element, update, options); - this.options.asynchronous = true; - this.options.onComplete = this.onComplete.bind(this); - this.options.defaultParams = this.options.parameters || null; - this.url = url; - }, - - getUpdatedChoices: function() { - entry = encodeURIComponent(this.options.paramName) + '=' + - encodeURIComponent(this.getToken()); - - this.options.parameters = this.options.callback ? - this.options.callback(this.element, entry) : entry; - - if(this.options.defaultParams) - this.options.parameters += '&' + this.options.defaultParams; - - new Ajax.Request(this.url, this.options); - }, - - onComplete: function(request) { - this.updateChoices(request.responseText); - } - -}); - -// The local array autocompleter. Used when you'd prefer to -// inject an array of autocompletion options into the page, rather -// than sending out Ajax queries, which can be quite slow sometimes. -// -// The constructor takes four parameters. The first two are, as usual, -// the id of the monitored textbox, and id of the autocompletion menu. -// The third is the array you want to autocomplete from, and the fourth -// is the options block. -// -// Extra local autocompletion options: -// - choices - How many autocompletion choices to offer -// -// - partialSearch - If false, the autocompleter will match entered -// text only at the beginning of strings in the -// autocomplete array. Defaults to true, which will -// match text at the beginning of any *word* in the -// strings in the autocomplete array. If you want to -// search anywhere in the string, additionally set -// the option fullSearch to true (default: off). -// -// - fullSsearch - Search anywhere in autocomplete array strings. -// -// - partialChars - How many characters to enter before triggering -// a partial match (unlike minChars, which defines -// how many characters are required to do any match -// at all). Defaults to 2. -// -// - ignoreCase - Whether to ignore case when autocompleting. -// Defaults to true. -// -// It's possible to pass in a custom function as the 'selector' -// option, if you prefer to write your own autocompletion logic. -// In that case, the other options above will not apply unless -// you support them. - -Autocompleter.Local = Class.create(); -Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), { - initialize: function(element, update, array, options) { - this.baseInitialize(element, update, options); - this.options.array = array; - }, - - getUpdatedChoices: function() { - this.updateChoices(this.options.selector(this)); - }, - - setOptions: function(options) { - this.options = Object.extend({ - choices: 10, - partialSearch: true, - partialChars: 2, - ignoreCase: true, - fullSearch: false, - selector: function(instance) { - var ret = []; // Beginning matches - var partial = []; // Inside matches - var entry = instance.getToken(); - var count = 0; - - for (var i = 0; i < instance.options.array.length && - ret.length < instance.options.choices ; i++) { - - var elem = instance.options.array[i]; - var foundPos = instance.options.ignoreCase ? - elem.toLowerCase().indexOf(entry.toLowerCase()) : - elem.indexOf(entry); - - while (foundPos != -1) { - if (foundPos == 0 && elem.length != entry.length) { - ret.push("
      • " + elem.substr(0, entry.length) + "" + - elem.substr(entry.length) + "
      • "); - break; - } else if (entry.length >= instance.options.partialChars && - instance.options.partialSearch && foundPos != -1) { - if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { - partial.push("
      • " + elem.substr(0, foundPos) + "" + - elem.substr(foundPos, entry.length) + "" + elem.substr( - foundPos + entry.length) + "
      • "); - break; - } - } - - foundPos = instance.options.ignoreCase ? - elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : - elem.indexOf(entry, foundPos + 1); - - } - } - if (partial.length) - ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)) - return "
          " + ret.join('') + "
        "; - } - }, options || {}); - } -}); - -// AJAX in-place editor -// -// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor - -// Use this if you notice weird scrolling problems on some browsers, -// the DOM might be a bit confused when this gets called so do this -// waits 1 ms (with setTimeout) until it does the activation -Field.scrollFreeActivate = function(field) { - setTimeout(function() { - Field.activate(field); - }, 1); -} - -Ajax.InPlaceEditor = Class.create(); -Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99"; -Ajax.InPlaceEditor.prototype = { - initialize: function(element, url, options) { - this.url = url; - this.element = $(element); - - this.options = Object.extend({ - paramName: "value", - okButton: true, - okText: "ok", - cancelLink: true, - cancelText: "cancel", - savingText: "Saving...", - clickToEditText: "Click to edit", - okText: "ok", - rows: 1, - onComplete: function(transport, element) { - new Effect.Highlight(element, {startcolor: this.options.highlightcolor}); - }, - onFailure: function(transport) { - alert("Error communicating with the server: " + transport.responseText.stripTags()); - }, - callback: function(form) { - return Form.serialize(form); - }, - handleLineBreaks: true, - loadingText: 'Loading...', - savingClassName: 'inplaceeditor-saving', - loadingClassName: 'inplaceeditor-loading', - formClassName: 'inplaceeditor-form', - highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor, - highlightendcolor: "#FFFFFF", - externalControl: null, - submitOnBlur: false, - ajaxOptions: {}, - evalScripts: false - }, options || {}); - - if(!this.options.formId && this.element.id) { - this.options.formId = this.element.id + "-inplaceeditor"; - if ($(this.options.formId)) { - // there's already a form with that name, don't specify an id - this.options.formId = null; - } - } - - if (this.options.externalControl) { - this.options.externalControl = $(this.options.externalControl); - } - - this.originalBackground = Element.getStyle(this.element, 'background-color'); - if (!this.originalBackground) { - this.originalBackground = "transparent"; - } - - this.element.title = this.options.clickToEditText; - - this.onclickListener = this.enterEditMode.bindAsEventListener(this); - this.mouseoverListener = this.enterHover.bindAsEventListener(this); - this.mouseoutListener = this.leaveHover.bindAsEventListener(this); - Event.observe(this.element, 'click', this.onclickListener); - Event.observe(this.element, 'mouseover', this.mouseoverListener); - Event.observe(this.element, 'mouseout', this.mouseoutListener); - if (this.options.externalControl) { - Event.observe(this.options.externalControl, 'click', this.onclickListener); - Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener); - Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener); - } - }, - enterEditMode: function(evt) { - if (this.saving) return; - if (this.editing) return; - this.editing = true; - this.onEnterEditMode(); - if (this.options.externalControl) { - Element.hide(this.options.externalControl); - } - Element.hide(this.element); - this.createForm(); - this.element.parentNode.insertBefore(this.form, this.element); - if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField); - // stop the event to avoid a page refresh in Safari - if (evt) { - Event.stop(evt); - } - return false; - }, - createForm: function() { - this.form = document.createElement("form"); - this.form.id = this.options.formId; - Element.addClassName(this.form, this.options.formClassName) - this.form.onsubmit = this.onSubmit.bind(this); - - this.createEditField(); - - if (this.options.textarea) { - var br = document.createElement("br"); - this.form.appendChild(br); - } - - if (this.options.okButton) { - okButton = document.createElement("input"); - okButton.type = "submit"; - okButton.value = this.options.okText; - okButton.className = 'editor_ok_button'; - this.form.appendChild(okButton); - } - - if (this.options.cancelLink) { - cancelLink = document.createElement("a"); - cancelLink.href = "#"; - cancelLink.appendChild(document.createTextNode(this.options.cancelText)); - cancelLink.onclick = this.onclickCancel.bind(this); - cancelLink.className = 'editor_cancel'; - this.form.appendChild(cancelLink); - } - }, - hasHTMLLineBreaks: function(string) { - if (!this.options.handleLineBreaks) return false; - return string.match(/
        /i); - }, - convertHTMLLineBreaks: function(string) { - return string.replace(/
        /gi, "\n").replace(//gi, "\n").replace(/<\/p>/gi, "\n").replace(/

        /gi, ""); - }, - createEditField: function() { - var text; - if(this.options.loadTextURL) { - text = this.options.loadingText; - } else { - text = this.getText(); - } - - var obj = this; - - if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) { - this.options.textarea = false; - var textField = document.createElement("input"); - textField.obj = this; - textField.type = "text"; - textField.name = this.options.paramName; - textField.value = text; - textField.style.backgroundColor = this.options.highlightcolor; - textField.className = 'editor_field'; - var size = this.options.size || this.options.cols || 0; - if (size != 0) textField.size = size; - if (this.options.submitOnBlur) - textField.onblur = this.onSubmit.bind(this); - this.editField = textField; - } else { - this.options.textarea = true; - var textArea = document.createElement("textarea"); - textArea.obj = this; - textArea.name = this.options.paramName; - textArea.value = this.convertHTMLLineBreaks(text); - textArea.rows = this.options.rows; - textArea.cols = this.options.cols || 40; - textArea.className = 'editor_field'; - if (this.options.submitOnBlur) - textArea.onblur = this.onSubmit.bind(this); - this.editField = textArea; - } - - if(this.options.loadTextURL) { - this.loadExternalText(); - } - this.form.appendChild(this.editField); - }, - getText: function() { - return this.element.innerHTML; - }, - loadExternalText: function() { - Element.addClassName(this.form, this.options.loadingClassName); - this.editField.disabled = true; - new Ajax.Request( - this.options.loadTextURL, - Object.extend({ - asynchronous: true, - onComplete: this.onLoadedExternalText.bind(this) - }, this.options.ajaxOptions) - ); - }, - onLoadedExternalText: function(transport) { - Element.removeClassName(this.form, this.options.loadingClassName); - this.editField.disabled = false; - this.editField.value = transport.responseText.stripTags(); - Field.scrollFreeActivate(this.editField); - }, - onclickCancel: function() { - this.onComplete(); - this.leaveEditMode(); - return false; - }, - onFailure: function(transport) { - this.options.onFailure(transport); - if (this.oldInnerHTML) { - this.element.innerHTML = this.oldInnerHTML; - this.oldInnerHTML = null; - } - return false; - }, - onSubmit: function() { - // onLoading resets these so we need to save them away for the Ajax call - var form = this.form; - var value = this.editField.value; - - // do this first, sometimes the ajax call returns before we get a chance to switch on Saving... - // which means this will actually switch on Saving... *after* we've left edit mode causing Saving... - // to be displayed indefinitely - this.onLoading(); - - if (this.options.evalScripts) { - new Ajax.Request( - this.url, Object.extend({ - parameters: this.options.callback(form, value), - onComplete: this.onComplete.bind(this), - onFailure: this.onFailure.bind(this), - asynchronous:true, - evalScripts:true - }, this.options.ajaxOptions)); - } else { - new Ajax.Updater( - { success: this.element, - // don't update on failure (this could be an option) - failure: null }, - this.url, Object.extend({ - parameters: this.options.callback(form, value), - onComplete: this.onComplete.bind(this), - onFailure: this.onFailure.bind(this) - }, this.options.ajaxOptions)); - } - // stop the event to avoid a page refresh in Safari - if (arguments.length > 1) { - Event.stop(arguments[0]); - } - return false; - }, - onLoading: function() { - this.saving = true; - this.removeForm(); - this.leaveHover(); - this.showSaving(); - }, - showSaving: function() { - this.oldInnerHTML = this.element.innerHTML; - this.element.innerHTML = this.options.savingText; - Element.addClassName(this.element, this.options.savingClassName); - this.element.style.backgroundColor = this.originalBackground; - Element.show(this.element); - }, - removeForm: function() { - if(this.form) { - if (this.form.parentNode) Element.remove(this.form); - this.form = null; - } - }, - enterHover: function() { - if (this.saving) return; - this.element.style.backgroundColor = this.options.highlightcolor; - if (this.effect) { - this.effect.cancel(); - } - Element.addClassName(this.element, this.options.hoverClassName) - }, - leaveHover: function() { - if (this.options.backgroundColor) { - this.element.style.backgroundColor = this.oldBackground; - } - Element.removeClassName(this.element, this.options.hoverClassName) - if (this.saving) return; - this.effect = new Effect.Highlight(this.element, { - startcolor: this.options.highlightcolor, - endcolor: this.options.highlightendcolor, - restorecolor: this.originalBackground - }); - }, - leaveEditMode: function() { - Element.removeClassName(this.element, this.options.savingClassName); - this.removeForm(); - this.leaveHover(); - this.element.style.backgroundColor = this.originalBackground; - Element.show(this.element); - if (this.options.externalControl) { - Element.show(this.options.externalControl); - } - this.editing = false; - this.saving = false; - this.oldInnerHTML = null; - this.onLeaveEditMode(); - }, - onComplete: function(transport) { - this.leaveEditMode(); - this.options.onComplete.bind(this)(transport, this.element); - }, - onEnterEditMode: function() {}, - onLeaveEditMode: function() {}, - dispose: function() { - if (this.oldInnerHTML) { - this.element.innerHTML = this.oldInnerHTML; - } - this.leaveEditMode(); - Event.stopObserving(this.element, 'click', this.onclickListener); - Event.stopObserving(this.element, 'mouseover', this.mouseoverListener); - Event.stopObserving(this.element, 'mouseout', this.mouseoutListener); - if (this.options.externalControl) { - Event.stopObserving(this.options.externalControl, 'click', this.onclickListener); - Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener); - Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener); - } - } -}; - -Ajax.InPlaceCollectionEditor = Class.create(); -Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype); -Object.extend(Ajax.InPlaceCollectionEditor.prototype, { - createEditField: function() { - if (!this.cached_selectTag) { - var selectTag = document.createElement("select"); - var collection = this.options.collection || []; - var optionTag; - collection.each(function(e,i) { - optionTag = document.createElement("option"); - optionTag.value = (e instanceof Array) ? e[0] : e; - if((typeof this.options.value == 'undefined') && - ((e instanceof Array) ? this.element.innerHTML == e[1] : e == optionTag.value)) optionTag.selected = true; - if(this.options.value==optionTag.value) optionTag.selected = true; - optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e)); - selectTag.appendChild(optionTag); - }.bind(this)); - this.cached_selectTag = selectTag; - } - - this.editField = this.cached_selectTag; - if(this.options.loadTextURL) this.loadExternalText(); - this.form.appendChild(this.editField); - this.options.callback = function(form, value) { - return "value=" + encodeURIComponent(value); - } - } -}); - -// Delayed observer, like Form.Element.Observer, -// but waits for delay after last key input -// Ideal for live-search fields - -Form.Element.DelayedObserver = Class.create(); -Form.Element.DelayedObserver.prototype = { - initialize: function(element, delay, callback) { - this.delay = delay || 0.5; - this.element = $(element); - this.callback = callback; - this.timer = null; - this.lastValue = $F(this.element); - Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this)); - }, - delayedListener: function(event) { - if(this.lastValue == $F(this.element)) return; - if(this.timer) clearTimeout(this.timer); - this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000); - this.lastValue = $F(this.element); - }, - onTimerEvent: function() { - this.timer = null; - this.callback(this.element, $F(this.element)); - } -}; diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/dragdrop.js b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/dragdrop.js deleted file mode 100644 index c71ddb82..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/dragdrop.js +++ /dev/null @@ -1,942 +0,0 @@ -// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// (c) 2005, 2006 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) -// -// script.aculo.us is freely distributable under the terms of an MIT-style license. -// For details, see the script.aculo.us web site: http://script.aculo.us/ - -if(typeof Effect == 'undefined') - throw("dragdrop.js requires including script.aculo.us' effects.js library"); - -var Droppables = { - drops: [], - - remove: function(element) { - this.drops = this.drops.reject(function(d) { return d.element==$(element) }); - }, - - add: function(element) { - element = $(element); - var options = Object.extend({ - greedy: true, - hoverclass: null, - tree: false - }, arguments[1] || {}); - - // cache containers - if(options.containment) { - options._containers = []; - var containment = options.containment; - if((typeof containment == 'object') && - (containment.constructor == Array)) { - containment.each( function(c) { options._containers.push($(c)) }); - } else { - options._containers.push($(containment)); - } - } - - if(options.accept) options.accept = [options.accept].flatten(); - - Element.makePositioned(element); // fix IE - options.element = element; - - this.drops.push(options); - }, - - findDeepestChild: function(drops) { - deepest = drops[0]; - - for (i = 1; i < drops.length; ++i) - if (Element.isParent(drops[i].element, deepest.element)) - deepest = drops[i]; - - return deepest; - }, - - isContained: function(element, drop) { - var containmentNode; - if(drop.tree) { - containmentNode = element.treeNode; - } else { - containmentNode = element.parentNode; - } - return drop._containers.detect(function(c) { return containmentNode == c }); - }, - - isAffected: function(point, element, drop) { - return ( - (drop.element!=element) && - ((!drop._containers) || - this.isContained(element, drop)) && - ((!drop.accept) || - (Element.classNames(element).detect( - function(v) { return drop.accept.include(v) } ) )) && - Position.within(drop.element, point[0], point[1]) ); - }, - - deactivate: function(drop) { - if(drop.hoverclass) - Element.removeClassName(drop.element, drop.hoverclass); - this.last_active = null; - }, - - activate: function(drop) { - if(drop.hoverclass) - Element.addClassName(drop.element, drop.hoverclass); - this.last_active = drop; - }, - - show: function(point, element) { - if(!this.drops.length) return; - var affected = []; - - if(this.last_active) this.deactivate(this.last_active); - this.drops.each( function(drop) { - if(Droppables.isAffected(point, element, drop)) - affected.push(drop); - }); - - if(affected.length>0) { - drop = Droppables.findDeepestChild(affected); - Position.within(drop.element, point[0], point[1]); - if(drop.onHover) - drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); - - Droppables.activate(drop); - } - }, - - fire: function(event, element) { - if(!this.last_active) return; - Position.prepare(); - - if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active)) - if (this.last_active.onDrop) - this.last_active.onDrop(element, this.last_active.element, event); - }, - - reset: function() { - if(this.last_active) - this.deactivate(this.last_active); - } -} - -var Draggables = { - drags: [], - observers: [], - - register: function(draggable) { - if(this.drags.length == 0) { - this.eventMouseUp = this.endDrag.bindAsEventListener(this); - this.eventMouseMove = this.updateDrag.bindAsEventListener(this); - this.eventKeypress = this.keyPress.bindAsEventListener(this); - - Event.observe(document, "mouseup", this.eventMouseUp); - Event.observe(document, "mousemove", this.eventMouseMove); - Event.observe(document, "keypress", this.eventKeypress); - } - this.drags.push(draggable); - }, - - unregister: function(draggable) { - this.drags = this.drags.reject(function(d) { return d==draggable }); - if(this.drags.length == 0) { - Event.stopObserving(document, "mouseup", this.eventMouseUp); - Event.stopObserving(document, "mousemove", this.eventMouseMove); - Event.stopObserving(document, "keypress", this.eventKeypress); - } - }, - - activate: function(draggable) { - if(draggable.options.delay) { - this._timeout = setTimeout(function() { - Draggables._timeout = null; - window.focus(); - Draggables.activeDraggable = draggable; - }.bind(this), draggable.options.delay); - } else { - window.focus(); // allows keypress events if window isn't currently focused, fails for Safari - this.activeDraggable = draggable; - } - }, - - deactivate: function() { - this.activeDraggable = null; - }, - - updateDrag: function(event) { - if(!this.activeDraggable) return; - var pointer = [Event.pointerX(event), Event.pointerY(event)]; - // Mozilla-based browsers fire successive mousemove events with - // the same coordinates, prevent needless redrawing (moz bug?) - if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; - this._lastPointer = pointer; - - this.activeDraggable.updateDrag(event, pointer); - }, - - endDrag: function(event) { - if(this._timeout) { - clearTimeout(this._timeout); - this._timeout = null; - } - if(!this.activeDraggable) return; - this._lastPointer = null; - this.activeDraggable.endDrag(event); - this.activeDraggable = null; - }, - - keyPress: function(event) { - if(this.activeDraggable) - this.activeDraggable.keyPress(event); - }, - - addObserver: function(observer) { - this.observers.push(observer); - this._cacheObserverCallbacks(); - }, - - removeObserver: function(element) { // element instead of observer fixes mem leaks - this.observers = this.observers.reject( function(o) { return o.element==element }); - this._cacheObserverCallbacks(); - }, - - notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' - if(this[eventName+'Count'] > 0) - this.observers.each( function(o) { - if(o[eventName]) o[eventName](eventName, draggable, event); - }); - if(draggable.options[eventName]) draggable.options[eventName](draggable, event); - }, - - _cacheObserverCallbacks: function() { - ['onStart','onEnd','onDrag'].each( function(eventName) { - Draggables[eventName+'Count'] = Draggables.observers.select( - function(o) { return o[eventName]; } - ).length; - }); - } -} - -/*--------------------------------------------------------------------------*/ - -var Draggable = Class.create(); -Draggable._dragging = {}; - -Draggable.prototype = { - initialize: function(element) { - var defaults = { - handle: false, - reverteffect: function(element, top_offset, left_offset) { - var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; - new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur, - queue: {scope:'_draggable', position:'end'} - }); - }, - endeffect: function(element) { - var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0; - new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, - queue: {scope:'_draggable', position:'end'}, - afterFinish: function(){ - Draggable._dragging[element] = false - } - }); - }, - zindex: 1000, - revert: false, - scroll: false, - scrollSensitivity: 20, - scrollSpeed: 15, - snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] } - delay: 0 - }; - - if(!arguments[1] || typeof arguments[1].endeffect == 'undefined') - Object.extend(defaults, { - starteffect: function(element) { - element._opacity = Element.getOpacity(element); - Draggable._dragging[element] = true; - new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); - } - }); - - var options = Object.extend(defaults, arguments[1] || {}); - - this.element = $(element); - - if(options.handle && (typeof options.handle == 'string')) - this.handle = this.element.down('.'+options.handle, 0); - - if(!this.handle) this.handle = $(options.handle); - if(!this.handle) this.handle = this.element; - - if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) { - options.scroll = $(options.scroll); - this._isScrollChild = Element.childOf(this.element, options.scroll); - } - - Element.makePositioned(this.element); // fix IE - - this.delta = this.currentDelta(); - this.options = options; - this.dragging = false; - - this.eventMouseDown = this.initDrag.bindAsEventListener(this); - Event.observe(this.handle, "mousedown", this.eventMouseDown); - - Draggables.register(this); - }, - - destroy: function() { - Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); - Draggables.unregister(this); - }, - - currentDelta: function() { - return([ - parseInt(Element.getStyle(this.element,'left') || '0'), - parseInt(Element.getStyle(this.element,'top') || '0')]); - }, - - initDrag: function(event) { - if(typeof Draggable._dragging[this.element] != 'undefined' && - Draggable._dragging[this.element]) return; - if(Event.isLeftClick(event)) { - // abort on form elements, fixes a Firefox issue - var src = Event.element(event); - if(src.tagName && ( - src.tagName=='INPUT' || - src.tagName=='SELECT' || - src.tagName=='OPTION' || - src.tagName=='BUTTON' || - src.tagName=='TEXTAREA')) return; - - var pointer = [Event.pointerX(event), Event.pointerY(event)]; - var pos = Position.cumulativeOffset(this.element); - this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); - - Draggables.activate(this); - Event.stop(event); - } - }, - - startDrag: function(event) { - this.dragging = true; - - if(this.options.zindex) { - this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); - this.element.style.zIndex = this.options.zindex; - } - - if(this.options.ghosting) { - this._clone = this.element.cloneNode(true); - Position.absolutize(this.element); - this.element.parentNode.insertBefore(this._clone, this.element); - } - - if(this.options.scroll) { - if (this.options.scroll == window) { - var where = this._getWindowScroll(this.options.scroll); - this.originalScrollLeft = where.left; - this.originalScrollTop = where.top; - } else { - this.originalScrollLeft = this.options.scroll.scrollLeft; - this.originalScrollTop = this.options.scroll.scrollTop; - } - } - - Draggables.notify('onStart', this, event); - - if(this.options.starteffect) this.options.starteffect(this.element); - }, - - updateDrag: function(event, pointer) { - if(!this.dragging) this.startDrag(event); - Position.prepare(); - Droppables.show(pointer, this.element); - Draggables.notify('onDrag', this, event); - - this.draw(pointer); - if(this.options.change) this.options.change(this); - - if(this.options.scroll) { - this.stopScrolling(); - - var p; - if (this.options.scroll == window) { - with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; } - } else { - p = Position.page(this.options.scroll); - p[0] += this.options.scroll.scrollLeft + Position.deltaX; - p[1] += this.options.scroll.scrollTop + Position.deltaY; - p.push(p[0]+this.options.scroll.offsetWidth); - p.push(p[1]+this.options.scroll.offsetHeight); - } - var speed = [0,0]; - if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity); - if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity); - if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity); - if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity); - this.startScrolling(speed); - } - - // fix AppleWebKit rendering - if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); - - Event.stop(event); - }, - - finishDrag: function(event, success) { - this.dragging = false; - - if(this.options.ghosting) { - Position.relativize(this.element); - Element.remove(this._clone); - this._clone = null; - } - - if(success) Droppables.fire(event, this.element); - Draggables.notify('onEnd', this, event); - - var revert = this.options.revert; - if(revert && typeof revert == 'function') revert = revert(this.element); - - var d = this.currentDelta(); - if(revert && this.options.reverteffect) { - this.options.reverteffect(this.element, - d[1]-this.delta[1], d[0]-this.delta[0]); - } else { - this.delta = d; - } - - if(this.options.zindex) - this.element.style.zIndex = this.originalZ; - - if(this.options.endeffect) - this.options.endeffect(this.element); - - Draggables.deactivate(this); - Droppables.reset(); - }, - - keyPress: function(event) { - if(event.keyCode!=Event.KEY_ESC) return; - this.finishDrag(event, false); - Event.stop(event); - }, - - endDrag: function(event) { - if(!this.dragging) return; - this.stopScrolling(); - this.finishDrag(event, true); - Event.stop(event); - }, - - draw: function(point) { - var pos = Position.cumulativeOffset(this.element); - if(this.options.ghosting) { - var r = Position.realOffset(this.element); - pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY; - } - - var d = this.currentDelta(); - pos[0] -= d[0]; pos[1] -= d[1]; - - if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) { - pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft; - pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop; - } - - var p = [0,1].map(function(i){ - return (point[i]-pos[i]-this.offset[i]) - }.bind(this)); - - if(this.options.snap) { - if(typeof this.options.snap == 'function') { - p = this.options.snap(p[0],p[1],this); - } else { - if(this.options.snap instanceof Array) { - p = p.map( function(v, i) { - return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this)) - } else { - p = p.map( function(v) { - return Math.round(v/this.options.snap)*this.options.snap }.bind(this)) - } - }} - - var style = this.element.style; - if((!this.options.constraint) || (this.options.constraint=='horizontal')) - style.left = p[0] + "px"; - if((!this.options.constraint) || (this.options.constraint=='vertical')) - style.top = p[1] + "px"; - - if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering - }, - - stopScrolling: function() { - if(this.scrollInterval) { - clearInterval(this.scrollInterval); - this.scrollInterval = null; - Draggables._lastScrollPointer = null; - } - }, - - startScrolling: function(speed) { - if(!(speed[0] || speed[1])) return; - this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed]; - this.lastScrolled = new Date(); - this.scrollInterval = setInterval(this.scroll.bind(this), 10); - }, - - scroll: function() { - var current = new Date(); - var delta = current - this.lastScrolled; - this.lastScrolled = current; - if(this.options.scroll == window) { - with (this._getWindowScroll(this.options.scroll)) { - if (this.scrollSpeed[0] || this.scrollSpeed[1]) { - var d = delta / 1000; - this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] ); - } - } - } else { - this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000; - this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000; - } - - Position.prepare(); - Droppables.show(Draggables._lastPointer, this.element); - Draggables.notify('onDrag', this); - if (this._isScrollChild) { - Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); - Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; - Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; - if (Draggables._lastScrollPointer[0] < 0) - Draggables._lastScrollPointer[0] = 0; - if (Draggables._lastScrollPointer[1] < 0) - Draggables._lastScrollPointer[1] = 0; - this.draw(Draggables._lastScrollPointer); - } - - if(this.options.change) this.options.change(this); - }, - - _getWindowScroll: function(w) { - var T, L, W, H; - with (w.document) { - if (w.document.documentElement && documentElement.scrollTop) { - T = documentElement.scrollTop; - L = documentElement.scrollLeft; - } else if (w.document.body) { - T = body.scrollTop; - L = body.scrollLeft; - } - if (w.innerWidth) { - W = w.innerWidth; - H = w.innerHeight; - } else if (w.document.documentElement && documentElement.clientWidth) { - W = documentElement.clientWidth; - H = documentElement.clientHeight; - } else { - W = body.offsetWidth; - H = body.offsetHeight - } - } - return { top: T, left: L, width: W, height: H }; - } -} - -/*--------------------------------------------------------------------------*/ - -var SortableObserver = Class.create(); -SortableObserver.prototype = { - initialize: function(element, observer) { - this.element = $(element); - this.observer = observer; - this.lastValue = Sortable.serialize(this.element); - }, - - onStart: function() { - this.lastValue = Sortable.serialize(this.element); - }, - - onEnd: function() { - Sortable.unmark(); - if(this.lastValue != Sortable.serialize(this.element)) - this.observer(this.element) - } -} - -var Sortable = { - SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/, - - sortables: {}, - - _findRootElement: function(element) { - while (element.tagName != "BODY") { - if(element.id && Sortable.sortables[element.id]) return element; - element = element.parentNode; - } - }, - - options: function(element) { - element = Sortable._findRootElement($(element)); - if(!element) return; - return Sortable.sortables[element.id]; - }, - - destroy: function(element){ - var s = Sortable.options(element); - - if(s) { - Draggables.removeObserver(s.element); - s.droppables.each(function(d){ Droppables.remove(d) }); - s.draggables.invoke('destroy'); - - delete Sortable.sortables[s.element.id]; - } - }, - - create: function(element) { - element = $(element); - var options = Object.extend({ - element: element, - tag: 'li', // assumes li children, override with tag: 'tagname' - dropOnEmpty: false, - tree: false, - treeTag: 'ul', - overlap: 'vertical', // one of 'vertical', 'horizontal' - constraint: 'vertical', // one of 'vertical', 'horizontal', false - containment: element, // also takes array of elements (or id's); or false - handle: false, // or a CSS class - only: false, - delay: 0, - hoverclass: null, - ghosting: false, - scroll: false, - scrollSensitivity: 20, - scrollSpeed: 15, - format: this.SERIALIZE_RULE, - onChange: Prototype.emptyFunction, - onUpdate: Prototype.emptyFunction - }, arguments[1] || {}); - - // clear any old sortable with same element - this.destroy(element); - - // build options for the draggables - var options_for_draggable = { - revert: true, - scroll: options.scroll, - scrollSpeed: options.scrollSpeed, - scrollSensitivity: options.scrollSensitivity, - delay: options.delay, - ghosting: options.ghosting, - constraint: options.constraint, - handle: options.handle }; - - if(options.starteffect) - options_for_draggable.starteffect = options.starteffect; - - if(options.reverteffect) - options_for_draggable.reverteffect = options.reverteffect; - else - if(options.ghosting) options_for_draggable.reverteffect = function(element) { - element.style.top = 0; - element.style.left = 0; - }; - - if(options.endeffect) - options_for_draggable.endeffect = options.endeffect; - - if(options.zindex) - options_for_draggable.zindex = options.zindex; - - // build options for the droppables - var options_for_droppable = { - overlap: options.overlap, - containment: options.containment, - tree: options.tree, - hoverclass: options.hoverclass, - onHover: Sortable.onHover - } - - var options_for_tree = { - onHover: Sortable.onEmptyHover, - overlap: options.overlap, - containment: options.containment, - hoverclass: options.hoverclass - } - - // fix for gecko engine - Element.cleanWhitespace(element); - - options.draggables = []; - options.droppables = []; - - // drop on empty handling - if(options.dropOnEmpty || options.tree) { - Droppables.add(element, options_for_tree); - options.droppables.push(element); - } - - (this.findElements(element, options) || []).each( function(e) { - // handles are per-draggable - var handle = options.handle ? - $(e).down('.'+options.handle,0) : e; - options.draggables.push( - new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); - Droppables.add(e, options_for_droppable); - if(options.tree) e.treeNode = element; - options.droppables.push(e); - }); - - if(options.tree) { - (Sortable.findTreeElements(element, options) || []).each( function(e) { - Droppables.add(e, options_for_tree); - e.treeNode = element; - options.droppables.push(e); - }); - } - - // keep reference - this.sortables[element.id] = options; - - // for onupdate - Draggables.addObserver(new SortableObserver(element, options.onUpdate)); - - }, - - // return all suitable-for-sortable elements in a guaranteed order - findElements: function(element, options) { - return Element.findChildren( - element, options.only, options.tree ? true : false, options.tag); - }, - - findTreeElements: function(element, options) { - return Element.findChildren( - element, options.only, options.tree ? true : false, options.treeTag); - }, - - onHover: function(element, dropon, overlap) { - if(Element.isParent(dropon, element)) return; - - if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) { - return; - } else if(overlap>0.5) { - Sortable.mark(dropon, 'before'); - if(dropon.previousSibling != element) { - var oldParentNode = element.parentNode; - element.style.visibility = "hidden"; // fix gecko rendering - dropon.parentNode.insertBefore(element, dropon); - if(dropon.parentNode!=oldParentNode) - Sortable.options(oldParentNode).onChange(element); - Sortable.options(dropon.parentNode).onChange(element); - } - } else { - Sortable.mark(dropon, 'after'); - var nextElement = dropon.nextSibling || null; - if(nextElement != element) { - var oldParentNode = element.parentNode; - element.style.visibility = "hidden"; // fix gecko rendering - dropon.parentNode.insertBefore(element, nextElement); - if(dropon.parentNode!=oldParentNode) - Sortable.options(oldParentNode).onChange(element); - Sortable.options(dropon.parentNode).onChange(element); - } - } - }, - - onEmptyHover: function(element, dropon, overlap) { - var oldParentNode = element.parentNode; - var droponOptions = Sortable.options(dropon); - - if(!Element.isParent(dropon, element)) { - var index; - - var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only}); - var child = null; - - if(children) { - var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); - - for (index = 0; index < children.length; index += 1) { - if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) { - offset -= Element.offsetSize (children[index], droponOptions.overlap); - } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) { - child = index + 1 < children.length ? children[index + 1] : null; - break; - } else { - child = children[index]; - break; - } - } - } - - dropon.insertBefore(element, child); - - Sortable.options(oldParentNode).onChange(element); - droponOptions.onChange(element); - } - }, - - unmark: function() { - if(Sortable._marker) Sortable._marker.hide(); - }, - - mark: function(dropon, position) { - // mark on ghosting only - var sortable = Sortable.options(dropon.parentNode); - if(sortable && !sortable.ghosting) return; - - if(!Sortable._marker) { - Sortable._marker = - ($('dropmarker') || Element.extend(document.createElement('DIV'))). - hide().addClassName('dropmarker').setStyle({position:'absolute'}); - document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); - } - var offsets = Position.cumulativeOffset(dropon); - Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'}); - - if(position=='after') - if(sortable.overlap == 'horizontal') - Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'}); - else - Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'}); - - Sortable._marker.show(); - }, - - _tree: function(element, options, parent) { - var children = Sortable.findElements(element, options) || []; - - for (var i = 0; i < children.length; ++i) { - var match = children[i].id.match(options.format); - - if (!match) continue; - - var child = { - id: encodeURIComponent(match ? match[1] : null), - element: element, - parent: parent, - children: [], - position: parent.children.length, - container: $(children[i]).down(options.treeTag) - } - - /* Get the element containing the children and recurse over it */ - if (child.container) - this._tree(child.container, options, child) - - parent.children.push (child); - } - - return parent; - }, - - tree: function(element) { - element = $(element); - var sortableOptions = this.options(element); - var options = Object.extend({ - tag: sortableOptions.tag, - treeTag: sortableOptions.treeTag, - only: sortableOptions.only, - name: element.id, - format: sortableOptions.format - }, arguments[1] || {}); - - var root = { - id: null, - parent: null, - children: [], - container: element, - position: 0 - } - - return Sortable._tree(element, options, root); - }, - - /* Construct a [i] index for a particular node */ - _constructIndex: function(node) { - var index = ''; - do { - if (node.id) index = '[' + node.position + ']' + index; - } while ((node = node.parent) != null); - return index; - }, - - sequence: function(element) { - element = $(element); - var options = Object.extend(this.options(element), arguments[1] || {}); - - return $(this.findElements(element, options) || []).map( function(item) { - return item.id.match(options.format) ? item.id.match(options.format)[1] : ''; - }); - }, - - setSequence: function(element, new_sequence) { - element = $(element); - var options = Object.extend(this.options(element), arguments[2] || {}); - - var nodeMap = {}; - this.findElements(element, options).each( function(n) { - if (n.id.match(options.format)) - nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode]; - n.parentNode.removeChild(n); - }); - - new_sequence.each(function(ident) { - var n = nodeMap[ident]; - if (n) { - n[1].appendChild(n[0]); - delete nodeMap[ident]; - } - }); - }, - - serialize: function(element) { - element = $(element); - var options = Object.extend(Sortable.options(element), arguments[1] || {}); - var name = encodeURIComponent( - (arguments[1] && arguments[1].name) ? arguments[1].name : element.id); - - if (options.tree) { - return Sortable.tree(element, arguments[1]).children.map( function (item) { - return [name + Sortable._constructIndex(item) + "[id]=" + - encodeURIComponent(item.id)].concat(item.children.map(arguments.callee)); - }).flatten().join('&'); - } else { - return Sortable.sequence(element, arguments[1]).map( function(item) { - return name + "[]=" + encodeURIComponent(item); - }).join('&'); - } - } -} - -// Returns true if child is contained within element -Element.isParent = function(child, element) { - if (!child.parentNode || child == element) return false; - if (child.parentNode == element) return true; - return Element.isParent(child.parentNode, element); -} - -Element.findChildren = function(element, only, recursive, tagName) { - if(!element.hasChildNodes()) return null; - tagName = tagName.toUpperCase(); - if(only) only = [only].flatten(); - var elements = []; - $A(element.childNodes).each( function(e) { - if(e.tagName && e.tagName.toUpperCase()==tagName && - (!only || (Element.classNames(e).detect(function(v) { return only.include(v) })))) - elements.push(e); - if(recursive) { - var grandchildren = Element.findChildren(e, only, recursive, tagName); - if(grandchildren) elements.push(grandchildren); - } - }); - - return (elements.length>0 ? elements.flatten() : []); -} - -Element.offsetSize = function (element, type) { - return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')]; -} diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/effects.js b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/effects.js deleted file mode 100644 index 3b02eda2..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/effects.js +++ /dev/null @@ -1,1088 +0,0 @@ -// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// Contributors: -// Justin Palmer (http://encytemedia.com/) -// Mark Pilgrim (http://diveintomark.org/) -// Martin Bialasinki -// -// script.aculo.us is freely distributable under the terms of an MIT-style license. -// For details, see the script.aculo.us web site: http://script.aculo.us/ - -// converts rgb() and #xxx to #xxxxxx format, -// returns self (or first argument) if not convertable -String.prototype.parseColor = function() { - var color = '#'; - if(this.slice(0,4) == 'rgb(') { - var cols = this.slice(4,this.length-1).split(','); - var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); - } else { - if(this.slice(0,1) == '#') { - if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); - if(this.length==7) color = this.toLowerCase(); - } - } - return(color.length==7 ? color : (arguments[0] || this)); -} - -/*--------------------------------------------------------------------------*/ - -Element.collectTextNodes = function(element) { - return $A($(element).childNodes).collect( function(node) { - return (node.nodeType==3 ? node.nodeValue : - (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); - }).flatten().join(''); -} - -Element.collectTextNodesIgnoreClass = function(element, className) { - return $A($(element).childNodes).collect( function(node) { - return (node.nodeType==3 ? node.nodeValue : - ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? - Element.collectTextNodesIgnoreClass(node, className) : '')); - }).flatten().join(''); -} - -Element.setContentZoom = function(element, percent) { - element = $(element); - element.setStyle({fontSize: (percent/100) + 'em'}); - if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); - return element; -} - -Element.getOpacity = function(element){ - element = $(element); - var opacity; - if (opacity = element.getStyle('opacity')) - return parseFloat(opacity); - if (opacity = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) - if(opacity[1]) return parseFloat(opacity[1]) / 100; - return 1.0; -} - -Element.setOpacity = function(element, value){ - element= $(element); - if (value == 1){ - element.setStyle({ opacity: - (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? - 0.999999 : 1.0 }); - if(/MSIE/.test(navigator.userAgent) && !window.opera) - element.setStyle({filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')}); - } else { - if(value < 0.00001) value = 0; - element.setStyle({opacity: value}); - if(/MSIE/.test(navigator.userAgent) && !window.opera) - element.setStyle( - { filter: element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') + - 'alpha(opacity='+value*100+')' }); - } - return element; -} - -Element.getInlineOpacity = function(element){ - return $(element).style.opacity || ''; -} - -Element.forceRerendering = function(element) { - try { - element = $(element); - var n = document.createTextNode(' '); - element.appendChild(n); - element.removeChild(n); - } catch(e) { } -}; - -/*--------------------------------------------------------------------------*/ - -Array.prototype.call = function() { - var args = arguments; - this.each(function(f){ f.apply(this, args) }); -} - -/*--------------------------------------------------------------------------*/ - -var Effect = { - _elementDoesNotExistError: { - name: 'ElementDoesNotExistError', - message: 'The specified DOM element does not exist, but is required for this effect to operate' - }, - tagifyText: function(element) { - if(typeof Builder == 'undefined') - throw("Effect.tagifyText requires including script.aculo.us' builder.js library"); - - var tagifyStyle = 'position:relative'; - if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1'; - - element = $(element); - $A(element.childNodes).each( function(child) { - if(child.nodeType==3) { - child.nodeValue.toArray().each( function(character) { - element.insertBefore( - Builder.node('span',{style: tagifyStyle}, - character == ' ' ? String.fromCharCode(160) : character), - child); - }); - Element.remove(child); - } - }); - }, - multiple: function(element, effect) { - var elements; - if(((typeof element == 'object') || - (typeof element == 'function')) && - (element.length)) - elements = element; - else - elements = $(element).childNodes; - - var options = Object.extend({ - speed: 0.1, - delay: 0.0 - }, arguments[2] || {}); - var masterDelay = options.delay; - - $A(elements).each( function(element, index) { - new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); - }); - }, - PAIRS: { - 'slide': ['SlideDown','SlideUp'], - 'blind': ['BlindDown','BlindUp'], - 'appear': ['Appear','Fade'] - }, - toggle: function(element, effect) { - element = $(element); - effect = (effect || 'appear').toLowerCase(); - var options = Object.extend({ - queue: { position:'end', scope:(element.id || 'global'), limit: 1 } - }, arguments[2] || {}); - Effect[element.visible() ? - Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); - } -}; - -var Effect2 = Effect; // deprecated - -/* ------------- transitions ------------- */ - -Effect.Transitions = { - linear: Prototype.K, - sinoidal: function(pos) { - return (-Math.cos(pos*Math.PI)/2) + 0.5; - }, - reverse: function(pos) { - return 1-pos; - }, - flicker: function(pos) { - return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4; - }, - wobble: function(pos) { - return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5; - }, - pulse: function(pos, pulses) { - pulses = pulses || 5; - return ( - Math.round((pos % (1/pulses)) * pulses) == 0 ? - ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) : - 1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) - ); - }, - none: function(pos) { - return 0; - }, - full: function(pos) { - return 1; - } -}; - -/* ------------- core effects ------------- */ - -Effect.ScopedQueue = Class.create(); -Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), { - initialize: function() { - this.effects = []; - this.interval = null; - }, - _each: function(iterator) { - this.effects._each(iterator); - }, - add: function(effect) { - var timestamp = new Date().getTime(); - - var position = (typeof effect.options.queue == 'string') ? - effect.options.queue : effect.options.queue.position; - - switch(position) { - case 'front': - // move unstarted effects after this effect - this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { - e.startOn += effect.finishOn; - e.finishOn += effect.finishOn; - }); - break; - case 'with-last': - timestamp = this.effects.pluck('startOn').max() || timestamp; - break; - case 'end': - // start effect after last queued effect has finished - timestamp = this.effects.pluck('finishOn').max() || timestamp; - break; - } - - effect.startOn += timestamp; - effect.finishOn += timestamp; - - if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) - this.effects.push(effect); - - if(!this.interval) - this.interval = setInterval(this.loop.bind(this), 40); - }, - remove: function(effect) { - this.effects = this.effects.reject(function(e) { return e==effect }); - if(this.effects.length == 0) { - clearInterval(this.interval); - this.interval = null; - } - }, - loop: function() { - var timePos = new Date().getTime(); - this.effects.invoke('loop', timePos); - } -}); - -Effect.Queues = { - instances: $H(), - get: function(queueName) { - if(typeof queueName != 'string') return queueName; - - if(!this.instances[queueName]) - this.instances[queueName] = new Effect.ScopedQueue(); - - return this.instances[queueName]; - } -} -Effect.Queue = Effect.Queues.get('global'); - -Effect.DefaultOptions = { - transition: Effect.Transitions.sinoidal, - duration: 1.0, // seconds - fps: 25.0, // max. 25fps due to Effect.Queue implementation - sync: false, // true for combining - from: 0.0, - to: 1.0, - delay: 0.0, - queue: 'parallel' -} - -Effect.Base = function() {}; -Effect.Base.prototype = { - position: null, - start: function(options) { - this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {}); - this.currentFrame = 0; - this.state = 'idle'; - this.startOn = this.options.delay*1000; - this.finishOn = this.startOn + (this.options.duration*1000); - this.event('beforeStart'); - if(!this.options.sync) - Effect.Queues.get(typeof this.options.queue == 'string' ? - 'global' : this.options.queue.scope).add(this); - }, - loop: function(timePos) { - if(timePos >= this.startOn) { - if(timePos >= this.finishOn) { - this.render(1.0); - this.cancel(); - this.event('beforeFinish'); - if(this.finish) this.finish(); - this.event('afterFinish'); - return; - } - var pos = (timePos - this.startOn) / (this.finishOn - this.startOn); - var frame = Math.round(pos * this.options.fps * this.options.duration); - if(frame > this.currentFrame) { - this.render(pos); - this.currentFrame = frame; - } - } - }, - render: function(pos) { - if(this.state == 'idle') { - this.state = 'running'; - this.event('beforeSetup'); - if(this.setup) this.setup(); - this.event('afterSetup'); - } - if(this.state == 'running') { - if(this.options.transition) pos = this.options.transition(pos); - pos *= (this.options.to-this.options.from); - pos += this.options.from; - this.position = pos; - this.event('beforeUpdate'); - if(this.update) this.update(pos); - this.event('afterUpdate'); - } - }, - cancel: function() { - if(!this.options.sync) - Effect.Queues.get(typeof this.options.queue == 'string' ? - 'global' : this.options.queue.scope).remove(this); - this.state = 'finished'; - }, - event: function(eventName) { - if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); - if(this.options[eventName]) this.options[eventName](this); - }, - inspect: function() { - return '#'; - } -} - -Effect.Parallel = Class.create(); -Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), { - initialize: function(effects) { - this.effects = effects || []; - this.start(arguments[1]); - }, - update: function(position) { - this.effects.invoke('render', position); - }, - finish: function(position) { - this.effects.each( function(effect) { - effect.render(1.0); - effect.cancel(); - effect.event('beforeFinish'); - if(effect.finish) effect.finish(position); - effect.event('afterFinish'); - }); - } -}); - -Effect.Event = Class.create(); -Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), { - initialize: function() { - var options = Object.extend({ - duration: 0 - }, arguments[0] || {}); - this.start(options); - }, - update: Prototype.emptyFunction -}); - -Effect.Opacity = Class.create(); -Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), { - initialize: function(element) { - this.element = $(element); - if(!this.element) throw(Effect._elementDoesNotExistError); - // make this work on IE on elements without 'layout' - if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout)) - this.element.setStyle({zoom: 1}); - var options = Object.extend({ - from: this.element.getOpacity() || 0.0, - to: 1.0 - }, arguments[1] || {}); - this.start(options); - }, - update: function(position) { - this.element.setOpacity(position); - } -}); - -Effect.Move = Class.create(); -Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), { - initialize: function(element) { - this.element = $(element); - if(!this.element) throw(Effect._elementDoesNotExistError); - var options = Object.extend({ - x: 0, - y: 0, - mode: 'relative' - }, arguments[1] || {}); - this.start(options); - }, - setup: function() { - // Bug in Opera: Opera returns the "real" position of a static element or - // relative element that does not have top/left explicitly set. - // ==> Always set top and left for position relative elements in your stylesheets - // (to 0 if you do not need them) - this.element.makePositioned(); - this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); - this.originalTop = parseFloat(this.element.getStyle('top') || '0'); - if(this.options.mode == 'absolute') { - // absolute movement, so we need to calc deltaX and deltaY - this.options.x = this.options.x - this.originalLeft; - this.options.y = this.options.y - this.originalTop; - } - }, - update: function(position) { - this.element.setStyle({ - left: Math.round(this.options.x * position + this.originalLeft) + 'px', - top: Math.round(this.options.y * position + this.originalTop) + 'px' - }); - } -}); - -// for backwards compatibility -Effect.MoveBy = function(element, toTop, toLeft) { - return new Effect.Move(element, - Object.extend({ x: toLeft, y: toTop }, arguments[3] || {})); -}; - -Effect.Scale = Class.create(); -Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), { - initialize: function(element, percent) { - this.element = $(element); - if(!this.element) throw(Effect._elementDoesNotExistError); - var options = Object.extend({ - scaleX: true, - scaleY: true, - scaleContent: true, - scaleFromCenter: false, - scaleMode: 'box', // 'box' or 'contents' or {} with provided values - scaleFrom: 100.0, - scaleTo: percent - }, arguments[2] || {}); - this.start(options); - }, - setup: function() { - this.restoreAfterFinish = this.options.restoreAfterFinish || false; - this.elementPositioning = this.element.getStyle('position'); - - this.originalStyle = {}; - ['top','left','width','height','fontSize'].each( function(k) { - this.originalStyle[k] = this.element.style[k]; - }.bind(this)); - - this.originalTop = this.element.offsetTop; - this.originalLeft = this.element.offsetLeft; - - var fontSize = this.element.getStyle('font-size') || '100%'; - ['em','px','%','pt'].each( function(fontSizeType) { - if(fontSize.indexOf(fontSizeType)>0) { - this.fontSize = parseFloat(fontSize); - this.fontSizeType = fontSizeType; - } - }.bind(this)); - - this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; - - this.dims = null; - if(this.options.scaleMode=='box') - this.dims = [this.element.offsetHeight, this.element.offsetWidth]; - if(/^content/.test(this.options.scaleMode)) - this.dims = [this.element.scrollHeight, this.element.scrollWidth]; - if(!this.dims) - this.dims = [this.options.scaleMode.originalHeight, - this.options.scaleMode.originalWidth]; - }, - update: function(position) { - var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); - if(this.options.scaleContent && this.fontSize) - this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); - this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); - }, - finish: function(position) { - if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle); - }, - setDimensions: function(height, width) { - var d = {}; - if(this.options.scaleX) d.width = Math.round(width) + 'px'; - if(this.options.scaleY) d.height = Math.round(height) + 'px'; - if(this.options.scaleFromCenter) { - var topd = (height - this.dims[0])/2; - var leftd = (width - this.dims[1])/2; - if(this.elementPositioning == 'absolute') { - if(this.options.scaleY) d.top = this.originalTop-topd + 'px'; - if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; - } else { - if(this.options.scaleY) d.top = -topd + 'px'; - if(this.options.scaleX) d.left = -leftd + 'px'; - } - } - this.element.setStyle(d); - } -}); - -Effect.Highlight = Class.create(); -Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), { - initialize: function(element) { - this.element = $(element); - if(!this.element) throw(Effect._elementDoesNotExistError); - var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {}); - this.start(options); - }, - setup: function() { - // Prevent executing on elements not in the layout flow - if(this.element.getStyle('display')=='none') { this.cancel(); return; } - // Disable background image during the effect - this.oldStyle = { - backgroundImage: this.element.getStyle('background-image') }; - this.element.setStyle({backgroundImage: 'none'}); - if(!this.options.endcolor) - this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); - if(!this.options.restorecolor) - this.options.restorecolor = this.element.getStyle('background-color'); - // init color calculations - this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); - this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); - }, - update: function(position) { - this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ - return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) }); - }, - finish: function() { - this.element.setStyle(Object.extend(this.oldStyle, { - backgroundColor: this.options.restorecolor - })); - } -}); - -Effect.ScrollTo = Class.create(); -Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), { - initialize: function(element) { - this.element = $(element); - this.start(arguments[1] || {}); - }, - setup: function() { - Position.prepare(); - var offsets = Position.cumulativeOffset(this.element); - if(this.options.offset) offsets[1] += this.options.offset; - var max = window.innerHeight ? - window.height - window.innerHeight : - document.body.scrollHeight - - (document.documentElement.clientHeight ? - document.documentElement.clientHeight : document.body.clientHeight); - this.scrollStart = Position.deltaY; - this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart; - }, - update: function(position) { - Position.prepare(); - window.scrollTo(Position.deltaX, - this.scrollStart + (position*this.delta)); - } -}); - -/* ------------- combination effects ------------- */ - -Effect.Fade = function(element) { - element = $(element); - var oldOpacity = element.getInlineOpacity(); - var options = Object.extend({ - from: element.getOpacity() || 1.0, - to: 0.0, - afterFinishInternal: function(effect) { - if(effect.options.to!=0) return; - effect.element.hide().setStyle({opacity: oldOpacity}); - }}, arguments[1] || {}); - return new Effect.Opacity(element,options); -} - -Effect.Appear = function(element) { - element = $(element); - var options = Object.extend({ - from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), - to: 1.0, - // force Safari to render floated elements properly - afterFinishInternal: function(effect) { - effect.element.forceRerendering(); - }, - beforeSetup: function(effect) { - effect.element.setOpacity(effect.options.from).show(); - }}, arguments[1] || {}); - return new Effect.Opacity(element,options); -} - -Effect.Puff = function(element) { - element = $(element); - var oldStyle = { - opacity: element.getInlineOpacity(), - position: element.getStyle('position'), - top: element.style.top, - left: element.style.left, - width: element.style.width, - height: element.style.height - }; - return new Effect.Parallel( - [ new Effect.Scale(element, 200, - { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), - new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], - Object.extend({ duration: 1.0, - beforeSetupInternal: function(effect) { - Position.absolutize(effect.effects[0].element) - }, - afterFinishInternal: function(effect) { - effect.effects[0].element.hide().setStyle(oldStyle); } - }, arguments[1] || {}) - ); -} - -Effect.BlindUp = function(element) { - element = $(element); - element.makeClipping(); - return new Effect.Scale(element, 0, - Object.extend({ scaleContent: false, - scaleX: false, - restoreAfterFinish: true, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping(); - } - }, arguments[1] || {}) - ); -} - -Effect.BlindDown = function(element) { - element = $(element); - var elementDimensions = element.getDimensions(); - return new Effect.Scale(element, 100, Object.extend({ - scaleContent: false, - scaleX: false, - scaleFrom: 0, - scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, - restoreAfterFinish: true, - afterSetup: function(effect) { - effect.element.makeClipping().setStyle({height: '0px'}).show(); - }, - afterFinishInternal: function(effect) { - effect.element.undoClipping(); - } - }, arguments[1] || {})); -} - -Effect.SwitchOff = function(element) { - element = $(element); - var oldOpacity = element.getInlineOpacity(); - return new Effect.Appear(element, Object.extend({ - duration: 0.4, - from: 0, - transition: Effect.Transitions.flicker, - afterFinishInternal: function(effect) { - new Effect.Scale(effect.element, 1, { - duration: 0.3, scaleFromCenter: true, - scaleX: false, scaleContent: false, restoreAfterFinish: true, - beforeSetup: function(effect) { - effect.element.makePositioned().makeClipping(); - }, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity}); - } - }) - } - }, arguments[1] || {})); -} - -Effect.DropOut = function(element) { - element = $(element); - var oldStyle = { - top: element.getStyle('top'), - left: element.getStyle('left'), - opacity: element.getInlineOpacity() }; - return new Effect.Parallel( - [ new Effect.Move(element, {x: 0, y: 100, sync: true }), - new Effect.Opacity(element, { sync: true, to: 0.0 }) ], - Object.extend( - { duration: 0.5, - beforeSetup: function(effect) { - effect.effects[0].element.makePositioned(); - }, - afterFinishInternal: function(effect) { - effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); - } - }, arguments[1] || {})); -} - -Effect.Shake = function(element) { - element = $(element); - var oldStyle = { - top: element.getStyle('top'), - left: element.getStyle('left') }; - return new Effect.Move(element, - { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { - effect.element.undoPositioned().setStyle(oldStyle); - }}) }}) }}) }}) }}) }}); -} - -Effect.SlideDown = function(element) { - element = $(element).cleanWhitespace(); - // SlideDown need to have the content of the element wrapped in a container element with fixed height! - var oldInnerBottom = element.down().getStyle('bottom'); - var elementDimensions = element.getDimensions(); - return new Effect.Scale(element, 100, Object.extend({ - scaleContent: false, - scaleX: false, - scaleFrom: window.opera ? 0 : 1, - scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, - restoreAfterFinish: true, - afterSetup: function(effect) { - effect.element.makePositioned(); - effect.element.down().makePositioned(); - if(window.opera) effect.element.setStyle({top: ''}); - effect.element.makeClipping().setStyle({height: '0px'}).show(); - }, - afterUpdateInternal: function(effect) { - effect.element.down().setStyle({bottom: - (effect.dims[0] - effect.element.clientHeight) + 'px' }); - }, - afterFinishInternal: function(effect) { - effect.element.undoClipping().undoPositioned(); - effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } - }, arguments[1] || {}) - ); -} - -Effect.SlideUp = function(element) { - element = $(element).cleanWhitespace(); - var oldInnerBottom = element.down().getStyle('bottom'); - return new Effect.Scale(element, window.opera ? 0 : 1, - Object.extend({ scaleContent: false, - scaleX: false, - scaleMode: 'box', - scaleFrom: 100, - restoreAfterFinish: true, - beforeStartInternal: function(effect) { - effect.element.makePositioned(); - effect.element.down().makePositioned(); - if(window.opera) effect.element.setStyle({top: ''}); - effect.element.makeClipping().show(); - }, - afterUpdateInternal: function(effect) { - effect.element.down().setStyle({bottom: - (effect.dims[0] - effect.element.clientHeight) + 'px' }); - }, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom}); - effect.element.down().undoPositioned(); - } - }, arguments[1] || {}) - ); -} - -// Bug in opera makes the TD containing this element expand for a instance after finish -Effect.Squish = function(element) { - return new Effect.Scale(element, window.opera ? 1 : 0, { - restoreAfterFinish: true, - beforeSetup: function(effect) { - effect.element.makeClipping(); - }, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping(); - } - }); -} - -Effect.Grow = function(element) { - element = $(element); - var options = Object.extend({ - direction: 'center', - moveTransition: Effect.Transitions.sinoidal, - scaleTransition: Effect.Transitions.sinoidal, - opacityTransition: Effect.Transitions.full - }, arguments[1] || {}); - var oldStyle = { - top: element.style.top, - left: element.style.left, - height: element.style.height, - width: element.style.width, - opacity: element.getInlineOpacity() }; - - var dims = element.getDimensions(); - var initialMoveX, initialMoveY; - var moveX, moveY; - - switch (options.direction) { - case 'top-left': - initialMoveX = initialMoveY = moveX = moveY = 0; - break; - case 'top-right': - initialMoveX = dims.width; - initialMoveY = moveY = 0; - moveX = -dims.width; - break; - case 'bottom-left': - initialMoveX = moveX = 0; - initialMoveY = dims.height; - moveY = -dims.height; - break; - case 'bottom-right': - initialMoveX = dims.width; - initialMoveY = dims.height; - moveX = -dims.width; - moveY = -dims.height; - break; - case 'center': - initialMoveX = dims.width / 2; - initialMoveY = dims.height / 2; - moveX = -dims.width / 2; - moveY = -dims.height / 2; - break; - } - - return new Effect.Move(element, { - x: initialMoveX, - y: initialMoveY, - duration: 0.01, - beforeSetup: function(effect) { - effect.element.hide().makeClipping().makePositioned(); - }, - afterFinishInternal: function(effect) { - new Effect.Parallel( - [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), - new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), - new Effect.Scale(effect.element, 100, { - scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, - sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) - ], Object.extend({ - beforeSetup: function(effect) { - effect.effects[0].element.setStyle({height: '0px'}).show(); - }, - afterFinishInternal: function(effect) { - effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); - } - }, options) - ) - } - }); -} - -Effect.Shrink = function(element) { - element = $(element); - var options = Object.extend({ - direction: 'center', - moveTransition: Effect.Transitions.sinoidal, - scaleTransition: Effect.Transitions.sinoidal, - opacityTransition: Effect.Transitions.none - }, arguments[1] || {}); - var oldStyle = { - top: element.style.top, - left: element.style.left, - height: element.style.height, - width: element.style.width, - opacity: element.getInlineOpacity() }; - - var dims = element.getDimensions(); - var moveX, moveY; - - switch (options.direction) { - case 'top-left': - moveX = moveY = 0; - break; - case 'top-right': - moveX = dims.width; - moveY = 0; - break; - case 'bottom-left': - moveX = 0; - moveY = dims.height; - break; - case 'bottom-right': - moveX = dims.width; - moveY = dims.height; - break; - case 'center': - moveX = dims.width / 2; - moveY = dims.height / 2; - break; - } - - return new Effect.Parallel( - [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), - new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), - new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) - ], Object.extend({ - beforeStartInternal: function(effect) { - effect.effects[0].element.makePositioned().makeClipping(); - }, - afterFinishInternal: function(effect) { - effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } - }, options) - ); -} - -Effect.Pulsate = function(element) { - element = $(element); - var options = arguments[1] || {}; - var oldOpacity = element.getInlineOpacity(); - var transition = options.transition || Effect.Transitions.sinoidal; - var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) }; - reverser.bind(transition); - return new Effect.Opacity(element, - Object.extend(Object.extend({ duration: 2.0, from: 0, - afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } - }, options), {transition: reverser})); -} - -Effect.Fold = function(element) { - element = $(element); - var oldStyle = { - top: element.style.top, - left: element.style.left, - width: element.style.width, - height: element.style.height }; - element.makeClipping(); - return new Effect.Scale(element, 5, Object.extend({ - scaleContent: false, - scaleX: false, - afterFinishInternal: function(effect) { - new Effect.Scale(element, 1, { - scaleContent: false, - scaleY: false, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping().setStyle(oldStyle); - } }); - }}, arguments[1] || {})); -}; - -Effect.Morph = Class.create(); -Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), { - initialize: function(element) { - this.element = $(element); - if(!this.element) throw(Effect._elementDoesNotExistError); - var options = Object.extend({ - style: '' - }, arguments[1] || {}); - this.start(options); - }, - setup: function(){ - function parseColor(color){ - if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff'; - color = color.parseColor(); - return $R(0,2).map(function(i){ - return parseInt( color.slice(i*2+1,i*2+3), 16 ) - }); - } - this.transforms = this.options.style.parseStyle().map(function(property){ - var originalValue = this.element.getStyle(property[0]); - return $H({ - style: property[0], - originalValue: property[1].unit=='color' ? - parseColor(originalValue) : parseFloat(originalValue || 0), - targetValue: property[1].unit=='color' ? - parseColor(property[1].value) : property[1].value, - unit: property[1].unit - }); - }.bind(this)).reject(function(transform){ - return ( - (transform.originalValue == transform.targetValue) || - ( - transform.unit != 'color' && - (isNaN(transform.originalValue) || isNaN(transform.targetValue)) - ) - ) - }); - }, - update: function(position) { - var style = $H(), value = null; - this.transforms.each(function(transform){ - value = transform.unit=='color' ? - $R(0,2).inject('#',function(m,v,i){ - return m+(Math.round(transform.originalValue[i]+ - (transform.targetValue[i] - transform.originalValue[i])*position)).toColorPart() }) : - transform.originalValue + Math.round( - ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit; - style[transform.style] = value; - }); - this.element.setStyle(style); - } -}); - -Effect.Transform = Class.create(); -Object.extend(Effect.Transform.prototype, { - initialize: function(tracks){ - this.tracks = []; - this.options = arguments[1] || {}; - this.addTracks(tracks); - }, - addTracks: function(tracks){ - tracks.each(function(track){ - var data = $H(track).values().first(); - this.tracks.push($H({ - ids: $H(track).keys().first(), - effect: Effect.Morph, - options: { style: data } - })); - }.bind(this)); - return this; - }, - play: function(){ - return new Effect.Parallel( - this.tracks.map(function(track){ - var elements = [$(track.ids) || $$(track.ids)].flatten(); - return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) }); - }).flatten(), - this.options - ); - } -}); - -Element.CSS_PROPERTIES = ['azimuth', 'backgroundAttachment', 'backgroundColor', 'backgroundImage', - 'backgroundPosition', 'backgroundRepeat', 'borderBottomColor', 'borderBottomStyle', - 'borderBottomWidth', 'borderCollapse', 'borderLeftColor', 'borderLeftStyle', 'borderLeftWidth', - 'borderRightColor', 'borderRightStyle', 'borderRightWidth', 'borderSpacing', 'borderTopColor', - 'borderTopStyle', 'borderTopWidth', 'bottom', 'captionSide', 'clear', 'clip', 'color', 'content', - 'counterIncrement', 'counterReset', 'cssFloat', 'cueAfter', 'cueBefore', 'cursor', 'direction', - 'display', 'elevation', 'emptyCells', 'fontFamily', 'fontSize', 'fontSizeAdjust', 'fontStretch', - 'fontStyle', 'fontVariant', 'fontWeight', 'height', 'left', 'letterSpacing', 'lineHeight', - 'listStyleImage', 'listStylePosition', 'listStyleType', 'marginBottom', 'marginLeft', 'marginRight', - 'marginTop', 'markerOffset', 'marks', 'maxHeight', 'maxWidth', 'minHeight', 'minWidth', 'opacity', - 'orphans', 'outlineColor', 'outlineOffset', 'outlineStyle', 'outlineWidth', 'overflowX', 'overflowY', - 'paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop', 'page', 'pageBreakAfter', 'pageBreakBefore', - 'pageBreakInside', 'pauseAfter', 'pauseBefore', 'pitch', 'pitchRange', 'position', 'quotes', - 'richness', 'right', 'size', 'speakHeader', 'speakNumeral', 'speakPunctuation', 'speechRate', 'stress', - 'tableLayout', 'textAlign', 'textDecoration', 'textIndent', 'textShadow', 'textTransform', 'top', - 'unicodeBidi', 'verticalAlign', 'visibility', 'voiceFamily', 'volume', 'whiteSpace', 'widows', - 'width', 'wordSpacing', 'zIndex']; - -Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/; - -String.prototype.parseStyle = function(){ - var element = Element.extend(document.createElement('div')); - element.innerHTML = '

        '; - var style = element.down().style, styleRules = $H(); - - Element.CSS_PROPERTIES.each(function(property){ - if(style[property]) styleRules[property] = style[property]; - }); - - var result = $H(); - - styleRules.each(function(pair){ - var property = pair[0], value = pair[1], unit = null; - - if(value.parseColor('#zzzzzz') != '#zzzzzz') { - value = value.parseColor(); - unit = 'color'; - } else if(Element.CSS_LENGTH.test(value)) - var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/), - value = parseFloat(components[1]), unit = (components.length == 3) ? components[2] : null; - - result[property.underscore().dasherize()] = $H({ value:value, unit:unit }); - }.bind(this)); - - return result; -}; - -Element.morph = function(element, style) { - new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {})); - return element; -}; - -['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom', - 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each( - function(f) { Element.Methods[f] = Element[f]; } -); - -Element.Methods.visualEffect = function(element, effect, options) { - s = effect.gsub(/_/, '-').camelize(); - effect_class = s.charAt(0).toUpperCase() + s.substring(1); - new Effect[effect_class](element, options); - return $(element); -}; - -Element.addMethods(); \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/prototype.js b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/prototype.js deleted file mode 100644 index 50582217..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/javascripts/prototype.js +++ /dev/null @@ -1,2515 +0,0 @@ -/* Prototype JavaScript framework, version 1.5.0 - * (c) 2005-2007 Sam Stephenson - * - * Prototype is freely distributable under the terms of an MIT-style license. - * For details, see the Prototype web site: http://prototype.conio.net/ - * -/*--------------------------------------------------------------------------*/ - -var Prototype = { - Version: '1.5.0', - BrowserFeatures: { - XPath: !!document.evaluate - }, - - ScriptFragment: '(?:)((\n|\r|.)*?)(?:<\/script>)', - emptyFunction: function() {}, - K: function(x) { return x } -} - -var Class = { - create: function() { - return function() { - this.initialize.apply(this, arguments); - } - } -} - -var Abstract = new Object(); - -Object.extend = function(destination, source) { - for (var property in source) { - destination[property] = source[property]; - } - return destination; -} - -Object.extend(Object, { - inspect: function(object) { - try { - if (object === undefined) return 'undefined'; - if (object === null) return 'null'; - return object.inspect ? object.inspect() : object.toString(); - } catch (e) { - if (e instanceof RangeError) return '...'; - throw e; - } - }, - - keys: function(object) { - var keys = []; - for (var property in object) - keys.push(property); - return keys; - }, - - values: function(object) { - var values = []; - for (var property in object) - values.push(object[property]); - return values; - }, - - clone: function(object) { - return Object.extend({}, object); - } -}); - -Function.prototype.bind = function() { - var __method = this, args = $A(arguments), object = args.shift(); - return function() { - return __method.apply(object, args.concat($A(arguments))); - } -} - -Function.prototype.bindAsEventListener = function(object) { - var __method = this, args = $A(arguments), object = args.shift(); - return function(event) { - return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments))); - } -} - -Object.extend(Number.prototype, { - toColorPart: function() { - var digits = this.toString(16); - if (this < 16) return '0' + digits; - return digits; - }, - - succ: function() { - return this + 1; - }, - - times: function(iterator) { - $R(0, this, true).each(iterator); - return this; - } -}); - -var Try = { - these: function() { - var returnValue; - - for (var i = 0, length = arguments.length; i < length; i++) { - var lambda = arguments[i]; - try { - returnValue = lambda(); - break; - } catch (e) {} - } - - return returnValue; - } -} - -/*--------------------------------------------------------------------------*/ - -var PeriodicalExecuter = Class.create(); -PeriodicalExecuter.prototype = { - initialize: function(callback, frequency) { - this.callback = callback; - this.frequency = frequency; - this.currentlyExecuting = false; - - this.registerCallback(); - }, - - registerCallback: function() { - this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - stop: function() { - if (!this.timer) return; - clearInterval(this.timer); - this.timer = null; - }, - - onTimerEvent: function() { - if (!this.currentlyExecuting) { - try { - this.currentlyExecuting = true; - this.callback(this); - } finally { - this.currentlyExecuting = false; - } - } - } -} -String.interpret = function(value){ - return value == null ? '' : String(value); -} - -Object.extend(String.prototype, { - gsub: function(pattern, replacement) { - var result = '', source = this, match; - replacement = arguments.callee.prepareReplacement(replacement); - - while (source.length > 0) { - if (match = source.match(pattern)) { - result += source.slice(0, match.index); - result += String.interpret(replacement(match)); - source = source.slice(match.index + match[0].length); - } else { - result += source, source = ''; - } - } - return result; - }, - - sub: function(pattern, replacement, count) { - replacement = this.gsub.prepareReplacement(replacement); - count = count === undefined ? 1 : count; - - return this.gsub(pattern, function(match) { - if (--count < 0) return match[0]; - return replacement(match); - }); - }, - - scan: function(pattern, iterator) { - this.gsub(pattern, iterator); - return this; - }, - - truncate: function(length, truncation) { - length = length || 30; - truncation = truncation === undefined ? '...' : truncation; - return this.length > length ? - this.slice(0, length - truncation.length) + truncation : this; - }, - - strip: function() { - return this.replace(/^\s+/, '').replace(/\s+$/, ''); - }, - - stripTags: function() { - return this.replace(/<\/?[^>]+>/gi, ''); - }, - - stripScripts: function() { - return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); - }, - - extractScripts: function() { - var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); - var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); - return (this.match(matchAll) || []).map(function(scriptTag) { - return (scriptTag.match(matchOne) || ['', ''])[1]; - }); - }, - - evalScripts: function() { - return this.extractScripts().map(function(script) { return eval(script) }); - }, - - escapeHTML: function() { - var div = document.createElement('div'); - var text = document.createTextNode(this); - div.appendChild(text); - return div.innerHTML; - }, - - unescapeHTML: function() { - var div = document.createElement('div'); - div.innerHTML = this.stripTags(); - return div.childNodes[0] ? (div.childNodes.length > 1 ? - $A(div.childNodes).inject('',function(memo,node){ return memo+node.nodeValue }) : - div.childNodes[0].nodeValue) : ''; - }, - - toQueryParams: function(separator) { - var match = this.strip().match(/([^?#]*)(#.*)?$/); - if (!match) return {}; - - return match[1].split(separator || '&').inject({}, function(hash, pair) { - if ((pair = pair.split('='))[0]) { - var name = decodeURIComponent(pair[0]); - var value = pair[1] ? decodeURIComponent(pair[1]) : undefined; - - if (hash[name] !== undefined) { - if (hash[name].constructor != Array) - hash[name] = [hash[name]]; - if (value) hash[name].push(value); - } - else hash[name] = value; - } - return hash; - }); - }, - - toArray: function() { - return this.split(''); - }, - - succ: function() { - return this.slice(0, this.length - 1) + - String.fromCharCode(this.charCodeAt(this.length - 1) + 1); - }, - - camelize: function() { - var parts = this.split('-'), len = parts.length; - if (len == 1) return parts[0]; - - var camelized = this.charAt(0) == '-' - ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) - : parts[0]; - - for (var i = 1; i < len; i++) - camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); - - return camelized; - }, - - capitalize: function(){ - return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); - }, - - underscore: function() { - return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); - }, - - dasherize: function() { - return this.gsub(/_/,'-'); - }, - - inspect: function(useDoubleQuotes) { - var escapedString = this.replace(/\\/g, '\\\\'); - if (useDoubleQuotes) - return '"' + escapedString.replace(/"/g, '\\"') + '"'; - else - return "'" + escapedString.replace(/'/g, '\\\'') + "'"; - } -}); - -String.prototype.gsub.prepareReplacement = function(replacement) { - if (typeof replacement == 'function') return replacement; - var template = new Template(replacement); - return function(match) { return template.evaluate(match) }; -} - -String.prototype.parseQuery = String.prototype.toQueryParams; - -var Template = Class.create(); -Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; -Template.prototype = { - initialize: function(template, pattern) { - this.template = template.toString(); - this.pattern = pattern || Template.Pattern; - }, - - evaluate: function(object) { - return this.template.gsub(this.pattern, function(match) { - var before = match[1]; - if (before == '\\') return match[2]; - return before + String.interpret(object[match[3]]); - }); - } -} - -var $break = new Object(); -var $continue = new Object(); - -var Enumerable = { - each: function(iterator) { - var index = 0; - try { - this._each(function(value) { - try { - iterator(value, index++); - } catch (e) { - if (e != $continue) throw e; - } - }); - } catch (e) { - if (e != $break) throw e; - } - return this; - }, - - eachSlice: function(number, iterator) { - var index = -number, slices = [], array = this.toArray(); - while ((index += number) < array.length) - slices.push(array.slice(index, index+number)); - return slices.map(iterator); - }, - - all: function(iterator) { - var result = true; - this.each(function(value, index) { - result = result && !!(iterator || Prototype.K)(value, index); - if (!result) throw $break; - }); - return result; - }, - - any: function(iterator) { - var result = false; - this.each(function(value, index) { - if (result = !!(iterator || Prototype.K)(value, index)) - throw $break; - }); - return result; - }, - - collect: function(iterator) { - var results = []; - this.each(function(value, index) { - results.push((iterator || Prototype.K)(value, index)); - }); - return results; - }, - - detect: function(iterator) { - var result; - this.each(function(value, index) { - if (iterator(value, index)) { - result = value; - throw $break; - } - }); - return result; - }, - - findAll: function(iterator) { - var results = []; - this.each(function(value, index) { - if (iterator(value, index)) - results.push(value); - }); - return results; - }, - - grep: function(pattern, iterator) { - var results = []; - this.each(function(value, index) { - var stringValue = value.toString(); - if (stringValue.match(pattern)) - results.push((iterator || Prototype.K)(value, index)); - }) - return results; - }, - - include: function(object) { - var found = false; - this.each(function(value) { - if (value == object) { - found = true; - throw $break; - } - }); - return found; - }, - - inGroupsOf: function(number, fillWith) { - fillWith = fillWith === undefined ? null : fillWith; - return this.eachSlice(number, function(slice) { - while(slice.length < number) slice.push(fillWith); - return slice; - }); - }, - - inject: function(memo, iterator) { - this.each(function(value, index) { - memo = iterator(memo, value, index); - }); - return memo; - }, - - invoke: function(method) { - var args = $A(arguments).slice(1); - return this.map(function(value) { - return value[method].apply(value, args); - }); - }, - - max: function(iterator) { - var result; - this.each(function(value, index) { - value = (iterator || Prototype.K)(value, index); - if (result == undefined || value >= result) - result = value; - }); - return result; - }, - - min: function(iterator) { - var result; - this.each(function(value, index) { - value = (iterator || Prototype.K)(value, index); - if (result == undefined || value < result) - result = value; - }); - return result; - }, - - partition: function(iterator) { - var trues = [], falses = []; - this.each(function(value, index) { - ((iterator || Prototype.K)(value, index) ? - trues : falses).push(value); - }); - return [trues, falses]; - }, - - pluck: function(property) { - var results = []; - this.each(function(value, index) { - results.push(value[property]); - }); - return results; - }, - - reject: function(iterator) { - var results = []; - this.each(function(value, index) { - if (!iterator(value, index)) - results.push(value); - }); - return results; - }, - - sortBy: function(iterator) { - return this.map(function(value, index) { - return {value: value, criteria: iterator(value, index)}; - }).sort(function(left, right) { - var a = left.criteria, b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; - }).pluck('value'); - }, - - toArray: function() { - return this.map(); - }, - - zip: function() { - var iterator = Prototype.K, args = $A(arguments); - if (typeof args.last() == 'function') - iterator = args.pop(); - - var collections = [this].concat(args).map($A); - return this.map(function(value, index) { - return iterator(collections.pluck(index)); - }); - }, - - size: function() { - return this.toArray().length; - }, - - inspect: function() { - return '#'; - } -} - -Object.extend(Enumerable, { - map: Enumerable.collect, - find: Enumerable.detect, - select: Enumerable.findAll, - member: Enumerable.include, - entries: Enumerable.toArray -}); -var $A = Array.from = function(iterable) { - if (!iterable) return []; - if (iterable.toArray) { - return iterable.toArray(); - } else { - var results = []; - for (var i = 0, length = iterable.length; i < length; i++) - results.push(iterable[i]); - return results; - } -} - -Object.extend(Array.prototype, Enumerable); - -if (!Array.prototype._reverse) - Array.prototype._reverse = Array.prototype.reverse; - -Object.extend(Array.prototype, { - _each: function(iterator) { - for (var i = 0, length = this.length; i < length; i++) - iterator(this[i]); - }, - - clear: function() { - this.length = 0; - return this; - }, - - first: function() { - return this[0]; - }, - - last: function() { - return this[this.length - 1]; - }, - - compact: function() { - return this.select(function(value) { - return value != null; - }); - }, - - flatten: function() { - return this.inject([], function(array, value) { - return array.concat(value && value.constructor == Array ? - value.flatten() : [value]); - }); - }, - - without: function() { - var values = $A(arguments); - return this.select(function(value) { - return !values.include(value); - }); - }, - - indexOf: function(object) { - for (var i = 0, length = this.length; i < length; i++) - if (this[i] == object) return i; - return -1; - }, - - reverse: function(inline) { - return (inline !== false ? this : this.toArray())._reverse(); - }, - - reduce: function() { - return this.length > 1 ? this : this[0]; - }, - - uniq: function() { - return this.inject([], function(array, value) { - return array.include(value) ? array : array.concat([value]); - }); - }, - - clone: function() { - return [].concat(this); - }, - - size: function() { - return this.length; - }, - - inspect: function() { - return '[' + this.map(Object.inspect).join(', ') + ']'; - } -}); - -Array.prototype.toArray = Array.prototype.clone; - -function $w(string){ - string = string.strip(); - return string ? string.split(/\s+/) : []; -} - -if(window.opera){ - Array.prototype.concat = function(){ - var array = []; - for(var i = 0, length = this.length; i < length; i++) array.push(this[i]); - for(var i = 0, length = arguments.length; i < length; i++) { - if(arguments[i].constructor == Array) { - for(var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) - array.push(arguments[i][j]); - } else { - array.push(arguments[i]); - } - } - return array; - } -} -var Hash = function(obj) { - Object.extend(this, obj || {}); -}; - -Object.extend(Hash, { - toQueryString: function(obj) { - var parts = []; - - this.prototype._each.call(obj, function(pair) { - if (!pair.key) return; - - if (pair.value && pair.value.constructor == Array) { - var values = pair.value.compact(); - if (values.length < 2) pair.value = values.reduce(); - else { - key = encodeURIComponent(pair.key); - values.each(function(value) { - value = value != undefined ? encodeURIComponent(value) : ''; - parts.push(key + '=' + encodeURIComponent(value)); - }); - return; - } - } - if (pair.value == undefined) pair[1] = ''; - parts.push(pair.map(encodeURIComponent).join('=')); - }); - - return parts.join('&'); - } -}); - -Object.extend(Hash.prototype, Enumerable); -Object.extend(Hash.prototype, { - _each: function(iterator) { - for (var key in this) { - var value = this[key]; - if (value && value == Hash.prototype[key]) continue; - - var pair = [key, value]; - pair.key = key; - pair.value = value; - iterator(pair); - } - }, - - keys: function() { - return this.pluck('key'); - }, - - values: function() { - return this.pluck('value'); - }, - - merge: function(hash) { - return $H(hash).inject(this, function(mergedHash, pair) { - mergedHash[pair.key] = pair.value; - return mergedHash; - }); - }, - - remove: function() { - var result; - for(var i = 0, length = arguments.length; i < length; i++) { - var value = this[arguments[i]]; - if (value !== undefined){ - if (result === undefined) result = value; - else { - if (result.constructor != Array) result = [result]; - result.push(value) - } - } - delete this[arguments[i]]; - } - return result; - }, - - toQueryString: function() { - return Hash.toQueryString(this); - }, - - inspect: function() { - return '#'; - } -}); - -function $H(object) { - if (object && object.constructor == Hash) return object; - return new Hash(object); -}; -ObjectRange = Class.create(); -Object.extend(ObjectRange.prototype, Enumerable); -Object.extend(ObjectRange.prototype, { - initialize: function(start, end, exclusive) { - this.start = start; - this.end = end; - this.exclusive = exclusive; - }, - - _each: function(iterator) { - var value = this.start; - while (this.include(value)) { - iterator(value); - value = value.succ(); - } - }, - - include: function(value) { - if (value < this.start) - return false; - if (this.exclusive) - return value < this.end; - return value <= this.end; - } -}); - -var $R = function(start, end, exclusive) { - return new ObjectRange(start, end, exclusive); -} - -var Ajax = { - getTransport: function() { - return Try.these( - function() {return new XMLHttpRequest()}, - function() {return new ActiveXObject('Msxml2.XMLHTTP')}, - function() {return new ActiveXObject('Microsoft.XMLHTTP')} - ) || false; - }, - - activeRequestCount: 0 -} - -Ajax.Responders = { - responders: [], - - _each: function(iterator) { - this.responders._each(iterator); - }, - - register: function(responder) { - if (!this.include(responder)) - this.responders.push(responder); - }, - - unregister: function(responder) { - this.responders = this.responders.without(responder); - }, - - dispatch: function(callback, request, transport, json) { - this.each(function(responder) { - if (typeof responder[callback] == 'function') { - try { - responder[callback].apply(responder, [request, transport, json]); - } catch (e) {} - } - }); - } -}; - -Object.extend(Ajax.Responders, Enumerable); - -Ajax.Responders.register({ - onCreate: function() { - Ajax.activeRequestCount++; - }, - onComplete: function() { - Ajax.activeRequestCount--; - } -}); - -Ajax.Base = function() {}; -Ajax.Base.prototype = { - setOptions: function(options) { - this.options = { - method: 'post', - asynchronous: true, - contentType: 'application/x-www-form-urlencoded', - encoding: 'UTF-8', - parameters: '' - } - Object.extend(this.options, options || {}); - - this.options.method = this.options.method.toLowerCase(); - if (typeof this.options.parameters == 'string') - this.options.parameters = this.options.parameters.toQueryParams(); - } -} - -Ajax.Request = Class.create(); -Ajax.Request.Events = - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; - -Ajax.Request.prototype = Object.extend(new Ajax.Base(), { - _complete: false, - - initialize: function(url, options) { - this.transport = Ajax.getTransport(); - this.setOptions(options); - this.request(url); - }, - - request: function(url) { - this.url = url; - this.method = this.options.method; - var params = this.options.parameters; - - if (!['get', 'post'].include(this.method)) { - // simulate other verbs over post - params['_method'] = this.method; - this.method = 'post'; - } - - params = Hash.toQueryString(params); - if (params && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_=' - - // when GET, append parameters to URL - if (this.method == 'get' && params) - this.url += (this.url.indexOf('?') > -1 ? '&' : '?') + params; - - try { - Ajax.Responders.dispatch('onCreate', this, this.transport); - - this.transport.open(this.method.toUpperCase(), this.url, - this.options.asynchronous); - - if (this.options.asynchronous) - setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10); - - this.transport.onreadystatechange = this.onStateChange.bind(this); - this.setRequestHeaders(); - - var body = this.method == 'post' ? (this.options.postBody || params) : null; - - this.transport.send(body); - - /* Force Firefox to handle ready state 4 for synchronous requests */ - if (!this.options.asynchronous && this.transport.overrideMimeType) - this.onStateChange(); - - } - catch (e) { - this.dispatchException(e); - } - }, - - onStateChange: function() { - var readyState = this.transport.readyState; - if (readyState > 1 && !((readyState == 4) && this._complete)) - this.respondToReadyState(this.transport.readyState); - }, - - setRequestHeaders: function() { - var headers = { - 'X-Requested-With': 'XMLHttpRequest', - 'X-Prototype-Version': Prototype.Version, - 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' - }; - - if (this.method == 'post') { - headers['Content-type'] = this.options.contentType + - (this.options.encoding ? '; charset=' + this.options.encoding : ''); - - /* Force "Connection: close" for older Mozilla browsers to work - * around a bug where XMLHttpRequest sends an incorrect - * Content-length header. See Mozilla Bugzilla #246651. - */ - if (this.transport.overrideMimeType && - (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) - headers['Connection'] = 'close'; - } - - // user-defined headers - if (typeof this.options.requestHeaders == 'object') { - var extras = this.options.requestHeaders; - - if (typeof extras.push == 'function') - for (var i = 0, length = extras.length; i < length; i += 2) - headers[extras[i]] = extras[i+1]; - else - $H(extras).each(function(pair) { headers[pair.key] = pair.value }); - } - - for (var name in headers) - this.transport.setRequestHeader(name, headers[name]); - }, - - success: function() { - return !this.transport.status - || (this.transport.status >= 200 && this.transport.status < 300); - }, - - respondToReadyState: function(readyState) { - var state = Ajax.Request.Events[readyState]; - var transport = this.transport, json = this.evalJSON(); - - if (state == 'Complete') { - try { - this._complete = true; - (this.options['on' + this.transport.status] - || this.options['on' + (this.success() ? 'Success' : 'Failure')] - || Prototype.emptyFunction)(transport, json); - } catch (e) { - this.dispatchException(e); - } - - if ((this.getHeader('Content-type') || 'text/javascript').strip(). - match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i)) - this.evalResponse(); - } - - try { - (this.options['on' + state] || Prototype.emptyFunction)(transport, json); - Ajax.Responders.dispatch('on' + state, this, transport, json); - } catch (e) { - this.dispatchException(e); - } - - if (state == 'Complete') { - // avoid memory leak in MSIE: clean up - this.transport.onreadystatechange = Prototype.emptyFunction; - } - }, - - getHeader: function(name) { - try { - return this.transport.getResponseHeader(name); - } catch (e) { return null } - }, - - evalJSON: function() { - try { - var json = this.getHeader('X-JSON'); - return json ? eval('(' + json + ')') : null; - } catch (e) { return null } - }, - - evalResponse: function() { - try { - return eval(this.transport.responseText); - } catch (e) { - this.dispatchException(e); - } - }, - - dispatchException: function(exception) { - (this.options.onException || Prototype.emptyFunction)(this, exception); - Ajax.Responders.dispatch('onException', this, exception); - } -}); - -Ajax.Updater = Class.create(); - -Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { - initialize: function(container, url, options) { - this.container = { - success: (container.success || container), - failure: (container.failure || (container.success ? null : container)) - } - - this.transport = Ajax.getTransport(); - this.setOptions(options); - - var onComplete = this.options.onComplete || Prototype.emptyFunction; - this.options.onComplete = (function(transport, param) { - this.updateContent(); - onComplete(transport, param); - }).bind(this); - - this.request(url); - }, - - updateContent: function() { - var receiver = this.container[this.success() ? 'success' : 'failure']; - var response = this.transport.responseText; - - if (!this.options.evalScripts) response = response.stripScripts(); - - if (receiver = $(receiver)) { - if (this.options.insertion) - new this.options.insertion(receiver, response); - else - receiver.update(response); - } - - if (this.success()) { - if (this.onComplete) - setTimeout(this.onComplete.bind(this), 10); - } - } -}); - -Ajax.PeriodicalUpdater = Class.create(); -Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { - initialize: function(container, url, options) { - this.setOptions(options); - this.onComplete = this.options.onComplete; - - this.frequency = (this.options.frequency || 2); - this.decay = (this.options.decay || 1); - - this.updater = {}; - this.container = container; - this.url = url; - - this.start(); - }, - - start: function() { - this.options.onComplete = this.updateComplete.bind(this); - this.onTimerEvent(); - }, - - stop: function() { - this.updater.options.onComplete = undefined; - clearTimeout(this.timer); - (this.onComplete || Prototype.emptyFunction).apply(this, arguments); - }, - - updateComplete: function(request) { - if (this.options.decay) { - this.decay = (request.responseText == this.lastText ? - this.decay * this.options.decay : 1); - - this.lastText = request.responseText; - } - this.timer = setTimeout(this.onTimerEvent.bind(this), - this.decay * this.frequency * 1000); - }, - - onTimerEvent: function() { - this.updater = new Ajax.Updater(this.container, this.url, this.options); - } -}); -function $(element) { - if (arguments.length > 1) { - for (var i = 0, elements = [], length = arguments.length; i < length; i++) - elements.push($(arguments[i])); - return elements; - } - if (typeof element == 'string') - element = document.getElementById(element); - return Element.extend(element); -} - -if (Prototype.BrowserFeatures.XPath) { - document._getElementsByXPath = function(expression, parentElement) { - var results = []; - var query = document.evaluate(expression, $(parentElement) || document, - null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); - for (var i = 0, length = query.snapshotLength; i < length; i++) - results.push(query.snapshotItem(i)); - return results; - }; -} - -document.getElementsByClassName = function(className, parentElement) { - if (Prototype.BrowserFeatures.XPath) { - var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]"; - return document._getElementsByXPath(q, parentElement); - } else { - var children = ($(parentElement) || document.body).getElementsByTagName('*'); - var elements = [], child; - for (var i = 0, length = children.length; i < length; i++) { - child = children[i]; - if (Element.hasClassName(child, className)) - elements.push(Element.extend(child)); - } - return elements; - } -}; - -/*--------------------------------------------------------------------------*/ - -if (!window.Element) - var Element = new Object(); - -Element.extend = function(element) { - if (!element || _nativeExtensions || element.nodeType == 3) return element; - - if (!element._extended && element.tagName && element != window) { - var methods = Object.clone(Element.Methods), cache = Element.extend.cache; - - if (element.tagName == 'FORM') - Object.extend(methods, Form.Methods); - if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName)) - Object.extend(methods, Form.Element.Methods); - - Object.extend(methods, Element.Methods.Simulated); - - for (var property in methods) { - var value = methods[property]; - if (typeof value == 'function' && !(property in element)) - element[property] = cache.findOrStore(value); - } - } - - element._extended = true; - return element; -}; - -Element.extend.cache = { - findOrStore: function(value) { - return this[value] = this[value] || function() { - return value.apply(null, [this].concat($A(arguments))); - } - } -}; - -Element.Methods = { - visible: function(element) { - return $(element).style.display != 'none'; - }, - - toggle: function(element) { - element = $(element); - Element[Element.visible(element) ? 'hide' : 'show'](element); - return element; - }, - - hide: function(element) { - $(element).style.display = 'none'; - return element; - }, - - show: function(element) { - $(element).style.display = ''; - return element; - }, - - remove: function(element) { - element = $(element); - element.parentNode.removeChild(element); - return element; - }, - - update: function(element, html) { - html = typeof html == 'undefined' ? '' : html.toString(); - $(element).innerHTML = html.stripScripts(); - setTimeout(function() {html.evalScripts()}, 10); - return element; - }, - - replace: function(element, html) { - element = $(element); - html = typeof html == 'undefined' ? '' : html.toString(); - if (element.outerHTML) { - element.outerHTML = html.stripScripts(); - } else { - var range = element.ownerDocument.createRange(); - range.selectNodeContents(element); - element.parentNode.replaceChild( - range.createContextualFragment(html.stripScripts()), element); - } - setTimeout(function() {html.evalScripts()}, 10); - return element; - }, - - inspect: function(element) { - element = $(element); - var result = '<' + element.tagName.toLowerCase(); - $H({'id': 'id', 'className': 'class'}).each(function(pair) { - var property = pair.first(), attribute = pair.last(); - var value = (element[property] || '').toString(); - if (value) result += ' ' + attribute + '=' + value.inspect(true); - }); - return result + '>'; - }, - - recursivelyCollect: function(element, property) { - element = $(element); - var elements = []; - while (element = element[property]) - if (element.nodeType == 1) - elements.push(Element.extend(element)); - return elements; - }, - - ancestors: function(element) { - return $(element).recursivelyCollect('parentNode'); - }, - - descendants: function(element) { - return $A($(element).getElementsByTagName('*')); - }, - - immediateDescendants: function(element) { - if (!(element = $(element).firstChild)) return []; - while (element && element.nodeType != 1) element = element.nextSibling; - if (element) return [element].concat($(element).nextSiblings()); - return []; - }, - - previousSiblings: function(element) { - return $(element).recursivelyCollect('previousSibling'); - }, - - nextSiblings: function(element) { - return $(element).recursivelyCollect('nextSibling'); - }, - - siblings: function(element) { - element = $(element); - return element.previousSiblings().reverse().concat(element.nextSiblings()); - }, - - match: function(element, selector) { - if (typeof selector == 'string') - selector = new Selector(selector); - return selector.match($(element)); - }, - - up: function(element, expression, index) { - return Selector.findElement($(element).ancestors(), expression, index); - }, - - down: function(element, expression, index) { - return Selector.findElement($(element).descendants(), expression, index); - }, - - previous: function(element, expression, index) { - return Selector.findElement($(element).previousSiblings(), expression, index); - }, - - next: function(element, expression, index) { - return Selector.findElement($(element).nextSiblings(), expression, index); - }, - - getElementsBySelector: function() { - var args = $A(arguments), element = $(args.shift()); - return Selector.findChildElements(element, args); - }, - - getElementsByClassName: function(element, className) { - return document.getElementsByClassName(className, element); - }, - - readAttribute: function(element, name) { - element = $(element); - if (document.all && !window.opera) { - var t = Element._attributeTranslations; - if (t.values[name]) return t.values[name](element, name); - if (t.names[name]) name = t.names[name]; - var attribute = element.attributes[name]; - if(attribute) return attribute.nodeValue; - } - return element.getAttribute(name); - }, - - getHeight: function(element) { - return $(element).getDimensions().height; - }, - - getWidth: function(element) { - return $(element).getDimensions().width; - }, - - classNames: function(element) { - return new Element.ClassNames(element); - }, - - hasClassName: function(element, className) { - if (!(element = $(element))) return; - var elementClassName = element.className; - if (elementClassName.length == 0) return false; - if (elementClassName == className || - elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) - return true; - return false; - }, - - addClassName: function(element, className) { - if (!(element = $(element))) return; - Element.classNames(element).add(className); - return element; - }, - - removeClassName: function(element, className) { - if (!(element = $(element))) return; - Element.classNames(element).remove(className); - return element; - }, - - toggleClassName: function(element, className) { - if (!(element = $(element))) return; - Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className); - return element; - }, - - observe: function() { - Event.observe.apply(Event, arguments); - return $A(arguments).first(); - }, - - stopObserving: function() { - Event.stopObserving.apply(Event, arguments); - return $A(arguments).first(); - }, - - // removes whitespace-only text node children - cleanWhitespace: function(element) { - element = $(element); - var node = element.firstChild; - while (node) { - var nextNode = node.nextSibling; - if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) - element.removeChild(node); - node = nextNode; - } - return element; - }, - - empty: function(element) { - return $(element).innerHTML.match(/^\s*$/); - }, - - descendantOf: function(element, ancestor) { - element = $(element), ancestor = $(ancestor); - while (element = element.parentNode) - if (element == ancestor) return true; - return false; - }, - - scrollTo: function(element) { - element = $(element); - var pos = Position.cumulativeOffset(element); - window.scrollTo(pos[0], pos[1]); - return element; - }, - - getStyle: function(element, style) { - element = $(element); - if (['float','cssFloat'].include(style)) - style = (typeof element.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat'); - style = style.camelize(); - var value = element.style[style]; - if (!value) { - if (document.defaultView && document.defaultView.getComputedStyle) { - var css = document.defaultView.getComputedStyle(element, null); - value = css ? css[style] : null; - } else if (element.currentStyle) { - value = element.currentStyle[style]; - } - } - - if((value == 'auto') && ['width','height'].include(style) && (element.getStyle('display') != 'none')) - value = element['offset'+style.capitalize()] + 'px'; - - if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) - if (Element.getStyle(element, 'position') == 'static') value = 'auto'; - if(style == 'opacity') { - if(value) return parseFloat(value); - if(value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) - if(value[1]) return parseFloat(value[1]) / 100; - return 1.0; - } - return value == 'auto' ? null : value; - }, - - setStyle: function(element, style) { - element = $(element); - for (var name in style) { - var value = style[name]; - if(name == 'opacity') { - if (value == 1) { - value = (/Gecko/.test(navigator.userAgent) && - !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0; - if(/MSIE/.test(navigator.userAgent) && !window.opera) - element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,''); - } else if(value == '') { - if(/MSIE/.test(navigator.userAgent) && !window.opera) - element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,''); - } else { - if(value < 0.00001) value = 0; - if(/MSIE/.test(navigator.userAgent) && !window.opera) - element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') + - 'alpha(opacity='+value*100+')'; - } - } else if(['float','cssFloat'].include(name)) name = (typeof element.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat'; - element.style[name.camelize()] = value; - } - return element; - }, - - getDimensions: function(element) { - element = $(element); - var display = $(element).getStyle('display'); - if (display != 'none' && display != null) // Safari bug - return {width: element.offsetWidth, height: element.offsetHeight}; - - // All *Width and *Height properties give 0 on elements with display none, - // so enable the element temporarily - var els = element.style; - var originalVisibility = els.visibility; - var originalPosition = els.position; - var originalDisplay = els.display; - els.visibility = 'hidden'; - els.position = 'absolute'; - els.display = 'block'; - var originalWidth = element.clientWidth; - var originalHeight = element.clientHeight; - els.display = originalDisplay; - els.position = originalPosition; - els.visibility = originalVisibility; - return {width: originalWidth, height: originalHeight}; - }, - - makePositioned: function(element) { - element = $(element); - var pos = Element.getStyle(element, 'position'); - if (pos == 'static' || !pos) { - element._madePositioned = true; - element.style.position = 'relative'; - // Opera returns the offset relative to the positioning context, when an - // element is position relative but top and left have not been defined - if (window.opera) { - element.style.top = 0; - element.style.left = 0; - } - } - return element; - }, - - undoPositioned: function(element) { - element = $(element); - if (element._madePositioned) { - element._madePositioned = undefined; - element.style.position = - element.style.top = - element.style.left = - element.style.bottom = - element.style.right = ''; - } - return element; - }, - - makeClipping: function(element) { - element = $(element); - if (element._overflow) return element; - element._overflow = element.style.overflow || 'auto'; - if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') - element.style.overflow = 'hidden'; - return element; - }, - - undoClipping: function(element) { - element = $(element); - if (!element._overflow) return element; - element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; - element._overflow = null; - return element; - } -}; - -Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf}); - -Element._attributeTranslations = {}; - -Element._attributeTranslations.names = { - colspan: "colSpan", - rowspan: "rowSpan", - valign: "vAlign", - datetime: "dateTime", - accesskey: "accessKey", - tabindex: "tabIndex", - enctype: "encType", - maxlength: "maxLength", - readonly: "readOnly", - longdesc: "longDesc" -}; - -Element._attributeTranslations.values = { - _getAttr: function(element, attribute) { - return element.getAttribute(attribute, 2); - }, - - _flag: function(element, attribute) { - return $(element).hasAttribute(attribute) ? attribute : null; - }, - - style: function(element) { - return element.style.cssText.toLowerCase(); - }, - - title: function(element) { - var node = element.getAttributeNode('title'); - return node.specified ? node.nodeValue : null; - } -}; - -Object.extend(Element._attributeTranslations.values, { - href: Element._attributeTranslations.values._getAttr, - src: Element._attributeTranslations.values._getAttr, - disabled: Element._attributeTranslations.values._flag, - checked: Element._attributeTranslations.values._flag, - readonly: Element._attributeTranslations.values._flag, - multiple: Element._attributeTranslations.values._flag -}); - -Element.Methods.Simulated = { - hasAttribute: function(element, attribute) { - var t = Element._attributeTranslations; - attribute = t.names[attribute] || attribute; - return $(element).getAttributeNode(attribute).specified; - } -}; - -// IE is missing .innerHTML support for TABLE-related elements -if (document.all && !window.opera){ - Element.Methods.update = function(element, html) { - element = $(element); - html = typeof html == 'undefined' ? '' : html.toString(); - var tagName = element.tagName.toUpperCase(); - if (['THEAD','TBODY','TR','TD'].include(tagName)) { - var div = document.createElement('div'); - switch (tagName) { - case 'THEAD': - case 'TBODY': - div.innerHTML = '' + html.stripScripts() + '
        '; - depth = 2; - break; - case 'TR': - div.innerHTML = '' + html.stripScripts() + '
        '; - depth = 3; - break; - case 'TD': - div.innerHTML = '
        ' + html.stripScripts() + '
        '; - depth = 4; - } - $A(element.childNodes).each(function(node){ - element.removeChild(node) - }); - depth.times(function(){ div = div.firstChild }); - - $A(div.childNodes).each( - function(node){ element.appendChild(node) }); - } else { - element.innerHTML = html.stripScripts(); - } - setTimeout(function() {html.evalScripts()}, 10); - return element; - } -}; - -Object.extend(Element, Element.Methods); - -var _nativeExtensions = false; - -if(/Konqueror|Safari|KHTML/.test(navigator.userAgent)) - ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) { - var className = 'HTML' + tag + 'Element'; - if(window[className]) return; - var klass = window[className] = {}; - klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__; - }); - -Element.addMethods = function(methods) { - Object.extend(Element.Methods, methods || {}); - - function copy(methods, destination, onlyIfAbsent) { - onlyIfAbsent = onlyIfAbsent || false; - var cache = Element.extend.cache; - for (var property in methods) { - var value = methods[property]; - if (!onlyIfAbsent || !(property in destination)) - destination[property] = cache.findOrStore(value); - } - } - - if (typeof HTMLElement != 'undefined') { - copy(Element.Methods, HTMLElement.prototype); - copy(Element.Methods.Simulated, HTMLElement.prototype, true); - copy(Form.Methods, HTMLFormElement.prototype); - [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) { - copy(Form.Element.Methods, klass.prototype); - }); - _nativeExtensions = true; - } -} - -var Toggle = new Object(); -Toggle.display = Element.toggle; - -/*--------------------------------------------------------------------------*/ - -Abstract.Insertion = function(adjacency) { - this.adjacency = adjacency; -} - -Abstract.Insertion.prototype = { - initialize: function(element, content) { - this.element = $(element); - this.content = content.stripScripts(); - - if (this.adjacency && this.element.insertAdjacentHTML) { - try { - this.element.insertAdjacentHTML(this.adjacency, this.content); - } catch (e) { - var tagName = this.element.tagName.toUpperCase(); - if (['TBODY', 'TR'].include(tagName)) { - this.insertContent(this.contentFromAnonymousTable()); - } else { - throw e; - } - } - } else { - this.range = this.element.ownerDocument.createRange(); - if (this.initializeRange) this.initializeRange(); - this.insertContent([this.range.createContextualFragment(this.content)]); - } - - setTimeout(function() {content.evalScripts()}, 10); - }, - - contentFromAnonymousTable: function() { - var div = document.createElement('div'); - div.innerHTML = '' + this.content + '
        '; - return $A(div.childNodes[0].childNodes[0].childNodes); - } -} - -var Insertion = new Object(); - -Insertion.Before = Class.create(); -Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { - initializeRange: function() { - this.range.setStartBefore(this.element); - }, - - insertContent: function(fragments) { - fragments.each((function(fragment) { - this.element.parentNode.insertBefore(fragment, this.element); - }).bind(this)); - } -}); - -Insertion.Top = Class.create(); -Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { - initializeRange: function() { - this.range.selectNodeContents(this.element); - this.range.collapse(true); - }, - - insertContent: function(fragments) { - fragments.reverse(false).each((function(fragment) { - this.element.insertBefore(fragment, this.element.firstChild); - }).bind(this)); - } -}); - -Insertion.Bottom = Class.create(); -Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { - initializeRange: function() { - this.range.selectNodeContents(this.element); - this.range.collapse(this.element); - }, - - insertContent: function(fragments) { - fragments.each((function(fragment) { - this.element.appendChild(fragment); - }).bind(this)); - } -}); - -Insertion.After = Class.create(); -Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { - initializeRange: function() { - this.range.setStartAfter(this.element); - }, - - insertContent: function(fragments) { - fragments.each((function(fragment) { - this.element.parentNode.insertBefore(fragment, - this.element.nextSibling); - }).bind(this)); - } -}); - -/*--------------------------------------------------------------------------*/ - -Element.ClassNames = Class.create(); -Element.ClassNames.prototype = { - initialize: function(element) { - this.element = $(element); - }, - - _each: function(iterator) { - this.element.className.split(/\s+/).select(function(name) { - return name.length > 0; - })._each(iterator); - }, - - set: function(className) { - this.element.className = className; - }, - - add: function(classNameToAdd) { - if (this.include(classNameToAdd)) return; - this.set($A(this).concat(classNameToAdd).join(' ')); - }, - - remove: function(classNameToRemove) { - if (!this.include(classNameToRemove)) return; - this.set($A(this).without(classNameToRemove).join(' ')); - }, - - toString: function() { - return $A(this).join(' '); - } -}; - -Object.extend(Element.ClassNames.prototype, Enumerable); -var Selector = Class.create(); -Selector.prototype = { - initialize: function(expression) { - this.params = {classNames: []}; - this.expression = expression.toString().strip(); - this.parseExpression(); - this.compileMatcher(); - }, - - parseExpression: function() { - function abort(message) { throw 'Parse error in selector: ' + message; } - - if (this.expression == '') abort('empty expression'); - - var params = this.params, expr = this.expression, match, modifier, clause, rest; - while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) { - params.attributes = params.attributes || []; - params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''}); - expr = match[1]; - } - - if (expr == '*') return this.params.wildcard = true; - - while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) { - modifier = match[1], clause = match[2], rest = match[3]; - switch (modifier) { - case '#': params.id = clause; break; - case '.': params.classNames.push(clause); break; - case '': - case undefined: params.tagName = clause.toUpperCase(); break; - default: abort(expr.inspect()); - } - expr = rest; - } - - if (expr.length > 0) abort(expr.inspect()); - }, - - buildMatchExpression: function() { - var params = this.params, conditions = [], clause; - - if (params.wildcard) - conditions.push('true'); - if (clause = params.id) - conditions.push('element.readAttribute("id") == ' + clause.inspect()); - if (clause = params.tagName) - conditions.push('element.tagName.toUpperCase() == ' + clause.inspect()); - if ((clause = params.classNames).length > 0) - for (var i = 0, length = clause.length; i < length; i++) - conditions.push('element.hasClassName(' + clause[i].inspect() + ')'); - if (clause = params.attributes) { - clause.each(function(attribute) { - var value = 'element.readAttribute(' + attribute.name.inspect() + ')'; - var splitValueBy = function(delimiter) { - return value + ' && ' + value + '.split(' + delimiter.inspect() + ')'; - } - - switch (attribute.operator) { - case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break; - case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break; - case '|=': conditions.push( - splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect() - ); break; - case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break; - case '': - case undefined: conditions.push('element.hasAttribute(' + attribute.name.inspect() + ')'); break; - default: throw 'Unknown operator ' + attribute.operator + ' in selector'; - } - }); - } - - return conditions.join(' && '); - }, - - compileMatcher: function() { - this.match = new Function('element', 'if (!element.tagName) return false; \ - element = $(element); \ - return ' + this.buildMatchExpression()); - }, - - findElements: function(scope) { - var element; - - if (element = $(this.params.id)) - if (this.match(element)) - if (!scope || Element.childOf(element, scope)) - return [element]; - - scope = (scope || document).getElementsByTagName(this.params.tagName || '*'); - - var results = []; - for (var i = 0, length = scope.length; i < length; i++) - if (this.match(element = scope[i])) - results.push(Element.extend(element)); - - return results; - }, - - toString: function() { - return this.expression; - } -} - -Object.extend(Selector, { - matchElements: function(elements, expression) { - var selector = new Selector(expression); - return elements.select(selector.match.bind(selector)).map(Element.extend); - }, - - findElement: function(elements, expression, index) { - if (typeof expression == 'number') index = expression, expression = false; - return Selector.matchElements(elements, expression || '*')[index || 0]; - }, - - findChildElements: function(element, expressions) { - return expressions.map(function(expression) { - return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null], function(results, expr) { - var selector = new Selector(expr); - return results.inject([], function(elements, result) { - return elements.concat(selector.findElements(result || element)); - }); - }); - }).flatten(); - } -}); - -function $$() { - return Selector.findChildElements(document, $A(arguments)); -} -var Form = { - reset: function(form) { - $(form).reset(); - return form; - }, - - serializeElements: function(elements, getHash) { - var data = elements.inject({}, function(result, element) { - if (!element.disabled && element.name) { - var key = element.name, value = $(element).getValue(); - if (value != undefined) { - if (result[key]) { - if (result[key].constructor != Array) result[key] = [result[key]]; - result[key].push(value); - } - else result[key] = value; - } - } - return result; - }); - - return getHash ? data : Hash.toQueryString(data); - } -}; - -Form.Methods = { - serialize: function(form, getHash) { - return Form.serializeElements(Form.getElements(form), getHash); - }, - - getElements: function(form) { - return $A($(form).getElementsByTagName('*')).inject([], - function(elements, child) { - if (Form.Element.Serializers[child.tagName.toLowerCase()]) - elements.push(Element.extend(child)); - return elements; - } - ); - }, - - getInputs: function(form, typeName, name) { - form = $(form); - var inputs = form.getElementsByTagName('input'); - - if (!typeName && !name) return $A(inputs).map(Element.extend); - - for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { - var input = inputs[i]; - if ((typeName && input.type != typeName) || (name && input.name != name)) - continue; - matchingInputs.push(Element.extend(input)); - } - - return matchingInputs; - }, - - disable: function(form) { - form = $(form); - form.getElements().each(function(element) { - element.blur(); - element.disabled = 'true'; - }); - return form; - }, - - enable: function(form) { - form = $(form); - form.getElements().each(function(element) { - element.disabled = ''; - }); - return form; - }, - - findFirstElement: function(form) { - return $(form).getElements().find(function(element) { - return element.type != 'hidden' && !element.disabled && - ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); - }); - }, - - focusFirstElement: function(form) { - form = $(form); - form.findFirstElement().activate(); - return form; - } -} - -Object.extend(Form, Form.Methods); - -/*--------------------------------------------------------------------------*/ - -Form.Element = { - focus: function(element) { - $(element).focus(); - return element; - }, - - select: function(element) { - $(element).select(); - return element; - } -} - -Form.Element.Methods = { - serialize: function(element) { - element = $(element); - if (!element.disabled && element.name) { - var value = element.getValue(); - if (value != undefined) { - var pair = {}; - pair[element.name] = value; - return Hash.toQueryString(pair); - } - } - return ''; - }, - - getValue: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - return Form.Element.Serializers[method](element); - }, - - clear: function(element) { - $(element).value = ''; - return element; - }, - - present: function(element) { - return $(element).value != ''; - }, - - activate: function(element) { - element = $(element); - element.focus(); - if (element.select && ( element.tagName.toLowerCase() != 'input' || - !['button', 'reset', 'submit'].include(element.type) ) ) - element.select(); - return element; - }, - - disable: function(element) { - element = $(element); - element.disabled = true; - return element; - }, - - enable: function(element) { - element = $(element); - element.blur(); - element.disabled = false; - return element; - } -} - -Object.extend(Form.Element, Form.Element.Methods); -var Field = Form.Element; -var $F = Form.Element.getValue; - -/*--------------------------------------------------------------------------*/ - -Form.Element.Serializers = { - input: function(element) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - return Form.Element.Serializers.inputSelector(element); - default: - return Form.Element.Serializers.textarea(element); - } - }, - - inputSelector: function(element) { - return element.checked ? element.value : null; - }, - - textarea: function(element) { - return element.value; - }, - - select: function(element) { - return this[element.type == 'select-one' ? - 'selectOne' : 'selectMany'](element); - }, - - selectOne: function(element) { - var index = element.selectedIndex; - return index >= 0 ? this.optionValue(element.options[index]) : null; - }, - - selectMany: function(element) { - var values, length = element.length; - if (!length) return null; - - for (var i = 0, values = []; i < length; i++) { - var opt = element.options[i]; - if (opt.selected) values.push(this.optionValue(opt)); - } - return values; - }, - - optionValue: function(opt) { - // extend element because hasAttribute may not be native - return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; - } -} - -/*--------------------------------------------------------------------------*/ - -Abstract.TimedObserver = function() {} -Abstract.TimedObserver.prototype = { - initialize: function(element, frequency, callback) { - this.frequency = frequency; - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - this.registerCallback(); - }, - - registerCallback: function() { - setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - onTimerEvent: function() { - var value = this.getValue(); - var changed = ('string' == typeof this.lastValue && 'string' == typeof value - ? this.lastValue != value : String(this.lastValue) != String(value)); - if (changed) { - this.callback(this.element, value); - this.lastValue = value; - } - } -} - -Form.Element.Observer = Class.create(); -Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.Observer = Class.create(); -Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { - getValue: function() { - return Form.serialize(this.element); - } -}); - -/*--------------------------------------------------------------------------*/ - -Abstract.EventObserver = function() {} -Abstract.EventObserver.prototype = { - initialize: function(element, callback) { - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - if (this.element.tagName.toLowerCase() == 'form') - this.registerFormCallbacks(); - else - this.registerCallback(this.element); - }, - - onElementEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - }, - - registerFormCallbacks: function() { - Form.getElements(this.element).each(this.registerCallback.bind(this)); - }, - - registerCallback: function(element) { - if (element.type) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - Event.observe(element, 'click', this.onElementEvent.bind(this)); - break; - default: - Event.observe(element, 'change', this.onElementEvent.bind(this)); - break; - } - } - } -} - -Form.Element.EventObserver = Class.create(); -Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.EventObserver = Class.create(); -Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { - getValue: function() { - return Form.serialize(this.element); - } -}); -if (!window.Event) { - var Event = new Object(); -} - -Object.extend(Event, { - KEY_BACKSPACE: 8, - KEY_TAB: 9, - KEY_RETURN: 13, - KEY_ESC: 27, - KEY_LEFT: 37, - KEY_UP: 38, - KEY_RIGHT: 39, - KEY_DOWN: 40, - KEY_DELETE: 46, - KEY_HOME: 36, - KEY_END: 35, - KEY_PAGEUP: 33, - KEY_PAGEDOWN: 34, - - element: function(event) { - return event.target || event.srcElement; - }, - - isLeftClick: function(event) { - return (((event.which) && (event.which == 1)) || - ((event.button) && (event.button == 1))); - }, - - pointerX: function(event) { - return event.pageX || (event.clientX + - (document.documentElement.scrollLeft || document.body.scrollLeft)); - }, - - pointerY: function(event) { - return event.pageY || (event.clientY + - (document.documentElement.scrollTop || document.body.scrollTop)); - }, - - stop: function(event) { - if (event.preventDefault) { - event.preventDefault(); - event.stopPropagation(); - } else { - event.returnValue = false; - event.cancelBubble = true; - } - }, - - // find the first node with the given tagName, starting from the - // node the event was triggered on; traverses the DOM upwards - findElement: function(event, tagName) { - var element = Event.element(event); - while (element.parentNode && (!element.tagName || - (element.tagName.toUpperCase() != tagName.toUpperCase()))) - element = element.parentNode; - return element; - }, - - observers: false, - - _observeAndCache: function(element, name, observer, useCapture) { - if (!this.observers) this.observers = []; - if (element.addEventListener) { - this.observers.push([element, name, observer, useCapture]); - element.addEventListener(name, observer, useCapture); - } else if (element.attachEvent) { - this.observers.push([element, name, observer, useCapture]); - element.attachEvent('on' + name, observer); - } - }, - - unloadCache: function() { - if (!Event.observers) return; - for (var i = 0, length = Event.observers.length; i < length; i++) { - Event.stopObserving.apply(this, Event.observers[i]); - Event.observers[i][0] = null; - } - Event.observers = false; - }, - - observe: function(element, name, observer, useCapture) { - element = $(element); - useCapture = useCapture || false; - - if (name == 'keypress' && - (navigator.appVersion.match(/Konqueror|Safari|KHTML/) - || element.attachEvent)) - name = 'keydown'; - - Event._observeAndCache(element, name, observer, useCapture); - }, - - stopObserving: function(element, name, observer, useCapture) { - element = $(element); - useCapture = useCapture || false; - - if (name == 'keypress' && - (navigator.appVersion.match(/Konqueror|Safari|KHTML/) - || element.detachEvent)) - name = 'keydown'; - - if (element.removeEventListener) { - element.removeEventListener(name, observer, useCapture); - } else if (element.detachEvent) { - try { - element.detachEvent('on' + name, observer); - } catch (e) {} - } - } -}); - -/* prevent memory leaks in IE */ -if (navigator.appVersion.match(/\bMSIE\b/)) - Event.observe(window, 'unload', Event.unloadCache, false); -var Position = { - // set to true if needed, warning: firefox performance problems - // NOT neeeded for page scrolling, only if draggable contained in - // scrollable elements - includeScrollOffsets: false, - - // must be called before calling withinIncludingScrolloffset, every time the - // page is scrolled - prepare: function() { - this.deltaX = window.pageXOffset - || document.documentElement.scrollLeft - || document.body.scrollLeft - || 0; - this.deltaY = window.pageYOffset - || document.documentElement.scrollTop - || document.body.scrollTop - || 0; - }, - - realOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.scrollTop || 0; - valueL += element.scrollLeft || 0; - element = element.parentNode; - } while (element); - return [valueL, valueT]; - }, - - cumulativeOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - } while (element); - return [valueL, valueT]; - }, - - positionedOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - if (element) { - if(element.tagName=='BODY') break; - var p = Element.getStyle(element, 'position'); - if (p == 'relative' || p == 'absolute') break; - } - } while (element); - return [valueL, valueT]; - }, - - offsetParent: function(element) { - if (element.offsetParent) return element.offsetParent; - if (element == document.body) return element; - - while ((element = element.parentNode) && element != document.body) - if (Element.getStyle(element, 'position') != 'static') - return element; - - return document.body; - }, - - // caches x/y coordinate pair to use with overlap - within: function(element, x, y) { - if (this.includeScrollOffsets) - return this.withinIncludingScrolloffsets(element, x, y); - this.xcomp = x; - this.ycomp = y; - this.offset = this.cumulativeOffset(element); - - return (y >= this.offset[1] && - y < this.offset[1] + element.offsetHeight && - x >= this.offset[0] && - x < this.offset[0] + element.offsetWidth); - }, - - withinIncludingScrolloffsets: function(element, x, y) { - var offsetcache = this.realOffset(element); - - this.xcomp = x + offsetcache[0] - this.deltaX; - this.ycomp = y + offsetcache[1] - this.deltaY; - this.offset = this.cumulativeOffset(element); - - return (this.ycomp >= this.offset[1] && - this.ycomp < this.offset[1] + element.offsetHeight && - this.xcomp >= this.offset[0] && - this.xcomp < this.offset[0] + element.offsetWidth); - }, - - // within must be called directly before - overlap: function(mode, element) { - if (!mode) return 0; - if (mode == 'vertical') - return ((this.offset[1] + element.offsetHeight) - this.ycomp) / - element.offsetHeight; - if (mode == 'horizontal') - return ((this.offset[0] + element.offsetWidth) - this.xcomp) / - element.offsetWidth; - }, - - page: function(forElement) { - var valueT = 0, valueL = 0; - - var element = forElement; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - - // Safari fix - if (element.offsetParent==document.body) - if (Element.getStyle(element,'position')=='absolute') break; - - } while (element = element.offsetParent); - - element = forElement; - do { - if (!window.opera || element.tagName=='BODY') { - valueT -= element.scrollTop || 0; - valueL -= element.scrollLeft || 0; - } - } while (element = element.parentNode); - - return [valueL, valueT]; - }, - - clone: function(source, target) { - var options = Object.extend({ - setLeft: true, - setTop: true, - setWidth: true, - setHeight: true, - offsetTop: 0, - offsetLeft: 0 - }, arguments[2] || {}) - - // find page position of source - source = $(source); - var p = Position.page(source); - - // find coordinate system to use - target = $(target); - var delta = [0, 0]; - var parent = null; - // delta [0,0] will do fine with position: fixed elements, - // position:absolute needs offsetParent deltas - if (Element.getStyle(target,'position') == 'absolute') { - parent = Position.offsetParent(target); - delta = Position.page(parent); - } - - // correct by body offsets (fixes Safari) - if (parent == document.body) { - delta[0] -= document.body.offsetLeft; - delta[1] -= document.body.offsetTop; - } - - // set position - if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; - if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; - if(options.setWidth) target.style.width = source.offsetWidth + 'px'; - if(options.setHeight) target.style.height = source.offsetHeight + 'px'; - }, - - absolutize: function(element) { - element = $(element); - if (element.style.position == 'absolute') return; - Position.prepare(); - - var offsets = Position.positionedOffset(element); - var top = offsets[1]; - var left = offsets[0]; - var width = element.clientWidth; - var height = element.clientHeight; - - element._originalLeft = left - parseFloat(element.style.left || 0); - element._originalTop = top - parseFloat(element.style.top || 0); - element._originalWidth = element.style.width; - element._originalHeight = element.style.height; - - element.style.position = 'absolute'; - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.width = width + 'px'; - element.style.height = height + 'px'; - }, - - relativize: function(element) { - element = $(element); - if (element.style.position == 'relative') return; - Position.prepare(); - - element.style.position = 'relative'; - var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); - var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); - - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.height = element._originalHeight; - element.style.width = element._originalWidth; - } -} - -// Safari returns margins on body which is incorrect if the child is absolutely -// positioned. For performance reasons, redefine Position.cumulativeOffset for -// KHTML/WebKit only. -if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { - Position.cumulativeOffset = function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - if (element.offsetParent == document.body) - if (Element.getStyle(element, 'position') == 'absolute') break; - - element = element.offsetParent; - } while (element); - - return [valueL, valueT]; - } -} - -Element.addMethods(); \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/robots.txt b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/robots.txt deleted file mode 100644 index 4ab9e89f..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/robots.txt +++ /dev/null @@ -1 +0,0 @@ -# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/stylesheets/scaffold.css b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/stylesheets/scaffold.css deleted file mode 100644 index 8f239a35..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/public/stylesheets/scaffold.css +++ /dev/null @@ -1,74 +0,0 @@ -body { background-color: #fff; color: #333; } - -body, p, ol, ul, td { - font-family: verdana, arial, helvetica, sans-serif; - font-size: 13px; - line-height: 18px; -} - -pre { - background-color: #eee; - padding: 10px; - font-size: 11px; -} - -a { color: #000; } -a:visited { color: #666; } -a:hover { color: #fff; background-color:#000; } - -.fieldWithErrors { - padding: 2px; - background-color: red; - display: table; -} - -#errorExplanation { - width: 400px; - border: 2px solid red; - padding: 7px; - padding-bottom: 12px; - margin-bottom: 20px; - background-color: #f0f0f0; -} - -#errorExplanation h2 { - text-align: left; - font-weight: bold; - padding: 5px 5px 5px 15px; - font-size: 12px; - margin: -7px; - background-color: #c00; - color: #fff; -} - -#errorExplanation p { - color: #333; - margin-bottom: 0; - padding: 5px; -} - -#errorExplanation ul li { - font-size: 12px; - list-style: square; -} - -div.uploadStatus { - margin: 5px; -} - -div.progressBar { - margin: 5px; -} - -div.progressBar div.border { - background-color: #fff; - border: 1px solid grey; - width: 100%; -} - -div.progressBar div.background { - background-color: #333; - height: 18px; - width: 0%; -} - diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/about b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/about deleted file mode 100755 index 7b07d46a..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/about +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/about' \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/breakpointer b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/breakpointer deleted file mode 100755 index 64af76ed..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/breakpointer +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/breakpointer' \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/console b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/console deleted file mode 100755 index 42f28f7d..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/console +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/console' \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/destroy b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/destroy deleted file mode 100755 index fa0e6fcd..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/destroy +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/destroy' \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/generate b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/generate deleted file mode 100755 index ef976e09..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/generate +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/generate' \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/performance/benchmarker b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/performance/benchmarker deleted file mode 100755 index c842d35d..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/performance/benchmarker +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../../config/boot' -require 'commands/performance/benchmarker' diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/performance/profiler b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/performance/profiler deleted file mode 100755 index d855ac8b..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/performance/profiler +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../../config/boot' -require 'commands/performance/profiler' diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/plugin b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/plugin deleted file mode 100755 index 26ca64c0..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/plugin +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/plugin' \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/inspector b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/inspector deleted file mode 100755 index bf25ad86..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/inspector +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../../config/boot' -require 'commands/process/inspector' diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/reaper b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/reaper deleted file mode 100755 index c77f0453..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/reaper +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../../config/boot' -require 'commands/process/reaper' diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/spawner b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/spawner deleted file mode 100755 index 7118f398..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/process/spawner +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../../config/boot' -require 'commands/process/spawner' diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/runner b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/runner deleted file mode 100755 index ccc30f9d..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/runner +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/runner' \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/server b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/server deleted file mode 100755 index dfabcb88..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/script/server +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../config/boot' -require 'commands/server' \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/double_sti_parent_relationships.yml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/double_sti_parent_relationships.yml deleted file mode 100644 index 5bf02933..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/double_sti_parent_relationships.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html - -# one: -# column: value -# -# two: -# column: value diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/double_sti_parents.yml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/double_sti_parents.yml deleted file mode 100644 index 5bf02933..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/double_sti_parents.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html - -# one: -# column: value -# -# two: -# column: value diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/organic_substances.yml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/organic_substances.yml deleted file mode 100644 index 123ef537..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/organic_substances.yml +++ /dev/null @@ -1,5 +0,0 @@ -one: - type: Bone - -two: - type: Bone diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/single_sti_parent_relationships.yml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/single_sti_parent_relationships.yml deleted file mode 100644 index 5bf02933..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/single_sti_parent_relationships.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html - -# one: -# column: value -# -# two: -# column: value diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/single_sti_parents.yml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/single_sti_parents.yml deleted file mode 100644 index 5bf02933..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/single_sti_parents.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html - -# one: -# column: value -# -# two: -# column: value diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/sticks.yml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/sticks.yml deleted file mode 100644 index 157d7472..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/sticks.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html - -one: - name: MyString - -two: - name: MyString diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/stones.yml b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/stones.yml deleted file mode 100644 index 157d7472..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/fixtures/stones.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html - -one: - name: MyString - -two: - name: MyString diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/addresses_controller_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/addresses_controller_test.rb deleted file mode 100644 index 65284b5b..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/addresses_controller_test.rb +++ /dev/null @@ -1,57 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' -require 'addresses_controller' - -# Re-raise errors caught by the controller. -class AddressesController; def rescue_action(e) raise e end; end - -class AddressesControllerTest < Test::Unit::TestCase - fixtures :addresses - - def setup - @controller = AddressesController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end - - def test_should_get_index - get :index - assert_response :success - assert assigns(:addresses) - end - - def test_should_get_new - get :new - assert_response :success - end - - def test_should_create_address - assert_difference('Address.count') do - post :create, :address => { :country_id => 1, :user_id => 1, :state_id => 1} - end - - assert_redirected_to address_path(assigns(:address)) - end - - def test_should_show_address - get :show, :id => 1 - assert_response :success - end - - def test_should_get_edit - get :edit, :id => 1 - assert_response :success - end - - def test_should_update_address - put :update, :id => 1, :address => { } - assert_redirected_to address_path(assigns(:address)) - end - - def test_should_destroy_address - assert_difference('Address.count', -1) do - delete :destroy, :id => 1 - end - - assert_redirected_to addresses_path - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/bones_controller_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/bones_controller_test.rb deleted file mode 100644 index fc0c7bd8..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/bones_controller_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class BonesControllerTest < ActionController::TestCase - # Replace this with your real tests. - def test_truth - assert true - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/sellers_controller_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/sellers_controller_test.rb deleted file mode 100644 index fb992e5d..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/sellers_controller_test.rb +++ /dev/null @@ -1,57 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' -require 'sellers_controller' - -# Re-raise errors caught by the controller. -class SellersController; def rescue_action(e) raise e end; end - -class SellersControllerTest < Test::Unit::TestCase - fixtures :sellers - - def setup - @controller = SellersController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end - - def test_should_get_index - get :index - assert_response :success - assert assigns(:sellers) - end - - def test_should_get_new - get :new - assert_response :success - end - - def test_should_create_seller - assert_difference('Seller.count') do - post :create, :seller => { } - end - - assert_redirected_to seller_path(assigns(:seller)) - end - - def test_should_show_seller - get :show, :id => 1 - assert_response :success - end - - def test_should_get_edit - get :edit, :id => 1 - assert_response :success - end - - def test_should_update_seller - put :update, :id => 1, :seller => { } - assert_redirected_to seller_path(assigns(:seller)) - end - - def test_should_destroy_seller - assert_difference('Seller.count', -1) do - delete :destroy, :id => 1 - end - - assert_redirected_to sellers_path - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/states_controller_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/states_controller_test.rb deleted file mode 100644 index 2e93453b..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/states_controller_test.rb +++ /dev/null @@ -1,57 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' -require 'states_controller' - -# Re-raise errors caught by the controller. -class StatesController; def rescue_action(e) raise e end; end - -class StatesControllerTest < Test::Unit::TestCase - fixtures :states - - def setup - @controller = StatesController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end - - def test_should_get_index - get :index - assert_response :success - assert assigns(:states) - end - - def test_should_get_new - get :new - assert_response :success - end - - def test_should_create_state - assert_difference('State.count') do - post :create, :state => { } - end - - assert_redirected_to state_path(assigns(:state)) - end - - def test_should_show_state - get :show, :id => 1 - assert_response :success - end - - def test_should_get_edit - get :edit, :id => 1 - assert_response :success - end - - def test_should_update_state - put :update, :id => 1, :state => { } - assert_redirected_to state_path(assigns(:state)) - end - - def test_should_destroy_state - assert_difference('State.count', -1) do - delete :destroy, :id => 1 - end - - assert_redirected_to states_path - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/users_controller_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/users_controller_test.rb deleted file mode 100644 index bc36751f..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/functional/users_controller_test.rb +++ /dev/null @@ -1,57 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' -require 'users_controller' - -# Re-raise errors caught by the controller. -class UsersController; def rescue_action(e) raise e end; end - -class UsersControllerTest < Test::Unit::TestCase - fixtures :users - - def setup - @controller = UsersController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end - - def test_should_get_index - get :index - assert_response :success - assert assigns(:users) - end - - def test_should_get_new - get :new - assert_response :success - end - - def test_should_create_user - assert_difference('User.count') do - post :create, :user => { } - end - - assert_redirected_to user_path(assigns(:user)) - end - - def test_should_show_user - get :show, :id => 1 - assert_response :success - end - - def test_should_get_edit - get :edit, :id => 1 - assert_response :success - end - - def test_should_update_user - put :update, :id => 1, :user => { } - assert_redirected_to user_path(assigns(:user)) - end - - def test_should_destroy_user - assert_difference('User.count', -1) do - delete :destroy, :id => 1 - end - - assert_redirected_to users_path - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/test_helper.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/test_helper.rb deleted file mode 100644 index 773c49de..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/test_helper.rb +++ /dev/null @@ -1,8 +0,0 @@ -ENV["RAILS_ENV"] = "development" -require File.expand_path(File.dirname(__FILE__) + "/../config/environment") -require 'test_help' - -class Test::Unit::TestCase - self.use_transactional_fixtures = true - self.use_instantiated_fixtures = false -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/bone_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/bone_test.rb deleted file mode 100644 index 8afcb87b..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/bone_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class BoneTest < Test::Unit::TestCase - # Replace this with your real tests. - def test_truth - assert true - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/double_sti_parent_relationship_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/double_sti_parent_relationship_test.rb deleted file mode 100644 index dc20e74d..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/double_sti_parent_relationship_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class DoubleStiParentRelationshipTest < Test::Unit::TestCase - # Replace this with your real tests. - def test_truth - assert true - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/double_sti_parent_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/double_sti_parent_test.rb deleted file mode 100644 index 154383a2..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/double_sti_parent_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class DoubleStiParentTest < Test::Unit::TestCase - # Replace this with your real tests. - def test_truth - assert true - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/organic_substance_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/organic_substance_test.rb deleted file mode 100644 index af328b95..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/organic_substance_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class OrganicSubstanceTest < Test::Unit::TestCase - # Replace this with your real tests. - def test_truth - assert true - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/single_sti_parent_relationship_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/single_sti_parent_relationship_test.rb deleted file mode 100644 index d5563fd8..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/single_sti_parent_relationship_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class SingleStiParentRelationshipTest < Test::Unit::TestCase - # Replace this with your real tests. - def test_truth - assert true - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/single_sti_parent_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/single_sti_parent_test.rb deleted file mode 100644 index 70a00ecb..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/single_sti_parent_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class SingleStiParentTest < Test::Unit::TestCase - # Replace this with your real tests. - def test_truth - assert true - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/stick_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/stick_test.rb deleted file mode 100644 index 6729e0d6..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/stick_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class StickTest < Test::Unit::TestCase - # Replace this with your real tests. - def test_truth - assert true - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/stone_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/stone_test.rb deleted file mode 100644 index 76b518d7..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/app/test/unit/stone_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class StoneTest < Test::Unit::TestCase - # Replace this with your real tests. - def test_truth - assert true - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/integration/server_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/integration/server_test.rb deleted file mode 100644 index e53ea1aa..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/integration/server_test.rb +++ /dev/null @@ -1,43 +0,0 @@ - -require "#{File.dirname(__FILE__)}/../test_helper" -require 'open-uri' - -# Start the server - -class ServerTest < Test::Unit::TestCase - - PORT = 43040 - URL = "http://localhost:#{PORT}/" - - def setup - @pid = Process.fork do - Dir.chdir RAILS_ROOT do - # print "S" - exec("script/server -p #{PORT} &> #{LOG}") - end - end - sleep(5) - end - - def teardown - # Process.kill(9, @pid) doesn't work because Mongrel has double-forked itself away - `ps awx | grep #{PORT} | grep -v grep | awk '{print $1}'`.split("\n").each do |pid| - system("kill -9 #{pid}") - # print "K" - end - sleep(2) - @pid = nil - end - - def test_association_reloading - assert_match(/Bones: index/, open(URL + 'bones').read) - assert_match(/Bones: index/, open(URL + 'bones').read) - assert_match(/Bones: index/, open(URL + 'bones').read) - assert_match(/Bones: index/, open(URL + 'bones').read) - end - - def test_verify_autoload_gets_invoked_in_console - # XXX Probably can use script/runner to test this - end - -end \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/fish.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/fish.rb deleted file mode 100644 index 204642e9..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/fish.rb +++ /dev/null @@ -1,5 +0,0 @@ -class Aquatic::Fish < ActiveRecord::Base - # set_table_name "fish" - # attr_accessor :after_find_test, :after_initialize_test -end - diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/pupils_whale.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/pupils_whale.rb deleted file mode 100644 index ae4cbc18..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/pupils_whale.rb +++ /dev/null @@ -1,7 +0,0 @@ - -class Aquatic::PupilsWhale < ActiveRecord::Base - set_table_name "little_whale_pupils" - belongs_to :whale, :class_name => "Aquatic::Whale", :foreign_key => "whale_id" - belongs_to :aquatic_pupil, :polymorphic => true -end - diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/whale.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/whale.rb deleted file mode 100644 index 0ca1b7fb..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/models/aquatic/whale.rb +++ /dev/null @@ -1,15 +0,0 @@ -# see http://dev.rubyonrails.org/ticket/5935 -module Aquatic; end -require 'aquatic/fish' -require 'aquatic/pupils_whale' - -class Aquatic::Whale < ActiveRecord::Base - # set_table_name "whales" - - has_many_polymorphs(:aquatic_pupils, :from => [:dogs, :"aquatic/fish"], - :through => "aquatic/pupils_whales") do - def a_method - :correct_block_result - end - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/beautiful_fight_relationship.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/beautiful_fight_relationship.rb deleted file mode 100644 index b678c982..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/models/beautiful_fight_relationship.rb +++ /dev/null @@ -1,26 +0,0 @@ - -require 'extension_module' - -class BeautifulFightRelationship < ActiveRecord::Base - set_table_name 'keep_your_enemies_close' - - belongs_to :enemy, :polymorphic => true - belongs_to :protector, :polymorphic => true - # polymorphic relationships with column names different from the relationship name - # are not supported by Rails - - acts_as_double_polymorphic_join :enemies => [:dogs, :kittens, :frogs], - :protectors => [:wild_boars, :kittens, :"aquatic/fish", :dogs], - :enemies_extend => [ExtensionModule, proc {}], - :protectors_extend => proc { - def a_method - :correct_proc_result - end - }, - :join_extend => proc { - def a_method - :correct_join_result - end - } -end - diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/canine.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/canine.rb deleted file mode 100644 index b0010160..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/models/canine.rb +++ /dev/null @@ -1,9 +0,0 @@ -class Canine < ActiveRecord::Base - self.abstract_class = true - - def an_abstract_method - :correct_abstract_method_response - end - -end - diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/cat.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/cat.rb deleted file mode 100644 index 0c99ff08..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/models/cat.rb +++ /dev/null @@ -1,5 +0,0 @@ -class Cat < ActiveRecord::Base - # STI base class - self.inheritance_column = 'cat_type' -end - diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/dog.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/dog.rb deleted file mode 100644 index 7f027237..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/models/dog.rb +++ /dev/null @@ -1,18 +0,0 @@ - -require 'canine' - -class Dog < Canine - attr_accessor :after_find_test, :after_initialize_test - set_table_name "bow_wows" - - def after_find - @after_find_test = true -# puts "After find called on #{name}." - end - - def after_initialize - @after_initialize_test = true - end - -end - diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/eaters_foodstuff.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/eaters_foodstuff.rb deleted file mode 100644 index d904bb16..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/models/eaters_foodstuff.rb +++ /dev/null @@ -1,10 +0,0 @@ - -class EatersFoodstuff < ActiveRecord::Base - belongs_to :foodstuff, :class_name => "Petfood", :foreign_key => "foodstuff_id" - belongs_to :eater, :polymorphic => true - - def before_save - self.some_attribute = 3 - end -end - diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/frog.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/frog.rb deleted file mode 100644 index 5a0f4658..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/models/frog.rb +++ /dev/null @@ -1,4 +0,0 @@ -class Frog < ActiveRecord::Base - -end - diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/kitten.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/kitten.rb deleted file mode 100644 index 2a244c03..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/models/kitten.rb +++ /dev/null @@ -1,3 +0,0 @@ -class Kitten < Cat -# has_many :eaters_parents, :dependent => true, :as => 'eater' -end \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/parentship.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/parentship.rb deleted file mode 100644 index e87b759b..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/models/parentship.rb +++ /dev/null @@ -1,4 +0,0 @@ -class Parentship < ActiveRecord::Base - belongs_to :parent, :class_name => "Person", :foreign_key => "parent_id" - belongs_to :kid, :polymorphic => true, :foreign_type => "child_type" -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/person.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/person.rb deleted file mode 100644 index 5d019829..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/models/person.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'parentship' -class Person < ActiveRecord::Base - has_many_polymorphs :kids, - :through => :parentships, - :from => [:people], - :as => :parent, - :polymorphic_type_key => "child_type", - :conditions => "people.age < 10" -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/petfood.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/petfood.rb deleted file mode 100644 index df420ea8..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/models/petfood.rb +++ /dev/null @@ -1,39 +0,0 @@ -# see http://dev.rubyonrails.org/ticket/5935 -require 'eaters_foodstuff' -require 'petfood' -require 'cat' -module Aquatic; end -require 'aquatic/fish' -require 'dog' -require 'wild_boar' -require 'kitten' -require 'tabby' -require 'extension_module' -require 'other_extension_module' - -class Petfood < ActiveRecord::Base - set_primary_key 'the_petfood_primary_key' - has_many_polymorphs :eaters, - :from => [:dogs, :petfoods, :wild_boars, :kittens, - :tabbies, :"aquatic/fish"], -# :dependent => :destroy, :destroy is now the default - :rename_individual_collections => true, - :as => :foodstuff, - :foreign_key => "foodstuff_id", - :ignore_duplicates => false, - :conditions => "NULL IS NULL", - :order => "eaters_foodstuffs.updated_at ASC", - :parent_order => "petfoods.the_petfood_primary_key DESC", - :parent_conditions => "petfoods.name IS NULL OR petfoods.name != 'Snausages'", - :extend => [ExtensionModule, OtherExtensionModule, proc {}], - :join_extend => proc { - def a_method - :correct_join_result - end - }, - :parent_extend => proc { - def a_method - :correct_parent_proc_result - end - } - end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/tabby.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/tabby.rb deleted file mode 100644 index 3cd0f994..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/models/tabby.rb +++ /dev/null @@ -1,2 +0,0 @@ -class Tabby < Cat -end \ No newline at end of file diff --git a/vendor/gems/has_many_polymorphs-2.13/test/models/wild_boar.rb b/vendor/gems/has_many_polymorphs-2.13/test/models/wild_boar.rb deleted file mode 100644 index 27d36a53..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/models/wild_boar.rb +++ /dev/null @@ -1,3 +0,0 @@ -class WildBoar < ActiveRecord::Base -end - diff --git a/vendor/gems/has_many_polymorphs-2.13/test/modules/extension_module.rb b/vendor/gems/has_many_polymorphs-2.13/test/modules/extension_module.rb deleted file mode 100644 index 7cb4eff4..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/modules/extension_module.rb +++ /dev/null @@ -1,9 +0,0 @@ - -module ExtensionModule - def a_method - :correct_module_result - end - def self.a_method - :incorrect_module_result - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/modules/other_extension_module.rb b/vendor/gems/has_many_polymorphs-2.13/test/modules/other_extension_module.rb deleted file mode 100644 index 16313bd8..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/modules/other_extension_module.rb +++ /dev/null @@ -1,9 +0,0 @@ - -module OtherExtensionModule - def another_method - :correct_other_module_result - end - def self.another_method - :incorrect_other_module_result - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/patches/symlinked_plugins_1.2.6.diff b/vendor/gems/has_many_polymorphs-2.13/test/patches/symlinked_plugins_1.2.6.diff deleted file mode 100644 index 99e0df3e..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/patches/symlinked_plugins_1.2.6.diff +++ /dev/null @@ -1,46 +0,0 @@ -Index: /trunk/railties/lib/rails_generator/lookup.rb -=================================================================== ---- /trunk/railties/lib/rails_generator/lookup.rb (revision 4310) -+++ /trunk/railties/lib/rails_generator/lookup.rb (revision 6101) -@@ -101,5 +101,5 @@ - sources << PathSource.new(:lib, "#{::RAILS_ROOT}/lib/generators") - sources << PathSource.new(:vendor, "#{::RAILS_ROOT}/vendor/generators") -- sources << PathSource.new(:plugins, "#{::RAILS_ROOT}/vendor/plugins/**/generators") -+ sources << PathSource.new(:plugins, "#{::RAILS_ROOT}/vendor/plugins/*/**/generators") - end - sources << PathSource.new(:user, "#{Dir.user_home}/.rails/generators") -Index: /trunk/railties/lib/tasks/rails.rb -=================================================================== ---- /trunk/railties/lib/tasks/rails.rb (revision 5469) -+++ /trunk/railties/lib/tasks/rails.rb (revision 6101) -@@ -6,3 +6,3 @@ - # Load any custom rakefile extensions - Dir["#{RAILS_ROOT}/lib/tasks/**/*.rake"].sort.each { |ext| load ext } --Dir["#{RAILS_ROOT}/vendor/plugins/**/tasks/**/*.rake"].sort.each { |ext| load ext } -+Dir["#{RAILS_ROOT}/vendor/plugins/*/**/tasks/**/*.rake"].sort.each { |ext| load ext } -Index: /trunk/railties/lib/tasks/testing.rake -=================================================================== ---- /trunk/railties/lib/tasks/testing.rake (revision 5263) -+++ /trunk/railties/lib/tasks/testing.rake (revision 6101) -@@ -109,9 +109,9 @@ - t.pattern = "vendor/plugins/#{ENV['PLUGIN']}/test/**/*_test.rb" - else -- t.pattern = 'vendor/plugins/**/test/**/*_test.rb' -+ t.pattern = 'vendor/plugins/*/**/test/**/*_test.rb' - end - - t.verbose = true - end -- Rake::Task['test:plugins'].comment = "Run the plugin tests in vendor/plugins/**/test (or specify with PLUGIN=name)" -+ Rake::Task['test:plugins'].comment = "Run the plugin tests in vendor/plugins/*/**/test (or specify with PLUGIN=name)" - end -Index: /trunk/railties/CHANGELOG -=================================================================== ---- /trunk/railties/CHANGELOG (revision 6069) -+++ /trunk/railties/CHANGELOG (revision 6101) -@@ -1,3 +1,5 @@ - *SVN* -+ -+* Plugins may be symlinked in vendor/plugins. #4245 [brandon, progrium@gmail.com] - - * Resource generator depends on the model generator rather than duplicating it. #7269 [bscofield] diff --git a/vendor/gems/has_many_polymorphs-2.13/test/schema.rb b/vendor/gems/has_many_polymorphs-2.13/test/schema.rb deleted file mode 100644 index 39d869dc..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/schema.rb +++ /dev/null @@ -1,87 +0,0 @@ -ActiveRecord::Schema.define(:version => 0) do - create_table :petfoods, :force => true, :primary_key => :the_petfood_primary_key do |t| - t.column :name, :string - t.column :created_at, :datetime, :null => false - t.column :updated_at, :datetime, :null => false - end - - create_table :bow_wows, :force => true do |t| - t.column :name, :string - t.column :created_at, :datetime, :null => false - t.column :updated_at, :datetime, :null => false - end - - create_table :cats, :force => true do |t| - t.column :name, :string - t.column :cat_type, :string - t.column :created_at, :datetime, :null => false - t.column :updated_at, :datetime, :null => false - end - - create_table :frogs, :force => true do |t| - t.column :name, :string - t.column :created_at, :datetime, :null => false - t.column :updated_at, :datetime, :null => false - end - - create_table :wild_boars, :force => true do |t| - t.column :name, :string - t.column :created_at, :datetime, :null => false - t.column :updated_at, :datetime, :null => false - end - - create_table :eaters_foodstuffs, :force => true do |t| - t.column :foodstuff_id, :integer - t.column :eater_id, :integer - t.column :some_attribute, :integer, :default => 0 - t.column :eater_type, :string - t.column :created_at, :datetime, :null => false - t.column :updated_at, :datetime, :null => false - end - - create_table :fish, :force => true do |t| - t.column :name, :string - t.column :speed, :integer - t.column :created_at, :datetime, :null => false - t.column :updated_at, :datetime, :null => false - end - - create_table :whales, :force => true do |t| - t.column :name, :string - t.column :created_at, :datetime, :null => false - t.column :updated_at, :datetime, :null => false - end - - create_table :little_whale_pupils, :force => true do |t| - t.column :whale_id, :integer - t.column :aquatic_pupil_id, :integer - t.column :aquatic_pupil_type, :string - t.column :created_at, :datetime, :null => false - t.column :updated_at, :datetime, :null => false - end - - create_table :keep_your_enemies_close, :force => true do |t| - t.column :enemy_id, :integer - t.column :enemy_type, :string - t.column :protector_id, :integer - t.column :protector_type, :string - t.column :created_at, :datetime, :null => false - t.column :updated_at, :datetime, :null => false - end - - create_table :parentships, :force => true do |t| - t.column :parent_id, :integer - t.column :child_type, :string - t.column :kid_id, :integer - t.column :created_at, :datetime, :null => false - t.column :updated_at, :datetime, :null => false - end - - create_table :people, :force => true do |t| - t.column :name, :string - t.column :age, :integer - t.column :created_at, :datetime, :null => false - t.column :updated_at, :datetime, :null => false - end - -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/setup.rb b/vendor/gems/has_many_polymorphs-2.13/test/setup.rb deleted file mode 100644 index 52535798..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/setup.rb +++ /dev/null @@ -1,14 +0,0 @@ - -# Setup integration system for the integration suite - -Dir.chdir "#{File.dirname(__FILE__)}/integration/app/" do - Dir.chdir "vendor/plugins" do - system("rm has_many_polymorphs; ln -s ../../../../../ has_many_polymorphs") - end - - system "rake db:drop --trace RAILS_GEM_VERSION=2.2.2 " - system "rake db:create --trace RAILS_GEM_VERSION=2.2.2 " - system "rake db:migrate --trace" - system "rake db:fixtures:load --trace" -end - diff --git a/vendor/gems/has_many_polymorphs-2.13/test/test_helper.rb b/vendor/gems/has_many_polymorphs-2.13/test/test_helper.rb deleted file mode 100644 index 363a6607..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/test_helper.rb +++ /dev/null @@ -1,51 +0,0 @@ - -$VERBOSE = nil -require 'rubygems' -require 'echoe' -require 'test/unit' -require 'multi_rails_init' -require 'ruby-debug' - -if defined? ENV['MULTIRAILS_RAILS_VERSION'] - ENV['RAILS_GEM_VERSION'] = ENV['MULTIRAILS_RAILS_VERSION'] -end - -Echoe.silence do - HERE = File.expand_path(File.dirname(__FILE__)) - $LOAD_PATH << HERE - # $LOAD_PATH << "#{HERE}/integration/app" -end - -LOG = "#{HERE}/integration/app/log/development.log" - -### For unit tests - -require 'integration/app/config/environment' -require 'test_help' - -ActiveSupport::Inflector.inflections {|i| i.irregular 'fish', 'fish' } - -$LOAD_PATH.unshift(Test::Unit::TestCase.fixture_path = HERE + "/fixtures") -$LOAD_PATH.unshift(HERE + "/models") -$LOAD_PATH.unshift(HERE + "/modules") - -class Test::Unit::TestCase - self.use_transactional_fixtures = !(ActiveRecord::Base.connection.is_a? ActiveRecord::ConnectionAdapters::MysqlAdapter rescue false) - self.use_instantiated_fixtures = false -end - -Echoe.silence do - load(HERE + "/schema.rb") -end - -### For integration tests - -def truncate - system("> #{LOG}") -end - -def log - File.open(LOG, 'r') do |f| - f.read - end -end diff --git a/vendor/gems/has_many_polymorphs-2.13/test/unit/has_many_polymorphs_test.rb b/vendor/gems/has_many_polymorphs-2.13/test/unit/has_many_polymorphs_test.rb deleted file mode 100644 index 7f4b05a4..00000000 --- a/vendor/gems/has_many_polymorphs-2.13/test/unit/has_many_polymorphs_test.rb +++ /dev/null @@ -1,714 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -require 'dog' -require 'wild_boar' -require 'frog' -require 'cat' -require 'kitten' -require 'aquatic/whale' -require 'aquatic/fish' -require 'aquatic/pupils_whale' -require 'beautiful_fight_relationship' - -class PolymorphTest < Test::Unit::TestCase - - set_fixture_class :bow_wows => Dog - set_fixture_class :keep_your_enemies_close => BeautifulFightRelationship - set_fixture_class :whales => Aquatic::Whale - set_fixture_class :fish => Aquatic::Fish - set_fixture_class :little_whale_pupils => Aquatic::PupilsWhale - - fixtures :cats, :bow_wows, :frogs, :wild_boars, :eaters_foodstuffs, :petfoods, - :fish, :whales, :little_whale_pupils, :keep_your_enemies_close, :people - - def setup - @association_error = ActiveRecord::Associations::PolymorphicError - @kibbles = Petfood.find(1) - @bits = Petfood.find(2) - @shamu = Aquatic::Whale.find(1) - @swimmy = Aquatic::Fish.find(1) - @rover = Dog.find(1) - @spot = Dog.find(2) - @puma = WildBoar.find(1) - @chloe = Kitten.find(1) - @alice = Kitten.find(2) - @toby = Tabby.find(3) - @froggy = Frog.find(1) - - @join_count = EatersFoodstuff.count - @kibbles_eaters_count = @kibbles.eaters.size - @bits_eaters_count = @bits.eaters.size - - @double_join_count = BeautifulFightRelationship.count - @alice_enemies_count = @alice.enemies.size - end - - def test_all_relationship_validities - # q = [] - # ObjectSpace.each_object(Class){|c| q << c if c.ancestors.include? ActiveRecord::Base } - # q.each{|c| puts "#{c.name}.reflect_on_all_associations.map(&:check_validity!)"} - Petfood.reflect_on_all_associations.map(&:check_validity!) - Tabby.reflect_on_all_associations.map(&:check_validity!) - Kitten.reflect_on_all_associations.map(&:check_validity!) - Dog.reflect_on_all_associations.map(&:check_validity!) - Canine.reflect_on_all_associations.map(&:check_validity!) - Aquatic::Fish.reflect_on_all_associations.map(&:check_validity!) - EatersFoodstuff.reflect_on_all_associations.map(&:check_validity!) - WildBoar.reflect_on_all_associations.map(&:check_validity!) - Frog.reflect_on_all_associations.map(&:check_validity!) - Cat.reflect_on_all_associations.map(&:check_validity!) - BeautifulFightRelationship.reflect_on_all_associations.map(&:check_validity!) - Person.reflect_on_all_associations.map(&:check_validity!) - Parentship.reflect_on_all_associations.map(&:check_validity!) - Aquatic::Whale.reflect_on_all_associations.map(&:check_validity!) - Aquatic::PupilsWhale.reflect_on_all_associations.map(&:check_validity!) - end - - def test_assignment - assert @kibbles.eaters.blank? - assert @kibbles.eaters.push(Cat.find_by_name('Chloe')) - assert_equal @kibbles_eaters_count += 1, @kibbles.eaters.count - - @kibbles.reload - assert_equal @kibbles_eaters_count, @kibbles.eaters.count - end - - def test_duplicate_assignment - # try to add a duplicate item when :ignore_duplicates is false - @kibbles.eaters.push(@alice) - assert @kibbles.eaters.include?(@alice) - @kibbles.eaters.push(@alice) - assert_equal @kibbles_eaters_count + 2, @kibbles.eaters.count - assert_equal @join_count + 2, EatersFoodstuff.count - end - - def test_create_and_push - assert @kibbles.eaters.push(@spot) - assert_equal @kibbles_eaters_count += 1, @kibbles.eaters.count - assert @kibbles.eaters << @rover - assert @kibbles.eaters << Kitten.create(:name => "Miranda") - assert_equal @kibbles_eaters_count += 2, @kibbles.eaters.length - - @kibbles.reload - assert_equal @kibbles_eaters_count, @kibbles.eaters.length - - # test that ids and new flags were set appropriately - assert_not_nil @kibbles.eaters[0].id - assert !@kibbles.eaters[1].new_record? - end - - def test_reload - assert @kibbles.reload - assert @kibbles.eaters.reload - end - - def test_add_join_record - assert_equal Kitten, @chloe.class - assert join = EatersFoodstuff.new(:foodstuff_id => @bits.id, :eater_id => @chloe.id, :eater_type => @chloe.class.name ) - assert join.save! - assert join.id - assert_equal @join_count + 1, EatersFoodstuff.count - - #assert_equal @bits_eaters_count, @bits.eaters.size # Doesn't behave this way on latest edge anymore - assert_equal @bits_eaters_count + 1, @bits.eaters.count # SQL - - # reload; is the new association there? - assert @bits.eaters.reload - assert @bits.eaters.include?(@chloe) - end - - def test_build_join_record_on_association - assert_equal Kitten, @chloe.class - assert join = @chloe.eaters_foodstuffs.build(:foodstuff => @bits) - # assert_equal join.eater_type, @chloe.class.name # will be STI parent type - assert join.save! - assert join.id - assert_equal @join_count + 1, EatersFoodstuff.count - - assert @bits.eaters.reload - assert @bits.eaters.include?(@chloe) - end - -# not supporting this, since has_many :through doesn't support it either -# def test_add_unsaved -# # add an unsaved item -# assert @bits.eaters << Kitten.new(:name => "Bridget") -# assert_nil Kitten.find_by_name("Bridget") -# assert_equal @bits_eaters_count + 1, @bits.eaters.count -# -# assert @bits.save -# @bits.reload -# assert_equal @bits_eaters_count + 1, @bits.eaters.count -# -# end - - def test_self_reference - assert @kibbles.eaters << @bits - assert_equal @kibbles_eaters_count += 1, @kibbles.eaters.count - assert @kibbles.eaters.include?(@bits) - @kibbles.reload - assert @kibbles.foodstuffs_of_eaters.blank? - - @bits.reload - assert @bits.foodstuffs_of_eaters.include?(@kibbles) - assert_equal [@kibbles], @bits.foodstuffs_of_eaters - end - - def test_remove - assert @kibbles.eaters << @chloe - @kibbles.reload - assert @kibbles.eaters.delete(@kibbles.eaters[0]) - assert_equal @kibbles_eaters_count, @kibbles.eaters.count - end - - def test_destroy - assert @kibbles.eaters.push(@chloe) - @kibbles.reload - assert @kibbles.eaters.length > 0 - assert @kibbles.eaters[0].destroy - @kibbles.reload - assert_equal @kibbles_eaters_count, @kibbles.eaters.count - end - - def test_clear - @kibbles.eaters << [@chloe, @spot, @rover] - @kibbles.reload - assert @kibbles.eaters.clear.blank? - assert @kibbles.eaters.blank? - @kibbles.reload - assert @kibbles.eaters.blank? - end - - def test_individual_collections - assert @kibbles.eaters.push(@chloe) - # check if individual collections work - assert_equal @kibbles.eater_kittens.length, 1 - assert @kibbles.eater_dogs - assert 1, @rover.eaters_foodstuffs.count - end - - def test_individual_collections_push - assert_equal [@chloe], (@kibbles.eater_kittens << @chloe) - @kibbles.reload - assert @kibbles.eaters.include?(@chloe) - assert @kibbles.eater_kittens.include?(@chloe) - assert !@kibbles.eater_dogs.include?(@chloe) - end - - def test_individual_collections_delete - @kibbles.eaters << [@chloe, @spot, @rover] - @kibbles.reload - assert_equal [@chloe], @kibbles.eater_kittens.delete(@chloe) - assert @kibbles.eater_kittens.empty? - @kibbles.eater_kittens.delete(@chloe) # what should this return? - - @kibbles.reload - assert @kibbles.eater_kittens.empty? - assert @kibbles.eater_dogs.include?(@spot) - end - - def test_individual_collections_clear - @kibbles.eaters << [@chloe, @spot, @rover] - @kibbles.reload - - assert_equal [], @kibbles.eater_kittens.clear - assert @kibbles.eater_kittens.empty? - assert_equal 2, @kibbles.eaters.size - - assert @kibbles.eater_kittens.empty? - assert_equal 2, @kibbles.eaters.size - assert !@kibbles.eater_kittens.include?(@chloe) - assert !@kibbles.eaters.include?(@chloe) - - @kibbles.reload - assert @kibbles.eater_kittens.empty? - assert_equal 2, @kibbles.eaters.size - assert !@kibbles.eater_kittens.include?(@chloe) - assert !@kibbles.eaters.include?(@chloe) - end - - def test_childrens_individual_collections - assert Cat.find_by_name('Chloe').eaters_foodstuffs - assert @kibbles.eaters_foodstuffs - end - - def test_self_referential_join_tables - # check that the self-reference join tables go the right ways - assert_equal @kibbles_eaters_count, @kibbles.eaters_foodstuffs.count - assert_equal @kibbles.eaters_foodstuffs.count, @kibbles.eaters_foodstuffs_as_child.count - end - - def test_dependent - assert @kibbles.eaters << @chloe - @kibbles.reload - - # delete ourself and see if :dependent was obeyed - dependent_rows = @kibbles.eaters_foodstuffs - assert_equal dependent_rows.length, @kibbles.eaters.count - @join_count = EatersFoodstuff.count - - @kibbles.destroy - assert_equal @join_count - dependent_rows.length, EatersFoodstuff.count - assert_equal 0, EatersFoodstuff.find(:all, :conditions => ['foodstuff_id = ?', 1] ).length - end - - def test_normal_callbacks - assert @rover.respond_to?(:after_initialize) - assert @rover.respond_to?(:after_find) - assert @rover.after_initialize_test - assert @rover.after_find_test - end - - def test_model_callbacks_not_overridden_by_plugin_callbacks - assert 0, @bits.eaters.count - assert @bits.eaters.push(@rover) - @bits.save - @bits2 = Petfood.find_by_name("Bits") - @bits.reload - assert rover = @bits2.eaters.select { |x| x.name == "Rover" }[0] - assert rover.after_initialize_test - assert rover.after_find_test - end - - def test_number_of_join_records - assert EatersFoodstuff.create(:foodstuff_id => 1, :eater_id => 1, :eater_type => "Cat") - @join_count = EatersFoodstuff.count - assert @join_count > 0 - end - - def test_number_of_regular_records - dogs = Dog.count - assert Dog.new(:name => "Auggie").save! - assert dogs + 1, Dog.count - end - - def test_attributes_come_through_when_child_has_underscore_in_table_name - join = EatersFoodstuff.new(:foodstuff_id => @bits.id, :eater_id => @puma.id, :eater_type => @puma.class.name) - join.save! - - @bits.eaters.reload - - assert_equal "Puma", @puma.name - assert_equal "Puma", @bits.eaters.first.name - end - - - def test_before_save_on_join_table_is_not_clobbered_by_sti_base_class_fix - assert @kibbles.eaters << @chloe - assert_equal 3, @kibbles.eaters_foodstuffs.first.some_attribute - end - - def test_sti_type_counts_are_correct - @kibbles.eaters << [@chloe, @alice, @toby] - assert_equal 2, @kibbles.eater_kittens.count - assert_equal 1, @kibbles.eater_tabbies.count - assert !@kibbles.respond_to?(:eater_cats) - end - - - def test_creating_namespaced_relationship - assert @shamu.aquatic_pupils.empty? - @shamu.aquatic_pupils << @swimmy - assert_equal 1, @shamu.aquatic_pupils.length - @shamu.reload - assert_equal 1, @shamu.aquatic_pupils.length - end - - def test_namespaced_polymorphic_collection - @shamu.aquatic_pupils << @swimmy - assert @shamu.aquatic_pupils.include?(@swimmy) - @shamu.reload - assert @shamu.aquatic_pupils.include?(@swimmy) - - @shamu.aquatic_pupils << @spot - assert @shamu.dogs.include?(@spot) - assert @shamu.aquatic_pupils.include?(@swimmy) - assert_equal @swimmy, @shamu.aquatic_fish.first - assert_equal 10, @shamu.aquatic_fish.first.speed - end - - def test_deleting_namespaced_relationship - @shamu.aquatic_pupils << @swimmy - @shamu.aquatic_pupils << @spot - - @shamu.reload - @shamu.aquatic_pupils.delete @spot - assert !@shamu.dogs.include?(@spot) - assert !@shamu.aquatic_pupils.include?(@spot) - assert_equal 1, @shamu.aquatic_pupils.length - end - - def test_unrenamed_parent_of_namespaced_child - @shamu.aquatic_pupils << @swimmy - assert_equal [@shamu], @swimmy.whales - end - - def test_empty_double_collections - assert @puma.enemies.empty? - assert @froggy.protectors.empty? - assert @alice.enemies.empty? - assert @spot.protectors.empty? - assert @alice.beautiful_fight_relationships_as_enemy.empty? - assert @alice.beautiful_fight_relationships_as_protector.empty? - assert @alice.beautiful_fight_relationships.empty? - end - - def test_double_collection_assignment - @alice.enemies << @spot - @alice.reload - @spot.reload - assert @spot.protectors.include?(@alice) - assert @alice.enemies.include?(@spot) - assert !@alice.protectors.include?(@alice) - assert_equal 1, @alice.beautiful_fight_relationships_as_protector.size - assert_equal 0, @alice.beautiful_fight_relationships_as_enemy.size - assert_equal 1, @alice.beautiful_fight_relationships.size - - # self reference - assert_equal 1, @alice.enemies.length - @alice.enemies.push @alice - assert @alice.enemies.include?(@alice) - assert_equal 2, @alice.enemies.length - @alice.reload - assert_equal 2, @alice.beautiful_fight_relationships_as_protector.size - assert_equal 1, @alice.beautiful_fight_relationships_as_enemy.size - assert_equal 3, @alice.beautiful_fight_relationships.size - end - - def test_double_collection_build_join_record_on_association - - join = @alice.beautiful_fight_relationships_as_protector.build(:enemy => @spot) - - assert_equal @alice.class.base_class.name, join.protector_type - assert_nothing_raised { join.save! } - - assert join.id - assert_equal @double_join_count + 1, BeautifulFightRelationship.count - - assert @alice.enemies.reload - assert @alice.enemies.include?(@spot) - end - - def test_double_dependency_injection -# breakpoint - end - - def test_double_collection_deletion - @alice.enemies << @spot - @alice.reload - assert @alice.enemies.include?(@spot) - @alice.enemies.delete(@spot) - assert !@alice.enemies.include?(@spot) - assert @alice.enemies.empty? - @alice.reload - assert !@alice.enemies.include?(@spot) - assert @alice.enemies.empty? - assert_equal 0, @alice.beautiful_fight_relationships.size - end - - def test_double_collection_deletion_from_opposite_side - @alice.protectors << @puma - @alice.reload - assert @alice.protectors.include?(@puma) - @alice.protectors.delete(@puma) - assert !@alice.protectors.include?(@puma) - assert @alice.protectors.empty? - @alice.reload - assert !@alice.protectors.include?(@puma) - assert @alice.protectors.empty? - assert_equal 0, @alice.beautiful_fight_relationships.size - end - - def test_individual_collections_created_for_double_relationship - assert @alice.dogs.empty? - @alice.enemies << @spot - - assert @alice.enemies.include?(@spot) - assert !@alice.kittens.include?(@alice) - - assert !@alice.dogs.include?(@spot) - @alice.reload - assert @alice.dogs.include?(@spot) - assert !WildBoar.find(@alice.id).dogs.include?(@spot) # make sure the parent type is checked - end - - def test_individual_collections_created_for_double_relationship_from_opposite_side - assert @alice.wild_boars.empty? - @alice.protectors << @puma - - assert @alice.protectors.include?(@puma) - assert !@alice.wild_boars.include?(@puma) - @alice.reload - assert @alice.wild_boars.include?(@puma) - - assert !Dog.find(@alice.id).wild_boars.include?(@puma) # make sure the parent type is checked - end - - def test_self_referential_individual_collections_created_for_double_relationship - @alice.enemies << @alice - @alice.reload - assert @alice.enemy_kittens.include?(@alice) - assert @alice.protector_kittens.include?(@alice) - assert @alice.kittens.include?(@alice) - assert_equal 2, @alice.kittens.size - - @alice.enemies << (@chloe = Kitten.find_by_name('Chloe')) - @alice.reload - assert @alice.enemy_kittens.include?(@chloe) - assert !@alice.protector_kittens.include?(@chloe) - assert @alice.kittens.include?(@chloe) - assert_equal 3, @alice.kittens.size - end - - def test_child_of_polymorphic_join_can_reach_parent - @alice.enemies << @spot - @alice.reload - assert @spot.protectors.include?(@alice) - end - - def test_double_collection_deletion_from_child_polymorphic_join - @alice.enemies << @spot - @spot.protectors.delete(@alice) - assert !@spot.protectors.include?(@alice) - @alice.reload - assert !@alice.enemies.include?(@spot) - BeautifulFightRelationship.create(:protector_id => 2, :protector_type => "Dog", :enemy_id => @spot.id, :enemy_type => @spot.class.name) - @alice.enemies << @spot - @spot.protectors.delete(@alice) - assert !@spot.protectors.include?(@alice) - end - - def test_collection_query_on_unsaved_record - assert Dog.new.enemies.empty? - assert Dog.new.foodstuffs_of_eaters.empty? - end - - def test_double_individual_collections_push - assert_equal [@chloe], (@spot.protector_kittens << @chloe) - @spot.reload - assert @spot.protectors.include?(@chloe) - assert @spot.protector_kittens.include?(@chloe) - assert !@spot.protector_dogs.include?(@chloe) - - assert_equal [@froggy], (@spot.frogs << @froggy) - @spot.reload - assert @spot.enemies.include?(@froggy) - assert @spot.frogs.include?(@froggy) - assert !@spot.enemy_dogs.include?(@froggy) - end - - def test_double_individual_collections_delete - @spot.protectors << [@chloe, @puma] - @spot.reload - assert_equal [@chloe], @spot.protector_kittens.delete(@chloe) - assert @spot.protector_kittens.empty? - @spot.protector_kittens.delete(@chloe) # again, unclear what .delete should return - - @spot.reload - assert @spot.protector_kittens.empty? - assert @spot.wild_boars.include?(@puma) - end - - def test_double_individual_collections_clear - @spot.protectors << [@chloe, @puma, @alice] - @spot.reload - assert_equal [], @spot.protector_kittens.clear - assert @spot.protector_kittens.empty? - assert_equal 1, @spot.protectors.size - @spot.reload - assert @spot.protector_kittens.empty? - assert_equal 1, @spot.protectors.size - assert !@spot.protector_kittens.include?(@chloe) - assert !@spot.protectors.include?(@chloe) - assert !@spot.protector_kittens.include?(@alice) - assert !@spot.protectors.include?(@alice) - assert @spot.protectors.include?(@puma) - assert @spot.wild_boars.include?(@puma) - end - - def test_single_extensions - assert_equal :correct_block_result, @shamu.aquatic_pupils.a_method - @kibbles.eaters.push(@alice) - @kibbles.eaters.push(@spot) - assert_equal :correct_join_result, @kibbles.eaters_foodstuffs.a_method - assert_equal :correct_module_result, @kibbles.eaters.a_method - assert_equal :correct_other_module_result, @kibbles.eaters.another_method - @kibbles.eaters.each do |eater| - assert_equal :correct_join_result, eater.eaters_foodstuffs.a_method - end - assert_equal :correct_parent_proc_result, @kibbles.foodstuffs_of_eaters.a_method - assert_equal :correct_parent_proc_result, @kibbles.eaters.first.foodstuffs_of_eaters.a_method - end - - def test_double_extensions - assert_equal :correct_proc_result, @spot.protectors.a_method - assert_equal :correct_module_result, @spot.enemies.a_method - assert_equal :correct_join_result, @spot.beautiful_fight_relationships_as_enemy.a_method - assert_equal :correct_join_result, @spot.beautiful_fight_relationships_as_protector.a_method - assert_equal :correct_join_result, @froggy.beautiful_fight_relationships.a_method - assert_equal :correct_join_result, @froggy.beautiful_fight_relationships_as_enemy.a_method - assert_raises(NoMethodError) {@froggy.beautiful_fight_relationships_as_protector.a_method} - end - - def test_pluralization_checks - assert_raises(@association_error) { - eval "class SomeModel < ActiveRecord::Base - has_many_polymorphs :polymorphs, :from => [:dog, :cats] - end" } - assert_raises(@association_error) { - eval "class SomeModel < ActiveRecord::Base - has_many_polymorphs :polymorph, :from => [:dogs, :cats] - end" } - assert_raises(@association_error) { - eval "class SomeModel < ActiveRecord::Base - acts_as_double_polymorphic_join :polymorph => [:dogs, :cats], :unimorphs => [:dogs, :cats] - end" } - end - - def test_error_message_on_namespaced_targets - assert_raises(@association_error) { - eval "class SomeModel < ActiveRecord::Base - has_many_polymorphs :polymorphs, :from => [:fish] - end" } - end - - def test_single_custom_finders - [@kibbles, @alice, @puma, @spot, @bits].each {|record| @kibbles.eaters << record; sleep 1} # XXX yeah i know - assert_equal @kibbles.eaters, @kibbles.eaters.find(:all, :order => "eaters_foodstuffs.created_at ASC") - assert_equal @kibbles.eaters.reverse, @kibbles.eaters.find(:all, :order => "eaters_foodstuffs.created_at DESC") - if (ActiveRecord::Base.connection.is_a? ActiveRecord::ConnectionAdapters::MysqlAdapter rescue false) - assert_equal @kibbles.eaters.sort_by(&:created_at), @kibbles.eaters.find(:all, :order => "IFNULL(bow_wows.created_at,(IFNULL(petfoods.created_at,(IFNULL(wild_boars.created_at,(IFNULL(cats.created_at,fish.created_at))))))) ASC") - end - assert_equal @kibbles.eaters.select{|x| x.is_a? Petfood}, @kibbles.eater_petfoods.find(:all, :order => "eaters_foodstuffs.created_at ASC") - end - - def test_double_custom_finders - @spot.protectors << [@chloe, @puma, @alice] - assert_equal [@chloe], @spot.protectors.find(:all, :conditions => ["cats.name = ?", @chloe.name], :limit => 1) - assert_equal [], @spot.protectors.find(:all, :conditions => ["cats.name = ?", @chloe.name], :limit => 1, :offset => 1) - assert_equal 2, @spot.protectors.find(:all, :limit => 100, :offset => 1).size - end - - def test_single_custom_finder_parameters_carry_to_individual_relationships - # XXX test nullout here - end - - def test_double_custom_finder_parameters_carry_to_individual_relationships - # XXX test nullout here - end - - def test_include_doesnt_fail - assert_nothing_raised do - @spot.protectors.find(:all, :include => :wild_boars) - end - end - - def test_abstract_method - assert_equal :correct_abstract_method_response, @spot.an_abstract_method - end - - def test_missing_target_should_raise - @kibbles.eaters << [@kibbles, @alice, @puma, @spot, @bits] - @spot.destroy_without_callbacks - assert_raises(@association_error) { @kibbles.eaters.reload } -# assert_raises(@association_error) { @kibbles.eater_dogs.reload } # bah AR - end - - def test_lazy_loading_is_lazy - # XXX - end - - def test_push_with_skip_duplicates_false_doesnt_load_target - # Loading kibbles locally again because setup calls .size which loads target - kibbles = Petfood.find(1) - assert !kibbles.eaters.loaded? - assert !(kibbles.eater_dogs << Dog.create!(:name => "Mongy")).loaded? - assert !kibbles.eaters.loaded? - end - - def test_association_foreign_key_is_sane - assert_equal "eater_id", Petfood.reflect_on_association(:eaters).association_foreign_key - end - - def test_reflection_instance_methods_are_sane - assert_equal EatersFoodstuff, Petfood.reflect_on_association(:eaters).klass - assert_equal EatersFoodstuff.name, Petfood.reflect_on_association(:eaters).class_name - end - - def test_parent_order - @alice.foodstuffs_of_eaters << Petfood.find(:all, :order => "the_petfood_primary_key ASC") - @alice.reload #not necessary - assert_equal [2,1], @alice.foodstuffs_of_eaters.map(&:id) - end - - def test_parent_conditions - @kibbles.eaters << @alice - assert_equal [@alice], @kibbles.eaters - - @snausages = Petfood.create(:name => 'Snausages') - @snausages.eaters << @alice - assert_equal [@alice], @snausages.eaters - - assert_equal [@kibbles], @alice.foodstuffs_of_eaters - end - - def test_self_referential_hmp_with_conditions - p = Person.find(:first) - kid = Person.create(:name => "Tim", :age => 3) - p.kids << kid - - kid.reload; p.reload - - # assert_equal [p], kid.parents - # assert Rails.has_one? Bug - # non-standard foreign_type key is not set properly when you are the polymorphic interface of a has_many going to a :through - - assert_equal [kid], p.kids - assert_equal [kid], p.people - end - -# def test_polymorphic_include -# @kibbles.eaters << [@kibbles, @alice, @puma, @spot, @bits] -# assert @kibbles.eaters.include?(@kibbles.eaters_foodstuffs.find(:all, :include => :eater).first.eater) -# end -# -# def test_double_polymorphic_include -# end -# -# def test_single_child_include -# end -# -# def test_double_child_include -# end -# -# def test_single_include_from_parent -# end -# -# def test_double_include_from_parent -# end -# -# def test_meta_referential_single_include -# end -# -# def test_meta_referential_double_include -# end -# -# def test_meta_referential_single_include -# end -# -# def test_meta_referential_single_double_multi_include -# end -# -# def test_dont_ignore_duplicates -# end -# -# def test_ignore_duplicates -# end -# -# def test_tagging_system_generator -# end -# -# def test_tagging_system_library -# end - -end From b2e6253b4c193c1025f8ba85e870be5a429de62b Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Sun, 8 Apr 2012 22:10:43 +0200 Subject: [PATCH 080/134] restore all associations for tags. All tests are passing --- app/helpers/todos_helper.rb | 1 - app/models/recurring_todo.rb | 2 + app/models/tag.rb | 34 ++------- app/models/tagging.rb | 9 +-- app/models/todo.rb | 8 ++- config/environment.rb | 1 - lib/is_taggable.rb | 91 ++++++++++++++++++++++++ test/functional/todos_controller_test.rb | 2 +- 8 files changed, 107 insertions(+), 41 deletions(-) create mode 100644 lib/is_taggable.rb diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index 3f616b86..37c884ee 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -1,5 +1,4 @@ module TodosHelper - def remote_star_icon(todo=@todo) link_to( image_tag_for_star(todo), diff --git a/app/models/recurring_todo.rb b/app/models/recurring_todo.rb index 634b242b..f3ef3363 100644 --- a/app/models/recurring_todo.rb +++ b/app/models/recurring_todo.rb @@ -6,6 +6,8 @@ class RecurringTodo < ActiveRecord::Base has_many :todos + include IsTaggable + named_scope :active, :conditions => { :state => 'active'} named_scope :completed, :conditions => { :state => 'completed'} diff --git a/app/models/tag.rb b/app/models/tag.rb index 0d6d24e5..bb39407a 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -1,9 +1,8 @@ - -# The Tag model. This model is automatically generated and added to your app if -# you run the tagging generator included with has_many_polymorphs. - class Tag < ActiveRecord::Base - + + has_many :taggings + has_many :taggable, :through => :taggings + DELIMITER = "," # Controls how to split and join tagnames from strings. You may need to change the validates_format_of parameters if you change this. JOIN_DELIMITER = ", " @@ -12,26 +11,6 @@ class Tag < ActiveRecord::Base validates_presence_of :name validates_uniqueness_of :name, :case_sensitive => false - # Change this validation if you need more complex tag names. - # validates_format_of :name, :with => /^[a-zA-Z0-9\_\-]+$/, :message => "can not contain special characters" - - # Set up the polymorphic relationship. - has_many_polymorphs :taggables, - :from => [:todos, :recurring_todos], - :through => :taggings, - :dependent => :destroy, - :skip_duplicates => false, - :parent_extend => proc { - # Defined on the taggable models, not on Tag itself. Return the tagnames - # associated with this record as a string. - def to_s - self.map(&:name).sort.join(Tag::JOIN_DELIMITER) - end - def all_except_starred - self.reject{|tag| tag.name == Todo::STARRED_TAG_NAME} - end - } - # Callback to strip extra spaces from the tagname before saving it. If you # allow tags to be renamed later, you might want to use the # before_save callback instead. @@ -43,9 +22,4 @@ class Tag < ActiveRecord::Base taggings.create :taggable => taggable, :user => user end - # Tag::Error class. Raised by ActiveRecord::Base::TaggingExtensions if - # something goes wrong. - class Error < StandardError - end - end diff --git a/app/models/tagging.rb b/app/models/tagging.rb index 4d16acd2..d00b1406 100644 --- a/app/models/tagging.rb +++ b/app/models/tagging.rb @@ -1,16 +1,13 @@ # The Tagging join model. This model is automatically generated and added to your app if you run the tagging generator included with has_many_polymorphs. -class Tagging < ActiveRecord::Base +class Tagging < ActiveRecord::Base belongs_to :tag belongs_to :taggable, :polymorphic => true - - # If you also need to use acts_as_list, you will have to manage the tagging positions manually by creating decorated join records when you associate Tags with taggables. - # acts_as_list :scope => :taggable - + # This callback makes sure that an orphaned Tag is deleted if it no longer tags anything. def after_destroy tag.destroy_without_callbacks if tag and tag.taggings.count == 0 - end + end end diff --git a/app/models/todo.rb b/app/models/todo.rb index c056ff58..201234c2 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -2,12 +2,16 @@ class Todo < ActiveRecord::Base after_save :save_predecessors - # relations + # associations belongs_to :context belongs_to :project belongs_to :user belongs_to :recurring_todo + # Tag association + include IsTaggable + + # Dependencies associations has_many :predecessor_dependencies, :foreign_key => 'predecessor_id', :class_name => 'Dependency', :dependent => :destroy has_many :successor_dependencies, :foreign_key => 'successor_id', :class_name => 'Dependency', :dependent => :destroy has_many :predecessors, :through => :successor_dependencies @@ -16,7 +20,7 @@ class Todo < ActiveRecord::Base :source => :predecessor, :conditions => ['NOT (todos.state = ?)', 'completed'] has_many :pending_successors, :through => :predecessor_dependencies, :source => :successor, :conditions => ['todos.state = ?', 'pending'] - + # scopes for states of this todo named_scope :active, :conditions => { :state => 'active' } named_scope :active_or_hidden, :conditions => ["todos.state = ? OR todos.state = ?", 'active', 'project_hidden'] diff --git a/config/environment.rb b/config/environment.rb index 390f585b..fcb6fed8 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -78,7 +78,6 @@ end require 'name_part_finder' require 'tracks/todo_list' require 'tracks/config' -require 'tagging_extensions' # Needed for tagging-specific extensions require 'digest/sha1' #Needed to support 'rake db:fixtures:load' on some ruby installs: http://dev.rousette.org.uk/ticket/557 if ( SITE_CONFIG['authentication_schemes'].include? 'ldap') diff --git a/lib/is_taggable.rb b/lib/is_taggable.rb new file mode 100644 index 00000000..2308a0b6 --- /dev/null +++ b/lib/is_taggable.rb @@ -0,0 +1,91 @@ +# These methods are adapted from has_many_polymorphs' tagging_extensions + +module IsTaggable + + def self.included(klass) + klass.class_eval do + + # Add tags associations + has_many :taggings, :as => :taggable + has_many :tags, :through => :taggings do + def to_s + self.map(&:name).sort.join(Tag::JOIN_DELIMITER) + end + def all_except_starred + self.reject{|tag| tag.name == Todo::STARRED_TAG_NAME} + end + end + + def tag_list + tags.reload + tags.to_s + end + + def tag_list=(value) + tag_with(value) + end + + # Replace the existing tags on self. Accepts a string of tagnames, an array of tagnames, or an array of Tags. + def tag_with list + list = tag_cast_to_string(list) + + # Transactions may not be ideal for you here; be aware. + Tag.transaction do + current = tags.map(&:name) + _add_tags(list - current) + _remove_tags(current - list) + end + + self + end + + # Add tags to self. Accepts a string of tagnames, an array of tagnames, or an array of Tags. + # + # We need to avoid name conflicts with the built-in ActiveRecord association methods, thus the underscores. + def _add_tags incoming + tag_cast_to_string(incoming).each do |tag_name| + # added following check to prevent empty tags from being saved (which will fail) + unless tag_name.blank? + begin + tag = Tag.find_or_create_by_name(tag_name) + raise Tag::Error, "tag could not be saved: #{tag_name}" if tag.new_record? + tags << tag + rescue ActiveRecord::StatementInvalid => e + raise unless e.to_s =~ /duplicate/i + end + end + end + end + + # Removes tags from self. Accepts a string of tagnames, an array of tagnames, or an array of Tags. + def _remove_tags outgoing + outgoing = tag_cast_to_string(outgoing) + tags.delete(*(tags.select{|tag| outgoing.include? tag.name})) + end + + def tag_cast_to_string obj + case obj + when Array + obj.map! do |item| + case item + # removed next line as it prevents using numbers as tags + # when /^\d+$/, Fixnum then Tag.find(item).name # This will be slow if you use ids a lot. + when Tag then item.name + when String then item + else + raise "Invalid type" + end + end + when String + obj = obj.split(Tag::DELIMITER).map do |tag_name| + tag_name.strip.squeeze(" ") + end + else + raise "Invalid object of class #{obj.class} as tagging method parameter" + end.flatten.compact.map(&:downcase).uniq + end + + end + end + +end diff --git a/test/functional/todos_controller_test.rb b/test/functional/todos_controller_test.rb index fcdc20bc..cfb9cdec 100644 --- a/test/functional/todos_controller_test.rb +++ b/test/functional/todos_controller_test.rb @@ -261,7 +261,7 @@ class TodosControllerTest < ActionController::TestCase def test_find_tagged_with login_as(:admin_user) @user = User.find(@request.session['user_id']) - tag = Tag.find_by_name('foo').todos + tag = Tag.find_by_name('foo').taggings @tagged = tag.count get :tag, :name => 'foo' assert_response :success From 93494631f15cf65ff39d7dbd1228a129001023ff Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Mon, 9 Apr 2012 11:51:36 +0200 Subject: [PATCH 081/134] backup old hmp extensions --- backup_hmp/tagging_extensions.rb | 200 +++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 backup_hmp/tagging_extensions.rb diff --git a/backup_hmp/tagging_extensions.rb b/backup_hmp/tagging_extensions.rb new file mode 100644 index 00000000..2808f42a --- /dev/null +++ b/backup_hmp/tagging_extensions.rb @@ -0,0 +1,200 @@ +class ActiveRecord::Base #:nodoc: + + # These extensions make models taggable. This file is automatically generated and required by your app if you run the tagging generator included with has_many_polymorphs. + module TaggingExtensions + + # Add tags to self. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags. + # + # We need to avoid name conflicts with the built-in ActiveRecord association methods, thus the underscores. + def _add_tags incoming + taggable?(true) + tag_cast_to_string(incoming).each do |tag_name| + # added following check to prevent empty tags from being saved (which will fail) + unless tag_name.blank? + begin + tag = Tag.find_or_create_by_name(tag_name) + raise Tag::Error, "tag could not be saved: #{tag_name}" if tag.new_record? + tags << tag + rescue ActiveRecord::StatementInvalid => e + raise unless e.to_s =~ /duplicate/i + end + end + end + end + + # Removes tags from self. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags. + def _remove_tags outgoing + taggable?(true) + outgoing = tag_cast_to_string(outgoing) + tags.delete(*(tags.select do |tag| + outgoing.include? tag.name + end)) + end + + # Returns the tags on self as a string. + def tag_list + # Redefined later to avoid an RDoc parse error. + end + + # Replace the existing tags on self. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags. + def tag_with list + #:stopdoc: + taggable?(true) + list = tag_cast_to_string(list) + + # Transactions may not be ideal for you here; be aware. + Tag.transaction do + current = tags.map(&:name) + _add_tags(list - current) + _remove_tags(current - list) + end + + self + #:startdoc: + end + + # Returns the tags on self as a string. + def tag_list #:nodoc: + #:stopdoc: + taggable?(true) + tags.reload + tags.to_s + #:startdoc: + end + + def tag_list=(value) + tag_with(value) + end + + private + + def tag_cast_to_string obj #:nodoc: + case obj + when Array + obj.map! do |item| + case item + # removed next line as it prevents using numbers as tags + # when /^\d+$/, Fixnum then Tag.find(item).name # This will be slow if you use ids a lot. + when Tag then item.name + when String then item + else + raise "Invalid type" + end + end + when String + obj = obj.split(Tag::DELIMITER).map do |tag_name| + tag_name.strip.squeeze(" ") + end + else + raise "Invalid object of class #{obj.class} as tagging method parameter" + end.flatten.compact.map(&:downcase).uniq + end + + # Check if a model is in the :taggables target list. The alternative to this check is to explicitly include a TaggingMethods module (which you would create) in each target model. + def taggable?(should_raise = false) #:nodoc: + unless flag = respond_to?(:tags) + raise "#{self.class} is not a taggable model" if should_raise + end + flag + end + + end + + module TaggingFinders + # Find all the objects tagged with the supplied list of tags + # + # Usage : Model.tagged_with("ruby") + # Model.tagged_with("hello", "world") + # Model.tagged_with("hello", "world", :limit => 10) + # + # XXX This query strategy is not performant, and needs to be rewritten as an inverted join or a series of unions + # + def tagged_with(*tag_list) + options = tag_list.last.is_a?(Hash) ? tag_list.pop : {} + tag_list = parse_tags(tag_list) + + scope = scope(:find) + options[:select] ||= "#{table_name}.*" + options[:from] ||= "#{table_name}, tags, taggings" + + sql = "SELECT #{(scope && scope[:select]) || options[:select]} " + sql << "FROM #{(scope && scope[:from]) || options[:from]} " + + add_joins!(sql, options[:joins], scope) + + sql << "WHERE #{table_name}.#{primary_key} = taggings.taggable_id " + sql << "AND taggings.taggable_type = '#{ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s}' " + sql << "AND taggings.tag_id = tags.id " + + tag_list_condition = tag_list.map {|name| "'#{name}'"}.join(", ") + + sql << "AND (tags.name IN (#{sanitize_sql(tag_list_condition)})) " + sql << "AND #{sanitize_sql(options[:conditions])} " if options[:conditions] + + columns = column_names.map do |column| + "#{table_name}.#{column}" + end.join(", ") + + sql << "GROUP BY #{columns} " + sql << "HAVING COUNT(taggings.tag_id) = #{tag_list.size}" + + add_order!(sql, options[:order], scope) + add_limit!(sql, options, scope) + add_lock!(sql, options, scope) + + find_by_sql(sql) + end + + def self.tagged_with_any(*tag_list) + options = tag_list.last.is_a?(Hash) ? tag_list.pop : {} + tag_list = parse_tags(tag_list) + + scope = scope(:find) + options[:select] ||= "#{table_name}.*" + options[:from] ||= "#{table_name}, meta_tags, taggings" + + sql = "SELECT #{(scope && scope[:select]) || options[:select]} " + sql << "FROM #{(scope && scope[:from]) || options[:from]} " + + add_joins!(sql, options, scope) + + sql << "WHERE #{table_name}.#{primary_key} = taggings.taggable_id " + sql << "AND taggings.taggable_type = '#{ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s}' " + sql << "AND taggings.meta_tag_id = meta_tags.id " + + sql << "AND (" + or_options = [] + tag_list.each do |name| + or_options << "meta_tags.name = '#{name}'" + end + or_options_joined = or_options.join(" OR ") + sql << "#{or_options_joined}) " + + + sql << "AND #{sanitize_sql(options[:conditions])} " if options[:conditions] + + columns = column_names.map do |column| + "#{table_name}.#{column}" + end.join(", ") + + sql << "GROUP BY #{columns} " + + add_order!(sql, options[:order], scope) + add_limit!(sql, options, scope) + add_lock!(sql, options, scope) + + find_by_sql(sql) + end + + def parse_tags(tags) + return [] if tags.blank? + tags = Array(tags).first + tags = tags.respond_to?(:flatten) ? tags.flatten : tags.split(Tag::DELIMITER) + tags.map { |tag| tag.strip.squeeze(" ") }.flatten.compact.map(&:downcase).uniq + end + + end + + include TaggingExtensions + extend TaggingFinders +end From 1a6edbe7c2a22e362e70d0656a252c0060c692b3 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Wed, 11 Apr 2012 13:39:12 +0200 Subject: [PATCH 082/134] add some basic tests for tags noew we cannot rely on a tested gem --- app/models/tagging.rb | 2 +- test/unit/is_taggable_test.rb | 46 +++++++++++++++++++++++++++++++++++ test/unit/tag_test.rb | 19 +++++++++++++-- test/unit/tagging_test.rb | 14 ++++++++--- test/unit/todo_test.rb | 23 +++++++++--------- 5 files changed, 85 insertions(+), 19 deletions(-) create mode 100644 test/unit/is_taggable_test.rb diff --git a/app/models/tagging.rb b/app/models/tagging.rb index d00b1406..46291f6a 100644 --- a/app/models/tagging.rb +++ b/app/models/tagging.rb @@ -1,5 +1,5 @@ -# The Tagging join model. This model is automatically generated and added to your app if you run the tagging generator included with has_many_polymorphs. +# The Tagging join model. class Tagging < ActiveRecord::Base diff --git a/test/unit/is_taggable_test.rb b/test/unit/is_taggable_test.rb new file mode 100644 index 00000000..c9d67b43 --- /dev/null +++ b/test/unit/is_taggable_test.rb @@ -0,0 +1,46 @@ +require File.expand_path(File.dirname(__FILE__) + '/../test_helper') + +class IsTaggableTest < ActiveSupport::TestCase + fixtures :todos, :recurring_todos + + def test_models_are_taggable + assert Todo.find(:first).respond_to?(:tag_list) + assert RecurringTodo.find(:first).respond_to?(:tag_list) + end + + def test_test_to_s + t = Todo.create(:description => "test", :context => Context.first) + t.tag_list = "one, two, three" + + # tags will be sorted alphabetical + assert_equal "one, three, two", t.tag_list + assert_equal "one, three, two", t.tags.to_s + end + + def test_getting_all_tags_except_starred + t = Todo.create(:description => "test", :context => Context.first) + t.tag_list = "one, two, three" + t.toggle_star! + + assert_equal "one, starred, three, two", t.tag_list + assert_equal "one, three, two", t.tags.all_except_starred.map(&:name).sort.join(", ") + end + + def test_editing_tags + t = Todo.create(:description => "test", :context => Context.first) + t.tag_list = "a, b, c" + + assert_equal 3, t.tags.count + + t.tag_with "a, b" + + assert_equal "a, b", t.tag_list, "should remove tag c" + + t.tag_with "a, b, c, d" + assert_equal "a, b, c, d", t.tag_list, "should add c and d" + + t.tag_with "a, b, e, f" + assert_equal "a, b, e, f", t.tag_list, "should add e and f and remove c and d" + end + +end \ No newline at end of file diff --git a/test/unit/tag_test.rb b/test/unit/tag_test.rb index fff511b9..e2f5d54a 100644 --- a/test/unit/tag_test.rb +++ b/test/unit/tag_test.rb @@ -3,7 +3,6 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') class TagTest < ActiveSupport::TestCase fixtures :tags - # Replace this with your real tests. def test_find_or_create_with_single_word tag = Tag.find_or_create_by_name("test") assert !tag.new_record? @@ -26,5 +25,21 @@ class TagTest < ActiveSupport::TestCase tag = Tag.find_or_create_by_name("8.1.2") assert !tag.new_record? end - + + def test_tag_name_always_lowercase + tag = Tag.find_or_create_by_name("UPPER") + assert !tag.new_record? + + upper = Tag.find_by_name("UPPER") + assert_not_nil upper + assert upper.name == "upper" + end + + def test_tag_name_stripped_of_spaces + tag = Tag.find_or_create_by_name(" strip spaces ") + assert !tag.new_record? + + assert tag.name == "strip spaces" + end + end diff --git a/test/unit/tagging_test.rb b/test/unit/tagging_test.rb index b660ea2e..7335450e 100644 --- a/test/unit/tagging_test.rb +++ b/test/unit/tagging_test.rb @@ -1,10 +1,16 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') class TaggingTest < ActiveSupport::TestCase - fixtures :taggings + fixtures :taggings, :tags - # Replace this with your real tests. - def test_truth - assert true + def test_removes_unused_tags + tag = Tag.create!(:name => "hello") + tagging = Tagging.create!(:tag => tag, :taggable_id => 1) + + assert_equal 1, Tagging.find(:all, :conditions => ["tag_id = ?", tag.id]).count + + tagging.destroy + + assert_nil Tag.find_by_name("hello") end end diff --git a/test/unit/todo_test.rb b/test/unit/todo_test.rb index 481c4894..48ee7c07 100644 --- a/test/unit/todo_test.rb +++ b/test/unit/todo_test.rb @@ -256,11 +256,11 @@ class TodoTest < ActiveSupport::TestCase tag_c = Tag.find_by_name("c") todos_with_a = Todo.with_tag(tag_a) - assert 1, todos_with_a.count + assert_equal 1, todos_with_a.count assert_equal todo.description, todos_with_a.first.description todos_with_b = Todo.with_tag(tag_b) - assert 1, todos_with_b.count + assert_equal 1, todos_with_b.count assert_equal todo.id, todos_with_b.first.id todo2 = @not_completed2 @@ -270,10 +270,10 @@ class TodoTest < ActiveSupport::TestCase tag_d = Tag.find_by_name("d") todos_with_a = Todo.with_tag(tag_a) - assert 2, todos_with_a.count + assert_equal 2, todos_with_a.count todos_with_d = Todo.with_tag(tag_d) - assert 1, todos_with_a.count + assert_equal 1, todos_with_d.count end def test_finding_todos_with_more_tags_using_OR @@ -293,12 +293,12 @@ class TodoTest < ActiveSupport::TestCase # overlapping tags tag_ids = [tag_a.id, tag_c.id] todos_with_a_or_c = Todo.with_tags(tag_ids) - assert 2, todos_with_a_or_c.count + assert_equal 2, todos_with_a_or_c.count # non-overlapping tags tag_ids = [tag_b.id, tag_d.id] todos_with_b_or_d = Todo.with_tags(tag_ids) - assert 2, todos_with_b_or_d.count + assert_equal 2, todos_with_b_or_d.count end def test_finding_todos_with_more_tags_using_AND @@ -314,8 +314,8 @@ class TodoTest < ActiveSupport::TestCase tag_b_id = Tag.find_by_name("b").id todos_with_a_and_b = Todo.with_tags([tag_a_id]).with_tags([tag_b_id]) - assert 1, todos_with_a_and_b.count - assert todo1.id, todos_with_a_and_b.first.id + assert_equal 1, todos_with_a_and_b.count + assert_equal todo1.id, todos_with_a_and_b.first.id end def test_finding_todos_with_more_tags_using_AND_and_OR @@ -332,14 +332,14 @@ class TodoTest < ActiveSupport::TestCase tag_c_id = Tag.find_by_name("c").id todos_with_aORc_and_b = Todo.with_tags([tag_a_id, tag_c_id]).with_tags([tag_b_id]) - assert 1, todos_with_aORc_and_b.count - assert todo1.id, todos_with_aORc_and_b.first.id + assert_equal 1, todos_with_aORc_and_b.count + assert_equal todo1.id, todos_with_aORc_and_b.first.id # let todo2 fit the expression todo2.tag_list = "a, b, r" todo2.save! todos_with_aORc_and_b = Todo.with_tags([tag_a_id, tag_c_id]).with_tags([tag_b_id]) - assert 2, todos_with_aORc_and_b.count + assert_equal 2, todos_with_aORc_and_b.count end # test named_scopes @@ -385,6 +385,5 @@ class TodoTest < ActiveSupport::TestCase assert !older_created_todos.include?(todo_now) assert !recent_created_todos.include?(todo_old) end - end From b18d846d92b7ee4d5909be854d673c770777c58f Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Wed, 11 Apr 2012 13:42:47 +0200 Subject: [PATCH 083/134] remove backup of hmp's tagging_extensions --- backup_hmp/tagging_extensions.rb | 200 ------------------------------- 1 file changed, 200 deletions(-) delete mode 100644 backup_hmp/tagging_extensions.rb diff --git a/backup_hmp/tagging_extensions.rb b/backup_hmp/tagging_extensions.rb deleted file mode 100644 index 2808f42a..00000000 --- a/backup_hmp/tagging_extensions.rb +++ /dev/null @@ -1,200 +0,0 @@ -class ActiveRecord::Base #:nodoc: - - # These extensions make models taggable. This file is automatically generated and required by your app if you run the tagging generator included with has_many_polymorphs. - module TaggingExtensions - - # Add tags to self. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags. - # - # We need to avoid name conflicts with the built-in ActiveRecord association methods, thus the underscores. - def _add_tags incoming - taggable?(true) - tag_cast_to_string(incoming).each do |tag_name| - # added following check to prevent empty tags from being saved (which will fail) - unless tag_name.blank? - begin - tag = Tag.find_or_create_by_name(tag_name) - raise Tag::Error, "tag could not be saved: #{tag_name}" if tag.new_record? - tags << tag - rescue ActiveRecord::StatementInvalid => e - raise unless e.to_s =~ /duplicate/i - end - end - end - end - - # Removes tags from self. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags. - def _remove_tags outgoing - taggable?(true) - outgoing = tag_cast_to_string(outgoing) - tags.delete(*(tags.select do |tag| - outgoing.include? tag.name - end)) - end - - # Returns the tags on self as a string. - def tag_list - # Redefined later to avoid an RDoc parse error. - end - - # Replace the existing tags on self. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags. - def tag_with list - #:stopdoc: - taggable?(true) - list = tag_cast_to_string(list) - - # Transactions may not be ideal for you here; be aware. - Tag.transaction do - current = tags.map(&:name) - _add_tags(list - current) - _remove_tags(current - list) - end - - self - #:startdoc: - end - - # Returns the tags on self as a string. - def tag_list #:nodoc: - #:stopdoc: - taggable?(true) - tags.reload - tags.to_s - #:startdoc: - end - - def tag_list=(value) - tag_with(value) - end - - private - - def tag_cast_to_string obj #:nodoc: - case obj - when Array - obj.map! do |item| - case item - # removed next line as it prevents using numbers as tags - # when /^\d+$/, Fixnum then Tag.find(item).name # This will be slow if you use ids a lot. - when Tag then item.name - when String then item - else - raise "Invalid type" - end - end - when String - obj = obj.split(Tag::DELIMITER).map do |tag_name| - tag_name.strip.squeeze(" ") - end - else - raise "Invalid object of class #{obj.class} as tagging method parameter" - end.flatten.compact.map(&:downcase).uniq - end - - # Check if a model is in the :taggables target list. The alternative to this check is to explicitly include a TaggingMethods module (which you would create) in each target model. - def taggable?(should_raise = false) #:nodoc: - unless flag = respond_to?(:tags) - raise "#{self.class} is not a taggable model" if should_raise - end - flag - end - - end - - module TaggingFinders - # Find all the objects tagged with the supplied list of tags - # - # Usage : Model.tagged_with("ruby") - # Model.tagged_with("hello", "world") - # Model.tagged_with("hello", "world", :limit => 10) - # - # XXX This query strategy is not performant, and needs to be rewritten as an inverted join or a series of unions - # - def tagged_with(*tag_list) - options = tag_list.last.is_a?(Hash) ? tag_list.pop : {} - tag_list = parse_tags(tag_list) - - scope = scope(:find) - options[:select] ||= "#{table_name}.*" - options[:from] ||= "#{table_name}, tags, taggings" - - sql = "SELECT #{(scope && scope[:select]) || options[:select]} " - sql << "FROM #{(scope && scope[:from]) || options[:from]} " - - add_joins!(sql, options[:joins], scope) - - sql << "WHERE #{table_name}.#{primary_key} = taggings.taggable_id " - sql << "AND taggings.taggable_type = '#{ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s}' " - sql << "AND taggings.tag_id = tags.id " - - tag_list_condition = tag_list.map {|name| "'#{name}'"}.join(", ") - - sql << "AND (tags.name IN (#{sanitize_sql(tag_list_condition)})) " - sql << "AND #{sanitize_sql(options[:conditions])} " if options[:conditions] - - columns = column_names.map do |column| - "#{table_name}.#{column}" - end.join(", ") - - sql << "GROUP BY #{columns} " - sql << "HAVING COUNT(taggings.tag_id) = #{tag_list.size}" - - add_order!(sql, options[:order], scope) - add_limit!(sql, options, scope) - add_lock!(sql, options, scope) - - find_by_sql(sql) - end - - def self.tagged_with_any(*tag_list) - options = tag_list.last.is_a?(Hash) ? tag_list.pop : {} - tag_list = parse_tags(tag_list) - - scope = scope(:find) - options[:select] ||= "#{table_name}.*" - options[:from] ||= "#{table_name}, meta_tags, taggings" - - sql = "SELECT #{(scope && scope[:select]) || options[:select]} " - sql << "FROM #{(scope && scope[:from]) || options[:from]} " - - add_joins!(sql, options, scope) - - sql << "WHERE #{table_name}.#{primary_key} = taggings.taggable_id " - sql << "AND taggings.taggable_type = '#{ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s}' " - sql << "AND taggings.meta_tag_id = meta_tags.id " - - sql << "AND (" - or_options = [] - tag_list.each do |name| - or_options << "meta_tags.name = '#{name}'" - end - or_options_joined = or_options.join(" OR ") - sql << "#{or_options_joined}) " - - - sql << "AND #{sanitize_sql(options[:conditions])} " if options[:conditions] - - columns = column_names.map do |column| - "#{table_name}.#{column}" - end.join(", ") - - sql << "GROUP BY #{columns} " - - add_order!(sql, options[:order], scope) - add_limit!(sql, options, scope) - add_lock!(sql, options, scope) - - find_by_sql(sql) - end - - def parse_tags(tags) - return [] if tags.blank? - tags = Array(tags).first - tags = tags.respond_to?(:flatten) ? tags.flatten : tags.split(Tag::DELIMITER) - tags.map { |tag| tag.strip.squeeze(" ") }.flatten.compact.map(&:downcase).uniq - end - - end - - include TaggingExtensions - extend TaggingFinders -end From ac270884ed480f808e1785a42f0a9ec80da9fce3 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Wed, 11 Apr 2012 20:21:28 +0200 Subject: [PATCH 084/134] add more translations for he locale. Contributed by Darian Shalev --- app/helpers/application_helper.rb | 1 + app/views/contexts/_context_listing.rhtml | 2 +- app/views/contexts/_new_context_form.rhtml | 2 +- app/views/layouts/standard.html.erb | 4 +- app/views/notes/_note_details.rhtml | 2 +- app/views/projects/_project_listing.rhtml | 2 +- app/views/recurring_todos/_edit_form.html.erb | 8 +- .../recurring_todos/_recurring_todo_form.erb | 4 +- app/views/stats/_projects.rhtml | 16 +- config/locales/en.yml | 11 +- config/locales/he.yml | 2626 +++++++++++++++++ config/locales/nl.yml | 663 +++-- public/javascripts/application.js | 17 +- .../i18n/jquery.ui.datepicker-he.js | 23 + 14 files changed, 3025 insertions(+), 356 deletions(-) create mode 100644 config/locales/he.yml create mode 100644 public/javascripts/i18n/jquery.ui.datepicker-he.js diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 6a5776e3..3744e1f2 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -249,6 +249,7 @@ module ApplicationHelper contexts.show_form contexts.show_form_title contexts.new_context_pre contexts.new_context_post common.cancel common.ok + common.update common.create common.ajaxError todos.unresolved_dependency }.each do |s| js << "i18n['#{s}'] = '#{ t(s).gsub(/'/, "\\\\'") }';\n" diff --git a/app/views/contexts/_context_listing.rhtml b/app/views/contexts/_context_listing.rhtml index b865bcca..256b3b07 100644 --- a/app/views/contexts/_context_listing.rhtml +++ b/app/views/contexts/_context_listing.rhtml @@ -10,7 +10,7 @@ suppress_delete_button ||= false <%= suppress_edit_button ? "" : link_to_edit_context(context, image_tag( "blank.png", :title => t('contexts.edit_context'), :class=>"edit_item")) -%> <%= suppress_drag_handle ? "" : image_tag('grip.png', :width => '7', :height => '16', :border => '0', :title => t('common.drag_handle'), :class => 'grip')-%>
        - <%= link_to_context( context ) %> <%= " (" + count_undone_todos_phrase(context,"actions") + ")" %> + <%= link_to_context( context ) %> <%= " (" + count_undone_todos_phrase(context,t('common.actions_midsentence')) + ")" %>
        diff --git a/app/views/recurring_todos/_edit_form.html.erb b/app/views/recurring_todos/_edit_form.html.erb index 798752d6..2f9f6de8 100644 --- a/app/views/recurring_todos/_edit_form.html.erb +++ b/app/views/recurring_todos/_edit_form.html.erb @@ -1,11 +1,5 @@
        - <% #form_remote_tag( - #url => recurring_todo_path(@recurring_todo), :method => :put, - #:html=> { :id=>'recurring-todo-form-edit-action', :name=>'recurring_todo', :class => 'inline-form' }, - #:before => "$('#recurring_todo_edit_action_submit').block({message: null})", - #:complete => "$('#recurring_todo_edit_action_submit').unblock();$('#recurring-todo-form-edit-action').clearForm();") do - form_for(@recurring_todo, :html=> { :id=>'recurring-todo-form-edit-action', :name=>'recurring_todo', :class => 'inline-form' }) do |f| - -%> +<% form_for(@recurring_todo, :html=> { :id=>'recurring-todo-form-edit-action', :name=>'recurring_todo', :class => 'inline-form' }) do |f| -%>
        <%= error_messages_for("item", :object_name => 'action') %>
        diff --git a/app/views/recurring_todos/_recurring_todo_form.erb b/app/views/recurring_todos/_recurring_todo_form.erb index a2f60355..668579a3 100644 --- a/app/views/recurring_todos/_recurring_todo_form.erb +++ b/app/views/recurring_todos/_recurring_todo_form.erb @@ -1,8 +1,6 @@ <%- reset_tab_index %>
        - <% - form_for(@new_recurring_todo, :html=> { :id=>'recurring-todo-form-new-action', :name=>'recurring_todo', :class => 'inline-form' }) do - -%> +<% form_for(@new_recurring_todo, :html=> { :id=>'recurring-todo-form-new-action', :name=>'recurring_todo', :class => 'inline-form' }) do -%>
        <%= error_messages_for("item", :object_name => 'action') %>
        diff --git a/app/views/stats/_projects.rhtml b/app/views/stats/_projects.rhtml index 230a7ffb..42d47a6c 100755 --- a/app/views/stats/_projects.rhtml +++ b/app/views/stats/_projects.rhtml @@ -1,10 +1,10 @@

        <%= t('stats.top10_projects') %>

        <% i=0 - @projects_and_actions.each do |p| + @projects_and_actions.each do |p| i+=1 -%> - <%= i -%> - <%= link_to p.name, {:controller => "projects", :action => "show", :id => p.id}%> (<%=p.count %> actions)
        - <% end + <%= i -%> - <%= link_to p.name, {:controller => "projects", :action => "show", :id => p.id}%> (<%=p.count %> <%= t('common.actions_midsentence') %>)
        + <% end if i < 10 i.upto 10 do |j| -%> <%= i -%> - n/a (n/a)
        @@ -16,10 +16,10 @@

        <%= t('stats.top10_projects_30days') %>

        <% i=0 - @projects_and_actions_last30days.each do |p| + @projects_and_actions_last30days.each do |p| i+=1 -%> - <%= i -%> - <%= link_to p.name, {:controller => "projects", :action => "show", :id => p.id} %> (<%=p.count %> actions)
        - <% end + <%= i -%> - <%= link_to p.name, {:controller => "projects", :action => "show", :id => p.id} %> (<%=p.count %> <%= t('common.actions_midsentence') %>)
        + <% end if i < 10 i.upto 10 do |j| -%> <%= i -%> - n/a (n/a)
        @@ -31,8 +31,8 @@

        <%= t('stats.top10_longrunning') %>

        <% i=0 - @projects_and_runtime.each do |id, name, days| + @projects_and_runtime.each do |id, name, days| i+=1 -%> - <%= i -%> - <%= link_to name, {:controller => "projects", :action => "show", :id => id} %> (<%=days %> days)
        + <%= i -%> - <%= link_to name, {:controller => "projects", :action => "show", :id => id} %> (<%=days %> <%= t('common.days_midsentence') %>)
        <% end -%>
        \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index 56590447..de87c596 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -47,6 +47,8 @@ en: projects_title: Projects search: Search All Items preferences_title: Show my preferences + admin: Admin + help: "?" integrations: opensearch_description: Search in Tracks applescript_next_action_prompt: "Description of next action:" @@ -141,6 +143,7 @@ en: email: Email search: Search ajaxError: There was an error retrieving from server + days_midsentence: days data: import_successful: Import was successful. import_errors: Some errors occurred during import @@ -174,6 +177,7 @@ en: context: Context description: Description due: Due + tags: Tags user: last_name: Last name first_name: First name @@ -198,6 +202,9 @@ en: sms_email: From email first_name: First name show_completed_projects_in_sidebar: Show completed projects in sidebar + note: + created_at: Created at + updated_at: Updated at errors: messages: greater_than_or_equal_to: must be greater than or equal to %{count} @@ -205,7 +212,7 @@ en: confirmation: doesn't match confirmation less_than_or_equal_to: must be less than or equal to %{count} blank: can't be blank - invalid: cannot contain the comma (',') character + invalid: "cannot contain the comma (',') character" exclusion: is reserved odd: must be odd even: must be even @@ -587,6 +594,7 @@ en: no_notes_available: "Currently there are no notes: add notes to projects from individual project pages." note_header: Note %{id} delete_note_confirm: Are you sure that you want to delete the note '%{id}'? + in_project: "In: " states: hidden_plural: Hidden completed: Completed @@ -768,6 +776,7 @@ en: toggle_single: Add a next action add_action: Add action add_actions: Add actions + add_context: Add Context tags_for_all_actions: Tags for all actions (sep. with commas) toggle_single_title: Add a new next action project_for_all_actions: Project for all actions diff --git a/config/locales/he.yml b/config/locales/he.yml new file mode 100644 index 00000000..03098728 --- /dev/null +++ b/config/locales/he.yml @@ -0,0 +1,2626 @@ +--- +he: + search: + contexts_matching_query: !binary | + 15TXp9ep16jXmdedINeq15XXkNee15nXnSDXnNep15DXmdec16rXkA== + + projects_matching_query: !binary | + 16TXqNeV15nXmden15jXmdedINeq15XXkNee15nXnSDXqdeQ15nXnNeq15A= + + todos_matching_query: !binary | + 157XqdeZ157XldeqINeq15XXkNee15XXqiDXqdeQ15nXnNeq15A= + + no_results: !binary | + 15TXl9eZ16TXldepINec15Ag15TXoNeZ15Eg16rXldem15DXldeq + + notes_matching_query: !binary | + 16TXqten15nXnSDXqteV15DXnteZ150g16nXkNeZ15zXqteQ + + tags_matching_query: !binary | + 16rXkteZ15XXqiDXqteV15DXnteV16og15zXqdeQ15nXnNeq15A= + + models: + project: + feed_title: !binary | + 16TXqNeV15nXmden15jXmdedINeR157Xodec15XXnNeZ150= + + feed_description: !binary | + 16jXqdeZ157XqiDXm9ecINeU16TXqNeV15nXmden15jXmdedINei15HXldeo + ICV7dXNlcm5hbWV9 + + todo: + error_date_must_be_future: !binary | + 15fXmdeZ15Eg15zXlNeZ15XXqiDXqteQ16jXmdeaINei16rXmdeT15k= + + user: + error_context_not_associated: !binary | + 157XlteU15Qg15TXp9ep16ggJXtjb250ZXh0fSDXkNeZ16DXlSDXntep15XX + mdeZ15og16LXnSDXnteW15Qg157Xqdeq157XqSAle3VzZXJ9Lg== + + error_project_not_associated: !binary | + 157XlteU15Qg16TXqNeV15nXmden15ggJXtwcm9qZWN0fSDXkNeZ16DXlSDX + ntep15XXmdeZ15og16LXnSDXnteW15Qg157Xqdeq157XqSAle3VzZXJ9Lg== + + preference: + due_on: !binary | + LSDXmdei15Mg15Ele2RhdGV9 + + due_in: !binary | + 16rXkNeo15nXmiDXmdei15Mg15HXoteV15MgJXtkYXlzfSDXmdee15nXnQ== + + layouts: + toggle_contexts_title: !binary | + 15TXodeq16jXqi/XlNem15LXqiDXqdeT15XXqiDXnteV16HXqteo15nXnQ== + + navigation: + search: !binary | + 15fXmdek15XXqSDXm9ecINeU16TXqNeZ15jXmded + + home: !binary | + 15HXmdeq + + home_title: !binary | + 15HXmdeq + + organize: !binary | + 15DXqNeS15XXnw== + + projects_title: !binary | + 16TXqNeV15nXmden15jXmded + + view: !binary | + 16rXpteV15LXlA== + + manage_users: !binary | + 16DXmdeU15XXnCDXntep16rXntep15nXnQ== + + feeds_title: !binary | + 16bXpNeZ15Qg15HXqNep15nXnteqINeU15TXlteg15XXqiDXlNeW157Xmdeg + 15Q= + + manage_users_title: !binary | + 15TXldeh16TXlCDXkNeVINeU16HXqNeUINep15wg157Xqdeq157XqdeZ150= + + feeds: !binary | + 15TXlteg15XXqg== + + api_docs: !binary | + 16rXmdei15XXkyDXntee16nXpyDXqteb16DXldeq + + completed_tasks: !binary | + 15HXldem16I= + + stats_title: !binary | + 15TXpteS16og15TXodeY15jXmdeh15jXmden15Qg16nXnNeZ + + export: !binary | + 15nXpteV15A= + + notes_title: !binary | + 15TXpteS16og15DXqiDXm9ecINeU16TXqten15nXnQ== + + completed_tasks_title: !binary | + 15TXodeq15nXmded + + integrations_: !binary | + 16nXmdec15XXkSDXnteh15zXldec15nXnQ== + + tickler: !binary | + 157WtNeW1rDXm9a41rzXqA== + + tickler_title: !binary | + 157WtNeW1rDXm9a41rzXqA== + + preferences_title: !binary | + 15TXpteS16og15TXoteT16TXldeq15k= + + contexts_title: !binary | + 15TXp9ep16jXmded + + review_title: !binary | + 16LXqNeZ15vXpiDXkdeZ16fXldeo16o= + + export_title: !binary | + 15nXkdeV15Ag15XXmdem15XXkCDXoNeq15XXoNeZ150= + + calendar: !binary | + 15zXldeXINep16DXlA== + + stats: !binary | + 16HXmNeY15nXodeY15nXp9eU + + recurring_todos_title: !binary | + 16DXmdeU15XXnCDXpNei15XXnNeV16og157Xl9eW15XXqNeZ15XXqg== + + recurring_todos: !binary | + 157XqdeZ157XldeqINee15fXlteV16jXmdeV16o= + + starred: !binary | + 157XldeT15LXqdeZ150= + + calendar_title: !binary | + 15zXldeXINep16DXlCDXqdecINee16nXmdee15XXqiDXnNeR15nXpteV16I= + + starred_title: !binary | + 15TXpteS16og16TXoteV15zXldeqINee15XXk9eS16nXldeq + + preferences: !binary | + 15TXoteT16TXldeq + + toggle_notes_title: !binary | + 15HXl9eZ16jXqiDXm9ecINeU16TXqten15nXnQ== + + mobile_navigation: + home: !binary | + MS3XkdeZ16o= + + new_action: !binary | + MC3XpNei15XXnNeUINeX15PXqdeU + + feeds: !binary | + 15TXlteg15XXqg== + + logout: !binary | + 16bXkA== + + projects: !binary | + My3XpNeo15XXmdeZ16fXmNeZ150= + + tickler: !binary | + 157WtNeW1rDXm9a41rzXqA== + + starred: !binary | + NC3XnteV15PXktep15nXnQ== + + contexts: !binary | + Mi3XlNen16nXqNeZ150= + + toggle_contexts: !binary | + 15TXpteS16og16nXk9eV16og157Xldeh16rXqNeZ150= + + toggle_notes: !binary | + 15HXl9eZ16jXqiDXpNeq16fXmded + + next_actions_rss_feed: !binary | + 15TXlteg16og16jXodehINec16TXoteV15zXldeqINeU157Xqdea + + todos: + delete_recurring_action_confirm: !binary | + 15TXkNedINec157Xl9eV16cg15DXqiDXlNek16LXmdec15XXqiDXlNee15fX + lteV16jXmdeqICcle2Rlc2NyaXB0aW9ufSc/ + + completed_rest_of_previous_month: !binary | + 15TXodeq15nXmdee15Ug15HXmdeq16jXqiDXlNeX15XXk9epINeU16fXldeT + 150= + + recurrence_completed: !binary | + 15DXmdefINek16LXldec16og15TXntep15og15zXpNei15XXnNeUINeU157X + l9eW15XXqNeZ16og16nXodeV15nXnteULiDXlNee15fXlteV16jXmdeV16og + 15TXodeq15nXmdee15Qu + + all_completed_tagged_page_title: !binary | + 157Xodec15XXnNeZ1506Oteb15wg15TXpNei15XXnNeV16og16nXlNeh16rX + mdeZ157XlSDXotedINeU16rXkteZ16ogJXt0YWdfbmFtZX0= + + next_actions_title_additions: + due_within_a_week: !binary | + 16rXldeaINep15HXldei + + completed: !binary | + 16TXoteV15zXldeqINep15TXodeq15nXnteV + + due_today: !binary | + 15zXlNeZ15XXnQ== + + recurring_deleted_success: !binary | + 15TXpNei15XXnNeUINeU157Xl9eW15XXqNeZ16og16DXnteX16fXlCDXkdeU + 16bXnNeX15Q= + + add_new_recurring: !binary | + 15TXldeh16TXqiDXpNei15XXnNeUINee15fXlteV16jXmdeqINeX15PXqdeU + + delete: !binary | + 157Xl9eZ16fXlA== + + action_marked_complete: "\xD7\x94\xD7\xA4\xD7\xA2\xD7\x95\xD7\x9C\xD7\x94 '%{description}' \xD7\xA1\xD7\x95\xD7\x9E\xD7\xA0\xD7\x94 \xD7\x9B- %{completed}" + add_another_dependency: !binary | + 15TXldeh16TXqiDXqtec15XXqiDXoNeV16HXpNeq + + completed_tasks_title: !binary | + 157Xodec15XXnNeZ1506Otee16nXmdee15XXqiDXqdeU15XXqdec157XlQ== + + no_deferred_actions: !binary | + 15DXmdefINeb16jXkteiINek16LXldec15XXqiDXqdeg15PXl9eVLg== + + clear_due_date: !binary | + 157Xl9eZ16fXqiDXqteQ16jXmdeaINeZ16LXkw== + + show_on_date: !binary | + 15TXpteSINeR16rXkNeo15nXmiAle2RhdGV9 + + action_deferred: !binary | + 15TXpNei15XXnNeUICcle2Rlc2NyaXB0aW9ufScg16DXk9eX16rXlA== + + new_related_todo_created_short: !binary | + 15nXpteZ16jXqiDXntep15nXnteUINeX15PXqdeU + + deferred_tasks_title: !binary | + 157Xodec15XXnNeZ1506Otee1rTXltaw15vWuNa816g= + + no_deferred_actions_with: !binary | + 15DXmdefINek16LXldec15XXqiDXk9eX15XXmdeV16og16LXnSDXlNeq15LX + mdeqICcle3RhZ19uYW1lfSc= + + blocked_by: !binary | + 16DXl9eh150g16LXnCDXmdeT15kgJXtwcmVkZWNlc3NvcnN9 + + action_saved: !binary | + 16TXoteV15zXlCDXoNep157XqNeU + + completed_rest_of_month: !binary | + 15TXodeq15nXmdee15Ug15HXmdeq16jXqiDXlNeX15XXk9epINeU16DXldeb + 15fXmQ== + + clear_show_from_date: !binary | + 16DXp9eUINeU16bXkteUINee16rXkNeo15nXmg== + + recurrence_period: !binary | + 16rXp9eV16TXqiDXnteX15bXldeo15nXldeq + + next_action_description: !binary | + 16rXmdeQ15XXqCDXpNei15XXnNeqINeU157Xqdea + + show_from: !binary | + 15TXpteS15Qg154t + + calendar_page_title: !binary | + 157Xodec15XXnNeZ1506Otec15XXlyDXqdeg15Q= + + error_starring_recurring: !binary | + INeU15PXktep16og15TXntep15nXnteUINeU157Xl9eW15XXqNeZ16ogIFwn + JXtkZXNjcmlwdGlvbn1cJyDXnNeQINem15zXl9eU + + completed_tagged_page_title: !binary | + 157Xodec15XXnNeZ1506Otee16nXmdee15XXqiDXqdeU16HXqteZ15nXnteV + INei150g16rXkteZ16ogJyV7dGFnX25hbWV9Jw== + + tickler_items_due: + other: !binary | + JXtjb3VudH0g157XlNee1rTXltaw15vWuNa816jXmdedINeU15LXmdei15Ug + 15zXqteQ16jXmdeaINeU15nXoteTIC0g15nXqSDXnNeo16LXoNefINeU16LX + nteV15Mg15zXlNem15LXlC4= + + one: !binary | + 15DXl9eTINee15TXnta015bWsNeb1rjWvNeo15nXnSDXlNeS15nXoiDXnNeq + 15DXqNeZ15og15TXmdei15MgLSDXmdepINec16jXoteg158g15TXotee15XX + kyDXnNeU16bXkteULg== + + show_today: !binary | + 15TXpteS16og15TXmdeV150= + + completed_last_x_days: !binary | + 15TXodeq15nXmdee15Ug15EtJXtjb3VudH0g15TXmdee15nXnSDXlNeQ15fX + qNeV16DXmded + + completed: !binary | + 15TXodeq15nXmdee15U= + + remove_dependency: !binary | + 15TXodeo16og16rXnNeV16ogKNec15Ag157XldeX16cg15DXqiDXlNek16LX + ldec15Qp + + older_than_days: !binary | + 15XXldeq16cg157XotecICV7Y291bnR9INeZ157Xmded + + deferred_pending_actions: !binary | + 16TXoteV15zXldeqINee157XqteZ16DXldeqL9eT15fXldeZ15XXqg== + + scheduled_overdue: !binary | + 16rXldeW157XnyDXnNeq16bXldeS15Qg15zXpNeg15kgJXtkYXlzfSDXmdee + 15nXnQ== + + added_new_project: !binary | + 16DXldeh16Mg16TXqNeV15nXmden15gg15fXk9ep + + depends_on_separate_with_commas: !binary | + 16rXnNeV15kg15EtICjXmdepINec15TXpNeo15nXkyDXkdek16HXmden15nX + nSg= + + mobile_todos_page_title: !binary | + 15vXnCDXlNek16LXldec15XXqg== + + edit_recurring_todo: !binary | + 16LXqNeb15nXqiDXpNei15XXnNeV16og157Xl9eW15XXqNeZ15XXqg== + + delete_action: !binary | + 157Xl9eZ16fXqiDXpNei15XXnNeU + + calendar: + due_next_month_and_later: !binary | + 16rXkNeo15nXmiDXmdei15MgJXttb250aH0g15DXlSDXnteQ15XXl9eoINeZ + 15XXqteo + + get_in_ical_format: !binary | + 16fXkdec16og15zXldeXINep16DXlCDXlteUINeR16TXldeo157XmCBpQ2Fs + + no_actions_due_today: !binary | + 15DXmdefINek16LXldec15XXqiDXoNeV16HXpNeV16og15zXlNeZ15XXnQ== + + due_this_month: !binary | + 16rXkNeo15nXmiDXmdei15Mg15zXmdeq16jXqiDXl9eV15PXqSAle21vbnRo + fQ== + + no_actions_due_this_month: !binary | + 15DXmdefINek16LXldec15XXqiDXnNeR15nXpteV16Ig15HXmdeq16jXqiDX + lNeX15XXk9ep + + no_actions_due_next_week: !binary | + 15DXmdefINek16LXldec15XXqiDXnNeR15nXpteV16Ig15HXqdeR15XXoiDX + lNeR15A= + + due_today: !binary | + 15zXlNeZ15XXnQ== + + due_next_week: !binary | + 15zXqdeR15XXoiDXlNeR15A= + + due_this_week: !binary | + 15zXlNee16nXmiDXlNep15HXldei + + no_actions_due_after_this_month: !binary | + 15DXmdefINek16LXldec15XXqiDXnNeR15nXpteV16Ig15zXkNeX16gg15fX + ldeT16kg15bXlA== + + list_incomplete_next_actions_with_limit: !binary | + 16jXmdep157XqiAle2NvdW50fSDXpNei15XXnNeV16og15TXlNee16nXmiDX + qdec15Ag15TXodeq15nXmdee15U= + + to_tickler: !binary | + 15zXnta015bWsNeb1rjWvNeo + + cannot_add_dependency_to_completed_todo: !binary | + 15DXmdefINeQ16TXqdeo15XXqiDXnNeU15XXodeZ16Mg16TXoteV15zXlCDX + lteVINeb16rXnNeV16og15zXpNei15XXnNeUINep15TXodeq15nXmdee15Qh + + depends_on: !binary | + 16rXnNeV15kg15E= + + no_actions_due_this_week: !binary | + 15DXmdefINek16LXldec15XXqiDXlNee15nXldei15PXldeqINec15TXntep + 15og15TXqdeR15XXog== + + no_actions_found: !binary | + 15DXmdefINeb16jXkteiINek16LXldec15XXqiDXqdec15Ag15TXodeq15nX + mdee15U= + + context_changed: !binary | + 15TXp9ep16gg16nXldeg15Qg15wtJXtuYW1lfQ== + + archived_tasks_title: !binary | + 157Xodec15XXnNeZ1506INee16nXmdee15XXqiDXqdeU16HXqteZ15nXnteV + INeU15XXoteR16jXlSDXnNeQ16jXm9eZ15XXnw== + + no_incomplete_actions: !binary | + 15DXmdefINek16LXldec15XXqiDXqdec15Ag15TXodeq15nXmdee15U= + + completed_actions_with: !binary | + 16TXoteV15zXldeqINep15TXodeq15nXmdee15Ug16LXnSDXlNeq15LXmdeq + ICV7dGFnX25hbWV9ICA= + + added_new_next_action: !binary | + 16DXldeh16TXlCDXpNei15XXnNeqINeU157XqdeaINeX15PXqdeU + + unable_to_add_dependency: !binary | + 15zXkCDXoNeZ16rXnyDXnNeU15XXodeZ16Mg16rXnNeV16o= + + older_completed_items: !binary | + 157XqdeZ157XldeqINep15TXodeq15nXmdee15XXqiDXmdep16DXldeqINeZ + 15XXqteo + + no_deferred_pending_actions: !binary | + 15DXmdefINeb16jXkteiINek16LXldec15XXqiDXk9eX15XXmdeV16og15DX + lSDXntee16rXmdeg15XXqg== + + edit: !binary | + 16LXqNeZ15vXlA== + + next_actions_title: !binary | + 157Xodec15XXnNeZ150gLSDXpNei15XXnNeV16og15TXntep15o= + + defer_x_days: + other: !binary | + 15PXl9eZ15Qg15EtJXtjb3VudH0g15nXnteZ150= + + one: !binary | + 15PXl9eZ15Qg15HXmdeV150= + + completed_recurrence_completed: !binary | + 15DXmdefINek16LXldec16og15TXntep15og15zXpNei15XXnNeUINeU157X + l9eW15XXqNeZ16og16nXoNee15fXp9eULiDXlNek16LXldec15Qg15TXnteX + 15bXldeo15nXqiDXoNee15fXp9eULg== + + due: !binary | + 15nXoteT + + append_in_this_project: !binary | + 15HXpNeo15XXmdeZ16fXmCDXlteU + + completed_recurring: !binary | + 15TXodeq15nXmdee15Ug157XqdeZ157XldeqINee15fXlteV16jXmdeV16o= + + removed_predecessor: !binary | + 15TXldeh16jXlCV7c3VjY2Vzc29yfSAg15vXqtec15XXqiDXqdecICV7cHJl + ZGVjZXNzb3J9Lta+ + + confirm_delete: !binary | + 15TXkNedINec157Xl9eV16cg15DXqiDXlNek16LXmdec15XXqiAnJXtkZXNj + cmlwdGlvbn0nPw== + + task_list_title: !binary | + 157Xodec15XXnNeZ1506Oteo16nXmdee16og157XqdeZ157Xldeq + + no_completed_actions_with: !binary | + 15DXmdefINek16LXldec15XXqiDXqdeU16HXqteZ15nXnteVINei15wg15TX + qteS15nXqiAnJXt0YWdfbmFtZX0n + + set_to_pending: !binary | + JXt0YXNrfSDXlNeV15LXk9eo15Qg15vXntee16rXmdeg15Q= + + recurring_action_saved: !binary | + 16TXoteV15zXlCDXnteX15bXldeo15nXqiDXoNep157XqNeU + + recurring_pattern_removed: !binary | + 15TXk9ek15XXoSDXlNee15fXlteV16jXmSDXlNeV16HXqCDXni0le2NvdW50 + fQ== + + next_actions_due_date: + overdue_by: !binary | + 15HXkNeZ15fXldeoINep15wgJXtkYXlzfSDXmdeV150= + + overdue_by_plural: !binary | + 15HXkNeZ15fXldeoINep15wgJXtkYXlzfSDXmdee15nXnQ== + + due_in_x_days: !binary | + 15nXoteTINeR16LXldeTICV7ZGF5c30g15nXnteZ150= + + due_today: !binary | + 15zXlNeZ15XXnQ== + + due_tomorrow: !binary | + 15zXnteX16g= + + next_action_needed: !binary | + 15nXqSDXnNeU15bXmdefINec16TXl9eV16og16TXoteV15zXqiDXlNee16nX + miDXkNeX16o= + + added_dependency: !binary | + 16DXldeh16TXlCAle2RlcGVuZGVuY3l9INeb16rXnNeV16o= + + star_action: !binary | + 15TXk9eS16nXqiDXpNei15XXnNeU + + new_related_todo_not_created_short: !binary | + 15zXkCDXoNeV16bXqNeUINee16nXmdee15Q= + + completed_last_day: !binary | + 15TXodeq15nXmdee15Ug15EtMjQg16nXoteV16og15TXkNeX16jXldeg15XX + qg== + + tagged_with: !binary | + 157XqteV15nXmdeSINeRLSAmbHNxdW87JXt0YWdfbmFtZX0mcnNxdW87 + + no_recurring_todos: !binary | + 15DXmdefINeb16jXkteiINee16nXmdee15XXqiDXnteX15bXldeo15nXldeq + + deferred_actions_with: !binary | + 16TXoteV15zXldeqINeT15fXldeZ15XXqiDXotecINeq15LXmdeqICcle3Rh + Z19uYW1lfSc= + + error_removing_dependency: !binary | + 15TXqteo15fXqdeUINep15LXmdeQ15Qg15HXlNeh16jXqiDXlNeq15zXldeq + + error_deleting_recurring: !binary | + 15DXqNei15Qg16nXkteZ16LXlCDXkdee15fXmden16og15TXntep15nXnteU + INeU157Xl9eW15XXqNeZ16ogIFwnJXtkZXNjcmlwdGlvbn1cJw== + + feed_title_in_context: !binary | + 15HXlNen16nXqCAnJXtjb250ZXh0fSc= + + new_related_todo_created: !binary | + 157XqdeZ157XlCDXl9eT16nXlCDXlNeV16HXpNeUINec157XqdeZ157XlCDX + nteX15bXldeo15nXqiDXlteV + + recurring_action_deleted: !binary | + 16TXoteV15zXlCDXoNee15fXp9eULiDXnteQ15fXqCDXldeU16TXoteV15zX + lCDXnteX15bXldeo15nXqi4g16TXoteV15zXlCDXl9eT16nXlCDXoNeV16HX + pNeU + + recurring_todos: !binary | + 157XqdeZ157XldeqINee15fXlteV16jXmdeV16o= + + next_actions_description: !binary | + 157Xodeg1586 + + added_new_context: !binary | + 16DXldeh16Mg15TXp9ep16gg15fXk9ep + + show_tomorrow: !binary | + 15TXpteS16og157Xl9eo + + was_due_on_date: !binary | + 15TXmdeUINee15nXldei15Mg16LXkyAle2RhdGV9 + + tags: !binary | + 16rXkteZ15XXqiAo157Xldek16jXk9eV16og15HXpNeh15nXp9eZ150p + + completed_more_than_x_days_ago: !binary | + 15TXodeq15nXmdee15Ug15zXpNeg15kg15nXldeq16gg154tJXtjb3VudH0g + 15nXnteZ150= + + defer_date_after_due_date: !binary | + 16rXkNeo15nXmiDXlNeT15fXmdeZ15Qg157XkNeV15fXqCDXnteq15DXqNeZ + 15og15TXmdei15MuINeZ16kg15zXoteo15XXmiDXkNeqINeq15DXqNeZ15og + 15TXmdei15Mg15HXlNeq15DXnSDXnNek16DXmSDXkden16nXqiDXlNeT15fX + mdeZ15Qu + + error_saving_recurring: !binary | + 15DXqNei15Qg16nXkteZ16LXlCDXkdep157Xmdeo16og15TXntep15nXnteU + INeU157Xl9eW15XXqNeZ16ogIFwnJXtkZXNjcmlwdGlvbn1cJw== + + edit_action_with_description: !binary | + 16LXqNeZ15vXqiDXlNek16LXldec15QgJyV7ZGVzY3JpcHRpb259Jw== + + no_last_completed_actions: !binary | + 15zXkCDXoNee16bXkNeVINek16LXldec15XXqiDXqdeU16HXqteZ15nXnteV + + done: !binary | + 15TXodeq15nXmdedPw== + + action_saved_to_tickler: !binary | + 16TXoteV15zXlCDXoNep157XqNeUINec157WtNeW1rDXm9a41rzXqA== + + hidden_actions: !binary | + 16TXoteV15zXldeqINee15XXodeq16jXldeq + + edit_action: !binary | + 16LXqNeZ15vXqiDXpNei15XXnNeU + + completed_rest_of_week: !binary | + 15TXodeq15nXmdee15Ug15HXmdeq16jXqiDXqdeR15XXoiDXlteU + + action_due_on: !binary | + KNek16LXldec15Qg16LXkyAgJXtkYXRlfSk= + + convert_to_project: !binary | + 15nXpteZ16jXqiDXpNeo15XXmdeZ16fXmA== + + show_in_days: !binary | + 15TXpteSINeR16LXldeTICV7ZGF5c30g15nXnteZ150= + + added_new_next_action_singular: !binary | + 16DXldeh16TXlCDXpNei15XXnNeqINeU157XqdeaINeX15PXqdeU + + drag_action_title: !binary | + 15nXqSDXnNeS16jXldeoINeQ15wg16TXoteV15zXlCDXkNeX16jXqiDXm9eT + 15kg15zXmdem15XXqCDXqtec15XXqiDXkdeU + + added_new_next_action_plural: !binary | + 16DXldeh16TXlSDXpNei15XXnNeV16og15TXntep15og15fXk9ep15XXqg== + + feed_title_in_project: !binary | + 15HXpNeo15XXmdeZ16fXmCAnJXtwcm9qZWN0fSc= + + no_completed_recurring: !binary | + 15DXmdefINeb16jXkteiINee16nXmdee15XXqiDXnteX15bXldeo15nXldeq + INep15TXodeq15nXmdee15U= + + recurrence: + starts_on: !binary | + 157XqteX15nXnCDXkQ== + + ends_on_number_times: !binary | + 157Xodeq15nXmdedINec15DXl9eoICV7bnVtYmVyfSDXpNei157Xmded + + ends_on: !binary | + 157Xodeq15nXmdedINeR + + yearly_options: !binary | + 15TXkteT16jXldeqINec16TXoteV15zXldeqINeR157Xl9eW15XXqNeZ15XX + qiDXqdeg16rXmdeV16o= + + daily_every_number_day: !binary | + 15vXnCAle251bWJlcn0gINeZ157Xmded + + show_options: !binary | + 15TXpteS16og157XqdeZ157Xldeq + + daily: !binary | + 15nXldee15k= + + show_option_always: !binary | + 16rXnteZ15M= + + monthly_every_xth_day: !binary | + 15nXldedICV7ZGF5fSDXlCAtJXtkYXlfb2Zfd2Vla30gINeR15vXnCAle21v + bnRofSDXl9eV15PXqQ== + + every_work_day: !binary | + 15HXm9ecINeZ15XXnSDXoteR15XXk9eU + + recurrence_on_options: !binary | + 15TXkteT16jXqiDXnteX15bXldeo15nXldeqINec16TXmQ== + + weekly: !binary | + 16nXkdeV16LXmQ== + + yearly: !binary | + 16nXoNeq15nXqg== + + daily_options: !binary | + 15TXkteT16jXldeqINec16TXoteV15zXldeqINee15fXlteV16jXmdeV16og + 15nXldee15nXldeq + + monthly: !binary | + 15fXldeT16nXmQ== + + ends_on_date: !binary | + 157Xodeq15nXmdedINeRLSV7ZGF0ZX0= + + pattern: + third: !binary | + 16nXnNeZ16nXmQ== + + from: !binary | + 154= + + every_day: !binary | + 15vXnCDXmdeV150= + + on_day_n: !binary | + 15HXmdeV150gJXtufQ== + + on_work_days: !binary | + 15HXmdee15kg16LXkdeV15PXlA== + + until: !binary | + 16LXkw== + + every_month: !binary | + 15vXnCDXl9eV15PXqQ== + + every_xth_day_of_every_n_months: "\xD7\x9B\xD7\x9C %{x} %{day} \xD7\x91\xD7\x9B\xD7\x9C %{n_months}" + weekly: !binary | + 16nXkdeV16LXmQ== + + fourth: !binary | + 16jXkdeZ16LXmQ== + + first: !binary | + 16jXkNep15XXnw== + + due: !binary | + 15nXoteT + + second: !binary | + 16nXoNeZ + + last: !binary | + 15DXl9eo15XXnw== + + every_year_on: !binary | + 15HXm9ecINep16DXlCDXkdeq15DXqNeZ15ogJXtkYXRlfQ== + + every_n: !binary | + 15vXnCAle259 + + times: !binary | + 15stJXtudW1iZXJ9INek16LXnteZ150= + + the_xth_day_of_month: !binary | + 15TXmdeV150g15QtICV7eH0gJXtkYXl9INeR15fXldeT16kgJXttb250aH0= + + show: !binary | + 15TXpteS15Q= + + yearly_every_xth_day: !binary | + 15nXldedICV7ZGF5fSDXlCAtJXtkYXlfb2Zfd2Vla30gINeR15vXnCAle21v + bnRofSDXl9eV15PXqQ== + + monthly_options: !binary | + 15TXkteT16jXldeqINec16TXoteV15zXldeqINeR15fXlteV16jXmdeV16og + 15fXldeT16nXmdeq + + no_end_date: !binary | + 15DXmdefINeq15DXqNeZ15og16HXmdeV150= + + show_days_before: !binary | + JXtkYXlzfSDXmdee15nXnSDXnNek16DXmSDXqteQ16jXmdeaINeU15nXoteT + INec157XqdeZ157XlA== + + from_tickler: !binary | + 16rXkNeo15nXmiDXlNeZ16LXkyDXnNee16nXmdee15Qg157XkteZ16Ig157X + lNee1rTXltaw15vWuNa816ggKNec15Ag16DXp9eR16Ig16rXkNeo15nXmiDX + mdei15Mp + + weekly_every_number_week: !binary | + 15fXldeW16gg15vXnCAle251bWJlcn0gINep15HXldeiINeR + + day_x_on_every_x_month: !binary | + 15HXmdeV150gJXtkYXl9INeR15vXnCAle21vbnRofSAg15fXldeT16k= + + weekly_options: !binary | + 15TXkteT16jXldeqINec16TXoteV15zXldeqINeR157Xl9eW15XXqNeZ15XX + qiDXqdeR15XXoteZ16o= + + yearly_every_x_day: "\xD7\x9B\xD7\x9C %{month} %{day}" + recurrence_on_due_date: !binary | + 15nXoteTINec157XqdeZ157XlA== + + error_completing_todo: !binary | + 15DXqNei15Qg16nXkteZ16LXlCDXkdeh15nXldedIC8g15TXpNei15zXlCDX + qdecINee16nXmdee15QgJXtkZXNjcmlwdGlvbn0= + + in_pending_state: !binary | + 15HXntem15Eg15TXnteq16DXlA== + + action_marked_complete_error: !binary | + 15TXpNei15XXnNeUIDxzdHJvbmc+JyV7ZGVzY3JpcHRpb259Jzwvc3Ryb25n + Pta+15zXkNa+INeh15XXnteg15Qg15sgLSA8c3Ryb25nPiV7Y29tcGxldGVk + fSDXoten15Eg16nXkteZ15DXqiDXqdeo16o8L3N0cm9uZz4= + + completed_today: + other: !binary | + 16LXkyDXoteq15Qg15TXodeq15nXmdee15UgJXtjb3VudH0g16TXoteV15zX + qiDXlNeZ15XXnS4= + + one: !binary | + 15TXldep15zXnteUINek16LXldec15Qg15DXl9eqINeU15nXldedLCDXoteT + INei16rXlC4= + + no_hidden_actions: !binary | + 15zXkCDXoNee16bXkNeVINek16LXldec15XXqiDXnteV16HXqteo15XXqg== + + all_completed: !binary | + 15vXnCDXlNek16LXldec15XXqiDXqdeU16HXqteZ15nXnteV + + action_deleted_error: !binary | + 16DXm9ep15zXlCDXnteX15nXp9eqINeU16TXoteV15zXlA== + + action_deleted_success: !binary | + 16TXoteV15zXqiDXlNee16nXmiDXoNee15fXp9eUINeR15TXptec15fXlA== + + star_action_with_description: !binary | + 15TXk9eS16nXqiDXpNei15nXnNeV16ogJyV7ZGVzY3JpcHRpb259Jw== + + unresolved_dependency: !binary | + 15TXoteo15og16nXlNeV15vXoNehINeR16rXnNeV16og15zXkCDXqteQ150g + 15zXkNejINek16LXldec15Qg16fXmdeZ157Xqi4g15TXoteo15og15zXkCDX + mdep157XqCDXotedINeZ16rXqNeqINeU16TXoteV15zXlC4g15zXlNee16nX + mdeaPw== + + completed_actions: !binary | + 16TXoteV15zXldeqINep15TXodeq15nXmdee15U= + + pending: !binary | + 157Xnteq15nXnw== + + error_starring: !binary | + 15TXk9eS16nXqiDXlNee16nXmdee15QgIFwnJXtkZXNjcmlwdGlvbn1cJyDX + nNeQINem15zXl9eU + + delete_recurring_action_title: !binary | + 157Xl9eZ16fXqiDXpNei15XXnNeUINee15fXlteV16jXmdeq + + no_project: !binary | + LS3XkNeZ158g16TXqNeV15nXmden15gtLQ== + + in_hidden_state: !binary | + 15HXntem15Eg157Xldeh16rXqA== + + recurring_actions_title: !binary | + 157Xodec15XXnNeZ1506Otek16LXldec15XXqiDXnteX15bXldeo15nXldeq + + completed_in_archive: + other: !binary | + 16fXmdeZ157XldeqICV7Y291bnR9INek16LXldec15XXqiDXqdeU16HXqteZ + 15nXnteVINeR15DXqNeb15nXldefLg== + + one: !binary | + 16fXmdeZ157XqiDXkdeQ16jXm9eZ15XXnyDXpNei15XXnNeUINep15TXodeq + 15nXmdee15Qu + + error_deleting_item: !binary | + 15DXqNei15Qg16nXkteZ15DXlCDXkdee15fXmden16og15TXpNeo15nXmCAl + e2Rlc2NyaXB0aW9ufQ== + + tagged_page_title: !binary | + 157Xodec15XXnNeZ1506Oteq15LXmdeV16og16LXnSAnJXt0YWdfbmFtZX0n + + no_actions_with: !binary | + 15DXmdefINeb16jXkteiINek16LXldec15XXqiDXqdec15Ag15TXodeq15nX + mdee15XXqiDXotedINeU16rXkteZ16ogJyV7dGFnX25hbWV9Jw== + + feeds: + completed: !binary | + 15TXodeq15nXmdedOiAle2RhdGV9 + + due: !binary | + 15nXoteTICV7ZGF0ZX0= + + no_completed_actions: !binary | + 15DXmdefINeb16jXkteiINek16LXldec15XXqiDXqdeU16HXqteZ15nXnteV + Lg== + + no_actions_found_title: !binary | + 15zXkCDXoNee16bXkCDXpNei15XXnNeV16o= + + error_toggle_complete: !binary | + 15zXkCDXoNeZ16rXnyDXnNeh157XnyDXntep15nXnteUINebIteU16HXqteZ + 15nXnteUIg== + + next_actions_description_additions: + due_date: !binary | + 16LXnSDXqteQ16jXmdeaINeZ16LXkyAle2R1ZV9kYXRlfSDXkNeVINee15XX + p9eT150g15nXldeq16gg + + completed: !binary | + 15EtJXtjb3VudH0g15TXmdee15nXnSDXlNeQ15fXqNeV16DXmded + + list_incomplete_next_actions: !binary | + 16jXqdeZ157XqiDXpNei15XXnNeV16og15TXntep15og16nXnNeQINeU16HX + qteZ15nXnteV + + has_x_pending: + other: !binary | + 157Xm9eZ15wgJXtjb3VudH0g16TXoteV15zXqiDXntee16rXmdeg15XXqg== + + one: !binary | + 15HXotecINek16LXldec15Qg15PXl9eV15nXlCDXkNeX16o= + + deleted_success: !binary | + 15TXpNei15XXnNeUINeg157Xl9en15Qg15HXlNem15zXl9eU + + overdue: !binary | + 15HXkNeZ15fXldeo + + integrations: + applescript_success_before_id: !binary | + 16TXoteV15zXqiDXlNee16nXmiDXotedINeW15nXlNeV15k= + + gmail_description: !binary | + 15fWstek1rTXmdelINec15TXldeh16TXqiDXnteh15zXldec15nXnSDXnC1H + bWFpbA== + + opensearch_description: !binary | + 15fXmdek15XXqSDXkdee16HXnNeV15zXmded + + applescript_success_after_id: !binary | + 16DXldem16g= + + applescript_next_action_prompt: !binary | + 16rXmdeQ15XXqCDXlNek16LXldec15XXqiDXlNeR15DXldeqOg== + + activerecord: + attributes: + project: + default_context_name: !binary | + 15TXp9ep16gg15HXqNeZ16jXqiDXnteX15PXnA== + + default_tags: !binary | + 16rXkteZ15XXqiDXkdeo15nXqNeqINee15fXk9ec + + name: !binary | + 16nXnQ== + + description: !binary | + 16rXmdeQ15XXqA== + + todo: + show_from: !binary | + 15TXpteSINee + + project: !binary | + 16TXqNeV15nXmden15jXmded + + context: !binary | + 15TXp9ep16g= + + due: !binary | + 16rXkNeo15nXmiDXmdei15M= + + predecessors: !binary | + 16rXnNeV15kg15E= + + notes: !binary | + 16TXqten15nXnQ== + + description: !binary | + 16rXmdeQ15XXqA== + + user: + last_name: !binary | + 16nXnSDXntep16TXl9eU + + first_name: !binary | + 16nXnSDXpNeo15jXmQ== + + preference: + sms_context: !binary | + 15PXldeQItecINeR16jXmdeo16og157Xl9eT16gg16LXkdeV16gg15TXp9ep + 16g= + + time_zone: !binary | + 15DXlteV16gg15bXntef + + refresh: !binary | + 16rXk9eZ16jXldeqINeo16LXoNeV158gKNeR15PXp9eV16op + + last_name: !binary | + 16nXnSDXntep16TXl9eU + + date_format: !binary | + 157Xkdeg15Qg16rXkNeo15nXmg== + + show_project_on_todo_done: !binary | + 16LXkdeV16gg15zXotee15XXkyDXlNek16jXldeZ15nXp9eYINeR16HXmdeV + 150g157XqdeZ157XlA== + + review_period: !binary | + 16rXk9eZ16jXldeqINeo16LXoNeV158g16TXqNeV15nXmden15g= + + week_starts: !binary | + 16nXkdeV16Ig157XqteX15nXnCDXkdeZ15XXnQ== + + due_style: !binary | + 16HXkteg15XXnyDXqteQ16jXmdeaINeZ16LXkw== + + show_number_completed: !binary | + 15TXpteSINee16HXpNenINek16LXldec15XXqiDXqdeR15XXptei15U= + + mobile_todos_per_page: !binary | + 157Xodek16gg16TXoteV15zXldeqINec15PXoyAo16rXpteV15LXlCDXoNeZ + 15nXk9eqKQ== + + show_hidden_projects_in_sidebar: !binary | + 15TXpteSINek16jXldeZ15nXp9eY15nXnSAg157Xldeh16rXqNeZ150g15HX + pteT + + show_completed_projects_in_sidebar: !binary | + 15TXpteSINek16jXldeZ15nXp9eY15nXnSDXqdeU16HXqteZ15nXnteVINeR + 16bXkw== + + sms_email: !binary | + 15PXldeQ16gg157XkNeq + + locale: !binary | + 16nXpNeU + + verbose_action_descriptors: !binary | + 16rXmdeQ15XXqNeZINee16nXmdee15XXqiDXntek15XXqNeY15nXnQ== + + first_name: !binary | + 16nXnSDXpNeo15jXmQ== + + title_date_format: !binary | + 157Xkdeg15Qg16rXkNeo15nXmiDXm9eV16rXqNeq + + show_hidden_contexts_in_sidebar: !binary | + 15TXpteSINeU16fXqdeo15nXnSDXnteV16HXqteo15nXnSDXkdem15M= + + staleness_starts: !binary | + 15TXqteX15zXqiDXqtek15zXldeq + + errors: + models: + project: + attributes: + name: + blank: !binary | + 15zXpNeo15XXmdeZ16fXmCDXl9eZ15nXkSDXnNeU15nXldeqINep150= + + taken: !binary | + 15vXkdeoINen15nXmded + + too_long: !binary | + 16LXnCDXqdedINeU16TXqNeV15nXmden15gg15zXlNeb15nXnCDXpNeX15XX + qiDXni0yNTYg16rXldeV15nXnQ== + + template: + header: + other: !binary | + 16nXkteZ15DXldeqINee16DXoteVINee157XldeT15wgJXttb2RlbH0g15zX + lNeZ16nXnteo + + one: !binary | + 16nXkteZ15DXlCDXnteg16LXlCDXntee15XXk9ecICV7bW9kZWx9INec15TX + mdep157XqA== + + body: !binary | + 15HXoteZ15XXqiDXkdep15PXldeqINeU15HXkNeZ1506 + + messages: + exclusion: !binary | + 16nXnteV16g= + + blank: !binary | + 15zXkCDXmdeb15XXnCDXnNeU15nXldeqINeo15nXpw== + + too_short: !binary | + 16fXpteoINem15PXmSAo15zXm9ecINeU16TXl9eV16ogJXtjb3VudH0g16rX + ldeV15nXnSg= + + empty: !binary | + 15zXkCDXmdeb15XXnCDXnNeU15nXldeqINeo15nXpw== + + taken: !binary | + 15vXkdeoINeg157XpteQINeR16nXmdee15XXqQ== + + wrong_length: !binary | + 15HXkNeV16jXmiDXnNeQINeg15vXldefICjXpteo15nXmiDXnNeU15nXldeq + ICV7Y291bnR9INeq15XXldeZ150o + + record_invalid: !binary | + 15DXmdee15XXqiDXoNeb16nXnCAle2Vycm9yc30= + + inclusion: !binary | + 15zXkCDXnteV15vXnCDXkdeo16nXmdee15Q= + + greater_than_or_equal_to: !binary | + 15fXmdeZ15Eg15zXlNeZ15XXqiDXkteV15PXnCDXkNeVINep15XXldeUINec + ICV7Y291bnR9 + + confirmation: !binary | + 15DXmdeg15Ug16rXldeQ150g15DXqiDXlNeQ15nXqdeV16g= + + accepted: !binary | + 15fXmdeZ15Eg15zXlNeq16fXkdec + + greater_than: !binary | + 15fXmdeZ15Eg15zXlNeZ15XXqiDXkteT15XXnCDXniAle2NvdW50fQ== + + too_long: !binary | + 15DXqNeV15og157Xk9eZICjXnNeb15wg15TXmdeV16rXqCAle2NvdW50fSDX + qteV15XXmdedKA== + + less_than_or_equal_to: !binary | + 15fXmdeZ15Eg15zXlNeZ15XXqiDXp9eY158g15DXlSDXqdeV15XXlCDXnCAl + e2NvdW50fQ== + + not_a_number: !binary | + 15DXmdeg15Ug157Xodek16g= + + less_than: !binary | + 15fXmdeZ15Eg15zXlNeZ15XXqiDXp9eY158g154gJHtjb3VudH0= + + equal_to: !binary | + 15fXmdeZ15Eg15zXlNeZ15XXqiDXqdeV15XXlCDXnCAle2NvdW50fQ== + + invalid: !binary | + 15zXkCDXmdeb15XXnCDXnNeU15vXmdecINeQ16og16rXlSAoJywnKSDXlNek + 16HXmden + + even: !binary | + 15fXmdeZ15Eg15zXlNeZ15XXqiDXlteV15LXmQ== + + odd: !binary | + 15fXmdeZ15Eg15zXlNeZ15XXqiDXkNeZINeW15XXkteZ + + full_messages: + format: "%{attribute} %{message}" + states: + stalled: !binary | + 16DXotem16g= + + current_plural: !binary | + 157XoteV15PXm9eg15nXnQ== + + active: !binary | + 16TXoteZ15w= + + stalled_plural: !binary | + 16LXpteV16jXmded + + active_plural: !binary | + 16TXoteZ15zXmded + + review_plural: !binary | + 157XqteV15DXqNeb15nXnQ== + + review: !binary | + 157XqteV15DXqNea + + visible: !binary | + 15LXnNeV15k= + + completed: !binary | + 15TXodeq15nXmded + + visible_plural: !binary | + 15LXnNeV15nXmded + + blocked: !binary | + 16DXl9eh150= + + blocked_plural: !binary | + 15fXodeV157Xmded + + hidden_plural: !binary | + 157Xldeh16rXqNeZ150= + + completed_plural: !binary | + 15TXodeq15nXmdee15U= + + current: !binary | + 16LXk9eb16DXmQ== + + hidden: !binary | + 157Xldeh16rXqNeZ150= + + datetime: + prompts: + minute: !binary | + 15PXp9eU + + hour: !binary | + 16nXoteU + + year: !binary | + 16nXoNeU + + month: !binary | + 15fXldeT16k= + + second: !binary | + 16nXoNeZ15XXqg== + + day: !binary | + 15nXlded + + distance_in_words: + almost_x_years: + other: !binary | + 15vXntei15ggJXtjb3VudH0g16nXoNeZ150= + + one: !binary | + 15vXntei15gg16nXoNeU + + half_a_minute: !binary | + 15fXpteZINeT16fXlA== + + x_minutes: + other: !binary | + JXtjb3VudH0g15PXp9eV16o= + + one: !binary | + 15PXp9eU + + about_x_hours: + other: !binary | + 15stJXtjb3VudH0g16nXoteV16o= + + one: !binary | + 15vXqdei15Q= + + x_months: + other: !binary | + JXtjb3VudH0g15fXldeT16nXmded + + one: !binary | + 15fXldeT16k= + + x_seconds: + other: !binary | + JXtjb3VudH0g16nXoNeZ15XXqg== + + one: !binary | + 16nXoNeZ15nXlA== + + less_than_x_seconds: + other: !binary | + 16TXl9eV16og154tJXtjb3VudH0g16nXoNeZ15XXqg== + + zero: !binary | + 16TXl9eV16og157Xqdeg15nXmdeU + + one: !binary | + 16TXl9eV16og157Xqdeg15nXmdeU + + over_x_years: + other: !binary | + 157XotecICV7Y291bnR9INep16DXmded + + one: !binary | + 157Xotec15Qg15zXqdeg15Q= + + less_than_x_minutes: + other: !binary | + 16TXl9eV16og154tJXtjb3VudH0g15PXp9eV16o= + + zero: !binary | + 16TXl9eV16og157Xk9en15Q= + + one: !binary | + 16TXl9eV16og157Xk9en15Q= + + about_x_months: + other: !binary | + 15stJXtjb3VudH0g15fXldeT16nXmded + + one: !binary | + 15vXl9eV15PXqQ== + + x_days: + other: !binary | + JXtjb3VudH0g15nXnteZ150= + + one: !binary | + 15nXlded + + about_x_years: + other: !binary | + 15stJXtjb3VudH0g16nXoNeZ150= + + one: !binary | + 15vXqdeg15Q= + + errors: + user_unauthorized: !binary | + NDAxINec15Ag157XkNeV16nXqDog16jXpyDXntep16rXntep15nXnSDXkdeT + 16jXkteqINee16DXlNecINeo16nXkNeZ150g15zXlNek16LXmdecINek16LX + ldec15Qg15bXlQ== + + users: + confirm_password: !binary | + 15DXmdep15XXqCDXodeZ16HXnteQ + + total_actions: !binary | + 16HXmiDXpNei15XXnNeV16o= + + change_auth_type_title: !binary | + 157Xodec15XXnNeZ1506Otep15nXoNeV15kg16nXmdeY16og15TXlteT15TX + ldeq + + openid_ok_pref_failed: !binary | + 15vXqteV15HXqiDXlNeW15TXldeqICV7dXJsfSAu15DXldee16rXlCDXkdeU + 16bXnNeX15Qg15DXmiDXkNeo16LXlCDXqten15zXlCDXkdep157Xmdeo16og + 15TXkteT16jXldeqINeU15TXlteT15TXldeq + + total_users_count: !binary | + 16fXmdeZ157XmdedICV7Y291bnR9INee16nXqtee16nXmded + + total_notes: !binary | + 16HXmiDXpNeq16fXmded + + manage_users: !binary | + 16DXmdeU15XXnCDXntep16rXntep15nXnQ== + + you_have_to_reset_your_password: !binary | + 15nXqSDXnNeQ16TXoSDXkNeqINeU16HXmdeh157XkA== + + no_signups_title: !binary | + 157Xodec15XXnNeZ1506OteQ15nXnyDXqNeZ16nXldee15nXnQ== + + account_signup: !binary | + 16jXmdep15XXnSDXnNeX16nXkdeV158= + + new_user_heading: !binary | + 16jXmdep15XXnSDXntep16rXntepINeX15PXqTo= + + choose_password: !binary | + 15HXl9eZ16jXqiDXodeZ16HXnteQ + + auth_change_submit: !binary | + 16nXmdeg15XXmSDXqdeZ15jXqiDXkNeZ157Xldeq + + identity_url: !binary | + 15vXqteV15HXqiDXlteU15XXqg== + + signup: !binary | + 16jXmdep15XXnQ== + + signup_successful: !binary | + 16jXmdep15XXnSDXnteV16bXnNeXINei15HXldeoINee16nXqtee16kgJXt1 + c2VybmFtZX0u + + change_password_prompt: !binary | + 15nXqSDXnNeb16rXldeRINeQ16og15TXodeZ16HXnteQINeU15fXk9ep15Qg + 15HXqdeT15XXqiDXqdec157XmNeUINeV15zXlNen15zXmdenICfXqdeg15Qg + 16HXmdeh157XkCcg15vXk9eZINec15TXl9ec15nXoyDXkNeqINeU16HXmdeh + 157XkCDXlNeg15XXm9eX15nXqiDXkdeX15PXqdeULg== + + password_confirmation_label: !binary | + 15DXmdee15XXqiDXodeZ16HXnteQ + + user_created: !binary | + 157Xqdeq157XqSDXoNeV16bXqA== + + auth_type_updated: !binary | + 16nXmdeY16og15DXmdee15XXqiDXoteV15PXm9eg15Q= + + label_auth_type: !binary | + 16nXmdeY16og15DXmdee15XXqg== + + first_user_heading: !binary | + 15HXqNeV15vXmdedINeU15HXkNeZ150g15DXnCDXnteh15zXldec15nXnS4g + 15vXk9eZINec15TXqteX15nXnCwg15nXqSDXnNeZ16bXldeoINeX16nXkdeV + 158g157XoNeU15w6 + + total_contexts: !binary | + 16HXmiDXlNen16nXqNeZ150= + + failed_to_delete_user: !binary | + 157Xl9eZ16fXqiDXlNee16nXqtee16kgJXt1c2VybmFtZX0g16DXm9ep15zX + lA== + + openid_url_verified: !binary | + 15vXqteV15HXqiDXlNeW15TXldeqICV7dXJsfSAu15DXldee16rXlCDXkdeU + 16bXnNeX15Qg15XXkNeV16TXnyDXlNeQ15nXnteV16og16DXp9eR16Ig15wt + T3BlbklELg== + + destroy_confirmation: !binary | + 15DXlteU16jXlDog15TXpNei15XXnNeUINeq157Xl9enINeQ16og15TXntep + 16rXntepICcle2xvZ2lufScsINeb15wg15TXpNei15XXnNeV16osINeU16TX + qNeV15nXmden15jXmdedINeV15TXpNeq16fXmdedLiDXlNeQ150g15zXlNee + 16nXmdeaPw== + + destroy_successful: !binary | + 157Xqdeq157XqSAle2xvZ2lufSDXlNeV16nXnteTINeR15TXptec15fXlA== + + password_updated: !binary | + 16HXmdeh157XkCDXoteV15PXm9eg15Qu + + new_user_title: !binary | + 157Xodec15XXnNeZ1506Oteo15nXqdeV150g157Xqdeq157XqSDXm9ee16DX + lNec + + change_password_title: !binary | + 157Xodec15XXnNeZ1506Otep15nXoNeV15kg16HXmdeh157XkA== + + register_with_cas: !binary | + 16LXnSDXntep16rXntepINeU16nXkCLXniDXqdec15o= + + destroy_user: !binary | + 15TXqdee15PXqiDXntep16rXntep + + successfully_deleted_user: !binary | + 157Xqdeq157XqSAgJXt1c2VybmFtZX0g16DXnteX16cg15HXlNem15zXl9eU + + new_token_generated: !binary | + 15DXodeZ157XldefINeX15PXqSDXoNeV16bXqCDXkdeU16bXnNeX15Q= + + destroy_error: !binary | + 15DXqNei15Qg16nXkteZ15DXlCDXkdee15fXmden16og15TXntep16rXntep + ICV7bG9naW59 + + change_authentication_type: !binary | + 16nXmdeg15XXmSDXqdeZ15jXqiDXlNeW15PXlNeV16o= + + select_authentication_type: !binary | + 15nXqSDXnNeR15fXldeoINeQ16og16nXmdeY16og15TXlteZ15TXldeZINeU + 15fXk9ep15Qg15XXnNeU15zXnNeZ16cgJ9ep15nXoNeV15kg16nXmdeY16og + 15TXlteT15TXldeqJyDXnNeR15fXmdeo16og15TXqdeZ15jXlCDXlNeg15XX + m9eX15nXqg== + + auth_type_update_error: !binary | + 15DXqNei15Qg16nXkteZ15DXlCDXkdei15nXk9eb15XXnyDXqdeZ15jXqiDX + lNeQ15nXnteV16o6ICV7ZXJyb3JfbWVzc2FnZXN9 + + total_projects: !binary | + 16HXlCLXmyDXpNeo15XXmden15jXmded + + change_password_submit: !binary | + 16nXmdeg15XXmSDXodeZ16HXnteQ + + desired_login: !binary | + 157Xqdeq157XqSDXm9eg15nXodeUINeo16bXldeZ + + new_password_label: !binary | + 16HXmdeh157XkCDXl9eT16nXlA== + + signup_new_user: !binary | + 16jXqdeV150g157Xqdeq157XqSDXl9eT16k= + + common: + search: !binary | + 15fXmdek15XXqQ== + + third: !binary | + 16nXnNeZ16nXmQ== + + project: !binary | + 16TXqNeV15nXmden15g= + + action: !binary | + 16TXoteV15zXlA== + + ajaxError: !binary | + 16nXkteZ15DXlCDXkdeq15LXldeR15Qg157XlNep16jXqg== + + previous: !binary | + 15TXp9eV15PXnQ== + + sort: + by_task_count: !binary | + 15zXpNeZINee16HXpNeoINee16nXmdee15XXqg== + + alphabetically_title: !binary | + 16HXk9eoINek16jXldeZ15nXp9eY15nXnSDXkNec16TXkdeY15nXqg== + + sort: !binary | + 157XmdeZ158= + + by_task_count_title: !binary | + 157XmdeZ158g15zXpNeZINee16HXpNeoINee16nXmdee15XXqg== + + alphabetically_confirm: !binary | + 15zXodeT16gg15DXqiDXlNek16jXldeZ15nXp9eY15nXnSDXkdeh15PXqCDX + kNec16TXkdeq15k/INeU16TXoteV15zXlCDXqteX15zXmdejINeQ16og15TX + odeT16gg15TXp9eZ15nXnQ== + + by_task_count_title_confirm: !binary | + 15zXodeT16gg15DXqiDXlNek16jXldeZ15nXp9eY15nXnSDXnNek15kg157X + odek16gg15TXntep15nXnteV16o/INeU16TXoteV15zXlCDXqteX15zXmdej + INeQ16og15TXodeT16gg15TXp9eZ15nXnQ== + + alphabetically: !binary | + 15DXnNek15HXqteZ + + server_error: !binary | + 15TXqteo15fXqdeUINep15LXmdeQ16og16nXqNeq + + email: !binary | + 15PXldeQItec + + weeks: !binary | + 16nXkdeV16LXldeq + + ok: !binary | + 15DXlden15k= + + actions: !binary | + 16TXoteV15zXldeq + + todo: !binary | + 157XqdeZ157XlA== + + website: !binary | + 15DXqteo + + review: !binary | + 15HXmden15XXqNeq + + logout: !binary | + 16bXkA== + + numbered_step: !binary | + 16bXoteTICV7bnVtYmVyfQ== + + drag_handle: !binary | + 157XqdeV15o= + + context: !binary | + 15TXp9ep16g= + + bugs: !binary | + 15HXkNeS15nXnQ== + + show_all: !binary | + 15TXpteSINeU15vXnA== + + fourth: !binary | + 16jXkdeZ16LXmQ== + + forum: !binary | + 16TXldeo15XXnQ== + + next: !binary | + 15TXkdeQ + + projects: !binary | + 16TXqNeV15nXmden15jXmded + + contribute: !binary | + 16rXqNeV150= + + optional: !binary | + 15DXpNep16jXmQ== + + week: !binary | + 16nXkdeV16I= + + back: !binary | + 15DXl9eV16jXlA== + + actions_midsentence: !binary | + 16TXoteV15zXldeq + + first: !binary | + 16jXkNep15XXnw== + + wiki: !binary | + 15XXmden15k= + + month: !binary | + 15fXldeT16k= + + add: !binary | + 15TXldeh16M= + + second: !binary | + 16nXoNeZ + + last: !binary | + 15DXl9eo15XXnw== + + none: !binary | + 15TXoteo15Q= + + notes: !binary | + 15TXoteo15XXqg== + + cancel: !binary | + 15HXmNec + + go_back: !binary | + 15fXlteV16g= + + forth: !binary | + 15XXkNeZ15zXmg== + + description: !binary | + 16rXmdeQ15XXqA== + + recurring_todos: !binary | + 16TXoteV15zXldeqINee15fXlteV16jXmdeV16o= + + months: !binary | + 15fXldeT16nXmded + + update: !binary | + 16LXk9eb158= + + create: !binary | + 16bXldeo + + contexts: !binary | + 15TXp9ep16jXmded + + errors_with_fields: !binary | + 16nXkteZ16jXldeqINeR16nXk9eV16og15TXntem15XXmdeZ16DXmded + + data: + import_errors: !binary | + 16nXkteZ15DXldeqINeR15nXkdeV15A= + + import_successful: !binary | + 15nXkdeV15Ag15HXldem16Ig15HXlNem15zXl9eU + + date: + formats: + default: "%Y-%m-%d " + longer: "%A %B %d, %Y" + short: "%b %d " + long: "%B %d, %Y " + projects: + default_context_set: !binary | + 15HXl9eZ16jXqiDXlNen16nXqCDXkdeo15nXqNeqINeU157Xl9eT15wg15zX + pNeo15XXmdeZ16fXmCDXnC0le2RlZmF1bHRfY29udGV4dH0= + + add_note: !binary | + 15TXldeh16TXqiDXpNeq16c= + + hidden_projects: !binary | + 16TXqNeV15nXmden15jXmdedINep15TXldeh16rXqNeV + + default_tags_removed_notice: !binary | + 16rXkteZ15XXqiDXkdeo15nXqNeqINeU157Xl9eT15wg15TXldeh16jXlQ== + + deferred_actions: !binary | + 16TXoteV15zXldeqINep16DXk9eX15Ug16LXkdeV16gg16TXqNeV15nXmden + 15gg15bXlA== + + add_note_submit: !binary | + 15TXldeh16TXqiDXpNeq16c= + + page_title: !binary | + 157Xodec15XXnNeZ1506Otek16jXldeZ15nXp9eYOiAle3Byb2plY3R9 + + was_marked_complete: !binary | + 16HXldee158g15vXkdeV16bXog== + + with_no_default_context: !binary | + 15zXnNeQINeU16fXqdeoINeR16jXmdeo16og157Xl9eT15w= + + no_default_context: !binary | + ICDXkNeZ158g15TXp9ep16gg15HXqNeZ16jXqiDXnteX15PXnCDXnNek16jX + ldeZ15nXp9eYINeW15Q= + + completed_actions_empty: !binary | + 15DXmdefINek16LXldec15XXqiDXqdeU16HXqteZ15nXnteVINeR16TXqNeV + 15nXmden15gg15bXlA== + + edit_project_settings: !binary | + 16LXqNeZ15vXqiDXlNeS15PXqNeV16og16TXqNeV15nXmden15g= + + with_default_context: !binary | + 16LXnSDXlNen16nXqCDXkdeZ16jXqiDXnteX15PXnCAnJXtjb250ZXh0X25h + bWV9Jw== + + add_project: !binary | + 15TXldeh16TXqiDXpNeo15XXmdeZ16fXmA== + + set_default_tags_notice: !binary | + 15HXl9eZ16jXqiDXqteS15nXldeqINeR16jXmdeo16og15TXnteX15PXnCDX + nC0le2RlZmF1bHRfdGFnc30= + + with_no_default_tags: !binary | + 15XXnNec15Ag16rXkteZ15XXqiDXkdeo15nXqNeqINee15fXk9ec + + completed_actions: !binary | + 16TXoteV15zXldeqINep15TXodeq15nXmdee15Ug15HXpNeo15XXmdeZ16fX + mCDXlteU + + hide_form_title: !binary | + 15TXodeq16jXqiDXmNeV16TXoSDXpNeo15XXmdeZ16fXmCDXl9eT16k= + + is_active: !binary | + 16TXoteZ15w= + + completed_projects: !binary | + 16TXqNeV15nXmden15jXmdedINep15TXodeq15nXmdee15U= + + no_actions_in_project: !binary | + 15DXmdefINeb16jXkteiINee16nXmdee15XXqiDXqdecINeU15XXqdec157X + lSDXkdek16jXldeZ15nXp9eYINeW15Q= + + to_new_project_page: !binary | + 16LXkdeV16gg15zXotee15XXkyDXlNek16jXldeZ15nXp9eYINeU15fXk9ep + + default_context: !binary | + 15TXp9ep16gg15HXqNeZ16jXqiDXlNee15fXk9epINec16TXqNeV15nXmden + 15gg15bXlCAle2NvbnRleHR9 + + delete_project: !binary | + 157Xl9eZ16fXqiDXpNeo15XXmdeZ16fXmA== + + status_project_name_changed: !binary | + 16nXnSDXlNek16jXldeZ15nXp9eYINep15XXoNeU + + no_last_completed_recurring_todos: !binary | + 15zXkCDXoNee16bXkNeVINee16nXmdee15XXqSDXnteX15bXldeo15nXldeq + INep15TXodeq15nXmdee15U= + + project_state: !binary | + 15TXpNeo15XXmdeZ16fXmCAle3N0YXRlfQ== + + delete_project_title: !binary | + 157Xl9eZ16fXqiDXlNek16jXldeZ15nXp9eY + + completed_tasks_title: !binary | + 157Xodec15XXnNeZ1506OteU16bXkteqINeo16nXmdee16og15TXntep15nX + nteV16og16nXlNeV16nXnNee15Ug15HXpNeo15XXmdeZ16fXmCAgJyV7cHJv + amVjdF9uYW1lfSc= + + was_marked_hidden: !binary | + 16HXldee158g15vXnteV16HXqteo + + show_form_title: !binary | + 15nXpteZ16jXqiDXpNeo15XXmdeZ16fXmCDXl9eT16k= + + notes_empty: !binary | + 15DXmdefINek16rXp9eZ150g15zXpNeo15XXmdeZ16fXmCDXlteU + + delete_project_confirmation: !binary | + 15TXkNedINec157Xl9eV16cg15DXqiDXlNek16jXldeZ15nXp9eYICAnJXtu + YW1lfSc/ + + default_context_removed: !binary | + 15TXp9ep16gg15HXqNeZ16jXqiDXlNee15fXk9ecINeU15XXodeo + + list_completed_projects: !binary | + 157Xodec15XXnNeZ1506Oteo16nXmdee16og15TXpNeo15XXmdeZ16fXmNeZ + 150g16nXlNeV15zXqdee15U= + + hide_form: !binary | + 15TXodeq16jXqiDXmNeV16TXoQ== + + deferred_actions_empty: !binary | + 15DXmdefINek16LXldec15XXqiDXqdeg15PXl9eVINei15HXldeoINek16jX + ldeZ15nXp9eYINeW15Q= + + actions_in_project_title: !binary | + 16TXoteV15zXldeqINeR16TXqNeV15nXmden15gg15bXlA== + + settings: !binary | + 15TXkteT16jXldeq + + notes: !binary | + 16TXqten15nXnQ== + + project_saved_status: !binary | + 16TXqNeV15nXmden15gg16DXqdee16g= + + no_notes_attached: !binary | + 15DXmdefINeb16jXkteiINek16rXp9eZ150g15TXnten15XXqdeo15nXnSDX + nNek16jXldeZ15nXp9eYINeW15Q= + + list_projects: !binary | + 157Xodec15XXnNeZ1506Oteo16nXmdee16og16TXqNeV15nXmden15jXmded + + all_completed_tasks_title: !binary | + 157Xodec15XXnNeZ1506OteU16bXkteqINeo16nXmdee16og15vXnCDXlNee + 16nXmdee15XXqiDXqdeU15XXqdec157XlSDXkdek16jXldeZ15nXp9eYICAn + JXtwcm9qZWN0X25hbWV9Jw== + + this_project: !binary | + 16TXqNeV15nXmden15gg15bXlA== + + todos_append: !binary | + 15HXpNeo15XXmdeZ16fXmCDXlteU + + active_projects: !binary | + 16TXqNeV15nXmden15jXmdedINek16LXmdec15nXnQ== + + show_form: !binary | + 15TXldeh16TXqiDXpNeo15XXmdeZ16fXmA== + + with_default_tags: !binary | + 16LXnSDXlNeq15LXmdeV16ogICcle3RhZ3N9JyDXm9eR16jXmdeo16og15TX + nteX15PXnA== + + state: !binary | + 15TXpNeo15XXmdeZ16fXmCDXkdee16bXkSAle3N0YXRlfQ== + + no_last_completed_projects: !binary | + 15zXkCDXoNee16bXkNeVINek16jXldeZ15nXp9eY15nXnSDXqdeU16HXqteZ + 15nXnteV + + edit_project_title: !binary | + 16LXqNeZ15vXqiDXpNeo15XXmdeZ16fXmA== + + list_reviews: !binary | + 157Xodec15XXnNeZ1506Oteh16fXmdeo15Q= + + no_projects: !binary | + 15DXmdefINeb16jXkteiINek16jXldeZ15nXp9eY15nXnQ== + + number: + currency: + format: + delimiter: "," + format: "%u%n " + separator: . + unit: !binary | + 4oKq + + format: + delimiter: "," + separator: . + human: + storage_units: + format: "%u%n" + units: + gb: !binary | + 15In15nXkteU15HXmdeZ15g= + + mb: !binary | + 157XkteUINeR15nXmdeY + + byte: + other: !binary | + 15HXqteZ150= + + one: !binary | + 15HXmdeZ15g= + + tb: !binary | + 15jXqNeUINeR15nXmdeY + + kb: !binary | + 16fXmdec15Ug15HXmdeZ15g= + + support: + select: + prompt: !binary | + 15nXqSDXnNeR16bXoiDXkdeX15nXqNeU + + array: + words_connector: "," + two_words_connector: !binary | + 15Ut + + last_word_connector: !binary | + LCDXlS0= + + notes: + delete_item_title: !binary | + 157Xl9eZ16fXqiDXpNeo15nXmA== + + delete_note_title: !binary | + 157Xl9eZ16fXqiDXlNek16rXpyAnJXtpZH0n + + delete_note_confirm: !binary | + 15TXkNedINec157Xl9eV16cg15DXqiDXlNek16rXpyAgJyV7aWR9Jz8= + + show_note_title: !binary | + 15TXpteS16og16TXqten + + edit_item_title: !binary | + 16LXqNeZ15vXqiDXpNeo15nXmA== + + delete_confirmation: !binary | + 15TXkNedINec157Xl9eV16cg15DXqiDXlNek16rXpyAgJyV7aWR9Jz8= + + note_location_link: !binary | + 15HXqteV15o6 + + note_header: !binary | + 16TXqtenICV7aWR9 + + note_link_title: !binary | + 15TXpteS16og16TXqtenICV7aWR9 + + deleted_note: !binary | + 15TXpNeq16cgJyV7aWR9JyDXoNee15fXpw== + + no_notes_available: !binary | + 15DXmdefINeb16jXkteiINek16rXp9eZ1506INeg15nXqtefINec15TXldeh + 15nXoyDXpNeq16fXmdedINec16TWsNa816jXlda515nWtten1rDXmNeZ150g + 16HXpNem15nXpNeZ15nXnSDXntei157XldeTINeU16TWsNa816jXlda515nW + tten1rDXmA== + + sidebar: + list_name_hidden_contexts: !binary | + 15TXp9ep16jXmdedINee15XXodeq16jXmded + + list_name_active_contexts: !binary | + 15TXp9ep16jXmdedINek16LXmdec15nXnQ== + + list_empty: !binary | + 15DXmdef + + list_name_completed_projects: !binary | + 16TXqNeV15nXmden15jXmdedINep15TXodeq15nXmdee15U= + + list_name_active_projects: !binary | + 16TXqNeV15nXmden15jXmdedINek16LXmdec15nXnQ== + + list_name_hidden_projects: !binary | + 16TXqNeV15nXmden15jXmdedINee15XXodeq16jXmded + + stats: + click_to_return: !binary | + 15TXp9ec16fXlCDXotecICV7bGlua30g16rXl9eW15nXqCDXnNei157XldeT + INeU16HXmNeY15nXodeY15nXp9eU + + running_time_all_legend: + actions: !binary | + 16TXoteV15zXldeq + + percentage: !binary | + 15DXl9eV15Y= + + running_time: !binary | + 15bXntefINee16bXmNeR16gg15zXpNei15XXnNeV16ogKNep15HXldei15XX + qikuINeU16fXnNen15Qg16LXnCDXlNeR16gg15zXnteZ15PXoiDXoNeV16HX + ow== + + totals_hidden_context_count: !binary | + 15UtJXtjb3VudH0g15HXlNen16nXqNeZ150g157Xldeh16rXqNeZ150u + + tod30: !binary | + 15bXntefINeR15nXldedICgzMCDXmdee15nXnSDXkNeX16jXldeg15kp + + open_per_week_legend: + weeks: !binary | + 16nXkdeV16LXldeqINen15XXk9edINec15vXnw== + + actions: !binary | + 16TXoteV15zXldeq + + action_completion_time_title: !binary | + 15bXntefINeh15nXldedICjXm9ecINeU16TXoteV15zXldeqINep15TXodeq + 15nXmdee15Up + + index_title: !binary | + 157Xodec15XXnNeZ1506Oteh15jXmNeZ16HXmNeZ16fXlA== + + top10_projects_30days: !binary | + MTAg16TXqNeV15nXmden15jXmdedINee15XXkdeZ15zXmdedINeRLTMwINeU + 15nXnteZ150g15TXkNeX16jXldeg15nXnQ== + + running_time_legend: + weeks: !binary | + 15bXntefINee16bXmNeR16gg15zXpNei15XXnNeV16ogKNep15HXldei15XX + qikuINeU16fXnNen15Qg16LXnCDXlNeR16gg15zXnteZ15PXoiDXoNeV16HX + ow== + + actions: !binary | + 16TXoteV15zXldeq + + percentage: !binary | + 15DXl9eV15Y= + + action_selection_title: !binary | + 157Xodec15XXnNeZ1506OteR15fXmdeo16og16TXoteV15zXlA== + + running_time_all: !binary | + 15bXntefINee16bXmNeR16gg15zXm9ecINeU16TXoteV15zXldeqINep15zX + kCDXlNeh16rXmdeZ157XlQ== + + actions_avg_completed_30days: !binary | + 15XXlNeh16rXmdeZ157XlSDXkdee157Xldem16IgJXtjb3VudH0g16TXoteV + 15zXldeqINec15nXlded + + time_of_day: !binary | + 15bXntefINeR15nXldedICjXm9ecINeU16TXoteV15zXldeqKQ== + + totals_action_count: !binary | + 16fXmdeZ157XldeqICV7Y291bnR9INek16LXldec15XXqiDXkdeh15og15TX + m9ec + + totals_unique_tags: !binary | + 157XqteV15og16rXkteZ15XXqiDXkNec15UsICV7Y291bnR9INeZ15nXl9eV + 15PXmdeV16ou + + actions_avg_completion_time: !binary | + 157Xm9ecINeU16TXoteV15zXmdeV16og16nXoNeh16rXmdeZ157XldeqINeU + 15bXntefINeU157XnteV16bXoiDXnNeh15nXldedINeU15XXkCAle2NvdW50 + fSDXmdee15nXnQ== + + time_of_day_legend: + time_of_day: !binary | + 15bXntefINeR15nXlded + + number_of_actions: !binary | + 157Xodek16gg16TXoteV15zXldeq + + totals_hidden_project_count: !binary | + JXtjb3VudH0g157Xldeh16rXqNeZ150= + + top5_visible_contexts_with_incomplete_actions: !binary | + NSDXlNeU16fXqdeo15nXnSDXlNee15XXkdeZ15zXmdedINei150g16TXoteV + 15zXldeqINep15zXkCDXlNeh16rXmdeZ157XlQ== + + tag_cloud_description: !binary | + 16LXoNefINeU16rXkteZ15XXqiDXnteb15nXnCDXqteS15nXldeqINec15vX + nCDXlNek16LXldec15XXqiAo15TXodeq15nXmdee15UsINec15Ag15TXodeq + 15nXmdee15UsINeS15zXldeZ15XXqiDXlS/XkNeVINee15XXodeq16jXldeq + KA== + + open_per_week: !binary | + 16TXoteV15zXldeqINeU157XqdeaICjXnteV16bXkteV16og15DXlSDXnteV + 16HXqteo15XXqikg15zXm9ecINep15HXldei + + totals_visible_context_count: !binary | + 157XqteV15og15DXnNeVICV7Y291bnR9INeU16fXqdeo15nXnSDXktec15XX + mdeZ150= + + actions_30days_title: !binary | + 16TXoteV15zXldeqINeRLTMwINeU15nXnteZ150g15TXkNeX16jXldeg15nX + nQ== + + tag_cloud_90days_title: !binary | + 16LXoNefINeq15LXmdeV16og15zXpNei15XXnNeV16og15EtOTAg15TXmdee + 15nXnSDXlNeQ15fXqNeV16DXmded + + totals_context_count: !binary | + 16fXmdeZ157XmdedICV7Y291bnR9INeU16fXqdeo15nXnS4= + + actions_avg_completed: !binary | + 15XXlNeh16rXmdeZ157XlSDXkdee157Xldem16IgJXtjb3VudH0g16TXoteV + 15zXldeqINec15fXldeT16k= + + actions_last_year_legend: + months_ago: !binary | + 15fXldeT16nXmdedINen15XXk9ed + + number_of_actions: !binary | + 157Xodek16gg15TXpNei15XXnNeV16o= + + totals: !binary | + 16HXmdeb15XXnteZ150= + + contexts: !binary | + 15TXp9ep16jXmded + + actions_lastyear_title: !binary | + 16TXoteV15zXldeqINeRLTEyINeU15fXldeT16nXmdedINeU15DXl9eo15XX + oNeZ150= + + actions_selected_from_week: !binary | + 16TXoteV15zXldeqINeg15HXl9eo15XXqiDXntep15HXldei + + tod30_legend: + time_of_day: !binary | + 15bXntefINeR15nXlded + + number_of_actions: !binary | + 157Xodek16gg16TXoteV15zXldeq + + totals_blocked_actions: !binary | + JXtjb3VudH0g16rXnNeV15nXmdedINeR16HXmdeV150g15TXntep15nXnteV + 16og16nXnNeU150= + + totals_actions_completed: !binary | + JXtjb3VudH0g157XlNedINeU16HXqteZ15nXnteV + + actions_dow_30days_legend: + day_of_week: !binary | + 15nXldedINeR16nXkdeV16I= + + number_of_actions: !binary | + 157Xodek16gg16TXoteV15zXldeq + + tag_cloud_title: !binary | + 16LXoNefINeq15LXmdeV16og15zXm9ecINeU16TXoteV15zXldeq + + actions_day_of_week_legend: + day_of_week: !binary | + 15nXldedINeR16nXkdeV16I= + + number_of_actions: !binary | + 157Xodek16gg16TXoteV15zXldeq + + no_actions_selected: !binary | + 15zXkCDXoNeR15fXqNeVINek16LXldec15XXqg== + + totals_tag_count: !binary | + 16fXmdeZ157XmdedICV7Y291bnR9INeq15LXmdeV16og15TXntep15XXmdeZ + 15vXldeqINec16TXoteV15zXldeqLg== + + projects: !binary | + 16TXqNeV15nXmden15jXmded + + totals_incomplete_actions: !binary | + 16fXmdeZ157XldeqICV7Y291bnR9INek16LXldec15XXqiDXqdec15Ag15TX + odeq15nXmdee15U= + + spread_of_actions_for_all_context: !binary | + 16TXmdeW15XXqCDXpNei15XXnNeV16og15zXm9ecINeU15TXp9ep16jXmded + + totals_first_action: !binary | + 157XkNeWINeU16TXoteV15zXlCDXlNeo15DXqdeV16DXlCDXkS0le2RhdGV9 + + no_tags_available: !binary | + 15DXmdefINeq15LXmdeV16og15bXnteZ16DXldeq + + actions: !binary | + 16TXoteV15zXldeq + + tag_cloud_90days_description: !binary | + 16LXoNefINeU16rXkteZ15XXqiDXnteb15nXnCDXqteS15nXldeqINei15HX + ldeoINek16LXldec15XXqiDXqdeg15XXpteo15Ug15DXlSDXlNeh16rXmdeZ + 157XlSDXkS05MCDXlNeZ157XmdedINeU15DXl9eo15XXoNeZ150u + + current_running_time_of_incomplete_visible_actions: !binary | + 15bXntefINee16bXmNeR16gg15zXm9ecINeU16TXoteV15zXldeqINeU15LX + nNeV15nXldeq + + totals_active_project_count: !binary | + 157XqteV15vXnSwgJXtjb3VudH0g15TXnSDXpNeo15XXmdeZ16fXmNeZ150g + 16TXoteZ15zXmded + + other_actions_label: !binary | + KNeQ15fXqNeZ150p + + actions_actions_avg_created_30days: !binary | + 15EtMzAg15TXmdee15nXnSDXlNeQ15fXqNeV16DXmdedINeg15XXpteo15Ug + 15HXntee15XXpteiICV7Y291bnR9INek16LXldec15XXqg== + + click_to_show_actions_from_week: !binary | + 15TXp9ec16fXlCDXotecICV7bGlua30g16rXpteZ15Ig15DXqiDXlNek16LX + ldec15XXqiDXntep15HXldeiICV7d2Vla30g15XXkNeZ15zXmg== + + actions_avg_created: !binary | + 15EtMTIg15TXl9eV15PXqdeZ150g15TXkNeX16jXldeg15nXnSDXmdeV16bX + qNeVINeR157Xldem16IgJXtjb3VudH0g16TXoteV15zXldeq + + labels: + created: !binary | + 16DXldem16jXlQ== + + avg_created: !binary | + 16DXldem16jXlSDXkdee157Xldem16I= + + avg_completed: !binary | + 15TXodeq15nXmdee15Ug15HXntee15XXptei + + completed: !binary | + 15TXodeq15nXmdee15U= + + month_avg_completed: !binary | + JXttb250aHN9INeU16HXqteZ15nXnteVINeR157XnteV16bXoiDXnNeX15XX + k9ep + + month_avg_created: !binary | + JXttb250aHN9INeg15XXpteo15Ug15HXntee15XXpteiINec15fXldeT16k= + + top10_projects: !binary | + MTAg16TXqNeV15nXmden15jXmdedINee15XXkdeZ15zXmded + + more_stats_will_appear: !binary | + 16HXmNeY15nXodeY15nXp9eV16og16DXldeh16TXldeqINeZ15XXpteS15Ug + 15vXkNefINec15DXl9eoINeU15XXodek16og16TXoteV15zXldeqINeg15XX + odek15XXqi4= + + actions_further: !binary | + 15XXkNeZ15zXmg== + + totals_deferred_actions: !binary | + 157XlNefICV7Y291bnR9INek16LXldec15XXqiDXk9eX15XXmdeV16og15HX + nta015bWsNeb1rjWvNeo + + click_to_update_actions: !binary | + 15TXp9ec16fXlCDXotecINeU15HXqCDXkdeS16jXoyDXntei15PXm9eg16og + 15DXqiDXlNek16LXldec15Qg15zXnteY15Q= + + totals_project_count: !binary | + 16fXmdeZ157XmdedICV7Y291bnR9INek16jXldeZ15nXp9eY15nXnS4= + + totals_completed_project_count: !binary | + JXtjb3VudH0g157XlNedINek16jXldeZ15nXp9eY15nXnSDXqdeg16HXqteZ + 15nXnteVLg== + + actions_last_year: !binary | + 16TXoteV15zXldeqINeR16nXoNeZ150g15TXkNeX16jXldeg15XXqg== + + actions_min_max_completion_days: !binary | + 15nXl9ehINeW157XnyDXnteZ15bXoteo15kv157Xmdeo15HXmSDXnNeh15nX + ldedINeU15XXkCAle21pbn0vJXttYXh9Lg== + + actions_min_completion_time: !binary | + 15TXltee158g15TXnteW16LXqNeZINec16HXmdeV150g15TXldeQICV7dGlt + ZX0u + + top5_contexts: !binary | + NSDXlNen16nXqNeZ150g157XldeR15nXnNeZ150= + + legend: + day_of_week: !binary | + 15nXldedINeR16nXkdeV16I= + + actions: !binary | + 16TXoteV15zXldeq + + number_of_days: !binary | + 157Xodek16gg15nXnteZ150g16fXldeT150g15zXm9ef + + percentage: !binary | + 15DXl9eV15Y= + + months_ago: !binary | + 15fXldeT16nXmdedINen15XXk9ed + + running_time: !binary | + 15bXntefINee16bXmNeR16gg15zXpNei15XXnNeUICjXqdeR15XXoteV16op + + number_of_actions: !binary | + 157Xodek16gg16TXoteV15zXldeq + + click_to_return_link: !binary | + 15vXkNef + + actions_day_of_week_title: !binary | + 15nXldedINeR16nXkdeV16IgKNeb15wg15TXpNei15XXnNeV16op + + spread_of_running_actions_for_visible_contexts: !binary | + 16TXmdeW15XXqCDXlNek16LXldec15XXqiDXnNeU16fXqdeo15nXnSDXktec + 15XXmdeZ150= + + tags: !binary | + 16rXkteZ15XXqg== + + top10_longrunning: !binary | + MTAg15TXpNeo15XXmdeZ16fXmNeZ150g16nXqNem15nXnSDXlNeb15kg15TX + qNeR15Qg15bXntef + + actions_dow_30days_title: !binary | + 15nXldedINeR16nXkdeV16IgKDMwINeU15nXnteZ150g15TXkNeX16jXldeg + 15nXnSg= + + footer: + send_feedback: !binary | + 16nXnNeZ15fXqiDXntep15XXkSDXotecINeS15nXqNeh15AgJXt2ZXJzaW9u + fQ== + + time: + formats: + month_day: "%B %d " + default: "%a, %d %b %Y %H:%M:%S %z " + short: "%d %b %H:%M " + long: "%B %d, %Y " + am: !binary | + 15zXpNeg15Qi16Y= + + pm: !binary | + 15DXl9eUItem + + login: + successful_with_session_info: !binary | + 15vXoNeZ16HXlCDXnteV16bXnNeX16o6 + + cas_logged_in_greeting: !binary | + 16nXnNeV150gJXt1c2VybmFtZX0hINeU15bXmdeU15XXmSDXlNem15zXmdeX + + cas_signup_link: !binary | + 15HXp9ep16og157Xqdeq157XqQ== + + option_separator: !binary | + 15DXlSw= + + session_time_out: !binary | + 16TXkiDXqteV16fXoyDXlNeS15nXqdeULiDXoNeQICV7bGlua30= + + login_standard: !binary | + 15fXlteo15Qg15zXm9eg15nXodeUINeU16jXkteZ15zXlA== + + unsuccessful: !binary | + 15vXoNeZ16HXlCDXoNeb16nXnNeULg== + + please_login: !binary | + 15nXqSDXnNeU15vXoNehINeb15PXmSDXnNeU16nXqtee16kg15Et157Xodec + 15XXnNeZ150= + + session_will_not_expire: !binary | + 15TXkteZ16nXlCDXnNec15Ag16rXpNeV15LXlC4= + + openid_identity_url_not_found: !binary | + 15zXptei16jXoNeVLCDXnNeQINen15nXmdedINee16nXqtee16kg16LXnSDX + m9eq15XXkdeqINeW15TXldeqICAoJXtpZGVudGl0eV91cmx9KQ== + + user_no_expiry: !binary | + 15TXqdeQ16jXqiDXl9eZ15HXldeo + + cas_no_user_found: !binary | + JXt1c2VybmFtZX0g16nXnNeV150hINeQ15nXnyDXl9ep15HXldefINeR16nX + nSDXlteUINeR157Xodec15XXnNeZ150u + + logged_out: !binary | + 15HXldem16LXlCDXmdem15nXkNeUINeeLdee16HXnNeV15zXmded + + login_cas: !binary | + 15TXktei15Qg15DXnCDXqdeQItee + + session_will_expire: !binary | + 16rXlden16Mg15TXkteZ16nXlCDXmdek15XXkiDXnNeQ15fXqCAle2hvdXJz + fSDXqdei15Qo15XXqikg16nXnCDXl9eV16HXqCDXpNei15nXnNeV16ou + + login_with_openid: !binary | + 15vXoNeZ16HXlCDXotecIE9wZW5JRA== + + account_login: !binary | + 15vXoNeZ16HXlCDXnNeX16nXkdeV158= + + cas_login: !binary | + 15TXqteX15HXqNeV16og16nXkCLXniAo16nXmdeo15XXqiDXkNeZ157Xldeq + INee16jXm9eW15kp + + cas_create_account: !binary | + 15DXnSDXkdeo16bXldeg15og15zXkden16kg15nXqSDXnNeU157XqdeZ15og + 15wtJXtzaWdudXBfbGlua30= + + successful: !binary | + 15vXoNeZ16HXlCDXkdeV16bXoteUINeR15TXptec15fXlC4g15HXqNeV15og + 16nXldeR15oh + + sign_in: !binary | + 15vXoNeZ16HXlA== + + cas_username_not_found: !binary | + 15zXptei16jXoNeVLCDXnNeQINen15nXmdedINee16nXqtee16kg16nXkCLX + niDXkdep150gKCV7dXNlcm5hbWV9KQ== + + mobile_use_openid: !binary | + Li4u15DXlSDXm9eg15nXodeUINei150gT3BlbklE + + log_in_again: !binary | + 15vXoNeZ16HXlCDXnteX15XXk9ep16o= + + feedlist: + context_centric_actions: !binary | + 15TXlteg15XXqiDXoteR15XXqCDXpNei15XXnNeV16og16nXnNeQINeg16HX + qteZ15nXnteVINeR15TXp9ep16gg16DXqteV158= + + all_projects: !binary | + 15vXnCDXlNek16jXldeZ15nXp9eY15nXnQ== + + projects_and_actions: !binary | + 16TXqNeV15XXmden15jXmdedINek16LXmdec15nXnSDXldeU16TXoteV15zX + ldeqINep15zXlNed + + context_needed: !binary | + 16bXqNeZ15og15zXlNeZ15XXqiDXnNek15fXldeqINeU16fXqdeoINeQ15fX + kyDXnNek16DXmSDXqdeg15nXqtefINec15HXp9ep16gg15TXlteg15Q= + + actions_due_next_week: !binary | + 16TXoteV15zXldeqINep15nXqSDXnNeR16bXoiDXkdep15HXoteqINeU15nX + nteZ150g15TXp9eo15XXkdeZ150= + + choose_project: !binary | + 15HXl9eZ16jXqiDXlNek16jXldeZ15nXp9eYINei15HXldeo15Ug15PXqNeV + 16nXlCDXlNeW16DXlA== + + ical_feed: !binary | + 15TXlteg16ogaUNhbA== + + all_contexts: !binary | + 15vXnCDXlNeU16fXqdeo15nXnQ== + + active_projects_wo_next: !binary | + 16TXqNeV15nXmden15jXmdedINek16LXmdec15nXnSDXnNec15Ag16TXoteV + 15zXldeqINeU157Xqdea + + active_starred_actions: !binary | + 15vXnCDXlNek16LXldec15XXqiDXlNek16LXmdec15XXqiDXldeU157Xk9eS + 16nXldeq + + notice_incomplete_only: !binary | + 15TXoteo15Q6INeb15wg15TXlNeW16DXldeqINee16bXmdeS15XXqiDXkNeq + INeb15wg15TXpNei15XXnNeV16og16nXnNeQINeh15XXnteg15Ug15vXnteR + 15XXptei15XXqiDXkNec15Ag15DXnSDXm9efINeg15HXl9eoINeR157XpNeV + 16jXqSDXkNeX16jXqi4= + + legend: !binary | + 157Xp9eo15A6 + + project_needed: !binary | + 15PXqNeV16kg15zXpNeX15XXqiDXpNeo15XXmdeZ16fXmCDXkNeX15Mg15zX + pNeg15kg16nXoNeZ16rXnyDXnNeR16fXqSDXlNeW16DXlA== + + project_centric: !binary | + 15TXlteg15XXqiDXoteR15XXqCDXpNei15XXnNeV16og16nXnNeQINeU16HX + qteZ15nXnteVINeR16TXqNeV15nXmden15gg157XodeV15nXmded + + actions_due_today: !binary | + 16TXoteV15zXldeqINec15HXmdem15XXoiDXlNeZ15XXnSDXkNeVINee15XX + p9eT150g15nXldeq16g= + + plain_text_feed: !binary | + 15TXlteg16og15jXp9eh15gg16TXqdeV15g= + + select_feed_for_project: !binary | + 15HXl9eZ16jXqiDXlNeU15bXoNeUINei15HXldeoINeU16TXqNeV15nXmden + 15g= + + actions_completed_last_week: !binary | + 16TXoteV15zXldeqINep15TXodeq15nXmdee15Ug15HXqdeR16LXqiDXlNeZ + 157XmdedINeU15DXl9eo15XXoNeZ150= + + rss_feed: !binary | + 15TXlteg16og16jXodeh + + last_fixed_number: !binary | + JXtudW1iZXJ9INek16LXldec15XXqiDXkNeX16jXldeg15XXqg== + + choose_context: !binary | + 15HXl9eZ16jXqiDXlNeU16fXqdeoINei15HXldeo15Ug15PXqNeV16nXlCDX + lNeW16DXlA== + + select_feed_for_context: !binary | + 15HXl9eZ16jXqiDXlNeU15bXoNeUINei15HXldeoINeU15TXp9ep16gg15TX + oNeq15XXnw== + + all_actions: !binary | + 15vXnCDXlNek16LXldec15XXqg== + + contexts: + no_contexts_active: !binary | + 15DXmdefINeb16jXkteiINeU16fXqdeo15nXnSDXpNei15nXnNeZ150= + + last_completed_in_context: !binary | + 15HXlNen16nXqCDXlteUICAo15DXl9eo15XXoNeV16ogJXtudW1iZXJ9KQ== + + delete_context_confirmation: !binary | + 15TXkNedINec157Xl9eV16cg15DXqiDXlNeU16fXqdeoICAnJXtuYW1lfSc/ + INeZ16kg15zXlNeW15TXqCDXntek16DXmSDXqdek16LXldec15Qg15bXlSDX + nteq15fXldenINeQ16og15vXnCDXlNek16LXldec15XXqiDXlNee15fXlteV + 16jXmdeV16og15HXlNen16nXqCDXlteU + + delete_context: !binary | + 157Xl9enINeU16fXqdeo + + status_active: !binary | + 15TXlNen16nXqCDXpNei15nXnA== + + save_status_message: !binary | + 15TXp9ep16gg16DXqdee16g= + + context_deleted: !binary | + 16DXnteX16cg15TXp9ep16ggJyV7bmFtZX0n + + edit_context: !binary | + 16LXqNeZ15vXqiDXlNen16nXqA== + + delete_context_title: !binary | + 157Xl9eZ16fXqiDXlNen16nXqA== + + hide_form_title: !binary | + 15TXodeq16jXqiDXmNeV16TXoSDXlNen16nXqCDXl9eT16k= + + add_context: !binary | + 15TXldeh16TXqiDXlNen16nXqA== + + status_hidden: !binary | + 15TXlNen16nXqCDXnteV16HXqteo + + context_name: !binary | + 16nXnSDXlNen16nXqA== + + new_context_post: !binary | + JyDXmdeV15XXpteo15Ug15HXoNeV16HXoy4g15TXkNedINec15TXntep15nX + mj8= + + no_contexts_hidden: !binary | + 15DXmdefINeb16jXkteiINeU16fXqdeo15nXnSDXnteV16HXqteo15nXnQ== + + new_context_pre: !binary | + 15TXp9ep16gg15fXk9epICc= + + completed_tasks_title: !binary | + 157Xodec15XXnNeZ1506Otek16LXldec15XXqiDXqdeR15XXptei15Ug15HX + ntec15XXkNefINeR15TXp9ep16ggICcle2NvbnRleHRfbmFtZX0n + + update_status_message: !binary | + 16nXldeg15Qg16nXnSDXlNeU16fXqdeo + + show_form_title: !binary | + 15TXldeh16TXqiDXlNen16nXqA== + + hide_form: !binary | + 15TXodeq16jXqiDXmNeV16TXoQ== + + context_hide: !binary | + 15TXodeq16jXlCDXntei157XldeTINeU15HXmdeqPw== + + visible_contexts: !binary | + 15TXp9ep16jXmdedINeS15zXldeZ15nXnQ== + + hidden_contexts: !binary | + 15TXp9ep16jXmdedINee15XXodeq16jXmded + + all_completed_tasks_title: !binary | + 157Xodec15XXnNeZ1506Oteb15wg15TXpNei15XXnNeV16og16nXkdeV16bX + oteVINeR157XnNeV15DXnyDXkdeU16fXqdeoICAnJXtjb250ZXh0X25hbWV9 + Jw== + + no_actions: !binary | + 15DXmdefINeb16jXkteiINek16LXldec15XXqiDXqdec15Ag15TXldep15zX + nteVINeR15TXp9ep16gg15TXoNeV15vXl9eZ + + todos_append: !binary | + 15HXlNen16nXqCDXlteU + + show_form: !binary | + 15nXpteZ16jXqiDXlNen16nXqCDXl9eT16k= + + shared: + toggle_single: !binary | + 15TXldeh16TXqiDXpNei15XXnNeqINeU157Xqdea + + project_for_all_actions: !binary | + 16TXqNeV15nXmden15gg15zXm9ecINeU16TXoteV15zXldeq + + hide_action_form_title: !binary | + 15TXodeq16jXqiDXmNeV16TXoSDXpNei15XXnNeV16og15fXk9ep15XXqg== + + make_actions_dependent: !binary | + 15nXpteZ16jXqiDXqtec15XXqiDXkdeZ158g16TXoteV15zXldeq + + add_action: !binary | + 15TXldeh16TXqiDXpNei15XXnNeU + + toggle_multi: !binary | + 15TXldeh16TXqiDXpNei15XXnNeV16og15TXntep15og157XqNeV15HXldeq + + toggle_multi_title: !binary | + 15jXldek16Eg16nXmdeg15XXmSDXntem15Eg16TXoteV15zXlCDXkdeV15PX + k9eqIC8g16TXoteV15zXldeqINee16jXldeR15XXqg== + + hide_form: !binary | + 15TXodeq16jXqiDXmNeV16TXoQ== + + multiple_next_actions: !binary | + 16TXoteV15zXldeqINeU157XqdeaINee16jXldeR15XXqiAo16TXoteV15zX + lCDXkNeX16og15HXqdeV16jXlCk= + + tags_for_all_actions: !binary | + 16rXkteZ15XXqiDXnNeb15wg15TXpNei15XXnNeV16ogKNeZ16kg15zXlNek + 16jXmdeTINeR16TXodeZ16fXmdedKQ== + + context_for_all_actions: !binary | + 15TXp9ep16gg15zXm9ecINeU16TXoteV15zXldeq + + toggle_single_title: !binary | + 15TXldeh16TXqiDXpNei15XXnNeqINeU157XqdeaINeX15PXqdeU + + separate_tags_with_commas: !binary | + 157Xldek16jXkyDXkdek16HXmden15nXnQ== + + add_actions: !binary | + 15TXldeh16TXqiDXpNei15XXnNeU + + preferences: + change_identity_url: !binary | + 16nXmdeg15XXmSDXm9eq15XXkdeqIFVSTCDXlNeW15PXlNeV16o= + + page_title_edit: !binary | + 157Xodec15XXnNeZ1506Otei16jXmdeb16og15TXoteT16TXldeq + + sms_context_none: !binary | + 15zXnNeQ + + current_authentication_type: !binary | + 16nXmdeY16og15TXlteZ15TXldeZINep15zXmSDXlNeZ15AgJXthdXRoX3R5 + cGV9 + + page_title: !binary | + 157Xodec15XXnNeZ1506OteU16LXk9ek15XXqg== + + open_id_url: !binary | + 15vXqteV15HXqiDXlteZ15TXldeZIE9wZW5JRCDXqdec15og15TXmdeQ + + change_password: !binary | + 16HXmdeg15XXmSDXodeZ16HXnteQ + + edit_preferences: !binary | + 16LXqNeZ15vXqiDXlNei15PXpNeV16o= + + show_number_completed: !binary | + 15TXpteSICV7bnVtYmVyfSDXpNeo15nXmNeZ150g16nXlNeh16rXmdeZ157X + lQ== + + updated: !binary | + 15TXoteT16TXldeqINei15XXk9eb16DXlQ== + + token_description: !binary | + 15DXodeZ157XldefICjXntep157XqSDXnNeU15bXoNeV16og15nXqdeZ157X + ldepINee157XqdenINeq15vXqteg15XXqik= + + is_true: !binary | + 15fXmdeV15HXmQ== + + password_changed: !binary | + 15TXodeZ16HXnteQINep15XXoNeq15QsINeZ16kg15zXlNeZ15vXoNehINep + 16DXmdeqLg== + + generate_new_token_confirm: !binary | + 15HXmNeV15c/INeZ16bXmdeo16og15DXodeZ157XldefINeX15PXqSDXqteX + 15zXmdejINeQ16og15TXkNeh15nXnteV158g15TXp9eZ15nXnSDXldeq15HX + mNecINeQ16og15TXqdeZ157XldepINeR15Uu + + authentication_header: !binary | + 15TXlteZ15TXldeZINep15zXmQ== + + generate_new_token: !binary | + 15nXpteZ16jXqiDXkNeh15nXnteV158g15fXk9ep + + staleness_starts_after: !binary | + 16rXpNec15XXqiDXnteq15fXmdec15Qg15zXkNeX16ggJXtkYXlzfSDXmdee + 15nXnQ== + + title: !binary | + 15TXlNeS15PXqNeV16og16nXnNeZ + + tabs: + authentication: !binary | + 15DXmdee15XXqg== + + profile: !binary | + 16TXqNeV16TXmdec + + tracks_behavior: !binary | + 15TXqteg15TXkteV16og157Xodec15XXnNeZ150= + + date_and_time: !binary | + 16rXkNeo15nXmiDXldep16LXlA== + + change_authentication_type: !binary | + 16nXmdeg15XXmSDXodeV15Ig15TXlteT15TXldeq + + is_false: !binary | + 16nXnNeZ15zXmQ== + + token_header: !binary | + 15TXkNeh15nXnteV158g16nXnNeZ + diff --git a/config/locales/nl.yml b/config/locales/nl.yml index e8823318..1f2308dc 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -1,91 +1,35 @@ ---- -nl: - common: - back: Terug - recurring_todos: Herhalende acties - actions: Acties - third: Derde - add: Toevoegen - previous: Vorige - go_back: Ga terug - logout: Log uit - second: Tweede - actions_midsentence: acties - optional: optioneel - week: week - none: Geen - show_all: Toon alle - cancel: Annuleer - month: maand - server_error: Een fout heeft op de server plaatsgevonden - notes: Notities - forum: Forum - last: Laatste - review: Evaluatie - projects: Projecten - action: Actie - project: Project - contribute: Bijdragen - ok: Ok - first: Eerste - website: Website - numbered_step: Stap %{number} - sort: - by_task_count_title: Sorteer op aantal acties - by_task_count_title_confirm: Weet u zeker dat u deze op aantal acties wilt sorteren? Dat zal de huidige sorteervolgorde aanpassen. - alphabetically: Alfabetisch - sort: Sorteer - alphabetically_confirm: Weet u zeker dat u deze projecten alfabetisch wilt sorteren? Dat zal de huidige sorteervolgorde aanpassen. - alphabetically_title: Sorteer projecten alfabetisch - by_task_count: Op aantal acties - drag_handle: SLEEP - create: Maken - months: maanden - description: Beschrijving - fourth: Vierde - next: Volgende - contexts: Contexten - todo: actie - context: Context - errors_with_fields: Er waren problemen met de volgende velden - update: Bijwerken - weeks: weken - forth: Vierde - wiki: Wiki - bugs: Fouten - ajaxError: Er is een fout opgetreden bij het ophalen van gegevens van de server - email: E-mail - search: Zoeken - number: - format: +--- +nl: + number: + format: separator: "," delimiter: . - human: - storage_units: + human: + storage_units: format: "%n %u" - units: + units: kb: KB tb: TB gb: GB - byte: + byte: one: Byte other: Bytes mb: MB - currency: - format: + currency: + format: format: "%u %n" unit: !binary | 4oKs separator: "," delimiter: . - layouts: + layouts: toggle_contexts_title: Maak ingeklapte contexten (on)zichtbaar toggle_notes: Toggle notities toggle_contexts: Toggle ingeklapte contexten next_actions_rss_feed: RSS-feed van de acties toggle_notes_title: Toggle alle notities - mobile_navigation: + mobile_navigation: new_action: Nieuwe actie logout: Afmelden feeds: Feeds @@ -94,10 +38,11 @@ nl: tickler: Tickler contexts: Contexten home: Start - navigation: + navigation: manage_users_title: Toevoegen of verwijderen gebruikers - recurring_todos: Terugkerende acties api_docs: REST API Docs + recurring_todos: Terugkerende acties + help: "?" feeds: Feeds stats: Statistieken starred: Ster @@ -107,79 +52,141 @@ nl: integrations_: Integreer Tracks export_title: Import en export van gegevens preferences: Voorkeuren - feeds_title: Zie een lijst met beschikbare feeds + admin: Admin calendar_title: Kalender met acties met deadline - recurring_todos_title: Beheren terugkerende acties - tickler: Tickler + feeds_title: Zie een lijst met beschikbare feeds completed_tasks: Gereed + tickler: Tickler stats_title: Zie je statistieken home_title: Start starred_title: Zie je ster acties + recurring_todos_title: Beheren terugkerende acties view: Bekijk organize: Organiseer completed_tasks_title: Afgerond home: Start contexts_title: Contexten export: Export - projects_title: Projecten - search: Zoeken in alle items preferences_title: Toon mijn voorkeuren review_title: Evaluatie uitvoeren + search: Zoeken in alle items + projects_title: Projecten calendar: Agenda - integrations: + integrations: opensearch_description: Zoek in Tracks - gmail_description: Gadget om Tracks toe te voegen aan Gmail als een gadget applescript_next_action_prompt: "Omschrijving van de actie:" + gmail_description: Gadget om Tracks toe te voegen aan Gmail als een gadget applescript_success_after_id: gemaakt applescript_success_before_id: Nieuwe actie met ID - activerecord: - attributes: - project: + common: + back: Terug + recurring_todos: Herhalende acties + actions: Acties + third: Derde + add: Toevoegen + previous: Vorige + go_back: Ga terug + logout: Log uit + second: Tweede + show_all: Toon alle + none: Geen + week: week + optional: optioneel + cancel: Annuleer + month: maand + actions_midsentence: acties + server_error: Een fout heeft op de server plaatsgevonden + forum: Forum + notes: Notities + last: Laatste + projects: Projecten + review: Evaluatie + action: Actie + project: Project + days_midsentence: dagen + contribute: Bijdragen + ok: Ok + website: Website + first: Eerste + numbered_step: Stap %{number} + errors_with_fields: Er waren problemen met de volgende velden + create: Maken + sort: + by_task_count_title: Sorteer op aantal acties + by_task_count_title_confirm: Weet u zeker dat u deze op aantal acties wilt sorteren? Dat zal de huidige sorteervolgorde aanpassen. + alphabetically: Alfabetisch + alphabetically_title: Sorteer projecten alfabetisch + sort: Sorteer + alphabetically_confirm: Weet u zeker dat u deze projecten alfabetisch wilt sorteren? Dat zal de huidige sorteervolgorde aanpassen. + by_task_count: Op aantal acties + months: maanden + description: Beschrijving + next: Volgende + fourth: Vierde + context: Context + todo: actie + contexts: Contexten + drag_handle: SLEEP + update: Bijwerken + forth: Vierde + weeks: weken + wiki: Wiki + bugs: Fouten + ajaxError: Er is een fout opgetreden bij het ophalen van gegevens van de server + email: E-mail + search: Zoeken + activerecord: + attributes: + project: name: Naam default_tags: Standaard Tags default_context_name: Standaard context description: Beschrijving - todo: + note: + created_at: Gemaakt op + updated_at: Bijgewerkt op + todo: show_from: Tonen vanaf predecessors: Afhankelijkheden notes: Notities project: Project + tags: Labels description: Beschrijving context: Context due: Deadline - user: + user: last_name: Achternaam first_name: Voornaam - preference: + preference: show_hidden_projects_in_sidebar: Toon verborgen projecten in sidebar date_format: Datum formaat show_hidden_contexts_in_sidebar: Toon verborgen contexten in sidebar - verbose_action_descriptors: Context en project uitschrijven in actielijst - mobile_todos_per_page: Acties per pagina (mobiel) staleness_starts: Begin van markeren openstaande actie sms_context: Standaard context voor email - show_number_completed: Aantal te tonen afgeronde acties + verbose_action_descriptors: Context en project uitschrijven in actielijst + mobile_todos_per_page: Acties per pagina (mobiel) title_date_format: Datum formaat in titel + show_number_completed: Aantal te tonen afgeronde acties refresh: Ververs interval (in minuten) week_starts: Week start op last_name: Achternaam + due_style: Deadline stijl locale: Taal time_zone: Tijdzone - due_style: Deadline stijl - sms_email: Van email show_project_on_todo_done: Ga naar project pagina wanneer actie gereed is + sms_email: Van email show_completed_projects_in_sidebar: Toon afgeronde projecten in sidebar first_name: Voornaam review_period: Project evaluatie interval - errors: - models: - project: - attributes: - name: + errors: + models: + project: + attributes: + name: blank: project moet een naam hebben too_long: project naam moet minder dan 256 karakters hebben taken: bestaat al - messages: + messages: record_invalid: "Validatie mislukt: %{errors}" greater_than_or_equal_to: moet groter of gelijk zijn aan %{count} confirmation: komt niet overeen met de configuratie @@ -200,58 +207,57 @@ nl: taken: is al gepakt inclusion: is niet opgenomen in de lijst not_a_number: is niet een getal - template: + full_messages: + format: "%{attribute} %{message}" + template: body: Er waren problemen met de volgende velden - header: + header: one: 1 fout voorkomt het kunnen bewaren van deze %{model} other: "%{count} fouten voorkomen dat dit %{model} bewaard kan worden" - full_messages: - format: "%{attribute} %{message}" - data: + data: import_successful: De import was succesvol import_errors: Er hebben zich fouten voorgedaan bij de import - models: - project: + models: + project: feed_title: Tracks Projecten feed_description: Een overzicht van alle projecten voor %{username} - todo: + todo: error_date_must_be_future: moet een datum in de toekomst zijn - user: + user: error_context_not_associated: Context %{context} niet geassocieerd met gebruikers %{user}. error_project_not_associated: Project %{project} niet geassocieerd met gebruikers %{user}. - preference: + preference: due_on: Deadline op %{date} due_in: Deadline over %{days} dagen - due_styles: + due_styles: - Deadline over ____ dagen - Deadline op ____ - stats: - tag_cloud_title: Tag Cloud voor alle acties + stats: totals_hidden_context_count: en %{count} zijn verborgen contexten. actions_avg_created: In de afgelopen 12 maanden heeft u gemiddeld%{count} acties aangemaakt actions_min_max_completion_days: De max-/minimum dagen tot voltooiing is %{min}/%{max}. totals_actions_completed: "%{count} van deze zijn voltooid." + tag_cloud_title: Tag Cloud voor alle acties + top5_visible_contexts_with_incomplete_actions: Top 5 zichtbare contexten met onvolledige acties actions_actions_avg_created_30days: In de afgelopen 30 dagen heeft u gemiddeld %{count} acties gemaakt actions_avg_completed: en voltooide een gemiddelde van %{count} acties per maand. - top5_visible_contexts_with_incomplete_actions: Top 5 zichtbare contexten met onvolledige acties actions: Acties - time_of_day_legend: + time_of_day_legend: number_of_actions: Aantal acties time_of_day: Tijd van de dag totals_incomplete_actions: U heeft %{count} onvolledige acties totals_action_count: u heeft een totaal van %{count} acties - running_time_legend: + totals_deferred_actions: waarvan %{count} uitgestelde acties in de tickler zijn + running_time_legend: actions: Acties percentage: Percentage weeks: Looptijd van een actie (weken). Klik op een balk voor meer info - totals_deferred_actions: waarvan %{count} uitgestelde acties in de tickler zijn tag_cloud_90days_title: Tag cloud met acties in afgelopen 90 dagen tod30: Tijd van de dag (laatste 30 dagen) tags: Tags projects: Projecten actions_avg_completion_time: Van al uw afgeronde acties, de gemiddelde tijd dat dit in beslag nam is %{count} dagen. - actions_day_of_week_title: Dag van de week (alle acties) - labels: + labels: month_avg_completed: "%{months} gem afgerond per maand" completed: Afgerond month_avg_created: "%{months} gem gemaakt per maand" @@ -260,11 +266,13 @@ nl: created: Gemaakt totals_completed_project_count: en %{count} zijn afgeronde projecten. actions_selected_from_week: Gekozen acties van week + actions_day_of_week_title: Dag van de week (alle acties) actions_lastyear_title: Acties in de afgelopen 12 maanden open_per_week: Active (zichtbare en verborgen) volgende acties per week action_selection_title: "TRACKS:: Actie selectie" totals_project_count: U heeft %{count} projecten. - legend: + current_running_time_of_incomplete_visible_actions: Huidige looptijd van onvolledige zichtbare acties + legend: number_of_days: Aantal dagen geleden actions: Acties number_of_actions: Aantal acties @@ -272,34 +280,33 @@ nl: running_time: Looptijd van een actie (weken) percentage: Percentage months_ago: Maanden geleden - current_running_time_of_incomplete_visible_actions: Huidige looptijd van onvolledige zichtbare acties - tod30_legend: + tod30_legend: number_of_actions: Aantal acties time_of_day: Tijd van de dag totals_context_count: U heeft %{count} contexten. - open_per_week_legend: + open_per_week_legend: actions: Acties weeks: Weken geleden - actions_last_year_legend: + actions_last_year_legend: number_of_actions: Aantal acties months_ago: Maanden geleden top10_projects: Top 10 projecten top5_contexts: Top 5 contexten - totals: Totalen contexts: Contexten + totals: Totalen click_to_return: Klik %{link} om terug te keren naar de statistieken pagina. tag_cloud_90days_description: Deze tag cloud bevat tags van acties die zijn gemaakt of voltooid in de afgelopen 90 dagen. totals_visible_context_count: Van deze zijn %{count} zichtbare contexten - running_time_all: Huidige looptijd van alle onvolledige acties top10_projects_30days: Top 10 project in de laatste 30 dagen + running_time_all: Huidige looptijd van alle onvolledige acties actions_min_completion_time: De minimale tijd tot afronding is %{time}. action_completion_time_title: Doorlooptijd (alle voltooide acties) click_to_show_actions_from_week: Klik %{link} om de acties van week %{week} en verder te zien. top10_longrunning: Top 10 langstlopende projecten no_actions_selected: Er zijn geen acties geselecteerd. - actions_further: en verder totals_tag_count: U heeft %{count} tags geplaatst op acties. - actions_dow_30days_legend: + actions_further: en verder + actions_dow_30days_legend: number_of_actions: Aantal acties day_of_week: Dag van de week totals_first_action: Sinds uw eerste actie op %{date} @@ -309,36 +316,36 @@ nl: spread_of_actions_for_all_context: Verdeling van acties voor alle contexten more_stats_will_appear: Meer statistieken zullen hier verschijnen zodra u acties hebt toegevoegd. actions_avg_completed_30days: en voltooide een gemiddelde van %{count} acties per dag. - actions_dow_30days_title: Dag van de week (laatste 30 dagen) actions_30days_title: Acties in de afgelopen 30 dagen no_tags_available: geen tags beschikbaar index_title: TRACKS::Statistiek - actions_day_of_week_legend: + actions_dow_30days_title: Dag van de week (laatste 30 dagen) + actions_day_of_week_legend: number_of_actions: Aantal acties day_of_week: Dag van de week spread_of_running_actions_for_visible_contexts: Verdeling van actieve acties voor zichtbare contexten - totals_blocked_actions: "%{count} zijn afhankelijk van de voltooiing van hun acties." - actions_last_year: Acties in de afgelopen jaren - totals_unique_tags: Van deze tags zijn %{count} uniek. totals_active_project_count: Van deze zijn %{count} actieve projecten - running_time_all_legend: + actions_last_year: Acties in de afgelopen jaren + totals_blocked_actions: "%{count} zijn afhankelijk van de voltooiing van hun acties." + totals_unique_tags: Van deze tags zijn %{count} uniek. + running_time_all_legend: actions: Acties running_time: Looptijd van een actie (weken). Klik op een balk voor meer info percentage: Percentage other_actions_label: (anderen) totals_hidden_project_count: "%{count} zijn verborgen" time_of_day: Tijd van de dag (alle acties) - todos: - show_from: Toon vanaf + todos: error_starring_recurring: Kon niet de ster van deze terugkerende actie niet omzetten \'%{description}\' + show_from: Toon vanaf recurring_action_deleted: Actie werd verwijderd. Omdat deze actie herhalend is. werd een nieuwe actie toegevoegd completed_actions: Voltooide acties - completed_rest_of_previous_month: Afgerond in de rest van de vorige maand + blocked_by: Geblokkeerd door %{predecessors} completed_recurring: Afgesloten terugkerende todos added_new_next_action: Nieuwe actie toegevoegd - blocked_by: Geblokkeerd door %{predecessors} - completed_recurrence_completed: Er is geen actie na de terugkerende actie die u new verwijderd heeft. De herhaling is voltooid + completed_rest_of_previous_month: Afgerond in de rest van de vorige maand star_action: Markeer deze actie met een ster + completed_recurrence_completed: Er is geen actie na de terugkerende actie die u new verwijderd heeft. De herhaling is voltooid defer_date_after_due_date: Uitsteldatum is na de vervaldag. Gelieve vervaldag bewerken alvorens uitsteldatum aan te passen. unable_to_add_dependency: Niet in staat om de afhankelijkheid toe te voegen done: Voltooid? @@ -346,17 +353,17 @@ nl: tagged_with: gelabeld met ‘%{tag_name}’ completed: Afgerond no_deferred_actions_with: Geen uitgestelde acties met de tag '%{tag_name}' - edit_action_with_description: Bewerk de actie '%{description}' no_hidden_actions: Momenteel zijn er geen verborgen acties gevonden action_due_on: (deadline actie op %{date}) - archived_tasks_title: "TRACKS:: Gearchiveerde voltooide taken" + edit_action_with_description: Bewerk de actie '%{description}' remove_dependency: Verwijder afhankelijkheid (zal niet de actie zelf verwijderen) + archived_tasks_title: "TRACKS:: Gearchiveerde voltooide taken" list_incomplete_next_actions: Toon onvoltooide acties tags: Tags (gescheiden door komma's) action_deleted_success: Actie succesvol verwijderd + add_another_dependency: Nog een afhankelijkheid toevoegen new_related_todo_created: Een nieuwe actie is toegevoegd, die behoort bij deze terugkerende todo context_changed: Context veranderd in '%{name}' - add_another_dependency: Nog een afhankelijkheid toevoegen mobile_todos_page_title: Alle acties delete_recurring_action_title: Verwijder de terugkerende actie removed_predecessor: "'%{successor}' is verwijderd als afhankelijkheid van '%{predecessor}'." @@ -368,127 +375,128 @@ nl: edit_action: Actie bewerken added_new_context: Nieuwe context toegevoegd next_actions_description: "Filter:" + older_completed_items: Oudere voltooide items list_incomplete_next_actions_with_limit: Toont de laatste %{count} onvoltooide acties set_to_pending: "'%{task}' als wachtend ingesteld" added_new_project: Nieuw project toegevoegd - next_actions_title_additions: + next_actions_title_additions: completed: acties voltooid due_today: deadline vandaag due_within_a_week: deadline binnen een week - older_completed_items: Oudere voltooide items - error_deleting_item: Er is een fout opgetreden bij het verwijderen van het item '%{description}' + task_list_title: TRACKS::Toon acties edit_recurring_todo: Bewerk herhalende actie append_in_this_project: in dit project - task_list_title: TRACKS::Toon acties + error_deleting_item: Er is een fout opgetreden bij het verwijderen van het item '%{description}' no_actions_due_this_week: Geen acties met deadline in rest van deze week - no_deferred_pending_actions: Momenteel zijn er geen uitgestelde of wachtende acties no_recurring_todos: Momenteel zijn er geen terugkerende acties error_completing_todo: Er was een fout bij het voltooien / activeren van de terugkerende actie '%{description}' recurring_pattern_removed: Het herhalingspatroon is verwijderd van %{count} convert_to_project: Maak project + no_deferred_pending_actions: Momenteel zijn er geen uitgestelde of wachtende acties delete_recurring_action_confirm: Weet u zeker dat u wilt de terugkerende actie '%{description}' wilt verwijderen? completed_last_day: Voltooid in de laatste 24 uur + all_completed: Alle afgeronde acties + error_saving_recurring: Er is een fout opgetreden het opslaan van de terugkerende actie '%{description}' show_in_days: Toon over %{days} dagen no_project: -- Geen project -- - error_saving_recurring: Er is een fout opgetreden het opslaan van de terugkerende actie '%{description}' completed_more_than_x_days_ago: Voltooid meer dan %{count} dagen geleden - new_related_todo_created_short: een nieuwe actie gemaakt feed_title_in_context: in context '%{context}' - all_completed: Alle afgeronde acties + new_related_todo_created_short: een nieuwe actie gemaakt edit: Bewerken - older_than_days: Ouder dan %{count} dagen completed_tagged_page_title: "TRACKS:: Afgeronde acties met tag %{tag_name}" + older_than_days: Ouder dan %{count} dagen pending: Wachtend completed_actions_with: Afgeronde acties met de tag %{tag_name} - feed_title_in_project: In het project '%{project}' - deleted_success: De actie werd met succes verwijderd. completed_tasks_title: TRACKS::Voltooide taken + deleted_success: De actie werd met succes verwijderd. + feed_title_in_project: In het project '%{project}' clear_due_date: Maak deadline leeg error_removing_dependency: Er is een fout opgetreden het verwijderen van de afhankelijke actie hidden_actions: Verborgen acties - deferred_actions_with: Uitgestelde acties met de tag '%{tag_name}' was_due_on_date: had deadline op %{date} show_on_date: Toon op %{date} recurrence_period: Herhaling periode + deferred_actions_with: Uitgestelde acties met de tag '%{tag_name}' confirm_delete: Weet u zeker dat u de actie '%{description}' wilt verwijderen? recurring_deleted_success: De recurrente actie is succesvol verwijderd. + deferred_tasks_title: TRACKS::Tickler next_actions_title: Tracks - Acties next_action_description: Actie beschrijving - deferred_tasks_title: TRACKS::Tickler no_completed_actions_with: Geen voltooide acties met de tag '%{tag_name}' clear_show_from_date: Maak de datum Tonen Vanaf leeg calendar_page_title: TRACKS::Agenda in_hidden_state: in verborgen toestand unresolved_dependency: De waarde die u ingevoerd heeft in het afhankelijkheden veld is niet herleidbaar naar een bestaande actie. Deze waarde wordt niet bewaard met de rest van de actie. Doorgaan? - next_actions_due_date: - overdue_by: Over deadline met %{days} dag - due_in_x_days: Deadline over %{days} dagen - due_today: Deadline vandaag - overdue_by_plural: Over deadline met %{days} dagen - due_tomorrow: Deadline morgen show_today: Toon vandaag no_actions_found_title: Geen acties gevonden + next_actions_due_date: + overdue_by: Over deadline met %{days} dag + due_today: Deadline vandaag + due_in_x_days: Deadline over %{days} dagen + overdue_by_plural: Over deadline met %{days} dagen + due_tomorrow: Deadline morgen completed_last_x_days: Voltooid in de laatste %{count} dagen - defer_x_days: + no_actions_with: Momenteel zijn er geen onvoltooide acties met de tag '%{tag_name}' + defer_x_days: one: Een dag uitstellen other: "%{count} dagen uitstellen" - no_actions_with: Momenteel zijn er geen onvoltooide acties met de tag '%{tag_name}' added_new_next_action_singular: Nieuwe actie toegevoegd no_completed_actions: Momenteel zijn er geen voltooide acties. - feeds: + feeds: completed: "Voltooid: %{date}" due: "Deadline: %{date}" deferred_pending_actions: Uitgestelde/wachtende acties - has_x_pending: + has_x_pending: one: Heeft een wachtende actie other: Heeft %{count} wachtende acties delete_action: Verwijder actie error_deleting_recurring: Er is een fout opgetreden bij het verwijderen van het item \'%{description}\' recurring_todos: Terugkerende acties delete: Verwijder - drag_action_title: Sleep naar een andere actie om deze afhankelijk te maken van die actie cannot_add_dependency_to_completed_todo: Kan deze actie niet als een afhankelijkheid van een voltooide actie toevoegen! + drag_action_title: Sleep naar een andere actie om deze afhankelijk te maken van die actie no_last_completed_actions: Geen afgeronde acties gevonden - tickler_items_due: + depends_on: Hangt af van + tickler_items_due: one: Een tickler item wordt nu zichtbaar - vernieuw de pagina om het te zien. other: "%{count} tickerl items zijn nu zichtbaar - vernieuw de pagina om ze te zien." - depends_on: Hangt af van action_marked_complete: De actie '%{description}' werd gemarkeerd als %{completed} - added_new_next_action_plural: Nieuwe acties toegevoegd completed_today: Vandaag afgerond + added_new_next_action_plural: Nieuwe acties toegevoegd new_related_todo_not_created_short: een nieuwe actie is niet gemaakt completed_rest_of_week: Afgerond in de rest van deze week error_starring: Kon niet de ster van deze actie niet omzetten \'%{description}\' show_tomorrow: Toon morgen - calendar: + calendar: get_in_ical_format: Ontvang deze agenda in iCal-formaat due_next_week: Deadline volgende week no_actions_due_next_week: Geen acties met deadline in volgende week due_this_week: Deadline in rest van deze week - no_actions_due_today: Geen acties met deadline vandaag due_today: Deadline vandaag + no_actions_due_today: Geen acties met deadline vandaag due_next_month_and_later: Deadline in %{month} en later no_actions_due_after_this_month: Geen acties met deadline na deze maand no_actions_due_this_month: Geen acties met deadline in de rest van deze maand due_this_month: Deadline in rest van %{month} + added_dependency: "%{dependency} als afhankelijkheid toegevoegd." action_deferred: De actie '%{description}' is uitgesteld - recurrence: + recurrence: + every_work_day: Elke werkdag ends_on_number_times: Eindigt na %{number} keer ends_on_date: Eindigt op %{date} - every_work_day: Elke werkdag recurrence_on_due_date: de datum dat deadline van de actie is weekly_options: Instellingen voor de wekelijkse terugkerende acties - weekly: Wekelijks monthly_options: Instellingen voor maandelijks terugkerende acties + weekly: Wekelijks monthly: Maandelijks starts_on: Begint op daily_options: Instellingen voor dagelijks terugkerende acties show_option_always: altijd daily: Dagelijks - pattern: + pattern: third: derde - month_names: - - + month_names: + - - januari - februari - maart @@ -503,19 +511,15 @@ nl: - december every_n: elke %{n} second: tweede - every_xth_day_of_every_n_months: elke %{x} %{day} van elke %{n_months} on_day_n: op dag %{n} + every_xth_day_of_every_n_months: elke %{x} %{day} van elke %{n_months} from: vanaf weekly: wekelijks every_day: elke dag last: laatste the_xth_day_of_month: de %{x} %{day} van %{month} times: voor %{number} keer - every_year_on: elk jaar op %{date} - on_work_days: op werkdagen - first: eerste - show: Tonen - day_names: + day_names: - zondag - maandag - dinsdag @@ -523,12 +527,16 @@ nl: - donderdag - vrijdag - zaterdag + first: eerste + show: Tonen + every_year_on: elk jaar op %{date} + on_work_days: op werkdagen fourth: vierde due: Deadline - until: tot every_month: elke maand - recurrence_on_options: Stel herhaling in op + until: tot yearly_every_x_day: Elke %{month} %{day} + recurrence_on_options: Stel herhaling in op daily_every_number_day: Elke %{number} dag(en) ends_on: Eindigt op show_options: Toon de actie @@ -543,33 +551,33 @@ nl: yearly: Jaarlijks tagged_page_title: TRACKS::Tagged met '%{tag_name}' no_completed_recurring: Momenteel zijn er geen voltooide terugkerende acties - added_dependency: "%{dependency} als afhankelijkheid toegevoegd." all_completed_tagged_page_title: "TRACKS:: Alle afgeronde acties met tag %{tag_name}" + recurrence_completed: Er is geen volgende actie na de terugkerende actie die u zojuist hebt voltooid. De herhaling is voltooid no_deferred_actions: Momenteel zijn er geen uitgestelde acties. completed_rest_of_month: Afgerond in de rest van deze maand - recurrence_completed: Er is geen volgende actie na de terugkerende actie die u zojuist hebt voltooid. De herhaling is voltooid no_actions_found: Momenteel zijn er geen onafgeronde acties. in_pending_state: in wachtende toestand error_toggle_complete: Kon deze actie niet als afgerond markeren due: Deadline action_marked_complete_error: De actie '%{description}' is niet gemarkeerd als %{completed} vanwege een fout op de server. - to_tickler: naar tickler - add_new_recurring: Voeg een nieuwe terugkerende actie toe depends_on_separate_with_commas: Afhankelijk van (gescheiden door komma's) recurring_action_saved: Terugkerende actie opgeslagen action_saved_to_tickler: Actie opgeslagen in tickler - completed_in_archive: + completed_in_archive: one: Er is een voltooide actie in het archief. other: Er zijn %{count} afgeronde acties in het archief. - next_actions_description_additions: + to_tickler: naar tickler + next_actions_description_additions: completed: in de afgelopen %{count} dagen due_date: met een deadline %{due_date} of eerder overdue: Achterstallig + add_new_recurring: Voeg een nieuwe terugkerende actie toe no_incomplete_actions: Er zijn geen onvoltooide acties - notes: + notes: delete_note_title: Verwijder de notitie '%{id}' delete_confirmation: Weet u zeker dat u de notitie '%{id}' wilt verwijderen? delete_item_title: Verwijder item + in_project: "In:" deleted_note: Verwijder notitie '%{id}' note_link_title: Toon notitie %{id} show_note_title: Toon notitie @@ -578,119 +586,119 @@ nl: no_notes_available: "Momenteel zijn er geen notities: voeg notities toe aan projecten vanaf de individuele project pagina's." note_header: Notitie %{id} delete_note_confirm: Weet u zeker dat u de notitie '%{id}' wilt verwijderen? - states: + states: hidden_plural: Verborgen review_plural: Gedateerde stalled: Vastgelopen completed: Afgerond current: Bijgewerkt - completed_plural: Afgeronde review: Gedateerde + completed_plural: Afgeronde blocked_plural: Geblokkeerde blocked: Geblokkeerd - stalled_plural: Vastgelopen visible_plural: Zichtbare + stalled_plural: Vastgelopen active_plural: Actieve visible: Zichtbaar hidden: Verborgen current_plural: Bijgewerkte active: Actief - errors: + errors: user_unauthorized: "401 Unauthorized: Alleen administratieve gebruikers mogen deze functie gebruiken." - projects: - edit_project_title: Bewerk project + projects: default_tags_removed_notice: De standaard tags zijn verwijderd default_context_set: Stel project standaard context in op %{default_context} no_actions_in_project: Momenteel zijn er geen onafgeronde acties in dit project deferred_actions: Uitgestelde acties voor dit project was_marked_hidden: is gemarkeerd als verborgen + edit_project_title: Bewerk project + page_title: "TRACKS:: Project: %{project}" hide_form: Verberg formulier all_completed_tasks_title: TRACKS::Toon alle afgeronde acties in het project '{project_name}' - page_title: "TRACKS:: Project: %{project}" + deferred_actions_empty: Er zijn geen uitgestelde acties voor dit project this_project: Dit project + project_state: Project is %{state}. list_completed_projects: TRACKS::Toon afgeronde projecten to_new_project_page: Ga naar de nieuwe projectpagina no_notes_attached: Momenteel zijn er geen notities toegevoegd aan dit project show_form_title: Maak een nieuw project - deferred_actions_empty: Er zijn geen uitgestelde acties voor dit project - project_state: Project is %{state}. + no_last_completed_projects: Geen afgeronde projecten gevonden no_last_completed_recurring_todos: Geen afgeronde herhalende acties gevonden todos_append: in dit project - no_last_completed_projects: Geen afgeronde projecten gevonden notes: Notities - notes_empty: Er zijn geen notities voor dit project no_projects: Momenteel zijn er geen projecten hide_form_title: Verberg nieuw project formulier list_reviews: TRACKS::Evaluatie + notes_empty: Er zijn geen notities voor dit project completed_actions_empty: Er zijn nog geen afgeronde acties voor dit project with_no_default_context: zonder standaard context delete_project: Project verwijderen - show_form: Toevoegen van een project - actions_in_project_title: Acties in dit project delete_project_confirmation: Weet u zeker dat u wilt het project '%{name} wilt verwijderen? with_default_context: met een standaard context '%{context_name}' + show_form: Toevoegen van een project + actions_in_project_title: Acties in dit project + with_default_tags: en met '%{tags}' als de standaard tags is_active: is actief + list_projects: "TRACKS:: Overzicht van projecten" completed_projects: Voltooide projecten + set_default_tags_notice: Stel project standaard tags in op %{default_tags} project_saved_status: Project opgeslagen + settings: Instellingen add_note: Een notitie toevoegen add_project: Voeg project toe - settings: Instellingen - with_default_tags: en met '%{tags}' als de standaard tags - list_projects: "TRACKS:: Overzicht van projecten" - set_default_tags_notice: Stel project standaard tags in op %{default_tags} + hidden_projects: Verborgen projecten completed_tasks_title: TRACKS::Toon afgeronde acties in het project '%{project_name}' delete_project_title: Verwijder het project - hidden_projects: Verborgen projecten default_context_removed: Standaard context verwijderd + completed_actions: Afgeronde acties voor dit project add_note_submit: Notitie toevoegen was_marked_complete: is gemarkeerd als voltooid - completed_actions: Afgeronde acties voor dit project + active_projects: Actieve projecten no_default_context: Dit project heeft geen standaard context with_no_default_tags: en zonder standaard tags edit_project_settings: Bewerk project instellingen state: Dit project is %{state} status_project_name_changed: Naam van het project werd gewijzigd default_context: De standaard context voor dit project is %{context} - active_projects: Actieve projecten - preferences: - change_identity_url: Verander uw Identity URL + preferences: open_id_url: Uw OpenID URL is + change_identity_url: Verander uw Identity URL staleness_starts_after: Markeren openstaande acties begint na %{days} dagen - change_password: Wijzig uw wachtwoord page_title: "TRACKS:: Voorkeuren" + change_password: Wijzig uw wachtwoord token_description: Token (voor feeds en API gebruik) title: Uw voorkeuren - is_false: Nee show_number_completed: Toon %{number} voltooide items - edit_preferences: Voorkeuren bewerken + is_false: Nee page_title_edit: "TRACKS:: Voorkeuren bewerken" is_true: Ja password_changed: Je wachtwoord is gewijzigd, meld je opnieuw aan. + edit_preferences: Voorkeuren bewerken generate_new_token: Genereer een nieuwe token sms_context_none: Geen token_header: Uw token - authentication_header: Uw authenticatie - updated: Voorkeuren bijgewerkt current_authentication_type: Uw authenticatietype is %{auth_type} + authentication_header: Uw authenticatie change_authentication_type: Verander uw authenticatietype + updated: Voorkeuren bijgewerkt generate_new_token_confirm: Weet u dit zeker? Het genereren van een nieuw token zal de bestaande te vervangen en dit zal het extern gebruiken van de oude token laten mislukken. - tabs: - tracks_behavior: Tracks gedrag + tabs: authentication: Authenticatie + tracks_behavior: Tracks gedrag profile: Profiel date_and_time: Datum en tijd - time: + time: am: ochtend - formats: + formats: default: "%A, %d %B %Y %H:%M:%S %z" time: "%H:%M" short: "%d %B %H:%M" month_day: "%d %B" long: "%A, %d. %B %Y, %H:%M" pm: middag - date: - month_names: - - + date: + month_names: + - - Januari - Februari - Maart @@ -703,7 +711,7 @@ nl: - Oktober - November - December - abbr_day_names: + abbr_day_names: - Zo - Ma - Di @@ -711,18 +719,18 @@ nl: - Do - Vr - Za - order: + order: - :day - :month - :year - formats: + formats: only_day: "%e" longer: "%A %d %B %Y" default: "%d-%m-%Y" short: "%e %b" month_day: "%B %d" long: "%e %B %Y" - day_names: + day_names: - Zondag - Maandag - Dinsdag @@ -730,8 +738,8 @@ nl: - Donderdag - Vrijdag - Zaterdag - abbr_month_names: - - + abbr_month_names: + - - Jan - Feb - Maa @@ -744,45 +752,30 @@ nl: - Okt - Nov - Dec - will_paginate: + will_paginate: previous_label: "\xC2\xABVorige" - page_entries_info: + page_entries_info: multi_page: Toon %{model} %{from} - %{to} van %{count} in totaal - single_page_html: + single_page_html: one: Toon 1 %{model} other: Toon alle %{count} %{model} zero: Geen %{model} gevonden - single_page: + single_page: one: Toon 1 %{model} other: Toon alle %{count} %{model} zero: Geen %{model} gevonden multi_page_html: Toon %{model} %{from} - %{to} van %{count} in totaal page_gap: "…" next_label: "Volgende \xC2\xBB" - support: - array: + support: + array: words_connector: "," last_word_connector: ", en" two_words_connector: en - select: + select: prompt: Selecteer - shared: - multiple_next_actions: Meerdere acties (een op elke regel) - make_actions_dependent: Maak acties afhankelijk van elkaar - hide_form: Verberg formulier - toggle_single: Voeg een actie toe - add_actions: Toevoegen acties - add_action: Actie toevoegen - tags_for_all_actions: Tags voor alle acties (scheiden met een komma) - project_for_all_actions: Project voor alle acties - context_for_all_actions: Context voor alle acties - toggle_multi: Voeg meerdere acties toe - toggle_single_title: Voeg een nieuwe actie toe - separate_tags_with_commas: gescheiden door komma's - toggle_multi_title: Toggle single / multi actie formulier - hide_action_form_title: Verberg nieuwe actie formulier - dates: - month_names: + dates: + month_names: - Januari - Februari - Maart @@ -795,7 +788,7 @@ nl: - Oktober - November - December - day_names: + day_names: - Zondag - Maandag - Dinsdag @@ -803,9 +796,25 @@ nl: - Donderdag - Vrijdag - Zaterdag - footer: + shared: + multiple_next_actions: Meerdere acties (een op elke regel) + make_actions_dependent: Maak acties afhankelijk van elkaar + toggle_single: Voeg een actie toe + hide_form: Verberg formulier + add_action: Actie toevoegen + add_actions: Toevoegen acties + tags_for_all_actions: Tags voor alle acties (scheiden met een komma) + project_for_all_actions: Project voor alle acties + context_for_all_actions: Context voor alle acties + toggle_multi: Voeg meerdere acties toe + toggle_single_title: Voeg een nieuwe actie toe + add_context: Toevoegen context + separate_tags_with_commas: gescheiden door komma's + toggle_multi_title: Toggle single / multi actie formulier + hide_action_form_title: Verberg nieuwe actie formulier + footer: send_feedback: Stuur reactie op %{version} - feedlist: + feedlist: actions_due_today: Acties die vandaag of eerder af moeten choose_context: Kies de context waar je een feed van wilt legend: Legenda @@ -814,105 +823,105 @@ nl: all_contexts: Alle contexten all_projects: Alle projecten choose_project: Kies het project waar je een feed van wilt + active_projects_wo_next: Actieve projecten zonder acties project_needed: "Er moet ten minste \xC3\xA9\xC3\xA9n project zijn voor een feed opgevraagd kan worden" select_feed_for_project: Kies de feed voor dit project - active_projects_wo_next: Actieve projecten zonder acties active_starred_actions: Alle gesterde, actieve acties - select_feed_for_context: Kies de feed voor deze context projects_and_actions: Actieve projecten met hun acties context_needed: "Er moet eerst ten minste \xC3\xA9\xC3\xA9n context zijn voor je een feed kan opvragen" + select_feed_for_context: Kies de feed voor deze context actions_due_next_week: Acties die binnen 7 dagen afgerond moeten notice_incomplete_only: "Merk op: alle feeds laten alleen acties zien die niet afgerond zijn, tenzij anders vermeld." - context_centric_actions: Feeds voor onafgeronde acties in een specifieke context - plain_text_feed: Reguliere tekst feed last_fixed_number: Laatste %{number} acties all_actions: Alle acties actions_completed_last_week: Acties afgerond in de afgelopen 7 dagen + context_centric_actions: Feeds voor onafgeronde acties in een specifieke context + plain_text_feed: Reguliere tekst feed project_centric: Feeds voor onafgeronde acties in een specifiek project - users: - first_user_heading: "Welkom bij TRACKS. Om te beginnen, maak dan een admin account:" - successfully_deleted_user: Succesvol gebruiker %{username} verwijderd - auth_type_update_error: "Er was een probleem met het bijwerken van uw authenticatietype: %{error_messages}" - failed_to_delete_user: Mislukt de gebruiker %{username} te verwijderen - destroy_successful: Gebruiker %{login} met succes verwijderd - total_contexts: Totaal aantal contexten - openid_url_verified: Je hebt %{url} met succes geverifieerd als je identiteit en uw authenticatie type OpenID opgeslagen. - signup_successful: Aanmelding succesvol voor gebruiker %{username}. - new_token_generated: Nieuwe token met succes gegenereerd - total_projects: Totaal aantal projecten - no_signups_title: "TRACKS:: Geen nieuwe aanmeldingen" - user_created: Gebruiker aangemaakt. - change_password_submit: Wachtwoord wijzigen - manage_users: Beheren gebruikers - account_signup: Aanmelden voor een account - password_updated: Wachtwoord bijgewerkt. - total_actions: Totaal aanal acties - desired_login: Gewenste login - confirm_password: Bevestig wachtwoord - new_user_heading: "Registreer een nieuwe gebruiker:" - signup: Aanmelden - auth_type_updated: Authenticatietype bijgewerkt. - destroy_error: Er is een fout opgetreden bij het verwijderen van de gebruiker '%{login}' - choose_password: Kies een wachtwoord - change_password_title: TRACKS::Wachtwoord wijzigen - change_auth_type_title: TRACKS::Wijzig authenticatietype - change_password_prompt: Voer uw nieuwe wachtwoord in de onderstaande velden in en kies 'Wachtwoord wijzigen' om uw huidige wachtwoord met uw nieuwe te vervangen. - password_confirmation_label: Bevestig wachtwoord - new_password_label: Nieuw wachtwoord - register_with_cas: Met uw CAS gebruikersnaam - label_auth_type: Authenticatietype - total_users_count: Je hebt een totaal van %{count} gebruikers - new_user_title: "TRACKS:: Aanmelden als de admin gebruiker" - destroy_user: Verwijder de gebruiker - you_have_to_reset_your_password: Je moet je wachtwoord opnieuw instellen - signup_new_user: Registreer nieuwe gebruiker - destroy_confirmation: "Waarschuwing: dit zal de gebruiker '%{login} verwijderen met al zijn acties, contexten, projecten en notities. Weet u zeker dat u wilt doorgaan?" - identity_url: Identiteit URL - openid_ok_pref_failed: Je hebt succesvol de %{url} geverifieerd als je identiteit, maar er was een probleem met het opslaan van uw authenticatie voorkeuren. - change_authentication_type: Wijzigen authenticatietype - auth_change_submit: Wijzigen authenticatietype - select_authentication_type: Selecteer uw nieuwe authenticatie type en klik op 'Wijzigen authenticatietype' om uw huidige instellingen te vervangen. - total_notes: Totaal aantal notities - sidebar: + sidebar: list_name_active_contexts: Actieve contexten list_name_active_projects: Actieve projecten list_empty: Geen list_name_completed_projects: Voltooide projecten list_name_hidden_projects: Verborgen projecten list_name_hidden_contexts: Verborgen contexten - contexts: + users: + destroy_successful: Gebruiker %{login} met succes verwijderd + total_contexts: Totaal aantal contexten + first_user_heading: "Welkom bij TRACKS. Om te beginnen, maak dan een admin account:" + openid_url_verified: Je hebt %{url} met succes geverifieerd als je identiteit en uw authenticatie type OpenID opgeslagen. + successfully_deleted_user: Succesvol gebruiker %{username} verwijderd + auth_type_update_error: "Er was een probleem met het bijwerken van uw authenticatietype: %{error_messages}" + failed_to_delete_user: Mislukt de gebruiker %{username} te verwijderen + total_projects: Totaal aantal projecten + signup_successful: Aanmelding succesvol voor gebruiker %{username}. + new_token_generated: Nieuwe token met succes gegenereerd + no_signups_title: "TRACKS:: Geen nieuwe aanmeldingen" + user_created: Gebruiker aangemaakt. + change_password_submit: Wachtwoord wijzigen + password_updated: Wachtwoord bijgewerkt. + manage_users: Beheren gebruikers + account_signup: Aanmelden voor een account + desired_login: Gewenste login + confirm_password: Bevestig wachtwoord + new_user_heading: "Registreer een nieuwe gebruiker:" + signup: Aanmelden + auth_type_updated: Authenticatietype bijgewerkt. + total_actions: Totaal aanal acties + choose_password: Kies een wachtwoord + change_password_title: TRACKS::Wachtwoord wijzigen + change_auth_type_title: TRACKS::Wijzig authenticatietype + change_password_prompt: Voer uw nieuwe wachtwoord in de onderstaande velden in en kies 'Wachtwoord wijzigen' om uw huidige wachtwoord met uw nieuwe te vervangen. + password_confirmation_label: Bevestig wachtwoord + destroy_error: Er is een fout opgetreden bij het verwijderen van de gebruiker '%{login}' + new_password_label: Nieuw wachtwoord + register_with_cas: Met uw CAS gebruikersnaam + label_auth_type: Authenticatietype + destroy_user: Verwijder de gebruiker + total_users_count: Je hebt een totaal van %{count} gebruikers + new_user_title: "TRACKS:: Aanmelden als de admin gebruiker" + you_have_to_reset_your_password: Je moet je wachtwoord opnieuw instellen + signup_new_user: Registreer nieuwe gebruiker + destroy_confirmation: "Waarschuwing: dit zal de gebruiker '%{login} verwijderen met al zijn acties, contexten, projecten en notities. Weet u zeker dat u wilt doorgaan?" + identity_url: Identiteit URL + auth_change_submit: Wijzigen authenticatietype + change_authentication_type: Wijzigen authenticatietype + openid_ok_pref_failed: Je hebt succesvol de %{url} geverifieerd als je identiteit, maar er was een probleem met het opslaan van uw authenticatie voorkeuren. + select_authentication_type: Selecteer uw nieuwe authenticatie type en klik op 'Wijzigen authenticatietype' om uw huidige instellingen te vervangen. + total_notes: Totaal aantal notities + contexts: delete_context_title: Verwijder context hide_form: Verberg formulier all_completed_tasks_title: "TRACKS:: Alle voltooide acties in context '%{context_name}'" show_form_title: Voeg een context toe delete_context_confirmation: Weet u zeker dat u de context '%{name}' wilt verwijderen? Merk op dat dit ook alle (herhalende) acties in deze context zal verwijderen! - delete_context: Verwijder context todos_append: in deze context + delete_context: Verwijder context edit_context: Bewerk context hide_form_title: "Verberg formulier voor nieuwe context " no_contexts_active: Momenteel zijn er geen actieve contexten context_hide: Verberg van de start pagina? hidden_contexts: Verborgen contexten - visible_contexts: Zichtbare contexten - save_status_message: Context bewaard - show_form: Maak een nieuwe context add_context: Context toevoegen + visible_contexts: Zichtbare contexten + show_form: Maak een nieuwe context + save_status_message: Context bewaard context_name: Context naam update_status_message: Naam van de context was veranderd + new_context_post: "' zal ook gemaakt worden. Weet u dit zeker?" completed_tasks_title: "TRACKS:: Voltooid acties in de context '%{context_name}'" status_active: Context is actief - new_context_post: "' zal ook gemaakt worden. Weet u dit zeker?" context_deleted: De context '%{name}' is verwijderd no_contexts_hidden: Momenteel zijn er geen verborgen contexten new_context_pre: Nieuwe context ' no_actions: Momenteel zijn er geen onafgeronde acties in deze context last_completed_in_context: in deze context (laatste %{number}) status_hidden: Context is verborgen - login: - openid_identity_url_not_found: Sorry, geen gebruiker met die identiteit URL bestaat (%{identity_url}) + login: user_no_expiry: Blijf ingelogd - login_cas: Ga naar het CAS sign_in: Meld aan + login_cas: Ga naar het CAS + openid_identity_url_not_found: Sorry, geen gebruiker met die identiteit URL bestaat (%{identity_url}) cas_no_user_found: Hallo,%{username}! Je hebt nog geen account op Tracks. cas_login: CAS Inloggen successful_with_session_info: "Login succesvol:" @@ -929,56 +938,56 @@ nl: option_separator: of, session_time_out: Sessie is verlopen. Gelieve %{link} login_standard: Ga terug naar de standaard login + unsuccessful: Login mislukt. log_in_again: opnieuw in te loggen. logged_out: Je bent afgemeld bij Tracks. login_with_openid: inloggen met een OpenID - unsuccessful: Login mislukt. - datetime: - prompts: + datetime: + prompts: minute: Minuut second: Seconden month: Maand hour: Uur day: Dag year: Jaar - distance_in_words: - less_than_x_minutes: + distance_in_words: + less_than_x_minutes: one: minder dan een minuut other: minder dan %{count} minuten zero: minder dan 1 minuut - almost_x_years: + almost_x_years: one: bijna 1 jaar other: bijna %{count} jaren - x_days: + x_days: one: 1 dag other: "%{count} dagen" - x_seconds: + x_seconds: one: 1 seconde other: "%{count} seconden" - about_x_hours: + about_x_hours: one: ongeveer 1 uur other: ongeveer %{count} uren - less_than_x_seconds: + less_than_x_seconds: one: minder dan 1 seconde other: minder dan %{count} seconden zero: minder dan 1 seconde - x_months: + x_months: one: 1 maand other: "%{count} maanden" - x_minutes: + x_minutes: one: 1 minuut other: "%{count} minuten" - about_x_years: + about_x_years: one: ongeveer 1 jaar other: ongeveer %{count} jaren - about_x_months: + about_x_months: one: ongeveer 1 maand other: ongeveer %{count} maanden - over_x_years: + over_x_years: one: over 1 jaar other: over %{count} jaren half_a_minute: halve minuut - search: + search: contexts_matching_query: Contexten passend bij zoekopdracht tags_matching_query: Tags passend bij zoekopdracht no_results: Uw zoekopdracht heeft geen resultaten opgeleverd. diff --git a/public/javascripts/application.js b/public/javascripts/application.js index 65c25b72..9d32e0f4 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -1016,8 +1016,14 @@ var RecurringTodosPage = { width: 750, modal: true, buttons: { - "Create": function() { submit_with_ajax_and_block_element('form.#recurring-todo-form-new-action', $(this).parents(".ui-dialog")); }, - Cancel: function() { $( this ).dialog( "close" ); } + create: { + text: i18n['common.create'], + click: function() { submit_with_ajax_and_block_element('form.#recurring-todo-form-new-action', $(this).parents(".ui-dialog")); }, + }, + cancel: { + text: i18n['common.cancel'], + click: function() { $( this ).dialog( "close" ); } + } }, show: "fade", hide: "fade", @@ -1043,11 +1049,14 @@ var RecurringTodosPage = { modal: true, buttons: { "Update": { - text: "Update", + text: i18n['common.update'], id: 'recurring_todo_edit_update_button', click: function() { submit_with_ajax_and_block_element('form#recurring-todo-form-edit-action', $(this).parents(".ui-dialog")); } }, - Cancel: function() { $( this ).dialog( "close" ); } + cancel: { + text: i18n['common.cancel'], + click: function() { $( this ).dialog( "close" ); } + } }, show: "fade", hide: "fade", diff --git a/public/javascripts/i18n/jquery.ui.datepicker-he.js b/public/javascripts/i18n/jquery.ui.datepicker-he.js new file mode 100644 index 00000000..3b3dc387 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-he.js @@ -0,0 +1,23 @@ +/* Hebrew initialisation for the UI Datepicker extension. */ +/* Written by Amir Hardon (ahardon at gmail dot com). */ +jQuery(function($){ + $.datepicker.regional['he'] = { + closeText: 'סגור', + prevText: '<הקודם', + nextText: 'הבא>', + currentText: 'היום', + monthNames: ['ינואר','פברואר','מרץ','אפריל','מאי','יוני', + 'יולי','אוגוסט','ספטמבר','אוקטובר','נובמבר','דצמבר'], + monthNamesShort: ['1','2','3','4','5','6', + '7','8','9','10','11','12'], + dayNames: ['ראשון','שני','שלישי','רביעי','חמישי','שישי','שבת'], + dayNamesShort: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'], + dayNamesMin: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'], + weekHeader: 'Wk', + dateFormat: 'dd/mm/yy', + firstDay: 0, + isRTL: true, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['he']); +}); From f32e5b256b7664a1116e4a9dc29535ff975de412 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Wed, 11 Apr 2012 21:09:46 +0200 Subject: [PATCH 085/134] further i18n changes for Hebrew, impacting other locales too --- app/views/contexts/_context_form.rhtml | 6 +- app/views/stats/_contexts.rhtml | 12 +- app/views/stats/_projects.rhtml | 4 +- app/views/stats/_tags.rhtml | 16 +- .../actions_completion_time_data.html.erb | 2 +- .../actions_day_of_week_30days_data.html.erb | 2 +- .../actions_day_of_week_all_data.html.erb | 2 +- .../actions_done_last12months_data.html.erb | 2 +- .../actions_done_last30days_data.html.erb | 1 + .../actions_done_lastyears_data.html.erb | 2 +- config/locales/en.yml | 2 + config/locales/nl.yml | 498 +++++++++--------- 12 files changed, 277 insertions(+), 272 deletions(-) diff --git a/app/views/contexts/_context_form.rhtml b/app/views/contexts/_context_form.rhtml index 92bd39aa..a73a2782 100644 --- a/app/views/contexts/_context_form.rhtml +++ b/app/views/contexts/_context_form.rhtml @@ -1,4 +1,4 @@ -<% context = context_form +<% context = context_form @context = context -%> @@ -11,10 +11,10 @@
        <%= error_messages_for("project") %>
        -
        +
        <%= text_field('context', 'name', :class => 'context-name', :tabindex => next_tab_index) %>
        - + <%= check_box('context', 'hide', {:class => 'context-hide', :tabindex => next_tab_index}) %> diff --git a/app/views/stats/_contexts.rhtml b/app/views/stats/_contexts.rhtml index ee3eae5e..a55b7b5d 100755 --- a/app/views/stats/_contexts.rhtml +++ b/app/views/stats/_contexts.rhtml @@ -8,14 +8,14 @@

        <%= t('stats.top5_contexts') %>

        <% 1.upto 5 do |i| - %><%=i-%> - - <%= i <= @actions_per_context.size ? link_to(@actions_per_context[i-1]['name'], {:controller => "contexts", :action => "show", :id => @actions_per_context[i-1]['id']}) : "n/a"%> + %><%=i-%> - + <%= i <= @actions_per_context.size ? link_to(@actions_per_context[i-1]['name'], {:controller => "contexts", :action => "show", :id => @actions_per_context[i-1]['id']}) : "n/a"%> ( - <%= i <= @actions_per_context.size ? @actions_per_context[i-1]['total'] : "n/a"%> + <%= i <= @actions_per_context.size ? @actions_per_context[i-1]['total'] : t('common.not_available_abbr')%> )
        <% end --%> +-%>
        @@ -25,9 +25,9 @@ %><%=i-%> - <%= i <= @running_actions_per_context.size ? link_to(@running_actions_per_context[i-1]['name'], {:controller => "contexts", :action => "show", :id => @running_actions_per_context[i-1]['id']}) : "n/a"-%> ( - <%= i <= @running_actions_per_context.size ? @running_actions_per_context[i-1]['total'] : "n/a"-%> + <%= i <= @running_actions_per_context.size ? @running_actions_per_context[i-1]['total'] : t('common.not_available_abbr')-%> )
        <% end --%> +-%>
        \ No newline at end of file diff --git a/app/views/stats/_projects.rhtml b/app/views/stats/_projects.rhtml index 42d47a6c..26ceb7e4 100755 --- a/app/views/stats/_projects.rhtml +++ b/app/views/stats/_projects.rhtml @@ -7,7 +7,7 @@ <% end if i < 10 i.upto 10 do |j| -%> - <%= i -%> - n/a (n/a)
        + <%= i -%> - <%=t('common.not_available_abbr')%> (<%=t('common.not_available_abbr')%>)
        <% end end -%> @@ -22,7 +22,7 @@ <% end if i < 10 i.upto 10 do |j| -%> - <%= i -%> - n/a (n/a)
        + <%= i -%> - <%=t('common.not_available_abbr')%> (<%=t('common.not_available_abbr')%>)
        <% end end -%> diff --git a/app/views/stats/_tags.rhtml b/app/views/stats/_tags.rhtml index b42ab7c7..5f5f2fe7 100755 --- a/app/views/stats/_tags.rhtml +++ b/app/views/stats/_tags.rhtml @@ -7,12 +7,12 @@ t('stats.no_tags_available') else @tags_for_cloud.each do |t| %> - <%= link_to t.name, - {:controller => "todos", :action => "tag", :id => t.name}, + <%= link_to t.name, + {:controller => "todos", :action => "tag", :id => t.name}, {:style => "font-size: " + (9 + 2*(t.count.to_i-@tags_min)/@tags_divisor).to_s + "pt", - :title => t.count.to_s+" actions"} + :title => t.count.to_s+" #{t('common.actions_midsentence')}"} -%> <% - end + end end-%>

        @@ -25,12 +25,12 @@ t('stats.no_tags_available') else @tags_for_cloud_90days.each do |t| %> - <%= link_to t.name, - {:controller => "todos", :action => "tag", :id => t.name}, + <%= link_to t.name, + {:controller => "todos", :action => "tag", :id => t.name}, {:style => "font-size: " + (9 + 2*(t.count.to_i-@tags_min_90days)/@tags_divisor_90days).to_s + "pt", - :title => t.count.to_s+" actions"} + :title => t.count.to_s+" #{t('common.actions_midsentence')}"} -%> <% - end + end end-%>

        \ No newline at end of file diff --git a/app/views/stats/actions_completion_time_data.html.erb b/app/views/stats/actions_completion_time_data.html.erb index d1830419..27008ffe 100755 --- a/app/views/stats/actions_completion_time_data.html.erb +++ b/app/views/stats/actions_completion_time_data.html.erb @@ -1,6 +1,6 @@ <%- time_labels = Array.new(@count){ |i| "#{i}-#{i+1}" } -time_labels[0] = "within 1" +time_labels[0] = t('stats.within_one') time_labels[@count] = "> #{@count}" -%> &title=<%= t('stats.action_completion_time_title') %>,{font-size:16},& diff --git a/app/views/stats/actions_day_of_week_30days_data.html.erb b/app/views/stats/actions_day_of_week_30days_data.html.erb index a61fe6a6..75adf7bb 100755 --- a/app/views/stats/actions_day_of_week_30days_data.html.erb +++ b/app/views/stats/actions_day_of_week_30days_data.html.erb @@ -6,7 +6,7 @@ &filled_bar_2=50,0x0066CC,0x0066CC,<%= t('stats.labels.completed') %>,8& &values=<%= @actions_creation_day_array.join(",") %>& &values_2=<%= @actions_completion_day_array.join(",") %>& -&x_labels=<%= Date::DAYNAMES.join(",") %>& +&x_labels=<%= t('date.day_names').join(",") %>& &y_min=0& <% # add one to @max for people who have no actions completed yet. diff --git a/app/views/stats/actions_day_of_week_all_data.html.erb b/app/views/stats/actions_day_of_week_all_data.html.erb index 1e8d23da..24e3ad6f 100755 --- a/app/views/stats/actions_day_of_week_all_data.html.erb +++ b/app/views/stats/actions_day_of_week_all_data.html.erb @@ -6,7 +6,7 @@ &filled_bar_2=50,0x0066CC,0x0066CC,<%= t('stats.labels.completed') %>,8& &values=<%= @actions_creation_day_array.join(",") %>& &values_2=<%= @actions_completion_day_array.join(",") %>& -&x_labels=<%= Date::DAYNAMES.join(",") %>& +&x_labels=<%= t('date.day_names').join(",") %>& &y_min=0& <% # add one to @max for people who have no actions completed yet. diff --git a/app/views/stats/actions_done_last12months_data.html.erb b/app/views/stats/actions_done_last12months_data.html.erb index 605f9a5f..8c681971 100755 --- a/app/views/stats/actions_done_last12months_data.html.erb +++ b/app/views/stats/actions_done_last12months_data.html.erb @@ -2,7 +2,7 @@ url_array = Array.new(13){ |i| url_for :controller => 'stats', :action => 'actions_done_last_years'} created_count_array = Array.new(13){ |i| @actions_created_last12months.count/12.0 } done_count_array = Array.new(13){ |i| @actions_done_last12months.count/12.0 } -month_names = Array.new(13){ |i| Date::MONTHNAMES[ (Time.now.mon - i -1 ) % 12 + 1 ]} +month_names = Array.new(13){ |i| t('date.month_names')[ (Time.now.mon - i -1 ) % 12 + 1 ]} -%> &title=<%= t('stats.actions_lastyear_title') %>,{font-size:16},& &y_legend=<%= t('stats.legend.number_of_actions') %>,12,0x736AFF& diff --git a/app/views/stats/actions_done_last30days_data.html.erb b/app/views/stats/actions_done_last30days_data.html.erb index 28e2903c..1693edb6 100755 --- a/app/views/stats/actions_done_last30days_data.html.erb +++ b/app/views/stats/actions_done_last30days_data.html.erb @@ -1,6 +1,7 @@ <%- created_count_array = Array.new(30){ |i| @actions_created_last30days.count/30.0 } done_count_array = Array.new(30){ |i| @actions_done_last30days.count/30.0 } +# TODO: make the strftime i18n proof time_labels = Array.new(30){ |i| (Time.zone.now-i.days).strftime("%a %d-%m") } -%> &title=<%= t('stats.actions_30days_title') %>,{font-size:16},& diff --git a/app/views/stats/actions_done_lastyears_data.html.erb b/app/views/stats/actions_done_lastyears_data.html.erb index 03cfa025..ae07bc36 100644 --- a/app/views/stats/actions_done_lastyears_data.html.erb +++ b/app/views/stats/actions_done_lastyears_data.html.erb @@ -1,7 +1,7 @@ <%- created_count_array = Array.new(@month_count+1){ |i| @actions_created_last_months.count/@month_count } done_count_array = Array.new(@month_count+1){ |i| @actions_done_last_months.count/@month_count } -month_names = Array.new(@month_count+1){ |i| Date::MONTHNAMES[ (Time.now.mon - i -1 ) % 12 + 1 ]+ " " + (Time.now - i.months).year.to_s} +month_names = Array.new(@month_count+1){ |i| t('date.month_names')[ (Time.now.mon - i -1 ) % 12 + 1 ]+ " " + (Time.now - i.months).year.to_s} -%> &title=<%= t('stats.actions_last_year') %>,{font-size:16},& &y_legend=<%= t('stats.actions_last_year_legend.number_of_actions') %>,12,0x736AFF& diff --git a/config/locales/en.yml b/config/locales/en.yml index de87c596..8f717f8a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -144,6 +144,7 @@ en: search: Search ajaxError: There was an error retrieving from server days_midsentence: days + not_available_abbr: "n/a" data: import_successful: Import was successful. import_errors: Some errors occurred during import @@ -243,6 +244,7 @@ en: other: "%{count} errors prohibited this %{model} from being saved" stats: index_title: TRACKS::Statistics + within_one: Within 1 tag_cloud_title: Tag cloud for all actions tag_cloud_description: This tag cloud includes tags of all actions (completed, not completed, visible and/or hidden) tag_cloud_90days_title: Tag cloud actions in past 90 days diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 1f2308dc..94eee94d 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -1,35 +1,35 @@ ---- -nl: - number: - format: +--- +nl: + number: + format: separator: "," delimiter: . - human: - storage_units: + human: + storage_units: format: "%n %u" - units: + units: kb: KB tb: TB gb: GB - byte: + byte: one: Byte other: Bytes mb: MB - currency: - format: + currency: + format: format: "%u %n" unit: !binary | 4oKs separator: "," delimiter: . - layouts: + layouts: toggle_contexts_title: Maak ingeklapte contexten (on)zichtbaar toggle_notes: Toggle notities toggle_contexts: Toggle ingeklapte contexten next_actions_rss_feed: RSS-feed van de acties toggle_notes_title: Toggle alle notities - mobile_navigation: + mobile_navigation: new_action: Nieuwe actie logout: Afmelden feeds: Feeds @@ -38,7 +38,7 @@ nl: tickler: Tickler contexts: Contexten home: Start - navigation: + navigation: manage_users_title: Toevoegen of verwijderen gebruikers api_docs: REST API Docs recurring_todos: Terugkerende acties @@ -51,8 +51,8 @@ nl: tickler_title: Tickler integrations_: Integreer Tracks export_title: Import en export van gegevens - preferences: Voorkeuren admin: Admin + preferences: Voorkeuren calendar_title: Kalender met acties met deadline feeds_title: Zie een lijst met beschikbare feeds completed_tasks: Gereed @@ -72,13 +72,13 @@ nl: search: Zoeken in alle items projects_title: Projecten calendar: Agenda - integrations: + integrations: opensearch_description: Zoek in Tracks applescript_next_action_prompt: "Omschrijving van de actie:" gmail_description: Gadget om Tracks toe te voegen aan Gmail als een gadget applescript_success_after_id: gemaakt applescript_success_before_id: Nieuwe actie met ID - common: + common: back: Terug recurring_todos: Herhalende acties actions: Acties @@ -89,9 +89,9 @@ nl: logout: Log uit second: Tweede show_all: Toon alle - none: Geen - week: week optional: optioneel + week: week + none: Geen cancel: Annuleer month: maand actions_midsentence: acties @@ -99,8 +99,8 @@ nl: forum: Forum notes: Notities last: Laatste - projects: Projecten review: Evaluatie + projects: Projecten action: Actie project: Project days_midsentence: dagen @@ -110,8 +110,7 @@ nl: first: Eerste numbered_step: Stap %{number} errors_with_fields: Er waren problemen met de volgende velden - create: Maken - sort: + sort: by_task_count_title: Sorteer op aantal acties by_task_count_title_confirm: Weet u zeker dat u deze op aantal acties wilt sorteren? Dat zal de huidige sorteervolgorde aanpassen. alphabetically: Alfabetisch @@ -119,33 +118,35 @@ nl: sort: Sorteer alphabetically_confirm: Weet u zeker dat u deze projecten alfabetisch wilt sorteren? Dat zal de huidige sorteervolgorde aanpassen. by_task_count: Op aantal acties + create: Maken months: maanden description: Beschrijving - next: Volgende fourth: Vierde - context: Context - todo: actie + next: Volgende contexts: Contexten + todo: actie + context: Context drag_handle: SLEEP update: Bijwerken - forth: Vierde weeks: weken + forth: Vierde wiki: Wiki bugs: Fouten ajaxError: Er is een fout opgetreden bij het ophalen van gegevens van de server email: E-mail + not_available_abbr: n/b search: Zoeken - activerecord: - attributes: - project: + activerecord: + attributes: + project: name: Naam default_tags: Standaard Tags default_context_name: Standaard context description: Beschrijving - note: + note: created_at: Gemaakt op updated_at: Bijgewerkt op - todo: + todo: show_from: Tonen vanaf predecessors: Afhankelijkheden notes: Notities @@ -154,39 +155,39 @@ nl: description: Beschrijving context: Context due: Deadline - user: + user: last_name: Achternaam first_name: Voornaam - preference: + preference: show_hidden_projects_in_sidebar: Toon verborgen projecten in sidebar - date_format: Datum formaat show_hidden_contexts_in_sidebar: Toon verborgen contexten in sidebar - staleness_starts: Begin van markeren openstaande actie + date_format: Datum formaat sms_context: Standaard context voor email verbose_action_descriptors: Context en project uitschrijven in actielijst mobile_todos_per_page: Acties per pagina (mobiel) - title_date_format: Datum formaat in titel + staleness_starts: Begin van markeren openstaande actie show_number_completed: Aantal te tonen afgeronde acties + title_date_format: Datum formaat in titel refresh: Ververs interval (in minuten) week_starts: Week start op last_name: Achternaam - due_style: Deadline stijl locale: Taal + due_style: Deadline stijl time_zone: Tijdzone - show_project_on_todo_done: Ga naar project pagina wanneer actie gereed is sms_email: Van email + show_project_on_todo_done: Ga naar project pagina wanneer actie gereed is show_completed_projects_in_sidebar: Toon afgeronde projecten in sidebar first_name: Voornaam review_period: Project evaluatie interval - errors: - models: - project: - attributes: - name: + errors: + models: + project: + attributes: + name: blank: project moet een naam hebben too_long: project naam moet minder dan 256 karakters hebben taken: bestaat al - messages: + messages: record_invalid: "Validatie mislukt: %{errors}" greater_than_or_equal_to: moet groter of gelijk zijn aan %{count} confirmation: komt niet overeen met de configuratie @@ -207,57 +208,58 @@ nl: taken: is al gepakt inclusion: is niet opgenomen in de lijst not_a_number: is niet een getal - full_messages: + full_messages: format: "%{attribute} %{message}" - template: + template: body: Er waren problemen met de volgende velden - header: + header: one: 1 fout voorkomt het kunnen bewaren van deze %{model} other: "%{count} fouten voorkomen dat dit %{model} bewaard kan worden" - data: + data: import_successful: De import was succesvol import_errors: Er hebben zich fouten voorgedaan bij de import - models: - project: + models: + project: feed_title: Tracks Projecten feed_description: Een overzicht van alle projecten voor %{username} - todo: + todo: error_date_must_be_future: moet een datum in de toekomst zijn - user: + user: error_context_not_associated: Context %{context} niet geassocieerd met gebruikers %{user}. error_project_not_associated: Project %{project} niet geassocieerd met gebruikers %{user}. - preference: + preference: due_on: Deadline op %{date} due_in: Deadline over %{days} dagen - due_styles: + due_styles: - Deadline over ____ dagen - Deadline op ____ - stats: + stats: + totals_actions_completed: "%{count} van deze zijn voltooid." totals_hidden_context_count: en %{count} zijn verborgen contexten. actions_avg_created: In de afgelopen 12 maanden heeft u gemiddeld%{count} acties aangemaakt actions_min_max_completion_days: De max-/minimum dagen tot voltooiing is %{min}/%{max}. - totals_actions_completed: "%{count} van deze zijn voltooid." tag_cloud_title: Tag Cloud voor alle acties - top5_visible_contexts_with_incomplete_actions: Top 5 zichtbare contexten met onvolledige acties actions_actions_avg_created_30days: In de afgelopen 30 dagen heeft u gemiddeld %{count} acties gemaakt actions_avg_completed: en voltooide een gemiddelde van %{count} acties per maand. + top5_visible_contexts_with_incomplete_actions: Top 5 zichtbare contexten met onvolledige acties actions: Acties - time_of_day_legend: + time_of_day_legend: number_of_actions: Aantal acties time_of_day: Tijd van de dag totals_incomplete_actions: U heeft %{count} onvolledige acties - totals_action_count: u heeft een totaal van %{count} acties - totals_deferred_actions: waarvan %{count} uitgestelde acties in de tickler zijn - running_time_legend: + running_time_legend: actions: Acties percentage: Percentage weeks: Looptijd van een actie (weken). Klik op een balk voor meer info + totals_action_count: u heeft een totaal van %{count} acties + totals_deferred_actions: waarvan %{count} uitgestelde acties in de tickler zijn tag_cloud_90days_title: Tag cloud met acties in afgelopen 90 dagen tod30: Tijd van de dag (laatste 30 dagen) tags: Tags projects: Projecten actions_avg_completion_time: Van al uw afgeronde acties, de gemiddelde tijd dat dit in beslag nam is %{count} dagen. - labels: + actions_selected_from_week: Gekozen acties van week + labels: month_avg_completed: "%{months} gem afgerond per maand" completed: Afgerond month_avg_created: "%{months} gem gemaakt per maand" @@ -265,14 +267,13 @@ nl: avg_completed: Gem afgerond created: Gemaakt totals_completed_project_count: en %{count} zijn afgeronde projecten. - actions_selected_from_week: Gekozen acties van week actions_day_of_week_title: Dag van de week (alle acties) actions_lastyear_title: Acties in de afgelopen 12 maanden open_per_week: Active (zichtbare en verborgen) volgende acties per week - action_selection_title: "TRACKS:: Actie selectie" totals_project_count: U heeft %{count} projecten. + action_selection_title: "TRACKS:: Actie selectie" current_running_time_of_incomplete_visible_actions: Huidige looptijd van onvolledige zichtbare acties - legend: + legend: number_of_days: Aantal dagen geleden actions: Acties number_of_actions: Aantal acties @@ -280,14 +281,14 @@ nl: running_time: Looptijd van een actie (weken) percentage: Percentage months_ago: Maanden geleden - tod30_legend: + tod30_legend: number_of_actions: Aantal acties time_of_day: Tijd van de dag totals_context_count: U heeft %{count} contexten. - open_per_week_legend: + open_per_week_legend: actions: Acties weeks: Weken geleden - actions_last_year_legend: + actions_last_year_legend: number_of_actions: Aantal acties months_ago: Maanden geleden top10_projects: Top 10 projecten @@ -301,12 +302,12 @@ nl: running_time_all: Huidige looptijd van alle onvolledige acties actions_min_completion_time: De minimale tijd tot afronding is %{time}. action_completion_time_title: Doorlooptijd (alle voltooide acties) - click_to_show_actions_from_week: Klik %{link} om de acties van week %{week} en verder te zien. top10_longrunning: Top 10 langstlopende projecten + click_to_show_actions_from_week: Klik %{link} om de acties van week %{week} en verder te zien. no_actions_selected: Er zijn geen acties geselecteerd. totals_tag_count: U heeft %{count} tags geplaatst op acties. actions_further: en verder - actions_dow_30days_legend: + actions_dow_30days_legend: number_of_actions: Aantal acties day_of_week: Dag van de week totals_first_action: Sinds uw eerste actie op %{date} @@ -316,187 +317,188 @@ nl: spread_of_actions_for_all_context: Verdeling van acties voor alle contexten more_stats_will_appear: Meer statistieken zullen hier verschijnen zodra u acties hebt toegevoegd. actions_avg_completed_30days: en voltooide een gemiddelde van %{count} acties per dag. + index_title: TRACKS::Statistiek actions_30days_title: Acties in de afgelopen 30 dagen no_tags_available: geen tags beschikbaar - index_title: TRACKS::Statistiek actions_dow_30days_title: Dag van de week (laatste 30 dagen) - actions_day_of_week_legend: + actions_day_of_week_legend: number_of_actions: Aantal acties day_of_week: Dag van de week + within_one: Binnen 1 spread_of_running_actions_for_visible_contexts: Verdeling van actieve acties voor zichtbare contexten - totals_active_project_count: Van deze zijn %{count} actieve projecten actions_last_year: Acties in de afgelopen jaren totals_blocked_actions: "%{count} zijn afhankelijk van de voltooiing van hun acties." totals_unique_tags: Van deze tags zijn %{count} uniek. - running_time_all_legend: + totals_active_project_count: Van deze zijn %{count} actieve projecten + running_time_all_legend: actions: Acties running_time: Looptijd van een actie (weken). Klik op een balk voor meer info percentage: Percentage other_actions_label: (anderen) totals_hidden_project_count: "%{count} zijn verborgen" time_of_day: Tijd van de dag (alle acties) - todos: - error_starring_recurring: Kon niet de ster van deze terugkerende actie niet omzetten \'%{description}\' + todos: show_from: Toon vanaf + error_starring_recurring: Kon niet de ster van deze terugkerende actie niet omzetten \'%{description}\' recurring_action_deleted: Actie werd verwijderd. Omdat deze actie herhalend is. werd een nieuwe actie toegevoegd completed_actions: Voltooide acties - blocked_by: Geblokkeerd door %{predecessors} completed_recurring: Afgesloten terugkerende todos added_new_next_action: Nieuwe actie toegevoegd completed_rest_of_previous_month: Afgerond in de rest van de vorige maand + blocked_by: Geblokkeerd door %{predecessors} + unable_to_add_dependency: Niet in staat om de afhankelijkheid toe te voegen star_action: Markeer deze actie met een ster completed_recurrence_completed: Er is geen actie na de terugkerende actie die u new verwijderd heeft. De herhaling is voltooid defer_date_after_due_date: Uitsteldatum is na de vervaldag. Gelieve vervaldag bewerken alvorens uitsteldatum aan te passen. - unable_to_add_dependency: Niet in staat om de afhankelijkheid toe te voegen done: Voltooid? star_action_with_description: markeer de actie '%{description}' met een ster tagged_with: gelabeld met ‘%{tag_name}’ completed: Afgerond no_deferred_actions_with: Geen uitgestelde acties met de tag '%{tag_name}' no_hidden_actions: Momenteel zijn er geen verborgen acties gevonden - action_due_on: (deadline actie op %{date}) edit_action_with_description: Bewerk de actie '%{description}' - remove_dependency: Verwijder afhankelijkheid (zal niet de actie zelf verwijderen) + action_due_on: (deadline actie op %{date}) archived_tasks_title: "TRACKS:: Gearchiveerde voltooide taken" + remove_dependency: Verwijder afhankelijkheid (zal niet de actie zelf verwijderen) list_incomplete_next_actions: Toon onvoltooide acties - tags: Tags (gescheiden door komma's) action_deleted_success: Actie succesvol verwijderd - add_another_dependency: Nog een afhankelijkheid toevoegen + tags: Tags (gescheiden door komma's) + delete_recurring_action_title: Verwijder de terugkerende actie new_related_todo_created: Een nieuwe actie is toegevoegd, die behoort bij deze terugkerende todo context_changed: Context veranderd in '%{name}' mobile_todos_page_title: Alle acties - delete_recurring_action_title: Verwijder de terugkerende actie + add_another_dependency: Nog een afhankelijkheid toevoegen + next_action_needed: U dient ten minste een actie in te vullen removed_predecessor: "'%{successor}' is verwijderd als afhankelijkheid van '%{predecessor}'." recurring_actions_title: TRACKS::Terugkerende acties - next_action_needed: U dient ten minste een actie in te vullen + action_deleted_error: Verwijderen van de actie is mislukt action_saved: Actie opgeslagen scheduled_overdue: Gepland om %{days} dagen geleden te tonen - action_deleted_error: Verwijderen van de actie is mislukt edit_action: Actie bewerken added_new_context: Nieuwe context toegevoegd next_actions_description: "Filter:" - older_completed_items: Oudere voltooide items list_incomplete_next_actions_with_limit: Toont de laatste %{count} onvoltooide acties set_to_pending: "'%{task}' als wachtend ingesteld" added_new_project: Nieuw project toegevoegd - next_actions_title_additions: + next_actions_title_additions: completed: acties voltooid due_today: deadline vandaag due_within_a_week: deadline binnen een week - task_list_title: TRACKS::Toon acties - edit_recurring_todo: Bewerk herhalende actie - append_in_this_project: in dit project - error_deleting_item: Er is een fout opgetreden bij het verwijderen van het item '%{description}' + older_completed_items: Oudere voltooide items no_actions_due_this_week: Geen acties met deadline in rest van deze week + append_in_this_project: in dit project + edit_recurring_todo: Bewerk herhalende actie + error_deleting_item: Er is een fout opgetreden bij het verwijderen van het item '%{description}' + task_list_title: TRACKS::Toon acties + completed_last_day: Voltooid in de laatste 24 uur + recurring_pattern_removed: Het herhalingspatroon is verwijderd van %{count} no_recurring_todos: Momenteel zijn er geen terugkerende acties error_completing_todo: Er was een fout bij het voltooien / activeren van de terugkerende actie '%{description}' - recurring_pattern_removed: Het herhalingspatroon is verwijderd van %{count} convert_to_project: Maak project no_deferred_pending_actions: Momenteel zijn er geen uitgestelde of wachtende acties delete_recurring_action_confirm: Weet u zeker dat u wilt de terugkerende actie '%{description}' wilt verwijderen? - completed_last_day: Voltooid in de laatste 24 uur - all_completed: Alle afgeronde acties - error_saving_recurring: Er is een fout opgetreden het opslaan van de terugkerende actie '%{description}' show_in_days: Toon over %{days} dagen no_project: -- Geen project -- + error_saving_recurring: Er is een fout opgetreden het opslaan van de terugkerende actie '%{description}' completed_more_than_x_days_ago: Voltooid meer dan %{count} dagen geleden + all_completed: Alle afgeronde acties feed_title_in_context: in context '%{context}' new_related_todo_created_short: een nieuwe actie gemaakt edit: Bewerken - completed_tagged_page_title: "TRACKS:: Afgeronde acties met tag %{tag_name}" older_than_days: Ouder dan %{count} dagen + completed_tagged_page_title: "TRACKS:: Afgeronde acties met tag %{tag_name}" pending: Wachtend completed_actions_with: Afgeronde acties met de tag %{tag_name} - completed_tasks_title: TRACKS::Voltooide taken deleted_success: De actie werd met succes verwijderd. + completed_tasks_title: TRACKS::Voltooide taken feed_title_in_project: In het project '%{project}' clear_due_date: Maak deadline leeg error_removing_dependency: Er is een fout opgetreden het verwijderen van de afhankelijke actie hidden_actions: Verborgen acties + recurrence_period: Herhaling periode was_due_on_date: had deadline op %{date} show_on_date: Toon op %{date} - recurrence_period: Herhaling periode deferred_actions_with: Uitgestelde acties met de tag '%{tag_name}' confirm_delete: Weet u zeker dat u de actie '%{description}' wilt verwijderen? recurring_deleted_success: De recurrente actie is succesvol verwijderd. - deferred_tasks_title: TRACKS::Tickler next_actions_title: Tracks - Acties next_action_description: Actie beschrijving + deferred_tasks_title: TRACKS::Tickler no_completed_actions_with: Geen voltooide acties met de tag '%{tag_name}' clear_show_from_date: Maak de datum Tonen Vanaf leeg + unresolved_dependency: De waarde die u ingevoerd heeft in het afhankelijkheden veld is niet herleidbaar naar een bestaande actie. Deze waarde wordt niet bewaard met de rest van de actie. Doorgaan? calendar_page_title: TRACKS::Agenda in_hidden_state: in verborgen toestand - unresolved_dependency: De waarde die u ingevoerd heeft in het afhankelijkheden veld is niet herleidbaar naar een bestaande actie. Deze waarde wordt niet bewaard met de rest van de actie. Doorgaan? show_today: Toon vandaag no_actions_found_title: Geen acties gevonden - next_actions_due_date: + next_actions_due_date: overdue_by: Over deadline met %{days} dag - due_today: Deadline vandaag due_in_x_days: Deadline over %{days} dagen + due_today: Deadline vandaag overdue_by_plural: Over deadline met %{days} dagen due_tomorrow: Deadline morgen completed_last_x_days: Voltooid in de laatste %{count} dagen no_actions_with: Momenteel zijn er geen onvoltooide acties met de tag '%{tag_name}' - defer_x_days: + defer_x_days: one: Een dag uitstellen other: "%{count} dagen uitstellen" added_new_next_action_singular: Nieuwe actie toegevoegd no_completed_actions: Momenteel zijn er geen voltooide acties. - feeds: + feeds: completed: "Voltooid: %{date}" due: "Deadline: %{date}" deferred_pending_actions: Uitgestelde/wachtende acties - has_x_pending: + has_x_pending: one: Heeft een wachtende actie other: Heeft %{count} wachtende acties delete_action: Verwijder actie error_deleting_recurring: Er is een fout opgetreden bij het verwijderen van het item \'%{description}\' recurring_todos: Terugkerende acties delete: Verwijder - cannot_add_dependency_to_completed_todo: Kan deze actie niet als een afhankelijkheid van een voltooide actie toevoegen! drag_action_title: Sleep naar een andere actie om deze afhankelijk te maken van die actie + cannot_add_dependency_to_completed_todo: Kan deze actie niet als een afhankelijkheid van een voltooide actie toevoegen! no_last_completed_actions: Geen afgeronde acties gevonden depends_on: Hangt af van - tickler_items_due: + tickler_items_due: one: Een tickler item wordt nu zichtbaar - vernieuw de pagina om het te zien. other: "%{count} tickerl items zijn nu zichtbaar - vernieuw de pagina om ze te zien." action_marked_complete: De actie '%{description}' werd gemarkeerd als %{completed} + completed_rest_of_week: Afgerond in de rest van deze week completed_today: Vandaag afgerond added_new_next_action_plural: Nieuwe acties toegevoegd new_related_todo_not_created_short: een nieuwe actie is niet gemaakt - completed_rest_of_week: Afgerond in de rest van deze week error_starring: Kon niet de ster van deze actie niet omzetten \'%{description}\' show_tomorrow: Toon morgen - calendar: + calendar: get_in_ical_format: Ontvang deze agenda in iCal-formaat due_next_week: Deadline volgende week no_actions_due_next_week: Geen acties met deadline in volgende week due_this_week: Deadline in rest van deze week - due_today: Deadline vandaag no_actions_due_today: Geen acties met deadline vandaag + due_today: Deadline vandaag due_next_month_and_later: Deadline in %{month} en later no_actions_due_after_this_month: Geen acties met deadline na deze maand no_actions_due_this_month: Geen acties met deadline in de rest van deze maand due_this_month: Deadline in rest van %{month} - added_dependency: "%{dependency} als afhankelijkheid toegevoegd." + tagged_page_title: TRACKS::Tagged met '%{tag_name}' action_deferred: De actie '%{description}' is uitgesteld - recurrence: - every_work_day: Elke werkdag + recurrence: ends_on_number_times: Eindigt na %{number} keer ends_on_date: Eindigt op %{date} + every_work_day: Elke werkdag recurrence_on_due_date: de datum dat deadline van de actie is weekly_options: Instellingen voor de wekelijkse terugkerende acties - monthly_options: Instellingen voor maandelijks terugkerende acties weekly: Wekelijks + monthly_options: Instellingen voor maandelijks terugkerende acties + daily_options: Instellingen voor dagelijks terugkerende acties monthly: Maandelijks starts_on: Begint op - daily_options: Instellingen voor dagelijks terugkerende acties show_option_always: altijd daily: Dagelijks - pattern: + pattern: third: derde - month_names: - - + month_names: + - - januari - februari - maart @@ -511,15 +513,15 @@ nl: - december every_n: elke %{n} second: tweede - on_day_n: op dag %{n} every_xth_day_of_every_n_months: elke %{x} %{day} van elke %{n_months} - from: vanaf + on_day_n: op dag %{n} weekly: wekelijks + from: vanaf every_day: elke dag last: laatste the_xth_day_of_month: de %{x} %{day} van %{month} times: voor %{number} keer - day_names: + day_names: - zondag - maandag - dinsdag @@ -542,163 +544,163 @@ nl: show_options: Toon de actie weekly_every_number_week: Herhaalt elke %{number} weken op yearly_every_xth_day: De %{day} %{day_of_week} van %{month} + yearly_options: Instellingen voor jaarlijks terugkerende acties + show_days_before: "%{days} dagen v\xC3\xB3\xC3\xB3r de deadline van actie" from_tickler: de datum dat de actie uit de tickler komt (geen deadline ingesteld) no_end_date: Geen einddatum day_x_on_every_x_month: Dag %{day} op elke %{month} maand - yearly_options: Instellingen voor jaarlijks terugkerende acties - show_days_before: "%{days} dagen v\xC3\xB3\xC3\xB3r de deadline van actie" monthly_every_xth_day: De %{day} %{day_of_week} van elke %{month} maand yearly: Jaarlijks - tagged_page_title: TRACKS::Tagged met '%{tag_name}' no_completed_recurring: Momenteel zijn er geen voltooide terugkerende acties + added_dependency: "%{dependency} als afhankelijkheid toegevoegd." all_completed_tagged_page_title: "TRACKS:: Alle afgeronde acties met tag %{tag_name}" - recurrence_completed: Er is geen volgende actie na de terugkerende actie die u zojuist hebt voltooid. De herhaling is voltooid no_deferred_actions: Momenteel zijn er geen uitgestelde acties. completed_rest_of_month: Afgerond in de rest van deze maand + recurrence_completed: Er is geen volgende actie na de terugkerende actie die u zojuist hebt voltooid. De herhaling is voltooid + error_toggle_complete: Kon deze actie niet als afgerond markeren no_actions_found: Momenteel zijn er geen onafgeronde acties. in_pending_state: in wachtende toestand - error_toggle_complete: Kon deze actie niet als afgerond markeren due: Deadline action_marked_complete_error: De actie '%{description}' is niet gemarkeerd als %{completed} vanwege een fout op de server. - depends_on_separate_with_commas: Afhankelijk van (gescheiden door komma's) - recurring_action_saved: Terugkerende actie opgeslagen - action_saved_to_tickler: Actie opgeslagen in tickler - completed_in_archive: + completed_in_archive: one: Er is een voltooide actie in het archief. other: Er zijn %{count} afgeronde acties in het archief. + no_incomplete_actions: Er zijn geen onvoltooide acties + depends_on_separate_with_commas: Afhankelijk van (gescheiden door komma's) + action_saved_to_tickler: Actie opgeslagen in tickler + recurring_action_saved: Terugkerende actie opgeslagen to_tickler: naar tickler - next_actions_description_additions: + next_actions_description_additions: completed: in de afgelopen %{count} dagen due_date: met een deadline %{due_date} of eerder overdue: Achterstallig add_new_recurring: Voeg een nieuwe terugkerende actie toe - no_incomplete_actions: Er zijn geen onvoltooide acties - notes: + notes: + in_project: "In:" delete_note_title: Verwijder de notitie '%{id}' delete_confirmation: Weet u zeker dat u de notitie '%{id}' wilt verwijderen? delete_item_title: Verwijder item - in_project: "In:" - deleted_note: Verwijder notitie '%{id}' note_link_title: Toon notitie %{id} show_note_title: Toon notitie + deleted_note: Verwijder notitie '%{id}' edit_item_title: Item bewerken note_location_link: "In:" no_notes_available: "Momenteel zijn er geen notities: voeg notities toe aan projecten vanaf de individuele project pagina's." note_header: Notitie %{id} delete_note_confirm: Weet u zeker dat u de notitie '%{id}' wilt verwijderen? - states: + states: hidden_plural: Verborgen review_plural: Gedateerde stalled: Vastgelopen completed: Afgerond current: Bijgewerkt - review: Gedateerde completed_plural: Afgeronde + review: Gedateerde blocked_plural: Geblokkeerde blocked: Geblokkeerd - visible_plural: Zichtbare stalled_plural: Vastgelopen + visible_plural: Zichtbare active_plural: Actieve visible: Zichtbaar hidden: Verborgen current_plural: Bijgewerkte active: Actief - errors: + errors: user_unauthorized: "401 Unauthorized: Alleen administratieve gebruikers mogen deze functie gebruiken." - projects: + projects: + was_marked_hidden: is gemarkeerd als verborgen + edit_project_title: Bewerk project default_tags_removed_notice: De standaard tags zijn verwijderd default_context_set: Stel project standaard context in op %{default_context} no_actions_in_project: Momenteel zijn er geen onafgeronde acties in dit project deferred_actions: Uitgestelde acties voor dit project - was_marked_hidden: is gemarkeerd als verborgen - edit_project_title: Bewerk project + all_completed_tasks_title: TRACKS::Toon alle afgeronde acties in het project '{project_name}' page_title: "TRACKS:: Project: %{project}" hide_form: Verberg formulier - all_completed_tasks_title: TRACKS::Toon alle afgeronde acties in het project '{project_name}' + no_notes_attached: Momenteel zijn er geen notities toegevoegd aan dit project + show_form_title: Maak een nieuw project deferred_actions_empty: Er zijn geen uitgestelde acties voor dit project this_project: Dit project project_state: Project is %{state}. list_completed_projects: TRACKS::Toon afgeronde projecten to_new_project_page: Ga naar de nieuwe projectpagina - no_notes_attached: Momenteel zijn er geen notities toegevoegd aan dit project - show_form_title: Maak een nieuw project - no_last_completed_projects: Geen afgeronde projecten gevonden no_last_completed_recurring_todos: Geen afgeronde herhalende acties gevonden todos_append: in dit project + no_last_completed_projects: Geen afgeronde projecten gevonden notes: Notities + notes_empty: Er zijn geen notities voor dit project no_projects: Momenteel zijn er geen projecten hide_form_title: Verberg nieuw project formulier list_reviews: TRACKS::Evaluatie - notes_empty: Er zijn geen notities voor dit project + delete_project: Project verwijderen completed_actions_empty: Er zijn nog geen afgeronde acties voor dit project with_no_default_context: zonder standaard context - delete_project: Project verwijderen - delete_project_confirmation: Weet u zeker dat u wilt het project '%{name} wilt verwijderen? - with_default_context: met een standaard context '%{context_name}' show_form: Toevoegen van een project actions_in_project_title: Acties in dit project + delete_project_confirmation: Weet u zeker dat u wilt het project '%{name} wilt verwijderen? + with_default_context: met een standaard context '%{context_name}' + add_note: Een notitie toevoegen + add_project: Voeg project toe with_default_tags: en met '%{tags}' als de standaard tags is_active: is actief list_projects: "TRACKS:: Overzicht van projecten" + settings: Instellingen completed_projects: Voltooide projecten set_default_tags_notice: Stel project standaard tags in op %{default_tags} project_saved_status: Project opgeslagen - settings: Instellingen - add_note: Een notitie toevoegen - add_project: Voeg project toe + delete_project_title: Verwijder het project hidden_projects: Verborgen projecten completed_tasks_title: TRACKS::Toon afgeronde acties in het project '%{project_name}' - delete_project_title: Verwijder het project + was_marked_complete: is gemarkeerd als voltooid default_context_removed: Standaard context verwijderd completed_actions: Afgeronde acties voor dit project add_note_submit: Notitie toevoegen - was_marked_complete: is gemarkeerd als voltooid - active_projects: Actieve projecten - no_default_context: Dit project heeft geen standaard context - with_no_default_tags: en zonder standaard tags edit_project_settings: Bewerk project instellingen - state: Dit project is %{state} status_project_name_changed: Naam van het project werd gewijzigd + active_projects: Actieve projecten + state: Dit project is %{state} + no_default_context: Dit project heeft geen standaard context default_context: De standaard context voor dit project is %{context} - preferences: - open_id_url: Uw OpenID URL is + with_no_default_tags: en zonder standaard tags + preferences: change_identity_url: Verander uw Identity URL staleness_starts_after: Markeren openstaande acties begint na %{days} dagen + open_id_url: Uw OpenID URL is page_title: "TRACKS:: Voorkeuren" change_password: Wijzig uw wachtwoord token_description: Token (voor feeds en API gebruik) title: Uw voorkeuren - show_number_completed: Toon %{number} voltooide items is_false: Nee + show_number_completed: Toon %{number} voltooide items + edit_preferences: Voorkeuren bewerken page_title_edit: "TRACKS:: Voorkeuren bewerken" is_true: Ja password_changed: Je wachtwoord is gewijzigd, meld je opnieuw aan. - edit_preferences: Voorkeuren bewerken - generate_new_token: Genereer een nieuwe token sms_context_none: Geen + generate_new_token: Genereer een nieuwe token token_header: Uw token - current_authentication_type: Uw authenticatietype is %{auth_type} authentication_header: Uw authenticatie - change_authentication_type: Verander uw authenticatietype updated: Voorkeuren bijgewerkt + current_authentication_type: Uw authenticatietype is %{auth_type} + change_authentication_type: Verander uw authenticatietype generate_new_token_confirm: Weet u dit zeker? Het genereren van een nieuw token zal de bestaande te vervangen en dit zal het extern gebruiken van de oude token laten mislukken. - tabs: - authentication: Authenticatie + tabs: tracks_behavior: Tracks gedrag + authentication: Authenticatie profile: Profiel date_and_time: Datum en tijd - time: + time: am: ochtend - formats: + formats: default: "%A, %d %B %Y %H:%M:%S %z" time: "%H:%M" short: "%d %B %H:%M" month_day: "%d %B" long: "%A, %d. %B %Y, %H:%M" pm: middag - date: - month_names: - - + date: + month_names: + - - Januari - Februari - Maart @@ -711,7 +713,7 @@ nl: - Oktober - November - December - abbr_day_names: + abbr_day_names: - Zo - Ma - Di @@ -719,18 +721,18 @@ nl: - Do - Vr - Za - order: + order: - :day - :month - :year - formats: + formats: only_day: "%e" longer: "%A %d %B %Y" default: "%d-%m-%Y" short: "%e %b" month_day: "%B %d" long: "%e %B %Y" - day_names: + day_names: - Zondag - Maandag - Dinsdag @@ -738,8 +740,8 @@ nl: - Donderdag - Vrijdag - Zaterdag - abbr_month_names: - - + abbr_month_names: + - - Jan - Feb - Maa @@ -752,30 +754,32 @@ nl: - Okt - Nov - Dec - will_paginate: + will_paginate: previous_label: "\xC2\xABVorige" - page_entries_info: + page_entries_info: multi_page: Toon %{model} %{from} - %{to} van %{count} in totaal - single_page_html: + single_page_html: one: Toon 1 %{model} other: Toon alle %{count} %{model} zero: Geen %{model} gevonden - single_page: + single_page: one: Toon 1 %{model} other: Toon alle %{count} %{model} zero: Geen %{model} gevonden multi_page_html: Toon %{model} %{from} - %{to} van %{count} in totaal page_gap: "…" next_label: "Volgende \xC2\xBB" - support: - array: + support: + array: words_connector: "," last_word_connector: ", en" two_words_connector: en - select: + select: prompt: Selecteer - dates: - month_names: + footer: + send_feedback: Stuur reactie op %{version} + dates: + month_names: - Januari - Februari - Maart @@ -788,7 +792,7 @@ nl: - Oktober - November - December - day_names: + day_names: - Zondag - Maandag - Dinsdag @@ -796,198 +800,196 @@ nl: - Donderdag - Vrijdag - Zaterdag - shared: + shared: multiple_next_actions: Meerdere acties (een op elke regel) - make_actions_dependent: Maak acties afhankelijk van elkaar toggle_single: Voeg een actie toe + make_actions_dependent: Maak acties afhankelijk van elkaar hide_form: Verberg formulier - add_action: Actie toevoegen add_actions: Toevoegen acties + add_action: Actie toevoegen tags_for_all_actions: Tags voor alle acties (scheiden met een komma) + toggle_single_title: Voeg een nieuwe actie toe project_for_all_actions: Project voor alle acties context_for_all_actions: Context voor alle acties toggle_multi: Voeg meerdere acties toe - toggle_single_title: Voeg een nieuwe actie toe - add_context: Toevoegen context separate_tags_with_commas: gescheiden door komma's + add_context: Toevoegen context toggle_multi_title: Toggle single / multi actie formulier hide_action_form_title: Verberg nieuwe actie formulier - footer: - send_feedback: Stuur reactie op %{version} - feedlist: - actions_due_today: Acties die vandaag of eerder af moeten + feedlist: choose_context: Kies de context waar je een feed van wilt + actions_due_today: Acties die vandaag of eerder af moeten legend: Legenda rss_feed: RSS Feed ical_feed: iCal feed all_contexts: Alle contexten - all_projects: Alle projecten choose_project: Kies het project waar je een feed van wilt - active_projects_wo_next: Actieve projecten zonder acties + all_projects: Alle projecten project_needed: "Er moet ten minste \xC3\xA9\xC3\xA9n project zijn voor een feed opgevraagd kan worden" select_feed_for_project: Kies de feed voor dit project + active_projects_wo_next: Actieve projecten zonder acties active_starred_actions: Alle gesterde, actieve acties - projects_and_actions: Actieve projecten met hun acties context_needed: "Er moet eerst ten minste \xC3\xA9\xC3\xA9n context zijn voor je een feed kan opvragen" select_feed_for_context: Kies de feed voor deze context + projects_and_actions: Actieve projecten met hun acties actions_due_next_week: Acties die binnen 7 dagen afgerond moeten notice_incomplete_only: "Merk op: alle feeds laten alleen acties zien die niet afgerond zijn, tenzij anders vermeld." - last_fixed_number: Laatste %{number} acties - all_actions: Alle acties actions_completed_last_week: Acties afgerond in de afgelopen 7 dagen context_centric_actions: Feeds voor onafgeronde acties in een specifieke context plain_text_feed: Reguliere tekst feed + last_fixed_number: Laatste %{number} acties + all_actions: Alle acties project_centric: Feeds voor onafgeronde acties in een specifiek project - sidebar: + sidebar: list_name_active_contexts: Actieve contexten list_name_active_projects: Actieve projecten list_empty: Geen list_name_completed_projects: Voltooide projecten list_name_hidden_projects: Verborgen projecten list_name_hidden_contexts: Verborgen contexten - users: - destroy_successful: Gebruiker %{login} met succes verwijderd - total_contexts: Totaal aantal contexten + users: first_user_heading: "Welkom bij TRACKS. Om te beginnen, maak dan een admin account:" openid_url_verified: Je hebt %{url} met succes geverifieerd als je identiteit en uw authenticatie type OpenID opgeslagen. successfully_deleted_user: Succesvol gebruiker %{username} verwijderd auth_type_update_error: "Er was een probleem met het bijwerken van uw authenticatietype: %{error_messages}" failed_to_delete_user: Mislukt de gebruiker %{username} te verwijderen - total_projects: Totaal aantal projecten + destroy_successful: Gebruiker %{login} met succes verwijderd + total_contexts: Totaal aantal contexten signup_successful: Aanmelding succesvol voor gebruiker %{username}. new_token_generated: Nieuwe token met succes gegenereerd - no_signups_title: "TRACKS:: Geen nieuwe aanmeldingen" + total_projects: Totaal aantal projecten user_created: Gebruiker aangemaakt. change_password_submit: Wachtwoord wijzigen - password_updated: Wachtwoord bijgewerkt. + no_signups_title: "TRACKS:: Geen nieuwe aanmeldingen" manage_users: Beheren gebruikers account_signup: Aanmelden voor een account - desired_login: Gewenste login + password_updated: Wachtwoord bijgewerkt. confirm_password: Bevestig wachtwoord new_user_heading: "Registreer een nieuwe gebruiker:" - signup: Aanmelden auth_type_updated: Authenticatietype bijgewerkt. + signup: Aanmelden total_actions: Totaal aanal acties - choose_password: Kies een wachtwoord - change_password_title: TRACKS::Wachtwoord wijzigen + desired_login: Gewenste login change_auth_type_title: TRACKS::Wijzig authenticatietype change_password_prompt: Voer uw nieuwe wachtwoord in de onderstaande velden in en kies 'Wachtwoord wijzigen' om uw huidige wachtwoord met uw nieuwe te vervangen. password_confirmation_label: Bevestig wachtwoord destroy_error: Er is een fout opgetreden bij het verwijderen van de gebruiker '%{login}' + choose_password: Kies een wachtwoord + change_password_title: TRACKS::Wachtwoord wijzigen new_password_label: Nieuw wachtwoord register_with_cas: Met uw CAS gebruikersnaam label_auth_type: Authenticatietype - destroy_user: Verwijder de gebruiker total_users_count: Je hebt een totaal van %{count} gebruikers new_user_title: "TRACKS:: Aanmelden als de admin gebruiker" - you_have_to_reset_your_password: Je moet je wachtwoord opnieuw instellen + destroy_user: Verwijder de gebruiker signup_new_user: Registreer nieuwe gebruiker destroy_confirmation: "Waarschuwing: dit zal de gebruiker '%{login} verwijderen met al zijn acties, contexten, projecten en notities. Weet u zeker dat u wilt doorgaan?" + you_have_to_reset_your_password: Je moet je wachtwoord opnieuw instellen identity_url: Identiteit URL - auth_change_submit: Wijzigen authenticatietype change_authentication_type: Wijzigen authenticatietype openid_ok_pref_failed: Je hebt succesvol de %{url} geverifieerd als je identiteit, maar er was een probleem met het opslaan van uw authenticatie voorkeuren. + auth_change_submit: Wijzigen authenticatietype select_authentication_type: Selecteer uw nieuwe authenticatie type en klik op 'Wijzigen authenticatietype' om uw huidige instellingen te vervangen. total_notes: Totaal aantal notities - contexts: + contexts: delete_context_title: Verwijder context - hide_form: Verberg formulier all_completed_tasks_title: "TRACKS:: Alle voltooide acties in context '%{context_name}'" + hide_form: Verberg formulier show_form_title: Voeg een context toe - delete_context_confirmation: Weet u zeker dat u de context '%{name}' wilt verwijderen? Merk op dat dit ook alle (herhalende) acties in deze context zal verwijderen! todos_append: in deze context + delete_context_confirmation: Weet u zeker dat u de context '%{name}' wilt verwijderen? Merk op dat dit ook alle (herhalende) acties in deze context zal verwijderen! delete_context: Verwijder context edit_context: Bewerk context hide_form_title: "Verberg formulier voor nieuwe context " + hidden_contexts: Verborgen contexten no_contexts_active: Momenteel zijn er geen actieve contexten context_hide: Verberg van de start pagina? - hidden_contexts: Verborgen contexten - add_context: Context toevoegen - visible_contexts: Zichtbare contexten show_form: Maak een nieuwe context + visible_contexts: Zichtbare contexten save_status_message: Context bewaard - context_name: Context naam + add_context: Context toevoegen update_status_message: Naam van de context was veranderd - new_context_post: "' zal ook gemaakt worden. Weet u dit zeker?" + context_name: Context naam completed_tasks_title: "TRACKS:: Voltooid acties in de context '%{context_name}'" status_active: Context is actief - context_deleted: De context '%{name}' is verwijderd - no_contexts_hidden: Momenteel zijn er geen verborgen contexten + new_context_post: "' zal ook gemaakt worden. Weet u dit zeker?" new_context_pre: Nieuwe context ' no_actions: Momenteel zijn er geen onafgeronde acties in deze context last_completed_in_context: in deze context (laatste %{number}) + context_deleted: De context '%{name}' is verwijderd + no_contexts_hidden: Momenteel zijn er geen verborgen contexten status_hidden: Context is verborgen - login: - user_no_expiry: Blijf ingelogd + login: sign_in: Meld aan - login_cas: Ga naar het CAS openid_identity_url_not_found: Sorry, geen gebruiker met die identiteit URL bestaat (%{identity_url}) - cas_no_user_found: Hallo,%{username}! Je hebt nog geen account op Tracks. - cas_login: CAS Inloggen + user_no_expiry: Blijf ingelogd + login_cas: Ga naar het CAS successful_with_session_info: "Login succesvol:" please_login: Log in om Tracks te gebruiken cas_logged_in_greeting: Hallo, %{username}! U bent geauthenticeerd. + cas_no_user_found: Hallo,%{username}! Je hebt nog geen account op Tracks. + cas_login: CAS Inloggen cas_username_not_found: Sorry, geen gebruiker met die CAS gebruikersnaam bestaat (%{username}) cas_create_account: Als u willen vragen ga hier om %{signup_link} mobile_use_openid: ... if inloggen met een OpenID - cas_signup_link: Aanvragen account account_login: Account login + cas_signup_link: Aanvragen account successful: Succesvol aangemeld. Welkom terug! session_will_not_expire: sessie zal niet verlopen. session_will_expire: sessie zal verlopen na %{hours} u(u)r(en) van inactiviteit. option_separator: of, session_time_out: Sessie is verlopen. Gelieve %{link} login_standard: Ga terug naar de standaard login - unsuccessful: Login mislukt. log_in_again: opnieuw in te loggen. logged_out: Je bent afgemeld bij Tracks. login_with_openid: inloggen met een OpenID - datetime: - prompts: + unsuccessful: Login mislukt. + datetime: + prompts: minute: Minuut second: Seconden month: Maand hour: Uur day: Dag year: Jaar - distance_in_words: - less_than_x_minutes: + distance_in_words: + less_than_x_minutes: one: minder dan een minuut other: minder dan %{count} minuten zero: minder dan 1 minuut - almost_x_years: + almost_x_years: one: bijna 1 jaar other: bijna %{count} jaren - x_days: + x_days: one: 1 dag other: "%{count} dagen" - x_seconds: + x_seconds: one: 1 seconde other: "%{count} seconden" - about_x_hours: + about_x_hours: one: ongeveer 1 uur other: ongeveer %{count} uren - less_than_x_seconds: + less_than_x_seconds: one: minder dan 1 seconde other: minder dan %{count} seconden zero: minder dan 1 seconde - x_months: + x_months: one: 1 maand other: "%{count} maanden" - x_minutes: + x_minutes: one: 1 minuut other: "%{count} minuten" - about_x_years: + about_x_years: one: ongeveer 1 jaar other: ongeveer %{count} jaren - about_x_months: + about_x_months: one: ongeveer 1 maand other: ongeveer %{count} maanden - over_x_years: + over_x_years: one: over 1 jaar other: over %{count} jaren half_a_minute: halve minuut - search: + search: contexts_matching_query: Contexten passend bij zoekopdracht tags_matching_query: Tags passend bij zoekopdracht no_results: Uw zoekopdracht heeft geen resultaten opgeleverd. From bb8b5a4c72189138ad4e625e08a4e400f9cd09fc Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Thu, 12 Apr 2012 11:34:08 +0200 Subject: [PATCH 086/134] store rendered notes of todos in database to avoid costly rendering when you load a page --- app/controllers/application_controller.rb | 8 ---- app/helpers/application_helper.rb | 18 -------- app/helpers/todos_helper.rb | 2 +- app/models/todo.rb | 9 ++++ .../20120412072508_add_rendered_notes.rb | 26 +++++++++++ lib/tracks/utils.rb | 45 +++++++++++++++++++ 6 files changed, 81 insertions(+), 27 deletions(-) create mode 100644 db/migrate/20120412072508_add_rendered_notes.rb create mode 100644 lib/tracks/utils.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 9255fc3a..5c3d385c 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -143,14 +143,6 @@ class ApplicationController < ActionController::Base return json_elems end - # Uses RedCloth to transform text using either Textile or Markdown Need to - # require redcloth above RedCloth 3.0 or greater is needed to use Markdown, - # otherwise it only handles Textile - # - def markdown(text) - RedCloth.new(text).to_html - end - # Here's the concept behind this "mobile content negotiation" hack: In # addition to the main, AJAXy Web UI, Tracks has a lightweight low-feature # 'mobile' version designed to be suitablef or use from a phone or PDA. It diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 3744e1f2..f7a2e696 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -189,24 +189,6 @@ module ApplicationHelper end end - AUTO_LINK_MESSAGE_RE = %r{message://<[^>]+>} unless const_defined?(:AUTO_LINK_MESSAGE_RE) - - # Converts message:// links to href. This URL scheme is used on Mac OS X - # to link to a mail message in Mail.app. - def auto_link_message(text) - text.gsub(AUTO_LINK_MESSAGE_RE) do - href = $& - left, right = $`, $' - # detect already linked URLs and URLs in the middle of a tag - if left =~ /<[^>]+$/ && right =~ /^[^>]*>/ - # do not change string; URL is alreay linked - href - else - content = content_tag(:a, h(href), :href => h(href)) - end - end - end - def format_note(note) note = auto_link_message(note) note = markdown(note) diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index 37c884ee..20e04191 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -64,7 +64,7 @@ module TodosHelper def collapsed_notes_image(todo) link = link_to(image_tag( 'blank.png', :width=>'16', :height=>'16', :border=>'0' ), "#", {:class => 'show_notes', :title => 'Show notes'}) - notes = content_tag(:div, {:class => "todo_notes", :id => dom_id(todo, 'notes'), :style => "display:none"}) { format_note(todo.notes) } + notes = content_tag(:div, {:class => "todo_notes", :id => dom_id(todo, 'notes'), :style => "display:none"}) { todo.rendered_notes } return link+notes end diff --git a/app/models/todo.rb b/app/models/todo.rb index 201234c2..88687ac1 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -1,5 +1,6 @@ class Todo < ActiveRecord::Base + before_save :render_note after_save :save_predecessors # associations @@ -396,4 +397,12 @@ class Todo < ActiveRecord::Base return todo end + def render_note + unless notes.nil? + rendered_notes = Tracks::Utils.render_text(notes) + else + rendered_notes = nil + end + end + end diff --git a/db/migrate/20120412072508_add_rendered_notes.rb b/db/migrate/20120412072508_add_rendered_notes.rb new file mode 100644 index 00000000..25fa4603 --- /dev/null +++ b/db/migrate/20120412072508_add_rendered_notes.rb @@ -0,0 +1,26 @@ +class AddRenderedNotes < ActiveRecord::Migration + def self.up + add_column :todos, 'rendered_notes', :text + + puts "-- Clearing show_from dates from completed todos" + # clear up completed todos that have show_from set. These could have been left over from before the AASM migration + Todo.completed.find(:all, :conditions =>[ "NOT(show_from IS NULL)"]).each {|t| t.show_from=nil; t.save!} + puts "-- Generating new column values from notes. This may take a while." + # Call save! on each todo to force generation of rendered_todos + i=0; max = Todo.all.count; start = Time.now + Todo.all.each do |todo| + todo.save(false) + i = i + 1 + if i%250==0 + elapsed_sec = (Time.now-start) + remaining = (elapsed_sec / i)*(max-i) + puts "Progress: #{i} / #{max} (#{(i.to_f/max.to_f*100.0).floor}%) ETA=#{remaining.floor}s" + end + end + puts "Done: #{i} / #{max}" + end + + def self.down + remove_column :todos, 'rendered_notes' + end +end diff --git a/lib/tracks/utils.rb b/lib/tracks/utils.rb new file mode 100644 index 00000000..01368a03 --- /dev/null +++ b/lib/tracks/utils.rb @@ -0,0 +1,45 @@ +module Tracks + + class Utils + AUTO_LINK_MESSAGE_RE = %r{message://<[^>]+>} unless const_defined?(:AUTO_LINK_MESSAGE_RE) + + # Converts message:// links to href. This URL scheme is used on Mac OS X + # to link to a mail message in Mail.app. + def self.auto_link_message(text) + text.gsub(AUTO_LINK_MESSAGE_RE) do + href = $& + left, right = $`, $' + # detect already linked URLs and URLs in the middle of a tag + if left =~ /<[^>]+$/ && right =~ /^[^>]*>/ + # do not change string; URL is alreay linked + href + else + content = content_tag(:a, h(href), :href => h(href)) + end + end + end + + def self.render_text(text) + rendered = Tracks::Utils.auto_link_message(text) + rendered = markdown(rendered) + rendered = ActionController::Base.helpers.auto_link(rendered, :link => :urls) + + # add onenote and message protocols + Sanitize::Config::RELAXED[:protocols]['a']['href'] << 'onenote' + Sanitize::Config::RELAXED[:protocols]['a']['href'] << 'message' + + rendered = Sanitize.clean(rendered, Sanitize::Config::RELAXED) + return rendered + 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 self.markdown(text) + RedCloth.new(text).to_html + end + + end + +end \ No newline at end of file From 12d8915eda82cd73478d99e49d67005451d3e70e Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Thu, 12 Apr 2012 12:47:25 +0200 Subject: [PATCH 087/134] Get all non-cucumber tests passing --- app/controllers/application_controller.rb | 2 +- app/controllers/todos_controller.rb | 2 +- app/helpers/application_helper.rb | 13 ------------- app/helpers/projects_helper.rb | 2 +- app/models/todo.rb | 6 +++--- lib/tracks/utils.rb | 12 +++++++++--- test/unit/todo_test.rb | 15 +++++++++++++++ 7 files changed, 30 insertions(+), 22 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 5c3d385c..aeae32cc 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -11,7 +11,7 @@ class ApplicationController < ActionController::Base helper :application include LoginSystem - helper_method :current_user, :prefs, :format_date, :markdown + helper_method :current_user, :prefs, :format_date layout proc{ |controller| controller.mobile? ? "mobile" : "standard" } exempt_from_layout /\.js\.erb$/ diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index fc6491a2..19a05d3c 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -1242,7 +1242,7 @@ class TodosController < ApplicationController def todo_feed_content # TODO: move view stuff into view, also the includes at the top lambda do |i| - item_notes = sanitize(markdown( i.notes )) if i.notes? + item_notes = i.rendered_notes if i.notes? due = "
        #{t('todos.feeds.due', :date => format_date(i.due))}
        \n" if i.due? done = "
        #{t('todos.feeds.completed', :date => format_date(i.completed_at))}
        \n" if i.completed? context_link = "#{ i.context.name }" diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index f7a2e696..1f318003 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -189,19 +189,6 @@ module ApplicationHelper end end - def format_note(note) - note = auto_link_message(note) - note = markdown(note) - note = auto_link(note, :link => :urls) - - # add onenote and message protocols - Sanitize::Config::RELAXED[:protocols]['a']['href'] << 'onenote' - Sanitize::Config::RELAXED[:protocols]['a']['href'] << 'message' - - note = Sanitize.clean(note, Sanitize::Config::RELAXED) - return note - end - def sidebar_html_for_titled_list (list, title) return content_tag(:h3, title+" (#{list.length})") + content_tag(:ul, sidebar_html_for_list(list)) diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 758c9c2f..0eb972eb 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -69,7 +69,7 @@ module ProjectsHelper def summary(project) project_description = '' - project_description += sanitize(markdown( project.description )) unless project.description.blank? + project_description += Tracks::Utils.render_text( project.description ) unless project.description.blank? project_description += content_tag(:p, "#{count_undone_todos_phrase(p)}. " + t('projects.project_state', :state => project.state) ) diff --git a/app/models/todo.rb b/app/models/todo.rb index 88687ac1..4f22077e 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -398,10 +398,10 @@ class Todo < ActiveRecord::Base end def render_note - unless notes.nil? - rendered_notes = Tracks::Utils.render_text(notes) + unless self.notes.nil? + self.rendered_notes = Tracks::Utils.render_text(notes) else - rendered_notes = nil + self.rendered_notes = nil end end diff --git a/lib/tracks/utils.rb b/lib/tracks/utils.rb index 01368a03..86c17751 100644 --- a/lib/tracks/utils.rb +++ b/lib/tracks/utils.rb @@ -14,7 +14,7 @@ module Tracks # do not change string; URL is alreay linked href else - content = content_tag(:a, h(href), :href => h(href)) + content = helpers.content_tag(:a, h(href), :href => h(href)) end end end @@ -22,7 +22,7 @@ module Tracks def self.render_text(text) rendered = Tracks::Utils.auto_link_message(text) rendered = markdown(rendered) - rendered = ActionController::Base.helpers.auto_link(rendered, :link => :urls) + rendered = helpers.auto_link(rendered, :link => :urls) # add onenote and message protocols Sanitize::Config::RELAXED[:protocols]['a']['href'] << 'onenote' @@ -39,7 +39,13 @@ module Tracks def self.markdown(text) RedCloth.new(text).to_html end - + + private + + def self.helpers + ActionController::Base.helpers + end + end end \ No newline at end of file diff --git a/test/unit/todo_test.rb b/test/unit/todo_test.rb index 48ee7c07..bfd8116a 100644 --- a/test/unit/todo_test.rb +++ b/test/unit/todo_test.rb @@ -386,4 +386,19 @@ class TodoTest < ActiveSupport::TestCase assert !recent_created_todos.include?(todo_old) end + def test_notes_are_rendered_on_save + user = @completed.user + todo = user.todos.create(:description => "test", :context => @completed.context) + + assert_nil todo.notes + assert_nil todo.rendered_notes + + todo.notes = "*test*" + todo.save! + todo.reload + + assert_equal "*test*", todo.notes + assert_equal "

        test

        ", todo.rendered_notes + end + end From a4d98a705a37f479ebf399ac9ee9049bb36fedd1 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Thu, 12 Apr 2012 13:36:49 +0200 Subject: [PATCH 088/134] make cucumber scenarios pass --- app/views/notes/_note_details.rhtml | 2 +- app/views/projects/_project_settings.rhtml | 2 +- app/views/todos/mobile_show_notes.rhtml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/notes/_note_details.rhtml b/app/views/notes/_note_details.rhtml index bd70567a..bd83f112 100644 --- a/app/views/notes/_note_details.rhtml +++ b/app/views/notes/_note_details.rhtml @@ -1,5 +1,5 @@ <% note = note_details -%> -
        <%= format_note(note.body) %>
        +
        <%= Tracks::Utils.render_text(note.body) %>
        <% unless project.description.blank? -%> -
        <%= format_note(project.description) %>
        +
        <%= Tracks::Utils.render_text(project.description) %>
        <% end -%>
        diff --git a/app/views/recurring_todos/index.html.erb b/app/views/recurring_todos/index.html.erb index 7f7da84c..6ae1fd5d 100644 --- a/app/views/recurring_todos/index.html.erb +++ b/app/views/recurring_todos/index.html.erb @@ -10,7 +10,7 @@
        - +

        <%= t('common.last') %> <%= t('todos.completed_recurring') %>

        diff --git a/app/views/stats/_contexts.rhtml b/app/views/stats/_contexts.rhtml index a55b7b5d..b09989eb 100755 --- a/app/views/stats/_contexts.rhtml +++ b/app/views/stats/_contexts.rhtml @@ -9,7 +9,9 @@ <% 1.upto 5 do |i| %><%=i-%> - - <%= i <= @actions_per_context.size ? link_to(@actions_per_context[i-1]['name'], {:controller => "contexts", :action => "show", :id => @actions_per_context[i-1]['id']}) : "n/a"%> + <%= i <= @actions_per_context.size ? + link_to(@actions_per_context[i-1]['name'], {:controller => "contexts", :action => "show", :id => @actions_per_context[i-1]['id']}) : + t('common.not_available_abbr')%> ( <%= i <= @actions_per_context.size ? @actions_per_context[i-1]['total'] : t('common.not_available_abbr')%> ) @@ -23,7 +25,9 @@ <% 1.upto 5 do |i| %><%=i-%> - - <%= i <= @running_actions_per_context.size ? link_to(@running_actions_per_context[i-1]['name'], {:controller => "contexts", :action => "show", :id => @running_actions_per_context[i-1]['id']}) : "n/a"-%> + <%= i <= @running_actions_per_context.size ? + link_to(@running_actions_per_context[i-1]['name'], {:controller => "contexts", :action => "show", :id => @running_actions_per_context[i-1]['id']}) : + t('common.not_available_abbr')-%> ( <%= i <= @running_actions_per_context.size ? @running_actions_per_context[i-1]['total'] : t('common.not_available_abbr')-%> ) diff --git a/app/views/stats/_projects.rhtml b/app/views/stats/_projects.rhtml index 26ceb7e4..5d0d014a 100755 --- a/app/views/stats/_projects.rhtml +++ b/app/views/stats/_projects.rhtml @@ -3,7 +3,7 @@ <% i=0 @projects_and_actions.each do |p| i+=1 -%> - <%= i -%> - <%= link_to p.name, {:controller => "projects", :action => "show", :id => p.id}%> (<%=p.count %> <%= t('common.actions_midsentence') %>)
        + <%= i -%> - <%= link_to p.name, {:controller => "projects", :action => "show", :id => p.id}%> (<%=p.count %> <%= t('common.actions_midsentence', :count => p.count) %>)
        <% end if i < 10 i.upto 10 do |j| -%> @@ -18,7 +18,7 @@ <% i=0 @projects_and_actions_last30days.each do |p| i+=1 -%> - <%= i -%> - <%= link_to p.name, {:controller => "projects", :action => "show", :id => p.id} %> (<%=p.count %> <%= t('common.actions_midsentence') %>)
        + <%= i -%> - <%= link_to p.name, {:controller => "projects", :action => "show", :id => p.id} %> (<%=p.count %> <%= t('common.actions_midsentence', :count => p.count) %>)
        <% end if i < 10 i.upto 10 do |j| -%> @@ -33,6 +33,6 @@ <% i=0 @projects_and_runtime.each do |id, name, days| i+=1 -%> - <%= i -%> - <%= link_to name, {:controller => "projects", :action => "show", :id => id} %> (<%=days %> <%= t('common.days_midsentence') %>)
        + <%= i -%> - <%= link_to name, {:controller => "projects", :action => "show", :id => id} %> (<%=days %> <%= t('common.days_midsentence', :count => days) %>)
        <% end -%>
        \ No newline at end of file diff --git a/app/views/stats/_tags.rhtml b/app/views/stats/_tags.rhtml index 5f5f2fe7..a2c8b945 100755 --- a/app/views/stats/_tags.rhtml +++ b/app/views/stats/_tags.rhtml @@ -10,7 +10,7 @@ <%= link_to t.name, {:controller => "todos", :action => "tag", :id => t.name}, {:style => "font-size: " + (9 + 2*(t.count.to_i-@tags_min)/@tags_divisor).to_s + "pt", - :title => t.count.to_s+" #{t('common.actions_midsentence')}"} + :title => t.count.to_s+" #{t('common.actions_midsentence', :count => t.count)}"} -%> <% end end-%> @@ -28,7 +28,7 @@ <%= link_to t.name, {:controller => "todos", :action => "tag", :id => t.name}, {:style => "font-size: " + (9 + 2*(t.count.to_i-@tags_min_90days)/@tags_divisor_90days).to_s + "pt", - :title => t.count.to_s+" #{t('common.actions_midsentence')}"} + :title => t.count.to_s+" #{t('common.actions_midsentence', :count => t.count)}"} -%> <% end end-%> diff --git a/app/views/stats/done.html.erb b/app/views/stats/done.html.erb index c6f38371..155daccf 100644 --- a/app/views/stats/done.html.erb +++ b/app/views/stats/done.html.erb @@ -1,6 +1,6 @@
        - +

        <%= t('common.last') %> <%= t('states.completed_plural' )%> <%= t('common.actions') %>

        @@ -12,15 +12,15 @@
        - -

        + +

        <%= t('common.last') %> <%= t('states.completed_plural' )%> <%= t('common.projects') %> -

        + <% if @last_completed_projects.empty? -%>

        <%= t('projects.no_last_completed_projects') %>

        <% else -%>
        - <%= render :partial => '/projects/project_listing', + <%= render :partial => '/projects/project_listing', :collection => @last_completed_projects, :locals => {:suppress_drag_handle => true} %> @@ -29,17 +29,15 @@
        - -

        + +

        <%= t('common.last') %> <%= t('states.completed_plural' )%> <%= t('common.recurring_todos') %> -

        + <% if @last_completed_recurring_todos.empty? -%>

        <%= t('projects.no_last_completed_recurring_todos') %>

        <% else -%> <%= render :partial => '/recurring_todos/recurring_todo', :collection => @last_completed_recurring_todos %> <% end -%>
        - - - -
        + +
        diff --git a/app/views/todos/_completed.rhtml b/app/views/todos/_completed.rhtml index f54601fc..b1a79823 100644 --- a/app/views/todos/_completed.rhtml +++ b/app/views/todos/_completed.rhtml @@ -3,7 +3,7 @@ suppress_project ||= false -%>
        - +

        <% if collapsible %> <%= image_tag("collapse.png") %> @@ -18,4 +18,4 @@ <%= render :partial => "todos/todo", :collection => completed, :locals => { :parent_container_type => "completed", :suppress_context => suppress_context, :suppress_project => suppress_project } %>

        -
        \ No newline at end of file +
        \ No newline at end of file diff --git a/app/views/todos/all_done.html.erb b/app/views/todos/all_done.html.erb index b758bb4f..5ecc4572 100644 --- a/app/views/todos/all_done.html.erb +++ b/app/views/todos/all_done.html.erb @@ -1,6 +1,6 @@ <% paginate_options = { - :class => :add_note_link, + :class => :add_note_link, :previous_label => '« '+ t('common.previous'), :next_label => t('common.next')+' »', :inner_window => 2 @@ -19,4 +19,4 @@ <%= will_paginate @done, paginate_options %> -
        + diff --git a/app/views/todos/done.html.erb b/app/views/todos/done.html.erb index b5a24941..aecc4b2a 100644 --- a/app/views/todos/done.html.erb +++ b/app/views/todos/done.html.erb @@ -26,6 +26,6 @@ <% end -%> -

        You can see all completed actions <%= link_to "here", determine_all_done_path %>

        +

        <%= t('todos.see_all_completed', :link => link_to(t("todos.all_completed_here"), determine_all_done_path)) %>

        - + diff --git a/config/initializers/i18n-config.rb b/config/initializers/i18n-config.rb new file mode 100644 index 00000000..d9f738a6 --- /dev/null +++ b/config/initializers/i18n-config.rb @@ -0,0 +1,36 @@ +module I18n::Backend::Pluralization + # rules taken from : http://www.gnu.org/software/hello/manual/gettext/Plural-forms.html + def pluralize(locale, entry, n) + return entry unless entry.is_a?(Hash) && n + if n == 0 && entry.has_key?(:zero) + key = :zero + else + key = case locale + when :pl # Polish + n==1 ? :one : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? :few : :other + when :cs, :sk # Czech, Slovak + n==1 ? :one : (n>=2 && n<=4) ? :few : :other + when :lt # Lithuanian + n%10==1 && n%100!=11 ? :one : n%10>=2 && (n%100<10 || n%100>=20) ? :few : :other + when :lv # Latvian + n%10==1 && n%100!=11 ? :one : n != 0 ? :few : :other + when :ru, :uk, :sr, :hr # Russian, Ukrainian, Serbian, Croatian + n%10==1 && n%100!=11 ? :one : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? :few : :other + when :sl # Slovenian + n%100==1 ? :one : n%100==2 ? :few : n%100==3 || n%100==4 ? :many : :other + when :ro # Romanian + n==1 ? :one : (n==0 || (n%100 > 0 && n%100 < 20)) ? :few : :other + when :gd # Gaeilge + n==1 ? :one : n==2 ? :two : :other; + # add another language if you like... + else + n==1 ? :one : :other # default :en + end + end + raise InvalidPluralizationData.new(entry, n) unless entry.has_key?(key) + entry[key] + end +end + +I18n::Backend::Simple.send(:include, I18n::Backend::Pluralization) +I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) \ No newline at end of file diff --git a/config/locales/cz.yml b/config/locales/cz.yml index f6db1b3b..17fa2b21 100755 --- a/config/locales/cz.yml +++ b/config/locales/cz.yml @@ -1,5 +1,68 @@ --- cz: + layouts: + toggle_contexts_title: "Zobraz\xC3\xAD/skryje sbalen\xC3\xA9 kontexty" + toggle_contexts: "P\xC5\x99epnout sbalen\xC3\xA9 kontexty" + toggle_notes: "Zobrazit/skr\xC3\xBDt pozn\xC3\xA1mky" + next_actions_rss_feed: "RSS feed aktu\xC3\xA1ln\xC3\xADch \xC3\xBAkol\xC5\xAF" + toggle_notes_title: "Zobraz\xC3\xAD/skryje v\xC5\xA1echny pozn\xC3\xA1mky" + mobile_navigation: + new_action: !binary | + MC1Ob3bDvSDDumtvbA== + + logout: "Odhl\xC3\xA1sit" + feeds: Feedy + starred: !binary | + NC1IdsSbemRpxI1reQ== + + projects: 3-Projekty + tickler: Tickler + contexts: 2-Kontexty + home: "1-Dom\xC5\xAF" + navigation: + manage_users_title: "P\xC5\x99idat nebo smazat u\xC5\xBEivatele" + recurring_todos: "Opakuj\xC3\xADc\xC3\xAD se \xC3\xBAkoly" + api_docs: REST API Dokumenty + help: "?" + feeds: Feedy + starred: "S hv\xC4\x9Bzdou" + stats: Statistiky + notes_title: "Zobrazit v\xC5\xA1echny pozn\xC3\xA1mky" + manage_users: !binary | + U3Byw6F2YSB1xb5pdmF0ZWzFrw== + + tickler_title: Tickler + admin: n/d + preferences: "Nastaven\xC3\xAD" + integrations_: Integrovat Tracks + export_title: Import a export dat + calendar_title: !binary | + S2FsZW5kw6HFmSBkYXRvdmFuw71jaCDDumtvbMWv + + feeds_title: "Seznam dostupn\xC3\xBDch feed\xC5\xAF" + stats_title: "Zobraz\xC3\xAD statistiky \xC3\xBAkol\xC5\xAF" + tickler: Tickler + home_title: !binary | + RG9txa8= + + starred_title: "Zobraz\xC3\xAD \xC3\xBAkoly s hv\xC4\x9Bzdi\xC4\x8Dkou" + recurring_todos_title: "Spr\xC3\xA1va opakovan\xC3\xBDch \xC3\xBAkol\xC5\xAF" + completed_tasks: "Hotov\xC3\xA9" + view: "Uk\xC3\xA1zat" + organize: "Spr\xC3\xA1va" + completed_tasks_title: "Hotov\xC3\xA9 \xC3\xBAkoly" + home: !binary | + RG9txa8= + + export: Export + contexts_title: Kontexty + preferences_title: "Zobraz\xC3\xAD mo\xC5\xBEnosti nastaven\xC3\xAD" + search: Hledat + review_title: "Prov\xC3\xA9st revizi" + projects_title: Projekty + calendar: !binary | + S2FsZW5kw6HFmQ== + number: format: separator: . @@ -34,80 +97,11 @@ cz: separator: . precision: 2 delimiter: "," - layouts: - toggle_contexts_title: "Zobraz\xC3\xAD/skryje sbalen\xC3\xA9 kontexty" - toggle_notes: "Zobrazit/skr\xC3\xBDt pozn\xC3\xA1mky" - toggle_contexts: "P\xC5\x99epnout sbalen\xC3\xA9 kontexty" - next_actions_rss_feed: "RSS feed aktu\xC3\xA1ln\xC3\xADch \xC3\xBAkol\xC5\xAF" - toggle_notes_title: "Zobraz\xC3\xAD/skryje v\xC5\xA1echny pozn\xC3\xA1mky" - mobile_navigation: - feeds: Feedy - new_action: !binary | - MC1Ob3bDvSDDumtvbA== - - logout: "Odhl\xC3\xA1sit" - starred: !binary | - NC1IdsSbemRpxI1reQ== - - projects: 3-Projekty - tickler: Tickler - contexts: 2-Kontexty - home: "1-Dom\xC5\xAF" - navigation: - manage_users_title: "P\xC5\x99idat nebo smazat u\xC5\xBEivatele" - api_docs: REST API Dokumenty - recurring_todos: "Opakuj\xC3\xADc\xC3\xAD se \xC3\xBAkoly" - feeds: Feedy - help: "?" - stats: Statistiky - starred: "S hv\xC4\x9Bzdou" - notes_title: "Zobrazit v\xC5\xA1echny pozn\xC3\xA1mky" - manage_users: !binary | - U3Byw6F2YSB1xb5pdmF0ZWzFrw== - - tickler_title: Tickler - admin: n/d - integrations_: Integrovat Tracks - export_title: Import a export dat - preferences: "Nastaven\xC3\xAD" - calendar_title: !binary | - S2FsZW5kw6HFmSBkYXRvdmFuw71jaCDDumtvbMWv - - feeds_title: "Seznam dostupn\xC3\xBDch feed\xC5\xAF" - completed_tasks: "Hotov\xC3\xA9" - stats_title: "Zobraz\xC3\xAD statistiky \xC3\xBAkol\xC5\xAF" - tickler: Tickler - home_title: !binary | - RG9txa8= - - starred_title: "Zobraz\xC3\xAD \xC3\xBAkoly s hv\xC4\x9Bzdi\xC4\x8Dkou" - recurring_todos_title: "Spr\xC3\xA1va opakovan\xC3\xBDch \xC3\xBAkol\xC5\xAF" - view: "Uk\xC3\xA1zat" - organize: "Spr\xC3\xA1va" - completed_tasks_title: "Hotov\xC3\xA9 \xC3\xBAkoly" - home: !binary | - RG9txa8= - - contexts_title: Kontexty - export: Export - preferences_title: "Zobraz\xC3\xAD mo\xC5\xBEnosti nastaven\xC3\xAD" - review_title: "Prov\xC3\xA9st revizi" - calendar: !binary | - S2FsZW5kw6HFmQ== - - search: Hledat - projects_title: Projekty - integrations: - opensearch_description: Prohledat Tracks - applescript_next_action_prompt: "Popis \xC3\xBAkolu:" - gmail_description: Gadget pro Tracks do Gmailu - applescript_success_after_id: "vytvo\xC5\x99en" - applescript_success_before_id: "Nov\xC3\xBD \xC3\xBAkol s ID" common: + recurring_todos: "Opakovan\xC3\xA9 \xC3\xBAkoly" back: !binary | WnDEm3Q= - recurring_todos: "Opakovan\xC3\xA9 \xC3\xBAkoly" actions: !binary | w5prb2x5 @@ -125,7 +119,6 @@ cz: second: !binary | RHJ1aMO9 - show_all: "Zobrazit v\xC5\xA1echny" none: !binary | xb3DoWRuw70= @@ -133,24 +126,44 @@ cz: dMO9ZGVu optional: "voliteln\xC3\xA9" + deferred: !binary | + b2Rsb8W+ZW7DqQ== + + show_all: "Zobrazit v\xC5\xA1echny" cancel: "Zru\xC5\xA1it" month: !binary | bcSbc8OtYw== - actions_midsentence: akce + actions_midsentence: + one: !binary | + w7prb2zFrw== + + other: !binary | + w5prb2x5 + + zero: !binary | + w5prb2x5 + + notes: "Pozn\xC3\xA1mky" server_error: Nastala chyba na serveru. forum: !binary | RsOzcnVt - notes: "Pozn\xC3\xA1mky" - last: "Posledn\xC3\xAD" projects: Projekty + last: "Posledn\xC3\xAD" + review: Revize action: !binary | w5prb2w= - review: Revize + days_midsentence: + one: den + other: !binary | + ZG7DrQ== + + zero: !binary | + ZG7DrQ== + project: Projekt - days_midsentence: dny contribute: !binary | UMWZaXNwxJt0 @@ -159,40 +172,49 @@ cz: first: !binary | UHJ2bsOt - numbered_step: Krok %{number} - errors_with_fields: !binary | - TmFzdGFseSBwb3TDrcW+ZSBzIG7DoXNsZWR1asOtY8OtbWkgcG9sw63EjWt5 - Og== + note: + one: !binary | + MSBuYSB2xJtkb23DrQ== + other: "%{count} na v\xC4\x9Bdomy" + zero: !binary | + MCBuYSB2xJtkb23DrQ== + + numbered_step: Krok %{number} create: "Vytvo\xC5\x99it" sort: by_task_count_title: "\xC5\x98adit podle po\xC4\x8Dtu \xC3\xBAkol\xC5\xAF" by_task_count_title_confirm: "Ur\xC4\x8Dit\xC4\x9B chcete \xC5\x99adit tyto projekty podle po\xC4\x8Dtu \xC3\xBAkol\xC5\xAF? St\xC3\xA1vaj\xC3\xADc\xC3\xAD po\xC5\x99ad\xC3\xAD bude ztraceno." alphabetically: "Abecedn\xC4\x9B" - alphabetically_title: "Se\xC5\x99adit projekty abecedn\xC4\x9B" sort: !binary | xZhhZGl0 + alphabetically_title: "Se\xC5\x99adit projekty abecedn\xC4\x9B" alphabetically_confirm: "Ur\xC4\x8Dit\xC4\x9B chcete \xC5\x99adit tyto projekty abecedn\xC4\x9B? St\xC3\xA1vaj\xC3\xADc\xC3\xAD po\xC5\x99ad\xC3\xAD bude ztraceno." by_task_count: "Podle po\xC4\x8Dtu \xC3\xBAkol\xC5\xAF" - months: !binary | - bcSbc8OtY2U= - - description: Popis todo: !binary | w7prb2w= + months: !binary | + bcSbc8OtY2U= + + errors_with_fields: !binary | + TmFzdGFseSBwb3TDrcW+ZSBzIG7DoXNsZWR1asOtY8OtbWkgcG9sw63EjWt5 + Og== + + description: Popis next: !binary | RGFsxaHDrQ== fourth: !binary | xIx0dnJ0w70= - context: Kontext - contexts: Kontexty drag_handle: !binary | Q0hZxaQgTcSa + context: Kontext + contexts: Kontexty + bugs: Chyby update: "Ulo\xC5\xBEit" weeks: !binary | dMO9ZG55 @@ -201,11 +223,16 @@ cz: xIx0dnJ0w70= wiki: Wiki - bugs: Chyby - ajaxError: "Chyba \xC4\x8Dten\xC3\xAD ze serveru" - not_available_abbr: "" email: Email + ajaxError: "Chyba \xC4\x8Dten\xC3\xAD ze serveru" search: Hledat + not_available_abbr: n/a + integrations: + opensearch_description: Prohledat Tracks + applescript_next_action_prompt: "Popis \xC3\xBAkolu:" + gmail_description: Gadget pro Tracks do Gmailu + applescript_success_after_id: "vytvo\xC5\x99en" + applescript_success_before_id: "Nov\xC3\xBD \xC3\xBAkol s ID" activerecord: attributes: project: @@ -221,23 +248,16 @@ cz: created_at: "Vytvo\xC5\x99eno:" updated_at: "Aktualizov\xC3\xA1n" todo: + show_from: Zobrazovat od predecessors: !binary | WsOhdmlzw60gbmE= - show_from: Zobrazovat od notes: "Pozn\xC3\xA1mky" - project: Projekt tags: Tagy + project: Projekt description: Popis context: Kontext due: "Pl\xC3\xA1nov\xC3\xA1no na" - user: - last_name: !binary | - Sm3DqW5v - - first_name: !binary | - UMWZw61qbWVuw60= - preference: show_hidden_projects_in_sidebar: "Zobrazovat skryt\xC3\xA9 projekty v sidebaru" show_hidden_contexts_in_sidebar: "Zobrazovat skryt\xC3\xA9 kontexty v sidebaru" @@ -246,8 +266,8 @@ cz: verbose_action_descriptors: "Ukecan\xC3\xA9 popisova\xC4\x8De \xC3\xBAkol\xC5\xAF" staleness_starts: "Jako pro\xC5\xA1l\xC3\xA9 ozna\xC4\x8Dit projekty star\xC5\xA1\xC3\xAD ne\xC5\xBE" mobile_todos_per_page: "\xC3\x9Akol\xC5\xAF na str\xC3\xA1nku (mobiln\xC3\xAD zobrazen\xC3\xAD)" - title_date_format: "Form\xC3\xA1t data nadpisu" show_number_completed: "Po\xC4\x8Det hotov\xC3\xBDch \xC3\xBAkol\xC5\xAF k zobrazen\xC3\xAD" + title_date_format: "Form\xC3\xA1t data nadpisu" refresh: "Interval obnoven\xC3\xAD str\xC3\xA1nky (v minut\xC3\xA1ch)" week_starts: !binary | WmHEjcOhdGVrIHTDvWRuZQ== @@ -260,13 +280,20 @@ cz: time_zone: !binary | xIxhc292w6kgcMOhc21v - show_project_on_todo_done: "Po spln\xC4\x9Bn\xC3\xAD \xC3\xBAkolu p\xC5\x99ej\xC3\xADt na projekt" sms_email: SMS email + show_project_on_todo_done: "Po spln\xC4\x9Bn\xC3\xAD \xC3\xBAkolu p\xC5\x99ej\xC3\xADt na projekt" + show_completed_projects_in_sidebar: "Zobrazovat hotov\xC3\xA9 projekty v sidebaru" first_name: !binary | Sm3DqW5v - show_completed_projects_in_sidebar: "Zobrazovat hotov\xC3\xA9 projekty v sidebaru" review_period: "Interval revize projekt\xC5\xAF" + user: + last_name: !binary | + Sm3DqW5v + + first_name: !binary | + UMWZw61qbWVuw60= + errors: models: project: @@ -306,6 +333,8 @@ cz: not_a_number: !binary | bmVuw60gxI3DrXNsbw== + full_messages: + format: "%{attribute} %{message}" template: body: !binary | TmFzdGFseSBwb3TDrcW+ZSBzIG7DoXNsZWR1asOtY8OtbWkgcG9sw63EjWt5 @@ -314,8 +343,6 @@ cz: header: one: "jedna chyba br\xC3\xA1n\xC3\xAD ulo\xC5\xBEen\xC3\xAD tohoto objektu %{model}" other: "%{count} chyb br\xC3\xA1n\xC3\xAD ulo\xC5\xBEen\xC3\xAD tohoto objektu %{model}" - full_messages: - format: "%{attribute} %{message}" data: import_successful: !binary | SW1wb3J0IGJ5bCDDunNwxJvFoW7DvS4= @@ -327,23 +354,23 @@ cz: feed_description: "V\xC5\xA1echny projekty u\xC5\xBEivatele %{username}" todo: error_date_must_be_future: "datum mus\xC3\xAD b\xC3\xBDt v budoucnosti" - user: - error_context_not_associated: "Kontext %{context} nepat\xC5\x99\xC3\xAD u\xC5\xBEivateli %{user}." - error_project_not_associated: "Projekt %{project} nepat\xC5\x99\xC3\xAD u\xC5\xBEivateli %{user}." preference: due_on: "Pl\xC3\xA1nov\xC3\xA1no na %{date}" due_in: "Pl\xC3\xA1nov\xC3\xA1no za %{days} dn\xC3\xAD" due_styles: - "Pl\xC3\xA1nov\xC3\xA1no za ___ dn\xC3\xAD" - "Pl\xC3\xA1nov\xC3\xA1no na _______" + user: + error_context_not_associated: "Kontext %{context} nepat\xC5\x99\xC3\xAD u\xC5\xBEivateli %{user}." + error_project_not_associated: "Projekt %{project} nepat\xC5\x99\xC3\xAD u\xC5\xBEivateli %{user}." stats: + actions_min_max_completion_days: "Maximum/minimum dn\xC3\xAD na dokon\xC4\x8Den\xC3\xAD je %{min}/%{max}." + totals_hidden_context_count: "a %{count} skryt\xC3\xBDch kontext\xC5\xAF." + actions_avg_created: "Za posledn\xC3\xADch 12 m\xC4\x9Bs\xC3\xADc\xC5\xAF bylo vytvo\xC5\x99eno pr\xC5\xAFm\xC4\x9Brn\xC4\x9B %{count} \xC3\xBAkol\xC5\xAF" + totals_actions_completed: "%{count} z nich je hotov\xC3\xBDch." tag_cloud_title: !binary | TXJhayDFoXTDrXRrxa8gcHJvIHbFoWVjaG55IMO6a2x5 - totals_hidden_context_count: "a %{count} skryt\xC3\xBDch kontext\xC5\xAF." - actions_avg_created: "Za posledn\xC3\xADch 12 m\xC4\x9Bs\xC3\xADc\xC5\xAF bylo vytvo\xC5\x99eno pr\xC5\xAFm\xC4\x9Brn\xC4\x9B %{count} \xC3\xBAkol\xC5\xAF" - actions_min_max_completion_days: "Maximum/minimum dn\xC3\xAD na dokon\xC4\x8Den\xC3\xAD je %{min}/%{max}." - totals_actions_completed: "%{count} z nich je hotov\xC3\xBDch." actions_actions_avg_created_30days: "Za posledn\xC3\xADch 30 dn\xC3\xAD bylo vytvo\xC5\x99eno pr\xC5\xAFm\xC4\x9Brn\xC4\x9B %{count} \xC3\xBAkol\xC5\xAF" actions_avg_completed: !binary | YSB1emF2xZllbm8gcHLFr23Em3JuxJsgJXtjb3VudH0gw7prb2zFryB6YSBt @@ -370,13 +397,13 @@ cz: weeks: "\xC4\x8Cas b\xC4\x9Bhu \xC3\xBAkolu (t\xC3\xBDdny). Klepn\xC4\x9Bte na sloupec pro dal\xC5\xA1\xC3\xAD info" totals_action_count: "m\xC3\xA1te celkem %{count} \xC3\xBAkol\xC5\xAF" tag_cloud_90days_title: "Zna\xC4\x8Dky \xC3\xBAkol\xC5\xAF z posledn\xC3\xADch 90-ti dn\xC3\xAD" + actions_avg_completion_time: "Pro v\xC5\xA1echny va\xC5\xA1e hotov\xC3\xA9 \xC3\xBAkoly je pr\xC5\xAFm\xC4\x9Brn\xC3\xBD \xC4\x8Das dokon\xC4\x8Den\xC3\xAD %{count} dn\xC3\xAD." tod30: "Denn\xC3\xAD doba (posledn\xC3\xADch 30 dn\xC3\xAD)" tags: !binary | xaB0w610a3k= projects: Projekty - actions_avg_completion_time: "Pro v\xC5\xA1echny va\xC5\xA1e hotov\xC3\xA9 \xC3\xBAkoly je pr\xC5\xAFm\xC4\x9Brn\xC3\xBD \xC4\x8Das dokon\xC4\x8Den\xC3\xAD %{count} dn\xC3\xAD." - actions_lastyear_title: "\xC3\x9Akoly za posledn\xC3\xADch 12 m\xC4\x9Bs\xC3\xADc\xC5\xAF" + totals_completed_project_count: "a %{count} je hotov\xC3\xBDch projekt\xC5\xAF." labels: month_avg_completed: !binary | JXttb250aHN9IG3Em3PDrcSNbsOtIHByxa9txJtyIGhvdG92w71jaA== @@ -393,8 +420,8 @@ cz: created: "Vytvo\xC5\x99eno" actions_selected_from_week: "\xC3\x9Akoly vybran\xC3\xA9 z t\xC3\xBDdne " - totals_completed_project_count: "a %{count} je hotov\xC3\xBDch projekt\xC5\xAF." actions_day_of_week_title: "Den v t\xC3\xBDdnu (v\xC5\xA1echny \xC3\xBAkoly)" + actions_lastyear_title: "\xC3\x9Akoly za posledn\xC3\xADch 12 m\xC4\x9Bs\xC3\xADc\xC5\xAF" open_per_week: "Aktivn\xC3\xAD (viditeln\xC3\xA9 i skryt\xC3\xA9) dal\xC5\xA1\xC3\xAD akce za t\xC3\xBDden" action_selection_title: !binary | VFJBQ0tTOjp2w71ixJtyIMO6a29sxa8= @@ -440,19 +467,19 @@ cz: months_ago: !binary | bcSbc8OtY8WvIHpwxJt0 - top10_projects: "Top 10 projekt\xC5\xAF" top5_contexts: "Top 5 kontext\xC5\xAF" - click_to_return: "Klepn\xC4\x9Bte %{link} pro n\xC3\xA1vrat ke statistik\xC3\xA1m." - totals: Celkem + top10_projects: "Top 10 projekt\xC5\xAF" contexts: Kontexty + totals: Celkem + click_to_return: "Klepn\xC4\x9Bte %{link} pro n\xC3\xA1vrat ke statistik\xC3\xA1m." tag_cloud_90days_description: "Tento mrak zahrnuje \xC5\xA1t\xC3\xADtky \xC3\xBAkol\xC5\xAF, kter\xC3\xA9 byly vytvo\xC5\x99eny nebo dokon\xC4\x8Deny v posledn\xC3\xADch 90-ti dnech." totals_visible_context_count: "Z nich je %{count} viditeln\xC3\xBDch kontext\xC5\xAF" - actions_min_completion_time: "Minim\xC3\xA1ln\xC3\xAD \xC4\x8Das k dokon\xC4\x8Den\xC3\xAD je %{time}." top10_projects_30days: "Top 10 projekt\xC5\xAF za posledn\xC3\xADch 30 dn\xC3\xAD" running_time_all: !binary | QWt0dcOhbG7DrSDEjWFzIGLEm2h1IHbFoWVjaCBuZWhvdG92w71jaCDDumtv bMWv + actions_min_completion_time: "Minim\xC3\xA1ln\xC3\xAD \xC4\x8Das k dokon\xC4\x8Den\xC3\xAD je %{time}." action_completion_time_title: "\xC4\x8Cas dokon\xC4\x8Den\xC3\xAD (v\xC5\xA1echny hotov\xC3\xA9 \xC3\xBAkoly)" click_to_show_actions_from_week: "Klepn\xC4\x9Bte %{link} pro zobrazen\xC3\xAD \xC3\xBAkol\xC5\xAF z t\xC3\xBDdne %{week} a dal\xC5\xA1\xC3\xADch." top10_longrunning: !binary | @@ -470,9 +497,9 @@ cz: day_of_week: "Den v t\xC3\xBDdnu" totals_first_action: "Od va\xC5\xA1eho prvn\xC3\xADho \xC3\xBAkolu %{date}" tag_cloud_description: "Tento mrak zahrnuje \xC5\xA1t\xC3\xADtky v\xC5\xA1ech \xC3\xBAkol\xC5\xAF (hotov\xC3\xBDch, nehotov\xC3\xBDch, viditeln\xC3\xBDch i skryt\xC3\xBDch)" + spread_of_actions_for_all_context: "Distribuce v\xC5\xA1ech \xC3\xBAkol\xC5\xAF do kontext\xC5\xAF" click_to_update_actions: "Klepn\xC4\x9Bte na sloupec v grafu pro zobrazen\xC3\xAD detail\xC5\xAF n\xC3\xAD\xC5\xBEe." click_to_return_link: zde - spread_of_actions_for_all_context: "Distribuce v\xC5\xA1ech \xC3\xBAkol\xC5\xAF do kontext\xC5\xAF" more_stats_will_appear: "Dal\xC5\xA1\xC3\xAD statistiky se zobraz\xC3\xAD a\xC5\xBE p\xC5\x99ibyde v\xC3\xADce \xC3\xBAkol\xC5\xAF." actions_avg_completed_30days: "a dokon\xC4\x8Deno pr\xC5\xAFm\xC4\x9Brn\xC4\x9B %{count} \xC3\xBAkol\xC5\xAF za den." actions_30days_title: "\xC3\x9Akoly za posledn\xC3\xADch 30 dn\xC3\xAD" @@ -501,21 +528,21 @@ cz: UG9kw61s other_actions_label: "(ostatn\xC3\xAD)" - time_of_day: "Denn\xC3\xAD doba (v\xC5\xA1echny \xC3\xBAkoly)" totals_hidden_project_count: "%{count} je skryt\xC3\xBDch" + time_of_day: "Denn\xC3\xAD doba (v\xC5\xA1echny \xC3\xBAkoly)" todos: - completed_actions: "Hotov\xC3\xA9 \xC3\xBAkoly" + recurring_action_deleted: "\xC3\x9Akol byl smaz\xC3\xA1n. Proto\xC5\xBEe jde o opakovan\xC3\xBD \xC3\xBAkol, byl vlo\xC5\xBEen nov\xC3\xBD \xC3\xBAkol" show_from: Zobrazovat od error_starring_recurring: "Nebylo mo\xC5\xBEno ohv\xC4\x9Bzdi\xC4\x8Dkovat opakovan\xC3\xBD \xC3\xBAkol \\'%{description}\\'" - recurring_action_deleted: "\xC3\x9Akol byl smaz\xC3\xA1n. Proto\xC5\xBEe jde o opakovan\xC3\xBD \xC3\xBAkol, byl vlo\xC5\xBEen nov\xC3\xBD \xC3\xBAkol" - completed_rest_of_previous_month: "Uzav\xC5\x99eno ve zbytku minul\xC3\xA9ho m\xC4\x9Bs\xC3\xADce" - completed_recurring: "Hotov\xC3\xA9 opakovan\xC3\xA9 \xC3\xBAkoly" + completed_actions: "Hotov\xC3\xA9 \xC3\xBAkoly" added_new_next_action: !binary | UMWZaWTDoW4gbm92w70gw7prb2w= + completed_recurring: "Hotov\xC3\xA9 opakovan\xC3\xA9 \xC3\xBAkoly" + completed_rest_of_previous_month: "Uzav\xC5\x99eno ve zbytku minul\xC3\xA9ho m\xC4\x9Bs\xC3\xADce" blocked_by: "\xC4\x8Cek\xC3\xA1 na %{predecessors}" - completed_recurrence_completed: "Bylo smaz\xC3\xA1no posledn\xC3\xAD opakov\xC3\xA1n\xC3\xAD opakovan\xC3\xA9ho \xC3\xBAkolu. Opakov\xC3\xA1n\xC3\xAD dokon\xC4\x8Deno" star_action: "Ozna\xC5\x99it hv\xC4\x9Bzdi\xC4\x8Dkou" + completed_recurrence_completed: "Bylo smaz\xC3\xA1no posledn\xC3\xAD opakov\xC3\xA1n\xC3\xAD opakovan\xC3\xA9ho \xC3\xBAkolu. Opakov\xC3\xA1n\xC3\xAD dokon\xC4\x8Deno" defer_date_after_due_date: "Datum zobrazen\xC3\xAD je a\xC5\xBE po pl\xC3\xA1novan\xC3\xA9m datu \xC3\xBAkolu. Upravte datum \xC3\xBAkolu p\xC5\x99ed dal\xC5\xA1\xC3\xADm pokusem o odplo\xC5\xBEen\xC3\xAD zobrazen\xC3\xAD." unable_to_add_dependency: "Nepoda\xC5\x99ilo se p\xC5\x99idat z\xC3\xA1vislost" done: Hotovo? @@ -531,22 +558,22 @@ cz: edit_action_with_description: "Upravit \xC3\xBAkol '%{description}'" action_due_on: "(\xC3\xBAkol pl\xC3\xA1nov\xC3\xA1n na %{date})" + list_incomplete_next_actions: "Zabraz\xC3\xAD nehotov\xC3\xA9 \xC3\xBAkoly" archived_tasks_title: "TRACKS::Archiv hotov\xC3\xBDch \xC3\xBAkol\xC5\xAF" remove_dependency: "Odstranit z\xC3\xA1vislost (nesma\xC5\xBEe \xC3\xBAkol)" - list_incomplete_next_actions: "Zabraz\xC3\xAD nehotov\xC3\xA9 \xC3\xBAkoly" - tags: !binary | - xaB0w610a3kgKG9kZMSbbGVuw6kgxI3DoXJrYW1pKQ== - action_deleted_success: !binary | w5prb2wgYnlsIMO6c3DEm8WhbsSbIHNtYXrDoW4= - mobile_todos_page_title: "V\xC5\xA1echny \xC3\xBAkoly" - new_related_todo_created: "Byl vytvo\xC5\x99en nov\xC3\xBD \xC3\xBAkol pat\xC5\x99\xC3\xADc\xC3\xAD do tohoto opakovan\xC3\xA9ho \xC3\xBAkolu" + tags: !binary | + xaB0w610a3kgKG9kZMSbbGVuw6kgxI3DoXJrYW1pKQ== + + delete_recurring_action_title: "Smazat opakovan\xC3\xBD \xC3\xBAkol" context_changed: "Kontext byl zm\xC4\x9Bn\xC4\x9Bn na %{name}" + new_related_todo_created: "Byl vytvo\xC5\x99en nov\xC3\xBD \xC3\xBAkol pat\xC5\x99\xC3\xADc\xC3\xAD do tohoto opakovan\xC3\xA9ho \xC3\xBAkolu" + mobile_todos_page_title: "V\xC5\xA1echny \xC3\xBAkoly" add_another_dependency: !binary | UMWZaWRhdCBkYWzFocOtIHrDoXZpc2xvc3Q= - delete_recurring_action_title: "Smazat opakovan\xC3\xBD \xC3\xBAkol" removed_predecessor: "Byl odstran\xC4\x9Bn %{successor} jako z\xC3\xA1vislost pro %{predecessor}." recurring_actions_title: "TRACKS::Opakovan\xC3\xA9 \xC3\xBAkoly" next_action_needed: "Je pot\xC5\x99eba zadat aspo\xC5\x88 jeden \xC3\xBAkol" @@ -558,23 +585,24 @@ cz: edit_action: "Upravit \xC3\xBAkol" added_new_context: "P\xC5\x99id\xC3\xA1n nov\xC3\xBD kontext" next_actions_description: "Filtr:" + list_incomplete_next_actions_with_limit: "Zobrazuje posledn\xC3\xADch %{count} nedokon\xC4\x8Den\xC3\xBDch \xC3\xBAkol\xC5\xAF" + set_to_pending: "%{task} nastaven jako \xC4\x8Dekaj\xC3\xADc\xC3\xAD" + added_new_project: "P\xC5\x99id\xC3\xA1n nov\xC3\xBD projekt" next_actions_title_additions: completed: "hotov\xC3\xA9 \xC3\xBAkoly" due_today: dnes due_within_a_week: !binary | YsSbaGVtIHTDvWRuZQ== - list_incomplete_next_actions_with_limit: "Zobrazuje posledn\xC3\xADch %{count} nedokon\xC4\x8Den\xC3\xBDch \xC3\xBAkol\xC5\xAF" - set_to_pending: "%{task} nastaven jako \xC4\x8Dekaj\xC3\xADc\xC3\xAD" - added_new_project: "P\xC5\x99id\xC3\xA1n nov\xC3\xBD projekt" older_completed_items: "" - error_deleting_item: "Nepoda\xC5\x99ilo se smazat polo\xC5\xBEku %{description}" - edit_recurring_todo: "Upravit opakovan\xC3\xBD \xC3\xBAkol" - append_in_this_project: v tomto projektu - task_list_title: "TRACKS::\xC3\x9Akoly" no_actions_due_this_week: !binary | xb3DoWRuw6kgw7prb2x5IHBsw6Fub3bDoW55IG5hIHRlbnRvIHTDvWRlbg== + all_completed_here: zde + append_in_this_project: v tomto projektu + edit_recurring_todo: "Upravit opakovan\xC3\xBD \xC3\xBAkol" + error_deleting_item: "Nepoda\xC5\x99ilo se smazat polo\xC5\xBEku %{description}" + task_list_title: "TRACKS::\xC3\x9Akoly" no_recurring_todos: !binary | xb3DoWRuw6kgb3Bha292YW7DqSDDumtvbHk= @@ -584,26 +612,26 @@ cz: no_deferred_pending_actions: !binary | xb3DoWRuw6kgb2Rsb8W+ZW7DqSBhbmkgxI1la2Fqw61jw60gw7prb2x5 - completed_last_day: "Ukon\xC4\x8Den\xC3\xA9 v posledn\xC3\xADch 24 hodin\xC3\xA1ch" delete_recurring_action_confirm: "Opravdu chcete smazat opakovan\xC3\xBD \xC3\xBAkol '%{description}'?" - show_in_days: "Zobrazit za %{days} dn\xC3\xAD" + completed_last_day: "Ukon\xC4\x8Den\xC3\xA9 v posledn\xC3\xADch 24 hodin\xC3\xA1ch" + feed_title_in_context: v kontextu '%{context}' no_project: "--\xC5\xBD\xC3\xA1dn\xC3\xBD projekt--" + show_in_days: "Zobrazit za %{days} dn\xC3\xAD" error_saving_recurring: "Nepoda\xC5\x99ilo se ulo\xC5\xBEit opakovan\xC3\xBD \xC3\xBAkol \\'%{description}\\'" completed_more_than_x_days_ago: "" - all_completed: "V\xC5\xA1echny hotov\xC3\xA9 \xC3\xBAkoly" - feed_title_in_context: v kontextu '%{context}' new_related_todo_created_short: "vytvo\xC5\x99en nov\xC3\xBD \xC3\xBAkol" + all_completed: "V\xC5\xA1echny hotov\xC3\xA9 \xC3\xBAkoly" edit: Upravit + completed_actions_with: "Hotov\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" older_than_days: "" completed_tagged_page_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" pending: !binary | xIxla2Fqw61jw60= - completed_actions_with: "Hotov\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" + completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly" deleted_success: !binary | w5prb2wgYnlsIMO6c3DEm8WhbsSbIHNtYXrDoW4u - completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly" feed_title_in_project: v projektu '%{project}' clear_due_date: "Smazat pl\xC3\xA1novan\xC3\xA9 datum \xC3\xBAkolu" error_removing_dependency: "Nepoda\xC5\x99ilo se odstranit z\xC3\xA1vislost" @@ -616,22 +644,23 @@ cz: recurring_deleted_success: !binary | T3Bha292YW7DvSDDumtvbCBieWwgw7pzcMSbxaFuxJsgc21hesOhbi4= - clear_show_from_date: "Odstranit datum zobrazen\xC3\xAD" + no_completed_actions_with: "\xC5\xBD\xC3\xA1dn\xC3\xA9 hotov\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" next_actions_title: "Tracks - \xC3\x9Akoly" next_action_description: "Popis \xC3\xBAkolu" deferred_tasks_title: TRACKS::Tickler - no_completed_actions_with: "\xC5\xBD\xC3\xA1dn\xC3\xA9 hotov\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" - unresolved_dependency: "Hodnota v poli 'z\xC3\xA1vis\xC3\xAD na' neodpov\xC3\xADd\xC3\xA1 \xC5\xBE\xC3\xA1dn\xC3\xA9mu existuj\xC3\xADc\xC3\xADmu \xC3\xBAkolu. Hodnota bude ignorov\xC3\xA1na. Pokra\xC4\x8Dovat?" - calendar_page_title: "TRACKS::Kalend\xC3\xA1\xC5\x99" + clear_show_from_date: "Odstranit datum zobrazen\xC3\xAD" in_hidden_state: "(skryt\xC3\xBD)" - show_today: Zobrazit Dnes + see_all_completed: "M\xC5\xAF\xC5\xBEete vid\xC4\x9Bt v\xC5\xA1echny dokon\xC4\x8Den\xC3\xA9 akce %{link}" + calendar_page_title: "TRACKS::Kalend\xC3\xA1\xC5\x99" + unresolved_dependency: "Hodnota v poli 'z\xC3\xA1vis\xC3\xAD na' neodpov\xC3\xADd\xC3\xA1 \xC5\xBE\xC3\xA1dn\xC3\xA9mu existuj\xC3\xADc\xC3\xADmu \xC3\xBAkolu. Hodnota bude ignorov\xC3\xA1na. Pokra\xC4\x8Dovat?" no_actions_found_title: !binary | TmVuYWxlemVueSDFvsOhZG7DqSDDumtvbHk= + show_today: Zobrazit Dnes next_actions_due_date: overdue_by: "Pro\xC5\xA1l\xC3\xA9 %{days} den" - due_today: Dnes due_in_x_days: "Za %{days} dn\xC3\xAD" + due_today: Dnes overdue_by_plural: "Pro\xC5\xA1l\xC3\xA9 %{days} dn\xC3\xAD" due_tomorrow: !binary | WsOtdHJh @@ -660,15 +689,15 @@ cz: feeds: completed: "Hotov\xC3\xA9: %{date}" due: "Pl\xC3\xA1nov\xC3\xA1no na: %{date}" - delete_action: "Smazat \xC3\xBAkol" - error_deleting_recurring: "Nepoda\xC5\x99ilo se smazat opakovan\xC3\xBD \xC3\xBAkol \\'%{description}\\'" recurring_todos: "Opakovan\xC3\xA9 \xC3\xBAkoly" + error_deleting_recurring: "Nepoda\xC5\x99ilo se smazat opakovan\xC3\xBD \xC3\xBAkol \\'%{description}\\'" + delete_action: "Smazat \xC3\xBAkol" delete: Smazat - drag_action_title: "P\xC5\x99et\xC3\xA1hnout na jin\xC3\xBD \xC3\xBAkol pro vytvo\xC5\x99en\xC3\xAD z\xC3\xA1vislosti" - cannot_add_dependency_to_completed_todo: "Nelze p\xC5\x99idat \xC3\xBAkol jako z\xC3\xA1vislost k hotov\xC3\xA9mu \xC3\xBAkolu!" no_last_completed_actions: !binary | xb3DoWRuw6kgaG90b3bDqSDDumtvbHk= + drag_action_title: "P\xC5\x99et\xC3\xA1hnout na jin\xC3\xBD \xC3\xBAkol pro vytvo\xC5\x99en\xC3\xAD z\xC3\xA1vislosti" + cannot_add_dependency_to_completed_todo: "Nelze p\xC5\x99idat \xC3\xBAkol jako z\xC3\xA1vislost k hotov\xC3\xA9mu \xC3\xBAkolu!" depends_on: !binary | WsOhdmlzw60gbmE= @@ -680,6 +709,7 @@ cz: added_new_next_action_plural: "\xC3\x9Akoly byly p\xC5\x99id\xC3\xA1ny" new_related_todo_not_created_short: "\xC3\xBAkol nebyl vytvo\xC5\x99en" completed_rest_of_week: "Dokon\xC4\x8Den\xC3\xA9 ve zbytku t\xC3\xBDdne" + show_tomorrow: "Zobrazit z\xC3\xADtra" error_starring: "Nepoda\xC5\x99ilo se ozna\xC4\x8Dit \xC3\xBAkol hv\xC4\x9Bzdi\xC4\x8Dkou '%{description}'" calendar: get_in_ical_format: "Kalend\xC3\xA1\xC5\x99 ve form\xC3\xA1tu iCal" @@ -702,9 +732,9 @@ cz: no_actions_due_this_month: "Na zbytek tohoto m\xC4\x9Bs\xC3\xADce nejsou \xC5\xBE\xC3\xA1dn\xC3\xA9 \xC3\xBAkoly" due_this_month: "Pl\xC3\xA1nov\xC3\xA1no na %{month}" - show_tomorrow: "Zobrazit z\xC3\xADtra" - tagged_page_title: "TRACKS::Se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" - action_deferred: "\xC3\x9Akol '%{description}' byl oldo\xC5\xBEen" + no_completed_recurring: !binary | + xb3DoWRuw6kgaG90b3bDqSBvcGFrb3ZhbsOpIMO6a29seQ== + recurrence: ends_on_date: "Kon\xC4\x8D\xC3\xAD %{date}" every_work_day: "Ka\xC5\xBEd\xC3\xBD pracovn\xC3\xAD den" @@ -717,16 +747,19 @@ cz: monthly_options: !binary | TmFzdGF2ZW7DrSBwcm8gbcSbc8OtxI1uw60gb3Bha292YW7DqSDDumtvbHk= + daily_options: "Nastaven\xC3\xAD pro denn\xC3\xAD opakovan\xC3\xA9 \xC3\xBAkoly" monthly: !binary | TcSbc8OtxI1uxJs= starts_on: !binary | WmHEjcOtbsOh - daily_options: "Nastaven\xC3\xAD pro denn\xC3\xAD opakovan\xC3\xA9 \xC3\xBAkoly" daily: !binary | RGVubsSb + show_option_always: !binary | + c3TDoWxl + pattern: third: !binary | dMWZZXTDrQ== @@ -754,21 +787,26 @@ cz: every_n: !binary | a2HFvmTDqSAle259 - every_xth_day_of_every_n_months: "ka\xC5\xBEd\xC3\xBD %{x} %{day} ka\xC5\xBEd\xC3\xBDch %{n_months}" second: !binary | ZHJ1aMO9 + every_xth_day_of_every_n_months: "ka\xC5\xBEd\xC3\xBD %{x} %{day} ka\xC5\xBEd\xC3\xBDch %{n_months}" on_day_n: "%{n}. den" weekly: !binary | a2HFvmTDvSB0w71kZW4= from: od + last: "posledn\xC3\xAD" every_day: !binary | a2HFvmTDvSBkZW4= - last: "posledn\xC3\xAD" - times: "(%{number} opakov\xC3\xA1n\xC3\xAD)" the_xth_day_of_month: "%{x} %{day} m\xC4\x9Bs\xC3\xADce %{month}" + times: "(%{number} opakov\xC3\xA1n\xC3\xAD)" + show: "uk\xC3\xA1zat" + first: !binary | + cHJ2bsOt + + every_year_on: "ka\xC5\xBEd\xC3\xBD rok %{date}" day_names: - "ned\xC4\x9Ble" - !binary | @@ -783,11 +821,6 @@ cz: cMOhdGVr - sobota - show: "uk\xC3\xA1zat" - first: !binary | - cHJ2bsOt - - every_year_on: "ka\xC5\xBEd\xC3\xBD rok %{date}" on_work_days: "v pracovn\xC3\xAD dny" fourth: !binary | xI10dnJ0w70= @@ -797,51 +830,50 @@ cz: a2HFvmTDvSBtxJtzw61j until: do - show_option_always: !binary | - c3TDoWxl - yearly_every_x_day: "Ka\xC5\xBEd\xC3\xBD %{month} %{day}" recurrence_on_options: "Nastavit opakov\xC3\xA1n\xC3\xAD na" daily_every_number_day: "Ka\xC5\xBEd\xC3\xBDch %{number} dn\xC3\xAD" - ends_on: !binary | - S29uxI3DrQ== - show_options: !binary | w5prw6F6YXQgw7prb2w= weekly_every_number_week: "Ka\xC5\xBEd\xC3\xBDch %{number} t\xC3\xBDdn\xC5\xAF" + ends_on: !binary | + S29uxI3DrQ== + show_days_before: "%{days} dn\xC3\xAD p\xC5\x99ed pl\xC3\xA1novan\xC3\xBDm datem" - yearly_every_xth_day: "%{day} %{day_of_week} m\xC4\x9Bs\xC3\xADce %{month}" from_tickler: "datum kdy \xC3\xBAkol vypadne z Tickleru (nen\xC3\xAD nastaveno pl\xC3\xA1novan\xC3\xA9 datum)" no_end_date: Nikdy day_x_on_every_x_month: "%{day}. den ka\xC5\xBEd\xC3\xBD %{month}. m\xC4\x9Bs\xC3\xADc" + yearly_every_xth_day: "%{day} %{day_of_week} m\xC4\x9Bs\xC3\xADce %{month}" yearly_options: "Nastaven\xC3\xAD pro ro\xC4\x8Dn\xC3\xAD opakovan\xC3\xA9 \xC3\xBAkoly" yearly: !binary | Um/EjW7Emw== monthly_every_xth_day: "%{day} %{day_of_week} ka\xC5\xBEd\xC3\xBD %{month}. m\xC4\x9Bs\xC3\xADc" - no_completed_recurring: !binary | - xb3DoWRuw6kgaG90b3bDqSBvcGFrb3ZhbsOpIMO6a29seQ== - + action_deferred: "\xC3\x9Akol '%{description}' byl oldo\xC5\xBEen" + tagged_page_title: "TRACKS::Se \xC5\xA1t\xC3\xADtkem '%{tag_name}'" added_dependency: "P\xC5\x99id\xC3\xA1no %{dependency} jako z\xC3\xA1vislost." + completed_rest_of_month: "Ukon\xC4\x8Den\xC3\xA9 ve zbytku tohoto m\xC4\x9Bs\xC3\xADce" + all_completed_tagged_page_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem %{tag_name}" no_deferred_actions: !binary | xb3DoWRuw6kgb2Rsb8W+ZW7DqSDDumtvbHku - all_completed_tagged_page_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly se \xC5\xA1t\xC3\xADtkem %{tag_name}" - completed_rest_of_month: "Ukon\xC4\x8Den\xC3\xA9 ve zbytku tohoto m\xC4\x9Bs\xC3\xADce" recurrence_completed: "Posledn\xC3\xAD opakov\xC3\xA1n\xC3\xAD \xC3\xBAkolu bylo ozna\xC4\x8Deno jako hotov\xC3\xA9. Opakovan\xC3\xBD \xC3\xBAkol je dokon\xC4\x8Den\xC3\xBD" - error_toggle_complete: "Nepoda\xC5\x99ilo se ozna\xC4\x8Dit \xC3\xBAkol jako hotov\xC3\xBD" - due: "Pl\xC3\xA1nov\xC3\xA1no na" + action_marked_complete_error: "\xC3\x9Akol '%{description}' NEBYL ozna\xC4\x8Den jako %{completed} kv\xC5\xAFli chyb\xC4\x9B na serveru." no_actions_found: !binary | xb3DoWRuw6kgYsSbxb7DrWPDrSDDumtvbHku in_pending_state: "ve stavu \xC4\x8Dekaj\xC3\xADc\xC3\xAD" - action_marked_complete_error: "\xC3\x9Akol '%{description}' NEBYL ozna\xC4\x8Den jako %{completed} kv\xC5\xAFli chyb\xC4\x9B na serveru." - depends_on_separate_with_commas: !binary | - WsOhdmlzw60gbmEgKG9kZMSbbGVubyDEjcOhcmthbWkp + error_toggle_complete: "Nepoda\xC5\x99ilo se ozna\xC4\x8Dit \xC3\xBAkol jako hotov\xC3\xBD" + due: "Pl\xC3\xA1nov\xC3\xA1no na" + no_incomplete_actions: !binary | + xb3DoWRuw6kgbmVob3RvdsOpIMO6a29seQ== action_saved_to_tickler: "\xC3\x9Akol byl ulo\xC5\xBEen do Tickleru" recurring_action_saved: "Opakovan\xC3\xBD \xC3\xBAkol byl ulo\xC5\xBEen" + depends_on_separate_with_commas: !binary | + WsOhdmlzw60gbmEgKG9kZMSbbGVubyDEjcOhcmthbWkp + completed_in_archive: one: "V archivu je hotov\xC3\xBD \xC3\xBAkol." other: "V archivu je %{count} hotov\xC3\xBDch \xC3\xBAkol\xC5\xAF." @@ -853,34 +885,104 @@ cz: U3Bvxb5kxJtuw6kgw7prb2x5 add_new_recurring: "Vytvo\xC5\x99it opakovan\xC3\xBD \xC3\xBAkol" - no_incomplete_actions: !binary | - xb3DoWRuw6kgbmVob3RvdsOpIMO6a29seQ== - notes: delete_note_title: "Smazat pozn\xC3\xA1mku '%{id}'" delete_confirmation: "Opravdu chcete smazat pozn\xC3\xA1mku '%{id}'?" in_project: "V:" delete_item_title: "Smazat polo\xC5\xBEku" + deleted_note: "Smazat pozn\xC3\xA1mku '%{id}'" note_link_title: "Zobrazit pozn\xC3\xA1mku %{id}" show_note_title: "Zobrazit pozn\xC3\xA1mku" - deleted_note: "Smazat pozn\xC3\xA1mku '%{id}'" edit_item_title: "Upravit polo\xC5\xBEku" note_location_link: "V:" no_notes_available: "\xC5\xBD\xC3\xA1dn\xC3\xA9 pozn\xC3\xA1mky: p\xC5\x99idejte pozn\xC3\xA1mky ze str\xC3\xA1nek jednotliv\xC3\xBDch projekt\xC5\xAF." note_header: "Pozn\xC3\xA1mka %{id}" delete_note_confirm: "Opravdu chcete smazat pozn\xC3\xA1mku '%{id}'?" + projects: + default_context_set: "V\xC3\xBDchoz\xC3\xAD kontext %{default_context} byl nastaven" + no_actions_in_project: !binary | + xb3DoWRuw6kgYWt0aXZuw60gw7prb2x5 + + deferred_actions: "Odlo\xC5\xBEen\xC3\xA9 \xC3\xBAkoly projektu" + was_marked_hidden: "byl ozna\xC4\x8Den jako skryt\xC3\xBD" + edit_project_title: Upravit projekt + default_tags_removed_notice: "V\xC3\xBDchoz\xC3\xAD \xC5\xA1t\xC3\xADtky byly odstran\xC4\x9Bny" + page_title: "TRACKS::Projekt: %{project}" + all_completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly projektu '%{project_name}'" + hide_form: !binary | + U2tyw710IGZvcm11bMOhxZk= + + list_completed_projects: "TRACKS::Hotov\xC3\xA9 projekty" + no_notes_attached: !binary | + xb3DoWRuw6kgcG96bsOhbWt5 + + to_new_project_page: "p\xC5\x99ej\xC3\xADt k nov\xC3\xA9mu projektu" + show_form_title: "Nov\xC3\xBD projekt" + deferred_actions_empty: !binary | + xb3DoWRuw6kgb2Rsb8W+ZW7DqSDDumtvbHk= + + project_state: Projekt je %{state}. + this_project: Tento projekt + no_last_completed_projects: !binary | + xb3DoWRuw6kgaG90b3bDqSBwcm9qZWt0eQ== + + no_last_completed_recurring_todos: !binary | + xb3DoWRuw6kgaG90b3bDqSBvcGFrb3ZhbsOpIMO6a29seQ== + + notes: "Pozn\xC3\xA1mky" + todos_append: v tomto projektu + list_reviews: TRACKS::Revize + notes_empty: !binary | + xb3DoWRuw6kgcG96bsOhbWt5 + + no_projects: !binary | + xb3DoWRuw6kgcHJvamVrdHk= + + hide_form_title: "Schovat formul\xC3\xA1\xC5\x99 zalo\xC5\xBEen\xC3\xAD projektu" + delete_project: Smazat projekt + completed_actions_empty: "V tomto projektu nejsou \xC5\xBE\xC3\xA1dn\xC3\xA9 hotov\xC3\xA9 \xC3\xBAkoly" + with_no_default_context: "bez v\xC3\xBDchoz\xC3\xADho kontextu" + delete_project_confirmation: Opravdu chcete smazat projekt '%{name}'? + with_default_context: "s v\xC3\xBDchoz\xC3\xADm kontextem '%{context_name}'" + show_form: "Nov\xC3\xBD projekt" + actions_in_project_title: "\xC3\x9Akoly v tomto projetku" + completed_projects: "Hotov\xC3\xA9 projetky" + is_active: "je aktivn\xC3\xAD" + add_note: "Nov\xC3\xA1 pozn\xC3\xA1mka" + set_default_tags_notice: "Nastavit v\xC3\xBDchoz\xC3\xAD \xC5\xA1\xC3\xADtky \xC3\xBAkol\xC5\xAF v tomto projektu %{default_tags}" + add_project: "P\xC5\x99idat projekt" + settings: "Nastaven\xC3\xAD" + project_saved_status: "Projekt byl ulo\xC5\xBEen" + list_projects: TRACKS::Projekty + with_default_tags: "a s '%{tags}' jako v\xC3\xBDchoz\xC3\xAD \xC5\xA1t\xC3\xADtky" + completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly projektu '%{project_name}'" + hidden_projects: "Skryt\xC3\xA9 projekty" + delete_project_title: "Sma\xC5\xBEe projekt" + default_context_removed: "V\xC3\xBDchoz\xC3\xAD kontext byl odstran\xC4\x9Bn" + add_note_submit: "Nov\xC3\xA1 pozn\xC3\xA1mka" + completed_actions: "Hotov\xC3\xA9 \xC3\xBAkoly tohoto projektu" + was_marked_complete: "byl ozna\xC4\x8Den jako hotov\xC3\xBD" + no_default_context: "Tento projekt nem\xC3\xA1 v\xC3\xBDchoz\xC3\xAD kontext" + with_no_default_tags: !binary | + YSBuZW3DoSDFvsOhZG7DqSB2w71jaG96w60gem5hxI1reQ== + + default_context: "V\xC3\xBDchoz\xC3\xAD kontext pro tento projekt je %{context}" + edit_project_settings: Upravit vlastnosti projektu + status_project_name_changed: "Jm\xC3\xA9no projektu bylo zm\xC4\x9Bn\xC4\x9Bno" + state: Tento projekt je %{state} + active_projects: "Aktivn\xC3\xAD projekty" states: hidden_plural: "Skryt\xC3\xA9" - review_plural: "Nerevidovan\xC3\xA9" stalled: !binary | T3B1xaF0xJtuw70= + review_plural: "Nerevidovan\xC3\xA9" completed: "Hotov\xC3\xBD" current: !binary | QWt0dcOhbG7DrQ== - completed_plural: "Hotov\xC3\xA9" review: "Nerevidovan\xC3\xBD" + completed_plural: "Hotov\xC3\xA9" blocked: "Blokovan\xC3\xBD" blocked_plural: "Blokovan\xC3\xA9" stalled_plural: !binary | @@ -889,99 +991,16 @@ cz: visible_plural: "Viditeln\xC3\xA9" active_plural: "Aktivn\xC3\xAD" visible: "Viditeln\xC3\xBD" + hidden: "Skryt\xC3\xBD" + active: "Aktivn\xC3\xAD" current_plural: !binary | QWt0dcOhbG7DrQ== - hidden: "Skryt\xC3\xBD" - active: "Aktivn\xC3\xAD" - projects: - was_marked_hidden: "byl ozna\xC4\x8Den jako skryt\xC3\xBD" - edit_project_title: Upravit projekt - default_tags_removed_notice: "V\xC3\xBDchoz\xC3\xAD \xC5\xA1t\xC3\xADtky byly odstran\xC4\x9Bny" - default_context_set: "V\xC3\xBDchoz\xC3\xAD kontext %{default_context} byl nastaven" - no_actions_in_project: !binary | - xb3DoWRuw6kgYWt0aXZuw60gw7prb2x5 - - deferred_actions: "Odlo\xC5\xBEen\xC3\xA9 \xC3\xBAkoly projektu" - all_completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly projektu '%{project_name}'" - page_title: "TRACKS::Projekt: %{project}" - hide_form: !binary | - U2tyw710IGZvcm11bMOhxZk= - - no_notes_attached: !binary | - xb3DoWRuw6kgcG96bsOhbWt5 - - show_form_title: "Nov\xC3\xBD projekt" - deferred_actions_empty: !binary | - xb3DoWRuw6kgb2Rsb8W+ZW7DqSDDumtvbHk= - - this_project: Tento projekt - project_state: Projekt je %{state}. - list_completed_projects: "TRACKS::Hotov\xC3\xA9 projekty" - to_new_project_page: "p\xC5\x99ej\xC3\xADt k nov\xC3\xA9mu projektu" - no_last_completed_recurring_todos: !binary | - xb3DoWRuw6kgaG90b3bDqSBvcGFrb3ZhbsOpIMO6a29seQ== - - todos_append: v tomto projektu - no_last_completed_projects: !binary | - xb3DoWRuw6kgaG90b3bDqSBwcm9qZWt0eQ== - - notes: "Pozn\xC3\xA1mky" - notes_empty: !binary | - xb3DoWRuw6kgcG96bsOhbWt5 - - no_projects: !binary | - xb3DoWRuw6kgcHJvamVrdHk= - - hide_form_title: "Schovat formul\xC3\xA1\xC5\x99 zalo\xC5\xBEen\xC3\xAD projektu" - list_reviews: TRACKS::Revize - delete_project: Smazat projekt - completed_actions_empty: "V tomto projektu nejsou \xC5\xBE\xC3\xA1dn\xC3\xA9 hotov\xC3\xA9 \xC3\xBAkoly" - with_no_default_context: "bez v\xC3\xBDchoz\xC3\xADho kontextu" - show_form: "Nov\xC3\xBD projekt" - actions_in_project_title: "\xC3\x9Akoly v tomto projetku" - delete_project_confirmation: Opravdu chcete smazat projekt '%{name}'? - with_default_context: "s v\xC3\xBDchoz\xC3\xADm kontextem '%{context_name}'" - add_note: "Nov\xC3\xA1 pozn\xC3\xA1mka" - add_project: "P\xC5\x99idat projekt" - with_default_tags: "a s '%{tags}' jako v\xC3\xBDchoz\xC3\xAD \xC5\xA1t\xC3\xADtky" - is_active: "je aktivn\xC3\xAD" - list_projects: TRACKS::Projekty - settings: "Nastaven\xC3\xAD" - completed_projects: "Hotov\xC3\xA9 projetky" - set_default_tags_notice: "Nastavit v\xC3\xBDchoz\xC3\xAD \xC5\xA1\xC3\xADtky \xC3\xBAkol\xC5\xAF v tomto projektu %{default_tags}" - project_saved_status: "Projekt byl ulo\xC5\xBEen" - delete_project_title: "Sma\xC5\xBEe projekt" - hidden_projects: "Skryt\xC3\xA9 projekty" - completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly projektu '%{project_name}'" - was_marked_complete: "byl ozna\xC4\x8Den jako hotov\xC3\xBD" - completed_actions: "Hotov\xC3\xA9 \xC3\xBAkoly tohoto projektu" - default_context_removed: "V\xC3\xBDchoz\xC3\xAD kontext byl odstran\xC4\x9Bn" - add_note_submit: "Nov\xC3\xA1 pozn\xC3\xA1mka" - edit_project_settings: Upravit vlastnosti projektu - status_project_name_changed: "Jm\xC3\xA9no projektu bylo zm\xC4\x9Bn\xC4\x9Bno" - active_projects: "Aktivn\xC3\xAD projekty" - default_context: "V\xC3\xBDchoz\xC3\xAD kontext pro tento projekt je %{context}" - state: Tento projekt je %{state} - no_default_context: "Tento projekt nem\xC3\xA1 v\xC3\xBDchoz\xC3\xAD kontext" - with_no_default_tags: !binary | - YSBuZW3DoSDFvsOhZG7DqSB2w71jaG96w60gem5hxI1reQ== - errors: user_unauthorized: "401 Neautorizov\xC3\xA1no: Jen administr\xC3\xA1to\xC5\x99i sm\xC3\xAD pou\xC5\xBE\xC3\xADvat tuto funkci." - time: - am: am - formats: - stats: "%a %d-%m" - default: "%a, %d %b %Y %H:%M:%S %z" - time: "" - short: "%d %b %H:%M" - month_day: "%B %d" - long: "%B %d, %Y %H:%M" - pm: pm preferences: - change_identity_url: "Zm\xC4\x9Bna URL identity" open_id_url: "Va\xC5\xA1e OpenID URL je" + change_identity_url: "Zm\xC4\x9Bna URL identity" staleness_starts_after: "Zastar\xC3\xA1n\xC3\xAD nast\xC3\xA1v\xC3\xA1 po %{days} dnech" page_title: "TRACKS::Nastaven\xC3\xAD" change_password: "Zm\xC4\x9Bna hesla" @@ -989,10 +1008,10 @@ cz: title: "Va\xC5\xA1e nastaven\xC3\xAD" is_false: ne show_number_completed: "Zobrazit %{number} hotov\xC3\xBDch polo\xC5\xBEek" + password_changed: "Heslo bylo zm\xC4\x9Bn\xC4\x9Bno. Pros\xC3\xADm znovu se p\xC5\x99ihla\xC5\xA1te." edit_preferences: "Editace nastaven\xC3\xAD" page_title_edit: "TRACKS::Editace nastaven\xC3\xAD" is_true: ano - password_changed: "Heslo bylo zm\xC4\x9Bn\xC4\x9Bno. Pros\xC3\xADm znovu se p\xC5\x99ihla\xC5\xA1te." sms_context_none: !binary | xb7DoWRuw70= @@ -1006,10 +1025,20 @@ cz: change_authentication_type: "Zm\xC4\x9Bna typu autentizace" generate_new_token_confirm: "Opravdu? Nov\xC3\xBD pe\xC5\xA1ek nahrad\xC3\xAD ten p\xC5\xAFvodn\xC3\xAD a zp\xC5\xAFsob\xC3\xAD nefunk\xC4\x8Dnost ve v\xC5\xA1ech aplikac\xC3\xADch, kde jej pou\xC5\xBE\xC3\xADv\xC3\xA1te." tabs: - tracks_behavior: "Chov\xC3\xA1n\xC3\xAD Tracks" authentication: Autentizace + tracks_behavior: "Chov\xC3\xA1n\xC3\xAD Tracks" profile: Profil date_and_time: "Datum a \xC4\x8Das" + time: + am: am + formats: + stats: "%a %d-%m" + default: "%a, %d %b %Y %H:%M:%S %z" + time: "" + short: "%d %b %H:%M" + month_day: "%B %d" + long: "%B %d, %Y %H:%M" + pm: pm date: month_names: - @@ -1130,10 +1159,10 @@ cz: send_feedback: "Poslat zp\xC4\x9Btnou vazbu na %{version}" shared: multiple_next_actions: "\xC3\x9Akoly (jeden na ka\xC5\xBEd\xC3\xA9m \xC5\x99\xC3\xA1dku)" + make_actions_dependent: "Akce budou vz\xC3\xA1jemn\xC4\x9B z\xC3\xA1visl\xC3\xA9" toggle_single: !binary | UMWZaWRhdCDDumtvbA== - make_actions_dependent: "Akce budou vz\xC3\xA1jemn\xC4\x9B z\xC3\xA1visl\xC3\xA9" hide_form: "Schovat formul\xC3\xA1\xC5\x99" add_actions: "P\xC5\x99idat \xC3\xBAkoly" add_action: !binary | @@ -1157,6 +1186,32 @@ cz: ZSDDumtvbMWv hide_action_form_title: "Skr\xC3\xBDt formul\xC3\xA1\xC5\x99 pro zalo\xC5\xBEen\xC3\xAD nov\xC3\xA9ho \xC3\xBAkolu" + feedlist: + choose_context: "Vyberte kontext jeho\xC5\xBE feed si p\xC5\x99ejete" + actions_due_today: "Akce pl\xC3\xA1novan\xC3\xA9 na dnes" + ical_feed: iCal feed + legend: "Legenda:" + all_contexts: "V\xC5\xA1echny kontexty" + rss_feed: RSS Feed + choose_project: "Vyberte projekt jeho\xC5\xBE feed si p\xC5\x99ejete" + all_projects: "V\xC5\xA1echny projekty" + project_needed: "Mus\xC3\xADte nejd\xC5\x99\xC3\xADve zalo\xC5\xBEit aspo\xC5\x88 jeden projekt" + select_feed_for_project: Vyberte feed pro tento projekt + active_projects_wo_next: "Aktivni projekty bez \xC3\xBAkol\xC5\xAF" + active_starred_actions: "V\xC5\xA1echny aktivn\xC3\xAD \xC3\xBAkoly s hv\xC4\x9Bzdi\xC4\x8Dkou" + context_needed: "Mus\xC3\xADte nejd\xC5\x99\xC3\xADve zalo\xC5\xBEit aspo\xC5\x88 jeden kontext" + select_feed_for_context: Select the feed for this context + projects_and_actions: "Aktivn\xC3\xAD projekty a jejich \xC3\xBAkoly" + notice_incomplete_only: "Pozn\xC3\xA1mka: v\xC5\xA1echny feedy obsahuj\xC3\xAD jen nehotov\xC3\xA9 \xC3\xBAkoly." + actions_due_next_week: !binary | + w5prb2x5IHBsw6Fub3ZhbsOpIG5hIHDFmcOtxaF0w61jaCBzZWRtIGRuw60= + + actions_completed_last_week: "\xC3\x9Akoly dokon\xC4\x8Den\xC3\xA9 v posledn\xC3\xADch sedmi dnech" + context_centric_actions: "Feedy s aktivn\xC3\xADmi \xC3\xBAkoly podle kontext\xC5\xAF" + plain_text_feed: "Prost\xC3\xBD text" + last_fixed_number: "Posledn\xC3\xADch %{number} \xC3\xBAkol\xC5\xAF" + all_actions: "V\xC5\xA1echny \xC3\xBAkoly" + project_centric: "Feedy s aktivn\xC3\xADmi \xC3\xBAkoly podle projektu" sidebar: list_name_active_contexts: "Aktivn\xC3\xAD kontexty" list_name_active_projects: "Aktivn\xC3\xAD projekty" @@ -1164,72 +1219,14 @@ cz: list_name_completed_projects: "Hotov\xC3\xA9 projekty" list_name_hidden_projects: "Skryt\xC3\xA9 projekty" list_name_hidden_contexts: "Skryt\xC3\xA9 kontexty" - feedlist: - actions_due_today: "Akce pl\xC3\xA1novan\xC3\xA9 na dnes" - choose_context: "Vyberte kontext jeho\xC5\xBE feed si p\xC5\x99ejete" - rss_feed: RSS Feed - legend: "Legenda:" - ical_feed: iCal feed - all_contexts: "V\xC5\xA1echny kontexty" - all_projects: "V\xC5\xA1echny projekty" - choose_project: "Vyberte projekt jeho\xC5\xBE feed si p\xC5\x99ejete" - project_needed: "Mus\xC3\xADte nejd\xC5\x99\xC3\xADve zalo\xC5\xBEit aspo\xC5\x88 jeden projekt" - select_feed_for_project: Vyberte feed pro tento projekt - active_projects_wo_next: "Aktivni projekty bez \xC3\xBAkol\xC5\xAF" - active_starred_actions: "V\xC5\xA1echny aktivn\xC3\xAD \xC3\xBAkoly s hv\xC4\x9Bzdi\xC4\x8Dkou" - select_feed_for_context: Select the feed for this context - projects_and_actions: "Aktivn\xC3\xAD projekty a jejich \xC3\xBAkoly" - context_needed: "Mus\xC3\xADte nejd\xC5\x99\xC3\xADve zalo\xC5\xBEit aspo\xC5\x88 jeden kontext" - actions_due_next_week: !binary | - w5prb2x5IHBsw6Fub3ZhbsOpIG5hIHDFmcOtxaF0w61jaCBzZWRtIGRuw60= - - notice_incomplete_only: "Pozn\xC3\xA1mka: v\xC5\xA1echny feedy obsahuj\xC3\xAD jen nehotov\xC3\xA9 \xC3\xBAkoly." - context_centric_actions: "Feedy s aktivn\xC3\xADmi \xC3\xBAkoly podle kontext\xC5\xAF" - plain_text_feed: "Prost\xC3\xBD text" - last_fixed_number: "Posledn\xC3\xADch %{number} \xC3\xBAkol\xC5\xAF" - all_actions: "V\xC5\xA1echny \xC3\xBAkoly" - actions_completed_last_week: "\xC3\x9Akoly dokon\xC4\x8Den\xC3\xA9 v posledn\xC3\xADch sedmi dnech" - project_centric: "Feedy s aktivn\xC3\xADmi \xC3\xBAkoly podle projektu" - contexts: - delete_context_title: Smazat kontext - all_completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly v kontextu '%{context_name}'" - hide_form: "Schovat formul\xC3\xA1\xC5\x99" - show_form_title: "Nov\xC3\xBD kontext" - todos_append: "v t\xC3\xA9to souvislosti" - delete_context_confirmation: "Opravdu chcete smazat kontext '%{name}'? Dojde ke smaz\xC3\xA1n\xC3\xAD v\xC5\xA1ech (opakovan\xC3\xBDch) \xC3\xBAkol\xC5\xAF z dan\xC3\xA9ho kontextu!" - delete_context: Smazat kontext - edit_context: Upravit kontext - hide_form_title: "Schovat formul\xC3\xA1\xC5\x99" - hidden_contexts: Schovat kontexty - no_contexts_active: !binary | - xb3DoWRuw6kgYWt0aXZuw60ga29udGV4dHk= - - context_hide: "Schovat z \xC3\xBAvodn\xC3\xAD str\xC3\xA1nky?" - show_form: "Nov\xC3\xBD kontext" - visible_contexts: "Viditeln\xC3\xA9 kontexty" - save_status_message: "Kontext ulo\xC5\xBEen" - add_context: "Vytvo\xC5\x99it kontext" - update_status_message: "N\xC3\xA1zev kontextu byl zm\xC4\x9Bn\xC4\x9Bn" - context_name: "N\xC3\xA1ev kontextu" - status_active: "Kontext je aktivn\xC3\xAD" - completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly v kontextu '%{context_name}'" - new_context_post: "' bude tak\xC3\xA9 vytvo\xC5\x99en. Opravdu?" - no_actions: "\xC5\xBD\xC3\xA1dn\xC3\xA9 aktivn\xC3\xAD \xC3\xBAkoly v tomto kontextu" - last_completed_in_context: "v tomto kontextu (posledn\xC3\xADch %{number})" - context_deleted: "Kontext byl odstran\xC4\x9Bn '%{name}'" - no_contexts_hidden: !binary | - xb3DoWRuw6kgc2tyeXTDqSBrb250ZXh0eQ== - - new_context_pre: "Nov\xC3\xBD kontext '" - status_hidden: "kontext je skryt\xC3\xBD" users: - successfully_deleted_user: "U\xC5\xBEivatel %{username} byl \xC3\xBAsp\xC4\x9B\xC5\xA1n\xC4\x9B smaz\xC3\xA1n" + openid_url_verified: "Identitn\xC3\xAD url %{url} bylo \xC3\xBAsp\xC4\x9B\xC5\xA1n\xC4\x9B ov\xC4\x9B\xC5\x99eno a nastavena autentizace pomoc\xC3\xAD OpenID." auth_type_update_error: "Nepoda\xC5\x99ilo se zm\xC4\x9Bnit typ autentizace: %{error_messages}" failed_to_delete_user: "Nepoda\xC5\x99ilo se smazat u\xC5\xBEivatele %{username}" destroy_successful: "U\xC5\xBEivatel %{login} byl \xC3\xBAsp\xC4\x9B\xC5\xA1n\xC4\x9B zni\xC4\x8Den" - total_contexts: "Kontext\xC5\xAF celkem" first_user_heading: "V\xC3\xADtejte v TRACKS. Nejd\xC5\x99\xC3\xADve je nutn\xC3\xA9 vytvo\xC5\x99it administr\xC3\xA1torsk\xC3\xBD \xC3\xBA\xC4\x8Det:" - openid_url_verified: "Identitn\xC3\xAD url %{url} bylo \xC3\xBAsp\xC4\x9B\xC5\xA1n\xC4\x9B ov\xC4\x9B\xC5\x99eno a nastavena autentizace pomoc\xC3\xAD OpenID." + total_contexts: "Kontext\xC5\xAF celkem" + successfully_deleted_user: "U\xC5\xBEivatel %{username} byl \xC3\xBAsp\xC4\x9B\xC5\xA1n\xC4\x9B smaz\xC3\xA1n" signup_successful: "Registrace u\xC5\xBEivatele %{username} byla \xC3\xBAsp\xC4\x9B\xC5\xA1n\xC3\xA1." new_token_generated: !binary | Tm92w70gcGXFoWVrIGJ5bCDDunNwxJvFoW7EmyB2eWdlbmVyb3bDoW4= @@ -1239,25 +1236,25 @@ cz: no_signups_title: "TRACKS::Registrace nen\xC3\xAD povolena" user_created: "U\xC5\xBEivatel byl vytvo\xC5\x99en." account_signup: "Registrace u\xC5\xBEivatele" - password_updated: "Heslo bylo zm\xC4\x9Bn\xC4\x9Bno." manage_users: !binary | U3Byw6F2YSB1xb5pdmF0ZWzFrw== - new_user_heading: "Registrace nov\xC3\xA9ho u\xC5\xBEivatele:" + password_updated: "Heslo bylo zm\xC4\x9Bn\xC4\x9Bno." auth_type_updated: "Typ autentizace byl zm\xC4\x9Bn\xC4\x9Bn." total_actions: "\xC3\x9Akol\xC5\xAF celkem" desired_login: "U\xC5\xBEivatelsk\xC3\xA9 jm\xC3\xA9no" signup: Registrace confirm_password: "Potvrzen\xC3\xAD hesla" - change_password_prompt: "Pro zm\xC4\x9Bnu hesla zadejte nov\xC3\xA9 hestlo do pol\xC3\xAD n\xC3\xAD\xC5\xBEe a stiskn\xC4\x9Bte 'Zm\xC4\x9Bna hesla'." + new_user_heading: "Registrace nov\xC3\xA9ho u\xC5\xBEivatele:" password_confirmation_label: "Potvrzen\xC3\xAD hesla" destroy_error: "Nepoda\xC5\x99ilo se smazat u\xC5\xBEivatele %{login}" choose_password: Zvolte heslo change_password_title: "TRACKS::Zm\xC4\x9Bna hesla" change_auth_type_title: "TRACKS::Zm\xC4\x9Bna z\xC5\xAFsobu autentizace" + change_password_prompt: "Pro zm\xC4\x9Bnu hesla zadejte nov\xC3\xA9 hestlo do pol\xC3\xAD n\xC3\xAD\xC5\xBEe a stiskn\xC4\x9Bte 'Zm\xC4\x9Bna hesla'." + new_password_label: "Nov\xC3\xA9 heslo" register_with_cas: "S va\xC5\xA1\xC3\xADm u\xC5\xBEivatelsk\xC3\xBDm jm\xC3\xA9nem z CASu" label_auth_type: "Zp\xC5\xAFsob autentizace" - new_password_label: "Nov\xC3\xA9 heslo" total_users_count: "M\xC3\xA1te celkem %{count} u\xC5\xBEivatel\xC5\xAF" new_user_title: "TRACKS::P\xC5\x99ihl\xC3\xA1\xC5\xA1en\xC3\xAD jako administr\xC3\xA1tor" destroy_user: "Zni\xC4\x8Dit u\xC5\xBEivatele" @@ -1272,15 +1269,45 @@ cz: change_authentication_type: !binary | Wm3Em25hIHpwxa9zb2J1IHDFmWlobGHFoW92w6Fuw60= - select_authentication_type: "Vyberte nov\xC3\xBD zp\xC5\xAFsob autentizace a stiskn\xC4\x9Bte 'Zm\xC4\x9Bnit zp\xC5\xAFsob p\xC5\x99ihla\xC5\xA1ov\xC3\xA1n\xC3\xAD'." total_notes: "Pozn\xC3\xA1mek celkem" + select_authentication_type: "Vyberte nov\xC3\xBD zp\xC5\xAFsob autentizace a stiskn\xC4\x9Bte 'Zm\xC4\x9Bnit zp\xC5\xAFsob p\xC5\x99ihla\xC5\xA1ov\xC3\xA1n\xC3\xAD'." + contexts: + delete_context_title: Smazat kontext + all_completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly v kontextu '%{context_name}'" + hide_form: "Schovat formul\xC3\xA1\xC5\x99" + show_form_title: "Nov\xC3\xBD kontext" + delete_context_confirmation: "Opravdu chcete smazat kontext '%{name}'? Dojde ke smaz\xC3\xA1n\xC3\xAD v\xC5\xA1ech (opakovan\xC3\xBDch) \xC3\xBAkol\xC5\xAF z dan\xC3\xA9ho kontextu!" + todos_append: "v t\xC3\xA9to souvislosti" + delete_context: Smazat kontext + edit_context: Upravit kontext + hide_form_title: "Schovat formul\xC3\xA1\xC5\x99" + hidden_contexts: Schovat kontexty + no_contexts_active: !binary | + xb3DoWRuw6kgYWt0aXZuw60ga29udGV4dHk= + + context_hide: "Schovat z \xC3\xBAvodn\xC3\xAD str\xC3\xA1nky?" + add_context: "Vytvo\xC5\x99it kontext" + show_form: "Nov\xC3\xBD kontext" + save_status_message: "Kontext ulo\xC5\xBEen" + visible_contexts: "Viditeln\xC3\xA9 kontexty" + update_status_message: "N\xC3\xA1zev kontextu byl zm\xC4\x9Bn\xC4\x9Bn" + context_name: "N\xC3\xA1ev kontextu" + status_active: "Kontext je aktivn\xC3\xAD" + completed_tasks_title: "TRACKS::Hotov\xC3\xA9 \xC3\xBAkoly v kontextu '%{context_name}'" + new_context_post: "' bude tak\xC3\xA9 vytvo\xC5\x99en. Opravdu?" + new_context_pre: "Nov\xC3\xBD kontext '" + no_actions: "\xC5\xBD\xC3\xA1dn\xC3\xA9 aktivn\xC3\xAD \xC3\xBAkoly v tomto kontextu" + last_completed_in_context: "v tomto kontextu (posledn\xC3\xADch %{number})" + context_deleted: "Kontext byl odstran\xC4\x9Bn '%{name}'" + no_contexts_hidden: !binary | + xb3DoWRuw6kgc2tyeXTDqSBrb250ZXh0eQ== + + status_hidden: "kontext je skryt\xC3\xBD" login: - login_cas: "p\xC5\x99ej\xC3\xADt na CAS" openid_identity_url_not_found: "Je n\xC3\xA1m l\xC3\xADto, neexistuje u\xC5\xBEivatel s touto identitou (%{identity_url})" user_no_expiry: "Neodhl\xC5\xA1ovat" sign_in: "P\xC5\x99ihl\xC3\xA1sit se" - please_login: "Pro pokra\xC4\x8Dov\xC3\xA1n\xC3\xAD se pros\xC3\xADm p\xC5\x99ihl\xC5\xA1te do Tracks" - cas_logged_in_greeting: "Zdrav\xC3\xAD\xC4\x8Dko, %{username}! Byl jste autorizov\xC3\xA1n." + login_cas: "p\xC5\x99ej\xC3\xADt na CAS" cas_no_user_found: "Nazdar, %{username}! Nem\xC3\xA1te \xC3\xBA\xC4\x8Det na Tracks." cas_login: !binary | UMWZaWhsw6HFoWVuw60gcMWZZXMgQ0FT @@ -1288,6 +1315,8 @@ cz: successful_with_session_info: !binary | UMWZaWhsw6HFoWVuw60gYnlsbyDDunNwxJvFoW7DqTo= + please_login: "Pro pokra\xC4\x8Dov\xC3\xA1n\xC3\xAD se pros\xC3\xADm p\xC5\x99ihl\xC5\xA1te do Tracks" + cas_logged_in_greeting: "Zdrav\xC3\xAD\xC4\x8Dko, %{username}! Byl jste autorizov\xC3\xA1n." cas_username_not_found: "Bohu\xC5\xBEel neexistuje u\xC5\xBEivatel v CASu se jm\xC3\xA9nem (%{username})" cas_create_account: "Pro vytvo\xC5\x99en\xC3\xAD \xC3\xBA\xC4\x8Dtu v CASu pros\xC3\xADm pokra\xC4\x8Dujte sem %{signup_link}" mobile_use_openid: !binary | @@ -1307,12 +1336,12 @@ cz: session_time_out: "Sezen\xC3\xAD vypr\xC5\xA1elo. Pros\xC3\xADm %{link}" session_will_expire: "sezen vypr\xC5\xA1\xC3\xAD za %{hours} hodin neaktivity." login_standard: "vra\xC5\xA5te se ke standardn\xC3\xADmu p\xC5\x99ihl\xC3\xA1\xC5\xA1en\xC3\xAD" - log_in_again: "p\xC5\x99ihla\xC5\xA1te se znovu." - logged_out: You have been logged out of Tracks. login_with_openid: "p\xC5\x99ihla\xC5\xA1te se se sv\xC3\xBDm OpenID" unsuccessful: !binary | UMWZaWhsw6HFoWVuw60gYnlsbyDDunNwxJvFoW7DqS4= + log_in_again: "p\xC5\x99ihla\xC5\xA1te se znovu." + logged_out: You have been logged out of Tracks. datetime: prompts: minute: Minuta @@ -1375,7 +1404,7 @@ cz: tags_matching_query: !binary | TmFsZXplbsOpIMWhdMOtdGt5 + no_results: "Na v\xC3\xA1\xC5\xA1 dotaz nebylo nic nalezeno." todos_matching_query: "Nalezen\xC3\xA9 \xC3\xBAkoly" projects_matching_query: "Nalezen\xC3\xA9 projekty" notes_matching_query: "Nalezen\xC3\xA9 pozn\xC3\xA1mky" - no_results: "Na v\xC3\xA1\xC5\xA1 dotaz nebylo nic nalezeno." diff --git a/config/locales/de.yml b/config/locales/de.yml index 112ddb61..39001004 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1,5 +1,54 @@ --- de: + layouts: + toggle_contexts_title: Machen Sie brach Kontexten (un)sichtbare + toggle_contexts: Toggle zusammengebrochen Kontexten + toggle_notes: Notizen umschalten + next_actions_rss_feed: RSS-Feed kommende Aufgaben + toggle_notes_title: Alle Notizen umschalten + mobile_navigation: + new_action: Neue Aufgabe + logout: Abmelden + feeds: Feeds + starred: Markiert + projects: Projekte + tickler: Notizbuch + contexts: Kontexte + home: Home + navigation: + manage_users_title: "Benutzer hinzuf\xC3\xBCgen oder entfernen" + recurring_todos: Sich wiederholende To-Dos + api_docs: REST API Docs + help: "?" + feeds: Feeds + starred: Markiert + stats: Statistiken + notes_title: Alle Notizen anzeigen + manage_users: Benutzer verwalten + tickler_title: Notizbuch + admin: Admin + preferences: Einstellungen + integrations_: Tracks integrieren + export_title: Daten importieren und exportieren + calendar_title: "Kalender mit \xC3\xBCberf\xC3\xA4lligen Aufgaben" + feeds_title: "Liste der verf\xC3\xBCgbaren Feeds anzeigen" + stats_title: Statistiken anzeigen + tickler: Notizbuch + home_title: Start + starred_title: Markierte Aufgaben betrachten + recurring_todos_title: Sich wiederholende To-Dos verwalten + completed_tasks: Erledigt + view: Betrachten + organize: Organisieren + completed_tasks_title: "Vollst\xC3\xA4ndig" + home: Start + export: Export + contexts_title: Kontexte + preferences_title: Meine Einstellungen + search: "Alle Eintr\xC3\xA4ge durchsuchen" + review_title: "Machen Sie \xC3\xBCberpr\xC3\xBCfen" + projects_title: Projekte + calendar: Kalender number: format: separator: "," @@ -34,121 +83,83 @@ de: separator: . precision: delimiter: "," - layouts: - toggle_contexts_title: Machen Sie brach Kontexten (un)sichtbare - toggle_notes: Notizen umschalten - toggle_contexts: Toggle zusammengebrochen Kontexten - next_actions_rss_feed: RSS-Feed kommende Aufgaben - toggle_notes_title: Alle Notizen umschalten - mobile_navigation: - feeds: Feeds - new_action: Neue Aufgabe - logout: Abmelden - starred: Markiert - projects: Projekte - tickler: Notizbuch - contexts: Kontexte - home: Home - navigation: - manage_users_title: "Benutzer hinzuf\xC3\xBCgen oder entfernen" - api_docs: REST API Docs - recurring_todos: Sich wiederholende To-Dos - feeds: Feeds - help: "?" - stats: Statistiken - starred: Markiert - notes_title: Alle Notizen anzeigen - manage_users: Benutzer verwalten - tickler_title: Notizbuch - admin: Admin - integrations_: Tracks integrieren - export_title: Daten importieren und exportieren - preferences: Einstellungen - calendar_title: "Kalender mit \xC3\xBCberf\xC3\xA4lligen Aufgaben" - feeds_title: "Liste der verf\xC3\xBCgbaren Feeds anzeigen" - completed_tasks: Erledigt - stats_title: Statistiken anzeigen - tickler: Notizbuch - home_title: Start - starred_title: Markierte Aufgaben betrachten - recurring_todos_title: Sich wiederholende To-Dos verwalten - view: Betrachten - organize: Organisieren - completed_tasks_title: "Vollst\xC3\xA4ndig" - home: Start - contexts_title: Kontexte - export: Export - preferences_title: Meine Einstellungen - review_title: "Machen Sie \xC3\xBCberpr\xC3\xBCfen" - calendar: Kalender - search: "Alle Eintr\xC3\xA4ge durchsuchen" - projects_title: Projekte + common: + recurring_todos: Wiederholenden Aktionen + back: "Zur\xC3\xBCck" + actions: Aktionen + third: Dritte + add: "Hinzuf\xC3\xBCgen" + go_back: "Zur\xC3\xBCck" + previous: Vorherige + logout: Abmelden + second: Zweite + none: Keine + week: Woche + optional: optional + deferred: Aufgeschoben + cancel: Abbrechen + show_all: Alle einzeigen + month: Monat + actions_midsentence: + one: Aktion + other: Aktionen + zero: Aktionen + forum: Forum + server_error: Auf dem Server ist ein Fehler aufgetreten. + notes: Notizen + projects: Projekte + last: Letzte + review: !binary | + w5xiZXJwcsO8ZnVuZw== + + action: Aktion + days_midsentence: + one: Tag + other: Tagen + zero: Tagen + project: Projekt + contribute: Mitwirken + ok: Ok + website: Website + first: Erste + note: + one: 1 Notiz + other: "%{count} Notizen" + zero: keine Notizen + numbered_step: Schritt %{number} + sort: + by_task_count_title: Nach Anzahl der Aufgaben sortieren + by_task_count_title_confirm: Sollen diese Projekte wirklich nach Anzahl der Aufgaben sortiert werden? Die bisherige Sortier-Reihenfolge wird damit überschrieben. + alphabetically: Alphabetisch + sort: Sortieren + alphabetically_title: Projekte alphabetisch sortieren + alphabetically_confirm: Sollen diese Projekte wirklich alphabetisch sortiert werden? Die bisherige Sortier-Reihenfolge wird damit überschrieben. + by_task_count: Nach Anzahl der Aufgaben + create: Erstellen + todo: Aktione + months: Monate + description: Beschreibung + errors_with_fields: "Mit folgenden Feldern sind Probleme aufgetreten:" + drag_handle: Verschieben + next: "N\xC3\xA4chste" + fourth: Vierte + context: Kontext + contexts: Kontexte + bugs: Bugs + update: Aktualisieren + forth: Vierte + weeks: Woche + wiki: Wiki + email: E-Mail + search: Suchen + ajaxError: Fehler beim Empfangen vom Server + not_available_abbr: n/b integrations: opensearch_description: In Tracks suchen applescript_next_action_prompt: "Beschreibung der n\xC3\xA4chsten Aufgabe:" gmail_description: "Gadget, um Tracks als Gadget zu Googlemail hinzuzuf\xC3\xBCgen" applescript_success_after_id: erstellt applescript_success_before_id: "N\xC3\xA4chste neue Aufgabe mit ID" - common: - back: "Zur\xC3\xBCck" - recurring_todos: Wiederholenden Aktionen - actions: Aktionen - third: Dritte - add: "Hinzuf\xC3\xBCgen" - previous: Vorherige - go_back: "Zur\xC3\xBCck" - logout: Abmelden - second: Zweite - show_all: Alle einzeigen - optional: optional - week: Woche - none: Keine - cancel: Abbrechen - month: Monat - actions_midsentence: Aktionen - server_error: Auf dem Server ist ein Fehler aufgetreten. - forum: Forum - notes: Notizen - last: Letzte - projects: Projekte - action: Aktion - review: !binary | - w5xiZXJwcsO8ZnVuZw== - - project: Projekt - days_midsentence: Tagen - contribute: Mitwirken - ok: Ok - website: Website - first: Erste - numbered_step: Schritt %{number} - errors_with_fields: "Mit folgenden Feldern sind Probleme aufgetreten:" - create: Erstellen - sort: - by_task_count_title: Nach Anzahl der Aufgaben sortieren - by_task_count_title_confirm: Sollen diese Projekte wirklich nach Anzahl der Aufgaben sortiert werden? Die bisherige Sortier-Reihenfolge wird damit überschrieben. - alphabetically: Alphabetisch - alphabetically_title: Projekte alphabetisch sortieren - sort: Sortieren - alphabetically_confirm: Sollen diese Projekte wirklich alphabetisch sortiert werden? Die bisherige Sortier-Reihenfolge wird damit überschrieben. - by_task_count: Nach Anzahl der Aufgaben - months: Monate - description: Beschreibung - todo: Aktione - fourth: Vierte - next: "N\xC3\xA4chste" - contexts: Kontexte - context: Kontext - drag_handle: Verschieben - update: Aktualisieren - weeks: Woche - forth: Vierte - wiki: Wiki - bugs: Bugs - ajaxError: Fehler beim Empfangen vom Server - not_available_abbr: n/b - email: E-Mail - search: Suchen activerecord: attributes: project: @@ -160,17 +171,14 @@ de: created_at: Erstellt am updated_at: Aktualisiert am todo: - predecessors: "H\xC3\xA4ngt ab von" show_from: Zeigen ab dem + predecessors: "H\xC3\xA4ngt ab von" notes: Notizen - project: Projekt tags: Stichworte + project: Projekt description: Beschreibung context: Kontext due: Fällig - user: - last_name: Nachname - first_name: Vorname preference: show_hidden_projects_in_sidebar: Zeige Versteckte Projekte in der Sidebar show_hidden_contexts_in_sidebar: "Zeige Versteckte Zusammenh\xC3\xA4nge in der Sidebar" @@ -179,19 +187,22 @@ de: verbose_action_descriptors: "Ausf\xC3\xBChrlich Aktion Deskriptoren" staleness_starts: Anfang des Abgestandenheit mobile_todos_per_page: Aufgaben pro Seite (Mobile Version) - title_date_format: Titel Datumsformat show_number_completed: "Zeige Zahl der abgeschlossenen Ma\xC3\x9Fnahmen" + title_date_format: Titel Datumsformat refresh: Aktualisierungsintverall (in Minuten) week_starts: Woche startet am last_name: Nachname due_style: "F\xC3\xA4llig stijl" locale: Zahle time_zone: Zeit Zone - show_project_on_todo_done: Zur Projektseite wechseln, wenn To-Do abgeschlossen sms_email: Per E-Mail - first_name: Name + show_project_on_todo_done: Zur Projektseite wechseln, wenn To-Do abgeschlossen show_completed_projects_in_sidebar: Zeige abgeschlossene Projekte in der Sidebar + first_name: Name review_period: Projekt-Review-Intervall + user: + last_name: Nachname + first_name: Vorname errors: models: project: @@ -221,13 +232,13 @@ de: taken: ist bereits vergeben inclusion: "ist kein g\xC3\xBCltiger Wert" not_a_number: ist keine Zahl - full_messages: - format: "%{attribute} %{message}" template: body: "Bitte \xC3\xBCberpr\xC3\xBCfen Sie die folgenden Felder:" header: one: "Konnte dieses %{model} Objekt nicht speichern: 1 Fehler." other: "Konnte dieses %{model} Objekt nicht speichern: %{count} Fehler." + full_messages: + format: "%{attribute} %{message}" data: import_successful: Import war erfolgreich. import_errors: Beim Import sind Fehler aufgetreten. @@ -237,21 +248,21 @@ de: feed_description: "Listet alle Projekte f\xC3\xBCr %{username} auf" todo: error_date_must_be_future: muss ein Datum in der Zukunft sein - user: - error_context_not_associated: "Kontext-ID %{context} nicht mit Benutzer-ID %{user} verkn\xC3\xBCpft." - error_project_not_associated: "Projekt-ID %{project} nicht mit User-ID %{user} verkn\xC3\xBCpft." preference: due_on: "F\xC3\xA4llig auf %{date}" due_in: "F\xC3\xA4llig in %{days} Tagen" due_styles: - "F\xC3\xA4llig in ___ Tagen" - "F\xC3\xA4llig am _______" + user: + error_context_not_associated: "Kontext-ID %{context} nicht mit Benutzer-ID %{user} verkn\xC3\xBCpft." + error_project_not_associated: "Projekt-ID %{project} nicht mit User-ID %{user} verkn\xC3\xBCpft." stats: - tag_cloud_title: Tag-Cloud aller Aktionen totals_hidden_context_count: und %{count} sind versteckte Kontexte. actions_avg_created: In den letzten 12 Monaten hast du im Durchschnitt %{count} Aktionen erstellt actions_min_max_completion_days: "Das Minimum/Maximum an Tagen einer Vervollst\xC3\xA4ndigung ist %{min}/%{max}." totals_actions_completed: "%{count} davon sind abgeschlossen." + tag_cloud_title: Tag-Cloud aller Aktionen actions_actions_avg_created_30days: In den letzten 30 Tagen hast du im Durchschnitt %{count} Aktionen erstellt actions_avg_completed: und %{count} durchschnittlich davon monatlich erledigt top5_visible_contexts_with_incomplete_actions: "Top 5 der sichtbaren Kontexte mit unvollst\xC3\xA4ndigen Aktionen" @@ -267,11 +278,11 @@ de: weeks: "Vergangene Zeit einer Aktion (Wochen). Klick auf eine Leiste f\xC3\xBCr mehr Informationen." totals_action_count: hattest du insgesamt %{count} Aktionen tag_cloud_90days_title: Tag-Cloud-Aktionen in den letzten 90 Tagen + actions_avg_completion_time: Durchschnittlich hast du %{count} Tage gebraucht, um eine Aktion abzuschliessen. tod30: Tageszeit (letzte 30 Tage) tags: Tags projects: Projekte - actions_avg_completion_time: Durchschnittlich hast du %{count} Tage gebraucht, um eine Aktion abzuschliessen. - actions_lastyear_title: Aktionen der letzten 12 Monate + totals_completed_project_count: und %{count} sind abgeschlossene Projekte. labels: month_avg_completed: "%{months} Monat durchschnittlich fertig gestellt" completed: Erledigt @@ -280,8 +291,8 @@ de: avg_completed: Durchschnittlich fertiggestellt created: Erstellt actions_selected_from_week: "Aktionen ausgew\xC3\xA4hlt ab Woche" - totals_completed_project_count: und %{count} sind abgeschlossene Projekte. actions_day_of_week_title: Wochentag (alle Aktionen) + actions_lastyear_title: Aktionen der letzten 12 Monate open_per_week: "Aktiv (sichtbar und unsichtbar) n\xC3\xA4chsten Aktionen pro Woche" action_selection_title: TRACKS::Aktionsauswahl totals_project_count: Du hast %{count} Projekte. @@ -304,16 +315,16 @@ de: actions_last_year_legend: number_of_actions: Anzahl Aktionen months_ago: Monate zuvor - top10_projects: Top 10 aller Projekte top5_contexts: Top 5 aller Kontexte - click_to_return: "Klick auf %{link} um zur Statistikseite zur\xC3\xBCckzukehren." - totals: Ingesamt + top10_projects: Top 10 aller Projekte contexts: Kontexte + totals: Ingesamt + click_to_return: "Klick auf %{link} um zur Statistikseite zur\xC3\xBCckzukehren." tag_cloud_90days_description: Diese Tag-Cloud beinhaltet Tags der Aktionen, die in den letzten 90 Tagen erstellt oder abgeschlossen wurden. totals_visible_context_count: Von diesen sind %{count} sichtbare Kontexte - actions_min_completion_time: "Die minimale Zeit betr\xC3\xA4gt %{time}." top10_projects_30days: Top-10-Projekt der letzten 30 Tage running_time_all: "Aktuelle Laufzeit aller unvollst\xC3\xA4ndigen Aktionen." + actions_min_completion_time: "Die minimale Zeit betr\xC3\xA4gt %{time}." action_completion_time_title: Fertigstellungszeit (alle abgeschlossenen Aktionen) click_to_show_actions_from_week: Klick auf %{link} um die Aktionen von Woche %{week} und danach anzuzeigen. top10_longrunning: "Top 10 der am l\xC3\xA4ngsten laufenden Projekte" @@ -325,14 +336,14 @@ de: day_of_week: Tag der Woche totals_first_action: Seit deiner ersten Aktion am %{date} tag_cloud_description: Diese Tag-Cloud beinhaltet Tags aller Aktionen (abgeschlossen, nicht abgeschlossen, sichtbar und/oder unsichtbar) + spread_of_actions_for_all_context: Aufgabenverteilung aller Kontexte click_to_update_actions: Klicke auf eine Leiste in der Grafik um die Aktionen unten zu aktualisieren. click_to_return_link: hier - spread_of_actions_for_all_context: Aufgabenverteilung aller Kontexte more_stats_will_appear: "Weitere Statistiken werden verf\xC3\xBCgbar, wenn einige Aufgaben hinzugef\xC3\xBCgt wurden." actions_avg_completed_30days: und %{count} durchschnittlich davon erledigt. + index_title: TRACKS::Statistik actions_30days_title: _Aktionen der letzten 30 Tage no_tags_available: "keine Tags verf\xC3\xBCgbar" - index_title: TRACKS::Statistik actions_dow_30days_title: Wochentag (letzte 30 Tage) actions_day_of_week_legend: number_of_actions: Anzahl der Aktionen @@ -348,19 +359,19 @@ de: running_time: "Laufzeit einer Aktion (Wochen). Klick auf eine Leiste f\xC3\xBCr mehr Informationen." percentage: Prozentsatz other_actions_label: (andere) - time_of_day: Tageszeit (alle Aktionen) totals_hidden_project_count: "%{count} sind versteckt" + time_of_day: Tageszeit (alle Aktionen) todos: - completed_actions: Erledigte Aufgaben + recurring_action_deleted: Die Aktion wurde gelöscht. Da dies eine wiederkehrende Aktion ist, wurde eine neue erstellt. show_from: Anzeigen ab dem error_starring_recurring: Konnte die Hervorhebung der wiederkehrenden Aufgabe \'%{description}\' nicht durchführen - recurring_action_deleted: Die Aktion wurde gelöscht. Da dies eine wiederkehrende Aktion ist, wurde eine neue erstellt. - completed_rest_of_previous_month: Fertiggestellt den Rest des Vormonats - completed_recurring: Abgeschlossene wiederkehrende To-Dos + completed_actions: Erledigte Aufgaben added_new_next_action: Neue Aktion angelegt + completed_recurring: Abgeschlossene wiederkehrende To-Dos + completed_rest_of_previous_month: Fertiggestellt den Rest des Vormonats blocked_by: Blockiert durch %{predecessors} - completed_recurrence_completed: Es gibt keine weitere Aktion nach der soeben gelöschten. Die Wiederholung ist abgeschlossen. star_action: Aktion markieren + completed_recurrence_completed: Es gibt keine weitere Aktion nach der soeben gelöschten. Die Wiederholung ist abgeschlossen. defer_date_after_due_date: "Zur\xC3\xBCckstellungsdatum nach Ablaufdatum. Bitte passe das Ablaufdatum an, dass es vor dem Zur\xC3\xBCckstellungsdatum liegt." unable_to_add_dependency: Abhängigkeit nicht hinzufügbar done: Erledigt? @@ -371,16 +382,16 @@ de: no_hidden_actions: Momentan sind keine versteckten Aufgaben vorhanden edit_action_with_description: Aktion '%{description}' bearbeiten action_due_on: "(Aktion f\xC3\xA4llig am %{date})" + list_incomplete_next_actions: Unerledigte Folge-Aufgaben anzeigen archived_tasks_title: TRACKS::Archivierte erledigte Aufgaben remove_dependency: Abhängigkeit löschen (löscht nicht die Aufgabe) - list_incomplete_next_actions: Unerledigte Folge-Aufgaben anzeigen - tags: Tags (Komma-separiert) action_deleted_success: Die nächste Aktion erfolgreich gelöscht - mobile_todos_page_title: Alle Aufgaben - new_related_todo_created: "Eine neue To-Do wurde hinzugef\xC3\xBCgt, die zu dieser wiederkehrenden To-Do geh\xC3\xB6rt" - context_changed: Kontext zu %{name} gewechselt - add_another_dependency: "F\xC3\xBCgen Sie eine andere Abh\xC3\xA4ngigkeit" + tags: Tags (Komma-separiert) delete_recurring_action_title: "Wiederkehrende Aktion '%{description}' l\xC3\xB6schen" + context_changed: Kontext zu %{name} gewechselt + new_related_todo_created: "Eine neue To-Do wurde hinzugef\xC3\xBCgt, die zu dieser wiederkehrenden To-Do geh\xC3\xB6rt" + mobile_todos_page_title: Alle Aufgaben + add_another_dependency: "F\xC3\xBCgen Sie eine andere Abh\xC3\xA4ngigkeit" removed_predecessor: "%{successor} entfernt als Abh\xC3\xA4ngigkeit von %{predecessor}." recurring_actions_title: TRACKS::Wiederkehrende Aktionen next_action_needed: Es muss mindestens eine folgende Aktion angelegt werden @@ -390,40 +401,41 @@ de: edit_action: Aktion bearbeiten added_new_context: "Neuer Kontext hinzugef\xC3\xBCgt" next_actions_description: "Filter:" + list_incomplete_next_actions_with_limit: Zeige die letzten %{count} unerledigten Folge-Aufgaben + set_to_pending: "%{task} als ausstehend markiert" + added_new_project: "Neues Projekt hinzugef\xC3\xBCgt" next_actions_title_additions: completed: Aufgaben erledigt due_today: heute fällig due_within_a_week: diese Woche fällig - list_incomplete_next_actions_with_limit: Zeige die letzten %{count} unerledigten Folge-Aufgaben - set_to_pending: "%{task} als ausstehend markiert" - added_new_project: "Neues Projekt hinzugef\xC3\xBCgt" older_completed_items: "Ältere erledigte Aufgaben" - error_deleting_item: Beim Löschen von %{description} trat ein Fehler auf - edit_recurring_todo: Bearbeiten Repetieren aktion - append_in_this_project: in diesem Projekt - task_list_title: TRACKS::Aufgaben anzeigen no_actions_due_this_week: Keine zu erledigenden Aufgaben für den Rest der Woche + all_completed_here: hier + append_in_this_project: in diesem Projekt + edit_recurring_todo: Bearbeiten Repetieren aktion + error_deleting_item: Beim Löschen von %{description} trat ein Fehler auf + task_list_title: TRACKS::Aufgaben anzeigen no_recurring_todos: Im Augenblick gibt es keine wiederkehrenden To-Dos error_completing_todo: Beim Abschliessen/Aktivieren der wiederkehrenden To-Do %{description} ist ein Fehler aufgetreten recurring_pattern_removed: Das Wiederauftreten Muster ist aus entfernt %{count} convert_to_project: In Projekt umwandeln no_deferred_pending_actions: Momentan sind keine aufgeschobenen oder ausstehenden Aufgaben vorhanden. - completed_last_day: In den letzten 24 Stunden erledigt delete_recurring_action_confirm: Soll die wiederkehrende Aktion '%{description}' wirklich gelöscht werden? - show_in_days: Anzeigen in %{days} Tagen + completed_last_day: In den letzten 24 Stunden erledigt + feed_title_in_context: im Kontext '%{context}' no_project: --Kein Projekt-- + show_in_days: Anzeigen in %{days} Tagen error_saving_recurring: Es gab einen Fehler beim Speichern der wiederkehrenden todo '%{description}' completed_more_than_x_days_ago: Vor mehr als %{count} Tagen erledigt - all_completed: Alle abgeschlossenen Aktionen - feed_title_in_context: im Kontext '%{context}' new_related_todo_created_short: hat einen neuen todo + all_completed: Alle abgeschlossenen Aktionen edit: Bearbeiten + completed_actions_with: Abgeschlossene Aktionen mit dem Tag %{tag_name} older_than_days: "Älter als %{count} Tage" completed_tagged_page_title: "TRACKS:: Erledigte Aufgaben mit Tag %{tag_name}" pending: Ausstehend - completed_actions_with: Abgeschlossene Aktionen mit dem Tag %{tag_name} - deleted_success: "Die Aktion wurde erfolgreich gel\xC3\xB6scht." completed_tasks_title: TRACKS::Erledigte Aufgaben + deleted_success: "Die Aktion wurde erfolgreich gel\xC3\xB6scht." feed_title_in_project: im Projekt '%{project}' clear_due_date: Fälligkeitsdatum leeren error_removing_dependency: "Beim Entfernen der Abh\xC3\xA4ngigkeit ist ein Fehler aufgetreten" @@ -434,20 +446,21 @@ de: deferred_actions_with: "Zur\xC3\xBCckgestellte Aktionen mit dem Tag '%{tag_name}'" confirm_delete: "Bist du sicher, dass du die Aktion '%{description}' l\xC3\xB6schen m\xC3\xB6chtest?" recurring_deleted_success: "Die wiederkehrende Aktion wurde erfolgreich gel\xC3\xB6scht." - clear_show_from_date: Datum leeren + no_completed_actions_with: Keine abgeschlossenen Aktionen mit dem Tag '%{tag_name}' next_actions_title: TRACKS::Weitere Aufgaben next_action_description: "Beschreibung der n\xC3\xA4chsten Aktion" deferred_tasks_title: TRACKS::Notizbuch - no_completed_actions_with: Keine abgeschlossenen Aktionen mit dem Tag '%{tag_name}' - unresolved_dependency: "Der Wert, den Sie in die Abh\xC3\xA4ngigkeit Feld eingegeben nicht zu einer bestehenden Aktion zu l\xC3\xB6sen. Dieser Wert wird nicht mit dem Rest der Aktion gerettet werden. Weiter gehen?" - calendar_page_title: TRACKS::Kalender + clear_show_from_date: Datum leeren in_hidden_state: als versteckt markiert - show_today: Heute anzeigen + see_all_completed: "Sie k\xC3\xB6nnen alle Aktionen abgeschlossen siehe %{link}" + calendar_page_title: TRACKS::Kalender + unresolved_dependency: "Der Wert, den Sie in die Abh\xC3\xA4ngigkeit Feld eingegeben nicht zu einer bestehenden Aktion zu l\xC3\xB6sen. Dieser Wert wird nicht mit dem Rest der Aktion gerettet werden. Weiter gehen?" no_actions_found_title: Keine Aktionen gefunden + show_today: Heute anzeigen next_actions_due_date: overdue_by: "\xC3\x9Cberf\xC3\xA4llig mit %{days} Tag" - due_today: "Heute f\xC3\xA4llig" due_in_x_days: "F\xC3\xA4llig in %{days} Tagen" + due_today: "Heute f\xC3\xA4llig" overdue_by_plural: "\xC3\x9Cberf\xC3\xA4llig mit %{days} Tagen" due_tomorrow: "F\xC3\xA4llig morgen" completed_last_x_days: In den letzten %{count} Tagen erledigt @@ -464,13 +477,13 @@ de: feeds: completed: "Erledigt: %{date}" due: "F&auuml;llig: %{date}" - delete_action: "Aktion l\xC3\xB6schen" - error_deleting_recurring: "Beim L\xC3\xB6schen der wiederkehrenden To-Do %{description} ist ein Fehler aufgetreten" recurring_todos: Wiederkehrende To-Dos + error_deleting_recurring: "Beim L\xC3\xB6schen der wiederkehrenden To-Do %{description} ist ein Fehler aufgetreten" + delete_action: "Aktion l\xC3\xB6schen" delete: "L\xC3\xB6schen" + no_last_completed_actions: Keine abgeschlossene Aktionen gefunden drag_action_title: "Auf andere Aktion ziehen, um sie als Abh\xC3\xA4ngigkeit zu definieren" cannot_add_dependency_to_completed_todo: "Kann nicht hinzugef\xC3\xBCgt werden diese Aktion als eine Abh\xC3\xA4ngigkeit zu einer abgeschlossenen Aktion!" - no_last_completed_actions: Keine abgeschlossene Aktionen gefunden depends_on: "H\xC3\xA4ngt ab von" tickler_items_due: one: Ein Notizbuch-Eintrag ist nun fällig - lade die Seite neu, um sie zu sehen. @@ -480,6 +493,7 @@ de: added_new_next_action_plural: Neue weiterführende Aufgaben angelegt new_related_todo_not_created_short: nicht schaffen todo completed_rest_of_week: Fertiggestellt den Rest dieser Woche + show_tomorrow: Morgen anzeigen error_starring: Konnte die Hervorhebung von \'%{description}\' nicht durchführen calendar: get_in_ical_format: Diesen Kalender im iCal Format herunterladen @@ -492,9 +506,7 @@ de: no_actions_due_after_this_month: Nach diesem Monat sind keine Aufgaben fällig no_actions_due_this_month: Keine Aktionen für den Rest des Monats due_this_month: Im %{month} fällig - show_tomorrow: Morgen anzeigen - tagged_page_title: TRACKS::Als '%{tag_name}' markiert - action_deferred: Die Aktion \'% {description}\' wurde vertagt + no_completed_recurring: Im Augenblick gibt es keine abgeschlossenen wiederkehrenden To-Dos recurrence: ends_on_date: Endet am %{date} every_work_day: Jeden Arbeitstag @@ -503,11 +515,13 @@ de: weekly_options: "Einstellungen f\xC3\xBCr sich w\xC3\xB6chentlich wiederholende Aktionen" weekly: "W\xC3\xB6chentlich" monthly_options: "Einstellungen f\xC3\xBCr sich monatlich wiederholende Aktionen" + daily_options: "Einstellungen f\xC3\xBCr sich t\xC3\xA4glich wiederholenden Aktionen" monthly: Monatlich starts_on: Beginnt am - daily_options: "Einstellungen f\xC3\xBCr sich t\xC3\xA4glich wiederholenden Aktionen" daily: "T\xC3\xA4glich" + show_option_always: immer pattern: + third: Drittel month_names: - - Januar @@ -524,17 +538,20 @@ de: - Oktober - November - Dezember - third: Drittel every_n: jeden %{n} - every_xth_day_of_every_n_months: "jedes %{x} %{day} jedes %{n_months} \xE2\x80\x8B" second: zweite + every_xth_day_of_every_n_months: "jedes %{x} %{day} jedes %{n_months} \xE2\x80\x8B" on_day_n: am Tag %{n} weekly: "w\xC3\xB6chentlich" from: von - every_day: jeden Tag last: zuletzt - times: "f\xC3\xBCr %{number} Zeiten" + every_day: jeden Tag the_xth_day_of_month: der %{x} %{day} von %{month} + times: "f\xC3\xBCr %{number} Zeiten" + first: erste + show: Show + every_year_on: jedes Jahr in %{date} + on_work_days: an Wochentagen day_names: - Sonntag - Montag @@ -543,43 +560,40 @@ de: - Donnerstag - Freitag - Samstag - show: Show - first: erste - every_year_on: jedes Jahr in %{date} - on_work_days: an Wochentagen fourth: vierte due: "F\xC3\xA4llig" every_month: jeden Monat until: bis - show_option_always: immer yearly_every_x_day: "Jeden %{day}. %{month} " recurrence_on_options: Setze Wiederholung auf daily_every_number_day: Alle %{number} Tage - ends_on: Endet am show_options: To-Do anzeigen weekly_every_number_week: Kehrt jede %{number}. Woche wieder am + ends_on: Endet am show_days_before: "%{days} Tage bevor die To-Do f\xC3\xA4llig ist" - yearly_every_xth_day: Den %{day} %{day_of_week} des %{month} from_tickler: the date todo comes from tickler (no due date set) no_end_date: Kein Enddatum day_x_on_every_x_month: Tag %{day} in jedem %{month}. Monat + yearly_every_xth_day: Den %{day} %{day_of_week} des %{month} yearly_options: "Einstellungen f\xC3\xBCr sich j\xC3\xA4hrlich wiederholende Aktionen" yearly: "J\xC3\xA4hrlich" monthly_every_xth_day: Der %{day} %{day_of_week} eines jeden %{month}. Monats - no_completed_recurring: Im Augenblick gibt es keine abgeschlossenen wiederkehrenden To-Dos + action_deferred: Die Aktion \'% {description}\' wurde vertagt + tagged_page_title: TRACKS::Als '%{tag_name}' markiert added_dependency: "%{dependency} als Abhängigkeit hinzugefügt." - no_deferred_actions: Zur Zeit sind keine zurückgestellten Aktionen vorhanden. - all_completed_tagged_page_title: "TRACKS:: Alle erledigten Aufgaben mit Tag %{tag_name}" completed_rest_of_month: Fertiggestellt den Rest des Monats + all_completed_tagged_page_title: "TRACKS:: Alle erledigten Aufgaben mit Tag %{tag_name}" + no_deferred_actions: Zur Zeit sind keine zurückgestellten Aktionen vorhanden. recurrence_completed: Nach dieser wiederkehrenden Aktion, die du gerade abgeschlossen hast, folgt keine mehr. Die Wiederholung endet hiermit - error_toggle_complete: "K\xC3\xB6nnte nicht diese Marke todo komplett" - due: Fällig + action_marked_complete_error: Die Aktion '%{description}' wurde aufgrund eines Fehlers NICHT als %{completed} markiert. no_actions_found: "Momentan gibt es keine unvollst\xC3\xA4ndigen Aktionen." in_pending_state: und als ausstehend markiert - action_marked_complete_error: Die Aktion '%{description}' wurde aufgrund eines Fehlers NICHT als %{completed} markiert. - depends_on_separate_with_commas: Hängt ab von (Komma-separiert) + error_toggle_complete: "K\xC3\xB6nnte nicht diese Marke todo komplett" + due: Fällig + no_incomplete_actions: Es gibt keine unerledigten Aufgaben action_saved_to_tickler: Aktion im Notizbuch gespeichert recurring_action_saved: Wiederkehrende Aktion gespeichert + depends_on_separate_with_commas: Hängt ab von (Komma-separiert) completed_in_archive: one: Es befindet sich eine erledigte Aufgabe im Archiv. other: Es befinden sich %{count} erledigte Aufgaben im Archiv. @@ -589,94 +603,120 @@ de: due_date: mit einem Datum %{due_date} oder früher overdue: "Überfällig" add_new_recurring: "F\xC3\xBCge eine neue wiederkehrende Aktion hinzu" - no_incomplete_actions: Es gibt keine unerledigten Aufgaben notes: delete_note_title: Notiz '%{id}' löschen delete_confirmation: "Bist du sicher, dass du die Notiz '%{id}' l\xC3\xB6schen m\xC3\xB6chtest?" in_project: "In:" delete_item_title: Eintrag löschen + deleted_note: "Notiz '%{id}' l\xC3\xB6schen" note_link_title: Notiz %{id} anzeigen show_note_title: Notiz anzeigen - deleted_note: "Notiz '%{id}' l\xC3\xB6schen" edit_item_title: Eintrag bearbeiten note_location_link: "In:" no_notes_available: "Derzeit gibt es keine Notizen: f\xC3\xBCge Notizen von der jeweiligen Projektseite hinzu." note_header: Notiz %{id} delete_note_confirm: Soll die Notiz '%{id}' wirklich gelöscht werden? + projects: + default_context_set: Standard-Kontext des Projekts auf %{default_context} gesetzt + no_actions_in_project: "Momentan gibt es keine unvollst\xC3\xA4ndigen Aktionen in diesem Projekt" + deferred_actions: "Aufgeschobene Aufgaben f\xC3\xBCr dieses Projekt" + was_marked_hidden: wurde als verborgen markiert + edit_project_title: Projekt bearbeiten + default_tags_removed_notice: Standard-Tags entfernt + page_title: "TRACKS::Projekt: %{project}" + all_completed_tasks_title: "TRACKS:: Alle auflisten Abgeschlossene Aktionen in Project '%{project_name}'" + hide_form: Fomular verstecken + list_completed_projects: "TRACKS:: Liste Abgeschlossene Projekte" + no_notes_attached: "Im Augenblick sind keine Notizen mit diesem Projekt verkn\xC3\xBCpft." + to_new_project_page: Zu neuem Projekt weiterleiten + show_form_title: Neues Projekt anlegen + deferred_actions_empty: "Es gibt keine aufgeschobenen Aufgaben f\xC3\xBCr dieses Projekt" + project_state: Projekt ist %{state} + this_project: Dieses Projekt + no_last_completed_projects: Keine abgeschlossene Projekte gefunden + no_last_completed_recurring_todos: Keine abgeschlossene sich wiederholende To-Dos gefunden + notes: Notizen + todos_append: an dieses Projekt + list_reviews: "TRACKS::R\xC3\xBCckblick" + notes_empty: "Es gibt keine Notizen f\xC3\xBCr dieses Projekt" + no_projects: Keine Projekte vorhanden + hide_form_title: Formular verstecken + delete_project: Projekt löschen + completed_actions_empty: "Es gibt keine erledigten Aufgaben f\xC3\xBCr dieses Projekt" + with_no_default_context: hat keinen Standardwert Kontext + delete_project_confirmation: Soll das Projekt '%{name}' wirklich gelöscht werden? + with_default_context: mit einem Standard-Rahmen von '%{context_name}' + show_form: Projekt erstellen + actions_in_project_title: Die Aktionen in diesem Projekt + completed_projects: Abgeschlossene Projekte + is_active: ist aktiv + add_note: "Notiz hinzuf\xC3\xBCgen" + set_default_tags_notice: Standard-Tags des Projekts auf %{default_tags} setzen + add_project: Projekt hinzufügen + settings: Einstellungen + project_saved_status: Projekt gespeichert + list_projects: TRACKS::Projektliste + with_default_tags: und mit '%{tags}' als Standard-Tags + completed_tasks_title: "TRACKS:: Liste Abgeschlossene Aktionen in Project '%{project_name}'" + hidden_projects: Versteckte Projekte + delete_project_title: Projekt löschen + default_context_removed: Standard-Kontext entfernt + add_note_submit: "Notiz hinzuf\xC3\xBCgen" + completed_actions: "Erledigte Aufgaben f\xC3\xBCr dieses Projekt" + was_marked_complete: wurde als erledigt markiert + no_default_context: Dieses Projekt hat keinen Standard-Kontext + with_no_default_tags: und hat keinen Standardwert Tags + edit_project_settings: Edit Project Settings + default_context: Der Standard-Kontext dieses Projektes ist %{context} + status_project_name_changed: "Projektname ge\xC3\xA4ndert" + state: Dieses Projekt ist %{state} + active_projects: Aktive Projekte states: hidden_plural: Versteckte - review_plural: Datiert stalled: Stalled + review_plural: Datiert completed: Erledigt current: Auf dem neusten Stand - completed_plural: Erledigte review: Datiert + completed_plural: Erledigte blocked: Verstopft blocked_plural: Verstopft stalled_plural: Stalled visible_plural: Sichtbare active_plural: Aktive visible: Sichtbar - current_plural: Auf dem neusten Stand hidden: Versteckt active: Aktiv - projects: - was_marked_hidden: wurde als verborgen markiert - edit_project_title: Projekt bearbeiten - default_tags_removed_notice: Standard-Tags entfernt - default_context_set: Standard-Kontext des Projekts auf %{default_context} gesetzt - no_actions_in_project: "Momentan gibt es keine unvollst\xC3\xA4ndigen Aktionen in diesem Projekt" - deferred_actions: "Aufgeschobene Aufgaben f\xC3\xBCr dieses Projekt" - all_completed_tasks_title: "TRACKS:: Alle auflisten Abgeschlossene Aktionen in Project '%{project_name}'" - page_title: "TRACKS::Projekt: %{project}" - hide_form: Fomular verstecken - no_notes_attached: "Im Augenblick sind keine Notizen mit diesem Projekt verkn\xC3\xBCpft." - show_form_title: Neues Projekt anlegen - deferred_actions_empty: "Es gibt keine aufgeschobenen Aufgaben f\xC3\xBCr dieses Projekt" - this_project: Dieses Projekt - project_state: Projekt ist %{state} - list_completed_projects: "TRACKS:: Liste Abgeschlossene Projekte" - to_new_project_page: Zu neuem Projekt weiterleiten - no_last_completed_recurring_todos: Keine abgeschlossene sich wiederholende To-Dos gefunden - todos_append: an dieses Projekt - no_last_completed_projects: Keine abgeschlossene Projekte gefunden - notes: Notizen - notes_empty: "Es gibt keine Notizen f\xC3\xBCr dieses Projekt" - no_projects: Keine Projekte vorhanden - hide_form_title: Formular verstecken - list_reviews: "TRACKS::R\xC3\xBCckblick" - delete_project: Projekt löschen - completed_actions_empty: "Es gibt keine erledigten Aufgaben f\xC3\xBCr dieses Projekt" - with_no_default_context: hat keinen Standardwert Kontext - show_form: Projekt erstellen - actions_in_project_title: Die Aktionen in diesem Projekt - delete_project_confirmation: Soll das Projekt '%{name}' wirklich gelöscht werden? - with_default_context: mit einem Standard-Rahmen von '%{context_name}' - add_note: "Notiz hinzuf\xC3\xBCgen" - add_project: Projekt hinzufügen - with_default_tags: und mit '%{tags}' als Standard-Tags - is_active: ist aktiv - list_projects: TRACKS::Projektliste - settings: Einstellungen - completed_projects: Abgeschlossene Projekte - set_default_tags_notice: Standard-Tags des Projekts auf %{default_tags} setzen - project_saved_status: Projekt gespeichert - delete_project_title: Projekt löschen - hidden_projects: Versteckte Projekte - completed_tasks_title: "TRACKS:: Liste Abgeschlossene Aktionen in Project '%{project_name}'" - was_marked_complete: wurde als erledigt markiert - completed_actions: "Erledigte Aufgaben f\xC3\xBCr dieses Projekt" - default_context_removed: Standard-Kontext entfernt - add_note_submit: "Notiz hinzuf\xC3\xBCgen" - edit_project_settings: Edit Project Settings - status_project_name_changed: "Projektname ge\xC3\xA4ndert" - active_projects: Aktive Projekte - default_context: Der Standard-Kontext dieses Projektes ist %{context} - state: Dieses Projekt ist %{state} - no_default_context: Dieses Projekt hat keinen Standard-Kontext - with_no_default_tags: und hat keinen Standardwert Tags + current_plural: Auf dem neusten Stand errors: user_unauthorized: "401 Unauthorized: Nur administrative Benutzer d\xC3\xBCrfen auf diese Funktion zugreifen." + preferences: + open_id_url: "Deine OpenID-URL lautet:" + change_identity_url: "\xC3\x84ndere deine Identit\xC3\xA4ts-URL" + staleness_starts_after: Abgestandenheit startet nach %{days} Tagen + page_title: TRACKS::Einstellungen + change_password: "Passwort \xC3\xA4ndern" + token_description: "Token (f\xC3\xBCr die Verwendung in Feeds und der API)" + title: Deine Einstellungen + is_false: Nein + show_number_completed: "Zeige %{number} erledigte Eintr\xC3\xA4ge" + password_changed: "Ihr Passwort ge\xC3\xA4ndert wurde, melden Sie sich bitte wieder an." + edit_preferences: Einstellungen bearbeiten + page_title_edit: "TRACKS::Einstellungen \xC3\xA4ndern" + is_true: Ja + sms_context_none: Keine + generate_new_token: Neues Token generieren + token_header: Dein Token + authentication_header: Deine Authentifizierung + updated: Einstellungen aktualisiert + current_authentication_type: Dein Authentifizierungsart ist %{auth_type} + change_authentication_type: "Authentifzierungsart \xC3\xA4ndern" + generate_new_token_confirm: "Bist du sicher? Wenn du ein neues Token generierst, wird dies das alte Token ersetzen und jegliche externe Nutzung st\xC3\xB6ren, die das alte Token verwendet." + tabs: + authentication: Authentication + tracks_behavior: Tracks Verhalten + profile: Profil + date_and_time: Datum und Uhrzeit time: am: vormittags formats: @@ -687,33 +727,6 @@ de: month_day: "%d. %B" long: "%A, %d. %B %Y, %H:%M Uhr" pm: nachmittags - preferences: - change_identity_url: "\xC3\x84ndere deine Identit\xC3\xA4ts-URL" - open_id_url: "Deine OpenID-URL lautet:" - staleness_starts_after: Abgestandenheit startet nach %{days} Tagen - page_title: TRACKS::Einstellungen - change_password: "Passwort \xC3\xA4ndern" - token_description: "Token (f\xC3\xBCr die Verwendung in Feeds und der API)" - title: Deine Einstellungen - is_false: Nein - show_number_completed: "Zeige %{number} erledigte Eintr\xC3\xA4ge" - edit_preferences: Einstellungen bearbeiten - page_title_edit: "TRACKS::Einstellungen \xC3\xA4ndern" - is_true: Ja - password_changed: "Ihr Passwort ge\xC3\xA4ndert wurde, melden Sie sich bitte wieder an." - sms_context_none: Keine - generate_new_token: Neues Token generieren - token_header: Dein Token - authentication_header: Deine Authentifizierung - updated: Einstellungen aktualisiert - current_authentication_type: Dein Authentifizierungsart ist %{auth_type} - change_authentication_type: "Authentifzierungsart \xC3\xA4ndern" - generate_new_token_confirm: "Bist du sicher? Wenn du ein neues Token generierst, wird dies das alte Token ersetzen und jegliche externe Nutzung st\xC3\xB6ren, die das alte Token verwendet." - tabs: - tracks_behavior: Tracks Verhalten - authentication: Authentication - profile: Profil - date_and_time: Datum und Uhrzeit date: month_names: - @@ -804,8 +817,8 @@ de: send_feedback: Senden Sie Feedback zu %{version} shared: multiple_next_actions: Mehrere neue Aufgaben (eine pro Zeile) - toggle_single: Weitere Aktion erstellen make_actions_dependent: "Machen Sie Aktionen voneinander abh\xC3\xA4ngig" + toggle_single: Weitere Aktion erstellen hide_form: Formular verstecken add_actions: "Aufgaben hinzuf\xC3\xBCgen" add_action: "Aufgabe hinzuf\xC3\xBCgen" @@ -818,6 +831,30 @@ de: add_context: "F\xC3\xBCgen Kontext" toggle_multi_title: "Zwischen Einzel- und Mehrfachformular f\xC3\xBCr neue Aufgaben umschalten" hide_action_form_title: "Formular f\xC3\xBCr neue Aufgaben verstecken" + feedlist: + choose_context: "Kontext f\xC3\xBCr den Feed w\xC3\xA4hlen" + actions_due_today: "Heute oder fr\xC3\xBCher f\xC3\xA4llig" + ical_feed: iCal-Feed + legend: "Legende:" + all_contexts: Alle Kontexte + rss_feed: RSS-Feed + choose_project: "Projekt f\xC3\xBCr den Feed w\xC3\xA4hlen" + all_projects: Alle Projekte + project_needed: Es muss mindestens ein Projekt existieren, bevor ein Feed abonniert werden kann. + select_feed_for_project: "Feed f\xC3\xBCr dieses Projekt ausw\xC3\xA4hlen" + active_projects_wo_next: Aktive Projekte ohne ausstehende Aufgaben + active_starred_actions: Alle markierten, aktiven Aufgaben + context_needed: Es muss mindestens ein Kontext existieren, bevor ein Feed abonniert werden kann. + select_feed_for_context: "Feed f\xC3\xBCr diesen Kontext ausw\xC3\xA4hlen" + projects_and_actions: Aktive Projekte und deren Aufgaben + notice_incomplete_only: "Hinweis: Alle Feeds zeigen nur Aufgaben, die noch nicht als erledigt markiert wurden." + actions_due_next_week: "In den n\xC3\xA4chsten 7 Tagen oder fr\xC3\xBCher f\xC3\xA4llige Aufgaben" + actions_completed_last_week: In den letzten 7 Tagen abgeschlossene Aufgaben + context_centric_actions: "Feeds f\xC3\xBCr unvollst\xC3\xA4ndige Aufgaben in einem bestimmten Kontext" + plain_text_feed: Plain-Text-Feed + last_fixed_number: Die letzten %{number} Aufgaben + all_actions: Alle Aufgaben + project_centric: "Feeds f\xC3\xBCr unvollst\xC3\xA4ndige Aufgaben in einem bestimmten Kontext" sidebar: list_name_active_contexts: Aktive Kontexte list_name_active_projects: Aktive Projekte @@ -825,30 +862,50 @@ de: list_name_completed_projects: Abgeschlossene Projekte list_name_hidden_projects: Versteckte Projekte list_name_hidden_contexts: Versteckte Kontexte - feedlist: - actions_due_today: "Heute oder fr\xC3\xBCher f\xC3\xA4llig" - choose_context: "Kontext f\xC3\xBCr den Feed w\xC3\xA4hlen" - rss_feed: RSS-Feed - legend: "Legende:" - ical_feed: iCal-Feed - all_contexts: Alle Kontexte - all_projects: Alle Projekte - choose_project: "Projekt f\xC3\xBCr den Feed w\xC3\xA4hlen" - project_needed: Es muss mindestens ein Projekt existieren, bevor ein Feed abonniert werden kann. - select_feed_for_project: "Feed f\xC3\xBCr dieses Projekt ausw\xC3\xA4hlen" - active_projects_wo_next: Aktive Projekte ohne ausstehende Aufgaben - active_starred_actions: Alle markierten, aktiven Aufgaben - select_feed_for_context: "Feed f\xC3\xBCr diesen Kontext ausw\xC3\xA4hlen" - projects_and_actions: Aktive Projekte und deren Aufgaben - context_needed: Es muss mindestens ein Kontext existieren, bevor ein Feed abonniert werden kann. - actions_due_next_week: "In den n\xC3\xA4chsten 7 Tagen oder fr\xC3\xBCher f\xC3\xA4llige Aufgaben" - notice_incomplete_only: "Hinweis: Alle Feeds zeigen nur Aufgaben, die noch nicht als erledigt markiert wurden." - context_centric_actions: "Feeds f\xC3\xBCr unvollst\xC3\xA4ndige Aufgaben in einem bestimmten Kontext" - plain_text_feed: Plain-Text-Feed - last_fixed_number: Die letzten %{number} Aufgaben - all_actions: Alle Aufgaben - actions_completed_last_week: In den letzten 7 Tagen abgeschlossene Aufgaben - project_centric: "Feeds f\xC3\xBCr unvollst\xC3\xA4ndige Aufgaben in einem bestimmten Kontext" + users: + openid_url_verified: Die URL %{url} wurde erfolgreich als Identität verifiziert und Deine Authentifizierung auf OpenID umgestellt. + auth_type_update_error: "Beim Ändern der Authentifizierung trat ein Fehler auf: %{error_messages}" + failed_to_delete_user: Löschen des Benutzers %{username} fehlgeschlagen + destroy_successful: "Benutzer %{login} wurde erfolgreich gel\xC3\xB6scht" + first_user_heading: "Willkommen bei TRACKS. Als erstes legen Sie bitte einen Administrator-Zugang an:" + total_contexts: Alle Kontexte + successfully_deleted_user: Benutzer %{username} erfolgreich gelöscht. + signup_successful: Benutzer %{username} erfolgreich angelegt. + new_token_generated: Neuer Token erfolgreich generiert + total_projects: Alle Projekte + change_password_submit: "Passwort \xC3\xA4ndern" + no_signups_title: TRACKS::Anmeldung nicht erlaubt + user_created: Benutzer angelegt. + account_signup: Accounteinrichtung + manage_users: Benutzer verwalten + password_updated: Passwort aktualisiert. + auth_type_updated: Authentifizierungs-Art erfolgreich geändert. + total_actions: Alle Aufgaben + desired_login: "Gew\xC3\xBCnschter Benutzername" + signup: Registrieren + confirm_password: "Passwort best\xC3\xA4tigen" + new_user_heading: "Einen neuen Benutzer anlegen:" + password_confirmation_label: "Passwort best\xC3\xA4tigen" + destroy_error: "Beim L\xC3\xB6schen des Benutzers %{login} ist ein Fehler aufgetreten." + choose_password: "Passwort w\xC3\xA4hlen" + change_password_title: TRACKS::Passwort ändern + change_auth_type_title: TRACKS::Authentifizierungstyp ändern + change_password_prompt: "Gib dein neues Passwort in die unten stehenden Felder ein und klicke auf 'Passwort \xC3\xA4ndern' um dein altes Passwort durch das neue zu ersetzen." + new_password_label: Neues Passwort + register_with_cas: Mit deinem CAS-Benutzernamen + label_auth_type: Authentifizierungsart + total_users_count: Derzeit existieren %{count} Benutzer + new_user_title: TRACKS::Als Administrator anmelden + destroy_user: "Benutzer l\xC3\xB6schen" + destroy_confirmation: "Achtung: der Benutzer '%{login}' wird mit all seinen Aufgaben, Kontexten, Projekten und Notizen gel\xC3\xB6scht. Bist du sicher, dass du fortfahren m\xC3\xB6chtest?" + you_have_to_reset_your_password: "Sie haben Ihr Passwort zur\xC3\xBCcksetzen" + signup_new_user: Neuen Benutzer anlegen + identity_url: Identity-URL + openid_ok_pref_failed: Die URL %{url} wurde erfolgreich als Identität verifiziert, beim Speichern der Einstellungen trat jedoch ein Fehler auf. + auth_change_submit: "Authentifizierungsart \xC3\xA4ndern" + change_authentication_type: "Authentifizierungsart \xC3\xA4ndern" + total_notes: Alle Notizen + select_authentication_type: "W\xC3\xA4hle deine neue Authentifizierungsart und klicke 'Authentifizierungsart \xC3\xA4ndern' an, um deine aktuellen Einstellungen zu \xC3\xBCberschreiben." contexts: delete_context_title: Kontext löschen all_completed_tasks_title: "TRACKS:: Alle Abgeschlossene Ma\xC3\x9Fnahmen im context '%{context_name}'" @@ -862,75 +919,31 @@ de: hidden_contexts: Versteckte Kontexte no_contexts_active: Derzeit gibt es keine aktiven Kontexte context_hide: Auf Startseite ausblenden? - show_form: Neuen Kontext erstellen - visible_contexts: Sichtbare Kontexte - save_status_message: Kontext gespeichert add_context: "Kontext hinzuf\xC3\xBCgen" + show_form: Neuen Kontext erstellen + save_status_message: Kontext gespeichert + visible_contexts: Sichtbare Kontexte update_status_message: "Kontextname wurde ge\xC3\xA4ndert" context_name: Kontextname status_active: Kontext ist aktiv completed_tasks_title: "TRACKS:: Abgeschlossene Ma\xC3\x9Fnahmen im context '%{context_name}'" new_context_post: "' wird ebenfalls angelegt. Fortfahren?" + new_context_pre: Der neue Kontext ' no_actions: "Momentan gibt es keine unvollst\xC3\xA4ndigen Aufgaben in diesem Kontext" last_completed_in_context: in diesem Kontext (letzte %{number}) context_deleted: "Gel\xC3\xB6schter Kontext '%{name}'" no_contexts_hidden: Derzeit gibt es keine versteckten Kontexte - new_context_pre: Der neue Kontext ' status_hidden: Kontext ist versteckt - users: - successfully_deleted_user: Benutzer %{username} erfolgreich gelöscht. - auth_type_update_error: "Beim Ändern der Authentifizierung trat ein Fehler auf: %{error_messages}" - failed_to_delete_user: Löschen des Benutzers %{username} fehlgeschlagen - destroy_successful: "Benutzer %{login} wurde erfolgreich gel\xC3\xB6scht" - total_contexts: Alle Kontexte - first_user_heading: "Willkommen bei TRACKS. Als erstes legen Sie bitte einen Administrator-Zugang an:" - openid_url_verified: Die URL %{url} wurde erfolgreich als Identität verifiziert und Deine Authentifizierung auf OpenID umgestellt. - signup_successful: Benutzer %{username} erfolgreich angelegt. - new_token_generated: Neuer Token erfolgreich generiert - total_projects: Alle Projekte - change_password_submit: "Passwort \xC3\xA4ndern" - no_signups_title: TRACKS::Anmeldung nicht erlaubt - user_created: Benutzer angelegt. - account_signup: Accounteinrichtung - password_updated: Passwort aktualisiert. - manage_users: Benutzer verwalten - new_user_heading: "Einen neuen Benutzer anlegen:" - auth_type_updated: Authentifizierungs-Art erfolgreich geändert. - total_actions: Alle Aufgaben - desired_login: "Gew\xC3\xBCnschter Benutzername" - signup: Registrieren - confirm_password: "Passwort best\xC3\xA4tigen" - change_password_prompt: "Gib dein neues Passwort in die unten stehenden Felder ein und klicke auf 'Passwort \xC3\xA4ndern' um dein altes Passwort durch das neue zu ersetzen." - password_confirmation_label: "Passwort best\xC3\xA4tigen" - destroy_error: "Beim L\xC3\xB6schen des Benutzers %{login} ist ein Fehler aufgetreten." - choose_password: "Passwort w\xC3\xA4hlen" - change_password_title: TRACKS::Passwort ändern - change_auth_type_title: TRACKS::Authentifizierungstyp ändern - register_with_cas: Mit deinem CAS-Benutzernamen - label_auth_type: Authentifizierungsart - new_password_label: Neues Passwort - total_users_count: Derzeit existieren %{count} Benutzer - new_user_title: TRACKS::Als Administrator anmelden - destroy_user: "Benutzer l\xC3\xB6schen" - destroy_confirmation: "Achtung: der Benutzer '%{login}' wird mit all seinen Aufgaben, Kontexten, Projekten und Notizen gel\xC3\xB6scht. Bist du sicher, dass du fortfahren m\xC3\xB6chtest?" - you_have_to_reset_your_password: "Sie haben Ihr Passwort zur\xC3\xBCcksetzen" - signup_new_user: Neuen Benutzer anlegen - identity_url: Identity-URL - openid_ok_pref_failed: Die URL %{url} wurde erfolgreich als Identität verifiziert, beim Speichern der Einstellungen trat jedoch ein Fehler auf. - auth_change_submit: "Authentifizierungsart \xC3\xA4ndern" - change_authentication_type: "Authentifizierungsart \xC3\xA4ndern" - select_authentication_type: "W\xC3\xA4hle deine neue Authentifizierungsart und klicke 'Authentifizierungsart \xC3\xA4ndern' an, um deine aktuellen Einstellungen zu \xC3\xBCberschreiben." - total_notes: Alle Notizen login: - login_cas: zum CAS gehen openid_identity_url_not_found: "Sorry, aber es existiert kein Benutzer mit der Identit\xC3\xA4ts-URL (%{identity_url})" user_no_expiry: Angemeldet bleiben sign_in: Anmeldung - please_login: Bitte melde dich an, um Tracks zu nutzen - cas_logged_in_greeting: Hallo, %{username}! Du bist authentifiziert. + login_cas: zum CAS gehen cas_no_user_found: Hallo, %{username}! Du hast leider keinen Tracks-Account. cas_login: CAS-Anmeldung successful_with_session_info: "Anmeldung erfolgreich:" + please_login: Bitte melde dich an, um Tracks zu nutzen + cas_logged_in_greeting: Hallo, %{username}! Du bist authentifiziert. cas_username_not_found: Sorry, aber es existiert kein Benutzer mit dem CAS-Benutzernamen (%{username}) cas_create_account: "Wenn du die Anfrage fortsetzen m\xC3\xB6chtest, klicke bitte hier: %{signup_link}" mobile_use_openid: "\xE2\x80\xA6oder mit einer OpenID anmelden" @@ -942,10 +955,10 @@ de: session_time_out: Sitzung abgelaufen. Bitte %{link} session_will_expire: "Sitzung wird nach %{hours} Stunde(n) der Inaktivit\xC3\xA4t ablaufen." login_standard: "zur\xC3\xBCck zum Standard-Login" - log_in_again: Erneut anmelden. - logged_out: Sie wurden von Tracks abgemeldet. login_with_openid: Mit einer OpenID anmelden unsuccessful: Anmeldung war nicht erfolgreich. + log_in_again: Erneut anmelden. + logged_out: Sie wurden von Tracks abgemeldet. datetime: prompts: minute: Minuten @@ -994,7 +1007,7 @@ de: search: contexts_matching_query: Kontexte entsprechen der Suche tags_matching_query: Tags entsprechen der Suche + no_results: Die Suche ergab kein Ergebnis. todos_matching_query: Todos entsprechen der Suche projects_matching_query: Projekte entsprechen der Suche notes_matching_query: Notizen entsprechen der Suche - no_results: Die Suche ergab kein Ergebnis. diff --git a/config/locales/en.yml b/config/locales/en.yml index af97c69e..429368a5 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -92,7 +92,10 @@ en: third: Third recurring_todos: Repeating Actions actions: Actions - actions_midsentence: actions + actions_midsentence: + zero: actions + one: action + other: actions add: Add previous: Previous show_all: Show all @@ -132,6 +135,10 @@ en: errors_with_fields: "There were problems with the following fields:" next: Next todo: todo + note: + zero: no notes + one: 1 note + other: %{count} notes context: Context drag_handle: DRAG description: Description @@ -143,7 +150,11 @@ en: email: Email search: Search ajaxError: There was an error retrieving from server - days_midsentence: days + days_midsentence: + zero: days + one: day + other: days + deferred: deferred not_available_abbr: "n/a" data: import_successful: Import was successful. @@ -584,6 +595,8 @@ en: add_new_recurring: Add a new recurring action edit_recurring_todo: Edit repeating action no_incomplete_actions: There are no incomplete actions + see_all_completed: You can see all completed actions %{link} + all_completed_here: here notes: delete_confirmation: Are you sure that you want to delete the note '%{id}'? delete_item_title: Delete item diff --git a/config/locales/es.yml b/config/locales/es.yml index c3baef2c..bf1ea096 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1,5 +1,54 @@ --- es: + layouts: + toggle_contexts_title: "Haga contextos se derrumb\xC3\xB3 (in)visible" + toggle_contexts: "Cambiar los contextos se derrumb\xC3\xB3" + toggle_notes: Activar/Desactivar notas + next_actions_rss_feed: RSS feed of next actions + toggle_notes_title: Activar/Desactivar todas las notas + mobile_navigation: + new_action: Nueva tarea + logout: "Cerrar sesi\xC3\xB3n" + feeds: Feeds + starred: avoritos + projects: Proyectos + tickler: Tickler + contexts: Contextos + home: Inicio + navigation: + manage_users_title: "A\xC3\xB1adir o eliminar usuarios" + recurring_todos: Tareas repetitivas + api_docs: REST API Docs + help: "?" + feeds: Feeds + starred: Estrellas + stats: "Estad\xC3\xADsticas" + notes_title: Mostrar todas las notas + manage_users: Administrar usuarios + tickler_title: Tickler + admin: Admin + preferences: Preferencias + integrations_: Integrar Tracks + export_title: Import and export data + calendar_title: Calendario de las acciones por + feeds_title: See a list of available feeds + stats_title: See your statistics + tickler: Tickler + home_title: Inicio + starred_title: See your starred actions + recurring_todos_title: Manage recurring actions + completed_tasks: Hecho + view: Ver + organize: Organizar + completed_tasks_title: Completed + home: Inicio + export: Export + contexts_title: Contexts + preferences_title: Mostrar mis preferencias + search: Search All Items + review_title: "Posibilidad de una revisi\xC3\xB3n" + projects_title: Proyectos + calendar: Calendario number: format: separator: . @@ -23,66 +72,11 @@ es: separator: . delimiter: "," - layouts: - toggle_contexts_title: "Haga contextos se derrumb\xC3\xB3 (in)visible" - toggle_notes: Activar/Desactivar notas - toggle_contexts: "Cambiar los contextos se derrumb\xC3\xB3" - next_actions_rss_feed: RSS feed of next actions - toggle_notes_title: Activar/Desactivar todas las notas - mobile_navigation: - feeds: Feeds - new_action: Nueva tarea - logout: "Cerrar sesi\xC3\xB3n" - starred: avoritos - projects: Proyectos - tickler: Tickler - contexts: Contextos - home: Inicio - navigation: - manage_users_title: "A\xC3\xB1adir o eliminar usuarios" - api_docs: REST API Docs - recurring_todos: Tareas repetitivas - feeds: Feeds - help: "?" - stats: "Estad\xC3\xADsticas" - starred: Estrellas - notes_title: Mostrar todas las notas - manage_users: Administrar usuarios - tickler_title: Tickler - admin: Admin - integrations_: Integrar Tracks - export_title: Import and export data - preferences: Preferencias - calendar_title: Calendario de las acciones por - feeds_title: See a list of available feeds - completed_tasks: Hecho - stats_title: See your statistics - tickler: Tickler - home_title: Inicio - starred_title: See your starred actions - recurring_todos_title: Manage recurring actions - view: Ver - organize: Organizar - completed_tasks_title: Completed - home: Inicio - contexts_title: Contexts - export: Export - preferences_title: Mostrar mis preferencias - review_title: "Posibilidad de una revisi\xC3\xB3n" - calendar: Calendario - search: Search All Items - projects_title: Proyectos - integrations: - opensearch_description: Buscar en las Tracks - applescript_next_action_prompt: "Descripci\xC3\xB3n de la pr\xC3\xB3xima tarea:" - gmail_description: "Gadget para a\xC3\xB1adir pistas a Gmail como un gadget" - applescript_success_after_id: creado - applescript_success_before_id: "Nueva acci\xC3\xB3n junto con la identificaci\xC3\xB3n" common: + recurring_todos: "Repetici\xC3\xB3n de acciones" back: !binary | QXRyw6Fz - recurring_todos: "Repetici\xC3\xB3n de acciones" actions: Tareas third: Tercero add: "A\xC3\xB1adir" @@ -90,56 +84,77 @@ es: go_back: "Volver atr\xC3\xA1s" logout: Salir second: Segundo - show_all: Mostrar todo optional: opcional week: semana none: Ninguno + deferred: pospuestas + show_all: Mostrar todo cancel: Cancelar month: mes - actions_midsentence: acciones + actions_midsentence: + one: tarea + other: tareas + zero: tareas + notes: Notas server_error: Ha ocurrido un error en el servidor. forum: Foro - notes: Notas - last: "\xC3\x9Altimo" projects: Proyectos - action: Tarea + last: "\xC3\x9Altimo" review: "Revisi\xC3\xB3n" - project: Proyecto - days_midsentence: !binary | - ZMOtYQ== + action: Tarea + days_midsentence: + one: !binary | + ZMOtYQ== + other: !binary | + ZMOtYXM= + + zero: !binary | + ZMOtYXM= + + project: Proyecto contribute: Contribuir ok: Ok website: Website first: Primero + note: + one: 1 nota + other: "%{count} notas" + zero: 0 notas numbered_step: Paso %{number} - errors_with_fields: "Ha habido problemas con los siguientes campos:" sort: by_task_count_title: "Ordenar por n\xC3\xBAmero de tareas" by_task_count_title_confirm: "\xC2\xBFEst\xC3\xA1 seguro que desea ordenar los proyectos por el n\xC3\xBAmero de tareas? Esto reemplazar\xC3\xA1 el orden existente." alphabetically: "Alfab\xC3\xA9ticamente" - alphabetically_title: "Proyectos de ordenar alfab\xC3\xA9ticamente" sort: Ordenar + alphabetically_title: "Proyectos de ordenar alfab\xC3\xA9ticamente" alphabetically_confirm: "\xC2\xBFEst\xC3\xA1 seguro que desea ordenar los proyectos por orden alfab\xC3\xA9tico? Esto reemplazar\xC3\xA1 el orden existente." by_task_count: "Por n\xC3\xBAmero de tareas" create: Crear - months: meses - description: "Descripci\xC3\xB3n" todo: Todo + months: meses + errors_with_fields: "Ha habido problemas con los siguientes campos:" + description: "Descripci\xC3\xB3n" fourth: Cuarto next: "Pr\xC3\xB3ximo" + drag_handle: ARRASTRAR contexts: Contextos context: Contexto - drag_handle: ARRASTRAR + bugs: Errores update: Actualizar weeks: semanas forth: Siguiente wiki: Wiki - bugs: Errores - ajaxError: Hubo un error al recuperar desde el servidor - not_available_abbr: n/e email: Email + ajaxError: Hubo un error al recuperar desde el servidor search: Buscar + not_available_abbr: n/e + integrations: + opensearch_description: Buscar en las Tracks + applescript_next_action_prompt: "Descripci\xC3\xB3n de la pr\xC3\xB3xima tarea:" + gmail_description: "Gadget para a\xC3\xB1adir pistas a Gmail como un gadget" + applescript_success_after_id: creado + applescript_success_before_id: "Nueva acci\xC3\xB3n junto con la identificaci\xC3\xB3n" activerecord: attributes: project: @@ -151,17 +166,14 @@ es: created_at: Creado el updated_at: actualizado a las todo: - predecessors: Depende de la show_from: Mostrar + predecessors: Depende de la notes: Notas - project: Proyecto tags: Etiquetas + project: Proyecto description: "Descripci\xC3\xB3n" context: Contexto due: "Fecha l\xC3\xADmite" - user: - last_name: Apellido - first_name: Primer nombre preference: show_hidden_projects_in_sidebar: Mostrar proyectos ocultos en el lateral show_hidden_contexts_in_sidebar: Mostrar los contextos ocultos en el lateral @@ -170,19 +182,22 @@ es: verbose_action_descriptors: "Descriptores detallado de acci\xC3\xB3n" staleness_starts: Comienzo de estancamiento mobile_todos_per_page: "Tareas por p\xC3\xA1gina (Vista M\xC3\xB3vil)" - title_date_format: "T\xC3\xADtulo del formato de fecha" show_number_completed: "Mostrar n\xC3\xBAmero de tareas completadas" + title_date_format: "T\xC3\xADtulo del formato de fecha" refresh: "Intervalo de actualizaci\xC3\xB3n (en minutos)" week_starts: La semana comienza last_name: Apellido due_style: Debido al estilo locale: Lugar time_zone: Zona horaria - show_project_on_todo_done: "Ir a la p\xC3\xA1gina del proyecto al completar la tarea" sms_email: Email origen - first_name: Nombre + show_project_on_todo_done: "Ir a la p\xC3\xA1gina del proyecto al completar la tarea" show_completed_projects_in_sidebar: Show completed projects in sidebar + first_name: Nombre review_period: "Intervalo de revisi\xC3\xB3n del proyecto" + user: + last_name: Apellido + first_name: Primer nombre errors: models: project: @@ -228,21 +243,21 @@ es: feed_description: Lists all the projects for %{username} todo: error_date_must_be_future: must be a date in the future - user: - error_context_not_associated: Context id %{context} not associated with user id %{user}. - error_project_not_associated: Project id %{project} not associated with user id %{user}. preference: due_on: Due on %{date} due_in: Due in %{days} days due_styles: - Due in ___ days - Due on _______ + user: + error_context_not_associated: Context id %{context} not associated with user id %{user}. + error_project_not_associated: Project id %{project} not associated with user id %{user}. stats: - tag_cloud_title: Tag cloud for all actions + actions_min_max_completion_days: The Max-/minimum days to complete is %{min}/%{max}. totals_hidden_context_count: and %{count} are hidden contexts. actions_avg_created: In the last 12 months you created on average %{count} actions - actions_min_max_completion_days: The Max-/minimum days to complete is %{min}/%{max}. totals_actions_completed: "%{count} of these are completed." + tag_cloud_title: Tag cloud for all actions actions_actions_avg_created_30days: In the last 30 days you created on average %{count} actions actions_avg_completed: and completed an average of %{count} actions per month. top5_visible_contexts_with_incomplete_actions: Top 5 visible contexts with incomplete actions @@ -258,11 +273,11 @@ es: weeks: Running time of an action (weeks). Click on a bar for more info totals_action_count: you have a total of %{count} actions tag_cloud_90days_title: Tag cloud actions in past 90 days + actions_avg_completion_time: Of all your completed actions, the average time to complete is %{count} days. tod30: Time of day (last 30 days) tags: Tags projects: Projects - actions_avg_completion_time: Of all your completed actions, the average time to complete is %{count} days. - actions_lastyear_title: Actions in the last 12 months + totals_completed_project_count: and %{count} are completed projects. labels: month_avg_completed: "%{months} Month avg completed" completed: Completed @@ -271,8 +286,8 @@ es: avg_completed: Avg completed created: Created actions_selected_from_week: "Actions selected from week " - totals_completed_project_count: and %{count} are completed projects. actions_day_of_week_title: Day of week (all actions) + actions_lastyear_title: Actions in the last 12 months open_per_week: "Pr\xC3\xB3ximas acciones activas (visibles y ocultas) a la semana" action_selection_title: TRACKS::Action selection totals_project_count: You have %{count} projects. @@ -295,16 +310,16 @@ es: actions_last_year_legend: number_of_actions: Number of actions months_ago: Months ago - top10_projects: Top 10 projects top5_contexts: Top 5 contexts - click_to_return: Click %{link} to return to the statistics page. - totals: Totals + top10_projects: Top 10 projects contexts: Contexts + totals: Totals + click_to_return: Click %{link} to return to the statistics page. tag_cloud_90days_description: This tag cloud includes tags of actions that were created or completed in the past 90 days. totals_visible_context_count: Of those %{count} are visible contexts - actions_min_completion_time: The minimum time to complete is %{time}. top10_projects_30days: Top 10 project in past 30 days running_time_all: Current running time of all incomplete actions + actions_min_completion_time: The minimum time to complete is %{time}. action_completion_time_title: Completion time (all completed actions) click_to_show_actions_from_week: Click %{link} to show the actions from week %{week} and further. top10_longrunning: Top 10 longest running projects @@ -316,9 +331,9 @@ es: day_of_week: "D\xC3\xADa de la semana" totals_first_action: Since your first action on %{date} tag_cloud_description: This tag cloud includes tags of all actions (completed, not completed, visible and/or hidden) + spread_of_actions_for_all_context: Spread of actions for all context click_to_update_actions: Click on a bar in the chart to update the actions below. click_to_return_link: here - spread_of_actions_for_all_context: Spread of actions for all context more_stats_will_appear: More statistics will appear here once you have added some actions. actions_avg_completed_30days: and completed an average of %{count} actions per day. actions_30days_title: Actions in the last 30 days @@ -339,19 +354,19 @@ es: running_time: Running time of an action (weeks). Click on a bar for more info percentage: Percentage other_actions_label: (otros) - time_of_day: Time of day (all actions) totals_hidden_project_count: "%{count} are hidden" + time_of_day: Time of day (all actions) todos: - completed_actions: Completed actions + recurring_action_deleted: Action was deleted. Because this action is recurring, a new action was added show_from: Show from error_starring_recurring: Could not toggle the star of recurring todo \'%{description}\' - recurring_action_deleted: Action was deleted. Because this action is recurring, a new action was added - completed_rest_of_previous_month: Completado en el resto del mes anterior - completed_recurring: Completed recurring todos + completed_actions: Completed actions added_new_next_action: Added new next action + completed_recurring: Completed recurring todos + completed_rest_of_previous_month: Completado en el resto del mes anterior blocked_by: Blocked by %{predecessors} - completed_recurrence_completed: There is no next action after the recurring action you just deleted. The recurrence is completed star_action: Star this action + completed_recurrence_completed: There is no next action after the recurring action you just deleted. The recurrence is completed defer_date_after_due_date: Defer date is after due date. Please edit and adjust due date before deferring. unable_to_add_dependency: Unable to add dependency done: Done? @@ -362,16 +377,16 @@ es: no_hidden_actions: Currently there are no hidden actions found edit_action_with_description: Edit the action '%{description}' action_due_on: (action due on %{date}) + list_incomplete_next_actions: Lista las siguientes tareas incompletas archived_tasks_title: TRACKS::Archived completed tasks remove_dependency: Remove dependency (does not delete the action) - list_incomplete_next_actions: Lista las siguientes tareas incompletas - tags: Tags (separate with commas) action_deleted_success: Successfully deleted next action - mobile_todos_page_title: Todas las tareas - new_related_todo_created: "Una nueva tarea fue a\xC3\xB1adida y que pertenece a esta tarea recurrente" - context_changed: Context changed to %{name} - add_another_dependency: Add another dependency + tags: Tags (separate with commas) delete_recurring_action_title: Delete the recurring action + context_changed: Context changed to %{name} + new_related_todo_created: "Una nueva tarea fue a\xC3\xB1adida y que pertenece a esta tarea recurrente" + mobile_todos_page_title: Todas las tareas + add_another_dependency: Add another dependency removed_predecessor: Removed %{successor} as dependency from %{predecessor}. recurring_actions_title: TRACKS::Recurring Actions next_action_needed: You need to submit at least one next action @@ -381,40 +396,43 @@ es: edit_action: Edit action added_new_context: Added new context next_actions_description: "Filter:" + list_incomplete_next_actions_with_limit: Lists the last %{count} incomplete next actions + set_to_pending: "%{task} set to pending" + added_new_project: Added new project next_actions_title_additions: completed: actions completed due_today: due today due_within_a_week: due within a week - list_incomplete_next_actions_with_limit: Lists the last %{count} incomplete next actions - set_to_pending: "%{task} set to pending" - added_new_project: Added new project older_completed_items: Older completed items - error_deleting_item: There was an error deleting the item %{description} - edit_recurring_todo: "Editar la acci\xC3\xB3n de repetici\xC3\xB3n" - append_in_this_project: in this project - task_list_title: TRACKS::List tasks no_actions_due_this_week: No actions due in rest of this week + all_completed_here: !binary | + YXF1w60= + + append_in_this_project: in this project + edit_recurring_todo: "Editar la acci\xC3\xB3n de repetici\xC3\xB3n" + error_deleting_item: There was an error deleting the item %{description} + task_list_title: TRACKS::List tasks no_recurring_todos: Currently there are no recurring todos error_completing_todo: There was an error completing / activating the recurring todo %{description} recurring_pattern_removed: "El patr\xC3\xB3n de repetici\xC3\xB3n se retira de %{count}" convert_to_project: Make project no_deferred_pending_actions: Currently there are no deferred or pending actions - completed_last_day: Completed in the last 24 hours delete_recurring_action_confirm: Are you sure that you want to delete the recurring action '%{description}'? - show_in_days: Show in %{days} days + completed_last_day: Completed in the last 24 hours + feed_title_in_context: in context '%{context}' no_project: --No project-- + show_in_days: Show in %{days} days error_saving_recurring: There was an error saving the recurring todo \'%{description}\' completed_more_than_x_days_ago: Completed more than %{count} days ago - all_completed: Todas las acciones realizadas - feed_title_in_context: in context '%{context}' new_related_todo_created_short: creada una nueva tarea + all_completed: Todas las acciones realizadas edit: Edit + completed_actions_with: Completed actions with the tag %{tag_name} older_than_days: Older than %{count} days completed_tagged_page_title: "TRACKS:: Las tareas completadas con etiqueta %{tag_name}" pending: Pending - completed_actions_with: Completed actions with the tag %{tag_name} - deleted_success: The action was deleted succesfully. completed_tasks_title: TRACKS::Completed tasks + deleted_success: The action was deleted succesfully. feed_title_in_project: in project '%{project}' clear_due_date: Clear due date error_removing_dependency: There was an error removing the dependency @@ -425,20 +443,21 @@ es: deferred_actions_with: Deferred actions with the tag '%{tag_name}' confirm_delete: Are you sure that you want to delete the action '%{description}'? recurring_deleted_success: The recurring action was deleted succesfully. - clear_show_from_date: Clear show from date + no_completed_actions_with: No completed actions with the tag '%{tag_name}' next_actions_title: Tracks - Next Actions next_action_description: "Descripci\xC3\xB3n de la nueva tarea" deferred_tasks_title: TRACKS::Tickler - no_completed_actions_with: No completed actions with the tag '%{tag_name}' - unresolved_dependency: The value you entered in the dependency field did not resolve to an existing action. This value will not be saved with the rest of the action. Continue? - calendar_page_title: TRACKS::Calendar + clear_show_from_date: Clear show from date in_hidden_state: en estado oculto - show_today: Show Today + see_all_completed: Usted puede ver todas las acciones realizadas %{link} + calendar_page_title: TRACKS::Calendar + unresolved_dependency: The value you entered in the dependency field did not resolve to an existing action. This value will not be saved with the rest of the action. Continue? no_actions_found_title: No actions found + show_today: Show Today next_actions_due_date: overdue_by: Overdue by %{days} day - due_today: Vence hoy due_in_x_days: "Vence en %{days} d\xC3\xADas" + due_today: Vence hoy overdue_by_plural: Overdue by %{days} days due_tomorrow: "Vence ma\xC3\xB1ana" completed_last_x_days: Completed in last %{count} days @@ -455,13 +474,13 @@ es: feeds: completed: "Completed: %{date}" due: "Due: %{date}" - delete_action: Delete action - error_deleting_recurring: There was an error deleting the recurring todo \'%{description}\' recurring_todos: Recurring todos + error_deleting_recurring: There was an error deleting the recurring todo \'%{description}\' + delete_action: Delete action delete: Delete + no_last_completed_actions: "No encontr\xC3\xB3 las acciones realizadas" drag_action_title: Drag onto another action to make it depend on that action cannot_add_dependency_to_completed_todo: Cannot add this action as a dependency to a completed action! - no_last_completed_actions: "No encontr\xC3\xB3 las acciones realizadas" depends_on: Depends on tickler_items_due: one: One tickler item is now due - refresh the page to see it. @@ -471,6 +490,7 @@ es: added_new_next_action_plural: Added new next actions new_related_todo_not_created_short: "no se cre\xC3\xB3 la tarea" completed_rest_of_week: Completado en el resto de esta semana + show_tomorrow: Show Tomorrow error_starring: Could not toggle the star of this todo \'%{description}\' calendar: get_in_ical_format: Get this calendar in iCal format @@ -483,9 +503,7 @@ es: no_actions_due_after_this_month: No actions due after this month no_actions_due_this_month: No actions due in rest of this month due_this_month: Due in rest of %{month} - show_tomorrow: Show Tomorrow - tagged_page_title: TRACKS::Tagged with '%{tag_name}' - action_deferred: "La acci\xC3\xB3n \\'%{description}\\' se aplaz\xC3\xB3" + no_completed_recurring: Currently there are no completed recurring todos recurrence: ends_on_date: Ends on %{date} every_work_day: Every work day @@ -494,11 +512,13 @@ es: weekly_options: Settings for weekly recurring actions weekly: Weekly monthly_options: Settings for monthly recurring actions + daily_options: Settings for daily recurring actions monthly: Monthly starts_on: Starts on - daily_options: Settings for daily recurring actions daily: Daily + show_option_always: always pattern: + third: third month_names: - - January @@ -513,17 +533,20 @@ es: - October - November - December - third: third every_n: every %{n} - every_xth_day_of_every_n_months: every %{x} %{day} of every %{n_months} second: second + every_xth_day_of_every_n_months: every %{x} %{day} of every %{n_months} on_day_n: on day %{n} weekly: weekly from: from - every_day: every day last: last - times: for %{number} times + every_day: every day the_xth_day_of_month: the %{x} %{day} of %{month} + times: for %{number} times + first: first + show: show + every_year_on: every year on %{date} + on_work_days: on work days day_names: - sunday - monday @@ -532,43 +555,40 @@ es: - thursday - friday - saturday - show: show - first: first - every_year_on: every year on %{date} - on_work_days: on work days fourth: fourth due: due every_month: every month until: until - show_option_always: always yearly_every_x_day: Every %{month} %{day} recurrence_on_options: Set recurrence on daily_every_number_day: Every %{number} day(s) - ends_on: Ends on show_options: Show the todo weekly_every_number_week: Returns every %{number} week on + ends_on: Ends on show_days_before: "%{days} days before the todo is due" - yearly_every_xth_day: The %{day} %{day_of_week} of %{month} from_tickler: the date todo comes from tickler (no due date set) no_end_date: No end date day_x_on_every_x_month: Day %{day} on every %{month} month + yearly_every_xth_day: The %{day} %{day_of_week} of %{month} yearly_options: Settings for yearly recurring actions yearly: Yearly monthly_every_xth_day: The %{day} %{day_of_week} of every %{month} month - no_completed_recurring: Currently there are no completed recurring todos + action_deferred: "La acci\xC3\xB3n \\'%{description}\\' se aplaz\xC3\xB3" + tagged_page_title: TRACKS::Tagged with '%{tag_name}' added_dependency: Added %{dependency} as dependency. - no_deferred_actions: Currently there are no deferred actions. - all_completed_tagged_page_title: "TRACKS:: Todas las tareas realizadas con etiqueta %{tag_name}" completed_rest_of_month: Completado en el resto de este mes + all_completed_tagged_page_title: "TRACKS:: Todas las tareas realizadas con etiqueta %{tag_name}" + no_deferred_actions: Currently there are no deferred actions. recurrence_completed: There is no next action after the recurring action you just finished. The recurrence is completed - error_toggle_complete: Could not mark this todo complete - due: "Fecha l\xC3\xADmite" + action_marked_complete_error: The action '%{description}' was NOT marked as %{completed} due to an error on the server. no_actions_found: Currently there are no incomplete actions. in_pending_state: en estado pendiente - action_marked_complete_error: The action '%{description}' was NOT marked as %{completed} due to an error on the server. - depends_on_separate_with_commas: Depende de (separar con comas) + error_toggle_complete: Could not mark this todo complete + due: "Fecha l\xC3\xADmite" + no_incomplete_actions: There are no incomplete actions action_saved_to_tickler: Action saved to tickler recurring_action_saved: Recurring action saved + depends_on_separate_with_commas: Depende de (separar con comas) completed_in_archive: one: There is one completed action in the archive. other: There are %{count} completed actions in the archive. @@ -578,94 +598,120 @@ es: due_date: with a due date %{due_date} or earlier overdue: Overdue add_new_recurring: Add a new recurring action - no_incomplete_actions: There are no incomplete actions notes: delete_note_title: Delete the note '%{id}' delete_confirmation: Are you sure that you want to delete the note '%{id}'? in_project: "En:" delete_item_title: Delete item + deleted_note: Deleted note '%{id}' note_link_title: Show note %{id} show_note_title: Show note - deleted_note: Deleted note '%{id}' edit_item_title: Edit item note_location_link: "In:" no_notes_available: "Currently there are no notes: add notes to projects from individual project pages." note_header: Note %{id} delete_note_confirm: Are you sure that you want to delete the note '%{id}'? + projects: + default_context_set: Set project's default context to %{default_context} + no_actions_in_project: Currently there are no incomplete actions in this project + deferred_actions: Tareas pospuestas para este proyecto + was_marked_hidden: has been marked as hidden + edit_project_title: Editar proyecto + default_tags_removed_notice: Removed the default tags + page_title: "TRACKS::Project: %{project}" + all_completed_tasks_title: "TRACKS:: Lista de todas las acciones terminado en '%{project_name}' Proyecto" + hide_form: Esconder formulario + list_completed_projects: "TRACKS:: Lista de Proyectos Realizados" + no_notes_attached: Currently there are no notes attached to this project + to_new_project_page: Take me to the new project page + show_form_title: Create a new project + deferred_actions_empty: There are no deferred actions for this project + project_state: Project is %{state}. + this_project: This project + no_last_completed_projects: No hay proyectos terminados encontrado + no_last_completed_recurring_todos: No se ha completado las acciones repetitivas que se encuentran + notes: Notes + todos_append: in this project + list_reviews: "TRACKS::Revisi\xC3\xB3n" + notes_empty: There are no notes for this project + no_projects: Currently there are no projects + hide_form_title: Hide new project form + delete_project: Delete project + completed_actions_empty: No hay tareas completadas para este proyecto + with_no_default_context: with no default context + delete_project_confirmation: Are you sure that you want to delete the project '%{name}'? + with_default_context: with a default context of '%{context_name}' + show_form: Add a project + actions_in_project_title: Actions in this project + completed_projects: Proyectos completados + is_active: "est\xC3\xA1 activo" + add_note: "A\xC3\xB1adir una nota" + set_default_tags_notice: Set project's default tags to %{default_tags} + add_project: "A\xC3\xB1adir Proyecto" + settings: Settings + project_saved_status: Project saved + list_projects: TRACKS::Lista de Proyectos + with_default_tags: and with '%{tags}' as the default tags + completed_tasks_title: "TRACKS:: Lista de Acciones completadas en '%{project_name}' Proyecto" + hidden_projects: Proyectos ocultos + delete_project_title: Delete the project + default_context_removed: Eliminado el contexto por defecto + add_note_submit: "A\xC3\xB1adir nota" + completed_actions: Tareas completadas para este proyecto + was_marked_complete: has been marked as completed + no_default_context: Este proyecto no tiene un contexto por defecto + with_no_default_tags: and with no default tags + default_context: The default context for this project is %{context} + edit_project_settings: Edit Project Settings + status_project_name_changed: Name of project was changed + state: This project is %{state} + active_projects: Active projects states: hidden_plural: Hidden - review_plural: Fechado stalled: Estancado + review_plural: Fechado completed: Completed current: "Hasta al d\xC3\xADa" - completed_plural: Completed review: Fechado + completed_plural: Completed blocked: Bloqueado blocked_plural: Bloqueado stalled_plural: Estancado visible_plural: Visible active_plural: Active visible: Visible - current_plural: "Hasta al d\xC3\xADa" hidden: Hidden active: Active - projects: - was_marked_hidden: has been marked as hidden - edit_project_title: Editar proyecto - default_tags_removed_notice: Removed the default tags - default_context_set: Set project's default context to %{default_context} - no_actions_in_project: Currently there are no incomplete actions in this project - deferred_actions: Tareas pospuestas para este proyecto - all_completed_tasks_title: "TRACKS:: Lista de todas las acciones terminado en '%{project_name}' Proyecto" - page_title: "TRACKS::Project: %{project}" - hide_form: Esconder formulario - no_notes_attached: Currently there are no notes attached to this project - show_form_title: Create a new project - deferred_actions_empty: There are no deferred actions for this project - this_project: This project - project_state: Project is %{state}. - list_completed_projects: "TRACKS:: Lista de Proyectos Realizados" - to_new_project_page: Take me to the new project page - no_last_completed_recurring_todos: No se ha completado las acciones repetitivas que se encuentran - todos_append: in this project - no_last_completed_projects: No hay proyectos terminados encontrado - notes: Notes - notes_empty: There are no notes for this project - no_projects: Currently there are no projects - hide_form_title: Hide new project form - list_reviews: "TRACKS::Revisi\xC3\xB3n" - delete_project: Delete project - completed_actions_empty: No hay tareas completadas para este proyecto - with_no_default_context: with no default context - show_form: Add a project - actions_in_project_title: Actions in this project - delete_project_confirmation: Are you sure that you want to delete the project '%{name}'? - with_default_context: with a default context of '%{context_name}' - add_note: "A\xC3\xB1adir una nota" - add_project: "A\xC3\xB1adir Proyecto" - with_default_tags: and with '%{tags}' as the default tags - is_active: "est\xC3\xA1 activo" - list_projects: TRACKS::Lista de Proyectos - settings: Settings - completed_projects: Proyectos completados - set_default_tags_notice: Set project's default tags to %{default_tags} - project_saved_status: Project saved - delete_project_title: Delete the project - hidden_projects: Proyectos ocultos - completed_tasks_title: "TRACKS:: Lista de Acciones completadas en '%{project_name}' Proyecto" - was_marked_complete: has been marked as completed - completed_actions: Tareas completadas para este proyecto - default_context_removed: Eliminado el contexto por defecto - add_note_submit: "A\xC3\xB1adir nota" - edit_project_settings: Edit Project Settings - status_project_name_changed: Name of project was changed - active_projects: Active projects - default_context: The default context for this project is %{context} - state: This project is %{state} - no_default_context: Este proyecto no tiene un contexto por defecto - with_no_default_tags: and with no default tags + current_plural: "Hasta al d\xC3\xADa" errors: user_unauthorized: "401 No autorizado: Solo los usuarios administrativos pueden acceder a esta funci\xC3\xB3n." + preferences: + open_id_url: Your OpenID URL is + change_identity_url: Change Your Identity URL + staleness_starts_after: Staleness starts after %{days} days + page_title: TRACKS::Preferences + change_password: Change your password + token_description: Token (for feeds and API use) + title: Your preferences + is_false: "false" + show_number_completed: Show %{number} completed items + password_changed: "Que ha cambiado la contrase\xC3\xB1a, por favor vuelve a iniciar sesi\xC3\xB3n." + edit_preferences: Edit preferences + page_title_edit: TRACKS::Edit Preferences + is_true: "true" + sms_context_none: None + generate_new_token: Generate a new token + token_header: Your token + authentication_header: Your authentication + updated: "Las preferencias de actualizaci\xC3\xB3n" + current_authentication_type: Your authentication type is %{auth_type} + change_authentication_type: Change your authentication type + generate_new_token_confirm: Are you sure? Generating a new token will replace the existing one and break any external usages of this token. + tabs: + authentication: "Autenticaci\xC3\xB3n" + tracks_behavior: Rastrea el comportamiento de + profile: Perfil + date_and_time: Fecha y hora time: am: soy formats: @@ -676,33 +722,6 @@ es: month_day: "%B %d" long: "%B %d, %Y %H:%M" pm: pm - preferences: - change_identity_url: Change Your Identity URL - open_id_url: Your OpenID URL is - staleness_starts_after: Staleness starts after %{days} days - page_title: TRACKS::Preferences - change_password: Change your password - token_description: Token (for feeds and API use) - title: Your preferences - is_false: "false" - show_number_completed: Show %{number} completed items - edit_preferences: Edit preferences - page_title_edit: TRACKS::Edit Preferences - is_true: "true" - password_changed: "Que ha cambiado la contrase\xC3\xB1a, por favor vuelve a iniciar sesi\xC3\xB3n." - sms_context_none: None - generate_new_token: Generate a new token - token_header: Your token - authentication_header: Your authentication - updated: "Las preferencias de actualizaci\xC3\xB3n" - current_authentication_type: Your authentication type is %{auth_type} - change_authentication_type: Change your authentication type - generate_new_token_confirm: Are you sure? Generating a new token will replace the existing one and break any external usages of this token. - tabs: - tracks_behavior: Rastrea el comportamiento de - authentication: "Autenticaci\xC3\xB3n" - profile: Perfil - date_and_time: Fecha y hora date: month_names: - @@ -781,8 +800,8 @@ es: send_feedback: "Env\xC3\xADa comentarios sobre el %{version}" shared: multiple_next_actions: Multiple next actions (one on each line) - toggle_single: Add a next action make_actions_dependent: "Aseg\xC3\xBArese que las acciones dependen unos de otros" + toggle_single: Add a next action hide_form: Esconder formulario add_actions: "A\xC3\xB1adir tareas" add_action: "A\xC3\xB1adir tarea" @@ -795,6 +814,30 @@ es: add_context: Agregue contexto toggle_multi_title: Toggle single/multi new action form hide_action_form_title: Hide new action form + feedlist: + choose_context: Elija el contexto en el que desea un canal de + actions_due_today: Acciones pendientes hoy o antes + ical_feed: "iCal alimentaci\xC3\xB3n" + legend: "Leyenda:" + all_contexts: Todos los contextos + rss_feed: RSS Feed + choose_project: Elegir el proyecto que quiere un canal de + all_projects: Todos los proyectos + project_needed: Es necesario que haya al menos un proyecto antes de poder solicitar un feed + select_feed_for_project: Seleccione la fuente para este proyecto + active_projects_wo_next: "Proyectos activos, sin las pr\xC3\xB3ximas acciones" + active_starred_actions: "Todas las acciones que protagoniz\xC3\xB3, activa" + context_needed: Es necesario que haya al menos un contexto antes de poder solicitar un feed + select_feed_for_context: "Seleccione la alimentaci\xC3\xB3n de este contexto" + projects_and_actions: Proyectos activos con sus acciones + notice_incomplete_only: "Nota: Todos los alimentos muestran s\xC3\xB3lo las acciones que no han sido marcadas como realizadas, a menos que se indique lo contrario." + actions_due_next_week: "Tareas pendientes en 7 d\xC3\xADas o menos" + actions_completed_last_week: "Tareas completadas en los \xC3\xBAltimos 7 d\xC3\xADas" + context_centric_actions: "Feeds de acciones incompletas en un contexto espec\xC3\xADfico" + plain_text_feed: Canal Texto sin formato + last_fixed_number: "\xC3\x9Altima %{number} acciones" + all_actions: Todas las tareas + project_centric: "Feeds de acciones incompletas en un proyecto espec\xC3\xADfico" sidebar: list_name_active_contexts: Active contexts list_name_active_projects: Active projects @@ -802,66 +845,14 @@ es: list_name_completed_projects: Completed projects list_name_hidden_projects: Hidden projects list_name_hidden_contexts: Hidden contexts - feedlist: - actions_due_today: Acciones pendientes hoy o antes - choose_context: Elija el contexto en el que desea un canal de - rss_feed: RSS Feed - legend: "Leyenda:" - ical_feed: "iCal alimentaci\xC3\xB3n" - all_contexts: Todos los contextos - all_projects: Todos los proyectos - choose_project: Elegir el proyecto que quiere un canal de - project_needed: Es necesario que haya al menos un proyecto antes de poder solicitar un feed - select_feed_for_project: Seleccione la fuente para este proyecto - active_projects_wo_next: "Proyectos activos, sin las pr\xC3\xB3ximas acciones" - active_starred_actions: "Todas las acciones que protagoniz\xC3\xB3, activa" - select_feed_for_context: "Seleccione la alimentaci\xC3\xB3n de este contexto" - projects_and_actions: Proyectos activos con sus acciones - context_needed: Es necesario que haya al menos un contexto antes de poder solicitar un feed - actions_due_next_week: "Tareas pendientes en 7 d\xC3\xADas o menos" - notice_incomplete_only: "Nota: Todos los alimentos muestran s\xC3\xB3lo las acciones que no han sido marcadas como realizadas, a menos que se indique lo contrario." - context_centric_actions: "Feeds de acciones incompletas en un contexto espec\xC3\xADfico" - plain_text_feed: Canal Texto sin formato - last_fixed_number: "\xC3\x9Altima %{number} acciones" - all_actions: Todas las tareas - actions_completed_last_week: "Tareas completadas en los \xC3\xBAltimos 7 d\xC3\xADas" - project_centric: "Feeds de acciones incompletas en un proyecto espec\xC3\xADfico" - contexts: - delete_context_title: Eliminar contexto - all_completed_tasks_title: "TRACKS:: Todas las acciones completadas en '%{context_name}' contexto" - hide_form: Esconder formulario - show_form_title: "A\xC3\xB1adir un contexto" - todos_append: en este contexto - delete_context_confirmation: "\xC2\xBFEst\xC3\xA1 seguro que desea eliminar '%{name}' el contexto? Tenga en cuenta que esto tambi\xC3\xA9n se eliminar\xC3\xA1n todas las acciones (la repetici\xC3\xB3n) en este contexto!" - delete_context: Eliminar contexto - edit_context: Editar contexto - hide_form_title: Ocultar el formulario nuevo contexto - hidden_contexts: Contextos ocultos - no_contexts_active: Actualmente no hay contextos activos - context_hide: "\xC2\xBFEsconder de la p\xC3\xA1gina principal?" - show_form: Crear un nuevo contexto - visible_contexts: Contextos visible - save_status_message: Contexto guardado - add_context: "A\xC3\xB1adir contexto" - update_status_message: Nombre de contexto ha cambiado - context_name: Nombre del contexto - status_active: "El contexto est\xC3\xA1 activo" - completed_tasks_title: "TRACKS:: Las acciones completadas en '%{context_name}' el contexto" - new_context_post: "' Tambi\xC3\xA9n se ha creado. \xC2\xBFEst\xC3\xA1 seguro?" - no_actions: Actualmente no hay acciones incompletas en este contexto - last_completed_in_context: "en este contexto (\xC3\xBAltimos %{number})" - context_deleted: Contexto eliminado '%{name}' - no_contexts_hidden: Actualmente no hay contextos ocultos - new_context_pre: Nuevo contexto ' - status_hidden: Contexto se oculta users: - successfully_deleted_user: Successfully deleted user %{username} + openid_url_verified: You have successfully verified %{url} as your identity and set your authentication type to OpenID. auth_type_update_error: "There was a problem updating your authentication type: %{error_messages}" failed_to_delete_user: Failed to delete user %{username} destroy_successful: User %{login} was successfully destroyed - total_contexts: Total contexts first_user_heading: "Welcome to TRACKS. To get started, please create an admin account:" - openid_url_verified: You have successfully verified %{url} as your identity and set your authentication type to OpenID. + total_contexts: Total contexts + successfully_deleted_user: Successfully deleted user %{username} signup_successful: Signup successful for user %{username}. new_token_generated: New token successfully generated total_projects: Total projects @@ -869,23 +860,23 @@ es: no_signups_title: TRACKS::No signups user_created: User created. account_signup: Account signup - password_updated: Password updated. manage_users: Manage users - new_user_heading: "Sign up a new user:" + password_updated: Password updated. auth_type_updated: Authentication type updated. total_actions: Total actions desired_login: Desired login signup: Signup confirm_password: Confirm password - change_password_prompt: Enter your new password in the fields below and click 'Change password' to replace your current password with your new one. + new_user_heading: "Sign up a new user:" password_confirmation_label: Confirm password destroy_error: There was an error deleting the user %{login} choose_password: Choose password change_password_title: TRACKS::Change password change_auth_type_title: TRACKS::Change authentication type + change_password_prompt: Enter your new password in the fields below and click 'Change password' to replace your current password with your new one. + new_password_label: New password register_with_cas: With your CAS username label_auth_type: Authentication type - new_password_label: New password total_users_count: You have a total of %{count} users new_user_title: TRACKS::Sign up as the admin user destroy_user: Destroy user @@ -896,18 +887,46 @@ es: openid_ok_pref_failed: You have successfully verified %{url} as your identity but there was a problem saving your authentication preferences. auth_change_submit: Change authentication type change_authentication_type: Change authentication type - select_authentication_type: Select your new authentication type and click 'Change authentication type' to replace your current settings. total_notes: Total notes + select_authentication_type: Select your new authentication type and click 'Change authentication type' to replace your current settings. + contexts: + delete_context_title: Eliminar contexto + all_completed_tasks_title: "TRACKS:: Todas las acciones completadas en '%{context_name}' contexto" + hide_form: Esconder formulario + show_form_title: "A\xC3\xB1adir un contexto" + delete_context_confirmation: "\xC2\xBFEst\xC3\xA1 seguro que desea eliminar '%{name}' el contexto? Tenga en cuenta que esto tambi\xC3\xA9n se eliminar\xC3\xA1n todas las acciones (la repetici\xC3\xB3n) en este contexto!" + todos_append: en este contexto + delete_context: Eliminar contexto + edit_context: Editar contexto + hide_form_title: Ocultar el formulario nuevo contexto + hidden_contexts: Contextos ocultos + no_contexts_active: Actualmente no hay contextos activos + context_hide: "\xC2\xBFEsconder de la p\xC3\xA1gina principal?" + add_context: "A\xC3\xB1adir contexto" + show_form: Crear un nuevo contexto + save_status_message: Contexto guardado + visible_contexts: Contextos visible + update_status_message: Nombre de contexto ha cambiado + context_name: Nombre del contexto + status_active: "El contexto est\xC3\xA1 activo" + completed_tasks_title: "TRACKS:: Las acciones completadas en '%{context_name}' el contexto" + new_context_post: "' Tambi\xC3\xA9n se ha creado. \xC2\xBFEst\xC3\xA1 seguro?" + new_context_pre: Nuevo contexto ' + no_actions: Actualmente no hay acciones incompletas en este contexto + last_completed_in_context: "en este contexto (\xC3\xBAltimos %{number})" + context_deleted: Contexto eliminado '%{name}' + no_contexts_hidden: Actualmente no hay contextos ocultos + status_hidden: Contexto se oculta login: - login_cas: go to the CAS openid_identity_url_not_found: Sorry, no user by that identity URL exists (%{identity_url}) user_no_expiry: Stay logged in sign_in: Entrar - please_login: Please log in to use Tracks - cas_logged_in_greeting: Hello, %{username}! You are authenticated. + login_cas: go to the CAS cas_no_user_found: Hello, %{username}! You do not have an account on Tracks. cas_login: CAS Login successful_with_session_info: "Login successful:" + please_login: Please log in to use Tracks + cas_logged_in_greeting: Hello, %{username}! You are authenticated. cas_username_not_found: Sorry, no user by that CAS username exists (%{username}) cas_create_account: If you like to request on please go here to %{signup_link} mobile_use_openid: "\xE2\x80\xA6or login with an OpenID" @@ -919,10 +938,10 @@ es: session_time_out: Session has timed out. Please %{link} session_will_expire: session will expire after %{hours} hour(s) of inactivity. login_standard: go back to the standard login - log_in_again: log in again. - logged_out: You have been logged out of Tracks. login_with_openid: login with an OpenID unsuccessful: Login unsuccessful. + log_in_again: log in again. + logged_out: You have been logged out of Tracks. datetime: prompts: minute: Minuto @@ -977,7 +996,7 @@ es: search: contexts_matching_query: Contexts matching query tags_matching_query: Tags matching query + no_results: Your search yielded no results. todos_matching_query: Todos matching query projects_matching_query: Projects matching query notes_matching_query: Notes matching query - no_results: Your search yielded no results. diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 3df8b481..f83d7cca 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -1,5 +1,56 @@ --- fr: + layouts: + toggle_contexts_title: "Faire des contextes effondr\xC3\xA9 (in)visibles" + toggle_contexts: "Basculer contextes effondr\xC3\xA9" + toggle_notes: Afficher/Cacher notes + next_actions_rss_feed: Flux RSS des prochaines actions + toggle_notes_title: Afficher/Cacher toutes les notes + mobile_navigation: + new_action: 0-Nouvelle action + logout: "D\xC3\xA9connexion" + feeds: Flux + starred: "Marqu\xC3\xA9" + projects: Projets + tickler: Reporteur + contexts: Contextes + home: Accueil + navigation: + manage_users_title: Ajouter ou supprimer des utilisateurs + recurring_todos: "T\xC3\xA2ches (todos) r\xC3\xA9p\xC3\xA9titives" + api_docs: Doc REST API + help: "?" + feeds: Flux + starred: "Marqu\xC3\xA9" + stats: Statistiques + notes_title: Voir toutes les notes + manage_users: Gestion des utilisateurs + tickler_title: Reporteur + admin: Admin + preferences: !binary | + UHLDqWbDqXJlbmNlcw== + + integrations_: "Int\xC3\xA9grer Tracks" + export_title: "Importer et exporter des donn\xC3\xA9es" + calendar_title: "Calendrier des actions \xC3\xA0 \xC3\xA9ch\xC3\xA9ance" + feeds_title: Voir une liste des flux disponibles + stats_title: Voir vos statistiques + tickler: Reporteur + home_title: Accueil + starred_title: "Voir vos actions pr\xC3\xA9f\xC3\xA9r\xC3\xA9es" + recurring_todos_title: "Gerer les actions r\xC3\xA9currentes" + completed_tasks: "Termin\xC3\xA9" + view: Vue + organize: Organiser + completed_tasks_title: "Termin\xC3\xA9" + home: Accueil + export: Exporter + contexts_title: Contextes + preferences_title: "Voir mes pr\xC3\xA9f\xC3\xA9rences" + search: Recherches tous les items + review_title: Faire examiner + projects_title: Projets + calendar: Calendrier number: format: separator: . @@ -31,57 +82,79 @@ fr: unit: $ separator: . delimiter: "," - layouts: - toggle_contexts_title: "Faire des contextes effondr\xC3\xA9 (in)visibles" - toggle_notes: Afficher/Cacher notes - toggle_contexts: "Basculer contextes effondr\xC3\xA9" - next_actions_rss_feed: Flux RSS des prochaines actions - toggle_notes_title: Afficher/Cacher toutes les notes - mobile_navigation: - feeds: Flux - new_action: 0-Nouvelle action - logout: "D\xC3\xA9connexion" - starred: "Marqu\xC3\xA9" - projects: Projets - tickler: Reporteur - contexts: Contextes - home: Accueil - navigation: - manage_users_title: Ajouter ou supprimer des utilisateurs - api_docs: Doc REST API - recurring_todos: "T\xC3\xA2ches (todos) r\xC3\xA9p\xC3\xA9titives" - feeds: Flux - help: "?" - stats: Statistiques - starred: "Marqu\xC3\xA9" - notes_title: Voir toutes les notes - manage_users: Gestion des utilisateurs - tickler_title: Reporteur - admin: Admin - integrations_: "Int\xC3\xA9grer Tracks" - export_title: "Importer et exporter des donn\xC3\xA9es" - preferences: !binary | - UHLDqWbDqXJlbmNlcw== + common: + recurring_todos: "R\xC3\xA9p\xC3\xA9tition d'actions" + back: Retour + actions: Actions + third: "Troisi\xC3\xA8me" + add: Ajouter + go_back: Retour + previous: !binary | + UHLDqWPDqWRlbnRl - calendar_title: "Calendrier des actions \xC3\xA0 \xC3\xA9ch\xC3\xA9ance" - feeds_title: Voir une liste des flux disponibles - completed_tasks: "Termin\xC3\xA9" - stats_title: Voir vos statistiques - tickler: Reporteur - home_title: Accueil - starred_title: "Voir vos actions pr\xC3\xA9f\xC3\xA9r\xC3\xA9es" - recurring_todos_title: "Gerer les actions r\xC3\xA9currentes" - view: Vue - organize: Organiser - completed_tasks_title: "Termin\xC3\xA9" - home: Accueil - contexts_title: Contextes - export: Exporter - preferences_title: "Voir mes pr\xC3\xA9f\xC3\xA9rences" - review_title: Faire examiner - calendar: Calendrier - search: Recherches tous les items - projects_title: Projets + logout: "D\xC3\xA9connexion" + second: Seconde + none: Aucun + week: semaine + optional: optionnel + deferred: "report\xC3\xA9es" + cancel: Annuler + show_all: Voir tous + month: mois + actions_midsentence: + one: action + other: actions + zero: actions + forum: Forum + server_error: Une erreur s\'est produite sur le serveur + notes: Notes + projects: Projets + last: Dernier + review: Revue + action: Action + days_midsentence: + one: jour + other: jours + zero: jours + project: Projet + contribute: Contribuer + ok: Ok + website: Site Web + first: Premier + note: + one: 1 noter + other: "%{count} notes" + zero: non notes + numbered_step: Etape %{number} + sort: + by_task_count_title: "Trier par nombre de t\xC3\xA2ches" + by_task_count_title_confirm: "Etes vous s\xC3\xBBr de vouloir trier ces projets par nombre de t\xC3\xA2ches ? L\\'ordre actuel sera remplac\xC3\xA9." + alphabetically: "Par ordre alphab\xC3\xA9tique" + sort: Trier + alphabetically_title: "Trier les projets par ordre alphab\xC3\xA9tique" + alphabetically_confirm: "Etes vous s\xC3\xBBr de vouloir trier ces projets par ordre alphab\xC3\xA9tique ? L\\'ordre actuel sera remplac\xC3\xA9." + by_task_count: "Par nombre de t\xC3\xA2ches" + create: !binary | + Q3LDqWVy + + todo: Action + months: Mois + description: Description + errors_with_fields: "Il y a des probl\xC3\xA8me avec les champs suivants :" + drag_handle: DRAG + next: Suivant + fourth: "Quatri\xC3\xA8me" + context: Contexte + contexts: Contextes + bugs: Bugs + update: "Mettre \xC3\xA0 jour" + forth: FORTH + weeks: semaines + wiki: Wiki + email: Email + search: Rechercher + ajaxError: "Une erreur s'est produite en acc\xC3\xA9dant un serveur" + not_available_abbr: n/a integrations: opensearch_description: Rechercher dans Tracks applescript_next_action_prompt: "Description de l'action suivante:" @@ -90,68 +163,6 @@ fr: Q3LDqcOp applescript_success_before_id: Nouvelle action suivante avec ID - common: - back: Retour - recurring_todos: "R\xC3\xA9p\xC3\xA9tition d'actions" - actions: Actions - third: "Troisi\xC3\xA8me" - add: Ajouter - previous: !binary | - UHLDqWPDqWRlbnRl - - go_back: Retour - logout: "D\xC3\xA9connexion" - second: Seconde - show_all: Voir tous - optional: optionnel - week: semaine - none: Aucun - cancel: Annuler - month: mois - actions_midsentence: actes - server_error: Une erreur s\'est produite sur le serveur - forum: Forum - notes: Notes - last: Dernier - projects: Projets - action: Action - review: Revue - project: Projet - days_midsentence: "journ\xC3\xA9es" - contribute: Contribuer - ok: Ok - website: Site Web - first: Premier - numbered_step: Etape %{number} - errors_with_fields: "Il y a des probl\xC3\xA8me avec les champs suivants :" - create: !binary | - Q3LDqWVy - - sort: - by_task_count_title: "Trier par nombre de t\xC3\xA2ches" - by_task_count_title_confirm: "Etes vous s\xC3\xBBr de vouloir trier ces projets par nombre de t\xC3\xA2ches ? L\\'ordre actuel sera remplac\xC3\xA9." - alphabetically: "Par ordre alphab\xC3\xA9tique" - alphabetically_title: "Trier les projets par ordre alphab\xC3\xA9tique" - sort: Trier - alphabetically_confirm: "Etes vous s\xC3\xBBr de vouloir trier ces projets par ordre alphab\xC3\xA9tique ? L\\'ordre actuel sera remplac\xC3\xA9." - by_task_count: "Par nombre de t\xC3\xA2ches" - months: Mois - description: Description - todo: Action - fourth: "Quatri\xC3\xA8me" - next: Suivant - contexts: Contextes - context: Contexte - drag_handle: DRAG - update: "Mettre \xC3\xA0 jour" - weeks: semaines - forth: FORTH - wiki: Wiki - bugs: Bugs - ajaxError: "Une erreur s'est produite en acc\xC3\xA9dant un serveur" - not_available_abbr: n/a - email: Email - search: Rechercher activerecord: attributes: project: @@ -165,17 +176,14 @@ fr: updated_at: "Mise \xC3\xA0 jour \xC3\xA0" todo: - predecessors: "D\xC3\xA9pend de" show_from: Afficher depuis + predecessors: "D\xC3\xA9pend de" notes: Note - project: Projet tags: "Mots-cl\xC3\xA9s" + project: Projet description: Description context: Contexte due: "Ech\xC3\xA9ance" - user: - last_name: Nom - first_name: "Pr\xC3\xA9nom" preference: show_hidden_projects_in_sidebar: "Montrer les projets cach\xC3\xA9s dans le panneau lat\xC3\xA9ral" show_hidden_contexts_in_sidebar: "Montrer les contextes cach\xC3\xA9s dans le panneau lat\xC3\xA9ral" @@ -184,19 +192,22 @@ fr: verbose_action_descriptors: "Descripteurs d\\'action d\xC3\xA9taill\xC3\xA9s" staleness_starts: "D\xC3\xA9but de d\xC3\xA9passement" mobile_todos_per_page: Actions par page (Vue Mobile) - title_date_format: Format de la date en titre show_number_completed: "Montrer le nombre d\\'action compl\xC3\xA9t\xC3\xA9es" + title_date_format: Format de la date en titre refresh: Intervalle de rafraichissement (en minutes) week_starts: Les semaines commencent un last_name: Nom due_style: "Style Ech\xC3\xA9ance" locale: Langue time_zone: Fuseau horaire - show_project_on_todo_done: "Aller au projet quand la t\xC3\xA2che est termin\xC3\xA9e" sms_email: De l\'Email - first_name: Nom + show_project_on_todo_done: "Aller au projet quand la t\xC3\xA2che est termin\xC3\xA9e" show_completed_projects_in_sidebar: "Montrer les projets compl\xC3\xA9t\xC3\xA9s dans le panneau lat\xC3\xA9ral" + first_name: Nom review_period: Intervalle de revue de projet + user: + last_name: Nom + first_name: "Pr\xC3\xA9nom" errors: models: project: @@ -244,21 +255,21 @@ fr: feed_description: Liste de tous les projets de %{username} todo: error_date_must_be_future: "doit \xC3\xAAtre une date dans le futur" - user: - error_context_not_associated: "L'identifiant contexte %{context} n'est pas associ\xC3\xA9 \xC3\xA0 l'identifiant utilisateur %{user}." - error_project_not_associated: "L'identifiant projet %{context} n'est pas associ\xC3\xA9 \xC3\xA0 l'identifiant utilisateur %{user}." preference: due_on: "Ech\xC3\xA9ance le %{date}" due_in: "Ech\xC3\xA9ance dans %{days} jours" due_styles: - "Ech\xC3\xA9ance dans ____ jours" - "Ech\xC3\xA9ance le ____" + user: + error_context_not_associated: "L'identifiant contexte %{context} n'est pas associ\xC3\xA9 \xC3\xA0 l'identifiant utilisateur %{user}." + error_project_not_associated: "L'identifiant projet %{context} n'est pas associ\xC3\xA9 \xC3\xA0 l'identifiant utilisateur %{user}." stats: - tag_cloud_title: Nuage de tag pour toutes les actions totals_hidden_context_count: "et %{count} sont des contextes cach\xC3\xA9s." actions_avg_created: "Dans les 12 derniers mois vous avez cr\xC3\xA9\xC3\xA9 une moyenne de %{count} actions" actions_min_max_completion_days: "Le nombre max/min de jours pour r\xC3\xA9aliser est %{min}/%{max}." totals_actions_completed: "dont %{count} sont r\xC3\xA9alis\xC3\xA9es." + tag_cloud_title: Nuage de tag pour toutes les actions actions_actions_avg_created_30days: "Dans les 30 jours vous avez cr\xC3\xA9er en moyenne %{count} actions" actions_avg_completed: "et r\xC3\xA9alis\xC3\xA9 une moyenne de %{count} actions par mois." top5_visible_contexts_with_incomplete_actions: Top 5 des contextes visible avec des actions en cours @@ -274,11 +285,11 @@ fr: weeks: Temps en cours d'une action (en semaines). Cliquer sur une barre pour plus d'info totals_action_count: vous avez un total de %{count} actions tag_cloud_90days_title: Nuage de tag des actions des 90 derniers jours + actions_avg_completion_time: "Pour toutes vos actions r\xC3\xA9alis\xC3\xA9s, le temps moyen de r\xC3\xA9alisation est %{count} jours." tod30: Heure (30 derniers jours) tags: Tags projects: Projets - actions_avg_completion_time: "Pour toutes vos actions r\xC3\xA9alis\xC3\xA9s, le temps moyen de r\xC3\xA9alisation est %{count} jours." - actions_lastyear_title: Actions des 12 derniers mois + totals_completed_project_count: "et %{count} sont des projets r\xC3\xA9alis\xC3\xA9s." labels: month_avg_completed: "%{month} mois moy. r\xC3\xA9alis\xC3\xA9" completed: !binary | @@ -293,8 +304,8 @@ fr: Q3LDqcOp actions_selected_from_week: "Actions selectionn\xC3\xA9es depuis la semaine" - totals_completed_project_count: "et %{count} sont des projets r\xC3\xA9alis\xC3\xA9s." actions_day_of_week_title: Jour de la semaine (toutes les actions) + actions_lastyear_title: Actions des 12 derniers mois open_per_week: "Actifs (visibles et cach\xC3\xA9s) prochaines actions par semaine" action_selection_title: TRACKS::Selection action totals_project_count: Vous avez %{count} projets @@ -317,16 +328,16 @@ fr: actions_last_year_legend: number_of_actions: Nombre d'actions months_ago: "Mois pr\xC3\xA9c\xC3\xA9dents" - top10_projects: Top 10 des projets top5_contexts: Top 5 des contextes - click_to_return: "Cliquer %{link} pour revenir \xC3\xA0 la page des statistiques" - totals: Totaux + top10_projects: Top 10 des projets contexts: Contextes + totals: Totaux + click_to_return: "Cliquer %{link} pour revenir \xC3\xA0 la page des statistiques" tag_cloud_90days_description: "Ce nuage de tag contient les tags des actions cr\xC3\xA9\xC3\xA9es ou r\xC3\xA9alis\xC3\xA9es dans les 90 derniers jours." totals_visible_context_count: De ceux-ci %{count} sont des contextes visibles - actions_min_completion_time: "Le temps minimum de r\xC3\xA9alisation est %{time}." top10_projects_30days: Top 10 des projets des 30 derniers jours running_time_all: "Temps en cours de toutes les actions incompl\xC3\xA8tes" + actions_min_completion_time: "Le temps minimum de r\xC3\xA9alisation est %{time}." action_completion_time_title: "Temps de r\xC3\xA9alisation (toutes les actions r\xC3\xA9alis\xC3\xA9es)" click_to_show_actions_from_week: Cliquer %{link} pour voir les actions depuis la semaine %{week}. top10_longrunning: Top 10 des plus long projets en cours @@ -338,14 +349,14 @@ fr: day_of_week: Jour de la semaine totals_first_action: "Depuis votre premi\xC3\xA8re action du %{date}" tag_cloud_description: "Ce nuage de tags contient les tags de toutes les actions (r\xC3\xA9alis\xC3\xA9es, en cours, visibles ou cach\xC3\xA9es)" + spread_of_actions_for_all_context: Vue des actions pour tous les contextes click_to_update_actions: Cliquer sur une barre du graphique pour mettre a jour les actions ci-dessous. click_to_return_link: ici - spread_of_actions_for_all_context: Vue des actions pour tous les contextes more_stats_will_appear: Plus de statistiques apparaitront quand vous aurez ajouter quelques actions. actions_avg_completed_30days: "et r\xC3\xA9alis\xC3\xA9 une moyenne de %{count} actions par jour." + index_title: TRACKS::Statistiques actions_30days_title: Actions des 30 derniers jours no_tags_available: pas de tags disponibles - index_title: TRACKS::Statistiques actions_dow_30days_title: Jour de la semaine (les 30 derniers jours) actions_day_of_week_legend: number_of_actions: Certain nombre d'actions @@ -361,19 +372,19 @@ fr: running_time: Temps en cours d'une action (en semaines). Cliquer sur une barre pour plus d'info percentage: Pourcentage other_actions_label: (autres) - time_of_day: Heure (toutes les actions) totals_hidden_project_count: "%{count} sont cach\xC3\xA9s" + time_of_day: Heure (toutes les actions) todos: - completed_actions: "Action compl\xC3\xA9t\xC3\xA9es" + recurring_action_deleted: "L'action a \xC3\xA9t\xC3\xA9 supprim\xC3\xA9e. Parce que cette action est r\xC3\xA9currente, une nouvelle action \xC3\xA0 \xC3\xA9t\xC3\xA9 ajout\xC3\xA9e" show_from: Afficher depuis error_starring_recurring: "Impossible d'actionner l'\xC3\xA9toile de la tache r\xC3\xA9currente \\'%{description}\\'" - recurring_action_deleted: "L'action a \xC3\xA9t\xC3\xA9 supprim\xC3\xA9e. Parce que cette action est r\xC3\xA9currente, une nouvelle action \xC3\xA0 \xC3\xA9t\xC3\xA9 ajout\xC3\xA9e" - completed_rest_of_previous_month: "Compl\xC3\xA9t\xC3\xA9 dans le reste du mois pr\xC3\xA9c\xC3\xA9dent" - completed_recurring: "T\xC3\xA2ches reccurents compl\xC3\xA9t\xC3\xA9s" + completed_actions: "Action compl\xC3\xA9t\xC3\xA9es" added_new_next_action: "Nouvelle action suivante ajout\xC3\xA9e" + completed_recurring: "T\xC3\xA2ches reccurents compl\xC3\xA9t\xC3\xA9s" + completed_rest_of_previous_month: "Compl\xC3\xA9t\xC3\xA9 dans le reste du mois pr\xC3\xA9c\xC3\xA9dent" blocked_by: "Bloqu\xC3\xA9 par %{predecessors}" - completed_recurrence_completed: "Il n'y pas d'action suivante apr\xC3\xA8s l'action r\xC3\xA9currente que vous avez supprim\xC3\xA9e. La r\xC3\xA9currence est termin\xC3\xA9e" star_action: Elire cette action + completed_recurrence_completed: "Il n'y pas d'action suivante apr\xC3\xA8s l'action r\xC3\xA9currente que vous avez supprim\xC3\xA9e. La r\xC3\xA9currence est termin\xC3\xA9e" defer_date_after_due_date: "La date de report est apr\xC3\xA8s la date d'\xC3\xA9ch\xC3\xA9ance. Veuillez ajuster la date d'\xC3\xA9cheance avant de reporter." unable_to_add_dependency: "Impossible d'ajouter la d\xC3\xA9pendance" done: "Termin\xC3\xA9 ?" @@ -386,16 +397,16 @@ fr: no_hidden_actions: "Il n'y a pas d'actions cach\xC3\xA9es actuellement" edit_action_with_description: Modifier l'action '%{description}' action_due_on: "(action \xC3\xA0 terminer avant le %{date})" + list_incomplete_next_actions: "Liste les prochaines actions incompl\xC3\xA8tes" archived_tasks_title: "TRACKS::T\xC3\xA2ches r\xC3\xA9alis\xC3\xA9es archiv\xC3\xA9es" remove_dependency: "Enlever les d\xC3\xA9pendances (l'action n'est pas supprim\xC3\xA9e)" - list_incomplete_next_actions: "Liste les prochaines actions incompl\xC3\xA8tes" - tags: "Tags (s\xC3\xA9par\xC3\xA9s par des virgules)" action_deleted_success: "L'action suivante \xC3\xA0 \xC3\xA9t\xC3\xA9 supprim\xC3\xA9e avec succ\xC3\xA8s" - mobile_todos_page_title: Toutes les actions - new_related_todo_created: "Une nouvelle t\xC3\xA2che a \xC3\xA9t\xC3\xA9 ajout\xC3\xA9e qui appartient \xC3\xA0 cette t\xC3\xA2che r\xC3\xA9currente" - context_changed: "Contexte chang\xC3\xA9 en %{name}" - add_another_dependency: "Ajouter une autre d\xC3\xA9pendance" + tags: "Tags (s\xC3\xA9par\xC3\xA9s par des virgules)" delete_recurring_action_title: "Supprimer l'action r\xC3\xA9currente" + context_changed: "Contexte chang\xC3\xA9 en %{name}" + new_related_todo_created: "Une nouvelle t\xC3\xA2che a \xC3\xA9t\xC3\xA9 ajout\xC3\xA9e qui appartient \xC3\xA0 cette t\xC3\xA2che r\xC3\xA9currente" + mobile_todos_page_title: Toutes les actions + add_another_dependency: "Ajouter une autre d\xC3\xA9pendance" removed_predecessor: "Suppression de %{successor} comme d\xC3\xA9pendance de %{predecessor}" recurring_actions_title: "TRACKS::Actions r\xC3\xA9currentes" next_action_needed: Vous devez soumettre au moins une prochaine action @@ -405,40 +416,41 @@ fr: edit_action: Modifier action added_new_context: "Nouveau context ajout\xC3\xA9" next_actions_description: "Filtre:" + list_incomplete_next_actions_with_limit: "Liste les %{count} derni\xC3\xA8res actions suivantes incompl\xC3\xA8tes" + set_to_pending: "%{task} mise en attente" + added_new_project: "Nouveau projet ajout\xC3\xA9" next_actions_title_additions: completed: "Actions compl\xC3\xA9t\xC3\xA9es" due_today: "\xC3\xA9ch\xC3\xA9ance aujourd'hui" due_within_a_week: "\xC3\xA9ch\xC3\xA9ance dans la semaine" - list_incomplete_next_actions_with_limit: "Liste les %{count} derni\xC3\xA8res actions suivantes incompl\xC3\xA8tes" - set_to_pending: "%{task} mise en attente" - added_new_project: "Nouveau projet ajout\xC3\xA9" older_completed_items: "Anciens \xC3\xA9l\xC3\xA9ments compl\xC3\xA9t\xC3\xA9s" - error_deleting_item: "Il s'est produit une erreur lors de la suppression de l'\xC3\xA9l\xC3\xA9ment %{description}" - edit_recurring_todo: "Modifier l'action r\xC3\xA9p\xC3\xA9tant" - append_in_this_project: dans ce projet - task_list_title: "TRACKS::Lister les t\xC3\xA2ches" no_actions_due_this_week: "Pas actions \xC3\xA0 faire cette semaine" + all_completed_here: ici + append_in_this_project: dans ce projet + edit_recurring_todo: "Modifier l'action r\xC3\xA9p\xC3\xA9tant" + error_deleting_item: "Il s'est produit une erreur lors de la suppression de l'\xC3\xA9l\xC3\xA9ment %{description}" + task_list_title: "TRACKS::Lister les t\xC3\xA2ches" no_recurring_todos: "Il n'y a pas de t\xC3\xA2ches r\xC3\xA9currentes actuellement" error_completing_todo: "Il s'est produit une erreur lors de l'execution de l'action r\xC3\xA9currente %{description}" recurring_pattern_removed: "La p\xC3\xA9riodicit\xC3\xA9 est retir\xC3\xA9 de %{count}" convert_to_project: Faire projet no_deferred_pending_actions: "Il n'y pas d'actions report\xC3\xA9es ou en attente actuellement" - completed_last_day: "Compl\xC3\xA9t\xC3\xA9 ces derni\xC3\xA8res 24 heures" delete_recurring_action_confirm: "Etes-vous s\xC3\xBBr de vouloir supprimer l'action r\xC3\xA9currente '%{description'}?" - show_in_days: Afficher dans %{days} jours + completed_last_day: "Compl\xC3\xA9t\xC3\xA9 ces derni\xC3\xA8res 24 heures" + feed_title_in_context: dans le contexte '%{context}' no_project: --Pas de projet-- + show_in_days: Afficher dans %{days} jours error_saving_recurring: "Il s'est produit une erreur lors de la sauvegarde de la t\xC3\xA2che r\xC3\xA9currente \\'%{description}\\'" completed_more_than_x_days_ago: "Compl\xC3\xA9t\xC3\xA9 il y a plus de %{count} jours" - all_completed: "Toutes les actions r\xC3\xA9alis\xC3\xA9es" - feed_title_in_context: dans le contexte '%{context}' new_related_todo_created_short: "\xC3\xA0 cr\xC3\xA9\xC3\xA9 une nouvelle t\xC3\xA2che" + all_completed: "Toutes les actions r\xC3\xA9alis\xC3\xA9es" edit: Modifier + completed_actions_with: "Action compl\xC3\xA9t\xC3\xA9es avec le tag %{tag_name}" older_than_days: Plus ancien que %{count} jours completed_tagged_page_title: "TRACKS::Les t\xC3\xA2ches termin\xC3\xA9es avec marquer %{tag_name}" pending: En attente - completed_actions_with: "Action compl\xC3\xA9t\xC3\xA9es avec le tag %{tag_name}" - deleted_success: "Action supprim\xC3\xA9e avec succ\xC3\xA8s." completed_tasks_title: "TRACKS::T\xC3\xA2ches compl\xC3\xA9t\xC3\xA9es" + deleted_success: "Action supprim\xC3\xA9e avec succ\xC3\xA8s." feed_title_in_project: dans le projet '%{project}' clear_due_date: "Effacer la date d'\xC3\xA9ch\xC3\xA9ance" error_removing_dependency: "Il s'est produit une erreur lors de la suppression de la d\xC3\xA9pendance" @@ -449,20 +461,21 @@ fr: deferred_actions_with: "Action report\xC3\xA9es avec le tag '%{tag_name}'" confirm_delete: "Etes-vous s\xC3\xBBr de vouloir supprimer l'action '%{description}' ?" recurring_deleted_success: "L'action r\xC3\xA9currente a \xC3\xA9t\xC3\xA9 supprim\xC3\xA9e avec succ\xC3\xA8s." - clear_show_from_date: Effacer show from date + no_completed_actions_with: "Pas d'actions compl\xC3\xA9t\xC3\xA9es avec le tag '%{tag_name}'" next_actions_title: Tracks - Prochaines Actions next_action_description: Description de la prochaine action deferred_tasks_title: TRACKS::Reporteur - no_completed_actions_with: "Pas d'actions compl\xC3\xA9t\xC3\xA9es avec le tag '%{tag_name}'" - unresolved_dependency: "La valeur saisie dans le champ d\xC3\xA9pendance ne correspond pas \xC3\xA0 une action existante. Cette valeur ne sera pas sauvegard\xC3\xA9e avec le reste de l'action. Continuer ?" - calendar_page_title: TRACKS::Calendrier + clear_show_from_date: Effacer show from date in_hidden_state: "a l\\'\xC3\xA9tat cach\xC3\xA9" - show_today: Afficher aujourd'hui + see_all_completed: Vous pouvez voir toutes les actions accomplies %{link} + calendar_page_title: TRACKS::Calendrier + unresolved_dependency: "La valeur saisie dans le champ d\xC3\xA9pendance ne correspond pas \xC3\xA0 une action existante. Cette valeur ne sera pas sauvegard\xC3\xA9e avec le reste de l'action. Continuer ?" no_actions_found_title: "Aucune action trouv\xC3\xA9e" + show_today: Afficher aujourd'hui next_actions_due_date: overdue_by: "D\xC3\xA9pass\xC3\xA9e de %{days} jour" - due_today: "Ech\xC3\xA9ance aujourd'hui" due_in_x_days: "Ech\xC3\xA9ance dans %{days} days" + due_today: "Ech\xC3\xA9ance aujourd'hui" overdue_by_plural: "D\xC3\xA9pass\xC3\xA9e de %{days} jours" due_tomorrow: "Ech\xC3\xA9ance demain" completed_last_x_days: "Compl\xC3\xA9t\xC3\xA9 ces %{count} jours" @@ -479,24 +492,23 @@ fr: feeds: completed: "Compl\xC3\xA9t\xC3\xA9 : %{date}" due: "Ech\xC3\xA9ance : %{date}" - delete_action: Supprimer action - error_deleting_recurring: "Il s'est produit une erreur lors de la suppression de la t\xC3\xA2che r\xC3\xA9currente \\'%{description}\\'" recurring_todos: "T\xC3\xA2ches r\xC3\xA9currentes" + error_deleting_recurring: "Il s'est produit une erreur lors de la suppression de la t\xC3\xA2che r\xC3\xA9currente \\'%{description}\\'" + delete_action: Supprimer action delete: Supprimer + no_last_completed_actions: "Aucune action achev\xC3\xA9e trouve" drag_action_title: "D\xC3\xA9placer sur une autre action pour la rendre d\xC3\xA9pendante de cette action" cannot_add_dependency_to_completed_todo: "Impossible d'ajouter cette action comme d\xC3\xA9pendance d'une action compl\xC3\xA9t\xC3\xA9e !" - no_last_completed_actions: "Aucune action achev\xC3\xA9e trouve" depends_on: "D\xC3\xA9pend de" tickler_items_due: one: "Un \xC3\xA9l\xC3\xA9ment du reporteur est arriv\xC3\xA9 \xC3\xA0 \xC3\xA9ch\xC3\xA9ance - rafraichir la page pour le voir." other: "%{count} \xC3\xA9l\xC3\xA9ments du reporteur sont arriv\xC3\xA9s \xC3\xA0 \xC3\xA9ch\xC3\xA9ance - rafraichir la page pour les voir." action_marked_complete: "L'action '%{description}' a \xC3\xA9t\xC3\xA9 marqu\xC3\xA9e comme %{completed}" - completed_today: - one: "Vous avez compl\xC3\xA9t\xC3\xA9 une action aujourd'hui" - other: "Vous avez compl\xC3\xA9t\xC3\xA9 %{count} action aujourd'hui" + completed_today: "otherVous avez compl\xC3\xA9t\xC3\xA9 %{count} action aujourd'huioneVous avez compl\xC3\xA9t\xC3\xA9 une action aujourd'hui" added_new_next_action_plural: "Nouvelles actions suivantes ajout\xC3\xA9es" new_related_todo_not_created_short: "n'a pas cr\xC3\xA9\xC3\xA9 la t\xC3\xA2che" completed_rest_of_week: "Compl\xC3\xA9t\xC3\xA9 dans le reste de cette semaine" + show_tomorrow: Afficher demain error_starring: "Impossible d'actionner l'\xC3\xA9toile de cette tache \\'%{description}\\'" calendar: get_in_ical_format: Obtenir ce calendrier au format iCal @@ -509,9 +521,7 @@ fr: no_actions_due_after_this_month: "Pas d'actions \xC3\xA0 r\xC3\xA9aliser apr\xC3\xA8s ce mois" no_actions_due_this_month: "Pas d'actions \xC3\xA0 terminer pour ce mois" due_this_month: "A r\xC3\xA9aliser avant la fin de %{month}" - show_tomorrow: Afficher demain - tagged_page_title: "TRACKS::Tagg\xC3\xA9 avec %{tag_name}'" - action_deferred: "L'action '%{description}' a \xC3\xA9t\xC3\xA9 report\xC3\xA9" + no_completed_recurring: "Il n'y a pas d'actions r\xC3\xA9currentes compl\xC3\xA9t\xC3\xA9es actuellement" recurrence: ends_on_date: Fini le %{date} every_work_day: "Chaque jour ouvr\xC3\xA9" @@ -520,11 +530,13 @@ fr: weekly_options: "Param\xC3\xA8tres pour les actions r\xC3\xA9currentes hebdomadaires" weekly: Toutes les semaines monthly_options: "Param\xC3\xA8tres pour les actions r\xC3\xA9currentes mensuelles" + daily_options: "Param\xC3\xA8tres des actions r\xC3\xA9currentes quotidiennes" monthly: Mensuellement starts_on: "D\xC3\xA9marre le" - daily_options: "Param\xC3\xA8tres des actions r\xC3\xA9currentes quotidiennes" daily: Quotidiennement + show_option_always: toujours pattern: + third: "troisi\xC3\xA8me" month_names: - - Janvier @@ -539,17 +551,20 @@ fr: - Octobre - Novembre - "D\xC3\xA9cembre" - third: "troisi\xC3\xA8me" every_n: tous les %{n} - every_xth_day_of_every_n_months: tous les %{x} %{day} tous les %{n_months} second: seconde + every_xth_day_of_every_n_months: tous les %{x} %{day} tous les %{n_months} on_day_n: le %{n}e jour weekly: Toutes les semaines from: de - every_day: chaque jour last: dernier - times: pour %{number} fois + every_day: chaque jour the_xth_day_of_month: le %{x} %{day} de %{month} + times: pour %{number} fois + first: premier + show: montrer + every_year_on: "chaque ann\xC3\xA9e le %{date}" + on_work_days: "les jours ouvr\xC3\xA9s" day_names: - Dimanche - Lundi @@ -558,43 +573,40 @@ fr: - Jeudi - Vendredi - Samedi - show: montrer - first: premier - every_year_on: "chaque ann\xC3\xA9e le %{date}" - on_work_days: "les jours ouvr\xC3\xA9s" fourth: "quatri\xC3\xA8me" due: "Ech\xC3\xA9ance" every_month: chaque mois until: jusqu'a - show_option_always: toujours yearly_every_x_day: Chaque %{month} %{day} recurrence_on_options: "Activer la r\xC3\xA9currence" daily_every_number_day: Tous les %{number} jour(s) - ends_on: Fini le show_options: "Montrer la t\xC3\xA2che" weekly_every_number_week: Returns every %{number} week on + ends_on: Fini le show_days_before: "%{days} jours avant la date d'\xC3\xA9ch\xC3\xA9ance de la t\xC3\xA2che" - yearly_every_xth_day: Chaque %{day} %{day_of_week} de %{month} from_tickler: "la date de la t\xC3\xA2che provient du reporteur (pas de date d\\'\xC3\xA9ch\xC3\xA9ance d\xC3\xA9finie)" no_end_date: Pas de date de fin day_x_on_every_x_month: Le %{day} tous les %{month} mois + yearly_every_xth_day: Chaque %{day} %{day_of_week} de %{month} yearly_options: "Param\xC3\xA8tres pour les actions r\xC3\xA9currentes annuelles" yearly: Tous les ans monthly_every_xth_day: Le %{day} %{day_of_week} tous les %{month} mois - no_completed_recurring: "Il n'y a pas d'actions r\xC3\xA9currentes compl\xC3\xA9t\xC3\xA9es actuellement" + action_deferred: "L'action '%{description}' a \xC3\xA9t\xC3\xA9 report\xC3\xA9" + tagged_page_title: "TRACKS::Tagg\xC3\xA9 avec %{tag_name}'" added_dependency: "%{dependency} ajout\xC3\xA9e comme d\xC3\xA9pendance" - no_deferred_actions: "Il n'y a pas d'actions report\xC3\xA9es actuellement" - all_completed_tagged_page_title: "TRACKS::Toutes les t\xC3\xA2ches accomplies par marquer %{tag_name}" completed_rest_of_month: "Compl\xC3\xA9t\xC3\xA9 dans le reste de ce mois-ci" + all_completed_tagged_page_title: "TRACKS::Toutes les t\xC3\xA2ches accomplies par marquer %{tag_name}" + no_deferred_actions: "Il n'y a pas d'actions report\xC3\xA9es actuellement" recurrence_completed: "Il n'y a pas d'action suivante apr\xC3\xA8s l'action r\xC3\xA9currente que vous venez de terminer. Fin de la r\xC3\xA9currence" - error_toggle_complete: "Impossible de marquer cette tache comme compl\xC3\xA9t\xC3\xA9e" - due: "Ech\xC3\xA9ance" + action_marked_complete_error: "L'action '%{description}' n'a PAS \xC3\xA9t\xC3\xA9 marqu\xC3\xA9e comme %{completed} a cause d'une erreur sur le serveur " no_actions_found: "Il n'y pas d'actions incompl\xC3\xA8tes actuellement." in_pending_state: en attente - action_marked_complete_error: "L'action '%{description}' n'a PAS \xC3\xA9t\xC3\xA9 marqu\xC3\xA9e comme %{completed} a cause d'une erreur sur le serveur " - depends_on_separate_with_commas: "D\xC3\xA9pend de (s\xC3\xA9parer avec des virgules)" + error_toggle_complete: "Impossible de marquer cette tache comme compl\xC3\xA9t\xC3\xA9e" + due: "Ech\xC3\xA9ance" + no_incomplete_actions: "Il n'y a pas d'actions incompl\xC3\xA8tes" action_saved_to_tickler: "Action sauvegard\xC3\xA9e dans le Reporteur" recurring_action_saved: "Action r\xC3\xA9currente sauv\xC3\xA9e" + depends_on_separate_with_commas: "D\xC3\xA9pend de (s\xC3\xA9parer avec des virgules)" completed_in_archive: one: "Il n'y a pas d'action compl\xC3\xA9t\xC3\xA9e dans l'archive" other: "Il y a %{count} actions compl\xC3\xA9t\xC3\xA9es dans l'archive" @@ -604,100 +616,126 @@ fr: due_date: "avec au plus la date d'\xC3\xA9ch\xC3\xA9ance %{due_date}" overdue: En retard add_new_recurring: "Ajouter une nouvelle action r\xC3\xA9currente" - no_incomplete_actions: "Il n'y a pas d'actions incompl\xC3\xA8tes" notes: delete_note_title: Supprimer la note '%{id}' delete_confirmation: Etes-vous sur de vouloir supprimer la note '%{id}' ? in_project: "Dans:" delete_item_title: "Supprimer l'\xC3\xA9l\xC3\xA9ment" + deleted_note: Supprimer la note '%{id}' note_link_title: Voir note %{id} show_note_title: Voir note - deleted_note: Supprimer la note '%{id}' edit_item_title: "Modifier l'\xC3\xA9l\xC3\xA9ment" note_location_link: "ln:" no_notes_available: "Il n'y a actuellement aucune note: ajouter des notes aux projets sur les pages individuelles des projets." note_header: Note %{id} delete_note_confirm: Etes-vous sur de vouloir supprimer la note '%{id}' ? + projects: + default_context_set: "D\xC3\xA9finir le contexte par d\xC3\xA9faut du projet \xC3\xA0 %{default_context}" + no_actions_in_project: "Il n'y pas d'action incompl\xC3\xA8tes pour ce projet" + deferred_actions: "Actions report\xC3\xA9es pour ce projet" + was_marked_hidden: "est cach\xC3\xA9" + edit_project_title: Editer le projet + default_tags_removed_notice: Supprimer les tags par defaut + page_title: "TRACKS::Projet: %{project}" + all_completed_tasks_title: "TRACKS::Tous les Actions Achev\xC3\xA9 en Projet '%{project_name}'" + hide_form: Cacher le formulaire + list_completed_projects: "TRACKS::Liste des projets achev\xC3\xA9s" + no_notes_attached: "Il n'y a actuellement aucune note attach\xC3\xA9e \xC3\xA0 ce projet" + to_new_project_page: "Aller \xC3\xA0 la page du nouveau projet" + show_form_title: "Cr\xC3\xA9er un nouveau projet" + deferred_actions_empty: "Il n'y a pas d'actions report\xC3\xA9es pour ce projet" + project_state: Le projet est %{state} + this_project: Ce projet + no_last_completed_projects: "Pas de projets termin\xC3\xA9s trouv\xC3\xA9s" + no_last_completed_recurring_todos: "Non termin\xC3\xA9 actions r\xC3\xA9p\xC3\xA9titives trouv\xC3\xA9es" + notes: Notes + todos_append: dans ce projet + list_reviews: TRACKS::Revue + notes_empty: Il n'y a pas de notes pour ce projet + no_projects: Il n'y a actuellement aucun projet + hide_form_title: Cacher le formulaire nouveau projet + delete_project: Supprimer projet + completed_actions_empty: "Il n'y a pas d'actions r\xC3\xA9alis\xC3\xA9es pour ce projet" + with_no_default_context: "sans contexte par d\xC3\xA9faut" + delete_project_confirmation: "Etes vous s\xC3\xBBr de vouloir supprimer le projet '%{name}' ?" + with_default_context: "avec '%{context_name}' comme contexte par d\xC3\xA9faut" + show_form: Ajouter un projet + actions_in_project_title: Actions pour ce projet + completed_projects: "Projets r\xC3\xA9alis\xC3\xA9s" + is_active: est actif + add_note: Ajouter une note + set_default_tags_notice: "D\xC3\xA9finir les tags par d\xC3\xA9faut du projet \xC3\xA0 %{default_tags}" + add_project: Ajouter projet + settings: "Param\xC3\xA8tres" + project_saved_status: "Projet sauvegard\xC3\xA9" + list_projects: TRACKS::Liste des Projets + with_default_tags: et avec '%{tags'} comme tags par defaut + completed_tasks_title: "TRACKS::Liste des actions men\xC3\xA9es \xC3\xA0 terme dans Projet '%{project_name}'" + hidden_projects: "Projets cach\xC3\xA9s" + delete_project_title: Supprimer le projet + default_context_removed: "Contexte par d\xC3\xA9faut supprim\xC3\xA9" + add_note_submit: Ajouter note + completed_actions: "Actions r\xC3\xA9alis\xC3\xA9es pour ce projet" + was_marked_complete: "est compl\xC3\xA9t\xC3\xA9" + no_default_context: Ce projet n'a pas de contexte par defaut + with_no_default_tags: "et sans tags par d\xC3\xA9faut" + default_context: "Le contexte par d\xC3\xA9faut pour ce projet est %{context}" + edit_project_settings: "Modifier les param\xC3\xA8tres du projet" + status_project_name_changed: "Le nom du projet a \xC3\xA9t\xC3\xA9 modifi\xC3\xA9" + state: Le projet est %{state} + active_projects: Projets actifs states: hidden_plural: "Cach\xC3\xA9s" + stalled: "Bloqu\xC3\xA9s" review_plural: !binary | RGF0w6ll - stalled: "Bloqu\xC3\xA9s" completed: "Complet\xC3\xA9" current: Up-to-date - completed_plural: "Complet\xC3\xA9s" review: !binary | RGF0w6ll + completed_plural: "Complet\xC3\xA9s" blocked: "Bloqu\xC3\xA9e" blocked_plural: "Bloqu\xC3\xA9e" stalled_plural: "Bloqu\xC3\xA9s" visible_plural: Visibles active_plural: Actifs visible: Visible - current_plural: Up-to-date hidden: !binary | Q2FjaMOp active: Actif - projects: - was_marked_hidden: "est cach\xC3\xA9" - edit_project_title: Editer le projet - default_tags_removed_notice: Supprimer les tags par defaut - default_context_set: "D\xC3\xA9finir le contexte par d\xC3\xA9faut du projet \xC3\xA0 %{default_context}" - no_actions_in_project: "Il n'y pas d'action incompl\xC3\xA8tes pour ce projet" - deferred_actions: "Actions report\xC3\xA9es pour ce projet" - all_completed_tasks_title: "TRACKS::Tous les Actions Achev\xC3\xA9 en Projet '%{project_name}'" - page_title: "TRACKS::Projet: %{project}" - hide_form: Cacher le formulaire - no_notes_attached: "Il n'y a actuellement aucune note attach\xC3\xA9e \xC3\xA0 ce projet" - show_form_title: "Cr\xC3\xA9er un nouveau projet" - deferred_actions_empty: "Il n'y a pas d'actions report\xC3\xA9es pour ce projet" - this_project: Ce projet - project_state: Le projet est %{state} - list_completed_projects: "TRACKS::Liste des projets achev\xC3\xA9s" - to_new_project_page: "Aller \xC3\xA0 la page du nouveau projet" - no_last_completed_recurring_todos: "Non termin\xC3\xA9 actions r\xC3\xA9p\xC3\xA9titives trouv\xC3\xA9es" - todos_append: dans ce projet - no_last_completed_projects: "Pas de projets termin\xC3\xA9s trouv\xC3\xA9s" - notes: Notes - notes_empty: Il n'y a pas de notes pour ce projet - no_projects: Il n'y a actuellement aucun projet - hide_form_title: Cacher le formulaire nouveau projet - list_reviews: TRACKS::Revue - delete_project: Supprimer projet - completed_actions_empty: "Il n'y a pas d'actions r\xC3\xA9alis\xC3\xA9es pour ce projet" - with_no_default_context: "sans contexte par d\xC3\xA9faut" - show_form: Ajouter un projet - actions_in_project_title: Actions pour ce projet - delete_project_confirmation: "Etes vous s\xC3\xBBr de vouloir supprimer le projet '%{name}' ?" - with_default_context: "avec '%{context_name}' comme contexte par d\xC3\xA9faut" - add_note: Ajouter une note - add_project: Ajouter projet - with_default_tags: et avec '%{tags'} comme tags par defaut - is_active: est actif - list_projects: TRACKS::Liste des Projets - settings: "Param\xC3\xA8tres" - completed_projects: "Projets r\xC3\xA9alis\xC3\xA9s" - set_default_tags_notice: "D\xC3\xA9finir les tags par d\xC3\xA9faut du projet \xC3\xA0 %{default_tags}" - project_saved_status: "Projet sauvegard\xC3\xA9" - delete_project_title: Supprimer le projet - hidden_projects: "Projets cach\xC3\xA9s" - completed_tasks_title: "TRACKS::Liste des actions men\xC3\xA9es \xC3\xA0 terme dans Projet '%{project_name}'" - was_marked_complete: "est compl\xC3\xA9t\xC3\xA9" - completed_actions: "Actions r\xC3\xA9alis\xC3\xA9es pour ce projet" - default_context_removed: "Contexte par d\xC3\xA9faut supprim\xC3\xA9" - add_note_submit: Ajouter note - edit_project_settings: "Modifier les param\xC3\xA8tres du projet" - status_project_name_changed: "Le nom du projet a \xC3\xA9t\xC3\xA9 modifi\xC3\xA9" - active_projects: Projets actifs - default_context: "Le contexte par d\xC3\xA9faut pour ce projet est %{context}" - state: Le projet est %{state} - no_default_context: Ce projet n'a pas de contexte par defaut - with_no_default_tags: "et sans tags par d\xC3\xA9faut" + current_plural: Up-to-date errors: user_unauthorized: "401 Non autoris\xC3\xA9: Administrateur seulement." + preferences: + open_id_url: Votre URL OpenID est + change_identity_url: "Modifier votre URL d'identit\xC3\xA9" + staleness_starts_after: "\"date de fraicher\" d\xC3\xA9pass\xC3\xA9e \xC3\xA0 pr\xC3\xA8s %{days} days" + page_title: "TRACKS::Pr\xC3\xA9f\xC3\xA9rences" + change_password: Modifier votre mot de passe + token_description: Jeton (pour flux et utilisation API) + title: "Vos pr\xC3\xA9f\xC3\xA9rences" + is_false: faux + show_number_completed: "Montrer %{number} items r\xC3\xA9alis\xC3\xA9s" + password_changed: "Votre mot de passe a \xC3\xA9t\xC3\xA9 chang\xC3\xA9, s'il vous pla\xC3\xAEt vous connecter \xC3\xA0 nouveau." + edit_preferences: "Editer les pr\xC3\xA9f\xC3\xA9rences" + page_title_edit: "TRACKS::Editer les pr\xC3\xA9f\xC3\xA9rences" + is_true: vrai + sms_context_none: Aucun + generate_new_token: "G\xC3\xA9n\xC3\xA9rer un nouveau jeton" + token_header: Votre jeton + authentication_header: Votre authentification + updated: "Pr\xC3\xA9f\xC3\xA9rences jour" + current_authentication_type: Votre type d'authentification est %{auth_type} + change_authentication_type: Modifier votre type d'authentification + generate_new_token_confirm: "Etes vous s\xC3\xBBr ? G\xC3\xA9n\xC3\xA9rer un nouveau jeton va remplacer le jeton existant et en interdire les utilisations externes." + tabs: + authentication: Authentification + tracks_behavior: Comportements Tracks + profile: Profil + date_and_time: Date et heure time: am: am formats: @@ -708,33 +746,6 @@ fr: month_day: "%B %d" long: "%B %d, %Y %H:%M" pm: pm - preferences: - change_identity_url: "Modifier votre URL d'identit\xC3\xA9" - open_id_url: Votre URL OpenID est - staleness_starts_after: "\"date de fraicher\" d\xC3\xA9pass\xC3\xA9e \xC3\xA0 pr\xC3\xA8s %{days} days" - page_title: "TRACKS::Pr\xC3\xA9f\xC3\xA9rences" - change_password: Modifier votre mot de passe - token_description: Jeton (pour flux et utilisation API) - title: "Vos pr\xC3\xA9f\xC3\xA9rences" - is_false: faux - show_number_completed: "Montrer %{number} items r\xC3\xA9alis\xC3\xA9s" - edit_preferences: "Editer les pr\xC3\xA9f\xC3\xA9rences" - page_title_edit: "TRACKS::Editer les pr\xC3\xA9f\xC3\xA9rences" - is_true: vrai - password_changed: "Votre mot de passe a \xC3\xA9t\xC3\xA9 chang\xC3\xA9, s'il vous pla\xC3\xAEt vous connecter \xC3\xA0 nouveau." - sms_context_none: Aucun - generate_new_token: "G\xC3\xA9n\xC3\xA9rer un nouveau jeton" - token_header: Votre jeton - authentication_header: Votre authentification - updated: "Pr\xC3\xA9f\xC3\xA9rences jour" - current_authentication_type: Votre type d'authentification est %{auth_type} - change_authentication_type: Modifier votre type d'authentification - generate_new_token_confirm: "Etes vous s\xC3\xBBr ? G\xC3\xA9n\xC3\xA9rer un nouveau jeton va remplacer le jeton existant et en interdire les utilisations externes." - tabs: - tracks_behavior: Comportements Tracks - authentication: Authentification - profile: Profil - date_and_time: Date et heure date: month_names: - @@ -821,8 +832,8 @@ fr: send_feedback: Envoyer un feedback sur %{version} shared: multiple_next_actions: Actions suivante multiples (une sur chaque ligne) - toggle_single: Ajouter action suivante make_actions_dependent: "Faire actions d\xC3\xA9pendantes les unes des autres" + toggle_single: Ajouter action suivante hide_form: Cacher le formulaire add_actions: Ajouter actions add_action: Ajouter action @@ -835,6 +846,30 @@ fr: add_context: Ajouter Contexte toggle_multi_title: Basculer formulaire action simple/multiple hide_action_form_title: Cacher le formulaire nouvelle action + feedlist: + choose_context: Choisir le contexte dont vous voulez un flux + actions_due_today: Actions devant se terminer aujourd'hui ou avant + ical_feed: Flux iCal + legend: "L\xC3\xA9gende" + all_contexts: Tous les contextes + rss_feed: Flux RSS + choose_project: Choisir le projet dont vous voulez un flux + all_projects: Tous les projets + project_needed: Il faut au moins un projet pour le flux + select_feed_for_project: Selectionner le flux pour ce projet + active_projects_wo_next: Projets actifs avec aucune action suivante + active_starred_actions: "Toutes les actions pr\xC3\xA9ferr\xC3\xA9es actives" + context_needed: Il faut au moins un contexte pour le flux + select_feed_for_context: Selectionner un flux pour ce contexte + projects_and_actions: Projets actifs et leurs actions + notice_incomplete_only: "NB: Les flux ne montrent que les actions incompl\xC3\xA8tes, sauf indication contraire" + actions_due_next_week: Actions devant se terminer dans les 7 prochains jours ou moins + actions_completed_last_week: "Actions r\xC3\xA9alis\xC3\xA9es dans les 7 derniers jours" + context_centric_actions: "Flux des actions dans un contexte sp\xC3\xA9cifique" + plain_text_feed: Flux texte + last_fixed_number: "Derni\xC3\xA8res %{number} actions" + all_actions: Toutes les actions + project_centric: "Flux des actions incompl\xC3\xA8tes d'un projet sp\xC3\xA9cifique" sidebar: list_name_active_contexts: Contextes actifs list_name_active_projects: Projets actifs @@ -842,66 +877,14 @@ fr: list_name_completed_projects: "Projets r\xC3\xA9alis\xC3\xA9s" list_name_hidden_projects: "Projets cach\xC3\xA9s" list_name_hidden_contexts: "Contextes cach\xC3\xA9s" - feedlist: - actions_due_today: Actions devant se terminer aujourd'hui ou avant - choose_context: Choisir le contexte dont vous voulez un flux - rss_feed: Flux RSS - legend: "L\xC3\xA9gende" - ical_feed: Flux iCal - all_contexts: Tous les contextes - all_projects: Tous les projets - choose_project: Choisir le projet dont vous voulez un flux - project_needed: Il faut au moins un projet pour le flux - select_feed_for_project: Selectionner le flux pour ce projet - active_projects_wo_next: Projets actifs avec aucune action suivante - active_starred_actions: "Toutes les actions pr\xC3\xA9ferr\xC3\xA9es actives" - select_feed_for_context: Selectionner un flux pour ce contexte - projects_and_actions: Projets actifs et leurs actions - context_needed: Il faut au moins un contexte pour le flux - actions_due_next_week: Actions devant se terminer dans les 7 prochains jours ou moins - notice_incomplete_only: "NB: Les flux ne montrent que les actions incompl\xC3\xA8tes, sauf indication contraire" - context_centric_actions: "Flux des actions dans un contexte sp\xC3\xA9cifique" - plain_text_feed: Flux texte - last_fixed_number: "Derni\xC3\xA8res %{number} actions" - all_actions: Toutes les actions - actions_completed_last_week: "Actions r\xC3\xA9alis\xC3\xA9es dans les 7 derniers jours" - project_centric: "Flux des actions incompl\xC3\xA8tes d'un projet sp\xC3\xA9cifique" - contexts: - delete_context_title: Supprimer contexte - all_completed_tasks_title: "TRACKS::Toutes les actions Achev\xC3\xA9 en le contexte '%{context_name}'" - hide_form: Cacher le formulaire - show_form_title: Ajouter un contexte - todos_append: dans ce contexte - delete_context_confirmation: "Etes vous s\xC3\xBBr de vouloir supprimer le contexte %{name}? Toutes les actions (r\xC3\xA9p\xC3\xA9titives) de ce contexte seront \xC3\xA9galement supprim\xC3\xA9es !" - delete_context: Supprimer contexte - edit_context: Modifier contexte - hide_form_title: Cacher le formulaire nouveau contexte - hidden_contexts: "Contextes cach\xC3\xA9s" - no_contexts_active: Actuellement, il n'y a pas de contextes actifs - context_hide: "Cach\xC3\xA9 de la premi\xC3\xA8re page ?" - show_form: "Cr\xC3\xA9er un nouveau contexte" - visible_contexts: Contextes visibles - save_status_message: "Contexte sauvegard\xC3\xA9" - add_context: Ajouter un contexte - update_status_message: "Le nom du contexte \xC3\xA0 \xC3\xA9t\xC3\xA9 modifi\xC3\xA9" - context_name: Nom du Contexte - status_active: Le Contexte est actif - completed_tasks_title: "TRACKS::actions Achev\xC3\xA9 en le contexte '%{context_name}'" - new_context_post: "'sera aussi cr\xC3\xA9\xC3\xA9. Etes-vous s\xC3\xBBr ?" - no_actions: "Actuellement, il n'y pas d'actions incompl\xC3\xA8tes dans ce contexte" - last_completed_in_context: dans ce contexte (dernier %{number}) - context_deleted: "Contexte \\'%{name}\\' supprim\xC3\xA9" - no_contexts_hidden: "Actuellement, il n'y a pas de contextes cach\xC3\xA9s" - new_context_pre: Nouveau contexte ' - status_hidden: "Le Contexte est cach\xC3\xA9" users: - successfully_deleted_user: "Utilisateur %{username} supprim\xC3\xA9 avec succ\xC3\xA8s" + openid_url_verified: "Vous avez v\xC3\xA9rifi\xC3\xA9 avec succ\xC3\xA8s votre identit\xC3\xA9 comme %{url} et d\xC3\xA9fini votre type authentification comme OpenID" auth_type_update_error: "Un probl\xC3\xA8me est survenu lors de la modification du type d'authentification : %{error_messages}" failed_to_delete_user: "La suppression de l'utilisateur {username} \xC3\xA0 \xC3\xA9chou\xC3\xA9" destroy_successful: "Utilisateur %{login} supprim\xC3\xA9 avec succ\xC3\xA8s" - total_contexts: Total contextes first_user_heading: "Bienvenu \xC3\xA0 TRAKS. Pour commencer, veuillez cr\xC3\xA9er un compte administrateur" - openid_url_verified: "Vous avez v\xC3\xA9rifi\xC3\xA9 avec succ\xC3\xA8s votre identit\xC3\xA9 comme %{url} et d\xC3\xA9fini votre type authentification comme OpenID" + total_contexts: Total contextes + successfully_deleted_user: "Utilisateur %{username} supprim\xC3\xA9 avec succ\xC3\xA8s" signup_successful: "Utilisateur %{username} cr\xC3\xA9\xC3\xA9 avec succ\xC3\xA8s." new_token_generated: "Nouveau token g\xC3\xA9n\xC3\xA9r\xC3\xA9 avec succ\xC3\xA9s" total_projects: Total projets @@ -909,23 +892,23 @@ fr: no_signups_title: TRACKS::Pas de signups user_created: "Utilisateur cr\xC3\xA9\xC3\xA9." account_signup: "Cr\xC3\xA9er un compte" - password_updated: "Mot de passe modifi\xC3\xA9." manage_users: "G\xC3\xA9rer utilisateurs" - new_user_heading: "Cr\xC3\xA9er un nouvel utilisateur:" + password_updated: "Mot de passe modifi\xC3\xA9." auth_type_updated: "Type d'authentification modifi\xC3\xA9." total_actions: Total actions desired_login: "Login souhait\xC3\xA9" signup: "Cr\xC3\xA9ation" confirm_password: Confirmer le mot de passe - change_password_prompt: Entrer votre nouveau mot de passe dans les champs ci-dessous et cliquer sur 'Modifier mot de passe' pour remplacer votre mot de passe actuel par le nouveau. + new_user_heading: "Cr\xC3\xA9er un nouvel utilisateur:" password_confirmation_label: Confirmer mot de passe destroy_error: Une erreur s'est produite lors de la suppression de l'utilisateur %{login} choose_password: Choisir le mot de passe change_password_title: TRACKS::Modifier mot de passe change_auth_type_title: TRACKS::Modifier le type d'authentification + change_password_prompt: Entrer votre nouveau mot de passe dans les champs ci-dessous et cliquer sur 'Modifier mot de passe' pour remplacer votre mot de passe actuel par le nouveau. + new_password_label: Nouveau mot de passe register_with_cas: Avec votre nom d'utilisateur CAS label_auth_type: Type d'authentification - new_password_label: Nouveau mot de passe total_users_count: Vous avez %{count} utilisateurs new_user_title: "TRACKS::Cr\xC3\xA9er un administrateur" destroy_user: Supprimer utilisateur @@ -936,18 +919,46 @@ fr: openid_ok_pref_failed: "Vous avez v\xC3\xA9rifi\xC3\xA9 avec succ\xC3\xA8s votre identit\xC3\xA9 comme %{url} mais un probl\xC3\xA8me est survenu lors de la sauvegarde de vos pr\xC3\xA9f\xC3\xA9rences d'authentification." auth_change_submit: Modifier le type d'authenfication change_authentication_type: Modifier le type d'authentification - select_authentication_type: "S\xC3\xA9lectionner votre nouveau type d'authentification et cliquer sur 'Modifier type d'authenfication' pour remplacer les param\xC3\xA8tres actuels." total_notes: Total notes + select_authentication_type: "S\xC3\xA9lectionner votre nouveau type d'authentification et cliquer sur 'Modifier type d'authenfication' pour remplacer les param\xC3\xA8tres actuels." + contexts: + delete_context_title: Supprimer contexte + all_completed_tasks_title: "TRACKS::Toutes les actions Achev\xC3\xA9 en le contexte '%{context_name}'" + hide_form: Cacher le formulaire + show_form_title: Ajouter un contexte + delete_context_confirmation: "Etes vous s\xC3\xBBr de vouloir supprimer le contexte %{name}? Toutes les actions (r\xC3\xA9p\xC3\xA9titives) de ce contexte seront \xC3\xA9galement supprim\xC3\xA9es !" + todos_append: dans ce contexte + delete_context: Supprimer contexte + edit_context: Modifier contexte + hide_form_title: Cacher le formulaire nouveau contexte + hidden_contexts: "Contextes cach\xC3\xA9s" + no_contexts_active: Actuellement, il n'y a pas de contextes actifs + context_hide: "Cach\xC3\xA9 de la premi\xC3\xA8re page ?" + add_context: Ajouter un contexte + show_form: "Cr\xC3\xA9er un nouveau contexte" + save_status_message: "Contexte sauvegard\xC3\xA9" + visible_contexts: Contextes visibles + update_status_message: "Le nom du contexte \xC3\xA0 \xC3\xA9t\xC3\xA9 modifi\xC3\xA9" + context_name: Nom du Contexte + status_active: Le Contexte est actif + completed_tasks_title: "TRACKS::actions Achev\xC3\xA9 en le contexte '%{context_name}'" + new_context_post: "'sera aussi cr\xC3\xA9\xC3\xA9. Etes-vous s\xC3\xBBr ?" + new_context_pre: Nouveau contexte ' + no_actions: "Actuellement, il n'y pas d'actions incompl\xC3\xA8tes dans ce contexte" + last_completed_in_context: dans ce contexte (dernier %{number}) + context_deleted: "Contexte \\'%{name}\\' supprim\xC3\xA9" + no_contexts_hidden: "Actuellement, il n'y a pas de contextes cach\xC3\xA9s" + status_hidden: "Le Contexte est cach\xC3\xA9" login: - login_cas: Aller au CAS openid_identity_url_not_found: "D\xC3\xA9sol\xC3\xA9, aucun utilisateur avec cette identit\xC3\xA9 URL n'existe (%{identity_url})" user_no_expiry: "Rester connect\xC3\xA9" sign_in: Se connecter - please_login: Veuillez vous connecter pour utiliser Tracks - cas_logged_in_greeting: "Bonjour, %{username}! Vous \xC3\xAAtes authentifi\xC3\xA9." + login_cas: Aller au CAS cas_no_user_found: Bonjour, %{username}! Vous n'avez pas de compte sur Tracks. cas_login: Login CAS successful_with_session_info: "La connexion \xC3\xA0 r\xC3\xA9ussi:" + please_login: Veuillez vous connecter pour utiliser Tracks + cas_logged_in_greeting: "Bonjour, %{username}! Vous \xC3\xAAtes authentifi\xC3\xA9." cas_username_not_found: "D\xC3\xA9sol\xC3\xA9, aucun utilisateur avec ce nom CAS n'existe (%{username})" cas_create_account: "Si vous voulez vous inscrire aller \xC3\xA0 %{signup_link}" mobile_use_openid: ... ou ce connecter avec un OpenID @@ -959,10 +970,10 @@ fr: session_time_out: "La session \xC3\xA0 expir\xC3\xA9. Merci de %{link}" session_will_expire: "la session expire apr\xC3\xA8s %{hours} heure(s) d'inactivit\xC3\xA9." login_standard: "retourner \xC3\xA0 l'\xC3\xA9cran de connexion standard" - log_in_again: Se reconnecter - logged_out: "Vous avez \xC3\xA9t\xC3\xA9 d\xC3\xA9connect\xC3\xA9 de Tracks." login_with_openid: se connecter avec un OpenID unsuccessful: "La connexion \xC3\xA0 \xC3\xA9chou\xC3\xA9." + log_in_again: Se reconnecter + logged_out: "Vous avez \xC3\xA9t\xC3\xA9 d\xC3\xA9connect\xC3\xA9 de Tracks." datetime: prompts: minute: Minute @@ -1013,7 +1024,7 @@ fr: search: contexts_matching_query: "Contextes correspondant \xC3\xA0 la requ\xC3\xAAte" tags_matching_query: "Tags correspondant \xC3\xA0 la requ\xC3\xAAte" + no_results: "Aucun r\xC3\xA9sultat \xC3\xA0 votre recherche." todos_matching_query: "AFaire (todos) correspondant \xC3\xA0 la requ\xC3\xAAte" projects_matching_query: "Projets correspondant \xC3\xA0 la requ\xC3\xAAte" notes_matching_query: "Notes correspondant \xC3\xA0 la requ\xC3\xAAte" - no_results: "Aucun r\xC3\xA9sultat \xC3\xA0 votre recherche." diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 06c616e1..9da89e90 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -1,5 +1,54 @@ --- nl: + layouts: + toggle_contexts_title: Maak ingeklapte contexten (on)zichtbaar + toggle_contexts: Toggle ingeklapte contexten + toggle_notes: Toggle notities + next_actions_rss_feed: RSS-feed van de acties + toggle_notes_title: Toggle alle notities + mobile_navigation: + new_action: Nieuwe actie + logout: Afmelden + feeds: Feeds + starred: Ster + projects: Projecten + tickler: Tickler + contexts: Contexten + home: Start + navigation: + manage_users_title: Toevoegen of verwijderen gebruikers + recurring_todos: Terugkerende acties + api_docs: REST API Docs + help: "?" + feeds: Feeds + starred: Ster + stats: Statistieken + notes_title: Toon alle notities + manage_users: Beheren gebruikers + tickler_title: Tickler + admin: Admin + preferences: Voorkeuren + integrations_: Integreer Tracks + export_title: Import en export van gegevens + calendar_title: Kalender met acties met deadline + feeds_title: Zie een lijst met beschikbare feeds + stats_title: Zie je statistieken + tickler: Tickler + home_title: Start + starred_title: Zie je ster acties + recurring_todos_title: Beheren terugkerende acties + completed_tasks: Gereed + organize: Organiseer + view: Bekijk + completed_tasks_title: Afgerond + home: Start + export: Export + contexts_title: Contexten + preferences_title: Toon mijn voorkeuren + search: Zoeken in alle items + review_title: Evaluatie uitvoeren + projects_title: Projecten + calendar: Agenda number: format: separator: "," @@ -23,58 +72,9 @@ nl: separator: "," delimiter: . - layouts: - toggle_contexts_title: Maak ingeklapte contexten (on)zichtbaar - toggle_notes: Toggle notities - toggle_contexts: Toggle ingeklapte contexten - next_actions_rss_feed: RSS-feed van de acties - toggle_notes_title: Toggle alle notities - mobile_navigation: - feeds: Feeds - new_action: Nieuwe actie - logout: Afmelden - starred: Ster - projects: Projecten - tickler: Tickler - contexts: Contexten - home: Start - navigation: - manage_users_title: Toevoegen of verwijderen gebruikers - api_docs: REST API Docs - recurring_todos: Terugkerende acties - feeds: Feeds - help: "?" - stats: Statistieken - starred: Ster - notes_title: Toon alle notities - manage_users: Beheren gebruikers - tickler_title: Tickler - admin: Admin - integrations_: Integreer Tracks - export_title: Import en export van gegevens - preferences: Voorkeuren - calendar_title: Kalender met acties met deadline - feeds_title: Zie een lijst met beschikbare feeds - completed_tasks: Gereed - stats_title: Zie je statistieken - home_title: Start - tickler: Tickler - starred_title: Zie je ster acties - recurring_todos_title: Beheren terugkerende acties - view: Bekijk - organize: Organiseer - completed_tasks_title: Afgerond - home: Start - contexts_title: Contexten - export: Export - preferences_title: Toon mijn voorkeuren - calendar: Agenda - review_title: Evaluatie uitvoeren - search: Zoeken in alle items - projects_title: Projecten common: - back: Terug recurring_todos: Herhalende acties + back: Terug actions: Acties third: Derde add: Toevoegen @@ -82,54 +82,65 @@ nl: go_back: Ga terug logout: Log uit second: Tweede - show_all: Toon alle none: Geen week: week optional: optioneel + deferred: uitgestelde + show_all: Toon alle cancel: Annuleer month: maand - actions_midsentence: acties + actions_midsentence: + one: actie + other: acties + zero: acties server_error: Een fout heeft op de server plaatsgevonden forum: Forum notes: Notities projects: Projecten last: Laatste - action: Actie review: Evaluatie + action: Actie + days_midsentence: + one: dag + other: dagen + zero: dagen project: Project - days_midsentence: dagen contribute: Bijdragen ok: Ok website: Website first: Eerste + note: + one: 1 notitie + other: "%{count} notities" + zero: geen notities numbered_step: Stap %{number} - errors_with_fields: Er waren problemen met de volgende velden create: Maken sort: by_task_count_title: Sorteer op aantal acties by_task_count_title_confirm: Weet u zeker dat u deze op aantal acties wilt sorteren? Dat zal de huidige sorteervolgorde aanpassen. alphabetically: Alfabetisch - alphabetically_title: Sorteer projecten alfabetisch sort: Sorteer + alphabetically_title: Sorteer projecten alfabetisch alphabetically_confirm: Weet u zeker dat u deze projecten alfabetisch wilt sorteren? Dat zal de huidige sorteervolgorde aanpassen. by_task_count: Op aantal acties - months: maanden - description: Beschrijving todo: actie + months: maanden + errors_with_fields: Er waren problemen met de volgende velden + description: Beschrijving next: Volgende fourth: Vierde + drag_handle: SLEEP context: Context contexts: Contexten - drag_handle: SLEEP + bugs: Fouten update: Bijwerken forth: Vierde weeks: weken wiki: Wiki - bugs: Fouten - ajaxError: Er is een fout opgetreden bij het ophalen van gegevens van de server - not_available_abbr: n/b email: E-mail + ajaxError: Er is een fout opgetreden bij het ophalen van gegevens van de server search: Zoeken + not_available_abbr: n/b integrations: opensearch_description: Zoek in Tracks applescript_next_action_prompt: "Omschrijving van de actie:" @@ -147,38 +158,38 @@ nl: created_at: Gemaakt op updated_at: Bijgewerkt op todo: - predecessors: Afhankelijkheden show_from: Tonen vanaf + predecessors: Afhankelijkheden notes: Notities tags: Labels project: Project description: Beschrijving context: Context due: Deadline - user: - last_name: Achternaam - first_name: Voornaam preference: show_hidden_projects_in_sidebar: Toon verborgen projecten in sidebar show_hidden_contexts_in_sidebar: Toon verborgen contexten in sidebar date_format: Datum formaat - verbose_action_descriptors: Context en project uitschrijven in actielijst sms_context: Standaard context voor email - staleness_starts: Begin van markeren openstaande actie + verbose_action_descriptors: Context en project uitschrijven in actielijst mobile_todos_per_page: Acties per pagina (mobiel) - title_date_format: Datum formaat in titel + staleness_starts: Begin van markeren openstaande actie show_number_completed: Aantal te tonen afgeronde acties + title_date_format: Datum formaat in titel refresh: Ververs interval (in minuten) week_starts: Week start op last_name: Achternaam - due_style: Deadline stijl locale: Taal + due_style: Deadline stijl time_zone: Tijdzone - show_project_on_todo_done: Ga naar project pagina wanneer actie gereed is sms_email: Van email - first_name: Voornaam + show_project_on_todo_done: Ga naar project pagina wanneer actie gereed is show_completed_projects_in_sidebar: Toon afgeronde projecten in sidebar + first_name: Voornaam review_period: Project evaluatie interval + user: + last_name: Achternaam + first_name: Voornaam errors: models: project: @@ -208,13 +219,13 @@ nl: taken: is al gepakt inclusion: is niet opgenomen in de lijst not_a_number: is niet een getal + full_messages: + format: "%{attribute} %{message}" template: body: Er waren problemen met de volgende velden header: one: 1 fout voorkomt het kunnen bewaren van deze %{model} other: "%{count} fouten voorkomen dat dit %{model} bewaard kan worden" - full_messages: - format: "%{attribute} %{message}" data: import_successful: De import was succesvol import_errors: Er hebben zich fouten voorgedaan bij de import @@ -224,21 +235,21 @@ nl: feed_description: Een overzicht van alle projecten voor %{username} todo: error_date_must_be_future: moet een datum in de toekomst zijn - user: - error_context_not_associated: Context %{context} niet geassocieerd met gebruikers %{user}. - error_project_not_associated: Project %{project} niet geassocieerd met gebruikers %{user}. preference: due_on: Deadline op %{date} due_in: Deadline over %{days} dagen due_styles: - Deadline over ____ dagen - Deadline op ____ + user: + error_context_not_associated: Context %{context} niet geassocieerd met gebruikers %{user}. + error_project_not_associated: Project %{project} niet geassocieerd met gebruikers %{user}. stats: - tag_cloud_title: Tag Cloud voor alle acties totals_hidden_context_count: en %{count} zijn verborgen contexten. actions_avg_created: In de afgelopen 12 maanden heeft u gemiddeld%{count} acties aangemaakt actions_min_max_completion_days: De max-/minimum dagen tot voltooiing is %{min}/%{max}. totals_actions_completed: "%{count} van deze zijn voltooid." + tag_cloud_title: Tag Cloud voor alle acties actions_actions_avg_created_30days: In de afgelopen 30 dagen heeft u gemiddeld %{count} acties gemaakt actions_avg_completed: en voltooide een gemiddelde van %{count} acties per maand. top5_visible_contexts_with_incomplete_actions: Top 5 zichtbare contexten met onvolledige acties @@ -254,11 +265,11 @@ nl: weeks: Looptijd van een actie (weken). Klik op een balk voor meer info totals_action_count: u heeft een totaal van %{count} acties tag_cloud_90days_title: Tag cloud met acties in afgelopen 90 dagen + actions_avg_completion_time: Van al uw afgeronde acties, de gemiddelde tijd dat dit in beslag nam is %{count} dagen. tod30: Tijd van de dag (laatste 30 dagen) tags: Tags projects: Projecten - actions_avg_completion_time: Van al uw afgeronde acties, de gemiddelde tijd dat dit in beslag nam is %{count} dagen. - actions_lastyear_title: Acties in de afgelopen 12 maanden + totals_completed_project_count: en %{count} zijn afgeronde projecten. labels: month_avg_completed: "%{months} gem afgerond per maand" completed: Afgerond @@ -267,8 +278,8 @@ nl: avg_completed: Gem afgerond created: Gemaakt actions_selected_from_week: Gekozen acties van week - totals_completed_project_count: en %{count} zijn afgeronde projecten. actions_day_of_week_title: Dag van de week (alle acties) + actions_lastyear_title: Acties in de afgelopen 12 maanden open_per_week: Active (zichtbare en verborgen) volgende acties per week action_selection_title: "TRACKS:: Actie selectie" totals_project_count: U heeft %{count} projecten. @@ -291,16 +302,16 @@ nl: actions_last_year_legend: number_of_actions: Aantal acties months_ago: Maanden geleden - top10_projects: Top 10 projecten top5_contexts: Top 5 contexten - click_to_return: Klik %{link} om terug te keren naar de statistieken pagina. - totals: Totalen + top10_projects: Top 10 projecten contexts: Contexten + totals: Totalen + click_to_return: Klik %{link} om terug te keren naar de statistieken pagina. tag_cloud_90days_description: Deze tag cloud bevat tags van acties die zijn gemaakt of voltooid in de afgelopen 90 dagen. totals_visible_context_count: Van deze zijn %{count} zichtbare contexten - actions_min_completion_time: De minimale tijd tot afronding is %{time}. top10_projects_30days: Top 10 project in de laatste 30 dagen running_time_all: Huidige looptijd van alle onvolledige acties + actions_min_completion_time: De minimale tijd tot afronding is %{time}. action_completion_time_title: Doorlooptijd (alle voltooide acties) click_to_show_actions_from_week: Klik %{link} om de acties van week %{week} en verder te zien. top10_longrunning: Top 10 langstlopende projecten @@ -312,14 +323,14 @@ nl: day_of_week: Dag van de week totals_first_action: Sinds uw eerste actie op %{date} tag_cloud_description: Deze tag cloud bevat tags van alle acties (afgerond, niet voltooid, zichtbaar en / of verborgen) + spread_of_actions_for_all_context: Verdeling van acties voor alle contexten click_to_update_actions: Klik op een balk in de grafiek op de acties hieronder aan te passen. click_to_return_link: hier - spread_of_actions_for_all_context: Verdeling van acties voor alle contexten more_stats_will_appear: Meer statistieken zullen hier verschijnen zodra u acties hebt toegevoegd. actions_avg_completed_30days: en voltooide een gemiddelde van %{count} acties per dag. + index_title: TRACKS::Statistiek actions_30days_title: Acties in de afgelopen 30 dagen no_tags_available: geen tags beschikbaar - index_title: TRACKS::Statistiek actions_dow_30days_title: Dag van de week (laatste 30 dagen) actions_day_of_week_legend: number_of_actions: Aantal acties @@ -335,19 +346,19 @@ nl: running_time: Looptijd van een actie (weken). Klik op een balk voor meer info percentage: Percentage other_actions_label: (anderen) - time_of_day: Tijd van de dag (alle acties) totals_hidden_project_count: "%{count} zijn verborgen" + time_of_day: Tijd van de dag (alle acties) todos: - completed_actions: Voltooide acties + recurring_action_deleted: Actie werd verwijderd. Omdat deze actie herhalend is. werd een nieuwe actie toegevoegd show_from: Toon vanaf error_starring_recurring: Kon niet de ster van deze terugkerende actie niet omzetten \'%{description}\' - recurring_action_deleted: Actie werd verwijderd. Omdat deze actie herhalend is. werd een nieuwe actie toegevoegd - completed_rest_of_previous_month: Afgerond in de rest van de vorige maand - completed_recurring: Afgesloten terugkerende todos + completed_actions: Voltooide acties added_new_next_action: Nieuwe actie toegevoegd + completed_recurring: Afgesloten terugkerende todos + completed_rest_of_previous_month: Afgerond in de rest van de vorige maand blocked_by: Geblokkeerd door %{predecessors} - completed_recurrence_completed: Er is geen actie na de terugkerende actie die u new verwijderd heeft. De herhaling is voltooid star_action: Markeer deze actie met een ster + completed_recurrence_completed: Er is geen actie na de terugkerende actie die u new verwijderd heeft. De herhaling is voltooid defer_date_after_due_date: Uitsteldatum is na de vervaldag. Gelieve vervaldag bewerken alvorens uitsteldatum aan te passen. unable_to_add_dependency: Niet in staat om de afhankelijkheid toe te voegen done: Voltooid? @@ -358,16 +369,16 @@ nl: no_hidden_actions: Momenteel zijn er geen verborgen acties gevonden edit_action_with_description: Bewerk de actie '%{description}' action_due_on: (deadline actie op %{date}) + list_incomplete_next_actions: Toon onvoltooide acties archived_tasks_title: "TRACKS:: Gearchiveerde voltooide taken" remove_dependency: Verwijder afhankelijkheid (zal niet de actie zelf verwijderen) - list_incomplete_next_actions: Toon onvoltooide acties - tags: Tags (gescheiden door komma's) action_deleted_success: Actie succesvol verwijderd - mobile_todos_page_title: Alle acties - new_related_todo_created: Een nieuwe actie is toegevoegd, die behoort bij deze terugkerende todo - context_changed: Context veranderd in '%{name}' - add_another_dependency: Nog een afhankelijkheid toevoegen + tags: Tags (gescheiden door komma's) delete_recurring_action_title: Verwijder de terugkerende actie + context_changed: Context veranderd in '%{name}' + new_related_todo_created: Een nieuwe actie is toegevoegd, die behoort bij deze terugkerende todo + mobile_todos_page_title: Alle acties + add_another_dependency: Nog een afhankelijkheid toevoegen removed_predecessor: "'%{successor}' is verwijderd als afhankelijkheid van '%{predecessor}'." recurring_actions_title: TRACKS::Terugkerende acties next_action_needed: U dient ten minste een actie in te vullen @@ -377,40 +388,41 @@ nl: edit_action: Actie bewerken added_new_context: Nieuwe context toegevoegd next_actions_description: "Filter:" + list_incomplete_next_actions_with_limit: Toont de laatste %{count} onvoltooide acties + set_to_pending: "'%{task}' als wachtend ingesteld" + added_new_project: Nieuw project toegevoegd next_actions_title_additions: completed: acties voltooid due_today: deadline vandaag due_within_a_week: deadline binnen een week - list_incomplete_next_actions_with_limit: Toont de laatste %{count} onvoltooide acties - set_to_pending: "'%{task}' als wachtend ingesteld" - added_new_project: Nieuw project toegevoegd older_completed_items: Oudere voltooide items - error_deleting_item: Er is een fout opgetreden bij het verwijderen van het item '%{description}' - edit_recurring_todo: Bewerk herhalende actie - append_in_this_project: in dit project - task_list_title: TRACKS::Toon acties no_actions_due_this_week: Geen acties met deadline in rest van deze week + all_completed_here: hier + append_in_this_project: in dit project + edit_recurring_todo: Bewerk herhalende actie + error_deleting_item: Er is een fout opgetreden bij het verwijderen van het item '%{description}' + task_list_title: TRACKS::Toon acties no_recurring_todos: Momenteel zijn er geen terugkerende acties error_completing_todo: Er was een fout bij het voltooien / activeren van de terugkerende actie '%{description}' recurring_pattern_removed: Het herhalingspatroon is verwijderd van %{count} convert_to_project: Maak project no_deferred_pending_actions: Momenteel zijn er geen uitgestelde of wachtende acties - completed_last_day: Voltooid in de laatste 24 uur delete_recurring_action_confirm: Weet u zeker dat u wilt de terugkerende actie '%{description}' wilt verwijderen? - show_in_days: Toon over %{days} dagen + completed_last_day: Voltooid in de laatste 24 uur + feed_title_in_context: in context '%{context}' no_project: -- Geen project -- + show_in_days: Toon over %{days} dagen error_saving_recurring: Er is een fout opgetreden het opslaan van de terugkerende actie '%{description}' completed_more_than_x_days_ago: Voltooid meer dan %{count} dagen geleden - all_completed: Alle afgeronde acties - feed_title_in_context: in context '%{context}' new_related_todo_created_short: een nieuwe actie gemaakt + all_completed: Alle afgeronde acties edit: Bewerken + completed_actions_with: Afgeronde acties met de tag %{tag_name} older_than_days: Ouder dan %{count} dagen completed_tagged_page_title: "TRACKS:: Afgeronde acties met tag %{tag_name}" pending: Wachtend - completed_actions_with: Afgeronde acties met de tag %{tag_name} - deleted_success: De actie werd met succes verwijderd. completed_tasks_title: TRACKS::Voltooide taken + deleted_success: De actie werd met succes verwijderd. feed_title_in_project: In het project '%{project}' clear_due_date: Maak deadline leeg error_removing_dependency: Er is een fout opgetreden het verwijderen van de afhankelijke actie @@ -421,20 +433,21 @@ nl: deferred_actions_with: Uitgestelde acties met de tag '%{tag_name}' confirm_delete: Weet u zeker dat u de actie '%{description}' wilt verwijderen? recurring_deleted_success: De recurrente actie is succesvol verwijderd. - clear_show_from_date: Maak de datum Tonen Vanaf leeg + no_completed_actions_with: Geen voltooide acties met de tag '%{tag_name}' next_actions_title: Tracks - Acties next_action_description: Actie beschrijving deferred_tasks_title: TRACKS::Tickler - no_completed_actions_with: Geen voltooide acties met de tag '%{tag_name}' - unresolved_dependency: De waarde die u ingevoerd heeft in het afhankelijkheden veld is niet herleidbaar naar een bestaande actie. Deze waarde wordt niet bewaard met de rest van de actie. Doorgaan? - calendar_page_title: TRACKS::Agenda + clear_show_from_date: Maak de datum Tonen Vanaf leeg in_hidden_state: in verborgen toestand - show_today: Toon vandaag + see_all_completed: Je kan alle afgeronde acties %{link} zien + calendar_page_title: TRACKS::Agenda + unresolved_dependency: De waarde die u ingevoerd heeft in het afhankelijkheden veld is niet herleidbaar naar een bestaande actie. Deze waarde wordt niet bewaard met de rest van de actie. Doorgaan? no_actions_found_title: Geen acties gevonden + show_today: Toon vandaag next_actions_due_date: overdue_by: Over deadline met %{days} dag - due_today: Deadline vandaag due_in_x_days: Deadline over %{days} dagen + due_today: Deadline vandaag overdue_by_plural: Over deadline met %{days} dagen due_tomorrow: Deadline morgen completed_last_x_days: Voltooid in de laatste %{count} dagen @@ -451,13 +464,13 @@ nl: feeds: completed: "Voltooid: %{date}" due: "Deadline: %{date}" - delete_action: Verwijder actie - error_deleting_recurring: Er is een fout opgetreden bij het verwijderen van het item \'%{description}\' recurring_todos: Terugkerende acties + error_deleting_recurring: Er is een fout opgetreden bij het verwijderen van het item \'%{description}\' + delete_action: Verwijder actie delete: Verwijder + no_last_completed_actions: Geen afgeronde acties gevonden drag_action_title: Sleep naar een andere actie om deze afhankelijk te maken van die actie cannot_add_dependency_to_completed_todo: Kan deze actie niet als een afhankelijkheid van een voltooide actie toevoegen! - no_last_completed_actions: Geen afgeronde acties gevonden depends_on: Hangt af van tickler_items_due: one: Een tickler item wordt nu zichtbaar - vernieuw de pagina om het te zien. @@ -467,6 +480,7 @@ nl: added_new_next_action_plural: Nieuwe acties toegevoegd new_related_todo_not_created_short: een nieuwe actie is niet gemaakt completed_rest_of_week: Afgerond in de rest van deze week + show_tomorrow: Toon morgen error_starring: Kon niet de ster van deze actie niet omzetten \'%{description}\' calendar: get_in_ical_format: Ontvang deze agenda in iCal-formaat @@ -479,9 +493,7 @@ nl: no_actions_due_after_this_month: Geen acties met deadline na deze maand no_actions_due_this_month: Geen acties met deadline in de rest van deze maand due_this_month: Deadline in rest van %{month} - show_tomorrow: Toon morgen - tagged_page_title: TRACKS::Tagged met '%{tag_name}' - action_deferred: De actie '%{description}' is uitgesteld + no_completed_recurring: Momenteel zijn er geen voltooide terugkerende acties recurrence: ends_on_date: Eindigt op %{date} every_work_day: Elke werkdag @@ -490,11 +502,13 @@ nl: weekly_options: Instellingen voor de wekelijkse terugkerende acties weekly: Wekelijks monthly_options: Instellingen voor maandelijks terugkerende acties + daily_options: Instellingen voor dagelijks terugkerende acties monthly: Maandelijks starts_on: Begint op - daily_options: Instellingen voor dagelijks terugkerende acties daily: Dagelijks + show_option_always: altijd pattern: + third: derde month_names: - - januari @@ -509,17 +523,20 @@ nl: - oktober - november - december - third: derde every_n: elke %{n} - every_xth_day_of_every_n_months: elke %{x} %{day} van elke %{n_months} second: tweede + every_xth_day_of_every_n_months: elke %{x} %{day} van elke %{n_months} on_day_n: op dag %{n} weekly: wekelijks from: vanaf - every_day: elke dag last: laatste - times: voor %{number} keer + every_day: elke dag the_xth_day_of_month: de %{x} %{day} van %{month} + times: voor %{number} keer + first: eerste + show: Tonen + every_year_on: elk jaar op %{date} + on_work_days: op werkdagen day_names: - zondag - maandag @@ -528,43 +545,40 @@ nl: - donderdag - vrijdag - zaterdag - show: Tonen - first: eerste - every_year_on: elk jaar op %{date} - on_work_days: op werkdagen fourth: vierde due: Deadline every_month: elke maand until: tot - show_option_always: altijd yearly_every_x_day: Elke %{month} %{day} recurrence_on_options: Stel herhaling in op daily_every_number_day: Elke %{number} dag(en) - ends_on: Eindigt op show_options: Toon de actie weekly_every_number_week: Herhaalt elke %{number} weken op + ends_on: Eindigt op show_days_before: "%{days} dagen v\xC3\xB3\xC3\xB3r de deadline van actie" - yearly_every_xth_day: De %{day} %{day_of_week} van %{month} from_tickler: de datum dat de actie uit de tickler komt (geen deadline ingesteld) no_end_date: Geen einddatum day_x_on_every_x_month: Dag %{day} op elke %{month} maand + yearly_every_xth_day: De %{day} %{day_of_week} van %{month} yearly_options: Instellingen voor jaarlijks terugkerende acties yearly: Jaarlijks monthly_every_xth_day: De %{day} %{day_of_week} van elke %{month} maand - no_completed_recurring: Momenteel zijn er geen voltooide terugkerende acties + action_deferred: De actie '%{description}' is uitgesteld + tagged_page_title: TRACKS::Tagged met '%{tag_name}' added_dependency: "%{dependency} als afhankelijkheid toegevoegd." - no_deferred_actions: Momenteel zijn er geen uitgestelde acties. - all_completed_tagged_page_title: "TRACKS:: Alle afgeronde acties met tag %{tag_name}" completed_rest_of_month: Afgerond in de rest van deze maand + all_completed_tagged_page_title: "TRACKS:: Alle afgeronde acties met tag %{tag_name}" + no_deferred_actions: Momenteel zijn er geen uitgestelde acties. recurrence_completed: Er is geen volgende actie na de terugkerende actie die u zojuist hebt voltooid. De herhaling is voltooid - error_toggle_complete: Kon deze actie niet als afgerond markeren - due: Deadline + action_marked_complete_error: De actie '%{description}' is niet gemarkeerd als %{completed} vanwege een fout op de server. no_actions_found: Momenteel zijn er geen onafgeronde acties. in_pending_state: in wachtende toestand - action_marked_complete_error: De actie '%{description}' is niet gemarkeerd als %{completed} vanwege een fout op de server. - depends_on_separate_with_commas: Afhankelijk van (gescheiden door komma's) + error_toggle_complete: Kon deze actie niet als afgerond markeren + due: Deadline + no_incomplete_actions: Er zijn geen onvoltooide acties action_saved_to_tickler: Actie opgeslagen in tickler recurring_action_saved: Terugkerende actie opgeslagen + depends_on_separate_with_commas: Afhankelijk van (gescheiden door komma's) completed_in_archive: one: Er is een voltooide actie in het archief. other: Er zijn %{count} afgeronde acties in het archief. @@ -574,94 +588,120 @@ nl: due_date: met een deadline %{due_date} of eerder overdue: Achterstallig add_new_recurring: Voeg een nieuwe terugkerende actie toe - no_incomplete_actions: Er zijn geen onvoltooide acties notes: delete_note_title: Verwijder de notitie '%{id}' delete_confirmation: Weet u zeker dat u de notitie '%{id}' wilt verwijderen? in_project: "In:" delete_item_title: Verwijder item + deleted_note: Verwijder notitie '%{id}' note_link_title: Toon notitie %{id} show_note_title: Toon notitie - deleted_note: Verwijder notitie '%{id}' edit_item_title: Item bewerken note_location_link: "In:" no_notes_available: "Momenteel zijn er geen notities: voeg notities toe aan projecten vanaf de individuele project pagina's." note_header: Notitie %{id} delete_note_confirm: Weet u zeker dat u de notitie '%{id}' wilt verwijderen? + projects: + default_context_set: Stel project standaard context in op %{default_context} + no_actions_in_project: Momenteel zijn er geen onafgeronde acties in dit project + deferred_actions: Uitgestelde acties voor dit project + was_marked_hidden: is gemarkeerd als verborgen + edit_project_title: Bewerk project + default_tags_removed_notice: De standaard tags zijn verwijderd + page_title: "TRACKS:: Project: %{project}" + all_completed_tasks_title: TRACKS::Toon alle afgeronde acties in het project '{project_name}' + hide_form: Verberg formulier + list_completed_projects: TRACKS::Toon afgeronde projecten + no_notes_attached: Momenteel zijn er geen notities toegevoegd aan dit project + to_new_project_page: Ga naar de nieuwe projectpagina + show_form_title: Maak een nieuw project + deferred_actions_empty: Er zijn geen uitgestelde acties voor dit project + project_state: Project is %{state}. + this_project: Dit project + no_last_completed_projects: Geen afgeronde projecten gevonden + no_last_completed_recurring_todos: Geen afgeronde herhalende acties gevonden + notes: Notities + todos_append: in dit project + list_reviews: TRACKS::Evaluatie + notes_empty: Er zijn geen notities voor dit project + no_projects: Momenteel zijn er geen projecten + hide_form_title: Verberg nieuw project formulier + delete_project: Project verwijderen + completed_actions_empty: Er zijn nog geen afgeronde acties voor dit project + with_no_default_context: zonder standaard context + delete_project_confirmation: Weet u zeker dat u wilt het project '%{name} wilt verwijderen? + with_default_context: met een standaard context '%{context_name}' + show_form: Toevoegen van een project + actions_in_project_title: Acties in dit project + completed_projects: Voltooide projecten + is_active: is actief + add_note: Een notitie toevoegen + set_default_tags_notice: Stel project standaard tags in op %{default_tags} + add_project: Voeg project toe + settings: Instellingen + project_saved_status: Project opgeslagen + list_projects: "TRACKS:: Overzicht van projecten" + with_default_tags: en met '%{tags}' als de standaard tags + completed_tasks_title: TRACKS::Toon afgeronde acties in het project '%{project_name}' + hidden_projects: Verborgen projecten + delete_project_title: Verwijder het project + default_context_removed: Standaard context verwijderd + add_note_submit: Notitie toevoegen + completed_actions: Afgeronde acties voor dit project + was_marked_complete: is gemarkeerd als voltooid + no_default_context: Dit project heeft geen standaard context + with_no_default_tags: en zonder standaard tags + default_context: De standaard context voor dit project is %{context} + edit_project_settings: Bewerk project instellingen + status_project_name_changed: Naam van het project werd gewijzigd + state: Dit project is %{state} + active_projects: Actieve projecten states: hidden_plural: Verborgen - review_plural: Gedateerde stalled: Vastgelopen + review_plural: Gedateerde completed: Afgerond current: Bijgewerkt - completed_plural: Afgeronde review: Gedateerde + completed_plural: Afgeronde blocked: Geblokkeerd blocked_plural: Geblokkeerde stalled_plural: Vastgelopen visible_plural: Zichtbare active_plural: Actieve visible: Zichtbaar - current_plural: Bijgewerkte hidden: Verborgen active: Actief - projects: - was_marked_hidden: is gemarkeerd als verborgen - edit_project_title: Bewerk project - default_tags_removed_notice: De standaard tags zijn verwijderd - default_context_set: Stel project standaard context in op %{default_context} - no_actions_in_project: Momenteel zijn er geen onafgeronde acties in dit project - deferred_actions: Uitgestelde acties voor dit project - all_completed_tasks_title: TRACKS::Toon alle afgeronde acties in het project '{project_name}' - page_title: "TRACKS:: Project: %{project}" - hide_form: Verberg formulier - no_notes_attached: Momenteel zijn er geen notities toegevoegd aan dit project - show_form_title: Maak een nieuw project - deferred_actions_empty: Er zijn geen uitgestelde acties voor dit project - this_project: Dit project - project_state: Project is %{state}. - list_completed_projects: TRACKS::Toon afgeronde projecten - to_new_project_page: Ga naar de nieuwe projectpagina - no_last_completed_recurring_todos: Geen afgeronde herhalende acties gevonden - todos_append: in dit project - no_last_completed_projects: Geen afgeronde projecten gevonden - notes: Notities - notes_empty: Er zijn geen notities voor dit project - no_projects: Momenteel zijn er geen projecten - hide_form_title: Verberg nieuw project formulier - list_reviews: TRACKS::Evaluatie - delete_project: Project verwijderen - completed_actions_empty: Er zijn nog geen afgeronde acties voor dit project - with_no_default_context: zonder standaard context - show_form: Toevoegen van een project - actions_in_project_title: Acties in dit project - delete_project_confirmation: Weet u zeker dat u wilt het project '%{name} wilt verwijderen? - with_default_context: met een standaard context '%{context_name}' - add_note: Een notitie toevoegen - add_project: Voeg project toe - with_default_tags: en met '%{tags}' als de standaard tags - is_active: is actief - settings: Instellingen - list_projects: "TRACKS:: Overzicht van projecten" - completed_projects: Voltooide projecten - set_default_tags_notice: Stel project standaard tags in op %{default_tags} - project_saved_status: Project opgeslagen - delete_project_title: Verwijder het project - hidden_projects: Verborgen projecten - completed_tasks_title: TRACKS::Toon afgeronde acties in het project '%{project_name}' - was_marked_complete: is gemarkeerd als voltooid - completed_actions: Afgeronde acties voor dit project - default_context_removed: Standaard context verwijderd - add_note_submit: Notitie toevoegen - edit_project_settings: Bewerk project instellingen - status_project_name_changed: Naam van het project werd gewijzigd - active_projects: Actieve projecten - default_context: De standaard context voor dit project is %{context} - state: Dit project is %{state} - no_default_context: Dit project heeft geen standaard context - with_no_default_tags: en zonder standaard tags + current_plural: Bijgewerkte errors: user_unauthorized: "401 Unauthorized: Alleen administratieve gebruikers mogen deze functie gebruiken." + preferences: + open_id_url: Uw OpenID URL is + change_identity_url: Verander uw Identity URL + staleness_starts_after: Markeren openstaande acties begint na %{days} dagen + page_title: "TRACKS:: Voorkeuren" + change_password: Wijzig uw wachtwoord + token_description: Token (voor feeds en API gebruik) + title: Uw voorkeuren + is_false: Nee + show_number_completed: Toon %{number} voltooide items + password_changed: Je wachtwoord is gewijzigd, meld je opnieuw aan. + edit_preferences: Voorkeuren bewerken + page_title_edit: "TRACKS:: Voorkeuren bewerken" + is_true: Ja + sms_context_none: Geen + generate_new_token: Genereer een nieuwe token + token_header: Uw token + authentication_header: Uw authenticatie + updated: Voorkeuren bijgewerkt + current_authentication_type: Uw authenticatietype is %{auth_type} + change_authentication_type: Verander uw authenticatietype + generate_new_token_confirm: Weet u dit zeker? Het genereren van een nieuw token zal de bestaande te vervangen en dit zal het extern gebruiken van de oude token laten mislukken. + tabs: + authentication: Authenticatie + tracks_behavior: Tracks gedrag + profile: Profiel + date_and_time: Datum en tijd time: am: ochtend formats: @@ -672,33 +712,6 @@ nl: month_day: "%d %B" long: "%A, %d. %B %Y, %H:%M" pm: middag - preferences: - change_identity_url: Verander uw Identity URL - open_id_url: Uw OpenID URL is - staleness_starts_after: Markeren openstaande acties begint na %{days} dagen - page_title: "TRACKS:: Voorkeuren" - change_password: Wijzig uw wachtwoord - token_description: Token (voor feeds en API gebruik) - title: Uw voorkeuren - is_false: Nee - show_number_completed: Toon %{number} voltooide items - edit_preferences: Voorkeuren bewerken - page_title_edit: "TRACKS:: Voorkeuren bewerken" - is_true: Ja - password_changed: Je wachtwoord is gewijzigd, meld je opnieuw aan. - sms_context_none: Geen - generate_new_token: Genereer een nieuwe token - token_header: Uw token - authentication_header: Uw authenticatie - updated: Voorkeuren bijgewerkt - current_authentication_type: Uw authenticatietype is %{auth_type} - change_authentication_type: Verander uw authenticatietype - generate_new_token_confirm: Weet u dit zeker? Het genereren van een nieuw token zal de bestaande te vervangen en dit zal het extern gebruiken van de oude token laten mislukken. - tabs: - tracks_behavior: Tracks gedrag - authentication: Authenticatie - profile: Profiel - date_and_time: Datum en tijd date: month_names: - @@ -755,6 +768,13 @@ nl: - Okt - Nov - Dec + support: + array: + words_connector: "," + last_word_connector: ", en" + two_words_connector: en + select: + prompt: Selecteer will_paginate: previous_label: "\xC2\xABVorige" page_entries_info: @@ -770,13 +790,6 @@ nl: multi_page_html: Toon %{model} %{from} - %{to} van %{count} in totaal page_gap: "…" next_label: "Volgende \xC2\xBB" - support: - array: - words_connector: "," - last_word_connector: ", en" - two_words_connector: en - select: - prompt: Selecteer dates: month_names: - Januari @@ -803,9 +816,9 @@ nl: send_feedback: Stuur reactie op %{version} shared: multiple_next_actions: Meerdere acties (een op elke regel) + make_actions_dependent: Maak acties afhankelijk van elkaar toggle_single: Voeg een actie toe hide_form: Verberg formulier - make_actions_dependent: Maak acties afhankelijk van elkaar add_actions: Toevoegen acties add_action: Actie toevoegen tags_for_all_actions: Tags voor alle acties (scheiden met een komma) @@ -817,6 +830,30 @@ nl: add_context: Toevoegen context toggle_multi_title: Toggle single / multi actie formulier hide_action_form_title: Verberg nieuwe actie formulier + feedlist: + choose_context: Kies de context waar je een feed van wilt + actions_due_today: Acties die vandaag of eerder af moeten + ical_feed: iCal feed + legend: Legenda + all_contexts: Alle contexten + rss_feed: RSS Feed + choose_project: Kies het project waar je een feed van wilt + all_projects: Alle projecten + project_needed: "Er moet ten minste \xC3\xA9\xC3\xA9n project zijn voor een feed opgevraagd kan worden" + select_feed_for_project: Kies de feed voor dit project + active_projects_wo_next: Actieve projecten zonder acties + active_starred_actions: Alle gesterde, actieve acties + context_needed: "Er moet eerst ten minste \xC3\xA9\xC3\xA9n context zijn voor je een feed kan opvragen" + select_feed_for_context: Kies de feed voor deze context + projects_and_actions: Actieve projecten met hun acties + notice_incomplete_only: "Merk op: alle feeds laten alleen acties zien die niet afgerond zijn, tenzij anders vermeld." + actions_due_next_week: Acties die binnen 7 dagen afgerond moeten + actions_completed_last_week: Acties afgerond in de afgelopen 7 dagen + context_centric_actions: Feeds voor onafgeronde acties in een specifieke context + plain_text_feed: Reguliere tekst feed + last_fixed_number: Laatste %{number} acties + all_actions: Alle acties + project_centric: Feeds voor onafgeronde acties in een specifiek project sidebar: list_name_active_contexts: Actieve contexten list_name_active_projects: Actieve projecten @@ -824,66 +861,14 @@ nl: list_name_completed_projects: Voltooide projecten list_name_hidden_projects: Verborgen projecten list_name_hidden_contexts: Verborgen contexten - feedlist: - actions_due_today: Acties die vandaag of eerder af moeten - choose_context: Kies de context waar je een feed van wilt - rss_feed: RSS Feed - legend: Legenda - ical_feed: iCal feed - all_contexts: Alle contexten - all_projects: Alle projecten - choose_project: Kies het project waar je een feed van wilt - project_needed: "Er moet ten minste \xC3\xA9\xC3\xA9n project zijn voor een feed opgevraagd kan worden" - select_feed_for_project: Kies de feed voor dit project - active_projects_wo_next: Actieve projecten zonder acties - active_starred_actions: Alle gesterde, actieve acties - select_feed_for_context: Kies de feed voor deze context - projects_and_actions: Actieve projecten met hun acties - context_needed: "Er moet eerst ten minste \xC3\xA9\xC3\xA9n context zijn voor je een feed kan opvragen" - actions_due_next_week: Acties die binnen 7 dagen afgerond moeten - notice_incomplete_only: "Merk op: alle feeds laten alleen acties zien die niet afgerond zijn, tenzij anders vermeld." - context_centric_actions: Feeds voor onafgeronde acties in een specifieke context - plain_text_feed: Reguliere tekst feed - last_fixed_number: Laatste %{number} acties - all_actions: Alle acties - actions_completed_last_week: Acties afgerond in de afgelopen 7 dagen - project_centric: Feeds voor onafgeronde acties in een specifiek project - contexts: - delete_context_title: Verwijder context - all_completed_tasks_title: "TRACKS:: Alle voltooide acties in context '%{context_name}'" - hide_form: Verberg formulier - show_form_title: Voeg een context toe - todos_append: in deze context - delete_context_confirmation: Weet u zeker dat u de context '%{name}' wilt verwijderen? Merk op dat dit ook alle (herhalende) acties in deze context zal verwijderen! - delete_context: Verwijder context - edit_context: Bewerk context - hide_form_title: "Verberg formulier voor nieuwe context " - hidden_contexts: Verborgen contexten - no_contexts_active: Momenteel zijn er geen actieve contexten - context_hide: Verberg van de start pagina? - show_form: Maak een nieuwe context - visible_contexts: Zichtbare contexten - save_status_message: Context bewaard - add_context: Context toevoegen - update_status_message: Naam van de context was veranderd - context_name: Context naam - status_active: Context is actief - completed_tasks_title: "TRACKS:: Voltooid acties in de context '%{context_name}'" - new_context_post: "' zal ook gemaakt worden. Weet u dit zeker?" - no_actions: Momenteel zijn er geen onafgeronde acties in deze context - last_completed_in_context: in deze context (laatste %{number}) - context_deleted: De context '%{name}' is verwijderd - no_contexts_hidden: Momenteel zijn er geen verborgen contexten - new_context_pre: Nieuwe context ' - status_hidden: Context is verborgen users: - successfully_deleted_user: Succesvol gebruiker %{username} verwijderd + openid_url_verified: Je hebt %{url} met succes geverifieerd als je identiteit en uw authenticatie type OpenID opgeslagen. auth_type_update_error: "Er was een probleem met het bijwerken van uw authenticatietype: %{error_messages}" failed_to_delete_user: Mislukt de gebruiker %{username} te verwijderen destroy_successful: Gebruiker %{login} met succes verwijderd - total_contexts: Totaal aantal contexten first_user_heading: "Welkom bij TRACKS. Om te beginnen, maak dan een admin account:" - openid_url_verified: Je hebt %{url} met succes geverifieerd als je identiteit en uw authenticatie type OpenID opgeslagen. + total_contexts: Totaal aantal contexten + successfully_deleted_user: Succesvol gebruiker %{username} verwijderd signup_successful: Aanmelding succesvol voor gebruiker %{username}. new_token_generated: Nieuwe token met succes gegenereerd total_projects: Totaal aantal projecten @@ -891,23 +876,23 @@ nl: no_signups_title: "TRACKS:: Geen nieuwe aanmeldingen" user_created: Gebruiker aangemaakt. account_signup: Aanmelden voor een account - password_updated: Wachtwoord bijgewerkt. manage_users: Beheren gebruikers - new_user_heading: "Registreer een nieuwe gebruiker:" + password_updated: Wachtwoord bijgewerkt. auth_type_updated: Authenticatietype bijgewerkt. total_actions: Totaal aanal acties desired_login: Gewenste login signup: Aanmelden confirm_password: Bevestig wachtwoord - change_password_prompt: Voer uw nieuwe wachtwoord in de onderstaande velden in en kies 'Wachtwoord wijzigen' om uw huidige wachtwoord met uw nieuwe te vervangen. + new_user_heading: "Registreer een nieuwe gebruiker:" password_confirmation_label: Bevestig wachtwoord destroy_error: Er is een fout opgetreden bij het verwijderen van de gebruiker '%{login}' choose_password: Kies een wachtwoord change_password_title: TRACKS::Wachtwoord wijzigen change_auth_type_title: TRACKS::Wijzig authenticatietype + change_password_prompt: Voer uw nieuwe wachtwoord in de onderstaande velden in en kies 'Wachtwoord wijzigen' om uw huidige wachtwoord met uw nieuwe te vervangen. + new_password_label: Nieuw wachtwoord register_with_cas: Met uw CAS gebruikersnaam label_auth_type: Authenticatietype - new_password_label: Nieuw wachtwoord total_users_count: Je hebt een totaal van %{count} gebruikers new_user_title: "TRACKS:: Aanmelden als de admin gebruiker" destroy_user: Verwijder de gebruiker @@ -918,18 +903,46 @@ nl: openid_ok_pref_failed: Je hebt succesvol de %{url} geverifieerd als je identiteit, maar er was een probleem met het opslaan van uw authenticatie voorkeuren. auth_change_submit: Wijzigen authenticatietype change_authentication_type: Wijzigen authenticatietype - select_authentication_type: Selecteer uw nieuwe authenticatie type en klik op 'Wijzigen authenticatietype' om uw huidige instellingen te vervangen. total_notes: Totaal aantal notities + select_authentication_type: Selecteer uw nieuwe authenticatie type en klik op 'Wijzigen authenticatietype' om uw huidige instellingen te vervangen. + contexts: + delete_context_title: Verwijder context + all_completed_tasks_title: "TRACKS:: Alle voltooide acties in context '%{context_name}'" + hide_form: Verberg formulier + show_form_title: Voeg een context toe + delete_context_confirmation: Weet u zeker dat u de context '%{name}' wilt verwijderen? Merk op dat dit ook alle (herhalende) acties in deze context zal verwijderen! + todos_append: in deze context + delete_context: Verwijder context + edit_context: Bewerk context + hide_form_title: "Verberg formulier voor nieuwe context " + hidden_contexts: Verborgen contexten + no_contexts_active: Momenteel zijn er geen actieve contexten + context_hide: Verberg van de start pagina? + add_context: Context toevoegen + show_form: Maak een nieuwe context + save_status_message: Context bewaard + visible_contexts: Zichtbare contexten + update_status_message: Naam van de context was veranderd + context_name: Context naam + status_active: Context is actief + completed_tasks_title: "TRACKS:: Voltooid acties in de context '%{context_name}'" + new_context_post: "' zal ook gemaakt worden. Weet u dit zeker?" + new_context_pre: Nieuwe context ' + no_actions: Momenteel zijn er geen onafgeronde acties in deze context + last_completed_in_context: in deze context (laatste %{number}) + context_deleted: De context '%{name}' is verwijderd + no_contexts_hidden: Momenteel zijn er geen verborgen contexten + status_hidden: Context is verborgen login: - login_cas: Ga naar het CAS openid_identity_url_not_found: Sorry, geen gebruiker met die identiteit URL bestaat (%{identity_url}) user_no_expiry: Blijf ingelogd sign_in: Meld aan - please_login: Log in om Tracks te gebruiken - cas_logged_in_greeting: Hallo, %{username}! U bent geauthenticeerd. + login_cas: Ga naar het CAS cas_no_user_found: Hallo,%{username}! Je hebt nog geen account op Tracks. cas_login: CAS Inloggen successful_with_session_info: "Login succesvol:" + please_login: Log in om Tracks te gebruiken + cas_logged_in_greeting: Hallo, %{username}! U bent geauthenticeerd. cas_username_not_found: Sorry, geen gebruiker met die CAS gebruikersnaam bestaat (%{username}) cas_create_account: Als u willen vragen ga hier om %{signup_link} mobile_use_openid: ... if inloggen met een OpenID @@ -941,10 +954,10 @@ nl: session_time_out: Sessie is verlopen. Gelieve %{link} session_will_expire: sessie zal verlopen na %{hours} u(u)r(en) van inactiviteit. login_standard: Ga terug naar de standaard login - log_in_again: opnieuw in te loggen. - logged_out: Je bent afgemeld bij Tracks. login_with_openid: inloggen met een OpenID unsuccessful: Login mislukt. + log_in_again: opnieuw in te loggen. + logged_out: Je bent afgemeld bij Tracks. datetime: prompts: minute: Minuut @@ -993,7 +1006,7 @@ nl: search: contexts_matching_query: Contexten passend bij zoekopdracht tags_matching_query: Tags passend bij zoekopdracht + no_results: Uw zoekopdracht heeft geen resultaten opgeleverd. todos_matching_query: Todos passend bij zoekopdracht projects_matching_query: Projecten passend bij zoekopdracht notes_matching_query: Notities passend bij zoekopdracht - no_results: Uw zoekopdracht heeft geen resultaten opgeleverd. From 1d1031dd55b8ac4902fcddba390b82c86aad5fe5 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Mon, 16 Apr 2012 13:25:28 +0200 Subject: [PATCH 092/134] fix #1280. Thanks Christian and Darian --- lib/tracks/utils.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/tracks/utils.rb b/lib/tracks/utils.rb index 86c17751..458adab4 100644 --- a/lib/tracks/utils.rb +++ b/lib/tracks/utils.rb @@ -1,3 +1,5 @@ +require 'redcloth' + module Tracks class Utils From c0161ecfc52b4e6c12bdd97104b0182152ea76da Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Mon, 16 Apr 2012 13:58:12 +0200 Subject: [PATCH 093/134] fix #1277 by commenting out the lines that run git. --- vendor/gems/aruba-0.2.2/aruba.gemspec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vendor/gems/aruba-0.2.2/aruba.gemspec b/vendor/gems/aruba-0.2.2/aruba.gemspec index 73432581..a2fef12d 100644 --- a/vendor/gems/aruba-0.2.2/aruba.gemspec +++ b/vendor/gems/aruba-0.2.2/aruba.gemspec @@ -14,9 +14,9 @@ Gem::Specification.new do |s| s.add_development_dependency('rspec', "~> 2.0.0.beta.22") s.rubygems_version = "1.3.7" - s.files = `git ls-files`.split("\n") - s.test_files = `git ls-files -- {spec,features}/*`.split("\n") - s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } + # s.files = `git ls-files`.split("\n") + # s.test_files = `git ls-files -- {spec,features}/*`.split("\n") + # s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.extra_rdoc_files = ["LICENSE", "README.rdoc", "History.txt"] s.rdoc_options = ["--charset=UTF-8"] s.require_path = "lib" From 343a4a584675b0221017945b4f0ca00ad065b2a0 Mon Sep 17 00:00:00 2001 From: Tim Madden Date: Mon, 16 Apr 2012 09:45:22 -0500 Subject: [PATCH 094/134] fixing extra argument on mobile projects page --- app/views/projects/_mobile_project_listing.rhtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/_mobile_project_listing.rhtml b/app/views/projects/_mobile_project_listing.rhtml index 440536bb..710128bb 100644 --- a/app/views/projects/_mobile_project_listing.rhtml +++ b/app/views/projects/_mobile_project_listing.rhtml @@ -1,4 +1,4 @@ <% project = mobile_project_listing -%>
        <%= link_to(project.name, project_path(project, :format => 'm')) + - " (" + count_undone_todos_and_notes_phrase(project,"actions") + ")" %>
        + " (" + count_undone_todos_and_notes_phrase(project) + ")" %> From d27ffb6ce0963f94c4a01da56265dfc9b3acb817 Mon Sep 17 00:00:00 2001 From: tim madden Date: Fri, 13 Apr 2012 17:33:39 -0500 Subject: [PATCH 095/134] mobile tuning change to make nav links even and consistent looking to make text bigger for fat fingers change to project nav adding images for arrows --- app/helpers/projects_helper.rb | 12 ++-- app/views/layouts/mobile.m.erb | 24 +++---- public/stylesheets/images/next.png | Bin 0 -> 366 bytes public/stylesheets/images/previous.png | Bin 0 -> 347 bytes public/stylesheets/mobile.css | 85 ++++++++++++++++++++----- 5 files changed, 89 insertions(+), 32 deletions(-) create mode 100644 public/stylesheets/images/next.png create mode 100644 public/stylesheets/images/previous.png diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 0eb972eb..638bfba0 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -32,16 +32,20 @@ module ProjectsHelper end def project_next_prev_mobile - html = '' + html = '
          ' unless @previous_project.nil? project_name = truncate(@previous_project.name, :length => 40, :omission => "...") - html << link_to_project_mobile(@previous_project, "5", "« 5-#{project_name}") + html << '' end - html << ' | ' if @previous_project && @next_project unless @next_project.nil? project_name = truncate(@next_project.name, :length => 40, :omission => "...") - html << link_to_project_mobile(@next_project, "6", "6-#{project_name} »") + html << '' end + html << '
        ' html end diff --git a/app/views/layouts/mobile.m.erb b/app/views/layouts/mobile.m.erb index 15d340b2..583d51b1 100644 --- a/app/views/layouts/mobile.m.erb +++ b/app/views/layouts/mobile.m.erb @@ -14,21 +14,21 @@ <% if current_user && !current_user.prefs.nil? -%>

        <% if @down_count -%><%= @down_count %><% end -%> <%= l(Date.today, :format => current_user.prefs.title_date_format) -%>

        -
        +
        <%= render_flash -%><%= yield -%>

        <% if current_user && !current_user.prefs.nil? -%> - + <% end -%> <%= render :partial => "shared/mobile_footer" -%> diff --git a/public/stylesheets/images/next.png b/public/stylesheets/images/next.png new file mode 100644 index 0000000000000000000000000000000000000000..62e10cfed120816342b7a5924e82a3019b3e8855 GIT binary patch literal 366 zcmeAS@N?(olHy`uVBq!ia0vp^LO{&J!3HGrh2HJ~QY^(zo*^7SP{WbZ0pxQQctjQh z)n5l;MkkHg6+l7B64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1TEd%8G= zXiPjiX|*47qCo5Zn+yw+LYY^I$#5O#7T{@`S^rlnhF8B~&AR3{c^Q2?V= zIm=!iG&&*guJlPPS>{@4?d$!%Yw!HswQAM%(2Gy*oBo!rz3HdJneKHA=xqj1S3j3^ HP6^eP*AeOHKHUqKdq!Zu_%?Hyu4g5GcUV1Ik6yBFTW^#_B$IXprRX|E{-7* zQ*$S*_iHVXIcgt2V+Z%|vu8ca{B+rxk7gY!NaacUEEaz-!SIFli#O+3T)Jatce)$g zKemIj&vEZ=XMfxD=kq<2dTh=wKTsGs?K(r`wA|`><@u{0Ez&4!ORQkxYy7_M^|C;b zyA0DOIZbw%r1CmZ;vSQ60=I$j?+GHzh6aq!>MolscNEyeq<(-cp=Nb*f^fud&bSKg z(6|0S1^4V)7eA-?_W@>u|Eemc2h=x2?CNEE_qFzaP8$1x*~RbH Date: Tue, 17 Apr 2012 15:33:02 +0200 Subject: [PATCH 096/134] merge latest changes for the he locale. Thanks Darian. --- app/controllers/stats_controller.rb | 2 +- config/locales/he.yml | 4772 ++++++++++++++------------- 2 files changed, 2436 insertions(+), 2338 deletions(-) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index 967e89bc..00081499 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -554,7 +554,7 @@ class StatsController < ApplicationController ) i=0 - @projects_and_runtime = Array.new(10, [-1, "n/a", "n/a"]) + @projects_and_runtime = Array.new(10, [-1, t('common.not_available_abbr'), t('common.not_available_abbr')]) @projects_and_runtime_sql.each do |r| days = difference_in_days(@today, r.created_at) # add one so that a project that you just created returns 1 day diff --git a/config/locales/he.yml b/config/locales/he.yml index 03098728..3fb0927f 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -1,887 +1,37 @@ --- he: - search: - contexts_matching_query: !binary | - 15TXp9ep16jXmdedINeq15XXkNee15nXnSDXnNep15DXmdec16rXkA== - - projects_matching_query: !binary | - 16TXqNeV15nXmden15jXmdedINeq15XXkNee15nXnSDXqdeQ15nXnNeq15A= - - todos_matching_query: !binary | - 157XqdeZ157XldeqINeq15XXkNee15XXqiDXqdeQ15nXnNeq15A= - - no_results: !binary | - 15TXl9eZ16TXldepINec15Ag15TXoNeZ15Eg16rXldem15DXldeq - - notes_matching_query: !binary | - 16TXqten15nXnSDXqteV15DXnteZ150g16nXkNeZ15zXqteQ - - tags_matching_query: !binary | - 16rXkteZ15XXqiDXqteV15DXnteV16og15zXqdeQ15nXnNeq15A= - - models: - project: - feed_title: !binary | - 16TXqNeV15nXmden15jXmdedINeR157Xodec15XXnNeZ150= - - feed_description: !binary | - 16jXqdeZ157XqiDXm9ecINeU16TXqNeV15nXmden15jXmdedINei15HXldeo - ICV7dXNlcm5hbWV9 - - todo: - error_date_must_be_future: !binary | - 15fXmdeZ15Eg15zXlNeZ15XXqiDXqteQ16jXmdeaINei16rXmdeT15k= - - user: - error_context_not_associated: !binary | - 157XlteU15Qg15TXp9ep16ggJXtjb250ZXh0fSDXkNeZ16DXlSDXntep15XX - mdeZ15og16LXnSDXnteW15Qg157Xqdeq157XqSAle3VzZXJ9Lg== - - error_project_not_associated: !binary | - 157XlteU15Qg16TXqNeV15nXmden15ggJXtwcm9qZWN0fSDXkNeZ16DXlSDX - ntep15XXmdeZ15og16LXnSDXnteW15Qg157Xqdeq157XqSAle3VzZXJ9Lg== - - preference: - due_on: !binary | - LSDXmdei15Mg15Ele2RhdGV9 - - due_in: !binary | - 16rXkNeo15nXmiDXmdei15Mg15HXoteV15MgJXtkYXlzfSDXmdee15nXnQ== - - layouts: - toggle_contexts_title: !binary | - 15TXodeq16jXqi/XlNem15LXqiDXqdeT15XXqiDXnteV16HXqteo15nXnQ== - - navigation: - search: !binary | - 15fXmdek15XXqSDXm9ecINeU16TXqNeZ15jXmded - - home: !binary | - 15HXmdeq - - home_title: !binary | - 15HXmdeq - - organize: !binary | - 15DXqNeS15XXnw== - - projects_title: !binary | - 16TXqNeV15nXmden15jXmded - - view: !binary | - 16rXpteV15LXlA== - - manage_users: !binary | - 16DXmdeU15XXnCDXntep16rXntep15nXnQ== - - feeds_title: !binary | - 16bXpNeZ15Qg15HXqNep15nXnteqINeU15TXlteg15XXqiDXlNeW157Xmdeg - 15Q= - - manage_users_title: !binary | - 15TXldeh16TXlCDXkNeVINeU16HXqNeUINep15wg157Xqdeq157XqdeZ150= - - feeds: !binary | - 15TXlteg15XXqg== - - api_docs: !binary | - 16rXmdei15XXkyDXntee16nXpyDXqteb16DXldeq - - completed_tasks: !binary | - 15HXldem16I= - - stats_title: !binary | - 15TXpteS16og15TXodeY15jXmdeh15jXmden15Qg16nXnNeZ - - export: !binary | - 15nXpteV15A= - - notes_title: !binary | - 15TXpteS16og15DXqiDXm9ecINeU16TXqten15nXnQ== - - completed_tasks_title: !binary | - 15TXodeq15nXmded - - integrations_: !binary | - 16nXmdec15XXkSDXnteh15zXldec15nXnQ== - - tickler: !binary | - 157WtNeW1rDXm9a41rzXqA== - - tickler_title: !binary | - 157WtNeW1rDXm9a41rzXqA== - - preferences_title: !binary | - 15TXpteS16og15TXoteT16TXldeq15k= - - contexts_title: !binary | - 15TXp9ep16jXmded - - review_title: !binary | - 16LXqNeZ15vXpiDXkdeZ16fXldeo16o= - - export_title: !binary | - 15nXkdeV15Ag15XXmdem15XXkCDXoNeq15XXoNeZ150= - - calendar: !binary | - 15zXldeXINep16DXlA== - - stats: !binary | - 16HXmNeY15nXodeY15nXp9eU - - recurring_todos_title: !binary | - 16DXmdeU15XXnCDXpNei15XXnNeV16og157Xl9eW15XXqNeZ15XXqg== - - recurring_todos: !binary | - 157XqdeZ157XldeqINee15fXlteV16jXmdeV16o= - - starred: !binary | - 157XldeT15LXqdeZ150= - - calendar_title: !binary | - 15zXldeXINep16DXlCDXqdecINee16nXmdee15XXqiDXnNeR15nXpteV16I= - - starred_title: !binary | - 15TXpteS16og16TXoteV15zXldeqINee15XXk9eS16nXldeq - - preferences: !binary | - 15TXoteT16TXldeq - - toggle_notes_title: !binary | - 15HXl9eZ16jXqiDXm9ecINeU16TXqten15nXnQ== - - mobile_navigation: - home: !binary | - MS3XkdeZ16o= - - new_action: !binary | - MC3XpNei15XXnNeUINeX15PXqdeU - - feeds: !binary | - 15TXlteg15XXqg== - - logout: !binary | - 16bXkA== - - projects: !binary | - My3XpNeo15XXmdeZ16fXmNeZ150= - - tickler: !binary | - 157WtNeW1rDXm9a41rzXqA== - - starred: !binary | - NC3XnteV15PXktep15nXnQ== - - contexts: !binary | - Mi3XlNen16nXqNeZ150= - - toggle_contexts: !binary | - 15TXpteS16og16nXk9eV16og157Xldeh16rXqNeZ150= - - toggle_notes: !binary | - 15HXl9eZ16jXqiDXpNeq16fXmded - - next_actions_rss_feed: !binary | - 15TXlteg16og16jXodehINec16TXoteV15zXldeqINeU157Xqdea - - todos: - delete_recurring_action_confirm: !binary | - 15TXkNedINec157Xl9eV16cg15DXqiDXlNek16LXmdec15XXqiDXlNee15fX - lteV16jXmdeqICcle2Rlc2NyaXB0aW9ufSc/ - - completed_rest_of_previous_month: !binary | - 15TXodeq15nXmdee15Ug15HXmdeq16jXqiDXlNeX15XXk9epINeU16fXldeT - 150= - - recurrence_completed: !binary | - 15DXmdefINek16LXldec16og15TXntep15og15zXpNei15XXnNeUINeU157X - l9eW15XXqNeZ16og16nXodeV15nXnteULiDXlNee15fXlteV16jXmdeV16og - 15TXodeq15nXmdee15Qu - - all_completed_tagged_page_title: !binary | - 157Xodec15XXnNeZ1506Oteb15wg15TXpNei15XXnNeV16og16nXlNeh16rX - mdeZ157XlSDXotedINeU16rXkteZ16ogJXt0YWdfbmFtZX0= - - next_actions_title_additions: - due_within_a_week: !binary | - 16rXldeaINep15HXldei - - completed: !binary | - 16TXoteV15zXldeqINep15TXodeq15nXnteV - - due_today: !binary | - 15zXlNeZ15XXnQ== - - recurring_deleted_success: !binary | - 15TXpNei15XXnNeUINeU157Xl9eW15XXqNeZ16og16DXnteX16fXlCDXkdeU - 16bXnNeX15Q= - - add_new_recurring: !binary | - 15TXldeh16TXqiDXpNei15XXnNeUINee15fXlteV16jXmdeqINeX15PXqdeU - - delete: !binary | - 157Xl9eZ16fXlA== - - action_marked_complete: "\xD7\x94\xD7\xA4\xD7\xA2\xD7\x95\xD7\x9C\xD7\x94 '%{description}' \xD7\xA1\xD7\x95\xD7\x9E\xD7\xA0\xD7\x94 \xD7\x9B- %{completed}" - add_another_dependency: !binary | - 15TXldeh16TXqiDXqtec15XXqiDXoNeV16HXpNeq - - completed_tasks_title: !binary | - 157Xodec15XXnNeZ1506Otee16nXmdee15XXqiDXqdeU15XXqdec157XlQ== - - no_deferred_actions: !binary | - 15DXmdefINeb16jXkteiINek16LXldec15XXqiDXqdeg15PXl9eVLg== - - clear_due_date: !binary | - 157Xl9eZ16fXqiDXqteQ16jXmdeaINeZ16LXkw== - - show_on_date: !binary | - 15TXpteSINeR16rXkNeo15nXmiAle2RhdGV9 - - action_deferred: !binary | - 15TXpNei15XXnNeUICcle2Rlc2NyaXB0aW9ufScg16DXk9eX16rXlA== - - new_related_todo_created_short: !binary | - 15nXpteZ16jXqiDXntep15nXnteUINeX15PXqdeU - - deferred_tasks_title: !binary | - 157Xodec15XXnNeZ1506Otee1rTXltaw15vWuNa816g= - - no_deferred_actions_with: !binary | - 15DXmdefINek16LXldec15XXqiDXk9eX15XXmdeV16og16LXnSDXlNeq15LX - mdeqICcle3RhZ19uYW1lfSc= - - blocked_by: !binary | - 16DXl9eh150g16LXnCDXmdeT15kgJXtwcmVkZWNlc3NvcnN9 - - action_saved: !binary | - 16TXoteV15zXlCDXoNep157XqNeU - - completed_rest_of_month: !binary | - 15TXodeq15nXmdee15Ug15HXmdeq16jXqiDXlNeX15XXk9epINeU16DXldeb - 15fXmQ== - - clear_show_from_date: !binary | - 16DXp9eUINeU16bXkteUINee16rXkNeo15nXmg== - - recurrence_period: !binary | - 16rXp9eV16TXqiDXnteX15bXldeo15nXldeq - - next_action_description: !binary | - 16rXmdeQ15XXqCDXpNei15XXnNeqINeU157Xqdea - - show_from: !binary | - 15TXpteS15Qg154t - - calendar_page_title: !binary | - 157Xodec15XXnNeZ1506Otec15XXlyDXqdeg15Q= - - error_starring_recurring: !binary | - INeU15PXktep16og15TXntep15nXnteUINeU157Xl9eW15XXqNeZ16ogIFwn - JXtkZXNjcmlwdGlvbn1cJyDXnNeQINem15zXl9eU - - completed_tagged_page_title: !binary | - 157Xodec15XXnNeZ1506Otee16nXmdee15XXqiDXqdeU16HXqteZ15nXnteV - INei150g16rXkteZ16ogJyV7dGFnX25hbWV9Jw== - - tickler_items_due: - other: !binary | - JXtjb3VudH0g157XlNee1rTXltaw15vWuNa816jXmdedINeU15LXmdei15Ug - 15zXqteQ16jXmdeaINeU15nXoteTIC0g15nXqSDXnNeo16LXoNefINeU16LX - nteV15Mg15zXlNem15LXlC4= - - one: !binary | - 15DXl9eTINee15TXnta015bWsNeb1rjWvNeo15nXnSDXlNeS15nXoiDXnNeq - 15DXqNeZ15og15TXmdei15MgLSDXmdepINec16jXoteg158g15TXotee15XX - kyDXnNeU16bXkteULg== - - show_today: !binary | - 15TXpteS16og15TXmdeV150= - - completed_last_x_days: !binary | - 15TXodeq15nXmdee15Ug15EtJXtjb3VudH0g15TXmdee15nXnSDXlNeQ15fX - qNeV16DXmded - - completed: !binary | - 15TXodeq15nXmdee15U= - - remove_dependency: !binary | - 15TXodeo16og16rXnNeV16ogKNec15Ag157XldeX16cg15DXqiDXlNek16LX - ldec15Qp - - older_than_days: !binary | - 15XXldeq16cg157XotecICV7Y291bnR9INeZ157Xmded - - deferred_pending_actions: !binary | - 16TXoteV15zXldeqINee157XqteZ16DXldeqL9eT15fXldeZ15XXqg== - - scheduled_overdue: !binary | - 16rXldeW157XnyDXnNeq16bXldeS15Qg15zXpNeg15kgJXtkYXlzfSDXmdee - 15nXnQ== - - added_new_project: !binary | - 16DXldeh16Mg16TXqNeV15nXmden15gg15fXk9ep - - depends_on_separate_with_commas: !binary | - 16rXnNeV15kg15EtICjXmdepINec15TXpNeo15nXkyDXkdek16HXmden15nX - nSg= - - mobile_todos_page_title: !binary | - 15vXnCDXlNek16LXldec15XXqg== - - edit_recurring_todo: !binary | - 16LXqNeb15nXqiDXpNei15XXnNeV16og157Xl9eW15XXqNeZ15XXqg== - - delete_action: !binary | - 157Xl9eZ16fXqiDXpNei15XXnNeU - - calendar: - due_next_month_and_later: !binary | - 16rXkNeo15nXmiDXmdei15MgJXttb250aH0g15DXlSDXnteQ15XXl9eoINeZ - 15XXqteo - - get_in_ical_format: !binary | - 16fXkdec16og15zXldeXINep16DXlCDXlteUINeR16TXldeo157XmCBpQ2Fs - - no_actions_due_today: !binary | - 15DXmdefINek16LXldec15XXqiDXoNeV16HXpNeV16og15zXlNeZ15XXnQ== - - due_this_month: !binary | - 16rXkNeo15nXmiDXmdei15Mg15zXmdeq16jXqiDXl9eV15PXqSAle21vbnRo - fQ== - - no_actions_due_this_month: !binary | - 15DXmdefINek16LXldec15XXqiDXnNeR15nXpteV16Ig15HXmdeq16jXqiDX - lNeX15XXk9ep - - no_actions_due_next_week: !binary | - 15DXmdefINek16LXldec15XXqiDXnNeR15nXpteV16Ig15HXqdeR15XXoiDX - lNeR15A= - - due_today: !binary | - 15zXlNeZ15XXnQ== - - due_next_week: !binary | - 15zXqdeR15XXoiDXlNeR15A= - - due_this_week: !binary | - 15zXlNee16nXmiDXlNep15HXldei - - no_actions_due_after_this_month: !binary | - 15DXmdefINek16LXldec15XXqiDXnNeR15nXpteV16Ig15zXkNeX16gg15fX - ldeT16kg15bXlA== - - list_incomplete_next_actions_with_limit: !binary | - 16jXmdep157XqiAle2NvdW50fSDXpNei15XXnNeV16og15TXlNee16nXmiDX - qdec15Ag15TXodeq15nXmdee15U= - - to_tickler: !binary | - 15zXnta015bWsNeb1rjWvNeo - - cannot_add_dependency_to_completed_todo: !binary | - 15DXmdefINeQ16TXqdeo15XXqiDXnNeU15XXodeZ16Mg16TXoteV15zXlCDX - lteVINeb16rXnNeV16og15zXpNei15XXnNeUINep15TXodeq15nXmdee15Qh - - depends_on: !binary | - 16rXnNeV15kg15E= - - no_actions_due_this_week: !binary | - 15DXmdefINek16LXldec15XXqiDXlNee15nXldei15PXldeqINec15TXntep - 15og15TXqdeR15XXog== - - no_actions_found: !binary | - 15DXmdefINeb16jXkteiINek16LXldec15XXqiDXqdec15Ag15TXodeq15nX - mdee15U= - - context_changed: !binary | - 15TXp9ep16gg16nXldeg15Qg15wtJXtuYW1lfQ== - - archived_tasks_title: !binary | - 157Xodec15XXnNeZ1506INee16nXmdee15XXqiDXqdeU16HXqteZ15nXnteV - INeU15XXoteR16jXlSDXnNeQ16jXm9eZ15XXnw== - - no_incomplete_actions: !binary | - 15DXmdefINek16LXldec15XXqiDXqdec15Ag15TXodeq15nXmdee15U= - - completed_actions_with: !binary | - 16TXoteV15zXldeqINep15TXodeq15nXmdee15Ug16LXnSDXlNeq15LXmdeq - ICV7dGFnX25hbWV9ICA= - - added_new_next_action: !binary | - 16DXldeh16TXlCDXpNei15XXnNeqINeU157XqdeaINeX15PXqdeU - - unable_to_add_dependency: !binary | - 15zXkCDXoNeZ16rXnyDXnNeU15XXodeZ16Mg16rXnNeV16o= - - older_completed_items: !binary | - 157XqdeZ157XldeqINep15TXodeq15nXmdee15XXqiDXmdep16DXldeqINeZ - 15XXqteo - - no_deferred_pending_actions: !binary | - 15DXmdefINeb16jXkteiINek16LXldec15XXqiDXk9eX15XXmdeV16og15DX - lSDXntee16rXmdeg15XXqg== - - edit: !binary | - 16LXqNeZ15vXlA== - - next_actions_title: !binary | - 157Xodec15XXnNeZ150gLSDXpNei15XXnNeV16og15TXntep15o= - - defer_x_days: - other: !binary | - 15PXl9eZ15Qg15EtJXtjb3VudH0g15nXnteZ150= - - one: !binary | - 15PXl9eZ15Qg15HXmdeV150= - - completed_recurrence_completed: !binary | - 15DXmdefINek16LXldec16og15TXntep15og15zXpNei15XXnNeUINeU157X - l9eW15XXqNeZ16og16nXoNee15fXp9eULiDXlNek16LXldec15Qg15TXnteX - 15bXldeo15nXqiDXoNee15fXp9eULg== - - due: !binary | - 15nXoteT - - append_in_this_project: !binary | - 15HXpNeo15XXmdeZ16fXmCDXlteU - - completed_recurring: !binary | - 15TXodeq15nXmdee15Ug157XqdeZ157XldeqINee15fXlteV16jXmdeV16o= - - removed_predecessor: !binary | - 15TXldeh16jXlCV7c3VjY2Vzc29yfSAg15vXqtec15XXqiDXqdecICV7cHJl - ZGVjZXNzb3J9Lta+ - - confirm_delete: !binary | - 15TXkNedINec157Xl9eV16cg15DXqiDXlNek16LXmdec15XXqiAnJXtkZXNj - cmlwdGlvbn0nPw== - - task_list_title: !binary | - 157Xodec15XXnNeZ1506Oteo16nXmdee16og157XqdeZ157Xldeq - - no_completed_actions_with: !binary | - 15DXmdefINek16LXldec15XXqiDXqdeU16HXqteZ15nXnteVINei15wg15TX - qteS15nXqiAnJXt0YWdfbmFtZX0n - - set_to_pending: !binary | - JXt0YXNrfSDXlNeV15LXk9eo15Qg15vXntee16rXmdeg15Q= - - recurring_action_saved: !binary | - 16TXoteV15zXlCDXnteX15bXldeo15nXqiDXoNep157XqNeU - - recurring_pattern_removed: !binary | - 15TXk9ek15XXoSDXlNee15fXlteV16jXmSDXlNeV16HXqCDXni0le2NvdW50 - fQ== - - next_actions_due_date: - overdue_by: !binary | - 15HXkNeZ15fXldeoINep15wgJXtkYXlzfSDXmdeV150= - - overdue_by_plural: !binary | - 15HXkNeZ15fXldeoINep15wgJXtkYXlzfSDXmdee15nXnQ== - - due_in_x_days: !binary | - 15nXoteTINeR16LXldeTICV7ZGF5c30g15nXnteZ150= - - due_today: !binary | - 15zXlNeZ15XXnQ== - - due_tomorrow: !binary | - 15zXnteX16g= - - next_action_needed: !binary | - 15nXqSDXnNeU15bXmdefINec16TXl9eV16og16TXoteV15zXqiDXlNee16nX - miDXkNeX16o= - - added_dependency: !binary | - 16DXldeh16TXlCAle2RlcGVuZGVuY3l9INeb16rXnNeV16o= - - star_action: !binary | - 15TXk9eS16nXqiDXpNei15XXnNeU - - new_related_todo_not_created_short: !binary | - 15zXkCDXoNeV16bXqNeUINee16nXmdee15Q= - - completed_last_day: !binary | - 15TXodeq15nXmdee15Ug15EtMjQg16nXoteV16og15TXkNeX16jXldeg15XX - qg== - - tagged_with: !binary | - 157XqteV15nXmdeSINeRLSAmbHNxdW87JXt0YWdfbmFtZX0mcnNxdW87 - - no_recurring_todos: !binary | - 15DXmdefINeb16jXkteiINee16nXmdee15XXqiDXnteX15bXldeo15nXldeq - - deferred_actions_with: !binary | - 16TXoteV15zXldeqINeT15fXldeZ15XXqiDXotecINeq15LXmdeqICcle3Rh - Z19uYW1lfSc= - - error_removing_dependency: !binary | - 15TXqteo15fXqdeUINep15LXmdeQ15Qg15HXlNeh16jXqiDXlNeq15zXldeq - - error_deleting_recurring: !binary | - 15DXqNei15Qg16nXkteZ16LXlCDXkdee15fXmden16og15TXntep15nXnteU - INeU157Xl9eW15XXqNeZ16ogIFwnJXtkZXNjcmlwdGlvbn1cJw== - - feed_title_in_context: !binary | - 15HXlNen16nXqCAnJXtjb250ZXh0fSc= - - new_related_todo_created: !binary | - 157XqdeZ157XlCDXl9eT16nXlCDXlNeV16HXpNeUINec157XqdeZ157XlCDX - nteX15bXldeo15nXqiDXlteV - - recurring_action_deleted: !binary | - 16TXoteV15zXlCDXoNee15fXp9eULiDXnteQ15fXqCDXldeU16TXoteV15zX - lCDXnteX15bXldeo15nXqi4g16TXoteV15zXlCDXl9eT16nXlCDXoNeV16HX - pNeU - - recurring_todos: !binary | - 157XqdeZ157XldeqINee15fXlteV16jXmdeV16o= - - next_actions_description: !binary | - 157Xodeg1586 - - added_new_context: !binary | - 16DXldeh16Mg15TXp9ep16gg15fXk9ep - - show_tomorrow: !binary | - 15TXpteS16og157Xl9eo - - was_due_on_date: !binary | - 15TXmdeUINee15nXldei15Mg16LXkyAle2RhdGV9 - - tags: !binary | - 16rXkteZ15XXqiAo157Xldek16jXk9eV16og15HXpNeh15nXp9eZ150p - - completed_more_than_x_days_ago: !binary | - 15TXodeq15nXmdee15Ug15zXpNeg15kg15nXldeq16gg154tJXtjb3VudH0g - 15nXnteZ150= - - defer_date_after_due_date: !binary | - 16rXkNeo15nXmiDXlNeT15fXmdeZ15Qg157XkNeV15fXqCDXnteq15DXqNeZ - 15og15TXmdei15MuINeZ16kg15zXoteo15XXmiDXkNeqINeq15DXqNeZ15og - 15TXmdei15Mg15HXlNeq15DXnSDXnNek16DXmSDXkden16nXqiDXlNeT15fX - mdeZ15Qu - - error_saving_recurring: !binary | - 15DXqNei15Qg16nXkteZ16LXlCDXkdep157Xmdeo16og15TXntep15nXnteU - INeU157Xl9eW15XXqNeZ16ogIFwnJXtkZXNjcmlwdGlvbn1cJw== - - edit_action_with_description: !binary | - 16LXqNeZ15vXqiDXlNek16LXldec15QgJyV7ZGVzY3JpcHRpb259Jw== - - no_last_completed_actions: !binary | - 15zXkCDXoNee16bXkNeVINek16LXldec15XXqiDXqdeU16HXqteZ15nXnteV - - done: !binary | - 15TXodeq15nXmdedPw== - - action_saved_to_tickler: !binary | - 16TXoteV15zXlCDXoNep157XqNeUINec157WtNeW1rDXm9a41rzXqA== - - hidden_actions: !binary | - 16TXoteV15zXldeqINee15XXodeq16jXldeq - - edit_action: !binary | - 16LXqNeZ15vXqiDXpNei15XXnNeU - - completed_rest_of_week: !binary | - 15TXodeq15nXmdee15Ug15HXmdeq16jXqiDXqdeR15XXoiDXlteU - - action_due_on: !binary | - KNek16LXldec15Qg16LXkyAgJXtkYXRlfSk= - - convert_to_project: !binary | - 15nXpteZ16jXqiDXpNeo15XXmdeZ16fXmA== - - show_in_days: !binary | - 15TXpteSINeR16LXldeTICV7ZGF5c30g15nXnteZ150= - - added_new_next_action_singular: !binary | - 16DXldeh16TXlCDXpNei15XXnNeqINeU157XqdeaINeX15PXqdeU - - drag_action_title: !binary | - 15nXqSDXnNeS16jXldeoINeQ15wg16TXoteV15zXlCDXkNeX16jXqiDXm9eT - 15kg15zXmdem15XXqCDXqtec15XXqiDXkdeU - - added_new_next_action_plural: !binary | - 16DXldeh16TXlSDXpNei15XXnNeV16og15TXntep15og15fXk9ep15XXqg== - - feed_title_in_project: !binary | - 15HXpNeo15XXmdeZ16fXmCAnJXtwcm9qZWN0fSc= - - no_completed_recurring: !binary | - 15DXmdefINeb16jXkteiINee16nXmdee15XXqiDXnteX15bXldeo15nXldeq - INep15TXodeq15nXmdee15U= - - recurrence: - starts_on: !binary | - 157XqteX15nXnCDXkQ== - - ends_on_number_times: !binary | - 157Xodeq15nXmdedINec15DXl9eoICV7bnVtYmVyfSDXpNei157Xmded - - ends_on: !binary | - 157Xodeq15nXmdedINeR - - yearly_options: !binary | - 15TXkteT16jXldeqINec16TXoteV15zXldeqINeR157Xl9eW15XXqNeZ15XX - qiDXqdeg16rXmdeV16o= - - daily_every_number_day: !binary | - 15vXnCAle251bWJlcn0gINeZ157Xmded - - show_options: !binary | - 15TXpteS16og157XqdeZ157Xldeq - - daily: !binary | - 15nXldee15k= - - show_option_always: !binary | - 16rXnteZ15M= - - monthly_every_xth_day: !binary | - 15nXldedICV7ZGF5fSDXlCAtJXtkYXlfb2Zfd2Vla30gINeR15vXnCAle21v - bnRofSDXl9eV15PXqQ== - - every_work_day: !binary | - 15HXm9ecINeZ15XXnSDXoteR15XXk9eU - - recurrence_on_options: !binary | - 15TXkteT16jXqiDXnteX15bXldeo15nXldeqINec16TXmQ== - - weekly: !binary | - 16nXkdeV16LXmQ== - - yearly: !binary | - 16nXoNeq15nXqg== - - daily_options: !binary | - 15TXkteT16jXldeqINec16TXoteV15zXldeqINee15fXlteV16jXmdeV16og - 15nXldee15nXldeq - - monthly: !binary | - 15fXldeT16nXmQ== - - ends_on_date: !binary | - 157Xodeq15nXmdedINeRLSV7ZGF0ZX0= - - pattern: - third: !binary | - 16nXnNeZ16nXmQ== - - from: !binary | - 154= - - every_day: !binary | - 15vXnCDXmdeV150= - - on_day_n: !binary | - 15HXmdeV150gJXtufQ== - - on_work_days: !binary | - 15HXmdee15kg16LXkdeV15PXlA== - - until: !binary | - 16LXkw== - - every_month: !binary | - 15vXnCDXl9eV15PXqQ== - - every_xth_day_of_every_n_months: "\xD7\x9B\xD7\x9C %{x} %{day} \xD7\x91\xD7\x9B\xD7\x9C %{n_months}" - weekly: !binary | - 16nXkdeV16LXmQ== - - fourth: !binary | - 16jXkdeZ16LXmQ== - - first: !binary | - 16jXkNep15XXnw== - - due: !binary | - 15nXoteT - - second: !binary | - 16nXoNeZ - - last: !binary | - 15DXl9eo15XXnw== - - every_year_on: !binary | - 15HXm9ecINep16DXlCDXkdeq15DXqNeZ15ogJXtkYXRlfQ== - - every_n: !binary | - 15vXnCAle259 - - times: !binary | - 15stJXtudW1iZXJ9INek16LXnteZ150= - - the_xth_day_of_month: !binary | - 15TXmdeV150g15QtICV7eH0gJXtkYXl9INeR15fXldeT16kgJXttb250aH0= - - show: !binary | - 15TXpteS15Q= - - yearly_every_xth_day: !binary | - 15nXldedICV7ZGF5fSDXlCAtJXtkYXlfb2Zfd2Vla30gINeR15vXnCAle21v - bnRofSDXl9eV15PXqQ== - - monthly_options: !binary | - 15TXkteT16jXldeqINec16TXoteV15zXldeqINeR15fXlteV16jXmdeV16og - 15fXldeT16nXmdeq - - no_end_date: !binary | - 15DXmdefINeq15DXqNeZ15og16HXmdeV150= - - show_days_before: !binary | - JXtkYXlzfSDXmdee15nXnSDXnNek16DXmSDXqteQ16jXmdeaINeU15nXoteT - INec157XqdeZ157XlA== - - from_tickler: !binary | - 16rXkNeo15nXmiDXlNeZ16LXkyDXnNee16nXmdee15Qg157XkteZ16Ig157X - lNee1rTXltaw15vWuNa816ggKNec15Ag16DXp9eR16Ig16rXkNeo15nXmiDX - mdei15Mp - - weekly_every_number_week: !binary | - 15fXldeW16gg15vXnCAle251bWJlcn0gINep15HXldeiINeR - - day_x_on_every_x_month: !binary | - 15HXmdeV150gJXtkYXl9INeR15vXnCAle21vbnRofSAg15fXldeT16k= - - weekly_options: !binary | - 15TXkteT16jXldeqINec16TXoteV15zXldeqINeR157Xl9eW15XXqNeZ15XX - qiDXqdeR15XXoteZ16o= - - yearly_every_x_day: "\xD7\x9B\xD7\x9C %{month} %{day}" - recurrence_on_due_date: !binary | - 15nXoteTINec157XqdeZ157XlA== - - error_completing_todo: !binary | - 15DXqNei15Qg16nXkteZ16LXlCDXkdeh15nXldedIC8g15TXpNei15zXlCDX - qdecINee16nXmdee15QgJXtkZXNjcmlwdGlvbn0= - - in_pending_state: !binary | - 15HXntem15Eg15TXnteq16DXlA== - - action_marked_complete_error: !binary | - 15TXpNei15XXnNeUIDxzdHJvbmc+JyV7ZGVzY3JpcHRpb259Jzwvc3Ryb25n - Pta+15zXkNa+INeh15XXnteg15Qg15sgLSA8c3Ryb25nPiV7Y29tcGxldGVk - fSDXoten15Eg16nXkteZ15DXqiDXqdeo16o8L3N0cm9uZz4= - - completed_today: - other: !binary | - 16LXkyDXoteq15Qg15TXodeq15nXmdee15UgJXtjb3VudH0g16TXoteV15zX - qiDXlNeZ15XXnS4= - - one: !binary | - 15TXldep15zXnteUINek16LXldec15Qg15DXl9eqINeU15nXldedLCDXoteT - INei16rXlC4= - - no_hidden_actions: !binary | - 15zXkCDXoNee16bXkNeVINek16LXldec15XXqiDXnteV16HXqteo15XXqg== - - all_completed: !binary | - 15vXnCDXlNek16LXldec15XXqiDXqdeU16HXqteZ15nXnteV - - action_deleted_error: !binary | - 16DXm9ep15zXlCDXnteX15nXp9eqINeU16TXoteV15zXlA== - - action_deleted_success: !binary | - 16TXoteV15zXqiDXlNee16nXmiDXoNee15fXp9eUINeR15TXptec15fXlA== - - star_action_with_description: !binary | - 15TXk9eS16nXqiDXpNei15nXnNeV16ogJyV7ZGVzY3JpcHRpb259Jw== - - unresolved_dependency: !binary | - 15TXoteo15og16nXlNeV15vXoNehINeR16rXnNeV16og15zXkCDXqteQ150g - 15zXkNejINek16LXldec15Qg16fXmdeZ157Xqi4g15TXoteo15og15zXkCDX - mdep157XqCDXotedINeZ16rXqNeqINeU16TXoteV15zXlC4g15zXlNee16nX - mdeaPw== - - completed_actions: !binary | - 16TXoteV15zXldeqINep15TXodeq15nXmdee15U= - - pending: !binary | - 157Xnteq15nXnw== - - error_starring: !binary | - 15TXk9eS16nXqiDXlNee16nXmdee15QgIFwnJXtkZXNjcmlwdGlvbn1cJyDX - nNeQINem15zXl9eU - - delete_recurring_action_title: !binary | - 157Xl9eZ16fXqiDXpNei15XXnNeUINee15fXlteV16jXmdeq - - no_project: !binary | - LS3XkNeZ158g16TXqNeV15nXmden15gtLQ== - - in_hidden_state: !binary | - 15HXntem15Eg157Xldeh16rXqA== - - recurring_actions_title: !binary | - 157Xodec15XXnNeZ1506Otek16LXldec15XXqiDXnteX15bXldeo15nXldeq - - completed_in_archive: - other: !binary | - 16fXmdeZ157XldeqICV7Y291bnR9INek16LXldec15XXqiDXqdeU16HXqteZ - 15nXnteVINeR15DXqNeb15nXldefLg== - - one: !binary | - 16fXmdeZ157XqiDXkdeQ16jXm9eZ15XXnyDXpNei15XXnNeUINep15TXodeq - 15nXmdee15Qu - - error_deleting_item: !binary | - 15DXqNei15Qg16nXkteZ15DXlCDXkdee15fXmden16og15TXpNeo15nXmCAl - e2Rlc2NyaXB0aW9ufQ== - - tagged_page_title: !binary | - 157Xodec15XXnNeZ1506Oteq15LXmdeV16og16LXnSAnJXt0YWdfbmFtZX0n - - no_actions_with: !binary | - 15DXmdefINeb16jXkteiINek16LXldec15XXqiDXqdec15Ag15TXodeq15nX - mdee15XXqiDXotedINeU16rXkteZ16ogJyV7dGFnX25hbWV9Jw== - - feeds: - completed: !binary | - 15TXodeq15nXmdedOiAle2RhdGV9 - - due: !binary | - 15nXoteTICV7ZGF0ZX0= - - no_completed_actions: !binary | - 15DXmdefINeb16jXkteiINek16LXldec15XXqiDXqdeU16HXqteZ15nXnteV - Lg== - - no_actions_found_title: !binary | - 15zXkCDXoNee16bXkCDXpNei15XXnNeV16o= - - error_toggle_complete: !binary | - 15zXkCDXoNeZ16rXnyDXnNeh157XnyDXntep15nXnteUINebIteU16HXqteZ - 15nXnteUIg== - - next_actions_description_additions: - due_date: !binary | - 16LXnSDXqteQ16jXmdeaINeZ16LXkyAle2R1ZV9kYXRlfSDXkNeVINee15XX - p9eT150g15nXldeq16gg - - completed: !binary | - 15EtJXtjb3VudH0g15TXmdee15nXnSDXlNeQ15fXqNeV16DXmded - - list_incomplete_next_actions: !binary | - 16jXqdeZ157XqiDXpNei15XXnNeV16og15TXntep15og16nXnNeQINeU16HX - qteZ15nXnteV - - has_x_pending: - other: !binary | - 157Xm9eZ15wgJXtjb3VudH0g16TXoteV15zXqiDXntee16rXmdeg15XXqg== - - one: !binary | - 15HXotecINek16LXldec15Qg15PXl9eV15nXlCDXkNeX16o= - - deleted_success: !binary | - 15TXpNei15XXnNeUINeg157Xl9en15Qg15HXlNem15zXl9eU - - overdue: !binary | - 15HXkNeZ15fXldeo + will_paginate: + page_entries_info: + multi_page: !binary | + 157XpteZ15IgJXttb2RlbH0gJXtmcm9tfSAtICV7dG99INee16rXldeaICV7 + Y291bnR9INeR16HXmiDXlNeb15w= + + single_page: + other: !binary | + 157XpteZ15Ig15DXqiDXm9ecICV7Y291bnR9ICV7bW9kZWx9 + + zero: !binary | + 15zXkCDXoNee16bXkCAle21vZGVsfQ== + + one: !binary | + 157XpteZ15IgJXttb2RlbH0g15DXl9eT + + multi_page_html: !binary | + 157XpteZ15IgJXttb2RlbH0gPGI+JXtmcm9tfSZuYnNwOy0mbmJzcDsle3Rv + fTwvYj4g157XqteV15ogPGI+JXtjb3VudH08L2I+INeR16HXmiDXlNeb15w= + + single_page_html: + other: "\xD7\x9E\xD7\xA6\xD7\x99\xD7\x92 \xD7\x9B\xD7\x9C %{count} %{model}" + zero: !binary | + 15zXkCDXoNee16bXkCAle21vZGVsfQ== + + one: "\xD7\x9E\xD7\xA6\xD7\x99\xD7\x92 1 %{model}" + previous_label: !binary | + JmxhcXVvOyDXlNen15XXk9ed + + page_gap: "…" + next_label: !binary | + 15TXkdeQICZyYXF1bzs= integrations: applescript_success_before_id: !binary | @@ -891,301 +41,345 @@ he: 15fWstek1rTXmdelINec15TXldeh16TXqiDXnteh15zXldec15nXnSDXnC1H bWFpbA== - opensearch_description: !binary | - 15fXmdek15XXqSDXkdee16HXnNeV15zXmded + applescript_next_action_prompt: !binary | + 16rXmdeQ15XXqCDXlNek16LXldec15XXqiDXlNeR15DXldeqOg== applescript_success_after_id: !binary | 16DXldem16g= - applescript_next_action_prompt: !binary | - 16rXmdeQ15XXqCDXlNek16LXldec15XXqiDXlNeR15DXldeqOg== + opensearch_description: !binary | + 15fXmdek15XXqSDXkdee16HXnNeV15zXmded - activerecord: - attributes: - project: - default_context_name: !binary | - 15TXp9ep16gg15HXqNeZ16jXqiDXnteX15PXnA== + projects: + edit_project_settings: !binary | + 16LXqNeZ15vXqiDXlNeS15PXqNeV16og16TXqNeV15nXmden15g= - default_tags: !binary | - 16rXkteZ15XXqiDXkdeo15nXqNeqINee15fXk9ec + deferred_actions_empty: !binary | + 15DXmdefINek16LXldec15XXqiDXqdeg15PXl9eVINei15HXldeoINek16jX + ldeZ15nXp9eYINeW15Q= - name: !binary | - 16nXnQ== + hide_form_title: !binary | + 15TXodeq16jXqiDXmNeV16TXoSDXpNeo15XXmdeZ16fXmCDXl9eT16k= - description: !binary | - 16rXmdeQ15XXqA== + completed_projects: !binary | + 16TXqNeV15nXmden15jXmdedINep15TXodeq15nXmdee15U= - todo: - show_from: !binary | - 15TXpteSINee + no_default_context: !binary | + 15DXmdefINeU16fXqdeoINeR16jXmdeo16og157Xl9eT15wg15zXpNeo15XX + mdeZ16fXmCDXlteU - project: !binary | - 16TXqNeV15nXmden15jXmded + settings: !binary | + 15TXkteT16jXldeq - context: !binary | - 15TXp9ep16g= + add_note_submit: !binary | + 15TXldeh16TXqiDXpNeq16c= - due: !binary | - 16rXkNeo15nXmiDXmdei15M= + no_last_completed_projects: !binary | + 15zXkCDXoNee16bXkNeVINek16jXldeZ15nXp9eY15nXnSDXqdeU16HXqteZ + 15nXnteV - predecessors: !binary | - 16rXnNeV15kg15E= + notes_empty: !binary | + 15DXmdefINek16rXp9eZ15XXqiDXnNek16jXldeZ15nXp9eYINeW15Q= - notes: !binary | - 16TXqten15nXnQ== + with_default_context: !binary | + 16LXnSDXlNen16nXqCDXkdeZ16jXqiDXnteX15PXnCAnJXtjb250ZXh0X25h + bWV9Jw== - description: !binary | - 16rXmdeQ15XXqA== + show_form: !binary | + 15TXldeh16TXqiDXpNeo15XXmdeZ16fXmA== - user: - last_name: !binary | - 16nXnSDXntep16TXl9eU + with_default_tags: !binary | + 16LXnSDXlNeq15LXmdeV16ogICcle3RhZ3N9JyDXm9eR16jXmdeo16og15TX + nteX15PXnA== - first_name: !binary | - 16nXnSDXpNeo15jXmQ== + completed_tasks_title: !binary | + 157Xodec15XXnNeZ1506OteU16bXkteqINeo16nXmdee16og15TXntep15nX + nteV16og16nXlNeV16nXnNee15Ug15HXpNeo15XXmdeZ16fXmCAgJyV7cHJv + amVjdF9uYW1lfSc= - preference: - sms_context: !binary | - 15PXldeQItecINeR16jXmdeo16og157Xl9eT16gg16LXkdeV16gg15TXp9ep - 16g= + edit_project_title: !binary | + 16LXqNeZ15vXqiDXpNeo15XXmdeZ16fXmA== - time_zone: !binary | - 15DXlteV16gg15bXntef + to_new_project_page: !binary | + 16LXkdeV16gg15zXotee15XXkyDXlNek16jXldeZ15nXp9eYINeU15fXk9ep - refresh: !binary | - 16rXk9eZ16jXldeqINeo16LXoNeV158gKNeR15PXp9eV16op + project_saved_status: !binary | + 16TXqNeV15nXmden15gg16DXqdee16g= - last_name: !binary | - 16nXnSDXntep16TXl9eU + default_context_removed: !binary | + 15TXp9ep16gg15HXqNeZ16jXqiDXlNee15fXk9ecINeU15XXodeo - date_format: !binary | - 157Xkdeg15Qg16rXkNeo15nXmg== + default_context_set: !binary | + 15HXl9eZ16jXqiDXlNen16nXqCDXkdeo15nXqNeqINeU157Xl9eT15wg15zX + pNeo15XXmdeZ16fXmCDXnC0le2RlZmF1bHRfY29udGV4dH0= - show_project_on_todo_done: !binary | - 16LXkdeV16gg15zXotee15XXkyDXlNek16jXldeZ15nXp9eYINeR16HXmdeV - 150g157XqdeZ157XlA== + with_no_default_tags: !binary | + 15XXnNec15Ag16rXkteZ15XXqiDXkdeo15nXqNeqINee15fXk9ec - review_period: !binary | - 16rXk9eZ16jXldeqINeo16LXoNeV158g16TXqNeV15nXmden15g= + was_marked_hidden: !binary | + 16HXldee158g15vXnteV16HXqteo - week_starts: !binary | - 16nXkdeV16Ig157XqteX15nXnCDXkdeZ15XXnQ== + no_projects: !binary | + 15DXmdefINeb16jXkteiINek16jXldeZ15nXp9eY15nXnQ== - due_style: !binary | - 16HXkteg15XXnyDXqteQ16jXmdeaINeZ16LXkw== + delete_project: !binary | + 157Xl9eZ16fXqiDXpNeo15XXmdeZ16fXmA== - show_number_completed: !binary | - 15TXpteSINee16HXpNenINek16LXldec15XXqiDXqdeR15XXptei15U= + delete_project_title: !binary | + 157Xl9eZ16fXqiDXlNek16jXldeZ15nXp9eY - mobile_todos_per_page: !binary | - 157Xodek16gg16TXoteV15zXldeqINec15PXoyAo16rXpteV15LXlCDXoNeZ - 15nXk9eqKQ== + active_projects: !binary | + 16TXqNeV15nXmden15jXmdedINek16LXmdec15nXnQ== - show_hidden_projects_in_sidebar: !binary | - 15TXpteSINek16jXldeZ15nXp9eY15nXnSAg157Xldeh16rXqNeZ150g15HX - pteT + list_completed_projects: !binary | + 157Xodec15XXnNeZ1506Oteo16nXmdee16og15TXpNeo15XXmdeZ16fXmNeZ + 150g16nXlNeV15zXqdee15U= - show_completed_projects_in_sidebar: !binary | - 15TXpteSINek16jXldeZ15nXp9eY15nXnSDXqdeU16HXqteZ15nXnteVINeR - 16bXkw== + no_last_completed_recurring_todos: !binary | + 15zXkCDXoNee16bXkNeVINee16nXmdee15XXqiDXnteX15bXldeo15nXldeq + INep15TXodeq15nXmdee15U= - sms_email: !binary | - 15PXldeQ16gg157XkNeq + state: !binary | + 15TXpNeo15XXmdeZ16fXmCDXkdee16bXkSAle3N0YXRlfQ== - locale: !binary | - 16nXpNeU + completed_actions_empty: !binary | + 15DXmdefINek16LXldec15XXqiDXqdeU16HXqteZ15nXnteVINeR16TXqNeV + 15nXmden15gg15bXlA== - verbose_action_descriptors: !binary | - 16rXmdeQ15XXqNeZINee16nXmdee15XXqiDXntek15XXqNeY15nXnQ== + add_project: !binary | + 15TXldeh16TXqiDXpNeo15XXmdeZ16fXmA== - first_name: !binary | - 16nXnSDXpNeo15jXmQ== + was_marked_complete: !binary | + 16HXldee158g15vXkdeV16bXog== - title_date_format: !binary | - 157Xkdeg15Qg16rXkNeo15nXmiDXm9eV16rXqNeq + no_actions_in_project: !binary | + 15DXmdefINeb16jXkteiINee16nXmdee15XXqiDXqdecINeU15XXqdec157X + lSDXkdek16jXldeZ15nXp9eYINeW15Q= - show_hidden_contexts_in_sidebar: !binary | - 15TXpteSINeU16fXqdeo15nXnSDXnteV16HXqteo15nXnSDXkdem15M= + page_title: !binary | + 157Xodec15XXnNeZ1506Otek16jXldeZ15nXp9eYOiAle3Byb2plY3R9 - staleness_starts: !binary | - 15TXqteX15zXqiDXqtek15zXldeq + delete_project_confirmation: !binary | + 15TXkNedINec157Xl9eV16cg15DXqiDXlNek16jXldeZ15nXp9eYICAnJXtu + YW1lfSc/ - errors: - models: - project: - attributes: - name: - blank: !binary | - 15zXpNeo15XXmdeZ16fXmCDXl9eZ15nXkSDXnNeU15nXldeqINep150= + actions_in_project_title: !binary | + 16TXoteV15zXldeqINeR16TXqNeV15nXmden15gg15bXlA== - taken: !binary | - 15vXkdeoINen15nXmded + add_note: !binary | + 15TXldeh16TXqiDXpNeq16c= - too_long: !binary | - 16LXnCDXqdedINeU16TXqNeV15nXmden15gg15zXlNeb15nXnCDXpNeX15XX - qiDXni0yNTYg16rXldeV15nXnQ== + list_projects: !binary | + 157Xodec15XXnNeZ1506Oteo16nXmdee16og16TXqNeV15nXmden15jXmded - template: - header: - other: !binary | - 16nXkteZ15DXldeqINee16DXoteVINee157XldeT15wgJXttb2RlbH0g15zX - lNeZ16nXnteo + todos_append: !binary | + 15HXpNeo15XXmdeZ16fXmCDXlteU - one: !binary | - 16nXkteZ15DXlCDXnteg16LXlCDXntee15XXk9ecICV7bW9kZWx9INec15TX - mdep157XqA== + default_tags_removed_notice: !binary | + 16rXkteZ15XXqiDXkdeo15nXqNeqINeU157Xl9eT15wg15TXldeh16jXlQ== - body: !binary | - 15HXoteZ15XXqiDXkdep15PXldeqINeU15HXkNeZ1506 + no_notes_attached: !binary | + 15DXmdefINeb16jXkteiINek16rXp9eZ15XXqiDXlNee16fXldep16jXldeq + INec16TXqNeV15nXmden15gg15bXlA== - messages: - exclusion: !binary | - 16nXnteV16g= + project_state: !binary | + 15TXpNeo15XXmdeZ16fXmCAle3N0YXRlfQ== - blank: !binary | - 15zXkCDXmdeb15XXnCDXnNeU15nXldeqINeo15nXpw== + hidden_projects: !binary | + 16TXqNeV15nXmden15jXmdedINep15TXldeh16rXqNeV - too_short: !binary | - 16fXpteoINem15PXmSAo15zXm9ecINeU16TXl9eV16ogJXtjb3VudH0g16rX - ldeV15nXnSg= + deferred_actions: !binary | + 16TXoteV15zXldeqINep16DXk9eX15Ug16LXkdeV16gg16TXqNeV15nXmden + 15gg15bXlA== - empty: !binary | - 15zXkCDXmdeb15XXnCDXnNeU15nXldeqINeo15nXpw== + default_context: !binary | + 15TXp9ep16gg15HXqNeZ16jXqiDXlNee15fXk9epINec16TXqNeV15nXmden + 15gg15bXlCAle2NvbnRleHR9 - taken: !binary | - 15vXkdeoINeg157XpteQINeR16nXmdee15XXqQ== + set_default_tags_notice: !binary | + 15HXl9eZ16jXqiDXqteS15nXldeqINeR16jXmdeo16og15TXnteX15PXnCDX + nC0le2RlZmF1bHRfdGFnc30= - wrong_length: !binary | - 15HXkNeV16jXmiDXnNeQINeg15vXldefICjXpteo15nXmiDXnNeU15nXldeq - ICV7Y291bnR9INeq15XXldeZ150o + completed_actions: !binary | + 16TXoteV15zXldeqINep15TXodeq15nXmdee15Ug15HXpNeo15XXmdeZ16fX + mCDXlteU - record_invalid: !binary | - 15DXmdee15XXqiDXoNeb16nXnCAle2Vycm9yc30= + status_project_name_changed: !binary | + 16nXnSDXlNek16jXldeZ15nXp9eYINep15XXoNeU - inclusion: !binary | - 15zXkCDXnteV15vXnCDXkdeo16nXmdee15Q= + with_no_default_context: !binary | + 15zXnNeQINeU16fXqdeoINeR16jXmdeo16og157Xl9eT15w= - greater_than_or_equal_to: !binary | - 15fXmdeZ15Eg15zXlNeZ15XXqiDXkteV15PXnCDXkNeVINep15XXldeUINec - ICV7Y291bnR9 + all_completed_tasks_title: !binary | + 157Xodec15XXnNeZ1506OteU16bXkteqINeo16nXmdee16og15vXnCDXlNee + 16nXmdee15XXqiDXqdeU15XXqdec157XlSDXkdek16jXldeZ15nXp9eYICAn + JXtwcm9qZWN0X25hbWV9Jw== - confirmation: !binary | - 15DXmdeg15Ug16rXldeQ150g15DXqiDXlNeQ15nXqdeV16g= - - accepted: !binary | - 15fXmdeZ15Eg15zXlNeq16fXkdec - - greater_than: !binary | - 15fXmdeZ15Eg15zXlNeZ15XXqiDXkteT15XXnCDXniAle2NvdW50fQ== - - too_long: !binary | - 15DXqNeV15og157Xk9eZICjXnNeb15wg15TXmdeV16rXqCAle2NvdW50fSDX - qteV15XXmdedKA== - - less_than_or_equal_to: !binary | - 15fXmdeZ15Eg15zXlNeZ15XXqiDXp9eY158g15DXlSDXqdeV15XXlCDXnCAl - e2NvdW50fQ== - - not_a_number: !binary | - 15DXmdeg15Ug157Xodek16g= - - less_than: !binary | - 15fXmdeZ15Eg15zXlNeZ15XXqiDXp9eY158g154gJHtjb3VudH0= - - equal_to: !binary | - 15fXmdeZ15Eg15zXlNeZ15XXqiDXqdeV15XXlCDXnCAle2NvdW50fQ== - - invalid: !binary | - 15zXkCDXmdeb15XXnCDXnNeU15vXmdecINeQ16og16rXlSAoJywnKSDXlNek - 16HXmden - - even: !binary | - 15fXmdeZ15Eg15zXlNeZ15XXqiDXlteV15LXmQ== - - odd: !binary | - 15fXmdeZ15Eg15zXlNeZ15XXqiDXkNeZINeW15XXkteZ - - full_messages: - format: "%{attribute} %{message}" - states: - stalled: !binary | - 16DXotem16g= - - current_plural: !binary | - 157XoteV15PXm9eg15nXnQ== - - active: !binary | + is_active: !binary | 16TXoteZ15w= - stalled_plural: !binary | - 16LXpteV16jXmded + hide_form: !binary | + 15TXodeq16jXqiDXmNeV16TXoQ== - active_plural: !binary | - 16TXoteZ15zXmded + show_form_title: !binary | + 15nXpteZ16jXqiDXpNeo15XXmdeZ16fXmCDXl9eT16k= - review_plural: !binary | - 157XqteV15DXqNeb15nXnQ== + notes: !binary | + 16TXqten15nXldeq - review: !binary | - 157XqteV15DXqNea + this_project: !binary | + 16TXqNeV15nXmden15gg15bXlA== - visible: !binary | - 15LXnNeV15k= + list_reviews: !binary | + 157Xodec15XXnNeZ1506Oteh16fXmdeo15Q= - completed: !binary | - 15TXodeq15nXmded + errors: + user_unauthorized: !binary | + NDAxINec15Ag157XkNeV16nXqDog16jXpyDXntep16rXntep15nXnSDXkdeT + 16jXkteqINee16DXlNecINeo16nXkNeZ150g15zXlNek16LXmdecINek16LX + ldec15Qg15bXlQ== - visible_plural: !binary | - 15LXnNeV15nXmded + support: + array: + words_connector: "," + last_word_connector: !binary | + LCDXlS0= - blocked: !binary | - 16DXl9eh150= + two_words_connector: !binary | + 15Ut - blocked_plural: !binary | - 15fXodeV157Xmded + select: + prompt: !binary | + 15nXqSDXnNeR16bXoiDXkdeX15nXqNeU - hidden_plural: !binary | - 157Xldeh16rXqNeZ150= + login: + log_in_again: !binary | + 15vXoNeZ16HXlCDXnteX15XXk9ep16o= - completed_plural: !binary | - 15TXodeq15nXmdee15U= + cas_login: !binary | + 15TXqteX15HXqNeV16og16nXkCLXniAo16nXmdeo15XXqiDXkNeZ157Xldeq + INee16jXm9eW15kp - current: !binary | - 16LXk9eb16DXmQ== + mobile_use_openid: !binary | + Li4u15DXlSDXm9eg15nXodeUINei150gT3BlbklE - hidden: !binary | - 157Xldeh16rXqNeZ150= + cas_signup_link: !binary | + 15HXp9ep16og157Xqdeq157XqQ== + + login_standard: !binary | + 15fXlteo15Qg15zXm9eg15nXodeUINeU16jXkteZ15zXlA== + + session_time_out: !binary | + 16TXkiDXqteV16fXoyDXlNeS15nXqdeULiDXoNeQICV7bGlua30= + + login_cas: !binary | + 15TXktei15Qg15DXnCDXqdeQItee + + sign_in: !binary | + 15vXoNeZ16HXlA== + + session_will_not_expire: !binary | + 15TXkteZ16nXlCDXnNec15Ag16rXpNeV15LXlC4= + + login_with_openid: !binary | + 15vXoNeZ16HXlCDXotecIE9wZW5JRA== + + cas_username_not_found: !binary | + 15zXptei16jXoNeVLCDXnNeQINen15nXmdedINee16nXqtee16kg16nXkCLX + niDXkdep150gKCV7dXNlcm5hbWV9KQ== + + cas_create_account: !binary | + 15DXnSDXkdeo16bXldeg15og15zXkden16kg15nXqSDXnNeU157XqdeZ15og + 15wtJXtzaWdudXBfbGlua30= + + logged_out: !binary | + 15HXldem16LXlCDXmdem15nXkNeUINeeLdee16HXnNeV15zXmded + + please_login: !binary | + 15nXqSDXnNeU15vXoNehINeb15PXmSDXnNeU16nXqtee16kg15Et157Xodec + 15XXnNeZ150= + + account_login: !binary | + 15vXoNeZ16HXlCDXnNeX16nXkdeV158= + + session_will_expire: !binary | + 16rXlden16Mg15TXkteZ16nXlCDXmdek15XXkiDXnNeQ15fXqCAle2hvdXJz + fSDXqdei15Qo15XXqikg16nXnCDXl9eV16HXqCDXpNei15nXnNeV16ou + + unsuccessful: !binary | + 15vXoNeZ16HXlCDXoNeb16nXnNeULg== + + openid_identity_url_not_found: !binary | + 15zXptei16jXoNeVLCDXnNeQINen15nXmdedINee16nXqtee16kg16LXnSDX + m9eq15XXkdeqINeW15TXldeqICAoJXtpZGVudGl0eV91cmx9KQ== + + successful: !binary | + 15vXoNeZ16HXlCDXkdeV16bXoteUINeR15TXptec15fXlC4g15HXqNeV15og + 16nXldeR15oh + + cas_no_user_found: !binary | + JXt1c2VybmFtZX0g16nXnNeV150hINeQ15nXnyDXl9ep15HXldefINeR16nX + nSDXlteUINeR157Xodec15XXnNeZ150u + + successful_with_session_info: !binary | + 15vXoNeZ16HXlCDXnteV16bXnNeX16o6 + + cas_logged_in_greeting: !binary | + 16nXnNeV150gJXt1c2VybmFtZX0hINeU15bXmdeU15XXmSDXlNem15zXmdeX + + option_separator: !binary | + 15DXlSw= + + user_no_expiry: !binary | + 15TXqdeQ16jXqiDXl9eZ15HXldeo + + sidebar: + list_name_active_contexts: !binary | + 15TXp9ep16jXmdedINek16LXmdec15nXnQ== + + list_name_completed_projects: !binary | + 16TXqNeV15nXmden15jXmdedINep15TXodeq15nXmdee15U= + + list_name_hidden_projects: !binary | + 16TXqNeV15nXmden15jXmdedINee15XXodeq16jXmded + + list_name_hidden_contexts: !binary | + 15TXp9ep16jXmdedINee15XXodeq16jXmded + + list_name_active_projects: !binary | + 16TXqNeV15nXmden15jXmdedINek16LXmdec15nXnQ== + + list_empty: !binary | + 15DXmdef datetime: - prompts: - minute: !binary | - 15PXp9eU - - hour: !binary | - 16nXoteU - - year: !binary | - 16nXoNeU - - month: !binary | - 15fXldeT16k= - - second: !binary | - 16nXoNeZ15XXqg== - - day: !binary | - 15nXlded - distance_in_words: - almost_x_years: + about_x_years: other: !binary | - 15vXntei15ggJXtjb3VudH0g16nXoNeZ150= + 15stJXtjb3VudH0g16nXoNeZ150= one: !binary | - 15vXntei15gg16nXoNeU + 15vXqdeg15Q= - half_a_minute: !binary | - 15fXpteZINeT16fXlA== + less_than_x_seconds: + other: !binary | + 16TXl9eV16og154tJXtjb3VudH0g16nXoNeZ15XXqg== + + zero: !binary | + 16TXl9eV16og157Xqdeg15nXmdeU + + one: !binary | + 16TXl9eV16og157Xqdeg15nXmdeU + + less_than_x_minutes: + other: !binary | + 16TXl9eV16og154tJXtjb3VudH0g15PXp9eV16o= + + zero: !binary | + 16TXl9eV16og157Xk9en15Q= + + one: !binary | + 16TXl9eV16og157Xk9en15Q= x_minutes: other: !binary | @@ -1194,6 +388,34 @@ he: one: !binary | 15PXp9eU + almost_x_years: + other: !binary | + 15vXntei15ggJXtjb3VudH0g16nXoNeZ150= + + one: !binary | + 15vXntei15gg16nXoNeU + + about_x_months: + other: !binary | + 15stJXtjb3VudH0g15fXldeT16nXmded + + one: !binary | + 15vXl9eV15PXqQ== + + x_seconds: + other: !binary | + JXtjb3VudH0g16nXoNeZ15XXqg== + + one: !binary | + 16nXoNeZ15nXlA== + + over_x_years: + other: !binary | + 157XotecICV7Y291bnR9INep16DXmded + + one: !binary | + 157Xotec15Qg15zXqdeg15Q= + about_x_hours: other: !binary | 15stJXtjb3VudH0g16nXoteV16o= @@ -1208,47 +430,6 @@ he: one: !binary | 15fXldeT16k= - x_seconds: - other: !binary | - JXtjb3VudH0g16nXoNeZ15XXqg== - - one: !binary | - 16nXoNeZ15nXlA== - - less_than_x_seconds: - other: !binary | - 16TXl9eV16og154tJXtjb3VudH0g16nXoNeZ15XXqg== - - zero: !binary | - 16TXl9eV16og157Xqdeg15nXmdeU - - one: !binary | - 16TXl9eV16og157Xqdeg15nXmdeU - - over_x_years: - other: !binary | - 157XotecICV7Y291bnR9INep16DXmded - - one: !binary | - 157Xotec15Qg15zXqdeg15Q= - - less_than_x_minutes: - other: !binary | - 16TXl9eV16og154tJXtjb3VudH0g15PXp9eV16o= - - zero: !binary | - 16TXl9eV16og157Xk9en15Q= - - one: !binary | - 16TXl9eV16og157Xk9en15Q= - - about_x_months: - other: !binary | - 15stJXtjb3VudH0g15fXldeT16nXmded - - one: !binary | - 15vXl9eV15PXqQ== - x_days: other: !binary | JXtjb3VudH0g15nXnteZ150= @@ -1256,106 +437,1508 @@ he: one: !binary | 15nXlded - about_x_years: - other: !binary | - 15stJXtjb3VudH0g16nXoNeZ150= + half_a_minute: !binary | + 15fXpteZINeT16fXlA== - one: !binary | - 15vXqdeg15Q= + prompts: + hour: !binary | + 16nXoteU - errors: - user_unauthorized: !binary | - NDAxINec15Ag157XkNeV16nXqDog16jXpyDXntep16rXntep15nXnSDXkdeT - 16jXkteqINee16DXlNecINeo16nXkNeZ150g15zXlNek16LXmdecINek16LX - ldec15Qg15bXlQ== + second: !binary | + 16nXoNeZ15XXqg== + + day: !binary | + 15nXlded + + minute: !binary | + 15PXp9eU + + month: !binary | + 15fXldeT16k= + + year: !binary | + 16nXoNeU + + activerecord: + errors: + template: + body: !binary | + 15HXoteZ15XXqiDXkdep15PXldeqINeU15HXkNeZ1506 + + header: + other: !binary | + 16nXkteZ15DXldeqINee16DXoteVINee157XldeT15wgJXttb2RlbH0g15zX + lNeZ16nXnteo + + one: !binary | + 16nXkteZ15DXlCDXnteg16LXlCDXntee15XXk9ecICV7bW9kZWx9INec15TX + mdep157XqA== + + messages: + greater_than: !binary | + 15fXmdeZ15Eg15zXlNeZ15XXqiDXkteT15XXnCDXniAle2NvdW50fQ== + + confirmation: !binary | + 15DXmdeg15Ug16rXldeQ150g15DXqiDXlNeQ15nXqdeV16g= + + too_short: !binary | + 16fXpteoINem15PXmSAo15zXm9ecINeU16TXl9eV16ogJXtjb3VudH0g16rX + ldeV15nXnSg= + + equal_to: !binary | + 15fXmdeZ15Eg15zXlNeZ15XXqiDXqdeV15XXlCDXnCAle2NvdW50fQ== + + too_long: !binary | + 15DXqNeV15og157Xk9eZICjXnNeb15wg15TXmdeV16rXqCAle2NvdW50fSDX + qteV15XXmdedKA== + + exclusion: !binary | + 16nXnteV16g= + + less_than: !binary | + 15fXmdeZ15Eg15zXlNeZ15XXqiDXp9eY158g154gJHtjb3VudH0= + + inclusion: !binary | + 15zXkCDXnteV15vXnCDXkdeo16nXmdee15Q= + + accepted: !binary | + 15fXmdeZ15Eg15zXlNeq16fXkdec + + blank: !binary | + 15zXkCDXmdeb15XXnCDXnNeU15nXldeqINeo15nXpw== + + odd: !binary | + 15fXmdeZ15Eg15zXlNeZ15XXqiDXkNeZINeW15XXkteZ + + invalid: !binary | + 15zXkCDXmdeb15XXnCDXnNeU15vXmdecINeQ16og16rXlSAoJywnKSDXlNek + 16HXmden + + wrong_length: !binary | + 15HXkNeV16jXmiDXnNeQINeg15vXldefICjXpteo15nXmiDXnNeU15nXldeq + ICV7Y291bnR9INeq15XXldeZ150o + + less_than_or_equal_to: !binary | + 15fXmdeZ15Eg15zXlNeZ15XXqiDXp9eY158g15DXlSDXqdeV15XXlCDXnCAl + e2NvdW50fQ== + + not_a_number: !binary | + 15DXmdeg15Ug157Xodek16g= + + record_invalid: !binary | + 15DXmdee15XXqiDXoNeb16nXnCAle2Vycm9yc30= + + taken: !binary | + 15vXkdeoINeg157XpteQINeR16nXmdee15XXqQ== + + even: !binary | + 15fXmdeZ15Eg15zXlNeZ15XXqiDXlteV15LXmQ== + + greater_than_or_equal_to: !binary | + 15fXmdeZ15Eg15zXlNeZ15XXqiDXkteV15PXnCDXkNeVINep15XXldeUINec + ICV7Y291bnR9 + + empty: !binary | + 15zXkCDXmdeb15XXnCDXnNeU15nXldeqINeo15nXpw== + + models: + project: + attributes: + name: + too_long: !binary | + 16LXnCDXqdedINeU16TXqNeV15nXmden15gg15zXlNeb15nXnCDXpNeX15XX + qiDXni0yNTYg16rXldeV15nXnQ== + + blank: !binary | + 15zXpNeo15XXmdeZ16fXmCDXl9eZ15nXkSDXnNeU15nXldeqINep150= + + taken: !binary | + 15vXkdeoINen15nXmded + + full_messages: + format: "%{attribute} %{message}" + attributes: + todo: + description: !binary | + 16rXmdeQ15XXqA== + + show_from: !binary | + 15TXpteSINee + + predecessors: !binary | + 16rXnNeV15kg15E= + + tags: !binary | + 16rXkteZ15XXqg== + + project: !binary | + 16TXqNeV15nXmden15jXmded + + due: !binary | + 16rXkNeo15nXmiDXmdei15M= + + context: !binary | + 15TXp9ep16g= + + notes: !binary | + 16TXqten15nXldeq + + note: + created_at: !binary | + 16DXldem16gg15E= + + updated_at: !binary | + 16LXldeT15vXnyDXkQ== + + user: + first_name: !binary | + 16nXnSDXpNeo15jXmQ== + + last_name: !binary | + 16nXnSDXntep16TXl9eU + + project: + name: !binary | + 16nXnQ== + + description: !binary | + 16rXmdeQ15XXqA== + + default_context_name: !binary | + 15TXp9ep16gg15HXqNeZ16jXqiDXnteX15PXnA== + + default_tags: !binary | + 16rXkteZ15XXqiDXkdeo15nXqNeqINee15fXk9ec + + preference: + review_period: !binary | + 16rXk9eZ16jXldeqINeo16LXoNeV158g16TXqNeV15nXmden15g= + + locale: !binary | + 16nXpNeU + + date_format: !binary | + 157Xkdeg15Qg16rXkNeo15nXmg== + + show_project_on_todo_done: !binary | + 16LXkdeV16gg15zXotee15XXkyDXlNek16jXldeZ15nXp9eYINeR16HXmdeV + 150g157XqdeZ157XlA== + + show_hidden_projects_in_sidebar: !binary | + 15TXpteSINek16jXldeZ15nXp9eY15nXnSDXnteV16HXqteo15nXnSDXkdem + 15M= + + show_completed_projects_in_sidebar: !binary | + 15TXpteSINek16jXldeZ15nXp9eY15nXnSDXqdeU16HXqteZ15nXnteVINeR + 16bXkw== + + verbose_action_descriptors: !binary | + 16rXmdeQ15XXqNeZINee16nXmdee15XXqiDXntek15XXqNeY15nXnQ== + + sms_context: !binary | + 15PXldeQItecINeR16jXmdeo16og157Xl9eT16gg16LXkdeV16gg15TXp9ep + 16g= + + first_name: !binary | + 16nXnSDXpNeo15jXmQ== + + sms_email: !binary | + 15PXldeQ16gg157XkNeq + + due_style: !binary | + 16HXkteg15XXnyDXqteQ16jXmdeaINeZ16LXkw== + + last_name: !binary | + 16nXnSDXntep16TXl9eU + + refresh: !binary | + 16rXk9eZ16jXldeqINeo16LXoNeV158gKNeR15PXp9eV16op + + title_date_format: !binary | + 157Xkdeg15Qg16rXkNeo15nXmiDXm9eV16rXqNeq + + show_number_completed: !binary | + 15TXpteSINee16HXpNenINek16LXldec15XXqiDXqdeR15XXptei15U= + + staleness_starts: !binary | + 15TXqteX15zXqiDXqtek15zXldeq + + week_starts: !binary | + 16nXkdeV16Ig157XqteX15nXnCDXkdeZ15XXnQ== + + show_hidden_contexts_in_sidebar: !binary | + 15TXpteSINeU16fXqdeo15nXnSDXnteV16HXqteo15nXnSDXkdem15M= + + mobile_todos_per_page: !binary | + 157Xodek16gg16TXoteV15zXldeqINec15PXoyAo16rXpteV15LXlCDXoNeZ + 15nXk9eqKQ== + + time_zone: !binary | + 15DXlteV16gg15bXntef + + data: + import_successful: !binary | + 15nXkdeV15Ag15HXldem16Ig15HXlNem15zXl9eU + + import_errors: !binary | + 16nXkteZ15DXldeqINeR15nXkdeV15A= + + date: + formats: + short: "%b %d " + longer: "%A %B %d, %Y" + default: "%Y-%m-%d " + long: "%B %d, %Y " + shared: + toggle_single_title: !binary | + 15TXldeh16TXqiDXpNei15XXnNeqINeU157XqdeaINeX15PXqdeU + + toggle_multi_title: !binary | + 15jXldek16Eg16nXmdeg15XXmSDXntem15Eg16TXoteV15zXlCDXkdeV15PX + k9eqIC8g16TXoteV15zXldeqINee16jXldeR15XXqg== + + toggle_multi: !binary | + 15TXldeh16TXqiDXpNei15XXnNeV16og15TXntep15og157XqNeV15HXldeq + + separate_tags_with_commas: !binary | + 157Xldek16jXkyDXkdek16HXmden15nXnQ== + + add_action: !binary | + 15TXldeh16TXqiDXpNei15XXnNeU + + tags_for_all_actions: !binary | + 16rXkteZ15XXqiDXnNeb15wg15TXpNei15XXnNeV16ogKNeZ16kg15zXlNek + 16jXmdeTINeR16TXodeZ16fXmdedKQ== + + multiple_next_actions: !binary | + 16TXoteV15zXldeqINeU157XqdeaINee16jXldeR15XXqiAo16TXoteV15zX + lCDXkNeX16og15HXqdeV16jXlCk= + + add_actions: !binary | + 15TXldeh16TXqiDXpNei15XXnNeU + + context_for_all_actions: !binary | + 15TXp9ep16gg15zXm9ecINeU16TXoteV15zXldeq + + hide_action_form_title: !binary | + 15TXodeq16jXqiDXmNeV16TXoSDXpNei15XXnNeV16og15fXk9ep15XXqg== + + make_actions_dependent: !binary | + 15nXpteZ16jXqiDXqtec15XXqiDXkdeZ158g16TXoteV15zXldeq + + toggle_single: !binary | + 15TXldeh16TXqiDXpNei15XXnNeqINeU157Xqdea + + project_for_all_actions: !binary | + 16TXqNeV15nXmden15gg15zXm9ecINeU16TXoteV15zXldeq + + hide_form: !binary | + 15TXodeq16jXqiDXmNeV16TXoQ== + + add_context: !binary | + 15TXldeh16TXqiDXlNen16nXqA== + + time: + pm: !binary | + 15DXl9eUItem + + formats: + short: "%d %b %H:%M " + stats: "%a %d-%m" + default: "%a, %d %b %Y %H:%M:%S %z " + month_day: "%B %d " + long: "%B %d, %Y " + am: !binary | + 15zXpNeg15Qi16Y= + + todos: + added_new_project: !binary | + 16DXldeh16Mg16TXqNeV15nXmden15gg15fXk9ep + + recurring_action_saved: !binary | + 16TXoteV15zXlCDXnteX15bXldeo15nXqiDXoNep157XqNeU + + completed_recurrence_completed: !binary | + 15DXmdefINek16LXldec16og15TXntep15og15zXpNei15XXnNeUINeU157X + l9eW15XXqNeZ16og16nXoNee15fXp9eULiDXlNek16LXldec15Qg15TXnteX + 15bXldeo15nXqiDXoNee15fXp9eULg== + + all_completed_tagged_page_title: !binary | + 157Xodec15XXnNeZ1506Oteb15wg15TXpNei15XXnNeV16og16nXlNeh16rX + mdeZ157XlSDXotedINeU16rXkteZ16ogJXt0YWdfbmFtZX0= + + depends_on_separate_with_commas: !binary | + 16rXnNeV15kg15EtICjXmdepINec15TXpNeo15nXkyDXkdek16HXmden15nX + nSg= + + next_actions_description_additions: + due_date: !binary | + 16LXnSDXqteQ16jXmdeaINeZ16LXkyAle2R1ZV9kYXRlfSDXkNeVINee15XX + p9eT150g15nXldeq16gg + + completed: !binary | + 15EtJXtjb3VudH0g15TXmdee15nXnSDXlNeQ15fXqNeV16DXmded + + next_action_description: !binary | + 16rXmdeQ15XXqCDXpNei15XXnNeqINeU157Xqdea + + calendar_page_title: !binary | + 157Xodec15XXnNeZ1506Otec15XXlyDXqdeg15Q= + + calendar: + no_actions_due_after_this_month: !binary | + 15DXmdefINek16LXldec15XXqiDXnNeR15nXpteV16Ig15zXkNeX16gg15fX + ldeT16kg15bXlA== + + due_this_month: !binary | + 16rXkNeo15nXmiDXmdei15Mg15zXmdeq16jXqiDXl9eV15PXqSAle21vbnRo + fQ== + + no_actions_due_today: !binary | + 15DXmdefINek16LXldec15XXqiDXoNeV16HXpNeV16og15zXlNeZ15XXnQ== + + due_next_week: !binary | + 15zXqdeR15XXoiDXlNeR15A= + + due_next_month_and_later: !binary | + 16rXkNeo15nXmiDXmdei15MgJXttb250aH0g15DXlSDXnteQ15XXl9eoINeZ + 15XXqteo + + due_today: !binary | + 15zXlNeZ15XXnQ== + + due_this_week: !binary | + 15zXlNee16nXmiDXlNep15HXldei + + get_in_ical_format: !binary | + 16fXkdec16og15zXldeXINep16DXlCDXlteUINeR16TXldeo157XmCBpQ2Fs + + no_actions_due_next_week: !binary | + 15DXmdefINek16LXldec15XXqiDXnNeR15nXpteV16Ig15HXqdeR15XXoiDX + lNeR15A= + + no_actions_due_this_month: !binary | + 15DXmdefINek16LXldec15XXqiDXnNeR15nXpteV16Ig15HXmdeq16jXqiDX + lNeX15XXk9ep + + recurring_deleted_success: !binary | + 15TXpNei15XXnNeUINeU157Xl9eW15XXqNeZ16og16DXnteX16fXlCDXkdeU + 16bXnNeX15Q= + + added_new_context: !binary | + 16DXldeh16Mg15TXp9ep16gg15fXk9ep + + edit: !binary | + 16LXqNeZ15vXlA== + + show_today: !binary | + 15TXpteS16og15TXmdeV150= + + added_dependency: !binary | + 16DXldeh16TXlCAle2RlcGVuZGVuY3l9INeb16rXnNeV16o= + + show_from: !binary | + 15TXpteS15Qg154t + + next_actions_due_date: + due_tomorrow: !binary | + 15zXnteX16g= + + due_in_x_days: !binary | + 15nXoteTINeR16LXldeTICV7ZGF5c30g15nXnteZ150= + + overdue_by_plural: !binary | + 15HXkNeZ15fXldeoINep15wgJXtkYXlzfSDXmdee15nXnQ== + + due_today: !binary | + 15zXlNeZ15XXnQ== + + overdue_by: !binary | + 15HXkNeZ15fXldeoINep15wgJXtkYXlzfSDXmdeV150= + + completed_rest_of_week: !binary | + 15TXodeq15nXmdee15Ug15HXmdeq16jXqiDXqdeR15XXoiDXlteU + + new_related_todo_created_short: !binary | + 15nXpteZ16jXqiDXntep15nXnteUINeX15PXqdeU + + delete_action: !binary | + 157Xl9eZ16fXqiDXpNei15XXnNeU + + task_list_title: !binary | + 157Xodec15XXnNeZ1506Oteo16nXmdee16og157XqdeZ157Xldeq + + blocked_by: !binary | + 16DXl9eh150g16LXnCDXmdeT15kgJXtwcmVkZWNlc3NvcnN9 + + error_deleting_recurring: !binary | + 15DXqNei15Qg16nXkteZ16LXlCDXkdee15fXmden16og15TXntep15nXnteU + INeU157Xl9eW15XXqNeZ16ogIFwnJXtkZXNjcmlwdGlvbn1cJw== + + feed_title_in_context: !binary | + 15HXlNen16nXqCAnJXtjb250ZXh0fSc= + + completed_actions_with: !binary | + 16TXoteV15zXldeqINep15TXodeq15nXmdee15Ug16LXnSDXlNeq15LXmdeq + ICV7dGFnX25hbWV9ICA= + + error_saving_recurring: !binary | + 15DXqNei15Qg16nXkteZ16LXlCDXkdep157Xmdeo16og15TXntep15nXnteU + INeU157Xl9eW15XXqNeZ16ogIFwnJXtkZXNjcmlwdGlvbn1cJw== + + delete: !binary | + 157Xl9eZ16fXlA== + + deferred_tasks_title: !binary | + 157Xodec15XXnNeZ1506Otee1rTXltaw15vWuNa816g= + + tagged_with: !binary | + 157XqteV15nXmdeSINeRLSAmbHNxdW87JXt0YWdfbmFtZX0mcnNxdW87 + + removed_predecessor: !binary | + 15TXldeh16jXlCV7c3VjY2Vzc29yfSAg15vXqtec15XXqiDXqdecICV7cHJl + ZGVjZXNzb3J9Lta+ + + no_recurring_todos: !binary | + 15DXmdefINeb16jXkteiINee16nXmdee15XXqiDXnteX15bXldeo15nXldeq + + added_new_next_action_plural: !binary | + 16DXldeh16TXlSDXpNei15XXnNeV16og15TXntep15og15fXk9ep15XXqg== + + in_pending_state: !binary | + 15HXntem15Eg15TXnteq16DXlA== + + clear_show_from_date: !binary | + 16DXp9eUINeU16bXkteUINee16rXkNeo15nXmg== + + scheduled_overdue: !binary | + 16rXldeW157XnyDXnNeq16bXldeS15Qg15zXpNeg15kgJXtkYXlzfSDXmdee + 15nXnQ== + + error_completing_todo: !binary | + 15DXqNei15Qg16nXkteZ16LXlCDXkdeh15nXldedIC8g15TXpNei15zXlCDX + qdecINee16nXmdee15QgJXtkZXNjcmlwdGlvbn0= + + no_hidden_actions: !binary | + 15zXkCDXoNee16bXkNeVINek16LXldec15XXqiDXnteV16HXqteo15XXqg== + + drag_action_title: !binary | + 15nXqSDXnNeS16jXldeoINeQ15wg16TXoteV15zXlCDXkNeX16jXqiDXm9eT + 15kg15zXmdem15XXqCDXqtec15XXqiDXkdeU + + depends_on: !binary | + 16rXnNeV15kg15E= + + new_related_todo_not_created_short: !binary | + 15zXkCDXoNeV16bXqNeUINee16nXmdee15Q= + + action_deleted_success: !binary | + 16TXoteV15zXqiDXlNee16nXmiDXoNee15fXp9eUINeR15TXptec15fXlA== + + feed_title_in_project: !binary | + 15HXpNeo15XXmdeZ16fXmCAnJXtwcm9qZWN0fSc= + + next_actions_title_additions: + completed: !binary | + 16TXoteV15zXldeqINep15TXodeq15nXnteV + + due_within_a_week: !binary | + 16rXldeaINep15HXldei + + due_today: !binary | + 15zXlNeZ15XXnQ== + + deferred_actions_with: !binary | + 16TXoteV15zXldeqINeT15fXldeZ15XXqiDXotecINeq15LXmdeqICcle3Rh + Z19uYW1lfSc= + + show_on_date: !binary | + 15TXpteSINeR16rXkNeo15nXmiAle2RhdGV9 + + recurring_todos: !binary | + 157XqdeZ157XldeqINee15fXlteV16jXmdeV16o= + + append_in_this_project: !binary | + 15HXpNeo15XXmdeZ16fXmCDXlteU + + next_action_needed: !binary | + 15nXqSDXnNeU15bXmdefINec16TXl9eV16og16TXoteV15zXqiDXlNee16nX + miDXkNeX16o= + + tickler_items_due: + other: !binary | + JXtjb3VudH0g157XlNee1rTXltaw15vWuNa816jXmdedINeU15LXmdei15Ug + 15zXqteQ16jXmdeaINeU15nXoteTIC0g15nXqSDXnNeo16LXoNefINeU16LX + nteV15Mg15zXlNem15LXlC4= + + one: !binary | + 15DXl9eTINee15TXnta015bWsNeb1rjWvNeo15nXnSDXlNeS15nXoiDXnNeq + 15DXqNeZ15og15TXmdei15MgLSDXmdepINec16jXoteg158g15TXotee15XX + kyDXnNeU16bXkteULg== + + action_deleted_error: !binary | + 16DXm9ep15zXlCDXnteX15nXp9eqINeU16TXoteV15zXlA== + + completed_rest_of_month: !binary | + 15TXodeq15nXmdee15Ug15HXmdeq16jXqiDXlNeX15XXk9epINeU16DXldeb + 15fXmQ== + + recurring_pattern_removed: !binary | + 15TXk9ek15XXoSDXlNee15fXlteV16jXmSDXlNeV16HXqCDXni0le2NvdW50 + fQ== + + done: !binary | + 15TXodeq15nXmdedPw== + + overdue: !binary | + 15HXkNeZ15fXldeo + + add_another_dependency: !binary | + 15TXldeh16TXqiDXqtec15XXqiDXoNeV16HXpNeq + + defer_x_days: + other: !binary | + 15PXl9eZ15Qg15EtJXtjb3VudH0g15nXnteZ150= + + one: !binary | + 15PXl9eZ15Qg15HXmdeV150= + + set_to_pending: !binary | + JXt0YXNrfSDXlNeV15LXk9eo15Qg15vXntee16rXmdeg15Q= + + completed_tasks_title: !binary | + 157Xodec15XXnNeZ1506Otee16nXmdee15XXqiDXqdeU15XXqdec157XlQ== + + completed_tagged_page_title: !binary | + 157Xodec15XXnNeZ1506Otee16nXmdee15XXqiDXqdeU16HXqteZ15nXnteV + INei150g16rXkteZ16ogJyV7dGFnX25hbWV9Jw== + + see_all_completed: !binary | + 16DXmdeq158g15zXqNeQ15XXqiDXm9ecINeb15wg15TXpNei15XXnNeV16og + 16nXlNeh16rXmdeZ157XlSDXm9eQ1586ICV7bGlua30= + + add_new_recurring: !binary | + 15TXldeh16TXqiDXpNei15XXnNeUINee15fXlteV16jXmdeqINeX15PXqdeU + + in_hidden_state: !binary | + 15HXntem15Eg157Xldeh16rXqA== + + list_incomplete_next_actions_with_limit: !binary | + 16jXmdep157XqiAle2NvdW50fSDXpNei15XXnNeV16og15TXlNee16nXmiDX + qdec15Ag15TXodeq15nXmdee15U= + + clear_due_date: !binary | + 157Xl9eZ16fXqiDXqteQ16jXmdeaINeZ16LXkw== + + deferred_pending_actions: !binary | + 16TXoteV15zXldeqINee157XqteZ16DXldeqL9eT15fXldeZ15XXqg== + + tagged_page_title: !binary | + 157Xodec15XXnNeZ1506Oteq15LXmdeV16og16LXnSAnJXt0YWdfbmFtZX0n + + action_saved: !binary | + 16TXoteV15zXlCDXoNep157XqNeU + + completed_last_day: !binary | + 15TXodeq15nXmdee15Ug15EtMjQg16nXoteV16og15TXkNeX16jXldeg15XX + qg== + + error_starring: !binary | + 15TXk9eS16nXqiDXlNee16nXmdee15QgIFwnJXtkZXNjcmlwdGlvbn1cJyDX + nNeQINem15zXl9eU + + defer_date_after_due_date: !binary | + 16rXkNeo15nXmiDXlNeT15fXmdeZ15Qg157XkNeV15fXqCDXnteq15DXqNeZ + 15og15TXmdei15MuINeZ16kg15zXoteo15XXmiDXkNeqINeq15DXqNeZ15og + 15TXmdei15Mg15HXlNeq15DXnSDXnNek16DXmSDXkden16nXqiDXlNeT15fX + mdeZ15Qu + + new_related_todo_created: !binary | + 157XqdeZ157XlCDXl9eT16nXlCDXlNeV16HXpNeUINec157XqdeZ157XlCDX + nteX15bXldeo15nXqiDXlteV + + completed_in_archive: + other: !binary | + 16fXmdeZ157XldeqICV7Y291bnR9INek16LXldec15XXqiDXqdeU16HXqteZ + 15nXnteVINeR15DXqNeb15nXldefLg== + + one: !binary | + 16fXmdeZ157XqiDXkdeQ16jXm9eZ15XXnyDXpNei15XXnNeUINep15TXodeq + 15nXmdee15Qu + + action_due_on: !binary | + KNek16LXldec15Qg16LXkyAgJXtkYXRlfSk= + + remove_dependency: !binary | + 15TXodeo16og16rXnNeV16ogKNec15Ag157XldeX16cg15DXqiDXlNek16LX + ldec15Qp + + star_action: !binary | + 15TXk9eS16nXqiDXpNei15XXnNeU + + completed_actions: !binary | + 16TXoteV15zXldeqINep15TXodeq15nXmdee15U= + + show_in_days: !binary | + 15TXpteSINeR16LXldeTICV7ZGF5c30g15nXnteZ150= + + tags: !binary | + 16rXkteZ15XXqiAo157Xldek16jXk9eV16og15HXpNeh15nXp9eZ150p + + recurrence_completed: !binary | + 15DXmdefINek16LXldec16og15TXntep15og15zXpNei15XXnNeUINeU157X + l9eW15XXqNeZ16og16nXodeV15nXnteULiDXlNee15fXlteV16jXmdeV16og + 15TXodeq15nXmdee15Qu + + edit_action_with_description: !binary | + 16LXqNeZ15vXqiDXlNek16LXldec15QgJyV7ZGVzY3JpcHRpb259Jw== + + deleted_success: !binary | + 15TXpNei15XXnNeUINeg157Xl9en15Qg15HXlNem15zXl9eU + + edit_action: !binary | + 16LXqNeZ15vXqiDXpNei15XXnNeU + + edit_recurring_todo: !binary | + 16LXqNeb15nXqiDXpNei15XXnNeV16og157Xl9eW15XXqNeZ15XXqg== + + no_actions_with: !binary | + 15DXmdefINeb16jXkteiINek16LXldec15XXqiDXqdec15Ag15TXodeq15nX + mdee15XXqiDXotedINeU16rXkteZ16ogJyV7dGFnX25hbWV9Jw== + + was_due_on_date: !binary | + 15TXmdeUINee15nXldei15Mg16LXkyAle2RhdGV9 + + confirm_delete: !binary | + 15TXkNedINec157Xl9eV16cg15DXqiDXlNek16LXmdec15XXqiAnJXtkZXNj + cmlwdGlvbn0nPw== + + no_actions_found_title: !binary | + 15zXkCDXoNee16bXkCDXpNei15XXnNeV16o= + + next_actions_title: !binary | + 157Xodec15XXnNeZ150gLSDXpNei15XXnNeV16og15TXntep15o= + + due: !binary | + 15nXoteT + + no_actions_due_this_week: !binary | + 15DXmdefINek16LXldec15XXqiDXlNee15nXldei15PXldeqINec15TXntep + 15og15TXqdeR15XXog== + + no_completed_recurring: !binary | + 15DXmdefINeb16jXkteiINee16nXmdee15XXqiDXnteX15bXldeo15nXldeq + INep15TXodeq15nXmdee15U= + + unresolved_dependency: !binary | + 15TXoteo15og16nXlNeV15vXoNehINeR16rXnNeV16og15zXkCDXqteQ150g + 15zXkNejINek16LXldec15Qg16fXmdeZ157Xqi4g15TXoteo15og15zXkCDX + mdep157XqCDXotedINeZ16rXqNeqINeU16TXoteV15zXlC4g15zXlNee16nX + mdeaPw== + + completed_recurring: !binary | + 15TXodeq15nXmdee15Ug157XqdeZ157XldeqINee15fXlteV16jXmdeV16o= + + no_project: !binary | + LS3XkNeZ158g16TXqNeV15nXmden15gtLQ== + + older_completed_items: !binary | + 157XqdeZ157XldeqINep15TXodeq15nXmdee15XXqiDXmdep16DXldeqINeZ + 15XXqteo + + archived_tasks_title: !binary | + 157Xodec15XXnNeZ1506INee16nXmdee15XXqiDXqdeU16HXqteZ15nXnteV + INeU15XXoteR16jXlSDXnNeQ16jXm9eZ15XXnw== + + completed_today: + other: !binary | + 16LXkyDXoteq15Qg15TXodeq15nXmdee15UgJXtjb3VudH0g16TXoteV15zX + qiDXlNeZ15XXnS4= + + one: !binary | + 15TXldep15zXnteUINek16LXldec15Qg15DXl9eqINeU15nXldedLCDXoteT + INei16rXlC4= + + pending: !binary | + 157Xnteq15nXnw== + + context_changed: !binary | + 15TXp9ep16gg16nXldeg15Qg15wtJXtuYW1lfQ== + + error_removing_dependency: !binary | + 15TXqteo15fXqdeUINep15LXmdeQ15Qg15HXlNeh16jXqiDXlNeq15zXldeq + + show_tomorrow: !binary | + 15TXpteS16og157Xl9eo + + error_toggle_complete: !binary | + 15zXkCDXoNeZ16rXnyDXnNeh157XnyDXntep15nXnteUINebIteU16HXqteZ + 15nXnteUIg== + + recurring_action_deleted: !binary | + 16TXoteV15zXlCDXoNee15fXp9eULiDXnteQ15fXqCDXldeU16TXoteV15zX + lCDXnteX15bXldeo15nXqi4g16TXoteV15zXlCDXl9eT16nXlCDXoNeV16HX + pNeU + + completed_more_than_x_days_ago: !binary | + 15TXodeq15nXmdee15Ug15zXpNeg15kg15nXldeq16gg154tJXtjb3VudH0g + 15nXnteZ150= + + delete_recurring_action_confirm: !binary | + 15TXkNedINec157Xl9eV16cg15DXqiDXlNek16LXmdec15XXqiDXlNee15fX + lteV16jXmdeqICcle2Rlc2NyaXB0aW9ufSc/ + + no_completed_actions_with: !binary | + 15DXmdefINek16LXldec15XXqiDXqdeU16HXqteZ15nXnteVINei15wg15TX + qteS15nXqiAnJXt0YWdfbmFtZX0n + + feeds: + completed: !binary | + 15TXodeq15nXmdedOiAle2RhdGV9 + + due: !binary | + 15nXoteTICV7ZGF0ZX0= + + completed_rest_of_previous_month: !binary | + 15TXodeq15nXmdee15Ug15HXmdeq16jXqiDXlNeX15XXk9epINeU16fXldeT + 150= + + cannot_add_dependency_to_completed_todo: !binary | + 15DXmdefINeQ16TXqdeo15XXqiDXnNeU15XXodeZ16Mg16TXoteV15zXlCDX + lteVINeb16rXnNeV16og15zXpNei15XXnNeUINep15TXodeq15nXmdee15Qh + + completed: !binary | + 15TXodeq15nXmdee15U= + + list_incomplete_next_actions: !binary | + 16jXqdeZ157XqiDXpNei15XXnNeV16og15TXntep15og16nXnNeQINeU16HX + qteZ15nXnteV + + recurrence: + recurrence_on_options: !binary | + 15TXkteT16jXqiDXnteX15bXldeo15nXldeqINec16TXmQ== + + show_days_before: !binary | + JXtkYXlzfSDXmdee15nXnSDXnNek16DXmSDXqteQ16jXmdeaINeU15nXoteT + INec157XqdeZ157XlA== + + ends_on: !binary | + 157Xodeq15nXmdedINeR + + monthly: !binary | + 15fXldeT16nXmQ== + + every_work_day: !binary | + 15HXm9ecINeZ15XXnSDXoteR15XXk9eU + + weekly_options: !binary | + 15TXkteT16jXldeqINec16TXoteV15zXldeqINeR157Xl9eW15XXqNeZ15XX + qiDXqdeR15XXoteZ16o= + + daily_options: !binary | + 15TXkteT16jXldeqINec16TXoteV15zXldeqINee15fXlteV16jXmdeV16og + 15nXldee15nXldeq + + weekly_every_number_week: !binary | + 15fXldeW16gg15vXnCAle251bWJlcn0gINep15HXldeiINeR + + yearly_every_xth_day: !binary | + 15nXldedICV7ZGF5fSDXlCAtJXtkYXlfb2Zfd2Vla30gINeR15vXnCAle21v + bnRofSDXl9eV15PXqQ== + + weekly: !binary | + 16nXkdeV16LXmQ== + + daily_every_number_day: !binary | + 15vXnCAle251bWJlcn0gINeZ157Xmded + + ends_on_date: !binary | + 157Xodeq15nXmdedINeRLSV7ZGF0ZX0= + + ends_on_number_times: !binary | + 157Xodeq15nXmdedINec15DXl9eoICV7bnVtYmVyfSDXpNei157Xmded + + recurrence_on_due_date: !binary | + 15nXoteTINec157XqdeZ157XlA== + + monthly_options: !binary | + 15TXkteT16jXldeqINec16TXoteV15zXldeqINeR15fXlteV16jXmdeV16og + 15fXldeT16nXmdeq + + starts_on: !binary | + 157XqteX15nXnCDXkQ== + + show_option_always: !binary | + 16rXnteZ15M= + + monthly_every_xth_day: !binary | + 15nXldedICV7ZGF5fSDXlCAtJXtkYXlfb2Zfd2Vla30gINeR15vXnCAle21v + bnRofSDXl9eV15PXqQ== + + daily: !binary | + 15nXldee15k= + + no_end_date: !binary | + 15DXmdefINeq15DXqNeZ15og16HXmdeV150= + + show_options: !binary | + 15TXpteS16og157XqdeZ157Xldeq + + day_x_on_every_x_month: !binary | + 15HXmdeV150gJXtkYXl9INeR15vXnCAle21vbnRofSAg15fXldeT16k= + + pattern: + on_day_n: !binary | + 15HXmdeV150gJXtufQ== + + on_work_days: !binary | + 15HXmdee15kg16LXkdeV15PXlA== + + times: !binary | + 15stJXtudW1iZXJ9INek16LXnteZ150= + + second: !binary | + 16nXoNeZ + + every_month: !binary | + 15vXnCDXl9eV15PXqQ== + + weekly: !binary | + 16nXkdeV16LXmQ== + + every_day: !binary | + 15vXnCDXmdeV150= + + third: !binary | + 16nXnNeZ16nXmQ== + + show: !binary | + 15TXpteS15Q= + + every_year_on: !binary | + 15HXm9ecINep16DXlCDXkdeq15DXqNeZ15ogJXtkYXRlfQ== + + last: !binary | + 15DXl9eo15XXnw== + + the_xth_day_of_month: !binary | + 15TXmdeV150g15QtICV7eH0gJXtkYXl9INeR15fXldeT16kgJXttb250aH0= + + fourth: !binary | + 16jXkdeZ16LXmQ== + + until: !binary | + 16LXkw== + + every_n: !binary | + 15vXnCAle259 + + first: !binary | + 16jXkNep15XXnw== + + every_xth_day_of_every_n_months: "\xD7\x9B\xD7\x9C %{x} %{day} \xD7\x91\xD7\x9B\xD7\x9C %{n_months}" + due: !binary | + 15nXoteT + + from: !binary | + 154= + + yearly: !binary | + 16nXoNeq15nXqg== + + yearly_every_x_day: "\xD7\x9B\xD7\x9C %{month} %{day}" + from_tickler: !binary | + 16rXkNeo15nXmiDXlNeZ16LXkyDXnNee16nXmdee15Qg157XkteZ16Ig157X + lNee1rTXltaw15vWuNa816ggKNec15Ag16DXp9eR16Ig16rXkNeo15nXmiDX + mdei15Mp + + yearly_options: !binary | + 15TXkteT16jXldeqINec16TXoteV15zXldeqINeR157Xl9eW15XXqNeZ15XX + qiDXqdeg16rXmdeV16o= + + no_deferred_pending_actions: !binary | + 15DXmdefINeb16jXkteiINek16LXldec15XXqiDXk9eX15XXmdeV16og15DX + lSDXntee16rXmdeg15XXqg== + + action_marked_complete_error: !binary | + 15TXpNei15XXnNeUIDxzdHJvbmc+JyV7ZGVzY3JpcHRpb259Jzwvc3Ryb25n + Pta+15zXkNa+INeh15XXnteg15Qg15sgLSA8c3Ryb25nPiV7Y29tcGxldGVk + fSDXoten15Eg16nXkteZ15DXqiDXqdeo16o8L3N0cm9uZz4= + + recurrence_period: !binary | + 16rXp9eV16TXqiDXnteX15bXldeo15nXldeq + + no_last_completed_actions: !binary | + 15zXkCDXoNee16bXkNeVINek16LXldec15XXqiDXqdeU16HXqteZ15nXnteV + + hidden_actions: !binary | + 16TXoteV15zXldeqINee15XXodeq16jXldeq + + to_tickler: !binary | + 15zXnta015bWsNeb1rjWvNeo + + added_new_next_action_singular: !binary | + 16DXldeh16TXlCDXpNei15XXnNeqINeU157XqdeaINeX15PXqdeU + + star_action_with_description: !binary | + 15TXk9eS16nXqiDXpNei15nXnNeV16ogJyV7ZGVzY3JpcHRpb259Jw== + + no_completed_actions: !binary | + 15DXmdefINeb16jXkteiINek16LXldec15XXqiDXqdeU16HXqteZ15nXnteV + Lg== + + no_incomplete_actions: !binary | + 15DXmdefINek16LXldec15XXqiDXqdec15Ag15TXodeq15nXmdee15U= + + older_than_days: !binary | + 15XXldeq16cg157XotecICV7Y291bnR9INeZ157Xmded + + error_deleting_item: !binary | + 15DXqNei15Qg16nXkteZ15DXlCDXkdee15fXmden16og15TXpNeo15nXmCAl + e2Rlc2NyaXB0aW9ufQ== + + action_saved_to_tickler: !binary | + 16TXoteV15zXlCDXoNep157XqNeUINec157WtNeW1rDXm9a41rzXqA== + + recurring_actions_title: !binary | + 157Xodec15XXnNeZ1506Otek16LXldec15XXqiDXnteX15bXldeo15nXldeq + + action_deferred: !binary | + 15TXpNei15XXnNeUICcle2Rlc2NyaXB0aW9ufScg16DXk9eX16rXlA== + + action_marked_complete: "\xD7\x94\xD7\xA4\xD7\xA2\xD7\x95\xD7\x9C\xD7\x94 '%{description}' \xD7\xA1\xD7\x95\xD7\x9E\xD7\xA0\xD7\x94 \xD7\x9B- %{completed}" + no_deferred_actions_with: !binary | + 15DXmdefINek16LXldec15XXqiDXk9eX15XXmdeV16og16LXnSDXlNeq15LX + mdeqICcle3RhZ19uYW1lfSc= + + error_starring_recurring: !binary | + INeU15PXktep16og15TXntep15nXnteUINeU157Xl9eW15XXqNeZ16ogIFwn + JXtkZXNjcmlwdGlvbn1cJyDXnNeQINem15zXl9eU + + has_x_pending: + other: !binary | + 157Xm9eZ15wgJXtjb3VudH0g16TXoteV15zXqiDXntee16rXmdeg15XXqg== + + one: !binary | + 15HXotecINek16LXldec15Qg15PXl9eV15nXlCDXkNeX16o= + + no_deferred_actions: !binary | + 15DXmdefINeb16jXkteiINek16LXldec15XXqiDXqdeg15PXl9eVLg== + + completed_last_x_days: !binary | + 15TXodeq15nXmdee15Ug15EtJXtjb3VudH0g15TXmdee15nXnSDXlNeQ15fX + qNeV16DXmded + + mobile_todos_page_title: !binary | + 15vXnCDXlNek16LXldec15XXqg== + + convert_to_project: !binary | + 15nXpteZ16jXqiDXpNeo15XXmdeZ16fXmA== + + added_new_next_action: !binary | + 16DXldeh16TXlCDXpNei15XXnNeqINeU157XqdeaINeX15PXqdeU + + no_actions_found: !binary | + 15DXmdefINeb16jXkteiINek16LXldec15XXqiDXqdec15Ag15TXodeq15nX + mdee15U= + + delete_recurring_action_title: !binary | + 157Xl9eZ16fXqiDXpNei15XXnNeUINee15fXlteV16jXmdeq + + all_completed_here: !binary | + 15vXkNef + + all_completed: !binary | + 15vXnCDXlNek16LXldec15XXqiDXqdeU16HXqteZ15nXnteV + + unable_to_add_dependency: !binary | + 15zXkCDXoNeZ16rXnyDXnNeU15XXodeZ16Mg16rXnNeV16o= + + next_actions_description: !binary | + 157Xodeg1586 + + stats: + actions_avg_completed_30days: !binary | + 15XXlNeh16rXmdeZ157XlSDXkdee157Xldem16IgJXtjb3VudH0g16TXoteV + 15zXldeqINec15nXlded + + projects: !binary | + 16TXqNeV15nXmden15jXmded + + actions_dow_30days_legend: + number_of_actions: !binary | + 157Xodek16gg16TXoteV15zXldeq + + day_of_week: !binary | + 15nXldedINeR16nXkdeV16I= + + click_to_return: !binary | + 15TXp9ec16fXlCDXotecICV7bGlua30g16rXl9eW15nXqCDXnNei157XldeT + INeU16HXmNeY15nXodeY15nXp9eU + + top10_projects: !binary | + 16LXqdeo16og15TXpNeo15XXmdeZ16fXmNeZ150g15TXnteV15HXmdec15nX + nQ== + + other_actions_label: !binary | + KNeQ15fXqNeZ150p + + top5_contexts: !binary | + NSDXlNen16nXqNeZ150g157XldeR15nXnNeZ150= + + totals_context_count: !binary | + 16fXmdeZ157XmdedICV7Y291bnR9INeU16fXqdeo15nXnS4= + + running_time_legend: + percentage: !binary | + 15DXl9eV15Y= + + weeks: !binary | + 15bXntefINee16bXmNeR16gg15zXpNei15XXnNeV16ogKNep15HXldei15XX + qikuINeU16fXnNen15Qg16LXnCDXlNeR16gg15zXnteZ15PXoiDXoNeV16HX + ow== + + actions: !binary | + 16TXoteV15zXldeq + + actions_avg_created: !binary | + 15EtMTIg15TXl9eV15PXqdeZ150g15TXkNeX16jXldeg15nXnSDXmdeV16bX + qNeVINeR157Xldem16IgJXtjb3VudH0g16TXoteV15zXldeq + + actions_avg_completed: !binary | + 15XXlNeh16rXmdeZ157XlSDXkdee157Xldem16IgJXtjb3VudH0g16TXoteV + 15zXldeqINec15fXldeT16k= + + totals_incomplete_actions: !binary | + 16fXmdeZ157XldeqICV7Y291bnR9INek16LXldec15XXqiDXqdec15Ag15TX + odeq15nXmdee15U= + + top5_visible_contexts_with_incomplete_actions: !binary | + NSDXlNeU16fXqdeo15nXnSDXlNee15XXkdeZ15zXmdedINei150g16TXoteV + 15zXldeqINep15zXkCDXlNeh16rXmdeZ157XlQ== + + index_title: !binary | + 157Xodec15XXnNeZ1506Oteh15jXmNeZ16HXmNeZ16fXlA== + + tag_cloud_90days_title: !binary | + 16LXoNefINeq15LXmdeV16og15zXpNei15XXnNeV16og15EtOTAg15TXmdee + 15nXnSDXlNeQ15fXqNeV16DXmded + + action_completion_time_title: !binary | + 15bXntefINeh15nXldedICjXm9ecINeU16TXoteV15zXldeqINep15TXodeq + 15nXmdee15Up + + open_per_week_legend: + weeks: !binary | + 16nXkdeV16LXldeqINen15XXk9edINec15vXnw== + + actions: !binary | + 16TXoteV15zXldeq + + action_selection_title: !binary | + 157Xodec15XXnNeZ1506OteR15fXmdeo16og16TXoteV15zXlA== + + actions_day_of_week_title: !binary | + 15nXldedINeR16nXkdeV16IgKNeb15wg15TXpNei15XXnNeV16op + + spread_of_actions_for_all_context: !binary | + 16TXmdeW15XXqCDXpNei15XXnNeV16og15zXm9ecINeU15TXp9ep16jXmded + + totals_hidden_project_count: !binary | + JXtjb3VudH0g157Xldeh16rXqNeZ150= + + totals_deferred_actions: !binary | + 157XlNefICV7Y291bnR9INek16LXldec15XXqiDXk9eX15XXmdeV16og15HX + nta015bWsNeb1rjWvNeo + + click_to_show_actions_from_week: !binary | + 15TXp9ec16fXlCDXotecICV7bGlua30g16rXpteZ15Ig15DXqiDXlNek16LX + ldec15XXqiDXntep15HXldeiICV7d2Vla30g15XXkNeZ15zXmg== + + actions_dow_30days_title: !binary | + 15nXldedINeR16nXkdeV16IgKDMwINeU15nXnteZ150g15TXkNeX16jXldeg + 15nXnSg= + + legend: + number_of_actions: !binary | + 157Xodek16gg16TXoteV15zXldeq + + percentage: !binary | + 15DXl9eV15Y= + + number_of_days: !binary | + 157Xodek16gg15nXnteZ150g16fXldeT150g15zXm9ef + + day_of_week: !binary | + 15nXldedINeR16nXkdeV16I= + + running_time: !binary | + 15bXntefINee16bXmNeR16gg15zXpNei15XXnNeUICjXqdeR15XXoteV16op + + months_ago: !binary | + 15fXldeT16nXmdedINen15XXk9ed + + actions: !binary | + 16TXoteV15zXldeq + + actions_last_year_legend: + number_of_actions: !binary | + 157Xodek16gg15TXpNei15XXnNeV16o= + + months_ago: !binary | + 15fXldeT16nXmdedINen15XXk9ed + + totals_visible_context_count: !binary | + 157XqteV15og15DXnNeVICV7Y291bnR9INeU16fXqdeo15nXnSDXktec15XX + mdeZ150= + + totals_blocked_actions: !binary | + JXtjb3VudH0g16rXnNeV15nXmdedINeR16HXmdeV150g15TXntep15nXnteV + 16og16nXnNeU150= + + spread_of_running_actions_for_visible_contexts: !binary | + 16TXmdeW15XXqCDXlNek16LXldec15XXqiDXnNeU16fXqdeo15nXnSDXktec + 15XXmdeZ150= + + tag_cloud_description: !binary | + 16LXoNefINeU16rXkteZ15XXqiDXnteb15nXnCDXqteS15nXldeqINec15vX + nCDXlNek16LXldec15XXqiAo15TXodeq15nXmdee15UsINec15Ag15TXodeq + 15nXmdee15UsINeS15zXldeZ15XXqiDXlS/XkNeVINee15XXodeq16jXldeq + KA== + + totals: !binary | + 16HXmdeb15XXnteZ150= + + time_of_day_legend: + number_of_actions: !binary | + 157Xodek16gg16TXoteV15zXldeq + + time_of_day: !binary | + 15bXntefINeR15nXlded + + tags: !binary | + 16rXkteZ15XXqg== + + totals_action_count: !binary | + 16fXmdeZ157XldeqICV7Y291bnR9INek16LXldec15XXqiDXkdeh15og15TX + m9ec + + more_stats_will_appear: !binary | + 16HXmNeY15nXodeY15nXp9eV16og16DXldeh16TXldeqINeZ15XXpteS15Ug + 15vXkNefINec15DXl9eoINeU15XXodek16og16TXoteV15zXldeqINeg15XX + odek15XXqi4= + + open_per_week: !binary | + 16TXoteV15zXldeqINeU157XqdeaICjXnteV16bXkteV16og15DXlSDXnteV + 16HXqteo15XXqikg15zXm9ecINep15HXldei + + no_actions_selected: !binary | + 15zXkCDXoNeR15fXqNeVINek16LXldec15XXqg== + + totals_completed_project_count: !binary | + JXtjb3VudH0g157XlNedINek16jXldeZ15nXp9eY15nXnSDXqdeg16HXqteZ + 15nXnteVLg== + + totals_hidden_context_count: !binary | + 15UtJXtjb3VudH0g15HXlNen16nXqNeZ150g157Xldeh16rXqNeZ150u + + actions_day_of_week_legend: + number_of_actions: !binary | + 157Xodek16gg16TXoteV15zXldeq + + day_of_week: !binary | + 15nXldedINeR16nXkdeV16I= + + click_to_update_actions: !binary | + 15TXp9ec16fXlCDXotecINeU15HXqCDXkdeS16jXoyDXntei15PXm9eg16og + 15DXqiDXlNek16LXldec15Qg15zXnteY15Q= + + totals_first_action: !binary | + 157XkNeWINeU16TXoteV15zXlCDXlNeo15DXqdeV16DXlCDXkS0le2RhdGV9 + + tod30: !binary | + 15bXntefINeR15nXldedICgzMCDXmdee15nXnSDXkNeX16jXldeg15kp + + tag_cloud_90days_description: !binary | + 16LXoNefINeU16rXkteZ15XXqiDXnteb15nXnCDXqteS15nXldeqINei15HX + ldeoINek16LXldec15XXqiDXqdeg15XXpteo15Ug15DXlSDXlNeh16rXmdeZ + 157XlSDXkS05MCDXlNeZ157XmdedINeU15DXl9eo15XXoNeZ150u + + top10_projects_30days: !binary | + 16LXqdeo16og15TXpNeo15XXmdeZ16fXmNeZ150g15TXnteV15HXmdec15nX + nSDXkS0zMCDXlNeZ157XmdedINeU15DXl9eo15XXoNeZ150= + + top10_longrunning: !binary | + MTAg15TXpNeo15XXmdeZ16fXmNeZ150g16nXqNem15nXnSDXlNeb15kg15TX + qNeR15Qg15bXntef + + within_one: !binary | + 16rXldeaIDE= + + actions: !binary | + 16TXoteV15zXldeq + + no_tags_available: !binary | + 15DXmdefINeq15LXmdeV16og15bXnteZ16DXldeq + + actions_min_completion_time: !binary | + 15TXltee158g15TXnteW16LXqNeZINec16HXmdeV150g15TXldeQICV7dGlt + ZX0u + + totals_active_project_count: !binary | + 157XqteV15vXnSwgJXtjb3VudH0g15TXnSDXpNeo15XXmdeZ16fXmNeZ150g + 16TXoteZ15zXmded + + actions_selected_from_week: !binary | + 16TXoteV15zXldeqINeg15HXl9eo15XXqiDXntep15HXldei + + totals_actions_completed: !binary | + JXtjb3VudH0g157XlNedINeU16HXqteZ15nXnteV + + actions_avg_completion_time: !binary | + 157Xm9ecINeU16TXoteV15zXmdeV16og16nXoNeh16rXmdeZ157XldeqINeU + 15bXntefINeU157XnteV16bXoiDXnNeh15nXldedINeU15XXkCAle2NvdW50 + fSDXmdee15nXnQ== + + time_of_day: !binary | + 15bXntefINeR15nXldedICjXm9ecINeU16TXoteV15zXldeqKQ== + + labels: + avg_created: !binary | + 16DXldem16jXlSDXkdee157Xldem16I= + + created: !binary | + 16DXldem16jXlQ== + + month_avg_created: !binary | + JXttb250aHN9INeg15XXpteo15Ug15HXntee15XXpteiINec15fXldeT16k= + + completed: !binary | + 15TXodeq15nXmdee15U= + + month_avg_completed: !binary | + JXttb250aHN9INeU16HXqteZ15nXnteVINeR157XnteV16bXoiDXnNeX15XX + k9ep + + avg_completed: !binary | + 15TXodeq15nXmdee15Ug15HXntee15XXptei + + actions_further: !binary | + 15XXkNeZ15zXmg== + + tag_cloud_title: !binary | + 16LXoNefINeq15LXmdeV16og15zXm9ecINeU16TXoteV15zXldeq + + running_time_all_legend: + percentage: !binary | + 15DXl9eV15Y= + + running_time: !binary | + 15bXntefINee16bXmNeR16gg15zXpNei15XXnNeV16ogKNep15HXldei15XX + qikuINeU16fXnNen15Qg16LXnCDXlNeR16gg15zXnteZ15PXoiDXoNeV16HX + ow== + + actions: !binary | + 16TXoteV15zXldeq + + totals_tag_count: !binary | + 16fXmdeZ157XmdedICV7Y291bnR9INeq15LXmdeV16og15TXntep15XXmdeZ + 15vXldeqINec16TXoteV15zXldeqLg== + + totals_project_count: !binary | + 16fXmdeZ157XmdedICV7Y291bnR9INek16jXldeZ15nXp9eY15nXnS4= + + actions_30days_title: !binary | + 16TXoteV15zXldeqINeRLTMwINeU15nXnteZ150g15TXkNeX16jXldeg15nX + nQ== + + current_running_time_of_incomplete_visible_actions: !binary | + 15bXntefINee16bXmNeR16gg15zXm9ecINeU16TXoteV15zXldeqINeU15LX + nNeV15nXldeq + + click_to_return_link: !binary | + 15vXkNef + + tod30_legend: + number_of_actions: !binary | + 157Xodek16gg16TXoteV15zXldeq + + time_of_day: !binary | + 15bXntefINeR15nXlded + + contexts: !binary | + 15TXp9ep16jXmded + + running_time_all: !binary | + 15bXntefINee16bXmNeR16gg15zXm9ecINeU16TXoteV15zXldeqINep15zX + kCDXlNeh16rXmdeZ157XlQ== + + actions_min_max_completion_days: !binary | + 15nXl9ehINeW157XnyDXnteZ15bXoteo15kv157Xmdeo15HXmSDXnNeh15nX + ldedINeU15XXkCAle21pbn0vJXttYXh9Lg== + + totals_unique_tags: !binary | + 157XqteV15og16rXkteZ15XXqiDXkNec15UsICV7Y291bnR9INeZ15nXl9eV + 15PXmdeV16ou + + actions_lastyear_title: !binary | + 16TXoteV15zXldeqINeRLTEyINeU15fXldeT16nXmdedINeU15DXl9eo15XX + oNeZ150= + + actions_last_year: !binary | + 16TXoteV15zXldeqINeR16nXoNeZ150g15TXkNeX16jXldeg15XXqg== + + actions_actions_avg_created_30days: !binary | + 15EtMzAg15TXmdee15nXnSDXlNeQ15fXqNeV16DXmdedINeg15XXpteo15Ug + 15HXntee15XXpteiICV7Y291bnR9INek16LXldec15XXqg== + + search: + no_results: !binary | + 15TXl9eZ16TXldepINec15Ag15TXoNeZ15Eg16rXldem15DXldeq + + contexts_matching_query: !binary | + 15TXp9ep16jXmdedINeq15XXkNee15nXnSDXnNep15DXmdec16rXkA== + + projects_matching_query: !binary | + 16TXqNeV15nXmden15jXmdedINeq15XXkNee15nXnSDXqdeQ15nXnNeq15A= + + todos_matching_query: !binary | + 157XqdeZ157XldeqINeq15XXkNee15XXqiDXqdeQ15nXnNeq15A= + + tags_matching_query: !binary | + 16rXkteZ15XXqiDXqteV15DXnteV16og15zXqdeQ15nXnNeq15A= + + notes_matching_query: !binary | + 16TXqten15nXldeqINeq15XXkNee15XXqiDXqdeQ15nXnNeq15A= + + contexts: + last_completed_in_context: !binary | + 15HXlNen16nXqCDXlteUICAo15DXl9eo15XXoNeV16ogJXtudW1iZXJ9KQ== + + hide_form_title: !binary | + 15TXodeq16jXqiDXmNeV16TXoSDXlNen16nXqCDXl9eT16k= + + status_hidden: !binary | + 15TXlNen16nXqCDXnteV16HXqteo + + delete_context_title: !binary | + 157Xl9eZ16fXqiDXlNen16nXqA== + + delete_context_confirmation: !binary | + 15TXkNedINec157Xl9eV16cg15DXqiDXlNeU16fXqdeoICAnJXtuYW1lfSc/ + INeZ16kg15zXlNeW15TXqCDXntek16DXmSDXqdek16LXldec15Qg15bXlSDX + nteq15fXldenINeQ16og15vXnCDXlNek16LXldec15XXqiDXlNee15fXlteV + 16jXmdeV16og15HXlNen16nXqCDXlteU + + update_status_message: !binary | + 16nXldeg15Qg16nXnSDXlNeU16fXqdeo + + edit_context: !binary | + 16LXqNeZ15vXqiDXlNen16nXqA== + + show_form: !binary | + 15nXpteZ16jXqiDXlNen16nXqCDXl9eT16k= + + context_name: !binary | + 16nXnSDXlNen16nXqA== + + completed_tasks_title: !binary | + 157Xodec15XXnNeZ1506Otek16LXldec15XXqiDXqdeR15XXptei15Ug15HX + ntec15XXkNefINeR15TXp9ep16ggICcle2NvbnRleHRfbmFtZX0n + + no_contexts_active: !binary | + 15DXmdefINeb16jXkteiINeU16fXqdeo15nXnSDXpNei15nXnNeZ150= + + save_status_message: !binary | + 15TXp9ep16gg16DXqdee16g= + + no_actions: !binary | + 15DXmdefINeb16jXkteiINek16LXldec15XXqiDXqdec15Ag15TXldep15zX + nteVINeR15TXp9ep16gg15TXoNeV15vXl9eZ + + delete_context: !binary | + 157Xl9enINeU16fXqdeo + + hidden_contexts: !binary | + 15TXp9ep16jXmdedINee15XXodeq16jXmded + + visible_contexts: !binary | + 15TXp9ep16jXmdedINeS15zXldeZ15nXnQ== + + context_hide: !binary | + 15TXodeq16jXlCDXntei157XldeTINeU15HXmdeqPw== + + context_deleted: !binary | + 16DXnteX16cg15TXp9ep16ggJyV7bmFtZX0n + + todos_append: !binary | + 15HXlNen16nXqCDXlteU + + new_context_post: !binary | + JyDXmdeV15XXpteo15Ug15HXoNeV16HXoy4g15TXkNedINec15TXntep15nX + mj8= + + no_contexts_hidden: !binary | + 15DXmdefINeb16jXkteiINeU16fXqdeo15nXnSDXnteV16HXqteo15nXnQ== + + status_active: !binary | + 15TXlNen16nXqCDXpNei15nXnA== + + all_completed_tasks_title: !binary | + 157Xodec15XXnNeZ1506Oteb15wg15TXpNei15XXnNeV16og16nXkdeV16bX + oteVINeR157XnNeV15DXnyDXkdeU16fXqdeoICAnJXtjb250ZXh0X25hbWV9 + Jw== + + hide_form: !binary | + 15TXodeq16jXqiDXmNeV16TXoQ== + + add_context: !binary | + 15TXldeh16TXqiDXlNen16nXqA== + + new_context_pre: !binary | + 15TXp9ep16gg15fXk9epICc= + + show_form_title: !binary | + 15TXldeh16TXqiDXlNen16nXqA== + + models: + todo: + error_date_must_be_future: !binary | + 15fXmdeZ15Eg15zXlNeZ15XXqiDXqteQ16jXmdeaINei16rXmdeT15k= + + user: + error_project_not_associated: !binary | + 157XlteU15Qg16TXqNeV15nXmden15ggJXtwcm9qZWN0fSDXkNeZ16DXlSDX + ntep15XXmdeZ15og16LXnSDXnteW15Qg157Xqdeq157XqSAle3VzZXJ9Lg== + + error_context_not_associated: !binary | + 157XlteU15Qg15TXp9ep16ggJXtjb250ZXh0fSDXkNeZ16DXlSDXntep15XX + mdeZ15og16LXnSDXnteW15Qg157Xqdeq157XqSAle3VzZXJ9Lg== + + project: + feed_title: !binary | + 16TXqNeV15nXmden15jXmdedINeR157Xodec15XXnNeZ150= + + feed_description: !binary | + 16jXqdeZ157XqiDXm9ecINeU16TXqNeV15nXmden15jXmdedINei15HXldeo + ICV7dXNlcm5hbWV9 + + preference: + due_on: !binary | + LSDXmdei15Mg15Ele2RhdGV9 + + due_in: !binary | + 16rXkNeo15nXmiDXmdei15Mg15HXoteV15MgJXtkYXlzfSDXmdee15nXnQ== users: - confirm_password: !binary | - 15DXmdep15XXqCDXodeZ16HXnteQ - - total_actions: !binary | - 16HXmiDXpNei15XXnNeV16o= - - change_auth_type_title: !binary | - 157Xodec15XXnNeZ1506Otep15nXoNeV15kg16nXmdeY16og15TXlteT15TX - ldeq - - openid_ok_pref_failed: !binary | - 15vXqteV15HXqiDXlNeW15TXldeqICV7dXJsfSAu15DXldee16rXlCDXkdeU - 16bXnNeX15Qg15DXmiDXkNeo16LXlCDXqten15zXlCDXkdep157Xmdeo16og - 15TXkteT16jXldeqINeU15TXlteT15TXldeq - - total_users_count: !binary | - 16fXmdeZ157XmdedICV7Y291bnR9INee16nXqtee16nXmded - total_notes: !binary | - 16HXmiDXpNeq16fXmded + 15vXnCDXlNek16rXp9eZ15XXqg== - manage_users: !binary | - 16DXmdeU15XXnCDXntep16rXntep15nXnQ== + destroy_successful: !binary | + 157Xqdeq157XqSAle2xvZ2lufSDXlNeV16nXnteTINeR15TXptec15fXlA== - you_have_to_reset_your_password: !binary | - 15nXqSDXnNeQ16TXoSDXkNeqINeU16HXmdeh157XkA== - - no_signups_title: !binary | - 157Xodec15XXnNeZ1506OteQ15nXnyDXqNeZ16nXldee15nXnQ== - - account_signup: !binary | - 16jXmdep15XXnSDXnNeX16nXkdeV158= - - new_user_heading: !binary | - 16jXmdep15XXnSDXntep16rXntepINeX15PXqTo= - - choose_password: !binary | - 15HXl9eZ16jXqiDXodeZ16HXnteQ - - auth_change_submit: !binary | - 16nXmdeg15XXmSDXqdeZ15jXqiDXkNeZ157Xldeq - - identity_url: !binary | - 15vXqteV15HXqiDXlteU15XXqg== - - signup: !binary | - 16jXmdep15XXnQ== - - signup_successful: !binary | - 16jXmdep15XXnSDXnteV16bXnNeXINei15HXldeoINee16nXqtee16kgJXt1 - c2VybmFtZX0u - - change_password_prompt: !binary | - 15nXqSDXnNeb16rXldeRINeQ16og15TXodeZ16HXnteQINeU15fXk9ep15Qg - 15HXqdeT15XXqiDXqdec157XmNeUINeV15zXlNen15zXmdenICfXqdeg15Qg - 16HXmdeh157XkCcg15vXk9eZINec15TXl9ec15nXoyDXkNeqINeU16HXmdeh - 157XkCDXlNeg15XXm9eX15nXqiDXkdeX15PXqdeULg== - - password_confirmation_label: !binary | - 15DXmdee15XXqiDXodeZ16HXnteQ - - user_created: !binary | - 157Xqdeq157XqSDXoNeV16bXqA== - - auth_type_updated: !binary | - 16nXmdeY16og15DXmdee15XXqiDXoteV15PXm9eg15Q= - - label_auth_type: !binary | - 16nXmdeY16og15DXmdee15XXqg== - - first_user_heading: !binary | - 15HXqNeV15vXmdedINeU15HXkNeZ150g15DXnCDXnteh15zXldec15nXnS4g - 15vXk9eZINec15TXqteX15nXnCwg15nXqSDXnNeZ16bXldeoINeX16nXkdeV - 158g157XoNeU15w6 - - total_contexts: !binary | - 16HXmiDXlNen16nXqNeZ150= - - failed_to_delete_user: !binary | - 157Xl9eZ16fXqiDXlNee16nXqtee16kgJXt1c2VybmFtZX0g16DXm9ep15zX - lA== - - openid_url_verified: !binary | - 15vXqteV15HXqiDXlNeW15TXldeqICV7dXJsfSAu15DXldee16rXlCDXkdeU - 16bXnNeX15Qg15XXkNeV16TXnyDXlNeQ15nXnteV16og16DXp9eR16Ig15wt - T3BlbklELg== + change_password_submit: !binary | + 16nXmdeg15XXmSDXodeZ16HXnteQ destroy_confirmation: !binary | 15DXlteU16jXlDog15TXpNei15XXnNeUINeq157Xl9enINeQ16og15TXntep @@ -1363,37 +1946,56 @@ he: qNeV15nXmden15jXmdedINeV15TXpNeq16fXmdedLiDXlNeQ150g15zXlNee 16nXmdeaPw== - destroy_successful: !binary | - 157Xqdeq157XqSAle2xvZ2lufSDXlNeV16nXnteTINeR15TXptec15fXlA== + label_auth_type: !binary | + 16nXmdeY16og15DXmdee15XXqg== - password_updated: !binary | - 16HXmdeh157XkCDXoteV15PXm9eg15Qu + identity_url: !binary | + 15vXqteV15HXqiDXlteU15XXqg== + + total_users_count: !binary | + 16fXmdeZ157XmdedICV7Y291bnR9INee16nXqtee16nXmded new_user_title: !binary | 157Xodec15XXnNeZ1506Oteo15nXqdeV150g157Xqdeq157XqSDXm9ee16DX lNec + account_signup: !binary | + 16jXmdep15XXnSDXnNeX16nXkdeV158= + + password_confirmation_label: !binary | + 15DXmdee15XXqiDXodeZ16HXnteQ + change_password_title: !binary | 157Xodec15XXnNeZ1506Otep15nXoNeV15kg16HXmdeh157XkA== - register_with_cas: !binary | - 16LXnSDXntep16rXntepINeU16nXkCLXniDXqdec15o= + no_signups_title: !binary | + 157Xodec15XXnNeZ1506OteQ15nXnyDXqNeZ16nXldee15nXnQ== - destroy_user: !binary | - 15TXqdee15PXqiDXntep16rXntep + new_user_heading: !binary | + 16jXmdep15XXnSDXntep16rXntepINeX15PXqTo= - successfully_deleted_user: !binary | - 157Xqdeq157XqSAgJXt1c2VybmFtZX0g16DXnteX16cg15HXlNem15zXl9eU - - new_token_generated: !binary | - 15DXodeZ157XldefINeX15PXqSDXoNeV16bXqCDXkdeU16bXnNeX15Q= + total_projects: !binary | + 16TXqNeV15nXp9eY15nXnSDXkdeh15og15TXm9ec destroy_error: !binary | 15DXqNei15Qg16nXkteZ15DXlCDXkdee15fXmden16og15TXntep16rXntep ICV7bG9naW59 - change_authentication_type: !binary | - 16nXmdeg15XXmSDXqdeZ15jXqiDXlNeW15PXlNeV16o= + new_password_label: !binary | + 16HXmdeh157XkCDXl9eT16nXlA== + + you_have_to_reset_your_password: !binary | + 15nXqSDXnNeQ16TXoSDXkNeqINeU16HXmdeh157XkA== + + openid_ok_pref_failed: !binary | + 15vXqteV15HXqiDXlNeW15TXldeqICV7dXJsfSAu15DXldee16rXlCDXkdeU + 16bXnNeX15Qg15DXmiDXkNeo16LXlCDXqten15zXlCDXkdep157Xmdeo16og + 15TXkteT16jXldeqINeU15TXlteT15TXldeq + + first_user_heading: !binary | + 15HXqNeV15vXmdedINeU15HXkNeZ150g15DXnCDXnteh15zXldec15nXnS4g + 15vXk9eZINec15TXqteX15nXnCwg15nXqSDXnNeZ16bXldeoINeX16nXkdeV + 158g157XoNeU15w6 select_authentication_type: !binary | 15nXqSDXnNeR15fXldeoINeQ16og16nXmdeY16og15TXlteZ15TXldeZINeU @@ -1401,180 +2003,201 @@ he: 15TXlteT15TXldeqJyDXnNeR15fXmdeo16og15TXqdeZ15jXlCDXlNeg15XX m9eX15nXqg== + desired_login: !binary | + 157Xqdeq157XqSDXm9eg15nXodeUINeo16bXldeZ + + confirm_password: !binary | + 15DXmdep15XXqCDXodeZ16HXnteQ + + change_password_prompt: !binary | + 15nXqSDXnNeb16rXldeRINeQ16og15TXodeZ16HXnteQINeU15fXk9ep15Qg + 15HXqdeT15XXqiDXqdec157XmNeUINeV15zXlNen15zXmdenICfXqdeg15Qg + 16HXmdeh157XkCcg15vXk9eZINec15TXl9ec15nXoyDXkNeqINeU16HXmdeh + 157XkCDXlNeg15XXm9eX15nXqiDXkdeX15PXqdeULg== + + failed_to_delete_user: !binary | + 157Xl9eZ16fXqiDXlNee16nXqtee16kgJXt1c2VybmFtZX0g16DXm9ep15zX + lA== + + register_with_cas: !binary | + 16LXnSDXntep16rXntepINeU16nXkCLXniDXqdec15o= + + new_token_generated: !binary | + 15DXodeZ157XldefINeX15PXqSDXoNeV16bXqCDXkdeU16bXnNeX15Q= + + password_updated: !binary | + 16HXmdeh157XkCDXoteV15PXm9eg15Qu + + total_actions: !binary | + 16HXmiDXpNei15XXnNeV16o= + + choose_password: !binary | + 15HXl9eZ16jXqiDXodeZ16HXnteQ + + auth_change_submit: !binary | + 16nXmdeg15XXmSDXqdeZ15jXqiDXkNeZ157Xldeq + + total_contexts: !binary | + 16HXmiDXlNen16nXqNeZ150= + + manage_users: !binary | + 16DXmdeU15XXnCDXntep16rXntep15nXnQ== + + auth_type_updated: !binary | + 16nXmdeY16og15DXmdee15XXqiDXoteV15PXm9eg15Q= + + signup_successful: !binary | + 16jXmdep15XXnSDXnteV16bXnNeXINei15HXldeoINee16nXqtee16kgJXt1 + c2VybmFtZX0u + + change_authentication_type: !binary | + 16nXmdeg15XXmSDXqdeZ15jXqiDXlNeW15PXlNeV16o= + auth_type_update_error: !binary | 15DXqNei15Qg16nXkteZ15DXlCDXkdei15nXk9eb15XXnyDXqdeZ15jXqiDX lNeQ15nXnteV16o6ICV7ZXJyb3JfbWVzc2FnZXN9 - total_projects: !binary | - 16HXlCLXmyDXpNeo15XXmden15jXmded - - change_password_submit: !binary | - 16nXmdeg15XXmSDXodeZ16HXnteQ - - desired_login: !binary | - 157Xqdeq157XqSDXm9eg15nXodeUINeo16bXldeZ - - new_password_label: !binary | - 16HXmdeh157XkCDXl9eT16nXlA== + change_auth_type_title: !binary | + 157Xodec15XXnNeZ1506Otep15nXoNeV15kg16nXmdeY16og15TXlteT15TX + ldeq signup_new_user: !binary | 16jXqdeV150g157Xqdeq157XqSDXl9eT16k= + openid_url_verified: !binary | + 15vXqteV15HXqiDXlNeW15TXldeqICV7dXJsfSAu15DXldee16rXlCDXkdeU + 16bXnNeX15Qg15XXkNeV16TXnyDXlNeQ15nXnteV16og16DXp9eR16Ig15wt + T3BlbklELg== + + destroy_user: !binary | + 15TXqdee15PXqiDXntep16rXntep + + user_created: !binary | + 157Xqdeq157XqSDXoNeV16bXqA== + + signup: !binary | + 16jXmdep15XXnQ== + + successfully_deleted_user: !binary | + 157Xqdeq157XqSAgJXt1c2VybmFtZX0g16DXnteX16cg15HXlNem15zXl9eU + + preferences: + page_title_edit: !binary | + 157Xodec15XXnNeZ1506Otei16jXmdeb16og15TXoteT16TXldeq + + authentication_header: !binary | + 15TXlteZ15TXldeZINep15zXmQ== + + change_password: !binary | + 16HXmdeg15XXmSDXodeZ16HXnteQ + + staleness_starts_after: !binary | + 16rXpNec15XXqiDXnteq15fXmdec15Qg15zXkNeX16ggJXtkYXlzfSDXmdee + 15nXnQ== + + change_identity_url: !binary | + 16nXmdeg15XXmSDXm9eq15XXkdeqIFVSTCDXlNeW15PXlNeV16o= + + updated: !binary | + 15TXoteT16TXldeqINei15XXk9eb16DXlQ== + + current_authentication_type: !binary | + 16nXmdeY16og15TXlteZ15TXldeZINep15zXmSDXlNeZ15AgJXthdXRoX3R5 + cGV9 + + token_description: !binary | + 15DXodeZ157XldefICjXntep157XqSDXnNeU15bXoNeV16og15nXqdeZ157X + ldepINee157XqdenINeq15vXqteg15XXqik= + + edit_preferences: !binary | + 16LXqNeZ15vXqiDXlNei15PXpNeV16o= + + is_true: !binary | + 15fXmdeV15HXmQ== + + token_header: !binary | + 15TXkNeh15nXnteV158g16nXnNeZ + + generate_new_token_confirm: !binary | + 15HXmNeV15c/INeZ16bXmdeo16og15DXodeZ157XldefINeX15PXqSDXqteX + 15zXmdejINeQ16og15TXkNeh15nXnteV158g15TXp9eZ15nXnSDXldeq15HX + mNecINeQ16og15TXqdeZ157XldepINeR15Uu + + is_false: !binary | + 16nXnNeZ15zXmQ== + + tabs: + authentication: !binary | + 15DXmdee15XXqg== + + tracks_behavior: !binary | + 15TXqteg15TXkteV16og157Xodec15XXnNeZ150= + + date_and_time: !binary | + 16rXkNeo15nXmiDXldep16LXlA== + + profile: !binary | + 16TXqNeV16TXmdec + + page_title: !binary | + 157Xodec15XXnNeZ1506OteU16LXk9ek15XXqg== + + sms_context_none: !binary | + 15zXnNeQ + + change_authentication_type: !binary | + 16nXmdeg15XXmSDXodeV15Ig15TXlteT15TXldeq + + open_id_url: !binary | + 15vXqteV15HXqiDXlteZ15TXldeZIE9wZW5JRCDXqdec15og15TXmdeQ + + show_number_completed: !binary | + 15TXpteSICV7bnVtYmVyfSDXpNeo15nXmNeZ150g16nXlNeh16rXmdeZ157X + lQ== + + generate_new_token: !binary | + 15nXpteZ16jXqiDXkNeh15nXnteV158g15fXk9ep + + password_changed: !binary | + 15TXodeZ16HXnteQINep15XXoNeq15QsINeZ16kg15zXlNeZ15vXoNehINep + 16DXmdeqLg== + + title: !binary | + 15TXlNeS15PXqNeV16og16nXnNeZ + common: - search: !binary | - 15fXmdek15XXqQ== - - third: !binary | - 16nXnNeZ16nXmQ== - - project: !binary | - 16TXqNeV15nXmden15g= - - action: !binary | - 16TXoteV15zXlA== - - ajaxError: !binary | - 16nXkteZ15DXlCDXkdeq15LXldeR15Qg157XlNep16jXqg== - - previous: !binary | - 15TXp9eV15PXnQ== - - sort: - by_task_count: !binary | - 15zXpNeZINee16HXpNeoINee16nXmdee15XXqg== - - alphabetically_title: !binary | - 16HXk9eoINek16jXldeZ15nXp9eY15nXnSDXkNec16TXkdeY15nXqg== - - sort: !binary | - 157XmdeZ158= - - by_task_count_title: !binary | - 157XmdeZ158g15zXpNeZINee16HXpNeoINee16nXmdee15XXqg== - - alphabetically_confirm: !binary | - 15zXodeT16gg15DXqiDXlNek16jXldeZ15nXp9eY15nXnSDXkdeh15PXqCDX - kNec16TXkdeq15k/INeU16TXoteV15zXlCDXqteX15zXmdejINeQ16og15TX - odeT16gg15TXp9eZ15nXnQ== - - by_task_count_title_confirm: !binary | - 15zXodeT16gg15DXqiDXlNek16jXldeZ15nXp9eY15nXnSDXnNek15kg157X - odek16gg15TXntep15nXnteV16o/INeU16TXoteV15zXlCDXqteX15zXmdej - INeQ16og15TXodeT16gg15TXp9eZ15nXnQ== - - alphabetically: !binary | - 15DXnNek15HXqteZ - - server_error: !binary | - 15TXqteo15fXqdeUINep15LXmdeQ16og16nXqNeq - - email: !binary | - 15PXldeQItec - - weeks: !binary | - 16nXkdeV16LXldeq - - ok: !binary | - 15DXlden15k= - - actions: !binary | - 16TXoteV15zXldeq - - todo: !binary | - 157XqdeZ157XlA== - - website: !binary | - 15DXqteo - - review: !binary | - 15HXmden15XXqNeq - - logout: !binary | - 16bXkA== - numbered_step: !binary | 16bXoteTICV7bnVtYmVyfQ== - drag_handle: !binary | - 157XqdeV15o= - - context: !binary | - 15TXp9ep16g= - - bugs: !binary | - 15HXkNeS15nXnQ== - - show_all: !binary | - 15TXpteSINeU15vXnA== - - fourth: !binary | - 16jXkdeZ16LXmQ== - - forum: !binary | - 16TXldeo15XXnQ== - - next: !binary | - 15TXkdeQ - projects: !binary | 16TXqNeV15nXmden15jXmded - contribute: !binary | - 16rXqNeV150= - - optional: !binary | - 15DXpNep16jXmQ== - - week: !binary | - 16nXkdeV16I= - - back: !binary | - 15DXl9eV16jXlA== - - actions_midsentence: !binary | - 16TXoteV15zXldeq - - first: !binary | - 16jXkNep15XXnw== - - wiki: !binary | - 15XXmden15k= - - month: !binary | - 15fXldeT16k= - add: !binary | 15TXldeh16M= - second: !binary | - 16nXoNeZ - - last: !binary | - 15DXl9eo15XXnw== - - none: !binary | - 15TXoteo15Q= - - notes: !binary | - 15TXoteo15XXqg== - - cancel: !binary | - 15HXmNec - go_back: !binary | 15fXlteV16g= + optional: !binary | + 15DXpNep16jXmQ== + + contribute: !binary | + 16rXqNeV150= + + todo: !binary | + 157XqdeZ157XlA== + forth: !binary | 15XXkNeZ15zXmg== - description: !binary | - 16rXmdeQ15XXqA== + none: !binary | + 15TXoteo15Q= - recurring_todos: !binary | - 16TXoteV15zXldeqINee15fXlteV16jXmdeV16o= + back: !binary | + 15DXl9eV16jXlA== - months: !binary | - 15fXldeT16nXmded + second: !binary | + 16nXoNeZ update: !binary | 16LXk9eb158= @@ -1582,224 +2205,412 @@ he: create: !binary | 16bXldeo - contexts: !binary | - 15TXp9ep16jXmded + description: !binary | + 16rXmdeQ15XXqA== + + bugs: !binary | + 15HXkNeS15nXnQ== + + third: !binary | + 16nXnNeZ16nXmQ== + + weeks: !binary | + 16nXkdeV16LXldeq + + days_midsentence: + other: !binary | + 15nXnteZ150= + + zero: !binary | + 15nXnteZ150= + + one: !binary | + 15nXlded + + cancel: !binary | + 15HXmNec + + sort: + sort: !binary | + 157XmdeZ158= + + by_task_count: !binary | + 15zXpNeZINee16HXpNeoINee16nXmdee15XXqg== + + alphabetically_title: !binary | + 16HXk9eoINek16jXldeZ15nXp9eY15nXnSDXkNec16TXkdeY15nXqg== + + by_task_count_title_confirm: !binary | + 15zXodeT16gg15DXqiDXlNek16jXldeZ15nXp9eY15nXnSDXnNek15kg157X + odek16gg15TXntep15nXnteV16o/INeU16TXoteV15zXlCDXqteX15zXmdej + INeQ16og15TXodeT16gg15TXp9eZ15nXnQ== + + alphabetically_confirm: !binary | + 15zXodeT16gg15DXqiDXlNek16jXldeZ15nXp9eY15nXnSDXkdeh15PXqCDX + kNec16TXkdeq15k/INeU16TXoteV15zXlCDXqteX15zXmdejINeQ16og15TX + odeT16gg15TXp9eZ15nXnQ== + + by_task_count_title: !binary | + 157XmdeZ158g15zXpNeZINee16HXpNeoINee16nXmdee15XXqg== + + alphabetically: !binary | + 15DXnNek15HXqteZ errors_with_fields: !binary | 16nXkteZ16jXldeqINeR16nXk9eV16og15TXntem15XXmdeZ16DXmded - data: - import_errors: !binary | - 16nXkteZ15DXldeqINeR15nXkdeV15A= + ajaxError: !binary | + 16nXkteZ15DXlCDXkdeq15LXldeR15Qg157XlNep16jXqg== - import_successful: !binary | - 15nXkdeV15Ag15HXldem16Ig15HXlNem15zXl9eU + server_error: !binary | + 15TXqteo15fXqdeUINep15LXmdeQ16og16nXqNeq - date: - formats: - default: "%Y-%m-%d " - longer: "%A %B %d, %Y" - short: "%b %d " - long: "%B %d, %Y " - projects: - default_context_set: !binary | - 15HXl9eZ16jXqiDXlNen16nXqCDXkdeo15nXqNeqINeU157Xl9eT15wg15zX - pNeo15XXmdeZ16fXmCDXnC0le2RlZmF1bHRfY29udGV4dH0= + action: !binary | + 16TXoteV15zXlA== - add_note: !binary | - 15TXldeh16TXqiDXpNeq16c= + last: !binary | + 15DXl9eo15XXnw== - hidden_projects: !binary | - 16TXqNeV15nXmden15jXmdedINep15TXldeh16rXqNeV + email: !binary | + 15PXldeQItec - default_tags_removed_notice: !binary | - 16rXkteZ15XXqiDXkdeo15nXqNeqINeU157Xl9eT15wg15TXldeh16jXlQ== + note: + other: !binary | + JXtjb3VudH0g16TXqten15nXldeq - deferred_actions: !binary | - 16TXoteV15zXldeqINep16DXk9eX15Ug16LXkdeV16gg16TXqNeV15nXmden - 15gg15bXlA== + zero: !binary | + 15DXmdefINek16rXp9eZ15XXqg== - add_note_submit: !binary | - 15TXldeh16TXqiDXpNeq16c= + one: !binary | + 16TXqten15Q= - page_title: !binary | - 157Xodec15XXnNeZ1506Otek16jXldeZ15nXp9eYOiAle3Byb2plY3R9 + deferred: !binary | + 16DXk9eX15Q= - was_marked_complete: !binary | - 16HXldee158g15vXkdeV16bXog== + previous: !binary | + 15TXp9eV15PXnQ== - with_no_default_context: !binary | - 15zXnNeQINeU16fXqdeoINeR16jXmdeo16og157Xl9eT15w= + months: !binary | + 15fXldeT16nXmded - no_default_context: !binary | - ICDXkNeZ158g15TXp9ep16gg15HXqNeZ16jXqiDXnteX15PXnCDXnNek16jX - ldeZ15nXp9eYINeW15Q= + fourth: !binary | + 16jXkdeZ16LXmQ== - completed_actions_empty: !binary | - 15DXmdefINek16LXldec15XXqiDXqdeU16HXqteZ15nXnteVINeR16TXqNeV - 15nXmden15gg15bXlA== + search: !binary | + 15fXmdek15XXqQ== - edit_project_settings: !binary | - 16LXqNeZ15vXqiDXlNeS15PXqNeV16og16TXqNeV15nXmden15g= + contexts: !binary | + 15TXp9ep16jXmded - with_default_context: !binary | - 16LXnSDXlNen16nXqCDXkdeZ16jXqiDXnteX15PXnCAnJXtjb250ZXh0X25h - bWV9Jw== + recurring_todos: !binary | + 16TXoteV15zXldeqINee15fXlteV16jXmdeV16o= - add_project: !binary | - 15TXldeh16TXqiDXpNeo15XXmdeZ16fXmA== + project: !binary | + 16TXqNeV15nXmden15g= - set_default_tags_notice: !binary | - 15HXl9eZ16jXqiDXqteS15nXldeqINeR16jXmdeo16og15TXnteX15PXnCDX - nC0le2RlZmF1bHRfdGFnc30= + website: !binary | + 15DXqteo - with_no_default_tags: !binary | - 15XXnNec15Ag16rXkteZ15XXqiDXkdeo15nXqNeqINee15fXk9ec + logout: !binary | + 16bXkA== - completed_actions: !binary | - 16TXoteV15zXldeqINep15TXodeq15nXmdee15Ug15HXpNeo15XXmdeZ16fX - mCDXlteU + forum: !binary | + 16TXldeo15XXnQ== - hide_form_title: !binary | - 15TXodeq16jXqiDXmNeV16TXoSDXpNeo15XXmdeZ16fXmCDXl9eT16k= + month: !binary | + 15fXldeT16k= - is_active: !binary | - 16TXoteZ15w= + week: !binary | + 16nXkdeV16I= - completed_projects: !binary | - 16TXqNeV15nXmden15jXmdedINep15TXodeq15nXmdee15U= + first: !binary | + 16jXkNep15XXnw== - no_actions_in_project: !binary | - 15DXmdefINeb16jXkteiINee16nXmdee15XXqiDXqdecINeU15XXqdec157X - lSDXkdek16jXldeZ15nXp9eYINeW15Q= + show_all: !binary | + 15TXpteSINeU15vXnA== - to_new_project_page: !binary | - 16LXkdeV16gg15zXotee15XXkyDXlNek16jXldeZ15nXp9eYINeU15fXk9ep + review: !binary | + 15HXmden15XXqNeq - default_context: !binary | - 15TXp9ep16gg15HXqNeZ16jXqiDXlNee15fXk9epINec16TXqNeV15nXmden - 15gg15bXlCAle2NvbnRleHR9 + context: !binary | + 15TXp9ep16g= - delete_project: !binary | - 157Xl9eZ16fXqiDXpNeo15XXmdeZ16fXmA== + drag_handle: !binary | + 157XqdeV15o= - status_project_name_changed: !binary | - 16nXnSDXlNek16jXldeZ15nXp9eYINep15XXoNeU + wiki: !binary | + 15XXmden15k= - no_last_completed_recurring_todos: !binary | - 15zXkCDXoNee16bXkNeVINee16nXmdee15XXqSDXnteX15bXldeo15nXldeq - INep15TXodeq15nXmdee15U= + not_available_abbr: !binary | + 15wv15k= - project_state: !binary | - 15TXpNeo15XXmdeZ16fXmCAle3N0YXRlfQ== + actions: !binary | + 16TXoteV15zXldeq - delete_project_title: !binary | - 157Xl9eZ16fXqiDXlNek16jXldeZ15nXp9eY - - completed_tasks_title: !binary | - 157Xodec15XXnNeZ1506OteU16bXkteqINeo16nXmdee16og15TXntep15nX - nteV16og16nXlNeV16nXnNee15Ug15HXpNeo15XXmdeZ16fXmCAgJyV7cHJv - amVjdF9uYW1lfSc= - - was_marked_hidden: !binary | - 16HXldee158g15vXnteV16HXqteo - - show_form_title: !binary | - 15nXpteZ16jXqiDXpNeo15XXmdeZ16fXmCDXl9eT16k= - - notes_empty: !binary | - 15DXmdefINek16rXp9eZ150g15zXpNeo15XXmdeZ16fXmCDXlteU - - delete_project_confirmation: !binary | - 15TXkNedINec157Xl9eV16cg15DXqiDXlNek16jXldeZ15nXp9eYICAnJXtu - YW1lfSc/ - - default_context_removed: !binary | - 15TXp9ep16gg15HXqNeZ16jXqiDXlNee15fXk9ecINeU15XXodeo - - list_completed_projects: !binary | - 157Xodec15XXnNeZ1506Oteo16nXmdee16og15TXpNeo15XXmdeZ16fXmNeZ - 150g16nXlNeV15zXqdee15U= - - hide_form: !binary | - 15TXodeq16jXqiDXmNeV16TXoQ== - - deferred_actions_empty: !binary | - 15DXmdefINek16LXldec15XXqiDXqdeg15PXl9eVINei15HXldeoINek16jX - ldeZ15nXp9eYINeW15Q= - - actions_in_project_title: !binary | - 16TXoteV15zXldeqINeR16TXqNeV15nXmden15gg15bXlA== - - settings: !binary | - 15TXkteT16jXldeq + next: !binary | + 15TXkdeQ notes: !binary | - 16TXqten15nXnQ== + 16TXqten15nXldeq - project_saved_status: !binary | - 16TXqNeV15nXmden15gg16DXqdee16g= + ok: !binary | + 15DXlden15k= - no_notes_attached: !binary | - 15DXmdefINeb16jXkteiINek16rXp9eZ150g15TXnten15XXqdeo15nXnSDX - nNek16jXldeZ15nXp9eYINeW15Q= + actions_midsentence: + other: !binary | + 16TXoteV15zXldeq - list_projects: !binary | - 157Xodec15XXnNeZ1506Oteo16nXmdee16og16TXqNeV15nXmden15jXmded + zero: !binary | + 16TXoteV15zXldeq - all_completed_tasks_title: !binary | - 157Xodec15XXnNeZ1506OteU16bXkteqINeo16nXmdee16og15vXnCDXlNee - 16nXmdee15XXqiDXqdeU15XXqdec157XlSDXkdek16jXldeZ15nXp9eYICAn - JXtwcm9qZWN0X25hbWV9Jw== + one: !binary | + 16TXoteV15zXlA== - this_project: !binary | - 16TXqNeV15nXmden15gg15bXlA== + layouts: + toggle_notes_title: !binary | + 15fXqdeZ16TXqiDXm9ecINeU16TXqten15nXldeq - todos_append: !binary | - 15HXpNeo15XXmdeZ16fXmCDXlteU + mobile_navigation: + home: !binary | + MS3XkdeZ16o= - active_projects: !binary | - 16TXqNeV15nXmden15jXmdedINek16LXmdec15nXnQ== + projects: !binary | + 16TXqNeV15nXmden15jXmded - show_form: !binary | - 15TXldeh16TXqiDXpNeo15XXmdeZ16fXmA== + tickler: !binary | + 157WtNeW1rDXm9a41rzXqA== - with_default_tags: !binary | - 16LXnSDXlNeq15LXmdeV16ogICcle3RhZ3N9JyDXm9eR16jXmdeo16og15TX - nteX15PXnA== + starred: !binary | + NC3XnteV15PXktep15nXnQ== - state: !binary | - 15TXpNeo15XXmdeZ16fXmCDXkdee16bXkSAle3N0YXRlfQ== + feeds: !binary | + 15TXlteg15XXqg== - no_last_completed_projects: !binary | - 15zXkCDXoNee16bXkNeVINek16jXldeZ15nXp9eY15nXnSDXqdeU16HXqteZ - 15nXnteV + new_action: !binary | + MC3XpNei15XXnNeUINeX15PXqdeU - edit_project_title: !binary | - 16LXqNeZ15vXqiDXpNeo15XXmdeZ16fXmA== + contexts: !binary | + Mi3XlNen16nXqNeZ150= - list_reviews: !binary | - 157Xodec15XXnNeZ1506Oteh16fXmdeo15Q= + logout: !binary | + 16bXkA== - no_projects: !binary | - 15DXmdefINeb16jXkteiINek16jXldeZ15nXp9eY15nXnQ== + navigation: + home: !binary | + 15HXmdeq + + starred_title: !binary | + 15TXpteS16og16TXoteV15zXldeqINee15XXk9eS16nXldeq + + recurring_todos_title: !binary | + 16DXmdeU15XXnCDXpNei15XXnNeV16og157Xl9eW15XXqNeZ15XXqg== + + tickler: !binary | + 157WtNeW1rDXm9a41rzXqA== + + help: "?" + admin: !binary | + 16DXmdeU15XXnA== + + starred: !binary | + 157XldeT15LXqdeZ150= + + completed_tasks_title: !binary | + 15TXodeq15nXmded + + api_docs: !binary | + 16rXmdei15XXkyDXntee16nXpyDXqteb16DXldeq + + integrations_: !binary | + 16nXmdec15XXkSDXnteh15zXldec15nXnQ== + + feeds: !binary | + 15TXlteg15XXqg== + + preferences_title: !binary | + 15TXpteS16og15TXoteT16TXldeq15k= + + export_title: !binary | + 15nXkdeV15Ag15XXmdem15XXkCDXoNeq15XXoNeZ150= + + stats: !binary | + 16HXmNeY15nXodeY15nXp9eU + + home_title: !binary | + 15HXmdeq + + organize: !binary | + 15DXqNeS15XXnw== + + feeds_title: !binary | + 16bXpNeZ15Qg15HXqNep15nXnteqINeU15TXlteg15XXqiDXlNeW157Xmdeg + 15Q= + + manage_users: !binary | + 16DXmdeU15XXnCDXntep16rXntep15nXnQ== + + notes_title: !binary | + 15TXpteS16og15vXnCDXlNek16rXp9eZ15XXqg== + + search: !binary | + 15fXmdek15XXqSDXm9ecINeU16TXqNeZ15jXmded + + completed_tasks: !binary | + 15HXldem16I= + + review_title: !binary | + 16LXqNeZ15vXpiDXkdeZ16fXldeo16o= + + recurring_todos: !binary | + 157XqdeZ157XldeqINee15fXlteV16jXmdeV16o= + + preferences: !binary | + 15TXoteT16TXldeq + + manage_users_title: !binary | + 15TXldeh16TXlCDXkNeVINeU16HXqNeUINep15wg157Xqdeq157XqdeZ150= + + stats_title: !binary | + 15TXpteS16og15TXodeY15jXmdeh15jXmden15Qg16nXnNeZ + + view: !binary | + 16rXpteV15LXlA== + + contexts_title: !binary | + 15TXp9ep16jXmded + + calendar_title: !binary | + 15zXldeXINep16DXlCDXqdecINee16nXmdee15XXqiDXnNeR15nXpteV16I= + + projects_title: !binary | + 16TXqNeV15nXmden15jXmded + + calendar: !binary | + 15zXldeXINep16DXlA== + + tickler_title: !binary | + 157WtNeW1rDXm9a41rzXqA== + + export: !binary | + 15nXpteV15A= + + next_actions_rss_feed: !binary | + 15TXlteg16og16jXodehINec16TXoteV15zXldeqINeU157Xqdea + + toggle_contexts_title: !binary | + 15TXodeq16jXqi/XlNem15LXqiDXqdeT15XXqiDXnteV16HXqteo15nXnQ== + + toggle_contexts: !binary | + 15TXpteS16og16nXk9eV16og157Xldeh16rXqNeZ150= + + toggle_notes: !binary | + 15fXqdeZ16TXqiDXpNeq16fXmdeV16o= + + feedlist: + actions_due_today: !binary | + 16TXoteV15zXldeqINec15HXmdem15XXoiDXlNeZ15XXnSDXkNeVINee15XX + p9eT150g15nXldeq16g= + + active_projects_wo_next: !binary | + 16TXqNeV15nXmden15jXmdedINek16LXmdec15nXnSDXnNec15Ag16TXoteV + 15zXldeqINeU157Xqdea + + select_feed_for_project: !binary | + 15HXl9eZ16jXqiDXlNeU15bXoNeUINei15HXldeoINeU16TXqNeV15nXmden + 15g= + + actions_completed_last_week: !binary | + 16TXoteV15zXldeqINep15TXodeq15nXmdee15Ug15HXqdeR16LXqiDXlNeZ + 157XmdedINeU15DXl9eo15XXoNeZ150= + + all_contexts: !binary | + 15vXnCDXlNeU16fXqdeo15nXnQ== + + project_needed: !binary | + 15PXqNeV16kg15zXpNeX15XXqiDXpNeo15XXmdeZ16fXmCDXkNeX15Mg15zX + pNeg15kg16nXoNeZ16rXnyDXnNeR16fXqSDXlNeW16DXlA== + + notice_incomplete_only: !binary | + 15TXoteo15Q6INeb15wg15TXlNeW16DXldeqINee16bXmdeS15XXqiDXkNeq + INeb15wg15TXpNei15XXnNeV16og16nXnNeQINeh15XXnteg15Ug15vXnteR + 15XXptei15XXqiDXkNec15Ag15DXnSDXm9efINeg15HXl9eoINeR157XpNeV + 16jXqSDXkNeX16jXqi4= + + choose_context: !binary | + 15HXl9eZ16jXqiDXlNeU16fXqdeoINei15HXldeo15Ug15PXqNeV16nXlCDX + lNeW16DXlA== + + all_projects: !binary | + 15vXnCDXlNek16jXldeZ15nXp9eY15nXnQ== + + context_centric_actions: !binary | + 15TXlteg15XXqiDXoteR15XXqCDXpNei15XXnNeV16og16nXnNeQINeg16HX + qteZ15nXnteVINeR15TXp9ep16gg16DXqteV158= + + context_needed: !binary | + 16bXqNeZ15og15zXlNeZ15XXqiDXnNek15fXldeqINeU16fXqdeoINeQ15fX + kyDXnNek16DXmSDXqdeg15nXqtefINec15HXp9ep16gg15TXlteg15Q= + + project_centric: !binary | + 15TXlteg15XXqiDXoteR15XXqCDXpNei15XXnNeV16og16nXnNeQINeU16HX + qteZ15nXnteVINeR16TXqNeV15nXmden15gg157XodeV15nXmded + + ical_feed: !binary | + 15TXlteg16ogaUNhbA== + + active_starred_actions: !binary | + 15vXnCDXlNek16LXldec15XXqiDXlNek16LXmdec15XXqiDXldeU157Xk9eS + 16nXldeq + + last_fixed_number: !binary | + JXtudW1iZXJ9INek16LXldec15XXqiDXkNeX16jXldeg15XXqg== + + rss_feed: !binary | + 15TXlteg16og16jXodeh + + choose_project: !binary | + 15HXl9eZ16jXqiDXlNek16jXldeZ15nXp9eYINei15HXldeo15Ug15PXqNeV + 16nXlCDXlNeW16DXlA== + + projects_and_actions: !binary | + 16TXqNeV15XXmden15jXmdedINek16LXmdec15nXnSDXldeU16TXoteV15zX + ldeqINep15zXlNed + + actions_due_next_week: !binary | + 16TXoteV15zXldeqINep15nXqSDXnNeR16bXoiDXkdep15HXoteqINeU15nX + nteZ150g15TXp9eo15XXkdeZ150= + + plain_text_feed: !binary | + 15TXlteg16og15jXp9eh15gg16TXqdeV15g= + + all_actions: !binary | + 15vXnCDXlNek16LXldec15XXqg== + + legend: !binary | + 157Xp9eo15A6 + + select_feed_for_context: !binary | + 15HXl9eZ16jXqiDXlNeU15bXoNeUINei15HXldeoINeU15TXp9ep16gg15TX + oNeq15XXnw== number: currency: format: - delimiter: "," - format: "%u%n " - separator: . unit: !binary | 4oKq - format: - delimiter: "," - separator: . + separator: . + delimiter: "," + format: "%u%n " human: storage_units: - format: "%u%n" units: + tb: !binary | + 15jXqNeUINeR15nXmdeY + + kb: !binary | + 16fXmdec15Ug15HXmdeZ15g= + gb: !binary | 15In15nXkteU15HXmdeZ15g= @@ -1813,814 +2624,101 @@ he: one: !binary | 15HXmdeZ15g= - tb: !binary | - 15jXqNeUINeR15nXmdeY - - kb: !binary | - 16fXmdec15Ug15HXmdeZ15g= - - support: - select: - prompt: !binary | - 15nXqSDXnNeR16bXoiDXkdeX15nXqNeU - - array: - words_connector: "," - two_words_connector: !binary | - 15Ut - - last_word_connector: !binary | - LCDXlS0= - - notes: - delete_item_title: !binary | - 157Xl9eZ16fXqiDXpNeo15nXmA== - - delete_note_title: !binary | - 157Xl9eZ16fXqiDXlNek16rXpyAnJXtpZH0n - - delete_note_confirm: !binary | - 15TXkNedINec157Xl9eV16cg15DXqiDXlNek16rXpyAgJyV7aWR9Jz8= - - show_note_title: !binary | - 15TXpteS16og16TXqten - - edit_item_title: !binary | - 16LXqNeZ15vXqiDXpNeo15nXmA== - - delete_confirmation: !binary | - 15TXkNedINec157Xl9eV16cg15DXqiDXlNek16rXpyAgJyV7aWR9Jz8= - - note_location_link: !binary | - 15HXqteV15o6 - - note_header: !binary | - 16TXqtenICV7aWR9 - - note_link_title: !binary | - 15TXpteS16og16TXqtenICV7aWR9 - - deleted_note: !binary | - 15TXpNeq16cgJyV7aWR9JyDXoNee15fXpw== - - no_notes_available: !binary | - 15DXmdefINeb16jXkteiINek16rXp9eZ1506INeg15nXqtefINec15TXldeh - 15nXoyDXpNeq16fXmdedINec16TWsNa816jXlda515nWtten1rDXmNeZ150g - 16HXpNem15nXpNeZ15nXnSDXntei157XldeTINeU16TWsNa816jXlda515nW - tten1rDXmA== - - sidebar: - list_name_hidden_contexts: !binary | - 15TXp9ep16jXmdedINee15XXodeq16jXmded - - list_name_active_contexts: !binary | - 15TXp9ep16jXmdedINek16LXmdec15nXnQ== - - list_empty: !binary | - 15DXmdef - - list_name_completed_projects: !binary | - 16TXqNeV15nXmden15jXmdedINep15TXodeq15nXmdee15U= - - list_name_active_projects: !binary | - 16TXqNeV15nXmden15jXmdedINek16LXmdec15nXnQ== - - list_name_hidden_projects: !binary | - 16TXqNeV15nXmden15jXmdedINee15XXodeq16jXmded - - stats: - click_to_return: !binary | - 15TXp9ec16fXlCDXotecICV7bGlua30g16rXl9eW15nXqCDXnNei157XldeT - INeU16HXmNeY15nXodeY15nXp9eU - - running_time_all_legend: - actions: !binary | - 16TXoteV15zXldeq - - percentage: !binary | - 15DXl9eV15Y= - - running_time: !binary | - 15bXntefINee16bXmNeR16gg15zXpNei15XXnNeV16ogKNep15HXldei15XX - qikuINeU16fXnNen15Qg16LXnCDXlNeR16gg15zXnteZ15PXoiDXoNeV16HX - ow== - - totals_hidden_context_count: !binary | - 15UtJXtjb3VudH0g15HXlNen16nXqNeZ150g157Xldeh16rXqNeZ150u - - tod30: !binary | - 15bXntefINeR15nXldedICgzMCDXmdee15nXnSDXkNeX16jXldeg15kp - - open_per_week_legend: - weeks: !binary | - 16nXkdeV16LXldeqINen15XXk9edINec15vXnw== - - actions: !binary | - 16TXoteV15zXldeq - - action_completion_time_title: !binary | - 15bXntefINeh15nXldedICjXm9ecINeU16TXoteV15zXldeqINep15TXodeq - 15nXmdee15Up - - index_title: !binary | - 157Xodec15XXnNeZ1506Oteh15jXmNeZ16HXmNeZ16fXlA== - - top10_projects_30days: !binary | - MTAg16TXqNeV15nXmden15jXmdedINee15XXkdeZ15zXmdedINeRLTMwINeU - 15nXnteZ150g15TXkNeX16jXldeg15nXnQ== - - running_time_legend: - weeks: !binary | - 15bXntefINee16bXmNeR16gg15zXpNei15XXnNeV16ogKNep15HXldei15XX - qikuINeU16fXnNen15Qg16LXnCDXlNeR16gg15zXnteZ15PXoiDXoNeV16HX - ow== - - actions: !binary | - 16TXoteV15zXldeq - - percentage: !binary | - 15DXl9eV15Y= - - action_selection_title: !binary | - 157Xodec15XXnNeZ1506OteR15fXmdeo16og16TXoteV15zXlA== - - running_time_all: !binary | - 15bXntefINee16bXmNeR16gg15zXm9ecINeU16TXoteV15zXldeqINep15zX - kCDXlNeh16rXmdeZ157XlQ== - - actions_avg_completed_30days: !binary | - 15XXlNeh16rXmdeZ157XlSDXkdee157Xldem16IgJXtjb3VudH0g16TXoteV - 15zXldeqINec15nXlded - - time_of_day: !binary | - 15bXntefINeR15nXldedICjXm9ecINeU16TXoteV15zXldeqKQ== - - totals_action_count: !binary | - 16fXmdeZ157XldeqICV7Y291bnR9INek16LXldec15XXqiDXkdeh15og15TX - m9ec - - totals_unique_tags: !binary | - 157XqteV15og16rXkteZ15XXqiDXkNec15UsICV7Y291bnR9INeZ15nXl9eV - 15PXmdeV16ou - - actions_avg_completion_time: !binary | - 157Xm9ecINeU16TXoteV15zXmdeV16og16nXoNeh16rXmdeZ157XldeqINeU - 15bXntefINeU157XnteV16bXoiDXnNeh15nXldedINeU15XXkCAle2NvdW50 - fSDXmdee15nXnQ== - - time_of_day_legend: - time_of_day: !binary | - 15bXntefINeR15nXlded - - number_of_actions: !binary | - 157Xodek16gg16TXoteV15zXldeq - - totals_hidden_project_count: !binary | - JXtjb3VudH0g157Xldeh16rXqNeZ150= - - top5_visible_contexts_with_incomplete_actions: !binary | - NSDXlNeU16fXqdeo15nXnSDXlNee15XXkdeZ15zXmdedINei150g16TXoteV - 15zXldeqINep15zXkCDXlNeh16rXmdeZ157XlQ== - - tag_cloud_description: !binary | - 16LXoNefINeU16rXkteZ15XXqiDXnteb15nXnCDXqteS15nXldeqINec15vX - nCDXlNek16LXldec15XXqiAo15TXodeq15nXmdee15UsINec15Ag15TXodeq - 15nXmdee15UsINeS15zXldeZ15XXqiDXlS/XkNeVINee15XXodeq16jXldeq - KA== - - open_per_week: !binary | - 16TXoteV15zXldeqINeU157XqdeaICjXnteV16bXkteV16og15DXlSDXnteV - 16HXqteo15XXqikg15zXm9ecINep15HXldei - - totals_visible_context_count: !binary | - 157XqteV15og15DXnNeVICV7Y291bnR9INeU16fXqdeo15nXnSDXktec15XX - mdeZ150= - - actions_30days_title: !binary | - 16TXoteV15zXldeqINeRLTMwINeU15nXnteZ150g15TXkNeX16jXldeg15nX - nQ== - - tag_cloud_90days_title: !binary | - 16LXoNefINeq15LXmdeV16og15zXpNei15XXnNeV16og15EtOTAg15TXmdee - 15nXnSDXlNeQ15fXqNeV16DXmded - - totals_context_count: !binary | - 16fXmdeZ157XmdedICV7Y291bnR9INeU16fXqdeo15nXnS4= - - actions_avg_completed: !binary | - 15XXlNeh16rXmdeZ157XlSDXkdee157Xldem16IgJXtjb3VudH0g16TXoteV - 15zXldeqINec15fXldeT16k= - - actions_last_year_legend: - months_ago: !binary | - 15fXldeT16nXmdedINen15XXk9ed - - number_of_actions: !binary | - 157Xodek16gg15TXpNei15XXnNeV16o= - - totals: !binary | - 16HXmdeb15XXnteZ150= - - contexts: !binary | - 15TXp9ep16jXmded - - actions_lastyear_title: !binary | - 16TXoteV15zXldeqINeRLTEyINeU15fXldeT16nXmdedINeU15DXl9eo15XX - oNeZ150= - - actions_selected_from_week: !binary | - 16TXoteV15zXldeqINeg15HXl9eo15XXqiDXntep15HXldei - - tod30_legend: - time_of_day: !binary | - 15bXntefINeR15nXlded - - number_of_actions: !binary | - 157Xodek16gg16TXoteV15zXldeq - - totals_blocked_actions: !binary | - JXtjb3VudH0g16rXnNeV15nXmdedINeR16HXmdeV150g15TXntep15nXnteV - 16og16nXnNeU150= - - totals_actions_completed: !binary | - JXtjb3VudH0g157XlNedINeU16HXqteZ15nXnteV - - actions_dow_30days_legend: - day_of_week: !binary | - 15nXldedINeR16nXkdeV16I= - - number_of_actions: !binary | - 157Xodek16gg16TXoteV15zXldeq - - tag_cloud_title: !binary | - 16LXoNefINeq15LXmdeV16og15zXm9ecINeU16TXoteV15zXldeq - - actions_day_of_week_legend: - day_of_week: !binary | - 15nXldedINeR16nXkdeV16I= - - number_of_actions: !binary | - 157Xodek16gg16TXoteV15zXldeq - - no_actions_selected: !binary | - 15zXkCDXoNeR15fXqNeVINek16LXldec15XXqg== - - totals_tag_count: !binary | - 16fXmdeZ157XmdedICV7Y291bnR9INeq15LXmdeV16og15TXntep15XXmdeZ - 15vXldeqINec16TXoteV15zXldeqLg== - - projects: !binary | - 16TXqNeV15nXmden15jXmded - - totals_incomplete_actions: !binary | - 16fXmdeZ157XldeqICV7Y291bnR9INek16LXldec15XXqiDXqdec15Ag15TX - odeq15nXmdee15U= - - spread_of_actions_for_all_context: !binary | - 16TXmdeW15XXqCDXpNei15XXnNeV16og15zXm9ecINeU15TXp9ep16jXmded - - totals_first_action: !binary | - 157XkNeWINeU16TXoteV15zXlCDXlNeo15DXqdeV16DXlCDXkS0le2RhdGV9 - - no_tags_available: !binary | - 15DXmdefINeq15LXmdeV16og15bXnteZ16DXldeq - - actions: !binary | - 16TXoteV15zXldeq - - tag_cloud_90days_description: !binary | - 16LXoNefINeU16rXkteZ15XXqiDXnteb15nXnCDXqteS15nXldeqINei15HX - ldeoINek16LXldec15XXqiDXqdeg15XXpteo15Ug15DXlSDXlNeh16rXmdeZ - 157XlSDXkS05MCDXlNeZ157XmdedINeU15DXl9eo15XXoNeZ150u - - current_running_time_of_incomplete_visible_actions: !binary | - 15bXntefINee16bXmNeR16gg15zXm9ecINeU16TXoteV15zXldeqINeU15LX - nNeV15nXldeq - - totals_active_project_count: !binary | - 157XqteV15vXnSwgJXtjb3VudH0g15TXnSDXpNeo15XXmdeZ16fXmNeZ150g - 16TXoteZ15zXmded - - other_actions_label: !binary | - KNeQ15fXqNeZ150p - - actions_actions_avg_created_30days: !binary | - 15EtMzAg15TXmdee15nXnSDXlNeQ15fXqNeV16DXmdedINeg15XXpteo15Ug - 15HXntee15XXpteiICV7Y291bnR9INek16LXldec15XXqg== - - click_to_show_actions_from_week: !binary | - 15TXp9ec16fXlCDXotecICV7bGlua30g16rXpteZ15Ig15DXqiDXlNek16LX - ldec15XXqiDXntep15HXldeiICV7d2Vla30g15XXkNeZ15zXmg== - - actions_avg_created: !binary | - 15EtMTIg15TXl9eV15PXqdeZ150g15TXkNeX16jXldeg15nXnSDXmdeV16bX - qNeVINeR157Xldem16IgJXtjb3VudH0g16TXoteV15zXldeq - - labels: - created: !binary | - 16DXldem16jXlQ== - - avg_created: !binary | - 16DXldem16jXlSDXkdee157Xldem16I= - - avg_completed: !binary | - 15TXodeq15nXmdee15Ug15HXntee15XXptei - - completed: !binary | - 15TXodeq15nXmdee15U= - - month_avg_completed: !binary | - JXttb250aHN9INeU16HXqteZ15nXnteVINeR157XnteV16bXoiDXnNeX15XX - k9ep - - month_avg_created: !binary | - JXttb250aHN9INeg15XXpteo15Ug15HXntee15XXpteiINec15fXldeT16k= - - top10_projects: !binary | - MTAg16TXqNeV15nXmden15jXmdedINee15XXkdeZ15zXmded - - more_stats_will_appear: !binary | - 16HXmNeY15nXodeY15nXp9eV16og16DXldeh16TXldeqINeZ15XXpteS15Ug - 15vXkNefINec15DXl9eoINeU15XXodek16og16TXoteV15zXldeqINeg15XX - odek15XXqi4= - - actions_further: !binary | - 15XXkNeZ15zXmg== - - totals_deferred_actions: !binary | - 157XlNefICV7Y291bnR9INek16LXldec15XXqiDXk9eX15XXmdeV16og15HX - nta015bWsNeb1rjWvNeo - - click_to_update_actions: !binary | - 15TXp9ec16fXlCDXotecINeU15HXqCDXkdeS16jXoyDXntei15PXm9eg16og - 15DXqiDXlNek16LXldec15Qg15zXnteY15Q= - - totals_project_count: !binary | - 16fXmdeZ157XmdedICV7Y291bnR9INek16jXldeZ15nXp9eY15nXnS4= - - totals_completed_project_count: !binary | - JXtjb3VudH0g157XlNedINek16jXldeZ15nXp9eY15nXnSDXqdeg16HXqteZ - 15nXnteVLg== - - actions_last_year: !binary | - 16TXoteV15zXldeqINeR16nXoNeZ150g15TXkNeX16jXldeg15XXqg== - - actions_min_max_completion_days: !binary | - 15nXl9ehINeW157XnyDXnteZ15bXoteo15kv157Xmdeo15HXmSDXnNeh15nX - ldedINeU15XXkCAle21pbn0vJXttYXh9Lg== - - actions_min_completion_time: !binary | - 15TXltee158g15TXnteW16LXqNeZINec16HXmdeV150g15TXldeQICV7dGlt - ZX0u - - top5_contexts: !binary | - NSDXlNen16nXqNeZ150g157XldeR15nXnNeZ150= - - legend: - day_of_week: !binary | - 15nXldedINeR16nXkdeV16I= - - actions: !binary | - 16TXoteV15zXldeq - - number_of_days: !binary | - 157Xodek16gg15nXnteZ150g16fXldeT150g15zXm9ef - - percentage: !binary | - 15DXl9eV15Y= - - months_ago: !binary | - 15fXldeT16nXmdedINen15XXk9ed - - running_time: !binary | - 15bXntefINee16bXmNeR16gg15zXpNei15XXnNeUICjXqdeR15XXoteV16op - - number_of_actions: !binary | - 157Xodek16gg16TXoteV15zXldeq - - click_to_return_link: !binary | - 15vXkNef - - actions_day_of_week_title: !binary | - 15nXldedINeR16nXkdeV16IgKNeb15wg15TXpNei15XXnNeV16op - - spread_of_running_actions_for_visible_contexts: !binary | - 16TXmdeW15XXqCDXlNek16LXldec15XXqiDXnNeU16fXqdeo15nXnSDXktec - 15XXmdeZ150= - - tags: !binary | - 16rXkteZ15XXqg== - - top10_longrunning: !binary | - MTAg15TXpNeo15XXmdeZ16fXmNeZ150g16nXqNem15nXnSDXlNeb15kg15TX - qNeR15Qg15bXntef - - actions_dow_30days_title: !binary | - 15nXldedINeR16nXkdeV16IgKDMwINeU15nXnteZ150g15TXkNeX16jXldeg - 15nXnSg= - + format: "%u%n" + format: + separator: . + delimiter: "," footer: send_feedback: !binary | 16nXnNeZ15fXqiDXntep15XXkSDXotecINeS15nXqNeh15AgJXt2ZXJzaW9u fQ== - time: - formats: - month_day: "%B %d " - default: "%a, %d %b %Y %H:%M:%S %z " - short: "%d %b %H:%M " - long: "%B %d, %Y " - am: !binary | - 15zXpNeg15Qi16Y= + notes: + delete_item_title: !binary | + 157Xl9eZ16fXqiDXpNeo15nXmA== - pm: !binary | - 15DXl9eUItem + in_project: !binary | + 15E6 - login: - successful_with_session_info: !binary | - 15vXoNeZ16HXlCDXnteV16bXnNeX16o6 + show_note_title: !binary | + 15TXpteS16og16TXqten15nXqg== - cas_logged_in_greeting: !binary | - 16nXnNeV150gJXt1c2VybmFtZX0hINeU15bXmdeU15XXmSDXlNem15zXmdeX + note_location_link: !binary | + 15HXqteV15o6 - cas_signup_link: !binary | - 15HXp9ep16og157Xqdeq157XqQ== + deleted_note: !binary | + 15TXpNeq16fXmdeqICcle2lkfScg16DXnteX16fXlA== - option_separator: !binary | - 15DXlSw= + delete_confirmation: !binary | + 15TXkNedINec157Xl9eV16cg15DXqiDXlNek16rXp9eZ16ogICcle2lkfSc/ - session_time_out: !binary | - 16TXkiDXqteV16fXoyDXlNeS15nXqdeULiDXoNeQICV7bGlua30= + delete_note_confirm: !binary | + 15TXkNedINec157Xl9eV16cg15DXqiDXlNek16rXp9eZ16ogICcle2lkfSc/ - login_standard: !binary | - 15fXlteo15Qg15zXm9eg15nXodeUINeU16jXkteZ15zXlA== + note_link_title: !binary | + 15TXpteS16og16TXqten15nXqiAle2lkfQ== - unsuccessful: !binary | - 15vXoNeZ16HXlCDXoNeb16nXnNeULg== + edit_item_title: !binary | + 16LXqNeZ15vXqiDXpNeo15nXmA== - please_login: !binary | - 15nXqSDXnNeU15vXoNehINeb15PXmSDXnNeU16nXqtee16kg15Et157Xodec - 15XXnNeZ150= + no_notes_available: !binary | + 15DXmdefINeb16jXkteiINek16rXp9eZ15XXqjog16DXmdeq158g15zXlNeV + 16HXmdejINek16rXp9eZ15XXqiDXnNek1rDWvNeo15XWudeZ1rbXp9aw15jX + mdedINeh16TXpteZ16TXmdeZ150g157Xotee15XXkyDXlNek1rDWvNeo15XW + udeZ1rbXp9aw15g= - session_will_not_expire: !binary | - 15TXkteZ16nXlCDXnNec15Ag16rXpNeV15LXlC4= + note_header: !binary | + 16TXqten15nXqiAle2lkfQ== - openid_identity_url_not_found: !binary | - 15zXptei16jXoNeVLCDXnNeQINen15nXmdedINee16nXqtee16kg16LXnSDX - m9eq15XXkdeqINeW15TXldeqICAoJXtpZGVudGl0eV91cmx9KQ== + delete_note_title: !binary | + 157Xl9eZ16fXqiDXlNek16rXp9eZ16ogJyV7aWR9Jw== - user_no_expiry: !binary | - 15TXqdeQ16jXqiDXl9eZ15HXldeo + states: + stalled_plural: !binary | + 16LXpteV16jXmded - cas_no_user_found: !binary | - JXt1c2VybmFtZX0g16nXnNeV150hINeQ15nXnyDXl9ep15HXldefINeR16nX - nSDXlteUINeR157Xodec15XXnNeZ150u + visible_plural: !binary | + 15LXnNeV15nXmded - logged_out: !binary | - 15HXldem16LXlCDXmdem15nXkNeUINeeLdee16HXnNeV15zXmded + hidden: !binary | + 157Xldeh16rXqNeZ150= - login_cas: !binary | - 15TXktei15Qg15DXnCDXqdeQItee + review_plural: !binary | + 157XqteV15DXqNeb15nXnQ== - session_will_expire: !binary | - 16rXlden16Mg15TXkteZ16nXlCDXmdek15XXkiDXnNeQ15fXqCAle2hvdXJz - fSDXqdei15Qo15XXqikg16nXnCDXl9eV16HXqCDXpNei15nXnNeV16ou + completed_plural: !binary | + 15TXodeq15nXmdee15U= - login_with_openid: !binary | - 15vXoNeZ16HXlCDXotecIE9wZW5JRA== + current_plural: !binary | + 157XoteV15PXm9eg15nXnQ== - account_login: !binary | - 15vXoNeZ16HXlCDXnNeX16nXkdeV158= + visible: !binary | + 15LXnNeV15k= - cas_login: !binary | - 15TXqteX15HXqNeV16og16nXkCLXniAo16nXmdeo15XXqiDXkNeZ157Xldeq - INee16jXm9eW15kp + completed: !binary | + 15TXodeq15nXmded - cas_create_account: !binary | - 15DXnSDXkdeo16bXldeg15og15zXkden16kg15nXqSDXnNeU157XqdeZ15og - 15wtJXtzaWdudXBfbGlua30= + hidden_plural: !binary | + 157Xldeh16rXqNeZ150= - successful: !binary | - 15vXoNeZ16HXlCDXkdeV16bXoteUINeR15TXptec15fXlC4g15HXqNeV15og - 16nXldeR15oh + blocked_plural: !binary | + 15fXodeV157Xmded - sign_in: !binary | - 15vXoNeZ16HXlA== + stalled: !binary | + 16DXotem16g= - cas_username_not_found: !binary | - 15zXptei16jXoNeVLCDXnNeQINen15nXmdedINee16nXqtee16kg16nXkCLX - niDXkdep150gKCV7dXNlcm5hbWV9KQ== + current: !binary | + 16LXk9eb16DXmQ== - mobile_use_openid: !binary | - Li4u15DXlSDXm9eg15nXodeUINei150gT3BlbklE + active_plural: !binary | + 16TXoteZ15zXmded - log_in_again: !binary | - 15vXoNeZ16HXlCDXnteX15XXk9ep16o= + active: !binary | + 16TXoteZ15w= - feedlist: - context_centric_actions: !binary | - 15TXlteg15XXqiDXoteR15XXqCDXpNei15XXnNeV16og16nXnNeQINeg16HX - qteZ15nXnteVINeR15TXp9ep16gg16DXqteV158= + review: !binary | + 157XqteV15DXqNea - all_projects: !binary | - 15vXnCDXlNek16jXldeZ15nXp9eY15nXnQ== - - projects_and_actions: !binary | - 16TXqNeV15XXmden15jXmdedINek16LXmdec15nXnSDXldeU16TXoteV15zX - ldeqINep15zXlNed - - context_needed: !binary | - 16bXqNeZ15og15zXlNeZ15XXqiDXnNek15fXldeqINeU16fXqdeoINeQ15fX - kyDXnNek16DXmSDXqdeg15nXqtefINec15HXp9ep16gg15TXlteg15Q= - - actions_due_next_week: !binary | - 16TXoteV15zXldeqINep15nXqSDXnNeR16bXoiDXkdep15HXoteqINeU15nX - nteZ150g15TXp9eo15XXkdeZ150= - - choose_project: !binary | - 15HXl9eZ16jXqiDXlNek16jXldeZ15nXp9eYINei15HXldeo15Ug15PXqNeV - 16nXlCDXlNeW16DXlA== - - ical_feed: !binary | - 15TXlteg16ogaUNhbA== - - all_contexts: !binary | - 15vXnCDXlNeU16fXqdeo15nXnQ== - - active_projects_wo_next: !binary | - 16TXqNeV15nXmden15jXmdedINek16LXmdec15nXnSDXnNec15Ag16TXoteV - 15zXldeqINeU157Xqdea - - active_starred_actions: !binary | - 15vXnCDXlNek16LXldec15XXqiDXlNek16LXmdec15XXqiDXldeU157Xk9eS - 16nXldeq - - notice_incomplete_only: !binary | - 15TXoteo15Q6INeb15wg15TXlNeW16DXldeqINee16bXmdeS15XXqiDXkNeq - INeb15wg15TXpNei15XXnNeV16og16nXnNeQINeh15XXnteg15Ug15vXnteR - 15XXptei15XXqiDXkNec15Ag15DXnSDXm9efINeg15HXl9eoINeR157XpNeV - 16jXqSDXkNeX16jXqi4= - - legend: !binary | - 157Xp9eo15A6 - - project_needed: !binary | - 15PXqNeV16kg15zXpNeX15XXqiDXpNeo15XXmdeZ16fXmCDXkNeX15Mg15zX - pNeg15kg16nXoNeZ16rXnyDXnNeR16fXqSDXlNeW16DXlA== - - project_centric: !binary | - 15TXlteg15XXqiDXoteR15XXqCDXpNei15XXnNeV16og16nXnNeQINeU16HX - qteZ15nXnteVINeR16TXqNeV15nXmden15gg157XodeV15nXmded - - actions_due_today: !binary | - 16TXoteV15zXldeqINec15HXmdem15XXoiDXlNeZ15XXnSDXkNeVINee15XX - p9eT150g15nXldeq16g= - - plain_text_feed: !binary | - 15TXlteg16og15jXp9eh15gg16TXqdeV15g= - - select_feed_for_project: !binary | - 15HXl9eZ16jXqiDXlNeU15bXoNeUINei15HXldeoINeU16TXqNeV15nXmden - 15g= - - actions_completed_last_week: !binary | - 16TXoteV15zXldeqINep15TXodeq15nXmdee15Ug15HXqdeR16LXqiDXlNeZ - 157XmdedINeU15DXl9eo15XXoNeZ150= - - rss_feed: !binary | - 15TXlteg16og16jXodeh - - last_fixed_number: !binary | - JXtudW1iZXJ9INek16LXldec15XXqiDXkNeX16jXldeg15XXqg== - - choose_context: !binary | - 15HXl9eZ16jXqiDXlNeU16fXqdeoINei15HXldeo15Ug15PXqNeV16nXlCDX - lNeW16DXlA== - - select_feed_for_context: !binary | - 15HXl9eZ16jXqiDXlNeU15bXoNeUINei15HXldeoINeU15TXp9ep16gg15TX - oNeq15XXnw== - - all_actions: !binary | - 15vXnCDXlNek16LXldec15XXqg== - - contexts: - no_contexts_active: !binary | - 15DXmdefINeb16jXkteiINeU16fXqdeo15nXnSDXpNei15nXnNeZ150= - - last_completed_in_context: !binary | - 15HXlNen16nXqCDXlteUICAo15DXl9eo15XXoNeV16ogJXtudW1iZXJ9KQ== - - delete_context_confirmation: !binary | - 15TXkNedINec157Xl9eV16cg15DXqiDXlNeU16fXqdeoICAnJXtuYW1lfSc/ - INeZ16kg15zXlNeW15TXqCDXntek16DXmSDXqdek16LXldec15Qg15bXlSDX - nteq15fXldenINeQ16og15vXnCDXlNek16LXldec15XXqiDXlNee15fXlteV - 16jXmdeV16og15HXlNen16nXqCDXlteU - - delete_context: !binary | - 157Xl9enINeU16fXqdeo - - status_active: !binary | - 15TXlNen16nXqCDXpNei15nXnA== - - save_status_message: !binary | - 15TXp9ep16gg16DXqdee16g= - - context_deleted: !binary | - 16DXnteX16cg15TXp9ep16ggJyV7bmFtZX0n - - edit_context: !binary | - 16LXqNeZ15vXqiDXlNen16nXqA== - - delete_context_title: !binary | - 157Xl9eZ16fXqiDXlNen16nXqA== - - hide_form_title: !binary | - 15TXodeq16jXqiDXmNeV16TXoSDXlNen16nXqCDXl9eT16k= - - add_context: !binary | - 15TXldeh16TXqiDXlNen16nXqA== - - status_hidden: !binary | - 15TXlNen16nXqCDXnteV16HXqteo - - context_name: !binary | - 16nXnSDXlNen16nXqA== - - new_context_post: !binary | - JyDXmdeV15XXpteo15Ug15HXoNeV16HXoy4g15TXkNedINec15TXntep15nX - mj8= - - no_contexts_hidden: !binary | - 15DXmdefINeb16jXkteiINeU16fXqdeo15nXnSDXnteV16HXqteo15nXnQ== - - new_context_pre: !binary | - 15TXp9ep16gg15fXk9epICc= - - completed_tasks_title: !binary | - 157Xodec15XXnNeZ1506Otek16LXldec15XXqiDXqdeR15XXptei15Ug15HX - ntec15XXkNefINeR15TXp9ep16ggICcle2NvbnRleHRfbmFtZX0n - - update_status_message: !binary | - 16nXldeg15Qg16nXnSDXlNeU16fXqdeo - - show_form_title: !binary | - 15TXldeh16TXqiDXlNen16nXqA== - - hide_form: !binary | - 15TXodeq16jXqiDXmNeV16TXoQ== - - context_hide: !binary | - 15TXodeq16jXlCDXntei157XldeTINeU15HXmdeqPw== - - visible_contexts: !binary | - 15TXp9ep16jXmdedINeS15zXldeZ15nXnQ== - - hidden_contexts: !binary | - 15TXp9ep16jXmdedINee15XXodeq16jXmded - - all_completed_tasks_title: !binary | - 157Xodec15XXnNeZ1506Oteb15wg15TXpNei15XXnNeV16og16nXkdeV16bX - oteVINeR157XnNeV15DXnyDXkdeU16fXqdeoICAnJXtjb250ZXh0X25hbWV9 - Jw== - - no_actions: !binary | - 15DXmdefINeb16jXkteiINek16LXldec15XXqiDXqdec15Ag15TXldep15zX - nteVINeR15TXp9ep16gg15TXoNeV15vXl9eZ - - todos_append: !binary | - 15HXlNen16nXqCDXlteU - - show_form: !binary | - 15nXpteZ16jXqiDXlNen16nXqCDXl9eT16k= - - shared: - toggle_single: !binary | - 15TXldeh16TXqiDXpNei15XXnNeqINeU157Xqdea - - project_for_all_actions: !binary | - 16TXqNeV15nXmden15gg15zXm9ecINeU16TXoteV15zXldeq - - hide_action_form_title: !binary | - 15TXodeq16jXqiDXmNeV16TXoSDXpNei15XXnNeV16og15fXk9ep15XXqg== - - make_actions_dependent: !binary | - 15nXpteZ16jXqiDXqtec15XXqiDXkdeZ158g16TXoteV15zXldeq - - add_action: !binary | - 15TXldeh16TXqiDXpNei15XXnNeU - - toggle_multi: !binary | - 15TXldeh16TXqiDXpNei15XXnNeV16og15TXntep15og157XqNeV15HXldeq - - toggle_multi_title: !binary | - 15jXldek16Eg16nXmdeg15XXmSDXntem15Eg16TXoteV15zXlCDXkdeV15PX - k9eqIC8g16TXoteV15zXldeqINee16jXldeR15XXqg== - - hide_form: !binary | - 15TXodeq16jXqiDXmNeV16TXoQ== - - multiple_next_actions: !binary | - 16TXoteV15zXldeqINeU157XqdeaINee16jXldeR15XXqiAo16TXoteV15zX - lCDXkNeX16og15HXqdeV16jXlCk= - - tags_for_all_actions: !binary | - 16rXkteZ15XXqiDXnNeb15wg15TXpNei15XXnNeV16ogKNeZ16kg15zXlNek - 16jXmdeTINeR16TXodeZ16fXmdedKQ== - - context_for_all_actions: !binary | - 15TXp9ep16gg15zXm9ecINeU16TXoteV15zXldeq - - toggle_single_title: !binary | - 15TXldeh16TXqiDXpNei15XXnNeqINeU157XqdeaINeX15PXqdeU - - separate_tags_with_commas: !binary | - 157Xldek16jXkyDXkdek16HXmden15nXnQ== - - add_actions: !binary | - 15TXldeh16TXqiDXpNei15XXnNeU - - preferences: - change_identity_url: !binary | - 16nXmdeg15XXmSDXm9eq15XXkdeqIFVSTCDXlNeW15PXlNeV16o= - - page_title_edit: !binary | - 157Xodec15XXnNeZ1506Otei16jXmdeb16og15TXoteT16TXldeq - - sms_context_none: !binary | - 15zXnNeQ - - current_authentication_type: !binary | - 16nXmdeY16og15TXlteZ15TXldeZINep15zXmSDXlNeZ15AgJXthdXRoX3R5 - cGV9 - - page_title: !binary | - 157Xodec15XXnNeZ1506OteU16LXk9ek15XXqg== - - open_id_url: !binary | - 15vXqteV15HXqiDXlteZ15TXldeZIE9wZW5JRCDXqdec15og15TXmdeQ - - change_password: !binary | - 16HXmdeg15XXmSDXodeZ16HXnteQ - - edit_preferences: !binary | - 16LXqNeZ15vXqiDXlNei15PXpNeV16o= - - show_number_completed: !binary | - 15TXpteSICV7bnVtYmVyfSDXpNeo15nXmNeZ150g16nXlNeh16rXmdeZ157X - lQ== - - updated: !binary | - 15TXoteT16TXldeqINei15XXk9eb16DXlQ== - - token_description: !binary | - 15DXodeZ157XldefICjXntep157XqSDXnNeU15bXoNeV16og15nXqdeZ157X - ldepINee157XqdenINeq15vXqteg15XXqik= - - is_true: !binary | - 15fXmdeV15HXmQ== - - password_changed: !binary | - 15TXodeZ16HXnteQINep15XXoNeq15QsINeZ16kg15zXlNeZ15vXoNehINep - 16DXmdeqLg== - - generate_new_token_confirm: !binary | - 15HXmNeV15c/INeZ16bXmdeo16og15DXodeZ157XldefINeX15PXqSDXqteX - 15zXmdejINeQ16og15TXkNeh15nXnteV158g15TXp9eZ15nXnSDXldeq15HX - mNecINeQ16og15TXqdeZ157XldepINeR15Uu - - authentication_header: !binary | - 15TXlteZ15TXldeZINep15zXmQ== - - generate_new_token: !binary | - 15nXpteZ16jXqiDXkNeh15nXnteV158g15fXk9ep - - staleness_starts_after: !binary | - 16rXpNec15XXqiDXnteq15fXmdec15Qg15zXkNeX16ggJXtkYXlzfSDXmdee - 15nXnQ== - - title: !binary | - 15TXlNeS15PXqNeV16og16nXnNeZ - - tabs: - authentication: !binary | - 15DXmdee15XXqg== - - profile: !binary | - 16TXqNeV16TXmdec - - tracks_behavior: !binary | - 15TXqteg15TXkteV16og157Xodec15XXnNeZ150= - - date_and_time: !binary | - 16rXkNeo15nXmiDXldep16LXlA== - - change_authentication_type: !binary | - 16nXmdeg15XXmSDXodeV15Ig15TXlteT15TXldeq - - is_false: !binary | - 16nXnNeZ15zXmQ== - - token_header: !binary | - 15TXkNeh15nXnteV158g16nXnNeZ + blocked: !binary | + 16DXl9eh150= From 5d61b9600eaf8e7005c76fa4abcedded24d020d3 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Wed, 18 Apr 2012 16:50:47 +0200 Subject: [PATCH 097/134] fix #1286. The sidebar now updates correctly after update of project settings --- app/controllers/projects_controller.rb | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index b9766f89..24aa5eac 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -194,21 +194,13 @@ class ProjectsController < ApplicationController if @saved @project.transition_to(@new_state) if @state_changed if boolean_param('wants_render') - if (@project.hidden?) - @project_project_hidden_todo_counts = Hash.new - @project_project_hidden_todo_counts[@project.id] = @project.reload().todos.active_or_hidden.count - else - @project_not_done_counts = Hash.new - @project_not_done_counts[@project.id] = @project.reload().todos.active_or_hidden.count - end @contexts = current_user.contexts update_state_counts init_data_for_sidebar template = 'projects/update.js.erb' - # TODO: are these params ever set? or is this dead code? - + # TODO: are these params ever set? or is this dead code? elsif boolean_param('update_status') template = 'projects/update_status.js.rjs' elsif boolean_param('update_default_context') From 6e15c38efe5a4806c6ba1cec7155ea041d6e58d7 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Thu, 19 Apr 2012 00:35:46 +0200 Subject: [PATCH 098/134] update docs and default database from changes in 2.1 tree --- README | 2 +- ...ank.sqlite3.db => tracks-blank.sqlite3.db} | Bin 49152 -> 54272 bytes ...e.sqlite3.db => tracks-example.sqlite3.db} | Bin 50176 -> 56320 bytes ...test.sqlite3.db => tracks-test.sqlite3.db} | Bin 48128 -> 54272 bytes doc/CHANGELOG | 50 +++++++++++------- doc/README_DEVELOPERS | 6 ++- 6 files changed, 36 insertions(+), 22 deletions(-) rename db/{tracks-20-blank.sqlite3.db => tracks-blank.sqlite3.db} (72%) rename db/{tracks-20-example.sqlite3.db => tracks-example.sqlite3.db} (64%) rename db/{tracks-20-test.sqlite3.db => tracks-test.sqlite3.db} (66%) diff --git a/README b/README index a701b3de..848cefa0 100644 --- a/README +++ b/README @@ -13,7 +13,7 @@ * Copyright: (cc) 2004-2012 rousette.org.uk. * License: GNU GPL -More documentation for Tracks can be found within the /doc directory. +More documentation for Tracks can be found within the /doc directory The manual includes full instructions for both new installations and upgrades from older installations of Tracks. diff --git a/db/tracks-20-blank.sqlite3.db b/db/tracks-blank.sqlite3.db similarity index 72% rename from db/tracks-20-blank.sqlite3.db rename to db/tracks-blank.sqlite3.db index d3aa896f999eeabd3b64546b437a1a33bd97584d..aa3388a9d51408c73231d479782ff5eb388a3fc4 100644 GIT binary patch delta 1829 zcmaJ>drVVj6u;;DN?(+=P~a+1xRhr>@V3wgs6*x>q9Ac%qEWd+dZRT!Yg-kWj+QdF z#l;9G`(w*AQj%@imYH~Cvdke%$o^Q|7LAE9OI#LQW}J(gOSb)?dwealL1*?Q_uPAa z=Y76&Pc%xS@6$8Ix!oMcx!99F=O$J(RdjO=^JQ5K($O19fr~z(f6#~YXL^^;)7$hG zy`ki4d#IzKnn|n587VDdgtstKU}VIS!-(0yNVbjhdoy|>7bMqqNa=INYPLah@-cbj$SWUO6@`LG{?8X&>EhHcD%SWZ4 z9P$TzHo-p>k@w3XVf}`U?K?Vq1V^*5wYx{yx}&qxKG7~*EK#YZRiX-2mAM#Fy{%lR zTu*fCvNU`}1)S+p9#?BYPr0iccNM;-fQM8wG&ZWi7hNTw!xOG~{g^|m;kR#xcn3y1 zN^oYA0VA6#z<{53R59){Q#;nN5po!RDbZ<224oJebKG@^kv+`e9E~;Tad>kH81c=` zlaP(ITPneXU0al*c)3Bt^E{j^kM!*ukRt(KAe-SzcF1nv|wXz9TX=K9PDjO>{MMGQ0EtyaaV~pK-h!R62J!-rBZ+PhQs8%q zAdBBUy$;G3c@qYwi}2dCNCubV2Uk{rZBdYie_biU;n;X$eA%R!mCK#uxO3ou^Tb3F z6lj>0{Thv#i!m6lL1|2n;@Byyi^s`4#=w{ke;f1Sy9_Ii>+##T3H#z3pf(lZ z8k3%i7c#V(>@CCPvz1`a2zJjF>we+V|LJp_BDis7*l&Eldki*O=5~_m@-4b}F;?F#C!p?VFf=4W5nZ@wQ~uFZi*? PGw;#yFuUzv4mBG` delta 1400 zcma)6Yiv|i5I%F}cJJLs*{*%u+U+hayW6GRU7!>ZMJOOpVi71{0)?iQ_F8M~!`-{P zltAo53yBywJN%-FA&t=zRM=e!KMWd){t{3iMoc6z_#gp7sEJCnQBRka#K#YBPQH6) z=9@WlW+rD~90vyQu-mnk{rwvf;X1J?uRKqxHM}}yT!6phFF1j>@djSUYj{2@ zY40*(%;7)}m~EY%T|J#KR%youpxPRp`a%{93)*nYl;~?^g;oqf)M$@KqmtQb_IC8f zm{mg^?r$BcjMLuRV;Z~7nCh@dsW005g3)eDTArlEV@5Q_GzE*Nj*BrTqEAwc=ZvV) zll|U#(GJx@Je^sfXr%aEa6*Vhxnf0xcr<&`znWVg)GRw$rGbO9ON?FO!>pD`PDQ0M zv`15Qj|X0DFxz&$Xv~~H^LNnErv`9%zDiE^#u%ie4%vp5vCim_FY;BgEHu@Hx99rQ)@W_XAiLjhV>^Fe;Tsy8&i zP%@X-Oy4OI@<5T~oURy*%*s`CC~`mZ={cF1mtvZDA_Y!*WtksJ==ieiSlE&3P_oL- zNi3b3O^xkka{UT%xWL1F6aiyGEa%-tL_7SnqIn_cG|^m?-QR2j-cm^Y89%tEG?dBs z@6&2%o$00bcG&2L9d6!HOqFI3JULE_S*?|*dc6k*U3B-d*E-W`FV)g&O;`0MX{wVZ z9~~nH%%;jKVYySX*T`3%>9Z&W{fzaqTd*4@`62!Xb_>yN?JJ#$32`sIV`@-AwecW* zV|w6W`psMnbELeL_9chujl&;7fYM11Z4frH3nv{BOQ0&JIV&}LQ%=Iv8agk$bTR3m zXllXO?$XRbMR6+7%AghQ@FcEhcNw|1?L*e$r#Dl6n3oIiW6I6DedJ7rAtDvUbUW^% zT}d~0%%)xGr7$;Fh5Ae(eVPu*Bq!33LCv&o2@Yitf1Qu;0ltTuyoYC9r#65%_AY&Q;RbE|{ERlv__&OeNQTXY;Q#;t diff --git a/db/tracks-20-example.sqlite3.db b/db/tracks-example.sqlite3.db similarity index 64% rename from db/tracks-20-example.sqlite3.db rename to db/tracks-example.sqlite3.db index 665c2c3ba39dde265450c5d83eb99dde7856eb18..c36b67034566ac84b8576e38cdc7ad6046e16548 100644 GIT binary patch delta 2705 zcmaJ?drVvB6~E{EE?nE#7-NEg#NY=n2aI1B18v&S1Qxw={nL^RhAHWFiQ}cK^dIyt z{VQFepVE)$AL#XjPTfPd+RGWY%*;q}5hDgYBb%}r(Q6pVQ8S`aF`~#=;^(zB)h5fR zcr+v)^N)z5p-9kT3Wa0hpg3yU+1%2!zrDxgsx@_X^_V*Mx3}A7o^eo%U-V6a+Y#*U8>5qFooWqPh4LogVPFiB&9{vmN7!VVaZ zMN@wPzgN9_&cxG3Vno3?m`$E1$B0PwktX6G#)OWagNd9*VskrPZf7m~d~UC^KBpmt zI2&9}uhUzfQ!gVfw)VQ5>~ZDz?n9h8bxFkM_BnkXCYR$)B6V(;v)*0nap%+~5wE+> z)!=rrvl6ekgODpZFoQe5vG*GMhwP!9uK^`qvp=DF&Ls$jef!{4E1qoK zfd*70b$oD|`pI4TDH z;Ydu3T1-;NY*PLKU1gN>(N$*E7gWd9DJ8#9a+#wq(Nc1m9lA)g!&Jky0cZ+69>(<` zRCM56m0lYr8m=P^f4ZVm#t(yrYfi)8s@N^zDoHnxBOE!x^ahCURIWx&rqjn{^HV-Z z{d0HhZEosmHuW?;(cWybq+kn9m^P!WsSw`>J^rL73$IxA;4hl;vB_G3RmBFJwHD*t zjxFAx_)K7IDCUm^2HCBT21W-C1x72~UayTgWhfAh`Pa%tWR(&O#Kc%=ShOuYn#uF5 zEU(YTf2Eq*nk^Wrs^Enze1E$Y^6<{~+lkMc3dsUrAXUwIjyq5GlAqCS6ldcv)|_%^ z*8;LlzL6YYndIMl7a7~Q$VF2<)Zxb_GpfxyvDaKAFarZ)u|ue9(_^<;iHl}Oi5$sc zakyU`^~WMd#PGd$Lan77Y*>EK0R@S#AJj2V>+zSpTVXTa?cF|qfM5DXrXrC!^lu@- zpZJPaNYN0uGS*=>8rpyy~WtsC*VY%0XE?|za5NBX&$~l zsmB$6A&o2YF)&#NB}w!#ve$sGU+e-C1{TZFa;XmrFn(zVnAzHjf4S5Kh3LOf4HmZE zj<+T!=TGuWuVtzenP>hbRnJO(($o!$8#THkY1;ZY;#lyBZpeiY@N4sB%5r0PU zMy951W5EjthDD2QX@*xX@IPREH>OzN^H>&vp94SqjWx;}^bo6z4p!!B3&y4&fofU# z)N~PkJZ(|MGp&N5wF=^8_$_wBT^IA9CMlrD$%|z;x2VVCy?SuS=zOofOE#M&f2Cz8 zG8hUo>$PRf`Z9=nL#!!`%fufPM?|&?4}`?1KN9vw#|8$(Xfz^SIGyK|^iHHB_e)z$ zU7aRNx`cFgx;|#YrgFispP8`j|Clhs`jz-lBfuqDu`~S)$%=b7Jlu}^WNb@8p2grb z1#8crNbUJH{e(5b-_a};Erh^8EOb<)c>C=l#$V>>-|0=d%=p)+M$JPZtV`THTTC0_ zGZfw_@A6U$)snBsEpmhWoLnK7$s1&moF^}nbL1?UB;R3S9w8ypPo5?{q=U4O$4NbL zlPXe5j3l4sx`F_#!k6#`+=9!y~K`l&lgA+0hv5p{XwI zmQ!%KPhBa)Yw<`i<(!bDSu$uU*^p&Ad`yS+ULBsK4!z4C2nYTDLs6 zU%udlTKvt0Jw;M8QF2C(j+13FLt2fH7gr!z!h>H4ym`r z>T=tiwRTs%$?a}*dm5ddcy^{F7x1tdn3Ox>4eK6|!`t4wx-CSKZHjEjeqMLtA+qB? zeNkP+(eKj^vO>m45%a2o=$_1$c00@)7FAzuusm?mh(;3gnKurZy4wBVA&Hf%h45di C)%D^4 delta 2007 zcmcgs|4*Cc7JtrjUf#B}rA1&bg|@sc(5^xmQ04ARb|>2ycY3E(o!LcY(f;8g|OrcVUmR~ zN@?k|4FZ~WUwUPpl*#M<9SbBlz~BJiz^~wD*gvN|2$_E8PB7(iWZrR=LrRtMIqPDq zi*I0CG;L#0ni|P7D2f6PuZoBJ_e92Hk+GOA3>&t!G)E1fTdz~sb-k5zp~Bh}m|86x6qgI8TlHLf$D$8J z2I8?Lo&Sf7OK2|XT@}rwwAF>wjV+s+x3_nz9oyU6YgKP79*#%6Y9c%~usb}qysKbp)f*!S_2L*%G8W%tD-#_(7C4A0^*oW^*j z(6S4w?J`!wU}SG(bTBeHFdT_7OCGu)9v&JR9vzA?kA$s2yL>L0`4PLaze+G1i$w%Nq`K)>gQgSU=xv5cj1N@%bDC?VJ>&7_x0Qbwv@Fr;=1eeVML zvSgWs?WxEWVq~9UEJAsI;rsLC^MnYwRnMl{*#K zPY2U(D5r2=F{RT*h5AcYmwWd_1-IV7gT-{b?{;wN_GkKvXui+E`%B0l_k&9Z2jYI? zGJ~?t1xYLYc+qWIdYNu&pj!9ROoYsa-Z?zz4J3_0PohBfoqTXQbW68R=W%`xbCnmK6iL zpNa7ejBv)I{8M~L)Bb`dOB4F zb$Uf#rOMNjvLz#*x``O#yUFmL@2+NCjUlYXYILK5b~GXK1^z4lp3n2o_$T}#f0w_> z&+)VTMLx?<^OO7-e~eG_L;SBi&PREs@Wl?$PCZ9ooS&yH@4w_QiPnMp_+_sBf4j-Q zEY573zDMjk!JTtjKDX~E$o8KVo?PpyxxC6#-xSP_klJv^>QK|_`o^d=yXsG#T$h@@ NymhHdW#%tC;J?tRO;`W` diff --git a/db/tracks-20-test.sqlite3.db b/db/tracks-test.sqlite3.db similarity index 66% rename from db/tracks-20-test.sqlite3.db rename to db/tracks-test.sqlite3.db index f170433147cc60b23729b172904d8104f206da79..6abee81b725f548a5cafd67d804fdf4aa800f785 100644 GIT binary patch delta 2629 zcmaJ@drVu`8Nc5-*Ie7!*u;Qih~fG=fDIV@z}V2Hfd(Q7B$S3snHKOId;{(Xrr4xu zRxNQM(5m?Z@@>&7MO6bysH&{0>~`(8tlG4fv`*Sfsn$x}Baxb>d!^IXJ+i4g_hM5g zbi2C#uFvoM&Ue1=p6_u_{ezr(fi6{*UgJ0}$bR|j+H#X$GF;<4*K0Hk)6rilGeLTX zendZ{f1o$%b^0#-Rn|QG8QS2fV{^3*CaNo$uv(ZXFJZ!BWWsDwkfJ}dkvWC zbwV+Ir>~ZczCj++;>#^=FyK2abu|5i4j=E^4MsNo8tC!(o^4QqU)i&i8Q|HArB^xn z7y4UzjsA#UWv}2x+O5-2E6gV4nItjr)DF`#iAUtIRFdc@n@A;MiKNy{Xf4F#X?ZFp zPmRUpq{aY@nu?B($EU`VWM#l$P-1{Unu9bs#5B(WO&=^qSO0b};okmi<($JHSglrA zaHz+nDpo~lw!XOy@X?n08`O|td(6nO$W$UFCnZriQ@5g9Lxwo|HM*bto17;@Y=@ns zv`=f|0G!4E#{r9(0Eb7~+>+1l@wR$=VbSmJQ10-kpwJwQ767hBp}pMpz-HQkB8Aqz zuB}R;nL@$Mw1XOjwzGgHhr*j_L%c!@6xjAg$XB(=HpMld=Qw(fxpan_CWw*i0x;SF z%qe34U$5`QKh|&6kZF!gGs+PXnll>Jz(0LdeUteE%Rjg5dbp=+xJMlBdT^jel=85I zL)BI2?y})mYb^Lib20v>sTzMHHRJcYDzM90gFoL@iC=bB;e}n>f-(6>bapZoVMojk z;aGHLY$7`2@&|)%c1DxYWGb?r+cHb*STrT4;zwn7=KdmHsUTQ7{A2w>Ly2H*Y=kq# z_>)d2l;Q2p53;}SvXNDOtCHg9IPM(jCEukxC@!bxo99|g>+!Ke^-7IMRaD&VkBWWb z%!^_e+VFcEZL4*6j#emGK= z9XrGW`GN(1IMM)B4C!1s$Y(y!YqR|1onjYDPL30}T2}YCr@4Q^Jozj&(kB>LcpWao zz-T?*9;wECqXM2BwL&?bjd;MWY=KwiEqF6xqiJmgM(5k0CWk&i9=76@OM@U{bgd4h z%cIPu^yOXPU}Gn~f4LuQ7`fO45*v5ot@-(tQ+(!yB15+5secI->!v-&anFGdo+l=< zLV+fi(@)W~xe9-`P>(-5t;Y+epMg5Iz8pP^TC^|d@txBq99syZb+H=HuyOyQ34gKB z1Fjsan~c=p>e_bpnv`Ylt~qtnqF~)=hjb~LBGq_xR0|EN4{widEeJ5tB`Jp!iN_>& zTJI37Lu^TaEop(q9NmJRhz=7GP4y>nS+I;9+EnzYEV(mFykV7pg|&l}c9mBu7eqLS zz@JzNe~V7AJlMUIj^GkWFc}dTM`HNiBcg$*}G65GoidrupVG0?D#(>OtV5Mf2tASQ>^GN+(WVA z?ggK2$2}Z(W>RU(6MU9mx=t&#L_-0JG^*rPNfoJq%+h<*rd1~dbwW_78g-h_eth!p zR8MUX9ZSWJ$s`l|E4A=o1Cj%jFNY4efx_!`gFz}$6D#z$$Xn!l^W<4_ zmOMk|$(L9dOp`b{Og=}3$zHOX>?C30Cyit~v6Bjx3t9qj2mS_shFfrhh08eL#5ZrA zENJu{Tc{h>dw;&ux96aORv+F3c|#k}Mze3*fHt~)a0A+C_pMv7?^~~xD0xfC367i~ z@6lt-wn?IUq+YPz$FfDovc+1GOtFfZuiJh#Oy3?gxKw!k%<_|J+$d}oFh&>qPGCAh pOo#Js9f6z-}(}EkHy%>a6{OQG^{{sHh)hPe~ delta 1815 zcmZWpZA_C_6u#%)+rBNd6fE%a)ej1#RH#5J1~A9~Q49n@!SSKf0u7=T5DLsiCsl(k zn~}E%{V}oyaf{OhCv6tDWV*$;Kl3Zm_+wc#%a)AHY-TRem`KLnR?sou+?@B`=RW7$ z^W1yx9r=unJfmZ&aW}})?`tX7Db*`e6f!KZ`{Bvu>^XbN9kCC!91(`wQvNgHzcVXs0E zMG=k```qn&Jc9$C{(*=QDmPV?H&&S&%PVTD%wY(PCL2C$E`pU<(2|bFm#Oh1qkv5< z<%@l~$Bq7$gvB9-S~f2BWBNT_kGI{^zunin+tY&wmx&SY%+?INWzw#+A1+i1qQL;8 zrIAGX`g?bII(!3*|EMMDyg<=l>O`?-h0DCQYF&9#ZKJuaskS!PY#H#meIAQ>$lc$u z)7_u#%(uT}*xVhy?jes2TWien!UZVR7;)O9=3!Sny*XJ1WAS=T3eMXUN?_*+J0FVU zlPso@YDhVNHreGOM2nxUuMSizLW-n$7Q@LALXN0TAKX08A&zL!~%a@eSjZ24$vM5(X0vv(k3VnRb}R)Ky|jIG=2^>lX2Qf&BnSt+yE zM4%bjysimc~}AVhBKnR?Znn zGI3#hg*`pL*pXl8aORtx&XPh`iK}><5N4&zEEf=y%$lxP^E#_h8D7ukyN5Sz!HNUIm3=k&N9V?1_AN?y+$;%6#%^ z>|oYdC9^`Or_a;V>FMd{_6#UA3T6PGyQ{0ar)z+wbG9CEN0vcJY>aIVcSVPLAeO!6 zM*r)k1|~w}Fx0_XC0AZ030sE>-EHi*#i+|lQsu!=S5eqQaxHytShC^@f?zGtbDp3#{ zWQRQ2Ap<8-gU-PO{N|1ZZ(@RS;a2wyCeofHeBb8)b7ZBPzTDsrt~$fNk`?cK9vzxL ztB`wrb8PBuo*33Hkhh53eg`ilw3j|$dnKuw`Blj{=UWBo3sLkqfokj+wBUi^!}#&o zw_wGYVFT7lQ5Y@ha9k>atO#;hM)n7E$O2V(Lo(v6VGZ^N@|j;_!uFZfkR6Fw7S!YS zGxn)ts^B=+$f?Z<0Tqu`l2ZiCaE`vqoa{6?CBL)On}NFF+!)8gE4HC-tzWR>zPp8x zhhN-nV1A_;AI}tneIalW^KVMWqk|hEM@B?^H0T8jZXK$G+=a0Q4-BQCX($2z9!i5q zcyKJt>9Bn`g>K8lPXd{+BBJQGKx%NmQWH{6{==Ay?nL26)*I!lgt=HQvoa$SSu9gC zM(5}g`iRcbpXrbE4!usV(aZD_y-3f|DLO&N>2W$rN9a4$M|)@}?qVHClhgR?%~{-d Gd*)xKX9K(d diff --git a/doc/CHANGELOG b/doc/CHANGELOG index 7095f83c..973dc5da 100644 --- a/doc/CHANGELOG +++ b/doc/CHANGELOG @@ -13,35 +13,40 @@ * Copyright: (cc) 2004-2012 rousette.org.uk. * License: GNU GPL -== Version 2.1RC1 +== Version 2.2devel -NOTE 1: To use this version you need to migrate your database. Not migrating will -cause new actions not to appear! +== Version 2.1 -NOTE 2: This version of tracks has moved to a new place on GitHub. Also the wiki moved -to GitHub, see the changed URLs above. +NOTE 1: To use this version you need to migrate your database. Not migrating +will cause new actions not to appear! + +NOTE 2: Tracks' source code has moved to a new place on GitHub. Also the wiki +moved to GitHub, see the changed URLs above. New and changed features: 1. Redesign of the completed todos: a new overview page. Also all context and project pages have a link to their completed actions -2. New locales (es and fr) and updated locales (de, nl) +2. New locales (es, he and fr) and updated locales (de, nl) 3. You can star an action right from the form for adding a new action 4. Redesign of preferences page 5. You can now mark an action complete from the tickler 6. Project names can now contain comma (',') in it name 7. Context view now shows hidden and pending actions -8. Mobile improvements by Tim Madden (we now require some javascript support on the mobile) +8. Mobile improvements by Tim Madden (we now require some javascript support + on the mobile) 9. Two extra defer periods in the context menu of an action 10.There is a review page where you can see stalled or neglected projects. There is a reviewed button on the project edit page. -11.You need to change your password: migrated to better BCrypt hash algoritm for storing passwords by Jan Stępień +11.You need to change your password: migrated to better BCrypt hash algoritm for + storing passwords by Jan Stępień New features (technical) 1. There are two example ruby scripts in /doc to use the REST API to add a todo or a project template with todos from the command line 2. The tag page can now select actions from mulitple tags using AND and OR. There is no gui for this. - Syntax is /todos/tag/tagA,tagB?and=tagC to select all todos with (tagA or tagB) AND tagC + Syntax is /todos/tag/tagA,tagB?and=tagC to select all todos + with (tagA or tagB) AND tagC Under the hood: 1. Upgraded rails to 2.3.12, jquery to 1.7.1 and jquery-ui to 1.8.17 @@ -52,8 +57,9 @@ Under the hood: 5. Migrated to cucumber and capybara for integration testing 6. Development mode shows a work-in-progress banner on top of the screen -See https://github.com/tracksapp/tracks/compare/v2.0...master for all -detailed changes +See https://github.com/tracksapp/tracks/compare/v2.0...v2.1 for all detailed +changes. And for those upgrading from 2.1RC1, the changes are here: +https://github.com/tracksapp/tracks/compare/v2.1RC1...v2.1 == Version 2.0 @@ -78,12 +84,13 @@ New features: 14. Support for adding Tracks as a GMail Widget with instructions on the Integrations page 15. Tracks now supports internationalization. First translations are German and - Dutch. See http://www.getontracks.org/wiki/Translating-Tracks if you'd like to - help translate Tracks to other languages + Dutch. See http://www.getontracks.org/wiki/Translating-Tracks if you'd like + to help translate Tracks to other languages Under the hood 1. All js is migrated to jQuery and most ui-widgets are migrated to jQuery-UI -2. Cucumber is added for integration testing. The RSpec stories are migrated to cucumber +2. Cucumber is added for integration testing. The RSpec stories are migrated to + cucumber 3. Upgraded to rails 2.3.11 and upgraded most gems/plugins 3. Bugfixes (lots of them) @@ -92,11 +99,14 @@ Under the hood New features: 1. Recurring todos 2. Cleanup of feed page and add feed for starred actions -3. New interface to import an email / sms messages into Tracks (needs an email server on the same server as Tracks) +3. New interface to import an email / sms messages into Tracks (needs an email + server on the same server as Tracks) 4. New buttons to quickly defer an action 1 or 7 days -5. Calendar view to review due actions, includes iCal feed to use in your calendar app (tested with Google Calendar, Evolution, Outlook 2007) +5. Calendar view to review due actions, includes iCal feed to use in your + calendar app (tested with Google Calendar, Evolution, Outlook 2007) 6. You can now sort projects on number of active todos -7. Support for OpenSearch. This means you can add a Tracks as a search provider in your webbrowser (tested on FF3 and IE7) +7. Support for OpenSearch. This means you can add a Tracks as a search provider + in your webbrowser (tested on FF3 and IE7) Under the hood: 1. We now allow users again to stay logged in on two devices at the same time @@ -112,7 +122,8 @@ Under the hood: 4. Bugfixes == Version 1.5 -1. Show from date allows you to postpone the appearance of actions in the list until you can do something about them (like a 'tickler') +1. Show from date allows you to postpone the appearance of actions in the list + until you can do something about them (like a 'tickler') 2. Tagging of actions 3. Simple management of users (deleting users through the web interface) 4. Import and export of data in various formats @@ -122,7 +133,8 @@ Under the hood: 8. Optional support for authentication via OpenID or LDAP 9. Update to Rails 1.2.3 10. Per-user time zone preference -11. Use autocomplete fields for Project and Context specification to support on-the-fly adding of each +11. Use autocomplete fields for Project and Context specification to support + on-the-fly adding of each 12. Add a "Hidden" status to projects 13. Add optional Default Context for a Project 14. Add ability to sort projects alphabetically diff --git a/doc/README_DEVELOPERS b/doc/README_DEVELOPERS index 7570c9ce..8382f908 100644 --- a/doc/README_DEVELOPERS +++ b/doc/README_DEVELOPERS @@ -7,7 +7,8 @@ Tracks is using See README for links to the respective sites -Also see the Development pages on the wiki for details on installing, testing, upgrading, etc. +Also see the Development pages on the wiki for details on installing, testing, +upgrading, etc. 2. Dependencies @@ -35,7 +36,8 @@ Running cucumber/selenium tests in :memory mode does not seem to work. The rspec tests are not actively maintained. -See the wiki for more information on testing: https://github.com/TracksApp/tracks/wiki/Testing +See the wiki for more information on testing: +https://github.com/TracksApp/tracks/wiki/Testing 4. Contributing From 3180d88fae9b2313b7f601074d0a2735da095853 Mon Sep 17 00:00:00 2001 From: tim madden Date: Sat, 21 Apr 2012 10:57:36 -0500 Subject: [PATCH 099/134] tweak to note display on project page to stop wrapping around note link icon divs for the project note adding margin to prevent the note from wrapping around the link icon --- app/views/notes/_notes_summary.rhtml | 5 +++-- public/stylesheets/standard.css | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/views/notes/_notes_summary.rhtml b/app/views/notes/_notes_summary.rhtml index 0ffbf07c..f34424d3 100644 --- a/app/views/notes/_notes_summary.rhtml +++ b/app/views/notes/_notes_summary.rhtml @@ -1,11 +1,12 @@ <% note = notes_summary -%>
        + +
        <%= rendered_note(note) %>
        <% note = nil -%> diff --git a/public/stylesheets/standard.css b/public/stylesheets/standard.css index 2dd69060..b7124f62 100644 --- a/public/stylesheets/standard.css +++ b/public/stylesheets/standard.css @@ -550,6 +550,10 @@ div.note_wrapper p { display: inline; } +div.note_note { + margin-left:24px; +} + div.note_footer { border-top: 1px solid #999; padding-top: 3px; From b932ac210fd1e0f2797fa917bf8eb7f0adc39fe0 Mon Sep 17 00:00:00 2001 From: tim madden Date: Sat, 28 Apr 2012 22:34:03 -0500 Subject: [PATCH 100/134] fix for mobile new todo tags no being saved the mobile interface shares the form for creating and updating todos. the todo controller was using different names for them. this change aligns them. --- app/controllers/todos_controller.rb | 4 ++-- app/views/todos/_edit_form.rhtml | 4 ++-- app/views/todos/_edit_mobile_form.rhtml | 4 ++-- public/stylesheets/mobile.css | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 19a05d3c..3ae8c5ed 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -1424,8 +1424,8 @@ class TodosController < ApplicationController end def update_tags - if params[:tag_list] - @todo.tag_with(params[:tag_list]) + if params[:todo_tag_list] + @todo.tag_with(params[:todo_tag_list]) @todo.tags(true) #force a reload for proper rendering end end diff --git a/app/views/todos/_edit_form.rhtml b/app/views/todos/_edit_form.rhtml index 9ffb3d39..9081ad16 100644 --- a/app/views/todos/_edit_form.rhtml +++ b/app/views/todos/_edit_form.rhtml @@ -23,8 +23,8 @@ form_for(todo, :html=> { :name=>'todo', :id => dom_id(@todo, 'form'), :class => - - <%= text_field_tag 'tag_list', tag_list_text, :id => dom_id(@todo, 'tag_list'), :size => 30, :tabindex => next_tab_index %> + + <%= text_field_tag 'todo_tag_list', tag_list_text, :id => dom_id(@todo, 'todo_tag_list'), :size => 30, :tabindex => next_tab_index %>
        diff --git a/app/views/todos/_edit_mobile_form.rhtml b/app/views/todos/_edit_mobile_form.rhtml index df130e65..973dee68 100644 --- a/app/views/todos/_edit_mobile_form.rhtml +++ b/app/views/todos/_edit_mobile_form.rhtml @@ -6,8 +6,8 @@ <% this_year = current_user.time.to_date.strftime("%Y").to_i -%>

        <%= text_field( "todo", "description", "tabindex" => 1, "maxlength" => 100, "size" => 50) %> -

        -<%= text_field_tag "tag_list", @tag_list_text, :size => 50, :tabindex => 2 %> +

        +<%= text_field_tag "todo_tag_list", @tag_list_text, :size => 50, :tabindex => 2 %>

        <%= unless @mobile_from_context collection_select( "todo", "context_id", @contexts, "id", "name", {}, {"tabindex" => 3} ) diff --git a/public/stylesheets/mobile.css b/public/stylesheets/mobile.css index f10e5632..b43cdbf9 100644 --- a/public/stylesheets/mobile.css +++ b/public/stylesheets/mobile.css @@ -230,7 +230,7 @@ table.c { display:inline; } -input#todo_description, input#tag_list, textarea#todo_notes, select#todo_project_id, select#todo_context_id { +input#todo_description, input#todo_tag_list, textarea#todo_notes, select#todo_project_id, select#todo_context_id { width: 95%; } From a83c8b3f928b18f8029aaea4926b1f8f2a22f6ff Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Thu, 5 Apr 2012 10:43:56 +0200 Subject: [PATCH 101/134] initial upgrade to rails 3.2.3 --- .gitignore.rails2 | 25 + Gemfile | 88 ++- Gemfile.lock | 181 ++++--- Gemfile.rails2.3 | 65 +++ Gemfile.rails3 | 39 ++ README.rdoc | 261 +++++++++ Rakefile | 15 +- app/assets/images/rails.png | Bin 0 -> 6646 bytes app/assets/javascripts/application.js | 15 + app/assets/stylesheets/application.css | 13 + app/controllers/application_controller.rb | 321 ----------- .../application_controller.rb.rails2 | 324 +++++++++++ app/helpers/application_helper.rb | 2 - app/helpers/application_helper.rb.rails2 | 301 +++++++++++ app/mailers/.gitkeep | 0 app/models/.gitkeep | 0 app/views/layouts/application.html.erb | 14 + config.ru | 4 + config/application.rb | 59 ++ config/boot.rb | 130 +---- config/database.yml.rails2 | 37 ++ config/environment.rb | 121 +---- config/environment.rb.rails2 | 119 ++++ config/environments/development.rb | 46 +- config/environments/development.rb.rails2 | 19 + config/environments/production.rb | 74 ++- config/environments/production.rb.rails2 | 17 + config/environments/test.rb | 56 +- config/initializers/backtrace_silencers.rb | 4 +- config/initializers/inflections.rb | 7 +- config/initializers/mime_types.rb | 5 +- config/initializers/secret_token.rb | 7 + config/initializers/session_store.rb | 8 + config/initializers/wrap_parameters.rb | 14 + config/routes.rb | 149 ++---- config/routes.rb.rails2 | 113 ++++ db/seeds.rb | 7 + doc/README_FOR_APP | 2 + lib/assets/.gitkeep | 0 lib/tasks/.gitkeep | 0 public/404.html | 34 +- public/422.html | 34 +- public/500.html | 32 +- public/index.html | 241 +++++++++ script/about | 0 script/rails | 6 + test/fixtures/.gitkeep | 0 test/functional/.gitkeep | 0 test/integration/.gitkeep | 0 test/performance/browsing_test.rb | 12 + test/test_helper.rb | 153 +----- test/test_helper.rb.rails2 | 152 ++++++ test/unit/.gitkeep | 0 vendor/assets/javascripts/.gitkeep | 0 vendor/assets/stylesheets/.gitkeep | 0 vendor/plugins/.gitkeep | 0 vendor/plugins/rails_upgrade/MIT-LICENSE | 20 + vendor/plugins/rails_upgrade/README.rdoc | 26 + vendor/plugins/rails_upgrade/Rakefile | 22 + vendor/plugins/rails_upgrade/init.rb | 2 + vendor/plugins/rails_upgrade/install.rb | 38 ++ .../rails_upgrade/lib/application_checker.rb | 506 ++++++++++++++++++ .../rails_upgrade/lib/gemfile_generator.rb | 95 ++++ .../lib/new_configuration_generator.rb | 59 ++ .../rails_upgrade/lib/rails_upgrade.rb | 0 .../rails_upgrade/lib/routes_upgrader.rb | 344 ++++++++++++ .../lib/tasks/rails_upgrade_tasks.rake | 79 +++ .../test/application_checker_test.rb | 344 ++++++++++++ .../test/gemfile_generator_test.rb | 72 +++ .../test/new_configuration_generator_test.rb | 63 +++ .../test/routes_upgrader_test.rb | 218 ++++++++ .../plugins/rails_upgrade/test/test_helper.rb | 5 + vendor/plugins/rails_upgrade/uninstall.rb | 1 + 73 files changed, 4141 insertions(+), 1079 deletions(-) create mode 100644 .gitignore.rails2 create mode 100644 Gemfile.rails2.3 create mode 100644 Gemfile.rails3 create mode 100644 README.rdoc create mode 100644 app/assets/images/rails.png create mode 100644 app/assets/javascripts/application.js create mode 100644 app/assets/stylesheets/application.css create mode 100644 app/controllers/application_controller.rb.rails2 create mode 100644 app/helpers/application_helper.rb.rails2 create mode 100644 app/mailers/.gitkeep create mode 100644 app/models/.gitkeep create mode 100644 app/views/layouts/application.html.erb create mode 100644 config.ru create mode 100644 config/application.rb create mode 100644 config/database.yml.rails2 create mode 100644 config/environment.rb.rails2 create mode 100644 config/environments/development.rb.rails2 create mode 100644 config/environments/production.rb.rails2 create mode 100644 config/initializers/secret_token.rb create mode 100644 config/initializers/session_store.rb create mode 100644 config/initializers/wrap_parameters.rb create mode 100644 config/routes.rb.rails2 create mode 100644 db/seeds.rb create mode 100644 doc/README_FOR_APP create mode 100644 lib/assets/.gitkeep create mode 100644 lib/tasks/.gitkeep create mode 100644 public/index.html mode change 100644 => 100755 script/about create mode 100755 script/rails create mode 100644 test/fixtures/.gitkeep create mode 100644 test/functional/.gitkeep create mode 100644 test/integration/.gitkeep create mode 100644 test/performance/browsing_test.rb create mode 100644 test/test_helper.rb.rails2 create mode 100644 test/unit/.gitkeep create mode 100644 vendor/assets/javascripts/.gitkeep create mode 100644 vendor/assets/stylesheets/.gitkeep create mode 100644 vendor/plugins/.gitkeep create mode 100644 vendor/plugins/rails_upgrade/MIT-LICENSE create mode 100644 vendor/plugins/rails_upgrade/README.rdoc create mode 100644 vendor/plugins/rails_upgrade/Rakefile create mode 100644 vendor/plugins/rails_upgrade/init.rb create mode 100644 vendor/plugins/rails_upgrade/install.rb create mode 100644 vendor/plugins/rails_upgrade/lib/application_checker.rb create mode 100644 vendor/plugins/rails_upgrade/lib/gemfile_generator.rb create mode 100644 vendor/plugins/rails_upgrade/lib/new_configuration_generator.rb create mode 100644 vendor/plugins/rails_upgrade/lib/rails_upgrade.rb create mode 100644 vendor/plugins/rails_upgrade/lib/routes_upgrader.rb create mode 100644 vendor/plugins/rails_upgrade/lib/tasks/rails_upgrade_tasks.rake create mode 100644 vendor/plugins/rails_upgrade/test/application_checker_test.rb create mode 100644 vendor/plugins/rails_upgrade/test/gemfile_generator_test.rb create mode 100644 vendor/plugins/rails_upgrade/test/new_configuration_generator_test.rb create mode 100644 vendor/plugins/rails_upgrade/test/routes_upgrader_test.rb create mode 100644 vendor/plugins/rails_upgrade/test/test_helper.rb create mode 100644 vendor/plugins/rails_upgrade/uninstall.rb diff --git a/.gitignore.rails2 b/.gitignore.rails2 new file mode 100644 index 00000000..8e2cc0f5 --- /dev/null +++ b/.gitignore.rails2 @@ -0,0 +1,25 @@ +*~ +*.tmproj +.dotest +/.emacs-project +/.redcar +config/database.yml +config/site.yml +config/deploy.rb +db/*.sqlite3 +db/data.yml +db/schema.rb +log +nbproject +public/javascripts/cache +public/stylesheets/cache +tmp +vendor/plugins/query_trace/ +rerun.txt +public/javascripts/jquery-cached.js +public/javascripts/tracks-cached.js +public/stylesheets/tracks-cached.css +.idea +.rvmrc +.yardoc +tags diff --git a/Gemfile b/Gemfile index 87eca690..ab4e34b2 100644 --- a/Gemfile +++ b/Gemfile @@ -1,64 +1,38 @@ -source :gemcutter -source "http://gems.github.com/" +source 'https://rubygems.org' -gem "rake", "~>0.8.7" -gem "rails", "~>2.3.12" -gem "highline", "~>1.5.0" -gem "RedCloth", "4.2.8" -gem "sanitize", "~>1.2.1" -gem "rack", "1.1.0" -gem "will_paginate", "~> 2.3.15" -gem "acts_as_list", "~>0.1.4" -gem "aasm", "~>2.2.0" -gem "rubyjedi-actionwebservice", :require => "actionwebservice" -gem "rubycas-client", "~>2.2.1" -gem "ruby-openid", :require => "openid" +gem 'rails', '3.2.3' -# you may comment out the database driver you will not be using. -# This will prevent a native build of the driver. Building native drivers is not always possible on all hosters -gem "sqlite3" -gem "mysql" +# Bundle edge Rails instead: +# gem 'rails', :git => 'git://github.com/rails/rails.git' -gem 'bcrypt-ruby', '~> 2.1.4' -gem 'htmlentities', '~> 4.3.0' -gem "mail" +gem 'sqlite3' -if RUBY_VERSION.to_f >= 1.9 - gem "soap4r-ruby1.9" -else - gem "soap4r", "~>1.5.8" + +# Gems used only for assets and not required +# in production environments by default. +group :assets do + gem 'sass-rails', '~> 3.2.3' + gem 'coffee-rails', '~> 3.2.1' + + # See https://github.com/sstephenson/execjs#readme for more supported runtimes + # gem 'therubyracer', :platform => :ruby + + gem 'uglifier', '>= 1.0.3' end -group :development do - if RUBY_VERSION.to_f >= 1.9 - gem "ruby-debug19" - gem "mongrel", "1.2.0.pre2" - else - gem "ruby-debug" - gem "mongrel" - end - gem "yard" -end +gem 'jquery-rails' -group :test do - gem "test-unit", "1.2.3" - gem "flexmock" - gem "ZenTest", ">=4.0.0" - gem "hpricot" - gem "hoe" - gem "rspec-rails", "~>1.3.3" - gem "thoughtbot-factory_girl" - gem 'memory_test_fix', '~>0.1.3' - gem "capybara", ">=0.3.5" - gem "selenium-webdriver" # Note that > 2.14 has problems: https://code.google.com/p/selenium/issues/detail?id=3075 - gem "database_cleaner", ">=0.5.0" - gem "cucumber-rails", "~>0.3.2" - gem "aruba", "0.2.2", :path => "vendor/gems/aruba-0.2.2" - - # uncomment to use the webkit option. This depends on Qt to be installed - #gem "capybara-webkit" - - # uncomment to be able to make screenshots from scenarios - #gem "capybara-screenshot" - #gem "launchy" -end +# To use ActiveModel has_secure_password +# gem 'bcrypt-ruby', '~> 3.0.0' + +# To use Jbuilder templates for JSON +# gem 'jbuilder' + +# Use unicorn as the app server +# gem 'unicorn' + +# Deploy with Capistrano +# gem 'capistrano' + +# To use debugger +# gem 'ruby-debug19', :require => 'ruby-debug' diff --git a/Gemfile.lock b/Gemfile.lock index 783cfdf0..6d053889 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,28 +1,36 @@ -PATH - remote: vendor/gems/aruba-0.2.2 - specs: - aruba (0.2.2) - GEM - remote: http://rubygems.org/ - remote: http://gems.github.com/ + remote: https://rubygems.org/ specs: - RedCloth (4.2.8) - ZenTest (4.6.2) - aasm (2.2.1) - actionmailer (2.3.14) - actionpack (= 2.3.14) - actionpack (2.3.14) - activesupport (= 2.3.14) - rack (~> 1.1.0) - activerecord (2.3.14) - activesupport (= 2.3.14) - activeresource (2.3.14) - activesupport (= 2.3.14) - activesupport (2.3.14) - acts_as_list (0.1.4) - bcrypt-ruby (2.1.4) + actionmailer (3.2.3) + actionpack (= 3.2.3) + mail (~> 2.4.4) + actionpack (3.2.3) + activemodel (= 3.2.3) + activesupport (= 3.2.3) + builder (~> 3.0.0) + erubis (~> 2.7.0) + journey (~> 1.0.1) + rack (~> 1.4.0) + rack-cache (~> 1.2) + rack-test (~> 0.6.1) + sprockets (~> 2.1.2) + activemodel (3.2.3) + activesupport (= 3.2.3) + builder (~> 3.0.0) + activerecord (3.2.3) + activemodel (= 3.2.3) + activesupport (= 3.2.3) + arel (~> 3.0.2) + tzinfo (~> 0.3.29) + activeresource (3.2.3) + activemodel (= 3.2.3) + activesupport (= 3.2.3) + activesupport (3.2.3) + i18n (~> 0.6) + multi_json (~> 1.0) + arel (3.0.2) builder (3.0.0) +<<<<<<< HEAD capybara (1.1.2) mime-types (>= 1.16) nokogiri (>= 1.3.3) @@ -57,80 +65,82 @@ GEM hpricot (0.8.6) htmlentities (4.3.1) httpclient (2.2.4) +======= + coffee-rails (3.2.2) + coffee-script (>= 2.2.0) + railties (~> 3.2.0) + coffee-script (2.2.0) + coffee-script-source + execjs + coffee-script-source (1.2.0) + erubis (2.7.0) + execjs (1.3.0) + multi_json (~> 1.0) + hike (1.2.1) +>>>>>>> initial upgrade to rails 3.2.3 i18n (0.6.0) - json (1.6.5) - linecache (0.46) - rbx-require-relative (> 0.0.4) - mail (2.4.1) + journey (1.0.3) + jquery-rails (2.0.2) + railties (>= 3.2.0, < 5.0) + thor (~> 0.14) + json (1.6.6) + mail (2.4.4) i18n (>= 0.4.0) mime-types (~> 1.16) treetop (~> 1.4.8) - memory_test_fix (0.1.3) - mime-types (1.17.2) - mongrel (1.1.5) - cgi_multipart_eof_fix (>= 2.4) - daemons (>= 1.0.3) - fastthread (>= 1.0.1) - gem_plugin (>= 0.2.3) - multi_json (1.1.0) - mysql (2.8.1) - nokogiri (1.4.7) + mime-types (1.18) + multi_json (1.2.0) polyglot (0.3.3) - rack (1.1.0) + rack (1.4.1) + rack-cache (1.2) + rack (>= 0.4) + rack-ssl (1.3.2) + rack rack-test (0.6.1) rack (>= 1.0) - rails (2.3.14) - actionmailer (= 2.3.14) - actionpack (= 2.3.14) - activerecord (= 2.3.14) - activeresource (= 2.3.14) - activesupport (= 2.3.14) - rake (>= 0.8.3) - rake (0.8.7) - rbx-require-relative (0.0.5) - rspec (1.3.2) - rspec-rails (1.3.4) - rack (>= 1.0.0) - rspec (~> 1.3.1) - ruby-debug (0.10.4) - columnize (>= 0.1) - ruby-debug-base (~> 0.10.4.0) - ruby-debug-base (0.10.4) - linecache (>= 0.3) - ruby-openid (2.1.8) - rubycas-client (2.2.1) - activesupport - rubyjedi-actionwebservice (2.3.5.20100714122544) - actionpack (~> 2.3.0) - activerecord (~> 2.3.0) - activesupport (~> 2.3.0) - rubyzip (0.9.6.1) - sanitize (1.2.1) - nokogiri (~> 1.4.1) - selenium-webdriver (2.20.0) - childprocess (>= 0.2.5) - ffi (~> 1.0) - multi_json (~> 1.0) - rubyzip - soap4r (1.5.8) - httpclient (>= 2.1.1) + rails (3.2.3) + actionmailer (= 3.2.3) + actionpack (= 3.2.3) + activerecord (= 3.2.3) + activeresource (= 3.2.3) + activesupport (= 3.2.3) + bundler (~> 1.0) + railties (= 3.2.3) + railties (3.2.3) + actionpack (= 3.2.3) + activesupport (= 3.2.3) + rack-ssl (~> 1.3.2) + rake (>= 0.8.7) + rdoc (~> 3.4) + thor (~> 0.14.6) + rake (0.9.2.2) + rdoc (3.12) + json (~> 1.4) + sass (3.1.15) + sass-rails (3.2.5) + railties (~> 3.2.0) + sass (>= 3.1.10) + tilt (~> 1.3) + sprockets (2.1.2) + hike (~> 1.2) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) sqlite3 (1.3.5) - term-ansicolor (1.0.7) - test-unit (1.2.3) - hoe (>= 1.5.1) - thoughtbot-factory_girl (1.2.2) + thor (0.14.6) + tilt (1.3.3) treetop (1.4.10) polyglot polyglot (>= 0.3.1) - will_paginate (2.3.16) - xpath (0.1.4) - nokogiri (~> 1.3) - yard (0.7.5) + tzinfo (0.3.32) + uglifier (1.2.4) + execjs (>= 0.3.0) + multi_json (>= 1.0.2) PLATFORMS ruby DEPENDENCIES +<<<<<<< HEAD RedCloth (= 4.2.8) ZenTest (>= 4.0.0) aasm (~> 2.2.0) @@ -160,8 +170,11 @@ DEPENDENCIES sanitize (~> 1.2.1) selenium-webdriver soap4r (~> 1.5.8) +======= + coffee-rails (~> 3.2.1) + jquery-rails + rails (= 3.2.3) + sass-rails (~> 3.2.3) +>>>>>>> initial upgrade to rails 3.2.3 sqlite3 - test-unit (= 1.2.3) - thoughtbot-factory_girl - will_paginate (~> 2.3.15) - yard + uglifier (>= 1.0.3) diff --git a/Gemfile.rails2.3 b/Gemfile.rails2.3 new file mode 100644 index 00000000..dc3af876 --- /dev/null +++ b/Gemfile.rails2.3 @@ -0,0 +1,65 @@ +source :gemcutter +source "http://gems.github.com/" + +gem "rake", "~>0.8.7" +gem "rails", "~>2.3.12" +gem "highline", "~>1.5.0" +gem "RedCloth", "4.2.8" +gem "sanitize", "~>1.2.1" +gem "rack", "1.1.0" +gem "will_paginate", "~> 2.3.15" +gem "has_many_polymorphs", "~> 2.13" +gem "acts_as_list", "~>0.1.4" +gem "aasm", "~>2.2.0" +gem "rubyjedi-actionwebservice", :require => "actionwebservice" +gem "rubycas-client", "~>2.2.1" +gem "ruby-openid", :require => "openid" + +# you may comment out the database driver you will not be using. +# This will prevent a native build of the driver. Building native drivers is not always possible on all hosters +gem "sqlite3" +gem "mysql" + +gem 'bcrypt-ruby', '~> 2.1.4' +gem 'htmlentities', '~> 4.3.0' +gem "mail" + +if RUBY_VERSION.to_f >= 1.9 + gem "soap4r-ruby1.9" +else + gem "soap4r", "~>1.5.8" +end + +group :development do + if RUBY_VERSION.to_f >= 1.9 + gem "ruby-debug19" + gem "mongrel", "1.2.0.pre2" + else + gem "ruby-debug" + gem "mongrel" + end + gem "yard" +end + +group :test do + gem "test-unit", "1.2.3" + gem "flexmock" + gem "ZenTest", ">=4.0.0" + gem "hpricot" + gem "hoe" + gem "rspec-rails", "~>1.3.3" + gem "thoughtbot-factory_girl" + gem 'memory_test_fix', '~>0.1.3' + gem "capybara", ">=0.3.5" + gem "selenium-webdriver" # Note that > 2.14 has problems: https://code.google.com/p/selenium/issues/detail?id=3075 + gem "database_cleaner", ">=0.5.0" + gem "cucumber-rails", "~>0.3.2" + gem "aruba", "0.2.2", :path => "vendor/gems/aruba-0.2.2" + + # uncomment to use the webkit option. This depends on Qt to be installed + #gem "capybara-webkit" + + # uncomment to be able to make screenshots from scenarios + #gem "capybara-screenshot" + #gem "launchy" +end diff --git a/Gemfile.rails3 b/Gemfile.rails3 new file mode 100644 index 00000000..c07b2b6a --- /dev/null +++ b/Gemfile.rails3 @@ -0,0 +1,39 @@ +source 'https://rubygems.org' + +gem 'rails', '3.2.3' + +# Bundle edge Rails instead: +# gem 'rails', :git => 'git://github.com/rails/rails.git' + +gem 'sqlite3' +gem 'mysql' + + +# Gems used only for assets and not required +# in production environments by default. +group :assets do + gem 'sass-rails', '~> 3.2.3' + gem 'coffee-rails', '~> 3.2.1' + + # See https://github.com/sstephenson/execjs#readme for more supported runtimes + # gem 'therubyracer', :platform => :ruby + + gem 'uglifier', '>= 1.0.3' +end + +gem 'jquery-rails' + +# To use ActiveModel has_secure_password +# gem 'bcrypt-ruby', '~> 3.0.0' + +# To use Jbuilder templates for JSON +# gem 'jbuilder' + +# Use unicorn as the app server +# gem 'unicorn' + +# Deploy with Capistrano +# gem 'capistrano' + +# To use debugger +# gem 'ruby-debug19', :require => 'ruby-debug' diff --git a/README.rdoc b/README.rdoc new file mode 100644 index 00000000..7c36f235 --- /dev/null +++ b/README.rdoc @@ -0,0 +1,261 @@ +== Welcome to Rails + +Rails is a web-application framework that includes everything needed to create +database-backed web applications according to the Model-View-Control pattern. + +This pattern splits the view (also called the presentation) into "dumb" +templates that are primarily responsible for inserting pre-built 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 an 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 are 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. + + +== Getting Started + +1. At the command prompt, create a new Rails application: + rails new myapp (where myapp is the application name) + +2. Change directory to myapp and start the web server: + cd myapp; rails server (run with --help for options) + +3. Go to http://localhost:3000/ and you'll see: + "Welcome aboard: You're riding Ruby on Rails!" + +4. Follow the guidelines to start developing your application. You can find +the following resources handy: + +* The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html +* Ruby on Rails Tutorial Book: http://www.railstutorial.org/ + + +== Debugging Rails + +Sometimes your application goes wrong. Fortunately there are a lot of tools that +will help you debug it and get it back on the rails. + +First area to check is the application log files. Have "tail -f" commands +running on the server.log and development.log. 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. + +You can also log your own messages directly into the log file from your code +using the Ruby logger class from inside your controllers. Example: + + class WeblogController < ActionController::Base + def destroy + @weblog = Weblog.find(params[:id]) + @weblog.destroy + logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!") + end + end + +The result will be a message in your log file along the lines of: + + Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1! + +More information on how to use the logger is at http://www.ruby-doc.org/core/ + +Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are +several books available online as well: + +* Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe) +* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide) + +These two books will bring you up to speed on the Ruby language and also on +programming in general. + + +== Debugger + +Debugger support is available through the debugger command when you start your +Mongrel or WEBrick server with --debugger. This means that you can break out of +execution at any point in the code, investigate and change the model, and then, +resume execution! You need to install ruby-debug to run the server in debugging +mode. With gems, use sudo gem install ruby-debug. Example: + + class WeblogController < ActionController::Base + def index + @posts = Post.all + debugger + end + end + +So the controller will accept the action, run the first line, then present you +with a IRB prompt in the server window. Here you can do things like: + + >> @posts.inspect + => "[#nil, "body"=>nil, "id"=>"1"}>, + #"Rails", "body"=>"Only ten..", "id"=>"2"}>]" + >> @posts.first.title = "hello from a debugger" + => "hello from a debugger" + +...and even better, you can examine how your runtime objects actually work: + + >> f = @posts.first + => #nil, "body"=>nil, "id"=>"1"}> + >> f. + Display all 152 possibilities? (y or n) + +Finally, when you're ready to resume execution, you can enter "cont". + + +== Console + +The console is a Ruby shell, which allows you to interact with your +application's domain model. 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. Starting the script +without arguments will launch it in the development environment. + +To start the console, run rails console from the application +directory. + +Options: + +* Passing the -s, --sandbox argument will rollback any modifications + made to the database. +* Passing an environment name as an argument will load the corresponding + environment. Example: rails console production. + +To reload your controllers and models after launching the console run +reload! + +More information about irb can be found at: +link:http://www.rubycentral.org/pickaxe/irb.html + + +== dbconsole + +You can go to the command line of your database directly through rails +dbconsole. You would be connected to the database with the credentials +defined in database.yml. Starting the script without arguments will connect you +to the development database. Passing an argument will connect you to a different +database, like rails dbconsole production. Currently works for MySQL, +PostgreSQL and SQLite 3. + +== Description of Contents + +The default directory structure of a generated Ruby on Rails application: + + |-- app + | |-- assets + | |-- images + | |-- javascripts + | `-- stylesheets + | |-- controllers + | |-- helpers + | |-- mailers + | |-- models + | `-- views + | `-- layouts + |-- config + | |-- environments + | |-- initializers + | `-- locales + |-- db + |-- doc + |-- lib + | `-- tasks + |-- log + |-- public + |-- script + |-- test + | |-- fixtures + | |-- functional + | |-- integration + | |-- performance + | `-- unit + |-- tmp + | |-- cache + | |-- pids + | |-- sessions + | `-- sockets + `-- vendor + |-- assets + `-- stylesheets + `-- plugins + +app + Holds all the code that's specific to this particular application. + +app/assets + Contains subdirectories for images, stylesheets, and JavaScript files. + +app/controllers + Holds controllers that should be named like weblogs_controller.rb for + automated URL mapping. All controllers should descend from + ApplicationController which itself descends from ActionController::Base. + +app/models + Holds models that should be named like post.rb. Models descend from + ActiveRecord::Base by default. + +app/views + Holds the template files for the view that should be named like + weblogs/index.html.erb for the WeblogsController#index action. All views use + eRuby syntax by default. + +app/views/layouts + Holds the template files for layouts to be used with views. This models the + common header/footer method of wrapping views. In your views, define a layout + using the layout :default and create a file named default.html.erb. + Inside default.html.erb, call <% yield %> to render the view using this + layout. + +app/helpers + Holds view helpers that should be named like weblogs_helper.rb. These are + generated for you automatically when using generators for controllers. + Helpers can be used to wrap functionality for your views into methods. + +config + Configuration files for the Rails environment, the routing map, the database, + and other dependencies. + +db + Contains the database schema in schema.rb. db/migrate contains all the + sequence of Migrations for your schema. + +doc + This directory is where your application documentation will be stored when + generated using rake doc:app + +lib + Application specific libraries. Basically, any kind of custom code that + doesn't belong under controllers, models, or helpers. This directory is in + the load path. + +public + The directory available for the web server. Also contains the dispatchers and the + default HTML files. This should be set as the DOCUMENT_ROOT of your web + server. + +script + Helper scripts for automation and generation. + +test + Unit and functional tests along with fixtures. When using the rails generate + command, template test files will be generated for you and placed in this + directory. + +vendor + External libraries that the application depends on. Also includes the plugins + subdirectory. If the app has frozen rails, those gems also go here, under + vendor/rails/. This directory is in the load path. diff --git a/Rakefile b/Rakefile index 2704572a..af3b6bdc 100644 --- a/Rakefile +++ b/Rakefile @@ -1,16 +1,7 @@ +#!/usr/bin/env rake # 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 File.expand_path('../config/application', __FILE__) -require 'rake' -require 'rake/testtask' -require 'rake/rdoctask' - -require 'tasks/rails' - -begin - require 'test/rails/rake_tasks' -rescue LoadError => e - #It's ok if you don't have ZenTest installed if you're not a developer -end +Tracksapp::Application.load_tasks diff --git a/app/assets/images/rails.png b/app/assets/images/rails.png new file mode 100644 index 0000000000000000000000000000000000000000..d5edc04e65f555e3ba4dcdaad39dc352e75b575e GIT binary patch literal 6646 zcmVpVcQya!6@Dsmj@#jv7C*qh zIhOJ6_K0n?*d`*T7TDuW-}m`9Kz3~>+7`DUkbAraU%yi+R{N~~XA2B%zt-4=tLimUer9!2M~N{G5bftFij_O&)a zsHnOppFIzebQ`RA0$!yUM-lg#*o@_O2wf422iLnM6cU(ktYU8#;*G!QGhIy9+ZfzKjLuZo%@a z-i@9A`X%J{^;2q&ZHY3C(B%gqCPW!8{9C0PMcNZccefK){s|V5-xxtHQc@uf>XqhD z7#N^siWqetgq29aX>G^olMf=bbRF6@Y(}zYxw6o!9WBdG1unP}<(V;zKlcR2p86fq zYjaqB^;Ycq>Wy@5T1xOzG3tucG3e%nPvajaN{CrFbnzv^9&K3$NrDm*eQe4`BGQ2bI;dFEwyt>hK%X!L6)82aOZp zsrGcJ#7PoX7)s|~t6is?FfX*7vWdREi58tiY4S)t6u*|kv?J)d_$r+CH#eZ?Ef+I_ z(eVlX8dh~4QP?o*E`_MgaNFIKj*rtN(0Raj3ECjSXcWfd#27NYs&~?t`QZFT}!Zaf=ldZIhi}LhQlqLo+o5(Pvui&{7PD__^53f9j>HW`Q z_V8X5j~$|GP9qXu0C#!@RX2}lXD35@3N5{BkUi%jtaPQ*H6OX2zIz4QPuqmTv3`vG{zc>l3t0B9E75h< z8&twGh%dp7WPNI+tRl%#gf2}Epg8st+~O4GjtwJsXfN;EjAmyr6z5dnaFU(;IV~QK zW62fogF~zA``(Q>_SmD!izc6Y4zq*97|NAPHp1j5X7Op2%;GLYm>^HEMyObo6s7l) zE3n|aOHi5~B84!}b^b*-aL2E)>OEJX_tJ~t<#VJ?bT?lDwyDB&5SZ$_1aUhmAY}#* zs@V1I+c5md9%R-o#_DUfqVtRk>59{+Opd5Yu%dAU#VQW}^m}x-30ftBx#527{^pI4 z6l2C6C7QBG$~NLYb3rVdLD#Z{+SleOp`(Lg5J}`kxdTHe(nV5BdpLrD=l|)e$gEqA zwI6vuX-PFCtcDIH>bGY2dwq&^tf+&R?)nY-@7_j%4CMRAF}C9w%p86W<2!aSY$p+k zrkFtG=cGo38RnrG28;?PNk%7a@faaXq&MS*&?1Z`7Ojw7(#>}ZG4nMAs3VXxfdW>i zY4VX02c5;f7jDPY_7@Oa)CHH}cH<3y#}_!nng^W+h1e-RL*YFYOteC@h?BtJZ+?sE zy)P5^8Mregx{nQaw1NY-|3>{Z)|0`?zc?G2-acYiSU`tj#sSGfm7k86ZQ0SQgPevcklHxM9<~4yW zR796sisf1|!#{Z=e^)0;_8iUhL8g(;j$l=02FTPZ(dZV@s#aQ`DHkLM6=YsbE4iQ!b#*374l0Jw5;jD%J;vQayq=nD8-kHI~f9Ux|32SJUM`> zGp2UGK*4t?cRKi!2he`zI#j0f${I#f-jeT?u_C7S4WsA0)ryi-1L0(@%pa^&g5x=e z=KW9+Nn(=)1T&S8g_ug%dgk*~l2O-$r9#zEGBdQsweO%t*6F4c8JC36JtTizCyy+E4h%G(+ z5>y$%0txMuQ$e~wjFgN(xrAndHQo`Za+K*?gUVDTBV&Ap^}|{w#CIq{DRe}+l@(Ec zCCV6f_?dY_{+f{}6XGn!pL_up?}@>KijT^$w#Lb6iHW&^8RP~g6y=vZBXx~B9nI^i zGexaPjcd(%)zGw!DG_dDwh-7x6+ST#R^${iz_M$uM!da8SxgB_;Z0G%Y*HpvLjKw; zX=ir7i1O$-T|*TBoH$dlW+TLf5j5sep^DlDtkox;Kg{Q%EXWedJq@J@%VAcK)j3y1 zShM!CS#qax;D@RND%2t3W6kv+#Ky0F9<3YKDbV^XJ=^$s(Vtza8V72YY)577nnldI zHMA0PUo!F3j(ubV*CM@PiK<^|RM2(DuCbG7`W}Rg(xdYC>C~ z;1KJGLN&$cRxSZunjXcntykmpFJ7;dk>shY(DdK&3K_JDJ6R%D`e~6Qv67@Rwu+q9 z*|NG{r}4F8f{Dfzt0+cZMd$fvlX3Q`dzM46@r?ISxr;9gBTG2rmfiGOD*#c*3f)cc zF+PFZobY$-^}J8 z%n=h4;x2}cP!@SiVd!v;^Wwo0(N??-ygDr7gG^NKxDjSo{5T{?$|Qo5;8V!~D6O;F*I zuY!gd@+2j_8Rn=UWDa#*4E2auWoGYDddMW7t0=yuC(xLWky?vLimM~!$3fgu!dR>p z?L?!8z>6v$|MsLb&dU?ob)Zd!B)!a*Z2eTE7 zKCzP&e}XO>CT%=o(v+WUY`Az*`9inbTG& z_9_*oQKw;sc8{ipoBC`S4Tb7a%tUE)1fE+~ib$;|(`|4QbXc2>VzFi%1nX%ti;^s3~NIL0R}!!a{0A zyCRp0F7Y&vcP&3`&Dzv5!&#h}F2R-h&QhIfq*ts&qO13{_CP}1*sLz!hI9VoTSzTu zok5pV0+~jrGymE~{TgbS#nN5+*rF7ij)cnSLQw0Ltc70zmk|O!O(kM<3zw-sUvkx~ z2`y+{xAwKSa-0}n7{$I@Zop7CWy%_xIeN1e-7&OjQ6vZZPbZ^3_ z(~=;ZSP98S2oB#35b1~_x`2gWiPdIVddEf`AD9<@c_s)TM;3J$T_l?pr{<7PTgdiy zBc5IGx)g~n=s+Z$RzYCmv8PlJu%gkh^;%mTGMc)UwRINVD~K;`Rl!5@hhGg;y>5qj zq|u-Yf0q_~Y+Mbivkkfa0nAOzB1acnytogsj_m7FB(-FjihMek#GAU4M!iXCgdK8a zjoKm?*|iz7;dHm4$^hh(`Ufl>yb>$hjIA-;>{>C}G0Di%bGvUsJkfLAV|xq32c>RqJqTBJ3Dx zYC;*Dt|S$b6)aCJFnK(Eey$M1DpVV~_MIhwK> zygo(jWC|_IRw|456`roEyXtkNLWNAt-4N1qyN$I@DvBzt;e|?g<*HK1%~cq|^u*}C zmMrwh>{QAq?Ar~4l^DqT%SQ)w)FA(#7#u+N;>E975rYML>)LgE`2<7nN=C1pC{IkV zVw}_&v6j&S?QVh*)wF3#XmE@0($^BVl1969csLKUBNer{suVd!a~B!0MxWY?=(GD6 zy$G&ERFR#i6G4=2F?R4}Mz3B?3tnpoX3)qFF2sh9-Jn*e%9F>i{WG7$_~XyOO2!+@ z6k+38KyD@-0=uee54D0!Z1@B^ilj~StchdOn(*qvg~s5QJpWGc!6U^Aj!xt-HZn_V zS%|fyQ5YS@EP2lBIodXCLjG_+a)%En+7jzngk@J>6D~^xbxKkvf-R0-c%mX+o{?&j zZZ%RxFeav8Y0gkwtdtrwUb-i0Egd2C=ADu%w5VV-hNJvl)GZ?M;y$!?b=S+wKRK7Q zcOjPT!p<*#8m;TsBih=@Xc&c)?Vy`Ys>IvK@|1%N+M6J-^RCRaZcPP2eQh9DEGZr+ z?8B~wF14mk4Xkuen{wY^CWwS1PI<8gikY*)3?RSo5l8es4*J z43k_BIwc}of=6Pfs%xIxlMDGOJN zvl!a>G)52XMqA%fbgkZi%)%bN*ZzZw2!rn4@+J)2eK#kWuEW{)W~-`y1vhA5-7p%R z&f5N!a9f8cK1Xa=O}=9{wg%}Ur^+8Y(!UCeqw>%wj@|bYHD-bZO~mk3L$9_^MmF3G zvCiK^e@q6G?tHkM8%GqsBMZaB20W$UEt_5r~jc#WlR>Bv{6W>A=!#InoY zLOd04@Rz?*7PpW8u|+}bt`?+Z(GsX{Br4A2$ZZ(26Degmr9`O=t2KgHTL*==R3xcP z&Y(J7hC@6_x8zVz!CX3l4Xtss6i7r#E6kXMNN1~>9KTRzewfp))ij%)SBBl0fZdYP zd!zzQD5u8yk-u|41|Rqz7_tCFUMThZJVj)yQf6^Cwtn|Ew6cm5J|u1Bq>MWX-AfB&NE;C z62@=-0le`E6-CurMKjoIy)BuUmhMGJb}pPx!@GLWMT+wH2R?wA=MEy)o57~feFp8P zY@YXAyt4<1FD<|iw{FGQu~GEI<4C64)V*QiVk+VzOV^9GWf4ir#oYgHJz!wq>iZV#_6@_{)&lum)4x z_Of*CLVQ7wdT#XT-(h0qH%mcIF7yzMIvvTN3bPceK>PpJi(=3Nny zbSn}p$dGKQUlX&-t~RR)#F7I<8NCD^yke(vdf#4^aAh}M-{tS9-&^tC4`KU_pToXy z+|K8sx}a)Kh{h{;*V1#hs1xB%(?j>)g~`Wv(9F)f=Qn)(daVB7hZtcp^#LrEr1T1J zZSJ*lVyVVjhy)mkex9Whn=EinKDHe@KlfQI-Fl7M?-c~HnW0;C;+MbUY8?FToy;A+ zs&Nc7VZ=Of+e!G6s#+S5WBU)kgQq_I1@!uH74GJ-+O|%0HXm9Mqlvp|j%0`T>fr9^ zK;qo>XdwZW<>%tTA+<(1^6(>=-2N;hRgBnjvEjN;VbKMbFg--WrGy|XESoH1p|M4` z86(gC^vB4qScASZ&cdpT{~QDN-jC|GJ(RYoW1VW4!SSn- zhQds9&RBKn6M&GVK_Aayt(Hekbnw=tr>f z^o@v9_*iQO1*zeOrts9Q-$pc@!StS&kz$cF`s@pM`rmJXTP&h5G)A74!0e%ZJbl}( zssI|_!%~_hZFypv*S^JE5N&Kvmx7KiG<|fGMO=WrH+@Yhuj+KwiS#l4>@%2nl zS)mDikfmokO4q2A)hRVZBq2-5q&XC>%HOLkOYxZ66(s86?=0s4z5xbiOV)}L-&6b)h6(~CIaR#JNw~46+WBiU7IhB zq!NuR4!TsYnyBg>@G=Ib*cMq^k<}AMpCeYEf&dzfiGI-wOQ7hb+nA zkN7_){y&c3xC0 AQ~&?~ literal 0 HcmV?d00001 diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js new file mode 100644 index 00000000..9097d830 --- /dev/null +++ b/app/assets/javascripts/application.js @@ -0,0 +1,15 @@ +// This is a manifest file that'll be compiled into application.js, which will include all the files +// listed below. +// +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, +// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. +// +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// the compiled file. +// +// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD +// GO AFTER THE REQUIRES BELOW. +// +//= require jquery +//= require jquery_ujs +//= require_tree . diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css new file mode 100644 index 00000000..3b5cc664 --- /dev/null +++ b/app/assets/stylesheets/application.css @@ -0,0 +1,13 @@ +/* + * This is a manifest file that'll be compiled into application.css, which will include all the files + * listed below. + * + * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, + * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. + * + * You're free to add application-wide styles to this file and they'll appear at the top of the + * compiled file, but it's generally better to create a new file per style scope. + * + *= require_self + *= require_tree . +*/ diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 761be1d9..e8065d95 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,324 +1,3 @@ -# 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 "tracks/source_view" - class ApplicationController < ActionController::Base - protect_from_forgery - - helper :application - include LoginSystem - helper_method :current_user, :prefs, :format_date - - layout proc{ |controller| controller.mobile? ? "mobile" : "standard" } - exempt_from_layout /\.js\.erb$/ - - before_filter :check_for_deprecated_password_hash - before_filter :set_session_expiration - before_filter :set_time_zone - before_filter :set_zindex_counter - before_filter :set_locale - prepend_before_filter :login_required - prepend_before_filter :enable_mobile_content_negotiation - after_filter :set_charset - - # By default, sets the charset to UTF-8 if it isn't already set - def set_charset - headers["Content-Type"] ||= "text/html; charset=UTF-8" - end - - def set_locale - locale = params[:locale] # specifying a locale in the request takes precedence - locale = locale || prefs.locale unless current_user.nil? # otherwise, the locale of the currently logged in user takes over - locale = locale || request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first if request.env['HTTP_ACCEPT_LANGUAGE'] - I18n.locale = locale.nil? ? I18n.default_locale : (I18n::available_locales.include?(locale.to_sym) ? locale : I18n.default_locale) - logger.debug("Selected '#{I18n.locale}' as locale") - end - - def set_session_expiration - # http://wiki.rubyonrails.com/rails/show/HowtoChangeSessionOptions - unless session == nil - return if self.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 - - # Redirects to change_password_user_path if the current user uses a - # deprecated password hashing algorithm. - def check_for_deprecated_password_hash - if current_user and current_user.uses_deprecated_password? - notify :warning, t('users.you_have_to_reset_your_password') - redirect_to change_password_user_path current_user - end - end - - def render_failure message, status = 404 - render :text => message, :status => status - end - - # def rescue_action(exception) - # log_error(exception) if logger - # respond_to do |format| - # format.html do - # notify :warning, "An error occurred on the server." - # render :action => "index" - # end - # format.js { render :action => 'error' } - # format.xml { render :text => 'An error occurred on the server.' + $! } - # end - # end - - # Returns a count of next actions in the given context or project The result - # is count and a string descriptor, correctly pluralised if there are no - # actions or multiple actions - # - def count_undone_todos_phrase(todos_parent) - count = count_undone_todos(todos_parent) - deferred_count = count_deferred_todos(todos_parent) - if count == 0 && deferred_count > 0 - word = I18n.t('common.actions_midsentence', :count => deferred_count) - word = I18n.t('common.deferred') + " " + word - return deferred_count.to_s + " " + word - else - word = I18n.t('common.actions_midsentence', :count => count) - return count.to_s + " " + word - end - 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 - - def count_deferred_todos(todos_parent) - if todos_parent.nil? - count = 0 - else - count = todos_parent.todos.deferred.count - end - end - - # Convert a date object to the format specified in the user's preferences in - # config/settings.yml - # - def format_date(date) - return date ? date.in_time_zone(prefs.time_zone).strftime("#{prefs.date_format}") : '' - end - - def for_autocomplete(coll, substr) - if substr # protect agains empty request - filtered = coll.find_all{|item| item.name.downcase.include? substr.downcase} - json_elems = Array[*filtered.map{ |e| {:id => e.id.to_s, :value => e.name} }].to_json - return json_elems - else - return "" - end - end - - def format_dependencies_as_json_for_auto_complete(entries) - json_elems = Array[*entries.map{ |e| {:value => e.id.to_s, :label => e.specification} }].to_json - return json_elems - end - - # Here's the concept behind this "mobile content negotiation" hack: In - # addition to the main, AJAXy Web UI, Tracks has a lightweight low-feature - # 'mobile' version designed to be suitablef or use from a phone or PDA. It - # makes some sense that tne pages of that mobile version are simply alternate - # representations of the same Todo resources. The implementation goal was to - # treat mobile as another format and be able to use respond_to to render both - # versions. Unfortunately, I ran into a lot of trouble simply registering a - # new mime type 'text/html' with format :m because :html already is linked to - # that mime type and the new registration was forcing all html requests to be - # rendered in the mobile view. The before_filter and after_filter hackery - # below accomplishs that implementation goal by using a 'fake' mime type - # during the processing and then setting it to 'text/html' in an - # 'after_filter' -LKM 2007-04-01 - def mobile? - return params[:format] == 'm' - end - - def enable_mobile_content_negotiation - if mobile? - request.format = :m - end - end - - def create_todo_from_recurring_todo(rt, date=nil) - # create todo and initialize with data from recurring_todo rt - todo = current_user.todos.build( { :description => rt.description, :notes => rt.notes, :project_id => rt.project_id, :context_id => rt.context_id}) - todo.recurring_todo_id = rt.id - - # set dates - todo.due = rt.get_due_date(date) - - show_from_date = rt.get_show_from_date(date) - if show_from_date.nil? - todo.show_from=nil - else - # make sure that show_from is not in the past - todo.show_from = show_from_date < Time.zone.now ? nil : show_from_date - end - - saved = todo.save - if saved - todo.tag_with(rt.tag_list) - todo.tags.reload - end - - # increate number of occurences created from recurring todo - rt.inc_occurences - - # mark recurring todo complete if there are no next actions left - checkdate = todo.due.nil? ? todo.show_from : todo.due - rt.toggle_completion! unless rt.has_next_todo(checkdate) - - return saved ? todo : nil - end - - def handle_unverified_request - unless request.format=="application/xml" - super # handle xml http auth via our own login code - end - end - - protected - - def admin_login_required - unless User.find_by_id_and_is_admin(session['user_id'], true) - render :text => t('errors.user_unauthorized'), :status => 401 - return false - end - end - - def redirect_back_or_home - respond_to do |format| - format.html { redirect_back_or_default home_url } - format.m { redirect_back_or_default mobile_url } - end - end - - def boolean_param(param_name) - return false if param_name.blank? - s = params[param_name] - 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 - - def self.openid_enabled? - Tracks::Config.openid_enabled? - end - - def openid_enabled? - self.class.openid_enabled? - end - - def self.cas_enabled? - Tracks::Config.cas_enabled? - end - - def cas_enabled? - self.class.cas_enabled? - end - - def self.prefered_auth? - Tracks::Config.prefered_auth? - end - - def prefered_auth? - self.class.prefered_auth? - end - - # all completed todos [today@00:00, today@now] - def get_done_today(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES}) - start_of_this_day = Time.zone.now.beginning_of_day - completed_todos.completed_after(start_of_this_day).all(includes) - end - - # all completed todos [begin_of_week, start_of_today] - def get_done_this_week(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES}) - start_of_this_week = Time.zone.now.beginning_of_week - start_of_this_day = Time.zone.now.beginning_of_day - completed_todos.completed_before(start_of_this_day).completed_after(start_of_this_week).all(includes) - end - - # all completed todos [begin_of_month, begin_of_week] - def get_done_this_month(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES}) - start_of_this_month = Time.zone.now.beginning_of_month - start_of_this_week = Time.zone.now.beginning_of_week - completed_todos.completed_before(start_of_this_week).completed_after(start_of_this_month).all(includes) - end - - private - - def parse_date_per_user_prefs( s ) - prefs.parse_date(s) - end - - def init_data_for_sidebar - @completed_projects = current_user.projects.completed - @hidden_projects = current_user.projects.hidden - @active_projects = current_user.projects.active - - @active_contexts = current_user.contexts.active - @hidden_contexts = current_user.contexts.hidden - - init_not_done_counts - if prefs.show_hidden_projects_in_sidebar - init_project_hidden_todo_counts(['project']) - end - end - - def init_not_done_counts(parents = ['project','context']) - parents.each do |parent| - eval("@#{parent}_not_done_counts = @#{parent}_not_done_counts || current_user.todos.active.count(:group => :#{parent}_id)") - end - end - - def init_project_hidden_todo_counts(parents = ['project','context']) - parents.each do |parent| - eval("@#{parent}_project_hidden_todo_counts = @#{parent}_project_hidden_todo_counts || current_user.todos.count(:conditions => ['state = ? or state = ?', 'project_hidden', 'active'], :group => :#{parent}_id)") - end - end - - # 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 - - def set_time_zone - Time.zone = current_user.prefs.time_zone if logged_in? - end - - def set_zindex_counter - # this counter can be used to handle the IE z-index bug - @z_index_counter = 500 - end - end diff --git a/app/controllers/application_controller.rb.rails2 b/app/controllers/application_controller.rb.rails2 new file mode 100644 index 00000000..761be1d9 --- /dev/null +++ b/app/controllers/application_controller.rb.rails2 @@ -0,0 +1,324 @@ +# 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 "tracks/source_view" + +class ApplicationController < ActionController::Base + + protect_from_forgery + + helper :application + include LoginSystem + helper_method :current_user, :prefs, :format_date + + layout proc{ |controller| controller.mobile? ? "mobile" : "standard" } + exempt_from_layout /\.js\.erb$/ + + before_filter :check_for_deprecated_password_hash + before_filter :set_session_expiration + before_filter :set_time_zone + before_filter :set_zindex_counter + before_filter :set_locale + prepend_before_filter :login_required + prepend_before_filter :enable_mobile_content_negotiation + after_filter :set_charset + + # By default, sets the charset to UTF-8 if it isn't already set + def set_charset + headers["Content-Type"] ||= "text/html; charset=UTF-8" + end + + def set_locale + locale = params[:locale] # specifying a locale in the request takes precedence + locale = locale || prefs.locale unless current_user.nil? # otherwise, the locale of the currently logged in user takes over + locale = locale || request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first if request.env['HTTP_ACCEPT_LANGUAGE'] + I18n.locale = locale.nil? ? I18n.default_locale : (I18n::available_locales.include?(locale.to_sym) ? locale : I18n.default_locale) + logger.debug("Selected '#{I18n.locale}' as locale") + end + + def set_session_expiration + # http://wiki.rubyonrails.com/rails/show/HowtoChangeSessionOptions + unless session == nil + return if self.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 + + # Redirects to change_password_user_path if the current user uses a + # deprecated password hashing algorithm. + def check_for_deprecated_password_hash + if current_user and current_user.uses_deprecated_password? + notify :warning, t('users.you_have_to_reset_your_password') + redirect_to change_password_user_path current_user + end + end + + def render_failure message, status = 404 + render :text => message, :status => status + end + + # def rescue_action(exception) + # log_error(exception) if logger + # respond_to do |format| + # format.html do + # notify :warning, "An error occurred on the server." + # render :action => "index" + # end + # format.js { render :action => 'error' } + # format.xml { render :text => 'An error occurred on the server.' + $! } + # end + # end + + # Returns a count of next actions in the given context or project The result + # is count and a string descriptor, correctly pluralised if there are no + # actions or multiple actions + # + def count_undone_todos_phrase(todos_parent) + count = count_undone_todos(todos_parent) + deferred_count = count_deferred_todos(todos_parent) + if count == 0 && deferred_count > 0 + word = I18n.t('common.actions_midsentence', :count => deferred_count) + word = I18n.t('common.deferred') + " " + word + return deferred_count.to_s + " " + word + else + word = I18n.t('common.actions_midsentence', :count => count) + return count.to_s + " " + word + end + 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 + + def count_deferred_todos(todos_parent) + if todos_parent.nil? + count = 0 + else + count = todos_parent.todos.deferred.count + end + end + + # Convert a date object to the format specified in the user's preferences in + # config/settings.yml + # + def format_date(date) + return date ? date.in_time_zone(prefs.time_zone).strftime("#{prefs.date_format}") : '' + end + + def for_autocomplete(coll, substr) + if substr # protect agains empty request + filtered = coll.find_all{|item| item.name.downcase.include? substr.downcase} + json_elems = Array[*filtered.map{ |e| {:id => e.id.to_s, :value => e.name} }].to_json + return json_elems + else + return "" + end + end + + def format_dependencies_as_json_for_auto_complete(entries) + json_elems = Array[*entries.map{ |e| {:value => e.id.to_s, :label => e.specification} }].to_json + return json_elems + end + + # Here's the concept behind this "mobile content negotiation" hack: In + # addition to the main, AJAXy Web UI, Tracks has a lightweight low-feature + # 'mobile' version designed to be suitablef or use from a phone or PDA. It + # makes some sense that tne pages of that mobile version are simply alternate + # representations of the same Todo resources. The implementation goal was to + # treat mobile as another format and be able to use respond_to to render both + # versions. Unfortunately, I ran into a lot of trouble simply registering a + # new mime type 'text/html' with format :m because :html already is linked to + # that mime type and the new registration was forcing all html requests to be + # rendered in the mobile view. The before_filter and after_filter hackery + # below accomplishs that implementation goal by using a 'fake' mime type + # during the processing and then setting it to 'text/html' in an + # 'after_filter' -LKM 2007-04-01 + def mobile? + return params[:format] == 'm' + end + + def enable_mobile_content_negotiation + if mobile? + request.format = :m + end + end + + def create_todo_from_recurring_todo(rt, date=nil) + # create todo and initialize with data from recurring_todo rt + todo = current_user.todos.build( { :description => rt.description, :notes => rt.notes, :project_id => rt.project_id, :context_id => rt.context_id}) + todo.recurring_todo_id = rt.id + + # set dates + todo.due = rt.get_due_date(date) + + show_from_date = rt.get_show_from_date(date) + if show_from_date.nil? + todo.show_from=nil + else + # make sure that show_from is not in the past + todo.show_from = show_from_date < Time.zone.now ? nil : show_from_date + end + + saved = todo.save + if saved + todo.tag_with(rt.tag_list) + todo.tags.reload + end + + # increate number of occurences created from recurring todo + rt.inc_occurences + + # mark recurring todo complete if there are no next actions left + checkdate = todo.due.nil? ? todo.show_from : todo.due + rt.toggle_completion! unless rt.has_next_todo(checkdate) + + return saved ? todo : nil + end + + def handle_unverified_request + unless request.format=="application/xml" + super # handle xml http auth via our own login code + end + end + + protected + + def admin_login_required + unless User.find_by_id_and_is_admin(session['user_id'], true) + render :text => t('errors.user_unauthorized'), :status => 401 + return false + end + end + + def redirect_back_or_home + respond_to do |format| + format.html { redirect_back_or_default home_url } + format.m { redirect_back_or_default mobile_url } + end + end + + def boolean_param(param_name) + return false if param_name.blank? + s = params[param_name] + 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 + + def self.openid_enabled? + Tracks::Config.openid_enabled? + end + + def openid_enabled? + self.class.openid_enabled? + end + + def self.cas_enabled? + Tracks::Config.cas_enabled? + end + + def cas_enabled? + self.class.cas_enabled? + end + + def self.prefered_auth? + Tracks::Config.prefered_auth? + end + + def prefered_auth? + self.class.prefered_auth? + end + + # all completed todos [today@00:00, today@now] + def get_done_today(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES}) + start_of_this_day = Time.zone.now.beginning_of_day + completed_todos.completed_after(start_of_this_day).all(includes) + end + + # all completed todos [begin_of_week, start_of_today] + def get_done_this_week(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES}) + start_of_this_week = Time.zone.now.beginning_of_week + start_of_this_day = Time.zone.now.beginning_of_day + completed_todos.completed_before(start_of_this_day).completed_after(start_of_this_week).all(includes) + end + + # all completed todos [begin_of_month, begin_of_week] + def get_done_this_month(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES}) + start_of_this_month = Time.zone.now.beginning_of_month + start_of_this_week = Time.zone.now.beginning_of_week + completed_todos.completed_before(start_of_this_week).completed_after(start_of_this_month).all(includes) + end + + private + + def parse_date_per_user_prefs( s ) + prefs.parse_date(s) + end + + def init_data_for_sidebar + @completed_projects = current_user.projects.completed + @hidden_projects = current_user.projects.hidden + @active_projects = current_user.projects.active + + @active_contexts = current_user.contexts.active + @hidden_contexts = current_user.contexts.hidden + + init_not_done_counts + if prefs.show_hidden_projects_in_sidebar + init_project_hidden_todo_counts(['project']) + end + end + + def init_not_done_counts(parents = ['project','context']) + parents.each do |parent| + eval("@#{parent}_not_done_counts = @#{parent}_not_done_counts || current_user.todos.active.count(:group => :#{parent}_id)") + end + end + + def init_project_hidden_todo_counts(parents = ['project','context']) + parents.each do |parent| + eval("@#{parent}_project_hidden_todo_counts = @#{parent}_project_hidden_todo_counts || current_user.todos.count(:conditions => ['state = ? or state = ?', 'project_hidden', 'active'], :group => :#{parent}_id)") + end + end + + # 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 + + def set_time_zone + Time.zone = current_user.prefs.time_zone if logged_in? + end + + def set_zindex_counter + # this counter can be used to handle the IE z-index bug + @z_index_counter = 500 + end + +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 183b4c31..915c9f8e 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,5 +1,3 @@ -# The methods added to this helper will be available to all templates in the -# application. module ApplicationHelper # Replicates the link_to method but also checks request.request_uri to find diff --git a/app/helpers/application_helper.rb.rails2 b/app/helpers/application_helper.rb.rails2 new file mode 100644 index 00000000..39c591e4 --- /dev/null +++ b/app/helpers/application_helper.rb.rails2 @@ -0,0 +1,301 @@ +# The methods added to this helper will be available to all templates in the +# application. +module ApplicationHelper + + # Replicates the link_to method but also checks request.request_uri to find + # current page. If that matches the url, the link is marked id = "current" + # + def navigation_link(name, options = {}, html_options = nil, *parameters_for_method_reference) + if html_options + html_options = html_options.stringify_keys + 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\"" : "" + + "#{name || url}" + end + + def days_from_today(date) + date.in_time_zone.to_date - current_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) + return "" if due.nil? + + days = days_from_today(due) + + colors = ['amber','amber','orange','orange','orange','orange','orange','orange'] + color = :red if days < 0 + color = :green if days > 7 + color = colors[days] if color.nil? + + return content_tag(:a, {:title => format_date(due)}) { + content_tag(:span, {:class => color}) { + case days + when 0 + t('todos.next_actions_due_date.due_today') + when 1 + t('todos.next_actions_due_date.due_tomorrow') + when 2..7 + if prefs.due_style == Preference.due_styles[:due_on] + # TODO: internationalize strftime here + t('models.preference.due_on', :date => due.strftime("%A")) + else + t('models.preference.due_in', :days => days) + end + else + # overdue or due very soon! sound the alarm! + if days == -1 + t('todos.next_actions_due_date.overdue_by', :days => days * -1) + elsif days < -1 + t('todos.next_actions_due_date.overdue_by_plural', :days => days * -1) + else + # more than a week away - relax + t('models.preference.due_in', :days => days) + end + end + } + } + end + + # Check due date in comparison to today's date Flag up date appropriately with + # 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 + when 0 + ""+ format_date(due) + "" + when 1 + "" + format_date(due) + "" + # due 2-7 days away + when 2..7 + "" + format_date(due) + "" + else + # overdue or due very soon! sound the alarm! + if days < 0 + "" + format_date(due) +"" + else + # more than a week away - relax + "" + format_date(due) + "" + end + 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(" "," ") + end + + def count_undone_todos_and_notes_phrase(project, string="actions") + s = count_undone_todos_phrase(project, string) + s += ", #{pluralize(project.note_count, 'note')}" unless project.note_count == 0 + s + end + + def link_to_context(context, descriptor = sanitize(context.name)) + link_to( descriptor, context, :title => "View context: #{context.name}" ) + end + + def link_to_project(project, descriptor = sanitize(project.name)) + link_to( descriptor, project, :title => "View project: #{project.name}" ) + end + + def link_to_edit_note (note, descriptor = sanitize(note.id.to_s)) + link_to(descriptor, + url_for({:controller => 'notes', :action => 'edit', :id => note.id}), + {:id => "link_edit_#{dom_id(note)}", :class => "note_edit_settings"}) + end + + def link_to_project_mobile(project, accesskey, descriptor = sanitize(project.name)) + link_to( descriptor, project_path(project, :format => 'm'), {:title => "View project: #{project.name}", :accesskey => accesskey} ) + end + + def item_link_to_context(item) + descriptor = "[C]" + descriptor = "[#{item.context.name}]" if prefs.verbose_action_descriptors + link_to_context( item.context, descriptor ) + end + + def item_link_to_project(item) + descriptor = "[P]" + descriptor = "[#{item.project.name}]" if prefs.verbose_action_descriptors + link_to_project( item.project, descriptor ) + end + + def render_flash + render :partial => 'shared/flash', :object => flash + end + + def recurrence_time_span(rt) + case rt.ends_on + when "no_end_date" + return rt.start_from.nil? ? "" : I18n.t("todos.recurrence.pattern.from") + " " + format_date(rt.start_from) + when "ends_on_number_of_times" + return I18n.t("todos.recurrence.pattern.times", :number => rt.number_of_occurences) + when "ends_on_end_date" + starts = rt.start_from.nil? ? "" : I18n.t("todos.recurrence.pattern.from") + " " + format_date(rt.start_from) + ends = rt.end_date.nil? ? "" : " " + I18n.t("todos.recurrence.pattern.until") + " " + format_date(rt.end_date) + return starts+ends + else + raise Exception.new, "unknown recurrence time span selection (#{rt.ends_on})" + end + end + + def recurrence_pattern_as_text(recurring_todo) + rt = recurring_todo.recurring_target_as_text + rp = recurring_todo.recurrence_pattern + # only add space if recurrence_pattern has content + rp = " " + rp if !rp.nil? + rts = recurrence_time_span(recurring_todo) + # only add space if recurrence_time_span has content + rts = " " + rts if !(rts == "") + return rt+rp+rts + end + + def date_format_for_date_picker() + standard_format = current_user.prefs.date_format + translations = [ + ['%m', 'mm'], + ['%b', 'M'], + ['%B', 'MM'], + ['%d', 'dd'], + ['%a', 'D'], + ['%A', 'DD'], + ['%y', 'y'], + ['%Y', 'yy'] + ] + translations.inject(standard_format) do |str, translation| + str.gsub(*translation) + end + end + + AUTO_LINK_MESSAGE_RE = %r{message://<[^>]+>} unless const_defined?(:AUTO_LINK_MESSAGE_RE) + + # Converts message:// links to href. This URL scheme is used on Mac OS X + # to link to a mail message in Mail.app. + def auto_link_message(text) + text.gsub(AUTO_LINK_MESSAGE_RE) do + href = $& + left, right = $`, $' + # detect already linked URLs and URLs in the middle of a tag + if left =~ /<[^>]+$/ && right =~ /^[^>]*>/ + # do not change string; URL is alreay linked + href + else + content = content_tag(:a, h(href), :href => h(href)) + end + end + end + + def format_note(note) + note = auto_link_message(note) + note = markdown(note) + note = auto_link(note, :link => :urls) + + # add onenote and message protocols + Sanitize::Config::RELAXED[:protocols]['a']['href'] << 'onenote' + Sanitize::Config::RELAXED[:protocols]['a']['href'] << 'message' + + note = Sanitize.clean(note, Sanitize::Config::RELAXED) + return note + end + + def sidebar_html_for_titled_list (list, title) + return content_tag(:h3, title+" (#{list.length})") + + content_tag(:ul, sidebar_html_for_list(list)) + end + + def sidebar_html_for_list(list) + if list.empty? + return content_tag(:li, t('sidebar.list_empty')) + else + return list.inject("") do |html, item| + link = (item.class == "Project") ? link_to_project( item ) : link_to_context(item) + html << content_tag(:li, link + " (" + count_undone_todos_phrase(item,"actions")+")") + end + end + end + + def generate_i18n_strings + js = "i18n_locale='#{I18n.locale}';\n" + js << "i18n = new Array();\n" + %w{ + shared.toggle_multi shared.toggle_multi_title + shared.hide_form shared.hide_action_form_title + shared.toggle_single shared.toggle_single_title + projects.hide_form projects.hide_form_title + projects.show_form projects.show_form_title + contexts.hide_form contexts.hide_form_title + contexts.show_form contexts.show_form_title + contexts.new_context_pre contexts.new_context_post + common.cancel common.ok + common.ajaxError todos.unresolved_dependency + }.each do |s| + js << "i18n['#{s}'] = '#{ t(s).gsub(/'/, "\\\\'") }';\n" + end + return js + end + + def javascript_tag_for_i18n_datepicker + locale = I18n.locale + # do not include en as locale since this the available by default + if locale and locale != :en + javascript_include_tag("i18n/jquery.ui.datepicker-#{locale}.js") + end + end + + def determine_done_path + case @controller.controller_name + when "contexts" + done_todos_context_path(@context) + when "projects" + done_todos_project_path(@project) + when "todos" + if source_view_is(:tag) + done_tag_path(@tag_name) + else + done_todos_path + end + else + done_todos_path + end + end + + def determine_all_done_path + case @controller.controller_name + when "contexts" + all_done_todos_context_path(@context) + when "projects" + all_done_todos_project_path(@project) + when "todos" + if source_view_is(:tag) + all_done_tag_path(@tag_name) + else + all_done_todos_path + end + else + all_done_todos_path + end + end + +end diff --git a/app/mailers/.gitkeep b/app/mailers/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/app/models/.gitkeep b/app/models/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb new file mode 100644 index 00000000..d29802cd --- /dev/null +++ b/app/views/layouts/application.html.erb @@ -0,0 +1,14 @@ + + + + Tracksapp + <%= stylesheet_link_tag "application", :media => "all" %> + <%= javascript_include_tag "application" %> + <%= csrf_meta_tags %> + + + +<%= yield %> + + + diff --git a/config.ru b/config.ru new file mode 100644 index 00000000..7ed77ad6 --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +# This file is used by Rack-based servers to start the application. + +require ::File.expand_path('../config/environment', __FILE__) +run Tracksapp::Application diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 00000000..9455b87e --- /dev/null +++ b/config/application.rb @@ -0,0 +1,59 @@ +require File.expand_path('../boot', __FILE__) + +require 'rails/all' + +if defined?(Bundler) + # If you precompile assets before deploying to production, use this line + Bundler.require(*Rails.groups(:assets => %w(development test))) + # If you want your assets lazily compiled in production, use this line + # Bundler.require(:default, :assets, Rails.env) +end + +module Tracksapp + class Application < Rails::Application + # Settings in config/environments/* take precedence over those specified here. + # Application configuration should go into files in config/initializers + # -- all .rb files in that directory are automatically loaded. + + # Custom directories with classes and modules you want to be autoloadable. + # config.autoload_paths += %W(#{config.root}/extras) + + # Only load the plugins named here, in the order given (default is alphabetical). + # :all can be used as a placeholder for all plugins not explicitly named. + # config.plugins = [ :exception_notification, :ssl_requirement, :all ] + + # Activate observers that should always be running. + # config.active_record.observers = :cacher, :garbage_collector, :forum_observer + + # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. + # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. + # config.time_zone = 'Central Time (US & Canada)' + + # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. + # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] + # config.i18n.default_locale = :de + + # Configure the default encoding used in templates for Ruby 1.9. + config.encoding = "utf-8" + + # Configure sensitive parameters which will be filtered from the log file. + config.filter_parameters += [:password] + + # Use SQL instead of Active Record's schema dumper when creating the database. + # This is necessary if your schema can't be completely dumped by the schema dumper, + # like if you have constraints or database-specific column types + # config.active_record.schema_format = :sql + + # Enforce whitelist mode for mass assignment. + # This will create an empty whitelist of attributes available for mass-assignment for all models + # in your app. As such, your models will need to explicitly whitelist or blacklist accessible + # parameters by using an attr_accessible or attr_protected declaration. + config.active_record.whitelist_attributes = true + + # Enable the asset pipeline + config.assets.enabled = true + + # Version of your assets, change this if you want to expire all your assets + config.assets.version = '1.0' + end +end diff --git a/config/boot.rb b/config/boot.rb index 57528ecc..4489e586 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,128 +1,6 @@ -# Don't change this file! -# Configure your app in config/environment.rb and config/environments/*.rb +require 'rubygems' -RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT) +# Set up gems listed in the Gemfile. +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) -module Rails - class << self - def boot! - unless booted? - preinitialize - pick_boot.run - end - end - - def booted? - defined? Rails::Initializer - end - - def pick_boot - (vendor_rails? ? VendorBoot : GemBoot).new - end - - def vendor_rails? - File.exist?("#{RAILS_ROOT}/vendor/rails") - end - - def preinitialize - load(preinitializer_path) if File.exist?(preinitializer_path) - end - - def preinitializer_path - "#{RAILS_ROOT}/config/preinitializer.rb" - end - end - - class Boot - def run - load_initializer - Rails::Initializer.run(:set_load_path) - end - end - - class VendorBoot < Boot - def load_initializer - require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer" - Rails::Initializer.run(:install_gem_spec_stubs) - Rails::GemDependency.add_frozen_gem_path - end - end - - class GemBoot < Boot - def load_initializer - self.class.load_rubygems - load_rails_gem - require 'initializer' - end - - def load_rails_gem - if version = self.class.gem_version - gem 'rails', version - else - gem 'rails' - end - rescue Gem::LoadError => load_error - if load_error.message =~ /Could not find RubyGem rails/ - STDERR.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.) - exit 1 - else - raise - end - end - - class << self - def rubygems_version - Gem::RubyGemsVersion rescue nil - end - - def gem_version - if defined? RAILS_GEM_VERSION - RAILS_GEM_VERSION - elsif ENV.include?('RAILS_GEM_VERSION') - ENV['RAILS_GEM_VERSION'] - else - parse_gem_version(read_environment_rb) - end - end - - def load_rubygems - min_version = '1.3.2' - require 'rubygems' - unless rubygems_version >= min_version - $stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.) - exit 1 - end - - rescue LoadError - $stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org) - exit 1 - end - - def parse_gem_version(text) - $1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/ - end - - private - def read_environment_rb - File.read("#{RAILS_ROOT}/config/environment.rb") - end - end - end -end - -class Rails::Boot - def run - load_initializer - - Rails::Initializer.class_eval do - def load_gems - @bundler_loaded ||= Bundler.require :default, Rails.env - end - end - - Rails::Initializer.run(:set_load_path) - end -end - -# All that for this: -Rails.boot! +require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) diff --git a/config/database.yml.rails2 b/config/database.yml.rails2 new file mode 100644 index 00000000..da7aebc8 --- /dev/null +++ b/config/database.yml.rails2 @@ -0,0 +1,37 @@ +# MySQL. Versions 4.1 and 5.0 are recommended. +# +# +# Be sure to use new-style password hashing: +# http://dev.mysql.com/doc/refman/5.0/en/old-client.html +development: + adapter: mysql + database: tracks_trunk + encoding: utf8 + host: localhost + username: tracks + password: 32tracks55 + +mdevelopment: + adapter: sqlite3 + database: db/tracks-21-test.sqlite3.db + +test: &TEST +# adapter: sqlite3 +# database: ":memory:" +# verbosity: quiet + adapter: mysql + database: tracks_test + host: localhost + username: tracks + password: 32tracks55 + +production: + adapter: mysql + database: tracks_trunk + encoding: utf8 + host: localhost + username: tracks + password: 32tracks55 + +cucumber: + <<: *TEST diff --git a/config/environment.rb b/config/environment.rb index fcb6fed8..8e8e1fdb 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,118 +1,5 @@ -# Be sure to restart your webserver when you modify this file. -# Uncomment below to force Rails into production mode +# Load the rails application +require File.expand_path('../application', __FILE__) -# (Use only when you can't set environment variables through your web/app server) -# ENV['RAILS_ENV'] = 'production' - -# Bootstrap the Rails environment, frameworks, and default configuration -require File.join(File.dirname(__FILE__), 'boot') - -require 'yaml' -SITE_CONFIG = YAML.load_file(File.join(File.dirname(__FILE__), 'site.yml')) - -class Rails::Configuration - attr_accessor :action_web_service -end - -Encoding.default_external = Encoding::UTF_8 if RUBY_VERSION > "1.9" - -Rails::Initializer.run do |config| - # Skip frameworks you're not going to use - # config.frameworks -= [ :action_web_service, :action_mailer ] - config.autoload_paths += %W( #{RAILS_ROOT}/app/apis ) - - config.action_controller.use_accept_header = true - - # Use the database for sessions instead of the file system - # (create the session table with 'rake create_sessions_table') - config.action_controller.session_store = :active_record_store - - config.action_controller.session = { - :key => '_tracks_session_id', - :secret => SITE_CONFIG['salt'] * (30.0 / SITE_CONFIG['salt'].length).ceil #must be at least 30 characters - } - - config.action_controller.relative_url_root = SITE_CONFIG['subdir'] if SITE_CONFIG['subdir'] - - # Enable page/fragment caching by setting a file-based store - # (remember to create the caching directory and make it readable to the application) - # config.action_controller.fragment_cache_store = :file_store, "#{RAILS_ROOT}/cache" - - # Activate observers that should always be running - # config.active_record.observers = :cacher, :garbage_collector - - # Make Active Record use UTC-base instead of local time - config.active_record.default_timezone = :utc - - # You''ll probably want to change this to the time zone of the computer where Tracks is running - # run rake time:zones:local have Rails suggest time zone names on your system - config.time_zone = SITE_CONFIG['time_zone'] - - # Use Active Record's schema dumper instead of SQL when creating the test database - # (enables use of different database adapters for development and test environments) - config.active_record.schema_format = :ruby - - # allow other protocols in urls for sanitzer. Add to your liking, for example - # config.action_view.sanitized_allowed_protocols = 'onenote', 'blah', 'proto' - # to enable "link":onenote://... or "link":blah://... hyperlinks - config.action_view.sanitized_allowed_protocols = 'onenote', 'message' - - # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. - # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] - # config.i18n.default_locale = :de - -end - -# Add new inflection rules using the following format -# (all these examples are active by default): -# Inflector.inflections do |inflect| -# inflect.plural /^(ox)$/i, '\1en' -# inflect.singular /^(ox)en/i, '\1' -# inflect.irregular 'person', 'people' -# inflect.uncountable %w( fish sheep ) -# end - -# Include your application configuration below - - -require 'name_part_finder' -require 'tracks/todo_list' -require 'tracks/config' -require 'digest/sha1' #Needed to support 'rake db:fixtures:load' on some ruby installs: http://dev.rousette.org.uk/ticket/557 - -if ( SITE_CONFIG['authentication_schemes'].include? 'ldap') - require 'net/ldap' #requires ruby-net-ldap gem be installed - require 'simple_ldap_authenticator' - ldap = SITE_CONFIG['ldap'] - SimpleLdapAuthenticator.ldap_library = ldap['library'] - SimpleLdapAuthenticator.servers = ldap['servers'] - SimpleLdapAuthenticator.use_ssl = ldap['ssl'] - SimpleLdapAuthenticator.login_format = ldap['login_format'] -end - -if ( SITE_CONFIG['authentication_schemes'].include? 'open_id') - #requires ruby-openid gem to be installed - OpenID::Util.logger = RAILS_DEFAULT_LOGGER -end - -if ( SITE_CONFIG['authentication_schemes'].include? 'cas') - #requires rubycas-client gem to be installed - if defined? CASClient - require 'casclient/frameworks/rails/filter' - CASClient::Frameworks::Rails::Filter.configure( - :cas_base_url => SITE_CONFIG['cas_server'] , - :cas_server_logout => SITE_CONFIG['cas_server_logout'] - ) - end -end - -# changed in development.rb to show under_construction bar -NOTIFY_BAR = "" unless defined?(NOTIFY_BAR) - -tracks_version='2.2devel' -# comment out next two lines if you do not want (or can not) the date of the -# last git commit in the footer -info=`git log --pretty=format:"%ai" -1` -tracks_version=tracks_version + ' ('+info+')' - -TRACKS_VERSION=tracks_version +# Initialize the rails application +Tracksapp::Application.initialize! diff --git a/config/environment.rb.rails2 b/config/environment.rb.rails2 new file mode 100644 index 00000000..390f585b --- /dev/null +++ b/config/environment.rb.rails2 @@ -0,0 +1,119 @@ +# Be sure to restart your webserver when you modify this file. +# Uncomment below to force Rails into production mode + +# (Use only when you can't set environment variables through your web/app server) +# ENV['RAILS_ENV'] = 'production' + +# Bootstrap the Rails environment, frameworks, and default configuration +require File.join(File.dirname(__FILE__), 'boot') + +require 'yaml' +SITE_CONFIG = YAML.load_file(File.join(File.dirname(__FILE__), 'site.yml')) + +class Rails::Configuration + attr_accessor :action_web_service +end + +Encoding.default_external = Encoding::UTF_8 if RUBY_VERSION > "1.9" + +Rails::Initializer.run do |config| + # Skip frameworks you're not going to use + # config.frameworks -= [ :action_web_service, :action_mailer ] + config.autoload_paths += %W( #{RAILS_ROOT}/app/apis ) + + config.action_controller.use_accept_header = true + + # Use the database for sessions instead of the file system + # (create the session table with 'rake create_sessions_table') + config.action_controller.session_store = :active_record_store + + config.action_controller.session = { + :key => '_tracks_session_id', + :secret => SITE_CONFIG['salt'] * (30.0 / SITE_CONFIG['salt'].length).ceil #must be at least 30 characters + } + + config.action_controller.relative_url_root = SITE_CONFIG['subdir'] if SITE_CONFIG['subdir'] + + # Enable page/fragment caching by setting a file-based store + # (remember to create the caching directory and make it readable to the application) + # config.action_controller.fragment_cache_store = :file_store, "#{RAILS_ROOT}/cache" + + # Activate observers that should always be running + # config.active_record.observers = :cacher, :garbage_collector + + # Make Active Record use UTC-base instead of local time + config.active_record.default_timezone = :utc + + # You''ll probably want to change this to the time zone of the computer where Tracks is running + # run rake time:zones:local have Rails suggest time zone names on your system + config.time_zone = SITE_CONFIG['time_zone'] + + # Use Active Record's schema dumper instead of SQL when creating the test database + # (enables use of different database adapters for development and test environments) + config.active_record.schema_format = :ruby + + # allow other protocols in urls for sanitzer. Add to your liking, for example + # config.action_view.sanitized_allowed_protocols = 'onenote', 'blah', 'proto' + # to enable "link":onenote://... or "link":blah://... hyperlinks + config.action_view.sanitized_allowed_protocols = 'onenote', 'message' + + # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. + # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] + # config.i18n.default_locale = :de + +end + +# Add new inflection rules using the following format +# (all these examples are active by default): +# Inflector.inflections do |inflect| +# inflect.plural /^(ox)$/i, '\1en' +# inflect.singular /^(ox)en/i, '\1' +# inflect.irregular 'person', 'people' +# inflect.uncountable %w( fish sheep ) +# end + +# Include your application configuration below + + +require 'name_part_finder' +require 'tracks/todo_list' +require 'tracks/config' +require 'tagging_extensions' # Needed for tagging-specific extensions +require 'digest/sha1' #Needed to support 'rake db:fixtures:load' on some ruby installs: http://dev.rousette.org.uk/ticket/557 + +if ( SITE_CONFIG['authentication_schemes'].include? 'ldap') + require 'net/ldap' #requires ruby-net-ldap gem be installed + require 'simple_ldap_authenticator' + ldap = SITE_CONFIG['ldap'] + SimpleLdapAuthenticator.ldap_library = ldap['library'] + SimpleLdapAuthenticator.servers = ldap['servers'] + SimpleLdapAuthenticator.use_ssl = ldap['ssl'] + SimpleLdapAuthenticator.login_format = ldap['login_format'] +end + +if ( SITE_CONFIG['authentication_schemes'].include? 'open_id') + #requires ruby-openid gem to be installed + OpenID::Util.logger = RAILS_DEFAULT_LOGGER +end + +if ( SITE_CONFIG['authentication_schemes'].include? 'cas') + #requires rubycas-client gem to be installed + if defined? CASClient + require 'casclient/frameworks/rails/filter' + CASClient::Frameworks::Rails::Filter.configure( + :cas_base_url => SITE_CONFIG['cas_server'] , + :cas_server_logout => SITE_CONFIG['cas_server_logout'] + ) + end +end + +# changed in development.rb to show under_construction bar +NOTIFY_BAR = "" unless defined?(NOTIFY_BAR) + +tracks_version='2.2devel' +# comment out next two lines if you do not want (or can not) the date of the +# last git commit in the footer +info=`git log --pretty=format:"%ai" -1` +tracks_version=tracks_version + ' ('+info+')' + +TRACKS_VERSION=tracks_version diff --git a/config/environments/development.rb b/config/environments/development.rb index 05c880d7..8a835a34 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,19 +1,37 @@ -# In the development environment your application's code is reloaded on -# every request. This slows down response time but is perfect for development -# since you don't have to restart the webserver when you make code changes. -config.cache_classes = false +Tracksapp::Application.configure do + # Settings specified here will take precedence over those in config/application.rb -# Log error messages when you accidentally call methods on nil. -config.whiny_nils = true + # In the development environment your application's code is reloaded on + # every request. This slows down response time but is perfect for development + # since you don't have to restart the web server when you make code changes. + config.cache_classes = false -# Show full error reports and disable caching -config.action_controller.consider_all_requests_local = true -config.action_controller.perform_caching = false + # Log error messages when you accidentally call methods on nil. + config.whiny_nils = true -# Don't care if the mailer can't send -config.action_mailer.raise_delivery_errors = false + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_controller.perform_caching = false -# Unique cookies -config.action_controller.session = { :key => 'TracksDev' } + # Don't care if the mailer can't send + config.action_mailer.raise_delivery_errors = false -NOTIFY_BAR="
         
        " + # Print deprecation notices to the Rails logger + config.active_support.deprecation = :log + + # Only use best-standards-support built into browsers + config.action_dispatch.best_standards_support = :builtin + + # Raise exception on mass assignment protection for Active Record models + config.active_record.mass_assignment_sanitizer = :strict + + # Log the query plan for queries taking more than this (works + # with SQLite, MySQL, and PostgreSQL) + config.active_record.auto_explain_threshold_in_seconds = 0.5 + + # Do not compress assets + config.assets.compress = false + + # Expands the lines which load the assets + config.assets.debug = true +end diff --git a/config/environments/development.rb.rails2 b/config/environments/development.rb.rails2 new file mode 100644 index 00000000..05c880d7 --- /dev/null +++ b/config/environments/development.rb.rails2 @@ -0,0 +1,19 @@ +# In the development environment your application's code is reloaded on +# every request. This slows down response time but is perfect for development +# since you don't have to restart the webserver when you make code changes. +config.cache_classes = false + +# Log error messages when you accidentally call methods on nil. +config.whiny_nils = true + +# Show full error reports and disable caching +config.action_controller.consider_all_requests_local = true +config.action_controller.perform_caching = false + +# Don't care if the mailer can't send +config.action_mailer.raise_delivery_errors = false + +# Unique cookies +config.action_controller.session = { :key => 'TracksDev' } + +NOTIFY_BAR="
         
        " diff --git a/config/environments/production.rb b/config/environments/production.rb index 56470f47..e43b1775 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -1,17 +1,67 @@ -# The production environment is meant for finished, "live" apps. -# Code is not reloaded between requests -config.cache_classes = true +Tracksapp::Application.configure do + # Settings specified here will take precedence over those in config/application.rb -# Use a different logger for distributed setups -# config.logger = SyslogLogger.new + # Code is not reloaded between requests + config.cache_classes = true + # Full error reports are disabled and caching is turned on + config.consider_all_requests_local = false + config.action_controller.perform_caching = true -# Full error reports are disabled and caching is turned on -config.action_controller.consider_all_requests_local = false -config.action_controller.perform_caching = true + # Disable Rails's static asset server (Apache or nginx will already do this) + config.serve_static_assets = false -# Enable serving of images, stylesheets, and javascripts from an asset server -# config.action_controller.asset_host = "http://assets.example.com" + # Compress JavaScripts and CSS + config.assets.compress = true -# Disable delivery errors if you bad email addresses should just be ignored -# config.action_mailer.raise_delivery_errors = false \ No newline at end of file + # Don't fallback to assets pipeline if a precompiled asset is missed + config.assets.compile = false + + # Generate digests for assets URLs + config.assets.digest = true + + # Defaults to Rails.root.join("public/assets") + # config.assets.manifest = YOUR_PATH + + # Specifies the header that your server uses for sending files + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # See everything in the log (default is :info) + # config.log_level = :debug + + # Prepend all log lines with the following tags + # config.log_tags = [ :subdomain, :uuid ] + + # Use a different logger for distributed setups + # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) + + # Use a different cache store in production + # config.cache_store = :mem_cache_store + + # Enable serving of images, stylesheets, and JavaScripts from an asset server + # config.action_controller.asset_host = "http://assets.example.com" + + # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) + # config.assets.precompile += %w( search.js ) + + # Disable delivery errors, bad email addresses will be ignored + # config.action_mailer.raise_delivery_errors = false + + # Enable threaded mode + # config.threadsafe! + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation can not be found) + config.i18n.fallbacks = true + + # Send deprecation notices to registered listeners + config.active_support.deprecation = :notify + + # Log the query plan for queries taking more than this (works + # with SQLite, MySQL, and PostgreSQL) + # config.active_record.auto_explain_threshold_in_seconds = 0.5 +end diff --git a/config/environments/production.rb.rails2 b/config/environments/production.rb.rails2 new file mode 100644 index 00000000..56470f47 --- /dev/null +++ b/config/environments/production.rb.rails2 @@ -0,0 +1,17 @@ +# The production environment is meant for finished, "live" apps. +# Code is not reloaded between requests +config.cache_classes = true + +# Use a different logger for distributed setups +# config.logger = SyslogLogger.new + + +# Full error reports are disabled and caching is turned on +config.action_controller.consider_all_requests_local = false +config.action_controller.perform_caching = true + +# Enable serving of images, stylesheets, and javascripts from an asset server +# config.action_controller.asset_host = "http://assets.example.com" + +# Disable delivery errors if you bad email addresses should just be ignored +# config.action_mailer.raise_delivery_errors = false \ No newline at end of file diff --git a/config/environments/test.rb b/config/environments/test.rb index 2b031cb9..76646cb2 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -1,33 +1,37 @@ -# The test environment is used exclusively to run your application's -# test suite. You never need to work with it otherwise. Remember that -# your test database is "scratch space" for the test suite and is wiped -# and recreated between test runs. Don't rely on the data there! -config.cache_classes = true +Tracksapp::Application.configure do + # Settings specified here will take precedence over those in config/application.rb -# Log error messages when you accidentally call methods on nil. -config.whiny_nils = true + # The test environment is used exclusively to run your application's + # test suite. You never need to work with it otherwise. Remember that + # your test database is "scratch space" for the test suite and is wiped + # and recreated between test runs. Don't rely on the data there! + config.cache_classes = true -# Show full error reports and disable caching -config.action_controller.consider_all_requests_local = true -config.action_controller.perform_caching = false + # Configure static asset server for tests with Cache-Control for performance + config.serve_static_assets = true + config.static_cache_control = "public, max-age=3600" -# Tell ActionMailer not to deliver emails to the real world. -# The :test delivery method accumulates sent emails in the -# ActionMailer::Base.deliveries array. -config.action_mailer.delivery_method = :test + # Log error messages when you accidentally call methods on nil + config.whiny_nils = true -# Disable request forgery protection in test environment -config.action_controller.allow_forgery_protection = false + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_controller.perform_caching = false -# Unique cookies and use cookies for session -config.action_controller.session_store = :cookie_store -config.action_controller.session = { :key => 'TracksTest', :secret => SITE_CONFIG['salt'] * (30.0 / SITE_CONFIG['salt'].length).ceil } + # Raise exceptions instead of rendering exception templates + config.action_dispatch.show_exceptions = false -# Overwrite the default settings for fixtures in tests. See Fixtures -# for more details about these settings. -# config.transactional_fixtures = true -# config.instantiated_fixtures = false -# config.pre_loaded_fixtures = false -SITE_CONFIG['salt'] ||= 'change-me' + # Disable request forgery protection in test environment + config.action_controller.allow_forgery_protection = false -config.time_zone = 'UTC' + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Raise exception on mass assignment protection for Active Record models + config.active_record.mass_assignment_sanitizer = :strict + + # Print deprecation notices to the stderr + config.active_support.deprecation = :stderr +end diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb index c2169ed0..59385cdf 100644 --- a/config/initializers/backtrace_silencers.rb +++ b/config/initializers/backtrace_silencers.rb @@ -3,5 +3,5 @@ # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } -# You can also remove all the silencers if you're trying do debug a problem that might steem from framework code. -# Rails.backtrace_cleaner.remove_silencers! \ No newline at end of file +# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. +# Rails.backtrace_cleaner.remove_silencers! diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index d531b8bb..5d8d9be2 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -1,6 +1,6 @@ # Be sure to restart your server when you modify this file. -# Add new inflection rules using the following format +# Add new inflection rules using the following format # (all these examples are active by default): # ActiveSupport::Inflector.inflections do |inflect| # inflect.plural /^(ox)$/i, '\1en' @@ -8,3 +8,8 @@ # inflect.irregular 'person', 'people' # inflect.uncountable %w( fish sheep ) # end +# +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections do |inflect| +# inflect.acronym 'RESTful' +# end diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb index 9b1d568c..da62ea3e 100644 --- a/config/initializers/mime_types.rb +++ b/config/initializers/mime_types.rb @@ -1,5 +1,8 @@ +# Be sure to restart your server when you modify this file. + # Add new mime types for use in respond_to blocks: # Mime::Type.register "text/richtext", :rtf -# Mime::Type.register "application/x-mobile", :mobile +# Mime::Type.register_alias "text/html", :iphone + Mime::Type.register_alias "text/html", :m Mime::Type.register_alias "text/plain", :autocomplete diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb new file mode 100644 index 00000000..40e49e58 --- /dev/null +++ b/config/initializers/secret_token.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# Your secret key for verifying the integrity of signed cookies. +# If you change this key, all old signed cookies will become invalid! +# Make sure the secret is at least 30 characters and all random, +# no regular words or you'll be exposed to dictionary attacks. +Tracksapp::Application.config.secret_token = '978c88b98f3b7885b2e88a831545bd3c5d80d0f528b32096dafa7dc9010b2180e2391c059c5347a244709a2257e3d13f0841fbdc56e8052af3c3396916b5805b' diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb new file mode 100644 index 00000000..deb11eee --- /dev/null +++ b/config/initializers/session_store.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +Tracksapp::Application.config.session_store :cookie_store, key: '_tracksapp_session' + +# Use the database for sessions instead of the cookie-based default, +# which shouldn't be used to store highly confidential information +# (create the session table with "rails generate session_migration") +# Tracksapp::Application.config.session_store :active_record_store diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb new file mode 100644 index 00000000..999df201 --- /dev/null +++ b/config/initializers/wrap_parameters.rb @@ -0,0 +1,14 @@ +# Be sure to restart your server when you modify this file. +# +# This file contains settings for ActionController::ParamsWrapper which +# is enabled by default. + +# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. +ActiveSupport.on_load(:action_controller) do + wrap_parameters format: [:json] +end + +# Disable root element in JSON by default. +ActiveSupport.on_load(:active_record) do + self.include_root_in_json = false +end diff --git a/config/routes.rb b/config/routes.rb index ec0ed738..2d76d3dd 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,113 +1,58 @@ -ActionController::Routing::Routes.draw do |map| - map.resources :users, - :member => {:change_password => :get, :update_password => :post, - :change_auth_type => :get, :update_auth_type => :post, :complete => :get, - :refresh_token => :post } +Tracksapp::Application.routes.draw do + # The priority is based upon order of creation: + # first created -> highest priority. - map.with_options :controller => :users do |users| - users.signup 'signup', :action => "new" - end + # Sample of regular route: + # match 'products/:id' => 'catalog#view' + # Keep in mind you can assign values other than :controller and :action - map.resources :contexts, :collection => {:order => :post, :done => :get}, :member => {:done_todos => :get, :all_done_todos => :get} do |contexts| - contexts.resources :todos, :name_prefix => "context_" - end + # Sample of named route: + # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase + # This route can be invoked with purchase_url(:id => product.id) - map.resources :projects, - :collection => {:order => :post, :alphabetize => :post, :actionize => :post, :done => :get}, - :member => {:done_todos => :get, :all_done_todos => :get, :set_reviewed => :get} do |projects| - projects.resources :todos, :name_prefix => "project_" - end + # Sample resource route (maps HTTP verbs to controller actions automatically): + # resources :products - map.with_options :controller => :projects do |projects| - projects.review 'review', :action => :review - end + # Sample resource route with options: + # resources :products do + # member do + # get 'short' + # post 'toggle' + # end + # + # collection do + # get 'sold' + # end + # end - map.resources :notes + # Sample resource route with sub-resources: + # resources :products do + # resources :comments, :sales + # resource :seller + # end - map.resources :todos, - :member => {:toggle_check => :put, :toggle_star => :put, :defer => :put}, - :collection => {:check_deferred => :post, :filter_to_context => :post, :filter_to_project => :post, :done => :get, :all_done => :get - } + # Sample resource route with more complex sub-resources + # resources :products do + # resources :comments + # resources :sales do + # get 'recent', :on => :collection + # end + # end - map.with_options :controller => :todos do |todos| - todos.home '', :action => "index" - todos.tickler 'tickler.:format', :action => "list_deferred" - todos.mobile_tickler 'tickler.m', :action => "list_deferred", :format => 'm' + # Sample resource route within a namespace: + # namespace :admin do + # # Directs /admin/products/* to Admin::ProductsController + # # (app/controllers/admin/products_controller.rb) + # resources :products + # end - # This route works for tags with dots like /todos/tag/version1.5 - # please note that this pattern consumes everything after /todos/tag - # so /todos/tag/version1.5.xml will result in :name => 'version1.5.xml' - # UPDATE: added support for mobile view. All tags ending on .m will be - # routed to mobile view of tags. - todos.mobile_tag 'todos/tag/:name.m', :action => "tag", :format => 'm' - todos.text_tag 'todos/tag/:name.txt', :action => "tag", :format => 'txt' - todos.tag 'todos/tag/:name', :action => "tag", :name => /.*/ - todos.done_tag 'todos/done/tag/:name', :action => "done_tag" - todos.all_done_tag 'todos/all_done/tag/:name', :action => "all_done_tag" + # You can have the root of your site routed with "root" + # just remember to delete public/index.html. + # root :to => 'welcome#index' - todos.tags 'tags.autocomplete', :action => "tags", :format => 'autocomplete' - todos.auto_complete_for_predecessor 'auto_complete_for_predecessor', :action => 'auto_complete_for_predecessor' - - todos.calendar 'calendar.ics', :action => "calendar", :format => 'ics' - todos.calendar 'calendar.xml', :action => "calendar", :format => 'xml' - todos.calendar 'calendar', :action => "calendar" - - todos.hidden 'hidden.xml', :action => "list_hidden", :format => 'xml' - - todos.mobile 'mobile', :action => "index", :format => 'm' - todos.mobile_abbrev 'm', :action => "index", :format => 'm' - todos.mobile_abbrev_new 'm/new', :action => "new", :format => 'm' - - todos.mobile_todo_show_notes 'todos/notes/:id.m', :action => "show_notes", :format => 'm' - todos.todo_show_notes 'todos/notes/:id', :action => "show_notes" - todos.done_todos 'todos/done', :action => :done - todos.all_done_todos 'todos/all_done', :action => :all_done - end - map.root :controller => 'todos' # Make OpenID happy because it needs #root_url defined - - map.resources :recurring_todos, :collection => {:done => :get}, - :member => {:toggle_check => :put, :toggle_star => :put} - map.with_options :controller => :recurring_todos do |rt| - rt.recurring_todos 'recurring_todos', :action => 'index' - end - - map.with_options :controller => :login do |login| - login.login 'login', :action => 'login' - login.login_cas 'login_cas', :action => 'login_cas' - login.formatted_login 'login.:format', :action => 'login' - login.logout 'logout', :action => 'logout' - login.formatted_logout 'logout.:format', :action => 'logout' - end - - map.with_options :controller => :feedlist do |fl| - fl.mobile_feeds 'feeds.m', :action => 'index', :format => 'm' - fl.feeds 'feeds', :action => 'index' - end - - map.with_options :controller => :integrations do |i| - i.integrations 'integrations', :action => 'index' - i.rest_api_docs 'integrations/rest_api', :action => "rest_api" - i.search_plugin 'integrations/search_plugin.xml', :action => 'search_plugin', :format => 'xml' - i.google_gadget 'integrations/google_gadget.xml', :action => 'google_gadget', :format => 'xml' - i.cloudmailin 'integrations/cloudmailin', :action => 'cloudmailin' - end - - map.with_options :controller => :preferences do |p| - p.preferences 'preferences', :action => 'index' - p.preferences_date_format 'preferences/render_date_format', :action => 'render_date_format' - end - - map.with_options :controller => :stats do |stats| - stats.stats 'stats', :action => 'index' - stats.done_overview 'done', :action => 'done' - end - - map.search 'search', :controller => 'search', :action => 'index' - map.data 'data', :controller => 'data', :action => 'index' - - Translate::Routes.translation_ui(map) if Rails.env != "production" - - # Install the default route as the lowest priority. - map.connect ':controller/:action/:id' + # See how all your routes lay out with "rake routes" + # This is a legacy wild controller route that's not recommended for RESTful applications. + # Note: This route will make all actions in every controller accessible via GET requests. + # match ':controller(/:action(/:id))(.:format)' end diff --git a/config/routes.rb.rails2 b/config/routes.rb.rails2 new file mode 100644 index 00000000..ec0ed738 --- /dev/null +++ b/config/routes.rb.rails2 @@ -0,0 +1,113 @@ +ActionController::Routing::Routes.draw do |map| + map.resources :users, + :member => {:change_password => :get, :update_password => :post, + :change_auth_type => :get, :update_auth_type => :post, :complete => :get, + :refresh_token => :post } + + map.with_options :controller => :users do |users| + users.signup 'signup', :action => "new" + end + + map.resources :contexts, :collection => {:order => :post, :done => :get}, :member => {:done_todos => :get, :all_done_todos => :get} do |contexts| + contexts.resources :todos, :name_prefix => "context_" + end + + map.resources :projects, + :collection => {:order => :post, :alphabetize => :post, :actionize => :post, :done => :get}, + :member => {:done_todos => :get, :all_done_todos => :get, :set_reviewed => :get} do |projects| + projects.resources :todos, :name_prefix => "project_" + end + + map.with_options :controller => :projects do |projects| + projects.review 'review', :action => :review + end + + map.resources :notes + + map.resources :todos, + :member => {:toggle_check => :put, :toggle_star => :put, :defer => :put}, + :collection => {:check_deferred => :post, :filter_to_context => :post, :filter_to_project => :post, :done => :get, :all_done => :get + } + + map.with_options :controller => :todos do |todos| + todos.home '', :action => "index" + todos.tickler 'tickler.:format', :action => "list_deferred" + todos.mobile_tickler 'tickler.m', :action => "list_deferred", :format => 'm' + + # This route works for tags with dots like /todos/tag/version1.5 + # please note that this pattern consumes everything after /todos/tag + # so /todos/tag/version1.5.xml will result in :name => 'version1.5.xml' + # UPDATE: added support for mobile view. All tags ending on .m will be + # routed to mobile view of tags. + todos.mobile_tag 'todos/tag/:name.m', :action => "tag", :format => 'm' + todos.text_tag 'todos/tag/:name.txt', :action => "tag", :format => 'txt' + todos.tag 'todos/tag/:name', :action => "tag", :name => /.*/ + todos.done_tag 'todos/done/tag/:name', :action => "done_tag" + todos.all_done_tag 'todos/all_done/tag/:name', :action => "all_done_tag" + + todos.tags 'tags.autocomplete', :action => "tags", :format => 'autocomplete' + todos.auto_complete_for_predecessor 'auto_complete_for_predecessor', :action => 'auto_complete_for_predecessor' + + todos.calendar 'calendar.ics', :action => "calendar", :format => 'ics' + todos.calendar 'calendar.xml', :action => "calendar", :format => 'xml' + todos.calendar 'calendar', :action => "calendar" + + todos.hidden 'hidden.xml', :action => "list_hidden", :format => 'xml' + + todos.mobile 'mobile', :action => "index", :format => 'm' + todos.mobile_abbrev 'm', :action => "index", :format => 'm' + todos.mobile_abbrev_new 'm/new', :action => "new", :format => 'm' + + todos.mobile_todo_show_notes 'todos/notes/:id.m', :action => "show_notes", :format => 'm' + todos.todo_show_notes 'todos/notes/:id', :action => "show_notes" + todos.done_todos 'todos/done', :action => :done + todos.all_done_todos 'todos/all_done', :action => :all_done + end + map.root :controller => 'todos' # Make OpenID happy because it needs #root_url defined + + map.resources :recurring_todos, :collection => {:done => :get}, + :member => {:toggle_check => :put, :toggle_star => :put} + map.with_options :controller => :recurring_todos do |rt| + rt.recurring_todos 'recurring_todos', :action => 'index' + end + + map.with_options :controller => :login do |login| + login.login 'login', :action => 'login' + login.login_cas 'login_cas', :action => 'login_cas' + login.formatted_login 'login.:format', :action => 'login' + login.logout 'logout', :action => 'logout' + login.formatted_logout 'logout.:format', :action => 'logout' + end + + map.with_options :controller => :feedlist do |fl| + fl.mobile_feeds 'feeds.m', :action => 'index', :format => 'm' + fl.feeds 'feeds', :action => 'index' + end + + map.with_options :controller => :integrations do |i| + i.integrations 'integrations', :action => 'index' + i.rest_api_docs 'integrations/rest_api', :action => "rest_api" + i.search_plugin 'integrations/search_plugin.xml', :action => 'search_plugin', :format => 'xml' + i.google_gadget 'integrations/google_gadget.xml', :action => 'google_gadget', :format => 'xml' + i.cloudmailin 'integrations/cloudmailin', :action => 'cloudmailin' + end + + map.with_options :controller => :preferences do |p| + p.preferences 'preferences', :action => 'index' + p.preferences_date_format 'preferences/render_date_format', :action => 'render_date_format' + end + + map.with_options :controller => :stats do |stats| + stats.stats 'stats', :action => 'index' + stats.done_overview 'done', :action => 'done' + end + + map.search 'search', :controller => 'search', :action => 'index' + map.data 'data', :controller => 'data', :action => 'index' + + Translate::Routes.translation_ui(map) if Rails.env != "production" + + # Install the default route as the lowest priority. + map.connect ':controller/:action/:id' + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 00000000..4edb1e85 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,7 @@ +# This file should contain all the record creation needed to seed the database with its default values. +# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). +# +# Examples: +# +# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) +# Mayor.create(name: 'Emanuel', city: cities.first) diff --git a/doc/README_FOR_APP b/doc/README_FOR_APP new file mode 100644 index 00000000..fe41f5cc --- /dev/null +++ b/doc/README_FOR_APP @@ -0,0 +1,2 @@ +Use this README file to introduce your application and point to useful places in the API for learning more. +Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries. diff --git a/lib/assets/.gitkeep b/lib/assets/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/lib/tasks/.gitkeep b/lib/tasks/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/public/404.html b/public/404.html index eff660b9..9a48320a 100644 --- a/public/404.html +++ b/public/404.html @@ -1,23 +1,19 @@ - - - - + + - The page you were looking for doesn't exist (404) - + @@ -27,4 +23,4 @@

        You may have mistyped the address or the page may have moved.

        - \ No newline at end of file + diff --git a/public/422.html b/public/422.html index b54e4a3c..83660ab1 100644 --- a/public/422.html +++ b/public/422.html @@ -1,23 +1,19 @@ - - - - + + - The change you wanted was rejected (422) - + @@ -27,4 +23,4 @@

        Maybe you tried to change something you didn't have access to.

        - \ No newline at end of file + diff --git a/public/500.html b/public/500.html index 4bc0a825..2d13a43d 100644 --- a/public/500.html +++ b/public/500.html @@ -1,23 +1,19 @@ - - - - + + - We're sorry, but something went wrong (500) - + diff --git a/public/index.html b/public/index.html new file mode 100644 index 00000000..a1d50995 --- /dev/null +++ b/public/index.html @@ -0,0 +1,241 @@ + + + + Ruby on Rails: Welcome aboard + + + + +
        + + +
        + + + + +
        +

        Getting started

        +

        Here’s how to get rolling:

        + +
          +
        1. +

          Use rails generate to create your models and controllers

          +

          To see all available options, run it without parameters.

          +
        2. + +
        3. +

          Set up a default route and remove public/index.html

          +

          Routes are set up in config/routes.rb.

          +
        4. + +
        5. +

          Create your database

          +

          Run rake db:create to create your database. If you're not using SQLite (the default), edit config/database.yml with your username and password.

          +
        6. +
        +
        +
        + + +
        + + diff --git a/script/about b/script/about old mode 100644 new mode 100755 diff --git a/script/rails b/script/rails new file mode 100755 index 00000000..f8da2cff --- /dev/null +++ b/script/rails @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby +# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. + +APP_PATH = File.expand_path('../../config/application', __FILE__) +require File.expand_path('../../config/boot', __FILE__) +require 'rails/commands' diff --git a/test/fixtures/.gitkeep b/test/fixtures/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/test/functional/.gitkeep b/test/functional/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/test/integration/.gitkeep b/test/integration/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/test/performance/browsing_test.rb b/test/performance/browsing_test.rb new file mode 100644 index 00000000..3fea27b9 --- /dev/null +++ b/test/performance/browsing_test.rb @@ -0,0 +1,12 @@ +require 'test_helper' +require 'rails/performance_test_help' + +class BrowsingTest < ActionDispatch::PerformanceTest + # Refer to the documentation for all available options + # self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory] + # :output => 'tmp/performance', :formats => [:flat] } + + def test_homepage + get '/' + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index 40d8a464..8bf1192f 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,152 +1,13 @@ ENV["RAILS_ENV"] = "test" -require 'thread' -require File.expand_path(File.dirname(__FILE__) + "/../config/environment") -require File.expand_path(File.dirname(__FILE__) + "/../app/controllers/application_controller") -require 'test_help' -require 'flexmock/test_unit' #and the flexmock gem, too! -require 'action_web_service/test_invoke' - -module Tracks - class Config - def self.salt - "change-me" - end - def self.auth_schemes - return ["database","open_id"] - end - end -end - -class Test::Unit::TestCase - include AuthenticatedTestHelper - - def xml_document - @xml_document ||= HTML::Document.new(@response.body, false, true) - end - - def assert_xml_select(*args, &block) - @html_document = xml_document - assert_select(*args, &block) - end - - def assert_error_on(model_instance, attribute, expected_error) - actual_error = model_instance.errors.on attribute.to_sym - assert_equal expected_error, actual_error - end - - alias_method :assert_errors_on, :assert_error_on - - def assert_value_changed(object, method = nil) - initial_value = object.send(method) - yield - assert_not_equal initial_value, object.send(method), "#{object}##{method}" - end - -end +require File.expand_path('../../config/environment', __FILE__) +require 'rails/test_help' class ActiveSupport::TestCase - - # Generates a random string of ascii characters (a-z, "1 0") - # of a given length for testing assignment to fields - # for validation purposes + # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order. # - def generate_random_string(length) - string = "" - characters = %w(a b c d e f g h i j k l m n o p q r s t u v w z y z 1\ 0) - length.times do - pick = characters[rand(26)] - string << pick - end - return string - end - - def next_week - 1.week.from_now.utc - end - - # Courtesy of http://habtm.com/articles/2006/02/20/assert-yourself-man-redirecting-with-rjs - def assert_js_redirected_to(options={}, message=nil) - clean_backtrace do - assert_response(:success, message) - assert_equal 'text/javascript', @response.content_type, 'Response should be Javascript content-type'; - js_regexp = %r{(\w+://)?.*?(/|$|\\\?)(.*)} - url_regexp = %r{^window\.location\.href [=] ['"]#{js_regexp}['"][;]$} - redirected_to = @response.body.match(url_regexp) - assert_not_nil(redirected_to, message) - redirected_to = redirected_to[3] - msg = build_message(message, "expected a JS redirect to , found one to ", options, redirected_to) - - if options.is_a?(String) - assert_equal(options.gsub(/^\//, ''), redirected_to, message) - elsif options.is_a?(Regexp) - assert(options =~ redirected_to, "#{message} #{options} #{redirected_to}") - else - msg = build_message(message, "response is not a redirection to all of the options supplied (redirection is )", redirected_to) - assert_equal(@controller.url_for(options).match(js_regexp)[3], redirected_to, msg) - end - end - end - - def set_user_to_current_time_zone(user) - jan_offset = Time.now.beginning_of_year.utc_offset - jul_offset = Time.now.beginning_of_year.change(:month => 7).utc_offset - offset = jan_offset < jul_offset ? jan_offset : jul_offset - offset = if offset.to_s.match(/(\+|-)?(\d+):(\d+)/) - sign = $1 == '-' ? -1 : 1 - hours, minutes = $2.to_f, $3.to_f - ((hours * 3600) + (minutes.to_f * 60)) * sign - elsif offset.to_f.abs <= 13 - offset.to_f * 3600 - else - offset.to_f - end - zone = ActiveSupport::TimeZone.all.find{|t| t.utc_offset == offset} - user.prefs.update_attribute(:time_zone, zone.name) - end -end - -class ActionController::IntegrationTest - Tag #avoid errors in integration tests - - def assert_test_environment_ok - assert_equal "test", ENV['RAILS_ENV'] - assert_equal "change-me", Tracks::Config.salt - end - - def authenticated_post_xml(url, username, password, parameters, headers = {}) - post url, - parameters, - {'AUTHORIZATION' => "Basic " + Base64.encode64("#{username}:#{password}"), - 'ACCEPT' => 'application/xml', - 'CONTENT_TYPE' => 'application/xml' - }.merge(headers) - end - - def authenticated_get_xml(url, username, password, parameters, headers = {}) - get url, - parameters, - {'AUTHORIZATION' => "Basic " + Base64.encode64("#{username}:#{password}"), - 'ACCEPT' => 'application/xml', - 'CONTENT_TYPE' => 'application/xml' - }.merge(headers) - end - - def assert_response_and_body(type, body, message = nil) - assert_equal body, @response.body, message - assert_response type, message - end - - def assert_response_and_body_matches(type, body_regex, message = nil) - assert_response type, message - assert_match body_regex, @response.body, message - end - - def assert_401_unauthorized - assert_response_and_body 401, "401 Unauthorized: You are not authorized to interact with Tracks." - end - - def assert_401_unauthorized_admin - assert_response_and_body 401, "401 Unauthorized: Only admin users are allowed access to this function." - end + # Note: You'll currently still have to declare fixtures explicitly in integration tests + # -- they do not yet inherit this setting + fixtures :all + # Add more helper methods to be used by all tests here... end diff --git a/test/test_helper.rb.rails2 b/test/test_helper.rb.rails2 new file mode 100644 index 00000000..40d8a464 --- /dev/null +++ b/test/test_helper.rb.rails2 @@ -0,0 +1,152 @@ +ENV["RAILS_ENV"] = "test" +require 'thread' +require File.expand_path(File.dirname(__FILE__) + "/../config/environment") +require File.expand_path(File.dirname(__FILE__) + "/../app/controllers/application_controller") +require 'test_help' +require 'flexmock/test_unit' #and the flexmock gem, too! +require 'action_web_service/test_invoke' + +module Tracks + class Config + def self.salt + "change-me" + end + def self.auth_schemes + return ["database","open_id"] + end + end +end + +class Test::Unit::TestCase + include AuthenticatedTestHelper + + def xml_document + @xml_document ||= HTML::Document.new(@response.body, false, true) + end + + def assert_xml_select(*args, &block) + @html_document = xml_document + assert_select(*args, &block) + end + + def assert_error_on(model_instance, attribute, expected_error) + actual_error = model_instance.errors.on attribute.to_sym + assert_equal expected_error, actual_error + end + + alias_method :assert_errors_on, :assert_error_on + + def assert_value_changed(object, method = nil) + initial_value = object.send(method) + yield + assert_not_equal initial_value, object.send(method), "#{object}##{method}" + end + +end + +class ActiveSupport::TestCase + + # Generates a random string of ascii characters (a-z, "1 0") + # of a given length for testing assignment to fields + # for validation purposes + # + def generate_random_string(length) + string = "" + characters = %w(a b c d e f g h i j k l m n o p q r s t u v w z y z 1\ 0) + length.times do + pick = characters[rand(26)] + string << pick + end + return string + end + + def next_week + 1.week.from_now.utc + end + + # Courtesy of http://habtm.com/articles/2006/02/20/assert-yourself-man-redirecting-with-rjs + def assert_js_redirected_to(options={}, message=nil) + clean_backtrace do + assert_response(:success, message) + assert_equal 'text/javascript', @response.content_type, 'Response should be Javascript content-type'; + js_regexp = %r{(\w+://)?.*?(/|$|\\\?)(.*)} + url_regexp = %r{^window\.location\.href [=] ['"]#{js_regexp}['"][;]$} + redirected_to = @response.body.match(url_regexp) + assert_not_nil(redirected_to, message) + redirected_to = redirected_to[3] + msg = build_message(message, "expected a JS redirect to , found one to ", options, redirected_to) + + if options.is_a?(String) + assert_equal(options.gsub(/^\//, ''), redirected_to, message) + elsif options.is_a?(Regexp) + assert(options =~ redirected_to, "#{message} #{options} #{redirected_to}") + else + msg = build_message(message, "response is not a redirection to all of the options supplied (redirection is )", redirected_to) + assert_equal(@controller.url_for(options).match(js_regexp)[3], redirected_to, msg) + end + end + end + + def set_user_to_current_time_zone(user) + jan_offset = Time.now.beginning_of_year.utc_offset + jul_offset = Time.now.beginning_of_year.change(:month => 7).utc_offset + offset = jan_offset < jul_offset ? jan_offset : jul_offset + offset = if offset.to_s.match(/(\+|-)?(\d+):(\d+)/) + sign = $1 == '-' ? -1 : 1 + hours, minutes = $2.to_f, $3.to_f + ((hours * 3600) + (minutes.to_f * 60)) * sign + elsif offset.to_f.abs <= 13 + offset.to_f * 3600 + else + offset.to_f + end + zone = ActiveSupport::TimeZone.all.find{|t| t.utc_offset == offset} + user.prefs.update_attribute(:time_zone, zone.name) + end +end + +class ActionController::IntegrationTest + Tag #avoid errors in integration tests + + def assert_test_environment_ok + assert_equal "test", ENV['RAILS_ENV'] + assert_equal "change-me", Tracks::Config.salt + end + + def authenticated_post_xml(url, username, password, parameters, headers = {}) + post url, + parameters, + {'AUTHORIZATION' => "Basic " + Base64.encode64("#{username}:#{password}"), + 'ACCEPT' => 'application/xml', + 'CONTENT_TYPE' => 'application/xml' + }.merge(headers) + end + + def authenticated_get_xml(url, username, password, parameters, headers = {}) + get url, + parameters, + {'AUTHORIZATION' => "Basic " + Base64.encode64("#{username}:#{password}"), + 'ACCEPT' => 'application/xml', + 'CONTENT_TYPE' => 'application/xml' + }.merge(headers) + end + + def assert_response_and_body(type, body, message = nil) + assert_equal body, @response.body, message + assert_response type, message + end + + def assert_response_and_body_matches(type, body_regex, message = nil) + assert_response type, message + assert_match body_regex, @response.body, message + end + + def assert_401_unauthorized + assert_response_and_body 401, "401 Unauthorized: You are not authorized to interact with Tracks." + end + + def assert_401_unauthorized_admin + assert_response_and_body 401, "401 Unauthorized: Only admin users are allowed access to this function." + end + +end diff --git a/test/unit/.gitkeep b/test/unit/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/vendor/assets/javascripts/.gitkeep b/vendor/assets/javascripts/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/vendor/assets/stylesheets/.gitkeep b/vendor/assets/stylesheets/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/vendor/plugins/.gitkeep b/vendor/plugins/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/vendor/plugins/rails_upgrade/MIT-LICENSE b/vendor/plugins/rails_upgrade/MIT-LICENSE new file mode 100644 index 00000000..a7f3e561 --- /dev/null +++ b/vendor/plugins/rails_upgrade/MIT-LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2010 Jeremy McAnally + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/plugins/rails_upgrade/README.rdoc b/vendor/plugins/rails_upgrade/README.rdoc new file mode 100644 index 00000000..581d35d7 --- /dev/null +++ b/vendor/plugins/rails_upgrade/README.rdoc @@ -0,0 +1,26 @@ += rails-upgrade + +A simple battery of scripts for upgrading Rails app/checking them for required updates. This application should work on Rails 2.x and 3.0, with a focus on upgrading to 3.0. + +== Usage + +You need to install this plugin first: + + script/plugin install git://github.com/rails/rails_upgrade.git + +Then you can run its rake tasks to check your application: + + # Check your app for required upgrades + rake rails:upgrade:check + + # Backup your likely modified files that might be overwritten by the generator + rake rails:upgrade:backup + + # Generate a new route file + rake rails:upgrade:routes + + # Generate a Gemfile from your config.gem directives + rake rails:upgrade:gems + + # Generate code for a new config/application.rb from your environment.rb + rake rails:upgrade:configuration \ No newline at end of file diff --git a/vendor/plugins/rails_upgrade/Rakefile b/vendor/plugins/rails_upgrade/Rakefile new file mode 100644 index 00000000..421514ed --- /dev/null +++ b/vendor/plugins/rails_upgrade/Rakefile @@ -0,0 +1,22 @@ +require 'rake' +require 'rake/testtask' +require 'rake/rdoctask' + +desc 'Default: run unit tests.' +task :default => :test + +Rake::TestTask.new do |t| + t.libs << 'lib' + t.libs << 'test' + t.test_files = FileList['test/*_test.rb'] + t.verbose = true +end + +desc 'Generate documentation for the rails_upgrade plugin.' +Rake::RDocTask.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'rdoc' + rdoc.title = 'Rails-upgrade' + rdoc.options << '--line-numbers' << '--inline-source' + rdoc.rdoc_files.include('README') + rdoc.rdoc_files.include('lib/**/*.rb') +end diff --git a/vendor/plugins/rails_upgrade/init.rb b/vendor/plugins/rails_upgrade/init.rb new file mode 100644 index 00000000..f134b171 --- /dev/null +++ b/vendor/plugins/rails_upgrade/init.rb @@ -0,0 +1,2 @@ +# Get long stack traces for easier debugging; you'll thank me later. +Rails.backtrace_cleaner.remove_silencers! if Rails.respond_to?(:backtrace_cleaner) diff --git a/vendor/plugins/rails_upgrade/install.rb b/vendor/plugins/rails_upgrade/install.rb new file mode 100644 index 00000000..f064427c --- /dev/null +++ b/vendor/plugins/rails_upgrade/install.rb @@ -0,0 +1,38 @@ +puts "Thanks for installing the Rails upgrade plugin. This is a set of generators and analysis tools to help you upgrade your application to Rails 3. It consists of three tasks... + +To get a feel for what you'll need to change to get your app running, run the application analysis: + + rake rails:upgrade:check + +This should give you an idea of the manual changes that need to be done, but you'll probably want to upgrade some of those automatically. The fastest way to do this is to run 'rails .', which will simply generate a new app on top of your existing code. But this generation also has the effect of replacing some existing files, some of which you might not want to replace. To back those up, first run: + + rake rails:upgrade:backup + +That will backup files you've probably edited that will be replaced in the upgrade; if you finish the upgrade and find that you don't need the old copies, just delete them. Otherwise, copy their contents back into the new files or run one of the following upgraders... + +Routes upgrader +=============== + +To generate a new routes file from your existing routes file, simply run the following Rake task: + + rake rails:upgrade:routes + +This will output a new routes file that you can copy and paste or pipe into a new, Rails 3 compatible config/routes.rb. + +Gemfile generator +================= + +Creating a new Gemfile is as simple as running: + + rake rails:upgrade:gems + +This task will extract your config.gem calls and generate code you can put into a bundler compatible Gemfile. + +Configuration generator +======================= + +Much of the configuration information that lived in environment.rb now belongs in a new file named config/application.rb; use the following task to generate code you can put into config/application.rb from your existing config/environment.rb: + + rake rails:upgrade:configuration + +" \ No newline at end of file diff --git a/vendor/plugins/rails_upgrade/lib/application_checker.rb b/vendor/plugins/rails_upgrade/lib/application_checker.rb new file mode 100644 index 00000000..813890b1 --- /dev/null +++ b/vendor/plugins/rails_upgrade/lib/application_checker.rb @@ -0,0 +1,506 @@ +require 'open3' + +module Rails + module Upgrading + class ApplicationChecker + def initialize + @issues = [] + + raise NotInRailsAppError unless in_rails_app? + end + + def in_rails_app? + File.exist?("config/environment.rb") + end + + # Run all the check methods + def run + # Ruby 1.8 returns method names as strings whereas 1.9 uses symbols + the_methods = (self.public_methods - Object.methods) - [:run, :initialize, "run", "initialize"] + + the_methods.each {|m| send m } + end + + # Check for deprecated ActiveRecord calls + def check_ar_methods + files = [] + ["find(:all", "find(:first", "find.*:conditions =>", ":joins =>"].each do |v| + lines = grep_for(v, "app/") + files += extract_filenames(lines) || [] + end + + unless files.empty? + alert( + "Soon-to-be-deprecated ActiveRecord calls", + "Methods such as find(:all), find(:first), finds with conditions, and the :joins option will soon be deprecated.", + "http://m.onkey.org/2010/1/22/active-record-query-interface", + files + ) + end + + lines = grep_for("named_scope", "app/models/") + files = extract_filenames(lines) + + unless files.empty? + alert( + "named_scope is now just scope", + "The named_scope method has been renamed to just scope.", + "http://github.com/rails/rails/commit/d60bb0a9e4be2ac0a9de9a69041a4ddc2e0cc914", + files + ) + end + end + + def check_validation_on_methods + files = [] + + ["validate_on_create", "validate_on_update"].each do |v| + lines = grep_for(v, "app/models/") + files += extract_filenames(lines) || [] + end + + unless files.empty? + alert( + "Updated syntax for validate_on_* methods", + "Validate-on-callback methods (validate_on_create/validate_on_destroy) have been changed to validate :x, :on => :create", + "https://rails.lighthouseapp.com/projects/8994/tickets/3880-validate_on_create-and-validate_on_update-no-longer-seem-to-exist", + files + ) + end + end + + def check_before_validation_on_methods + files = [] + + %w(before_validation_on_create before_validation_on_update).each do |v| + lines = grep_for(v, "app/models/") + files += extract_filenames(lines) || [] + end + + unless files.empty? + alert( + "Updated syntax for before_validation_on_* methods", + "before_validation_on_* methods have been changed to before_validation(:on => :create/:update) { ... }", + "https://rails.lighthouseapp.com/projects/8994/tickets/4699-before_validation_on_create-and-before_validation_on_update-doesnt-exist", + files + ) + end + end + + # Check for deprecated router syntax + def check_routes + lines = ["map\\.", "ActionController::Routing::Routes", "\\.resources"].map do |v| + grep_for(v, "config/routes.rb").empty? ? nil : true + end.compact + + unless lines.empty? + alert( + "Old router API", + "The router API has totally changed.", + "http://yehudakatz.com/2009/12/26/the-rails-3-router-rack-it-up/", + "config/routes.rb" + ) + end + end + + # Check for deprecated test_help require + def check_test_help + files = [] + + # Hate to duplicate code, but we have to double quote this one... + lines = grep_for("\'test_help\'", "test/", true) + files += extract_filenames(lines) || [] + + lines = grep_for("\"test_help\"", "test/") + files += extract_filenames(lines) || [] + + files.uniq! + + unless files.empty? + alert( + "Deprecated test_help path", + "You now must require 'rails/test_help' not just 'test_help'.", + "http://weblog.rubyonrails.org/2009/9/1/gem-packaging-best-practices", + files + ) + end + end + + # Check for old (pre-application.rb) environment.rb file + def check_environment + unless File.exist?("config/application.rb") + alert( + "New file needed: config/application.rb", + "You need to add a config/application.rb.", + "http://omgbloglol.com/post/353978923/the-path-to-rails-3-approaching-the-upgrade", + "config/application.rb" + ) + end + + lines = grep_for("config.", "config/environment.rb") + + unless lines.empty? + alert( + "Old environment.rb", + "environment.rb doesn't do what it used to; you'll need to move some of that into application.rb.", + "http://omgbloglol.com/post/353978923/the-path-to-rails-3-approaching-the-upgrade", + "config/environment.rb" + ) + end + end + + # Check for deprecated constants + def check_deprecated_constants + files = [] + ["RAILS_ENV", "RAILS_ROOT", "RAILS_DEFAULT_LOGGER"].each do |v| + lines = grep_for(v, "app/") + files += extract_filenames(lines) || [] + + lines = grep_for(v, "lib/") + files += extract_filenames(lines) || [] + end + + unless files.empty? + alert( + "Deprecated constant(s)", + "Constants like RAILS_ENV, RAILS_ROOT, and RAILS_DEFAULT_LOGGER are now deprecated.", + "http://litanyagainstfear.com/blog/2010/02/03/the-rails-module/", + files.uniq + ) + end + end + + # Check for old-style config.gem calls + def check_gems + lines = grep_for("config.gem ", "config/*.rb") + lines += grep_for("config.gem ", "config/**/*.rb") + files = extract_filenames(lines) + + unless files.empty? + alert( + "Old gem bundling (config.gems)", + "The old way of bundling is gone now. You need a Gemfile for bundler.", + "http://omgbloglol.com/post/353978923/the-path-to-rails-3-approaching-the-upgrade", + files + ) + end + end + + # Checks for old mailer syntax in both mailer classes and those + # classes utilizing the mailers + def check_mailers + lines = grep_for("deliver_", "app/models/ #{base_path}app/controllers/ #{base_path}app/observers/") + files = extract_filenames(lines) + + unless files.empty? + alert( + "Deprecated ActionMailer API", + "You're using the old ActionMailer API to send e-mails in a controller, model, or observer.", + "http://lindsaar.net/2010/1/26/new-actionmailer-api-in-rails-3", + files + ) + end + + files = [] + ["recipients ", "attachment(?!s) ", "(?", "app/views/**/*") + lines += grep_for("<% .*javascript_tag.* do.*%>", "app/views/**/*") + lines += grep_for("<% .*form_for.* do.*%>", "app/views/**/*") + lines += grep_for("<% .*form_tag.* do.*%>", "app/views/**/*") + lines += grep_for("<% .*fields_for.* do.*%>", "app/views/**/*") + lines += grep_for("<% .*field_set_tag.* do.*%>", "app/views/**/*") + + files = extract_filenames(lines) + + if !files.blank? + alert( + "Deprecated ERb helper calls", + "Block helpers that use concat (e.g., form_for) should use <%= instead of <%. The current form will continue to work for now, but you will get deprecation warnings since this form will go away in the future.", + "http://weblog.rubyonrails.org/", + files + ) + end + end + + # Checks for old-style AJAX helpers + def check_old_ajax_helpers + files = [] + ['link_to_remote','form_remote_tag','remote_form_for'].each do |type| + lines = grep_for(type, "app/views/**/*") + inner_files = extract_filenames(lines) + files += inner_files unless inner_files.nil? + end + + unless files.empty? + alert( + "Deprecated AJAX helper calls", + "AJAX javascript helpers have been switched to be unobtrusive and use :remote => true instead of having a seperate function to handle remote requests.", + "http://blog.jordanwest.me/modest-rubyist-archive/rails-3-ujs-and-csrf-meta-tags", + files + ) + end + end + + # Checks for old cookie secret settings + def check_old_cookie_secret + lines = grep_for("ActionController::Base.cookie_verifier_secret = ", "config/**/*") + files = extract_filenames(lines) + + unless files.empty? + alert( + "Deprecated cookie secret setting", + "Previously, cookie secret was set directly on ActionController::Base; it's now config.secret_token.", + "http://lindsaar.net/2010/4/7/rails_3_session_secret_and_session_store", + files + ) + end + end + + def check_old_session_secret + lines = grep_for("ActionController::Base.session = {", "config/**/*") + files = extract_filenames(lines) + + unless files.empty? + alert( + "Deprecated session secret setting", + "Previously, session secret was set directly on ActionController::Base; it's now config.secret_token.", + "http://lindsaar.net/2010/4/7/rails_3_session_secret_and_session_store", + files + ) + end + end + + # Checks for old session settings + def check_old_session_setting + lines = grep_for("ActionController::Base.session_store", "config/**/*") + files = extract_filenames(lines) + + unless files.empty? + alert( + "Old session store setting", + "Previously, session store was set directly on ActionController::Base; it's now config.session_store :whatever.", + "http://lindsaar.net/2010/4/7/rails_3_session_secret_and_session_store", + files + ) + end + end + + #Check for old ActionMailer :sent_on attributes + def check_old_action_mailer_sent_on_setting + files = [] + lines = grep_for("sent_on", "app/*") + files += extract_filenames(lines) || [] + + unless files.empty? + alert( + "Deprecated ActionMailer attribute :sent_on", + "Using the new mailer API, you can specify :date to the mail method.", + "http://stackoverflow.com/questions/7367185/weird-error-when-delivering-mail-undefined-method-index-for-2011-09-09-2215", + files + ) + end + end + def check_old_filter_parameter + files = [] + lines = grep_for("filter_parameter_logging", "app/controllers/*") + files += extract_filenames(lines) || [] + + unless files.empty? + alert( + "Deprecated filter_parameter_logging calls", + "The list of filtered parameters are now stored in /config/application.rb. For example: config.filter_parameters += [:password]", + "http://de.asciicasts.com/episodes/224-controller-in-rails-3", + files + ) + end + end + private + def grep_for_with_perl_regex(text, where = "./", double_quote = false) + grep_for(text, where, double_quote, true) + end + + # Find a string in a set of files; calls +find_with_grep+ and +find_with_rak+ + # depending on platform. + # + # TODO: Figure out if this works on Windows. + def grep_for(text, where = "./", double_quote = false, perl_regex = false) + # If they're on Windows, they probably don't have grep. + @probably_has_grep ||= (Config::CONFIG['host_os'].downcase =~ /mswin|windows|mingw/).nil? + + # protect against double root paths in Rails 3 + where.gsub!(Regexp.new(base_path),'') + + lines = if @probably_has_grep + find_with_grep(text, base_path + where, double_quote, perl_regex) + else + find_with_rak(text, base_path + where, double_quote) + end + + # ignore comments + lines.gsub /^(\/[^:]+:)?\s*#.+$/m, "" + end + + # Sets a base path for finding files; mostly for testing + def base_path + Dir.pwd + "/" + end + + # Use the grep utility to find a string in a set of files + def find_with_grep(text, where, double_quote, perl_regex = false) + value = "" + # Specifically double quote for finding 'test_help' + command = if double_quote + "grep -rH #{"-P" if perl_regex} \"#{text}\" #{where} | grep -v \.svn" + else + "grep -rH #{"-P" if perl_regex} '#{text}' #{where} | grep -v \.svn" + end + + Open3.popen3(command) do |stdin, stdout, stderr| + value = stdout.read + end + value + end + + # Use the rak gem to grep the files (not yet implemented) + def find_with_rak(text, where, double_quote) + value = "" + Open3.popen3("rak --nogroup -l '#{Regexp.escape(text)}' #{where}") do |stdin, stdout, stderr| + value = stdout.read + end + value + end + + # Extract the filenames from the grep output + def extract_filenames(output) + if @probably_has_grep + filenames = extract_filenames_from_grep(output) + else + filenames = extract_filenames_from_rak(output) + end + + filenames.compact.map do |f| + f.gsub(base_path, "") + end + end + + def extract_filenames_from_grep(output) + return [] if output.empty? + + output.split("\n").map do |fn| + if m = fn.match(/^(.+?):/) + m[1] + end + end.compact.uniq + end + + def extract_filenames_from_rak(output) + return [] if output.empty? + + output.split("\n").uniq + end + + # Terminal colors, borrowed from Thor + CLEAR = "\e[0m" + BOLD = "\e[1m" + RED = "\e[31m" + YELLOW = "\e[33m" + CYAN = "\e[36m" + WHITE = "\e[37m" + + # Show an upgrade alert to the user + def alert(title, text, more_info_url, culprits) + if Config::CONFIG['host_os'].downcase =~ /mswin|windows|mingw/ + basic_alert(title, text, more_info_url, culprits) + else + color_alert(title, text, more_info_url, culprits) + end + end + + # Show an upgrade alert to the user. If we're on Windows, we can't + # use terminal colors, hence this method. + def basic_alert(title, text, more_info_url, culprits) + puts "** " + title + puts text + puts "More information: #{more_info_url}" + puts + puts "The culprits: " + Array(culprits).each do |c| + puts "\t- #{c}" + end + puts + end + + # Show a colorful alert to the user + def color_alert(title, text, more_info_url, culprits) + puts "#{RED}#{BOLD}#{title}#{CLEAR}" + puts "#{WHITE}#{text}" + puts "#{BOLD}More information:#{CLEAR} #{CYAN}#{more_info_url}" + puts + puts "#{WHITE}The culprits: " + Array(culprits).each do |c| + puts "#{YELLOW}\t- #{c}" + end + ensure + puts "#{CLEAR}" + end + end + end +end diff --git a/vendor/plugins/rails_upgrade/lib/gemfile_generator.rb b/vendor/plugins/rails_upgrade/lib/gemfile_generator.rb new file mode 100644 index 00000000..b2a2b204 --- /dev/null +++ b/vendor/plugins/rails_upgrade/lib/gemfile_generator.rb @@ -0,0 +1,95 @@ +module Rails + module Upgrading + class GemfileGenerator + def generate_new_gemfile + if has_environment? + generate_gemfile + else + raise FileNotFoundError, "Can't find environment.rb [config/environment.rb]!" + end + end + + def has_environment? + File.exists?("config/environment.rb") + end + + def environment_code + File.open("config/environment.rb").read + end + + def generate_gemfile + environment_file = environment_code + + # Get each line that starts with config.gem + gem_lines = environment_file.split("\n").select {|l| l =~ /^\s*config\.gem/} + + # Toss those lines to a generator class; the lines are evaluated in the + # context of that instance. + config = GemfileGenerator.new + config.instance_eval(gem_lines.join("\n")) + + config.output + end + end + + class GemfileGenerator + # Creates a target for the config.gem calls + def config + self + end + + def initialize + @gems = [] + end + + # Receive a call to add a gem to the list + def gem(name, options={}) + data = {} + + # Add new keys from old keys + data[:require] = options[:lib] if options[:lib] + data[:source] = options[:source] if options[:source] + + version = options[:version] + @gems << [name, version, data] + end + + # Generate the Gemfile output + def output + # Generic preamble, taken from Yehuda Katz's blog + preamble = < '#{v}'"}.join(", ") + end + + # If we have a source, generate a call to +source+ then output the + # gem call. Otherwise, just generate the gem requirement. + if source + str = ["'#{name}'", version_string, data_string].compact.join(", ") + "source '#{source}'\ngem #{str}" + else + str = ["'#{name}'", version_string, data_string].compact.join(", ") + "gem #{str}" + end + end.join("\n") + end + end + end +end diff --git a/vendor/plugins/rails_upgrade/lib/new_configuration_generator.rb b/vendor/plugins/rails_upgrade/lib/new_configuration_generator.rb new file mode 100644 index 00000000..82d29d3c --- /dev/null +++ b/vendor/plugins/rails_upgrade/lib/new_configuration_generator.rb @@ -0,0 +1,59 @@ +require 'active_support/core_ext/string/inflections' + +module Rails + module Upgrading + class NewConfigurationGenerator + def generate_new_configurations + if has_environment? + generate_new_application_rb + else + raise FileNotFoundError, "Can't find environment.rb [config/environment.rb]!" + end + end + + def has_environment? + File.exists?("config/environment.rb") + end + + def environment_code + File.open("config/environment.rb").read + end + + def generate_new_application_rb + environment_file = environment_code + + initializer_code = "" + if matches = environment_file.match(/Rails\:\:Initializer\.run do \|config\|\n(.*)\nend/m) + initializer_code = matches[1] + else + raise "There doesn't seem to be a real environment.rb in your app. Are you sure config/environment.rb has the right contents?" + end + + frame = "# Put this in config/application.rb +require File.expand_path('../boot', __FILE__) + +require 'rails/all' + +Bundler.require(:default, Rails.env) if defined?(Bundler) + +module #{app_name.classify} + class Application < Rails::Application + config.autoload_paths += [config.root.join('lib')] + config.encoding = 'utf-8' +%s + end +end" + + frame % [indent(initializer_code)] + end + + def indent(text) + text.split("\n").map {|l| " #{l}"}.join("\n") + end + + def app_name + File.basename(Dir.pwd) + end + end + end +end diff --git a/vendor/plugins/rails_upgrade/lib/rails_upgrade.rb b/vendor/plugins/rails_upgrade/lib/rails_upgrade.rb new file mode 100644 index 00000000..e69de29b diff --git a/vendor/plugins/rails_upgrade/lib/routes_upgrader.rb b/vendor/plugins/rails_upgrade/lib/routes_upgrader.rb new file mode 100644 index 00000000..00c10a41 --- /dev/null +++ b/vendor/plugins/rails_upgrade/lib/routes_upgrader.rb @@ -0,0 +1,344 @@ +# TODO: Fix formatting on member/collection methods + +module Rails + module Upgrading + module FakeRouter + module ActionController + module Routing + class Routes + def self.setup + @redrawer = Rails::Upgrading::RouteRedrawer.new + end + + def self.redrawer + @redrawer + end + + def self.draw + yield @redrawer + end + end + end + end + end + + class RoutesUpgrader + def generate_new_routes + if has_routes_file? + upgrade_routes + else + raise FileNotFoundError, "Can't find your routes file [config/routes.rb]!" + end + end + + def has_routes_file? + File.exists?("config/routes.rb") + end + + def routes_code + File.read("config/routes.rb") + end + + def upgrade_routes + FakeRouter::ActionController::Routing::Routes.setup + + # Read and eval the file; our fake route mapper will capture + # the calls to draw routes and generate new route code + FakeRouter.module_eval(routes_code) + + # Give the route set to the code generator and get its output + generator = RouteGenerator.new(FakeRouter::ActionController::Routing::Routes.redrawer.routes) + generator.generate + end + end + + class RouteRedrawer + attr_accessor :routes + + def self.stack + @stack + end + + def self.stack=(val) + @stack = val + end + + def initialize + @routes = [] + + # The old default route was actually two routes; we generate the new style + # one only if we haven't generated it for the first old default route. + @default_route_generated = false + + # Setup the stack for parents; used use proper indentation + self.class.stack = [@routes] + end + + def root(options) + debug "mapping root" + @routes << FakeRoute.new("/", options) + end + + def connect(path, options={}) + debug "connecting #{path}" + + if (path == ":controller/:action/:id.:format" || path == ":controller/:action/:id") + if !@default_route_generated + current_parent << FakeRoute.new("/:controller(/:action(/:id))", {:default_route => true}) + + @default_route_generated = true + end + else + current_parent << FakeRoute.new(path, options) + end + end + + def resources(*args, &block) + _res(FakeResourceRoute, args, &block) + end + + def resource(*args, &block) + _res(FakeSingletonResourceRoute, args, &block) + end + + def _res(klass, args) + if args.last.is_a?(Hash) + options = args.pop + debug "options #{options.inspect}" + end + + args.each do |a| + current_parent << klass.new(a, options || {}) + debug "mapping resources #{current_parent.last.name}" + + if block_given? + parent = current_parent.last + + parent = stack(parent) do + yield(self) + end + end + end + end + + def namespace(name, options = {}) + debug "mapping namespace #{name}" + namespace = FakeNamespace.new(name, options) + + namespace = stack(namespace) do + yield(self) + end + + current_parent << namespace + end + + def method_missing(m, *args) + debug "named route: #{m}" + current_parent << FakeRoute.new(args.shift, args.pop, m.to_s) + end + + def self.indent + ' ' * ((stack.length) * 2) + end + + private + def debug(txt) + puts txt if ENV['DEBUG'] + end + + def stack(obj) + self.class.stack << obj + yield + self.class.stack.pop + end + + def current_parent + self.class.stack.last + end + end + + class RouteObject + def indent_lines(code_lines) + if code_lines.length > 1 + code_lines.flatten.map {|l| "#{@indent}#{l.chomp}"}.join("\n") + "\n" + else + "#{@indent}#{code_lines.shift}" + end + end + + def opts_to_string(opts) + opts.is_a?(Hash) ? opts.map {|k, v| + ":#{k} => " + (v.is_a?(Hash) ? ('{ ' + opts_to_string(v) + ' }') : "#{value_to_string(v)}") + }.join(", ") : opts.to_s + end + + def value_to_string(value) + case value + when Regexp, Symbol, Array then value.inspect + when String then "'" + value.to_s + "'" + else value.to_s + end + end + end + + class FakeNamespace < RouteObject + attr_accessor :routes, :name, :options + + def initialize(name, options = {}) + @routes = [] + @name, @options = name, options + @indent = RouteRedrawer.indent + end + + def to_route_code + if !@options.empty? + options = ', ' + opts_to_string(@options) + else + options = '' + end + + lines = ["namespace :#{@name}#{options} do", @routes.map {|r| r.to_route_code}, "end"] + + indent_lines(lines) + end + + def <<(val) + @routes << val + end + + def last + @routes.last + end + end + + class FakeRoute < RouteObject + attr_accessor :name, :path, :options + + def initialize(path, options, name = "") + @path = path + @options = options || {} + @name = name + @indent = RouteRedrawer.indent + end + + def to_route_code + if @options[:default_route] + indent_lines ["match '#{@path}'"] + else + base = "match '%s' => '%s#%s'" + extra_options = [] + + if not name.empty? + extra_options << ":as => :#{name}" + end + + if @options[:requirements] + @options[:constraints] = @options.delete(:requirements) + end + + if @options[:conditions] + @options[:via] = @options.delete(:conditions).delete(:method) + end + + @options ||= {} + base = (base % [@path, @options.delete(:controller), (@options.delete(:action) || "index")]) + opts = opts_to_string(@options) + + route_pieces = ([base] + extra_options + [opts]) + route_pieces.delete("") + + indent_lines [route_pieces.join(", ")] + end + end + end + + class FakeResourceRoute < RouteObject + attr_accessor :name, :children + + def initialize(name, options = {}) + @name = name + @children = [] + @options = options + @indent = RouteRedrawer.indent + end + + def to_route_code + # preserve :only & :except options + copied_options = @options.reject { |k,v| ![:only, :except].member?(k) } + unless copied_options.empty? + copied_options_str = ", " + copied_options.map { |k, v| "#{k.inspect} => #{v.inspect}" }.join(",") + end + + if !@children.empty? || @options.has_key?(:collection) || @options.has_key?(:member) + prefix = ["#{route_method} :#{@name}#{copied_options_str} do"] + lines = prefix + custom_methods + [@children.map {|r| r.to_route_code}.join("\n"), "end"] + + indent_lines(lines) + else + base = "#{route_method} :%s#{copied_options_str}" + indent_lines [base % [@name]] + end + end + + def custom_methods + collection_code = generate_custom_methods_for(:collection) + member_code = generate_custom_methods_for(:member) + [collection_code, member_code] + end + + def generate_custom_methods_for(group) + return "" unless @options[group] + + method_code = [] + + RouteRedrawer.stack << self + @options[group].each do |name, methods| + [*methods].each do |method| + method_code << "#{method} :#{name}" + end + end + RouteRedrawer.stack.pop + + indent_lines ["#{group} do", method_code, "end"].flatten + end + + def route_method + "resources" + end + + def <<(val) + @children << val + end + + def last + @children.last + end + end + + class FakeSingletonResourceRoute < FakeResourceRoute + def route_method + "resource" + end + end + + class RouteGenerator + def initialize(routes) + @routes = routes + @new_code = "" + end + + def generate + @new_code = @routes.map do |r| + r.to_route_code + end.join("\n") + + "#{app_name.underscore.classify}::Application.routes.draw do\n#{@new_code}\nend\n" + end + + private + def app_name + File.basename(Dir.pwd) + end + end + end +end diff --git a/vendor/plugins/rails_upgrade/lib/tasks/rails_upgrade_tasks.rake b/vendor/plugins/rails_upgrade/lib/tasks/rails_upgrade_tasks.rake new file mode 100644 index 00000000..ab409de8 --- /dev/null +++ b/vendor/plugins/rails_upgrade/lib/tasks/rails_upgrade_tasks.rake @@ -0,0 +1,79 @@ +$:.unshift(File.dirname(__FILE__) + "/../../lib") +require 'routes_upgrader' +require 'gemfile_generator' +require 'application_checker' +require 'new_configuration_generator' +require "active_support" + +require 'fileutils' + +namespace :rails do + namespace :upgrade do + desc "Runs a battery of checks on your Rails 2.x app and generates a report on required upgrades for Rails 3" + task :check do + checker = Rails::Upgrading::ApplicationChecker.new + checker.run + end + + desc "Generates a Gemfile for your Rails 3 app out of your config.gem directives" + task :gems do + generator = Rails::Upgrading::GemfileGenerator.new + new_gemfile = generator.generate_new_gemfile + + puts new_gemfile + end + + desc "Create a new, upgraded route file from your current routes.rb" + task :routes do + upgrader = Rails::Upgrading::RoutesUpgrader.new + new_routes = upgrader.generate_new_routes + + puts new_routes + end + + desc "Extracts your configuration code so you can create a new config/application.rb" + task :configuration do + upgrader = Rails::Upgrading::NewConfigurationGenerator.new + new_config = upgrader.generate_new_application_rb + + puts new_config + end + + CLEAR = "\e[0m" unless defined? CLEAR + CYAN = "\e[36m" unless defined? CYAN + WHITE = "\e[37m" unless defined? WHITE + + desc "Backs up your likely modified files so you can run the Rails 3 generator on your app with little risk" + task :backup do + files = [".gitignore", + "app/controllers/application_controller.rb", + "app/helpers/application_helper.rb", + "config/routes.rb", + "config/environment.rb", + "config/environments/development.rb", + "config/environments/production.rb", + "config/environments/staging.rb", + "config/database.yml", + "config.ru", + "doc/README_FOR_APP", + "test/test_helper.rb"] + + puts + files.each do |f| + if File.exist?(f) + puts "#{CYAN}* #{CLEAR}backing up #{WHITE}#{f}#{CLEAR} to #{WHITE}#{f}.rails2#{CLEAR}" + FileUtils.cp(f, "#{f}.rails2") + end + end + + puts + puts "This is a list of the files analyzed and backed up (if they existed);\nyou will probably not want the generator to replace them since\nyou probably modified them (but now they're safe if you accidentally do!)." + puts + + files.each do |f| + puts "#{CYAN}- #{CLEAR}#{f}" + end + puts + end + end +end diff --git a/vendor/plugins/rails_upgrade/test/application_checker_test.rb b/vendor/plugins/rails_upgrade/test/application_checker_test.rb new file mode 100644 index 00000000..e0fbf754 --- /dev/null +++ b/vendor/plugins/rails_upgrade/test/application_checker_test.rb @@ -0,0 +1,344 @@ +require 'test_helper' +require 'application_checker' +require 'fileutils' + +tmp_dir = File.expand_path("#{File.dirname(__FILE__)}/fixtures/tmp") + +if defined? BASE_ROOT + BASE_ROOT.replace tmp_dir +else + BASE_ROOT = tmp_dir +end +FileUtils.mkdir_p BASE_ROOT + +# Stub out methods on upgrader class +module Rails + module Upgrading + class ApplicationChecker + attr_reader :alerts, :culprits + + def base_path + BASE_ROOT + "/" + end + + def in_rails_app? + true + end + + def initialize + @alerts = {} + @culprits = {} + end + + def alert(title, text, more_info_url, culprits) + @alerts[title] = [text, more_info_url] + @culprits[title] = culprits + end + end + end +end + +class ApplicationCheckerTest < ActiveSupport::TestCase + def setup + @checker = Rails::Upgrading::ApplicationChecker.new + @old_dir = Dir.pwd + + Dir.chdir(BASE_ROOT) + end + + def test_check_ar_methods_in_controller + make_file("app/controllers", "post_controller.rb", "Post.find(:all)") + @checker.check_ar_methods + + assert @checker.alerts.has_key?("Soon-to-be-deprecated ActiveRecord calls") + end + + def test_check_ar_methods_in_models + make_file("app/models", "post.rb", "Post.find(:all)") + @checker.check_ar_methods + + key = "Soon-to-be-deprecated ActiveRecord calls" + assert @checker.alerts.has_key?(key) + assert_equal "app/models/post.rb", @checker.culprits[key].first + end + + def test_check_svn_subdirs_are_not_included + make_file("app/models/.svn/text-base", "foo.rb.tmp", "Post.find(:all)") + @checker.check_ar_methods + assert @checker.alerts.empty? + end + + def test_check_validation_on_methods + make_file("app/models", "post.rb", "validate_on_create :comments_valid?") + @checker.check_validation_on_methods + + assert @checker.alerts.has_key?("Updated syntax for validate_on_* methods") + end + + def test_check_before_validation_on_methods + make_file("app/models", "post.rb", "before_validation_on_create :comments_valid?") + @checker.check_before_validation_on_methods + + assert @checker.alerts.has_key?("Updated syntax for before_validation_on_* methods") + end + + def test_named_scope_left_over + make_file("app/models", "post.rb", "named_scope :failure") + @checker.check_ar_methods + + assert @checker.alerts.has_key?("named_scope is now just scope") + end + + def test_check_routes + make_file("config/", "routes.rb", " map.connect 'fail'") + @checker.check_routes + + assert @checker.alerts.has_key?("Old router API") + end + + def test_check_for_old_test_help + make_file("test/", "test_helper.rb", " require 'test_help'") + @checker.check_test_help + + assert @checker.alerts.has_key?("Deprecated test_help path") + end + + def test_check_for_old_test_help_with_double_quotes + make_file("test/", "test_helper.rb", " require \"test_help\"") + @checker.check_test_help + + assert @checker.alerts.has_key?("Deprecated test_help path") + end + + def test_check_for_old_test_help_doesnt_see_test_helper + make_file("test/", "test_helper.rb", " require 'test_helper'") + @checker.check_test_help + + assert !@checker.alerts.has_key?("Deprecated test_help path") + end + + def test_check_lack_of_app_dot_rb + @checker.check_environment + + assert @checker.alerts.has_key?("New file needed: config/application.rb") + end + + def test_check_environment_syntax + make_file("config/", "environment.rb", "config.frameworks = []") + @checker.check_environment + + assert @checker.alerts.has_key?("Old environment.rb") + end + + def test_check_gems + make_file("config/", "environment.rb", "config.gem 'rails'") + @checker.check_gems + + assert @checker.alerts.has_key?("Old gem bundling (config.gems)") + end + + def test_check_gems_finds_nothing + @checker.check_gems + + assert_equal false, @checker.alerts.has_key?("Old gem bundling (config.gems)") + end + + def test_check_mailer_finds_nothing + @checker.check_mailers + + assert_equal false, @checker.alerts.has_key?("Old ActionMailer class API") + end + + def test_check_mailer_syntax + make_file("app/models/", "notifications.rb", "def signup\nrecipients @users\n end") + @checker.check_mailers + + assert @checker.alerts.has_key?("Old ActionMailer class API") + end + + def test_check_mailer_syntax_from + make_file("app/models/", "notifications.rb", "def signup\nfrom @user\n end") + @checker.check_mailers + + assert @checker.alerts.has_key?("Old ActionMailer class API") + end + + def test_check_mailer_syntax_subject + make_file("app/models/", "notifications.rb", "def signup\nsubject @subject\n end") + @checker.check_mailers + + assert @checker.alerts.has_key?("Old ActionMailer class API") + end + + def test_check_mailer_syntax_attachment + make_file("app/models/", "notifications.rb", "def signup\nattachment 'application/pdf' do |a|\n end") + @checker.check_mailers + + assert @checker.alerts.has_key?("Old ActionMailer class API") + end + + def test_new_check_mailer_syntax_from + make_file("app/models/", "notifications.rb", "def signup\n:from => @users\n end") + @checker.check_mailers + + assert ! @checker.alerts.has_key?("Old ActionMailer class API") + end + + def test_new_check_mailer_syntax_subject + make_file("app/models/", "notifications.rb", "def signup\n:subject => @users\n end") + @checker.check_mailers + + assert ! @checker.alerts.has_key?("Old ActionMailer class API") + end + + def test_new_check_mailer_syntax_attachments + make_file("app/models/", "notifications.rb", "def signup\nattachments['an-image.jp'] = File.read('an-image.jpg')\n end") + @checker.check_mailers + + assert ! @checker.alerts.has_key?("Old ActionMailer class API") + end + + def test_check_mailer_api + make_file("app/controllers/", "thing_controller.rb", "def signup\n Notifications.deliver_signup\n end") + @checker.check_mailers + + assert @checker.alerts.has_key?("Deprecated ActionMailer API") + end + + def test_check_generators + make_file("vendor/plugins/thing/generators/thing/", "thing_generator.rb", "def manifest\n m.whatever\n end") + @checker.check_generators + + assert @checker.alerts.has_key?("Old Rails generator API") + end + + def test_check_plugins + make_file("vendor/plugins/rspec-rails/", "whatever.rb", "def rspec; end") + @checker.check_plugins + + assert @checker.alerts.has_key?("Known broken plugins") + end + + def test_ignoring_comments + make_file("config/", "routes.rb", "# map.connect 'fail'") + @checker.check_routes + + assert !@checker.alerts.has_key?("Old router API") + end + + def test_check_deprecated_constants_in_app_code + make_file("app/controllers/", "thing_controller.rb", "class ThingController; THING = RAILS_ENV; end;") + @checker.check_deprecated_constants + + assert @checker.alerts.has_key?("Deprecated constant(s)") + end + + def test_check_deprecated_constants_in_lib + make_file("lib/", "extra_thing.rb", "class ExtraThing; THING = RAILS_ENV; end;") + @checker.check_deprecated_constants + + assert @checker.alerts.has_key?("Deprecated constant(s)") + end + + def test_check_deprecated_cookie_finds_nothing + @checker.check_old_cookie_secret + assert_equal false, @checker.alerts.has_key?("Deprecated cookie secret setting") + end + + def test_check_deprecated_cookie_settings + make_file("config/initializers/", "more_settings.rb", "ActionController::Base.cookie_verifier_secret = 'OMG'") + @checker.check_old_cookie_secret + + assert @checker.alerts.has_key?("Deprecated cookie secret setting") + end + + def test_check_deprecated_session_finds_nothing + @checker.check_old_session_secret + assert_equal false, @checker.alerts.has_key?("Deprecated session secret setting") + end + + def test_check_deprecated_session_secret + make_file("config/initializers/", "more_settings.rb", "ActionController::Base.session = {\n:whatever => 'woot'\n}") + @checker.check_old_session_secret + + assert @checker.alerts.has_key?("Deprecated session secret setting") + end + + def test_check_old_session_setting_finds_nothing + @checker.check_old_session_setting + assert_equal false, @checker.alerts.has_key?("Old session store setting") + end + + def test_check_deprecated_session_settings + make_file("config/initializers/", "more_settings.rb", "ActionController::Base.session_store = :cookie\nthings.awesome(:whatever)") + @checker.check_old_session_setting + + assert @checker.alerts.has_key?("Old session store setting") + end + + def test_check_helpers + make_file("app/views/users/", "test.html.erb", "blah blah blah<% form_for(:thing) do |f| %> <%= f.whatever %> <% end %>") + @checker.check_old_helpers + + assert @checker.alerts.has_key?("Deprecated ERb helper calls") + + end + + def test_check_old_helpers_lets_regular_blocks_pass + make_file("app/views/users/", "another_test.html.erb", "blah blah blah<% @some_items.each do |item| %> <%= item %> <% end %>") + @checker.check_old_helpers + + assert_equal @checker.alerts.has_key?("Deprecated ERb helper calls"), false + end + + def test_check_old_helpers_lets_regular_blocks_pass + make_file("app/views/users/", "another_test.html.erb", "blah blah blah<% @some_items.each do |item| %> <%= item %> <% end %>") + @checker.check_old_helpers + + assert_equal false, @checker.alerts.has_key?("Deprecated ERb helper calls") + end + + def test_check_old_ajax_helpers + make_file("app/views/sections", "section.js", "<%= link_to_remote 'section-', :update => 'sections', :url => {:action => :destroy, :controller => 'sections', :id => @section.id } %>") + @checker.check_old_ajax_helpers + + assert @checker.alerts.has_key?("Deprecated AJAX helper calls") + end + + def test_check_old_ajax_helpers + make_file("app/controllers", "application_controller.rb", "filter_parameter_logging :password") + @checker.check_old_filter_parameter + + assert @checker.alerts.has_key?("Deprecated filter_parameter_logging calls") + end + + def test_check_old_ajax_helpers_empty + @checker.check_old_ajax_helpers + + assert ! @checker.alerts.has_key?("Deprecated AJAX helper calls") + end + + def test_check_old_action_mailer_sent_on_setting + make_file("app/models", "mailer.rb", "sent_on Time.now") + @checker.check_old_action_mailer_sent_on_setting + + assert @checker.alerts.has_key?("Deprecated ActionMailer attribute :sent_on") + end + + def teardown + clear_files + + Dir.chdir(@old_dir) + end + + def make_file(where, name=nil, contents=nil) + FileUtils.mkdir_p "#{BASE_ROOT}/#{where}" + File.open("#{BASE_ROOT}/#{where}/#{name}", "w+") do |f| + f.write(contents) + end if name + end + + def clear_files + FileUtils.rm_rf(Dir.glob("#{BASE_ROOT}/*")) + end +end \ No newline at end of file diff --git a/vendor/plugins/rails_upgrade/test/gemfile_generator_test.rb b/vendor/plugins/rails_upgrade/test/gemfile_generator_test.rb new file mode 100644 index 00000000..afa8e83b --- /dev/null +++ b/vendor/plugins/rails_upgrade/test/gemfile_generator_test.rb @@ -0,0 +1,72 @@ +require 'test_helper' +require 'gemfile_generator' + +# Stub out methods on upgrader class +module Rails + module Upgrading + class GemfileGenerator + attr_writer :environment_code + + def has_environment? + true + end + + def environment_code + @environment_code + end + end + end +end + +class GemfileGeneratorTest < ActiveSupport::TestCase + PREAMBLE = < 'kamping'", generator.generate_gemfile + end + + def test_generates_with_all_options + generator = Rails::Upgrading::GemfileGenerator.new + generator.environment_code = "config.gem 'camping', :lib => 'kamping', :source => 'http://code.whytheluckystiff.net', :version => '2.1.1'" + + assert_equal PREAMBLE + "source 'http://code.whytheluckystiff.net'\ngem 'camping', '2.1.1', :require => 'kamping'", generator.generate_gemfile + end +end diff --git a/vendor/plugins/rails_upgrade/test/new_configuration_generator_test.rb b/vendor/plugins/rails_upgrade/test/new_configuration_generator_test.rb new file mode 100644 index 00000000..16756d9f --- /dev/null +++ b/vendor/plugins/rails_upgrade/test/new_configuration_generator_test.rb @@ -0,0 +1,63 @@ +require 'test_helper' +require 'new_configuration_generator' + +# Stub out methods on upgrader class +module Rails + module Upgrading + class NewConfigurationGenerator + attr_writer :environment_code + + def has_environment? + true + end + + def environment_code + @environment_code + end + + def app_name + "my_application" + end + end + end +end + +class NewConfigurationGeneratorTest < ActiveSupport::TestCase + FRAME = "# Put this in config/application.rb +require File.expand_path('../boot', __FILE__) + +module MyApplication + class Application < Rails::Application +%s + end +end" + + CONFIG = " config.what_have_you = 'thing' + config.action_controller = 'what'" + + CODE = "require 'w/e' + +this_happens_before_the(code) +more_before_the_code! + +Rails::Initializer.run do |config| +%s +end + +this_is_after_the_code +" + + def test_raises_error_with_no_code + generator = Rails::Upgrading::NewConfigurationGenerator.new + generator.environment_code = "" + + assert_raises(RuntimeError) { generator.generate_new_application_rb } + end + + def test_generates_with_code + generator = Rails::Upgrading::NewConfigurationGenerator.new + generator.environment_code = CODE % [CONFIG] + + assert_equal FRAME % [generator.indent(CONFIG)], generator.generate_new_application_rb + end +end \ No newline at end of file diff --git a/vendor/plugins/rails_upgrade/test/routes_upgrader_test.rb b/vendor/plugins/rails_upgrade/test/routes_upgrader_test.rb new file mode 100644 index 00000000..955bccec --- /dev/null +++ b/vendor/plugins/rails_upgrade/test/routes_upgrader_test.rb @@ -0,0 +1,218 @@ +require 'test_helper' +require 'routes_upgrader' + +# Stub out methods on upgrader class +module Rails + module Upgrading + class RoutesUpgrader + attr_writer :routes_code + + def has_routes_file? + true + end + + def routes_code + @routes_code + end + end + + class RouteGenerator + def app_name + "MyApplication" + end + end + end +end + +class RoutesUpgraderTest < ActiveSupport::TestCase + def setup + Rails::Upgrading::RouteRedrawer.stack = [] + end + + def test_generates_routes_file + routes_code = " + ActionController::Routing::Routes.draw do |map| + map.connect '/home', :controller => 'home', :action => 'index' + map.login '/login', :controller => 'sessions', :action => 'new' + + map.resources :hats + map.resource :store + end + " + + new_routes_code = "MyApplication::Application.routes.draw do + match '/home' => 'home#index' + match '/login' => 'sessions#new', :as => :login + resources :hats + resource :store +end +" + + upgrader = Rails::Upgrading::RoutesUpgrader.new + upgrader.routes_code = routes_code + + result = upgrader.generate_new_routes + + assert_equal new_routes_code, result + end + + def test_generates_code_for_regular_route + route = Rails::Upgrading::FakeRoute.new("/about", {:controller => 'static', :action => 'about'}) + assert_equal "match '/about' => 'static#about'", route.to_route_code + end + + def test_generates_code_for_named_route + route = Rails::Upgrading::FakeRoute.new("/about", {:controller => 'static', :action => 'about'}, "about") + assert_equal "match '/about' => 'static#about', :as => :about", route.to_route_code + end + + def test_generates_code_for_namespace + ns = Rails::Upgrading::FakeNamespace.new("static") + # Add a route to the namespace + ns << Rails::Upgrading::FakeRoute.new("/about", {:controller => 'static', :action => 'about'}) + + assert_equal "namespace :static do\nmatch '/about' => 'static#about'\nend\n", ns.to_route_code + end + + def test_generates_code_for_namespace_with_options + ns = Rails::Upgrading::FakeNamespace.new("static", { :path_prefix => 'prefix' }) + # Add a route to the namespace + ns << Rails::Upgrading::FakeRoute.new("/about", {:controller => 'static', :action => 'about'}) + + assert_equal "namespace :static, :path_prefix => 'prefix' do\nmatch '/about' => 'static#about'\nend\n", ns.to_route_code + end + + def test_generates_code_for_resources + route = Rails::Upgrading::FakeResourceRoute.new("hats") + assert_equal "resources :hats", route.to_route_code + end + + def test_generates_code_for_resources + route = Rails::Upgrading::FakeSingletonResourceRoute.new("hat") + assert_equal "resource :hat", route.to_route_code + end + + def test_generates_code_for_resources_with_block_and_options + routes_code = <<-ROUTES + ActionController::Routing::Routes.draw do |map| + map.resources :people, :collection => {:search => :get} do |p| + p.resource :vuvuzela + end + end + ROUTES + + upgrader = Rails::Upgrading::RoutesUpgrader.new + upgrader.routes_code = routes_code + result = upgrader.generate_new_routes + + assert_equal "MyApplication::Application.routes.draw do\n resources :people do\n collection do\n get :search\n end\n \n resource :vuvuzela\n end\n\nend\n", result + end + + def test_generates_code_for_resources_with_special_methods + route = Rails::Upgrading::FakeResourceRoute.new("hats", {:member => {:wear => :get}, :collection => {:toss => :post}}) + assert_equal "resources :hats do\ncollection do\npost :toss\nend\nmember do\nget :wear\nend\n\nend\n", route.to_route_code + end + + def test_generates_code_for_resources_with_multiple_special_methods_per_name + route = Rails::Upgrading::FakeResourceRoute.new("hats", {:member => {:wear => [:get, :put]}, :collection => {:toss => [:get, :post]}}) + assert_equal "resources :hats do\ncollection do\nget :toss\npost :toss\nend\nmember do\nget :wear\nput :wear\nend\n\nend\n", route.to_route_code + end + + def test_generates_code_for_route_with_extra_params + route = Rails::Upgrading::FakeRoute.new("/about", {:controller => 'static', :action => 'about', :something => 'extra'}) + assert_equal "match '/about' => 'static#about', :something => 'extra'", route.to_route_code + end + + def test_generates_code_for_route_with_requirements + route = Rails::Upgrading::FakeRoute.new("/foo", {:controller => 'foo', :action => 'bar', :requirements => {:digit => /%d/}}) + assert_equal "match '/foo' => 'foo#bar', :constraints => { :digit => /%d/ }", route.to_route_code + end + + def test_generates_code_for_root + routes_code = " + ActionController::Routing::Routes.draw do |map| + map.root :controller => 'home', :action => 'index' + end + " + + new_routes_code = "MyApplication::Application.routes.draw do + match '/' => 'home#index' +end +" + + upgrader = Rails::Upgrading::RoutesUpgrader.new + upgrader.routes_code = routes_code + + result = upgrader.generate_new_routes + + assert_equal new_routes_code, result + end + + def test_generates_code_for_default_route + routes_code = " + ActionController::Routing::Routes.draw do |map| + map.connect ':controller/:action/:id.:format' + map.connect ':controller/:action/:id' + end + " + + new_routes_code = "MyApplication::Application.routes.draw do + match '/:controller(/:action(/:id))' +end +" + + upgrader = Rails::Upgrading::RoutesUpgrader.new + upgrader.routes_code = routes_code + + result = upgrader.generate_new_routes + + assert_equal new_routes_code, result + end + + + def test_preserves_resources_except_option + route = Rails::Upgrading::FakeResourceRoute.new("hats", :except => [:index]) + assert_equal "resources :hats, :except => [:index]", route.to_route_code + end + + def test_preserves_resources_only_option + route = Rails::Upgrading::FakeResourceRoute.new("hats", :only => :show) + assert_equal "resources :hats, :only => :show", route.to_route_code + end + + def test_generates_code_for_delete_route + routes_code = %Q{ +ActionController::Routing::Routes.draw do |map| + map.sign_out '/sign_out', :controller => 'sessions', :action => 'destroy', :conditions => {:method => :delete} +end + } + + new_routes_code = %Q{ +MyApplication::Application.routes.draw do + match '/sign_out' => 'sessions#destroy', :as => :sign_out, :via => :delete +end + } + + upgrader = Rails::Upgrading::RoutesUpgrader.new + upgrader.routes_code = routes_code + assert_equal new_routes_code.strip, upgrader.generate_new_routes.strip + end + + def test_generates_code_for_delete_route + routes_code = %Q{ +ActionController::Routing::Routes.draw do |map| + map.sign_out '/sign_out', :controller => 'sessions', :action => 'destroy', :conditions => {:method => [:delete, :get]} +end + } + + new_routes_code = %Q{ +MyApplication::Application.routes.draw do + match '/sign_out' => 'sessions#destroy', :as => :sign_out, :via => [:delete, :get] +end + } + + upgrader = Rails::Upgrading::RoutesUpgrader.new + upgrader.routes_code = routes_code + assert_equal new_routes_code.strip, upgrader.generate_new_routes.strip + end +end diff --git a/vendor/plugins/rails_upgrade/test/test_helper.rb b/vendor/plugins/rails_upgrade/test/test_helper.rb new file mode 100644 index 00000000..eede0d0f --- /dev/null +++ b/vendor/plugins/rails_upgrade/test/test_helper.rb @@ -0,0 +1,5 @@ +require 'test/unit' + +require 'rubygems' +require 'active_support' +require 'active_support/test_case' diff --git a/vendor/plugins/rails_upgrade/uninstall.rb b/vendor/plugins/rails_upgrade/uninstall.rb new file mode 100644 index 00000000..97383334 --- /dev/null +++ b/vendor/plugins/rails_upgrade/uninstall.rb @@ -0,0 +1 @@ +# Uninstall hook code here From 86afd42148145b794908e80e5baf3c4237a5e34a Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Thu, 5 Apr 2012 22:19:47 +0200 Subject: [PATCH 102/134] Work in progress: has_many_polymorphs does not work with rails 3.2 because of intrusive changes in rails internals. I think we need to rip out this dependency... --- Gemfile | 62 +- Gemfile.lock | 90 +-- Gemfile.rails2.3 | 65 -- Gemfile.rails3 | 39 -- app/apis/todo_api.rb | 22 - app/controllers/application_controller.rb | 329 ++++++++++ app/helpers/application_helper.rb | 2 + app/helpers/application_helper.rb.rails2 | 301 --------- app/models/context.rb | 10 +- app/models/project.rb | 12 +- app/models/recurring_todo.rb | 4 +- app/models/todo.rb | 38 +- app/models/user.rb | 62 +- config/application.rb | 13 + config/database.yml.rails2 | 37 -- config/database.yml.tmpl | 34 +- config/environment.rb.rails2 | 119 ---- config/environments/cucumber.rb | 58 +- config/environments/development.rb | 7 + config/environments/development.rb.rails2 | 19 - config/environments/production.rb | 2 +- config/environments/production.rb.rails2 | 17 - config/environments/test.rb | 8 + .../cookie_verification_secret.rb | 7 - config/initializers/mongrel_workaround.rb | 107 ---- config/initializers/new_rails_defaults.rb | 21 - config/initializers/session_store.rb | 4 +- config/preinitializer.rb | 21 - config/routes.rb | 117 ++++ config/routes.rb.rails2 | 113 ---- config/site.yml.tmpl | 4 +- doc/README_FOR_APP | 2 - lib/authenticated_test_helper.rb | 113 ---- lib/login_system.rb | 33 +- lib/name_part_finder.rb | 5 - lib/tasks/.gitkeep | 0 lib/tasks/cucumber-tracks.rake | 38 -- lib/tasks/cucumber.rake | 53 -- lib/tasks/database.rake | 27 - lib/tasks/extract_fixtures.rake | 17 - lib/tasks/gems.rake | 34 -- lib/tasks/load_exported_fixtures.rake | 8 - lib/tasks/query_trace_toggle.rake | 50 -- lib/tasks/reset_password.rake | 23 - lib/tasks/rspec.rake | 144 ----- lib/tasks/setup_tracks.rake | 15 - lib/tasks/upgrade_sqlite_db.rake | 40 -- lib/tracks/config.rb | 27 - lib/tracks/todo_list.rb | 59 -- vendor/plugins/extra_validations/init.rb | 2 - .../lib/extra_validations.rb | 29 - .../plugins/open_id_authentication/CHANGELOG | 35 -- vendor/plugins/open_id_authentication/README | 231 ------- .../plugins/open_id_authentication/Rakefile | 22 - ...open_id_authentication_tables_generator.rb | 11 - .../templates/migration.rb | 20 - .../templates/migration.rb | 26 - ...open_id_authentication_tables_generator.rb | 11 - vendor/plugins/open_id_authentication/init.rb | 18 - .../lib/open_id_authentication.rb | 240 -------- .../lib/open_id_authentication/association.rb | 9 - .../lib/open_id_authentication/db_store.rb | 55 -- .../lib/open_id_authentication/nonce.rb | 5 - .../lib/open_id_authentication/request.rb | 23 - .../open_id_authentication/timeout_fixes.rb | 20 - .../tasks/open_id_authentication_tasks.rake | 30 - .../test/normalize_test.rb | 32 - .../test/open_id_authentication_test.rb | 46 -- .../test/status_test.rb | 14 - .../test/test_helper.rb | 17 - vendor/plugins/resource_feeder/README | 7 - vendor/plugins/resource_feeder/Rakefile | 22 - vendor/plugins/resource_feeder/init.rb | 2 - .../resource_feeder/lib/resource_feeder.rb | 2 - .../lib/resource_feeder/atom.rb | 67 -- .../lib/resource_feeder/common.rb | 24 - .../lib/resource_feeder/rss.rb | 68 --- .../resource_feeder/test/atom_feed_test.rb | 85 --- .../resource_feeder/test/rss_feed_test.rb | 86 --- .../resource_feeder/test/test_helper.rb | 64 -- .../plugins/simple_ldap_authenticator/README | 5 - .../simple_ldap_authenticator/Rakefile | 22 - .../plugins/simple_ldap_authenticator/init.rb | 2 - .../simple_ldap_authenticator/install.rb | 1 - .../lib/simple_ldap_authenticator.rb | 127 ---- .../simple_ldap_authenticator_tasks.rake | 4 - .../test/simple_ldap_authenticator_test.rb | 8 - vendor/plugins/skinny_spec/.gitignore | 2 - vendor/plugins/skinny_spec/README.rdoc | 270 -------- vendor/plugins/skinny_spec/Rakefile | 11 - .../additional/helper_overrides.txt | 58 -- .../skinny_scaffold_generator.rb | 102 ---- .../skinny_scaffold/templates/controller.rb | 105 ---- .../templates/controller_spec.rb | 93 --- .../skinny_scaffold/templates/form.html.erb | 25 - .../skinny_scaffold/templates/form.html.haml | 18 - .../templates/form.html_spec.rb | 40 -- .../skinny_scaffold/templates/helper.rb | 2 - .../skinny_scaffold/templates/helper_spec.rb | 5 - .../skinny_scaffold/templates/index.html.erb | 31 - .../skinny_scaffold/templates/index.html.haml | 23 - .../templates/index.html_spec.rb | 15 - .../templates/index_partial.html.erb | 12 - .../templates/index_partial.html.haml | 11 - .../templates/index_partial.html_spec.rb | 31 - .../skinny_scaffold/templates/migration.rb | 14 - .../skinny_scaffold/templates/model.rb | 2 - .../skinny_scaffold/templates/model_spec.rb | 25 - .../skinny_scaffold/templates/show.html.erb | 15 - .../skinny_scaffold/templates/show.html.haml | 13 - .../templates/show.html_spec.rb | 31 - .../lib/lucky_sneaks/common_spec_helpers.rb | 83 --- .../controller_request_helpers.rb | 67 -- .../lucky_sneaks/controller_spec_helpers.rb | 571 ----------------- .../lucky_sneaks/controller_stub_helpers.rb | 238 -------- .../lib/lucky_sneaks/model_spec_helpers.rb | 496 --------------- .../lib/lucky_sneaks/view_spec_helpers.rb | 577 ------------------ .../lib/lucky_sneaks/view_stub_helpers.rb | 15 - vendor/plugins/skinny_spec/lib/skinny_spec.rb | 26 - vendor/plugins/swf_fu/CHANGELOG.rdoc | 46 -- vendor/plugins/swf_fu/FLASH_OBJECT.rdoc | 31 - vendor/plugins/swf_fu/LICENSE | 29 - vendor/plugins/swf_fu/README.rdoc | 92 --- vendor/plugins/swf_fu/Rakefile | 22 - .../swf_fu/assets/javascripts/swfobject.js | 4 - .../swf_fu/assets/swfs/expressInstall.swf | Bin 727 -> 0 bytes vendor/plugins/swf_fu/init.rb | 14 - vendor/plugins/swf_fu/install.rb | 24 - .../helpers/asset_tag_helper/swf_asset.rb | 61 -- .../lib/action_view/helpers/swf_fu_helper.rb | 197 ------ vendor/plugins/swf_fu/test/results.rb | 42 -- vendor/plugins/swf_fu/test/swf_fu_test.rb | 159 ----- vendor/plugins/swf_fu/test/test_helper.rb | 20 - vendor/plugins/swf_fu/uninstall.rb | 6 - vendor/plugins/translate/MIT-LICENSE | 20 - vendor/plugins/translate/README | 63 -- vendor/plugins/translate/Rakefile | 11 - vendor/plugins/translate/init.rb | 8 - vendor/plugins/translate/lib/translate.rb | 8 - .../plugins/translate/lib/translate/file.rb | 35 -- .../plugins/translate/lib/translate/keys.rb | 152 ----- vendor/plugins/translate/lib/translate/log.rb | 35 -- .../plugins/translate/lib/translate/routes.rb | 11 - .../translate/lib/translate/storage.rb | 28 - .../translate/lib/translate_controller.rb | 165 ----- .../plugins/translate/lib/translate_helper.rb | 45 -- .../controllers/translate_controller_spec.rb | 129 ---- vendor/plugins/translate/spec/file_spec.rb | 54 -- .../files/translate/app/models/article.rb | 12 - .../files/translate/app/views/category.erb | 1 - .../files/translate/app/views/category.html | 1 - .../translate/app/views/category.html.erb | 1 - .../files/translate/app/views/category.rhtml | 5 - .../public/javascripts/application.js | 1 - vendor/plugins/translate/spec/keys_spec.rb | 179 ------ vendor/plugins/translate/spec/log_spec.rb | 47 -- vendor/plugins/translate/spec/spec_helper.rb | 11 - vendor/plugins/translate/spec/storage_spec.rb | 33 - vendor/plugins/translate/tasks/translate.rake | 178 ------ .../translate/views/layouts/translate.rhtml | 359 ----------- .../views/translate/_pagination.rhtml | 24 - .../translate/views/translate/index.rhtml | 114 ---- 162 files changed, 704 insertions(+), 8724 deletions(-) delete mode 100644 Gemfile.rails2.3 delete mode 100644 Gemfile.rails3 delete mode 100644 app/apis/todo_api.rb delete mode 100644 app/helpers/application_helper.rb.rails2 delete mode 100644 config/database.yml.rails2 delete mode 100644 config/environment.rb.rails2 delete mode 100644 config/environments/development.rb.rails2 delete mode 100644 config/environments/production.rb.rails2 delete mode 100644 config/initializers/cookie_verification_secret.rb delete mode 100644 config/initializers/mongrel_workaround.rb delete mode 100644 config/initializers/new_rails_defaults.rb delete mode 100644 config/preinitializer.rb delete mode 100644 config/routes.rb.rails2 delete mode 100644 doc/README_FOR_APP delete mode 100644 lib/authenticated_test_helper.rb delete mode 100644 lib/name_part_finder.rb delete mode 100644 lib/tasks/.gitkeep delete mode 100644 lib/tasks/cucumber-tracks.rake delete mode 100644 lib/tasks/cucumber.rake delete mode 100644 lib/tasks/database.rake delete mode 100644 lib/tasks/extract_fixtures.rake delete mode 100644 lib/tasks/gems.rake delete mode 100644 lib/tasks/load_exported_fixtures.rake delete mode 100644 lib/tasks/query_trace_toggle.rake delete mode 100644 lib/tasks/reset_password.rake delete mode 100644 lib/tasks/rspec.rake delete mode 100644 lib/tasks/setup_tracks.rake delete mode 100644 lib/tasks/upgrade_sqlite_db.rake delete mode 100644 lib/tracks/config.rb delete mode 100644 lib/tracks/todo_list.rb delete mode 100644 vendor/plugins/extra_validations/init.rb delete mode 100644 vendor/plugins/extra_validations/lib/extra_validations.rb delete mode 100644 vendor/plugins/open_id_authentication/CHANGELOG delete mode 100644 vendor/plugins/open_id_authentication/README delete mode 100644 vendor/plugins/open_id_authentication/Rakefile delete mode 100644 vendor/plugins/open_id_authentication/generators/open_id_authentication_tables/open_id_authentication_tables_generator.rb delete mode 100644 vendor/plugins/open_id_authentication/generators/open_id_authentication_tables/templates/migration.rb delete mode 100644 vendor/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/templates/migration.rb delete mode 100644 vendor/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/upgrade_open_id_authentication_tables_generator.rb delete mode 100644 vendor/plugins/open_id_authentication/init.rb delete mode 100644 vendor/plugins/open_id_authentication/lib/open_id_authentication.rb delete mode 100644 vendor/plugins/open_id_authentication/lib/open_id_authentication/association.rb delete mode 100644 vendor/plugins/open_id_authentication/lib/open_id_authentication/db_store.rb delete mode 100644 vendor/plugins/open_id_authentication/lib/open_id_authentication/nonce.rb delete mode 100644 vendor/plugins/open_id_authentication/lib/open_id_authentication/request.rb delete mode 100644 vendor/plugins/open_id_authentication/lib/open_id_authentication/timeout_fixes.rb delete mode 100644 vendor/plugins/open_id_authentication/tasks/open_id_authentication_tasks.rake delete mode 100644 vendor/plugins/open_id_authentication/test/normalize_test.rb delete mode 100644 vendor/plugins/open_id_authentication/test/open_id_authentication_test.rb delete mode 100644 vendor/plugins/open_id_authentication/test/status_test.rb delete mode 100644 vendor/plugins/open_id_authentication/test/test_helper.rb delete mode 100644 vendor/plugins/resource_feeder/README delete mode 100644 vendor/plugins/resource_feeder/Rakefile delete mode 100644 vendor/plugins/resource_feeder/init.rb delete mode 100644 vendor/plugins/resource_feeder/lib/resource_feeder.rb delete mode 100644 vendor/plugins/resource_feeder/lib/resource_feeder/atom.rb delete mode 100644 vendor/plugins/resource_feeder/lib/resource_feeder/common.rb delete mode 100644 vendor/plugins/resource_feeder/lib/resource_feeder/rss.rb delete mode 100644 vendor/plugins/resource_feeder/test/atom_feed_test.rb delete mode 100644 vendor/plugins/resource_feeder/test/rss_feed_test.rb delete mode 100644 vendor/plugins/resource_feeder/test/test_helper.rb delete mode 100644 vendor/plugins/simple_ldap_authenticator/README delete mode 100644 vendor/plugins/simple_ldap_authenticator/Rakefile delete mode 100644 vendor/plugins/simple_ldap_authenticator/init.rb delete mode 100644 vendor/plugins/simple_ldap_authenticator/install.rb delete mode 100644 vendor/plugins/simple_ldap_authenticator/lib/simple_ldap_authenticator.rb delete mode 100644 vendor/plugins/simple_ldap_authenticator/tasks/simple_ldap_authenticator_tasks.rake delete mode 100644 vendor/plugins/simple_ldap_authenticator/test/simple_ldap_authenticator_test.rb delete mode 100644 vendor/plugins/skinny_spec/.gitignore delete mode 100644 vendor/plugins/skinny_spec/README.rdoc delete mode 100644 vendor/plugins/skinny_spec/Rakefile delete mode 100644 vendor/plugins/skinny_spec/additional/helper_overrides.txt delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/skinny_scaffold_generator.rb delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/controller.rb delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/controller_spec.rb delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.erb delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.haml delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html_spec.rb delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/helper.rb delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/helper_spec.rb delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.erb delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.haml delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html_spec.rb delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.erb delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.haml delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html_spec.rb delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/migration.rb delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/model.rb delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/model_spec.rb delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.erb delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.haml delete mode 100644 vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html_spec.rb delete mode 100644 vendor/plugins/skinny_spec/lib/lucky_sneaks/common_spec_helpers.rb delete mode 100644 vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_request_helpers.rb delete mode 100644 vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_spec_helpers.rb delete mode 100644 vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_stub_helpers.rb delete mode 100644 vendor/plugins/skinny_spec/lib/lucky_sneaks/model_spec_helpers.rb delete mode 100644 vendor/plugins/skinny_spec/lib/lucky_sneaks/view_spec_helpers.rb delete mode 100644 vendor/plugins/skinny_spec/lib/lucky_sneaks/view_stub_helpers.rb delete mode 100644 vendor/plugins/skinny_spec/lib/skinny_spec.rb delete mode 100644 vendor/plugins/swf_fu/CHANGELOG.rdoc delete mode 100644 vendor/plugins/swf_fu/FLASH_OBJECT.rdoc delete mode 100644 vendor/plugins/swf_fu/LICENSE delete mode 100644 vendor/plugins/swf_fu/README.rdoc delete mode 100644 vendor/plugins/swf_fu/Rakefile delete mode 100644 vendor/plugins/swf_fu/assets/javascripts/swfobject.js delete mode 100755 vendor/plugins/swf_fu/assets/swfs/expressInstall.swf delete mode 100644 vendor/plugins/swf_fu/init.rb delete mode 100644 vendor/plugins/swf_fu/install.rb delete mode 100644 vendor/plugins/swf_fu/lib/action_view/helpers/asset_tag_helper/swf_asset.rb delete mode 100644 vendor/plugins/swf_fu/lib/action_view/helpers/swf_fu_helper.rb delete mode 100644 vendor/plugins/swf_fu/test/results.rb delete mode 100644 vendor/plugins/swf_fu/test/swf_fu_test.rb delete mode 100644 vendor/plugins/swf_fu/test/test_helper.rb delete mode 100644 vendor/plugins/swf_fu/uninstall.rb delete mode 100644 vendor/plugins/translate/MIT-LICENSE delete mode 100644 vendor/plugins/translate/README delete mode 100644 vendor/plugins/translate/Rakefile delete mode 100644 vendor/plugins/translate/init.rb delete mode 100644 vendor/plugins/translate/lib/translate.rb delete mode 100644 vendor/plugins/translate/lib/translate/file.rb delete mode 100644 vendor/plugins/translate/lib/translate/keys.rb delete mode 100644 vendor/plugins/translate/lib/translate/log.rb delete mode 100644 vendor/plugins/translate/lib/translate/routes.rb delete mode 100644 vendor/plugins/translate/lib/translate/storage.rb delete mode 100644 vendor/plugins/translate/lib/translate_controller.rb delete mode 100644 vendor/plugins/translate/lib/translate_helper.rb delete mode 100644 vendor/plugins/translate/spec/controllers/translate_controller_spec.rb delete mode 100644 vendor/plugins/translate/spec/file_spec.rb delete mode 100644 vendor/plugins/translate/spec/files/translate/app/models/article.rb delete mode 100644 vendor/plugins/translate/spec/files/translate/app/views/category.erb delete mode 100644 vendor/plugins/translate/spec/files/translate/app/views/category.html delete mode 100644 vendor/plugins/translate/spec/files/translate/app/views/category.html.erb delete mode 100644 vendor/plugins/translate/spec/files/translate/app/views/category.rhtml delete mode 100644 vendor/plugins/translate/spec/files/translate/public/javascripts/application.js delete mode 100644 vendor/plugins/translate/spec/keys_spec.rb delete mode 100644 vendor/plugins/translate/spec/log_spec.rb delete mode 100644 vendor/plugins/translate/spec/spec_helper.rb delete mode 100644 vendor/plugins/translate/spec/storage_spec.rb delete mode 100644 vendor/plugins/translate/tasks/translate.rake delete mode 100644 vendor/plugins/translate/views/layouts/translate.rhtml delete mode 100644 vendor/plugins/translate/views/translate/_pagination.rhtml delete mode 100644 vendor/plugins/translate/views/translate/index.rhtml diff --git a/Gemfile b/Gemfile index ab4e34b2..e4e9d0a8 100644 --- a/Gemfile +++ b/Gemfile @@ -5,8 +5,31 @@ gem 'rails', '3.2.3' # Bundle edge Rails instead: # gem 'rails', :git => 'git://github.com/rails/rails.git' -gem 'sqlite3' +# you may comment out the database driver you will not be using. +# This will prevent a native build of the driver. Building native drivers is not always possible on all hosters +gem "sqlite3" +gem "mysql2" +gem "highline", "~>1.5.0" +gem "RedCloth" +# gem "sanitize", "~>1.2.1" +# gem "will_paginate" +gem "has_many_polymorphs", :git => "git://github.com/lrbalt/has_many_polymorphs.git", :branch => "try" +gem "acts_as_list", "~>0.1.4" +gem "aasm", "~>2.2.0" +# TODO: gem "rubyjedi-actionwebservice", :require => "actionwebservice" +# gem "rubycas-client", "~>2.2.1" +# gem "ruby-openid", :require => "openid" +# gem "open_id_authentication" +# gem 'htmlentities', '~> 4.3.0' +# gem "mail" +# gem "swf_fu" + +# if RUBY_VERSION.to_f >= 1.9 +# gem "soap4r-ruby1.9" +# else +# gem "soap4r", "~>1.5.8" +# end # Gems used only for assets and not required # in production environments by default. @@ -23,7 +46,7 @@ end gem 'jquery-rails' # To use ActiveModel has_secure_password -# gem 'bcrypt-ruby', '~> 3.0.0' +gem 'bcrypt-ruby', '~> 3.0.0' # To use Jbuilder templates for JSON # gem 'jbuilder' @@ -36,3 +59,38 @@ gem 'jquery-rails' # To use debugger # gem 'ruby-debug19', :require => 'ruby-debug' + + +# group :development do +# if RUBY_VERSION.to_f >= 1.9 +# gem "ruby-debug19" +# gem "mongrel", "1.2.0.pre2" +# else +# gem "ruby-debug" +# gem "mongrel" +# end +# gem "yard" +# end +# +# group :test do +# gem "test-unit", "1.2.3" +# gem "flexmock" +# gem "ZenTest", ">=4.0.0" +# gem "hpricot" +# gem "hoe" +# gem "rspec-rails", "~>1.3.3" +# # TODO: gem "thoughtbot-factory_girl" +# gem 'memory_test_fix', '~>0.1.3' +# gem "capybara", ">=0.3.5" +# gem "selenium-webdriver" # Note that > 2.14 has problems: https://code.google.com/p/selenium/issues/detail?id=3075 +# gem "database_cleaner", ">=0.5.0" +# gem "cucumber-rails", "~>0.3.2" +# gem "aruba", "0.2.2", :path => "vendor/gems/aruba-0.2.2" + + # uncomment to use the webkit option. This depends on Qt to be installed + #gem "capybara-webkit" + + # uncomment to be able to make screenshots from scenarios + #gem "capybara-screenshot" + #gem "launchy" +# end diff --git a/Gemfile.lock b/Gemfile.lock index 6d053889..c7d44b87 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,16 @@ +GIT + remote: git://github.com/lrbalt/has_many_polymorphs.git + revision: bb0a7af8ac7418717954cab42a5476ca9806f858 + branch: try + specs: + has_many_polymorphs (3.0.0.beta1) + activerecord + GEM remote: https://rubygems.org/ specs: + RedCloth (4.2.9) + aasm (2.2.1) actionmailer (3.2.3) actionpack (= 3.2.3) mail (~> 2.4.4) @@ -28,56 +38,22 @@ GEM activesupport (3.2.3) i18n (~> 0.6) multi_json (~> 1.0) + acts_as_list (0.1.5) arel (3.0.2) + bcrypt-ruby (3.0.1) builder (3.0.0) -<<<<<<< HEAD - capybara (1.1.2) - mime-types (>= 1.16) - nokogiri (>= 1.3.3) - rack (>= 1.0.0) - rack-test (>= 0.5.4) - selenium-webdriver (~> 2.0) - xpath (~> 0.1.4) - cgi_multipart_eof_fix (2.5.0) - childprocess (0.3.1) - ffi (~> 1.0.6) - columnize (0.3.6) - cucumber (1.1.4) - builder (>= 2.1.2) - diff-lcs (>= 1.1.2) - gherkin (~> 2.7.1) - json (>= 1.4.6) - term-ansicolor (>= 1.0.6) - cucumber-rails (0.3.2) - cucumber (>= 0.8.0) - daemons (1.1.8) - database_cleaner (0.7.1) - diff-lcs (1.1.3) - fastthread (1.0.7) - ffi (1.0.11) - flexmock (0.9.0) - gem_plugin (0.2.3) - gherkin (2.7.7) - json (>= 1.4.6) - highline (1.5.2) - hoe (2.13.1) - rake (~> 0.8) - hpricot (0.8.6) - htmlentities (4.3.1) - httpclient (2.2.4) -======= coffee-rails (3.2.2) coffee-script (>= 2.2.0) railties (~> 3.2.0) coffee-script (2.2.0) coffee-script-source execjs - coffee-script-source (1.2.0) + coffee-script-source (1.3.1) erubis (2.7.0) execjs (1.3.0) multi_json (~> 1.0) + highline (1.5.2) hike (1.2.1) ->>>>>>> initial upgrade to rails 3.2.3 i18n (0.6.0) journey (1.0.3) jquery-rails (2.0.2) @@ -90,6 +66,7 @@ GEM treetop (~> 1.4.8) mime-types (1.18) multi_json (1.2.0) + mysql2 (0.3.11) polyglot (0.3.3) rack (1.4.1) rack-cache (1.2) @@ -131,7 +108,7 @@ GEM treetop (1.4.10) polyglot polyglot (>= 0.3.1) - tzinfo (0.3.32) + tzinfo (0.3.33) uglifier (1.2.4) execjs (>= 0.3.0) multi_json (>= 1.0.2) @@ -140,41 +117,16 @@ PLATFORMS ruby DEPENDENCIES -<<<<<<< HEAD - RedCloth (= 4.2.8) - ZenTest (>= 4.0.0) + RedCloth aasm (~> 2.2.0) acts_as_list (~> 0.1.4) - aruba (= 0.2.2)! - bcrypt-ruby (~> 2.1.4) - capybara (>= 0.3.5) - cucumber-rails (~> 0.3.2) - database_cleaner (>= 0.5.0) - flexmock - highline (~> 1.5.0) - hoe - hpricot - htmlentities (~> 4.3.0) - mail - memory_test_fix (~> 0.1.3) - mongrel - mysql - rack (= 1.1.0) - rails (~> 2.3.12) - rake (~> 0.8.7) - rspec-rails (~> 1.3.3) - ruby-debug - ruby-openid - rubycas-client (~> 2.2.1) - rubyjedi-actionwebservice - sanitize (~> 1.2.1) - selenium-webdriver - soap4r (~> 1.5.8) -======= + bcrypt-ruby (~> 3.0.0) coffee-rails (~> 3.2.1) + has_many_polymorphs! + highline (~> 1.5.0) jquery-rails + mysql2 rails (= 3.2.3) sass-rails (~> 3.2.3) ->>>>>>> initial upgrade to rails 3.2.3 sqlite3 uglifier (>= 1.0.3) diff --git a/Gemfile.rails2.3 b/Gemfile.rails2.3 deleted file mode 100644 index dc3af876..00000000 --- a/Gemfile.rails2.3 +++ /dev/null @@ -1,65 +0,0 @@ -source :gemcutter -source "http://gems.github.com/" - -gem "rake", "~>0.8.7" -gem "rails", "~>2.3.12" -gem "highline", "~>1.5.0" -gem "RedCloth", "4.2.8" -gem "sanitize", "~>1.2.1" -gem "rack", "1.1.0" -gem "will_paginate", "~> 2.3.15" -gem "has_many_polymorphs", "~> 2.13" -gem "acts_as_list", "~>0.1.4" -gem "aasm", "~>2.2.0" -gem "rubyjedi-actionwebservice", :require => "actionwebservice" -gem "rubycas-client", "~>2.2.1" -gem "ruby-openid", :require => "openid" - -# you may comment out the database driver you will not be using. -# This will prevent a native build of the driver. Building native drivers is not always possible on all hosters -gem "sqlite3" -gem "mysql" - -gem 'bcrypt-ruby', '~> 2.1.4' -gem 'htmlentities', '~> 4.3.0' -gem "mail" - -if RUBY_VERSION.to_f >= 1.9 - gem "soap4r-ruby1.9" -else - gem "soap4r", "~>1.5.8" -end - -group :development do - if RUBY_VERSION.to_f >= 1.9 - gem "ruby-debug19" - gem "mongrel", "1.2.0.pre2" - else - gem "ruby-debug" - gem "mongrel" - end - gem "yard" -end - -group :test do - gem "test-unit", "1.2.3" - gem "flexmock" - gem "ZenTest", ">=4.0.0" - gem "hpricot" - gem "hoe" - gem "rspec-rails", "~>1.3.3" - gem "thoughtbot-factory_girl" - gem 'memory_test_fix', '~>0.1.3' - gem "capybara", ">=0.3.5" - gem "selenium-webdriver" # Note that > 2.14 has problems: https://code.google.com/p/selenium/issues/detail?id=3075 - gem "database_cleaner", ">=0.5.0" - gem "cucumber-rails", "~>0.3.2" - gem "aruba", "0.2.2", :path => "vendor/gems/aruba-0.2.2" - - # uncomment to use the webkit option. This depends on Qt to be installed - #gem "capybara-webkit" - - # uncomment to be able to make screenshots from scenarios - #gem "capybara-screenshot" - #gem "launchy" -end diff --git a/Gemfile.rails3 b/Gemfile.rails3 deleted file mode 100644 index c07b2b6a..00000000 --- a/Gemfile.rails3 +++ /dev/null @@ -1,39 +0,0 @@ -source 'https://rubygems.org' - -gem 'rails', '3.2.3' - -# Bundle edge Rails instead: -# gem 'rails', :git => 'git://github.com/rails/rails.git' - -gem 'sqlite3' -gem 'mysql' - - -# Gems used only for assets and not required -# in production environments by default. -group :assets do - gem 'sass-rails', '~> 3.2.3' - gem 'coffee-rails', '~> 3.2.1' - - # See https://github.com/sstephenson/execjs#readme for more supported runtimes - # gem 'therubyracer', :platform => :ruby - - gem 'uglifier', '>= 1.0.3' -end - -gem 'jquery-rails' - -# To use ActiveModel has_secure_password -# gem 'bcrypt-ruby', '~> 3.0.0' - -# To use Jbuilder templates for JSON -# gem 'jbuilder' - -# Use unicorn as the app server -# gem 'unicorn' - -# Deploy with Capistrano -# gem 'capistrano' - -# To use debugger -# gem 'ruby-debug19', :require => 'ruby-debug' diff --git a/app/apis/todo_api.rb b/app/apis/todo_api.rb deleted file mode 100644 index 5f980a64..00000000 --- a/app/apis/todo_api.rb +++ /dev/null @@ -1,22 +0,0 @@ -class TodoApi < ActionWebService::API::Base - api_method :new_todo, - :expects => [{:username => :string}, {:token => :string}, {:context_id => :int}, {:description => :string}, {:notes => :string}], - :returns => [:int] - - api_method :new_todo_for_project, - :expects => [{:username => :string}, {:token => :string}, {:context_id => :int}, {:project_id => :int}, {:description => :string}, {:notes => :string}], - :returns => [:int] - - api_method :new_rich_todo, - :expects => [{:username => :string}, {:token => :string}, {:default_context_id => :int}, {:description => :string}, {:notes => :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 diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index e8065d95..457ac53d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,3 +1,332 @@ +# 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 "tracks/source_view" + class ApplicationController < ActionController::Base + protect_from_forgery + + helper :application + include LoginSystem + helper_method :current_user, :prefs, :format_date, :markdown + + layout proc{ |controller| controller.mobile? ? "mobile" : "standard" } + # exempt_from_layout /\.js\.erb$/ + + before_filter :check_for_deprecated_password_hash + before_filter :set_session_expiration + before_filter :set_time_zone + before_filter :set_zindex_counter + before_filter :set_locale + prepend_before_filter :login_required + prepend_before_filter :enable_mobile_content_negotiation + after_filter :set_charset + + # By default, sets the charset to UTF-8 if it isn't already set + def set_charset + headers["Content-Type"] ||= "text/html; charset=UTF-8" + end + + def set_locale + locale = params[:locale] # specifying a locale in the request takes precedence + locale = locale || prefs.locale unless current_user.nil? # otherwise, the locale of the currently logged in user takes over + locale = locale || request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first if request.env['HTTP_ACCEPT_LANGUAGE'] + I18n.locale = locale.nil? ? I18n.default_locale : (I18n::available_locales.include?(locale.to_sym) ? locale : I18n.default_locale) + logger.debug("Selected '#{I18n.locale}' as locale") + end + + def set_session_expiration + # http://wiki.rubyonrails.com/rails/show/HowtoChangeSessionOptions + unless session == nil + return if self.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 + + # Redirects to change_password_user_path if the current user uses a + # deprecated password hashing algorithm. + def check_for_deprecated_password_hash + if current_user and current_user.uses_deprecated_password? + notify :warning, t('users.you_have_to_reset_your_password') + redirect_to change_password_user_path current_user + end + end + + def render_failure message, status = 404 + render :text => message, :status => status + end + + # def rescue_action(exception) + # log_error(exception) if logger + # respond_to do |format| + # format.html do + # notify :warning, "An error occurred on the server." + # render :action => "index" + # end + # format.js { render :action => 'error' } + # format.xml { render :text => 'An error occurred on the server.' + $! } + # end + # end + + # Returns a count of next actions in the given context or project The result + # is count and a string descriptor, correctly pluralised if there are no + # actions or multiple actions + # + def count_undone_todos_phrase(todos_parent, string="actions") + count = count_undone_todos(todos_parent) + deferred_count = count_deferred_todos(todos_parent) + if count == 0 && deferred_count > 0 + word = deferred_count == 1 ? string.singularize : string.pluralize + word = "deferred " + word + deferred_count.to_s + " " + word + else + word = count == 1 ? string.singularize : string.pluralize + count.to_s + " " + word + end + 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 + + def count_deferred_todos(todos_parent) + if todos_parent.nil? + count = 0 + else + count = todos_parent.todos.deferred.count + end + end + + # Convert a date object to the format specified in the user's preferences in + # config/settings.yml + # + def format_date(date) + return date ? date.in_time_zone(prefs.time_zone).strftime("#{prefs.date_format}") : '' + end + + def for_autocomplete(coll, substr) + if substr # protect agains empty request + filtered = coll.find_all{|item| item.name.downcase.include? substr.downcase} + json_elems = Array[*filtered.map{ |e| {:id => e.id.to_s, :value => e.name} }].to_json + return json_elems + else + return "" + end + end + + def format_dependencies_as_json_for_auto_complete(entries) + json_elems = Array[*entries.map{ |e| {:value => e.id.to_s, :label => e.specification} }].to_json + return json_elems + end + + # Uses RedCloth to transform text using either Textile or Markdown Need to + # require redcloth above RedCloth 3.0 or greater is needed to use Markdown, + # otherwise it only handles Textile + # + def markdown(text) + RedCloth.new(text).to_html + end + + # Here's the concept behind this "mobile content negotiation" hack: In + # addition to the main, AJAXy Web UI, Tracks has a lightweight low-feature + # 'mobile' version designed to be suitablef or use from a phone or PDA. It + # makes some sense that tne pages of that mobile version are simply alternate + # representations of the same Todo resources. The implementation goal was to + # treat mobile as another format and be able to use respond_to to render both + # versions. Unfortunately, I ran into a lot of trouble simply registering a + # new mime type 'text/html' with format :m because :html already is linked to + # that mime type and the new registration was forcing all html requests to be + # rendered in the mobile view. The before_filter and after_filter hackery + # below accomplishs that implementation goal by using a 'fake' mime type + # during the processing and then setting it to 'text/html' in an + # 'after_filter' -LKM 2007-04-01 + def mobile? + return params[:format] == 'm' + end + + def enable_mobile_content_negotiation + if mobile? + request.format = :m + end + end + + def create_todo_from_recurring_todo(rt, date=nil) + # create todo and initialize with data from recurring_todo rt + todo = current_user.todos.build( { :description => rt.description, :notes => rt.notes, :project_id => rt.project_id, :context_id => rt.context_id}) + todo.recurring_todo_id = rt.id + + # set dates + todo.due = rt.get_due_date(date) + + show_from_date = rt.get_show_from_date(date) + if show_from_date.nil? + todo.show_from=nil + else + # make sure that show_from is not in the past + todo.show_from = show_from_date < Time.zone.now ? nil : show_from_date + end + + saved = todo.save + if saved + todo.tag_with(rt.tag_list) + todo.tags.reload + end + + # increate number of occurences created from recurring todo + rt.inc_occurences + + # mark recurring todo complete if there are no next actions left + checkdate = todo.due.nil? ? todo.show_from : todo.due + rt.toggle_completion! unless rt.has_next_todo(checkdate) + + return saved ? todo : nil + end + + def handle_unverified_request + unless request.format=="application/xml" + super # handle xml http auth via our own login code + end + end + + protected + + def admin_login_required + unless User.find_by_id_and_is_admin(session['user_id'], true) + render :text => t('errors.user_unauthorized'), :status => 401 + return false + end + end + + def redirect_back_or_home + respond_to do |format| + format.html { redirect_back_or_default home_url } + format.m { redirect_back_or_default mobile_url } + end + end + + def boolean_param(param_name) + return false if param_name.blank? + s = params[param_name] + 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 + + def self.openid_enabled? + Tracks::Config.openid_enabled? + end + + def openid_enabled? + self.class.openid_enabled? + end + + def self.cas_enabled? + Tracks::Config.cas_enabled? + end + + def cas_enabled? + self.class.cas_enabled? + end + + def self.prefered_auth? + Tracks::Config.prefered_auth? + end + + def prefered_auth? + self.class.prefered_auth? + end + + # all completed todos [today@00:00, today@now] + def get_done_today(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES}) + start_of_this_day = Time.zone.now.beginning_of_day + completed_todos.completed_after(start_of_this_day).all(includes) + end + + # all completed todos [begin_of_week, start_of_today] + def get_done_this_week(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES}) + start_of_this_week = Time.zone.now.beginning_of_week + start_of_this_day = Time.zone.now.beginning_of_day + completed_todos.completed_before(start_of_this_day).completed_after(start_of_this_week).all(includes) + end + + # all completed todos [begin_of_month, begin_of_week] + def get_done_this_month(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES}) + start_of_this_month = Time.zone.now.beginning_of_month + start_of_this_week = Time.zone.now.beginning_of_week + completed_todos.completed_before(start_of_this_week).completed_after(start_of_this_month).all(includes) + end + + private + + def parse_date_per_user_prefs( s ) + prefs.parse_date(s) + end + + def init_data_for_sidebar + @completed_projects = current_user.projects.completed + @hidden_projects = current_user.projects.hidden + @active_projects = current_user.projects.active + + @active_contexts = current_user.contexts.active + @hidden_contexts = current_user.contexts.hidden + + init_not_done_counts + if prefs.show_hidden_projects_in_sidebar + init_project_hidden_todo_counts(['project']) + end + end + + def init_not_done_counts(parents = ['project','context']) + parents.each do |parent| + eval("@#{parent}_not_done_counts = @#{parent}_not_done_counts || current_user.todos.active.count(:group => :#{parent}_id)") + end + end + + def init_project_hidden_todo_counts(parents = ['project','context']) + parents.each do |parent| + eval("@#{parent}_project_hidden_todo_counts = @#{parent}_project_hidden_todo_counts || current_user.todos.count(:conditions => ['state = ? or state = ?', 'project_hidden', 'active'], :group => :#{parent}_id)") + end + end + + # 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 + + def set_time_zone + Time.zone = current_user.prefs.time_zone if logged_in? + end + + def set_zindex_counter + # this counter can be used to handle the IE z-index bug + @z_index_counter = 500 + end + end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 915c9f8e..183b4c31 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,3 +1,5 @@ +# The methods added to this helper will be available to all templates in the +# application. module ApplicationHelper # Replicates the link_to method but also checks request.request_uri to find diff --git a/app/helpers/application_helper.rb.rails2 b/app/helpers/application_helper.rb.rails2 deleted file mode 100644 index 39c591e4..00000000 --- a/app/helpers/application_helper.rb.rails2 +++ /dev/null @@ -1,301 +0,0 @@ -# The methods added to this helper will be available to all templates in the -# application. -module ApplicationHelper - - # Replicates the link_to method but also checks request.request_uri to find - # current page. If that matches the url, the link is marked id = "current" - # - def navigation_link(name, options = {}, html_options = nil, *parameters_for_method_reference) - if html_options - html_options = html_options.stringify_keys - 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\"" : "" - - "#{name || url}" - end - - def days_from_today(date) - date.in_time_zone.to_date - current_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) - return "" if due.nil? - - days = days_from_today(due) - - colors = ['amber','amber','orange','orange','orange','orange','orange','orange'] - color = :red if days < 0 - color = :green if days > 7 - color = colors[days] if color.nil? - - return content_tag(:a, {:title => format_date(due)}) { - content_tag(:span, {:class => color}) { - case days - when 0 - t('todos.next_actions_due_date.due_today') - when 1 - t('todos.next_actions_due_date.due_tomorrow') - when 2..7 - if prefs.due_style == Preference.due_styles[:due_on] - # TODO: internationalize strftime here - t('models.preference.due_on', :date => due.strftime("%A")) - else - t('models.preference.due_in', :days => days) - end - else - # overdue or due very soon! sound the alarm! - if days == -1 - t('todos.next_actions_due_date.overdue_by', :days => days * -1) - elsif days < -1 - t('todos.next_actions_due_date.overdue_by_plural', :days => days * -1) - else - # more than a week away - relax - t('models.preference.due_in', :days => days) - end - end - } - } - end - - # Check due date in comparison to today's date Flag up date appropriately with - # 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 - when 0 - ""+ format_date(due) + "" - when 1 - "" + format_date(due) + "" - # due 2-7 days away - when 2..7 - "" + format_date(due) + "" - else - # overdue or due very soon! sound the alarm! - if days < 0 - "" + format_date(due) +"" - else - # more than a week away - relax - "" + format_date(due) + "" - end - 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(" "," ") - end - - def count_undone_todos_and_notes_phrase(project, string="actions") - s = count_undone_todos_phrase(project, string) - s += ", #{pluralize(project.note_count, 'note')}" unless project.note_count == 0 - s - end - - def link_to_context(context, descriptor = sanitize(context.name)) - link_to( descriptor, context, :title => "View context: #{context.name}" ) - end - - def link_to_project(project, descriptor = sanitize(project.name)) - link_to( descriptor, project, :title => "View project: #{project.name}" ) - end - - def link_to_edit_note (note, descriptor = sanitize(note.id.to_s)) - link_to(descriptor, - url_for({:controller => 'notes', :action => 'edit', :id => note.id}), - {:id => "link_edit_#{dom_id(note)}", :class => "note_edit_settings"}) - end - - def link_to_project_mobile(project, accesskey, descriptor = sanitize(project.name)) - link_to( descriptor, project_path(project, :format => 'm'), {:title => "View project: #{project.name}", :accesskey => accesskey} ) - end - - def item_link_to_context(item) - descriptor = "[C]" - descriptor = "[#{item.context.name}]" if prefs.verbose_action_descriptors - link_to_context( item.context, descriptor ) - end - - def item_link_to_project(item) - descriptor = "[P]" - descriptor = "[#{item.project.name}]" if prefs.verbose_action_descriptors - link_to_project( item.project, descriptor ) - end - - def render_flash - render :partial => 'shared/flash', :object => flash - end - - def recurrence_time_span(rt) - case rt.ends_on - when "no_end_date" - return rt.start_from.nil? ? "" : I18n.t("todos.recurrence.pattern.from") + " " + format_date(rt.start_from) - when "ends_on_number_of_times" - return I18n.t("todos.recurrence.pattern.times", :number => rt.number_of_occurences) - when "ends_on_end_date" - starts = rt.start_from.nil? ? "" : I18n.t("todos.recurrence.pattern.from") + " " + format_date(rt.start_from) - ends = rt.end_date.nil? ? "" : " " + I18n.t("todos.recurrence.pattern.until") + " " + format_date(rt.end_date) - return starts+ends - else - raise Exception.new, "unknown recurrence time span selection (#{rt.ends_on})" - end - end - - def recurrence_pattern_as_text(recurring_todo) - rt = recurring_todo.recurring_target_as_text - rp = recurring_todo.recurrence_pattern - # only add space if recurrence_pattern has content - rp = " " + rp if !rp.nil? - rts = recurrence_time_span(recurring_todo) - # only add space if recurrence_time_span has content - rts = " " + rts if !(rts == "") - return rt+rp+rts - end - - def date_format_for_date_picker() - standard_format = current_user.prefs.date_format - translations = [ - ['%m', 'mm'], - ['%b', 'M'], - ['%B', 'MM'], - ['%d', 'dd'], - ['%a', 'D'], - ['%A', 'DD'], - ['%y', 'y'], - ['%Y', 'yy'] - ] - translations.inject(standard_format) do |str, translation| - str.gsub(*translation) - end - end - - AUTO_LINK_MESSAGE_RE = %r{message://<[^>]+>} unless const_defined?(:AUTO_LINK_MESSAGE_RE) - - # Converts message:// links to href. This URL scheme is used on Mac OS X - # to link to a mail message in Mail.app. - def auto_link_message(text) - text.gsub(AUTO_LINK_MESSAGE_RE) do - href = $& - left, right = $`, $' - # detect already linked URLs and URLs in the middle of a tag - if left =~ /<[^>]+$/ && right =~ /^[^>]*>/ - # do not change string; URL is alreay linked - href - else - content = content_tag(:a, h(href), :href => h(href)) - end - end - end - - def format_note(note) - note = auto_link_message(note) - note = markdown(note) - note = auto_link(note, :link => :urls) - - # add onenote and message protocols - Sanitize::Config::RELAXED[:protocols]['a']['href'] << 'onenote' - Sanitize::Config::RELAXED[:protocols]['a']['href'] << 'message' - - note = Sanitize.clean(note, Sanitize::Config::RELAXED) - return note - end - - def sidebar_html_for_titled_list (list, title) - return content_tag(:h3, title+" (#{list.length})") + - content_tag(:ul, sidebar_html_for_list(list)) - end - - def sidebar_html_for_list(list) - if list.empty? - return content_tag(:li, t('sidebar.list_empty')) - else - return list.inject("") do |html, item| - link = (item.class == "Project") ? link_to_project( item ) : link_to_context(item) - html << content_tag(:li, link + " (" + count_undone_todos_phrase(item,"actions")+")") - end - end - end - - def generate_i18n_strings - js = "i18n_locale='#{I18n.locale}';\n" - js << "i18n = new Array();\n" - %w{ - shared.toggle_multi shared.toggle_multi_title - shared.hide_form shared.hide_action_form_title - shared.toggle_single shared.toggle_single_title - projects.hide_form projects.hide_form_title - projects.show_form projects.show_form_title - contexts.hide_form contexts.hide_form_title - contexts.show_form contexts.show_form_title - contexts.new_context_pre contexts.new_context_post - common.cancel common.ok - common.ajaxError todos.unresolved_dependency - }.each do |s| - js << "i18n['#{s}'] = '#{ t(s).gsub(/'/, "\\\\'") }';\n" - end - return js - end - - def javascript_tag_for_i18n_datepicker - locale = I18n.locale - # do not include en as locale since this the available by default - if locale and locale != :en - javascript_include_tag("i18n/jquery.ui.datepicker-#{locale}.js") - end - end - - def determine_done_path - case @controller.controller_name - when "contexts" - done_todos_context_path(@context) - when "projects" - done_todos_project_path(@project) - when "todos" - if source_view_is(:tag) - done_tag_path(@tag_name) - else - done_todos_path - end - else - done_todos_path - end - end - - def determine_all_done_path - case @controller.controller_name - when "contexts" - all_done_todos_context_path(@context) - when "projects" - all_done_todos_project_path(@project) - when "todos" - if source_view_is(:tag) - all_done_tag_path(@tag_name) - else - all_done_todos_path - end - else - all_done_todos_path - end - end - -end diff --git a/app/models/context.rb b/app/models/context.rb index 2a797397..ee97a134 100644 --- a/app/models/context.rb +++ b/app/models/context.rb @@ -5,19 +5,19 @@ class Context < ActiveRecord::Base has_many :recurring_todos, :dependent => :delete_all belongs_to :user - named_scope :active, :conditions => { :hide => false } - named_scope :hidden, :conditions => { :hide => true } + scope :active, :conditions => { :hide => false } + scope :hidden, :conditions => { :hide => true } acts_as_list :scope => :user, :top_of_list => 0 - extend NamePartFinder - include Tracks::TodoList + # extend NamePartFinder + # include Tracks::TodoList 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 comma (',') character" +# validates_does_not_contain :name, :string => ',', :message => "cannot contain the comma (',') character" def self.feed_options(user) # TODO: move to view or helper diff --git a/app/models/project.rb b/app/models/project.rb index adba4559..c9a845cc 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -6,10 +6,10 @@ class Project < ActiveRecord::Base belongs_to :default_context, :class_name => "Context", :foreign_key => "default_context_id" belongs_to :user - named_scope :active, :conditions => { :state => 'active' } - named_scope :hidden, :conditions => { :state => 'hidden' } - named_scope :completed, :conditions => { :state => 'completed'} - named_scope :uncompleted, :conditions => ["NOT(state = ?)", 'completed'] + scope :active, :conditions => { :state => 'active' } + scope :hidden, :conditions => { :state => 'hidden' } + scope :completed, :conditions => { :state => 'completed'} + scope :uncompleted, :conditions => ["NOT(state = ?)", 'completed'] validates_presence_of :name validates_length_of :name, :maximum => 255 @@ -21,8 +21,8 @@ class Project < ActiveRecord::Base aasm_column :state aasm_initial_state :active - extend NamePartFinder - #include Tracks::TodoList + # extend NamePartFinder + # include Tracks::TodoList aasm_state :active aasm_state :hidden, :enter => :hide_todos, :exit => :unhide_todos diff --git a/app/models/recurring_todo.rb b/app/models/recurring_todo.rb index f3ef3363..869750d8 100644 --- a/app/models/recurring_todo.rb +++ b/app/models/recurring_todo.rb @@ -8,8 +8,8 @@ class RecurringTodo < ActiveRecord::Base include IsTaggable - named_scope :active, :conditions => { :state => 'active'} - named_scope :completed, :conditions => { :state => 'completed'} + scope :active, :conditions => { :state => 'active'} + scope :completed, :conditions => { :state => 'completed'} attr_protected :user diff --git a/app/models/todo.rb b/app/models/todo.rb index 1d3a3b83..75f1fef4 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -23,33 +23,33 @@ class Todo < ActiveRecord::Base :source => :successor, :conditions => ['todos.state = ?', 'pending'] # scopes for states of this todo - named_scope :active, :conditions => { :state => 'active' } - named_scope :active_or_hidden, :conditions => ["todos.state = ? OR todos.state = ?", 'active', 'project_hidden'] - named_scope :not_completed, :conditions => ['NOT (todos.state = ?)', 'completed'] - named_scope :completed, :conditions => ["NOT (todos.completed_at IS NULL)"] - named_scope :deferred, :conditions => ["todos.completed_at IS NULL AND NOT (todos.show_from IS NULL)"] - named_scope :blocked, :conditions => ['todos.state = ?', 'pending'] - named_scope :pending, :conditions => ['todos.state = ?', 'pending'] - named_scope :deferred_or_blocked, :conditions => ["(todos.completed_at IS NULL AND NOT(todos.show_from IS NULL)) OR (todos.state = ?)", "pending"] - named_scope :not_deferred_or_blocked, :conditions => ["(todos.completed_at IS NULL) AND (todos.show_from IS NULL) AND (NOT todos.state = ?)", "pending"] - named_scope :hidden, + scope :active, :conditions => { :state => 'active' } + scope :active_or_hidden, :conditions => ["todos.state = ? OR todos.state = ?", 'active', 'project_hidden'] + scope :not_completed, :conditions => ['NOT (todos.state = ?)', 'completed'] + scope :completed, :conditions => ["NOT (todos.completed_at IS NULL)"] + scope :deferred, :conditions => ["todos.completed_at IS NULL AND NOT (todos.show_from IS NULL)"] + scope :blocked, :conditions => ['todos.state = ?', 'pending'] + scope :pending, :conditions => ['todos.state = ?', 'pending'] + scope :deferred_or_blocked, :conditions => ["(todos.completed_at IS NULL AND NOT(todos.show_from IS NULL)) OR (todos.state = ?)", "pending"] + scope :not_deferred_or_blocked, :conditions => ["(todos.completed_at IS NULL) AND (todos.show_from IS NULL) AND (NOT todos.state = ?)", "pending"] + scope :hidden, :joins => "INNER JOIN contexts c_hidden ON c_hidden.id = todos.context_id", :conditions => ["todos.state = ? OR (c_hidden.hide = ? AND (todos.state = ? OR todos.state = ? OR todos.state = ?))", 'project_hidden', true, 'active', 'deferred', 'pending'] - named_scope :not_hidden, + scope :not_hidden, :joins => "INNER JOIN contexts c_hidden ON c_hidden.id = todos.context_id", :conditions => ['NOT(todos.state = ? OR (c_hidden.hide = ? AND (todos.state = ? OR todos.state = ? OR todos.state = ?)))', 'project_hidden', true, 'active', 'deferred', 'pending'] # other scopes - named_scope :are_due, :conditions => ['NOT (todos.due IS NULL)'] - named_scope :with_tag, lambda { |tag_id| {:joins => :taggings, :conditions => ["taggings.tag_id = ? ", tag_id] } } - named_scope :with_tags, lambda { |tag_ids| {:conditions => ["EXISTS(SELECT * from taggings t WHERE t.tag_id IN (?) AND t.taggable_id=todos.id AND t.taggable_type='Todo')", tag_ids] } } - named_scope :of_user, lambda { |user_id| {:conditions => ["todos.user_id = ? ", user_id] } } - named_scope :completed_after, lambda { |date| {:conditions => ["todos.completed_at > ?", date] } } - named_scope :completed_before, lambda { |date| {:conditions => ["todos.completed_at < ?", date] } } - named_scope :created_after, lambda { |date| {:conditions => ["todos.created_at > ?", date] } } - named_scope :created_before, lambda { |date| {:conditions => ["todos.created_at < ?", date] } } + scope :are_due, :conditions => ['NOT (todos.due IS NULL)'] + scope :with_tag, lambda { |tag_id| {:joins => :taggings, :conditions => ["taggings.tag_id = ? ", tag_id] } } + scope :with_tags, lambda { |tag_ids| {:conditions => ["EXISTS(SELECT * from taggings t WHERE t.tag_id IN (?) AND t.taggable_id=todos.id AND t.taggable_type='Todo')", tag_ids] } } + scope :of_user, lambda { |user_id| {:conditions => ["todos.user_id = ? ", user_id] } } + scope :completed_after, lambda { |date| {:conditions => ["todos.completed_at > ?", date] } } + scope :completed_before, lambda { |date| {:conditions => ["todos.completed_at < ?", date] } } + scope :created_after, lambda { |date| {:conditions => ["todos.created_at > ?", date] } } + scope :created_before, lambda { |date| {:conditions => ["todos.created_at < ?", date] } } STARRED_TAG_NAME = "starred" DEFAULT_INCLUDES = [ :project, :context, :tags, :taggings, :pending_successors, :uncompleted_predecessors, :recurring_todo ] diff --git a/app/models/user.rb b/app/models/user.rb index 26ebe9c7..2dcaf367 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -9,9 +9,9 @@ class User < ActiveRecord::Base has_many :contexts, :order => 'position ASC', :dependent => :delete_all do - def find_by_params(params) - find(params['id'] || params['context_id']) || nil - end + # def find_by_params(params) + # find(params['id'] || params['context_id']) || nil + # end def update_positions(context_ids) context_ids.each_with_index {|id, position| context = self.detect { |c| c.id == id.to_i } @@ -23,9 +23,9 @@ class User < ActiveRecord::Base has_many :projects, :order => 'projects.position ASC', :dependent => :delete_all do - def find_by_params(params) - find(params['id'] || params['project_id']) - end + # def find_by_params(params) + # find(params['id'] || params['project_id']) + # end def update_positions(project_ids) project_ids.each_with_index {|id, position| project = self.detect { |p| p.id == id.to_i } @@ -100,11 +100,11 @@ class User < ActiveRecord::Base validates_confirmation_of :password validates_length_of :login, :within => 3..80 validates_uniqueness_of :login, :on => :create - validates_presence_of :open_id_url, :if => :using_openid? + # validates_presence_of :open_id_url, :if => :using_openid? before_create :crypt_password, :generate_token before_update :crypt_password - before_save :normalize_open_id_url + # before_save :normalize_open_id_url #for will_paginate plugin cattr_accessor :per_page @@ -145,10 +145,10 @@ class User < ActiveRecord::Base return nil end - def self.find_by_open_id_url(raw_identity_url) - normalized_open_id_url = OpenIdAuthentication.normalize_identifier(raw_identity_url) - find(:first, :conditions => ['open_id_url = ?', normalized_open_id_url]) - end + # def self.find_by_open_id_url(raw_identity_url) + # normalized_open_id_url = OpenIdAuthentication.normalize_identifier(raw_identity_url) + # find(:first, :conditions => ['open_id_url = ?', normalized_open_id_url]) + # end def self.no_users_yet? count == 0 @@ -192,7 +192,7 @@ class User < ActiveRecord::Base end def generate_token - self.token = sha1 "#{Time.now.to_i}#{rand}" + self.token = Digest::SHA1.hexdigest "#{Time.now.to_i}#{rand}" end def remember_token? @@ -202,14 +202,14 @@ class User < ActiveRecord::Base # These create and unset the fields required for remembering users between browser closes def remember_me self.remember_token_expires_at = 2.weeks.from_now.utc - self.remember_token ||= sha1("#{login}--#{remember_token_expires_at}") - save(false) + self.remember_token ||= Digest::SHA1.hexdigest("#{login}--#{remember_token_expires_at}") + save end def forget_me self.remember_token_expires_at = nil self.remember_token = nil - save(false) + save end # Returns true if the user has a password hashed using SHA-1. @@ -248,19 +248,19 @@ protected auth_type == 'database' && crypted_password.blank? || !password.blank? end - def using_openid? - auth_type == 'open_id' - end - - def normalize_open_id_url - return if open_id_url.nil? - - # fixup empty url value - if open_id_url.empty? - self.open_id_url = nil - return - end - - self.open_id_url = OpenIdAuthentication.normalize_identifier(open_id_url) - end + # def using_openid? + # auth_type == 'open_id' + # end + # + # def normalize_open_id_url + # return if open_id_url.nil? + # + # # fixup empty url value + # if open_id_url.empty? + # self.open_id_url = nil + # return + # end + # + # self.open_id_url = OpenIdAuthentication.normalize_identifier(open_id_url) + # end end diff --git a/config/application.rb b/config/application.rb index 9455b87e..1e249c52 100644 --- a/config/application.rb +++ b/config/application.rb @@ -9,6 +9,9 @@ if defined?(Bundler) # Bundler.require(:default, :assets, Rails.env) end +require 'yaml' +SITE_CONFIG = YAML.load_file(File.join(File.dirname(__FILE__), 'site.yml')) + module Tracksapp class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. @@ -28,6 +31,7 @@ module Tracksapp # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # config.time_zone = 'Central Time (US & Canada)' + config.time_zone = SITE_CONFIG['time_zone'] # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] @@ -49,11 +53,20 @@ module Tracksapp # in your app. As such, your models will need to explicitly whitelist or blacklist accessible # parameters by using an attr_accessible or attr_protected declaration. config.active_record.whitelist_attributes = true + + # Set timezone of dates in database + config.active_record.default_timezone = :utc # Enable the asset pipeline config.assets.enabled = true # Version of your assets, change this if you want to expire all your assets config.assets.version = '1.0' + + # configure Tracks to handle deployment in a subdir + config.action_controller.relative_url_root = SITE_CONFIG['subdir'] if SITE_CONFIG['subdir'] + + # allow onenote:// and message:// as protocols for urls + config.action_view.sanitized_allowed_protocols = 'onenote', 'message' end end diff --git a/config/database.yml.rails2 b/config/database.yml.rails2 deleted file mode 100644 index da7aebc8..00000000 --- a/config/database.yml.rails2 +++ /dev/null @@ -1,37 +0,0 @@ -# MySQL. Versions 4.1 and 5.0 are recommended. -# -# -# Be sure to use new-style password hashing: -# http://dev.mysql.com/doc/refman/5.0/en/old-client.html -development: - adapter: mysql - database: tracks_trunk - encoding: utf8 - host: localhost - username: tracks - password: 32tracks55 - -mdevelopment: - adapter: sqlite3 - database: db/tracks-21-test.sqlite3.db - -test: &TEST -# adapter: sqlite3 -# database: ":memory:" -# verbosity: quiet - adapter: mysql - database: tracks_test - host: localhost - username: tracks - password: 32tracks55 - -production: - adapter: mysql - database: tracks_trunk - encoding: utf8 - host: localhost - username: tracks - password: 32tracks55 - -cucumber: - <<: *TEST diff --git a/config/database.yml.tmpl b/config/database.yml.tmpl index 92f18f06..f2b6ef57 100644 --- a/config/database.yml.tmpl +++ b/config/database.yml.tmpl @@ -1,5 +1,15 @@ development: - adapter: mysql + adapter: mysql2 + database: tracks + # set this if you are storing utf8 in your mysql database to handle strings + # like "Réné". Not needed for sqlite. For PostgreSQL use encoding: unicode + # encoding: utf8 + host: localhost + username: root + password: + +production: + adapter: mysql2 database: tracks # set this if you are storing utf8 in your mysql database to handle strings # like "Réné".Not needed for sqlite. For PostgreSQL use encoding: unicode @@ -8,19 +18,21 @@ development: username: root password: +# The following is an example to configure Tracks to use sqlite + +#production: +# adapter: sqlite3 +# database: db/tracks-20-blank.sqlite3.db +# pool: 5 +# timeout: 5000 + + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. test: &TEST adapter: sqlite3 database: ":memory:" -production: - adapter: mysql - database: tracks - # set this if you are storing utf8 in your mysql database to handle strings - # like "Réné".Not needed for sqlite. For PostgreSQL use encoding: unicode - # encoding: utf8 - host: localhost - username: root - password: - cucumber: <<: *TEST diff --git a/config/environment.rb.rails2 b/config/environment.rb.rails2 deleted file mode 100644 index 390f585b..00000000 --- a/config/environment.rb.rails2 +++ /dev/null @@ -1,119 +0,0 @@ -# Be sure to restart your webserver when you modify this file. -# Uncomment below to force Rails into production mode - -# (Use only when you can't set environment variables through your web/app server) -# ENV['RAILS_ENV'] = 'production' - -# Bootstrap the Rails environment, frameworks, and default configuration -require File.join(File.dirname(__FILE__), 'boot') - -require 'yaml' -SITE_CONFIG = YAML.load_file(File.join(File.dirname(__FILE__), 'site.yml')) - -class Rails::Configuration - attr_accessor :action_web_service -end - -Encoding.default_external = Encoding::UTF_8 if RUBY_VERSION > "1.9" - -Rails::Initializer.run do |config| - # Skip frameworks you're not going to use - # config.frameworks -= [ :action_web_service, :action_mailer ] - config.autoload_paths += %W( #{RAILS_ROOT}/app/apis ) - - config.action_controller.use_accept_header = true - - # Use the database for sessions instead of the file system - # (create the session table with 'rake create_sessions_table') - config.action_controller.session_store = :active_record_store - - config.action_controller.session = { - :key => '_tracks_session_id', - :secret => SITE_CONFIG['salt'] * (30.0 / SITE_CONFIG['salt'].length).ceil #must be at least 30 characters - } - - config.action_controller.relative_url_root = SITE_CONFIG['subdir'] if SITE_CONFIG['subdir'] - - # Enable page/fragment caching by setting a file-based store - # (remember to create the caching directory and make it readable to the application) - # config.action_controller.fragment_cache_store = :file_store, "#{RAILS_ROOT}/cache" - - # Activate observers that should always be running - # config.active_record.observers = :cacher, :garbage_collector - - # Make Active Record use UTC-base instead of local time - config.active_record.default_timezone = :utc - - # You''ll probably want to change this to the time zone of the computer where Tracks is running - # run rake time:zones:local have Rails suggest time zone names on your system - config.time_zone = SITE_CONFIG['time_zone'] - - # Use Active Record's schema dumper instead of SQL when creating the test database - # (enables use of different database adapters for development and test environments) - config.active_record.schema_format = :ruby - - # allow other protocols in urls for sanitzer. Add to your liking, for example - # config.action_view.sanitized_allowed_protocols = 'onenote', 'blah', 'proto' - # to enable "link":onenote://... or "link":blah://... hyperlinks - config.action_view.sanitized_allowed_protocols = 'onenote', 'message' - - # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. - # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] - # config.i18n.default_locale = :de - -end - -# Add new inflection rules using the following format -# (all these examples are active by default): -# Inflector.inflections do |inflect| -# inflect.plural /^(ox)$/i, '\1en' -# inflect.singular /^(ox)en/i, '\1' -# inflect.irregular 'person', 'people' -# inflect.uncountable %w( fish sheep ) -# end - -# Include your application configuration below - - -require 'name_part_finder' -require 'tracks/todo_list' -require 'tracks/config' -require 'tagging_extensions' # Needed for tagging-specific extensions -require 'digest/sha1' #Needed to support 'rake db:fixtures:load' on some ruby installs: http://dev.rousette.org.uk/ticket/557 - -if ( SITE_CONFIG['authentication_schemes'].include? 'ldap') - require 'net/ldap' #requires ruby-net-ldap gem be installed - require 'simple_ldap_authenticator' - ldap = SITE_CONFIG['ldap'] - SimpleLdapAuthenticator.ldap_library = ldap['library'] - SimpleLdapAuthenticator.servers = ldap['servers'] - SimpleLdapAuthenticator.use_ssl = ldap['ssl'] - SimpleLdapAuthenticator.login_format = ldap['login_format'] -end - -if ( SITE_CONFIG['authentication_schemes'].include? 'open_id') - #requires ruby-openid gem to be installed - OpenID::Util.logger = RAILS_DEFAULT_LOGGER -end - -if ( SITE_CONFIG['authentication_schemes'].include? 'cas') - #requires rubycas-client gem to be installed - if defined? CASClient - require 'casclient/frameworks/rails/filter' - CASClient::Frameworks::Rails::Filter.configure( - :cas_base_url => SITE_CONFIG['cas_server'] , - :cas_server_logout => SITE_CONFIG['cas_server_logout'] - ) - end -end - -# changed in development.rb to show under_construction bar -NOTIFY_BAR = "" unless defined?(NOTIFY_BAR) - -tracks_version='2.2devel' -# comment out next two lines if you do not want (or can not) the date of the -# last git commit in the footer -info=`git log --pretty=format:"%ai" -1` -tracks_version=tracks_version + ' ('+info+')' - -TRACKS_VERSION=tracks_version diff --git a/config/environments/cucumber.rb b/config/environments/cucumber.rb index 7fdab2ac..329c3624 100644 --- a/config/environments/cucumber.rb +++ b/config/environments/cucumber.rb @@ -1,26 +1,44 @@ -# Edit at your own peril - it's recommended to regenerate this file -# in the future when you upgrade to a newer version of Cucumber. +Tracksapp::Application.configure do + # Settings specified here will take precedence over those in config/application.rb -# IMPORTANT: Setting config.cache_classes to false is known to -# break Cucumber's use_transactional_fixtures method. -# For more information see https://rspec.lighthouseapp.com/projects/16211/tickets/165 -config.cache_classes = true + # The test environment is used exclusively to run your application's + # test suite. You never need to work with it otherwise. Remember that + # your test database is "scratch space" for the test suite and is wiped + # and recreated between test runs. Don't rely on the data there! + config.cache_classes = true -# Log error messages when you accidentally call methods on nil. -config.whiny_nils = true + # Configure static asset server for tests with Cache-Control for performance + config.serve_static_assets = true + config.static_cache_control = "public, max-age=3600" -# Show full error reports and disable caching -config.action_controller.consider_all_requests_local = true -config.action_controller.perform_caching = false + # Log error messages when you accidentally call methods on nil + config.whiny_nils = true -# Disable request forgery protection in test environment -config.action_controller.allow_forgery_protection = false + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_controller.perform_caching = false -# Tell Action Mailer not to deliver emails to the real world. -# The :test delivery method accumulates sent emails in the -# ActionMailer::Base.deliveries array. -config.action_mailer.delivery_method = :test + # Raise exceptions instead of rendering exception templates + config.action_dispatch.show_exceptions = false -# Unique cookies and use cookies for session -config.action_controller.session_store = :cookie_store -config.action_controller.session = { :key => 'TracksCucumber', :secret => SITE_CONFIG['salt'] * (30.0 / SITE_CONFIG['salt'].length).ceil } \ No newline at end of file + # Disable request forgery protection in test environment + config.action_controller.allow_forgery_protection = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Raise exception on mass assignment protection for Active Record models + config.active_record.mass_assignment_sanitizer = :strict + + # Print deprecation notices to the stderr + config.active_support.deprecation = :stderr + + # Unique cookies and use cookies for session + # config.action_controller.session_store :cookie_store, :key => 'TracksCucumber' + + SITE_CONFIG['salt'] ||= 'change-me' + + config.time_zone = 'UTC' +end \ No newline at end of file diff --git a/config/environments/development.rb b/config/environments/development.rb index 8a835a34..d0d8ed54 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -34,4 +34,11 @@ Tracksapp::Application.configure do # Expands the lines which load the assets config.assets.debug = true + + # Unique cookies + # config.action_controller.session_store :cookie_store, :key => 'TracksCucumber' + # config.action_controller.session = { :key => 'TracksDev' } + + NOTIFY_BAR="
         
        " + end diff --git a/config/environments/development.rb.rails2 b/config/environments/development.rb.rails2 deleted file mode 100644 index 05c880d7..00000000 --- a/config/environments/development.rb.rails2 +++ /dev/null @@ -1,19 +0,0 @@ -# In the development environment your application's code is reloaded on -# every request. This slows down response time but is perfect for development -# since you don't have to restart the webserver when you make code changes. -config.cache_classes = false - -# Log error messages when you accidentally call methods on nil. -config.whiny_nils = true - -# Show full error reports and disable caching -config.action_controller.consider_all_requests_local = true -config.action_controller.perform_caching = false - -# Don't care if the mailer can't send -config.action_mailer.raise_delivery_errors = false - -# Unique cookies -config.action_controller.session = { :key => 'TracksDev' } - -NOTIFY_BAR="
         
        " diff --git a/config/environments/production.rb b/config/environments/production.rb index e43b1775..5f5d7431 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -63,5 +63,5 @@ Tracksapp::Application.configure do # Log the query plan for queries taking more than this (works # with SQLite, MySQL, and PostgreSQL) - # config.active_record.auto_explain_threshold_in_seconds = 0.5 + config.active_record.auto_explain_threshold_in_seconds = 0.5 end diff --git a/config/environments/production.rb.rails2 b/config/environments/production.rb.rails2 deleted file mode 100644 index 56470f47..00000000 --- a/config/environments/production.rb.rails2 +++ /dev/null @@ -1,17 +0,0 @@ -# The production environment is meant for finished, "live" apps. -# Code is not reloaded between requests -config.cache_classes = true - -# Use a different logger for distributed setups -# config.logger = SyslogLogger.new - - -# Full error reports are disabled and caching is turned on -config.action_controller.consider_all_requests_local = false -config.action_controller.perform_caching = true - -# Enable serving of images, stylesheets, and javascripts from an asset server -# config.action_controller.asset_host = "http://assets.example.com" - -# Disable delivery errors if you bad email addresses should just be ignored -# config.action_mailer.raise_delivery_errors = false \ No newline at end of file diff --git a/config/environments/test.rb b/config/environments/test.rb index 76646cb2..480c13b2 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -34,4 +34,12 @@ Tracksapp::Application.configure do # Print deprecation notices to the stderr config.active_support.deprecation = :stderr + + # Unique cookies and use cookies for session + # config.action_controller.session_store = :cookie_store + # config.action_controller.session = { :key => 'TracksTest', :secret => SITE_CONFIG['salt'] * (30.0 / SITE_CONFIG['salt'].length).ceil } + + SITE_CONFIG['salt'] ||= 'change-me' + + config.time_zone = 'UTC' end diff --git a/config/initializers/cookie_verification_secret.rb b/config/initializers/cookie_verification_secret.rb deleted file mode 100644 index b824a8a0..00000000 --- a/config/initializers/cookie_verification_secret.rb +++ /dev/null @@ -1,7 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Your secret key for verifying the integrity of signed cookies. -# If you change this key, all old signed cookies will become invalid! -# Make sure the secret is at least 30 characters and all random, -# no regular words or you'll be exposed to dictionary attacks. -ActionController::Base.cookie_verifier_secret = 'cdb112742619b87ea7cdcfc9a0f664abaf49dbd12bbc22d9d94ef990b4a0eb9776a9a62ca225e01a014ca8ac8bfda8ae704ce3367b4f75dea3082cea00d6609f'; diff --git a/config/initializers/mongrel_workaround.rb b/config/initializers/mongrel_workaround.rb deleted file mode 100644 index 60b207b9..00000000 --- a/config/initializers/mongrel_workaround.rb +++ /dev/null @@ -1,107 +0,0 @@ -# adapted from https://gist.github.com/471663 and https://rails.lighthouseapp.com/projects/8994/tickets/4690-mongrel-doesnt-work-with-rails-238 - -def check_mongrel_around_115 -begin - # Gem.available? is deprecated from rubygems 1.8.2 - Gem::Specification::find_by_name "mongrel", "~>1.1.5" - rescue - if RUBY_VERSION[2] == "9" - false - else - Gem.available?('mongrel', '~>1.1.5') - end - end -end - -mongrel115 = check_mongrel_around_115 - -if Rails.version == '2.3.14' && mongrel115 && self.class.const_defined?(:Mongrel) - - # Pulled right from latest rack. Old looked like this in 1.1.0 version. - # - # def [](k) - # super(@names[k] ||= @names[k.downcase]) - # end - # - module Rack - module Utils - class HeaderHash < Hash - def [](k) - super(@names[k]) if @names[k] - super(@names[k.downcase]) - end - end - end - end - - # Code pulled from the ticket above. - # - class Mongrel::CGIWrapper - def header_with_rails_fix(options = 'text/html') - @head['cookie'] = options.delete('cookie').flatten.map { |v| v.sub(/^\n/,'') } if options.class != String and options['cookie'] - header_without_rails_fix(options) - end - alias_method_chain :header, :rails_fix - end - - # Pulled right from 2.3.10 ActionPack. Simple diff was - # - # if headers.include?('Set-Cookie') - # headers['cookie'] = headers.delete('Set-Cookie').split("\n") - # end - # - # to - # - # if headers['Set-Cookie'] - # headers['cookie'] = headers.delete('Set-Cookie').split("\n") - # end - # - module ActionController - class CGIHandler - def self.dispatch_cgi(app, cgi, out = $stdout) - env = cgi.__send__(:env_table) - env.delete "HTTP_CONTENT_LENGTH" - - cgi.stdinput.extend ProperStream - - env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - - env.update({ - "rack.version" => [0,1], - "rack.input" => cgi.stdinput, - "rack.errors" => $stderr, - "rack.multithread" => false, - "rack.multiprocess" => true, - "rack.run_once" => false, - "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http" - }) - - env["QUERY_STRING"] ||= "" - env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] - env["REQUEST_PATH"] ||= "/" - env.delete "PATH_INFO" if env["PATH_INFO"] == "" - - status, headers, body = app.call(env) - begin - out.binmode if out.respond_to?(:binmode) - out.sync = false if out.respond_to?(:sync=) - - headers['Status'] = status.to_s - - if headers['Set-Cookie'] - headers['cookie'] = headers.delete('Set-Cookie').split("\n") - end - - out.write(cgi.header(headers)) - - body.each { |part| - out.write part - out.flush if out.respond_to?(:flush) - } - ensure - body.close if body.respond_to?(:close) - end - end - end - end -end diff --git a/config/initializers/new_rails_defaults.rb b/config/initializers/new_rails_defaults.rb deleted file mode 100644 index c94db0a6..00000000 --- a/config/initializers/new_rails_defaults.rb +++ /dev/null @@ -1,21 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# These settings change the behavior of Rails 2 apps and will be defaults -# for Rails 3. You can remove this initializer when Rails 3 is released. - -if defined?(ActiveRecord) - # Include Active Record class name as root for JSON serialized output. - ActiveRecord::Base.include_root_in_json = true - - # Store the full class name (including module namespace) in STI type column. - ActiveRecord::Base.store_full_sti_class = true -end - -ActionController::Routing.generate_best_match = false - -# Use ISO 8601 format for JSON serialized times and dates. -ActiveSupport.use_standard_json_time_format = true - -# Don't escape HTML entities in JSON, leave that for the #json_escape helper. -# if you're including raw json in an HTML page. -ActiveSupport.escape_html_entities_in_json = false \ No newline at end of file diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index deb11eee..3ec999da 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -1,8 +1,10 @@ # Be sure to restart your server when you modify this file. -Tracksapp::Application.config.session_store :cookie_store, key: '_tracksapp_session' +#Tracksapp::Application.config.session_store :cookie_store, key: '_tracksapp_session' # Use the database for sessions instead of the cookie-based default, # which shouldn't be used to store highly confidential information # (create the session table with "rails generate session_migration") # Tracksapp::Application.config.session_store :active_record_store + +Tracksapp::Application.config.session_store :active_record_store, :key => '_tracks_session_id' \ No newline at end of file diff --git a/config/preinitializer.rb b/config/preinitializer.rb deleted file mode 100644 index a6b4d1e6..00000000 --- a/config/preinitializer.rb +++ /dev/null @@ -1,21 +0,0 @@ -begin - require "rubygems" - require "bundler" -rescue LoadError - raise "Could not load the bundler gem. Install it with `gem install bundler`." -end - -if Gem::Version.new(Bundler::VERSION) <= Gem::Version.new("0.9.24") - raise RuntimeError, "Your bundler version is too old for Rails 2.3." + - "Run `gem install bundler` to upgrade." -end - -begin - # Set up load paths for all bundled gems - ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__) - Bundler.setup -rescue Bundler::GemNotFound - raise RuntimeError, "Bundler couldn't find some gems." + - "Did you run `bundle install`?" -end - diff --git a/config/routes.rb b/config/routes.rb index 2d76d3dd..8178b8ee 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -55,4 +55,121 @@ Tracksapp::Application.routes.draw do # This is a legacy wild controller route that's not recommended for RESTful applications. # Note: This route will make all actions in every controller accessible via GET requests. # match ':controller(/:action(/:id))(.:format)' + + root :to => 'todos#index' + + match "tickler" => "todos#list_deferred" + + # map.resources :users, + # :member => {:change_password => :get, :update_password => :post, + # :change_auth_type => :get, :update_auth_type => :post, :complete => :get, + # :refresh_token => :post } + # + # map.with_options :controller => :users do |users| + # users.signup 'signup', :action => "new" + # end + # + # map.resources :contexts, :collection => {:order => :post, :done => :get}, :member => {:done_todos => :get, :all_done_todos => :get} do |contexts| + # contexts.resources :todos, :name_prefix => "context_" + # end + # + # map.resources :projects, + # :collection => {:order => :post, :alphabetize => :post, :actionize => :post, :done => :get}, + # :member => {:done_todos => :get, :all_done_todos => :get, :set_reviewed => :get} do |projects| + # projects.resources :todos, :name_prefix => "project_" + # end + # + # map.with_options :controller => :projects do |projects| + # projects.review 'review', :action => :review + # end + # + # map.resources :notes + # + # map.resources :todos, + # :member => {:toggle_check => :put, :toggle_star => :put, :defer => :put}, + # :collection => {:check_deferred => :post, :filter_to_context => :post, :filter_to_project => :post, :done => :get, :all_done => :get + # } + # + # map.with_options :controller => :todos do |todos| + # todos.home '', :action => "index" + # todos.tickler 'tickler.:format', :action => "list_deferred" + # todos.mobile_tickler 'tickler.m', :action => "list_deferred", :format => 'm' + # + # # This route works for tags with dots like /todos/tag/version1.5 + # # please note that this pattern consumes everything after /todos/tag + # # so /todos/tag/version1.5.xml will result in :name => 'version1.5.xml' + # # UPDATE: added support for mobile view. All tags ending on .m will be + # # routed to mobile view of tags. + # todos.mobile_tag 'todos/tag/:name.m', :action => "tag", :format => 'm' + # todos.text_tag 'todos/tag/:name.txt', :action => "tag", :format => 'txt' + # todos.tag 'todos/tag/:name', :action => "tag", :name => /.*/ + # todos.done_tag 'todos/done/tag/:name', :action => "done_tag" + # todos.all_done_tag 'todos/all_done/tag/:name', :action => "all_done_tag" + # + # todos.tags 'tags.autocomplete', :action => "tags", :format => 'autocomplete' + # todos.auto_complete_for_predecessor 'auto_complete_for_predecessor', :action => 'auto_complete_for_predecessor' + # + # todos.calendar 'calendar.ics', :action => "calendar", :format => 'ics' + # todos.calendar 'calendar.xml', :action => "calendar", :format => 'xml' + # todos.calendar 'calendar', :action => "calendar" + # + # todos.hidden 'hidden.xml', :action => "list_hidden", :format => 'xml' + # + # todos.mobile 'mobile', :action => "index", :format => 'm' + # todos.mobile_abbrev 'm', :action => "index", :format => 'm' + # todos.mobile_abbrev_new 'm/new', :action => "new", :format => 'm' + # + # todos.mobile_todo_show_notes 'todos/notes/:id.m', :action => "show_notes", :format => 'm' + # todos.todo_show_notes 'todos/notes/:id', :action => "show_notes" + # todos.done_todos 'todos/done', :action => :done + # todos.all_done_todos 'todos/all_done', :action => :all_done + # end + # map.root :controller => 'todos' # Make OpenID happy because it needs #root_url defined + # + # map.resources :recurring_todos, :collection => {:done => :get}, + # :member => {:toggle_check => :put, :toggle_star => :put} + # map.with_options :controller => :recurring_todos do |rt| + # rt.recurring_todos 'recurring_todos', :action => 'index' + # end + # + # map.with_options :controller => :login do |login| + # login.login 'login', :action => 'login' + # login.login_cas 'login_cas', :action => 'login_cas' + # login.formatted_login 'login.:format', :action => 'login' + # login.logout 'logout', :action => 'logout' + # login.formatted_logout 'logout.:format', :action => 'logout' + # end + # + # map.with_options :controller => :feedlist do |fl| + # fl.mobile_feeds 'feeds.m', :action => 'index', :format => 'm' + # fl.feeds 'feeds', :action => 'index' + # end + # + # map.with_options :controller => :integrations do |i| + # i.integrations 'integrations', :action => 'index' + # i.rest_api_docs 'integrations/rest_api', :action => "rest_api" + # i.search_plugin 'integrations/search_plugin.xml', :action => 'search_plugin', :format => 'xml' + # i.google_gadget 'integrations/google_gadget.xml', :action => 'google_gadget', :format => 'xml' + # i.cloudmailin 'integrations/cloudmailin', :action => 'cloudmailin' + # end + # + # map.with_options :controller => :preferences do |p| + # p.preferences 'preferences', :action => 'index' + # p.preferences_date_format 'preferences/render_date_format', :action => 'render_date_format' + # end + # + # map.with_options :controller => :stats do |stats| + # stats.stats 'stats', :action => 'index' + # stats.done_overview 'done', :action => 'done' + # end + # + # map.search 'search', :controller => 'search', :action => 'index' + # map.data 'data', :controller => 'data', :action => 'index' + # + # Translate::Routes.translation_ui(map) if Rails.env != "production" + # + # # Install the default route as the lowest priority. + # map.connect ':controller/:action/:id' + # + end diff --git a/config/routes.rb.rails2 b/config/routes.rb.rails2 deleted file mode 100644 index ec0ed738..00000000 --- a/config/routes.rb.rails2 +++ /dev/null @@ -1,113 +0,0 @@ -ActionController::Routing::Routes.draw do |map| - map.resources :users, - :member => {:change_password => :get, :update_password => :post, - :change_auth_type => :get, :update_auth_type => :post, :complete => :get, - :refresh_token => :post } - - map.with_options :controller => :users do |users| - users.signup 'signup', :action => "new" - end - - map.resources :contexts, :collection => {:order => :post, :done => :get}, :member => {:done_todos => :get, :all_done_todos => :get} do |contexts| - contexts.resources :todos, :name_prefix => "context_" - end - - map.resources :projects, - :collection => {:order => :post, :alphabetize => :post, :actionize => :post, :done => :get}, - :member => {:done_todos => :get, :all_done_todos => :get, :set_reviewed => :get} do |projects| - projects.resources :todos, :name_prefix => "project_" - end - - map.with_options :controller => :projects do |projects| - projects.review 'review', :action => :review - end - - map.resources :notes - - map.resources :todos, - :member => {:toggle_check => :put, :toggle_star => :put, :defer => :put}, - :collection => {:check_deferred => :post, :filter_to_context => :post, :filter_to_project => :post, :done => :get, :all_done => :get - } - - map.with_options :controller => :todos do |todos| - todos.home '', :action => "index" - todos.tickler 'tickler.:format', :action => "list_deferred" - todos.mobile_tickler 'tickler.m', :action => "list_deferred", :format => 'm' - - # This route works for tags with dots like /todos/tag/version1.5 - # please note that this pattern consumes everything after /todos/tag - # so /todos/tag/version1.5.xml will result in :name => 'version1.5.xml' - # UPDATE: added support for mobile view. All tags ending on .m will be - # routed to mobile view of tags. - todos.mobile_tag 'todos/tag/:name.m', :action => "tag", :format => 'm' - todos.text_tag 'todos/tag/:name.txt', :action => "tag", :format => 'txt' - todos.tag 'todos/tag/:name', :action => "tag", :name => /.*/ - todos.done_tag 'todos/done/tag/:name', :action => "done_tag" - todos.all_done_tag 'todos/all_done/tag/:name', :action => "all_done_tag" - - todos.tags 'tags.autocomplete', :action => "tags", :format => 'autocomplete' - todos.auto_complete_for_predecessor 'auto_complete_for_predecessor', :action => 'auto_complete_for_predecessor' - - todos.calendar 'calendar.ics', :action => "calendar", :format => 'ics' - todos.calendar 'calendar.xml', :action => "calendar", :format => 'xml' - todos.calendar 'calendar', :action => "calendar" - - todos.hidden 'hidden.xml', :action => "list_hidden", :format => 'xml' - - todos.mobile 'mobile', :action => "index", :format => 'm' - todos.mobile_abbrev 'm', :action => "index", :format => 'm' - todos.mobile_abbrev_new 'm/new', :action => "new", :format => 'm' - - todos.mobile_todo_show_notes 'todos/notes/:id.m', :action => "show_notes", :format => 'm' - todos.todo_show_notes 'todos/notes/:id', :action => "show_notes" - todos.done_todos 'todos/done', :action => :done - todos.all_done_todos 'todos/all_done', :action => :all_done - end - map.root :controller => 'todos' # Make OpenID happy because it needs #root_url defined - - map.resources :recurring_todos, :collection => {:done => :get}, - :member => {:toggle_check => :put, :toggle_star => :put} - map.with_options :controller => :recurring_todos do |rt| - rt.recurring_todos 'recurring_todos', :action => 'index' - end - - map.with_options :controller => :login do |login| - login.login 'login', :action => 'login' - login.login_cas 'login_cas', :action => 'login_cas' - login.formatted_login 'login.:format', :action => 'login' - login.logout 'logout', :action => 'logout' - login.formatted_logout 'logout.:format', :action => 'logout' - end - - map.with_options :controller => :feedlist do |fl| - fl.mobile_feeds 'feeds.m', :action => 'index', :format => 'm' - fl.feeds 'feeds', :action => 'index' - end - - map.with_options :controller => :integrations do |i| - i.integrations 'integrations', :action => 'index' - i.rest_api_docs 'integrations/rest_api', :action => "rest_api" - i.search_plugin 'integrations/search_plugin.xml', :action => 'search_plugin', :format => 'xml' - i.google_gadget 'integrations/google_gadget.xml', :action => 'google_gadget', :format => 'xml' - i.cloudmailin 'integrations/cloudmailin', :action => 'cloudmailin' - end - - map.with_options :controller => :preferences do |p| - p.preferences 'preferences', :action => 'index' - p.preferences_date_format 'preferences/render_date_format', :action => 'render_date_format' - end - - map.with_options :controller => :stats do |stats| - stats.stats 'stats', :action => 'index' - stats.done_overview 'done', :action => 'done' - end - - map.search 'search', :controller => 'search', :action => 'index' - map.data 'data', :controller => 'data', :action => 'index' - - Translate::Routes.translation_ui(map) if Rails.env != "production" - - # Install the default route as the lowest priority. - map.connect ':controller/:action/:id' - -end diff --git a/config/site.yml.tmpl b/config/site.yml.tmpl index d5208a6c..a88c224d 100644 --- a/config/site.yml.tmpl +++ b/config/site.yml.tmpl @@ -5,10 +5,10 @@ salt: "change-me" # Uncomment ldap or open_id if you want to use those authentication schemes. # If you choose ldap, see the additional configuration options further down. +# NOTE: openid is not supported anymore. authentication_schemes: - "database" # - "ldap" - # - "open_id" # - "cas" @@ -54,5 +54,5 @@ open_signups: false # When integrating your tracks instance with http://cloudmailin.com/ by using the /integrations/cloudmailin URL, # this value is the cloudmailin-secret for verifying the authenticity of the request. -# (see http://docs.cloudmailin.com/validating_the_sender) +# (see http://docs.cloudmailin.com/validating_the_sender) # cloudmailin: asdasd diff --git a/doc/README_FOR_APP b/doc/README_FOR_APP deleted file mode 100644 index fe41f5cc..00000000 --- a/doc/README_FOR_APP +++ /dev/null @@ -1,2 +0,0 @@ -Use this README file to introduce your application and point to useful places in the API for learning more. -Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries. diff --git a/lib/authenticated_test_helper.rb b/lib/authenticated_test_helper.rb deleted file mode 100644 index 7a52e62b..00000000 --- a/lib/authenticated_test_helper.rb +++ /dev/null @@ -1,113 +0,0 @@ -module AuthenticatedTestHelper - # Sets the current user in the session from the user fixtures. - def login_as(user) - @request.session['user_id'] = user ? users(user).id : nil - end - - def content_type(type) - @request.env['Content-Type'] = type - end - - def accept(accept) - @request.env["HTTP_ACCEPT"] = accept - end - - def authorize_as(user) - if user - @request.env["HTTP_AUTHORIZATION"] = "Basic #{Base64.encode64("#{users(user).login}:test")}" - accept 'application/xml' - content_type 'application/xml' - else - @request.env["HTTP_AUTHORIZATION"] = nil - accept nil - content_type nil - end - end - - # http://project.ioni.st/post/217#post-217 - # - # def test_new_publication - # assert_difference(Publication, :count) do - # post :create, :publication => {...} - # # ... - # end - # end - # - def assert_difference(object, method = nil, difference = 1) - initial_value = object.send(method) - yield - assert_equal initial_value + difference, object.send(method), "#{object}##{method}" - end - - def assert_no_difference(object, method, &block) - assert_difference object, method, 0, &block - end - - # Assert the block redirects to the login - # - # assert_requires_login(:bob) { |c| c.get :edit, :id => 1 } - # - def assert_requires_login(login = nil) - yield HttpLoginProxy.new(self, login) - end - - def assert_http_authentication_required(login = nil) - yield XmlLoginProxy.new(self, login) - end - - def reset!(*instance_vars) - instance_vars = [:controller, :request, :response] unless instance_vars.any? - instance_vars.collect! { |v| "@#{v}".to_sym } - instance_vars.each do |var| - instance_variable_set(var, instance_variable_get(var).class.new) - end - end -end - -class BaseLoginProxy - attr_reader :controller - attr_reader :options - def initialize(controller, login) - @controller = controller - @login = login - end - - private - def authenticated - raise NotImplementedError - end - - def check - raise NotImplementedError - end - - def method_missing(method, *args) - @controller.reset! - authenticate - @controller.send(method, *args) - check - end -end - -class HttpLoginProxy < BaseLoginProxy - protected - def authenticate - @controller.login_as @login if @login - end - - def check - @controller.assert_redirected_to :controller => 'account', :action => 'login' - end -end - -class XmlLoginProxy < BaseLoginProxy - protected - def authenticate - @controller.accept 'application/xml' - @controller.authorize_as @login if @login - end - - def check - @controller.assert_response 401 - end -end \ No newline at end of file diff --git a/lib/login_system.rb b/lib/login_system.rb index 8a8a70a1..042c8a9d 100644 --- a/lib/login_system.rb +++ b/lib/login_system.rb @@ -1,6 +1,6 @@ require_dependency "user" -module LoginSystem +module LoginSystem def current_user get_current_user @@ -29,7 +29,7 @@ module LoginSystem protected # overwrite this if you want to restrict access to only a few actions - # or if you want to check if the user has the correct rights + # or if you want to check if the user has the correct rights # example: # # # only allow nonbobs @@ -42,7 +42,7 @@ module LoginSystem # overwrite this method if you only want to protect certain actions of the controller # example: - # + # # # don't protect the login and the about method # def protect?(action) # if ['action', 'about'].include?(action) @@ -59,7 +59,8 @@ module LoginSystem # cookie and log the user back in if appropriate def login_from_cookie return unless cookies[:auth_token] && !logged_in? - user = User.find_by_remember_token(cookies[:auth_token]) + token = cookies[:auth_token] + user = User.find_by_remember_token(token) if user && user.remember_token? session['user_id'] = user.id set_current_user(user) @@ -67,7 +68,7 @@ module LoginSystem cookies[:auth_token] = { :value => current_user.remember_token , :expires => current_user.remember_token_expires_at, :secure => SITE_CONFIG['secure_cookies'] } flash[:notice] = t('login.successful') end - end + end def login_or_feed_token_required if ['rss', 'atom', 'txt', 'ics'].include?(params[:format]) @@ -79,15 +80,15 @@ module LoginSystem login_required end - # login_required filter. add + # login_required filter. add # # before_filter :login_required # - # if the controller should be under any rights management. + # if the controller should be under any rights management. # for finer access control you can overwrite - # + # # def authorize?(user) - # + # def login_required if not protect?(action_name) @@ -107,13 +108,13 @@ module LoginSystem return true end - # store current location so that we can + # store current location so that we can # come back after the user logged in store_location unless params[:format] == 'js' # call overwriteable reaction to unauthorized access access_denied - return false + return false end def login_optional @@ -131,7 +132,7 @@ module LoginSystem return true end - return true + return true end def logged_in? @@ -150,7 +151,7 @@ module LoginSystem end # overwrite if you want to have special behavior in case the user is not authorized - # to access the current operation. + # to access the current operation. # the default action is to redirect to the login screen # example use : # a popup window might just close itself for instance @@ -164,7 +165,7 @@ module LoginSystem format.atom { basic_auth_denied } format.text { basic_auth_denied } end - end + end # store current uri in the session. # we can return to this location by calling return_location @@ -195,8 +196,8 @@ module LoginSystem authdata = request.env[location].to_s.split end end - if authdata and authdata[0] == 'Basic' - user, pass = Base64.decode64(authdata[1]).split(':')[0..1] + if authdata and authdata[0] == 'Basic' + user, pass = Base64.decode64(authdata[1]).split(':')[0..1] else user, pass = ['', ''] end diff --git a/lib/name_part_finder.rb b/lib/name_part_finder.rb deleted file mode 100644 index 79d66338..00000000 --- a/lib/name_part_finder.rb +++ /dev/null @@ -1,5 +0,0 @@ -module NamePartFinder - def find_by_namepart(namepart) - find_by_name(namepart) || find(:first, :conditions => ["name LIKE ?", namepart + '%']) - end -end \ No newline at end of file diff --git a/lib/tasks/.gitkeep b/lib/tasks/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/tasks/cucumber-tracks.rake b/lib/tasks/cucumber-tracks.rake deleted file mode 100644 index ae5bdfad..00000000 --- a/lib/tasks/cucumber-tracks.rake +++ /dev/null @@ -1,38 +0,0 @@ -# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. -# It is recommended to regenerate this file in the future when you upgrade to a -# newer version of cucumber-rails. Consider adding your own code to a new file -# instead of editing this one. Cucumber will automatically load all features/**/*.rb -# files. - -vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first -$LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil? - -begin - require 'cucumber/rake/task' - - namespace :cucumber do - Cucumber::Rake::Task.new({:selenium => :env_to_selenium}, 'Run features that require selenium') do |t| - t.binary = vendored_cucumber_bin - t.fork = true # You may get faster startup if you set this to false - t.profile = 'selenium' - end - - Cucumber::Rake::Task.new({:selenium_wip => :env_to_selenium}, 'Run unfinished features that require selenium') do |t| - t.binary = vendored_cucumber_bin - t.fork = true # You may get faster startup if you set this to false - t.profile = 'selenium_wip' - end - - task :env_to_selenium => 'db:test:prepare' do - ENV['RAILS_ENV'] = 'selenium' - end - - desc 'Run all features' - task :all => [:ok, :wip, :selenium, :selenium_wip] - end -rescue LoadError - desc 'cucumber rake task not available (cucumber not installed)' - task :cucumber do - abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin' - end -end \ No newline at end of file diff --git a/lib/tasks/cucumber.rake b/lib/tasks/cucumber.rake deleted file mode 100644 index 7db1a557..00000000 --- a/lib/tasks/cucumber.rake +++ /dev/null @@ -1,53 +0,0 @@ -# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. -# It is recommended to regenerate this file in the future when you upgrade to a -# newer version of cucumber-rails. Consider adding your own code to a new file -# instead of editing this one. Cucumber will automatically load all features/**/*.rb -# files. - - -unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks - -vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first -$LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil? - -begin - require 'cucumber/rake/task' - - namespace :cucumber do - Cucumber::Rake::Task.new({:ok => 'db:test:prepare'}, 'Run features that should pass') do |t| - t.binary = vendored_cucumber_bin # If nil, the gem's binary is used. - t.fork = true # You may get faster startup if you set this to false - t.profile = 'default' - end - - Cucumber::Rake::Task.new({:wip => 'db:test:prepare'}, 'Run features that are being worked on') do |t| - t.binary = vendored_cucumber_bin - t.fork = true # You may get faster startup if you set this to false - t.profile = 'wip' - end - - Cucumber::Rake::Task.new({:rerun => 'db:test:prepare'}, 'Record failing features and run only them if any exist') do |t| - t.binary = vendored_cucumber_bin - t.fork = true # You may get faster startup if you set this to false - t.profile = 'rerun' - end - - desc 'Run all features' - task :all => [:ok, :wip] - end - desc 'Alias for cucumber:ok' - task :cucumber => 'cucumber:ok' - - task :default => :cucumber - - task :features => :cucumber do - STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***" - end -rescue LoadError - desc 'cucumber rake task not available (cucumber not installed)' - task :cucumber do - abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin' - end -end - -end diff --git a/lib/tasks/database.rake b/lib/tasks/database.rake deleted file mode 100644 index eb02a45f..00000000 --- a/lib/tasks/database.rake +++ /dev/null @@ -1,27 +0,0 @@ -require 'rake' - -namespace :db do - desc "Dump the current SQLite3 or MySQL database to a sql file" - task :dump_sql do - load 'config/environment.rb' - abcs = ActiveRecord::Base.configurations - case abcs[RAILS_ENV]["adapter"] - when 'mysql' - ActiveRecord::Base.establish_connection(abcs[RAILS_ENV]) - File.open("db/#{RAILS_ENV}_data.sql", "w+") do |f| - if abcs[RAILS_ENV]["password"].blank? - f << `mysqldump -h #{abcs[RAILS_ENV]["host"]} -u #{abcs[RAILS_ENV]["username"]} #{abcs[RAILS_ENV]["database"]}` - else - f << `mysqldump -h #{abcs[RAILS_ENV]["host"]} -u #{abcs[RAILS_ENV]["username"]} -p#{abcs[RAILS_ENV]["password"]} #{abcs[RAILS_ENV]["database"]}` - end - end - when 'sqlite3' - ActiveRecord::Base.establish_connection(abcs[RAILS_ENV]) - File.open("db/#{RAILS_ENV}_data.sql", "w+") do |f| - f << `sqlite3 #{abcs[RAILS_ENV]["database"]} .dump` - end - else - raise "Task not supported by '#{abcs[RAILS_ENV]['adapter']}'" - end - end -end \ No newline at end of file diff --git a/lib/tasks/extract_fixtures.rake b/lib/tasks/extract_fixtures.rake deleted file mode 100644 index f69683a3..00000000 --- a/lib/tasks/extract_fixtures.rake +++ /dev/null @@ -1,17 +0,0 @@ -desc ' Create YAML test fixtures from data in an existing database. -Defaults to development database. Set RAILS_ENV to override (taken from Rails Recipes book).' -task :extract_fixtures => :environment do - sql = "SELECT * FROM %s" - skip_tables = ["schema_info", "sessions", "users"] - ActiveRecord::Base.establish_connection - (ActiveRecord::Base.connection.tables - skip_tables).each do |table_name| - i = "000" - File.open("#{RAILS_ROOT}/db/exported_fixtures/#{table_name}.yml", 'w' ) do |file| - data = ActiveRecord::Base.connection.select_all(sql % table_name) - file.write data.inject({}) { |hash, record| - hash["#{table_name}_#{i.succ!}"] = record - hash - }.to_yaml - end - end -end \ No newline at end of file diff --git a/lib/tasks/gems.rake b/lib/tasks/gems.rake deleted file mode 100644 index 464b787f..00000000 --- a/lib/tasks/gems.rake +++ /dev/null @@ -1,34 +0,0 @@ -desc "Copy third-party gems into ./lib" -task :freeze_other_gems do - # TODO Get this list from parsing environment.rb - libraries = %w(redcloth) - require 'rubygems' - require 'find' - - libraries.each do |library| - library_gem = Gem.cache.search(library).sort_by { |g| g.version }.last - puts "Freezing #{library} for #{library_gem.version}..." - - # TODO Add dependencies to list of libraries to freeze - #library_gem.dependencies.each { |g| libraries << g } - - folder_for_library = "#{library_gem.name}-#{library_gem.version}" - system "cd vendor; gem unpack -v '#{library_gem.version}' #{library_gem.name};" - - # Copy files recursively to ./lib - folder_for_library_with_lib = "vendor/#{folder_for_library}/lib/" - Find.find(folder_for_library_with_lib) do |original_file| - destination_file = "./lib/" + original_file.gsub(folder_for_library_with_lib, '') - - if File.directory?(original_file) - if !File.exist?(destination_file) - Dir.mkdir destination_file - end - else - File.copy original_file, destination_file - end - end - - system "rm -r vendor/#{folder_for_library}" - end -end diff --git a/lib/tasks/load_exported_fixtures.rake b/lib/tasks/load_exported_fixtures.rake deleted file mode 100644 index 10757471..00000000 --- a/lib/tasks/load_exported_fixtures.rake +++ /dev/null @@ -1,8 +0,0 @@ -desc "Load exported fixtures (in db/exported_fixtures) into the current environment's database" -task :load_exported_fixtures => :environment do - require 'active_record/fixtures' - ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym) - Dir.glob(File.join(RAILS_ROOT, 'db', 'exported_fixtures', '*.{yml,csv}')).each do |fixture_file| - Fixtures.create_fixtures('db/exported_fixtures', File.basename(fixture_file, '.*')) - end -end \ No newline at end of file diff --git a/lib/tasks/query_trace_toggle.rake b/lib/tasks/query_trace_toggle.rake deleted file mode 100644 index a6321541..00000000 --- a/lib/tasks/query_trace_toggle.rake +++ /dev/null @@ -1,50 +0,0 @@ -namespace :query_trace do - desc "Enables the query_trace plugin. Must restart server to take effect." - task :on => :environment do - unless File.exist?("#{RAILS_ROOT}/vendor/query_trace.tar.gz") - Dir.chdir("#{RAILS_ROOT}/vendor") do - url = "https://terralien.devguard.com/svn/projects/plugins/query_trace" - puts "Loading query_trace from #{url}..." - system "svn co #{url} query_trace" - system "tar zcf query_trace.tar.gz --exclude=.svn query_trace" - FileUtils.rm_rf("query_trace") - end - end - Dir.chdir("#{RAILS_ROOT}/vendor/plugins") do - system "tar zxf ../query_trace.tar.gz query_trace" - end - puts "QueryTrace plugin enabled. Must restart server to take effect." - end - - desc "Disables the query_trace plugin. Must restart server to take effect." - task :off => :environment do - FileUtils.rm_rf("#{RAILS_ROOT}/vendor/plugins/query_trace") - puts "QueryTrace plugin disabled. Must restart server to take effect." - end -end - -namespace :query_analyzer do - desc "Enables the query_analyzer plugin. Must restart server to take effect." - task :on => :environment do - unless File.exist?("#{RAILS_ROOT}/vendor/query_analyzer.tar.gz") - Dir.chdir("#{RAILS_ROOT}/vendor") do - url = "http://svn.nfectio.us/plugins/query_analyzer" - puts "Loading query_analyzer from #{url}..." - system "svn co #{url} query_analyzer" - system "tar zcf query_analyzer.tar.gz --exclude=.svn query_analyzer" - FileUtils.rm_rf("query_analyzer") - end - end - Dir.chdir("#{RAILS_ROOT}/vendor/plugins") do - system "tar zxf ../query_analyzer.tar.gz query_analyzer" - end - puts "QueryAnalyzer plugin enabled. Must restart server to take effect." - end - - desc "Disables the query_analyzer plugin. Must restart server to take effect." - task :off => :environment do - FileUtils.rm_rf("#{RAILS_ROOT}/vendor/plugins/query_analyzer") - puts "QueryAnalyzer plugin disabled. Must restart server to take effect." - end -end - diff --git a/lib/tasks/reset_password.rake b/lib/tasks/reset_password.rake deleted file mode 100644 index 6cc61a60..00000000 --- a/lib/tasks/reset_password.rake +++ /dev/null @@ -1,23 +0,0 @@ -namespace :tracks do - desc 'Replace the password of USER with a new one.' - task :password => :environment do - require "highline/import" - - user = User.find_by_login(ENV['USER']) - if user.nil? - puts "Sorry, we couldn't find user '#{ENV['USER']}'. To specify a different user, pass USER=username to this task." - exit 0 - end - - puts "Changing Tracks password for #{ENV['USER']}." - password = ask("New password: ") { |q| q.echo = false } - password_confirmation = ask('Retype new password: ') { |q| q.echo = false } - - begin - user.change_password(password, password_confirmation) - rescue ActiveRecord::RecordInvalid - puts "Sorry, we couldn't change #{ENV['USER']}'s password: " - user.errors.each_full { |msg| puts "- #{msg}\n" } - end - end -end diff --git a/lib/tasks/rspec.rake b/lib/tasks/rspec.rake deleted file mode 100644 index dba3ffcc..00000000 --- a/lib/tasks/rspec.rake +++ /dev/null @@ -1,144 +0,0 @@ -gem 'test-unit', '1.2.3' if RUBY_VERSION.to_f >= 1.9 -rspec_gem_dir = nil -Dir["#{RAILS_ROOT}/vendor/gems/*"].each do |subdir| - rspec_gem_dir = subdir if subdir.gsub("#{RAILS_ROOT}/vendor/gems/","") =~ /^(\w+-)?rspec-(\d+)/ && File.exist?("#{subdir}/lib/spec/rake/spectask.rb") -end -rspec_plugin_dir = File.expand_path(File.dirname(__FILE__) + '/../../vendor/plugins/rspec') - -if rspec_gem_dir && (test ?d, rspec_plugin_dir) - raise "\n#{'*'*50}\nYou have rspec installed in both vendor/gems and vendor/plugins\nPlease pick one and dispose of the other.\n#{'*'*50}\n\n" -end - -if rspec_gem_dir - $LOAD_PATH.unshift("#{rspec_gem_dir}/lib") -elsif File.exist?(rspec_plugin_dir) - $LOAD_PATH.unshift("#{rspec_plugin_dir}/lib") -end - -# Don't load rspec if running "rake gems:*" -unless ARGV.any? {|a| a =~ /^gems/} - -begin - require 'spec/rake/spectask' -rescue MissingSourceFile - module Spec - module Rake - class SpecTask - def initialize(name) - task name do - # if rspec-rails is a configured gem, this will output helpful material and exit ... - require File.expand_path(File.join(File.dirname(__FILE__),"..","..","config","environment")) - - # ... otherwise, do this: - raise <<-MSG - -#{"*" * 80} -* You are trying to run an rspec rake task defined in -* #{__FILE__}, -* but rspec can not be found in vendor/gems, vendor/plugins or system gems. -#{"*" * 80} -MSG - end - end - end - end - end -end - -Rake.application.instance_variable_get('@tasks').delete('default') - -spec_prereq = File.exist?(File.join(RAILS_ROOT, 'config', 'database.yml')) ? "db:test:prepare" : :noop -task :noop do -end - -task :default => :spec -task :stats => "spec:statsetup" - -desc "Run all specs in spec directory (excluding plugin specs)" -Spec::Rake::SpecTask.new(:spec => spec_prereq) do |t| - t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""] - t.spec_files = FileList['spec/**/*_spec.rb'] -end - -namespace :spec do - desc "Run all specs in spec directory with RCov (excluding plugin specs)" - Spec::Rake::SpecTask.new(:rcov) do |t| - t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""] - t.spec_files = FileList['spec/**/*_spec.rb'] - t.rcov = true - t.rcov_opts = lambda do - IO.readlines("#{RAILS_ROOT}/spec/rcov.opts").map {|l| l.chomp.split " "}.flatten - end - end - - desc "Print Specdoc for all specs (excluding plugin specs)" - Spec::Rake::SpecTask.new(:doc) do |t| - t.spec_opts = ["--format", "specdoc", "--dry-run"] - t.spec_files = FileList['spec/**/*_spec.rb'] - end - - desc "Print Specdoc for all plugin examples" - Spec::Rake::SpecTask.new(:plugin_doc) do |t| - t.spec_opts = ["--format", "specdoc", "--dry-run"] - t.spec_files = FileList['vendor/plugins/**/spec/**/*_spec.rb'].exclude('vendor/plugins/rspec/*') - end - - [:models, :controllers, :views, :helpers, :lib, :integration].each do |sub| - desc "Run the code examples in spec/#{sub}" - Spec::Rake::SpecTask.new(sub => spec_prereq) do |t| - t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""] - t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"] - end - end - - desc "Run the code examples in vendor/plugins (except RSpec's own)" - Spec::Rake::SpecTask.new(:plugins => spec_prereq) do |t| - t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""] - t.spec_files = FileList['vendor/plugins/**/spec/**/*_spec.rb'].exclude('vendor/plugins/rspec/*').exclude("vendor/plugins/rspec-rails/*") - end - - namespace :plugins do - desc "Runs the examples for rspec_on_rails" - Spec::Rake::SpecTask.new(:rspec_on_rails) do |t| - t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""] - t.spec_files = FileList['vendor/plugins/rspec-rails/spec/**/*_spec.rb'] - end - end - - # Setup specs for stats - task :statsetup do - require 'code_statistics' - ::STATS_DIRECTORIES << %w(Model\ specs spec/models) if File.exist?('spec/models') - ::STATS_DIRECTORIES << %w(View\ specs spec/views) if File.exist?('spec/views') - ::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers) if File.exist?('spec/controllers') - ::STATS_DIRECTORIES << %w(Helper\ specs spec/helpers) if File.exist?('spec/helpers') - ::STATS_DIRECTORIES << %w(Library\ specs spec/lib) if File.exist?('spec/lib') - ::STATS_DIRECTORIES << %w(Routing\ specs spec/routing) if File.exist?('spec/routing') - ::STATS_DIRECTORIES << %w(Integration\ specs spec/integration) if File.exist?('spec/integration') - ::CodeStatistics::TEST_TYPES << "Model specs" if File.exist?('spec/models') - ::CodeStatistics::TEST_TYPES << "View specs" if File.exist?('spec/views') - ::CodeStatistics::TEST_TYPES << "Controller specs" if File.exist?('spec/controllers') - ::CodeStatistics::TEST_TYPES << "Helper specs" if File.exist?('spec/helpers') - ::CodeStatistics::TEST_TYPES << "Library specs" if File.exist?('spec/lib') - ::CodeStatistics::TEST_TYPES << "Routing specs" if File.exist?('spec/routing') - ::CodeStatistics::TEST_TYPES << "Integration specs" if File.exist?('spec/integration') - end - - namespace :db do - namespace :fixtures do - desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z." - task :load => :environment do - ActiveRecord::Base.establish_connection(Rails.env) - base_dir = File.join(Rails.root, 'spec', 'fixtures') - fixtures_dir = ENV['FIXTURES_DIR'] ? File.join(base_dir, ENV['FIXTURES_DIR']) : base_dir - - require 'active_record/fixtures' - (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/).map {|f| File.join(fixtures_dir, f) } : Dir.glob(File.join(fixtures_dir, '*.{yml,csv}'))).each do |fixture_file| - Fixtures.create_fixtures(File.dirname(fixture_file), File.basename(fixture_file, '.*')) - end - end - end - end -end - -end diff --git a/lib/tasks/setup_tracks.rake b/lib/tasks/setup_tracks.rake deleted file mode 100644 index 0881dfb3..00000000 --- a/lib/tasks/setup_tracks.rake +++ /dev/null @@ -1,15 +0,0 @@ -desc "Initialises the installation, copy the *.tmpl files and directories to versions named without the .tmpl extension. It won't overwrite the files and directories if you've already copied them. You need to manually copy database.yml.tmpl -> database.yml and fill in the details before you run this task." -task :setup_tracks => :environment do - # Check the root directory for template files - FileList["*.tmpl"].each do |template_file| - f = File.basename(template_file) # with suffix - f_only = File.basename(template_file,".tmpl") # without suffix - if File.exists?(f_only) - puts f_only + " already exists" - else - cp_r(f, f_only) - puts f_only + " created" - end - end - -end \ No newline at end of file diff --git a/lib/tasks/upgrade_sqlite_db.rake b/lib/tasks/upgrade_sqlite_db.rake deleted file mode 100644 index 8e96fb18..00000000 --- a/lib/tasks/upgrade_sqlite_db.rake +++ /dev/null @@ -1,40 +0,0 @@ -desc "Updates sqlite/sqlite3 databases created under Tracks 1.03 to the format required for Tracks 1.04. After this is done, you should be able to keep up to date with changes in the schema by running rake db:migrate." -task :upgrade_sqlite_db => :environment do - # Change the three lines below appropriately for your setup - old_db = "tracks_103.db" - new_db = "tracks_104.db" - cmd = "sqlite3" - replace_string = "update todos set done='f' where done=0;\nupdate todos set done='t' where done=1;\nupdate contexts set hide='f' where hide=0;\nupdate contexts set hide='t' where hide=1;\nupdate projects set done='f' where done=0;\nupdate projects set done='t' where done=1;\nCREATE TABLE 'schema_info' (\n 'version' INTEGER default NULL\n);\nINSERT INTO \"schema_info\" VALUES(1);\nCOMMIT;" - - # cd to the db directory - cd("db") do - # Dump the old db into the temp file and replace the tinyints with booleans - `#{cmd} #{old_db} .dump | sed "s/tinyint(4) NOT NULL default '0'/boolean default 'f'/" > temp.sql` - # Create a second sqldump file for writing - sqldump = File.open("temp2.sql", "w+") - File.open("temp.sql") do |file| - file.each_line do |line| - # If COMMIT is on the line, insert the replace string - # else just write the line back in - # This effectively replaces COMMIT with the replace string - if /COMMIT/ =~ line - sqldump.write replace_string - else - sqldump.write line - end - end - sqldump.close - end - - # Read the second dump back in to a new db - system "#{cmd} #{new_db} < temp2.sql" - puts "Created the a new database called #{new_db}." - # Clean up the temp files - rm("temp.sql") - rm("temp2.sql") - puts "Temporary files cleaned up." - end - - # rake db:migrate - puts "Now check the database and run 'rake db:migrate' in the root of your Tracks installation." -end \ No newline at end of file diff --git a/lib/tracks/config.rb b/lib/tracks/config.rb deleted file mode 100644 index 0ca04f97..00000000 --- a/lib/tracks/config.rb +++ /dev/null @@ -1,27 +0,0 @@ -module Tracks - class Config - def self.salt - SITE_CONFIG['salt'] - end - - def self.auth_schemes - SITE_CONFIG['authentication_schemes'] || [] - end - - def self.openid_enabled? - auth_schemes.include?('open_id') - end - - def self.cas_enabled? - auth_schemes.include?('cas') - end - - def self.prefered_auth? - if SITE_CONFIG['prefered_auth'] - SITE_CONFIG['prefered_auth'] - else - auth_schemes.first - end - end - end -end \ No newline at end of file diff --git a/lib/tracks/todo_list.rb b/lib/tracks/todo_list.rb deleted file mode 100644 index b1a32229..00000000 --- a/lib/tracks/todo_list.rb +++ /dev/null @@ -1,59 +0,0 @@ -module Tracks - module TodoList - # TODO: this module should be deprecated. This could mostly (all?) be replaced by named scopes) - - def not_done_todos(opts={}) - @not_done_todos ||= self.find_not_done_todos(opts) - end - - def done_todos - @done_todos ||= self.find_done_todos - end - - def deferred_todos - @deferred_todos ||= self.find_deferred_todos - end - - def find_not_done_todos(opts={}) - with_not_done_scope(opts) do - self.todos.find(:all, :order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC") - end - end - - def find_deferred_todos(opts={}) - self.todos.find_in_state(:all, :deferred, :order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC") - end - - def find_done_todos - self.todos.completed.all(:order => "todos.completed_at DESC", :limit => self.user.prefs.show_number_completed) - end - - def not_done_todo_count(opts={}) - with_not_done_scope(opts) do - self.todos.count - end - end - - def with_not_done_scope(opts={}) - conditions = ["todos.state = ?", 'active'] - if opts.has_key?(:include_project_hidden_todos) && (opts[:include_project_hidden_todos] == true) - conditions = ["(todos.state = ? OR todos.state = ?)", 'active', 'project_hidden'] - end - if opts.has_key?(:tag) - conditions = ["todos.state = ? AND taggings.tag_id = ?", 'active', opts[:tag]] - end - self.todos.send :with_scope, :find => {:conditions => conditions, :include => [:taggings]} do - yield - end - end - - def done_todo_count - self.todos.count_in_state(:completed) - end - - def deferred_todo_count - self.todos.count_in_state(:deferred) - end - - end -end diff --git a/vendor/plugins/extra_validations/init.rb b/vendor/plugins/extra_validations/init.rb deleted file mode 100644 index 17709ad4..00000000 --- a/vendor/plugins/extra_validations/init.rb +++ /dev/null @@ -1,2 +0,0 @@ -require 'extra_validations' -ActiveRecord::Base.extend ExtraValidations \ No newline at end of file diff --git a/vendor/plugins/extra_validations/lib/extra_validations.rb b/vendor/plugins/extra_validations/lib/extra_validations.rb deleted file mode 100644 index be50b659..00000000 --- a/vendor/plugins/extra_validations/lib/extra_validations.rb +++ /dev/null @@ -1,29 +0,0 @@ -module ExtraValidations - - # Validates the value of the specified attribute by checking for a forbidden string - # - # class Person < ActiveRecord::Base - # validates_does_not_contain :first_name, :string => ',' - # end - # - # A string must be provided or else an exception will be raised. - # - # Configuration options: - # * message - A custom error message (default is: "is invalid") - # * string - The string to verify is not included (note: must be supplied!) - # * on Specifies when this validation is active (default is :save, other options :create, :update) - # * if - Specifies a method, proc or string to call to determine if the validation should - # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The - # method, proc or string should return or evaluate to a true or false value. - def validates_does_not_contain(*attr_names) - configuration = { :message => I18n.translate('activerecord.errors.messages')[:invalid], :on => :save, :string => nil } - configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash) - - raise(ArgumentError, "A string must be supplied as the :string option of the configuration hash") unless configuration[:string].is_a?(String) - - validates_each(attr_names, configuration) do |record, attr_name, value| - record.errors.add(attr_name, configuration[:message]) if value.to_s =~ Regexp.new(Regexp.escape(configuration[:string])) - end - end - -end diff --git a/vendor/plugins/open_id_authentication/CHANGELOG b/vendor/plugins/open_id_authentication/CHANGELOG deleted file mode 100644 index 7349bd3c..00000000 --- a/vendor/plugins/open_id_authentication/CHANGELOG +++ /dev/null @@ -1,35 +0,0 @@ -* Fake HTTP method from OpenID server since they only support a GET. Eliminates the need to set an extra route to match the server's reply. [Josh Peek] - -* OpenID 2.0 recommends that forms should use the field name "openid_identifier" rather than "openid_url" [Josh Peek] - -* Return open_id_response.display_identifier to the application instead of .endpoints.claimed_id. [nbibler] - -* Add Timeout protection [Rick] - -* An invalid identity url passed through authenticate_with_open_id will no longer raise an InvalidOpenId exception. Instead it will return Result[:missing] to the completion block. - -* Allow a return_to option to be used instead of the requested url [Josh Peek] - -* Updated plugin to use Ruby OpenID 2.x.x [Josh Peek] - -* Tied plugin to ruby-openid 1.1.4 gem until we can make it compatible with 2.x [DHH] - -* Use URI instead of regexps to normalize the URL and gain free, better matching #8136 [dkubb] - -* Allow -'s in #normalize_url [Rick] - -* remove instance of mattr_accessor, it was breaking tests since they don't load ActiveSupport. Fix Timeout test [Rick] - -* Throw a InvalidOpenId exception instead of just a RuntimeError when the URL can't be normalized [DHH] - -* Just use the path for the return URL, so extra query parameters don't interfere [DHH] - -* Added a new default database-backed store after experiencing trouble with the filestore on NFS. The file store is still available as an option [DHH] - -* Added normalize_url and applied it to all operations going through the plugin [DHH] - -* Removed open_id? as the idea of using the same input box for both OpenID and username has died -- use using_open_id? instead (which checks for the presence of params[:openid_url] by default) [DHH] - -* Added OpenIdAuthentication::Result to make it easier to deal with default situations where you don't care to do something particular for each error state [DHH] - -* Stop relying on root_url being defined, we can just grab the current url instead [DHH] \ No newline at end of file diff --git a/vendor/plugins/open_id_authentication/README b/vendor/plugins/open_id_authentication/README deleted file mode 100644 index 807cdc75..00000000 --- a/vendor/plugins/open_id_authentication/README +++ /dev/null @@ -1,231 +0,0 @@ -OpenIdAuthentication -==================== - -Provides a thin wrapper around the excellent ruby-openid gem from JanRan. Be sure to install that first: - - gem install ruby-openid - -To understand what OpenID is about and how it works, it helps to read the documentation for lib/openid/consumer.rb -from that gem. - -The specification used is http://openid.net/specs/openid-authentication-2_0.html. - - -Prerequisites -============= - -OpenID authentication uses the session, so be sure that you haven't turned that off. It also relies on a number of -database tables to store the authentication keys. So you'll have to run the migration to create these before you get started: - - rake open_id_authentication:db:create - -Or, use the included generators to install or upgrade: - - ./script/generate open_id_authentication_tables MigrationName - ./script/generate upgrade_open_id_authentication_tables MigrationName - -Alternatively, you can use the file-based store, which just relies on on tmp/openids being present in RAILS_ROOT. But be aware that this store only works if you have a single application server. And it's not safe to use across NFS. It's recommended that you use the database store if at all possible. To use the file-based store, you'll also have to add this line to your config/environment.rb: - - OpenIdAuthentication.store = :file - -This particular plugin also relies on the fact that the authentication action allows for both POST and GET operations. -If you're using RESTful authentication, you'll need to explicitly allow for this in your routes.rb. - -The plugin also expects to find a root_url method that points to the home page of your site. You can accomplish this by using a root route in config/routes.rb: - - map.root :controller => 'articles' - -This plugin relies on Rails Edge revision 6317 or newer. - - -Example -======= - -This example is just to meant to demonstrate how you could use OpenID authentication. You might well want to add -salted hash logins instead of plain text passwords and other requirements on top of this. Treat it as a starting point, -not a destination. - -Note that the User model referenced in the simple example below has an 'identity_url' attribute. You will want to add the same or similar field to whatever -model you are using for authentication. - -Also of note is the following code block used in the example below: - - authenticate_with_open_id do |result, identity_url| - ... - end - -In the above code block, 'identity_url' will need to match user.identity_url exactly. 'identity_url' will be a string in the form of 'http://example.com' - -If you are storing just 'example.com' with your user, the lookup will fail. - -There is a handy method in this plugin called 'normalize_url' that will help with validating OpenID URLs. - - OpenIdAuthentication.normalize_url(user.identity_url) - -The above will return a standardized version of the OpenID URL - the above called with 'example.com' will return 'http://example.com/' -It will also raise an InvalidOpenId exception if the URL is determined to not be valid. -Use the above code in your User model and validate OpenID URLs before saving them. - -config/routes.rb - - map.root :controller => 'articles' - map.resource :session - - -app/views/sessions/new.erb - - <% form_tag(session_url) do %> -

        - - <%= text_field_tag "name" %> -

        - -

        - - <%= password_field_tag %> -

        - -

        - ...or use: -

        - -

        - - <%= text_field_tag "openid_identifier" %> -

        - -

        - <%= submit_tag 'Sign in', :disable_with => "Signing in…" %> -

        - <% end %> - -app/controllers/sessions_controller.rb - class SessionsController < ApplicationController - def create - if using_open_id? - open_id_authentication - else - password_authentication(params[:name], params[:password]) - end - end - - - protected - def password_authentication(name, password) - if @current_user = @account.users.authenticate(params[:name], params[:password]) - successful_login - else - failed_login "Sorry, that username/password doesn't work" - end - end - - def open_id_authentication - authenticate_with_open_id do |result, identity_url| - if result.successful? - if @current_user = @account.users.find_by_identity_url(identity_url) - successful_login - else - failed_login "Sorry, no user by that identity URL exists (#{identity_url})" - end - else - failed_login result.message - end - end - end - - - private - def successful_login - session[:user_id] = @current_user.id - redirect_to(root_url) - end - - def failed_login(message) - flash[:error] = message - redirect_to(new_session_url) - end - end - - - -If you're fine with the result messages above and don't need individual logic on a per-failure basis, -you can collapse the case into a mere boolean: - - def open_id_authentication - authenticate_with_open_id do |result, identity_url| - if result.successful? && @current_user = @account.users.find_by_identity_url(identity_url) - successful_login - else - failed_login(result.message || "Sorry, no user by that identity URL exists (#{identity_url})") - end - end - end - - -Simple Registration OpenID Extension -==================================== - -Some OpenID Providers support this lightweight profile exchange protocol. See more: http://www.openidenabled.com/openid/simple-registration-extension - -You can support it in your app by changing #open_id_authentication - - def open_id_authentication(identity_url) - # Pass optional :required and :optional keys to specify what sreg fields you want. - # Be sure to yield registration, a third argument in the #authenticate_with_open_id block. - authenticate_with_open_id(identity_url, - :required => [ :nickname, :email ], - :optional => :fullname) do |result, identity_url, registration| - case result.status - when :missing - failed_login "Sorry, the OpenID server couldn't be found" - when :invalid - failed_login "Sorry, but this does not appear to be a valid OpenID" - when :canceled - failed_login "OpenID verification was canceled" - when :failed - failed_login "Sorry, the OpenID verification failed" - when :successful - if @current_user = @account.users.find_by_identity_url(identity_url) - assign_registration_attributes!(registration) - - if current_user.save - successful_login - else - failed_login "Your OpenID profile registration failed: " + - @current_user.errors.full_messages.to_sentence - end - else - failed_login "Sorry, no user by that identity URL exists" - end - end - end - end - - # registration is a hash containing the valid sreg keys given above - # use this to map them to fields of your user model - def assign_registration_attributes!(registration) - model_to_registration_mapping.each do |model_attribute, registration_attribute| - unless registration[registration_attribute].blank? - @current_user.send("#{model_attribute}=", registration[registration_attribute]) - end - end - end - - def model_to_registration_mapping - { :login => 'nickname', :email => 'email', :display_name => 'fullname' } - end - -Attribute Exchange OpenID Extension -=================================== - -Some OpenID providers also support the OpenID AX (attribute exchange) protocol for exchanging identity information between endpoints. See more: http://openid.net/specs/openid-attribute-exchange-1_0.html - -Accessing AX data is very similar to the Simple Registration process, described above -- just add the URI identifier for the AX field to your :optional or :required parameters. For example: - - authenticate_with_open_id(identity_url, - :required => [ :email, 'http://schema.openid.net/birthDate' ]) do |result, identity_url, registration| - -This would provide the sreg data for :email, and the AX data for 'http://schema.openid.net/birthDate' - - - -Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license \ No newline at end of file diff --git a/vendor/plugins/open_id_authentication/Rakefile b/vendor/plugins/open_id_authentication/Rakefile deleted file mode 100644 index 31074b85..00000000 --- a/vendor/plugins/open_id_authentication/Rakefile +++ /dev/null @@ -1,22 +0,0 @@ -require 'rake' -require 'rake/testtask' -require 'rake/rdoctask' - -desc 'Default: run unit tests.' -task :default => :test - -desc 'Test the open_id_authentication plugin.' -Rake::TestTask.new(:test) do |t| - t.libs << 'lib' - t.pattern = 'test/**/*_test.rb' - t.verbose = true -end - -desc 'Generate documentation for the open_id_authentication plugin.' -Rake::RDocTask.new(:rdoc) do |rdoc| - rdoc.rdoc_dir = 'rdoc' - rdoc.title = 'OpenIdAuthentication' - rdoc.options << '--line-numbers' << '--inline-source' - rdoc.rdoc_files.include('README') - rdoc.rdoc_files.include('lib/**/*.rb') -end diff --git a/vendor/plugins/open_id_authentication/generators/open_id_authentication_tables/open_id_authentication_tables_generator.rb b/vendor/plugins/open_id_authentication/generators/open_id_authentication_tables/open_id_authentication_tables_generator.rb deleted file mode 100644 index 6f78afc7..00000000 --- a/vendor/plugins/open_id_authentication/generators/open_id_authentication_tables/open_id_authentication_tables_generator.rb +++ /dev/null @@ -1,11 +0,0 @@ -class OpenIdAuthenticationTablesGenerator < Rails::Generator::NamedBase - def initialize(runtime_args, runtime_options = {}) - super - end - - def manifest - record do |m| - m.migration_template 'migration.rb', 'db/migrate' - end - end -end diff --git a/vendor/plugins/open_id_authentication/generators/open_id_authentication_tables/templates/migration.rb b/vendor/plugins/open_id_authentication/generators/open_id_authentication_tables/templates/migration.rb deleted file mode 100644 index ef2a0cfb..00000000 --- a/vendor/plugins/open_id_authentication/generators/open_id_authentication_tables/templates/migration.rb +++ /dev/null @@ -1,20 +0,0 @@ -class <%= class_name %> < ActiveRecord::Migration - def self.up - create_table :open_id_authentication_associations, :force => true do |t| - t.integer :issued, :lifetime - t.string :handle, :assoc_type - t.binary :server_url, :secret - end - - create_table :open_id_authentication_nonces, :force => true do |t| - t.integer :timestamp, :null => false - t.string :server_url, :null => true - t.string :salt, :null => false - end - end - - def self.down - drop_table :open_id_authentication_associations - drop_table :open_id_authentication_nonces - end -end diff --git a/vendor/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/templates/migration.rb b/vendor/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/templates/migration.rb deleted file mode 100644 index d13bbab2..00000000 --- a/vendor/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/templates/migration.rb +++ /dev/null @@ -1,26 +0,0 @@ -class <%= class_name %> < ActiveRecord::Migration - def self.up - drop_table :open_id_authentication_settings - drop_table :open_id_authentication_nonces - - create_table :open_id_authentication_nonces, :force => true do |t| - t.integer :timestamp, :null => false - t.string :server_url, :null => true - t.string :salt, :null => false - end - end - - def self.down - drop_table :open_id_authentication_nonces - - create_table :open_id_authentication_nonces, :force => true do |t| - t.integer :created - t.string :nonce - end - - create_table :open_id_authentication_settings, :force => true do |t| - t.string :setting - t.binary :value - end - end -end diff --git a/vendor/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/upgrade_open_id_authentication_tables_generator.rb b/vendor/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/upgrade_open_id_authentication_tables_generator.rb deleted file mode 100644 index 02fddd7f..00000000 --- a/vendor/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/upgrade_open_id_authentication_tables_generator.rb +++ /dev/null @@ -1,11 +0,0 @@ -class UpgradeOpenIdAuthenticationTablesGenerator < Rails::Generator::NamedBase - def initialize(runtime_args, runtime_options = {}) - super - end - - def manifest - record do |m| - m.migration_template 'migration.rb', 'db/migrate' - end - end -end diff --git a/vendor/plugins/open_id_authentication/init.rb b/vendor/plugins/open_id_authentication/init.rb deleted file mode 100644 index 808c7bdb..00000000 --- a/vendor/plugins/open_id_authentication/init.rb +++ /dev/null @@ -1,18 +0,0 @@ -if config.respond_to?(:gems) - config.gem 'ruby-openid', :lib => 'openid', :version => '>=2.0.4' -else - begin - require 'openid' - rescue LoadError - begin - gem 'ruby-openid', '>=2.0.4' - rescue Gem::LoadError - puts "Install the ruby-openid gem to enable OpenID support" - end - end -end - -config.to_prepare do - OpenID::Util.logger = Rails.logger - ActionController::Base.send :include, OpenIdAuthentication -end diff --git a/vendor/plugins/open_id_authentication/lib/open_id_authentication.rb b/vendor/plugins/open_id_authentication/lib/open_id_authentication.rb deleted file mode 100644 index b485c5fe..00000000 --- a/vendor/plugins/open_id_authentication/lib/open_id_authentication.rb +++ /dev/null @@ -1,240 +0,0 @@ -require 'uri' -require 'openid/extensions/sreg' -require 'openid/extensions/ax' -require 'openid/store/filesystem' - -require File.dirname(__FILE__) + '/open_id_authentication/association' -require File.dirname(__FILE__) + '/open_id_authentication/nonce' -require File.dirname(__FILE__) + '/open_id_authentication/db_store' -require File.dirname(__FILE__) + '/open_id_authentication/request' -require File.dirname(__FILE__) + '/open_id_authentication/timeout_fixes' if OpenID::VERSION == "2.0.4" - -module OpenIdAuthentication - OPEN_ID_AUTHENTICATION_DIR = RAILS_ROOT + "/tmp/openids" - - def self.store - @@store - end - - def self.store=(*store_option) - store, *parameters = *([ store_option ].flatten) - - @@store = case store - when :db - OpenIdAuthentication::DbStore.new - when :file - OpenID::Store::Filesystem.new(OPEN_ID_AUTHENTICATION_DIR) - else - store - end - end - - self.store = :db - - class InvalidOpenId < StandardError - end - - class Result - ERROR_MESSAGES = { - :missing => "Sorry, the OpenID server couldn't be found", - :invalid => "Sorry, but this does not appear to be a valid OpenID", - :canceled => "OpenID verification was canceled", - :failed => "OpenID verification failed", - :setup_needed => "OpenID verification needs setup" - } - - def self.[](code) - new(code) - end - - def initialize(code) - @code = code - end - - def status - @code - end - - ERROR_MESSAGES.keys.each { |state| define_method("#{state}?") { @code == state } } - - def successful? - @code == :successful - end - - def unsuccessful? - ERROR_MESSAGES.keys.include?(@code) - end - - def message - ERROR_MESSAGES[@code] - end - end - - # normalizes an OpenID according to http://openid.net/specs/openid-authentication-2_0.html#normalization - def self.normalize_identifier(identifier) - # clean up whitespace - identifier = identifier.to_s.strip - - # if an XRI has a prefix, strip it. - identifier.gsub!(/xri:\/\//i, '') - - # dodge XRIs -- TODO: validate, don't just skip. - unless ['=', '@', '+', '$', '!', '('].include?(identifier.at(0)) - # does it begin with http? if not, add it. - identifier = "http://#{identifier}" unless identifier =~ /^http/i - - # strip any fragments - identifier.gsub!(/\#(.*)$/, '') - - begin - uri = URI.parse(identifier) - uri.scheme = uri.scheme.downcase # URI should do this - identifier = uri.normalize.to_s - rescue URI::InvalidURIError - raise InvalidOpenId.new("#{identifier} is not an OpenID identifier") - end - end - - return identifier - end - - # deprecated for OpenID 2.0, where not all OpenIDs are URLs - def self.normalize_url(url) - ActiveSupport::Deprecation.warn "normalize_url has been deprecated, use normalize_identifier instead" - self.normalize_identifier(url) - end - - protected - def normalize_url(url) - OpenIdAuthentication.normalize_url(url) - end - - def normalize_identifier(url) - OpenIdAuthentication.normalize_identifier(url) - end - - # The parameter name of "openid_identifier" is used rather than the Rails convention "open_id_identifier" - # because that's what the specification dictates in order to get browser auto-complete working across sites - def using_open_id?(identity_url = nil) #:doc: - identity_url ||= params[:openid_identifier] || params[:openid_url] - !identity_url.blank? || params[:open_id_complete] - end - - def authenticate_with_open_id(identity_url = nil, options = {}, &block) #:doc: - identity_url ||= params[:openid_identifier] || params[:openid_url] - - if params[:open_id_complete].nil? - begin_open_id_authentication(identity_url, options, &block) - else - complete_open_id_authentication(&block) - end - end - - private - def begin_open_id_authentication(identity_url, options = {}) - identity_url = normalize_identifier(identity_url) - return_to = options.delete(:return_to) - method = options.delete(:method) - - options[:required] ||= [] # reduces validation later - options[:optional] ||= [] - - open_id_request = open_id_consumer.begin(identity_url) - add_simple_registration_fields(open_id_request, options) - add_ax_fields(open_id_request, options) - redirect_to(open_id_redirect_url(open_id_request, return_to, method)) - rescue OpenIdAuthentication::InvalidOpenId => e - yield Result[:invalid], identity_url, nil - rescue OpenID::OpenIDError, Timeout::Error => e - logger.error("[OPENID] #{e}") - yield Result[:missing], identity_url, nil - end - - def complete_open_id_authentication - params_with_path = params.reject { |key, value| request.path_parameters[key] } - params_with_path.delete(:format) - open_id_response = timeout_protection_from_identity_server { open_id_consumer.complete(params_with_path, requested_url) } - identity_url = normalize_identifier(open_id_response.display_identifier) if open_id_response.display_identifier - - case open_id_response.status - when OpenID::Consumer::SUCCESS - profile_data = {} - - # merge the SReg data and the AX data into a single hash of profile data - [ OpenID::SReg::Response, OpenID::AX::FetchResponse ].each do |data_response| - if data_response.from_success_response( open_id_response ) - profile_data.merge! data_response.from_success_response( open_id_response ).data - end - end - - yield Result[:successful], identity_url, profile_data - when OpenID::Consumer::CANCEL - yield Result[:canceled], identity_url, nil - when OpenID::Consumer::FAILURE - yield Result[:failed], identity_url, nil - when OpenID::Consumer::SETUP_NEEDED - yield Result[:setup_needed], open_id_response.setup_url, nil - end - end - - def open_id_consumer - OpenID::Consumer.new(session, OpenIdAuthentication.store) - end - - def add_simple_registration_fields(open_id_request, fields) - sreg_request = OpenID::SReg::Request.new - - # filter out AX identifiers (URIs) - required_fields = fields[:required].collect { |f| f.to_s unless f =~ /^https?:\/\// }.compact - optional_fields = fields[:optional].collect { |f| f.to_s unless f =~ /^https?:\/\// }.compact - - sreg_request.request_fields(required_fields, true) unless required_fields.blank? - sreg_request.request_fields(optional_fields, false) unless optional_fields.blank? - sreg_request.policy_url = fields[:policy_url] if fields[:policy_url] - open_id_request.add_extension(sreg_request) - end - - def add_ax_fields( open_id_request, fields ) - ax_request = OpenID::AX::FetchRequest.new - - # look through the :required and :optional fields for URIs (AX identifiers) - fields[:required].each do |f| - next unless f =~ /^https?:\/\// - ax_request.add( OpenID::AX::AttrInfo.new( f, nil, true ) ) - end - - fields[:optional].each do |f| - next unless f =~ /^https?:\/\// - ax_request.add( OpenID::AX::AttrInfo.new( f, nil, false ) ) - end - - open_id_request.add_extension( ax_request ) - end - - def open_id_redirect_url(open_id_request, return_to = nil, method = nil) - open_id_request.return_to_args['_method'] = (method || request.method).to_s - open_id_request.return_to_args['open_id_complete'] = '1' - open_id_request.redirect_url(root_url, return_to || requested_url) - end - - def requested_url - relative_url_root = self.class.respond_to?(:relative_url_root) ? - self.class.relative_url_root.to_s : - request.relative_url_root - "#{request.protocol}#{request.host_with_port}#{ActionController::Base.relative_url_root}#{request.path}" - end - - def timeout_protection_from_identity_server - yield - rescue Timeout::Error - Class.new do - def status - OpenID::FAILURE - end - - def msg - "Identity server timed out" - end - end.new - end -end diff --git a/vendor/plugins/open_id_authentication/lib/open_id_authentication/association.rb b/vendor/plugins/open_id_authentication/lib/open_id_authentication/association.rb deleted file mode 100644 index 9654eaeb..00000000 --- a/vendor/plugins/open_id_authentication/lib/open_id_authentication/association.rb +++ /dev/null @@ -1,9 +0,0 @@ -module OpenIdAuthentication - class Association < ActiveRecord::Base - set_table_name :open_id_authentication_associations - - def from_record - OpenID::Association.new(handle, secret, issued, lifetime, assoc_type) - end - end -end diff --git a/vendor/plugins/open_id_authentication/lib/open_id_authentication/db_store.rb b/vendor/plugins/open_id_authentication/lib/open_id_authentication/db_store.rb deleted file mode 100644 index 780fb6ad..00000000 --- a/vendor/plugins/open_id_authentication/lib/open_id_authentication/db_store.rb +++ /dev/null @@ -1,55 +0,0 @@ -require 'openid/store/interface' - -module OpenIdAuthentication - class DbStore < OpenID::Store::Interface - def self.cleanup_nonces - now = Time.now.to_i - Nonce.delete_all(["timestamp > ? OR timestamp < ?", now + OpenID::Nonce.skew, now - OpenID::Nonce.skew]) - end - - def self.cleanup_associations - now = Time.now.to_i - Association.delete_all(['issued + lifetime > ?',now]) - end - - def store_association(server_url, assoc) - remove_association(server_url, assoc.handle) - Association.create(:server_url => server_url, - :handle => assoc.handle, - :secret => assoc.secret, - :issued => assoc.issued, - :lifetime => assoc.lifetime, - :assoc_type => assoc.assoc_type) - end - - def get_association(server_url, handle = nil) - assocs = if handle.blank? - Association.find_all_by_server_url(server_url) - else - Association.find_all_by_server_url_and_handle(server_url, handle) - end - - assocs.reverse.each do |assoc| - a = assoc.from_record - if a.expires_in == 0 - assoc.destroy - else - return a - end - end if assocs.any? - - return nil - end - - def remove_association(server_url, handle) - Association.delete_all(['server_url = ? AND handle = ?', server_url, handle]) > 0 - end - - def use_nonce(server_url, timestamp, salt) - return false if Nonce.find_by_server_url_and_timestamp_and_salt(server_url, timestamp, salt) - return false if (timestamp - Time.now.to_i).abs > OpenID::Nonce.skew - Nonce.create(:server_url => server_url, :timestamp => timestamp, :salt => salt) - return true - end - end -end diff --git a/vendor/plugins/open_id_authentication/lib/open_id_authentication/nonce.rb b/vendor/plugins/open_id_authentication/lib/open_id_authentication/nonce.rb deleted file mode 100644 index c52f6c50..00000000 --- a/vendor/plugins/open_id_authentication/lib/open_id_authentication/nonce.rb +++ /dev/null @@ -1,5 +0,0 @@ -module OpenIdAuthentication - class Nonce < ActiveRecord::Base - set_table_name :open_id_authentication_nonces - end -end diff --git a/vendor/plugins/open_id_authentication/lib/open_id_authentication/request.rb b/vendor/plugins/open_id_authentication/lib/open_id_authentication/request.rb deleted file mode 100644 index e0cc8e3f..00000000 --- a/vendor/plugins/open_id_authentication/lib/open_id_authentication/request.rb +++ /dev/null @@ -1,23 +0,0 @@ -module OpenIdAuthentication - module Request - def self.included(base) - base.alias_method_chain :request_method, :openid - end - - def request_method_with_openid - if !parameters[:_method].blank? && parameters[:open_id_complete] == '1' - parameters[:_method].to_sym - else - request_method_without_openid - end - end - end -end - -# In Rails 2.3, the request object has been renamed -# from AbstractRequest to Request -if defined? ActionController::Request - ActionController::Request.send :include, OpenIdAuthentication::Request -else - ActionController::AbstractRequest.send :include, OpenIdAuthentication::Request -end diff --git a/vendor/plugins/open_id_authentication/lib/open_id_authentication/timeout_fixes.rb b/vendor/plugins/open_id_authentication/lib/open_id_authentication/timeout_fixes.rb deleted file mode 100644 index cc711c9a..00000000 --- a/vendor/plugins/open_id_authentication/lib/open_id_authentication/timeout_fixes.rb +++ /dev/null @@ -1,20 +0,0 @@ -# http://trac.openidenabled.com/trac/ticket/156 -module OpenID - @@timeout_threshold = 20 - - def self.timeout_threshold - @@timeout_threshold - end - - def self.timeout_threshold=(value) - @@timeout_threshold = value - end - - class StandardFetcher - def make_http(uri) - http = @proxy.new(uri.host, uri.port) - http.read_timeout = http.open_timeout = OpenID.timeout_threshold - http - end - end -end \ No newline at end of file diff --git a/vendor/plugins/open_id_authentication/tasks/open_id_authentication_tasks.rake b/vendor/plugins/open_id_authentication/tasks/open_id_authentication_tasks.rake deleted file mode 100644 index c71434a5..00000000 --- a/vendor/plugins/open_id_authentication/tasks/open_id_authentication_tasks.rake +++ /dev/null @@ -1,30 +0,0 @@ -namespace :open_id_authentication do - namespace :db do - desc "Creates authentication tables for use with OpenIdAuthentication" - task :create => :environment do - generate_migration(["open_id_authentication_tables", "add_open_id_authentication_tables"]) - end - - desc "Upgrade authentication tables from ruby-openid 1.x.x to 2.x.x" - task :upgrade => :environment do - generate_migration(["upgrade_open_id_authentication_tables", "upgrade_open_id_authentication_tables"]) - end - - def generate_migration(args) - require 'rails_generator' - require 'rails_generator/scripts/generate' - - if ActiveRecord::Base.connection.supports_migrations? - Rails::Generator::Scripts::Generate.new.run(args) - else - raise "Task unavailable to this database (no migration support)" - end - end - - desc "Clear the authentication tables" - task :clear => :environment do - OpenIdAuthentication::DbStore.cleanup_nonces - OpenIdAuthentication::DbStore.cleanup_associations - end - end -end diff --git a/vendor/plugins/open_id_authentication/test/normalize_test.rb b/vendor/plugins/open_id_authentication/test/normalize_test.rb deleted file mode 100644 index 635d3abc..00000000 --- a/vendor/plugins/open_id_authentication/test/normalize_test.rb +++ /dev/null @@ -1,32 +0,0 @@ -require File.dirname(__FILE__) + '/test_helper' - -class NormalizeTest < Test::Unit::TestCase - include OpenIdAuthentication - - NORMALIZATIONS = { - "openid.aol.com/nextangler" => "http://openid.aol.com/nextangler", - "http://openid.aol.com/nextangler" => "http://openid.aol.com/nextangler", - "https://openid.aol.com/nextangler" => "https://openid.aol.com/nextangler", - "HTTP://OPENID.AOL.COM/NEXTANGLER" => "http://openid.aol.com/NEXTANGLER", - "HTTPS://OPENID.AOL.COM/NEXTANGLER" => "https://openid.aol.com/NEXTANGLER", - "loudthinking.com" => "http://loudthinking.com/", - "http://loudthinking.com" => "http://loudthinking.com/", - "http://loudthinking.com:80" => "http://loudthinking.com/", - "https://loudthinking.com:443" => "https://loudthinking.com/", - "http://loudthinking.com:8080" => "http://loudthinking.com:8080/", - "techno-weenie.net" => "http://techno-weenie.net/", - "http://techno-weenie.net" => "http://techno-weenie.net/", - "http://techno-weenie.net " => "http://techno-weenie.net/", - "=name" => "=name" - } - - def test_normalizations - NORMALIZATIONS.each do |from, to| - assert_equal to, normalize_identifier(from) - end - end - - def test_broken_open_id - assert_raises(InvalidOpenId) { normalize_identifier(nil) } - end -end diff --git a/vendor/plugins/open_id_authentication/test/open_id_authentication_test.rb b/vendor/plugins/open_id_authentication/test/open_id_authentication_test.rb deleted file mode 100644 index ddcc17b9..00000000 --- a/vendor/plugins/open_id_authentication/test/open_id_authentication_test.rb +++ /dev/null @@ -1,46 +0,0 @@ -require File.dirname(__FILE__) + '/test_helper' - -class OpenIdAuthenticationTest < Test::Unit::TestCase - def setup - @controller = Class.new do - include OpenIdAuthentication - def params() {} end - end.new - end - - def test_authentication_should_fail_when_the_identity_server_is_missing - open_id_consumer = mock() - open_id_consumer.expects(:begin).raises(OpenID::OpenIDError) - @controller.expects(:open_id_consumer).returns(open_id_consumer) - @controller.expects(:logger).returns(mock(:error => true)) - - @controller.send(:authenticate_with_open_id, "http://someone.example.com") do |result, identity_url| - assert result.missing? - assert_equal "Sorry, the OpenID server couldn't be found", result.message - end - end - - def test_authentication_should_be_invalid_when_the_identity_url_is_invalid - @controller.send(:authenticate_with_open_id, "!") do |result, identity_url| - assert result.invalid?, "Result expected to be invalid but was not" - assert_equal "Sorry, but this does not appear to be a valid OpenID", result.message - end - end - - def test_authentication_should_fail_when_the_identity_server_times_out - open_id_consumer = mock() - open_id_consumer.expects(:begin).raises(Timeout::Error, "Identity Server took too long.") - @controller.expects(:open_id_consumer).returns(open_id_consumer) - @controller.expects(:logger).returns(mock(:error => true)) - - @controller.send(:authenticate_with_open_id, "http://someone.example.com") do |result, identity_url| - assert result.missing? - assert_equal "Sorry, the OpenID server couldn't be found", result.message - end - end - - def test_authentication_should_begin_when_the_identity_server_is_present - @controller.expects(:begin_open_id_authentication) - @controller.send(:authenticate_with_open_id, "http://someone.example.com") - end -end diff --git a/vendor/plugins/open_id_authentication/test/status_test.rb b/vendor/plugins/open_id_authentication/test/status_test.rb deleted file mode 100644 index b1d5e093..00000000 --- a/vendor/plugins/open_id_authentication/test/status_test.rb +++ /dev/null @@ -1,14 +0,0 @@ -require File.dirname(__FILE__) + '/test_helper' - -class StatusTest < Test::Unit::TestCase - include OpenIdAuthentication - - def test_state_conditional - assert Result[:missing].missing? - assert Result[:missing].unsuccessful? - assert !Result[:missing].successful? - - assert Result[:successful].successful? - assert !Result[:successful].unsuccessful? - end -end \ No newline at end of file diff --git a/vendor/plugins/open_id_authentication/test/test_helper.rb b/vendor/plugins/open_id_authentication/test/test_helper.rb deleted file mode 100644 index 43216e1e..00000000 --- a/vendor/plugins/open_id_authentication/test/test_helper.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'test/unit' -require 'rubygems' - -gem 'activesupport' -require 'active_support' - -gem 'actionpack' -require 'action_controller' - -gem 'mocha' -require 'mocha' - -gem 'ruby-openid' -require 'openid' - -RAILS_ROOT = File.dirname(__FILE__) unless defined? RAILS_ROOT -require File.dirname(__FILE__) + "/../lib/open_id_authentication" diff --git a/vendor/plugins/resource_feeder/README b/vendor/plugins/resource_feeder/README deleted file mode 100644 index 5502be25..00000000 --- a/vendor/plugins/resource_feeder/README +++ /dev/null @@ -1,7 +0,0 @@ -ResourceFeeder -============== - -Simple feeds for resources - -NOTE: This plugin depends on the latest version of simply_helpful, available here: -http://dev.rubyonrails.org/svn/rails/plugins/simply_helpful/ diff --git a/vendor/plugins/resource_feeder/Rakefile b/vendor/plugins/resource_feeder/Rakefile deleted file mode 100644 index 51fce7b3..00000000 --- a/vendor/plugins/resource_feeder/Rakefile +++ /dev/null @@ -1,22 +0,0 @@ -require 'rake' -require 'rake/testtask' -require 'rake/rdoctask' - -desc 'Default: run unit tests.' -task :default => :test - -desc 'Test the resource_feed plugin.' -Rake::TestTask.new(:test) do |t| - t.libs << 'lib' - t.pattern = 'test/**/*_test.rb' - t.verbose = true -end - -desc 'Generate documentation for the resource_feed plugin.' -Rake::RDocTask.new(:rdoc) do |rdoc| - rdoc.rdoc_dir = 'rdoc' - rdoc.title = 'ResourceFeed' - rdoc.options << '--line-numbers' << '--inline-source' - rdoc.rdoc_files.include('README') - rdoc.rdoc_files.include('lib/**/*.rb') -end diff --git a/vendor/plugins/resource_feeder/init.rb b/vendor/plugins/resource_feeder/init.rb deleted file mode 100644 index 7b55d76f..00000000 --- a/vendor/plugins/resource_feeder/init.rb +++ /dev/null @@ -1,2 +0,0 @@ -require 'resource_feeder' -ActionController::Base.send(:include, ResourceFeeder::Rss, ResourceFeeder::Atom) \ No newline at end of file diff --git a/vendor/plugins/resource_feeder/lib/resource_feeder.rb b/vendor/plugins/resource_feeder/lib/resource_feeder.rb deleted file mode 100644 index b5003419..00000000 --- a/vendor/plugins/resource_feeder/lib/resource_feeder.rb +++ /dev/null @@ -1,2 +0,0 @@ -require 'resource_feeder/rss' -require 'resource_feeder/atom' diff --git a/vendor/plugins/resource_feeder/lib/resource_feeder/atom.rb b/vendor/plugins/resource_feeder/lib/resource_feeder/atom.rb deleted file mode 100644 index 40af87df..00000000 --- a/vendor/plugins/resource_feeder/lib/resource_feeder/atom.rb +++ /dev/null @@ -1,67 +0,0 @@ -require 'resource_feeder/common' - -module ResourceFeeder - module Atom - include ResourceFeeder::Common - include ActionController::Routing - extend self - - def render_atom_feed_for(resources, options = {}) - render :text => atom_feed_for(resources, options), :content_type => Mime::ATOM - end - - def atom_feed_for(resources, options = {}) - xml = Builder::XmlMarkup.new(:indent => 2) - - options[:feed] ||= {} - options[:item] ||= {} - options[:url_writer] ||= self - - if options[:class] || resources.first - klass = options[:class] || resources.first.class - new_record = klass.new - else - options[:feed] = { :title => "Empty", :link => "http://example.com" } - end - - options[:feed][:title] ||= klass.name.pluralize - options[:feed][:id] ||= "tag:#{request.host_with_port}:#{klass.name.pluralize}" - options[:feed][:link] ||= polymorphic_url(new_record, :controller => options[:url_writer].controller_name) - - options[:item][:title] ||= [ :title, :subject, :headline, :name ] - options[:item][:description] ||= [ :description, :body, :content ] - options[:item][:pub_date] ||= [ :updated_at, :updated_on, :created_at, :created_on ] - options[:item][:author] ||= [ :author, :creator ] - - resource_link = lambda { |r| polymorphic_url(r, :controller => options[:url_writer].controller_name) } - - xml.instruct! - xml.feed "xml:lang" => "en-US", "xmlns" => 'http://www.w3.org/2005/Atom' do - xml.title(options[:feed][:title]) - xml.id(options[:feed][:id]) - xml.link(:rel => 'alternate', :type => 'text/html', :href => options[:feed][:link]) - xml.link(:rel => 'self', :type => 'application/atom+xml', :href => options[:feed][:self]) if options[:feed][:self] - xml.subtitle(options[:feed][:description]) if options[:feed][:description] - - for resource in resources - published_at = call_or_read(options[:item][:pub_date], resource) - - xml.entry do - xml.title(call_or_read(options[:item][:title], resource)) - xml.content(call_or_read(options[:item][:description], resource), :type => 'html') - xml.id("tag:#{request.host_with_port},#{published_at.xmlschema}:#{call_or_read(options[:item][:guid] || options[:item][:link] || resource_link, resource)}") - xml.published(published_at.xmlschema) - xml.updated((resource.respond_to?(:updated_at) ? call_or_read(options[:item][:pub_date] || :updated_at, resource) : published_at).xmlschema) - xml.link(:rel => 'alternate', :type => 'text/html', :href => call_or_read(options[:item][:link] || options[:item][:guid] || resource_link, resource)) - - if author = call_or_read(options[:item][:author], resource) - xml.author do - xml.name() - end - end - end - end - end - end - end -end diff --git a/vendor/plugins/resource_feeder/lib/resource_feeder/common.rb b/vendor/plugins/resource_feeder/lib/resource_feeder/common.rb deleted file mode 100644 index 383b965e..00000000 --- a/vendor/plugins/resource_feeder/lib/resource_feeder/common.rb +++ /dev/null @@ -1,24 +0,0 @@ -module ResourceFeeder - module Common - private - def call_or_read(procedure_or_attributes, resource) - case procedure_or_attributes - when nil - raise ArgumentError, "WTF is nil here? #{resource.inspect}" - when Array - attributes = procedure_or_attributes - if attr = attributes.select { |a| resource.respond_to?(a) }.first - resource.send attr - end - when Symbol - attribute = procedure_or_attributes - resource.send(attribute) - when Proc - procedure = procedure_or_attributes - procedure.call(resource) - else - raise ArgumentError, "WTF is #{procedure_or_attributes.inspect} here? #{resource.inspect}" - end - end - end -end diff --git a/vendor/plugins/resource_feeder/lib/resource_feeder/rss.rb b/vendor/plugins/resource_feeder/lib/resource_feeder/rss.rb deleted file mode 100644 index d3fa56d7..00000000 --- a/vendor/plugins/resource_feeder/lib/resource_feeder/rss.rb +++ /dev/null @@ -1,68 +0,0 @@ -require 'resource_feeder/common' - -module ResourceFeeder - module Rss - include ResourceFeeder::Common - include ActionController::Routing - extend self - - def render_rss_feed_for(resources, options = {}) - render :text => rss_feed_for(resources, options), :content_type => Mime::RSS - end - - def rss_feed_for(resources, options = {}) - xml = Builder::XmlMarkup.new(:indent => 2) - - options[:feed] ||= {} - options[:item] ||= {} - options[:url_writer] ||= self - - if options[:class] || resources.first - klass = options[:class] || resources.first.class - new_record = klass.new - else - options[:feed] = { :title => "Empty", :link => "http://example.com" } - end - use_content_encoded = options[:item].has_key?(:content_encoded) - - options[:feed][:title] ||= klass.name.pluralize - options[:feed][:link] ||= polymorphic_url(new_record, :controller => options[:url_writer].controller_name) - options[:feed][:language] ||= "en-us" - options[:feed][:ttl] ||= "40" - - options[:item][:title] ||= [ :title, :subject, :headline, :name ] - options[:item][:description] ||= [ :description, :body, :content ] - options[:item][:pub_date] ||= [ :updated_at, :updated_on, :created_at, :created_on ] - - resource_link = lambda { |r| polymorphic_url(r, :controller => options[:url_writer].controller_name) } - - rss_root_attributes = { :version => 2.0 } - rss_root_attributes.merge!("xmlns:content" => "http://purl.org/rss/1.0/modules/content/") if use_content_encoded - - xml.instruct! - - xml.rss(rss_root_attributes) do - xml.channel do - xml.title(options[:feed][:title]) - xml.link(options[:feed][:link]) - xml.description(options[:feed][:description]) if options[:feed][:description] - xml.language(options[:feed][:language]) - xml.ttl(options[:feed][:ttl]) - - for resource in resources - xml.item do - xml.title(call_or_read(options[:item][:title], resource)) - xml.description(call_or_read(options[:item][:description], resource)) - if use_content_encoded then - xml.content(:encoded) { xml.cdata!(call_or_read(options[:item][:content_encoded], resource)) } - end - xml.pubDate(call_or_read(options[:item][:pub_date], resource).to_s(:rfc822)) - xml.guid(call_or_read(options[:item][:guid] || options[:item][:link] || resource_link, resource)) - xml.link(call_or_read(options[:item][:link] || options[:item][:guid] || resource_link, resource)) - end - end - end - end - end - end -end diff --git a/vendor/plugins/resource_feeder/test/atom_feed_test.rb b/vendor/plugins/resource_feeder/test/atom_feed_test.rb deleted file mode 100644 index 3112da47..00000000 --- a/vendor/plugins/resource_feeder/test/atom_feed_test.rb +++ /dev/null @@ -1,85 +0,0 @@ -require File.dirname(__FILE__) + '/test_helper' -class AtomFeedTest < Test::Unit::TestCase - attr_reader :request - - def setup - @request = OpenStruct.new - @request.host_with_port = 'example.com' - @records = Array.new(5).fill(Post.new) - @records.each &:save - end - - def test_default_atom_feed - atom_feed_for @records - - assert_select 'feed' do - assert_select '>title', 'Posts' - assert_select '>id', "tag:#{request.host_with_port}:Posts" - assert_select '>link' do - assert_select "[rel='alternate']" - assert_select "[type='text/html']" - assert_select "[href='http://example.com/posts']" - end - assert_select 'entry', 5 do - assert_select 'title', :text => 'feed title (title)' - assert_select "content[type='html']", '<p>feed description (description)</p>' - assert_select 'id', "tag:#{request.host_with_port},#{@records.first.created_at.xmlschema}:#{'http://example.com/posts/1'}" - assert_select 'published', @records.first.created_at.xmlschema - assert_select 'updated', @records.first.created_at.xmlschema - assert_select 'link' do - assert_select "[rel='alternate']" - assert_select "[type='text/html']" - assert_select "[href='http://example.com/posts/1']" - end - end - end - end - - def test_should_allow_custom_feed_options - atom_feed_for @records, :feed => { :title => 'Custom Posts', :link => '/posts', :description => 'stuff', :self => '/posts.atom' } - - assert_select 'feed>title', 'Custom Posts' - assert_select "feed>link[href='/posts']" - assert_select 'feed>subtitle', 'stuff' - assert_select 'feed>link' do - assert_select "[rel='self']" - assert_select "[type='application/atom+xml']" - assert_select "[href='/posts.atom']" - end - end - - def test_should_allow_custom_item_attributes - atom_feed_for @records, :item => { :title => :name, :description => :body, :pub_date => :create_date, :link => :id } - - assert_select 'entry', 5 do - assert_select 'title', :text => 'feed title (name)' - assert_select "content[type='html']", '<p>feed description (body)</p>' - assert_select 'published', (@records.first.created_at - 5.minutes).xmlschema - assert_select 'updated', (@records.first.created_at - 5.minutes).xmlschema - assert_select 'id', "tag:#{request.host_with_port},#{(@records.first.created_at - 5.minutes).xmlschema}:1" - assert_select 'link' do - assert_select "[rel='alternate']" - assert_select "[type='text/html']" - assert_select "[href='1']" - end - end - end - - def test_should_allow_custom_item_attribute_blocks - atom_feed_for @records, :item => { :title => lambda { |r| r.name }, :description => lambda { |r| r.body }, :pub_date => lambda { |r| r.create_date }, - :link => lambda { |r| "/#{r.created_at.to_i}" }, :guid => lambda { |r| r.created_at.to_i } } - - assert_select 'entry', 5 do - assert_select 'title', :text => 'feed title (name)' - assert_select "content[type='html']", '<p>feed description (body)</p>' - assert_select 'published', (@records.first.created_at - 5.minutes).xmlschema - assert_select 'updated', (@records.first.created_at - 5.minutes).xmlschema - assert_select 'id', /:\d+$/ - assert_select 'link' do - assert_select "[rel='alternate']" - assert_select "[type='text/html']" - assert_select "[href=?]", /^\/\d+$/ - end - end - end -end diff --git a/vendor/plugins/resource_feeder/test/rss_feed_test.rb b/vendor/plugins/resource_feeder/test/rss_feed_test.rb deleted file mode 100644 index 90525baf..00000000 --- a/vendor/plugins/resource_feeder/test/rss_feed_test.rb +++ /dev/null @@ -1,86 +0,0 @@ -require File.dirname(__FILE__) + '/test_helper' -class RssFeedTest < Test::Unit::TestCase - def setup - @records = Array.new(5).fill(Post.new) - @records.each &:save - end - - def test_default_rss_feed - rss_feed_for @records - - assert_select 'rss[version="2.0"]' do - assert_select 'channel' do - assert_select '>title', 'Posts' - assert_select '>link', 'http://example.com/posts' - assert_select 'language', 'en-us' - assert_select 'ttl', '40' - end - assert_select 'item', 5 do - assert_select 'title', :text => 'feed title (title)' - assert_select 'description', '<p>feed description (description)</p>' - %w(guid link).each do |node| - assert_select node, 'http://example.com/posts/1' - end - assert_select 'pubDate', @records.first.created_at.to_s(:rfc822) - end - end - end - - def test_should_allow_custom_feed_options - rss_feed_for @records, :feed => { :title => 'Custom Posts', :link => '/posts', :description => 'stuff', :language => 'en-gb', :ttl => '80' } - - assert_select 'channel>title', 'Custom Posts' - assert_select 'channel>link', '/posts' - assert_select 'channel>description', 'stuff' - assert_select 'channel>language', 'en-gb' - assert_select 'channel>ttl', '80' - end - - def test_should_allow_custom_item_attributes - rss_feed_for @records, :item => { :title => :name, :description => :body, :pub_date => :create_date, :link => :id } - - assert_select 'item', 5 do - assert_select 'title', :text => 'feed title (name)' - assert_select 'description', '<p>feed description (body)</p>' - assert_select 'pubDate', (@records.first.created_at - 5.minutes).to_s(:rfc822) - assert_select 'link', '1' - assert_select 'guid', '1' - end - end - - def test_should_allow_custom_item_attribute_blocks - rss_feed_for @records, :item => { :title => lambda { |r| r.name }, :description => lambda { |r| r.body }, :pub_date => lambda { |r| r.create_date }, - :link => lambda { |r| "/#{r.created_at.to_i}" }, :guid => lambda { |r| r.created_at.to_i } } - - assert_select 'item', 5 do - assert_select 'title', :text => 'feed title (name)' - assert_select 'description', '<p>feed description (body)</p>' - assert_select 'pubDate', (@records.first.created_at - 5.minutes).to_s(:rfc822) - end - end - - # note that assert_select isnt easily able to get elements that have xml namespaces (as it thinks they are - # invalid html psuedo children), so we do some manual testing with the response body - def test_should_allow_content_encoded_for_items - rss_feed_for @records, :item => { :content_encoded => :full_html_body } - - html_content = "Here is some full content, with out any excerpts" - assert_equal 5, @response.body.scan("").size - assert_select 'item', 5 do - assert_select 'description + *', " { :content_encoded => :full_html_body } - assert_equal %[\n], - @response.body.grep(/\n], - @response.body.grep(/feed description (#{attr_name})

        " - end - end - - def full_html_body - "Here is some full content, with out any excerpts" - end - - def create_date - @created_at - 5.minutes - end -end - -class Test::Unit::TestCase - include ResourceFeeder::Rss, ResourceFeeder::Atom - - def render_feed(xml) - @response = OpenStruct.new - @response.headers = {'Content-Type' => 'text/xml'} - @response.body = xml - end - - def rss_feed_for_with_ostruct(resources, options = {}) - render_feed rss_feed_for_without_ostruct(resources, options) - end - - def atom_feed_for_with_ostruct(resources, options = {}) - render_feed atom_feed_for_without_ostruct(resources, options) - end - - alias_method_chain :rss_feed_for, :ostruct - alias_method_chain :atom_feed_for, :ostruct - - def html_document - @html_document ||= HTML::Document.new(@response.body, false, true) - end - - def posts_url - "http://example.com/posts" - end - - def post_url(post) - "http://example.com/posts/#{post.id}" - end -end diff --git a/vendor/plugins/simple_ldap_authenticator/README b/vendor/plugins/simple_ldap_authenticator/README deleted file mode 100644 index dc8ca509..00000000 --- a/vendor/plugins/simple_ldap_authenticator/README +++ /dev/null @@ -1,5 +0,0 @@ -SimpleLdapAuthenticator -======================= - -Allows for simple authentication to an LDAP server with a minimum of -configuration. See the RDoc for details. diff --git a/vendor/plugins/simple_ldap_authenticator/Rakefile b/vendor/plugins/simple_ldap_authenticator/Rakefile deleted file mode 100644 index f7c3459e..00000000 --- a/vendor/plugins/simple_ldap_authenticator/Rakefile +++ /dev/null @@ -1,22 +0,0 @@ -require 'rake' -require 'rake/testtask' -require 'rake/rdoctask' - -desc 'Default: run unit tests.' -task :default => :test - -desc 'Test the simple_ldap_authenticator plugin.' -Rake::TestTask.new(:test) do |t| - t.libs << 'lib' - t.pattern = 'test/**/*_test.rb' - t.verbose = true -end - -desc 'Generate documentation for the simple_ldap_authenticator plugin.' -Rake::RDocTask.new(:rdoc) do |rdoc| - rdoc.rdoc_dir = 'rdoc' - rdoc.title = 'SimpleLdapAuthenticator' - rdoc.options << '--line-numbers' << '--inline-source' - rdoc.rdoc_files.include('README') - rdoc.rdoc_files.include('lib/**/*.rb') -end diff --git a/vendor/plugins/simple_ldap_authenticator/init.rb b/vendor/plugins/simple_ldap_authenticator/init.rb deleted file mode 100644 index 85917669..00000000 --- a/vendor/plugins/simple_ldap_authenticator/init.rb +++ /dev/null @@ -1,2 +0,0 @@ -# Include hook code here -#require 'simple_ldap_authenticator' diff --git a/vendor/plugins/simple_ldap_authenticator/install.rb b/vendor/plugins/simple_ldap_authenticator/install.rb deleted file mode 100644 index f7732d37..00000000 --- a/vendor/plugins/simple_ldap_authenticator/install.rb +++ /dev/null @@ -1 +0,0 @@ -# Install hook code here diff --git a/vendor/plugins/simple_ldap_authenticator/lib/simple_ldap_authenticator.rb b/vendor/plugins/simple_ldap_authenticator/lib/simple_ldap_authenticator.rb deleted file mode 100644 index 2992d892..00000000 --- a/vendor/plugins/simple_ldap_authenticator/lib/simple_ldap_authenticator.rb +++ /dev/null @@ -1,127 +0,0 @@ -# SimpleLdapAuthenticator -# -# This plugin supports both Ruby/LDAP and Net::LDAP, defaulting to Ruby/LDAP -# if it is available. If both are installed and you want to force the use of -# Net::LDAP, set SimpleLdapAuthenticator.ldap_library = 'net/ldap'. - -# Allows for easily authenticating users via LDAP (or LDAPS). If authenticating -# via LDAP to a server running on localhost, you should only have to configure -# the login_format. -# -# Can be configured using the following accessors (with examples): -# * login_format = '%s@domain.com' # Active Directory, OR -# * login_format = 'cn=%s,cn=users,o=organization,c=us' # Other LDAP servers -# * servers = ['dc1.domain.com', 'dc2.domain.com'] # names/addresses of LDAP servers to use -# * use_ssl = true # for logging in via LDAPS -# * port = 3289 # instead of 389 for LDAP or 636 for LDAPS -# * logger = RAILS_DEFAULT_LOGGER # for logging authentication successes/failures -# -# The class is used as a global variable, you are not supposed to create an -# instance of it. For example: -# -# require 'simple_ldap_authenticator' -# SimpleLdapAuthenticator.servers = %w'dc1.domain.com dc2.domain.com' -# SimpleLdapAuthenticator.use_ssl = true -# SimpleLdapAuthenticator.login_format = '%s@domain.com' -# SimpleLdapAuthenticator.logger = RAILS_DEFAULT_LOGGER -# class LoginController < ApplicationController -# def login -# return redirect_to(:action=>'try_again') unless SimpleLdapAuthenticator.valid?(params[:username], params[:password]) -# session[:username] = params[:username] -# end -# end -class SimpleLdapAuthenticator - class << self - @servers = ['127.0.0.1'] - @use_ssl = false - @login_format = '%s' - attr_accessor :servers, :use_ssl, :port, :login_format, :logger, :connection, :ldap_library - - # Load the required LDAP library, either 'ldap' or 'net/ldap' - def load_ldap_library - return if @ldap_library_loaded - if ldap_library - if ldap_library == 'net/ldap' - require 'net/ldap' - else - require 'ldap' - require 'ldap/control' - end - else - begin - require 'ldap' - require 'ldap/control' - ldap_library = 'ldap' - rescue LoadError - require 'net/ldap' - ldap_library = 'net/ldap' - end - end - @ldap_library_loaded = true - end - - # The next LDAP server to which to connect - def server - servers[0] - end - - # The connection to the LDAP server. A single connection is made and the - # connection is only changed if a server returns an error other than - # invalid password. - def connection - return @connection if @connection - load_ldap_library - @connection = if ldap_library == 'net/ldap' - Net::LDAP.new(:host=>server, :port=>(port), :encryption=>(:simple_tls if use_ssl)) - else - (use_ssl ? LDAP::SSLConn : LDAP::Conn).new(server, port) - end - end - - # The port to use. Defaults to 389 for LDAP and 636 for LDAPS. - def port - @port ||= use_ssl ? 636 : 389 - end - - # Disconnect from current LDAP server and use a different LDAP server on the - # next authentication attempt - def switch_server - self.connection = nil - servers << servers.shift - end - - # Check the validity of a login/password combination - def valid?(login, password) - if ldap_library == 'net/ldap' - connection.authenticate(login_format % login.to_s, password.to_s) - begin - if connection.bind - logger.info("Authenticated #{login.to_s} by #{server}") if logger - true - else - logger.info("Error attempting to authenticate #{login.to_s} by #{server}: #{connection.get_operation_result.code} #{connection.get_operation_result.message}") if logger - switch_server unless connection.get_operation_result.code == 49 - false - end - rescue Net::LDAP::LdapError => error - logger.info("Error attempting to authenticate #{login.to_s} by #{server}: #{error.message}") if logger - switch_server - false - end - else - connection.unbind if connection.bound? - begin - connection.bind(login_format % login.to_s, password.to_s) - connection.unbind - logger.info("Authenticated #{login.to_s} by #{server}") if logger - true - rescue LDAP::ResultError => error - connection.unbind if connection.bound? - logger.info("Error attempting to authenticate #{login.to_s} by #{server}: #{error.message}") if logger - switch_server unless error.message == 'Invalid credentials' - false - end - end - end - end -end diff --git a/vendor/plugins/simple_ldap_authenticator/tasks/simple_ldap_authenticator_tasks.rake b/vendor/plugins/simple_ldap_authenticator/tasks/simple_ldap_authenticator_tasks.rake deleted file mode 100644 index 1916c233..00000000 --- a/vendor/plugins/simple_ldap_authenticator/tasks/simple_ldap_authenticator_tasks.rake +++ /dev/null @@ -1,4 +0,0 @@ -# desc "Explaining what the task does" -# task :simple_ldap_authenticator do -# # Task goes here -# end \ No newline at end of file diff --git a/vendor/plugins/simple_ldap_authenticator/test/simple_ldap_authenticator_test.rb b/vendor/plugins/simple_ldap_authenticator/test/simple_ldap_authenticator_test.rb deleted file mode 100644 index dfd92dae..00000000 --- a/vendor/plugins/simple_ldap_authenticator/test/simple_ldap_authenticator_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'test/unit' - -class SimpleLdapAuthenticatorTest < Test::Unit::TestCase - # Replace this with your real tests. - def test_this_plugin - flunk - end -end diff --git a/vendor/plugins/skinny_spec/.gitignore b/vendor/plugins/skinny_spec/.gitignore deleted file mode 100644 index 28f7b7da..00000000 --- a/vendor/plugins/skinny_spec/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.DS_Store -doc \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/README.rdoc b/vendor/plugins/skinny_spec/README.rdoc deleted file mode 100644 index 118b58e1..00000000 --- a/vendor/plugins/skinny_spec/README.rdoc +++ /dev/null @@ -1,270 +0,0 @@ -= Skinny Spec - -Skinny Spec is a collection of spec helper methods designed to help trim the fat and DRY up -some of the bloat that sometimes results from properly specing your classes and templates. - -== Requirements and Recommendations - -Obviously you'll need to be using RSpec[http://github.com/dchelimsky/rspec/tree/master] and -Rspec-Rails[http://github.com/dchelimsky/rspec-rails/tree/master] as your testing framework. - -Skinny Spec was originally designed [and best enjoyed] if you're using -Haml[http://github.com/nex3/haml/tree/master] and -make_resourceful[http://github.com/rsl/make_resourceful/tree/master] but will default to -ERb and a facsimile of Rails' default scaffolding [for the views and controllers, respectively] -if Haml and/or make_resourceful are not available. I recommend using them though. :) - -In addition, Skinny Spec uses Ruby2Ruby to make nicer expectation messages and you'll want to -have that installed as well. It's not a dependency or anything but it is highly -recommended. - -== Setup - -Once you've installed the plugin in your app's vendor/plugins folder, you're ready to rock! -Skinny Spec includes itself into the proper RSpec classes so there's no configuration on your -part. Sweet! - -== Usage - -The simplest way to use Skinny Specs is to generate a resource scaffold: - - script/generate skinny_scaffold User - -This command takes the usual complement of attribute definitions like -script/generate scaffold. Then have a look at the generated files (particularly the -specs) to see what's new and different with Skinny Spec. - -=== Controller Specs - -Let's look at the controller specs. - - describe UsersController do - describe "GET :index" do - before(:each) do - @users = stub_index(User) - end - - it_should_find_and_assign :users - it_should_render :template, "index" - end - - # ... - - describe "POST :create" do - describe "when successful" do - before(:each) do - @user = stub_create(User) - end - - it_should_initialize_and_save :user - it_should_redirect_to { user_url(@user) } - end - - # ... - -First thing you should see is an example group for GET :index. That stub_index method there -does a lot of work behind the curtain. I'll leave it up to you to check the documentation for it -(and its brothers and sister methods like stub_new) but I will point out that the -methods named stub_controller_method should only be used for stubbing and -mocking the main object of the method. To create mocks for other ancillary objects, please -use stub_find_all, stub_find_one, and stub_initialize. The reason -for this is because the former methods actually save us a step by defining an implicit -controller method request. If you add a new method to your resource routing, you'll want to -use the helper method define_request in those example groups to define an explicit -request, like so: - - describe "PUT :demote" do - define_request { put :demote } - - # ... - end - -You can also define a method called shared_request to "share" a -define_request across nested describe blocks, like so: - - describe "POST :create" do - def shared_request - post :create - end - - describe "when successful" do - # ... - end - - describe "when unsuccessful" do - # ... - end - end - -Note: When you're adding longer, more complicated controller specs you can still leverage -implicit and explicit requests by calling do_request in your spec as in the following -example: - - # Note this controller is UsersController and _not_ CategoriesController - # and that loading the categories isn't part of the default actions - # and cannot use the stub_controller_method helpers - # [which create implicit requests based on the controller method in the name] - # but uses stub_find_all instead - describe "GET :new" do - before(:each) do - @user = stub_new(User) - @categories = stub_find_all(Category) - end - - # ... - - it "should preload categories" do - Category.should_receive(:find).with(:all) - do_request - end - - it "should assign @categories" do - do_request - assigns[:categories].should == @categories - end - end - -Finally we get to the meat of the spec and of Skinny Specs itself: the actual expectations. -The first thing you'll notice is the use of example group (read: "describe" block) level methods -instead of the usual example (read: "it") blocks. Using this helper at the example group level -saves us three lines over using an example block. (If this isn't significant to you, this is -probably the wrong plugin for you as well. Sorry.) Note that none of these methods use the -instance variables defined in the "before" block because they are all nil at the example block -level. Let's look at a sample method to see how it works: - - it_should_find_and_assign :users - -This actually wraps two different expectations: one that User.should_receive(:find).with(:all) -and another that the instance variable @users is assigned with the return value from that finder call. -If you need to add more detailed arguments to the find, you can easily break this into two different -expectations like: - - it_should_find :users, :limit => 2 - it_should_assign :users - -See the documentation for the it_should_find for more information. You might have guessed that -it_should_initialize_assign and it_should_render_template work in a similar -fashion and you'd be right. Again, see the documentation for these individual methods for more -information. Lots of information in those docs. - -A useful helper method that doesn't appear in any of the scaffolding is with_default_restful_actions -which takes a block and evaluates it for each of the RESTful controller actions. Very useful for -spec'ing that these methods redirect to the login page when the user isn't logged in, for example. This -method is designed to be used inside an example like so: - - describe "when not logged in" do - it "should redirect all requests to the login page" do - with_default_restful_actions do - response.should redirect_to(login_url) - end - end - end - -Before we're through with the controller specs, let me point out one more important detail. In -order to use it_should_redirect_to we have to send the routing inside a block argument -there so it can be evaluated in the example context instead of the example group, where it -completely blows up. This methodology is used anywhere routing is referred to in a "skinny", -example group level spec. - -=== View Specs - -Now let's move to the view specs! - - describe "/users/form.html.haml" do - before(:each) do - @user = mock_and_assign(User, :stub => { - :name => "foo", - :birthday => 1.week.ago, - :adult => false - }) - end - - it_should_have_form_for :user - - it_should_allow_editing :user, :name - it_should_allow_editing :user, :birthday - it_should_allow_editing :user, :adult - - it_should_link_to_show :user - it_should_link_to { users_path } - end - -Like the special stub_index methods in the controller -specs, the view specs have a shorthand mock and stub helpers: mock_and_assign and -mock_and_assign_collection. These are well documented so please check them out. - -There are also some really nice helper methods that I'd like point out. First is -it_should_have_form_for. This is a really good convenience wrapper that basically wraps -the much longer: - - it "should use form_for to generate the proper form action and options" do - template.should_receive(:form_for).with(@user) - do_render - end - -Next up is the it_should_allow_editing helper. I love this method the most because it -really helps DRY up that view spec while at the same time being amazingly unbrittle. Instead of -creating an expectation for a specific form element, this method creates a generalized expectation -that there's a form element with the name attribute set in such away that it will -generate the proper params to use in the controller to edit or create the instance. -Check out the docs and the source for more information on this. Also check out -it_should_have_form_element_for which is roughly equivalent for those times when you use -form_tag instead. - -Finally let's look at those it_should_link_to_controller_method helpers. -These methods (and there's one each for the controller methods -new, edit, show, and delete) point to instance variables -which you should be created in the "before" blocks with mock_and_assign. The other is -it_should_allow_editing which is likewise covered extensively in the documentation and -I will just point out here that, like it_should_link_to_edit and such, it takes a -symbol for the name of the instance variable it refers to and additionally takes -a symbol for the name of the attribute to be edited. - -Also note that, when constructing a long form example, instead of defining an instance variable -for the name of the template and calling render @that_template you can simply call -do_render which takes the name of the template from the outermost example group where -it is customarily stated. - -=== Model Specs - -Skinny Spec adds a matcher for the various ActiveRecord associations. On the example group level -you call them like: - - it_should_belong_to :manager - it_should_have_many :clients - -Within an example you can call them on either the class or the instance setup in the -"before" block. These are equivalent: - - @user.should belong_to(:group) - User.should belong_to(:group) - -I've also added some very basic validation helpers like it_should_validate_presence_of, -it_should_validate_uniqueness_of, it_should_not_mass_assign. Please consult -the documentation for more information. - -== Miscellaneous Notes - -In the scaffolding, I have used my own idiomatic Rails usage: - -* All controller actions which use HTML forms [new, edit, etc] use a shared - form and leverage form_for to its fullest by letting it create the appropriate - action and options. -* Some instances where you might expect link_to are button_to. This is to provide a common - interface element which can be styled the same instead of a mishmash of links and buttons and - inputs everywhere. To take full advantage of this, I usually override many of Rails' default - helpers with custom ones that all use actual HTML BUTTON elements which are much - easier to style than "button" typed INPUT. I've provided a text file in the - "additional" folder of this plugin which you can use in your ApplicationHelper. (I also - provide an optional override helper for the label method which uses - #titleize instead of humanize for stylistic reasons). -* Probably more that I can't think of. - -== Credits and Thanks - -Sections of this code were taken from or inspired by Rick Olsen's -rspec_on_rails_on_crack[http://github.com/technoweenie/rspec_on_rails_on_crack/tree/master]. -Also thanks and props to Hampton Catlin and Nathan Weizenbaum for the lovely and imminently useable -Haml and make_resourceful. Also also praises and glory to David Chelimsky and the Rspec crew. - -Also thanks to Don Petersen, Nicolas Mérouze, Mikkel Malmberg, and Brandan Lennox for their suggestions and fixes. \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/Rakefile b/vendor/plugins/skinny_spec/Rakefile deleted file mode 100644 index b0adbc43..00000000 --- a/vendor/plugins/skinny_spec/Rakefile +++ /dev/null @@ -1,11 +0,0 @@ -require 'rake' -require 'rake/rdoctask' - -desc 'Generate documentation for the Skinny Spec plugin' -Rake::RDocTask.new(:rdoc) do |rdoc| - rdoc.rdoc_dir = 'doc' - rdoc.title = 'Skinny Spec' - rdoc.options << '--line-numbers' << '--inline-source' - rdoc.rdoc_files.include('README.rdoc') - rdoc.rdoc_files.include('lib/**/*.rb') -end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/additional/helper_overrides.txt b/vendor/plugins/skinny_spec/additional/helper_overrides.txt deleted file mode 100644 index 7717e079..00000000 --- a/vendor/plugins/skinny_spec/additional/helper_overrides.txt +++ /dev/null @@ -1,58 +0,0 @@ -# Please insert these into your ApplicationHelper - -# Replacement for Rails' default submit_tag helper -# using HTML button element rather than HTML input element -def submit_tag(text, options = {}) - content_tag :button, text, options.merge(:type => :submit) -end - -# Replacement for Rails' default button_to helper -# using HTML button element rather than HTML input element -def button_to(name, options = {}, html_options = {}) - html_options = html_options.stringify_keys - convert_boolean_attributes!(html_options, %w( disabled )) - - method_tag = '' - if (method = html_options.delete('method')) && %w{put delete}.include?(method.to_s) - method_tag = tag('input', :type => 'hidden', :name => '_method', :value => method.to_s) - end - - form_method = method.to_s == 'get' ? 'get' : 'post' - - request_token_tag = '' - if form_method == 'post' && protect_against_forgery? - request_token_tag = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) - end - - if confirm = html_options.delete("confirm") - html_options["onclick"] = "return #{confirm_javascript_function(confirm)};" - end - - url = options.is_a?(String) ? options : self.url_for(options) - name ||= url - - html_options.merge!("type" => "submit", "value" => name) - - "
        " + - method_tag + content_tag("button", name, html_options) + request_token_tag + "
        " -end - -# Replacement for Rails' default button_to_function helper -# using HTML button element rather than HTML input element -def button_to_function(name, *args, &block) - html_options = args.extract_options! - function = args[0] || '' - - html_options.symbolize_keys! - function = update_page(&block) if block_given? - content_tag(:button, name, html_options.merge({ - :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};" - })) -end - -# Replacement for Rails' default label helper -# using String#titleize rather than String#humanize -def label(object_name, method, text = nil, options = {}) - text ||= method.to_s[].titleize - super -end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/skinny_scaffold_generator.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/skinny_scaffold_generator.rb deleted file mode 100644 index 3cde3564..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/skinny_scaffold_generator.rb +++ /dev/null @@ -1,102 +0,0 @@ -class SkinnyScaffoldGenerator < Rails::Generator::NamedBase - attr_reader :controller_class_path, :controller_file_path, :controller_class_nesting, - :controller_class_nesting_depth, :controller_class_name, :controller_underscore_name, - :controller_plural_name, :template_language - alias_method :controller_file_name, :controller_underscore_name - alias_method :controller_singular_name, :controller_file_name - alias_method :controller_table_name, :controller_plural_name - - default_options :skip_migration => false - - def initialize(runtime_args, runtime_options = {}) - super - - base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@name.pluralize) - @controller_class_name_without_nesting, @controller_underscore_name, @controller_plural_name = inflect_names(base_name) - - if @controller_class_nesting.empty? - @controller_class_name = @controller_class_name_without_nesting - else - @controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}" - end - end - - def manifest - record do |m| - # Check for class naming collisions - m.class_collisions controller_class_path, "#{controller_class_name}Controller", "#{controller_class_name}Helper" - m.class_collisions class_path, "#{class_name}" - - # # Controller, helper, and views directories - m.directory File.join('app', 'views', controller_class_path, controller_file_name) - m.directory File.join('spec', 'views', controller_class_path, controller_file_name) - m.directory File.join('app', 'helpers', controller_class_path) - m.directory File.join('spec', 'helpers', controller_class_path) - m.directory File.join('app', 'controllers', controller_class_path) - m.directory File.join('spec', 'controllers', controller_class_path) - m.directory File.join('app', 'models', class_path) - m.directory File.join('spec', 'models', class_path) - - # Views - @template_language = defined?(Haml) ? "haml" : "erb" - %w{index show form}.each do |action| - m.template "#{action}.html.#{template_language}", - File.join('app/views', controller_class_path, controller_file_name, "#{action}.html.#{template_language}") - m.template "#{action}.html_spec.rb", - File.join('spec/views', controller_class_path, controller_file_name, "#{action}.html.#{template_language}_spec.rb") - end - m.template "index_partial.html.#{template_language}", - File.join('app/views', controller_class_path, controller_file_name, "_#{file_name}.html.#{template_language}") - m.template 'index_partial.html_spec.rb', - File.join('spec/views', controller_class_path, controller_file_name, "_#{file_name}.html.#{template_language}_spec.rb") - - # Helper - m.template 'helper.rb', - File.join('app/helpers', controller_class_path, "#{controller_file_name}_helper.rb") - m.template 'helper_spec.rb', - File.join('spec/helpers', controller_class_path, "#{controller_file_name}_helper_spec.rb") - - # Controller - m.template 'controller.rb', - File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb") - m.template 'controller_spec.rb', - File.join('spec/controllers', controller_class_path, "#{controller_file_name}_controller_spec.rb") - - # Model - m.template 'model.rb', - File.join('app/models', class_path, "#{file_name}.rb") - m.template 'model_spec.rb', - File.join('spec/models', class_path, "#{file_name}_spec.rb") - - # Routing - m.route_resources controller_file_name - - unless options[:skip_migration] - m.migration_template( - 'migration.rb', 'db/migrate', - :assigns => { - :migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}", - :attributes => attributes - }, - :migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}" - ) - end - end - end - -protected - def banner - "Usage: #{$0} skinny_scaffold ModelName [field:type, field:type]" - end - - def add_options!(opt) - opt.separator '' - opt.separator 'Options:' - opt.on("--skip-migration", - "Don't generate a migration file for this model") { |v| options[:skip_migration] = v } - end - - def model_name - class_name.demodulize - end -end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/controller.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/controller.rb deleted file mode 100644 index ea9b617d..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/controller.rb +++ /dev/null @@ -1,105 +0,0 @@ -class <%= controller_class_name %>Controller < ApplicationController - <%- if defined?(Resourceful::Maker) -%> - make_resourceful do - actions :all - - # Let's get the most use from form_for and share a single form here! - response_for :new, :edit do - render :template => "<%= plural_name %>/form" - end - - response_for :create_fails, :update_fails do - flash[:error] = "There was a problem!" - render :template => "<%= plural_name %>/form" - end - end - <%- else -%> - # GET /<%= table_name %> - # GET /<%= table_name %>.xml - def index - @<%= table_name %> = <%= class_name %>.find(:all) - - respond_to do |format| - format.html # index.html.erb - format.xml { render :xml => @<%= table_name %> } - end - end - - # GET /<%= table_name %>/1 - # GET /<%= table_name %>/1.xml - def show - @<%= file_name %> = <%= class_name %>.find(params[:id]) - - respond_to do |format| - format.html # show.html.erb - format.xml { render :xml => @<%= file_name %> } - end - end - - # GET /<%= table_name %>/new - # GET /<%= table_name %>/new.xml - def new - @<%= file_name %> = <%= class_name %>.new - - respond_to do |format| - format.html { render :template => "<%= plural_name %>/form" } - format.xml { render :xml => @<%= file_name %> } - end - end - - # GET /<%= table_name %>/1/edit - def edit - @<%= file_name %> = <%= class_name %>.find(params[:id]) - render :template => "<%= plural_name %>/form" - end - - # POST /<%= table_name %> - # POST /<%= table_name %>.xml - def create - @<%= file_name %> = <%= class_name %>.new(params[:<%= file_name %>]) - - respond_to do |format| - if @<%= file_name %>.save - flash[:notice] = '<%= class_name %> was successfully created.' - format.html { redirect_to(@<%= file_name %>) } - format.xml { render :xml => @<%= file_name %>, :status => :created, :location => @<%= file_name %> } - else - flash.now[:error] = '<%= class_name %> could not be created.' - format.html { render :template => "<%= plural_name %>/form" } - format.xml { render :xml => @<%= file_name %>.errors, :status => :unprocessable_entity } - end - end - end - - # PUT /<%= table_name %>/1 - # PUT /<%= table_name %>/1.xml - def update - @<%= file_name %> = <%= class_name %>.find(params[:id]) - - respond_to do |format| - if @<%= file_name %>.update_attributes(params[:<%= file_name %>]) - flash[:notice] = '<%= class_name %> was successfully updated.' - format.html { redirect_to(@<%= file_name %>) } - format.xml { head :ok } - else - flash.now[:error] = '<%= class_name %> could not be created.' - format.html { render :template => "<%= plural_name %>/form" } - format.xml { render :xml => @<%= file_name %>.errors, :status => :unprocessable_entity } - end - end - end - - # DELETE /<%= table_name %>/1 - # DELETE /<%= table_name %>/1.xml - def destroy - @<%= file_name %> = <%= class_name %>.find(params[:id]) - @<%= file_name %>.destroy - - respond_to do |format| - flash[:notice] = '<%= class_name %> was successfully deleted.' - format.html { redirect_to(<%= table_name %>_url) } - format.xml { head :ok } - end - end - <%- end -%> -end diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/controller_spec.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/controller_spec.rb deleted file mode 100644 index ff1b6b29..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/controller_spec.rb +++ /dev/null @@ -1,93 +0,0 @@ -require File.dirname(__FILE__) + '/../spec_helper' - -describe <%= controller_class_name %>Controller do - describe "GET :index" do - before(:each) do - @<%= plural_name %> = stub_index(<%= class_name %>) - end - - it_should_find_and_assign :<%= plural_name %> - it_should_render_template "index" - end - - describe "GET :new" do - before(:each) do - @<%= singular_name %> = stub_new(<%= class_name %>) - end - - it_should_initialize_and_assign :<%= singular_name %> - it_should_render_template "form" - end - - describe "POST :create" do - describe "when successful" do - before(:each) do - @<%= singular_name %> = stub_create(<%= class_name %>) - end - - it_should_initialize_and_save :<%= singular_name %> - it_should_set_flash :notice - it_should_redirect_to { <%= singular_name %>_url(@<%= singular_name %>) } - end - - describe "when unsuccessful" do - before(:each) do - @<%= singular_name %> = stub_create(<%= class_name %>, :return => :false) - end - - it_should_initialize_and_assign :<%= singular_name %> - it_should_set_flash :error - it_should_render_template "form" - end - end - - describe "GET :show" do - before(:each) do - @<%= singular_name %> = stub_show(<%= class_name %>) - end - - it_should_find_and_assign :<%= singular_name %> - it_should_render_template "show" - end - - describe "GET :edit" do - before(:each) do - @<%= singular_name %> = stub_edit(<%= class_name %>) - end - - it_should_find_and_assign :<%= singular_name %> - it_should_render_template "form" - end - - describe "PUT :update" do - describe "when successful" do - before(:each) do - @<%= singular_name %> = stub_update(<%= class_name %>) - end - - it_should_find_and_update :<%= singular_name %> - it_should_set_flash :notice - it_should_redirect_to { <%= singular_name %>_url(@<%= singular_name %>) } - end - - describe "when unsuccessful" do - before(:each) do - @<%= singular_name %> = stub_update(<%= class_name %>, :return => :false) - end - - it_should_find_and_assign :<%= singular_name %> - it_should_set_flash :error - it_should_render_template "form" - end - end - - describe "DELETE :destroy" do - before(:each) do - @<%= singular_name %> = stub_destroy(<%= class_name %>) - end - - it_should_find_and_destroy :<%= singular_name %> - it_should_set_flash :notice - it_should_redirect_to { <%= plural_name %>_url } - end -end diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.erb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.erb deleted file mode 100644 index ac30dc1b..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.erb +++ /dev/null @@ -1,25 +0,0 @@ -

        <%= singular_name %>.new_record? ? "New" : "Edit" %> <%= model_name %>

        -<%% form_for(@<%= singular_name %>) do |f| %> -
        - <%%= f.error_messages %> -
        - <%- if attributes.blank? -%> -

        Add your form elements here, please!

        - <%- else -%> - <%- attributes.each do |attribute| -%> -

        - <%%= f.label :<%= attribute.name %> %>
        - <%%= f.<%= attribute.field_type %> :<%= attribute.name %> %> -

        - <%- end -%> - <%- end -%> -
        - <%%= submit_tag "Save" %> - -
        -<%% end -%> \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.haml b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.haml deleted file mode 100644 index d97eabb9..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.haml +++ /dev/null @@ -1,18 +0,0 @@ -%h1== #{@<%= singular_name %>.new_record? ? "New" : "Edit"} #{<%= model_name %>} -- form_for @<%= singular_name %> do |f| - #form_errors= f.error_messages -<% if attributes.blank? -%> - %p Add your form elements here, please! -<% else -%> - <%- attributes.each do |attribute| -%> - %p - = f.label :<%= attribute.name %> - = f.<%= attribute.field_type %> :<%= attribute.name %> - <%- end -%> -<% end -%> - #commands - = submit_tag "Save" -#navigation_commands - - unless @<%= singular_name %>.new_record? - = button_to "Show", <%= singular_name %>_path(@<%= singular_name %>), :method => "get", :title => "Show <%= singular_name %>. Unsaved changes will be lost." - = button_to "Back to List", <%= plural_name %>_path, :class => "cancel", :method => "get", :title => "Return to <%= singular_name %> list without saving changes" \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html_spec.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html_spec.rb deleted file mode 100644 index bc6f6f24..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../../spec_helper' - -describe "<%= File.join(controller_class_path, controller_singular_name) %>/form.html.<%= template_language %>" do - before(:each) do - @<%= singular_name %> = mock_and_assign(<%= model_name %>, :stub => { -<% if attributes.blank? -%> - # Add your stub attributes and return values here like: - # :name => "Foo", :address => "815 Oceanic Drive" -<% else -%> - <%- attributes.each_with_index do |attribute, index| -%> - <%- case attribute.type when :string, :text -%> - :<%= attribute.name %> => "foo"<%= index < attributes.size - 1 ? "," : "" %> - <%- when :integer, :float, :decimal -%> - :<%= attribute.name %> => 815<%= index < attributes.size - 1 ? "," : "" %> - <%- when :boolean -%> - :<%= attribute.name %> => false<%= index < attributes.size - 1 ? "," : "" %> - <%- when :date, :datetime, :time, :timestamp -%> - :<%= attribute.name %> => 1.week.ago<%= index < attributes.size - 1 ? "," : "" %> - <%- else -%> - :<%= attribute.name %> => nil<%= index < attributes.size - 1 ? "," : "" %> # Could not determine valid attribute - <%- end -%> - <%- end -%> -<% end -%> - }) - end - - it_should_have_form_for :<%= singular_name %> -<% if attributes.blank? -%> - # Add specs for editing attributes here, please! Like this: - # - # it_should_allow_editing :<%= singular_name %>, :foo -<% else -%> - <%- attributes.each do |attribute| -%> - it_should_allow_editing :<%= singular_name %>, :<%= attribute.name %> - <%- end -%> -<% end -%> - - it_should_link_to_show :<%= singular_name %> - it_should_link_to { <%= plural_name %>_path } -end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/helper.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/helper.rb deleted file mode 100644 index 9bd821b1..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module <%= controller_class_name %>Helper -end diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/helper_spec.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/helper_spec.rb deleted file mode 100644 index 6a34ca2a..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/helper_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../spec_helper' - -describe <%= controller_class_name %>Helper do - # Add your specs here or remove this file completely, please! -end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.erb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.erb deleted file mode 100644 index 318f94e3..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.erb +++ /dev/null @@ -1,31 +0,0 @@ -

        <%= model_name %> List

        - - <%%- if @<%= plural_name %>.empty? -%> - - - - - - <%%- else -%> - - - <%- if attributes.blank? -%> - - <%- else -%> - <%- attributes.each do |attribute| -%> - - <%- end -%> - <%- end -%> - - - - - - - <%%= render :partial => @<%= plural_name %> %> - - <%%- end -%> -
        There are no <%= plural_name.humanize.downcase %>
        <%= attribute.name.titleize %>
        -
        - <%%= button_to "New <%= singular_name.titleize %>", new_<%= singular_name %>_path, :method => "get" %> -
        \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.haml b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.haml deleted file mode 100644 index b0c78b28..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.haml +++ /dev/null @@ -1,23 +0,0 @@ -%h1 <%= model_name %> List -%table - - if @<%= plural_name %>.empty? - %tbody - %tr.empty - %td== There are no <%= plural_name.humanize.downcase %> - - else - %thead - %tr -<% if attributes.blank? -%> - %th= # Generic display column -<% else -%> - <%- attributes.each do |attribute| -%> - %th <%= attribute.name.titleize %> - <%- end -%> -<% end -%> - %th.show= # 'Show' link column - %th.edit= # 'Edit' link column - %th.delete= # 'Delete' link column - %tbody - = render :partial => @<%= plural_name %> -#commands - = button_to "New <%= singular_name.titleize %>", new_<%= singular_name %>_path, :method => "get" \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html_spec.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html_spec.rb deleted file mode 100644 index cfe213f5..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../../spec_helper' - -describe "<%= File.join(controller_class_path, controller_singular_name) %>/index.html.<%= template_language %>" do - before(:each) do - @<%= plural_name %> = mock_and_assign_collection(<%= model_name %>) - template.stub! :render - end - - it "should render :partial => @<%= plural_name %>" do - template.should_receive(:render).with(:partial => @<%= plural_name %>) - do_render - end - - it_should_link_to_new :<%= singular_name %> -end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.erb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.erb deleted file mode 100644 index ecdca836..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.erb +++ /dev/null @@ -1,12 +0,0 @@ -"> -<% if attributes.blank? -%> - <%= model_name %> #<%%= <%= singular_name %>.id %> -<% else -%> - <%- attributes.each do |attribute| -%> - <%%=h <%= singular_name %>.<%= attribute.name %> %> - <%- end %> -<% end -%> - <%%= button_to "Show", <%= singular_name %>, :method => "get" %> - <%%= button_to "Edit", edit_<%= singular_name %>_path(<%= singular_name %>), :method => "get" %> - <%%= button_to "Delete", <%= singular_name %>, :method => "delete" %> - \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.haml b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.haml deleted file mode 100644 index 08b3b383..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.haml +++ /dev/null @@ -1,11 +0,0 @@ -%tr{:class => cycle("odd", "even")} -<% if attributes.blank? -%> - %td== <%= model_name %> #{<%= singular_name %>.id} -<% else -%> - <%- attributes.each do |attribute| -%> - %td=h <%= singular_name %>.<%= attribute.name %> - <%- end -%> -<% end -%> - %td.show= button_to "Show", <%= singular_name %>_path(<%= singular_name %>), :method => "get" - %td.edit= button_to "Edit", edit_<%= singular_name %>_path(<%= singular_name %>), :method => "get" - %td.delete= button_to "Delete", <%= singular_name %>, :method => "delete" \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html_spec.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html_spec.rb deleted file mode 100644 index 2a10afb1..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html_spec.rb +++ /dev/null @@ -1,31 +0,0 @@ -require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../../spec_helper' - -describe "<%= File.join(controller_class_path, controller_singular_name) %>/_<%= singular_name %>.html.<%= template_language %>" do - before(:each) do - @<%= singular_name %> = mock_and_assign(<%= model_name %>, :stub => { -<% if attributes.blank? -%> - # Add your stub attributes and return values here like: - # :name => "Foo", :created_at => 1.week.ago, :updated_at => nil -<% else -%> - <%- attributes.each_with_index do |attribute, index| -%> - <%- case attribute.type when :string, :text -%> - :<%= attribute.name %> => "foo"<%= index < attributes.size - 1 ? "," : "" %> - <%- when :integer, :float, :decimal -%> - :<%= attribute.name %> => 815<%= index < attributes.size - 1 ? "," : "" %> - <%- when :boolean -%> - :<%= attribute.name %> => false<%= index < attributes.size - 1 ? "," : "" %> - <%- when :date, :datetime, :time, :timestamp -%> - :<%= attribute.name %> => 1.week.ago<%= index < attributes.size - 1 ? "," : "" %> - <%- else -%> - :<%= attribute.name %> => nil<%= index < attributes.size - 1 ? "," : "" %> - <%- end -%> - <%- end -%> -<% end -%> - }) - template.stub!(:<%= singular_name %>).and_return(@<%= singular_name %>) - end - - it_should_link_to_show :<%= singular_name %> - it_should_link_to_edit :<%= singular_name %> - it_should_link_to_delete :<%= singular_name %> -end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/migration.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/migration.rb deleted file mode 100644 index 2e4c29c8..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/migration.rb +++ /dev/null @@ -1,14 +0,0 @@ -class <%= migration_name %> < ActiveRecord::Migration - def self.up - create_table :<%= table_name %>, :force => true do |t| -<% attributes.each do |attribute| -%> - t.column :<%= attribute.name %>, :<%= attribute.type %> -<% end -%> - t.timestamps - end - end - - def self.down - drop_table :<%= table_name %> - end -end diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/model.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/model.rb deleted file mode 100644 index 202f8b30..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/model.rb +++ /dev/null @@ -1,2 +0,0 @@ -class <%= class_name %> < ActiveRecord::Base -end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/model_spec.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/model_spec.rb deleted file mode 100644 index ed6a1945..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/model_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../spec_helper' - -describe <%= class_name %> do - def valid_attributes(args = {}) - { - # Add valid attributes for building your model instances here! - }.merge(args) - end - - before(:each) do - @<%= singular_name %> = <%= class_name %>.new - end - - after(:each) do - @<%= singular_name %>.destroy - end - - # Add your model specs here, please! - # And don't forget about the association matchers built-in to skinny_spec like: - # - # it_should_have_many :foos - # it_should_validate_presence_of :bar - # - # Check out the docs for more information. -end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.erb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.erb deleted file mode 100644 index 5db36d56..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.erb +++ /dev/null @@ -1,15 +0,0 @@ -

        Show <%= model_name %>

        -<% if attributes.blank? -%> -

        Add your customized markup here, please!

        -<% else -%> - <%- attributes.each do |attribute| -%> -

        - - <%%=h @<%= singular_name %>.<%= attribute.name %> %> -

        - <%- end -%> -<% end -%> -
        - <%%= button_to "Edit", edit_<%= singular_name %>_path(@<%= singular_name %>), :method => "get" %> - <%%= button_to "Back to List", <%= plural_name %>_path, :method => "get" %> -
        diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.haml b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.haml deleted file mode 100644 index d8afe80a..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.haml +++ /dev/null @@ -1,13 +0,0 @@ -%h1== Show #{<%= model_name %>} -<% if attributes.blank? -%> -%p Add your customized markup here, please! -<% else -%> - <%- attributes.each do |attribute| -%> -%p - %label <%= attribute.name.titleize %>: - =h @<%= singular_name %>.<%= attribute.name %> - <%- end -%> -<% end -%> -#commands - = button_to "Edit", edit_<%= singular_name %>_path(@<%= singular_name %>), :method => "get" - = button_to "Back to List", <%= plural_name %>_path, :method => "get" \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html_spec.rb b/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html_spec.rb deleted file mode 100644 index aefbbe17..00000000 --- a/vendor/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html_spec.rb +++ /dev/null @@ -1,31 +0,0 @@ -require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../../spec_helper' - -describe "<%= File.join(controller_class_path, controller_singular_name) %>/show.html.<%= template_language %>" do - before(:each) do -<% if attributes.blank? -%> - @<%= singular_name %> = mock_and_assign(<%= model_name %>) -<% else -%> - @<%= singular_name %> = mock_and_assign(<%= model_name %>, :stub => { - <%- attributes.each_with_index do |attribute, index| -%> - <%- case attribute.type when :string, :text -%> - :<%= attribute.name %> => "foo"<%= index < attributes.size - 1 ? "," : "" %> - <%- when :integer, :float, :decimal -%> - :<%= attribute.name %> => 815<%= index < attributes.size - 1 ? "," : "" %> - <%- when :boolean -%> - :<%= attribute.name %> => false<%= index < attributes.size - 1 ? "," : "" %> - <%- when :date, :datetime, :time, :timestamp -%> - :<%= attribute.name %> => 1.week.ago<%= index < attributes.size - 1 ? "," : "" %> - <%- else -%> - :<%= attribute.name %> => nil<%= index < attributes.size - 1 ? "," : "" %> - <%- end -%> - <%- end -%> - }) -<% end -%> - end - - # Add your specs here, please! But remember not to make them brittle - # by specing specing specific HTML elements and classes. - - it_should_link_to_edit :<%= singular_name %> - it_should_link_to { <%= plural_name %>_path } -end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/lib/lucky_sneaks/common_spec_helpers.rb b/vendor/plugins/skinny_spec/lib/lucky_sneaks/common_spec_helpers.rb deleted file mode 100644 index 0a7acff3..00000000 --- a/vendor/plugins/skinny_spec/lib/lucky_sneaks/common_spec_helpers.rb +++ /dev/null @@ -1,83 +0,0 @@ -module LuckySneaks - # These methods are mostly just called internally by various other spec helper - # methods but you're welcome to use them as needed in your own specs. - module CommonSpecHelpers - # Stubs out Time.now and returns value to use when comparing it. Example: - # - # time_now = stub_time_now - # @foo.some_method_that_resets_updated_at - # @foo.updated_at.should == time_now - def stub_time_now - returning Time.now do |now| - Time.stub!(:now).and_return(now) - end - end - - # Returns class for the specified name. Example: - # - # class_for("foo") # => Foo - def class_for(name) - name.to_s.constantize - rescue NameError - name.to_s.pluralize.classify.constantize - # Let any other error rise! - end - - # Returns instance variable for the specified name. Example: - # - # instance_for("foo") # => @foo - def instance_for(name) - instance_variable_get("@#{name.to_s.underscore}") - end - - # Wraps a matcher that checks if the receiver contains an A element (link) - # whose href attribute is set to the specified path. - def have_link_to(path) - have_tag("a[href='#{path}']") - end - - # Returns dummy value for specified attribute based on the datatype expected for that - # attribute. - def dummy_value_for(instance, attribute) - if datatype = instance.column_for_attribute(attribute) - actual = instance.send(attribute) - case datatype.type - when :string, :text - actual == "foo" ? "bar" : "food" - when :integer, :float, :decimal - actual == 108 ? 815 : 108 - when :boolean - actual ? false : true - when :date, :datetime, :time, :timestamp - actual == 1.week.ago ? 2.years.ago : 1.week.ago - end - end - end - - # Returns class description text - def class_description_text - if self.class.respond_to?(:description_text) - # Old school - self.class.description_text - else - # New school - self.class.description - end - end - - # Returns description text - def self_description_text - if respond_to?(:description_text) - # Old school - description_text - else - # New school - description - end - end - - def described_type - self.class.described_type - end - end -end diff --git a/vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_request_helpers.rb b/vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_request_helpers.rb deleted file mode 100644 index 4aeffaf4..00000000 --- a/vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_request_helpers.rb +++ /dev/null @@ -1,67 +0,0 @@ -module LuckySneaks - module ControllerRequestHelpers # :nodoc: - def self.included(base) - base.extend ExampleGroupMethods - end - - private - def define_implicit_request(method) - @controller_method = method - @implicit_request = case method - when :index, :new, :show, :edit - proc { get method, params } - when :create - proc { post :create, params } - when :update - proc { put :update, params } - when :destroy - proc { put :destroy, params } - end - end - - def eval_request - instance_eval &self.class.instance_variable_get("@the_request") - rescue ArgumentError # missing block - try_shared_request_definition - end - alias do_request eval_request - - def try_shared_request_definition - if defined?(shared_request) == "method" - shared_request - elsif @implicit_request - try_implicit_request - else - error_message = "Could not determine request definition for 'describe' context. " - error_message << "Please use define_request or define a shared_request." - raise ArgumentError, error_message - end - end - - def try_implicit_request - @implicit_request.call - end - - def get_response(&block) - eval_request - block.call(response) if block_given? - response - end - - module ExampleGroupMethods - # Defines a request at the example group ("describe") level to be evaluated in the examples. Example: - # - # define_request { get :index, params } - # - # Note: The following methods all define implicit requests: stub_index, stub_new, - # stub_create, stub_show, stub_edit, stub_update, and - # stub_destroy. Using them in your before blocks will allow you to forego - # defining explicit requests using define_request. See - # LuckySneaks::ControllerStubHelpers for information on these methods. - def define_request(&block) - raise ArgumentError, "Must provide a block to define a request!" unless block_given? - @the_request = block - end - end - end -end diff --git a/vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_spec_helpers.rb b/vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_spec_helpers.rb deleted file mode 100644 index 20bca87e..00000000 --- a/vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_spec_helpers.rb +++ /dev/null @@ -1,571 +0,0 @@ -$:.unshift File.join(File.dirname(__FILE__), "..") -require "skinny_spec" - -module LuckySneaks - module ControllerSpecHelpers # :nodoc: - include LuckySneaks::CommonSpecHelpers - include LuckySneaks::ControllerRequestHelpers - include LuckySneaks::ControllerStubHelpers - - def self.included(base) - base.extend ExampleGroupMethods - base.extend ControllerRequestHelpers::ExampleGroupMethods - end - - # Evaluates the specified block for each of the RESTful controller methods. - # This is useful to spec that all controller methods redirect when no user is - # logged in. - def with_default_restful_actions(params = {}, &block) - { - :get => :index, - :get => :new, - :post => :create - }.each do |method_id, message| - self.send method_id, message, params - block.call - end - { - :get => :edit, - :put => :update, - :delete => :destroy - }.each do |method_id, message| - if params[:before] - params.delete(:before).call - end - # Presuming any id will do - self.send method_id, message, params.merge(:id => 1) - block.call - end - end - - private - def create_ar_class_expectation(name, method, argument = nil, options = {}) - args = [] - unless options.delete(:only_method) - args << argument unless argument.nil? - args << hash_including(options) unless options.empty? - end - method = options.delete(:find_method) if options[:find_method] - if args.empty? - class_for(name).should_receive(method).and_return(instance_for(name)) - else - class_for(name).should_receive(method).with(*args).and_return(instance_for(name)) - end - end - - def create_positive_ar_instance_expectation(name, method, *args) - instance = instance_for(name) - if args.empty? - instance.should_receive(method).and_return(true) - else - instance.should_receive(method).with(*args).and_return(true) - end - end - - # These methods are designed to be used at the example group [read: "describe"] level - # to simplify and DRY up common expectations. - module ExampleGroupMethods - # Creates an expectation that the controller method calls ActiveRecord::Base.find. - # Examples: - # - # it_should_find :foos # => Foo.should_receive(:find).with(:all) - # it_should_find :foos, :all # An explicit version of the above - # it_should_find :foos, :conditions => {:foo => "bar"} # => Foo.should_receive(:find).with(:all, :conditions => {"foo" => "bar"} - # it_should_find :foos, "joe", :method => :find_all_by_name # Foo.should_receive(:find_all_by_name).with("joe") - # it_should_find :foo # => Foo.should_recieve(:find).with(@foo.id.to_s) - # it_should_find :foo, :params => "id" # => Foo.should_receive(:find).with(params[:id].to_s) - # it_should_find :foo, 2 # => Foo.should_receive(:find).with("2") - # it_should_find :foo, "joe", :method => :find_by_name # => Foo.should_recieve(:find_by_name).with("joe") - # - # Note: All params (key and value) will be strings if they come from a form element and are handled - # internally with this expectation. - def it_should_find(name, *args) - name_string = name.to_s - name_message = if name_string == name_string.singularize - "a #{name}" - else - name - end - it "should find #{name_message}" do - options = args.extract_options! - # Blech! - argument = if param = params[options.delete(:params)] - param.to_s - else - if args.first - args.first - elsif (instance = instance_variable_get("@#{name}")).is_a?(ActiveRecord::Base) - instance.id.to_s - else - :all - end - end - find_method = options.delete(:method) || :find - create_ar_class_expectation name, find_method, argument, options - eval_request - end - end - - # Negative version of it_should_find. This creates an expectation that - # the class never receives find at all. - def it_should_not_find(name) - name_string = name.to_s - name_message = if name_string == name_string.singularize - "a #{name}" - else - name - end - it "should not find #{name_message}" do - if name_string == name_string.singularize - class_for(name).should_not_receive(:find) - else - class_for(name).should_not_receive(:find).with(:all) - end - eval_request - end - end - - # Creates an expectation that the controller method calls ActiveRecord::Base.new. - # Takes optional params for the initialization arguments. Example - # - # it_should_initialize :foo # => Foo.should_receive(:new) - # it_should_initialize :foo, :params => :bar # => Foo.should_receive(:new).with(params[:bar]) - # it_should_initialize :foo, :bar => "baz" # => Foo.should_receive(:new).with(:bar => "baz") - def it_should_initialize(name, options = {}) - it "should initialize a #{name}" do - create_ar_class_expectation name, :new, params[options.delete(:params)], options - eval_request - end - end - - # Negative version of it_should_initialize. This creates an expectation - # that the class never recieves new at all. - def it_should_not_initialize(name) - it "should initialize a #{name}" do - class_for(name).should_not_receive(:new) - eval_request - end - end - - # Creates an expectation that the controller method calls ActiveRecord::Base#save on the - # named instance. Example: - # - # it_should_save :foo # => @foo.should_receive(:save).and_return(true) - # - # Note: This helper should not be used to spec a failed save call. Use it_should_assign - # instead, to verify that the instance is captured in an instance variable for the inevitable re-rendering - # of the form template. - def it_should_save(name) - it "should save the #{name}" do - create_positive_ar_instance_expectation name, :save - eval_request - end - end - - # Negative version of it_should_update. This creates an expectation - # that the instance never receives save at all. - def it_should_not_save(name) - it "should not save the #{name}" do - instance_for(name).should_not_receive(:save) - eval_request - end - end - - # Creates an expectation that the controller method calls ActiveRecord::Base#update_attributes - # on the named instance. Takes optional argument for params to specify in the - # expectation. Examples: - # - # it_should_update :foo # => @foo.should_receive(:update_attributes).and_return(true) - # it_should_update :foo, :params => :bar # => @foo.should_receive(:update_attributes).with(params[:bar]).and_return(true) - # - # Note: This helper should not be used to spec a failed update_attributes call. Use - # it_should_assign instead, to verify that the instance is captured in an instance variable - # for the inevitable re-rendering of the form template. - def it_should_update(name, options = {}) - it "should update the #{name}" do - create_positive_ar_instance_expectation name, :update_attributes, params[name] - eval_request - end - end - - # Negative version of it_should_update. This creates an expectation - # that the instance never receives update_attributes at all. - def it_should_not_update(name) - it "should not update the #{name}" do - instance_for(name).should_not_receive(:update_attributes) - eval_request - end - end - - # Creates an expectation that the controller method calls ActiveRecord::Base#destroy on the named - # instance. Example: - # - # it_should_destroy :foo # => @foo.should_receive(:destroy).and_return(true) - # - # Note: This helper should not be used to spec a failed destroy call. Use - # it_should_assign instead, if you need to verify that the instance is captured in an instance - # variable if it is re-rendered somehow. This is probably a really edge use case. - def it_should_destroy(name, options = {}) - it "should delete the #{name}" do - create_positive_ar_instance_expectation name, :destroy - eval_request - end - end - - # Negative version of it_should_destroy. This creates an expectation - # that the instance never receives destroy at all. - def it_should_not_destroy(name) - it "should not destroy the #{name}" do - instance_for(name).should_not_receive(:destroy) - eval_request - end - end - - # Creates expectation[s] that the controller method should assign the specified - # instance variables along with any specified values. Examples: - # - # it_should_assign :foo # => assigns[:foo].should == @foo - # it_should_assign :foo => "bar" # => assigns[:foo].should == "bar" - # it_should_assign :foo => :nil # => assigns[:foo].should be_nil - # it_should_assign :foo => :not_nil # => assigns[:foo].should_not be_nil - # it_should_assign :foo => :undefined # => controller.send(:instance_variables).should_not include("@foo") - # - # Very special thanks to Rick Olsen for the basis of this code. The only reason I even - # redefine it at all is purely an aesthetic choice for specs like "it should foo" - # over ones like "it foos". - def it_should_assign(*names) - names.each do |name| - if name.is_a?(Symbol) - it_should_assign name => name - elsif name.is_a?(Hash) - name.each do |key, value| - it_should_assign_instance_variable key, value - end - end - end - end - - # Essentially shorthand for it_should_assign name => :nil. This method can take multiple - # instance variable names, creating this shorthand for each name. See the docs for - # it_should_assign for more information. - def it_should_not_assign(*names) - names.each do |name| - # Assuming name is a symbol - it_should_assign name => :nil - end - end - - # Wraps the separate expectations it_should_find and it_should_assign - # for simple cases. If you need more control over the parameters of the find, this - # isn't the right helper method and you should write out the two expectations separately. - def it_should_find_and_assign(*names) - names.each do |name| - it_should_find name, :only_method => true - it_should_assign name - end - end - - # Negative version of it_should_find_and_assign. This creates an - # expectation that the class never receives find at all and that - # no matching instance variable is ever created. - def it_should_not_find_and_assign(*names) - names.each do |name| - it_should_not_find name - it_should_assign name => :nil - end - end - - # Wraps the separate expectations it_should_initialize and it_should_assign - # for simple cases. If you need more control over the parameters of the initialization, this - # isn't the right helper method and you should write out the two expectations separately. - # - # Note: This method is used for controller methods like new, where the instance - # is initialized without being saved (this includes failed create requests). - # If you want to spec that the controller method successfully saves the instance, - # please use it_should_initialize_and_save. - def it_should_initialize_and_assign(*names) - names.each do |name| - it_should_initialize name, :only_method => true - it_should_assign name - end - end - - # Negative version of it_should_initialize_and_assign. This creates an - # expectation that the class never receives new at all and that - # no matching instance variable is ever created. - def it_should_not_initialize_and_assign(*names) - names.each do |name| - it_should_not_initialize name - it_should_assign name => :nil - end - end - - # Wraps the separate expectations it_should_initialize and it_should_save - # for simple cases. If you need more control over the parameters of the initialization, this - # isn't the right helper method and you should write out the two expectations separately. - # - # Note: This method is used for controller methods like create, where the instance - # is initialized and successfully saved. If you want to spec that the instance is created - # but not saved, just use it_should_initialize_and_assign. - def it_should_initialize_and_save(*names) - names.each do |name| - it_should_initialize name, :only_method => true - it_should_save name - end - end - - # Wraps the separate expectations it_should_find and it_should_update - # for simple cases. If you need more control over the parameters of the find, this - # isn't the right helper method and you should write out the two expectations separately. - # - # Note: This method is used for controller methods like update, where the - # instance is loaded from the database and successfully saved. If you want to spec that the - # instance is found but not saved, just use it_should_find_and_assign. - def it_should_find_and_update(*names) - names.each do |name| - it_should_find name, :only_method => true - it_should_update name - end - end - - # Wraps the separate expectations it_should_find and it_should_destroy - # for simple cases. If you need more control over the parameters of the find, this - # isn't the right helper method and you should write out the two expectations separately. - def it_should_find_and_destroy(*names) - names.each do |name| - it_should_find name, :only_method => true - it_should_destroy name - end - end - - # Creates an expectation that the specified collection (flash, session, - # params, cookies) contains the specified key and value. To specify that - # the collection should be set to nil, specify the value as :nil instead. - def it_should_set(collection, key, value = nil, &block) - it "should set #{collection}[:#{key}]#{' with ' + value.inspect if value}" do - # Allow flash.now[:foo] to remain in the flash - flash.stub!(:sweep) if collection == :flash - eval_request - if value - if value == :nil - self.send(collection)[key].should be_nil - else - self.send(collection)[key].should == value - end - elsif block_given? - self.send(collection)[key].should == instance_eval(&block) - else - self.send(collection)[key].should_not be_nil - end - end - end - - # Wraps it_should_set :flash. To specify that the collection should be set - # to nil, specify the value as :nil instead. - def it_should_set_flash(name, value = nil, &block) - it_should_set :flash, name, value, &block - end - - # Wraps it_should_set :flash, :nil. - def it_should_not_set_flash(name) - it_should_set :flash, name, :nil - end - - # Wraps it_should_set :session. To specify that the collection should be set - # to nil, specify the value as :nil instead. - def it_should_set_session(name, value = nil, &block) - it_should_set :session, name, value, &block - end - - # Wraps it_should_set :session, :nil. - def it_should_not_set_session(name) - it_should_set :session, name, :nil - end - - # Wraps it_should_set :params. To specify that the collection should be set - # to nil, specify the value as :nil instead. - def it_should_set_params(name, value = nil, &block) - it_should_set :params, name, value, &block - end - - # Wraps it_should_set :params, :nil. - def it_should_not_set_params(name) - it_should_set :params, name, :nil - end - - # Wraps it_should_set :cookies. To specify that the collection should be set - # to nil, specify the value as :nil instead. - def it_should_set_cookies(name, value = nil, &block) - it_should_set :cookies, name, value, &block - end - - # Wraps it_should_set :cookies, :nil. - def it_should_not_set_cookies(name) - it_should_set :cookies, name, :nil - end - - # Wraps the various it_should_render_foo methods: - # it_should_render_template, it_should_render_partial, - # it_should_render_xml, it_should_render_json, - # it_should_render_formatted, and it_should_render_nothing. - def it_should_render(render_method, *args) - send "it_should_render_#{render_method}", *args - end - - # Creates an expectation that the controller method renders the specified template. - # Accepts the following options which create additional expectations. - # - # :content_type:: Creates an expectation that the Content-Type header for the response - # matches the one specified - # :status:: Creates an expectation that the HTTP status for the response - # matches the one specified - def it_should_render_template(name, options = {}) - create_status_expectation options[:status] if options[:status] - it "should render '#{name}' template" do - eval_request - response.should render_template(name) - end - create_content_type_expectation(options[:content_type]) if options[:content_type] - end - - # Creates an expectation that the controller method renders the specified partial. - # Accepts the following options which create additional expectations. - # - # :content_type:: Creates an expectation that the Content-Type header for the response - # matches the one specified - # :status:: Creates an expectation that the HTTP status for the response - # matches the one specified - def it_should_render_partial(name, options = {}) - create_status_expectation options[:status] if options[:status] - it "should render '#{name}' partial" do - controller.expect_render(:partial => name) - eval_request - end - create_content_type_expectation(options[:content_type]) if options[:content_type] - end - - # Creates an expectation that the controller method renders the specified record via to_xml. - # Accepts the following options which create additional expectations. - # - # :content_type:: Creates an expectation that the Content-Type header for the response - # matches the one specified - # :status:: Creates an expectation that the HTTP status for the response - # matches the one specified - def it_should_render_xml(record = nil, options = {}, &block) - it_should_render_formatted :xml, record, options, &block - end - - # Creates an expectation that the controller method renders the specified record via to_json. - # Accepts the following options which create additional expectations. - # - # :content_type:: Creates an expectation that the Content-Type header for the response - # matches the one specified - # :status:: Creates an expectation that the HTTP status for the response - # matches the one specified - def it_should_render_json(record = nil, options = {}, &block) - it_should_render_formatted :json, record, options, &block - end - - # Called internally by it_should_render_xml and it_should_render_json - # but should not really be called much externally unless you have defined your own - # formats with a matching to_foo method on the record. - # - # Which is probably never. - def it_should_render_formatted(format, record = nil, options = {}, &block) - create_status_expectation options[:status] if options[:status] - it "should render #{format.inspect}" do - if record.is_a?(Hash) - options = record - record = nil - end - if record.nil? && !block_given? - raise ArgumentError, "it_should_render must be called with either a record or a block and neither was given." - else - if record - pieces = record.to_s.split(".") - record = instance_variable_get("@#{pieces.shift}") - record = record.send(pieces.shift) until pieces.empty? - end - block ||= proc { record.send("to_#{format}") } - get_response do |response| - response.should have_text(block.call) - end - end - end - create_content_type_expectation(options[:content_type]) if options[:content_type] - end - - # Creates an expectation that the controller method returns a blank page. You'd already - # know when and why to use this so I'm not typing it out. - def it_should_render_nothing(options = {}) - create_status_expectation options[:status] if options[:status] - it "should render :nothing" do - get_response do |response| - response.body.strip.should be_blank - end - end - end - - # Creates an expectation that the controller method redirects to the specified destination. Example: - # - # it_should_redirect_to { foos_url } - # - # Note: This method takes a block to evaluate the route in the example - # context rather than the example group context. - def it_should_redirect_to(hint = nil, &route) - if hint.nil? && route.respond_to?(:to_ruby) - hint = route.to_ruby.gsub(/(^proc \{)|(\}$)/, '').strip - end - it "should redirect to #{(hint || route)}" do - eval_request - response.should redirect_to(instance_eval(&route)) - end - end - - # Negative version of it_should_redirect_to. - def it_should_not_redirect_to(hint = nil, &route) - if hint.nil? && route.respond_to?(:to_ruby) - hint = route.to_ruby.gsub(/(^proc \{)|(\}$)/, '').strip - end - it "should not redirect to #{(hint || route)}" do - eval_request - response.should_not redirect_to(instance_eval(&route)) - end - end - - # Creates an expectation that the controller method redirects back to the previous page - def it_should_redirect_to_referer - it "should redirect to the referring page" do - request.env["HTTP_REFERER"] = "http://test.host/referer" - eval_request - response.should redirect_to("http://test.host/referer") - end - end - alias it_should_redirect_to_referrer it_should_redirect_to_referer - - private - def it_should_assign_instance_variable(name, value) - expectation_proc = case value - when :nil - proc { assigns[name].should be_nil } - when :not_nil - proc { assigns[name].should_not be_nil } - when :undefined - proc { controller.send(:instance_variables).should_not include("@{name}") } - when Symbol - if (instance_variable = instance_variable_get("@#{name}")).nil? - proc { assigns[name].should_not be_nil } - else - proc { assigns[name].should == instance_variable } - end - else - proc { assigns[name].should == value } - end - it "should #{value == :nil ? 'not ' : ''}assign @#{name}" do - eval_request - instance_eval &expectation_proc - end - end - end - end -end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_stub_helpers.rb b/vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_stub_helpers.rb deleted file mode 100644 index 6d78ce54..00000000 --- a/vendor/plugins/skinny_spec/lib/lucky_sneaks/controller_stub_helpers.rb +++ /dev/null @@ -1,238 +0,0 @@ -module LuckySneaks # :nodoc: - # These methods are designed to be used in your example before blocks to accomplish - # a whole lot of functionality with just a tiny bit of effort. The methods which correspond - # to the controller methods perform the most duties as they create the mock_model instances, - # stub out all the necessary methods, and also create implicit requests to DRY up your spec - # file even more. You are encouraged to use these methods to setup the basic calls for your - # resources and only resort to the other methods when mocking and stubbing secondary objects - # and calls. - module ControllerStubHelpers - # Stubs out find :all and returns a collection of mock_model - # instances of that class. Accepts the following options: - # - # :find_method:: Method to use as finder call. Default is :find. - # Note: When specifying the method, the call is stubbed - # to accept any arguments. Caveat programmer. - # :format:: Format of the request. Used to only add to_xml and - # to_json when actually needed. - # :size:: Number of instances to return in the result. Default is 3. - # :stub:: Additional methods to stub on the instances - # - # Any additional options will be passed as arguments to the class find. - # You will want to make sure to pass those arguments to the it_should_find spec as well. - def stub_find_all(klass, options = {}) - returning(Array.new(options[:size] || 3){mock_model(klass)}) do |collection| - stub_out klass, options.delete(:stub) - if format = options.delete(:format) - stub_formatted collection, format - params[:format] = format - end - if find_method = options[:find_method] - # Not stubbing specific arguments here - # If you need more specificity, write a custom example - klass.stub!(find_method).and_return(collection) - else - klass.stub!(:find).with(:all).and_return(collection) - klass.stub!(:find).with(:all, hash_including(options)).and_return(collection) - end - end - end - - # Alias for stub_find_all but additionally defines an implicit request get :index. - def stub_index(klass, options = {}) - define_implicit_request :index - stub_find_all klass, options - end - - # Stubs out new method and returns a mock_model instance marked as a new record. - # Accepts the following options: - # - # :format:: Format of the request. Used to only add to_xml and - # to_json when actually needed. - # :stub:: Additional methods to stub on the instances - # - # It also accepts some options used to stub out save with a specified true - # or false but you should be using stub_create in that case. - def stub_initialize(klass, options = {}) - returning mock_model(klass) do |member| - stub_out member, options.delete(:stub) - if format = options[:format] - stub_formatted member, format - params[:format] = format - end - klass.stub!(:new).and_return(member) - if options[:params] - klass.stub!(:new).with(hash_including(options[:params])).and_return(member) - end - if options[:stub_save] - stub_ar_method member, :save, options[:return] - else - member.stub!(:new_record?).and_return(true) - member.stub!(:id).and_return(nil) - end - end - end - - # Alias for stub_initialize which additionally defines an implicit request get :new. - def stub_new(klass, options = {}) - define_implicit_request :new - stub_initialize klass, options - end - - # Alias for stub_initialize which additionally defines an implicit request post :create. - # - # Note: If stub_create is provided an optional :params hash, - # those params will be added to the example's params object. - def stub_create(klass, options = {}) - define_implicit_request :create - class_name = klass.name.underscore - options[:params] ||= params[class_name] - stub_initialize klass, options.merge(:stub_save => true) - end - - # Stubs out find and returns a single mock_model - # instances of that class. Accepts the following options: - # - # :find_method:: Method to use as finder call. Default is :find. - # :format:: Format of the request. Used to only add to_xml and - # to_json when actually needed. - # :stub:: Additional methods to stub on the instances - # :current_object:: If set to true, find will set params[:id] - # using the id of the mock_model instance - # and use that value as an argument when stubbing find - # - # Any additional options will be passed as arguments to find.You will want - # to make sure to pass those arguments to the it_should_find spec as well. - # - # Note: The option :stub_ar is used internally by stub_update - # and stub_destroy. If you need to stub update_attributes or - # destroy you should be using the aforementioned methods instead. - def stub_find_one(klass, options = {}) - returning mock_model(klass) do |member| - stub_out member, options.delete(:stub) - if format = options.delete(:format) - stub_formatted member, format - params[:format] = format - end - if options.delete(:current_object) - params[:id] = member.id - if ar_stub = options.delete(:stub_ar) - stub_ar_method member, ar_stub, options.delete(:return), options.delete(:update_params) - end - end - if find_method = options.delete(:find_method) - klass.stub!(find_method).and_return(member) - else - # Stubbing string and non-string just to be safe - klass.stub!(:find).with(member.id).and_return(member) - klass.stub!(:find).with(member.id.to_s).and_return(member) - unless options.empty? - klass.stub!(:find).with(member.id, hash_including(options)).and_return(member) - klass.stub!(:find).with(member.id.to_s, hash_including(options)).and_return(member) - end - end - end - end - - # Note: Use of this method with :child options (to mock - # association) is deprecated. Please use stub_association. - # - # Same as stub_find_one but setups the instance as the parent - # of the specified association. Example: - # - # stub_parent(Document, :child => :comments) - # - # This stubs Document.find, @document.comments (which - # will return Comment class), as well as params[:document_id]. - # This method is meant to be used in the controller for the specified child - # (CommentsController in this instance) in situations like: - # - # def index - # @document = Document.find(params[:document_id]) - # @comments = @document.comments.find(:all) - # end - def stub_parent(klass, options = {}) - returning stub_find_one(klass, options) do |member| - params[klass.name.foreign_key] = member.id - if offspring = options.delete(:child) - puts "stub_parent with :child option has been marked for deprecation" - puts "please use stub_association to create the mock instead" - member.stub!(offspring).and_return(class_for(offspring)) - end - end - end - - # Alias for stub_find_one which additionally defines an implicit request get :show. - def stub_show(klass, options = {}) - define_implicit_request :show - stub_find_one klass, options.merge(:current_object => true) - end - - # Alias for stub_find_one which additionally defines an implicit request get :edit. - def stub_edit(klass, options = {}) - define_implicit_request :edit - stub_find_one klass, options.merge(:current_object => true) - end - - # Alias for stub_find_one which additionally defines an implicit request put :update - # and stubs out the update_attribute method on the instance as well. - # - # Note: If stub_update is provided an optional :params hash, - # those params will be added to the example's params object. - def stub_update(klass, options = {}) - define_implicit_request :update - stub_find_one klass, options.merge(:current_object => true, :stub_ar => :update_attributes) - end - - # Alias for stub_find_one which additionally defines an implicit request delete :destroy - # and stubs out the destroy method on the instance as well. - def stub_destroy(klass, options = {}) - define_implicit_request :destroy - stub_find_one klass, options.merge(:current_object => true, :stub_ar => :destroy) - end - - # Stubs to_xml or to_json respectively based on format argument. - def stub_formatted(object, format) - return unless format - object.stub!("to_#{format}").and_return("#{object.class} formatted as #{format}") - end - - # Creates a mock object representing an association proxy, stubs the appropriate - # method on the parent object and returns that association proxy. - # Accepts the following option: - # - # :stub:: Additional methods to stub on the mock proxy object - def stub_association(object, association, options = {}) - # I know options isn't implemented anywhere - object_name = instance_variables.select{|name| instance_variable_get(name) == object} - returning mock("Association proxy for #{object_name}.#{association}") do |proxy| - stub_out proxy, options[:stub] if options[:stub] - object.stub!(association).and_return(proxy) - end - end - - private - # Stubs out multiple methods. You shouldn't be calling this yourself and if you do - # you should be able to understand the code yourself, right? - def stub_out(object, stubs = {}) - return if stubs.nil? - stubs.each do |method, value| - if value - object.stub!(method).and_return(value) - else - object.stub!(method) - end - end - end - - # Stubs out ActiveRecord::Base methods like #save, #update_attributes, etc - # that may be called on a found or instantiated mock_model instance. - def stub_ar_method(object, method, return_value, params = {}) - if params.blank? - object.stub!(method).and_return(return_value ? false : true) - else - object.stub!(method).with(hash_including(params)).and_return(return_value ? false : true) - end - end - end -end diff --git a/vendor/plugins/skinny_spec/lib/lucky_sneaks/model_spec_helpers.rb b/vendor/plugins/skinny_spec/lib/lucky_sneaks/model_spec_helpers.rb deleted file mode 100644 index 4119acc6..00000000 --- a/vendor/plugins/skinny_spec/lib/lucky_sneaks/model_spec_helpers.rb +++ /dev/null @@ -1,496 +0,0 @@ -$:.unshift File.join(File.dirname(__FILE__), "..") -require "skinny_spec" - -module LuckySneaks - # These methods are designed to be used in your example [read: "it"] blocks - # to make your model specs a little more DRY. You might also be interested - # in checking out the example block [read: "describe"] level versions in of these - # methods which can DRY things up even more: - # LuckySneaks::ModelSpecHelpers::ExampleGroupLevelMethods. - # - # Also check out the methods in LuckySneaks::ModelSpecHelpers::AssociationMatcher - # for some helpful matcher helper methods to use with these methods if you want to spec - # options on your association setups. - module ModelSpecHelpers - include LuckySneaks::CommonSpecHelpers - - def self.included(base) # :nodoc: - base.extend ExampleGroupLevelMethods - end - - # These methods cannot be used alone but are used in compliment with the association - # matchers in LuckySneaks::ModelSpecHelpers like have_many. Example: - # - # describe User do - # it "should have many memberships" do - # User.should have_many(:memberships) - # end - # - # it "should have many sites through memberships" do - # User.should have_many(:sites).through(:memberships) - # end - # - # it "should belong to a manager" do - # User.should belong_to(:manager).with_counter_cache - # end - # end - # - # Note: To spec these sorts of options using the example block helpers like - # it_should_have_many, just add them as options directly. This will use - # with_options rather than any specific matcher helpers but will have the same - # effects. Example: - # - # describe User do - # it_should_have_many :sites, :through => :memberships - # end - class AssociationMatcher - def initialize(associated, macro) # :nodoc: - @associated = associated - @macro = macro - @options = {} - end - - def matches?(main_model) # :nodoc: - unless main_model.respond_to?(:reflect_on_association) - if main_model.class.respond_to?(:reflect_on_association) - main_model = main_model.class - else - @not_model = main_model - return false - end - end - if @association = main_model.reflect_on_association(@associated) - @options.all?{|k, v| @association.options[k] == v || - [@association.options[k]] == v} # Stupid to_a being obsoleted! - end - end - - def failure_message # :nodoc: - if @not_model - " expected: #{@not_model} to be a subclass of ActiveRecord::Base class, but was not" - elsif @association - " expected: #{association_with(@options)}\n got: #{association_with(@association.options)}" - else - " expected: #{association_with(@options)}, but the association does not exist" - end - end - - def negative_failure_message # :nodoc: - if @association - " expected: #{association_with(@options)}\n got: #{association_with(@association.options)}" - else - " expected: #{association_with(@options)} to not occur but it does" - end - end - - # The following public methods are chainable extensions on the main matcher - # Examples: - # - # Foo.should have_many(:bars).through(:foobars).with_dependent(:destroy) - # Bar.should belong_to(:baz).with_class_name("Unbaz") - def through(through_model) - @options[:through] = through_model - self - end - - def and_includes(included_models) - @options[:include] = included_models - self - end - - def and_extends(*modules) - @options[:extends] = modules - self - end - - def with_counter_cache(counter_cache = true) - if counter_cache - @options[:counter_cache] = counter_cache - end - self - end - - def uniq(*irrelevant_args) - @options[:uniq] = true - self - end - alias and_is_unique uniq - alias with_unique uniq - - def polymorphic(*irrelevant_args) - @options[:polymorphic] = true - self - end - alias and_is_polymorphic polymorphic - alias with_polymorphic polymorphic - - def as(interface) - @options[:as] = interface - end - - # Use this to just specify the options as a hash. - # Note: It will completely override any previously set options - def with_options(options = {}) - options.each{|k, v| @options[k] = v} - self - end - - private - # Takes care of methods like with_dependent(:destroy) - def method_missing(method_id, *args, &block) - method_name = method_id.to_s - if method_name =~ /^with_(.*)/ - @options[$1.to_sym] = args - self - else - super method_id, *args, &block - end - end - - def association_with(options) - option_string = (options.nil? || options.empty?) ? "" : options.inspect - unless option_string.blank? - option_string.sub! /^\{(.*)\}$/, ', \1' - option_string.gsub! /\=\>/, ' => ' - end - "#{@macro} :#{@associated}#{option_string}" - end - end - - # Creates matcher that checks if the receiver has a belongs_to association - # with the specified model. - # - # Note: The argument should be a symbol as in the model's association definition - # and not the model's class name. - def belong_to(model) - AssociationMatcher.new model, :belongs_to - end - - # Creates matcher that checks if the receiver has a have_one association - # with the specified model. - # - # Note: The argument should be a symbol as in the model's association definition - # and not the model's class name. - def have_one(model) - AssociationMatcher.new model, :has_one - end - - # Creates matcher that checks if the receiver has a have_many association - # with the specified model. - # - # Note: The argument should be a symbol as in the model's association definition - # and not the model's class name. - def have_many(models) - AssociationMatcher.new models, :has_many - end - - # Creates matcher that checks if the receiver has a have_and_belong_to_many association - # with the specified model. - # - # Note: The argument should be a symbol as in the model's association definition - # and not the model's class name. - def have_and_belong_to_many(models) - AssociationMatcher.new models, :has_and_belongs_to_many - end - - private - def class_or_instance - @model_spec_class_or_instance ||= class_for(described_type) || instance - end - - def instance - @model_spec_instance ||= instance_for(described_type) - end - - # These methods are designed to be used at the example group [read: "describe"] level - # to simplify and DRY up common expectations. Some of these methods are wrappers for - # matchers which can also be used on the example level [read: within an "it" block]. See - # LuckySneaks::ModelSpecHelpers for more information. - # - # Note: The validation matchers are only meant to be used for simple validation checking - # not as a one-size-fits-all solution. - module ExampleGroupLevelMethods - # Creates an expectation that the current model being spec'd has a belong_to - # association with the specified model. Accepts optional arguments which are appended to - # the belong_to spec like this: - # - # it_should_belong_to :document, :counter_cache => true - # - # which is the same as writing out: - # - # it "should belong to document" do - # Comment.should belong_to(:document).with_options(:counter_cache => true) - # end - # - # If you want a more detailed spec description text, feel free to write this out in the long - # form and use belong_to and its related matcher helpers. - # - # Note: The argument should be a symbol as in the model's association definition - # and not the model's class name. - def it_should_belong_to(model, options = {}) - it "should belong to a #{model}" do - if options.empty? - class_or_instance.should belong_to(model) - else - class_or_instance.should belong_to(model).with_options(options) - end - end - end - - # Creates an expectation that the current model being spec'd has a have_one - # association with the specified model. Accepts optional arguments which are appended to - # the have_one spec like this: - # - # it_should_have_one :last_comment, :class_name => "Comment", :order => "created_at DESC" - # - # which is the same as writing out: - # - # it "should have one document" do - # Document.should have_one(:last_comment).with_options(:class_name => "Comment", :order => "created_at DESC") - # end - # - # If you want a more detailed spec description text, feel free to write this out in the long - # form and use have_one and its related matcher helpers. - # - # Note: The argument should be a symbol as in the model's association definition - # and not the model's class name. - def it_should_have_one(model, options = {}) - it "should have one #{model}" do - if options.empty? - class_or_instance.should have_one(model) - else - class_or_instance.should have_one(model).with_options(options) - end - end - end - - # Creates an expectation that the current model being spec'd has a have_many - # association with the specified model. Accepts optional arguments which are appended to - # the have_many spec like this: - # - # it_should_have_many :memberships, :through => :sites - # - # which is the same as writing out: - # - # it "should have many memberships" do - # User.should have_many(:memberships).with_options(:through => :sites) - # end - # - # If you want a more detailed spec description text, feel free to write this out in the long - # form and use have_many and its related matcher helpers. - # - # Note: The argument should be a symbol as in the model's association definition - # and not the model's class name. - def it_should_have_many(models, options = {}) - it "should have many #{models}" do - if options.empty? - class_or_instance.should have_many(models) - else - class_or_instance.should have_many(models).with_options(options) - end - end - end - - # Creates an expectation that the current model being spec'd has a have_and_belong_to_many - # association with the specified model. Accepts optional arguments which are appended to - # the have_and_belong_to_many spec like this: - # - # it_should_have_and_belong_to_many :documents, :include => :attachments - # - # which is the same as writing out: - # - # it "should belong to document" do - # User.should have_and_belong_to_many(:documents).with_options(:include => :attachments) - # end - # - # If you want a more detailed spec description text, feel free to write this out in the long - # form and use have_and_belong_to_many and its related matcher helpers. - # - # Note: The argument should be a symbol as in the model's association definition - # and not the model's class name. - def it_should_have_and_belong_to_many(models, options = {}) - it "should have and belong to many #{models}" do - if options.empty? - class_or_instance.should have_and_belong_to_many(models) - else - class_or_instance.should have_and_belong_to_many(models).with_options(options) - end - end - end - - # Creates an expectation that new instances of the model being spec'd - # should initialise the specified attributes with a default value. - # - # it_should_default_attributes :status => 'new' - # - def it_should_default_attributes(hash_attribute_values) - hash_attribute_values.each_pair do |a,v| - it "should default #{a} attribute to #{v}" do - class_or_instance.new.send(a).should == v - end - end - end - - # Creates an expectation that the current model being spec'd validates_presence_of - # the specified attribute. Takes an optional custom message to match the one in the model's - # validation. - def it_should_validate_presence_of(attribute, message = default_error_message(:blank)) - it "should not be valid if #{attribute} is blank" do - instance.send "#{attribute}=", nil - instance.errors_on(attribute).should include(message) - end - end - - # Negative version of it_should_validate_presence_of. See that method for more - # details. You'd probably only be using this in a nested example block to compare that - # one scenario validates presence and another does not (because of conditions in - # :if/:unless). - def it_should_not_validate_presence_of(attribute, message = default_error_message(:blank)) - it "should be valid if #{attribute} is blank" do - instance.send "#{attribute}=", nil - instance.errors_on(attribute).should_not include(message) - end - end - - # Creates an expectation that the current model being spec'd validates_inclusion_of - # the specified attribute. Takes an optional custom message to match the one in the model's - # validation. - def it_should_validate_inclusion_of(attribute, options = {}, message = default_error_message(:inclusion)) - it "should validate #{attribute} is in #{options[:in].to_s}" do - # We specifically do not try to go below the range on String and character ranges because that problem set is unpredictable. - lower = options[:in].first.respond_to?(:-) ? options[:in].first - 0.0001 : nil - higher = options[:in].last.succ - - instance.send "#{attribute}=", lower - instance.errors_on(attribute).should include(message) - - instance.send "#{attribute}=", higher - instance.errors_on(attribute).should include(message) - - instance.send "#{attribute}=", (lower+higher)/2 - instance.errors_on(attribute).should_not include(message) - end - end - - # Creates an expectation that the current model being spec'd validates_numericality_of - # the specified attribute. Takes an optional custom message to match the one in the model's - # validation. - def it_should_validate_numericality_of(attribute, message = default_error_message(:not_a_number)) - it "should validate #{attribute} is a numeric" do - instance.send "#{attribute}=", "NaN" - instance.errors_on(attribute).should include(message) - end - end - - # Negative version of it_should_validate_numericality_of. See that method for more - # details. You'd probably only be using this in a nested example block to compare that - # one scenario validates presence and another does not (because of conditions in - # :if/:unless). - def it_should_not_validate_numericality_of(attribute, message = default_error_message(:not_a_number)) - it "should not validate #{attribute} is a numeric" do - instance.send "#{attribute}=", "NaN" - instance.errors_on(attribute).should_not include(message) - end - end - - # Creates an expectation that the current model being spec'd validates_confirmation_of - # the specified attribute. Takes an optional custom message to match the one in the model's - # validation. - def it_should_validate_confirmation_of(attribute, message = default_error_message(:confirmation)) - it "should validate confirmation of #{attribute}" do - dummy_value = dummy_value_for(instance, attribute) || "try a string" - instance.send "#{attribute}=", dummy_value - instance.send "#{attribute}_confirmation=", dummy_value.succ - instance.errors_on(attribute).should include(message) - end - end - - # Creates an expectation that the current model being spec'd validates_uniqueness_of - # the specified attribute. Takes an optional custom message to match the one in the model's - # validation. - # - # Note: This method will fail completely if valid_attributes - # does not provide all the attributes needed to create a valid record. - def it_should_validate_uniqueness_of(attribute, message = default_error_message(:taken)) - it "should validate uniqueness of #{attribute}" do - previous_instance = instance.class.create!(valid_attributes) - instance.attributes = valid_attributes - instance.errors_on(attribute).should include(message) - previous_instance.destroy - end - end - - # Negative version of it_should_validate_uniqueness_of. See that method for more - # details. You'd probably only be using this in a nested example block to compare that - # one scenario validates presence and another does not (because of conditions in - # :if/:unless). - def it_should_not_validate_uniqueness_of(attribute, message = default_error_message(:taken)) - it "should not validate uniqueness of #{attribute}" do - previous_instance = instance.class.create!(valid_attributes) - instance.attributes = valid_attributes - instance.errors_on(attribute).should_not include(message) - previous_instance.destroy - end - end - - # Creates an expectation that the current model being spec'd accepts the specified values as - # valid for the specified attribute. This is most likely used with validates_format_of - # but there's nothing saying it couldn't be another validation. - def it_should_accept_as_valid(attribute, *values) - values.flatten.each do |value| - value_inspect = case value - when String : "'#{value}'" - when NilClass : "nil" - else value - end - it "should accept #{value_inspect} as a valid #{attribute}" do - instance.send "#{attribute}=", value - instance.errors_on(attribute).should == [] - end - end - end - - # Creates an expectation that the current model being spec'd does not accept the specified - # values as valid for the specified attribute. This is most likely used with - # validates_format_of but there's nothing saying it couldn't be another validation. - # Takes an optional argument :message => "some custom error messsage" for - # spec'ing the actual error message. - def it_should_not_accept_as_valid(attribute, *values) - options = values.extract_options! - values.flatten.each do |value| - value_inspect = case value - when String : "'#{value}'" - when NilClass : "nil" - else value - end - it "should not accept #{value_inspect} as a valid #{attribute}" do - instance.send "#{attribute}=", value - if options[:message] - instance.errors_on(attribute).should include(options[:message]) - else - instance.should have_at_least(1).errors_on(attribute) - end - end - end - end - - # Creates an expectation that the current model being spec'd doesn't allow mass-assignment - # of the specified attribute. - def it_should_not_mass_assign(attribute) - it "should not allow mass-assignment of #{attribute}" do - lambda { - instance.send :attributes=, {attribute => dummy_value_for(instance, attribute)} - }.should_not change(instance, attribute) - end - end - - def default_error_message(attribute) - if defined?(I18n) - I18n.translate attribute, :scope => "activerecord.errors.messages" - else - ActiveRecord::Errors.default_error_messages[attribute] - end - end - end - end -end diff --git a/vendor/plugins/skinny_spec/lib/lucky_sneaks/view_spec_helpers.rb b/vendor/plugins/skinny_spec/lib/lucky_sneaks/view_spec_helpers.rb deleted file mode 100644 index fb8775a1..00000000 --- a/vendor/plugins/skinny_spec/lib/lucky_sneaks/view_spec_helpers.rb +++ /dev/null @@ -1,577 +0,0 @@ -$:.unshift File.join(File.dirname(__FILE__), "..") -require "skinny_spec" - -module LuckySneaks - # These methods are designed to be used in your example [read: "it"] blocks - # to make your view specs less brittle and more DRY. You might also be interested - # in checking out the example block [read: "describe"] level versions in of these - # methods which can DRY things up even more: - # LuckySneaks::ViewSpecHelpers::ExampleGroupLevelMethods. - module ViewSpecHelpers - include LuckySneaks::CommonSpecHelpers - include LuckySneaks::ViewStubHelpers - include ActionController::PolymorphicRoutes - - def self.included(base) # :nodoc: - base.extend ExampleGroupLevelMethods - end - - # Wraps a matcher that checks if the receiver contains a FORM element with - # its action attribute set to the specified path. - def submit_to(path) - have_tag("form[action=#{path}]") - end - - # Wraps a matcher that checks if the receiver contains any of several form elements - # that would return sufficient named parameters to allow editing of the specified - # attribute on the specified instance. Example: - # - # response.should allow_editing(@foo, "bar") - # - # can be satisfied by any of the following HTML elements: - # - # - # - # - # - # - def allow_editing(instance, attribute) - instance_name = instance.class.name.underscore.downcase - column = instance.column_for_attribute(attribute) - if column && [Date, Time].include?(column.klass) - have_tag( - "input[name='#{instance_name}[#{attribute}]'], - select[name=?]", /#{instance_name}\[#{attribute}\(.*\)\]/ - ) - else - have_tag( - "input[type='text'][name='#{instance_name}[#{attribute}]'], - input[type='password'][name='#{instance_name}[#{attribute}]'], - select[name='#{instance_name}[#{attribute}]'], - textarea[name='#{instance_name}[#{attribute}]'], - input[type='checkbox'][name='#{instance_name}[#{attribute}]'], - input[type='checkbox'][name='#{instance_name}[#{attribute.to_s.tableize.singularize}_ids][]'], - input[type='radio'][name='#{instance_name}[#{attribute}]']" - ) - end - end - - # Wraps a matcher that checks if the receiver contains a FORM element - # whose enctype attribute is set to "multipart/form-data" - # and contains an INPUT element whose name attribute correlates - # with the provided instance and attribute. - def allow_uploading(instance, attribute) - instance_name = instance.class.name.underscore.downcase - have_tag("form[enctype='multipart/form-data'] input[type='file'][name='#{instance_name}[#{attribute}]']") - end - - # Wraps a matcher that checks if the receiver contains an A element (link) - # whose href attribute is set to the specified path or a FORM - # element whose action attribute is set to the specified path. - def have_link_or_button_to(path) - have_tag( - "a[href='#{path}'], - form[action='#{path}'] input, - form[action='#{path}'] button" - ) - end - alias have_link_to have_link_or_button_to - alias have_button_to have_link_or_button_to - - # Wraps have_link_or_button_to new_polymorphic_path for the specified class which - # corresponds with the new method of the controller. - # - # Note: This method may takes a string or symbol representing the model's name - # to send to have_link_or_button_to_show or the model's name itself. - def have_link_or_button_to_new(name) - have_link_or_button_to new_polymorphic_path(name.is_a?(ActiveRecord::Base) ? name : class_for(name)) - end - - # Wraps have_link_or_button_to polymorphic_path(instance) which - # corresponds with the show method of the controller. - def have_link_or_button_to_show(instance) - path = polymorphic_path(instance) - have_tag( - "a[href='#{path}'], - form[action='#{path}'][method='get'] input, - form[action='#{path}'][method='get'] button, - form[action='#{path}'] input[name='_method'][value='get'] + input, - form[action='#{path}'] input[name='_method'][value='get'] + button" - ) - end - alias have_link_to_show have_link_or_button_to_show - alias have_button_to_show have_link_or_button_to_show - - # Wraps have_link_or_button_to edit_polymorphic_path(instance) which - # corresponds with the edit method of the controller. - def have_link_or_button_to_edit(instance) - have_link_or_button_to edit_polymorphic_path(instance) - end - alias have_link_to_edit have_link_or_button_to_edit - alias have_button_to_edit have_link_or_button_to_edit - - # Wraps a matcher that checks if the receiver contains the HTML created by Rails' - # button_to helper: to wit, a FORM element whose action - # attribute is pointed at the polymorphic_path of the instance - # and contains an INPUT named "_method" with a value of "delete". - def have_button_to_delete(instance) - path = polymorphic_path(instance) - have_tag( - "form[action='#{path}'] input[name='_method'][value='delete'] + input, - form[action='#{path}'] input[name='_method'][value='delete'] + button, - a[href=\"#{path}\"][onclick*=\"f.method = 'POST'\"][onclick*=\"m.setAttribute('name', '_method'); m.setAttribute('value', 'delete')\"]" - ) - end - - # Creates a mock_model instance and adds it to the assigns collection - # using either the name passed as the first argument or the underscore version - # of its class name. Accepts optional arguments to stub out additional methods - # (and their return values) on the mock_model instance. Example: - # - # mock_and_assign(Foo, :stub => {:bar => "bar"}) - # - # is the same as running assigns[:foo] = mock_model(Foo, :bar => "bar"). - # - # mock_and_assign(Foo, "special_foo", :stub => {:bar => "baz"}) - # - # is the same as running assigns[:special_foo] = mock_model(Foo, :bar => "baz"). - # - # Note: Adding to the assigns collection returns the object added, so this can - # be chained a la @foo = mock_and_assign(Foo). - def mock_and_assign(klass, *args) - options = args.extract_options! - mocked = if options[:stub] - self.respond_to?(:stub_model) ? stub_model(klass, options[:stub]) : mock_model(klass, options[:stub]) - else - self.respond_to?(:stub_model) ? stub_model(klass) : mock_model(klass) - end - yield mocked if block_given? - self.assigns[args.first || "#{klass}".underscore] = mocked - end - - # Creates an array of mock_model instances in the manner of - # mock_and_assign. Accepts option[:size] which sets the size - # of the array (default is 3). - def mock_and_assign_collection(klass, *args) - options = args.extract_options! - return_me = Array.new(options[:size] || 3) do - mocked = if options[:stub] - self.respond_to?(:stub_model) ? stub_model(klass, options[:stub]) : mock_model(klass, options[:stub]) - else - self.respond_to?(:stub_model) ? stub_model(klass) : mock_model(klass) - end - yield mocked if block_given? - mocked - end - self.assigns[args.first || "#{klass}".tableize] = return_me - end - - private - def do_render - if @the_template - render @the_template - elsif File.exists?(File.join(RAILS_ROOT, "app/views", class_description_text)) - render class_description_text - else - error_message = "Cannot determine template for render. " - error_message << "Please define @the_template in the before block " - error_message << "or name your describe block so that it indicates the correct template." - raise NameError, error_message - end - end - - # These methods are designed to be used at the example group [read: "describe"] level - # to simplify and DRY up common expectations. Most of these methods are wrappers for - # matchers which can also be used on the example level [read: within an "it" block]. See - # LuckySneaks::ViewSpecHelpers for more information. - module ExampleGroupLevelMethods - include LuckySneaks::CommonSpecHelpers - - # Creates an expectation which calls submit_to on the response - # from rendering the template. See that method for more details. - # - # Note: This method takes a Proc to evaluate the route not simply a named route - # helper, which would be undefined in the scope of the example block. - def it_should_submit_to(hint = nil, &route) - if hint.nil? && route.respond_to?(:to_ruby) - hint = route.to_ruby.gsub(/(^proc \{)|(\}$)/, '').strip - end - it "should submit to #{(hint || route)}" do - do_render - response.should submit_to(instance_eval(&route)) - end - end - - # Negative version of it_should_submit_to. See that method for more - # details. - def it_should_not_submit_to(hint = nil, &route) - if hint.nil? && route.respond_to?(:to_ruby) - hint = route.to_ruby.gsub(/(^proc \{)|(\}$)/, '').strip - end - it "should not submit to #{(hint || route)}" do - do_render - response.should_not submit_to(instance_eval(&route)) - end - end - - # Creates an expectation that the template uses Rails' form_for to generate - # the proper form action and method to create or update the specified object. - # - # Note: This method takes a string or symbol representing the instance - # variable's name to create the expectation for form_for - # not an instance variable, which would be nil in the scope of the example block. - # If you use namespacing for your form_for, you'll have to manually write out - # a similar spec. - def it_should_have_form_for(name, options = {}) - it "should have a form_for(@#{name})" do - if options.empty? - template.should_receive(:form_for).with(instance_for(name)) - else - template.should_receive(:form_for).with(instance_for(name), hash_including(options)) - end - do_render - end - end - - # Negative version of it_should_have_form_for. See that method for more - # details. - def it_should_not_have_form_for(name, options = {}) - it "should not have a form_for(@#{name})" do - if options.empty? - template.should_not_receive(:form_for).with(instance_for(name)) - else - template.should_not_receive(:form_for).with(instance_for(name), hash_including(options)) - end - do_render - end - end - - # Creates an expectation which calls allow_editing on the rendered - # template for each attribute specified. See the docs for allow_editing - # for more details. - # - # Note: This method takes a string or symbol representing the instance - # variable's name to send to allow_editing - # not an instance variable, which would be nil in the scope of the example block. - def it_should_allow_editing(instance_name, *attributes) - attributes.flatten! - attributes.each do |attribute| - it "should allow editing of @#{instance_name}##{attribute}" do - do_render - response.should allow_editing(instance_for(instance_name), attribute) - end - end - end - - # Negative version of it_should_allow_editing. See that method for more - # details. - def it_should_not_allow_editing(instance_name, *attributes) - attributes.flatten! - attributes.each do |attribute| - it "should not allow editing of @#{instance_name}##{attribute}" do - do_render - response.should_not allow_editing(instance_for(instance_name), attribute) - end - end - end - - # Creates an expectation which calls allow_uploading on the rendered - # template for each attribute specified. See the docs for allow_uploading - # for more details. - # - # Note: This method takes a string or symbol representing the instance - # variable's name to send to allow_uploading - # not an instance variable, which would be nil in the scope of the example block. - def it_should_allow_uploading(instance_name, *attributes) - attributes.flatten! - attributes.each do |attribute| - it "should allow editing of @#{instance_name}##{attribute}" do - do_render - response.should allow_uploading(instance_for(instance_name), attribute) - end - end - end - - # Negative version of it_should_allow_uploading. See that method for more - # details. - def it_should_not_allow_uploading(instance_name, *attributes) - attributes.flatten! - attributes.each do |attribute| - it "should not allow editing of @#{instance_name}##{attribute}" do - do_render - response.should_not allow_uploading(instance_for(instance_name), attribute) - end - end - end - - # Creates an expectation that the rendered template contains a FORM element - # (INPUT, TEXTAREA, or SELECT) with the specified name. - def it_should_have_form_element_for(name) - it "should have a form element named '#{name}'" do - do_render - response.should have_tag( - "form input[name='#{name}'], - form textarea[name='#{name}'], - form select[name='#{name}']" - ) - end - end - - # Negative version of it_should_have_form_element_for. See that method - # for more details. - def it_should_not_have_form_element_for(name) - it "should not have a form element named '#{name}'" do - do_render - response.should_not have_tag( - "form input[name='#{name}'], - form textarea[name='#{name}'], - form select[name='#{name}']" - ) - end - end - - # Creates an expectation which calls have_link_or_button_to on the response - # from rendering the template. See that method for more details. - # - # Note: This method takes a block to evaluate the route in the example context - # instead of the example group context. - def it_should_link_to(hint = nil, &route) - if hint.nil? && route.respond_to?(:to_ruby) - hint = route.to_ruby.gsub(/(^proc \{)|(\}$)/, '').strip - end - it "should have a link/button to #{(hint || route)}" do - do_render - response.should have_link_or_button_to(instance_eval(&route)) - end - end - alias it_should_have_link_to it_should_link_to - alias it_should_have_button_to it_should_link_to - alias it_should_have_button_or_link_to it_should_link_to - - # Negative version of it_should_link_to. See that method - # for more details. - def it_should_not_link_to(hint = nil, &route) - if hint.nil? && route.respond_to?(:to_ruby) - hint = route.to_ruby.gsub(/(^proc \{)|(\}$)/, '').strip - end - it "should have a link/button to #{(hint || route)}" do - do_render - response.should_not have_link_or_button_to(instance_eval(&route)) - end - end - alias it_should_not_have_link_to it_should_not_link_to - alias it_should_not_have_button_to it_should_not_link_to - alias it_should_not_have_button_or_link_to it_should_not_link_to - - # Creates an expectation which calls have_link_or_button_to_new on the response - # from rendering the template. See that method for more details. - # - # Note: This method may takes a string or symbol representing the model's name - # to send to have_link_or_button_to_show or the model's name itself. - def it_should_link_to_new(name) - it "should have a link/button to create a new #{name}" do - do_render - response.should have_link_or_button_to_new(name) - end - end - alias it_should_have_link_to_new it_should_link_to_new - alias it_should_have_button_to_new it_should_link_to_new - alias it_should_have_button_or_link_to_new it_should_link_to_new - - # Negative version of it_should_link_to_show. See that method - # for more details. - def it_should_not_link_to_new(name) - it "should have a link/button to create a new #{name}" do - do_render - response.should_not have_link_or_button_to_new(name) - end - end - alias it_should_not_have_link_to_new it_should_not_link_to_new - alias it_should_not_have_button_to_new it_should_not_link_to_new - alias it_should_not_have_button_or_link_to_new it_should_not_link_to_new - - # Creates an expectation which calls have_link_or_button_to_show on the response - # from rendering the template. See that method for more details. - # - # Note: This method takes a string or symbol representing the instance - # variable's name to send to have_link_or_button_to_show - # not an instance variable, which would be nil in the scope of the example block. - def it_should_link_to_show(name) - it "should have a link/button to show @#{name}" do - do_render - response.should have_link_or_button_to_show(instance_for(name)) - end - end - alias it_should_have_link_to_show it_should_link_to_show - alias it_should_have_button_to_show it_should_link_to_show - alias it_should_have_button_or_link_to_show it_should_link_to_show - - # Negative version of it_should_link_to_show. See that method - # for more details. - def it_should_not_link_to_show(name) - it "should have a link/button to show @#{name}" do - do_render - response.should_not have_link_or_button_to_show(instance_for(name)) - end - end - alias it_should_not_have_link_to_show it_should_not_link_to_show - alias it_should_not_have_button_to_show it_should_not_link_to_show - alias it_should_not_have_button_or_link_to_show it_should_not_link_to_show - - # Creates an expectation which calls have_link_or_button_to_show - # for each member of the instance variable matching the specified name - # on the response from rendering the template. See that method for more details. - # - # Note: This method takes a string or symbol representing the instance - # variable's name and not an instance variable, which would be nil - # in the scope of the example block. - def it_should_link_to_show_each(name) - it "should have a link/button to show each member of @#{name}" do - do_render - instance_for(name).each do |member| - response.should have_link_or_button_to_show(member) - end - end - end - alias it_should_have_link_to_show_each it_should_link_to_show_each - alias it_should_have_button_to_show_each it_should_link_to_show_each - alias it_should_have_button_or_link_to_show_each it_should_link_to_show_each - - # Creates an expectation which calls have_link_or_button_to_edit on the response - # from rendering the template. See that method for more details. - # - # Note: This method takes a string or symbol representing the instance - # variable's name to send to have_link_or_button_to_edit - # not an instance variable, which would be nil in the scope of the example block. - def it_should_link_to_edit(name) - it "should have a link/button to edit @#{name}" do - do_render - response.should have_link_or_button_to_edit(instance_for(name)) - end - end - alias it_should_have_link_to_edit it_should_link_to_edit - alias it_should_have_button_to_edit it_should_link_to_edit - alias it_should_have_button_or_link_to_edit it_should_link_to_edit - - # Negative version of it_should_link_to_edit. See that method - # for more details. - def it_should_not_link_to_edit(name) - it "should have a link/button to edit @#{name}" do - do_render - response.should_not have_link_or_button_to_edit(instance_for(name)) - end - end - alias it_should_not_have_link_to_edit it_should_not_link_to_edit - alias it_should_not_have_button_to_edit it_should_not_link_to_edit - alias it_should_not_have_button_or_link_to_edit it_should_not_link_to_edit - - - # Creates an expectation which calls have_link_or_button_to_edit - # for each member of the instance variable matching the specified name - # on the response from rendering the template. See that method for more details. - # - # Note: This method takes a string or symbol representing the instance - # variable's name and not an instance variable, which would be nil - # in the scope of the example block. - def it_should_link_to_edit_each(name) - it "should have a link/button to edit each member of @#{name}" do - do_render - instance_for(name).each do |member| - response.should have_link_or_button_to_edit(member) - end - end - end - alias it_should_have_link_to_edit_each it_should_link_to_edit_each - alias it_should_have_button_to_edit_each it_should_link_to_edit_each - alias it_should_have_button_or_link_to_edit_each it_should_link_to_edit_each - - # Creates an expectation which calls have_link_or_button_to_delete on the response - # from rendering the template. See that method for more details. - # - # Note: This method takes a string or symbol representing the instance - # variable's name to send to have_link_or_button_to_delete - # not an instance variable, which would be nil in the scope of the example block. - def it_should_link_to_delete(name) - it "should have a link/button to delete @#{name}" do - do_render - response.should have_button_to_delete(instance_for(name)) - end - end - alias it_should_have_link_to_delete it_should_link_to_delete - alias it_should_have_button_to_delete it_should_link_to_delete - alias it_should_have_button_or_link_to_delete it_should_link_to_delete - - # Negative version of it_should_link_to_delete. See that method - # for more details. - def it_should_not_link_to_delete(name) - it "should not have a link/button to delete @#{name}" do - do_render - response.should_not have_button_to_delete(instance_for(name)) - end - end - alias it_should_not_have_link_to_delete it_should_not_link_to_delete - alias it_should_not_have_button_to_delete it_should_not_link_to_delete - alias it_should_not_have_button_or_link_to_delete it_should_not_link_to_delete - - # Creates an expectation which calls have_link_or_button_to_delete - # for each member of the instance variable matching the specified name - # on the response from rendering the template. See that method for more details. - # - # Note: This method takes a string or symbol representing the instance - # variable's name and not an instance variable, which would be nil - # in the scope of the example block. - def it_should_link_to_delete_each(name) - it "should have a link/button to delete each member of @#{name}" do - do_render - instance_for(name).each do |member| - response.should have_button_to_delete(member) - end - end - end - alias it_should_have_link_to_delete_each it_should_link_to_delete_each - alias it_should_have_button_to_delete_each it_should_link_to_delete_each - alias it_should_have_button_or_link_to_delete_each it_should_link_to_delete_each - - # Creates an expectation that the template should call render :partial - # with the specified template. - def it_should_render_partial(name) - it "should render :partial => '#{name}'" do - template.should_receive(:render).with(hash_including(:partial => name)) - do_render - end - end - - # Negative version of it_should_render_partial. See that method - # for more details. - def it_should_not_render_partial(name) - it "should not render :partial => '#{name}'" do - template.should_not_receive(:render).with(hash_including(:partial => name)) - do_render - end - end - - # Sets @the_template (for use in do_render) using the current - # example group description. Example: - # - # describe "users/index.haml.erb" do - # use_describe_for_template! - # # ... - # end - # - # This is equivalent to setting @the_template = "users/index.haml.erb" - # in a before block. - def use_describe_for_template! - template = self_description_text - if File.exists?(File.join(RAILS_ROOT, "app/views", template)) - before(:each) do - @the_template = template - end - else - error_message = "You called use_describe_for_template! " - error_message << "but 'app/views/#{template}' does not exist. " - raise NameError, error_message - end - end - end - end -end diff --git a/vendor/plugins/skinny_spec/lib/lucky_sneaks/view_stub_helpers.rb b/vendor/plugins/skinny_spec/lib/lucky_sneaks/view_stub_helpers.rb deleted file mode 100644 index 2dde384e..00000000 --- a/vendor/plugins/skinny_spec/lib/lucky_sneaks/view_stub_helpers.rb +++ /dev/null @@ -1,15 +0,0 @@ -$:.unshift File.join(File.dirname(__FILE__), "..") -require "skinny_spec" - -module LuckySneaks - # These methods are designed to be used in your example before blocks to accomplish - # a whole lot of functionality with just a tiny bit of effort. - module ViewStubHelpers - # Shorthand for the following stub: - # - # template.stub!(:render).with(hash_including(:partial => anything)) - def stub_partial_rendering! - template.stub!(:render).with(hash_including(:partial => anything)) - end - end -end \ No newline at end of file diff --git a/vendor/plugins/skinny_spec/lib/skinny_spec.rb b/vendor/plugins/skinny_spec/lib/skinny_spec.rb deleted file mode 100644 index 3c366ce1..00000000 --- a/vendor/plugins/skinny_spec/lib/skinny_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -# Let's make sure everyone else is loaded -require File.expand_path(RAILS_ROOT + "/config/environment") -require 'spec' -require 'spec/rails' -begin - require 'ruby2ruby' -rescue LoadError - puts "-----" - puts "Attention: skinny_spec requires ruby2ruby for nicer route descriptions" - puts "It is highly recommended that you install it: sudo gem install ruby2ruby" - puts "-----" -end - -# Let's load our family now -require "lucky_sneaks/common_spec_helpers" -require "lucky_sneaks/controller_request_helpers" -require "lucky_sneaks/controller_spec_helpers" -require "lucky_sneaks/controller_stub_helpers" -require "lucky_sneaks/model_spec_helpers" -require "lucky_sneaks/view_spec_helpers" - -# Let's all come together -Spec::Rails::Example::ViewExampleGroup.send :include, LuckySneaks::ViewSpecHelpers -Spec::Rails::Example::HelperExampleGroup.send :include, LuckySneaks::CommonSpecHelpers -Spec::Rails::Example::ControllerExampleGroup.send :include, LuckySneaks::ControllerSpecHelpers -Spec::Rails::Example::ModelExampleGroup.send :include, LuckySneaks::ModelSpecHelpers \ No newline at end of file diff --git a/vendor/plugins/swf_fu/CHANGELOG.rdoc b/vendor/plugins/swf_fu/CHANGELOG.rdoc deleted file mode 100644 index 7b99496e..00000000 --- a/vendor/plugins/swf_fu/CHANGELOG.rdoc +++ /dev/null @@ -1,46 +0,0 @@ -= swf_fu --- History - -== Version 1.4.0 - May 8, 2010 - -* Any option can be a block, in which case it is called (with the source swf passed as argument) - -== Version 1.3.1 - February 5, 2010 - -* Improved compatibility with Rails 3.0: swf_tag now outputs html_safe content. - -* Got rid of deprecation warning in Rails 2.2+ when using swf_tag in block form. - -== Version 1.3.0 - June 20, 2009 - -* Updated to swf_object v2.2. Change should not be noticeable to users, except compatibility improvements and better auto install. Added the option +switch_off_auto_hide_show+. - -== Version 1.2.0 - January 14, 2009 - -* flashvars[:id] will now default to the DOM id of the object. I didn't want to have any extra defaults than the very basic ones, but there is no easy way to get this from Flash (see http://www.actionscript.org/forums/showthread.php3?t=136044 ) and no easy way to specify that using +swf_default_options+. -* If flashvars is a string (e.g. "myVar=myValue") it will be parsed into a hash so that the behaviour for default values apply to strings or hashes. swf_default_options[:flashvars] can also be a string and will also be parsed before being merged. -* Small bug fix: the options passed as hashes (:flashvars, :parameters and :html_options) were changed if swf_default_options[:flashvars, ...] existed. They are now left unchanged. - -== Version 1.1.0 - January 3, 2009 - -* Improved the way to specify alternate content - -== Version 1.0.3 - January 3, 2009 - -* Improved javascript initialization - - :initialize => [1, 2, 3] # produces in javascript: obj.initialize(1,2,3) instead of ([1,2,3]) - # no :initialize produces in javascript: obj.initialize() instead of (null) - :initialize => nil # stil produces obj.initialize(null) - -== Version 1.0.2 - January 3, 2009 - -* Bug fix for flashvars in dynamic method - -== Version 1.0.1 - January 2, 2009 - -* File reorganization -* Bug fix for default options - -== Version 1.0 - X-mas, 2008 - -=== Initial release. diff --git a/vendor/plugins/swf_fu/FLASH_OBJECT.rdoc b/vendor/plugins/swf_fu/FLASH_OBJECT.rdoc deleted file mode 100644 index 87a0e72f..00000000 --- a/vendor/plugins/swf_fu/FLASH_OBJECT.rdoc +++ /dev/null @@ -1,31 +0,0 @@ -== Compatibility with FlashObject - -This document is intended for users of FlashObject, a (much older) swf embedding plugin that inspired swf_fu. - -You can choose to: - -1) keep both. They won't interfere and +flashobject_tag+ will continue to use the older SWFObject 1.5 library. - -2) remove FlashObject: - - script/plugin remove flashobject_helper - -You can also manually remove javascripts/flashobject.js - -+swf_fu+ will take over the +flashobject_tag+ and will use the new SWFObject 2.2 library. -This should not have impacts as long as: -* your swf path is absolute (e.g. "/path/to/my_flash.swf"). If it is relative, move your swf file from 'public/' to the new 'public/swfs/' asset folder -* you include the default javascripts (otherwise you need to include 'swfobject' explicitely and stop including 'flashobject') -* you don't use the javascript object before the page is loaded. SWFObject 2.2 makes the changes to the web page later -* you don't rely on the +verify_file_exists+ option (it doesn't do anything anymore) - -In either case 1 or 2, you change existing calls to +flashobject_tag+ for +swf_tag+ at your leisure. -The interface is similar and the main differences are some options name changes: - :flash_id => :id - :variables => :flashvars - :background_color => options[:parameters][:bgcolor] - -Moreover, the following defaults are gone: - :flashvars[:lzproxied] - :parameters[:scale] - :parameters[:bgcolor] diff --git a/vendor/plugins/swf_fu/LICENSE b/vendor/plugins/swf_fu/LICENSE deleted file mode 100644 index efd683ff..00000000 --- a/vendor/plugins/swf_fu/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -# swf_fu plugin for rails -# Copyright (c) 2010, Marc-André Lafortune. -# All rights reserved. -# Inspired by FlashObject by Davide D'Agostino aka DAddYE (http://www.lipsiasoft.com) -# Uses SWFObject.js 2.1 (http://code.google.com/p/swfobject) -# -# Licensed under the terms of the (modified) BSD License below: -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of the nor the -# names of its contributors may be used to endorse or promote products -# derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY -# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY -# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/plugins/swf_fu/README.rdoc b/vendor/plugins/swf_fu/README.rdoc deleted file mode 100644 index 1791f1ff..00000000 --- a/vendor/plugins/swf_fu/README.rdoc +++ /dev/null @@ -1,92 +0,0 @@ -= +swf_fu+ - -With the +swf_fu+ plugin, rails treats your swf files like any other asset (images, javascripts, etc...). - -+swf_fu+ (pronounced "swif-fu", bonus joke for french speakers) uses SWFObject 2.2 to embed swf objects in HTML and supports all its options. -SWFObject 2 is such a nice library that Adobe now uses it as the official way to embed swf! -SWFObject's project can be found at http://code.google.com/p/swfobject - -+swf_fu+ has been tested with rails v2.0 up to v3.0b and has decent test coverage so rake test:plugins should reveal any incompatibility. Comments and pull requests welcome: http://github.com/marcandre/swf_fu - -== Install - -Assuming you have git[http://git-scm.com/] installed (check with git version), it is easy to install from your applications directory: - - rails plugin install git://github.com/marcandre/swf_fu.git # rails 3 - - script/plugin install git://github.com/marcandre/swf_fu.git # rails 2 (starting at 2.0.2) - -For older versions of +rails+ or without +git+, you can always download -+swf_fu+ from github[http://github.com/marcandre/swf_fu/archives/master] and then install it manually: - - rails plugin install ~/Download/swf_fu # rails 3 - - script/plugin install ~/Downloads/swf_fu # rails 2.x - -== Usage - -=== Embedding in HTML - -To embed a swf file, use +swf_tag+: - <%= swf_tag "i_like_flashing" %> - -Exactly like images and javascripts, +swf_tag+ will use +swf_path+ -to determine the path of the swf file; it will assume it is in /public/swfs/ -unless specified otherwise and it will add the ".swf" extension automatically. - -You can specify alternate content either with the options :alt => "Get Flash!" or you can use +swf_tag+ as a block: - - <% swf_tag "i_like_flashing" do %> - Get Flash - <% end %> - -=== Options - -* :id - the DOM +id+ of the flash +object+ element that is used to contain the Flash object; defaults to the name of the swf in +source+ -* :width, :height - the width & height of the Flash object. Defaults to "100%". These could also specified using :size -* :size - the size of the Flash object, in the form "400x300". -* :mode - Either :dynamic (default) or :static. Refer to SWFObject's doc[http://code.google.com/p/swfobject/wiki/documentation#Should_I_use_the_static_or_dynamic_publishing_method?] -* :flashvars - a Hash of variables that are passed to the swf. Can also be a string like "foo=bar&hello=world". Defaults to {:id => the DOM id} -* :parameters - a Hash of configuration parameters for the swf. See Adobe's doc[http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_12701#optional] -* :html_options - a Hash of extra html options for the object tag. -* :alt - HTML text that is displayed when the Flash player is not available. Defaults to a "Get Flash" image pointing to Adobe Flash's installation page. This can also be specified as a block (see embedding section). In Rails 3, this text is _assumed_ to be HTML, so there is no need to call +html_safe+ on it. -* :flash_version - the version of the Flash player that is required (e.g. "7" (default) or "8.1.0") -* :auto_install - a swf file that will upgrade flash player if needed (defaults to "expressInstall" which was installed by +swf_fu+) -* :javascript_class - specify a javascript class (e.g. "MyFlash") for your flash object. If it exists, the initialize method will be called. -* :initialize - arguments to pass to the initialization method of your javascript class. -* :div_id - the DOM +id+ of the containing div itself. Defaults to "#{option[:id]}_div" -* :switch_off_auto_hide_show - switch off SWFObject's default hide/show behavior. SWFObject temporarily hides your SWF or alternative content until the library has decided which content to display. Defaults to nil. - -You can override these default options with a global setting: - - ActionView::Base.swf_default_options = {:mode => :static} # All swf_tag will use the static mode by default - -Any of these options can be a +Proc+, in which case it will be called each time swf_tag is called. - -For example, the following will generate unique IDs: - - my_swf_counter = 0 - ActionView::Base.swf_default_options[:id] = Proc.new{"swf_unique_id_#{my_swf_counter+=1}"} - -=== Javascript - -+swf_fu+ will add 'swfobject' to the list of default javascript files. If you don't include -the default javascripts, a simple javascript_include "swfobject" is needed. - -=== swf_path - -+swf_tag+ implements and relies on +swf_path+ which behaves in a similar fashion to +image_path+, +javascript_path+, etc...: - - swf_path("example") => "/swfs/example.swf" - swf_path("example.swf") => "/swfs/example.swf" - swf_path("fonts/optima") => "/swfs/fonts/optima.swf" - swf_path("/fonts/optima") => "/fonts/optima.swf" - swf_path("http://www.example.com/game.swf") => "http://www.example.com/game.swf" - -It takes into account the global setting +asset_host+, like any other asset: - - ActionController::Base.asset_host = "http://assets.example.com" - image_path("logo.jpg") => "http://assets.example.com/images/logo.jpg" - swf_path("fonts/optima") => "http://assets.example.com/swfs/fonts/optima.swf"" - -Copyright (c) 2010 Marc-André Lafortune, released under the BSD license diff --git a/vendor/plugins/swf_fu/Rakefile b/vendor/plugins/swf_fu/Rakefile deleted file mode 100644 index 9898dadb..00000000 --- a/vendor/plugins/swf_fu/Rakefile +++ /dev/null @@ -1,22 +0,0 @@ -require 'rake' -require 'rake/testtask' -require 'rake/rdoctask' - -desc 'Default: run unit tests.' -task :default => :test - -desc 'Test the swf_fu plugin.' -Rake::TestTask.new(:test) do |t| - t.libs << 'lib' - t.pattern = 'test/**/*_test.rb' - t.verbose = true -end - -desc 'Generate documentation for the swf_fu plugin.' -Rake::RDocTask.new(:rdoc) do |rdoc| - rdoc.rdoc_dir = 'rdoc' - rdoc.title = 'Swf Fu' - rdoc.options << '--line-numbers' << '--inline-source' << '-m README.rdoc' - rdoc.rdoc_files.include('*.rdoc') - rdoc.rdoc_files.include('lib/**/*.rb') -end diff --git a/vendor/plugins/swf_fu/assets/javascripts/swfobject.js b/vendor/plugins/swf_fu/assets/javascripts/swfobject.js deleted file mode 100644 index 8eafe9dd..00000000 --- a/vendor/plugins/swf_fu/assets/javascripts/swfobject.js +++ /dev/null @@ -1,4 +0,0 @@ -/* SWFObject v2.2 - is released under the MIT License -*/ -var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y0){for(var af=0;af0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad'}}aa.outerHTML='"+af+"";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;abM9VaMwSB_o5%t)!o>)g&X)EAYjgEPLcl5K%kkuIK}@4lZ{BkGMYAU20z( zNRb@8AZ~RNT{i-oQ>63S3q@bamddC&V#&}IBHXmBea0RPhMY!G_6yWA-{&u00bI?EPCUrE(n7GhyT+_4sC3vIfO8o*Hw?~a z;QV28jGXsc=C?Kce^ve?K|~w@>bMSCq>Q(O#T42y^Mv*pwUSN?9aMQms*Ld$rD0~q zQhI{Tv*fb=mqG|Gjsr39Bp7Dejr)q)1J&t=YBY?2Llv85=!N{vRx3=YEoRTjX+)n# zs ["swfobject"] -rescue NoMethodError # I think this might fail in Rails 2.1.x - ActionView::Helpers::AssetTagHelper.register_javascript_include_default 'swfobject' -end diff --git a/vendor/plugins/swf_fu/install.rb b/vendor/plugins/swf_fu/install.rb deleted file mode 100644 index fda481b0..00000000 --- a/vendor/plugins/swf_fu/install.rb +++ /dev/null @@ -1,24 +0,0 @@ -require "fileutils" - -# Some paths -src = File.dirname(__FILE__)+"/assets" -dest = File.dirname(__FILE__)+"/../../../public" - -filename = "#{dest}/javascripts/swfobject.js" -unless File.exist?(filename) - FileUtils.cp "#{src}/javascripts/swfobject.js", filename - puts "Copying 'swfobject.js'" -end - -unless File.exist?("#{dest}/swfs/") - FileUtils.mkdir "#{dest}/swfs/" - puts "Creating new 'swfs' directory for swf assets" -end - -filename = "#{dest}/swfs/expressInstall.swf" -unless File.exist?(filename) - FileUtils.cp "#{src}/swfs/expressInstall.swf", filename - puts "Copying 'expressInstall.swf', the default flash auto-installer." -end - -puts "Installation done." diff --git a/vendor/plugins/swf_fu/lib/action_view/helpers/asset_tag_helper/swf_asset.rb b/vendor/plugins/swf_fu/lib/action_view/helpers/asset_tag_helper/swf_asset.rb deleted file mode 100644 index 2fe6e5bd..00000000 --- a/vendor/plugins/swf_fu/lib/action_view/helpers/asset_tag_helper/swf_asset.rb +++ /dev/null @@ -1,61 +0,0 @@ -module ActionView #:nodoc: - - # ActionView::Base.swf_default_options is a hash that - # will be used to specify defaults in priority to the standard - # defaults. - class Base - @@swf_default_options = {} - cattr_accessor :swf_default_options - end - - module Helpers # :nodoc: - module AssetTagHelper - - # Computes the path to an swf asset in the public 'swfs' directory. - # Full paths from the document root will be passed through. - # Used internally by +swf_tag+ to build the swf path. - # - # ==== Examples - # swf_path("example") # => /swfs/example.swf - # swf_path("example.swf") # => /swfs/example.swf - # swf_path("fonts/optima") # => /swfs/fonts/optima.swf - # swf_path("/fonts/optima") # => /fonts/optima.swf - # swf_path("http://www.example.com/game.swf") # => http://www.example.com/game.swf - # - # It takes into account the global setting +asset_host+, like any other asset: - # - # ActionController::Base.asset_host = "http://assets.example.com" - # image_path("logo.jpg") # => http://assets.example.com/images/logo.jpg - # swf_path("fonts/optima") # => http://assets.example.com/swfs/fonts/optima.swf - # - def swf_path(source) - if defined? SwfTag - SwfTag.new(self, @controller, source).public_path - else - compute_public_path(source, SwfAsset::DIRECTORY, SwfAsset::EXTENSION) - end - end - alias_method :path_to_swf, :swf_path # aliased to avoid conflicts with a swf_path named route - - private - module SwfAsset # :nodoc: - DIRECTORY = 'swfs'.freeze - EXTENSION = 'swf'.freeze - - def directory - DIRECTORY - end - - def extension - EXTENSION - end - end - - # AssetTag is available since 2.1.1 (http://github.com/rails/rails/commit/900fd6eca9dd97d2341e89bcb27d7a82d62965bf ) - class SwfTag < AssetTag # :nodoc: - include SwfAsset - end if defined? AssetTag - end - end -end - diff --git a/vendor/plugins/swf_fu/lib/action_view/helpers/swf_fu_helper.rb b/vendor/plugins/swf_fu/lib/action_view/helpers/swf_fu_helper.rb deleted file mode 100644 index 3c05807c..00000000 --- a/vendor/plugins/swf_fu/lib/action_view/helpers/swf_fu_helper.rb +++ /dev/null @@ -1,197 +0,0 @@ -module ActionView #:nodoc: - module Helpers # :nodoc: - module SwfFuHelper - # Returns a set of tags that display a Flash object within an - # HTML page. - # - # Options: - # * :id - the DOM +id+ of the flash +object+ element that is used to contain the Flash object; defaults to the name of the swf in +source+ - # * :width, :height - the width & height of the Flash object. Defaults to "100%". These could also specified using :size - # * :size - the size of the Flash object, in the form "400x300". - # * :mode - Either :dynamic (default) or :static. Refer to SWFObject's doc[http://code.google.com/p/swfobject/wiki/documentation#Should_I_use_the_static_or_dynamic_publishing_method?] - # * :flashvars - a Hash of variables that are passed to the swf. Can also be a string like "foo=bar&hello=world" - # * :parameters - a Hash of configuration parameters for the swf. See Adobe's doc[http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_12701#optional] - # * :alt - HTML text that is displayed when the Flash player is not available. Defaults to a "Get Flash" image pointing to Adobe Flash's installation page. - # * :flash_version - the version of the Flash player that is required (e.g. "7" (default) or "8.1.0") - # * :auto_install - a swf file that will upgrade flash player if needed (defaults to "expressInstall" which was installed by swf_fu) - # * :javascript_class - specify a javascript class (e.g. "MyFlash") for your flash object. The initialize method will be called when the flash object is ready. - # * :initialize - arguments to pass to the initialization method of your javascript class. - # * :div_id - the DOM +id+ of the containing div itself. Defaults to "#{option[:id]}"_div - # - def swf_tag(source, options={}, &block) - Generator.new(source, options, self).generate(&block) - end - - # For compatibility with the older FlashObject. - # It modifies the given options before calling +swf_tag+. - # See FLASH_OBJECT.rdoc - def flashobject_tag_for_compatibility(source, options={}) - options = options.reverse_merge( - :auto_install => nil, - :parameters => {:scale => "noscale"}, - :variables => {:lzproxied => false}, - :flash_id => "flashcontent_#{rand(1_100)}", - :background_color => "#ffffff" - ) - { :variables => :flashvars, :flash_id => :id }.each{|from, to| options[to] ||= options.delete(from) } - options[:parameters][:bgcolor] ||= options.delete(:background_color) - swf_tag(source, options) - end - - alias_method :flashobject_tag, :flashobject_tag_for_compatibility unless defined? flashobject_tag - - private - DEFAULTS = { - :width => "100%", - :height => "100%", - :flash_version => 7, - :mode => :dynamic, - :auto_install => "expressInstall", - :alt => <<-"EOS".squeeze(" ").strip.freeze - - Get Adobe Flash player - - EOS - }.freeze - - class Generator # :nodoc: - VALID_MODES = [:static, :dynamic] - def initialize(source, options, view) - @view = view - @source = view.swf_path(source) - options = ActionView::Base.swf_default_options.merge(options) - options.each do |key, value| - options[key] = value.call(source) if value.respond_to?(:call) - end - [:html_options, :parameters, :flashvars].each do |k| - options[k] = convert_to_hash(options[k]).reverse_merge convert_to_hash(ActionView::Base.swf_default_options[k]) - end - options.reverse_merge!(DEFAULTS) - options[:id] ||= source.gsub(/^.*\//, '').gsub(/\.swf$/,'') - options[:id] = force_to_valid_id(options[:id]) - options[:div_id] ||= options[:id]+"_div" - options[:div_id] = force_to_valid_id(options[:div_id]) - options[:width], options[:height] = options[:size].scan(/^(\d*%?)x(\d*%?)$/).first if options[:size] - options[:auto_install] &&= @view.swf_path(options[:auto_install]) - options[:flashvars][:id] ||= options[:id] - @mode = options.delete(:mode) - @options = options - unless VALID_MODES.include? @mode - raise ArgumentError, "options[:mode] should be either #{VALID_MODES.join(' or ')}" - end - end - - def force_to_valid_id(id) - id = id.gsub /[^A-Za-z0-9\-_]/, "_" # HTML id can only contain these characters - id = "swf_" + id unless id =~ /^[A-Z]/i # HTML id must start with alpha - id - end - - def generate(&block) - if block_given? - @options[:alt] = @view.capture(&block) - if Rails::VERSION::STRING >= "3.0" - send(@mode) - elsif Rails::VERSION::STRING < "2.2" - @view.concat(send(@mode), block.binding) - else - @view.concat(send(@mode)) - end - else - send(@mode) - end - end - - private - CONCAT = ActiveSupport.const_defined?(:SafeBuffer) ? :safe_concat : :concat - def convert_to_hash(s) - case s - when Hash - s - when nil - {} - when String - s.split("&").inject({}) do |h, kvp| - key, value = kvp.split("=") - h[key.to_sym] = CGI::unescape(value) - h - end - else - raise ArgumentError, "#{s} should be a Hash, a String or nil" - end - end - - def convert_to_string(h) - h.map do |key_value| - key_value.map{|val| CGI::escape(val.to_s)}.join("=") - end.join("&") - end - - def static - param_list = @options[:parameters].map{|k,v| %() }.join("\n") - param_list += %(\n) unless @options[:flashvars].empty? - html_options = @options[:html_options].map{|k,v| %(#{k}="#{v}")}.join(" ") - r = @view.javascript_tag( - %(swfobject.registerObject("#{@options[:id]}_container", "#{@options[:flash_version]}", #{@options[:auto_install].to_json});) - ) - r.send CONCAT, <<-"EOS".strip -
        - - #{param_list} - - - #{param_list} - - #{@options[:alt]} - - - -
        - EOS - r << @view.javascript_tag(extend_js) if @options[:javascript_class] - r.send CONCAT, library_check - r - end - - def dynamic - @options[:html_options] = @options[:html_options].merge(:id => @options[:id]) - @options[:parameters] = @options[:parameters].dup # don't modify the original parameters - args = (([@source] + @options.values_at(:div_id,:width,:height,:flash_version)).map(&:to_s) + - @options.values_at(:auto_install,:flashvars,:parameters,:html_options) - ).map(&:to_json).join(",") - preambule = @options[:switch_off_auto_hide_show] ? "swfobject.switchOffAutoHideShow();" : "" - r = @view.javascript_tag(preambule + "swfobject.embedSWF(#{args})") - r.send CONCAT, <<-"EOS".strip -
        - #{@options[:alt]} -
        - EOS - r << @view.javascript_tag("swfobject.addDomLoadEvent(function(){#{extend_js}})") if @options[:javascript_class] - r.send CONCAT, library_check - r - end - - def extend_js - arglist = case - when @options[:initialize].instance_of?(Array) - @options[:initialize].map(&:to_json).join(",") - when @options.has_key?(:initialize) - @options[:initialize].to_json - else - "" - end - "Object.extend($('#{@options[:id]}'), #{@options[:javascript_class]}.prototype).initialize(#{arglist})" - end - - def library_check - return "" unless 'development' == ENV['RAILS_ENV'] - @view.javascript_tag(<<-"EOS") - if (typeof swfobject == 'undefined') { - document.getElementById('#{@options[:div_id]}').innerHTML = 'Warning: SWFObject.js was not loaded properly. Make sure you <%= javascript_include_tag :defaults %> or <%= javascript_include_tag :swfobject %>'; - } - EOS - end - end #class Generator - end - end -end diff --git a/vendor/plugins/swf_fu/test/results.rb b/vendor/plugins/swf_fu/test/results.rb deleted file mode 100644 index a7306b0d..00000000 --- a/vendor/plugins/swf_fu/test/results.rb +++ /dev/null @@ -1,42 +0,0 @@ -DYNAMIC_RESULT = <<'EOS' -
        - -Get Adobe Flash player - -
        -EOS - -STATIC_RESULT = <<'EOS' -
        - - - - - - - - - -Get Adobe Flash player - - - - -
        -EOS \ No newline at end of file diff --git a/vendor/plugins/swf_fu/test/swf_fu_test.rb b/vendor/plugins/swf_fu/test/swf_fu_test.rb deleted file mode 100644 index 64a2a8bf..00000000 --- a/vendor/plugins/swf_fu/test/swf_fu_test.rb +++ /dev/null @@ -1,159 +0,0 @@ -require File.expand_path(File.dirname(__FILE__)+'/test_helper') -require File.expand_path(File.dirname(__FILE__)+'/results') - -class SwfFuTest < ActionView::TestCase - def assert_same_stripped(expect, test) - expect, test = [expect, test].map{|s| s.split("\n").map(&:strip)} - same = expect & test - delta_expect, delta_test = [expect, test].map{|a| a-same} - STDOUT << "\n\n---- Actual result: ----\n" << test.join("\n") << "\n---------\n" unless delta_expect == delta_test - assert_equal delta_expect, delta_test - end - - context "swf_path" do - context "with no special asset host" do - should "deduce the extension" do - assert_equal swf_path("example.swf"), swf_path("example") - assert_starts_with "/swfs/example.swf", swf_path("example.swf") - end - - should "accept relative paths" do - assert_starts_with "/swfs/whatever/example.swf", swf_path("whatever/example.swf") - end - - should "leave full paths alone" do - ["/full/path.swf", "http://www.example.com/whatever.swf"].each do |p| - assert_starts_with p, swf_path(p) - end - end - end - - context "with custom asset host" do - HOST = "http://assets.example.com" - setup do - ActionController::Base.asset_host = HOST - end - - teardown do - ActionController::Base.asset_host = nil - end - - should "take it into account" do - assert_equal "#{HOST}/swfs/whatever.swf", swf_path("whatever") - end - end - end - - context "swf_tag" do - COMPLEX_OPTIONS = { :width => "456", :height => 123, - :flashvars => {:myVar => "value 1 > 2"}.freeze, - :javascript_class => "SomeClass", - :initialize => {:be => "good"}.freeze, - :parameters => {:play => true}.freeze - }.freeze - - should "understand size" do - assert_equal swf_tag("hello", :size => "123x456"), - swf_tag("hello", :width => 123, :height => "456") - end - - should "only accept valid modes" do - assert_raise(ArgumentError) { swf_tag("xyz", :mode => :xyz) } - end - - context "with custom defaults" do - setup do - test = {:flashvars=> {:xyz => "abc", :hello => "world"}.freeze, :mode => :static, :size => "400x300"}.freeze - @expect = swf_tag("test", test) - @expect_with_hello = swf_tag("test", :flashvars => {:xyz => "abc", :hello => "my friend"}, :mode => :static, :size => "400x300") - ActionView::Base.swf_default_options = test - end - - should "respect them" do - assert_equal @expect, swf_tag("test") - end - - should "merge suboptions" do - assert_equal @expect_with_hello, swf_tag("test", :flashvars => {:hello => "my friend"}.freeze) - end - - teardown { ActionView::Base.swf_default_options = {} } - end - - context "with proc options" do - should "call them" do - expect = swf_tag("test", :id => "generated_id_for_test") - assert_equal expect, swf_tag("test", :id => Proc.new{|arg| "generated_id_for_#{arg}"}) - end - - should "call global default's everytime" do - expect1 = swf_tag("test", :id => "call_number_1") - expect2 = swf_tag("test", :id => "call_number_2") - cnt = 0 - ActionView::Base.swf_default_options = { :id => Proc.new{ "call_number_#{cnt+=1}" }} - assert_equal expect1, swf_tag("test") - assert_equal expect2, swf_tag("test") - end - end - - context "with static mode" do - setup { ActionView::Base.swf_default_options = {:mode => :static} } - - should "deal with string flashvars" do - assert_equal swf_tag("hello", :flashvars => "xyz=abc", :mode => :static), - swf_tag("hello", :flashvars => {:xyz => "abc"}, :mode => :static) - end - - should "produce the expected code" do - assert_same_stripped STATIC_RESULT, swf_tag("mySwf", COMPLEX_OPTIONS.merge(:html_options => {:class => "lots"}.freeze).freeze) - end - - teardown { ActionView::Base.swf_default_options = {} } - end - - context "with dynamic mode" do - should "produce the expected code" do - assert_same_stripped DYNAMIC_RESULT, swf_tag("mySwf", COMPLEX_OPTIONS) - end - - end - - should "enforce HTML id validity" do - div_result = '
        ' - assert_match /#{div_result}/, swf_tag("123-456_ok$!+X") - obj_result = '"id":"swf_123-456_ok___X"' - assert_match /#{obj_result}/, swf_tag("123-456_ok$!+X") - end - - should "treat initialize arrays as list of parameters" do - assert_match 'initialize("hello","world")', swf_tag("mySwf", :initialize => ["hello", "world"], :javascript_class => "SomeClass") - end - - if ActiveSupport.const_defined?(:SafeBuffer) - should "be html safe" do - assert swf_tag("test").html_safe? - end - end - end - - context "flashobject_tag" do - should "be the same as swf_tag with different defaults" do - assert_same_stripped swf_tag("mySwf", - :auto_install => nil, - :parameters => {:scale => "noscale", :bgcolor => "#ffffff"}, - :flashvars => {:lzproxied => false}, - :id => "myFlash" - ), flashobject_tag("mySwf", :flash_id => "myFlash") - end - - should "be the same with custom settings" do - assert_same_stripped swf_tag("mySwf", - :auto_install => nil, - :parameters => {:scale => "noborder", :bgcolor => "#ffffff"}, - :flashvars => {:answer_is => 42}, - :id => "myFlash" - ), flashobject_tag("mySwf", :flash_id => "myFlash", :parameters => {:scale => "noborder"}, :variables => {:answer_is => 42}) - end - end -end - diff --git a/vendor/plugins/swf_fu/test/test_helper.rb b/vendor/plugins/swf_fu/test/test_helper.rb deleted file mode 100644 index 58d113f8..00000000 --- a/vendor/plugins/swf_fu/test/test_helper.rb +++ /dev/null @@ -1,20 +0,0 @@ -require 'test/unit' -require 'rubygems' -gem 'activesupport', '~> 2.3' -require 'active_support' -gem 'activerecord', '~> 2.3' -require 'active_record' -gem 'actionpack', '~> 2.3' -require 'active_support' -require 'action_view' -require 'action_controller' - -#require File.dirname(__FILE__)+'/../../../../config/environment.rb' -require 'action_view/test_case' -require "action_controller/test_process" -require 'shoulda' -require File.dirname(__FILE__) + '/../init' - -def assert_starts_with(start, what) - assert what.starts_with?(start), "#{what} does not start with #{start}" -end diff --git a/vendor/plugins/swf_fu/uninstall.rb b/vendor/plugins/swf_fu/uninstall.rb deleted file mode 100644 index bc3c1b57..00000000 --- a/vendor/plugins/swf_fu/uninstall.rb +++ /dev/null @@ -1,6 +0,0 @@ -require "fileutils" - -dest = File.dirname(__FILE__) + "/../../../public" -FileUtils.rm "#{dest}/javascripts/swfobject.js" rescue puts "Warning: swfobject.js could not be deleted" -FileUtils.rm "#{dest}/swfs/expressInstall.swf" rescue puts "Warning: expressInstall.swf could not be deleted" -Dir.rmdir "#{dest}/swfs/" rescue "don't worry if directory is not empty" \ No newline at end of file diff --git a/vendor/plugins/translate/MIT-LICENSE b/vendor/plugins/translate/MIT-LICENSE deleted file mode 100644 index 9376605b..00000000 --- a/vendor/plugins/translate/MIT-LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2009 [name of plugin creator] - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/plugins/translate/README b/vendor/plugins/translate/README deleted file mode 100644 index e2732dc9..00000000 --- a/vendor/plugins/translate/README +++ /dev/null @@ -1,63 +0,0 @@ -Translate -========= - -This plugin provides a web interface for translating Rails I18n texts (requires Rails 2.2 or higher) from one locale to another. The plugin has been tested only with the simple I18n backend that ships with Rails. I18n texts are read from and written to YAML files under config/locales. - -To translate to a new locale you need to add a YAML file for that locale that contains the locale as the top key and at least one translation. - -Please note that there are certain I18n keys that map to Array objects rather than strings and those are currently not dealt with by the translation UI. This means that Rails built in keys such as date.day_names need to be translated manually directly in the YAML file. - -To get the translation UI to write the YAML files in UTF8 you need to install the ya2yaml gem. - -The translation UI finds all I18n keys by extracting them from I18n lookups in your application source code. In addition it adds all :en and default locale keys from the I18n backend. - -- Updated: Each string in the UI now has an "Auto Translate" link which will send the original text to Google Translate and will input the returned translation into the form field for further clean up and review prior to saving. - - -Rake Tasks -========= - -In addition to the web UI this plugin adds the following rake tasks: - -translate:untranslated -translate:missing -translate:remove_obsolete_keys -translate:merge_keys -translate:google -translate:changed - -The missing task shows you any I18n keys in your code that do not have translations in the YAML file for your default locale, i.e. config/locales/sv.yml. - -The merge_keys task is supposed to be used in conjunction with Sven Fuch's Rails I18n TextMate bundle (http://github.com/svenfuchs/rails-i18n/tree/master). Texts and keys extracted with the TextMate bundle end up in the temporary file log/translations.yml. When you run the merge_keys rake task the keys are moved over to the corresponding I18n locale file, i.e. config/locales/sv.yml. The merge_keys task also checks for overwrites of existing keys by warning you that one of your extracted keys already exists with a different translation. - -The google task is used for auto translating from one locale to another using Google Translate. - -The changed rake task can show you between one YAML file to another which keys have had their texts changed. - -Installation -========= -Obtain the source with: - -./script/plugin install git://github.com/newsdesk/translate.git - -To mount the plugin, add the following to your config/routes.rb file: - -Translate::Routes.translation_ui(map) if RAILS_ENV != "production" - -Now visit /translate in your web browser to start translating. - -Dependencies -========= - -- Rails 2.2 or higher -- The ya2yaml gem if you want your YAML files written in UTF8 encoding. - -Authors -========= - -- Peter Marklund (programming) -- Joakim Westerlund (web design) - -Many thanks to http://newsdesk.se for sponsoring the development of this plugin. - -Copyright (c) 2009 Peter Marklund, released under the MIT license diff --git a/vendor/plugins/translate/Rakefile b/vendor/plugins/translate/Rakefile deleted file mode 100644 index 7e1954b7..00000000 --- a/vendor/plugins/translate/Rakefile +++ /dev/null @@ -1,11 +0,0 @@ -require 'rake' -require 'spec/rake/spectask' - -desc 'Default: run specs.' -task :default => :spec - -desc 'Run the specs' -Spec::Rake::SpecTask.new(:spec) do |t| - t.spec_opts = ['--colour --format progress --loadby mtime --reverse'] - t.spec_files = FileList['spec/**/*_spec.rb'] -end diff --git a/vendor/plugins/translate/init.rb b/vendor/plugins/translate/init.rb deleted file mode 100644 index 18707f83..00000000 --- a/vendor/plugins/translate/init.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'translate' - -# TODO: Use new method available_locales once Rails is upgraded, see: -# http://github.com/svenfuchs/i18n/commit/411f8fe7c8f3f89e9b6b921fa62ed66cb92f3af4 -def I18n.valid_locales - I18n.backend.send(:init_translations) unless I18n.backend.initialized? - backend.send(:translations).keys.reject { |locale| locale == :root } -end diff --git a/vendor/plugins/translate/lib/translate.rb b/vendor/plugins/translate/lib/translate.rb deleted file mode 100644 index 39629bf4..00000000 --- a/vendor/plugins/translate/lib/translate.rb +++ /dev/null @@ -1,8 +0,0 @@ -module Translate -end - -require File.join(File.dirname(__FILE__), "translate_controller") -require File.join(File.dirname(__FILE__), "translate_helper") -Dir[File.join(File.dirname(__FILE__), "translate", "*.rb")].each do |file| - require file -end diff --git a/vendor/plugins/translate/lib/translate/file.rb b/vendor/plugins/translate/lib/translate/file.rb deleted file mode 100644 index c8ae93b0..00000000 --- a/vendor/plugins/translate/lib/translate/file.rb +++ /dev/null @@ -1,35 +0,0 @@ -require 'fileutils' - -class Translate::File - attr_accessor :path - - def initialize(path) - self.path = path - end - - def write(keys) - FileUtils.mkdir_p File.dirname(path) - File.open(path, "w") do |file| - file.puts keys_to_yaml(Translate::File.deep_stringify_keys(keys)) - end - end - - def read - File.exists?(path) ? YAML::load(IO.read(path)) : {} - end - - # Stringifying keys for prettier YAML - def self.deep_stringify_keys(hash) - hash.inject({}) { |result, (key, value)| - value = deep_stringify_keys(value) if value.is_a? Hash - result[(key.to_s rescue key) || key] = value - result - } - end - - private - def keys_to_yaml(keys) - # Using ya2yaml, if available, for UTF8 support - keys.respond_to?(:ya2yaml) ? keys.ya2yaml(:escape_as_utf8 => true) : keys.to_yaml - end -end diff --git a/vendor/plugins/translate/lib/translate/keys.rb b/vendor/plugins/translate/lib/translate/keys.rb deleted file mode 100644 index 3bee3c41..00000000 --- a/vendor/plugins/translate/lib/translate/keys.rb +++ /dev/null @@ -1,152 +0,0 @@ -require 'pathname' - -class Translate::Keys - # Allows keys extracted from lookups in files to be cached - def self.files - @@files ||= Translate::Keys.new.files - end - - # Allows flushing of the files cache - def self.files=(files) - @@files = files - end - - def files - @files ||= extract_files - end - alias_method :to_hash, :files - - def keys - files.keys - end - alias_method :to_a, :keys - - def i18n_keys(locale) - I18n.backend.send(:init_translations) unless I18n.backend.initialized? - Translate::Keys.to_shallow_hash(I18n.backend.send(:translations)[locale.to_sym]).keys.sort - end - - def untranslated_keys - Translate::Keys.translated_locales.inject({}) do |missing, locale| - missing[locale] = i18n_keys(I18n.default_locale).map do |key| - I18n.backend.send(:lookup, locale, key).nil? ? key : nil - end.compact - missing - end - end - - def missing_keys - locale = I18n.default_locale; yaml_keys = {} - yaml_keys = Translate::Storage.file_paths(locale).inject({}) do |keys, path| - keys = keys.deep_merge(Translate::File.new(path).read[locale.to_s]) - end - files.reject { |key, file| self.class.contains_key?(yaml_keys, key) } - end - - def self.translated_locales - I18n.available_locales.reject { |locale| [:root, I18n.default_locale.to_sym].include?(locale) } - end - - # Checks if a nested hash contains the keys in dot separated I18n key. - # - # Example: - # - # hash = { - # :foo => { - # :bar => { - # :baz => 1 - # } - # } - # } - # - # contains_key?("foo", key) # => true - # contains_key?("foo.bar", key) # => true - # contains_key?("foo.bar.baz", key) # => true - # contains_key?("foo.bar.baz.bla", key) # => false - # - def self.contains_key?(hash, key) - keys = key.to_s.split(".") - return false if keys.empty? - !keys.inject(HashWithIndifferentAccess.new(hash)) do |memo, key| - memo.is_a?(Hash) ? memo.try(:[], key) : nil - end.nil? - end - - # Convert something like: - # - # { - # :pressrelease => { - # :label => { - # :one => "Pressmeddelande" - # } - # } - # } - # - # to: - # - # {'pressrelease.label.one' => "Pressmeddelande"} - # - def self.to_shallow_hash(hash) - hash.inject({}) do |shallow_hash, (key, value)| - if value.is_a?(Hash) - to_shallow_hash(value).each do |sub_key, sub_value| - shallow_hash[[key, sub_key].join(".")] = sub_value - end - else - shallow_hash[key.to_s] = value - end - shallow_hash - end - end - - # Convert something like: - # - # {'pressrelease.label.one' => "Pressmeddelande"} - # - # to: - # - # { - # :pressrelease => { - # :label => { - # :one => "Pressmeddelande" - # } - # } - # } - def self.to_deep_hash(hash) - hash.inject({}) do |deep_hash, (key, value)| - keys = key.to_s.split('.').reverse - leaf_key = keys.shift - key_hash = keys.inject({leaf_key.to_sym => value}) { |hash, key| {key.to_sym => hash} } - deep_merge!(deep_hash, key_hash) - deep_hash - end - end - - # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809 - def self.deep_merge!(hash1, hash2) - merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 } - hash1.merge!(hash2, &merger) - end - - private - - def extract_files - files_to_scan.inject(HashWithIndifferentAccess.new) do |files, file| - IO.read(file).scan(i18n_lookup_pattern).flatten.map(&:to_sym).each do |key| - files[key] ||= [] - path = Pathname.new(File.expand_path(file)).relative_path_from(Pathname.new(Rails.root)).to_s - files[key] << path if !files[key].include?(path) - end - files - end - end - - def i18n_lookup_pattern - /\b(?:I18n\.t|I18n\.translate|t)(?:\s|\():?'([a-z0-9_]+.[a-z0-9_.]+)'\)?/ - end - - def files_to_scan - Dir.glob(File.join(Translate::Storage.root_dir, "{app,config,lib}", "**","*.{rb,erb,rhtml}")) + - Dir.glob(File.join(Translate::Storage.root_dir, "public", "javascripts", "**","*.js")) - end -end diff --git a/vendor/plugins/translate/lib/translate/log.rb b/vendor/plugins/translate/lib/translate/log.rb deleted file mode 100644 index 9b5b3148..00000000 --- a/vendor/plugins/translate/lib/translate/log.rb +++ /dev/null @@ -1,35 +0,0 @@ -class Translate::Log - attr_accessor :from_locale, :to_locale, :keys - - def initialize(from_locale, to_locale, keys) - self.from_locale = from_locale - self.to_locale = to_locale - self.keys = keys - end - - def write_to_file - current_texts = File.exists?(file_path) ? file.read : {} - current_texts.merge!(from_texts) - file.write(current_texts) - end - - def read - file.read - end - - private - def file - @file ||= Translate::File.new(file_path) - end - - def from_texts - Translate::File.deep_stringify_keys(Translate::Keys.to_deep_hash(keys.inject({}) do |hash, key| - hash[key] = I18n.backend.send(:lookup, from_locale, key) - hash - end)) - end - - def file_path - File.join(Rails.root, "config", "locales", "log", "from_#{from_locale}_to_#{to_locale}.yml") - end -end diff --git a/vendor/plugins/translate/lib/translate/routes.rb b/vendor/plugins/translate/lib/translate/routes.rb deleted file mode 100644 index 8d02c869..00000000 --- a/vendor/plugins/translate/lib/translate/routes.rb +++ /dev/null @@ -1,11 +0,0 @@ -module Translate - class Routes - def self.translation_ui(map) - map.with_options(:controller => 'translate') do |t| - t.translate_list 'translate' - t.translate 'translate/translate', :action => 'translate' - t.translate_reload 'translate/reload', :action => 'reload' - end - end - end -end diff --git a/vendor/plugins/translate/lib/translate/storage.rb b/vendor/plugins/translate/lib/translate/storage.rb deleted file mode 100644 index 2b9a3858..00000000 --- a/vendor/plugins/translate/lib/translate/storage.rb +++ /dev/null @@ -1,28 +0,0 @@ -class Translate::Storage - attr_accessor :locale - - def initialize(locale) - self.locale = locale.to_sym - end - - def write_to_file - Translate::File.new(file_path).write(keys) - end - - def self.file_paths(locale) - Dir.glob(File.join(root_dir, "config", "locales", "**","#{locale}.yml")) - end - - def self.root_dir - Rails.root - end - - private - def keys - {locale => I18n.backend.send(:translations)[locale]} - end - - def file_path - File.join(Translate::Storage.root_dir, "config", "locales", "#{locale}.yml") - end -end diff --git a/vendor/plugins/translate/lib/translate_controller.rb b/vendor/plugins/translate/lib/translate_controller.rb deleted file mode 100644 index d06e171e..00000000 --- a/vendor/plugins/translate/lib/translate_controller.rb +++ /dev/null @@ -1,165 +0,0 @@ -class TranslateController < ActionController::Base - # It seems users with active_record_store may get a "no :secret given" error if we don't disable csrf protection, - skip_before_filter :verify_authenticity_token - - prepend_view_path(File.join(File.dirname(__FILE__), "..", "views")) - layout 'translate' - - before_filter :init_translations - before_filter :set_locale - - def index - initialize_keys - filter_by_key_pattern - filter_by_text_pattern - filter_by_translated_or_changed - sort_keys - paginate_keys - @total_entries = @keys.size - end - - def translate - I18n.backend.store_translations(@to_locale, Translate::Keys.to_deep_hash(params[:key])) - Translate::Storage.new(@to_locale).write_to_file - Translate::Log.new(@from_locale, @to_locale, params[:key].keys).write_to_file - force_init_translations # Force reload from YAML file - flash[:notice] = "Translations stored" - redirect_to params.slice(:filter, :sort_by, :key_type, :key_pattern, :text_type, :text_pattern).merge({:action => :index}) - end - - def reload - Translate::Keys.files = nil - redirect_to :action => 'index' - end - - private - def initialize_keys - @files = Translate::Keys.files - @keys = (@files.keys.map(&:to_s) + Translate::Keys.new.i18n_keys(@from_locale)).uniq - @keys.reject! do |key| - from_text = lookup(@from_locale, key) - # When translating from one language to another, make sure there is a text to translate from. - # Always exclude non string translation objects as we don't support editing them in the UI. - (@from_locale != @to_locale && !from_text.present?) || (from_text.present? && !from_text.is_a?(String)) - end - end - - def lookup(locale, key) - I18n.backend.send(:lookup, locale, key) - end - helper_method :lookup - - def filter_by_translated_or_changed - params[:filter] ||= 'all' - return if params[:filter] == 'all' - @keys.reject! do |key| - case params[:filter] - when 'untranslated' - lookup(@to_locale, key).present? - when 'translated' - lookup(@to_locale, key).blank? - when 'changed' - old_from_text(key).blank? || lookup(@from_locale, key) == old_from_text(key) - else - raise "Unknown filter '#{params[:filter]}'" - end - end - end - - def filter_by_key_pattern - return if params[:key_pattern].blank? - @keys.reject! do |key| - case params[:key_type] - when "starts_with" - !key.starts_with?(params[:key_pattern]) - when "contains" - key.index(params[:key_pattern]).nil? - else - raise "Unknown key_type '#{params[:key_type]}'" - end - end - end - - def filter_by_text_pattern - return if params[:text_pattern].blank? - @keys.reject! do |key| - case params[:text_type] - when 'contains' - !lookup(@from_locale, key).present? || !lookup(@from_locale, key).to_s.downcase.index(params[:text_pattern].downcase) - when 'equals' - !lookup(@from_locale, key).present? || lookup(@from_locale, key).to_s.downcase != params[:text_pattern].downcase - else - raise "Unknown text_type '#{params[:text_type]}'" - end - end - end - - def sort_keys - params[:sort_by] ||= "key" - case params[:sort_by] - when "key" - @keys.sort! - when "text" - @keys.sort! do |key1, key2| - if lookup(@from_locale, key1).present? && lookup(@from_locale, key2).present? - lookup(@from_locale, key1).to_s.downcase <=> lookup(@from_locale, key2).to_s.downcase - elsif lookup(@from_locale, key1).present? - -1 - else - 1 - end - end - else - raise "Unknown sort_by '#{params[:sort_by]}'" - end - end - - def paginate_keys - params[:page] ||= 1 - @paginated_keys = @keys[offset, per_page] - end - - def offset - (params[:page].to_i - 1) * per_page - end - - def per_page - 50 - end - helper_method :per_page - - def init_translations - I18n.backend.send(:init_translations) unless I18n.backend.initialized? - end - - def force_init_translations - I18n.backend.send(:init_translations) - end - - def default_locale - I18n.default_locale - end - - def set_locale - session[:from_locale] ||= default_locale - session[:to_locale] ||= :en - session[:from_locale] = params[:from_locale] if params[:from_locale].present? - session[:to_locale] = params[:to_locale] if params[:to_locale].present? - @from_locale = session[:from_locale].to_sym - @to_locale = session[:to_locale].to_sym - end - - def old_from_text(key) - return @old_from_text[key] if @old_from_text && @old_from_text[key] - @old_from_text = {} - text = key.split(".").inject(log_hash) do |hash, k| - hash ? hash[k] : nil - end - @old_from_text[key] = text - end - helper_method :old_from_text - - def log_hash - @log_hash ||= Translate::Log.new(@from_locale, @to_locale, {}).read - end -end diff --git a/vendor/plugins/translate/lib/translate_helper.rb b/vendor/plugins/translate/lib/translate_helper.rb deleted file mode 100644 index cb4c400f..00000000 --- a/vendor/plugins/translate/lib/translate_helper.rb +++ /dev/null @@ -1,45 +0,0 @@ -module TranslateHelper - def simple_filter(labels, param_name = 'filter', selected_value = nil) - selected_value ||= params[param_name] - filter = [] - labels.each do |item| - if item.is_a?(Array) - type, label = item - else - type = label = item - end - if type.to_s == selected_value.to_s - filter << "#{label}" - else - link_params = params.merge({param_name.to_s => type}) - link_params.merge!({"page" => nil}) if param_name.to_s != "page" - filter << link_to(label, link_params) - end - end - filter.join(" | ") - end - - def n_lines(text, line_size) - n_lines = 1 - if text.present? - n_lines = text.split("\n").size - if n_lines == 1 && text.length > line_size - n_lines = text.length / line_size + 1 - end - end - n_lines - end - - def translate_javascript_includes - sources = [] - if File.exists?(File.join(Rails.root, "public", "javascripts", "prototype.js")) - sources << "/javascripts/prototype.js" - else - sources << "http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js" - end - sources << "http://www.google.com/jsapi" - sources.map do |src| - %Q{} - end.join("\n") - end -end diff --git a/vendor/plugins/translate/spec/controllers/translate_controller_spec.rb b/vendor/plugins/translate/spec/controllers/translate_controller_spec.rb deleted file mode 100644 index e384811b..00000000 --- a/vendor/plugins/translate/spec/controllers/translate_controller_spec.rb +++ /dev/null @@ -1,129 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') - -describe TranslateController do - describe "index" do - before(:each) do - controller.stub!(:per_page).and_return(1) - I18n.backend.stub!(:translations).and_return(i18n_translations) - I18n.backend.instance_eval { @initialized = true } - keys = mock(:keys) - keys.stub!(:i18n_keys).and_return(['vendor.foobar']) - Translate::Keys.should_receive(:new).and_return(keys) - Translate::Keys.should_receive(:files).and_return(files) - I18n.stub!(:valid_locales).and_return([:en, :sv]) - I18n.stub!(:default_locale).and_return(:sv) - end - - it "shows sorted paginated keys from the translate from locale and extracted keys by default" do - get_page :index - assigns(:from_locale).should == :sv - assigns(:to_locale).should == :en - assigns(:files).should == files - assigns(:keys).sort.should == ['articles.new.page_title', 'home.page_title', 'vendor.foobar'] - assigns(:paginated_keys).should == ['articles.new.page_title'] - end - - it "can be paginated with the page param" do - get_page :index, :page => 2 - assigns(:files).should == files - assigns(:paginated_keys).should == ['home.page_title'] - end - - it "accepts a key_pattern param with key_type=starts_with" do - get_page :index, :key_pattern => 'articles', :key_type => 'starts_with' - assigns(:files).should == files - assigns(:paginated_keys).should == ['articles.new.page_title'] - assigns(:total_entries).should == 1 - end - - it "accepts a key_pattern param with key_type=contains" do - get_page :index, :key_pattern => 'page_', :key_type => 'contains' - assigns(:files).should == files - assigns(:total_entries).should == 2 - assigns(:paginated_keys).should == ['articles.new.page_title'] - end - - it "accepts a filter=untranslated param" do - get_page :index, :filter => 'untranslated' - assigns(:total_entries).should == 2 - assigns(:paginated_keys).should == ['articles.new.page_title'] - end - - it "accepts a filter=translated param" do - get_page :index, :filter => 'translated' - assigns(:total_entries).should == 1 - assigns(:paginated_keys).should == ['vendor.foobar'] - end - - it "accepts a filter=changed param" do - log = mock(:log) - old_translations = {:home => {:page_title => "Skapar ny artikel"}} - log.should_receive(:read).and_return(Translate::File.deep_stringify_keys(old_translations)) - Translate::Log.should_receive(:new).with(:sv, :en, {}).and_return(log) - get_page :index, :filter => 'changed' - assigns(:total_entries).should == 1 - assigns(:keys).should == ["home.page_title"] - end - - def i18n_translations - HashWithIndifferentAccess.new({ - :en => { - :vendor => { - :foobar => "Foo Baar" - } - }, - :sv => { - :articles => { - :new => { - :page_title => "Skapa ny artikel" - } - }, - :home => { - :page_title => "Välkommen till I18n" - }, - :vendor => { - :foobar => "Fobar" - } - } - }) - end - - def files - HashWithIndifferentAccess.new({ - :'home.page_title' => ["app/views/home/index.rhtml"], - :'general.back' => ["app/views/articles/new.rhtml", "app/views/categories/new.rhtml"], - :'articles.new.page_title' => ["app/views/articles/new.rhtml"] - }) - end - end - - describe "translate" do - it "should store translations to I18n backend and then write them to a YAML file" do - session[:from_locale] = :sv - session[:to_locale] = :en - translations = { - :articles => { - :new => { - :title => "New Article" - } - }, - :category => "Category" - } - key_param = {'articles.new.title' => "New Article", "category" => "Category"} - I18n.backend.should_receive(:store_translations).with(:en, translations) - storage = mock(:storage) - storage.should_receive(:write_to_file) - Translate::Storage.should_receive(:new).with(:en).and_return(storage) - log = mock(:log) - log.should_receive(:write_to_file) - Translate::Log.should_receive(:new).with(:sv, :en, key_param.keys).and_return(log) - post :translate, "key" => key_param - response.should be_redirect - end - end - - def get_page(*args) - get(*args) - response.should be_success - end -end diff --git a/vendor/plugins/translate/spec/file_spec.rb b/vendor/plugins/translate/spec/file_spec.rb deleted file mode 100644 index 5f94f5a9..00000000 --- a/vendor/plugins/translate/spec/file_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -require 'fileutils' -require File.dirname(__FILE__) + '/spec_helper' - -describe Translate::File do - describe "write" do - before(:each) do - @file = Translate::File.new(file_path) - end - - after(:each) do - FileUtils.rm(file_path) - end - - it "writes all I18n messages for a locale to YAML file" do - @file.write(translations) - @file.read.should == Translate::File.deep_stringify_keys(translations) - end - - def translations - { - :en => { - :article => { - :title => "One Article" - }, - :category => "Category" - } - } - end - end - - describe "deep_stringify_keys" do - it "should convert all keys in a hash to strings" do - Translate::File.deep_stringify_keys({ - :en => { - :article => { - :title => "One Article" - }, - :category => "Category" - } - }).should == { - "en" => { - "article" => { - "title" => "One Article" - }, - "category" => "Category" - } - } - end - end - - def file_path - File.join(File.dirname(__FILE__), "files", "en.yml") - end -end diff --git a/vendor/plugins/translate/spec/files/translate/app/models/article.rb b/vendor/plugins/translate/spec/files/translate/app/models/article.rb deleted file mode 100644 index d151e316..00000000 --- a/vendor/plugins/translate/spec/files/translate/app/models/article.rb +++ /dev/null @@ -1,12 +0,0 @@ -class Article < ActiveRecord::Base - def validate - # t('li') - errors.add_to_base([t(:'article.key1') + "#{t('article.key2')}"]) - I18n.t 'article.key3' - I18n.t 'article.key3' - I18n.t :'article.key4' - I18n.translate :'article.key5' - 'bla bla t' + "blubba bla" + ' foobar' - 'bla bla t ' + "blubba bla" + ' foobar' - end -end diff --git a/vendor/plugins/translate/spec/files/translate/app/views/category.erb b/vendor/plugins/translate/spec/files/translate/app/views/category.erb deleted file mode 100644 index 2146f874..00000000 --- a/vendor/plugins/translate/spec/files/translate/app/views/category.erb +++ /dev/null @@ -1 +0,0 @@ -<%= t(:'category_erb.key1') %> diff --git a/vendor/plugins/translate/spec/files/translate/app/views/category.html b/vendor/plugins/translate/spec/files/translate/app/views/category.html deleted file mode 100644 index 0947d174..00000000 --- a/vendor/plugins/translate/spec/files/translate/app/views/category.html +++ /dev/null @@ -1 +0,0 @@ -t(:'category_html.key1') diff --git a/vendor/plugins/translate/spec/files/translate/app/views/category.html.erb b/vendor/plugins/translate/spec/files/translate/app/views/category.html.erb deleted file mode 100644 index a226ccff..00000000 --- a/vendor/plugins/translate/spec/files/translate/app/views/category.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= t(:'category_html_erb.key1') %> diff --git a/vendor/plugins/translate/spec/files/translate/app/views/category.rhtml b/vendor/plugins/translate/spec/files/translate/app/views/category.rhtml deleted file mode 100644 index 235e5173..00000000 --- a/vendor/plugins/translate/spec/files/translate/app/views/category.rhtml +++ /dev/null @@ -1,5 +0,0 @@ - - -<%= t(:'category_rhtml.key1') %> diff --git a/vendor/plugins/translate/spec/files/translate/public/javascripts/application.js b/vendor/plugins/translate/spec/files/translate/public/javascripts/application.js deleted file mode 100644 index a673ca02..00000000 --- a/vendor/plugins/translate/spec/files/translate/public/javascripts/application.js +++ /dev/null @@ -1 +0,0 @@ -I18n.t('js.alert') \ No newline at end of file diff --git a/vendor/plugins/translate/spec/keys_spec.rb b/vendor/plugins/translate/spec/keys_spec.rb deleted file mode 100644 index 3b0bd629..00000000 --- a/vendor/plugins/translate/spec/keys_spec.rb +++ /dev/null @@ -1,179 +0,0 @@ -require File.dirname(__FILE__) + '/spec_helper' -require 'fileutils' - -describe Translate::Keys do - before(:each) do - I18n.stub!(:default_locale).and_return(:en) - @keys = Translate::Keys.new - Translate::Storage.stub!(:root_dir).and_return(i18n_files_dir) - end - - describe "to_a" do - it "extracts keys from I18n lookups in .rb, .html.erb, and .rhtml files" do - @keys.to_a.map(&:to_s).sort.should == ['article.key1', 'article.key2', 'article.key3', 'article.key4', 'article.key5', - 'category_erb.key1', 'category_html_erb.key1', 'category_rhtml.key1', 'js.alert'] - end - end - - describe "to_hash" do - it "return a hash with I18n keys and file lists" do - @keys.to_hash[:'article.key3'].should == ["vendor/plugins/translate/spec/files/translate/app/models/article.rb"] - end - end - - describe "i18n_keys" do - before(:each) do - I18n.backend.send(:init_translations) unless I18n.backend.initialized? - end - - it "should return all keys in the I18n backend translations hash" do - I18n.backend.should_receive(:translations).and_return(translations) - @keys.i18n_keys(:en).should == ['articles.new.page_title', 'categories.flash.created', 'empty', 'home.about'] - end - - describe "untranslated_keys" do - before(:each) do - I18n.backend.stub!(:translations).and_return(translations) - end - - it "should return a hash with keys with missing translations in each locale" do - @keys.untranslated_keys.should == { - :sv => ['articles.new.page_title', 'categories.flash.created', 'empty'] - } - end - end - - describe "missing_keys" do - before(:each) do - @file_path = File.join(i18n_files_dir, "config", "locales", "en.yml") - Translate::File.new(@file_path).write({ - :en => { - :home => { - :page_title => false, - :intro => { - :one => "intro one", - :other => "intro other" - } - } - } - }) - end - - after(:each) do - FileUtils.rm(@file_path) - end - - it "should return a hash with keys that are not in the locale file" do - @keys.stub!(:files).and_return({ - :'home.page_title' => "app/views/home/index.rhtml", - :'home.intro' => 'app/views/home/index.rhtml', - :'home.signup' => "app/views/home/_signup.rhtml", - :'about.index.page_title' => "app/views/about/index.rhtml" - }) - @keys.missing_keys.should == { - :'home.signup' => "app/views/home/_signup.rhtml", - :'about.index.page_title' => "app/views/about/index.rhtml" - } - end - end - - describe "contains_key?" do - it "works" do - hash = { - :foo => { - :bar => { - :baz => false - } - } - } - Translate::Keys.contains_key?(hash, "").should be_false - Translate::Keys.contains_key?(hash, "foo").should be_true - Translate::Keys.contains_key?(hash, "foo.bar").should be_true - Translate::Keys.contains_key?(hash, "foo.bar.baz").should be_true - Translate::Keys.contains_key?(hash, :"foo.bar.baz").should be_true - Translate::Keys.contains_key?(hash, "foo.bar.baz.bla").should be_false - end - end - - describe "translated_locales" do - before(:each) do - I18n.stub!(:default_locale).and_return(:en) - I18n.stub!(:available_locales).and_return([:sv, :no, :en, :root]) - end - - it "returns all avaiable except :root and the default" do - Translate::Keys.translated_locales.should == [:sv, :no] - end - end - - describe "to_deep_hash" do - it "convert shallow hash with dot separated keys to deep hash" do - Translate::Keys.to_deep_hash(shallow_hash).should == deep_hash - end - end - - describe "to_shallow_hash" do - it "converts a deep hash to a shallow one" do - Translate::Keys.to_shallow_hash(deep_hash).should == shallow_hash - end - end - - ########################################################################## - # - # Helper Methods - # - ########################################################################## - - def translations - { - :en => { - :home => { - :about => "This site is about making money" - }, - :articles => { - :new => { - :page_title => "New Article" - } - }, - :categories => { - :flash => { - :created => "Category created" - } - }, - :empty => nil - }, - :sv => { - :home => { - :about => false - } - } - } - end - end - - def shallow_hash - { - 'pressrelease.label.one' => "Pressmeddelande", - 'pressrelease.label.other' => "Pressmeddelanden", - 'article' => "Artikel", - 'category' => '' - } - end - - def deep_hash - { - :pressrelease => { - :label => { - :one => "Pressmeddelande", - :other => "Pressmeddelanden" - } - }, - :article => "Artikel", - :category => '' - } - end - - def i18n_files_dir - File.join(ENV['PWD'], "spec", "files", "translate") - end -end diff --git a/vendor/plugins/translate/spec/log_spec.rb b/vendor/plugins/translate/spec/log_spec.rb deleted file mode 100644 index 7dc9f542..00000000 --- a/vendor/plugins/translate/spec/log_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'fileutils' -require File.dirname(__FILE__) + '/spec_helper' - -describe Translate::Log do - describe "write_to_file" do - before(:each) do - I18n.locale = :sv - I18n.backend.store_translations(:sv, from_texts) - keys = Translate::Keys.new - @log = Translate::Log.new(:sv, :en, Translate::Keys.to_shallow_hash(from_texts).keys) - @log.stub!(:file_path).and_return(file_path) - FileUtils.rm_f file_path - end - - after(:each) do - FileUtils.rm_f file_path - end - - it "writes new log file with from texts" do - File.exists?(file_path).should be_false - @log.write_to_file - File.exists?(file_path).should be_true - Translate::File.new(file_path).read.should == Translate::File.deep_stringify_keys(from_texts) - end - - it "merges from texts with current texts in log file and re-writes the log file" do - @log.write_to_file - I18n.backend.store_translations(:sv, {:category => "Kategori ny"}) - @log.keys = ['category'] - @log.write_to_file - Translate::File.new(file_path).read['category'].should == "Kategori ny" - end - - def file_path - File.join(File.dirname(__FILE__), "files", "from_sv_to_en.yml") - end - - def from_texts - { - :article => { - :title => "En artikel" - }, - :category => "Kategori" - } - end - end -end diff --git a/vendor/plugins/translate/spec/spec_helper.rb b/vendor/plugins/translate/spec/spec_helper.rb deleted file mode 100644 index 5a919082..00000000 --- a/vendor/plugins/translate/spec/spec_helper.rb +++ /dev/null @@ -1,11 +0,0 @@ -begin - # Using PWD here instead of File.dirname(__FILE__) to be able to symlink to plugin - # from within a Rails app. - require File.expand_path(ENV['PWD'] + '/../../../spec/spec_helper') -rescue LoadError => e - puts "You need to install rspec in your base app\n#{e.message}: #{e.backtrace.join("\n")}" - exit -end - -plugin_spec_dir = File.dirname(__FILE__) -ActiveRecord::Base.logger = Logger.new(plugin_spec_dir + "/debug.log") diff --git a/vendor/plugins/translate/spec/storage_spec.rb b/vendor/plugins/translate/spec/storage_spec.rb deleted file mode 100644 index e6110c3d..00000000 --- a/vendor/plugins/translate/spec/storage_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -require File.dirname(__FILE__) + '/spec_helper' - -describe Translate::Storage do - describe "write_to_file" do - before(:each) do - @storage = Translate::Storage.new(:en) - end - - it "writes all I18n messages for a locale to YAML file" do - I18n.backend.should_receive(:translations).and_return(translations) - @storage.stub!(:file_path).and_return(file_path) - file = mock(:file) - file.should_receive(:write).with(translations) - Translate::File.should_receive(:new).with(file_path).and_return(file) - @storage.write_to_file - end - - def file_path - File.join(File.dirname(__FILE__), "files", "en.yml") - end - - def translations - { - :en => { - :article => { - :title => "One Article" - }, - :category => "Category" - } - } - end - end -end diff --git a/vendor/plugins/translate/tasks/translate.rake b/vendor/plugins/translate/tasks/translate.rake deleted file mode 100644 index a70b934c..00000000 --- a/vendor/plugins/translate/tasks/translate.rake +++ /dev/null @@ -1,178 +0,0 @@ -require 'yaml' - -class Hash - def deep_merge(other) - # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809 - merger = proc { |key, v1, v2| (Hash === v1 && Hash === v2) ? v1.merge(v2, &merger) : v2 } - merge(other, &merger) - end - - def set(keys, value) - key = keys.shift - if keys.empty? - self[key] = value - else - self[key] ||= {} - self[key].set keys, value - end - end - - if ENV['SORT'] - # copy of ruby's to_yaml method, prepending sort. - # before each so we get an ordered yaml file - def to_yaml( opts = {} ) - YAML::quick_emit( self, opts ) do |out| - out.map( taguri, to_yaml_style ) do |map| - sort.each do |k, v| #<- Adding sort. - map.add( k, v ) - end - end - end - end - end -end - -namespace :translate do - desc "Show untranslated keys for locale LOCALE" - task :untranslated => :environment do - from_locale = I18n.default_locale - untranslated = Translate::Keys.new.untranslated_keys - - messages = [] - untranslated.each do |locale, keys| - keys.each do |key| - from_text = I18n.backend.send(:lookup, from_locale, key) - messages << "#{locale}.#{key} (#{from_locale}.#{key}='#{from_text}')" - end - end - - if messages.present? - messages.each { |m| puts m } - else - puts "No untranslated keys" - end - end - - desc "Show I18n keys that are missing in the config/locales/default_locale.yml YAML file" - task :missing => :environment do - missing = Translate::Keys.new.missing_keys.inject([]) do |keys, (key, filename)| - keys << "#{key} in \t #{filename} is missing" - end - puts missing.present? ? missing.join("\n") : "No missing translations in the default locale file" - end - - desc "Remove all translation texts that are no longer present in the locale they were translated from" - task :remove_obsolete_keys => :environment do - I18n.backend.send(:init_translations) - master_locale = ENV['LOCALE'] || I18n.default_locale - Translate::Keys.translated_locales.each do |locale| - texts = {} - Translate::Keys.new.i18n_keys(locale).each do |key| - if I18n.backend.send(:lookup, master_locale, key).to_s.present? - texts[key] = I18n.backend.send(:lookup, locale, key) - end - end - I18n.backend.send(:translations)[locale] = nil # Clear out all current translations - I18n.backend.store_translations(locale, Translate::Keys.to_deep_hash(texts)) - Translate::Storage.new(locale).write_to_file - end - end - - desc "Merge I18n keys from log/translations.yml into config/locales/*.yml (for use with the Rails I18n TextMate bundle)" - task :merge_keys => :environment do - I18n.backend.send(:init_translations) - new_translations = YAML::load(IO.read(File.join(Rails.root, "log", "translations.yml"))) - raise("Can only merge in translations in single locale") if new_translations.keys.size > 1 - locale = new_translations.keys.first - - overwrites = false - Translate::Keys.to_shallow_hash(new_translations[locale]).keys.each do |key| - new_text = key.split(".").inject(new_translations[locale]) { |hash, sub_key| hash[sub_key] } - existing_text = I18n.backend.send(:lookup, locale.to_sym, key) - if existing_text && new_text != existing_text - puts "ERROR: key #{key} already exists with text '#{existing_text.inspect}' and would be overwritten by new text '#{new_text}'. " + - "Set environment variable OVERWRITE=1 if you really want to do this." - overwrites = true - end - end - - if !overwrites || ENV['OVERWRITE'] - I18n.backend.store_translations(locale, new_translations[locale]) - Translate::Storage.new(locale).write_to_file - end - end - - desc "Apply Google translate to auto translate all texts in locale ENV['FROM'] to locale ENV['TO']" - task :google => :environment do - raise "Please specify FROM and TO locales as environment variables" if ENV['FROM'].blank? || ENV['TO'].blank? - - # Depends on httparty gem - # http://www.robbyonrails.com/articles/2009/03/16/httparty-goes-foreign - class GoogleApi - include HTTParty - base_uri 'ajax.googleapis.com' - def self.translate(string, to, from) - tries = 0 - begin - get("/ajax/services/language/translate", - :query => {:langpair => "#{from}|#{to}", :q => string, :v => 1.0}, - :format => :json) - rescue - tries += 1 - puts("SLEEPING - retrying in 5...") - sleep(5) - retry if tries < 10 - end - end - end - - I18n.backend.send(:init_translations) - - start_at = Time.now - translations = {} - Translate::Keys.new.i18n_keys(ENV['FROM']).each do |key| - from_text = I18n.backend.send(:lookup, ENV['FROM'], key).to_s - to_text = I18n.backend.send(:lookup, ENV['TO'], key) - if !from_text.blank? && to_text.blank? - print "#{key}: '#{from_text[0, 40]}' => " - if !translations[from_text] - response = GoogleApi.translate(from_text, ENV['TO'], ENV['FROM']) - translations[from_text] = response["responseData"] && response["responseData"]["translatedText"] - end - if !(translation = translations[from_text]).blank? - translation.gsub!(/\(\(([a-z_.]+)\)\)/i, '{{\1}}') - # Google translate sometimes replaces {{foobar}} with (()) foobar. We skip these - if translation !~ /\(\(\)\)/ - puts "'#{translation[0, 40]}'" - I18n.backend.store_translations(ENV['TO'].to_sym, Translate::Keys.to_deep_hash({key => translation})) - else - puts "SKIPPING since interpolations were messed up: '#{translation[0,40]}'" - end - else - puts "NO TRANSLATION - #{response.inspect}" - end - end - end - - puts "\nTime elapsed: #{(((Time.now - start_at) / 60) * 10).to_i / 10.to_f} minutes" - Translate::Storage.new(ENV['TO'].to_sym).write_to_file - end - - desc "List keys that have changed I18n texts between YAML file ENV['FROM_FILE'] and YAML file ENV['TO_FILE']. Set ENV['VERBOSE'] to see changes" - task :changed => :environment do - from_hash = Translate::Keys.to_shallow_hash(Translate::File.new(ENV['FROM_FILE']).read) - to_hash = Translate::Keys.to_shallow_hash(Translate::File.new(ENV['TO_FILE']).read) - from_hash.each do |key, from_value| - if (to_value = to_hash[key]) && to_value != from_value - key_without_locale = key[/^[^.]+\.(.+)$/, 1] - if ENV['VERBOSE'] - puts "KEY: #{key_without_locale}" - puts "FROM VALUE: '#{from_value}'" - puts "TO VALUE: '#{to_value}'" - else - puts key_without_locale - end - end - end - end -end diff --git a/vendor/plugins/translate/views/layouts/translate.rhtml b/vendor/plugins/translate/views/layouts/translate.rhtml deleted file mode 100644 index 58dbc5c3..00000000 --- a/vendor/plugins/translate/views/layouts/translate.rhtml +++ /dev/null @@ -1,359 +0,0 @@ - - - - - - <%= h(@page_title) %> - - <%= translate_javascript_includes %> - - - - - - - -
        - <% if @page_title -%>

        <%=h @page_title %>

        <% end -%> - <% [:notice, :error].each do |message| %> - <%if flash[message] %> -
        - <%= h(flash[message]) if flash[message] %> -
        - <% end %> - <% end %> - <%= yield %> -
        - - diff --git a/vendor/plugins/translate/views/translate/_pagination.rhtml b/vendor/plugins/translate/views/translate/_pagination.rhtml deleted file mode 100644 index 64f4d690..00000000 --- a/vendor/plugins/translate/views/translate/_pagination.rhtml +++ /dev/null @@ -1,24 +0,0 @@ -<% - # Expects locals: - # - # total_entries - # per_page - - n_pages = total_entries/per_page + (total_entries % per_page > 0 ? 1 : 0) - current_page = (params[:page] || 1).to_i -%> - -<% if n_pages > 1 %> -

        Pages:

        -
        -
          - <% (1..n_pages).each do |page_number| %> - <% if current_page == page_number %> -
        • <%= link_to(page_number, params.merge(:page => page_number), :title => "Page #{page_number}" ) %>
        • - <% else %> -
        • <%= link_to(page_number, params.merge(:page => page_number), :title => "Page #{page_number}") %>
        • - <% end %> - <% end %> -
        -
        -<% end %> \ No newline at end of file diff --git a/vendor/plugins/translate/views/translate/index.rhtml b/vendor/plugins/translate/views/translate/index.rhtml deleted file mode 100644 index a057659d..00000000 --- a/vendor/plugins/translate/views/translate/index.rhtml +++ /dev/null @@ -1,114 +0,0 @@ -<% - @page_title = "Translate" - show_filters = ["all", "untranslated", "translated"] - show_filters << "changed" if @from_locale != @to_locale -%> - -
        - Search filter -
        -

        - <%= simple_filter(show_filters) %> -

        -

        - <%= simple_filter(["key", "text"], 'sort_by') %> -

        -
        - <% form_tag(params, :method => :get) do %> -
        -

        - <%= hidden_field_tag(:filter, params[:filter]) %> - <%= hidden_field_tag(:sort_by, params[:sort_by]) %> - - <%= select_tag(:from_locale, options_for_select(I18n.valid_locales, @from_locale.to_sym)) %> to - <%= select_tag(:to_locale, options_for_select(I18n.valid_locales, @to_locale.to_sym)) %> - <%= submit_tag "Display" %> -

        -
        -
        -

        - - <%= select_tag(:key_type, options_for_select([["contains", 'contains'], ["starts with", 'starts_with']], params[:key_type])) %> - <%= text_field_tag(:key_pattern, params[:key_pattern], :size => 50, :id => "key_pattern_value", :class => "text-default") %> -

        -

        - - <%= select_tag(:text_type, options_for_select(['contains', 'equals'], params[:text_type])) %> - <%= text_field_tag(:text_pattern, params[:text_pattern], :size => 50, :id => "text_pattern_value", :class => "text-default") %> -

        -

        - <%= submit_tag "Search" %> - <%= link_to "clear", params.merge({:text_pattern => nil, :key_pattern => nil}) %> -

        -
        - <% end %> -

        - Found <%= @total_entries %> messages -

        -

        - <%= link_to "Reload messages", translate_reload_path %> -

        -
        - - -
        - <%= render :partial => 'pagination', :locals => {:total_entries => @total_entries, :per_page => per_page} %> -
        - -<% if @total_entries > 0 %> -<% form_tag(translate_path) do %> -
        - <%= hidden_field_tag(:filter, params[:filter], :id => "hid_filter") %> - <%= hidden_field_tag(:sort_by, params[:sort_by], :id => "hid_sort_by") %> - <%= hidden_field_tag(:key_type, params[:key_type], :id => "hid_key_type") %> - <%= hidden_field_tag(:key_pattern, params[:key_pattern], :id => "hid_key_pattern") %> - <%= hidden_field_tag(:text_type, params[:text_type], :id => "hid_text_type") %> - <%= hidden_field_tag(:text_pattern, params[:text_pattern], :id => "hid_text_pattern") %> -
        -
        -

        Translations from <%= @from_locale %> to <%= @to_locale %>

        -

        - <%= submit_tag "Save Translations" %> -

        - <% @paginated_keys.each do |key| - from_text = lookup(@from_locale, key) - to_text = lookup(@to_locale, key) - line_size = 100 - n_lines = n_lines(from_text, line_size) - field_name = "key[#{key}]" - %> -
        - <% if from_text.present? %> -

        - <%= simple_format(h(from_text)) %> -

        - <% end %> -

        - <% if n_lines > 1 %> - <%= text_area_tag(field_name, to_text, :size => "#{line_size}x#{n_lines}", :id => key) %> - <% else %> - <%= text_field_tag(field_name, to_text, :size => line_size, :id => key) %> - <% end %> -

        -

        - - <%= link_to_function 'Auto Translate', "getGoogleTranslation('#{key}', \"#{escape_javascript(from_text)}\", '#{@from_locale}', '#{@to_locale}')", :style => 'padding: 0; margin: 0;' %> -
        - Key:<%=h key %>
        - <% if @files[key] %> - File:<%= @files[key].join("
        ") %> - <% end %> -
        -

        -
        -<% end %> -

        - <%= submit_tag "Save Translations" %> -

        -
        -<% end %> -<% end %> - -
        - <%= render :partial => 'pagination', :locals => {:total_entries => @total_entries, :per_page => per_page} %> -
        \ No newline at end of file From fde64e0b3d2fa3624c87913a668579da91be0ce6 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Thu, 5 Apr 2012 22:21:28 +0200 Subject: [PATCH 103/134] forgot to add these --- backup.rails2.3/Gemfile.rails2.3 | 65 ++ backup.rails2.3/Gemfile.rails3 | 39 ++ backup.rails2.3/app/apis/todo_api.rb | 22 + backup.rails2.3/application_helper.rb.rails2 | 301 +++++++++ backup.rails2.3/database.yml.rails2 | 37 ++ backup.rails2.3/development.rb.rails2 | 19 + backup.rails2.3/environment.rb.rails2 | 119 ++++ backup.rails2.3/lib/assets/.gitkeep | 0 .../lib/authenticated_test_helper.rb | 113 ++++ backup.rails2.3/lib/login_system.rb | 222 +++++++ backup.rails2.3/lib/name_part_finder.rb | 5 + backup.rails2.3/lib/tagging_extensions.rb | 200 ++++++ backup.rails2.3/lib/tasks/.gitkeep | 0 .../lib/tasks/cucumber-tracks.rake | 38 ++ backup.rails2.3/lib/tasks/cucumber.rake | 53 ++ backup.rails2.3/lib/tasks/database.rake | 27 + .../lib/tasks/extract_fixtures.rake | 17 + backup.rails2.3/lib/tasks/gems.rake | 34 ++ .../lib/tasks/load_exported_fixtures.rake | 8 + .../lib/tasks/query_trace_toggle.rake | 50 ++ backup.rails2.3/lib/tasks/reset_password.rake | 23 + backup.rails2.3/lib/tasks/rspec.rake | 144 +++++ backup.rails2.3/lib/tasks/setup_tracks.rake | 15 + .../lib/tasks/upgrade_sqlite_db.rake | 40 ++ backup.rails2.3/lib/tracks/config.rb | 27 + backup.rails2.3/lib/tracks/source_view.rb | 68 +++ backup.rails2.3/lib/tracks/todo_list.rb | 59 ++ backup.rails2.3/mongrel_workaround.rb | 107 ++++ backup.rails2.3/new_rails_defaults.rb | 21 + .../plugins/extra_validations/init.rb | 2 + .../lib/extra_validations.rb | 29 + .../plugins/open_id_authentication/CHANGELOG | 35 ++ .../plugins/open_id_authentication/README | 231 +++++++ .../plugins/open_id_authentication/Rakefile | 22 + ...open_id_authentication_tables_generator.rb | 11 + .../templates/migration.rb | 20 + .../templates/migration.rb | 26 + ...open_id_authentication_tables_generator.rb | 11 + .../plugins/open_id_authentication/init.rb | 18 + .../lib/open_id_authentication.rb | 240 ++++++++ .../lib/open_id_authentication/association.rb | 9 + .../lib/open_id_authentication/db_store.rb | 55 ++ .../lib/open_id_authentication/nonce.rb | 5 + .../lib/open_id_authentication/request.rb | 23 + .../open_id_authentication/timeout_fixes.rb | 20 + .../tasks/open_id_authentication_tasks.rake | 30 + .../test/normalize_test.rb | 32 + .../test/open_id_authentication_test.rb | 46 ++ .../test/status_test.rb | 14 + .../test/test_helper.rb | 17 + .../plugins/resource_feeder/README | 7 + .../plugins/resource_feeder/Rakefile | 22 + .../plugins/resource_feeder/init.rb | 2 + .../resource_feeder/lib/resource_feeder.rb | 2 + .../lib/resource_feeder/atom.rb | 67 ++ .../lib/resource_feeder/common.rb | 24 + .../lib/resource_feeder/rss.rb | 68 +++ .../resource_feeder/test/atom_feed_test.rb | 85 +++ .../resource_feeder/test/rss_feed_test.rb | 86 +++ .../resource_feeder/test/test_helper.rb | 64 ++ .../plugins/simple_ldap_authenticator/README | 5 + .../simple_ldap_authenticator/Rakefile | 22 + .../plugins/simple_ldap_authenticator/init.rb | 2 + .../simple_ldap_authenticator/install.rb | 1 + .../lib/simple_ldap_authenticator.rb | 127 ++++ .../simple_ldap_authenticator_tasks.rake | 4 + .../test/simple_ldap_authenticator_test.rb | 8 + .../plugins/skinny_spec/.gitignore | 2 + .../plugins/skinny_spec/README.rdoc | 270 ++++++++ backup.rails2.3/plugins/skinny_spec/Rakefile | 11 + .../additional/helper_overrides.txt | 58 ++ .../skinny_scaffold_generator.rb | 102 ++++ .../skinny_scaffold/templates/controller.rb | 105 ++++ .../templates/controller_spec.rb | 93 +++ .../skinny_scaffold/templates/form.html.erb | 25 + .../skinny_scaffold/templates/form.html.haml | 18 + .../templates/form.html_spec.rb | 40 ++ .../skinny_scaffold/templates/helper.rb | 2 + .../skinny_scaffold/templates/helper_spec.rb | 5 + .../skinny_scaffold/templates/index.html.erb | 31 + .../skinny_scaffold/templates/index.html.haml | 23 + .../templates/index.html_spec.rb | 15 + .../templates/index_partial.html.erb | 12 + .../templates/index_partial.html.haml | 11 + .../templates/index_partial.html_spec.rb | 31 + .../skinny_scaffold/templates/migration.rb | 14 + .../skinny_scaffold/templates/model.rb | 2 + .../skinny_scaffold/templates/model_spec.rb | 25 + .../skinny_scaffold/templates/show.html.erb | 15 + .../skinny_scaffold/templates/show.html.haml | 13 + .../templates/show.html_spec.rb | 31 + .../lib/lucky_sneaks/common_spec_helpers.rb | 83 +++ .../controller_request_helpers.rb | 67 ++ .../lucky_sneaks/controller_spec_helpers.rb | 571 +++++++++++++++++ .../lucky_sneaks/controller_stub_helpers.rb | 238 ++++++++ .../lib/lucky_sneaks/model_spec_helpers.rb | 496 +++++++++++++++ .../lib/lucky_sneaks/view_spec_helpers.rb | 577 ++++++++++++++++++ .../lib/lucky_sneaks/view_stub_helpers.rb | 15 + .../plugins/skinny_spec/lib/skinny_spec.rb | 26 + backup.rails2.3/plugins/swf_fu/CHANGELOG.rdoc | 46 ++ .../plugins/swf_fu/FLASH_OBJECT.rdoc | 31 + backup.rails2.3/plugins/swf_fu/LICENSE | 29 + backup.rails2.3/plugins/swf_fu/README.rdoc | 92 +++ backup.rails2.3/plugins/swf_fu/Rakefile | 22 + .../swf_fu/assets/javascripts/swfobject.js | 4 + .../swf_fu/assets/swfs/expressInstall.swf | Bin 0 -> 727 bytes backup.rails2.3/plugins/swf_fu/init.rb | 14 + backup.rails2.3/plugins/swf_fu/install.rb | 24 + .../helpers/asset_tag_helper/swf_asset.rb | 61 ++ .../lib/action_view/helpers/swf_fu_helper.rb | 197 ++++++ .../plugins/swf_fu/test/results.rb | 42 ++ .../plugins/swf_fu/test/swf_fu_test.rb | 159 +++++ .../plugins/swf_fu/test/test_helper.rb | 20 + backup.rails2.3/plugins/swf_fu/uninstall.rb | 6 + backup.rails2.3/plugins/translate/MIT-LICENSE | 20 + backup.rails2.3/plugins/translate/README | 63 ++ backup.rails2.3/plugins/translate/Rakefile | 11 + backup.rails2.3/plugins/translate/init.rb | 8 + .../plugins/translate/lib/translate.rb | 8 + .../plugins/translate/lib/translate/file.rb | 35 ++ .../plugins/translate/lib/translate/keys.rb | 152 +++++ .../plugins/translate/lib/translate/log.rb | 35 ++ .../plugins/translate/lib/translate/routes.rb | 11 + .../translate/lib/translate/storage.rb | 28 + .../translate/lib/translate_controller.rb | 165 +++++ .../plugins/translate/lib/translate_helper.rb | 45 ++ .../controllers/translate_controller_spec.rb | 129 ++++ .../plugins/translate/spec/file_spec.rb | 54 ++ .../files/translate/app/models/article.rb | 12 + .../files/translate/app/views/category.erb | 1 + .../files/translate/app/views/category.html | 1 + .../translate/app/views/category.html.erb | 1 + .../files/translate/app/views/category.rhtml | 5 + .../public/javascripts/application.js | 1 + .../plugins/translate/spec/keys_spec.rb | 179 ++++++ .../plugins/translate/spec/log_spec.rb | 47 ++ .../plugins/translate/spec/spec_helper.rb | 11 + .../plugins/translate/spec/storage_spec.rb | 33 + .../plugins/translate/tasks/translate.rake | 178 ++++++ .../translate/views/layouts/translate.rhtml | 359 +++++++++++ .../views/translate/_pagination.rhtml | 24 + .../translate/views/translate/index.rhtml | 114 ++++ backup.rails2.3/production.rb.rails2 | 17 + backup.rails2.3/routes.rb.rails2 | 113 ++++ config/initializers/tracks.rb | 45 ++ 145 files changed, 9044 insertions(+) create mode 100644 backup.rails2.3/Gemfile.rails2.3 create mode 100644 backup.rails2.3/Gemfile.rails3 create mode 100644 backup.rails2.3/app/apis/todo_api.rb create mode 100644 backup.rails2.3/application_helper.rb.rails2 create mode 100644 backup.rails2.3/database.yml.rails2 create mode 100644 backup.rails2.3/development.rb.rails2 create mode 100644 backup.rails2.3/environment.rb.rails2 create mode 100644 backup.rails2.3/lib/assets/.gitkeep create mode 100644 backup.rails2.3/lib/authenticated_test_helper.rb create mode 100644 backup.rails2.3/lib/login_system.rb create mode 100644 backup.rails2.3/lib/name_part_finder.rb create mode 100644 backup.rails2.3/lib/tagging_extensions.rb create mode 100644 backup.rails2.3/lib/tasks/.gitkeep create mode 100644 backup.rails2.3/lib/tasks/cucumber-tracks.rake create mode 100644 backup.rails2.3/lib/tasks/cucumber.rake create mode 100644 backup.rails2.3/lib/tasks/database.rake create mode 100644 backup.rails2.3/lib/tasks/extract_fixtures.rake create mode 100644 backup.rails2.3/lib/tasks/gems.rake create mode 100644 backup.rails2.3/lib/tasks/load_exported_fixtures.rake create mode 100644 backup.rails2.3/lib/tasks/query_trace_toggle.rake create mode 100644 backup.rails2.3/lib/tasks/reset_password.rake create mode 100644 backup.rails2.3/lib/tasks/rspec.rake create mode 100644 backup.rails2.3/lib/tasks/setup_tracks.rake create mode 100644 backup.rails2.3/lib/tasks/upgrade_sqlite_db.rake create mode 100644 backup.rails2.3/lib/tracks/config.rb create mode 100644 backup.rails2.3/lib/tracks/source_view.rb create mode 100644 backup.rails2.3/lib/tracks/todo_list.rb create mode 100644 backup.rails2.3/mongrel_workaround.rb create mode 100644 backup.rails2.3/new_rails_defaults.rb create mode 100644 backup.rails2.3/plugins/extra_validations/init.rb create mode 100644 backup.rails2.3/plugins/extra_validations/lib/extra_validations.rb create mode 100644 backup.rails2.3/plugins/open_id_authentication/CHANGELOG create mode 100644 backup.rails2.3/plugins/open_id_authentication/README create mode 100644 backup.rails2.3/plugins/open_id_authentication/Rakefile create mode 100644 backup.rails2.3/plugins/open_id_authentication/generators/open_id_authentication_tables/open_id_authentication_tables_generator.rb create mode 100644 backup.rails2.3/plugins/open_id_authentication/generators/open_id_authentication_tables/templates/migration.rb create mode 100644 backup.rails2.3/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/templates/migration.rb create mode 100644 backup.rails2.3/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/upgrade_open_id_authentication_tables_generator.rb create mode 100644 backup.rails2.3/plugins/open_id_authentication/init.rb create mode 100644 backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication.rb create mode 100644 backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/association.rb create mode 100644 backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/db_store.rb create mode 100644 backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/nonce.rb create mode 100644 backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/request.rb create mode 100644 backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/timeout_fixes.rb create mode 100644 backup.rails2.3/plugins/open_id_authentication/tasks/open_id_authentication_tasks.rake create mode 100644 backup.rails2.3/plugins/open_id_authentication/test/normalize_test.rb create mode 100644 backup.rails2.3/plugins/open_id_authentication/test/open_id_authentication_test.rb create mode 100644 backup.rails2.3/plugins/open_id_authentication/test/status_test.rb create mode 100644 backup.rails2.3/plugins/open_id_authentication/test/test_helper.rb create mode 100644 backup.rails2.3/plugins/resource_feeder/README create mode 100644 backup.rails2.3/plugins/resource_feeder/Rakefile create mode 100644 backup.rails2.3/plugins/resource_feeder/init.rb create mode 100644 backup.rails2.3/plugins/resource_feeder/lib/resource_feeder.rb create mode 100644 backup.rails2.3/plugins/resource_feeder/lib/resource_feeder/atom.rb create mode 100644 backup.rails2.3/plugins/resource_feeder/lib/resource_feeder/common.rb create mode 100644 backup.rails2.3/plugins/resource_feeder/lib/resource_feeder/rss.rb create mode 100644 backup.rails2.3/plugins/resource_feeder/test/atom_feed_test.rb create mode 100644 backup.rails2.3/plugins/resource_feeder/test/rss_feed_test.rb create mode 100644 backup.rails2.3/plugins/resource_feeder/test/test_helper.rb create mode 100644 backup.rails2.3/plugins/simple_ldap_authenticator/README create mode 100644 backup.rails2.3/plugins/simple_ldap_authenticator/Rakefile create mode 100644 backup.rails2.3/plugins/simple_ldap_authenticator/init.rb create mode 100644 backup.rails2.3/plugins/simple_ldap_authenticator/install.rb create mode 100644 backup.rails2.3/plugins/simple_ldap_authenticator/lib/simple_ldap_authenticator.rb create mode 100644 backup.rails2.3/plugins/simple_ldap_authenticator/tasks/simple_ldap_authenticator_tasks.rake create mode 100644 backup.rails2.3/plugins/simple_ldap_authenticator/test/simple_ldap_authenticator_test.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/.gitignore create mode 100644 backup.rails2.3/plugins/skinny_spec/README.rdoc create mode 100644 backup.rails2.3/plugins/skinny_spec/Rakefile create mode 100644 backup.rails2.3/plugins/skinny_spec/additional/helper_overrides.txt create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/skinny_scaffold_generator.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/controller.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/controller_spec.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.erb create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.haml create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html_spec.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/helper.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/helper_spec.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.erb create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.haml create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html_spec.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.erb create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.haml create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html_spec.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/migration.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/model.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/model_spec.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.erb create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.haml create mode 100644 backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html_spec.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/common_spec_helpers.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/controller_request_helpers.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/controller_spec_helpers.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/controller_stub_helpers.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/model_spec_helpers.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/view_spec_helpers.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/view_stub_helpers.rb create mode 100644 backup.rails2.3/plugins/skinny_spec/lib/skinny_spec.rb create mode 100644 backup.rails2.3/plugins/swf_fu/CHANGELOG.rdoc create mode 100644 backup.rails2.3/plugins/swf_fu/FLASH_OBJECT.rdoc create mode 100644 backup.rails2.3/plugins/swf_fu/LICENSE create mode 100644 backup.rails2.3/plugins/swf_fu/README.rdoc create mode 100644 backup.rails2.3/plugins/swf_fu/Rakefile create mode 100644 backup.rails2.3/plugins/swf_fu/assets/javascripts/swfobject.js create mode 100755 backup.rails2.3/plugins/swf_fu/assets/swfs/expressInstall.swf create mode 100644 backup.rails2.3/plugins/swf_fu/init.rb create mode 100644 backup.rails2.3/plugins/swf_fu/install.rb create mode 100644 backup.rails2.3/plugins/swf_fu/lib/action_view/helpers/asset_tag_helper/swf_asset.rb create mode 100644 backup.rails2.3/plugins/swf_fu/lib/action_view/helpers/swf_fu_helper.rb create mode 100644 backup.rails2.3/plugins/swf_fu/test/results.rb create mode 100644 backup.rails2.3/plugins/swf_fu/test/swf_fu_test.rb create mode 100644 backup.rails2.3/plugins/swf_fu/test/test_helper.rb create mode 100644 backup.rails2.3/plugins/swf_fu/uninstall.rb create mode 100644 backup.rails2.3/plugins/translate/MIT-LICENSE create mode 100644 backup.rails2.3/plugins/translate/README create mode 100644 backup.rails2.3/plugins/translate/Rakefile create mode 100644 backup.rails2.3/plugins/translate/init.rb create mode 100644 backup.rails2.3/plugins/translate/lib/translate.rb create mode 100644 backup.rails2.3/plugins/translate/lib/translate/file.rb create mode 100644 backup.rails2.3/plugins/translate/lib/translate/keys.rb create mode 100644 backup.rails2.3/plugins/translate/lib/translate/log.rb create mode 100644 backup.rails2.3/plugins/translate/lib/translate/routes.rb create mode 100644 backup.rails2.3/plugins/translate/lib/translate/storage.rb create mode 100644 backup.rails2.3/plugins/translate/lib/translate_controller.rb create mode 100644 backup.rails2.3/plugins/translate/lib/translate_helper.rb create mode 100644 backup.rails2.3/plugins/translate/spec/controllers/translate_controller_spec.rb create mode 100644 backup.rails2.3/plugins/translate/spec/file_spec.rb create mode 100644 backup.rails2.3/plugins/translate/spec/files/translate/app/models/article.rb create mode 100644 backup.rails2.3/plugins/translate/spec/files/translate/app/views/category.erb create mode 100644 backup.rails2.3/plugins/translate/spec/files/translate/app/views/category.html create mode 100644 backup.rails2.3/plugins/translate/spec/files/translate/app/views/category.html.erb create mode 100644 backup.rails2.3/plugins/translate/spec/files/translate/app/views/category.rhtml create mode 100644 backup.rails2.3/plugins/translate/spec/files/translate/public/javascripts/application.js create mode 100644 backup.rails2.3/plugins/translate/spec/keys_spec.rb create mode 100644 backup.rails2.3/plugins/translate/spec/log_spec.rb create mode 100644 backup.rails2.3/plugins/translate/spec/spec_helper.rb create mode 100644 backup.rails2.3/plugins/translate/spec/storage_spec.rb create mode 100644 backup.rails2.3/plugins/translate/tasks/translate.rake create mode 100644 backup.rails2.3/plugins/translate/views/layouts/translate.rhtml create mode 100644 backup.rails2.3/plugins/translate/views/translate/_pagination.rhtml create mode 100644 backup.rails2.3/plugins/translate/views/translate/index.rhtml create mode 100644 backup.rails2.3/production.rb.rails2 create mode 100644 backup.rails2.3/routes.rb.rails2 create mode 100644 config/initializers/tracks.rb diff --git a/backup.rails2.3/Gemfile.rails2.3 b/backup.rails2.3/Gemfile.rails2.3 new file mode 100644 index 00000000..dc3af876 --- /dev/null +++ b/backup.rails2.3/Gemfile.rails2.3 @@ -0,0 +1,65 @@ +source :gemcutter +source "http://gems.github.com/" + +gem "rake", "~>0.8.7" +gem "rails", "~>2.3.12" +gem "highline", "~>1.5.0" +gem "RedCloth", "4.2.8" +gem "sanitize", "~>1.2.1" +gem "rack", "1.1.0" +gem "will_paginate", "~> 2.3.15" +gem "has_many_polymorphs", "~> 2.13" +gem "acts_as_list", "~>0.1.4" +gem "aasm", "~>2.2.0" +gem "rubyjedi-actionwebservice", :require => "actionwebservice" +gem "rubycas-client", "~>2.2.1" +gem "ruby-openid", :require => "openid" + +# you may comment out the database driver you will not be using. +# This will prevent a native build of the driver. Building native drivers is not always possible on all hosters +gem "sqlite3" +gem "mysql" + +gem 'bcrypt-ruby', '~> 2.1.4' +gem 'htmlentities', '~> 4.3.0' +gem "mail" + +if RUBY_VERSION.to_f >= 1.9 + gem "soap4r-ruby1.9" +else + gem "soap4r", "~>1.5.8" +end + +group :development do + if RUBY_VERSION.to_f >= 1.9 + gem "ruby-debug19" + gem "mongrel", "1.2.0.pre2" + else + gem "ruby-debug" + gem "mongrel" + end + gem "yard" +end + +group :test do + gem "test-unit", "1.2.3" + gem "flexmock" + gem "ZenTest", ">=4.0.0" + gem "hpricot" + gem "hoe" + gem "rspec-rails", "~>1.3.3" + gem "thoughtbot-factory_girl" + gem 'memory_test_fix', '~>0.1.3' + gem "capybara", ">=0.3.5" + gem "selenium-webdriver" # Note that > 2.14 has problems: https://code.google.com/p/selenium/issues/detail?id=3075 + gem "database_cleaner", ">=0.5.0" + gem "cucumber-rails", "~>0.3.2" + gem "aruba", "0.2.2", :path => "vendor/gems/aruba-0.2.2" + + # uncomment to use the webkit option. This depends on Qt to be installed + #gem "capybara-webkit" + + # uncomment to be able to make screenshots from scenarios + #gem "capybara-screenshot" + #gem "launchy" +end diff --git a/backup.rails2.3/Gemfile.rails3 b/backup.rails2.3/Gemfile.rails3 new file mode 100644 index 00000000..c07b2b6a --- /dev/null +++ b/backup.rails2.3/Gemfile.rails3 @@ -0,0 +1,39 @@ +source 'https://rubygems.org' + +gem 'rails', '3.2.3' + +# Bundle edge Rails instead: +# gem 'rails', :git => 'git://github.com/rails/rails.git' + +gem 'sqlite3' +gem 'mysql' + + +# Gems used only for assets and not required +# in production environments by default. +group :assets do + gem 'sass-rails', '~> 3.2.3' + gem 'coffee-rails', '~> 3.2.1' + + # See https://github.com/sstephenson/execjs#readme for more supported runtimes + # gem 'therubyracer', :platform => :ruby + + gem 'uglifier', '>= 1.0.3' +end + +gem 'jquery-rails' + +# To use ActiveModel has_secure_password +# gem 'bcrypt-ruby', '~> 3.0.0' + +# To use Jbuilder templates for JSON +# gem 'jbuilder' + +# Use unicorn as the app server +# gem 'unicorn' + +# Deploy with Capistrano +# gem 'capistrano' + +# To use debugger +# gem 'ruby-debug19', :require => 'ruby-debug' diff --git a/backup.rails2.3/app/apis/todo_api.rb b/backup.rails2.3/app/apis/todo_api.rb new file mode 100644 index 00000000..5f980a64 --- /dev/null +++ b/backup.rails2.3/app/apis/todo_api.rb @@ -0,0 +1,22 @@ +class TodoApi < ActionWebService::API::Base + api_method :new_todo, + :expects => [{:username => :string}, {:token => :string}, {:context_id => :int}, {:description => :string}, {:notes => :string}], + :returns => [:int] + + api_method :new_todo_for_project, + :expects => [{:username => :string}, {:token => :string}, {:context_id => :int}, {:project_id => :int}, {:description => :string}, {:notes => :string}], + :returns => [:int] + + api_method :new_rich_todo, + :expects => [{:username => :string}, {:token => :string}, {:default_context_id => :int}, {:description => :string}, {:notes => :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 diff --git a/backup.rails2.3/application_helper.rb.rails2 b/backup.rails2.3/application_helper.rb.rails2 new file mode 100644 index 00000000..39c591e4 --- /dev/null +++ b/backup.rails2.3/application_helper.rb.rails2 @@ -0,0 +1,301 @@ +# The methods added to this helper will be available to all templates in the +# application. +module ApplicationHelper + + # Replicates the link_to method but also checks request.request_uri to find + # current page. If that matches the url, the link is marked id = "current" + # + def navigation_link(name, options = {}, html_options = nil, *parameters_for_method_reference) + if html_options + html_options = html_options.stringify_keys + 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\"" : "" + + "#{name || url}" + end + + def days_from_today(date) + date.in_time_zone.to_date - current_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) + return "" if due.nil? + + days = days_from_today(due) + + colors = ['amber','amber','orange','orange','orange','orange','orange','orange'] + color = :red if days < 0 + color = :green if days > 7 + color = colors[days] if color.nil? + + return content_tag(:a, {:title => format_date(due)}) { + content_tag(:span, {:class => color}) { + case days + when 0 + t('todos.next_actions_due_date.due_today') + when 1 + t('todos.next_actions_due_date.due_tomorrow') + when 2..7 + if prefs.due_style == Preference.due_styles[:due_on] + # TODO: internationalize strftime here + t('models.preference.due_on', :date => due.strftime("%A")) + else + t('models.preference.due_in', :days => days) + end + else + # overdue or due very soon! sound the alarm! + if days == -1 + t('todos.next_actions_due_date.overdue_by', :days => days * -1) + elsif days < -1 + t('todos.next_actions_due_date.overdue_by_plural', :days => days * -1) + else + # more than a week away - relax + t('models.preference.due_in', :days => days) + end + end + } + } + end + + # Check due date in comparison to today's date Flag up date appropriately with + # 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 + when 0 + ""+ format_date(due) + "" + when 1 + "" + format_date(due) + "" + # due 2-7 days away + when 2..7 + "" + format_date(due) + "" + else + # overdue or due very soon! sound the alarm! + if days < 0 + "" + format_date(due) +"" + else + # more than a week away - relax + "" + format_date(due) + "" + end + 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(" "," ") + end + + def count_undone_todos_and_notes_phrase(project, string="actions") + s = count_undone_todos_phrase(project, string) + s += ", #{pluralize(project.note_count, 'note')}" unless project.note_count == 0 + s + end + + def link_to_context(context, descriptor = sanitize(context.name)) + link_to( descriptor, context, :title => "View context: #{context.name}" ) + end + + def link_to_project(project, descriptor = sanitize(project.name)) + link_to( descriptor, project, :title => "View project: #{project.name}" ) + end + + def link_to_edit_note (note, descriptor = sanitize(note.id.to_s)) + link_to(descriptor, + url_for({:controller => 'notes', :action => 'edit', :id => note.id}), + {:id => "link_edit_#{dom_id(note)}", :class => "note_edit_settings"}) + end + + def link_to_project_mobile(project, accesskey, descriptor = sanitize(project.name)) + link_to( descriptor, project_path(project, :format => 'm'), {:title => "View project: #{project.name}", :accesskey => accesskey} ) + end + + def item_link_to_context(item) + descriptor = "[C]" + descriptor = "[#{item.context.name}]" if prefs.verbose_action_descriptors + link_to_context( item.context, descriptor ) + end + + def item_link_to_project(item) + descriptor = "[P]" + descriptor = "[#{item.project.name}]" if prefs.verbose_action_descriptors + link_to_project( item.project, descriptor ) + end + + def render_flash + render :partial => 'shared/flash', :object => flash + end + + def recurrence_time_span(rt) + case rt.ends_on + when "no_end_date" + return rt.start_from.nil? ? "" : I18n.t("todos.recurrence.pattern.from") + " " + format_date(rt.start_from) + when "ends_on_number_of_times" + return I18n.t("todos.recurrence.pattern.times", :number => rt.number_of_occurences) + when "ends_on_end_date" + starts = rt.start_from.nil? ? "" : I18n.t("todos.recurrence.pattern.from") + " " + format_date(rt.start_from) + ends = rt.end_date.nil? ? "" : " " + I18n.t("todos.recurrence.pattern.until") + " " + format_date(rt.end_date) + return starts+ends + else + raise Exception.new, "unknown recurrence time span selection (#{rt.ends_on})" + end + end + + def recurrence_pattern_as_text(recurring_todo) + rt = recurring_todo.recurring_target_as_text + rp = recurring_todo.recurrence_pattern + # only add space if recurrence_pattern has content + rp = " " + rp if !rp.nil? + rts = recurrence_time_span(recurring_todo) + # only add space if recurrence_time_span has content + rts = " " + rts if !(rts == "") + return rt+rp+rts + end + + def date_format_for_date_picker() + standard_format = current_user.prefs.date_format + translations = [ + ['%m', 'mm'], + ['%b', 'M'], + ['%B', 'MM'], + ['%d', 'dd'], + ['%a', 'D'], + ['%A', 'DD'], + ['%y', 'y'], + ['%Y', 'yy'] + ] + translations.inject(standard_format) do |str, translation| + str.gsub(*translation) + end + end + + AUTO_LINK_MESSAGE_RE = %r{message://<[^>]+>} unless const_defined?(:AUTO_LINK_MESSAGE_RE) + + # Converts message:// links to href. This URL scheme is used on Mac OS X + # to link to a mail message in Mail.app. + def auto_link_message(text) + text.gsub(AUTO_LINK_MESSAGE_RE) do + href = $& + left, right = $`, $' + # detect already linked URLs and URLs in the middle of a tag + if left =~ /<[^>]+$/ && right =~ /^[^>]*>/ + # do not change string; URL is alreay linked + href + else + content = content_tag(:a, h(href), :href => h(href)) + end + end + end + + def format_note(note) + note = auto_link_message(note) + note = markdown(note) + note = auto_link(note, :link => :urls) + + # add onenote and message protocols + Sanitize::Config::RELAXED[:protocols]['a']['href'] << 'onenote' + Sanitize::Config::RELAXED[:protocols]['a']['href'] << 'message' + + note = Sanitize.clean(note, Sanitize::Config::RELAXED) + return note + end + + def sidebar_html_for_titled_list (list, title) + return content_tag(:h3, title+" (#{list.length})") + + content_tag(:ul, sidebar_html_for_list(list)) + end + + def sidebar_html_for_list(list) + if list.empty? + return content_tag(:li, t('sidebar.list_empty')) + else + return list.inject("") do |html, item| + link = (item.class == "Project") ? link_to_project( item ) : link_to_context(item) + html << content_tag(:li, link + " (" + count_undone_todos_phrase(item,"actions")+")") + end + end + end + + def generate_i18n_strings + js = "i18n_locale='#{I18n.locale}';\n" + js << "i18n = new Array();\n" + %w{ + shared.toggle_multi shared.toggle_multi_title + shared.hide_form shared.hide_action_form_title + shared.toggle_single shared.toggle_single_title + projects.hide_form projects.hide_form_title + projects.show_form projects.show_form_title + contexts.hide_form contexts.hide_form_title + contexts.show_form contexts.show_form_title + contexts.new_context_pre contexts.new_context_post + common.cancel common.ok + common.ajaxError todos.unresolved_dependency + }.each do |s| + js << "i18n['#{s}'] = '#{ t(s).gsub(/'/, "\\\\'") }';\n" + end + return js + end + + def javascript_tag_for_i18n_datepicker + locale = I18n.locale + # do not include en as locale since this the available by default + if locale and locale != :en + javascript_include_tag("i18n/jquery.ui.datepicker-#{locale}.js") + end + end + + def determine_done_path + case @controller.controller_name + when "contexts" + done_todos_context_path(@context) + when "projects" + done_todos_project_path(@project) + when "todos" + if source_view_is(:tag) + done_tag_path(@tag_name) + else + done_todos_path + end + else + done_todos_path + end + end + + def determine_all_done_path + case @controller.controller_name + when "contexts" + all_done_todos_context_path(@context) + when "projects" + all_done_todos_project_path(@project) + when "todos" + if source_view_is(:tag) + all_done_tag_path(@tag_name) + else + all_done_todos_path + end + else + all_done_todos_path + end + end + +end diff --git a/backup.rails2.3/database.yml.rails2 b/backup.rails2.3/database.yml.rails2 new file mode 100644 index 00000000..da7aebc8 --- /dev/null +++ b/backup.rails2.3/database.yml.rails2 @@ -0,0 +1,37 @@ +# MySQL. Versions 4.1 and 5.0 are recommended. +# +# +# Be sure to use new-style password hashing: +# http://dev.mysql.com/doc/refman/5.0/en/old-client.html +development: + adapter: mysql + database: tracks_trunk + encoding: utf8 + host: localhost + username: tracks + password: 32tracks55 + +mdevelopment: + adapter: sqlite3 + database: db/tracks-21-test.sqlite3.db + +test: &TEST +# adapter: sqlite3 +# database: ":memory:" +# verbosity: quiet + adapter: mysql + database: tracks_test + host: localhost + username: tracks + password: 32tracks55 + +production: + adapter: mysql + database: tracks_trunk + encoding: utf8 + host: localhost + username: tracks + password: 32tracks55 + +cucumber: + <<: *TEST diff --git a/backup.rails2.3/development.rb.rails2 b/backup.rails2.3/development.rb.rails2 new file mode 100644 index 00000000..05c880d7 --- /dev/null +++ b/backup.rails2.3/development.rb.rails2 @@ -0,0 +1,19 @@ +# In the development environment your application's code is reloaded on +# every request. This slows down response time but is perfect for development +# since you don't have to restart the webserver when you make code changes. +config.cache_classes = false + +# Log error messages when you accidentally call methods on nil. +config.whiny_nils = true + +# Show full error reports and disable caching +config.action_controller.consider_all_requests_local = true +config.action_controller.perform_caching = false + +# Don't care if the mailer can't send +config.action_mailer.raise_delivery_errors = false + +# Unique cookies +config.action_controller.session = { :key => 'TracksDev' } + +NOTIFY_BAR="
         
        " diff --git a/backup.rails2.3/environment.rb.rails2 b/backup.rails2.3/environment.rb.rails2 new file mode 100644 index 00000000..390f585b --- /dev/null +++ b/backup.rails2.3/environment.rb.rails2 @@ -0,0 +1,119 @@ +# Be sure to restart your webserver when you modify this file. +# Uncomment below to force Rails into production mode + +# (Use only when you can't set environment variables through your web/app server) +# ENV['RAILS_ENV'] = 'production' + +# Bootstrap the Rails environment, frameworks, and default configuration +require File.join(File.dirname(__FILE__), 'boot') + +require 'yaml' +SITE_CONFIG = YAML.load_file(File.join(File.dirname(__FILE__), 'site.yml')) + +class Rails::Configuration + attr_accessor :action_web_service +end + +Encoding.default_external = Encoding::UTF_8 if RUBY_VERSION > "1.9" + +Rails::Initializer.run do |config| + # Skip frameworks you're not going to use + # config.frameworks -= [ :action_web_service, :action_mailer ] + config.autoload_paths += %W( #{RAILS_ROOT}/app/apis ) + + config.action_controller.use_accept_header = true + + # Use the database for sessions instead of the file system + # (create the session table with 'rake create_sessions_table') + config.action_controller.session_store = :active_record_store + + config.action_controller.session = { + :key => '_tracks_session_id', + :secret => SITE_CONFIG['salt'] * (30.0 / SITE_CONFIG['salt'].length).ceil #must be at least 30 characters + } + + config.action_controller.relative_url_root = SITE_CONFIG['subdir'] if SITE_CONFIG['subdir'] + + # Enable page/fragment caching by setting a file-based store + # (remember to create the caching directory and make it readable to the application) + # config.action_controller.fragment_cache_store = :file_store, "#{RAILS_ROOT}/cache" + + # Activate observers that should always be running + # config.active_record.observers = :cacher, :garbage_collector + + # Make Active Record use UTC-base instead of local time + config.active_record.default_timezone = :utc + + # You''ll probably want to change this to the time zone of the computer where Tracks is running + # run rake time:zones:local have Rails suggest time zone names on your system + config.time_zone = SITE_CONFIG['time_zone'] + + # Use Active Record's schema dumper instead of SQL when creating the test database + # (enables use of different database adapters for development and test environments) + config.active_record.schema_format = :ruby + + # allow other protocols in urls for sanitzer. Add to your liking, for example + # config.action_view.sanitized_allowed_protocols = 'onenote', 'blah', 'proto' + # to enable "link":onenote://... or "link":blah://... hyperlinks + config.action_view.sanitized_allowed_protocols = 'onenote', 'message' + + # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. + # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] + # config.i18n.default_locale = :de + +end + +# Add new inflection rules using the following format +# (all these examples are active by default): +# Inflector.inflections do |inflect| +# inflect.plural /^(ox)$/i, '\1en' +# inflect.singular /^(ox)en/i, '\1' +# inflect.irregular 'person', 'people' +# inflect.uncountable %w( fish sheep ) +# end + +# Include your application configuration below + + +require 'name_part_finder' +require 'tracks/todo_list' +require 'tracks/config' +require 'tagging_extensions' # Needed for tagging-specific extensions +require 'digest/sha1' #Needed to support 'rake db:fixtures:load' on some ruby installs: http://dev.rousette.org.uk/ticket/557 + +if ( SITE_CONFIG['authentication_schemes'].include? 'ldap') + require 'net/ldap' #requires ruby-net-ldap gem be installed + require 'simple_ldap_authenticator' + ldap = SITE_CONFIG['ldap'] + SimpleLdapAuthenticator.ldap_library = ldap['library'] + SimpleLdapAuthenticator.servers = ldap['servers'] + SimpleLdapAuthenticator.use_ssl = ldap['ssl'] + SimpleLdapAuthenticator.login_format = ldap['login_format'] +end + +if ( SITE_CONFIG['authentication_schemes'].include? 'open_id') + #requires ruby-openid gem to be installed + OpenID::Util.logger = RAILS_DEFAULT_LOGGER +end + +if ( SITE_CONFIG['authentication_schemes'].include? 'cas') + #requires rubycas-client gem to be installed + if defined? CASClient + require 'casclient/frameworks/rails/filter' + CASClient::Frameworks::Rails::Filter.configure( + :cas_base_url => SITE_CONFIG['cas_server'] , + :cas_server_logout => SITE_CONFIG['cas_server_logout'] + ) + end +end + +# changed in development.rb to show under_construction bar +NOTIFY_BAR = "" unless defined?(NOTIFY_BAR) + +tracks_version='2.2devel' +# comment out next two lines if you do not want (or can not) the date of the +# last git commit in the footer +info=`git log --pretty=format:"%ai" -1` +tracks_version=tracks_version + ' ('+info+')' + +TRACKS_VERSION=tracks_version diff --git a/backup.rails2.3/lib/assets/.gitkeep b/backup.rails2.3/lib/assets/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/backup.rails2.3/lib/authenticated_test_helper.rb b/backup.rails2.3/lib/authenticated_test_helper.rb new file mode 100644 index 00000000..7a52e62b --- /dev/null +++ b/backup.rails2.3/lib/authenticated_test_helper.rb @@ -0,0 +1,113 @@ +module AuthenticatedTestHelper + # Sets the current user in the session from the user fixtures. + def login_as(user) + @request.session['user_id'] = user ? users(user).id : nil + end + + def content_type(type) + @request.env['Content-Type'] = type + end + + def accept(accept) + @request.env["HTTP_ACCEPT"] = accept + end + + def authorize_as(user) + if user + @request.env["HTTP_AUTHORIZATION"] = "Basic #{Base64.encode64("#{users(user).login}:test")}" + accept 'application/xml' + content_type 'application/xml' + else + @request.env["HTTP_AUTHORIZATION"] = nil + accept nil + content_type nil + end + end + + # http://project.ioni.st/post/217#post-217 + # + # def test_new_publication + # assert_difference(Publication, :count) do + # post :create, :publication => {...} + # # ... + # end + # end + # + def assert_difference(object, method = nil, difference = 1) + initial_value = object.send(method) + yield + assert_equal initial_value + difference, object.send(method), "#{object}##{method}" + end + + def assert_no_difference(object, method, &block) + assert_difference object, method, 0, &block + end + + # Assert the block redirects to the login + # + # assert_requires_login(:bob) { |c| c.get :edit, :id => 1 } + # + def assert_requires_login(login = nil) + yield HttpLoginProxy.new(self, login) + end + + def assert_http_authentication_required(login = nil) + yield XmlLoginProxy.new(self, login) + end + + def reset!(*instance_vars) + instance_vars = [:controller, :request, :response] unless instance_vars.any? + instance_vars.collect! { |v| "@#{v}".to_sym } + instance_vars.each do |var| + instance_variable_set(var, instance_variable_get(var).class.new) + end + end +end + +class BaseLoginProxy + attr_reader :controller + attr_reader :options + def initialize(controller, login) + @controller = controller + @login = login + end + + private + def authenticated + raise NotImplementedError + end + + def check + raise NotImplementedError + end + + def method_missing(method, *args) + @controller.reset! + authenticate + @controller.send(method, *args) + check + end +end + +class HttpLoginProxy < BaseLoginProxy + protected + def authenticate + @controller.login_as @login if @login + end + + def check + @controller.assert_redirected_to :controller => 'account', :action => 'login' + end +end + +class XmlLoginProxy < BaseLoginProxy + protected + def authenticate + @controller.accept 'application/xml' + @controller.authorize_as @login if @login + end + + def check + @controller.assert_response 401 + end +end \ No newline at end of file diff --git a/backup.rails2.3/lib/login_system.rb b/backup.rails2.3/lib/login_system.rb new file mode 100644 index 00000000..bc25de08 --- /dev/null +++ b/backup.rails2.3/lib/login_system.rb @@ -0,0 +1,222 @@ +require_dependency "user" + +module LoginSystem + + def current_user + get_current_user + end + + def prefs + current_user.prefs unless current_user.nil? + end + + # Logout the {#current_user} and redirect to login page + # + # @param [String] message notification to display + def logout_user message=t('login.logged_out') + @user.forget_me if logged_in? + cookies.delete :auth_token + session['user_id'] = nil + if ( SITE_CONFIG['authentication_schemes'].include? 'cas') && session[:cas_user] + CASClient::Frameworks::Rails::Filter.logout(self) + else + reset_session + notify :notice, message + redirect_to_login + end + end + + protected + + # overwrite this if you want to restrict access to only a few actions + # or if you want to check if the user has the correct rights + # example: + # + # # only allow nonbobs + # def authorize?(user) + # user.login != "bob" + # end + def authorize?(user) + true + end + + # overwrite this method if you only want to protect certain actions of the controller + # example: + # + # # don't protect the login and the about method + # def protect?(action) + # if ['action', 'about'].include?(action) + # return false + # else + # return true + # end + # end + def protect?(action) + true + end + + # When called with before_filter :login_from_cookie will check for an :auth_token + # cookie and log the user back in if appropriate + def login_from_cookie + return unless cookies[:auth_token] && !logged_in? + token = cookies[:auth_token] + user = User.where(:remember_token => token) + if user && user.remember_token? + session['user_id'] = user.id + set_current_user(user) + current_user.remember_me + cookies[:auth_token] = { :value => current_user.remember_token , :expires => current_user.remember_token_expires_at, :secure => SITE_CONFIG['secure_cookies'] } + flash[:notice] = t('login.successful') + end + end + + def login_or_feed_token_required + if ['rss', 'atom', 'txt', 'ics'].include?(params[:format]) + if user = User.find_by_token(params[:token]) + set_current_user(user) + return true + end + end + login_required + end + + # login_required filter. add + # + # before_filter :login_required + # + # if the controller should be under any rights management. + # for finer access control you can overwrite + # + # def authorize?(user) + # + def login_required + + if not protect?(action_name) + return true + end + + login_from_cookie + + if session['user_id'] and authorize?(get_current_user) + return true + end + + http_user, http_pass = get_basic_auth_data + if user = User.authenticate(http_user, http_pass) + session['user_id'] = user.id + set_current_user(user) + return true + end + + # store current location so that we can + # come back after the user logged in + store_location unless params[:format] == 'js' + + # call overwriteable reaction to unauthorized access + access_denied + return false + end + + def login_optional + + login_from_cookie + + if session['user_id'] and authorize?(get_current_user) + return true + end + + http_user, http_pass = get_basic_auth_data + if user = User.authenticate(http_user, http_pass) + session['user_id'] = user.id + set_current_user(user) + return true + end + + return true + end + + def logged_in? + current_user != nil + end + + def get_current_user + if @user.nil? && session['user_id'] + @user = User.find(session['user_id']) + end + @user + end + + def set_current_user(user) + @user = user + end + + # overwrite if you want to have special behavior in case the user is not authorized + # to access the current operation. + # the default action is to redirect to the login screen + # example use : + # a popup window might just close itself for instance + def access_denied + respond_to do |format| + format.html { redirect_to login_path } + format.m { redirect_to formatted_login_path(:format => 'm') } + format.js { render :partial => 'login/redirect_to_login' } + format.xml { basic_auth_denied } + format.rss { basic_auth_denied } + format.atom { basic_auth_denied } + format.text { basic_auth_denied } + end + end + + # store current uri in the session. + # we can return to this location by calling return_location + def store_location + session['return-to'] = request.request_uri + end + + # move to the last store_location call or to the passed default one + def redirect_back_or_default(default) + if session['return-to'].nil? + redirect_to default + else + redirect_to session['return-to'] + session['return-to'] = nil + end + end + + # HTTP Basic auth code adapted from Coda Hale's simple_http_auth plugin. Thanks, Coda! + def get_basic_auth_data + + auth_locations = ['REDIRECT_REDIRECT_X_HTTP_AUTHORIZATION', + 'REDIRECT_X_HTTP_AUTHORIZATION', + 'X-HTTP_AUTHORIZATION', 'HTTP_AUTHORIZATION'] + + authdata = nil + for location in auth_locations + if request.env.has_key?(location) + authdata = request.env[location].to_s.split + end + end + if authdata and authdata[0] == 'Basic' + user, pass = Base64.decode64(authdata[1]).split(':')[0..1] + else + user, pass = ['', ''] + end + return user, pass + end + + def basic_auth_denied + response.headers["WWW-Authenticate"] = "Basic realm=\"'Tracks Login Required'\"" + render :text => t('login.unsuccessful'), :status => 401 + end + +private + + # Redirect the user to the login page. + def redirect_to_login + respond_to do |format| + format.html { redirect_to login_path } + format.m { redirect_to login_path(:format => 'm') } + end + end + +end \ No newline at end of file diff --git a/backup.rails2.3/lib/name_part_finder.rb b/backup.rails2.3/lib/name_part_finder.rb new file mode 100644 index 00000000..79d66338 --- /dev/null +++ b/backup.rails2.3/lib/name_part_finder.rb @@ -0,0 +1,5 @@ +module NamePartFinder + def find_by_namepart(namepart) + find_by_name(namepart) || find(:first, :conditions => ["name LIKE ?", namepart + '%']) + end +end \ No newline at end of file diff --git a/backup.rails2.3/lib/tagging_extensions.rb b/backup.rails2.3/lib/tagging_extensions.rb new file mode 100644 index 00000000..2808f42a --- /dev/null +++ b/backup.rails2.3/lib/tagging_extensions.rb @@ -0,0 +1,200 @@ +class ActiveRecord::Base #:nodoc: + + # These extensions make models taggable. This file is automatically generated and required by your app if you run the tagging generator included with has_many_polymorphs. + module TaggingExtensions + + # Add tags to self. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags. + # + # We need to avoid name conflicts with the built-in ActiveRecord association methods, thus the underscores. + def _add_tags incoming + taggable?(true) + tag_cast_to_string(incoming).each do |tag_name| + # added following check to prevent empty tags from being saved (which will fail) + unless tag_name.blank? + begin + tag = Tag.find_or_create_by_name(tag_name) + raise Tag::Error, "tag could not be saved: #{tag_name}" if tag.new_record? + tags << tag + rescue ActiveRecord::StatementInvalid => e + raise unless e.to_s =~ /duplicate/i + end + end + end + end + + # Removes tags from self. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags. + def _remove_tags outgoing + taggable?(true) + outgoing = tag_cast_to_string(outgoing) + tags.delete(*(tags.select do |tag| + outgoing.include? tag.name + end)) + end + + # Returns the tags on self as a string. + def tag_list + # Redefined later to avoid an RDoc parse error. + end + + # Replace the existing tags on self. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags. + def tag_with list + #:stopdoc: + taggable?(true) + list = tag_cast_to_string(list) + + # Transactions may not be ideal for you here; be aware. + Tag.transaction do + current = tags.map(&:name) + _add_tags(list - current) + _remove_tags(current - list) + end + + self + #:startdoc: + end + + # Returns the tags on self as a string. + def tag_list #:nodoc: + #:stopdoc: + taggable?(true) + tags.reload + tags.to_s + #:startdoc: + end + + def tag_list=(value) + tag_with(value) + end + + private + + def tag_cast_to_string obj #:nodoc: + case obj + when Array + obj.map! do |item| + case item + # removed next line as it prevents using numbers as tags + # when /^\d+$/, Fixnum then Tag.find(item).name # This will be slow if you use ids a lot. + when Tag then item.name + when String then item + else + raise "Invalid type" + end + end + when String + obj = obj.split(Tag::DELIMITER).map do |tag_name| + tag_name.strip.squeeze(" ") + end + else + raise "Invalid object of class #{obj.class} as tagging method parameter" + end.flatten.compact.map(&:downcase).uniq + end + + # Check if a model is in the :taggables target list. The alternative to this check is to explicitly include a TaggingMethods module (which you would create) in each target model. + def taggable?(should_raise = false) #:nodoc: + unless flag = respond_to?(:tags) + raise "#{self.class} is not a taggable model" if should_raise + end + flag + end + + end + + module TaggingFinders + # Find all the objects tagged with the supplied list of tags + # + # Usage : Model.tagged_with("ruby") + # Model.tagged_with("hello", "world") + # Model.tagged_with("hello", "world", :limit => 10) + # + # XXX This query strategy is not performant, and needs to be rewritten as an inverted join or a series of unions + # + def tagged_with(*tag_list) + options = tag_list.last.is_a?(Hash) ? tag_list.pop : {} + tag_list = parse_tags(tag_list) + + scope = scope(:find) + options[:select] ||= "#{table_name}.*" + options[:from] ||= "#{table_name}, tags, taggings" + + sql = "SELECT #{(scope && scope[:select]) || options[:select]} " + sql << "FROM #{(scope && scope[:from]) || options[:from]} " + + add_joins!(sql, options[:joins], scope) + + sql << "WHERE #{table_name}.#{primary_key} = taggings.taggable_id " + sql << "AND taggings.taggable_type = '#{ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s}' " + sql << "AND taggings.tag_id = tags.id " + + tag_list_condition = tag_list.map {|name| "'#{name}'"}.join(", ") + + sql << "AND (tags.name IN (#{sanitize_sql(tag_list_condition)})) " + sql << "AND #{sanitize_sql(options[:conditions])} " if options[:conditions] + + columns = column_names.map do |column| + "#{table_name}.#{column}" + end.join(", ") + + sql << "GROUP BY #{columns} " + sql << "HAVING COUNT(taggings.tag_id) = #{tag_list.size}" + + add_order!(sql, options[:order], scope) + add_limit!(sql, options, scope) + add_lock!(sql, options, scope) + + find_by_sql(sql) + end + + def self.tagged_with_any(*tag_list) + options = tag_list.last.is_a?(Hash) ? tag_list.pop : {} + tag_list = parse_tags(tag_list) + + scope = scope(:find) + options[:select] ||= "#{table_name}.*" + options[:from] ||= "#{table_name}, meta_tags, taggings" + + sql = "SELECT #{(scope && scope[:select]) || options[:select]} " + sql << "FROM #{(scope && scope[:from]) || options[:from]} " + + add_joins!(sql, options, scope) + + sql << "WHERE #{table_name}.#{primary_key} = taggings.taggable_id " + sql << "AND taggings.taggable_type = '#{ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s}' " + sql << "AND taggings.meta_tag_id = meta_tags.id " + + sql << "AND (" + or_options = [] + tag_list.each do |name| + or_options << "meta_tags.name = '#{name}'" + end + or_options_joined = or_options.join(" OR ") + sql << "#{or_options_joined}) " + + + sql << "AND #{sanitize_sql(options[:conditions])} " if options[:conditions] + + columns = column_names.map do |column| + "#{table_name}.#{column}" + end.join(", ") + + sql << "GROUP BY #{columns} " + + add_order!(sql, options[:order], scope) + add_limit!(sql, options, scope) + add_lock!(sql, options, scope) + + find_by_sql(sql) + end + + def parse_tags(tags) + return [] if tags.blank? + tags = Array(tags).first + tags = tags.respond_to?(:flatten) ? tags.flatten : tags.split(Tag::DELIMITER) + tags.map { |tag| tag.strip.squeeze(" ") }.flatten.compact.map(&:downcase).uniq + end + + end + + include TaggingExtensions + extend TaggingFinders +end diff --git a/backup.rails2.3/lib/tasks/.gitkeep b/backup.rails2.3/lib/tasks/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/backup.rails2.3/lib/tasks/cucumber-tracks.rake b/backup.rails2.3/lib/tasks/cucumber-tracks.rake new file mode 100644 index 00000000..ae5bdfad --- /dev/null +++ b/backup.rails2.3/lib/tasks/cucumber-tracks.rake @@ -0,0 +1,38 @@ +# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. +# It is recommended to regenerate this file in the future when you upgrade to a +# newer version of cucumber-rails. Consider adding your own code to a new file +# instead of editing this one. Cucumber will automatically load all features/**/*.rb +# files. + +vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first +$LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil? + +begin + require 'cucumber/rake/task' + + namespace :cucumber do + Cucumber::Rake::Task.new({:selenium => :env_to_selenium}, 'Run features that require selenium') do |t| + t.binary = vendored_cucumber_bin + t.fork = true # You may get faster startup if you set this to false + t.profile = 'selenium' + end + + Cucumber::Rake::Task.new({:selenium_wip => :env_to_selenium}, 'Run unfinished features that require selenium') do |t| + t.binary = vendored_cucumber_bin + t.fork = true # You may get faster startup if you set this to false + t.profile = 'selenium_wip' + end + + task :env_to_selenium => 'db:test:prepare' do + ENV['RAILS_ENV'] = 'selenium' + end + + desc 'Run all features' + task :all => [:ok, :wip, :selenium, :selenium_wip] + end +rescue LoadError + desc 'cucumber rake task not available (cucumber not installed)' + task :cucumber do + abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin' + end +end \ No newline at end of file diff --git a/backup.rails2.3/lib/tasks/cucumber.rake b/backup.rails2.3/lib/tasks/cucumber.rake new file mode 100644 index 00000000..7db1a557 --- /dev/null +++ b/backup.rails2.3/lib/tasks/cucumber.rake @@ -0,0 +1,53 @@ +# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. +# It is recommended to regenerate this file in the future when you upgrade to a +# newer version of cucumber-rails. Consider adding your own code to a new file +# instead of editing this one. Cucumber will automatically load all features/**/*.rb +# files. + + +unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks + +vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first +$LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil? + +begin + require 'cucumber/rake/task' + + namespace :cucumber do + Cucumber::Rake::Task.new({:ok => 'db:test:prepare'}, 'Run features that should pass') do |t| + t.binary = vendored_cucumber_bin # If nil, the gem's binary is used. + t.fork = true # You may get faster startup if you set this to false + t.profile = 'default' + end + + Cucumber::Rake::Task.new({:wip => 'db:test:prepare'}, 'Run features that are being worked on') do |t| + t.binary = vendored_cucumber_bin + t.fork = true # You may get faster startup if you set this to false + t.profile = 'wip' + end + + Cucumber::Rake::Task.new({:rerun => 'db:test:prepare'}, 'Record failing features and run only them if any exist') do |t| + t.binary = vendored_cucumber_bin + t.fork = true # You may get faster startup if you set this to false + t.profile = 'rerun' + end + + desc 'Run all features' + task :all => [:ok, :wip] + end + desc 'Alias for cucumber:ok' + task :cucumber => 'cucumber:ok' + + task :default => :cucumber + + task :features => :cucumber do + STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***" + end +rescue LoadError + desc 'cucumber rake task not available (cucumber not installed)' + task :cucumber do + abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin' + end +end + +end diff --git a/backup.rails2.3/lib/tasks/database.rake b/backup.rails2.3/lib/tasks/database.rake new file mode 100644 index 00000000..eb02a45f --- /dev/null +++ b/backup.rails2.3/lib/tasks/database.rake @@ -0,0 +1,27 @@ +require 'rake' + +namespace :db do + desc "Dump the current SQLite3 or MySQL database to a sql file" + task :dump_sql do + load 'config/environment.rb' + abcs = ActiveRecord::Base.configurations + case abcs[RAILS_ENV]["adapter"] + when 'mysql' + ActiveRecord::Base.establish_connection(abcs[RAILS_ENV]) + File.open("db/#{RAILS_ENV}_data.sql", "w+") do |f| + if abcs[RAILS_ENV]["password"].blank? + f << `mysqldump -h #{abcs[RAILS_ENV]["host"]} -u #{abcs[RAILS_ENV]["username"]} #{abcs[RAILS_ENV]["database"]}` + else + f << `mysqldump -h #{abcs[RAILS_ENV]["host"]} -u #{abcs[RAILS_ENV]["username"]} -p#{abcs[RAILS_ENV]["password"]} #{abcs[RAILS_ENV]["database"]}` + end + end + when 'sqlite3' + ActiveRecord::Base.establish_connection(abcs[RAILS_ENV]) + File.open("db/#{RAILS_ENV}_data.sql", "w+") do |f| + f << `sqlite3 #{abcs[RAILS_ENV]["database"]} .dump` + end + else + raise "Task not supported by '#{abcs[RAILS_ENV]['adapter']}'" + end + end +end \ No newline at end of file diff --git a/backup.rails2.3/lib/tasks/extract_fixtures.rake b/backup.rails2.3/lib/tasks/extract_fixtures.rake new file mode 100644 index 00000000..f69683a3 --- /dev/null +++ b/backup.rails2.3/lib/tasks/extract_fixtures.rake @@ -0,0 +1,17 @@ +desc ' Create YAML test fixtures from data in an existing database. +Defaults to development database. Set RAILS_ENV to override (taken from Rails Recipes book).' +task :extract_fixtures => :environment do + sql = "SELECT * FROM %s" + skip_tables = ["schema_info", "sessions", "users"] + ActiveRecord::Base.establish_connection + (ActiveRecord::Base.connection.tables - skip_tables).each do |table_name| + i = "000" + File.open("#{RAILS_ROOT}/db/exported_fixtures/#{table_name}.yml", 'w' ) do |file| + data = ActiveRecord::Base.connection.select_all(sql % table_name) + file.write data.inject({}) { |hash, record| + hash["#{table_name}_#{i.succ!}"] = record + hash + }.to_yaml + end + end +end \ No newline at end of file diff --git a/backup.rails2.3/lib/tasks/gems.rake b/backup.rails2.3/lib/tasks/gems.rake new file mode 100644 index 00000000..464b787f --- /dev/null +++ b/backup.rails2.3/lib/tasks/gems.rake @@ -0,0 +1,34 @@ +desc "Copy third-party gems into ./lib" +task :freeze_other_gems do + # TODO Get this list from parsing environment.rb + libraries = %w(redcloth) + require 'rubygems' + require 'find' + + libraries.each do |library| + library_gem = Gem.cache.search(library).sort_by { |g| g.version }.last + puts "Freezing #{library} for #{library_gem.version}..." + + # TODO Add dependencies to list of libraries to freeze + #library_gem.dependencies.each { |g| libraries << g } + + folder_for_library = "#{library_gem.name}-#{library_gem.version}" + system "cd vendor; gem unpack -v '#{library_gem.version}' #{library_gem.name};" + + # Copy files recursively to ./lib + folder_for_library_with_lib = "vendor/#{folder_for_library}/lib/" + Find.find(folder_for_library_with_lib) do |original_file| + destination_file = "./lib/" + original_file.gsub(folder_for_library_with_lib, '') + + if File.directory?(original_file) + if !File.exist?(destination_file) + Dir.mkdir destination_file + end + else + File.copy original_file, destination_file + end + end + + system "rm -r vendor/#{folder_for_library}" + end +end diff --git a/backup.rails2.3/lib/tasks/load_exported_fixtures.rake b/backup.rails2.3/lib/tasks/load_exported_fixtures.rake new file mode 100644 index 00000000..10757471 --- /dev/null +++ b/backup.rails2.3/lib/tasks/load_exported_fixtures.rake @@ -0,0 +1,8 @@ +desc "Load exported fixtures (in db/exported_fixtures) into the current environment's database" +task :load_exported_fixtures => :environment do + require 'active_record/fixtures' + ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym) + Dir.glob(File.join(RAILS_ROOT, 'db', 'exported_fixtures', '*.{yml,csv}')).each do |fixture_file| + Fixtures.create_fixtures('db/exported_fixtures', File.basename(fixture_file, '.*')) + end +end \ No newline at end of file diff --git a/backup.rails2.3/lib/tasks/query_trace_toggle.rake b/backup.rails2.3/lib/tasks/query_trace_toggle.rake new file mode 100644 index 00000000..a6321541 --- /dev/null +++ b/backup.rails2.3/lib/tasks/query_trace_toggle.rake @@ -0,0 +1,50 @@ +namespace :query_trace do + desc "Enables the query_trace plugin. Must restart server to take effect." + task :on => :environment do + unless File.exist?("#{RAILS_ROOT}/vendor/query_trace.tar.gz") + Dir.chdir("#{RAILS_ROOT}/vendor") do + url = "https://terralien.devguard.com/svn/projects/plugins/query_trace" + puts "Loading query_trace from #{url}..." + system "svn co #{url} query_trace" + system "tar zcf query_trace.tar.gz --exclude=.svn query_trace" + FileUtils.rm_rf("query_trace") + end + end + Dir.chdir("#{RAILS_ROOT}/vendor/plugins") do + system "tar zxf ../query_trace.tar.gz query_trace" + end + puts "QueryTrace plugin enabled. Must restart server to take effect." + end + + desc "Disables the query_trace plugin. Must restart server to take effect." + task :off => :environment do + FileUtils.rm_rf("#{RAILS_ROOT}/vendor/plugins/query_trace") + puts "QueryTrace plugin disabled. Must restart server to take effect." + end +end + +namespace :query_analyzer do + desc "Enables the query_analyzer plugin. Must restart server to take effect." + task :on => :environment do + unless File.exist?("#{RAILS_ROOT}/vendor/query_analyzer.tar.gz") + Dir.chdir("#{RAILS_ROOT}/vendor") do + url = "http://svn.nfectio.us/plugins/query_analyzer" + puts "Loading query_analyzer from #{url}..." + system "svn co #{url} query_analyzer" + system "tar zcf query_analyzer.tar.gz --exclude=.svn query_analyzer" + FileUtils.rm_rf("query_analyzer") + end + end + Dir.chdir("#{RAILS_ROOT}/vendor/plugins") do + system "tar zxf ../query_analyzer.tar.gz query_analyzer" + end + puts "QueryAnalyzer plugin enabled. Must restart server to take effect." + end + + desc "Disables the query_analyzer plugin. Must restart server to take effect." + task :off => :environment do + FileUtils.rm_rf("#{RAILS_ROOT}/vendor/plugins/query_analyzer") + puts "QueryAnalyzer plugin disabled. Must restart server to take effect." + end +end + diff --git a/backup.rails2.3/lib/tasks/reset_password.rake b/backup.rails2.3/lib/tasks/reset_password.rake new file mode 100644 index 00000000..6cc61a60 --- /dev/null +++ b/backup.rails2.3/lib/tasks/reset_password.rake @@ -0,0 +1,23 @@ +namespace :tracks do + desc 'Replace the password of USER with a new one.' + task :password => :environment do + require "highline/import" + + user = User.find_by_login(ENV['USER']) + if user.nil? + puts "Sorry, we couldn't find user '#{ENV['USER']}'. To specify a different user, pass USER=username to this task." + exit 0 + end + + puts "Changing Tracks password for #{ENV['USER']}." + password = ask("New password: ") { |q| q.echo = false } + password_confirmation = ask('Retype new password: ') { |q| q.echo = false } + + begin + user.change_password(password, password_confirmation) + rescue ActiveRecord::RecordInvalid + puts "Sorry, we couldn't change #{ENV['USER']}'s password: " + user.errors.each_full { |msg| puts "- #{msg}\n" } + end + end +end diff --git a/backup.rails2.3/lib/tasks/rspec.rake b/backup.rails2.3/lib/tasks/rspec.rake new file mode 100644 index 00000000..dba3ffcc --- /dev/null +++ b/backup.rails2.3/lib/tasks/rspec.rake @@ -0,0 +1,144 @@ +gem 'test-unit', '1.2.3' if RUBY_VERSION.to_f >= 1.9 +rspec_gem_dir = nil +Dir["#{RAILS_ROOT}/vendor/gems/*"].each do |subdir| + rspec_gem_dir = subdir if subdir.gsub("#{RAILS_ROOT}/vendor/gems/","") =~ /^(\w+-)?rspec-(\d+)/ && File.exist?("#{subdir}/lib/spec/rake/spectask.rb") +end +rspec_plugin_dir = File.expand_path(File.dirname(__FILE__) + '/../../vendor/plugins/rspec') + +if rspec_gem_dir && (test ?d, rspec_plugin_dir) + raise "\n#{'*'*50}\nYou have rspec installed in both vendor/gems and vendor/plugins\nPlease pick one and dispose of the other.\n#{'*'*50}\n\n" +end + +if rspec_gem_dir + $LOAD_PATH.unshift("#{rspec_gem_dir}/lib") +elsif File.exist?(rspec_plugin_dir) + $LOAD_PATH.unshift("#{rspec_plugin_dir}/lib") +end + +# Don't load rspec if running "rake gems:*" +unless ARGV.any? {|a| a =~ /^gems/} + +begin + require 'spec/rake/spectask' +rescue MissingSourceFile + module Spec + module Rake + class SpecTask + def initialize(name) + task name do + # if rspec-rails is a configured gem, this will output helpful material and exit ... + require File.expand_path(File.join(File.dirname(__FILE__),"..","..","config","environment")) + + # ... otherwise, do this: + raise <<-MSG + +#{"*" * 80} +* You are trying to run an rspec rake task defined in +* #{__FILE__}, +* but rspec can not be found in vendor/gems, vendor/plugins or system gems. +#{"*" * 80} +MSG + end + end + end + end + end +end + +Rake.application.instance_variable_get('@tasks').delete('default') + +spec_prereq = File.exist?(File.join(RAILS_ROOT, 'config', 'database.yml')) ? "db:test:prepare" : :noop +task :noop do +end + +task :default => :spec +task :stats => "spec:statsetup" + +desc "Run all specs in spec directory (excluding plugin specs)" +Spec::Rake::SpecTask.new(:spec => spec_prereq) do |t| + t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""] + t.spec_files = FileList['spec/**/*_spec.rb'] +end + +namespace :spec do + desc "Run all specs in spec directory with RCov (excluding plugin specs)" + Spec::Rake::SpecTask.new(:rcov) do |t| + t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""] + t.spec_files = FileList['spec/**/*_spec.rb'] + t.rcov = true + t.rcov_opts = lambda do + IO.readlines("#{RAILS_ROOT}/spec/rcov.opts").map {|l| l.chomp.split " "}.flatten + end + end + + desc "Print Specdoc for all specs (excluding plugin specs)" + Spec::Rake::SpecTask.new(:doc) do |t| + t.spec_opts = ["--format", "specdoc", "--dry-run"] + t.spec_files = FileList['spec/**/*_spec.rb'] + end + + desc "Print Specdoc for all plugin examples" + Spec::Rake::SpecTask.new(:plugin_doc) do |t| + t.spec_opts = ["--format", "specdoc", "--dry-run"] + t.spec_files = FileList['vendor/plugins/**/spec/**/*_spec.rb'].exclude('vendor/plugins/rspec/*') + end + + [:models, :controllers, :views, :helpers, :lib, :integration].each do |sub| + desc "Run the code examples in spec/#{sub}" + Spec::Rake::SpecTask.new(sub => spec_prereq) do |t| + t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""] + t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"] + end + end + + desc "Run the code examples in vendor/plugins (except RSpec's own)" + Spec::Rake::SpecTask.new(:plugins => spec_prereq) do |t| + t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""] + t.spec_files = FileList['vendor/plugins/**/spec/**/*_spec.rb'].exclude('vendor/plugins/rspec/*').exclude("vendor/plugins/rspec-rails/*") + end + + namespace :plugins do + desc "Runs the examples for rspec_on_rails" + Spec::Rake::SpecTask.new(:rspec_on_rails) do |t| + t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""] + t.spec_files = FileList['vendor/plugins/rspec-rails/spec/**/*_spec.rb'] + end + end + + # Setup specs for stats + task :statsetup do + require 'code_statistics' + ::STATS_DIRECTORIES << %w(Model\ specs spec/models) if File.exist?('spec/models') + ::STATS_DIRECTORIES << %w(View\ specs spec/views) if File.exist?('spec/views') + ::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers) if File.exist?('spec/controllers') + ::STATS_DIRECTORIES << %w(Helper\ specs spec/helpers) if File.exist?('spec/helpers') + ::STATS_DIRECTORIES << %w(Library\ specs spec/lib) if File.exist?('spec/lib') + ::STATS_DIRECTORIES << %w(Routing\ specs spec/routing) if File.exist?('spec/routing') + ::STATS_DIRECTORIES << %w(Integration\ specs spec/integration) if File.exist?('spec/integration') + ::CodeStatistics::TEST_TYPES << "Model specs" if File.exist?('spec/models') + ::CodeStatistics::TEST_TYPES << "View specs" if File.exist?('spec/views') + ::CodeStatistics::TEST_TYPES << "Controller specs" if File.exist?('spec/controllers') + ::CodeStatistics::TEST_TYPES << "Helper specs" if File.exist?('spec/helpers') + ::CodeStatistics::TEST_TYPES << "Library specs" if File.exist?('spec/lib') + ::CodeStatistics::TEST_TYPES << "Routing specs" if File.exist?('spec/routing') + ::CodeStatistics::TEST_TYPES << "Integration specs" if File.exist?('spec/integration') + end + + namespace :db do + namespace :fixtures do + desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z." + task :load => :environment do + ActiveRecord::Base.establish_connection(Rails.env) + base_dir = File.join(Rails.root, 'spec', 'fixtures') + fixtures_dir = ENV['FIXTURES_DIR'] ? File.join(base_dir, ENV['FIXTURES_DIR']) : base_dir + + require 'active_record/fixtures' + (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/).map {|f| File.join(fixtures_dir, f) } : Dir.glob(File.join(fixtures_dir, '*.{yml,csv}'))).each do |fixture_file| + Fixtures.create_fixtures(File.dirname(fixture_file), File.basename(fixture_file, '.*')) + end + end + end + end +end + +end diff --git a/backup.rails2.3/lib/tasks/setup_tracks.rake b/backup.rails2.3/lib/tasks/setup_tracks.rake new file mode 100644 index 00000000..0881dfb3 --- /dev/null +++ b/backup.rails2.3/lib/tasks/setup_tracks.rake @@ -0,0 +1,15 @@ +desc "Initialises the installation, copy the *.tmpl files and directories to versions named without the .tmpl extension. It won't overwrite the files and directories if you've already copied them. You need to manually copy database.yml.tmpl -> database.yml and fill in the details before you run this task." +task :setup_tracks => :environment do + # Check the root directory for template files + FileList["*.tmpl"].each do |template_file| + f = File.basename(template_file) # with suffix + f_only = File.basename(template_file,".tmpl") # without suffix + if File.exists?(f_only) + puts f_only + " already exists" + else + cp_r(f, f_only) + puts f_only + " created" + end + end + +end \ No newline at end of file diff --git a/backup.rails2.3/lib/tasks/upgrade_sqlite_db.rake b/backup.rails2.3/lib/tasks/upgrade_sqlite_db.rake new file mode 100644 index 00000000..8e96fb18 --- /dev/null +++ b/backup.rails2.3/lib/tasks/upgrade_sqlite_db.rake @@ -0,0 +1,40 @@ +desc "Updates sqlite/sqlite3 databases created under Tracks 1.03 to the format required for Tracks 1.04. After this is done, you should be able to keep up to date with changes in the schema by running rake db:migrate." +task :upgrade_sqlite_db => :environment do + # Change the three lines below appropriately for your setup + old_db = "tracks_103.db" + new_db = "tracks_104.db" + cmd = "sqlite3" + replace_string = "update todos set done='f' where done=0;\nupdate todos set done='t' where done=1;\nupdate contexts set hide='f' where hide=0;\nupdate contexts set hide='t' where hide=1;\nupdate projects set done='f' where done=0;\nupdate projects set done='t' where done=1;\nCREATE TABLE 'schema_info' (\n 'version' INTEGER default NULL\n);\nINSERT INTO \"schema_info\" VALUES(1);\nCOMMIT;" + + # cd to the db directory + cd("db") do + # Dump the old db into the temp file and replace the tinyints with booleans + `#{cmd} #{old_db} .dump | sed "s/tinyint(4) NOT NULL default '0'/boolean default 'f'/" > temp.sql` + # Create a second sqldump file for writing + sqldump = File.open("temp2.sql", "w+") + File.open("temp.sql") do |file| + file.each_line do |line| + # If COMMIT is on the line, insert the replace string + # else just write the line back in + # This effectively replaces COMMIT with the replace string + if /COMMIT/ =~ line + sqldump.write replace_string + else + sqldump.write line + end + end + sqldump.close + end + + # Read the second dump back in to a new db + system "#{cmd} #{new_db} < temp2.sql" + puts "Created the a new database called #{new_db}." + # Clean up the temp files + rm("temp.sql") + rm("temp2.sql") + puts "Temporary files cleaned up." + end + + # rake db:migrate + puts "Now check the database and run 'rake db:migrate' in the root of your Tracks installation." +end \ No newline at end of file diff --git a/backup.rails2.3/lib/tracks/config.rb b/backup.rails2.3/lib/tracks/config.rb new file mode 100644 index 00000000..0ca04f97 --- /dev/null +++ b/backup.rails2.3/lib/tracks/config.rb @@ -0,0 +1,27 @@ +module Tracks + class Config + def self.salt + SITE_CONFIG['salt'] + end + + def self.auth_schemes + SITE_CONFIG['authentication_schemes'] || [] + end + + def self.openid_enabled? + auth_schemes.include?('open_id') + end + + def self.cas_enabled? + auth_schemes.include?('cas') + end + + def self.prefered_auth? + if SITE_CONFIG['prefered_auth'] + SITE_CONFIG['prefered_auth'] + else + auth_schemes.first + end + end + end +end \ No newline at end of file diff --git a/backup.rails2.3/lib/tracks/source_view.rb b/backup.rails2.3/lib/tracks/source_view.rb new file mode 100644 index 00000000..8cb17ca8 --- /dev/null +++ b/backup.rails2.3/lib/tracks/source_view.rb @@ -0,0 +1,68 @@ +# Inspiration from Bruce Williams [http://codefluency.com/articles/2006/07/01/rails-views-getting-in-context/] +module Tracks + + module SourceViewSwitching + + class Responder + + def initialize(source_view) + @source_view = source_view.underscore.gsub(/\s+/,'_').to_sym rescue nil + end + + def nil? + yield if @source_view.nil? && block_given? + end + + def context + yield if :context == @source_view && block_given? + end + + def method_missing(check_source_view,*args) + yield if check_source_view == @source_view && block_given? + end + + end + + module Controller + + def self.included(base) + base.send(:helper, Tracks::SourceViewSwitching::Helper) + base.send(:helper_method, :source_view) + end + + def source_view_is( s ) + s == (params[:_source_view] || @source_view).to_sym + end + + def source_view_is_one_of( *s ) + s.include?(params[:_source_view].to_sym) + end + + def source_view + responder = Tracks::SourceViewSwitching::Responder.new(params[:_source_view] || @source_view) + block_given? ? yield(responder) : responder + end + + end + + module Helper + + def source_view_tag(name) + hidden_field_tag :_source_view, name.underscore.gsub(/\s+/,'_') + end + + def source_view_is( s ) + s == (params[:_source_view] || @source_view).to_sym + end + + def source_view_is_one_of( *s ) + s.include?(params[:_source_view].to_sym) + end + + end + + end + +end + +ActionController::Base.send(:include, Tracks::SourceViewSwitching::Controller) diff --git a/backup.rails2.3/lib/tracks/todo_list.rb b/backup.rails2.3/lib/tracks/todo_list.rb new file mode 100644 index 00000000..b1a32229 --- /dev/null +++ b/backup.rails2.3/lib/tracks/todo_list.rb @@ -0,0 +1,59 @@ +module Tracks + module TodoList + # TODO: this module should be deprecated. This could mostly (all?) be replaced by named scopes) + + def not_done_todos(opts={}) + @not_done_todos ||= self.find_not_done_todos(opts) + end + + def done_todos + @done_todos ||= self.find_done_todos + end + + def deferred_todos + @deferred_todos ||= self.find_deferred_todos + end + + def find_not_done_todos(opts={}) + with_not_done_scope(opts) do + self.todos.find(:all, :order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC") + end + end + + def find_deferred_todos(opts={}) + self.todos.find_in_state(:all, :deferred, :order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC") + end + + def find_done_todos + self.todos.completed.all(:order => "todos.completed_at DESC", :limit => self.user.prefs.show_number_completed) + end + + def not_done_todo_count(opts={}) + with_not_done_scope(opts) do + self.todos.count + end + end + + def with_not_done_scope(opts={}) + conditions = ["todos.state = ?", 'active'] + if opts.has_key?(:include_project_hidden_todos) && (opts[:include_project_hidden_todos] == true) + conditions = ["(todos.state = ? OR todos.state = ?)", 'active', 'project_hidden'] + end + if opts.has_key?(:tag) + conditions = ["todos.state = ? AND taggings.tag_id = ?", 'active', opts[:tag]] + end + self.todos.send :with_scope, :find => {:conditions => conditions, :include => [:taggings]} do + yield + end + end + + def done_todo_count + self.todos.count_in_state(:completed) + end + + def deferred_todo_count + self.todos.count_in_state(:deferred) + end + + end +end diff --git a/backup.rails2.3/mongrel_workaround.rb b/backup.rails2.3/mongrel_workaround.rb new file mode 100644 index 00000000..60b207b9 --- /dev/null +++ b/backup.rails2.3/mongrel_workaround.rb @@ -0,0 +1,107 @@ +# adapted from https://gist.github.com/471663 and https://rails.lighthouseapp.com/projects/8994/tickets/4690-mongrel-doesnt-work-with-rails-238 + +def check_mongrel_around_115 +begin + # Gem.available? is deprecated from rubygems 1.8.2 + Gem::Specification::find_by_name "mongrel", "~>1.1.5" + rescue + if RUBY_VERSION[2] == "9" + false + else + Gem.available?('mongrel', '~>1.1.5') + end + end +end + +mongrel115 = check_mongrel_around_115 + +if Rails.version == '2.3.14' && mongrel115 && self.class.const_defined?(:Mongrel) + + # Pulled right from latest rack. Old looked like this in 1.1.0 version. + # + # def [](k) + # super(@names[k] ||= @names[k.downcase]) + # end + # + module Rack + module Utils + class HeaderHash < Hash + def [](k) + super(@names[k]) if @names[k] + super(@names[k.downcase]) + end + end + end + end + + # Code pulled from the ticket above. + # + class Mongrel::CGIWrapper + def header_with_rails_fix(options = 'text/html') + @head['cookie'] = options.delete('cookie').flatten.map { |v| v.sub(/^\n/,'') } if options.class != String and options['cookie'] + header_without_rails_fix(options) + end + alias_method_chain :header, :rails_fix + end + + # Pulled right from 2.3.10 ActionPack. Simple diff was + # + # if headers.include?('Set-Cookie') + # headers['cookie'] = headers.delete('Set-Cookie').split("\n") + # end + # + # to + # + # if headers['Set-Cookie'] + # headers['cookie'] = headers.delete('Set-Cookie').split("\n") + # end + # + module ActionController + class CGIHandler + def self.dispatch_cgi(app, cgi, out = $stdout) + env = cgi.__send__(:env_table) + env.delete "HTTP_CONTENT_LENGTH" + + cgi.stdinput.extend ProperStream + + env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" + + env.update({ + "rack.version" => [0,1], + "rack.input" => cgi.stdinput, + "rack.errors" => $stderr, + "rack.multithread" => false, + "rack.multiprocess" => true, + "rack.run_once" => false, + "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http" + }) + + env["QUERY_STRING"] ||= "" + env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] + env["REQUEST_PATH"] ||= "/" + env.delete "PATH_INFO" if env["PATH_INFO"] == "" + + status, headers, body = app.call(env) + begin + out.binmode if out.respond_to?(:binmode) + out.sync = false if out.respond_to?(:sync=) + + headers['Status'] = status.to_s + + if headers['Set-Cookie'] + headers['cookie'] = headers.delete('Set-Cookie').split("\n") + end + + out.write(cgi.header(headers)) + + body.each { |part| + out.write part + out.flush if out.respond_to?(:flush) + } + ensure + body.close if body.respond_to?(:close) + end + end + end + end +end diff --git a/backup.rails2.3/new_rails_defaults.rb b/backup.rails2.3/new_rails_defaults.rb new file mode 100644 index 00000000..c94db0a6 --- /dev/null +++ b/backup.rails2.3/new_rails_defaults.rb @@ -0,0 +1,21 @@ +# Be sure to restart your server when you modify this file. + +# These settings change the behavior of Rails 2 apps and will be defaults +# for Rails 3. You can remove this initializer when Rails 3 is released. + +if defined?(ActiveRecord) + # Include Active Record class name as root for JSON serialized output. + ActiveRecord::Base.include_root_in_json = true + + # Store the full class name (including module namespace) in STI type column. + ActiveRecord::Base.store_full_sti_class = true +end + +ActionController::Routing.generate_best_match = false + +# Use ISO 8601 format for JSON serialized times and dates. +ActiveSupport.use_standard_json_time_format = true + +# Don't escape HTML entities in JSON, leave that for the #json_escape helper. +# if you're including raw json in an HTML page. +ActiveSupport.escape_html_entities_in_json = false \ No newline at end of file diff --git a/backup.rails2.3/plugins/extra_validations/init.rb b/backup.rails2.3/plugins/extra_validations/init.rb new file mode 100644 index 00000000..17709ad4 --- /dev/null +++ b/backup.rails2.3/plugins/extra_validations/init.rb @@ -0,0 +1,2 @@ +require 'extra_validations' +ActiveRecord::Base.extend ExtraValidations \ No newline at end of file diff --git a/backup.rails2.3/plugins/extra_validations/lib/extra_validations.rb b/backup.rails2.3/plugins/extra_validations/lib/extra_validations.rb new file mode 100644 index 00000000..be50b659 --- /dev/null +++ b/backup.rails2.3/plugins/extra_validations/lib/extra_validations.rb @@ -0,0 +1,29 @@ +module ExtraValidations + + # Validates the value of the specified attribute by checking for a forbidden string + # + # class Person < ActiveRecord::Base + # validates_does_not_contain :first_name, :string => ',' + # end + # + # A string must be provided or else an exception will be raised. + # + # Configuration options: + # * message - A custom error message (default is: "is invalid") + # * string - The string to verify is not included (note: must be supplied!) + # * on Specifies when this validation is active (default is :save, other options :create, :update) + # * if - Specifies a method, proc or string to call to determine if the validation should + # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The + # method, proc or string should return or evaluate to a true or false value. + def validates_does_not_contain(*attr_names) + configuration = { :message => I18n.translate('activerecord.errors.messages')[:invalid], :on => :save, :string => nil } + configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash) + + raise(ArgumentError, "A string must be supplied as the :string option of the configuration hash") unless configuration[:string].is_a?(String) + + validates_each(attr_names, configuration) do |record, attr_name, value| + record.errors.add(attr_name, configuration[:message]) if value.to_s =~ Regexp.new(Regexp.escape(configuration[:string])) + end + end + +end diff --git a/backup.rails2.3/plugins/open_id_authentication/CHANGELOG b/backup.rails2.3/plugins/open_id_authentication/CHANGELOG new file mode 100644 index 00000000..7349bd3c --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/CHANGELOG @@ -0,0 +1,35 @@ +* Fake HTTP method from OpenID server since they only support a GET. Eliminates the need to set an extra route to match the server's reply. [Josh Peek] + +* OpenID 2.0 recommends that forms should use the field name "openid_identifier" rather than "openid_url" [Josh Peek] + +* Return open_id_response.display_identifier to the application instead of .endpoints.claimed_id. [nbibler] + +* Add Timeout protection [Rick] + +* An invalid identity url passed through authenticate_with_open_id will no longer raise an InvalidOpenId exception. Instead it will return Result[:missing] to the completion block. + +* Allow a return_to option to be used instead of the requested url [Josh Peek] + +* Updated plugin to use Ruby OpenID 2.x.x [Josh Peek] + +* Tied plugin to ruby-openid 1.1.4 gem until we can make it compatible with 2.x [DHH] + +* Use URI instead of regexps to normalize the URL and gain free, better matching #8136 [dkubb] + +* Allow -'s in #normalize_url [Rick] + +* remove instance of mattr_accessor, it was breaking tests since they don't load ActiveSupport. Fix Timeout test [Rick] + +* Throw a InvalidOpenId exception instead of just a RuntimeError when the URL can't be normalized [DHH] + +* Just use the path for the return URL, so extra query parameters don't interfere [DHH] + +* Added a new default database-backed store after experiencing trouble with the filestore on NFS. The file store is still available as an option [DHH] + +* Added normalize_url and applied it to all operations going through the plugin [DHH] + +* Removed open_id? as the idea of using the same input box for both OpenID and username has died -- use using_open_id? instead (which checks for the presence of params[:openid_url] by default) [DHH] + +* Added OpenIdAuthentication::Result to make it easier to deal with default situations where you don't care to do something particular for each error state [DHH] + +* Stop relying on root_url being defined, we can just grab the current url instead [DHH] \ No newline at end of file diff --git a/backup.rails2.3/plugins/open_id_authentication/README b/backup.rails2.3/plugins/open_id_authentication/README new file mode 100644 index 00000000..807cdc75 --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/README @@ -0,0 +1,231 @@ +OpenIdAuthentication +==================== + +Provides a thin wrapper around the excellent ruby-openid gem from JanRan. Be sure to install that first: + + gem install ruby-openid + +To understand what OpenID is about and how it works, it helps to read the documentation for lib/openid/consumer.rb +from that gem. + +The specification used is http://openid.net/specs/openid-authentication-2_0.html. + + +Prerequisites +============= + +OpenID authentication uses the session, so be sure that you haven't turned that off. It also relies on a number of +database tables to store the authentication keys. So you'll have to run the migration to create these before you get started: + + rake open_id_authentication:db:create + +Or, use the included generators to install or upgrade: + + ./script/generate open_id_authentication_tables MigrationName + ./script/generate upgrade_open_id_authentication_tables MigrationName + +Alternatively, you can use the file-based store, which just relies on on tmp/openids being present in RAILS_ROOT. But be aware that this store only works if you have a single application server. And it's not safe to use across NFS. It's recommended that you use the database store if at all possible. To use the file-based store, you'll also have to add this line to your config/environment.rb: + + OpenIdAuthentication.store = :file + +This particular plugin also relies on the fact that the authentication action allows for both POST and GET operations. +If you're using RESTful authentication, you'll need to explicitly allow for this in your routes.rb. + +The plugin also expects to find a root_url method that points to the home page of your site. You can accomplish this by using a root route in config/routes.rb: + + map.root :controller => 'articles' + +This plugin relies on Rails Edge revision 6317 or newer. + + +Example +======= + +This example is just to meant to demonstrate how you could use OpenID authentication. You might well want to add +salted hash logins instead of plain text passwords and other requirements on top of this. Treat it as a starting point, +not a destination. + +Note that the User model referenced in the simple example below has an 'identity_url' attribute. You will want to add the same or similar field to whatever +model you are using for authentication. + +Also of note is the following code block used in the example below: + + authenticate_with_open_id do |result, identity_url| + ... + end + +In the above code block, 'identity_url' will need to match user.identity_url exactly. 'identity_url' will be a string in the form of 'http://example.com' - +If you are storing just 'example.com' with your user, the lookup will fail. + +There is a handy method in this plugin called 'normalize_url' that will help with validating OpenID URLs. + + OpenIdAuthentication.normalize_url(user.identity_url) + +The above will return a standardized version of the OpenID URL - the above called with 'example.com' will return 'http://example.com/' +It will also raise an InvalidOpenId exception if the URL is determined to not be valid. +Use the above code in your User model and validate OpenID URLs before saving them. + +config/routes.rb + + map.root :controller => 'articles' + map.resource :session + + +app/views/sessions/new.erb + + <% form_tag(session_url) do %> +

        + + <%= text_field_tag "name" %> +

        + +

        + + <%= password_field_tag %> +

        + +

        + ...or use: +

        + +

        + + <%= text_field_tag "openid_identifier" %> +

        + +

        + <%= submit_tag 'Sign in', :disable_with => "Signing in…" %> +

        + <% end %> + +app/controllers/sessions_controller.rb + class SessionsController < ApplicationController + def create + if using_open_id? + open_id_authentication + else + password_authentication(params[:name], params[:password]) + end + end + + + protected + def password_authentication(name, password) + if @current_user = @account.users.authenticate(params[:name], params[:password]) + successful_login + else + failed_login "Sorry, that username/password doesn't work" + end + end + + def open_id_authentication + authenticate_with_open_id do |result, identity_url| + if result.successful? + if @current_user = @account.users.find_by_identity_url(identity_url) + successful_login + else + failed_login "Sorry, no user by that identity URL exists (#{identity_url})" + end + else + failed_login result.message + end + end + end + + + private + def successful_login + session[:user_id] = @current_user.id + redirect_to(root_url) + end + + def failed_login(message) + flash[:error] = message + redirect_to(new_session_url) + end + end + + + +If you're fine with the result messages above and don't need individual logic on a per-failure basis, +you can collapse the case into a mere boolean: + + def open_id_authentication + authenticate_with_open_id do |result, identity_url| + if result.successful? && @current_user = @account.users.find_by_identity_url(identity_url) + successful_login + else + failed_login(result.message || "Sorry, no user by that identity URL exists (#{identity_url})") + end + end + end + + +Simple Registration OpenID Extension +==================================== + +Some OpenID Providers support this lightweight profile exchange protocol. See more: http://www.openidenabled.com/openid/simple-registration-extension + +You can support it in your app by changing #open_id_authentication + + def open_id_authentication(identity_url) + # Pass optional :required and :optional keys to specify what sreg fields you want. + # Be sure to yield registration, a third argument in the #authenticate_with_open_id block. + authenticate_with_open_id(identity_url, + :required => [ :nickname, :email ], + :optional => :fullname) do |result, identity_url, registration| + case result.status + when :missing + failed_login "Sorry, the OpenID server couldn't be found" + when :invalid + failed_login "Sorry, but this does not appear to be a valid OpenID" + when :canceled + failed_login "OpenID verification was canceled" + when :failed + failed_login "Sorry, the OpenID verification failed" + when :successful + if @current_user = @account.users.find_by_identity_url(identity_url) + assign_registration_attributes!(registration) + + if current_user.save + successful_login + else + failed_login "Your OpenID profile registration failed: " + + @current_user.errors.full_messages.to_sentence + end + else + failed_login "Sorry, no user by that identity URL exists" + end + end + end + end + + # registration is a hash containing the valid sreg keys given above + # use this to map them to fields of your user model + def assign_registration_attributes!(registration) + model_to_registration_mapping.each do |model_attribute, registration_attribute| + unless registration[registration_attribute].blank? + @current_user.send("#{model_attribute}=", registration[registration_attribute]) + end + end + end + + def model_to_registration_mapping + { :login => 'nickname', :email => 'email', :display_name => 'fullname' } + end + +Attribute Exchange OpenID Extension +=================================== + +Some OpenID providers also support the OpenID AX (attribute exchange) protocol for exchanging identity information between endpoints. See more: http://openid.net/specs/openid-attribute-exchange-1_0.html + +Accessing AX data is very similar to the Simple Registration process, described above -- just add the URI identifier for the AX field to your :optional or :required parameters. For example: + + authenticate_with_open_id(identity_url, + :required => [ :email, 'http://schema.openid.net/birthDate' ]) do |result, identity_url, registration| + +This would provide the sreg data for :email, and the AX data for 'http://schema.openid.net/birthDate' + + + +Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license \ No newline at end of file diff --git a/backup.rails2.3/plugins/open_id_authentication/Rakefile b/backup.rails2.3/plugins/open_id_authentication/Rakefile new file mode 100644 index 00000000..31074b85 --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/Rakefile @@ -0,0 +1,22 @@ +require 'rake' +require 'rake/testtask' +require 'rake/rdoctask' + +desc 'Default: run unit tests.' +task :default => :test + +desc 'Test the open_id_authentication plugin.' +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.pattern = 'test/**/*_test.rb' + t.verbose = true +end + +desc 'Generate documentation for the open_id_authentication plugin.' +Rake::RDocTask.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'rdoc' + rdoc.title = 'OpenIdAuthentication' + rdoc.options << '--line-numbers' << '--inline-source' + rdoc.rdoc_files.include('README') + rdoc.rdoc_files.include('lib/**/*.rb') +end diff --git a/backup.rails2.3/plugins/open_id_authentication/generators/open_id_authentication_tables/open_id_authentication_tables_generator.rb b/backup.rails2.3/plugins/open_id_authentication/generators/open_id_authentication_tables/open_id_authentication_tables_generator.rb new file mode 100644 index 00000000..6f78afc7 --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/generators/open_id_authentication_tables/open_id_authentication_tables_generator.rb @@ -0,0 +1,11 @@ +class OpenIdAuthenticationTablesGenerator < Rails::Generator::NamedBase + def initialize(runtime_args, runtime_options = {}) + super + end + + def manifest + record do |m| + m.migration_template 'migration.rb', 'db/migrate' + end + end +end diff --git a/backup.rails2.3/plugins/open_id_authentication/generators/open_id_authentication_tables/templates/migration.rb b/backup.rails2.3/plugins/open_id_authentication/generators/open_id_authentication_tables/templates/migration.rb new file mode 100644 index 00000000..ef2a0cfb --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/generators/open_id_authentication_tables/templates/migration.rb @@ -0,0 +1,20 @@ +class <%= class_name %> < ActiveRecord::Migration + def self.up + create_table :open_id_authentication_associations, :force => true do |t| + t.integer :issued, :lifetime + t.string :handle, :assoc_type + t.binary :server_url, :secret + end + + create_table :open_id_authentication_nonces, :force => true do |t| + t.integer :timestamp, :null => false + t.string :server_url, :null => true + t.string :salt, :null => false + end + end + + def self.down + drop_table :open_id_authentication_associations + drop_table :open_id_authentication_nonces + end +end diff --git a/backup.rails2.3/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/templates/migration.rb b/backup.rails2.3/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/templates/migration.rb new file mode 100644 index 00000000..d13bbab2 --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/templates/migration.rb @@ -0,0 +1,26 @@ +class <%= class_name %> < ActiveRecord::Migration + def self.up + drop_table :open_id_authentication_settings + drop_table :open_id_authentication_nonces + + create_table :open_id_authentication_nonces, :force => true do |t| + t.integer :timestamp, :null => false + t.string :server_url, :null => true + t.string :salt, :null => false + end + end + + def self.down + drop_table :open_id_authentication_nonces + + create_table :open_id_authentication_nonces, :force => true do |t| + t.integer :created + t.string :nonce + end + + create_table :open_id_authentication_settings, :force => true do |t| + t.string :setting + t.binary :value + end + end +end diff --git a/backup.rails2.3/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/upgrade_open_id_authentication_tables_generator.rb b/backup.rails2.3/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/upgrade_open_id_authentication_tables_generator.rb new file mode 100644 index 00000000..02fddd7f --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/upgrade_open_id_authentication_tables_generator.rb @@ -0,0 +1,11 @@ +class UpgradeOpenIdAuthenticationTablesGenerator < Rails::Generator::NamedBase + def initialize(runtime_args, runtime_options = {}) + super + end + + def manifest + record do |m| + m.migration_template 'migration.rb', 'db/migrate' + end + end +end diff --git a/backup.rails2.3/plugins/open_id_authentication/init.rb b/backup.rails2.3/plugins/open_id_authentication/init.rb new file mode 100644 index 00000000..808c7bdb --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/init.rb @@ -0,0 +1,18 @@ +if config.respond_to?(:gems) + config.gem 'ruby-openid', :lib => 'openid', :version => '>=2.0.4' +else + begin + require 'openid' + rescue LoadError + begin + gem 'ruby-openid', '>=2.0.4' + rescue Gem::LoadError + puts "Install the ruby-openid gem to enable OpenID support" + end + end +end + +config.to_prepare do + OpenID::Util.logger = Rails.logger + ActionController::Base.send :include, OpenIdAuthentication +end diff --git a/backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication.rb b/backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication.rb new file mode 100644 index 00000000..b485c5fe --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication.rb @@ -0,0 +1,240 @@ +require 'uri' +require 'openid/extensions/sreg' +require 'openid/extensions/ax' +require 'openid/store/filesystem' + +require File.dirname(__FILE__) + '/open_id_authentication/association' +require File.dirname(__FILE__) + '/open_id_authentication/nonce' +require File.dirname(__FILE__) + '/open_id_authentication/db_store' +require File.dirname(__FILE__) + '/open_id_authentication/request' +require File.dirname(__FILE__) + '/open_id_authentication/timeout_fixes' if OpenID::VERSION == "2.0.4" + +module OpenIdAuthentication + OPEN_ID_AUTHENTICATION_DIR = RAILS_ROOT + "/tmp/openids" + + def self.store + @@store + end + + def self.store=(*store_option) + store, *parameters = *([ store_option ].flatten) + + @@store = case store + when :db + OpenIdAuthentication::DbStore.new + when :file + OpenID::Store::Filesystem.new(OPEN_ID_AUTHENTICATION_DIR) + else + store + end + end + + self.store = :db + + class InvalidOpenId < StandardError + end + + class Result + ERROR_MESSAGES = { + :missing => "Sorry, the OpenID server couldn't be found", + :invalid => "Sorry, but this does not appear to be a valid OpenID", + :canceled => "OpenID verification was canceled", + :failed => "OpenID verification failed", + :setup_needed => "OpenID verification needs setup" + } + + def self.[](code) + new(code) + end + + def initialize(code) + @code = code + end + + def status + @code + end + + ERROR_MESSAGES.keys.each { |state| define_method("#{state}?") { @code == state } } + + def successful? + @code == :successful + end + + def unsuccessful? + ERROR_MESSAGES.keys.include?(@code) + end + + def message + ERROR_MESSAGES[@code] + end + end + + # normalizes an OpenID according to http://openid.net/specs/openid-authentication-2_0.html#normalization + def self.normalize_identifier(identifier) + # clean up whitespace + identifier = identifier.to_s.strip + + # if an XRI has a prefix, strip it. + identifier.gsub!(/xri:\/\//i, '') + + # dodge XRIs -- TODO: validate, don't just skip. + unless ['=', '@', '+', '$', '!', '('].include?(identifier.at(0)) + # does it begin with http? if not, add it. + identifier = "http://#{identifier}" unless identifier =~ /^http/i + + # strip any fragments + identifier.gsub!(/\#(.*)$/, '') + + begin + uri = URI.parse(identifier) + uri.scheme = uri.scheme.downcase # URI should do this + identifier = uri.normalize.to_s + rescue URI::InvalidURIError + raise InvalidOpenId.new("#{identifier} is not an OpenID identifier") + end + end + + return identifier + end + + # deprecated for OpenID 2.0, where not all OpenIDs are URLs + def self.normalize_url(url) + ActiveSupport::Deprecation.warn "normalize_url has been deprecated, use normalize_identifier instead" + self.normalize_identifier(url) + end + + protected + def normalize_url(url) + OpenIdAuthentication.normalize_url(url) + end + + def normalize_identifier(url) + OpenIdAuthentication.normalize_identifier(url) + end + + # The parameter name of "openid_identifier" is used rather than the Rails convention "open_id_identifier" + # because that's what the specification dictates in order to get browser auto-complete working across sites + def using_open_id?(identity_url = nil) #:doc: + identity_url ||= params[:openid_identifier] || params[:openid_url] + !identity_url.blank? || params[:open_id_complete] + end + + def authenticate_with_open_id(identity_url = nil, options = {}, &block) #:doc: + identity_url ||= params[:openid_identifier] || params[:openid_url] + + if params[:open_id_complete].nil? + begin_open_id_authentication(identity_url, options, &block) + else + complete_open_id_authentication(&block) + end + end + + private + def begin_open_id_authentication(identity_url, options = {}) + identity_url = normalize_identifier(identity_url) + return_to = options.delete(:return_to) + method = options.delete(:method) + + options[:required] ||= [] # reduces validation later + options[:optional] ||= [] + + open_id_request = open_id_consumer.begin(identity_url) + add_simple_registration_fields(open_id_request, options) + add_ax_fields(open_id_request, options) + redirect_to(open_id_redirect_url(open_id_request, return_to, method)) + rescue OpenIdAuthentication::InvalidOpenId => e + yield Result[:invalid], identity_url, nil + rescue OpenID::OpenIDError, Timeout::Error => e + logger.error("[OPENID] #{e}") + yield Result[:missing], identity_url, nil + end + + def complete_open_id_authentication + params_with_path = params.reject { |key, value| request.path_parameters[key] } + params_with_path.delete(:format) + open_id_response = timeout_protection_from_identity_server { open_id_consumer.complete(params_with_path, requested_url) } + identity_url = normalize_identifier(open_id_response.display_identifier) if open_id_response.display_identifier + + case open_id_response.status + when OpenID::Consumer::SUCCESS + profile_data = {} + + # merge the SReg data and the AX data into a single hash of profile data + [ OpenID::SReg::Response, OpenID::AX::FetchResponse ].each do |data_response| + if data_response.from_success_response( open_id_response ) + profile_data.merge! data_response.from_success_response( open_id_response ).data + end + end + + yield Result[:successful], identity_url, profile_data + when OpenID::Consumer::CANCEL + yield Result[:canceled], identity_url, nil + when OpenID::Consumer::FAILURE + yield Result[:failed], identity_url, nil + when OpenID::Consumer::SETUP_NEEDED + yield Result[:setup_needed], open_id_response.setup_url, nil + end + end + + def open_id_consumer + OpenID::Consumer.new(session, OpenIdAuthentication.store) + end + + def add_simple_registration_fields(open_id_request, fields) + sreg_request = OpenID::SReg::Request.new + + # filter out AX identifiers (URIs) + required_fields = fields[:required].collect { |f| f.to_s unless f =~ /^https?:\/\// }.compact + optional_fields = fields[:optional].collect { |f| f.to_s unless f =~ /^https?:\/\// }.compact + + sreg_request.request_fields(required_fields, true) unless required_fields.blank? + sreg_request.request_fields(optional_fields, false) unless optional_fields.blank? + sreg_request.policy_url = fields[:policy_url] if fields[:policy_url] + open_id_request.add_extension(sreg_request) + end + + def add_ax_fields( open_id_request, fields ) + ax_request = OpenID::AX::FetchRequest.new + + # look through the :required and :optional fields for URIs (AX identifiers) + fields[:required].each do |f| + next unless f =~ /^https?:\/\// + ax_request.add( OpenID::AX::AttrInfo.new( f, nil, true ) ) + end + + fields[:optional].each do |f| + next unless f =~ /^https?:\/\// + ax_request.add( OpenID::AX::AttrInfo.new( f, nil, false ) ) + end + + open_id_request.add_extension( ax_request ) + end + + def open_id_redirect_url(open_id_request, return_to = nil, method = nil) + open_id_request.return_to_args['_method'] = (method || request.method).to_s + open_id_request.return_to_args['open_id_complete'] = '1' + open_id_request.redirect_url(root_url, return_to || requested_url) + end + + def requested_url + relative_url_root = self.class.respond_to?(:relative_url_root) ? + self.class.relative_url_root.to_s : + request.relative_url_root + "#{request.protocol}#{request.host_with_port}#{ActionController::Base.relative_url_root}#{request.path}" + end + + def timeout_protection_from_identity_server + yield + rescue Timeout::Error + Class.new do + def status + OpenID::FAILURE + end + + def msg + "Identity server timed out" + end + end.new + end +end diff --git a/backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/association.rb b/backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/association.rb new file mode 100644 index 00000000..9654eaeb --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/association.rb @@ -0,0 +1,9 @@ +module OpenIdAuthentication + class Association < ActiveRecord::Base + set_table_name :open_id_authentication_associations + + def from_record + OpenID::Association.new(handle, secret, issued, lifetime, assoc_type) + end + end +end diff --git a/backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/db_store.rb b/backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/db_store.rb new file mode 100644 index 00000000..780fb6ad --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/db_store.rb @@ -0,0 +1,55 @@ +require 'openid/store/interface' + +module OpenIdAuthentication + class DbStore < OpenID::Store::Interface + def self.cleanup_nonces + now = Time.now.to_i + Nonce.delete_all(["timestamp > ? OR timestamp < ?", now + OpenID::Nonce.skew, now - OpenID::Nonce.skew]) + end + + def self.cleanup_associations + now = Time.now.to_i + Association.delete_all(['issued + lifetime > ?',now]) + end + + def store_association(server_url, assoc) + remove_association(server_url, assoc.handle) + Association.create(:server_url => server_url, + :handle => assoc.handle, + :secret => assoc.secret, + :issued => assoc.issued, + :lifetime => assoc.lifetime, + :assoc_type => assoc.assoc_type) + end + + def get_association(server_url, handle = nil) + assocs = if handle.blank? + Association.find_all_by_server_url(server_url) + else + Association.find_all_by_server_url_and_handle(server_url, handle) + end + + assocs.reverse.each do |assoc| + a = assoc.from_record + if a.expires_in == 0 + assoc.destroy + else + return a + end + end if assocs.any? + + return nil + end + + def remove_association(server_url, handle) + Association.delete_all(['server_url = ? AND handle = ?', server_url, handle]) > 0 + end + + def use_nonce(server_url, timestamp, salt) + return false if Nonce.find_by_server_url_and_timestamp_and_salt(server_url, timestamp, salt) + return false if (timestamp - Time.now.to_i).abs > OpenID::Nonce.skew + Nonce.create(:server_url => server_url, :timestamp => timestamp, :salt => salt) + return true + end + end +end diff --git a/backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/nonce.rb b/backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/nonce.rb new file mode 100644 index 00000000..c52f6c50 --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/nonce.rb @@ -0,0 +1,5 @@ +module OpenIdAuthentication + class Nonce < ActiveRecord::Base + set_table_name :open_id_authentication_nonces + end +end diff --git a/backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/request.rb b/backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/request.rb new file mode 100644 index 00000000..e0cc8e3f --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/request.rb @@ -0,0 +1,23 @@ +module OpenIdAuthentication + module Request + def self.included(base) + base.alias_method_chain :request_method, :openid + end + + def request_method_with_openid + if !parameters[:_method].blank? && parameters[:open_id_complete] == '1' + parameters[:_method].to_sym + else + request_method_without_openid + end + end + end +end + +# In Rails 2.3, the request object has been renamed +# from AbstractRequest to Request +if defined? ActionController::Request + ActionController::Request.send :include, OpenIdAuthentication::Request +else + ActionController::AbstractRequest.send :include, OpenIdAuthentication::Request +end diff --git a/backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/timeout_fixes.rb b/backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/timeout_fixes.rb new file mode 100644 index 00000000..cc711c9a --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/lib/open_id_authentication/timeout_fixes.rb @@ -0,0 +1,20 @@ +# http://trac.openidenabled.com/trac/ticket/156 +module OpenID + @@timeout_threshold = 20 + + def self.timeout_threshold + @@timeout_threshold + end + + def self.timeout_threshold=(value) + @@timeout_threshold = value + end + + class StandardFetcher + def make_http(uri) + http = @proxy.new(uri.host, uri.port) + http.read_timeout = http.open_timeout = OpenID.timeout_threshold + http + end + end +end \ No newline at end of file diff --git a/backup.rails2.3/plugins/open_id_authentication/tasks/open_id_authentication_tasks.rake b/backup.rails2.3/plugins/open_id_authentication/tasks/open_id_authentication_tasks.rake new file mode 100644 index 00000000..c71434a5 --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/tasks/open_id_authentication_tasks.rake @@ -0,0 +1,30 @@ +namespace :open_id_authentication do + namespace :db do + desc "Creates authentication tables for use with OpenIdAuthentication" + task :create => :environment do + generate_migration(["open_id_authentication_tables", "add_open_id_authentication_tables"]) + end + + desc "Upgrade authentication tables from ruby-openid 1.x.x to 2.x.x" + task :upgrade => :environment do + generate_migration(["upgrade_open_id_authentication_tables", "upgrade_open_id_authentication_tables"]) + end + + def generate_migration(args) + require 'rails_generator' + require 'rails_generator/scripts/generate' + + if ActiveRecord::Base.connection.supports_migrations? + Rails::Generator::Scripts::Generate.new.run(args) + else + raise "Task unavailable to this database (no migration support)" + end + end + + desc "Clear the authentication tables" + task :clear => :environment do + OpenIdAuthentication::DbStore.cleanup_nonces + OpenIdAuthentication::DbStore.cleanup_associations + end + end +end diff --git a/backup.rails2.3/plugins/open_id_authentication/test/normalize_test.rb b/backup.rails2.3/plugins/open_id_authentication/test/normalize_test.rb new file mode 100644 index 00000000..635d3abc --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/test/normalize_test.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/test_helper' + +class NormalizeTest < Test::Unit::TestCase + include OpenIdAuthentication + + NORMALIZATIONS = { + "openid.aol.com/nextangler" => "http://openid.aol.com/nextangler", + "http://openid.aol.com/nextangler" => "http://openid.aol.com/nextangler", + "https://openid.aol.com/nextangler" => "https://openid.aol.com/nextangler", + "HTTP://OPENID.AOL.COM/NEXTANGLER" => "http://openid.aol.com/NEXTANGLER", + "HTTPS://OPENID.AOL.COM/NEXTANGLER" => "https://openid.aol.com/NEXTANGLER", + "loudthinking.com" => "http://loudthinking.com/", + "http://loudthinking.com" => "http://loudthinking.com/", + "http://loudthinking.com:80" => "http://loudthinking.com/", + "https://loudthinking.com:443" => "https://loudthinking.com/", + "http://loudthinking.com:8080" => "http://loudthinking.com:8080/", + "techno-weenie.net" => "http://techno-weenie.net/", + "http://techno-weenie.net" => "http://techno-weenie.net/", + "http://techno-weenie.net " => "http://techno-weenie.net/", + "=name" => "=name" + } + + def test_normalizations + NORMALIZATIONS.each do |from, to| + assert_equal to, normalize_identifier(from) + end + end + + def test_broken_open_id + assert_raises(InvalidOpenId) { normalize_identifier(nil) } + end +end diff --git a/backup.rails2.3/plugins/open_id_authentication/test/open_id_authentication_test.rb b/backup.rails2.3/plugins/open_id_authentication/test/open_id_authentication_test.rb new file mode 100644 index 00000000..ddcc17b9 --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/test/open_id_authentication_test.rb @@ -0,0 +1,46 @@ +require File.dirname(__FILE__) + '/test_helper' + +class OpenIdAuthenticationTest < Test::Unit::TestCase + def setup + @controller = Class.new do + include OpenIdAuthentication + def params() {} end + end.new + end + + def test_authentication_should_fail_when_the_identity_server_is_missing + open_id_consumer = mock() + open_id_consumer.expects(:begin).raises(OpenID::OpenIDError) + @controller.expects(:open_id_consumer).returns(open_id_consumer) + @controller.expects(:logger).returns(mock(:error => true)) + + @controller.send(:authenticate_with_open_id, "http://someone.example.com") do |result, identity_url| + assert result.missing? + assert_equal "Sorry, the OpenID server couldn't be found", result.message + end + end + + def test_authentication_should_be_invalid_when_the_identity_url_is_invalid + @controller.send(:authenticate_with_open_id, "!") do |result, identity_url| + assert result.invalid?, "Result expected to be invalid but was not" + assert_equal "Sorry, but this does not appear to be a valid OpenID", result.message + end + end + + def test_authentication_should_fail_when_the_identity_server_times_out + open_id_consumer = mock() + open_id_consumer.expects(:begin).raises(Timeout::Error, "Identity Server took too long.") + @controller.expects(:open_id_consumer).returns(open_id_consumer) + @controller.expects(:logger).returns(mock(:error => true)) + + @controller.send(:authenticate_with_open_id, "http://someone.example.com") do |result, identity_url| + assert result.missing? + assert_equal "Sorry, the OpenID server couldn't be found", result.message + end + end + + def test_authentication_should_begin_when_the_identity_server_is_present + @controller.expects(:begin_open_id_authentication) + @controller.send(:authenticate_with_open_id, "http://someone.example.com") + end +end diff --git a/backup.rails2.3/plugins/open_id_authentication/test/status_test.rb b/backup.rails2.3/plugins/open_id_authentication/test/status_test.rb new file mode 100644 index 00000000..b1d5e093 --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/test/status_test.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/test_helper' + +class StatusTest < Test::Unit::TestCase + include OpenIdAuthentication + + def test_state_conditional + assert Result[:missing].missing? + assert Result[:missing].unsuccessful? + assert !Result[:missing].successful? + + assert Result[:successful].successful? + assert !Result[:successful].unsuccessful? + end +end \ No newline at end of file diff --git a/backup.rails2.3/plugins/open_id_authentication/test/test_helper.rb b/backup.rails2.3/plugins/open_id_authentication/test/test_helper.rb new file mode 100644 index 00000000..43216e1e --- /dev/null +++ b/backup.rails2.3/plugins/open_id_authentication/test/test_helper.rb @@ -0,0 +1,17 @@ +require 'test/unit' +require 'rubygems' + +gem 'activesupport' +require 'active_support' + +gem 'actionpack' +require 'action_controller' + +gem 'mocha' +require 'mocha' + +gem 'ruby-openid' +require 'openid' + +RAILS_ROOT = File.dirname(__FILE__) unless defined? RAILS_ROOT +require File.dirname(__FILE__) + "/../lib/open_id_authentication" diff --git a/backup.rails2.3/plugins/resource_feeder/README b/backup.rails2.3/plugins/resource_feeder/README new file mode 100644 index 00000000..5502be25 --- /dev/null +++ b/backup.rails2.3/plugins/resource_feeder/README @@ -0,0 +1,7 @@ +ResourceFeeder +============== + +Simple feeds for resources + +NOTE: This plugin depends on the latest version of simply_helpful, available here: +http://dev.rubyonrails.org/svn/rails/plugins/simply_helpful/ diff --git a/backup.rails2.3/plugins/resource_feeder/Rakefile b/backup.rails2.3/plugins/resource_feeder/Rakefile new file mode 100644 index 00000000..51fce7b3 --- /dev/null +++ b/backup.rails2.3/plugins/resource_feeder/Rakefile @@ -0,0 +1,22 @@ +require 'rake' +require 'rake/testtask' +require 'rake/rdoctask' + +desc 'Default: run unit tests.' +task :default => :test + +desc 'Test the resource_feed plugin.' +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.pattern = 'test/**/*_test.rb' + t.verbose = true +end + +desc 'Generate documentation for the resource_feed plugin.' +Rake::RDocTask.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'rdoc' + rdoc.title = 'ResourceFeed' + rdoc.options << '--line-numbers' << '--inline-source' + rdoc.rdoc_files.include('README') + rdoc.rdoc_files.include('lib/**/*.rb') +end diff --git a/backup.rails2.3/plugins/resource_feeder/init.rb b/backup.rails2.3/plugins/resource_feeder/init.rb new file mode 100644 index 00000000..7b55d76f --- /dev/null +++ b/backup.rails2.3/plugins/resource_feeder/init.rb @@ -0,0 +1,2 @@ +require 'resource_feeder' +ActionController::Base.send(:include, ResourceFeeder::Rss, ResourceFeeder::Atom) \ No newline at end of file diff --git a/backup.rails2.3/plugins/resource_feeder/lib/resource_feeder.rb b/backup.rails2.3/plugins/resource_feeder/lib/resource_feeder.rb new file mode 100644 index 00000000..b5003419 --- /dev/null +++ b/backup.rails2.3/plugins/resource_feeder/lib/resource_feeder.rb @@ -0,0 +1,2 @@ +require 'resource_feeder/rss' +require 'resource_feeder/atom' diff --git a/backup.rails2.3/plugins/resource_feeder/lib/resource_feeder/atom.rb b/backup.rails2.3/plugins/resource_feeder/lib/resource_feeder/atom.rb new file mode 100644 index 00000000..40af87df --- /dev/null +++ b/backup.rails2.3/plugins/resource_feeder/lib/resource_feeder/atom.rb @@ -0,0 +1,67 @@ +require 'resource_feeder/common' + +module ResourceFeeder + module Atom + include ResourceFeeder::Common + include ActionController::Routing + extend self + + def render_atom_feed_for(resources, options = {}) + render :text => atom_feed_for(resources, options), :content_type => Mime::ATOM + end + + def atom_feed_for(resources, options = {}) + xml = Builder::XmlMarkup.new(:indent => 2) + + options[:feed] ||= {} + options[:item] ||= {} + options[:url_writer] ||= self + + if options[:class] || resources.first + klass = options[:class] || resources.first.class + new_record = klass.new + else + options[:feed] = { :title => "Empty", :link => "http://example.com" } + end + + options[:feed][:title] ||= klass.name.pluralize + options[:feed][:id] ||= "tag:#{request.host_with_port}:#{klass.name.pluralize}" + options[:feed][:link] ||= polymorphic_url(new_record, :controller => options[:url_writer].controller_name) + + options[:item][:title] ||= [ :title, :subject, :headline, :name ] + options[:item][:description] ||= [ :description, :body, :content ] + options[:item][:pub_date] ||= [ :updated_at, :updated_on, :created_at, :created_on ] + options[:item][:author] ||= [ :author, :creator ] + + resource_link = lambda { |r| polymorphic_url(r, :controller => options[:url_writer].controller_name) } + + xml.instruct! + xml.feed "xml:lang" => "en-US", "xmlns" => 'http://www.w3.org/2005/Atom' do + xml.title(options[:feed][:title]) + xml.id(options[:feed][:id]) + xml.link(:rel => 'alternate', :type => 'text/html', :href => options[:feed][:link]) + xml.link(:rel => 'self', :type => 'application/atom+xml', :href => options[:feed][:self]) if options[:feed][:self] + xml.subtitle(options[:feed][:description]) if options[:feed][:description] + + for resource in resources + published_at = call_or_read(options[:item][:pub_date], resource) + + xml.entry do + xml.title(call_or_read(options[:item][:title], resource)) + xml.content(call_or_read(options[:item][:description], resource), :type => 'html') + xml.id("tag:#{request.host_with_port},#{published_at.xmlschema}:#{call_or_read(options[:item][:guid] || options[:item][:link] || resource_link, resource)}") + xml.published(published_at.xmlschema) + xml.updated((resource.respond_to?(:updated_at) ? call_or_read(options[:item][:pub_date] || :updated_at, resource) : published_at).xmlschema) + xml.link(:rel => 'alternate', :type => 'text/html', :href => call_or_read(options[:item][:link] || options[:item][:guid] || resource_link, resource)) + + if author = call_or_read(options[:item][:author], resource) + xml.author do + xml.name() + end + end + end + end + end + end + end +end diff --git a/backup.rails2.3/plugins/resource_feeder/lib/resource_feeder/common.rb b/backup.rails2.3/plugins/resource_feeder/lib/resource_feeder/common.rb new file mode 100644 index 00000000..383b965e --- /dev/null +++ b/backup.rails2.3/plugins/resource_feeder/lib/resource_feeder/common.rb @@ -0,0 +1,24 @@ +module ResourceFeeder + module Common + private + def call_or_read(procedure_or_attributes, resource) + case procedure_or_attributes + when nil + raise ArgumentError, "WTF is nil here? #{resource.inspect}" + when Array + attributes = procedure_or_attributes + if attr = attributes.select { |a| resource.respond_to?(a) }.first + resource.send attr + end + when Symbol + attribute = procedure_or_attributes + resource.send(attribute) + when Proc + procedure = procedure_or_attributes + procedure.call(resource) + else + raise ArgumentError, "WTF is #{procedure_or_attributes.inspect} here? #{resource.inspect}" + end + end + end +end diff --git a/backup.rails2.3/plugins/resource_feeder/lib/resource_feeder/rss.rb b/backup.rails2.3/plugins/resource_feeder/lib/resource_feeder/rss.rb new file mode 100644 index 00000000..d3fa56d7 --- /dev/null +++ b/backup.rails2.3/plugins/resource_feeder/lib/resource_feeder/rss.rb @@ -0,0 +1,68 @@ +require 'resource_feeder/common' + +module ResourceFeeder + module Rss + include ResourceFeeder::Common + include ActionController::Routing + extend self + + def render_rss_feed_for(resources, options = {}) + render :text => rss_feed_for(resources, options), :content_type => Mime::RSS + end + + def rss_feed_for(resources, options = {}) + xml = Builder::XmlMarkup.new(:indent => 2) + + options[:feed] ||= {} + options[:item] ||= {} + options[:url_writer] ||= self + + if options[:class] || resources.first + klass = options[:class] || resources.first.class + new_record = klass.new + else + options[:feed] = { :title => "Empty", :link => "http://example.com" } + end + use_content_encoded = options[:item].has_key?(:content_encoded) + + options[:feed][:title] ||= klass.name.pluralize + options[:feed][:link] ||= polymorphic_url(new_record, :controller => options[:url_writer].controller_name) + options[:feed][:language] ||= "en-us" + options[:feed][:ttl] ||= "40" + + options[:item][:title] ||= [ :title, :subject, :headline, :name ] + options[:item][:description] ||= [ :description, :body, :content ] + options[:item][:pub_date] ||= [ :updated_at, :updated_on, :created_at, :created_on ] + + resource_link = lambda { |r| polymorphic_url(r, :controller => options[:url_writer].controller_name) } + + rss_root_attributes = { :version => 2.0 } + rss_root_attributes.merge!("xmlns:content" => "http://purl.org/rss/1.0/modules/content/") if use_content_encoded + + xml.instruct! + + xml.rss(rss_root_attributes) do + xml.channel do + xml.title(options[:feed][:title]) + xml.link(options[:feed][:link]) + xml.description(options[:feed][:description]) if options[:feed][:description] + xml.language(options[:feed][:language]) + xml.ttl(options[:feed][:ttl]) + + for resource in resources + xml.item do + xml.title(call_or_read(options[:item][:title], resource)) + xml.description(call_or_read(options[:item][:description], resource)) + if use_content_encoded then + xml.content(:encoded) { xml.cdata!(call_or_read(options[:item][:content_encoded], resource)) } + end + xml.pubDate(call_or_read(options[:item][:pub_date], resource).to_s(:rfc822)) + xml.guid(call_or_read(options[:item][:guid] || options[:item][:link] || resource_link, resource)) + xml.link(call_or_read(options[:item][:link] || options[:item][:guid] || resource_link, resource)) + end + end + end + end + end + end +end diff --git a/backup.rails2.3/plugins/resource_feeder/test/atom_feed_test.rb b/backup.rails2.3/plugins/resource_feeder/test/atom_feed_test.rb new file mode 100644 index 00000000..3112da47 --- /dev/null +++ b/backup.rails2.3/plugins/resource_feeder/test/atom_feed_test.rb @@ -0,0 +1,85 @@ +require File.dirname(__FILE__) + '/test_helper' +class AtomFeedTest < Test::Unit::TestCase + attr_reader :request + + def setup + @request = OpenStruct.new + @request.host_with_port = 'example.com' + @records = Array.new(5).fill(Post.new) + @records.each &:save + end + + def test_default_atom_feed + atom_feed_for @records + + assert_select 'feed' do + assert_select '>title', 'Posts' + assert_select '>id', "tag:#{request.host_with_port}:Posts" + assert_select '>link' do + assert_select "[rel='alternate']" + assert_select "[type='text/html']" + assert_select "[href='http://example.com/posts']" + end + assert_select 'entry', 5 do + assert_select 'title', :text => 'feed title (title)' + assert_select "content[type='html']", '<p>feed description (description)</p>' + assert_select 'id', "tag:#{request.host_with_port},#{@records.first.created_at.xmlschema}:#{'http://example.com/posts/1'}" + assert_select 'published', @records.first.created_at.xmlschema + assert_select 'updated', @records.first.created_at.xmlschema + assert_select 'link' do + assert_select "[rel='alternate']" + assert_select "[type='text/html']" + assert_select "[href='http://example.com/posts/1']" + end + end + end + end + + def test_should_allow_custom_feed_options + atom_feed_for @records, :feed => { :title => 'Custom Posts', :link => '/posts', :description => 'stuff', :self => '/posts.atom' } + + assert_select 'feed>title', 'Custom Posts' + assert_select "feed>link[href='/posts']" + assert_select 'feed>subtitle', 'stuff' + assert_select 'feed>link' do + assert_select "[rel='self']" + assert_select "[type='application/atom+xml']" + assert_select "[href='/posts.atom']" + end + end + + def test_should_allow_custom_item_attributes + atom_feed_for @records, :item => { :title => :name, :description => :body, :pub_date => :create_date, :link => :id } + + assert_select 'entry', 5 do + assert_select 'title', :text => 'feed title (name)' + assert_select "content[type='html']", '<p>feed description (body)</p>' + assert_select 'published', (@records.first.created_at - 5.minutes).xmlschema + assert_select 'updated', (@records.first.created_at - 5.minutes).xmlschema + assert_select 'id', "tag:#{request.host_with_port},#{(@records.first.created_at - 5.minutes).xmlschema}:1" + assert_select 'link' do + assert_select "[rel='alternate']" + assert_select "[type='text/html']" + assert_select "[href='1']" + end + end + end + + def test_should_allow_custom_item_attribute_blocks + atom_feed_for @records, :item => { :title => lambda { |r| r.name }, :description => lambda { |r| r.body }, :pub_date => lambda { |r| r.create_date }, + :link => lambda { |r| "/#{r.created_at.to_i}" }, :guid => lambda { |r| r.created_at.to_i } } + + assert_select 'entry', 5 do + assert_select 'title', :text => 'feed title (name)' + assert_select "content[type='html']", '<p>feed description (body)</p>' + assert_select 'published', (@records.first.created_at - 5.minutes).xmlschema + assert_select 'updated', (@records.first.created_at - 5.minutes).xmlschema + assert_select 'id', /:\d+$/ + assert_select 'link' do + assert_select "[rel='alternate']" + assert_select "[type='text/html']" + assert_select "[href=?]", /^\/\d+$/ + end + end + end +end diff --git a/backup.rails2.3/plugins/resource_feeder/test/rss_feed_test.rb b/backup.rails2.3/plugins/resource_feeder/test/rss_feed_test.rb new file mode 100644 index 00000000..90525baf --- /dev/null +++ b/backup.rails2.3/plugins/resource_feeder/test/rss_feed_test.rb @@ -0,0 +1,86 @@ +require File.dirname(__FILE__) + '/test_helper' +class RssFeedTest < Test::Unit::TestCase + def setup + @records = Array.new(5).fill(Post.new) + @records.each &:save + end + + def test_default_rss_feed + rss_feed_for @records + + assert_select 'rss[version="2.0"]' do + assert_select 'channel' do + assert_select '>title', 'Posts' + assert_select '>link', 'http://example.com/posts' + assert_select 'language', 'en-us' + assert_select 'ttl', '40' + end + assert_select 'item', 5 do + assert_select 'title', :text => 'feed title (title)' + assert_select 'description', '<p>feed description (description)</p>' + %w(guid link).each do |node| + assert_select node, 'http://example.com/posts/1' + end + assert_select 'pubDate', @records.first.created_at.to_s(:rfc822) + end + end + end + + def test_should_allow_custom_feed_options + rss_feed_for @records, :feed => { :title => 'Custom Posts', :link => '/posts', :description => 'stuff', :language => 'en-gb', :ttl => '80' } + + assert_select 'channel>title', 'Custom Posts' + assert_select 'channel>link', '/posts' + assert_select 'channel>description', 'stuff' + assert_select 'channel>language', 'en-gb' + assert_select 'channel>ttl', '80' + end + + def test_should_allow_custom_item_attributes + rss_feed_for @records, :item => { :title => :name, :description => :body, :pub_date => :create_date, :link => :id } + + assert_select 'item', 5 do + assert_select 'title', :text => 'feed title (name)' + assert_select 'description', '<p>feed description (body)</p>' + assert_select 'pubDate', (@records.first.created_at - 5.minutes).to_s(:rfc822) + assert_select 'link', '1' + assert_select 'guid', '1' + end + end + + def test_should_allow_custom_item_attribute_blocks + rss_feed_for @records, :item => { :title => lambda { |r| r.name }, :description => lambda { |r| r.body }, :pub_date => lambda { |r| r.create_date }, + :link => lambda { |r| "/#{r.created_at.to_i}" }, :guid => lambda { |r| r.created_at.to_i } } + + assert_select 'item', 5 do + assert_select 'title', :text => 'feed title (name)' + assert_select 'description', '<p>feed description (body)</p>' + assert_select 'pubDate', (@records.first.created_at - 5.minutes).to_s(:rfc822) + end + end + + # note that assert_select isnt easily able to get elements that have xml namespaces (as it thinks they are + # invalid html psuedo children), so we do some manual testing with the response body + def test_should_allow_content_encoded_for_items + rss_feed_for @records, :item => { :content_encoded => :full_html_body } + + html_content = "Here is some full content, with out any excerpts" + assert_equal 5, @response.body.scan("").size + assert_select 'item', 5 do + assert_select 'description + *', " { :content_encoded => :full_html_body } + assert_equal %[\n], + @response.body.grep(/\n], + @response.body.grep(/feed description (#{attr_name})

        " + end + end + + def full_html_body + "Here is some full content, with out any excerpts" + end + + def create_date + @created_at - 5.minutes + end +end + +class Test::Unit::TestCase + include ResourceFeeder::Rss, ResourceFeeder::Atom + + def render_feed(xml) + @response = OpenStruct.new + @response.headers = {'Content-Type' => 'text/xml'} + @response.body = xml + end + + def rss_feed_for_with_ostruct(resources, options = {}) + render_feed rss_feed_for_without_ostruct(resources, options) + end + + def atom_feed_for_with_ostruct(resources, options = {}) + render_feed atom_feed_for_without_ostruct(resources, options) + end + + alias_method_chain :rss_feed_for, :ostruct + alias_method_chain :atom_feed_for, :ostruct + + def html_document + @html_document ||= HTML::Document.new(@response.body, false, true) + end + + def posts_url + "http://example.com/posts" + end + + def post_url(post) + "http://example.com/posts/#{post.id}" + end +end diff --git a/backup.rails2.3/plugins/simple_ldap_authenticator/README b/backup.rails2.3/plugins/simple_ldap_authenticator/README new file mode 100644 index 00000000..dc8ca509 --- /dev/null +++ b/backup.rails2.3/plugins/simple_ldap_authenticator/README @@ -0,0 +1,5 @@ +SimpleLdapAuthenticator +======================= + +Allows for simple authentication to an LDAP server with a minimum of +configuration. See the RDoc for details. diff --git a/backup.rails2.3/plugins/simple_ldap_authenticator/Rakefile b/backup.rails2.3/plugins/simple_ldap_authenticator/Rakefile new file mode 100644 index 00000000..f7c3459e --- /dev/null +++ b/backup.rails2.3/plugins/simple_ldap_authenticator/Rakefile @@ -0,0 +1,22 @@ +require 'rake' +require 'rake/testtask' +require 'rake/rdoctask' + +desc 'Default: run unit tests.' +task :default => :test + +desc 'Test the simple_ldap_authenticator plugin.' +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.pattern = 'test/**/*_test.rb' + t.verbose = true +end + +desc 'Generate documentation for the simple_ldap_authenticator plugin.' +Rake::RDocTask.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'rdoc' + rdoc.title = 'SimpleLdapAuthenticator' + rdoc.options << '--line-numbers' << '--inline-source' + rdoc.rdoc_files.include('README') + rdoc.rdoc_files.include('lib/**/*.rb') +end diff --git a/backup.rails2.3/plugins/simple_ldap_authenticator/init.rb b/backup.rails2.3/plugins/simple_ldap_authenticator/init.rb new file mode 100644 index 00000000..85917669 --- /dev/null +++ b/backup.rails2.3/plugins/simple_ldap_authenticator/init.rb @@ -0,0 +1,2 @@ +# Include hook code here +#require 'simple_ldap_authenticator' diff --git a/backup.rails2.3/plugins/simple_ldap_authenticator/install.rb b/backup.rails2.3/plugins/simple_ldap_authenticator/install.rb new file mode 100644 index 00000000..f7732d37 --- /dev/null +++ b/backup.rails2.3/plugins/simple_ldap_authenticator/install.rb @@ -0,0 +1 @@ +# Install hook code here diff --git a/backup.rails2.3/plugins/simple_ldap_authenticator/lib/simple_ldap_authenticator.rb b/backup.rails2.3/plugins/simple_ldap_authenticator/lib/simple_ldap_authenticator.rb new file mode 100644 index 00000000..2992d892 --- /dev/null +++ b/backup.rails2.3/plugins/simple_ldap_authenticator/lib/simple_ldap_authenticator.rb @@ -0,0 +1,127 @@ +# SimpleLdapAuthenticator +# +# This plugin supports both Ruby/LDAP and Net::LDAP, defaulting to Ruby/LDAP +# if it is available. If both are installed and you want to force the use of +# Net::LDAP, set SimpleLdapAuthenticator.ldap_library = 'net/ldap'. + +# Allows for easily authenticating users via LDAP (or LDAPS). If authenticating +# via LDAP to a server running on localhost, you should only have to configure +# the login_format. +# +# Can be configured using the following accessors (with examples): +# * login_format = '%s@domain.com' # Active Directory, OR +# * login_format = 'cn=%s,cn=users,o=organization,c=us' # Other LDAP servers +# * servers = ['dc1.domain.com', 'dc2.domain.com'] # names/addresses of LDAP servers to use +# * use_ssl = true # for logging in via LDAPS +# * port = 3289 # instead of 389 for LDAP or 636 for LDAPS +# * logger = RAILS_DEFAULT_LOGGER # for logging authentication successes/failures +# +# The class is used as a global variable, you are not supposed to create an +# instance of it. For example: +# +# require 'simple_ldap_authenticator' +# SimpleLdapAuthenticator.servers = %w'dc1.domain.com dc2.domain.com' +# SimpleLdapAuthenticator.use_ssl = true +# SimpleLdapAuthenticator.login_format = '%s@domain.com' +# SimpleLdapAuthenticator.logger = RAILS_DEFAULT_LOGGER +# class LoginController < ApplicationController +# def login +# return redirect_to(:action=>'try_again') unless SimpleLdapAuthenticator.valid?(params[:username], params[:password]) +# session[:username] = params[:username] +# end +# end +class SimpleLdapAuthenticator + class << self + @servers = ['127.0.0.1'] + @use_ssl = false + @login_format = '%s' + attr_accessor :servers, :use_ssl, :port, :login_format, :logger, :connection, :ldap_library + + # Load the required LDAP library, either 'ldap' or 'net/ldap' + def load_ldap_library + return if @ldap_library_loaded + if ldap_library + if ldap_library == 'net/ldap' + require 'net/ldap' + else + require 'ldap' + require 'ldap/control' + end + else + begin + require 'ldap' + require 'ldap/control' + ldap_library = 'ldap' + rescue LoadError + require 'net/ldap' + ldap_library = 'net/ldap' + end + end + @ldap_library_loaded = true + end + + # The next LDAP server to which to connect + def server + servers[0] + end + + # The connection to the LDAP server. A single connection is made and the + # connection is only changed if a server returns an error other than + # invalid password. + def connection + return @connection if @connection + load_ldap_library + @connection = if ldap_library == 'net/ldap' + Net::LDAP.new(:host=>server, :port=>(port), :encryption=>(:simple_tls if use_ssl)) + else + (use_ssl ? LDAP::SSLConn : LDAP::Conn).new(server, port) + end + end + + # The port to use. Defaults to 389 for LDAP and 636 for LDAPS. + def port + @port ||= use_ssl ? 636 : 389 + end + + # Disconnect from current LDAP server and use a different LDAP server on the + # next authentication attempt + def switch_server + self.connection = nil + servers << servers.shift + end + + # Check the validity of a login/password combination + def valid?(login, password) + if ldap_library == 'net/ldap' + connection.authenticate(login_format % login.to_s, password.to_s) + begin + if connection.bind + logger.info("Authenticated #{login.to_s} by #{server}") if logger + true + else + logger.info("Error attempting to authenticate #{login.to_s} by #{server}: #{connection.get_operation_result.code} #{connection.get_operation_result.message}") if logger + switch_server unless connection.get_operation_result.code == 49 + false + end + rescue Net::LDAP::LdapError => error + logger.info("Error attempting to authenticate #{login.to_s} by #{server}: #{error.message}") if logger + switch_server + false + end + else + connection.unbind if connection.bound? + begin + connection.bind(login_format % login.to_s, password.to_s) + connection.unbind + logger.info("Authenticated #{login.to_s} by #{server}") if logger + true + rescue LDAP::ResultError => error + connection.unbind if connection.bound? + logger.info("Error attempting to authenticate #{login.to_s} by #{server}: #{error.message}") if logger + switch_server unless error.message == 'Invalid credentials' + false + end + end + end + end +end diff --git a/backup.rails2.3/plugins/simple_ldap_authenticator/tasks/simple_ldap_authenticator_tasks.rake b/backup.rails2.3/plugins/simple_ldap_authenticator/tasks/simple_ldap_authenticator_tasks.rake new file mode 100644 index 00000000..1916c233 --- /dev/null +++ b/backup.rails2.3/plugins/simple_ldap_authenticator/tasks/simple_ldap_authenticator_tasks.rake @@ -0,0 +1,4 @@ +# desc "Explaining what the task does" +# task :simple_ldap_authenticator do +# # Task goes here +# end \ No newline at end of file diff --git a/backup.rails2.3/plugins/simple_ldap_authenticator/test/simple_ldap_authenticator_test.rb b/backup.rails2.3/plugins/simple_ldap_authenticator/test/simple_ldap_authenticator_test.rb new file mode 100644 index 00000000..dfd92dae --- /dev/null +++ b/backup.rails2.3/plugins/simple_ldap_authenticator/test/simple_ldap_authenticator_test.rb @@ -0,0 +1,8 @@ +require 'test/unit' + +class SimpleLdapAuthenticatorTest < Test::Unit::TestCase + # Replace this with your real tests. + def test_this_plugin + flunk + end +end diff --git a/backup.rails2.3/plugins/skinny_spec/.gitignore b/backup.rails2.3/plugins/skinny_spec/.gitignore new file mode 100644 index 00000000..28f7b7da --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +doc \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/README.rdoc b/backup.rails2.3/plugins/skinny_spec/README.rdoc new file mode 100644 index 00000000..118b58e1 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/README.rdoc @@ -0,0 +1,270 @@ += Skinny Spec + +Skinny Spec is a collection of spec helper methods designed to help trim the fat and DRY up +some of the bloat that sometimes results from properly specing your classes and templates. + +== Requirements and Recommendations + +Obviously you'll need to be using RSpec[http://github.com/dchelimsky/rspec/tree/master] and +Rspec-Rails[http://github.com/dchelimsky/rspec-rails/tree/master] as your testing framework. + +Skinny Spec was originally designed [and best enjoyed] if you're using +Haml[http://github.com/nex3/haml/tree/master] and +make_resourceful[http://github.com/rsl/make_resourceful/tree/master] but will default to +ERb and a facsimile of Rails' default scaffolding [for the views and controllers, respectively] +if Haml and/or make_resourceful are not available. I recommend using them though. :) + +In addition, Skinny Spec uses Ruby2Ruby to make nicer expectation messages and you'll want to +have that installed as well. It's not a dependency or anything but it is highly +recommended. + +== Setup + +Once you've installed the plugin in your app's vendor/plugins folder, you're ready to rock! +Skinny Spec includes itself into the proper RSpec classes so there's no configuration on your +part. Sweet! + +== Usage + +The simplest way to use Skinny Specs is to generate a resource scaffold: + + script/generate skinny_scaffold User + +This command takes the usual complement of attribute definitions like +script/generate scaffold. Then have a look at the generated files (particularly the +specs) to see what's new and different with Skinny Spec. + +=== Controller Specs + +Let's look at the controller specs. + + describe UsersController do + describe "GET :index" do + before(:each) do + @users = stub_index(User) + end + + it_should_find_and_assign :users + it_should_render :template, "index" + end + + # ... + + describe "POST :create" do + describe "when successful" do + before(:each) do + @user = stub_create(User) + end + + it_should_initialize_and_save :user + it_should_redirect_to { user_url(@user) } + end + + # ... + +First thing you should see is an example group for GET :index. That stub_index method there +does a lot of work behind the curtain. I'll leave it up to you to check the documentation for it +(and its brothers and sister methods like stub_new) but I will point out that the +methods named stub_controller_method should only be used for stubbing and +mocking the main object of the method. To create mocks for other ancillary objects, please +use stub_find_all, stub_find_one, and stub_initialize. The reason +for this is because the former methods actually save us a step by defining an implicit +controller method request. If you add a new method to your resource routing, you'll want to +use the helper method define_request in those example groups to define an explicit +request, like so: + + describe "PUT :demote" do + define_request { put :demote } + + # ... + end + +You can also define a method called shared_request to "share" a +define_request across nested describe blocks, like so: + + describe "POST :create" do + def shared_request + post :create + end + + describe "when successful" do + # ... + end + + describe "when unsuccessful" do + # ... + end + end + +Note: When you're adding longer, more complicated controller specs you can still leverage +implicit and explicit requests by calling do_request in your spec as in the following +example: + + # Note this controller is UsersController and _not_ CategoriesController + # and that loading the categories isn't part of the default actions + # and cannot use the stub_controller_method helpers + # [which create implicit requests based on the controller method in the name] + # but uses stub_find_all instead + describe "GET :new" do + before(:each) do + @user = stub_new(User) + @categories = stub_find_all(Category) + end + + # ... + + it "should preload categories" do + Category.should_receive(:find).with(:all) + do_request + end + + it "should assign @categories" do + do_request + assigns[:categories].should == @categories + end + end + +Finally we get to the meat of the spec and of Skinny Specs itself: the actual expectations. +The first thing you'll notice is the use of example group (read: "describe" block) level methods +instead of the usual example (read: "it") blocks. Using this helper at the example group level +saves us three lines over using an example block. (If this isn't significant to you, this is +probably the wrong plugin for you as well. Sorry.) Note that none of these methods use the +instance variables defined in the "before" block because they are all nil at the example block +level. Let's look at a sample method to see how it works: + + it_should_find_and_assign :users + +This actually wraps two different expectations: one that User.should_receive(:find).with(:all) +and another that the instance variable @users is assigned with the return value from that finder call. +If you need to add more detailed arguments to the find, you can easily break this into two different +expectations like: + + it_should_find :users, :limit => 2 + it_should_assign :users + +See the documentation for the it_should_find for more information. You might have guessed that +it_should_initialize_assign and it_should_render_template work in a similar +fashion and you'd be right. Again, see the documentation for these individual methods for more +information. Lots of information in those docs. + +A useful helper method that doesn't appear in any of the scaffolding is with_default_restful_actions +which takes a block and evaluates it for each of the RESTful controller actions. Very useful for +spec'ing that these methods redirect to the login page when the user isn't logged in, for example. This +method is designed to be used inside an example like so: + + describe "when not logged in" do + it "should redirect all requests to the login page" do + with_default_restful_actions do + response.should redirect_to(login_url) + end + end + end + +Before we're through with the controller specs, let me point out one more important detail. In +order to use it_should_redirect_to we have to send the routing inside a block argument +there so it can be evaluated in the example context instead of the example group, where it +completely blows up. This methodology is used anywhere routing is referred to in a "skinny", +example group level spec. + +=== View Specs + +Now let's move to the view specs! + + describe "/users/form.html.haml" do + before(:each) do + @user = mock_and_assign(User, :stub => { + :name => "foo", + :birthday => 1.week.ago, + :adult => false + }) + end + + it_should_have_form_for :user + + it_should_allow_editing :user, :name + it_should_allow_editing :user, :birthday + it_should_allow_editing :user, :adult + + it_should_link_to_show :user + it_should_link_to { users_path } + end + +Like the special stub_index methods in the controller +specs, the view specs have a shorthand mock and stub helpers: mock_and_assign and +mock_and_assign_collection. These are well documented so please check them out. + +There are also some really nice helper methods that I'd like point out. First is +it_should_have_form_for. This is a really good convenience wrapper that basically wraps +the much longer: + + it "should use form_for to generate the proper form action and options" do + template.should_receive(:form_for).with(@user) + do_render + end + +Next up is the it_should_allow_editing helper. I love this method the most because it +really helps DRY up that view spec while at the same time being amazingly unbrittle. Instead of +creating an expectation for a specific form element, this method creates a generalized expectation +that there's a form element with the name attribute set in such away that it will +generate the proper params to use in the controller to edit or create the instance. +Check out the docs and the source for more information on this. Also check out +it_should_have_form_element_for which is roughly equivalent for those times when you use +form_tag instead. + +Finally let's look at those it_should_link_to_controller_method helpers. +These methods (and there's one each for the controller methods +new, edit, show, and delete) point to instance variables +which you should be created in the "before" blocks with mock_and_assign. The other is +it_should_allow_editing which is likewise covered extensively in the documentation and +I will just point out here that, like it_should_link_to_edit and such, it takes a +symbol for the name of the instance variable it refers to and additionally takes +a symbol for the name of the attribute to be edited. + +Also note that, when constructing a long form example, instead of defining an instance variable +for the name of the template and calling render @that_template you can simply call +do_render which takes the name of the template from the outermost example group where +it is customarily stated. + +=== Model Specs + +Skinny Spec adds a matcher for the various ActiveRecord associations. On the example group level +you call them like: + + it_should_belong_to :manager + it_should_have_many :clients + +Within an example you can call them on either the class or the instance setup in the +"before" block. These are equivalent: + + @user.should belong_to(:group) + User.should belong_to(:group) + +I've also added some very basic validation helpers like it_should_validate_presence_of, +it_should_validate_uniqueness_of, it_should_not_mass_assign. Please consult +the documentation for more information. + +== Miscellaneous Notes + +In the scaffolding, I have used my own idiomatic Rails usage: + +* All controller actions which use HTML forms [new, edit, etc] use a shared + form and leverage form_for to its fullest by letting it create the appropriate + action and options. +* Some instances where you might expect link_to are button_to. This is to provide a common + interface element which can be styled the same instead of a mishmash of links and buttons and + inputs everywhere. To take full advantage of this, I usually override many of Rails' default + helpers with custom ones that all use actual HTML BUTTON elements which are much + easier to style than "button" typed INPUT. I've provided a text file in the + "additional" folder of this plugin which you can use in your ApplicationHelper. (I also + provide an optional override helper for the label method which uses + #titleize instead of humanize for stylistic reasons). +* Probably more that I can't think of. + +== Credits and Thanks + +Sections of this code were taken from or inspired by Rick Olsen's +rspec_on_rails_on_crack[http://github.com/technoweenie/rspec_on_rails_on_crack/tree/master]. +Also thanks and props to Hampton Catlin and Nathan Weizenbaum for the lovely and imminently useable +Haml and make_resourceful. Also also praises and glory to David Chelimsky and the Rspec crew. + +Also thanks to Don Petersen, Nicolas Mérouze, Mikkel Malmberg, and Brandan Lennox for their suggestions and fixes. \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/Rakefile b/backup.rails2.3/plugins/skinny_spec/Rakefile new file mode 100644 index 00000000..b0adbc43 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/Rakefile @@ -0,0 +1,11 @@ +require 'rake' +require 'rake/rdoctask' + +desc 'Generate documentation for the Skinny Spec plugin' +Rake::RDocTask.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'doc' + rdoc.title = 'Skinny Spec' + rdoc.options << '--line-numbers' << '--inline-source' + rdoc.rdoc_files.include('README.rdoc') + rdoc.rdoc_files.include('lib/**/*.rb') +end \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/additional/helper_overrides.txt b/backup.rails2.3/plugins/skinny_spec/additional/helper_overrides.txt new file mode 100644 index 00000000..7717e079 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/additional/helper_overrides.txt @@ -0,0 +1,58 @@ +# Please insert these into your ApplicationHelper + +# Replacement for Rails' default submit_tag helper +# using HTML button element rather than HTML input element +def submit_tag(text, options = {}) + content_tag :button, text, options.merge(:type => :submit) +end + +# Replacement for Rails' default button_to helper +# using HTML button element rather than HTML input element +def button_to(name, options = {}, html_options = {}) + html_options = html_options.stringify_keys + convert_boolean_attributes!(html_options, %w( disabled )) + + method_tag = '' + if (method = html_options.delete('method')) && %w{put delete}.include?(method.to_s) + method_tag = tag('input', :type => 'hidden', :name => '_method', :value => method.to_s) + end + + form_method = method.to_s == 'get' ? 'get' : 'post' + + request_token_tag = '' + if form_method == 'post' && protect_against_forgery? + request_token_tag = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) + end + + if confirm = html_options.delete("confirm") + html_options["onclick"] = "return #{confirm_javascript_function(confirm)};" + end + + url = options.is_a?(String) ? options : self.url_for(options) + name ||= url + + html_options.merge!("type" => "submit", "value" => name) + + "
        " + + method_tag + content_tag("button", name, html_options) + request_token_tag + "
        " +end + +# Replacement for Rails' default button_to_function helper +# using HTML button element rather than HTML input element +def button_to_function(name, *args, &block) + html_options = args.extract_options! + function = args[0] || '' + + html_options.symbolize_keys! + function = update_page(&block) if block_given? + content_tag(:button, name, html_options.merge({ + :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};" + })) +end + +# Replacement for Rails' default label helper +# using String#titleize rather than String#humanize +def label(object_name, method, text = nil, options = {}) + text ||= method.to_s[].titleize + super +end \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/skinny_scaffold_generator.rb b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/skinny_scaffold_generator.rb new file mode 100644 index 00000000..3cde3564 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/skinny_scaffold_generator.rb @@ -0,0 +1,102 @@ +class SkinnyScaffoldGenerator < Rails::Generator::NamedBase + attr_reader :controller_class_path, :controller_file_path, :controller_class_nesting, + :controller_class_nesting_depth, :controller_class_name, :controller_underscore_name, + :controller_plural_name, :template_language + alias_method :controller_file_name, :controller_underscore_name + alias_method :controller_singular_name, :controller_file_name + alias_method :controller_table_name, :controller_plural_name + + default_options :skip_migration => false + + def initialize(runtime_args, runtime_options = {}) + super + + base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@name.pluralize) + @controller_class_name_without_nesting, @controller_underscore_name, @controller_plural_name = inflect_names(base_name) + + if @controller_class_nesting.empty? + @controller_class_name = @controller_class_name_without_nesting + else + @controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}" + end + end + + def manifest + record do |m| + # Check for class naming collisions + m.class_collisions controller_class_path, "#{controller_class_name}Controller", "#{controller_class_name}Helper" + m.class_collisions class_path, "#{class_name}" + + # # Controller, helper, and views directories + m.directory File.join('app', 'views', controller_class_path, controller_file_name) + m.directory File.join('spec', 'views', controller_class_path, controller_file_name) + m.directory File.join('app', 'helpers', controller_class_path) + m.directory File.join('spec', 'helpers', controller_class_path) + m.directory File.join('app', 'controllers', controller_class_path) + m.directory File.join('spec', 'controllers', controller_class_path) + m.directory File.join('app', 'models', class_path) + m.directory File.join('spec', 'models', class_path) + + # Views + @template_language = defined?(Haml) ? "haml" : "erb" + %w{index show form}.each do |action| + m.template "#{action}.html.#{template_language}", + File.join('app/views', controller_class_path, controller_file_name, "#{action}.html.#{template_language}") + m.template "#{action}.html_spec.rb", + File.join('spec/views', controller_class_path, controller_file_name, "#{action}.html.#{template_language}_spec.rb") + end + m.template "index_partial.html.#{template_language}", + File.join('app/views', controller_class_path, controller_file_name, "_#{file_name}.html.#{template_language}") + m.template 'index_partial.html_spec.rb', + File.join('spec/views', controller_class_path, controller_file_name, "_#{file_name}.html.#{template_language}_spec.rb") + + # Helper + m.template 'helper.rb', + File.join('app/helpers', controller_class_path, "#{controller_file_name}_helper.rb") + m.template 'helper_spec.rb', + File.join('spec/helpers', controller_class_path, "#{controller_file_name}_helper_spec.rb") + + # Controller + m.template 'controller.rb', + File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb") + m.template 'controller_spec.rb', + File.join('spec/controllers', controller_class_path, "#{controller_file_name}_controller_spec.rb") + + # Model + m.template 'model.rb', + File.join('app/models', class_path, "#{file_name}.rb") + m.template 'model_spec.rb', + File.join('spec/models', class_path, "#{file_name}_spec.rb") + + # Routing + m.route_resources controller_file_name + + unless options[:skip_migration] + m.migration_template( + 'migration.rb', 'db/migrate', + :assigns => { + :migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}", + :attributes => attributes + }, + :migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}" + ) + end + end + end + +protected + def banner + "Usage: #{$0} skinny_scaffold ModelName [field:type, field:type]" + end + + def add_options!(opt) + opt.separator '' + opt.separator 'Options:' + opt.on("--skip-migration", + "Don't generate a migration file for this model") { |v| options[:skip_migration] = v } + end + + def model_name + class_name.demodulize + end +end \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/controller.rb b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/controller.rb new file mode 100644 index 00000000..ea9b617d --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/controller.rb @@ -0,0 +1,105 @@ +class <%= controller_class_name %>Controller < ApplicationController + <%- if defined?(Resourceful::Maker) -%> + make_resourceful do + actions :all + + # Let's get the most use from form_for and share a single form here! + response_for :new, :edit do + render :template => "<%= plural_name %>/form" + end + + response_for :create_fails, :update_fails do + flash[:error] = "There was a problem!" + render :template => "<%= plural_name %>/form" + end + end + <%- else -%> + # GET /<%= table_name %> + # GET /<%= table_name %>.xml + def index + @<%= table_name %> = <%= class_name %>.find(:all) + + respond_to do |format| + format.html # index.html.erb + format.xml { render :xml => @<%= table_name %> } + end + end + + # GET /<%= table_name %>/1 + # GET /<%= table_name %>/1.xml + def show + @<%= file_name %> = <%= class_name %>.find(params[:id]) + + respond_to do |format| + format.html # show.html.erb + format.xml { render :xml => @<%= file_name %> } + end + end + + # GET /<%= table_name %>/new + # GET /<%= table_name %>/new.xml + def new + @<%= file_name %> = <%= class_name %>.new + + respond_to do |format| + format.html { render :template => "<%= plural_name %>/form" } + format.xml { render :xml => @<%= file_name %> } + end + end + + # GET /<%= table_name %>/1/edit + def edit + @<%= file_name %> = <%= class_name %>.find(params[:id]) + render :template => "<%= plural_name %>/form" + end + + # POST /<%= table_name %> + # POST /<%= table_name %>.xml + def create + @<%= file_name %> = <%= class_name %>.new(params[:<%= file_name %>]) + + respond_to do |format| + if @<%= file_name %>.save + flash[:notice] = '<%= class_name %> was successfully created.' + format.html { redirect_to(@<%= file_name %>) } + format.xml { render :xml => @<%= file_name %>, :status => :created, :location => @<%= file_name %> } + else + flash.now[:error] = '<%= class_name %> could not be created.' + format.html { render :template => "<%= plural_name %>/form" } + format.xml { render :xml => @<%= file_name %>.errors, :status => :unprocessable_entity } + end + end + end + + # PUT /<%= table_name %>/1 + # PUT /<%= table_name %>/1.xml + def update + @<%= file_name %> = <%= class_name %>.find(params[:id]) + + respond_to do |format| + if @<%= file_name %>.update_attributes(params[:<%= file_name %>]) + flash[:notice] = '<%= class_name %> was successfully updated.' + format.html { redirect_to(@<%= file_name %>) } + format.xml { head :ok } + else + flash.now[:error] = '<%= class_name %> could not be created.' + format.html { render :template => "<%= plural_name %>/form" } + format.xml { render :xml => @<%= file_name %>.errors, :status => :unprocessable_entity } + end + end + end + + # DELETE /<%= table_name %>/1 + # DELETE /<%= table_name %>/1.xml + def destroy + @<%= file_name %> = <%= class_name %>.find(params[:id]) + @<%= file_name %>.destroy + + respond_to do |format| + flash[:notice] = '<%= class_name %> was successfully deleted.' + format.html { redirect_to(<%= table_name %>_url) } + format.xml { head :ok } + end + end + <%- end -%> +end diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/controller_spec.rb b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/controller_spec.rb new file mode 100644 index 00000000..ff1b6b29 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/controller_spec.rb @@ -0,0 +1,93 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe <%= controller_class_name %>Controller do + describe "GET :index" do + before(:each) do + @<%= plural_name %> = stub_index(<%= class_name %>) + end + + it_should_find_and_assign :<%= plural_name %> + it_should_render_template "index" + end + + describe "GET :new" do + before(:each) do + @<%= singular_name %> = stub_new(<%= class_name %>) + end + + it_should_initialize_and_assign :<%= singular_name %> + it_should_render_template "form" + end + + describe "POST :create" do + describe "when successful" do + before(:each) do + @<%= singular_name %> = stub_create(<%= class_name %>) + end + + it_should_initialize_and_save :<%= singular_name %> + it_should_set_flash :notice + it_should_redirect_to { <%= singular_name %>_url(@<%= singular_name %>) } + end + + describe "when unsuccessful" do + before(:each) do + @<%= singular_name %> = stub_create(<%= class_name %>, :return => :false) + end + + it_should_initialize_and_assign :<%= singular_name %> + it_should_set_flash :error + it_should_render_template "form" + end + end + + describe "GET :show" do + before(:each) do + @<%= singular_name %> = stub_show(<%= class_name %>) + end + + it_should_find_and_assign :<%= singular_name %> + it_should_render_template "show" + end + + describe "GET :edit" do + before(:each) do + @<%= singular_name %> = stub_edit(<%= class_name %>) + end + + it_should_find_and_assign :<%= singular_name %> + it_should_render_template "form" + end + + describe "PUT :update" do + describe "when successful" do + before(:each) do + @<%= singular_name %> = stub_update(<%= class_name %>) + end + + it_should_find_and_update :<%= singular_name %> + it_should_set_flash :notice + it_should_redirect_to { <%= singular_name %>_url(@<%= singular_name %>) } + end + + describe "when unsuccessful" do + before(:each) do + @<%= singular_name %> = stub_update(<%= class_name %>, :return => :false) + end + + it_should_find_and_assign :<%= singular_name %> + it_should_set_flash :error + it_should_render_template "form" + end + end + + describe "DELETE :destroy" do + before(:each) do + @<%= singular_name %> = stub_destroy(<%= class_name %>) + end + + it_should_find_and_destroy :<%= singular_name %> + it_should_set_flash :notice + it_should_redirect_to { <%= plural_name %>_url } + end +end diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.erb b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.erb new file mode 100644 index 00000000..ac30dc1b --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.erb @@ -0,0 +1,25 @@ +

        <%= singular_name %>.new_record? ? "New" : "Edit" %> <%= model_name %>

        +<%% form_for(@<%= singular_name %>) do |f| %> +
        + <%%= f.error_messages %> +
        + <%- if attributes.blank? -%> +

        Add your form elements here, please!

        + <%- else -%> + <%- attributes.each do |attribute| -%> +

        + <%%= f.label :<%= attribute.name %> %>
        + <%%= f.<%= attribute.field_type %> :<%= attribute.name %> %> +

        + <%- end -%> + <%- end -%> +
        + <%%= submit_tag "Save" %> + +
        +<%% end -%> \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.haml b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.haml new file mode 100644 index 00000000..d97eabb9 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html.haml @@ -0,0 +1,18 @@ +%h1== #{@<%= singular_name %>.new_record? ? "New" : "Edit"} #{<%= model_name %>} +- form_for @<%= singular_name %> do |f| + #form_errors= f.error_messages +<% if attributes.blank? -%> + %p Add your form elements here, please! +<% else -%> + <%- attributes.each do |attribute| -%> + %p + = f.label :<%= attribute.name %> + = f.<%= attribute.field_type %> :<%= attribute.name %> + <%- end -%> +<% end -%> + #commands + = submit_tag "Save" +#navigation_commands + - unless @<%= singular_name %>.new_record? + = button_to "Show", <%= singular_name %>_path(@<%= singular_name %>), :method => "get", :title => "Show <%= singular_name %>. Unsaved changes will be lost." + = button_to "Back to List", <%= plural_name %>_path, :class => "cancel", :method => "get", :title => "Return to <%= singular_name %> list without saving changes" \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html_spec.rb b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html_spec.rb new file mode 100644 index 00000000..bc6f6f24 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/form.html_spec.rb @@ -0,0 +1,40 @@ +require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../../spec_helper' + +describe "<%= File.join(controller_class_path, controller_singular_name) %>/form.html.<%= template_language %>" do + before(:each) do + @<%= singular_name %> = mock_and_assign(<%= model_name %>, :stub => { +<% if attributes.blank? -%> + # Add your stub attributes and return values here like: + # :name => "Foo", :address => "815 Oceanic Drive" +<% else -%> + <%- attributes.each_with_index do |attribute, index| -%> + <%- case attribute.type when :string, :text -%> + :<%= attribute.name %> => "foo"<%= index < attributes.size - 1 ? "," : "" %> + <%- when :integer, :float, :decimal -%> + :<%= attribute.name %> => 815<%= index < attributes.size - 1 ? "," : "" %> + <%- when :boolean -%> + :<%= attribute.name %> => false<%= index < attributes.size - 1 ? "," : "" %> + <%- when :date, :datetime, :time, :timestamp -%> + :<%= attribute.name %> => 1.week.ago<%= index < attributes.size - 1 ? "," : "" %> + <%- else -%> + :<%= attribute.name %> => nil<%= index < attributes.size - 1 ? "," : "" %> # Could not determine valid attribute + <%- end -%> + <%- end -%> +<% end -%> + }) + end + + it_should_have_form_for :<%= singular_name %> +<% if attributes.blank? -%> + # Add specs for editing attributes here, please! Like this: + # + # it_should_allow_editing :<%= singular_name %>, :foo +<% else -%> + <%- attributes.each do |attribute| -%> + it_should_allow_editing :<%= singular_name %>, :<%= attribute.name %> + <%- end -%> +<% end -%> + + it_should_link_to_show :<%= singular_name %> + it_should_link_to { <%= plural_name %>_path } +end \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/helper.rb b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/helper.rb new file mode 100644 index 00000000..9bd821b1 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/helper.rb @@ -0,0 +1,2 @@ +module <%= controller_class_name %>Helper +end diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/helper_spec.rb b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/helper_spec.rb new file mode 100644 index 00000000..6a34ca2a --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/helper_spec.rb @@ -0,0 +1,5 @@ +require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../spec_helper' + +describe <%= controller_class_name %>Helper do + # Add your specs here or remove this file completely, please! +end \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.erb b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.erb new file mode 100644 index 00000000..318f94e3 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.erb @@ -0,0 +1,31 @@ +

        <%= model_name %> List

        + + <%%- if @<%= plural_name %>.empty? -%> + + + + + + <%%- else -%> + + + <%- if attributes.blank? -%> + + <%- else -%> + <%- attributes.each do |attribute| -%> + + <%- end -%> + <%- end -%> + + + + + + + <%%= render :partial => @<%= plural_name %> %> + + <%%- end -%> +
        There are no <%= plural_name.humanize.downcase %>
        <%= attribute.name.titleize %>
        +
        + <%%= button_to "New <%= singular_name.titleize %>", new_<%= singular_name %>_path, :method => "get" %> +
        \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.haml b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.haml new file mode 100644 index 00000000..b0c78b28 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html.haml @@ -0,0 +1,23 @@ +%h1 <%= model_name %> List +%table + - if @<%= plural_name %>.empty? + %tbody + %tr.empty + %td== There are no <%= plural_name.humanize.downcase %> + - else + %thead + %tr +<% if attributes.blank? -%> + %th= # Generic display column +<% else -%> + <%- attributes.each do |attribute| -%> + %th <%= attribute.name.titleize %> + <%- end -%> +<% end -%> + %th.show= # 'Show' link column + %th.edit= # 'Edit' link column + %th.delete= # 'Delete' link column + %tbody + = render :partial => @<%= plural_name %> +#commands + = button_to "New <%= singular_name.titleize %>", new_<%= singular_name %>_path, :method => "get" \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html_spec.rb b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html_spec.rb new file mode 100644 index 00000000..cfe213f5 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index.html_spec.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../../spec_helper' + +describe "<%= File.join(controller_class_path, controller_singular_name) %>/index.html.<%= template_language %>" do + before(:each) do + @<%= plural_name %> = mock_and_assign_collection(<%= model_name %>) + template.stub! :render + end + + it "should render :partial => @<%= plural_name %>" do + template.should_receive(:render).with(:partial => @<%= plural_name %>) + do_render + end + + it_should_link_to_new :<%= singular_name %> +end \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.erb b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.erb new file mode 100644 index 00000000..ecdca836 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.erb @@ -0,0 +1,12 @@ +"> +<% if attributes.blank? -%> + <%= model_name %> #<%%= <%= singular_name %>.id %> +<% else -%> + <%- attributes.each do |attribute| -%> + <%%=h <%= singular_name %>.<%= attribute.name %> %> + <%- end %> +<% end -%> + <%%= button_to "Show", <%= singular_name %>, :method => "get" %> + <%%= button_to "Edit", edit_<%= singular_name %>_path(<%= singular_name %>), :method => "get" %> + <%%= button_to "Delete", <%= singular_name %>, :method => "delete" %> + \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.haml b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.haml new file mode 100644 index 00000000..08b3b383 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html.haml @@ -0,0 +1,11 @@ +%tr{:class => cycle("odd", "even")} +<% if attributes.blank? -%> + %td== <%= model_name %> #{<%= singular_name %>.id} +<% else -%> + <%- attributes.each do |attribute| -%> + %td=h <%= singular_name %>.<%= attribute.name %> + <%- end -%> +<% end -%> + %td.show= button_to "Show", <%= singular_name %>_path(<%= singular_name %>), :method => "get" + %td.edit= button_to "Edit", edit_<%= singular_name %>_path(<%= singular_name %>), :method => "get" + %td.delete= button_to "Delete", <%= singular_name %>, :method => "delete" \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html_spec.rb b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html_spec.rb new file mode 100644 index 00000000..2a10afb1 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/index_partial.html_spec.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../../spec_helper' + +describe "<%= File.join(controller_class_path, controller_singular_name) %>/_<%= singular_name %>.html.<%= template_language %>" do + before(:each) do + @<%= singular_name %> = mock_and_assign(<%= model_name %>, :stub => { +<% if attributes.blank? -%> + # Add your stub attributes and return values here like: + # :name => "Foo", :created_at => 1.week.ago, :updated_at => nil +<% else -%> + <%- attributes.each_with_index do |attribute, index| -%> + <%- case attribute.type when :string, :text -%> + :<%= attribute.name %> => "foo"<%= index < attributes.size - 1 ? "," : "" %> + <%- when :integer, :float, :decimal -%> + :<%= attribute.name %> => 815<%= index < attributes.size - 1 ? "," : "" %> + <%- when :boolean -%> + :<%= attribute.name %> => false<%= index < attributes.size - 1 ? "," : "" %> + <%- when :date, :datetime, :time, :timestamp -%> + :<%= attribute.name %> => 1.week.ago<%= index < attributes.size - 1 ? "," : "" %> + <%- else -%> + :<%= attribute.name %> => nil<%= index < attributes.size - 1 ? "," : "" %> + <%- end -%> + <%- end -%> +<% end -%> + }) + template.stub!(:<%= singular_name %>).and_return(@<%= singular_name %>) + end + + it_should_link_to_show :<%= singular_name %> + it_should_link_to_edit :<%= singular_name %> + it_should_link_to_delete :<%= singular_name %> +end \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/migration.rb b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/migration.rb new file mode 100644 index 00000000..2e4c29c8 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/migration.rb @@ -0,0 +1,14 @@ +class <%= migration_name %> < ActiveRecord::Migration + def self.up + create_table :<%= table_name %>, :force => true do |t| +<% attributes.each do |attribute| -%> + t.column :<%= attribute.name %>, :<%= attribute.type %> +<% end -%> + t.timestamps + end + end + + def self.down + drop_table :<%= table_name %> + end +end diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/model.rb b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/model.rb new file mode 100644 index 00000000..202f8b30 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/model.rb @@ -0,0 +1,2 @@ +class <%= class_name %> < ActiveRecord::Base +end \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/model_spec.rb b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/model_spec.rb new file mode 100644 index 00000000..ed6a1945 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/model_spec.rb @@ -0,0 +1,25 @@ +require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../spec_helper' + +describe <%= class_name %> do + def valid_attributes(args = {}) + { + # Add valid attributes for building your model instances here! + }.merge(args) + end + + before(:each) do + @<%= singular_name %> = <%= class_name %>.new + end + + after(:each) do + @<%= singular_name %>.destroy + end + + # Add your model specs here, please! + # And don't forget about the association matchers built-in to skinny_spec like: + # + # it_should_have_many :foos + # it_should_validate_presence_of :bar + # + # Check out the docs for more information. +end \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.erb b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.erb new file mode 100644 index 00000000..5db36d56 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.erb @@ -0,0 +1,15 @@ +

        Show <%= model_name %>

        +<% if attributes.blank? -%> +

        Add your customized markup here, please!

        +<% else -%> + <%- attributes.each do |attribute| -%> +

        + + <%%=h @<%= singular_name %>.<%= attribute.name %> %> +

        + <%- end -%> +<% end -%> +
        + <%%= button_to "Edit", edit_<%= singular_name %>_path(@<%= singular_name %>), :method => "get" %> + <%%= button_to "Back to List", <%= plural_name %>_path, :method => "get" %> +
        diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.haml b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.haml new file mode 100644 index 00000000..d8afe80a --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html.haml @@ -0,0 +1,13 @@ +%h1== Show #{<%= model_name %>} +<% if attributes.blank? -%> +%p Add your customized markup here, please! +<% else -%> + <%- attributes.each do |attribute| -%> +%p + %label <%= attribute.name.titleize %>: + =h @<%= singular_name %>.<%= attribute.name %> + <%- end -%> +<% end -%> +#commands + = button_to "Edit", edit_<%= singular_name %>_path(@<%= singular_name %>), :method => "get" + = button_to "Back to List", <%= plural_name %>_path, :method => "get" \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html_spec.rb b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html_spec.rb new file mode 100644 index 00000000..aefbbe17 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/generators/skinny_scaffold/templates/show.html_spec.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../../spec_helper' + +describe "<%= File.join(controller_class_path, controller_singular_name) %>/show.html.<%= template_language %>" do + before(:each) do +<% if attributes.blank? -%> + @<%= singular_name %> = mock_and_assign(<%= model_name %>) +<% else -%> + @<%= singular_name %> = mock_and_assign(<%= model_name %>, :stub => { + <%- attributes.each_with_index do |attribute, index| -%> + <%- case attribute.type when :string, :text -%> + :<%= attribute.name %> => "foo"<%= index < attributes.size - 1 ? "," : "" %> + <%- when :integer, :float, :decimal -%> + :<%= attribute.name %> => 815<%= index < attributes.size - 1 ? "," : "" %> + <%- when :boolean -%> + :<%= attribute.name %> => false<%= index < attributes.size - 1 ? "," : "" %> + <%- when :date, :datetime, :time, :timestamp -%> + :<%= attribute.name %> => 1.week.ago<%= index < attributes.size - 1 ? "," : "" %> + <%- else -%> + :<%= attribute.name %> => nil<%= index < attributes.size - 1 ? "," : "" %> + <%- end -%> + <%- end -%> + }) +<% end -%> + end + + # Add your specs here, please! But remember not to make them brittle + # by specing specing specific HTML elements and classes. + + it_should_link_to_edit :<%= singular_name %> + it_should_link_to { <%= plural_name %>_path } +end \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/common_spec_helpers.rb b/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/common_spec_helpers.rb new file mode 100644 index 00000000..0a7acff3 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/common_spec_helpers.rb @@ -0,0 +1,83 @@ +module LuckySneaks + # These methods are mostly just called internally by various other spec helper + # methods but you're welcome to use them as needed in your own specs. + module CommonSpecHelpers + # Stubs out Time.now and returns value to use when comparing it. Example: + # + # time_now = stub_time_now + # @foo.some_method_that_resets_updated_at + # @foo.updated_at.should == time_now + def stub_time_now + returning Time.now do |now| + Time.stub!(:now).and_return(now) + end + end + + # Returns class for the specified name. Example: + # + # class_for("foo") # => Foo + def class_for(name) + name.to_s.constantize + rescue NameError + name.to_s.pluralize.classify.constantize + # Let any other error rise! + end + + # Returns instance variable for the specified name. Example: + # + # instance_for("foo") # => @foo + def instance_for(name) + instance_variable_get("@#{name.to_s.underscore}") + end + + # Wraps a matcher that checks if the receiver contains an A element (link) + # whose href attribute is set to the specified path. + def have_link_to(path) + have_tag("a[href='#{path}']") + end + + # Returns dummy value for specified attribute based on the datatype expected for that + # attribute. + def dummy_value_for(instance, attribute) + if datatype = instance.column_for_attribute(attribute) + actual = instance.send(attribute) + case datatype.type + when :string, :text + actual == "foo" ? "bar" : "food" + when :integer, :float, :decimal + actual == 108 ? 815 : 108 + when :boolean + actual ? false : true + when :date, :datetime, :time, :timestamp + actual == 1.week.ago ? 2.years.ago : 1.week.ago + end + end + end + + # Returns class description text + def class_description_text + if self.class.respond_to?(:description_text) + # Old school + self.class.description_text + else + # New school + self.class.description + end + end + + # Returns description text + def self_description_text + if respond_to?(:description_text) + # Old school + description_text + else + # New school + description + end + end + + def described_type + self.class.described_type + end + end +end diff --git a/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/controller_request_helpers.rb b/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/controller_request_helpers.rb new file mode 100644 index 00000000..4aeffaf4 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/controller_request_helpers.rb @@ -0,0 +1,67 @@ +module LuckySneaks + module ControllerRequestHelpers # :nodoc: + def self.included(base) + base.extend ExampleGroupMethods + end + + private + def define_implicit_request(method) + @controller_method = method + @implicit_request = case method + when :index, :new, :show, :edit + proc { get method, params } + when :create + proc { post :create, params } + when :update + proc { put :update, params } + when :destroy + proc { put :destroy, params } + end + end + + def eval_request + instance_eval &self.class.instance_variable_get("@the_request") + rescue ArgumentError # missing block + try_shared_request_definition + end + alias do_request eval_request + + def try_shared_request_definition + if defined?(shared_request) == "method" + shared_request + elsif @implicit_request + try_implicit_request + else + error_message = "Could not determine request definition for 'describe' context. " + error_message << "Please use define_request or define a shared_request." + raise ArgumentError, error_message + end + end + + def try_implicit_request + @implicit_request.call + end + + def get_response(&block) + eval_request + block.call(response) if block_given? + response + end + + module ExampleGroupMethods + # Defines a request at the example group ("describe") level to be evaluated in the examples. Example: + # + # define_request { get :index, params } + # + # Note: The following methods all define implicit requests: stub_index, stub_new, + # stub_create, stub_show, stub_edit, stub_update, and + # stub_destroy. Using them in your before blocks will allow you to forego + # defining explicit requests using define_request. See + # LuckySneaks::ControllerStubHelpers for information on these methods. + def define_request(&block) + raise ArgumentError, "Must provide a block to define a request!" unless block_given? + @the_request = block + end + end + end +end diff --git a/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/controller_spec_helpers.rb b/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/controller_spec_helpers.rb new file mode 100644 index 00000000..20bca87e --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/controller_spec_helpers.rb @@ -0,0 +1,571 @@ +$:.unshift File.join(File.dirname(__FILE__), "..") +require "skinny_spec" + +module LuckySneaks + module ControllerSpecHelpers # :nodoc: + include LuckySneaks::CommonSpecHelpers + include LuckySneaks::ControllerRequestHelpers + include LuckySneaks::ControllerStubHelpers + + def self.included(base) + base.extend ExampleGroupMethods + base.extend ControllerRequestHelpers::ExampleGroupMethods + end + + # Evaluates the specified block for each of the RESTful controller methods. + # This is useful to spec that all controller methods redirect when no user is + # logged in. + def with_default_restful_actions(params = {}, &block) + { + :get => :index, + :get => :new, + :post => :create + }.each do |method_id, message| + self.send method_id, message, params + block.call + end + { + :get => :edit, + :put => :update, + :delete => :destroy + }.each do |method_id, message| + if params[:before] + params.delete(:before).call + end + # Presuming any id will do + self.send method_id, message, params.merge(:id => 1) + block.call + end + end + + private + def create_ar_class_expectation(name, method, argument = nil, options = {}) + args = [] + unless options.delete(:only_method) + args << argument unless argument.nil? + args << hash_including(options) unless options.empty? + end + method = options.delete(:find_method) if options[:find_method] + if args.empty? + class_for(name).should_receive(method).and_return(instance_for(name)) + else + class_for(name).should_receive(method).with(*args).and_return(instance_for(name)) + end + end + + def create_positive_ar_instance_expectation(name, method, *args) + instance = instance_for(name) + if args.empty? + instance.should_receive(method).and_return(true) + else + instance.should_receive(method).with(*args).and_return(true) + end + end + + # These methods are designed to be used at the example group [read: "describe"] level + # to simplify and DRY up common expectations. + module ExampleGroupMethods + # Creates an expectation that the controller method calls ActiveRecord::Base.find. + # Examples: + # + # it_should_find :foos # => Foo.should_receive(:find).with(:all) + # it_should_find :foos, :all # An explicit version of the above + # it_should_find :foos, :conditions => {:foo => "bar"} # => Foo.should_receive(:find).with(:all, :conditions => {"foo" => "bar"} + # it_should_find :foos, "joe", :method => :find_all_by_name # Foo.should_receive(:find_all_by_name).with("joe") + # it_should_find :foo # => Foo.should_recieve(:find).with(@foo.id.to_s) + # it_should_find :foo, :params => "id" # => Foo.should_receive(:find).with(params[:id].to_s) + # it_should_find :foo, 2 # => Foo.should_receive(:find).with("2") + # it_should_find :foo, "joe", :method => :find_by_name # => Foo.should_recieve(:find_by_name).with("joe") + # + # Note: All params (key and value) will be strings if they come from a form element and are handled + # internally with this expectation. + def it_should_find(name, *args) + name_string = name.to_s + name_message = if name_string == name_string.singularize + "a #{name}" + else + name + end + it "should find #{name_message}" do + options = args.extract_options! + # Blech! + argument = if param = params[options.delete(:params)] + param.to_s + else + if args.first + args.first + elsif (instance = instance_variable_get("@#{name}")).is_a?(ActiveRecord::Base) + instance.id.to_s + else + :all + end + end + find_method = options.delete(:method) || :find + create_ar_class_expectation name, find_method, argument, options + eval_request + end + end + + # Negative version of it_should_find. This creates an expectation that + # the class never receives find at all. + def it_should_not_find(name) + name_string = name.to_s + name_message = if name_string == name_string.singularize + "a #{name}" + else + name + end + it "should not find #{name_message}" do + if name_string == name_string.singularize + class_for(name).should_not_receive(:find) + else + class_for(name).should_not_receive(:find).with(:all) + end + eval_request + end + end + + # Creates an expectation that the controller method calls ActiveRecord::Base.new. + # Takes optional params for the initialization arguments. Example + # + # it_should_initialize :foo # => Foo.should_receive(:new) + # it_should_initialize :foo, :params => :bar # => Foo.should_receive(:new).with(params[:bar]) + # it_should_initialize :foo, :bar => "baz" # => Foo.should_receive(:new).with(:bar => "baz") + def it_should_initialize(name, options = {}) + it "should initialize a #{name}" do + create_ar_class_expectation name, :new, params[options.delete(:params)], options + eval_request + end + end + + # Negative version of it_should_initialize. This creates an expectation + # that the class never recieves new at all. + def it_should_not_initialize(name) + it "should initialize a #{name}" do + class_for(name).should_not_receive(:new) + eval_request + end + end + + # Creates an expectation that the controller method calls ActiveRecord::Base#save on the + # named instance. Example: + # + # it_should_save :foo # => @foo.should_receive(:save).and_return(true) + # + # Note: This helper should not be used to spec a failed save call. Use it_should_assign + # instead, to verify that the instance is captured in an instance variable for the inevitable re-rendering + # of the form template. + def it_should_save(name) + it "should save the #{name}" do + create_positive_ar_instance_expectation name, :save + eval_request + end + end + + # Negative version of it_should_update. This creates an expectation + # that the instance never receives save at all. + def it_should_not_save(name) + it "should not save the #{name}" do + instance_for(name).should_not_receive(:save) + eval_request + end + end + + # Creates an expectation that the controller method calls ActiveRecord::Base#update_attributes + # on the named instance. Takes optional argument for params to specify in the + # expectation. Examples: + # + # it_should_update :foo # => @foo.should_receive(:update_attributes).and_return(true) + # it_should_update :foo, :params => :bar # => @foo.should_receive(:update_attributes).with(params[:bar]).and_return(true) + # + # Note: This helper should not be used to spec a failed update_attributes call. Use + # it_should_assign instead, to verify that the instance is captured in an instance variable + # for the inevitable re-rendering of the form template. + def it_should_update(name, options = {}) + it "should update the #{name}" do + create_positive_ar_instance_expectation name, :update_attributes, params[name] + eval_request + end + end + + # Negative version of it_should_update. This creates an expectation + # that the instance never receives update_attributes at all. + def it_should_not_update(name) + it "should not update the #{name}" do + instance_for(name).should_not_receive(:update_attributes) + eval_request + end + end + + # Creates an expectation that the controller method calls ActiveRecord::Base#destroy on the named + # instance. Example: + # + # it_should_destroy :foo # => @foo.should_receive(:destroy).and_return(true) + # + # Note: This helper should not be used to spec a failed destroy call. Use + # it_should_assign instead, if you need to verify that the instance is captured in an instance + # variable if it is re-rendered somehow. This is probably a really edge use case. + def it_should_destroy(name, options = {}) + it "should delete the #{name}" do + create_positive_ar_instance_expectation name, :destroy + eval_request + end + end + + # Negative version of it_should_destroy. This creates an expectation + # that the instance never receives destroy at all. + def it_should_not_destroy(name) + it "should not destroy the #{name}" do + instance_for(name).should_not_receive(:destroy) + eval_request + end + end + + # Creates expectation[s] that the controller method should assign the specified + # instance variables along with any specified values. Examples: + # + # it_should_assign :foo # => assigns[:foo].should == @foo + # it_should_assign :foo => "bar" # => assigns[:foo].should == "bar" + # it_should_assign :foo => :nil # => assigns[:foo].should be_nil + # it_should_assign :foo => :not_nil # => assigns[:foo].should_not be_nil + # it_should_assign :foo => :undefined # => controller.send(:instance_variables).should_not include("@foo") + # + # Very special thanks to Rick Olsen for the basis of this code. The only reason I even + # redefine it at all is purely an aesthetic choice for specs like "it should foo" + # over ones like "it foos". + def it_should_assign(*names) + names.each do |name| + if name.is_a?(Symbol) + it_should_assign name => name + elsif name.is_a?(Hash) + name.each do |key, value| + it_should_assign_instance_variable key, value + end + end + end + end + + # Essentially shorthand for it_should_assign name => :nil. This method can take multiple + # instance variable names, creating this shorthand for each name. See the docs for + # it_should_assign for more information. + def it_should_not_assign(*names) + names.each do |name| + # Assuming name is a symbol + it_should_assign name => :nil + end + end + + # Wraps the separate expectations it_should_find and it_should_assign + # for simple cases. If you need more control over the parameters of the find, this + # isn't the right helper method and you should write out the two expectations separately. + def it_should_find_and_assign(*names) + names.each do |name| + it_should_find name, :only_method => true + it_should_assign name + end + end + + # Negative version of it_should_find_and_assign. This creates an + # expectation that the class never receives find at all and that + # no matching instance variable is ever created. + def it_should_not_find_and_assign(*names) + names.each do |name| + it_should_not_find name + it_should_assign name => :nil + end + end + + # Wraps the separate expectations it_should_initialize and it_should_assign + # for simple cases. If you need more control over the parameters of the initialization, this + # isn't the right helper method and you should write out the two expectations separately. + # + # Note: This method is used for controller methods like new, where the instance + # is initialized without being saved (this includes failed create requests). + # If you want to spec that the controller method successfully saves the instance, + # please use it_should_initialize_and_save. + def it_should_initialize_and_assign(*names) + names.each do |name| + it_should_initialize name, :only_method => true + it_should_assign name + end + end + + # Negative version of it_should_initialize_and_assign. This creates an + # expectation that the class never receives new at all and that + # no matching instance variable is ever created. + def it_should_not_initialize_and_assign(*names) + names.each do |name| + it_should_not_initialize name + it_should_assign name => :nil + end + end + + # Wraps the separate expectations it_should_initialize and it_should_save + # for simple cases. If you need more control over the parameters of the initialization, this + # isn't the right helper method and you should write out the two expectations separately. + # + # Note: This method is used for controller methods like create, where the instance + # is initialized and successfully saved. If you want to spec that the instance is created + # but not saved, just use it_should_initialize_and_assign. + def it_should_initialize_and_save(*names) + names.each do |name| + it_should_initialize name, :only_method => true + it_should_save name + end + end + + # Wraps the separate expectations it_should_find and it_should_update + # for simple cases. If you need more control over the parameters of the find, this + # isn't the right helper method and you should write out the two expectations separately. + # + # Note: This method is used for controller methods like update, where the + # instance is loaded from the database and successfully saved. If you want to spec that the + # instance is found but not saved, just use it_should_find_and_assign. + def it_should_find_and_update(*names) + names.each do |name| + it_should_find name, :only_method => true + it_should_update name + end + end + + # Wraps the separate expectations it_should_find and it_should_destroy + # for simple cases. If you need more control over the parameters of the find, this + # isn't the right helper method and you should write out the two expectations separately. + def it_should_find_and_destroy(*names) + names.each do |name| + it_should_find name, :only_method => true + it_should_destroy name + end + end + + # Creates an expectation that the specified collection (flash, session, + # params, cookies) contains the specified key and value. To specify that + # the collection should be set to nil, specify the value as :nil instead. + def it_should_set(collection, key, value = nil, &block) + it "should set #{collection}[:#{key}]#{' with ' + value.inspect if value}" do + # Allow flash.now[:foo] to remain in the flash + flash.stub!(:sweep) if collection == :flash + eval_request + if value + if value == :nil + self.send(collection)[key].should be_nil + else + self.send(collection)[key].should == value + end + elsif block_given? + self.send(collection)[key].should == instance_eval(&block) + else + self.send(collection)[key].should_not be_nil + end + end + end + + # Wraps it_should_set :flash. To specify that the collection should be set + # to nil, specify the value as :nil instead. + def it_should_set_flash(name, value = nil, &block) + it_should_set :flash, name, value, &block + end + + # Wraps it_should_set :flash, :nil. + def it_should_not_set_flash(name) + it_should_set :flash, name, :nil + end + + # Wraps it_should_set :session. To specify that the collection should be set + # to nil, specify the value as :nil instead. + def it_should_set_session(name, value = nil, &block) + it_should_set :session, name, value, &block + end + + # Wraps it_should_set :session, :nil. + def it_should_not_set_session(name) + it_should_set :session, name, :nil + end + + # Wraps it_should_set :params. To specify that the collection should be set + # to nil, specify the value as :nil instead. + def it_should_set_params(name, value = nil, &block) + it_should_set :params, name, value, &block + end + + # Wraps it_should_set :params, :nil. + def it_should_not_set_params(name) + it_should_set :params, name, :nil + end + + # Wraps it_should_set :cookies. To specify that the collection should be set + # to nil, specify the value as :nil instead. + def it_should_set_cookies(name, value = nil, &block) + it_should_set :cookies, name, value, &block + end + + # Wraps it_should_set :cookies, :nil. + def it_should_not_set_cookies(name) + it_should_set :cookies, name, :nil + end + + # Wraps the various it_should_render_foo methods: + # it_should_render_template, it_should_render_partial, + # it_should_render_xml, it_should_render_json, + # it_should_render_formatted, and it_should_render_nothing. + def it_should_render(render_method, *args) + send "it_should_render_#{render_method}", *args + end + + # Creates an expectation that the controller method renders the specified template. + # Accepts the following options which create additional expectations. + # + # :content_type:: Creates an expectation that the Content-Type header for the response + # matches the one specified + # :status:: Creates an expectation that the HTTP status for the response + # matches the one specified + def it_should_render_template(name, options = {}) + create_status_expectation options[:status] if options[:status] + it "should render '#{name}' template" do + eval_request + response.should render_template(name) + end + create_content_type_expectation(options[:content_type]) if options[:content_type] + end + + # Creates an expectation that the controller method renders the specified partial. + # Accepts the following options which create additional expectations. + # + # :content_type:: Creates an expectation that the Content-Type header for the response + # matches the one specified + # :status:: Creates an expectation that the HTTP status for the response + # matches the one specified + def it_should_render_partial(name, options = {}) + create_status_expectation options[:status] if options[:status] + it "should render '#{name}' partial" do + controller.expect_render(:partial => name) + eval_request + end + create_content_type_expectation(options[:content_type]) if options[:content_type] + end + + # Creates an expectation that the controller method renders the specified record via to_xml. + # Accepts the following options which create additional expectations. + # + # :content_type:: Creates an expectation that the Content-Type header for the response + # matches the one specified + # :status:: Creates an expectation that the HTTP status for the response + # matches the one specified + def it_should_render_xml(record = nil, options = {}, &block) + it_should_render_formatted :xml, record, options, &block + end + + # Creates an expectation that the controller method renders the specified record via to_json. + # Accepts the following options which create additional expectations. + # + # :content_type:: Creates an expectation that the Content-Type header for the response + # matches the one specified + # :status:: Creates an expectation that the HTTP status for the response + # matches the one specified + def it_should_render_json(record = nil, options = {}, &block) + it_should_render_formatted :json, record, options, &block + end + + # Called internally by it_should_render_xml and it_should_render_json + # but should not really be called much externally unless you have defined your own + # formats with a matching to_foo method on the record. + # + # Which is probably never. + def it_should_render_formatted(format, record = nil, options = {}, &block) + create_status_expectation options[:status] if options[:status] + it "should render #{format.inspect}" do + if record.is_a?(Hash) + options = record + record = nil + end + if record.nil? && !block_given? + raise ArgumentError, "it_should_render must be called with either a record or a block and neither was given." + else + if record + pieces = record.to_s.split(".") + record = instance_variable_get("@#{pieces.shift}") + record = record.send(pieces.shift) until pieces.empty? + end + block ||= proc { record.send("to_#{format}") } + get_response do |response| + response.should have_text(block.call) + end + end + end + create_content_type_expectation(options[:content_type]) if options[:content_type] + end + + # Creates an expectation that the controller method returns a blank page. You'd already + # know when and why to use this so I'm not typing it out. + def it_should_render_nothing(options = {}) + create_status_expectation options[:status] if options[:status] + it "should render :nothing" do + get_response do |response| + response.body.strip.should be_blank + end + end + end + + # Creates an expectation that the controller method redirects to the specified destination. Example: + # + # it_should_redirect_to { foos_url } + # + # Note: This method takes a block to evaluate the route in the example + # context rather than the example group context. + def it_should_redirect_to(hint = nil, &route) + if hint.nil? && route.respond_to?(:to_ruby) + hint = route.to_ruby.gsub(/(^proc \{)|(\}$)/, '').strip + end + it "should redirect to #{(hint || route)}" do + eval_request + response.should redirect_to(instance_eval(&route)) + end + end + + # Negative version of it_should_redirect_to. + def it_should_not_redirect_to(hint = nil, &route) + if hint.nil? && route.respond_to?(:to_ruby) + hint = route.to_ruby.gsub(/(^proc \{)|(\}$)/, '').strip + end + it "should not redirect to #{(hint || route)}" do + eval_request + response.should_not redirect_to(instance_eval(&route)) + end + end + + # Creates an expectation that the controller method redirects back to the previous page + def it_should_redirect_to_referer + it "should redirect to the referring page" do + request.env["HTTP_REFERER"] = "http://test.host/referer" + eval_request + response.should redirect_to("http://test.host/referer") + end + end + alias it_should_redirect_to_referrer it_should_redirect_to_referer + + private + def it_should_assign_instance_variable(name, value) + expectation_proc = case value + when :nil + proc { assigns[name].should be_nil } + when :not_nil + proc { assigns[name].should_not be_nil } + when :undefined + proc { controller.send(:instance_variables).should_not include("@{name}") } + when Symbol + if (instance_variable = instance_variable_get("@#{name}")).nil? + proc { assigns[name].should_not be_nil } + else + proc { assigns[name].should == instance_variable } + end + else + proc { assigns[name].should == value } + end + it "should #{value == :nil ? 'not ' : ''}assign @#{name}" do + eval_request + instance_eval &expectation_proc + end + end + end + end +end \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/controller_stub_helpers.rb b/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/controller_stub_helpers.rb new file mode 100644 index 00000000..6d78ce54 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/controller_stub_helpers.rb @@ -0,0 +1,238 @@ +module LuckySneaks # :nodoc: + # These methods are designed to be used in your example before blocks to accomplish + # a whole lot of functionality with just a tiny bit of effort. The methods which correspond + # to the controller methods perform the most duties as they create the mock_model instances, + # stub out all the necessary methods, and also create implicit requests to DRY up your spec + # file even more. You are encouraged to use these methods to setup the basic calls for your + # resources and only resort to the other methods when mocking and stubbing secondary objects + # and calls. + module ControllerStubHelpers + # Stubs out find :all and returns a collection of mock_model + # instances of that class. Accepts the following options: + # + # :find_method:: Method to use as finder call. Default is :find. + # Note: When specifying the method, the call is stubbed + # to accept any arguments. Caveat programmer. + # :format:: Format of the request. Used to only add to_xml and + # to_json when actually needed. + # :size:: Number of instances to return in the result. Default is 3. + # :stub:: Additional methods to stub on the instances + # + # Any additional options will be passed as arguments to the class find. + # You will want to make sure to pass those arguments to the it_should_find spec as well. + def stub_find_all(klass, options = {}) + returning(Array.new(options[:size] || 3){mock_model(klass)}) do |collection| + stub_out klass, options.delete(:stub) + if format = options.delete(:format) + stub_formatted collection, format + params[:format] = format + end + if find_method = options[:find_method] + # Not stubbing specific arguments here + # If you need more specificity, write a custom example + klass.stub!(find_method).and_return(collection) + else + klass.stub!(:find).with(:all).and_return(collection) + klass.stub!(:find).with(:all, hash_including(options)).and_return(collection) + end + end + end + + # Alias for stub_find_all but additionally defines an implicit request get :index. + def stub_index(klass, options = {}) + define_implicit_request :index + stub_find_all klass, options + end + + # Stubs out new method and returns a mock_model instance marked as a new record. + # Accepts the following options: + # + # :format:: Format of the request. Used to only add to_xml and + # to_json when actually needed. + # :stub:: Additional methods to stub on the instances + # + # It also accepts some options used to stub out save with a specified true + # or false but you should be using stub_create in that case. + def stub_initialize(klass, options = {}) + returning mock_model(klass) do |member| + stub_out member, options.delete(:stub) + if format = options[:format] + stub_formatted member, format + params[:format] = format + end + klass.stub!(:new).and_return(member) + if options[:params] + klass.stub!(:new).with(hash_including(options[:params])).and_return(member) + end + if options[:stub_save] + stub_ar_method member, :save, options[:return] + else + member.stub!(:new_record?).and_return(true) + member.stub!(:id).and_return(nil) + end + end + end + + # Alias for stub_initialize which additionally defines an implicit request get :new. + def stub_new(klass, options = {}) + define_implicit_request :new + stub_initialize klass, options + end + + # Alias for stub_initialize which additionally defines an implicit request post :create. + # + # Note: If stub_create is provided an optional :params hash, + # those params will be added to the example's params object. + def stub_create(klass, options = {}) + define_implicit_request :create + class_name = klass.name.underscore + options[:params] ||= params[class_name] + stub_initialize klass, options.merge(:stub_save => true) + end + + # Stubs out find and returns a single mock_model + # instances of that class. Accepts the following options: + # + # :find_method:: Method to use as finder call. Default is :find. + # :format:: Format of the request. Used to only add to_xml and + # to_json when actually needed. + # :stub:: Additional methods to stub on the instances + # :current_object:: If set to true, find will set params[:id] + # using the id of the mock_model instance + # and use that value as an argument when stubbing find + # + # Any additional options will be passed as arguments to find.You will want + # to make sure to pass those arguments to the it_should_find spec as well. + # + # Note: The option :stub_ar is used internally by stub_update + # and stub_destroy. If you need to stub update_attributes or + # destroy you should be using the aforementioned methods instead. + def stub_find_one(klass, options = {}) + returning mock_model(klass) do |member| + stub_out member, options.delete(:stub) + if format = options.delete(:format) + stub_formatted member, format + params[:format] = format + end + if options.delete(:current_object) + params[:id] = member.id + if ar_stub = options.delete(:stub_ar) + stub_ar_method member, ar_stub, options.delete(:return), options.delete(:update_params) + end + end + if find_method = options.delete(:find_method) + klass.stub!(find_method).and_return(member) + else + # Stubbing string and non-string just to be safe + klass.stub!(:find).with(member.id).and_return(member) + klass.stub!(:find).with(member.id.to_s).and_return(member) + unless options.empty? + klass.stub!(:find).with(member.id, hash_including(options)).and_return(member) + klass.stub!(:find).with(member.id.to_s, hash_including(options)).and_return(member) + end + end + end + end + + # Note: Use of this method with :child options (to mock + # association) is deprecated. Please use stub_association. + # + # Same as stub_find_one but setups the instance as the parent + # of the specified association. Example: + # + # stub_parent(Document, :child => :comments) + # + # This stubs Document.find, @document.comments (which + # will return Comment class), as well as params[:document_id]. + # This method is meant to be used in the controller for the specified child + # (CommentsController in this instance) in situations like: + # + # def index + # @document = Document.find(params[:document_id]) + # @comments = @document.comments.find(:all) + # end + def stub_parent(klass, options = {}) + returning stub_find_one(klass, options) do |member| + params[klass.name.foreign_key] = member.id + if offspring = options.delete(:child) + puts "stub_parent with :child option has been marked for deprecation" + puts "please use stub_association to create the mock instead" + member.stub!(offspring).and_return(class_for(offspring)) + end + end + end + + # Alias for stub_find_one which additionally defines an implicit request get :show. + def stub_show(klass, options = {}) + define_implicit_request :show + stub_find_one klass, options.merge(:current_object => true) + end + + # Alias for stub_find_one which additionally defines an implicit request get :edit. + def stub_edit(klass, options = {}) + define_implicit_request :edit + stub_find_one klass, options.merge(:current_object => true) + end + + # Alias for stub_find_one which additionally defines an implicit request put :update + # and stubs out the update_attribute method on the instance as well. + # + # Note: If stub_update is provided an optional :params hash, + # those params will be added to the example's params object. + def stub_update(klass, options = {}) + define_implicit_request :update + stub_find_one klass, options.merge(:current_object => true, :stub_ar => :update_attributes) + end + + # Alias for stub_find_one which additionally defines an implicit request delete :destroy + # and stubs out the destroy method on the instance as well. + def stub_destroy(klass, options = {}) + define_implicit_request :destroy + stub_find_one klass, options.merge(:current_object => true, :stub_ar => :destroy) + end + + # Stubs to_xml or to_json respectively based on format argument. + def stub_formatted(object, format) + return unless format + object.stub!("to_#{format}").and_return("#{object.class} formatted as #{format}") + end + + # Creates a mock object representing an association proxy, stubs the appropriate + # method on the parent object and returns that association proxy. + # Accepts the following option: + # + # :stub:: Additional methods to stub on the mock proxy object + def stub_association(object, association, options = {}) + # I know options isn't implemented anywhere + object_name = instance_variables.select{|name| instance_variable_get(name) == object} + returning mock("Association proxy for #{object_name}.#{association}") do |proxy| + stub_out proxy, options[:stub] if options[:stub] + object.stub!(association).and_return(proxy) + end + end + + private + # Stubs out multiple methods. You shouldn't be calling this yourself and if you do + # you should be able to understand the code yourself, right? + def stub_out(object, stubs = {}) + return if stubs.nil? + stubs.each do |method, value| + if value + object.stub!(method).and_return(value) + else + object.stub!(method) + end + end + end + + # Stubs out ActiveRecord::Base methods like #save, #update_attributes, etc + # that may be called on a found or instantiated mock_model instance. + def stub_ar_method(object, method, return_value, params = {}) + if params.blank? + object.stub!(method).and_return(return_value ? false : true) + else + object.stub!(method).with(hash_including(params)).and_return(return_value ? false : true) + end + end + end +end diff --git a/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/model_spec_helpers.rb b/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/model_spec_helpers.rb new file mode 100644 index 00000000..4119acc6 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/model_spec_helpers.rb @@ -0,0 +1,496 @@ +$:.unshift File.join(File.dirname(__FILE__), "..") +require "skinny_spec" + +module LuckySneaks + # These methods are designed to be used in your example [read: "it"] blocks + # to make your model specs a little more DRY. You might also be interested + # in checking out the example block [read: "describe"] level versions in of these + # methods which can DRY things up even more: + # LuckySneaks::ModelSpecHelpers::ExampleGroupLevelMethods. + # + # Also check out the methods in LuckySneaks::ModelSpecHelpers::AssociationMatcher + # for some helpful matcher helper methods to use with these methods if you want to spec + # options on your association setups. + module ModelSpecHelpers + include LuckySneaks::CommonSpecHelpers + + def self.included(base) # :nodoc: + base.extend ExampleGroupLevelMethods + end + + # These methods cannot be used alone but are used in compliment with the association + # matchers in LuckySneaks::ModelSpecHelpers like have_many. Example: + # + # describe User do + # it "should have many memberships" do + # User.should have_many(:memberships) + # end + # + # it "should have many sites through memberships" do + # User.should have_many(:sites).through(:memberships) + # end + # + # it "should belong to a manager" do + # User.should belong_to(:manager).with_counter_cache + # end + # end + # + # Note: To spec these sorts of options using the example block helpers like + # it_should_have_many, just add them as options directly. This will use + # with_options rather than any specific matcher helpers but will have the same + # effects. Example: + # + # describe User do + # it_should_have_many :sites, :through => :memberships + # end + class AssociationMatcher + def initialize(associated, macro) # :nodoc: + @associated = associated + @macro = macro + @options = {} + end + + def matches?(main_model) # :nodoc: + unless main_model.respond_to?(:reflect_on_association) + if main_model.class.respond_to?(:reflect_on_association) + main_model = main_model.class + else + @not_model = main_model + return false + end + end + if @association = main_model.reflect_on_association(@associated) + @options.all?{|k, v| @association.options[k] == v || + [@association.options[k]] == v} # Stupid to_a being obsoleted! + end + end + + def failure_message # :nodoc: + if @not_model + " expected: #{@not_model} to be a subclass of ActiveRecord::Base class, but was not" + elsif @association + " expected: #{association_with(@options)}\n got: #{association_with(@association.options)}" + else + " expected: #{association_with(@options)}, but the association does not exist" + end + end + + def negative_failure_message # :nodoc: + if @association + " expected: #{association_with(@options)}\n got: #{association_with(@association.options)}" + else + " expected: #{association_with(@options)} to not occur but it does" + end + end + + # The following public methods are chainable extensions on the main matcher + # Examples: + # + # Foo.should have_many(:bars).through(:foobars).with_dependent(:destroy) + # Bar.should belong_to(:baz).with_class_name("Unbaz") + def through(through_model) + @options[:through] = through_model + self + end + + def and_includes(included_models) + @options[:include] = included_models + self + end + + def and_extends(*modules) + @options[:extends] = modules + self + end + + def with_counter_cache(counter_cache = true) + if counter_cache + @options[:counter_cache] = counter_cache + end + self + end + + def uniq(*irrelevant_args) + @options[:uniq] = true + self + end + alias and_is_unique uniq + alias with_unique uniq + + def polymorphic(*irrelevant_args) + @options[:polymorphic] = true + self + end + alias and_is_polymorphic polymorphic + alias with_polymorphic polymorphic + + def as(interface) + @options[:as] = interface + end + + # Use this to just specify the options as a hash. + # Note: It will completely override any previously set options + def with_options(options = {}) + options.each{|k, v| @options[k] = v} + self + end + + private + # Takes care of methods like with_dependent(:destroy) + def method_missing(method_id, *args, &block) + method_name = method_id.to_s + if method_name =~ /^with_(.*)/ + @options[$1.to_sym] = args + self + else + super method_id, *args, &block + end + end + + def association_with(options) + option_string = (options.nil? || options.empty?) ? "" : options.inspect + unless option_string.blank? + option_string.sub! /^\{(.*)\}$/, ', \1' + option_string.gsub! /\=\>/, ' => ' + end + "#{@macro} :#{@associated}#{option_string}" + end + end + + # Creates matcher that checks if the receiver has a belongs_to association + # with the specified model. + # + # Note: The argument should be a symbol as in the model's association definition + # and not the model's class name. + def belong_to(model) + AssociationMatcher.new model, :belongs_to + end + + # Creates matcher that checks if the receiver has a have_one association + # with the specified model. + # + # Note: The argument should be a symbol as in the model's association definition + # and not the model's class name. + def have_one(model) + AssociationMatcher.new model, :has_one + end + + # Creates matcher that checks if the receiver has a have_many association + # with the specified model. + # + # Note: The argument should be a symbol as in the model's association definition + # and not the model's class name. + def have_many(models) + AssociationMatcher.new models, :has_many + end + + # Creates matcher that checks if the receiver has a have_and_belong_to_many association + # with the specified model. + # + # Note: The argument should be a symbol as in the model's association definition + # and not the model's class name. + def have_and_belong_to_many(models) + AssociationMatcher.new models, :has_and_belongs_to_many + end + + private + def class_or_instance + @model_spec_class_or_instance ||= class_for(described_type) || instance + end + + def instance + @model_spec_instance ||= instance_for(described_type) + end + + # These methods are designed to be used at the example group [read: "describe"] level + # to simplify and DRY up common expectations. Some of these methods are wrappers for + # matchers which can also be used on the example level [read: within an "it" block]. See + # LuckySneaks::ModelSpecHelpers for more information. + # + # Note: The validation matchers are only meant to be used for simple validation checking + # not as a one-size-fits-all solution. + module ExampleGroupLevelMethods + # Creates an expectation that the current model being spec'd has a belong_to + # association with the specified model. Accepts optional arguments which are appended to + # the belong_to spec like this: + # + # it_should_belong_to :document, :counter_cache => true + # + # which is the same as writing out: + # + # it "should belong to document" do + # Comment.should belong_to(:document).with_options(:counter_cache => true) + # end + # + # If you want a more detailed spec description text, feel free to write this out in the long + # form and use belong_to and its related matcher helpers. + # + # Note: The argument should be a symbol as in the model's association definition + # and not the model's class name. + def it_should_belong_to(model, options = {}) + it "should belong to a #{model}" do + if options.empty? + class_or_instance.should belong_to(model) + else + class_or_instance.should belong_to(model).with_options(options) + end + end + end + + # Creates an expectation that the current model being spec'd has a have_one + # association with the specified model. Accepts optional arguments which are appended to + # the have_one spec like this: + # + # it_should_have_one :last_comment, :class_name => "Comment", :order => "created_at DESC" + # + # which is the same as writing out: + # + # it "should have one document" do + # Document.should have_one(:last_comment).with_options(:class_name => "Comment", :order => "created_at DESC") + # end + # + # If you want a more detailed spec description text, feel free to write this out in the long + # form and use have_one and its related matcher helpers. + # + # Note: The argument should be a symbol as in the model's association definition + # and not the model's class name. + def it_should_have_one(model, options = {}) + it "should have one #{model}" do + if options.empty? + class_or_instance.should have_one(model) + else + class_or_instance.should have_one(model).with_options(options) + end + end + end + + # Creates an expectation that the current model being spec'd has a have_many + # association with the specified model. Accepts optional arguments which are appended to + # the have_many spec like this: + # + # it_should_have_many :memberships, :through => :sites + # + # which is the same as writing out: + # + # it "should have many memberships" do + # User.should have_many(:memberships).with_options(:through => :sites) + # end + # + # If you want a more detailed spec description text, feel free to write this out in the long + # form and use have_many and its related matcher helpers. + # + # Note: The argument should be a symbol as in the model's association definition + # and not the model's class name. + def it_should_have_many(models, options = {}) + it "should have many #{models}" do + if options.empty? + class_or_instance.should have_many(models) + else + class_or_instance.should have_many(models).with_options(options) + end + end + end + + # Creates an expectation that the current model being spec'd has a have_and_belong_to_many + # association with the specified model. Accepts optional arguments which are appended to + # the have_and_belong_to_many spec like this: + # + # it_should_have_and_belong_to_many :documents, :include => :attachments + # + # which is the same as writing out: + # + # it "should belong to document" do + # User.should have_and_belong_to_many(:documents).with_options(:include => :attachments) + # end + # + # If you want a more detailed spec description text, feel free to write this out in the long + # form and use have_and_belong_to_many and its related matcher helpers. + # + # Note: The argument should be a symbol as in the model's association definition + # and not the model's class name. + def it_should_have_and_belong_to_many(models, options = {}) + it "should have and belong to many #{models}" do + if options.empty? + class_or_instance.should have_and_belong_to_many(models) + else + class_or_instance.should have_and_belong_to_many(models).with_options(options) + end + end + end + + # Creates an expectation that new instances of the model being spec'd + # should initialise the specified attributes with a default value. + # + # it_should_default_attributes :status => 'new' + # + def it_should_default_attributes(hash_attribute_values) + hash_attribute_values.each_pair do |a,v| + it "should default #{a} attribute to #{v}" do + class_or_instance.new.send(a).should == v + end + end + end + + # Creates an expectation that the current model being spec'd validates_presence_of + # the specified attribute. Takes an optional custom message to match the one in the model's + # validation. + def it_should_validate_presence_of(attribute, message = default_error_message(:blank)) + it "should not be valid if #{attribute} is blank" do + instance.send "#{attribute}=", nil + instance.errors_on(attribute).should include(message) + end + end + + # Negative version of it_should_validate_presence_of. See that method for more + # details. You'd probably only be using this in a nested example block to compare that + # one scenario validates presence and another does not (because of conditions in + # :if/:unless). + def it_should_not_validate_presence_of(attribute, message = default_error_message(:blank)) + it "should be valid if #{attribute} is blank" do + instance.send "#{attribute}=", nil + instance.errors_on(attribute).should_not include(message) + end + end + + # Creates an expectation that the current model being spec'd validates_inclusion_of + # the specified attribute. Takes an optional custom message to match the one in the model's + # validation. + def it_should_validate_inclusion_of(attribute, options = {}, message = default_error_message(:inclusion)) + it "should validate #{attribute} is in #{options[:in].to_s}" do + # We specifically do not try to go below the range on String and character ranges because that problem set is unpredictable. + lower = options[:in].first.respond_to?(:-) ? options[:in].first - 0.0001 : nil + higher = options[:in].last.succ + + instance.send "#{attribute}=", lower + instance.errors_on(attribute).should include(message) + + instance.send "#{attribute}=", higher + instance.errors_on(attribute).should include(message) + + instance.send "#{attribute}=", (lower+higher)/2 + instance.errors_on(attribute).should_not include(message) + end + end + + # Creates an expectation that the current model being spec'd validates_numericality_of + # the specified attribute. Takes an optional custom message to match the one in the model's + # validation. + def it_should_validate_numericality_of(attribute, message = default_error_message(:not_a_number)) + it "should validate #{attribute} is a numeric" do + instance.send "#{attribute}=", "NaN" + instance.errors_on(attribute).should include(message) + end + end + + # Negative version of it_should_validate_numericality_of. See that method for more + # details. You'd probably only be using this in a nested example block to compare that + # one scenario validates presence and another does not (because of conditions in + # :if/:unless). + def it_should_not_validate_numericality_of(attribute, message = default_error_message(:not_a_number)) + it "should not validate #{attribute} is a numeric" do + instance.send "#{attribute}=", "NaN" + instance.errors_on(attribute).should_not include(message) + end + end + + # Creates an expectation that the current model being spec'd validates_confirmation_of + # the specified attribute. Takes an optional custom message to match the one in the model's + # validation. + def it_should_validate_confirmation_of(attribute, message = default_error_message(:confirmation)) + it "should validate confirmation of #{attribute}" do + dummy_value = dummy_value_for(instance, attribute) || "try a string" + instance.send "#{attribute}=", dummy_value + instance.send "#{attribute}_confirmation=", dummy_value.succ + instance.errors_on(attribute).should include(message) + end + end + + # Creates an expectation that the current model being spec'd validates_uniqueness_of + # the specified attribute. Takes an optional custom message to match the one in the model's + # validation. + # + # Note: This method will fail completely if valid_attributes + # does not provide all the attributes needed to create a valid record. + def it_should_validate_uniqueness_of(attribute, message = default_error_message(:taken)) + it "should validate uniqueness of #{attribute}" do + previous_instance = instance.class.create!(valid_attributes) + instance.attributes = valid_attributes + instance.errors_on(attribute).should include(message) + previous_instance.destroy + end + end + + # Negative version of it_should_validate_uniqueness_of. See that method for more + # details. You'd probably only be using this in a nested example block to compare that + # one scenario validates presence and another does not (because of conditions in + # :if/:unless). + def it_should_not_validate_uniqueness_of(attribute, message = default_error_message(:taken)) + it "should not validate uniqueness of #{attribute}" do + previous_instance = instance.class.create!(valid_attributes) + instance.attributes = valid_attributes + instance.errors_on(attribute).should_not include(message) + previous_instance.destroy + end + end + + # Creates an expectation that the current model being spec'd accepts the specified values as + # valid for the specified attribute. This is most likely used with validates_format_of + # but there's nothing saying it couldn't be another validation. + def it_should_accept_as_valid(attribute, *values) + values.flatten.each do |value| + value_inspect = case value + when String : "'#{value}'" + when NilClass : "nil" + else value + end + it "should accept #{value_inspect} as a valid #{attribute}" do + instance.send "#{attribute}=", value + instance.errors_on(attribute).should == [] + end + end + end + + # Creates an expectation that the current model being spec'd does not accept the specified + # values as valid for the specified attribute. This is most likely used with + # validates_format_of but there's nothing saying it couldn't be another validation. + # Takes an optional argument :message => "some custom error messsage" for + # spec'ing the actual error message. + def it_should_not_accept_as_valid(attribute, *values) + options = values.extract_options! + values.flatten.each do |value| + value_inspect = case value + when String : "'#{value}'" + when NilClass : "nil" + else value + end + it "should not accept #{value_inspect} as a valid #{attribute}" do + instance.send "#{attribute}=", value + if options[:message] + instance.errors_on(attribute).should include(options[:message]) + else + instance.should have_at_least(1).errors_on(attribute) + end + end + end + end + + # Creates an expectation that the current model being spec'd doesn't allow mass-assignment + # of the specified attribute. + def it_should_not_mass_assign(attribute) + it "should not allow mass-assignment of #{attribute}" do + lambda { + instance.send :attributes=, {attribute => dummy_value_for(instance, attribute)} + }.should_not change(instance, attribute) + end + end + + def default_error_message(attribute) + if defined?(I18n) + I18n.translate attribute, :scope => "activerecord.errors.messages" + else + ActiveRecord::Errors.default_error_messages[attribute] + end + end + end + end +end diff --git a/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/view_spec_helpers.rb b/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/view_spec_helpers.rb new file mode 100644 index 00000000..fb8775a1 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/view_spec_helpers.rb @@ -0,0 +1,577 @@ +$:.unshift File.join(File.dirname(__FILE__), "..") +require "skinny_spec" + +module LuckySneaks + # These methods are designed to be used in your example [read: "it"] blocks + # to make your view specs less brittle and more DRY. You might also be interested + # in checking out the example block [read: "describe"] level versions in of these + # methods which can DRY things up even more: + # LuckySneaks::ViewSpecHelpers::ExampleGroupLevelMethods. + module ViewSpecHelpers + include LuckySneaks::CommonSpecHelpers + include LuckySneaks::ViewStubHelpers + include ActionController::PolymorphicRoutes + + def self.included(base) # :nodoc: + base.extend ExampleGroupLevelMethods + end + + # Wraps a matcher that checks if the receiver contains a FORM element with + # its action attribute set to the specified path. + def submit_to(path) + have_tag("form[action=#{path}]") + end + + # Wraps a matcher that checks if the receiver contains any of several form elements + # that would return sufficient named parameters to allow editing of the specified + # attribute on the specified instance. Example: + # + # response.should allow_editing(@foo, "bar") + # + # can be satisfied by any of the following HTML elements: + # + # + # + # + # + # + def allow_editing(instance, attribute) + instance_name = instance.class.name.underscore.downcase + column = instance.column_for_attribute(attribute) + if column && [Date, Time].include?(column.klass) + have_tag( + "input[name='#{instance_name}[#{attribute}]'], + select[name=?]", /#{instance_name}\[#{attribute}\(.*\)\]/ + ) + else + have_tag( + "input[type='text'][name='#{instance_name}[#{attribute}]'], + input[type='password'][name='#{instance_name}[#{attribute}]'], + select[name='#{instance_name}[#{attribute}]'], + textarea[name='#{instance_name}[#{attribute}]'], + input[type='checkbox'][name='#{instance_name}[#{attribute}]'], + input[type='checkbox'][name='#{instance_name}[#{attribute.to_s.tableize.singularize}_ids][]'], + input[type='radio'][name='#{instance_name}[#{attribute}]']" + ) + end + end + + # Wraps a matcher that checks if the receiver contains a FORM element + # whose enctype attribute is set to "multipart/form-data" + # and contains an INPUT element whose name attribute correlates + # with the provided instance and attribute. + def allow_uploading(instance, attribute) + instance_name = instance.class.name.underscore.downcase + have_tag("form[enctype='multipart/form-data'] input[type='file'][name='#{instance_name}[#{attribute}]']") + end + + # Wraps a matcher that checks if the receiver contains an A element (link) + # whose href attribute is set to the specified path or a FORM + # element whose action attribute is set to the specified path. + def have_link_or_button_to(path) + have_tag( + "a[href='#{path}'], + form[action='#{path}'] input, + form[action='#{path}'] button" + ) + end + alias have_link_to have_link_or_button_to + alias have_button_to have_link_or_button_to + + # Wraps have_link_or_button_to new_polymorphic_path for the specified class which + # corresponds with the new method of the controller. + # + # Note: This method may takes a string or symbol representing the model's name + # to send to have_link_or_button_to_show or the model's name itself. + def have_link_or_button_to_new(name) + have_link_or_button_to new_polymorphic_path(name.is_a?(ActiveRecord::Base) ? name : class_for(name)) + end + + # Wraps have_link_or_button_to polymorphic_path(instance) which + # corresponds with the show method of the controller. + def have_link_or_button_to_show(instance) + path = polymorphic_path(instance) + have_tag( + "a[href='#{path}'], + form[action='#{path}'][method='get'] input, + form[action='#{path}'][method='get'] button, + form[action='#{path}'] input[name='_method'][value='get'] + input, + form[action='#{path}'] input[name='_method'][value='get'] + button" + ) + end + alias have_link_to_show have_link_or_button_to_show + alias have_button_to_show have_link_or_button_to_show + + # Wraps have_link_or_button_to edit_polymorphic_path(instance) which + # corresponds with the edit method of the controller. + def have_link_or_button_to_edit(instance) + have_link_or_button_to edit_polymorphic_path(instance) + end + alias have_link_to_edit have_link_or_button_to_edit + alias have_button_to_edit have_link_or_button_to_edit + + # Wraps a matcher that checks if the receiver contains the HTML created by Rails' + # button_to helper: to wit, a FORM element whose action + # attribute is pointed at the polymorphic_path of the instance + # and contains an INPUT named "_method" with a value of "delete". + def have_button_to_delete(instance) + path = polymorphic_path(instance) + have_tag( + "form[action='#{path}'] input[name='_method'][value='delete'] + input, + form[action='#{path}'] input[name='_method'][value='delete'] + button, + a[href=\"#{path}\"][onclick*=\"f.method = 'POST'\"][onclick*=\"m.setAttribute('name', '_method'); m.setAttribute('value', 'delete')\"]" + ) + end + + # Creates a mock_model instance and adds it to the assigns collection + # using either the name passed as the first argument or the underscore version + # of its class name. Accepts optional arguments to stub out additional methods + # (and their return values) on the mock_model instance. Example: + # + # mock_and_assign(Foo, :stub => {:bar => "bar"}) + # + # is the same as running assigns[:foo] = mock_model(Foo, :bar => "bar"). + # + # mock_and_assign(Foo, "special_foo", :stub => {:bar => "baz"}) + # + # is the same as running assigns[:special_foo] = mock_model(Foo, :bar => "baz"). + # + # Note: Adding to the assigns collection returns the object added, so this can + # be chained a la @foo = mock_and_assign(Foo). + def mock_and_assign(klass, *args) + options = args.extract_options! + mocked = if options[:stub] + self.respond_to?(:stub_model) ? stub_model(klass, options[:stub]) : mock_model(klass, options[:stub]) + else + self.respond_to?(:stub_model) ? stub_model(klass) : mock_model(klass) + end + yield mocked if block_given? + self.assigns[args.first || "#{klass}".underscore] = mocked + end + + # Creates an array of mock_model instances in the manner of + # mock_and_assign. Accepts option[:size] which sets the size + # of the array (default is 3). + def mock_and_assign_collection(klass, *args) + options = args.extract_options! + return_me = Array.new(options[:size] || 3) do + mocked = if options[:stub] + self.respond_to?(:stub_model) ? stub_model(klass, options[:stub]) : mock_model(klass, options[:stub]) + else + self.respond_to?(:stub_model) ? stub_model(klass) : mock_model(klass) + end + yield mocked if block_given? + mocked + end + self.assigns[args.first || "#{klass}".tableize] = return_me + end + + private + def do_render + if @the_template + render @the_template + elsif File.exists?(File.join(RAILS_ROOT, "app/views", class_description_text)) + render class_description_text + else + error_message = "Cannot determine template for render. " + error_message << "Please define @the_template in the before block " + error_message << "or name your describe block so that it indicates the correct template." + raise NameError, error_message + end + end + + # These methods are designed to be used at the example group [read: "describe"] level + # to simplify and DRY up common expectations. Most of these methods are wrappers for + # matchers which can also be used on the example level [read: within an "it" block]. See + # LuckySneaks::ViewSpecHelpers for more information. + module ExampleGroupLevelMethods + include LuckySneaks::CommonSpecHelpers + + # Creates an expectation which calls submit_to on the response + # from rendering the template. See that method for more details. + # + # Note: This method takes a Proc to evaluate the route not simply a named route + # helper, which would be undefined in the scope of the example block. + def it_should_submit_to(hint = nil, &route) + if hint.nil? && route.respond_to?(:to_ruby) + hint = route.to_ruby.gsub(/(^proc \{)|(\}$)/, '').strip + end + it "should submit to #{(hint || route)}" do + do_render + response.should submit_to(instance_eval(&route)) + end + end + + # Negative version of it_should_submit_to. See that method for more + # details. + def it_should_not_submit_to(hint = nil, &route) + if hint.nil? && route.respond_to?(:to_ruby) + hint = route.to_ruby.gsub(/(^proc \{)|(\}$)/, '').strip + end + it "should not submit to #{(hint || route)}" do + do_render + response.should_not submit_to(instance_eval(&route)) + end + end + + # Creates an expectation that the template uses Rails' form_for to generate + # the proper form action and method to create or update the specified object. + # + # Note: This method takes a string or symbol representing the instance + # variable's name to create the expectation for form_for + # not an instance variable, which would be nil in the scope of the example block. + # If you use namespacing for your form_for, you'll have to manually write out + # a similar spec. + def it_should_have_form_for(name, options = {}) + it "should have a form_for(@#{name})" do + if options.empty? + template.should_receive(:form_for).with(instance_for(name)) + else + template.should_receive(:form_for).with(instance_for(name), hash_including(options)) + end + do_render + end + end + + # Negative version of it_should_have_form_for. See that method for more + # details. + def it_should_not_have_form_for(name, options = {}) + it "should not have a form_for(@#{name})" do + if options.empty? + template.should_not_receive(:form_for).with(instance_for(name)) + else + template.should_not_receive(:form_for).with(instance_for(name), hash_including(options)) + end + do_render + end + end + + # Creates an expectation which calls allow_editing on the rendered + # template for each attribute specified. See the docs for allow_editing + # for more details. + # + # Note: This method takes a string or symbol representing the instance + # variable's name to send to allow_editing + # not an instance variable, which would be nil in the scope of the example block. + def it_should_allow_editing(instance_name, *attributes) + attributes.flatten! + attributes.each do |attribute| + it "should allow editing of @#{instance_name}##{attribute}" do + do_render + response.should allow_editing(instance_for(instance_name), attribute) + end + end + end + + # Negative version of it_should_allow_editing. See that method for more + # details. + def it_should_not_allow_editing(instance_name, *attributes) + attributes.flatten! + attributes.each do |attribute| + it "should not allow editing of @#{instance_name}##{attribute}" do + do_render + response.should_not allow_editing(instance_for(instance_name), attribute) + end + end + end + + # Creates an expectation which calls allow_uploading on the rendered + # template for each attribute specified. See the docs for allow_uploading + # for more details. + # + # Note: This method takes a string or symbol representing the instance + # variable's name to send to allow_uploading + # not an instance variable, which would be nil in the scope of the example block. + def it_should_allow_uploading(instance_name, *attributes) + attributes.flatten! + attributes.each do |attribute| + it "should allow editing of @#{instance_name}##{attribute}" do + do_render + response.should allow_uploading(instance_for(instance_name), attribute) + end + end + end + + # Negative version of it_should_allow_uploading. See that method for more + # details. + def it_should_not_allow_uploading(instance_name, *attributes) + attributes.flatten! + attributes.each do |attribute| + it "should not allow editing of @#{instance_name}##{attribute}" do + do_render + response.should_not allow_uploading(instance_for(instance_name), attribute) + end + end + end + + # Creates an expectation that the rendered template contains a FORM element + # (INPUT, TEXTAREA, or SELECT) with the specified name. + def it_should_have_form_element_for(name) + it "should have a form element named '#{name}'" do + do_render + response.should have_tag( + "form input[name='#{name}'], + form textarea[name='#{name}'], + form select[name='#{name}']" + ) + end + end + + # Negative version of it_should_have_form_element_for. See that method + # for more details. + def it_should_not_have_form_element_for(name) + it "should not have a form element named '#{name}'" do + do_render + response.should_not have_tag( + "form input[name='#{name}'], + form textarea[name='#{name}'], + form select[name='#{name}']" + ) + end + end + + # Creates an expectation which calls have_link_or_button_to on the response + # from rendering the template. See that method for more details. + # + # Note: This method takes a block to evaluate the route in the example context + # instead of the example group context. + def it_should_link_to(hint = nil, &route) + if hint.nil? && route.respond_to?(:to_ruby) + hint = route.to_ruby.gsub(/(^proc \{)|(\}$)/, '').strip + end + it "should have a link/button to #{(hint || route)}" do + do_render + response.should have_link_or_button_to(instance_eval(&route)) + end + end + alias it_should_have_link_to it_should_link_to + alias it_should_have_button_to it_should_link_to + alias it_should_have_button_or_link_to it_should_link_to + + # Negative version of it_should_link_to. See that method + # for more details. + def it_should_not_link_to(hint = nil, &route) + if hint.nil? && route.respond_to?(:to_ruby) + hint = route.to_ruby.gsub(/(^proc \{)|(\}$)/, '').strip + end + it "should have a link/button to #{(hint || route)}" do + do_render + response.should_not have_link_or_button_to(instance_eval(&route)) + end + end + alias it_should_not_have_link_to it_should_not_link_to + alias it_should_not_have_button_to it_should_not_link_to + alias it_should_not_have_button_or_link_to it_should_not_link_to + + # Creates an expectation which calls have_link_or_button_to_new on the response + # from rendering the template. See that method for more details. + # + # Note: This method may takes a string or symbol representing the model's name + # to send to have_link_or_button_to_show or the model's name itself. + def it_should_link_to_new(name) + it "should have a link/button to create a new #{name}" do + do_render + response.should have_link_or_button_to_new(name) + end + end + alias it_should_have_link_to_new it_should_link_to_new + alias it_should_have_button_to_new it_should_link_to_new + alias it_should_have_button_or_link_to_new it_should_link_to_new + + # Negative version of it_should_link_to_show. See that method + # for more details. + def it_should_not_link_to_new(name) + it "should have a link/button to create a new #{name}" do + do_render + response.should_not have_link_or_button_to_new(name) + end + end + alias it_should_not_have_link_to_new it_should_not_link_to_new + alias it_should_not_have_button_to_new it_should_not_link_to_new + alias it_should_not_have_button_or_link_to_new it_should_not_link_to_new + + # Creates an expectation which calls have_link_or_button_to_show on the response + # from rendering the template. See that method for more details. + # + # Note: This method takes a string or symbol representing the instance + # variable's name to send to have_link_or_button_to_show + # not an instance variable, which would be nil in the scope of the example block. + def it_should_link_to_show(name) + it "should have a link/button to show @#{name}" do + do_render + response.should have_link_or_button_to_show(instance_for(name)) + end + end + alias it_should_have_link_to_show it_should_link_to_show + alias it_should_have_button_to_show it_should_link_to_show + alias it_should_have_button_or_link_to_show it_should_link_to_show + + # Negative version of it_should_link_to_show. See that method + # for more details. + def it_should_not_link_to_show(name) + it "should have a link/button to show @#{name}" do + do_render + response.should_not have_link_or_button_to_show(instance_for(name)) + end + end + alias it_should_not_have_link_to_show it_should_not_link_to_show + alias it_should_not_have_button_to_show it_should_not_link_to_show + alias it_should_not_have_button_or_link_to_show it_should_not_link_to_show + + # Creates an expectation which calls have_link_or_button_to_show + # for each member of the instance variable matching the specified name + # on the response from rendering the template. See that method for more details. + # + # Note: This method takes a string or symbol representing the instance + # variable's name and not an instance variable, which would be nil + # in the scope of the example block. + def it_should_link_to_show_each(name) + it "should have a link/button to show each member of @#{name}" do + do_render + instance_for(name).each do |member| + response.should have_link_or_button_to_show(member) + end + end + end + alias it_should_have_link_to_show_each it_should_link_to_show_each + alias it_should_have_button_to_show_each it_should_link_to_show_each + alias it_should_have_button_or_link_to_show_each it_should_link_to_show_each + + # Creates an expectation which calls have_link_or_button_to_edit on the response + # from rendering the template. See that method for more details. + # + # Note: This method takes a string or symbol representing the instance + # variable's name to send to have_link_or_button_to_edit + # not an instance variable, which would be nil in the scope of the example block. + def it_should_link_to_edit(name) + it "should have a link/button to edit @#{name}" do + do_render + response.should have_link_or_button_to_edit(instance_for(name)) + end + end + alias it_should_have_link_to_edit it_should_link_to_edit + alias it_should_have_button_to_edit it_should_link_to_edit + alias it_should_have_button_or_link_to_edit it_should_link_to_edit + + # Negative version of it_should_link_to_edit. See that method + # for more details. + def it_should_not_link_to_edit(name) + it "should have a link/button to edit @#{name}" do + do_render + response.should_not have_link_or_button_to_edit(instance_for(name)) + end + end + alias it_should_not_have_link_to_edit it_should_not_link_to_edit + alias it_should_not_have_button_to_edit it_should_not_link_to_edit + alias it_should_not_have_button_or_link_to_edit it_should_not_link_to_edit + + + # Creates an expectation which calls have_link_or_button_to_edit + # for each member of the instance variable matching the specified name + # on the response from rendering the template. See that method for more details. + # + # Note: This method takes a string or symbol representing the instance + # variable's name and not an instance variable, which would be nil + # in the scope of the example block. + def it_should_link_to_edit_each(name) + it "should have a link/button to edit each member of @#{name}" do + do_render + instance_for(name).each do |member| + response.should have_link_or_button_to_edit(member) + end + end + end + alias it_should_have_link_to_edit_each it_should_link_to_edit_each + alias it_should_have_button_to_edit_each it_should_link_to_edit_each + alias it_should_have_button_or_link_to_edit_each it_should_link_to_edit_each + + # Creates an expectation which calls have_link_or_button_to_delete on the response + # from rendering the template. See that method for more details. + # + # Note: This method takes a string or symbol representing the instance + # variable's name to send to have_link_or_button_to_delete + # not an instance variable, which would be nil in the scope of the example block. + def it_should_link_to_delete(name) + it "should have a link/button to delete @#{name}" do + do_render + response.should have_button_to_delete(instance_for(name)) + end + end + alias it_should_have_link_to_delete it_should_link_to_delete + alias it_should_have_button_to_delete it_should_link_to_delete + alias it_should_have_button_or_link_to_delete it_should_link_to_delete + + # Negative version of it_should_link_to_delete. See that method + # for more details. + def it_should_not_link_to_delete(name) + it "should not have a link/button to delete @#{name}" do + do_render + response.should_not have_button_to_delete(instance_for(name)) + end + end + alias it_should_not_have_link_to_delete it_should_not_link_to_delete + alias it_should_not_have_button_to_delete it_should_not_link_to_delete + alias it_should_not_have_button_or_link_to_delete it_should_not_link_to_delete + + # Creates an expectation which calls have_link_or_button_to_delete + # for each member of the instance variable matching the specified name + # on the response from rendering the template. See that method for more details. + # + # Note: This method takes a string or symbol representing the instance + # variable's name and not an instance variable, which would be nil + # in the scope of the example block. + def it_should_link_to_delete_each(name) + it "should have a link/button to delete each member of @#{name}" do + do_render + instance_for(name).each do |member| + response.should have_button_to_delete(member) + end + end + end + alias it_should_have_link_to_delete_each it_should_link_to_delete_each + alias it_should_have_button_to_delete_each it_should_link_to_delete_each + alias it_should_have_button_or_link_to_delete_each it_should_link_to_delete_each + + # Creates an expectation that the template should call render :partial + # with the specified template. + def it_should_render_partial(name) + it "should render :partial => '#{name}'" do + template.should_receive(:render).with(hash_including(:partial => name)) + do_render + end + end + + # Negative version of it_should_render_partial. See that method + # for more details. + def it_should_not_render_partial(name) + it "should not render :partial => '#{name}'" do + template.should_not_receive(:render).with(hash_including(:partial => name)) + do_render + end + end + + # Sets @the_template (for use in do_render) using the current + # example group description. Example: + # + # describe "users/index.haml.erb" do + # use_describe_for_template! + # # ... + # end + # + # This is equivalent to setting @the_template = "users/index.haml.erb" + # in a before block. + def use_describe_for_template! + template = self_description_text + if File.exists?(File.join(RAILS_ROOT, "app/views", template)) + before(:each) do + @the_template = template + end + else + error_message = "You called use_describe_for_template! " + error_message << "but 'app/views/#{template}' does not exist. " + raise NameError, error_message + end + end + end + end +end diff --git a/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/view_stub_helpers.rb b/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/view_stub_helpers.rb new file mode 100644 index 00000000..2dde384e --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/lib/lucky_sneaks/view_stub_helpers.rb @@ -0,0 +1,15 @@ +$:.unshift File.join(File.dirname(__FILE__), "..") +require "skinny_spec" + +module LuckySneaks + # These methods are designed to be used in your example before blocks to accomplish + # a whole lot of functionality with just a tiny bit of effort. + module ViewStubHelpers + # Shorthand for the following stub: + # + # template.stub!(:render).with(hash_including(:partial => anything)) + def stub_partial_rendering! + template.stub!(:render).with(hash_including(:partial => anything)) + end + end +end \ No newline at end of file diff --git a/backup.rails2.3/plugins/skinny_spec/lib/skinny_spec.rb b/backup.rails2.3/plugins/skinny_spec/lib/skinny_spec.rb new file mode 100644 index 00000000..3c366ce1 --- /dev/null +++ b/backup.rails2.3/plugins/skinny_spec/lib/skinny_spec.rb @@ -0,0 +1,26 @@ +# Let's make sure everyone else is loaded +require File.expand_path(RAILS_ROOT + "/config/environment") +require 'spec' +require 'spec/rails' +begin + require 'ruby2ruby' +rescue LoadError + puts "-----" + puts "Attention: skinny_spec requires ruby2ruby for nicer route descriptions" + puts "It is highly recommended that you install it: sudo gem install ruby2ruby" + puts "-----" +end + +# Let's load our family now +require "lucky_sneaks/common_spec_helpers" +require "lucky_sneaks/controller_request_helpers" +require "lucky_sneaks/controller_spec_helpers" +require "lucky_sneaks/controller_stub_helpers" +require "lucky_sneaks/model_spec_helpers" +require "lucky_sneaks/view_spec_helpers" + +# Let's all come together +Spec::Rails::Example::ViewExampleGroup.send :include, LuckySneaks::ViewSpecHelpers +Spec::Rails::Example::HelperExampleGroup.send :include, LuckySneaks::CommonSpecHelpers +Spec::Rails::Example::ControllerExampleGroup.send :include, LuckySneaks::ControllerSpecHelpers +Spec::Rails::Example::ModelExampleGroup.send :include, LuckySneaks::ModelSpecHelpers \ No newline at end of file diff --git a/backup.rails2.3/plugins/swf_fu/CHANGELOG.rdoc b/backup.rails2.3/plugins/swf_fu/CHANGELOG.rdoc new file mode 100644 index 00000000..7b99496e --- /dev/null +++ b/backup.rails2.3/plugins/swf_fu/CHANGELOG.rdoc @@ -0,0 +1,46 @@ += swf_fu --- History + +== Version 1.4.0 - May 8, 2010 + +* Any option can be a block, in which case it is called (with the source swf passed as argument) + +== Version 1.3.1 - February 5, 2010 + +* Improved compatibility with Rails 3.0: swf_tag now outputs html_safe content. + +* Got rid of deprecation warning in Rails 2.2+ when using swf_tag in block form. + +== Version 1.3.0 - June 20, 2009 + +* Updated to swf_object v2.2. Change should not be noticeable to users, except compatibility improvements and better auto install. Added the option +switch_off_auto_hide_show+. + +== Version 1.2.0 - January 14, 2009 + +* flashvars[:id] will now default to the DOM id of the object. I didn't want to have any extra defaults than the very basic ones, but there is no easy way to get this from Flash (see http://www.actionscript.org/forums/showthread.php3?t=136044 ) and no easy way to specify that using +swf_default_options+. +* If flashvars is a string (e.g. "myVar=myValue") it will be parsed into a hash so that the behaviour for default values apply to strings or hashes. swf_default_options[:flashvars] can also be a string and will also be parsed before being merged. +* Small bug fix: the options passed as hashes (:flashvars, :parameters and :html_options) were changed if swf_default_options[:flashvars, ...] existed. They are now left unchanged. + +== Version 1.1.0 - January 3, 2009 + +* Improved the way to specify alternate content + +== Version 1.0.3 - January 3, 2009 + +* Improved javascript initialization + + :initialize => [1, 2, 3] # produces in javascript: obj.initialize(1,2,3) instead of ([1,2,3]) + # no :initialize produces in javascript: obj.initialize() instead of (null) + :initialize => nil # stil produces obj.initialize(null) + +== Version 1.0.2 - January 3, 2009 + +* Bug fix for flashvars in dynamic method + +== Version 1.0.1 - January 2, 2009 + +* File reorganization +* Bug fix for default options + +== Version 1.0 - X-mas, 2008 + +=== Initial release. diff --git a/backup.rails2.3/plugins/swf_fu/FLASH_OBJECT.rdoc b/backup.rails2.3/plugins/swf_fu/FLASH_OBJECT.rdoc new file mode 100644 index 00000000..87a0e72f --- /dev/null +++ b/backup.rails2.3/plugins/swf_fu/FLASH_OBJECT.rdoc @@ -0,0 +1,31 @@ +== Compatibility with FlashObject + +This document is intended for users of FlashObject, a (much older) swf embedding plugin that inspired swf_fu. + +You can choose to: + +1) keep both. They won't interfere and +flashobject_tag+ will continue to use the older SWFObject 1.5 library. + +2) remove FlashObject: + + script/plugin remove flashobject_helper + +You can also manually remove javascripts/flashobject.js + ++swf_fu+ will take over the +flashobject_tag+ and will use the new SWFObject 2.2 library. +This should not have impacts as long as: +* your swf path is absolute (e.g. "/path/to/my_flash.swf"). If it is relative, move your swf file from 'public/' to the new 'public/swfs/' asset folder +* you include the default javascripts (otherwise you need to include 'swfobject' explicitely and stop including 'flashobject') +* you don't use the javascript object before the page is loaded. SWFObject 2.2 makes the changes to the web page later +* you don't rely on the +verify_file_exists+ option (it doesn't do anything anymore) + +In either case 1 or 2, you change existing calls to +flashobject_tag+ for +swf_tag+ at your leisure. +The interface is similar and the main differences are some options name changes: + :flash_id => :id + :variables => :flashvars + :background_color => options[:parameters][:bgcolor] + +Moreover, the following defaults are gone: + :flashvars[:lzproxied] + :parameters[:scale] + :parameters[:bgcolor] diff --git a/backup.rails2.3/plugins/swf_fu/LICENSE b/backup.rails2.3/plugins/swf_fu/LICENSE new file mode 100644 index 00000000..efd683ff --- /dev/null +++ b/backup.rails2.3/plugins/swf_fu/LICENSE @@ -0,0 +1,29 @@ +# swf_fu plugin for rails +# Copyright (c) 2010, Marc-André Lafortune. +# All rights reserved. +# Inspired by FlashObject by Davide D'Agostino aka DAddYE (http://www.lipsiasoft.com) +# Uses SWFObject.js 2.1 (http://code.google.com/p/swfobject) +# +# Licensed under the terms of the (modified) BSD License below: +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/backup.rails2.3/plugins/swf_fu/README.rdoc b/backup.rails2.3/plugins/swf_fu/README.rdoc new file mode 100644 index 00000000..1791f1ff --- /dev/null +++ b/backup.rails2.3/plugins/swf_fu/README.rdoc @@ -0,0 +1,92 @@ += +swf_fu+ + +With the +swf_fu+ plugin, rails treats your swf files like any other asset (images, javascripts, etc...). + ++swf_fu+ (pronounced "swif-fu", bonus joke for french speakers) uses SWFObject 2.2 to embed swf objects in HTML and supports all its options. +SWFObject 2 is such a nice library that Adobe now uses it as the official way to embed swf! +SWFObject's project can be found at http://code.google.com/p/swfobject + ++swf_fu+ has been tested with rails v2.0 up to v3.0b and has decent test coverage so rake test:plugins should reveal any incompatibility. Comments and pull requests welcome: http://github.com/marcandre/swf_fu + +== Install + +Assuming you have git[http://git-scm.com/] installed (check with git version), it is easy to install from your applications directory: + + rails plugin install git://github.com/marcandre/swf_fu.git # rails 3 + + script/plugin install git://github.com/marcandre/swf_fu.git # rails 2 (starting at 2.0.2) + +For older versions of +rails+ or without +git+, you can always download ++swf_fu+ from github[http://github.com/marcandre/swf_fu/archives/master] and then install it manually: + + rails plugin install ~/Download/swf_fu # rails 3 + + script/plugin install ~/Downloads/swf_fu # rails 2.x + +== Usage + +=== Embedding in HTML + +To embed a swf file, use +swf_tag+: + <%= swf_tag "i_like_flashing" %> + +Exactly like images and javascripts, +swf_tag+ will use +swf_path+ +to determine the path of the swf file; it will assume it is in /public/swfs/ +unless specified otherwise and it will add the ".swf" extension automatically. + +You can specify alternate content either with the options :alt => "Get Flash!" or you can use +swf_tag+ as a block: + + <% swf_tag "i_like_flashing" do %> + Get Flash + <% end %> + +=== Options + +* :id - the DOM +id+ of the flash +object+ element that is used to contain the Flash object; defaults to the name of the swf in +source+ +* :width, :height - the width & height of the Flash object. Defaults to "100%". These could also specified using :size +* :size - the size of the Flash object, in the form "400x300". +* :mode - Either :dynamic (default) or :static. Refer to SWFObject's doc[http://code.google.com/p/swfobject/wiki/documentation#Should_I_use_the_static_or_dynamic_publishing_method?] +* :flashvars - a Hash of variables that are passed to the swf. Can also be a string like "foo=bar&hello=world". Defaults to {:id => the DOM id} +* :parameters - a Hash of configuration parameters for the swf. See Adobe's doc[http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_12701#optional] +* :html_options - a Hash of extra html options for the object tag. +* :alt - HTML text that is displayed when the Flash player is not available. Defaults to a "Get Flash" image pointing to Adobe Flash's installation page. This can also be specified as a block (see embedding section). In Rails 3, this text is _assumed_ to be HTML, so there is no need to call +html_safe+ on it. +* :flash_version - the version of the Flash player that is required (e.g. "7" (default) or "8.1.0") +* :auto_install - a swf file that will upgrade flash player if needed (defaults to "expressInstall" which was installed by +swf_fu+) +* :javascript_class - specify a javascript class (e.g. "MyFlash") for your flash object. If it exists, the initialize method will be called. +* :initialize - arguments to pass to the initialization method of your javascript class. +* :div_id - the DOM +id+ of the containing div itself. Defaults to "#{option[:id]}_div" +* :switch_off_auto_hide_show - switch off SWFObject's default hide/show behavior. SWFObject temporarily hides your SWF or alternative content until the library has decided which content to display. Defaults to nil. + +You can override these default options with a global setting: + + ActionView::Base.swf_default_options = {:mode => :static} # All swf_tag will use the static mode by default + +Any of these options can be a +Proc+, in which case it will be called each time swf_tag is called. + +For example, the following will generate unique IDs: + + my_swf_counter = 0 + ActionView::Base.swf_default_options[:id] = Proc.new{"swf_unique_id_#{my_swf_counter+=1}"} + +=== Javascript + ++swf_fu+ will add 'swfobject' to the list of default javascript files. If you don't include +the default javascripts, a simple javascript_include "swfobject" is needed. + +=== swf_path + ++swf_tag+ implements and relies on +swf_path+ which behaves in a similar fashion to +image_path+, +javascript_path+, etc...: + + swf_path("example") => "/swfs/example.swf" + swf_path("example.swf") => "/swfs/example.swf" + swf_path("fonts/optima") => "/swfs/fonts/optima.swf" + swf_path("/fonts/optima") => "/fonts/optima.swf" + swf_path("http://www.example.com/game.swf") => "http://www.example.com/game.swf" + +It takes into account the global setting +asset_host+, like any other asset: + + ActionController::Base.asset_host = "http://assets.example.com" + image_path("logo.jpg") => "http://assets.example.com/images/logo.jpg" + swf_path("fonts/optima") => "http://assets.example.com/swfs/fonts/optima.swf"" + +Copyright (c) 2010 Marc-André Lafortune, released under the BSD license diff --git a/backup.rails2.3/plugins/swf_fu/Rakefile b/backup.rails2.3/plugins/swf_fu/Rakefile new file mode 100644 index 00000000..9898dadb --- /dev/null +++ b/backup.rails2.3/plugins/swf_fu/Rakefile @@ -0,0 +1,22 @@ +require 'rake' +require 'rake/testtask' +require 'rake/rdoctask' + +desc 'Default: run unit tests.' +task :default => :test + +desc 'Test the swf_fu plugin.' +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.pattern = 'test/**/*_test.rb' + t.verbose = true +end + +desc 'Generate documentation for the swf_fu plugin.' +Rake::RDocTask.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'rdoc' + rdoc.title = 'Swf Fu' + rdoc.options << '--line-numbers' << '--inline-source' << '-m README.rdoc' + rdoc.rdoc_files.include('*.rdoc') + rdoc.rdoc_files.include('lib/**/*.rb') +end diff --git a/backup.rails2.3/plugins/swf_fu/assets/javascripts/swfobject.js b/backup.rails2.3/plugins/swf_fu/assets/javascripts/swfobject.js new file mode 100644 index 00000000..8eafe9dd --- /dev/null +++ b/backup.rails2.3/plugins/swf_fu/assets/javascripts/swfobject.js @@ -0,0 +1,4 @@ +/* SWFObject v2.2 + is released under the MIT License +*/ +var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y0){for(var af=0;af0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad'}}aa.outerHTML='"+af+"";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;abM9VaMwSB_o5%t)!o>)g&X)EAYjgEPLcl5K%kkuIK}@4lZ{BkGMYAU20z( zNRb@8AZ~RNT{i-oQ>63S3q@bamddC&V#&}IBHXmBea0RPhMY!G_6yWA-{&u00bI?EPCUrE(n7GhyT+_4sC3vIfO8o*Hw?~a z;QV28jGXsc=C?Kce^ve?K|~w@>bMSCq>Q(O#T42y^Mv*pwUSN?9aMQms*Ld$rD0~q zQhI{Tv*fb=mqG|Gjsr39Bp7Dejr)q)1J&t=YBY?2Llv85=!N{vRx3=YEoRTjX+)n# zs ["swfobject"] +rescue NoMethodError # I think this might fail in Rails 2.1.x + ActionView::Helpers::AssetTagHelper.register_javascript_include_default 'swfobject' +end diff --git a/backup.rails2.3/plugins/swf_fu/install.rb b/backup.rails2.3/plugins/swf_fu/install.rb new file mode 100644 index 00000000..fda481b0 --- /dev/null +++ b/backup.rails2.3/plugins/swf_fu/install.rb @@ -0,0 +1,24 @@ +require "fileutils" + +# Some paths +src = File.dirname(__FILE__)+"/assets" +dest = File.dirname(__FILE__)+"/../../../public" + +filename = "#{dest}/javascripts/swfobject.js" +unless File.exist?(filename) + FileUtils.cp "#{src}/javascripts/swfobject.js", filename + puts "Copying 'swfobject.js'" +end + +unless File.exist?("#{dest}/swfs/") + FileUtils.mkdir "#{dest}/swfs/" + puts "Creating new 'swfs' directory for swf assets" +end + +filename = "#{dest}/swfs/expressInstall.swf" +unless File.exist?(filename) + FileUtils.cp "#{src}/swfs/expressInstall.swf", filename + puts "Copying 'expressInstall.swf', the default flash auto-installer." +end + +puts "Installation done." diff --git a/backup.rails2.3/plugins/swf_fu/lib/action_view/helpers/asset_tag_helper/swf_asset.rb b/backup.rails2.3/plugins/swf_fu/lib/action_view/helpers/asset_tag_helper/swf_asset.rb new file mode 100644 index 00000000..2fe6e5bd --- /dev/null +++ b/backup.rails2.3/plugins/swf_fu/lib/action_view/helpers/asset_tag_helper/swf_asset.rb @@ -0,0 +1,61 @@ +module ActionView #:nodoc: + + # ActionView::Base.swf_default_options is a hash that + # will be used to specify defaults in priority to the standard + # defaults. + class Base + @@swf_default_options = {} + cattr_accessor :swf_default_options + end + + module Helpers # :nodoc: + module AssetTagHelper + + # Computes the path to an swf asset in the public 'swfs' directory. + # Full paths from the document root will be passed through. + # Used internally by +swf_tag+ to build the swf path. + # + # ==== Examples + # swf_path("example") # => /swfs/example.swf + # swf_path("example.swf") # => /swfs/example.swf + # swf_path("fonts/optima") # => /swfs/fonts/optima.swf + # swf_path("/fonts/optima") # => /fonts/optima.swf + # swf_path("http://www.example.com/game.swf") # => http://www.example.com/game.swf + # + # It takes into account the global setting +asset_host+, like any other asset: + # + # ActionController::Base.asset_host = "http://assets.example.com" + # image_path("logo.jpg") # => http://assets.example.com/images/logo.jpg + # swf_path("fonts/optima") # => http://assets.example.com/swfs/fonts/optima.swf + # + def swf_path(source) + if defined? SwfTag + SwfTag.new(self, @controller, source).public_path + else + compute_public_path(source, SwfAsset::DIRECTORY, SwfAsset::EXTENSION) + end + end + alias_method :path_to_swf, :swf_path # aliased to avoid conflicts with a swf_path named route + + private + module SwfAsset # :nodoc: + DIRECTORY = 'swfs'.freeze + EXTENSION = 'swf'.freeze + + def directory + DIRECTORY + end + + def extension + EXTENSION + end + end + + # AssetTag is available since 2.1.1 (http://github.com/rails/rails/commit/900fd6eca9dd97d2341e89bcb27d7a82d62965bf ) + class SwfTag < AssetTag # :nodoc: + include SwfAsset + end if defined? AssetTag + end + end +end + diff --git a/backup.rails2.3/plugins/swf_fu/lib/action_view/helpers/swf_fu_helper.rb b/backup.rails2.3/plugins/swf_fu/lib/action_view/helpers/swf_fu_helper.rb new file mode 100644 index 00000000..3c05807c --- /dev/null +++ b/backup.rails2.3/plugins/swf_fu/lib/action_view/helpers/swf_fu_helper.rb @@ -0,0 +1,197 @@ +module ActionView #:nodoc: + module Helpers # :nodoc: + module SwfFuHelper + # Returns a set of tags that display a Flash object within an + # HTML page. + # + # Options: + # * :id - the DOM +id+ of the flash +object+ element that is used to contain the Flash object; defaults to the name of the swf in +source+ + # * :width, :height - the width & height of the Flash object. Defaults to "100%". These could also specified using :size + # * :size - the size of the Flash object, in the form "400x300". + # * :mode - Either :dynamic (default) or :static. Refer to SWFObject's doc[http://code.google.com/p/swfobject/wiki/documentation#Should_I_use_the_static_or_dynamic_publishing_method?] + # * :flashvars - a Hash of variables that are passed to the swf. Can also be a string like "foo=bar&hello=world" + # * :parameters - a Hash of configuration parameters for the swf. See Adobe's doc[http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_12701#optional] + # * :alt - HTML text that is displayed when the Flash player is not available. Defaults to a "Get Flash" image pointing to Adobe Flash's installation page. + # * :flash_version - the version of the Flash player that is required (e.g. "7" (default) or "8.1.0") + # * :auto_install - a swf file that will upgrade flash player if needed (defaults to "expressInstall" which was installed by swf_fu) + # * :javascript_class - specify a javascript class (e.g. "MyFlash") for your flash object. The initialize method will be called when the flash object is ready. + # * :initialize - arguments to pass to the initialization method of your javascript class. + # * :div_id - the DOM +id+ of the containing div itself. Defaults to "#{option[:id]}"_div + # + def swf_tag(source, options={}, &block) + Generator.new(source, options, self).generate(&block) + end + + # For compatibility with the older FlashObject. + # It modifies the given options before calling +swf_tag+. + # See FLASH_OBJECT.rdoc + def flashobject_tag_for_compatibility(source, options={}) + options = options.reverse_merge( + :auto_install => nil, + :parameters => {:scale => "noscale"}, + :variables => {:lzproxied => false}, + :flash_id => "flashcontent_#{rand(1_100)}", + :background_color => "#ffffff" + ) + { :variables => :flashvars, :flash_id => :id }.each{|from, to| options[to] ||= options.delete(from) } + options[:parameters][:bgcolor] ||= options.delete(:background_color) + swf_tag(source, options) + end + + alias_method :flashobject_tag, :flashobject_tag_for_compatibility unless defined? flashobject_tag + + private + DEFAULTS = { + :width => "100%", + :height => "100%", + :flash_version => 7, + :mode => :dynamic, + :auto_install => "expressInstall", + :alt => <<-"EOS".squeeze(" ").strip.freeze + + Get Adobe Flash player + + EOS + }.freeze + + class Generator # :nodoc: + VALID_MODES = [:static, :dynamic] + def initialize(source, options, view) + @view = view + @source = view.swf_path(source) + options = ActionView::Base.swf_default_options.merge(options) + options.each do |key, value| + options[key] = value.call(source) if value.respond_to?(:call) + end + [:html_options, :parameters, :flashvars].each do |k| + options[k] = convert_to_hash(options[k]).reverse_merge convert_to_hash(ActionView::Base.swf_default_options[k]) + end + options.reverse_merge!(DEFAULTS) + options[:id] ||= source.gsub(/^.*\//, '').gsub(/\.swf$/,'') + options[:id] = force_to_valid_id(options[:id]) + options[:div_id] ||= options[:id]+"_div" + options[:div_id] = force_to_valid_id(options[:div_id]) + options[:width], options[:height] = options[:size].scan(/^(\d*%?)x(\d*%?)$/).first if options[:size] + options[:auto_install] &&= @view.swf_path(options[:auto_install]) + options[:flashvars][:id] ||= options[:id] + @mode = options.delete(:mode) + @options = options + unless VALID_MODES.include? @mode + raise ArgumentError, "options[:mode] should be either #{VALID_MODES.join(' or ')}" + end + end + + def force_to_valid_id(id) + id = id.gsub /[^A-Za-z0-9\-_]/, "_" # HTML id can only contain these characters + id = "swf_" + id unless id =~ /^[A-Z]/i # HTML id must start with alpha + id + end + + def generate(&block) + if block_given? + @options[:alt] = @view.capture(&block) + if Rails::VERSION::STRING >= "3.0" + send(@mode) + elsif Rails::VERSION::STRING < "2.2" + @view.concat(send(@mode), block.binding) + else + @view.concat(send(@mode)) + end + else + send(@mode) + end + end + + private + CONCAT = ActiveSupport.const_defined?(:SafeBuffer) ? :safe_concat : :concat + def convert_to_hash(s) + case s + when Hash + s + when nil + {} + when String + s.split("&").inject({}) do |h, kvp| + key, value = kvp.split("=") + h[key.to_sym] = CGI::unescape(value) + h + end + else + raise ArgumentError, "#{s} should be a Hash, a String or nil" + end + end + + def convert_to_string(h) + h.map do |key_value| + key_value.map{|val| CGI::escape(val.to_s)}.join("=") + end.join("&") + end + + def static + param_list = @options[:parameters].map{|k,v| %() }.join("\n") + param_list += %(\n) unless @options[:flashvars].empty? + html_options = @options[:html_options].map{|k,v| %(#{k}="#{v}")}.join(" ") + r = @view.javascript_tag( + %(swfobject.registerObject("#{@options[:id]}_container", "#{@options[:flash_version]}", #{@options[:auto_install].to_json});) + ) + r.send CONCAT, <<-"EOS".strip +
        + + #{param_list} + + + #{param_list} + + #{@options[:alt]} + + + +
        + EOS + r << @view.javascript_tag(extend_js) if @options[:javascript_class] + r.send CONCAT, library_check + r + end + + def dynamic + @options[:html_options] = @options[:html_options].merge(:id => @options[:id]) + @options[:parameters] = @options[:parameters].dup # don't modify the original parameters + args = (([@source] + @options.values_at(:div_id,:width,:height,:flash_version)).map(&:to_s) + + @options.values_at(:auto_install,:flashvars,:parameters,:html_options) + ).map(&:to_json).join(",") + preambule = @options[:switch_off_auto_hide_show] ? "swfobject.switchOffAutoHideShow();" : "" + r = @view.javascript_tag(preambule + "swfobject.embedSWF(#{args})") + r.send CONCAT, <<-"EOS".strip +
        + #{@options[:alt]} +
        + EOS + r << @view.javascript_tag("swfobject.addDomLoadEvent(function(){#{extend_js}})") if @options[:javascript_class] + r.send CONCAT, library_check + r + end + + def extend_js + arglist = case + when @options[:initialize].instance_of?(Array) + @options[:initialize].map(&:to_json).join(",") + when @options.has_key?(:initialize) + @options[:initialize].to_json + else + "" + end + "Object.extend($('#{@options[:id]}'), #{@options[:javascript_class]}.prototype).initialize(#{arglist})" + end + + def library_check + return "" unless 'development' == ENV['RAILS_ENV'] + @view.javascript_tag(<<-"EOS") + if (typeof swfobject == 'undefined') { + document.getElementById('#{@options[:div_id]}').innerHTML = 'Warning: SWFObject.js was not loaded properly. Make sure you <%= javascript_include_tag :defaults %> or <%= javascript_include_tag :swfobject %>'; + } + EOS + end + end #class Generator + end + end +end diff --git a/backup.rails2.3/plugins/swf_fu/test/results.rb b/backup.rails2.3/plugins/swf_fu/test/results.rb new file mode 100644 index 00000000..a7306b0d --- /dev/null +++ b/backup.rails2.3/plugins/swf_fu/test/results.rb @@ -0,0 +1,42 @@ +DYNAMIC_RESULT = <<'EOS' +
        + +Get Adobe Flash player + +
        +EOS + +STATIC_RESULT = <<'EOS' +
        + + + + + + + + + +Get Adobe Flash player + + + + +
        +EOS \ No newline at end of file diff --git a/backup.rails2.3/plugins/swf_fu/test/swf_fu_test.rb b/backup.rails2.3/plugins/swf_fu/test/swf_fu_test.rb new file mode 100644 index 00000000..64a2a8bf --- /dev/null +++ b/backup.rails2.3/plugins/swf_fu/test/swf_fu_test.rb @@ -0,0 +1,159 @@ +require File.expand_path(File.dirname(__FILE__)+'/test_helper') +require File.expand_path(File.dirname(__FILE__)+'/results') + +class SwfFuTest < ActionView::TestCase + def assert_same_stripped(expect, test) + expect, test = [expect, test].map{|s| s.split("\n").map(&:strip)} + same = expect & test + delta_expect, delta_test = [expect, test].map{|a| a-same} + STDOUT << "\n\n---- Actual result: ----\n" << test.join("\n") << "\n---------\n" unless delta_expect == delta_test + assert_equal delta_expect, delta_test + end + + context "swf_path" do + context "with no special asset host" do + should "deduce the extension" do + assert_equal swf_path("example.swf"), swf_path("example") + assert_starts_with "/swfs/example.swf", swf_path("example.swf") + end + + should "accept relative paths" do + assert_starts_with "/swfs/whatever/example.swf", swf_path("whatever/example.swf") + end + + should "leave full paths alone" do + ["/full/path.swf", "http://www.example.com/whatever.swf"].each do |p| + assert_starts_with p, swf_path(p) + end + end + end + + context "with custom asset host" do + HOST = "http://assets.example.com" + setup do + ActionController::Base.asset_host = HOST + end + + teardown do + ActionController::Base.asset_host = nil + end + + should "take it into account" do + assert_equal "#{HOST}/swfs/whatever.swf", swf_path("whatever") + end + end + end + + context "swf_tag" do + COMPLEX_OPTIONS = { :width => "456", :height => 123, + :flashvars => {:myVar => "value 1 > 2"}.freeze, + :javascript_class => "SomeClass", + :initialize => {:be => "good"}.freeze, + :parameters => {:play => true}.freeze + }.freeze + + should "understand size" do + assert_equal swf_tag("hello", :size => "123x456"), + swf_tag("hello", :width => 123, :height => "456") + end + + should "only accept valid modes" do + assert_raise(ArgumentError) { swf_tag("xyz", :mode => :xyz) } + end + + context "with custom defaults" do + setup do + test = {:flashvars=> {:xyz => "abc", :hello => "world"}.freeze, :mode => :static, :size => "400x300"}.freeze + @expect = swf_tag("test", test) + @expect_with_hello = swf_tag("test", :flashvars => {:xyz => "abc", :hello => "my friend"}, :mode => :static, :size => "400x300") + ActionView::Base.swf_default_options = test + end + + should "respect them" do + assert_equal @expect, swf_tag("test") + end + + should "merge suboptions" do + assert_equal @expect_with_hello, swf_tag("test", :flashvars => {:hello => "my friend"}.freeze) + end + + teardown { ActionView::Base.swf_default_options = {} } + end + + context "with proc options" do + should "call them" do + expect = swf_tag("test", :id => "generated_id_for_test") + assert_equal expect, swf_tag("test", :id => Proc.new{|arg| "generated_id_for_#{arg}"}) + end + + should "call global default's everytime" do + expect1 = swf_tag("test", :id => "call_number_1") + expect2 = swf_tag("test", :id => "call_number_2") + cnt = 0 + ActionView::Base.swf_default_options = { :id => Proc.new{ "call_number_#{cnt+=1}" }} + assert_equal expect1, swf_tag("test") + assert_equal expect2, swf_tag("test") + end + end + + context "with static mode" do + setup { ActionView::Base.swf_default_options = {:mode => :static} } + + should "deal with string flashvars" do + assert_equal swf_tag("hello", :flashvars => "xyz=abc", :mode => :static), + swf_tag("hello", :flashvars => {:xyz => "abc"}, :mode => :static) + end + + should "produce the expected code" do + assert_same_stripped STATIC_RESULT, swf_tag("mySwf", COMPLEX_OPTIONS.merge(:html_options => {:class => "lots"}.freeze).freeze) + end + + teardown { ActionView::Base.swf_default_options = {} } + end + + context "with dynamic mode" do + should "produce the expected code" do + assert_same_stripped DYNAMIC_RESULT, swf_tag("mySwf", COMPLEX_OPTIONS) + end + + end + + should "enforce HTML id validity" do + div_result = '
        ' + assert_match /#{div_result}/, swf_tag("123-456_ok$!+X") + obj_result = '"id":"swf_123-456_ok___X"' + assert_match /#{obj_result}/, swf_tag("123-456_ok$!+X") + end + + should "treat initialize arrays as list of parameters" do + assert_match 'initialize("hello","world")', swf_tag("mySwf", :initialize => ["hello", "world"], :javascript_class => "SomeClass") + end + + if ActiveSupport.const_defined?(:SafeBuffer) + should "be html safe" do + assert swf_tag("test").html_safe? + end + end + end + + context "flashobject_tag" do + should "be the same as swf_tag with different defaults" do + assert_same_stripped swf_tag("mySwf", + :auto_install => nil, + :parameters => {:scale => "noscale", :bgcolor => "#ffffff"}, + :flashvars => {:lzproxied => false}, + :id => "myFlash" + ), flashobject_tag("mySwf", :flash_id => "myFlash") + end + + should "be the same with custom settings" do + assert_same_stripped swf_tag("mySwf", + :auto_install => nil, + :parameters => {:scale => "noborder", :bgcolor => "#ffffff"}, + :flashvars => {:answer_is => 42}, + :id => "myFlash" + ), flashobject_tag("mySwf", :flash_id => "myFlash", :parameters => {:scale => "noborder"}, :variables => {:answer_is => 42}) + end + end +end + diff --git a/backup.rails2.3/plugins/swf_fu/test/test_helper.rb b/backup.rails2.3/plugins/swf_fu/test/test_helper.rb new file mode 100644 index 00000000..58d113f8 --- /dev/null +++ b/backup.rails2.3/plugins/swf_fu/test/test_helper.rb @@ -0,0 +1,20 @@ +require 'test/unit' +require 'rubygems' +gem 'activesupport', '~> 2.3' +require 'active_support' +gem 'activerecord', '~> 2.3' +require 'active_record' +gem 'actionpack', '~> 2.3' +require 'active_support' +require 'action_view' +require 'action_controller' + +#require File.dirname(__FILE__)+'/../../../../config/environment.rb' +require 'action_view/test_case' +require "action_controller/test_process" +require 'shoulda' +require File.dirname(__FILE__) + '/../init' + +def assert_starts_with(start, what) + assert what.starts_with?(start), "#{what} does not start with #{start}" +end diff --git a/backup.rails2.3/plugins/swf_fu/uninstall.rb b/backup.rails2.3/plugins/swf_fu/uninstall.rb new file mode 100644 index 00000000..bc3c1b57 --- /dev/null +++ b/backup.rails2.3/plugins/swf_fu/uninstall.rb @@ -0,0 +1,6 @@ +require "fileutils" + +dest = File.dirname(__FILE__) + "/../../../public" +FileUtils.rm "#{dest}/javascripts/swfobject.js" rescue puts "Warning: swfobject.js could not be deleted" +FileUtils.rm "#{dest}/swfs/expressInstall.swf" rescue puts "Warning: expressInstall.swf could not be deleted" +Dir.rmdir "#{dest}/swfs/" rescue "don't worry if directory is not empty" \ No newline at end of file diff --git a/backup.rails2.3/plugins/translate/MIT-LICENSE b/backup.rails2.3/plugins/translate/MIT-LICENSE new file mode 100644 index 00000000..9376605b --- /dev/null +++ b/backup.rails2.3/plugins/translate/MIT-LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2009 [name of plugin creator] + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/backup.rails2.3/plugins/translate/README b/backup.rails2.3/plugins/translate/README new file mode 100644 index 00000000..e2732dc9 --- /dev/null +++ b/backup.rails2.3/plugins/translate/README @@ -0,0 +1,63 @@ +Translate +========= + +This plugin provides a web interface for translating Rails I18n texts (requires Rails 2.2 or higher) from one locale to another. The plugin has been tested only with the simple I18n backend that ships with Rails. I18n texts are read from and written to YAML files under config/locales. + +To translate to a new locale you need to add a YAML file for that locale that contains the locale as the top key and at least one translation. + +Please note that there are certain I18n keys that map to Array objects rather than strings and those are currently not dealt with by the translation UI. This means that Rails built in keys such as date.day_names need to be translated manually directly in the YAML file. + +To get the translation UI to write the YAML files in UTF8 you need to install the ya2yaml gem. + +The translation UI finds all I18n keys by extracting them from I18n lookups in your application source code. In addition it adds all :en and default locale keys from the I18n backend. + +- Updated: Each string in the UI now has an "Auto Translate" link which will send the original text to Google Translate and will input the returned translation into the form field for further clean up and review prior to saving. + + +Rake Tasks +========= + +In addition to the web UI this plugin adds the following rake tasks: + +translate:untranslated +translate:missing +translate:remove_obsolete_keys +translate:merge_keys +translate:google +translate:changed + +The missing task shows you any I18n keys in your code that do not have translations in the YAML file for your default locale, i.e. config/locales/sv.yml. + +The merge_keys task is supposed to be used in conjunction with Sven Fuch's Rails I18n TextMate bundle (http://github.com/svenfuchs/rails-i18n/tree/master). Texts and keys extracted with the TextMate bundle end up in the temporary file log/translations.yml. When you run the merge_keys rake task the keys are moved over to the corresponding I18n locale file, i.e. config/locales/sv.yml. The merge_keys task also checks for overwrites of existing keys by warning you that one of your extracted keys already exists with a different translation. + +The google task is used for auto translating from one locale to another using Google Translate. + +The changed rake task can show you between one YAML file to another which keys have had their texts changed. + +Installation +========= +Obtain the source with: + +./script/plugin install git://github.com/newsdesk/translate.git + +To mount the plugin, add the following to your config/routes.rb file: + +Translate::Routes.translation_ui(map) if RAILS_ENV != "production" + +Now visit /translate in your web browser to start translating. + +Dependencies +========= + +- Rails 2.2 or higher +- The ya2yaml gem if you want your YAML files written in UTF8 encoding. + +Authors +========= + +- Peter Marklund (programming) +- Joakim Westerlund (web design) + +Many thanks to http://newsdesk.se for sponsoring the development of this plugin. + +Copyright (c) 2009 Peter Marklund, released under the MIT license diff --git a/backup.rails2.3/plugins/translate/Rakefile b/backup.rails2.3/plugins/translate/Rakefile new file mode 100644 index 00000000..7e1954b7 --- /dev/null +++ b/backup.rails2.3/plugins/translate/Rakefile @@ -0,0 +1,11 @@ +require 'rake' +require 'spec/rake/spectask' + +desc 'Default: run specs.' +task :default => :spec + +desc 'Run the specs' +Spec::Rake::SpecTask.new(:spec) do |t| + t.spec_opts = ['--colour --format progress --loadby mtime --reverse'] + t.spec_files = FileList['spec/**/*_spec.rb'] +end diff --git a/backup.rails2.3/plugins/translate/init.rb b/backup.rails2.3/plugins/translate/init.rb new file mode 100644 index 00000000..18707f83 --- /dev/null +++ b/backup.rails2.3/plugins/translate/init.rb @@ -0,0 +1,8 @@ +require 'translate' + +# TODO: Use new method available_locales once Rails is upgraded, see: +# http://github.com/svenfuchs/i18n/commit/411f8fe7c8f3f89e9b6b921fa62ed66cb92f3af4 +def I18n.valid_locales + I18n.backend.send(:init_translations) unless I18n.backend.initialized? + backend.send(:translations).keys.reject { |locale| locale == :root } +end diff --git a/backup.rails2.3/plugins/translate/lib/translate.rb b/backup.rails2.3/plugins/translate/lib/translate.rb new file mode 100644 index 00000000..39629bf4 --- /dev/null +++ b/backup.rails2.3/plugins/translate/lib/translate.rb @@ -0,0 +1,8 @@ +module Translate +end + +require File.join(File.dirname(__FILE__), "translate_controller") +require File.join(File.dirname(__FILE__), "translate_helper") +Dir[File.join(File.dirname(__FILE__), "translate", "*.rb")].each do |file| + require file +end diff --git a/backup.rails2.3/plugins/translate/lib/translate/file.rb b/backup.rails2.3/plugins/translate/lib/translate/file.rb new file mode 100644 index 00000000..c8ae93b0 --- /dev/null +++ b/backup.rails2.3/plugins/translate/lib/translate/file.rb @@ -0,0 +1,35 @@ +require 'fileutils' + +class Translate::File + attr_accessor :path + + def initialize(path) + self.path = path + end + + def write(keys) + FileUtils.mkdir_p File.dirname(path) + File.open(path, "w") do |file| + file.puts keys_to_yaml(Translate::File.deep_stringify_keys(keys)) + end + end + + def read + File.exists?(path) ? YAML::load(IO.read(path)) : {} + end + + # Stringifying keys for prettier YAML + def self.deep_stringify_keys(hash) + hash.inject({}) { |result, (key, value)| + value = deep_stringify_keys(value) if value.is_a? Hash + result[(key.to_s rescue key) || key] = value + result + } + end + + private + def keys_to_yaml(keys) + # Using ya2yaml, if available, for UTF8 support + keys.respond_to?(:ya2yaml) ? keys.ya2yaml(:escape_as_utf8 => true) : keys.to_yaml + end +end diff --git a/backup.rails2.3/plugins/translate/lib/translate/keys.rb b/backup.rails2.3/plugins/translate/lib/translate/keys.rb new file mode 100644 index 00000000..3bee3c41 --- /dev/null +++ b/backup.rails2.3/plugins/translate/lib/translate/keys.rb @@ -0,0 +1,152 @@ +require 'pathname' + +class Translate::Keys + # Allows keys extracted from lookups in files to be cached + def self.files + @@files ||= Translate::Keys.new.files + end + + # Allows flushing of the files cache + def self.files=(files) + @@files = files + end + + def files + @files ||= extract_files + end + alias_method :to_hash, :files + + def keys + files.keys + end + alias_method :to_a, :keys + + def i18n_keys(locale) + I18n.backend.send(:init_translations) unless I18n.backend.initialized? + Translate::Keys.to_shallow_hash(I18n.backend.send(:translations)[locale.to_sym]).keys.sort + end + + def untranslated_keys + Translate::Keys.translated_locales.inject({}) do |missing, locale| + missing[locale] = i18n_keys(I18n.default_locale).map do |key| + I18n.backend.send(:lookup, locale, key).nil? ? key : nil + end.compact + missing + end + end + + def missing_keys + locale = I18n.default_locale; yaml_keys = {} + yaml_keys = Translate::Storage.file_paths(locale).inject({}) do |keys, path| + keys = keys.deep_merge(Translate::File.new(path).read[locale.to_s]) + end + files.reject { |key, file| self.class.contains_key?(yaml_keys, key) } + end + + def self.translated_locales + I18n.available_locales.reject { |locale| [:root, I18n.default_locale.to_sym].include?(locale) } + end + + # Checks if a nested hash contains the keys in dot separated I18n key. + # + # Example: + # + # hash = { + # :foo => { + # :bar => { + # :baz => 1 + # } + # } + # } + # + # contains_key?("foo", key) # => true + # contains_key?("foo.bar", key) # => true + # contains_key?("foo.bar.baz", key) # => true + # contains_key?("foo.bar.baz.bla", key) # => false + # + def self.contains_key?(hash, key) + keys = key.to_s.split(".") + return false if keys.empty? + !keys.inject(HashWithIndifferentAccess.new(hash)) do |memo, key| + memo.is_a?(Hash) ? memo.try(:[], key) : nil + end.nil? + end + + # Convert something like: + # + # { + # :pressrelease => { + # :label => { + # :one => "Pressmeddelande" + # } + # } + # } + # + # to: + # + # {'pressrelease.label.one' => "Pressmeddelande"} + # + def self.to_shallow_hash(hash) + hash.inject({}) do |shallow_hash, (key, value)| + if value.is_a?(Hash) + to_shallow_hash(value).each do |sub_key, sub_value| + shallow_hash[[key, sub_key].join(".")] = sub_value + end + else + shallow_hash[key.to_s] = value + end + shallow_hash + end + end + + # Convert something like: + # + # {'pressrelease.label.one' => "Pressmeddelande"} + # + # to: + # + # { + # :pressrelease => { + # :label => { + # :one => "Pressmeddelande" + # } + # } + # } + def self.to_deep_hash(hash) + hash.inject({}) do |deep_hash, (key, value)| + keys = key.to_s.split('.').reverse + leaf_key = keys.shift + key_hash = keys.inject({leaf_key.to_sym => value}) { |hash, key| {key.to_sym => hash} } + deep_merge!(deep_hash, key_hash) + deep_hash + end + end + + # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809 + def self.deep_merge!(hash1, hash2) + merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 } + hash1.merge!(hash2, &merger) + end + + private + + def extract_files + files_to_scan.inject(HashWithIndifferentAccess.new) do |files, file| + IO.read(file).scan(i18n_lookup_pattern).flatten.map(&:to_sym).each do |key| + files[key] ||= [] + path = Pathname.new(File.expand_path(file)).relative_path_from(Pathname.new(Rails.root)).to_s + files[key] << path if !files[key].include?(path) + end + files + end + end + + def i18n_lookup_pattern + /\b(?:I18n\.t|I18n\.translate|t)(?:\s|\():?'([a-z0-9_]+.[a-z0-9_.]+)'\)?/ + end + + def files_to_scan + Dir.glob(File.join(Translate::Storage.root_dir, "{app,config,lib}", "**","*.{rb,erb,rhtml}")) + + Dir.glob(File.join(Translate::Storage.root_dir, "public", "javascripts", "**","*.js")) + end +end diff --git a/backup.rails2.3/plugins/translate/lib/translate/log.rb b/backup.rails2.3/plugins/translate/lib/translate/log.rb new file mode 100644 index 00000000..9b5b3148 --- /dev/null +++ b/backup.rails2.3/plugins/translate/lib/translate/log.rb @@ -0,0 +1,35 @@ +class Translate::Log + attr_accessor :from_locale, :to_locale, :keys + + def initialize(from_locale, to_locale, keys) + self.from_locale = from_locale + self.to_locale = to_locale + self.keys = keys + end + + def write_to_file + current_texts = File.exists?(file_path) ? file.read : {} + current_texts.merge!(from_texts) + file.write(current_texts) + end + + def read + file.read + end + + private + def file + @file ||= Translate::File.new(file_path) + end + + def from_texts + Translate::File.deep_stringify_keys(Translate::Keys.to_deep_hash(keys.inject({}) do |hash, key| + hash[key] = I18n.backend.send(:lookup, from_locale, key) + hash + end)) + end + + def file_path + File.join(Rails.root, "config", "locales", "log", "from_#{from_locale}_to_#{to_locale}.yml") + end +end diff --git a/backup.rails2.3/plugins/translate/lib/translate/routes.rb b/backup.rails2.3/plugins/translate/lib/translate/routes.rb new file mode 100644 index 00000000..8d02c869 --- /dev/null +++ b/backup.rails2.3/plugins/translate/lib/translate/routes.rb @@ -0,0 +1,11 @@ +module Translate + class Routes + def self.translation_ui(map) + map.with_options(:controller => 'translate') do |t| + t.translate_list 'translate' + t.translate 'translate/translate', :action => 'translate' + t.translate_reload 'translate/reload', :action => 'reload' + end + end + end +end diff --git a/backup.rails2.3/plugins/translate/lib/translate/storage.rb b/backup.rails2.3/plugins/translate/lib/translate/storage.rb new file mode 100644 index 00000000..2b9a3858 --- /dev/null +++ b/backup.rails2.3/plugins/translate/lib/translate/storage.rb @@ -0,0 +1,28 @@ +class Translate::Storage + attr_accessor :locale + + def initialize(locale) + self.locale = locale.to_sym + end + + def write_to_file + Translate::File.new(file_path).write(keys) + end + + def self.file_paths(locale) + Dir.glob(File.join(root_dir, "config", "locales", "**","#{locale}.yml")) + end + + def self.root_dir + Rails.root + end + + private + def keys + {locale => I18n.backend.send(:translations)[locale]} + end + + def file_path + File.join(Translate::Storage.root_dir, "config", "locales", "#{locale}.yml") + end +end diff --git a/backup.rails2.3/plugins/translate/lib/translate_controller.rb b/backup.rails2.3/plugins/translate/lib/translate_controller.rb new file mode 100644 index 00000000..d06e171e --- /dev/null +++ b/backup.rails2.3/plugins/translate/lib/translate_controller.rb @@ -0,0 +1,165 @@ +class TranslateController < ActionController::Base + # It seems users with active_record_store may get a "no :secret given" error if we don't disable csrf protection, + skip_before_filter :verify_authenticity_token + + prepend_view_path(File.join(File.dirname(__FILE__), "..", "views")) + layout 'translate' + + before_filter :init_translations + before_filter :set_locale + + def index + initialize_keys + filter_by_key_pattern + filter_by_text_pattern + filter_by_translated_or_changed + sort_keys + paginate_keys + @total_entries = @keys.size + end + + def translate + I18n.backend.store_translations(@to_locale, Translate::Keys.to_deep_hash(params[:key])) + Translate::Storage.new(@to_locale).write_to_file + Translate::Log.new(@from_locale, @to_locale, params[:key].keys).write_to_file + force_init_translations # Force reload from YAML file + flash[:notice] = "Translations stored" + redirect_to params.slice(:filter, :sort_by, :key_type, :key_pattern, :text_type, :text_pattern).merge({:action => :index}) + end + + def reload + Translate::Keys.files = nil + redirect_to :action => 'index' + end + + private + def initialize_keys + @files = Translate::Keys.files + @keys = (@files.keys.map(&:to_s) + Translate::Keys.new.i18n_keys(@from_locale)).uniq + @keys.reject! do |key| + from_text = lookup(@from_locale, key) + # When translating from one language to another, make sure there is a text to translate from. + # Always exclude non string translation objects as we don't support editing them in the UI. + (@from_locale != @to_locale && !from_text.present?) || (from_text.present? && !from_text.is_a?(String)) + end + end + + def lookup(locale, key) + I18n.backend.send(:lookup, locale, key) + end + helper_method :lookup + + def filter_by_translated_or_changed + params[:filter] ||= 'all' + return if params[:filter] == 'all' + @keys.reject! do |key| + case params[:filter] + when 'untranslated' + lookup(@to_locale, key).present? + when 'translated' + lookup(@to_locale, key).blank? + when 'changed' + old_from_text(key).blank? || lookup(@from_locale, key) == old_from_text(key) + else + raise "Unknown filter '#{params[:filter]}'" + end + end + end + + def filter_by_key_pattern + return if params[:key_pattern].blank? + @keys.reject! do |key| + case params[:key_type] + when "starts_with" + !key.starts_with?(params[:key_pattern]) + when "contains" + key.index(params[:key_pattern]).nil? + else + raise "Unknown key_type '#{params[:key_type]}'" + end + end + end + + def filter_by_text_pattern + return if params[:text_pattern].blank? + @keys.reject! do |key| + case params[:text_type] + when 'contains' + !lookup(@from_locale, key).present? || !lookup(@from_locale, key).to_s.downcase.index(params[:text_pattern].downcase) + when 'equals' + !lookup(@from_locale, key).present? || lookup(@from_locale, key).to_s.downcase != params[:text_pattern].downcase + else + raise "Unknown text_type '#{params[:text_type]}'" + end + end + end + + def sort_keys + params[:sort_by] ||= "key" + case params[:sort_by] + when "key" + @keys.sort! + when "text" + @keys.sort! do |key1, key2| + if lookup(@from_locale, key1).present? && lookup(@from_locale, key2).present? + lookup(@from_locale, key1).to_s.downcase <=> lookup(@from_locale, key2).to_s.downcase + elsif lookup(@from_locale, key1).present? + -1 + else + 1 + end + end + else + raise "Unknown sort_by '#{params[:sort_by]}'" + end + end + + def paginate_keys + params[:page] ||= 1 + @paginated_keys = @keys[offset, per_page] + end + + def offset + (params[:page].to_i - 1) * per_page + end + + def per_page + 50 + end + helper_method :per_page + + def init_translations + I18n.backend.send(:init_translations) unless I18n.backend.initialized? + end + + def force_init_translations + I18n.backend.send(:init_translations) + end + + def default_locale + I18n.default_locale + end + + def set_locale + session[:from_locale] ||= default_locale + session[:to_locale] ||= :en + session[:from_locale] = params[:from_locale] if params[:from_locale].present? + session[:to_locale] = params[:to_locale] if params[:to_locale].present? + @from_locale = session[:from_locale].to_sym + @to_locale = session[:to_locale].to_sym + end + + def old_from_text(key) + return @old_from_text[key] if @old_from_text && @old_from_text[key] + @old_from_text = {} + text = key.split(".").inject(log_hash) do |hash, k| + hash ? hash[k] : nil + end + @old_from_text[key] = text + end + helper_method :old_from_text + + def log_hash + @log_hash ||= Translate::Log.new(@from_locale, @to_locale, {}).read + end +end diff --git a/backup.rails2.3/plugins/translate/lib/translate_helper.rb b/backup.rails2.3/plugins/translate/lib/translate_helper.rb new file mode 100644 index 00000000..cb4c400f --- /dev/null +++ b/backup.rails2.3/plugins/translate/lib/translate_helper.rb @@ -0,0 +1,45 @@ +module TranslateHelper + def simple_filter(labels, param_name = 'filter', selected_value = nil) + selected_value ||= params[param_name] + filter = [] + labels.each do |item| + if item.is_a?(Array) + type, label = item + else + type = label = item + end + if type.to_s == selected_value.to_s + filter << "#{label}" + else + link_params = params.merge({param_name.to_s => type}) + link_params.merge!({"page" => nil}) if param_name.to_s != "page" + filter << link_to(label, link_params) + end + end + filter.join(" | ") + end + + def n_lines(text, line_size) + n_lines = 1 + if text.present? + n_lines = text.split("\n").size + if n_lines == 1 && text.length > line_size + n_lines = text.length / line_size + 1 + end + end + n_lines + end + + def translate_javascript_includes + sources = [] + if File.exists?(File.join(Rails.root, "public", "javascripts", "prototype.js")) + sources << "/javascripts/prototype.js" + else + sources << "http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js" + end + sources << "http://www.google.com/jsapi" + sources.map do |src| + %Q{} + end.join("\n") + end +end diff --git a/backup.rails2.3/plugins/translate/spec/controllers/translate_controller_spec.rb b/backup.rails2.3/plugins/translate/spec/controllers/translate_controller_spec.rb new file mode 100644 index 00000000..e384811b --- /dev/null +++ b/backup.rails2.3/plugins/translate/spec/controllers/translate_controller_spec.rb @@ -0,0 +1,129 @@ +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe TranslateController do + describe "index" do + before(:each) do + controller.stub!(:per_page).and_return(1) + I18n.backend.stub!(:translations).and_return(i18n_translations) + I18n.backend.instance_eval { @initialized = true } + keys = mock(:keys) + keys.stub!(:i18n_keys).and_return(['vendor.foobar']) + Translate::Keys.should_receive(:new).and_return(keys) + Translate::Keys.should_receive(:files).and_return(files) + I18n.stub!(:valid_locales).and_return([:en, :sv]) + I18n.stub!(:default_locale).and_return(:sv) + end + + it "shows sorted paginated keys from the translate from locale and extracted keys by default" do + get_page :index + assigns(:from_locale).should == :sv + assigns(:to_locale).should == :en + assigns(:files).should == files + assigns(:keys).sort.should == ['articles.new.page_title', 'home.page_title', 'vendor.foobar'] + assigns(:paginated_keys).should == ['articles.new.page_title'] + end + + it "can be paginated with the page param" do + get_page :index, :page => 2 + assigns(:files).should == files + assigns(:paginated_keys).should == ['home.page_title'] + end + + it "accepts a key_pattern param with key_type=starts_with" do + get_page :index, :key_pattern => 'articles', :key_type => 'starts_with' + assigns(:files).should == files + assigns(:paginated_keys).should == ['articles.new.page_title'] + assigns(:total_entries).should == 1 + end + + it "accepts a key_pattern param with key_type=contains" do + get_page :index, :key_pattern => 'page_', :key_type => 'contains' + assigns(:files).should == files + assigns(:total_entries).should == 2 + assigns(:paginated_keys).should == ['articles.new.page_title'] + end + + it "accepts a filter=untranslated param" do + get_page :index, :filter => 'untranslated' + assigns(:total_entries).should == 2 + assigns(:paginated_keys).should == ['articles.new.page_title'] + end + + it "accepts a filter=translated param" do + get_page :index, :filter => 'translated' + assigns(:total_entries).should == 1 + assigns(:paginated_keys).should == ['vendor.foobar'] + end + + it "accepts a filter=changed param" do + log = mock(:log) + old_translations = {:home => {:page_title => "Skapar ny artikel"}} + log.should_receive(:read).and_return(Translate::File.deep_stringify_keys(old_translations)) + Translate::Log.should_receive(:new).with(:sv, :en, {}).and_return(log) + get_page :index, :filter => 'changed' + assigns(:total_entries).should == 1 + assigns(:keys).should == ["home.page_title"] + end + + def i18n_translations + HashWithIndifferentAccess.new({ + :en => { + :vendor => { + :foobar => "Foo Baar" + } + }, + :sv => { + :articles => { + :new => { + :page_title => "Skapa ny artikel" + } + }, + :home => { + :page_title => "Välkommen till I18n" + }, + :vendor => { + :foobar => "Fobar" + } + } + }) + end + + def files + HashWithIndifferentAccess.new({ + :'home.page_title' => ["app/views/home/index.rhtml"], + :'general.back' => ["app/views/articles/new.rhtml", "app/views/categories/new.rhtml"], + :'articles.new.page_title' => ["app/views/articles/new.rhtml"] + }) + end + end + + describe "translate" do + it "should store translations to I18n backend and then write them to a YAML file" do + session[:from_locale] = :sv + session[:to_locale] = :en + translations = { + :articles => { + :new => { + :title => "New Article" + } + }, + :category => "Category" + } + key_param = {'articles.new.title' => "New Article", "category" => "Category"} + I18n.backend.should_receive(:store_translations).with(:en, translations) + storage = mock(:storage) + storage.should_receive(:write_to_file) + Translate::Storage.should_receive(:new).with(:en).and_return(storage) + log = mock(:log) + log.should_receive(:write_to_file) + Translate::Log.should_receive(:new).with(:sv, :en, key_param.keys).and_return(log) + post :translate, "key" => key_param + response.should be_redirect + end + end + + def get_page(*args) + get(*args) + response.should be_success + end +end diff --git a/backup.rails2.3/plugins/translate/spec/file_spec.rb b/backup.rails2.3/plugins/translate/spec/file_spec.rb new file mode 100644 index 00000000..5f94f5a9 --- /dev/null +++ b/backup.rails2.3/plugins/translate/spec/file_spec.rb @@ -0,0 +1,54 @@ +require 'fileutils' +require File.dirname(__FILE__) + '/spec_helper' + +describe Translate::File do + describe "write" do + before(:each) do + @file = Translate::File.new(file_path) + end + + after(:each) do + FileUtils.rm(file_path) + end + + it "writes all I18n messages for a locale to YAML file" do + @file.write(translations) + @file.read.should == Translate::File.deep_stringify_keys(translations) + end + + def translations + { + :en => { + :article => { + :title => "One Article" + }, + :category => "Category" + } + } + end + end + + describe "deep_stringify_keys" do + it "should convert all keys in a hash to strings" do + Translate::File.deep_stringify_keys({ + :en => { + :article => { + :title => "One Article" + }, + :category => "Category" + } + }).should == { + "en" => { + "article" => { + "title" => "One Article" + }, + "category" => "Category" + } + } + end + end + + def file_path + File.join(File.dirname(__FILE__), "files", "en.yml") + end +end diff --git a/backup.rails2.3/plugins/translate/spec/files/translate/app/models/article.rb b/backup.rails2.3/plugins/translate/spec/files/translate/app/models/article.rb new file mode 100644 index 00000000..d151e316 --- /dev/null +++ b/backup.rails2.3/plugins/translate/spec/files/translate/app/models/article.rb @@ -0,0 +1,12 @@ +class Article < ActiveRecord::Base + def validate + # t('li') + errors.add_to_base([t(:'article.key1') + "#{t('article.key2')}"]) + I18n.t 'article.key3' + I18n.t 'article.key3' + I18n.t :'article.key4' + I18n.translate :'article.key5' + 'bla bla t' + "blubba bla" + ' foobar' + 'bla bla t ' + "blubba bla" + ' foobar' + end +end diff --git a/backup.rails2.3/plugins/translate/spec/files/translate/app/views/category.erb b/backup.rails2.3/plugins/translate/spec/files/translate/app/views/category.erb new file mode 100644 index 00000000..2146f874 --- /dev/null +++ b/backup.rails2.3/plugins/translate/spec/files/translate/app/views/category.erb @@ -0,0 +1 @@ +<%= t(:'category_erb.key1') %> diff --git a/backup.rails2.3/plugins/translate/spec/files/translate/app/views/category.html b/backup.rails2.3/plugins/translate/spec/files/translate/app/views/category.html new file mode 100644 index 00000000..0947d174 --- /dev/null +++ b/backup.rails2.3/plugins/translate/spec/files/translate/app/views/category.html @@ -0,0 +1 @@ +t(:'category_html.key1') diff --git a/backup.rails2.3/plugins/translate/spec/files/translate/app/views/category.html.erb b/backup.rails2.3/plugins/translate/spec/files/translate/app/views/category.html.erb new file mode 100644 index 00000000..a226ccff --- /dev/null +++ b/backup.rails2.3/plugins/translate/spec/files/translate/app/views/category.html.erb @@ -0,0 +1 @@ +<%= t(:'category_html_erb.key1') %> diff --git a/backup.rails2.3/plugins/translate/spec/files/translate/app/views/category.rhtml b/backup.rails2.3/plugins/translate/spec/files/translate/app/views/category.rhtml new file mode 100644 index 00000000..235e5173 --- /dev/null +++ b/backup.rails2.3/plugins/translate/spec/files/translate/app/views/category.rhtml @@ -0,0 +1,5 @@ + + +<%= t(:'category_rhtml.key1') %> diff --git a/backup.rails2.3/plugins/translate/spec/files/translate/public/javascripts/application.js b/backup.rails2.3/plugins/translate/spec/files/translate/public/javascripts/application.js new file mode 100644 index 00000000..a673ca02 --- /dev/null +++ b/backup.rails2.3/plugins/translate/spec/files/translate/public/javascripts/application.js @@ -0,0 +1 @@ +I18n.t('js.alert') \ No newline at end of file diff --git a/backup.rails2.3/plugins/translate/spec/keys_spec.rb b/backup.rails2.3/plugins/translate/spec/keys_spec.rb new file mode 100644 index 00000000..3b0bd629 --- /dev/null +++ b/backup.rails2.3/plugins/translate/spec/keys_spec.rb @@ -0,0 +1,179 @@ +require File.dirname(__FILE__) + '/spec_helper' +require 'fileutils' + +describe Translate::Keys do + before(:each) do + I18n.stub!(:default_locale).and_return(:en) + @keys = Translate::Keys.new + Translate::Storage.stub!(:root_dir).and_return(i18n_files_dir) + end + + describe "to_a" do + it "extracts keys from I18n lookups in .rb, .html.erb, and .rhtml files" do + @keys.to_a.map(&:to_s).sort.should == ['article.key1', 'article.key2', 'article.key3', 'article.key4', 'article.key5', + 'category_erb.key1', 'category_html_erb.key1', 'category_rhtml.key1', 'js.alert'] + end + end + + describe "to_hash" do + it "return a hash with I18n keys and file lists" do + @keys.to_hash[:'article.key3'].should == ["vendor/plugins/translate/spec/files/translate/app/models/article.rb"] + end + end + + describe "i18n_keys" do + before(:each) do + I18n.backend.send(:init_translations) unless I18n.backend.initialized? + end + + it "should return all keys in the I18n backend translations hash" do + I18n.backend.should_receive(:translations).and_return(translations) + @keys.i18n_keys(:en).should == ['articles.new.page_title', 'categories.flash.created', 'empty', 'home.about'] + end + + describe "untranslated_keys" do + before(:each) do + I18n.backend.stub!(:translations).and_return(translations) + end + + it "should return a hash with keys with missing translations in each locale" do + @keys.untranslated_keys.should == { + :sv => ['articles.new.page_title', 'categories.flash.created', 'empty'] + } + end + end + + describe "missing_keys" do + before(:each) do + @file_path = File.join(i18n_files_dir, "config", "locales", "en.yml") + Translate::File.new(@file_path).write({ + :en => { + :home => { + :page_title => false, + :intro => { + :one => "intro one", + :other => "intro other" + } + } + } + }) + end + + after(:each) do + FileUtils.rm(@file_path) + end + + it "should return a hash with keys that are not in the locale file" do + @keys.stub!(:files).and_return({ + :'home.page_title' => "app/views/home/index.rhtml", + :'home.intro' => 'app/views/home/index.rhtml', + :'home.signup' => "app/views/home/_signup.rhtml", + :'about.index.page_title' => "app/views/about/index.rhtml" + }) + @keys.missing_keys.should == { + :'home.signup' => "app/views/home/_signup.rhtml", + :'about.index.page_title' => "app/views/about/index.rhtml" + } + end + end + + describe "contains_key?" do + it "works" do + hash = { + :foo => { + :bar => { + :baz => false + } + } + } + Translate::Keys.contains_key?(hash, "").should be_false + Translate::Keys.contains_key?(hash, "foo").should be_true + Translate::Keys.contains_key?(hash, "foo.bar").should be_true + Translate::Keys.contains_key?(hash, "foo.bar.baz").should be_true + Translate::Keys.contains_key?(hash, :"foo.bar.baz").should be_true + Translate::Keys.contains_key?(hash, "foo.bar.baz.bla").should be_false + end + end + + describe "translated_locales" do + before(:each) do + I18n.stub!(:default_locale).and_return(:en) + I18n.stub!(:available_locales).and_return([:sv, :no, :en, :root]) + end + + it "returns all avaiable except :root and the default" do + Translate::Keys.translated_locales.should == [:sv, :no] + end + end + + describe "to_deep_hash" do + it "convert shallow hash with dot separated keys to deep hash" do + Translate::Keys.to_deep_hash(shallow_hash).should == deep_hash + end + end + + describe "to_shallow_hash" do + it "converts a deep hash to a shallow one" do + Translate::Keys.to_shallow_hash(deep_hash).should == shallow_hash + end + end + + ########################################################################## + # + # Helper Methods + # + ########################################################################## + + def translations + { + :en => { + :home => { + :about => "This site is about making money" + }, + :articles => { + :new => { + :page_title => "New Article" + } + }, + :categories => { + :flash => { + :created => "Category created" + } + }, + :empty => nil + }, + :sv => { + :home => { + :about => false + } + } + } + end + end + + def shallow_hash + { + 'pressrelease.label.one' => "Pressmeddelande", + 'pressrelease.label.other' => "Pressmeddelanden", + 'article' => "Artikel", + 'category' => '' + } + end + + def deep_hash + { + :pressrelease => { + :label => { + :one => "Pressmeddelande", + :other => "Pressmeddelanden" + } + }, + :article => "Artikel", + :category => '' + } + end + + def i18n_files_dir + File.join(ENV['PWD'], "spec", "files", "translate") + end +end diff --git a/backup.rails2.3/plugins/translate/spec/log_spec.rb b/backup.rails2.3/plugins/translate/spec/log_spec.rb new file mode 100644 index 00000000..7dc9f542 --- /dev/null +++ b/backup.rails2.3/plugins/translate/spec/log_spec.rb @@ -0,0 +1,47 @@ +require 'fileutils' +require File.dirname(__FILE__) + '/spec_helper' + +describe Translate::Log do + describe "write_to_file" do + before(:each) do + I18n.locale = :sv + I18n.backend.store_translations(:sv, from_texts) + keys = Translate::Keys.new + @log = Translate::Log.new(:sv, :en, Translate::Keys.to_shallow_hash(from_texts).keys) + @log.stub!(:file_path).and_return(file_path) + FileUtils.rm_f file_path + end + + after(:each) do + FileUtils.rm_f file_path + end + + it "writes new log file with from texts" do + File.exists?(file_path).should be_false + @log.write_to_file + File.exists?(file_path).should be_true + Translate::File.new(file_path).read.should == Translate::File.deep_stringify_keys(from_texts) + end + + it "merges from texts with current texts in log file and re-writes the log file" do + @log.write_to_file + I18n.backend.store_translations(:sv, {:category => "Kategori ny"}) + @log.keys = ['category'] + @log.write_to_file + Translate::File.new(file_path).read['category'].should == "Kategori ny" + end + + def file_path + File.join(File.dirname(__FILE__), "files", "from_sv_to_en.yml") + end + + def from_texts + { + :article => { + :title => "En artikel" + }, + :category => "Kategori" + } + end + end +end diff --git a/backup.rails2.3/plugins/translate/spec/spec_helper.rb b/backup.rails2.3/plugins/translate/spec/spec_helper.rb new file mode 100644 index 00000000..5a919082 --- /dev/null +++ b/backup.rails2.3/plugins/translate/spec/spec_helper.rb @@ -0,0 +1,11 @@ +begin + # Using PWD here instead of File.dirname(__FILE__) to be able to symlink to plugin + # from within a Rails app. + require File.expand_path(ENV['PWD'] + '/../../../spec/spec_helper') +rescue LoadError => e + puts "You need to install rspec in your base app\n#{e.message}: #{e.backtrace.join("\n")}" + exit +end + +plugin_spec_dir = File.dirname(__FILE__) +ActiveRecord::Base.logger = Logger.new(plugin_spec_dir + "/debug.log") diff --git a/backup.rails2.3/plugins/translate/spec/storage_spec.rb b/backup.rails2.3/plugins/translate/spec/storage_spec.rb new file mode 100644 index 00000000..e6110c3d --- /dev/null +++ b/backup.rails2.3/plugins/translate/spec/storage_spec.rb @@ -0,0 +1,33 @@ +require File.dirname(__FILE__) + '/spec_helper' + +describe Translate::Storage do + describe "write_to_file" do + before(:each) do + @storage = Translate::Storage.new(:en) + end + + it "writes all I18n messages for a locale to YAML file" do + I18n.backend.should_receive(:translations).and_return(translations) + @storage.stub!(:file_path).and_return(file_path) + file = mock(:file) + file.should_receive(:write).with(translations) + Translate::File.should_receive(:new).with(file_path).and_return(file) + @storage.write_to_file + end + + def file_path + File.join(File.dirname(__FILE__), "files", "en.yml") + end + + def translations + { + :en => { + :article => { + :title => "One Article" + }, + :category => "Category" + } + } + end + end +end diff --git a/backup.rails2.3/plugins/translate/tasks/translate.rake b/backup.rails2.3/plugins/translate/tasks/translate.rake new file mode 100644 index 00000000..a70b934c --- /dev/null +++ b/backup.rails2.3/plugins/translate/tasks/translate.rake @@ -0,0 +1,178 @@ +require 'yaml' + +class Hash + def deep_merge(other) + # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809 + merger = proc { |key, v1, v2| (Hash === v1 && Hash === v2) ? v1.merge(v2, &merger) : v2 } + merge(other, &merger) + end + + def set(keys, value) + key = keys.shift + if keys.empty? + self[key] = value + else + self[key] ||= {} + self[key].set keys, value + end + end + + if ENV['SORT'] + # copy of ruby's to_yaml method, prepending sort. + # before each so we get an ordered yaml file + def to_yaml( opts = {} ) + YAML::quick_emit( self, opts ) do |out| + out.map( taguri, to_yaml_style ) do |map| + sort.each do |k, v| #<- Adding sort. + map.add( k, v ) + end + end + end + end + end +end + +namespace :translate do + desc "Show untranslated keys for locale LOCALE" + task :untranslated => :environment do + from_locale = I18n.default_locale + untranslated = Translate::Keys.new.untranslated_keys + + messages = [] + untranslated.each do |locale, keys| + keys.each do |key| + from_text = I18n.backend.send(:lookup, from_locale, key) + messages << "#{locale}.#{key} (#{from_locale}.#{key}='#{from_text}')" + end + end + + if messages.present? + messages.each { |m| puts m } + else + puts "No untranslated keys" + end + end + + desc "Show I18n keys that are missing in the config/locales/default_locale.yml YAML file" + task :missing => :environment do + missing = Translate::Keys.new.missing_keys.inject([]) do |keys, (key, filename)| + keys << "#{key} in \t #{filename} is missing" + end + puts missing.present? ? missing.join("\n") : "No missing translations in the default locale file" + end + + desc "Remove all translation texts that are no longer present in the locale they were translated from" + task :remove_obsolete_keys => :environment do + I18n.backend.send(:init_translations) + master_locale = ENV['LOCALE'] || I18n.default_locale + Translate::Keys.translated_locales.each do |locale| + texts = {} + Translate::Keys.new.i18n_keys(locale).each do |key| + if I18n.backend.send(:lookup, master_locale, key).to_s.present? + texts[key] = I18n.backend.send(:lookup, locale, key) + end + end + I18n.backend.send(:translations)[locale] = nil # Clear out all current translations + I18n.backend.store_translations(locale, Translate::Keys.to_deep_hash(texts)) + Translate::Storage.new(locale).write_to_file + end + end + + desc "Merge I18n keys from log/translations.yml into config/locales/*.yml (for use with the Rails I18n TextMate bundle)" + task :merge_keys => :environment do + I18n.backend.send(:init_translations) + new_translations = YAML::load(IO.read(File.join(Rails.root, "log", "translations.yml"))) + raise("Can only merge in translations in single locale") if new_translations.keys.size > 1 + locale = new_translations.keys.first + + overwrites = false + Translate::Keys.to_shallow_hash(new_translations[locale]).keys.each do |key| + new_text = key.split(".").inject(new_translations[locale]) { |hash, sub_key| hash[sub_key] } + existing_text = I18n.backend.send(:lookup, locale.to_sym, key) + if existing_text && new_text != existing_text + puts "ERROR: key #{key} already exists with text '#{existing_text.inspect}' and would be overwritten by new text '#{new_text}'. " + + "Set environment variable OVERWRITE=1 if you really want to do this." + overwrites = true + end + end + + if !overwrites || ENV['OVERWRITE'] + I18n.backend.store_translations(locale, new_translations[locale]) + Translate::Storage.new(locale).write_to_file + end + end + + desc "Apply Google translate to auto translate all texts in locale ENV['FROM'] to locale ENV['TO']" + task :google => :environment do + raise "Please specify FROM and TO locales as environment variables" if ENV['FROM'].blank? || ENV['TO'].blank? + + # Depends on httparty gem + # http://www.robbyonrails.com/articles/2009/03/16/httparty-goes-foreign + class GoogleApi + include HTTParty + base_uri 'ajax.googleapis.com' + def self.translate(string, to, from) + tries = 0 + begin + get("/ajax/services/language/translate", + :query => {:langpair => "#{from}|#{to}", :q => string, :v => 1.0}, + :format => :json) + rescue + tries += 1 + puts("SLEEPING - retrying in 5...") + sleep(5) + retry if tries < 10 + end + end + end + + I18n.backend.send(:init_translations) + + start_at = Time.now + translations = {} + Translate::Keys.new.i18n_keys(ENV['FROM']).each do |key| + from_text = I18n.backend.send(:lookup, ENV['FROM'], key).to_s + to_text = I18n.backend.send(:lookup, ENV['TO'], key) + if !from_text.blank? && to_text.blank? + print "#{key}: '#{from_text[0, 40]}' => " + if !translations[from_text] + response = GoogleApi.translate(from_text, ENV['TO'], ENV['FROM']) + translations[from_text] = response["responseData"] && response["responseData"]["translatedText"] + end + if !(translation = translations[from_text]).blank? + translation.gsub!(/\(\(([a-z_.]+)\)\)/i, '{{\1}}') + # Google translate sometimes replaces {{foobar}} with (()) foobar. We skip these + if translation !~ /\(\(\)\)/ + puts "'#{translation[0, 40]}'" + I18n.backend.store_translations(ENV['TO'].to_sym, Translate::Keys.to_deep_hash({key => translation})) + else + puts "SKIPPING since interpolations were messed up: '#{translation[0,40]}'" + end + else + puts "NO TRANSLATION - #{response.inspect}" + end + end + end + + puts "\nTime elapsed: #{(((Time.now - start_at) / 60) * 10).to_i / 10.to_f} minutes" + Translate::Storage.new(ENV['TO'].to_sym).write_to_file + end + + desc "List keys that have changed I18n texts between YAML file ENV['FROM_FILE'] and YAML file ENV['TO_FILE']. Set ENV['VERBOSE'] to see changes" + task :changed => :environment do + from_hash = Translate::Keys.to_shallow_hash(Translate::File.new(ENV['FROM_FILE']).read) + to_hash = Translate::Keys.to_shallow_hash(Translate::File.new(ENV['TO_FILE']).read) + from_hash.each do |key, from_value| + if (to_value = to_hash[key]) && to_value != from_value + key_without_locale = key[/^[^.]+\.(.+)$/, 1] + if ENV['VERBOSE'] + puts "KEY: #{key_without_locale}" + puts "FROM VALUE: '#{from_value}'" + puts "TO VALUE: '#{to_value}'" + else + puts key_without_locale + end + end + end + end +end diff --git a/backup.rails2.3/plugins/translate/views/layouts/translate.rhtml b/backup.rails2.3/plugins/translate/views/layouts/translate.rhtml new file mode 100644 index 00000000..58dbc5c3 --- /dev/null +++ b/backup.rails2.3/plugins/translate/views/layouts/translate.rhtml @@ -0,0 +1,359 @@ + + + + + + <%= h(@page_title) %> + + <%= translate_javascript_includes %> + + + + + + + +
        + <% if @page_title -%>

        <%=h @page_title %>

        <% end -%> + <% [:notice, :error].each do |message| %> + <%if flash[message] %> +
        + <%= h(flash[message]) if flash[message] %> +
        + <% end %> + <% end %> + <%= yield %> +
        + + diff --git a/backup.rails2.3/plugins/translate/views/translate/_pagination.rhtml b/backup.rails2.3/plugins/translate/views/translate/_pagination.rhtml new file mode 100644 index 00000000..64f4d690 --- /dev/null +++ b/backup.rails2.3/plugins/translate/views/translate/_pagination.rhtml @@ -0,0 +1,24 @@ +<% + # Expects locals: + # + # total_entries + # per_page + + n_pages = total_entries/per_page + (total_entries % per_page > 0 ? 1 : 0) + current_page = (params[:page] || 1).to_i +%> + +<% if n_pages > 1 %> +

        Pages:

        +
        +
          + <% (1..n_pages).each do |page_number| %> + <% if current_page == page_number %> +
        • <%= link_to(page_number, params.merge(:page => page_number), :title => "Page #{page_number}" ) %>
        • + <% else %> +
        • <%= link_to(page_number, params.merge(:page => page_number), :title => "Page #{page_number}") %>
        • + <% end %> + <% end %> +
        +
        +<% end %> \ No newline at end of file diff --git a/backup.rails2.3/plugins/translate/views/translate/index.rhtml b/backup.rails2.3/plugins/translate/views/translate/index.rhtml new file mode 100644 index 00000000..a057659d --- /dev/null +++ b/backup.rails2.3/plugins/translate/views/translate/index.rhtml @@ -0,0 +1,114 @@ +<% + @page_title = "Translate" + show_filters = ["all", "untranslated", "translated"] + show_filters << "changed" if @from_locale != @to_locale +%> + +
        + Search filter +
        +

        + <%= simple_filter(show_filters) %> +

        +

        + <%= simple_filter(["key", "text"], 'sort_by') %> +

        +
        + <% form_tag(params, :method => :get) do %> +
        +

        + <%= hidden_field_tag(:filter, params[:filter]) %> + <%= hidden_field_tag(:sort_by, params[:sort_by]) %> + + <%= select_tag(:from_locale, options_for_select(I18n.valid_locales, @from_locale.to_sym)) %> to + <%= select_tag(:to_locale, options_for_select(I18n.valid_locales, @to_locale.to_sym)) %> + <%= submit_tag "Display" %> +

        +
        +
        +

        + + <%= select_tag(:key_type, options_for_select([["contains", 'contains'], ["starts with", 'starts_with']], params[:key_type])) %> + <%= text_field_tag(:key_pattern, params[:key_pattern], :size => 50, :id => "key_pattern_value", :class => "text-default") %> +

        +

        + + <%= select_tag(:text_type, options_for_select(['contains', 'equals'], params[:text_type])) %> + <%= text_field_tag(:text_pattern, params[:text_pattern], :size => 50, :id => "text_pattern_value", :class => "text-default") %> +

        +

        + <%= submit_tag "Search" %> + <%= link_to "clear", params.merge({:text_pattern => nil, :key_pattern => nil}) %> +

        +
        + <% end %> +

        + Found <%= @total_entries %> messages +

        +

        + <%= link_to "Reload messages", translate_reload_path %> +

        +
        + + +
        + <%= render :partial => 'pagination', :locals => {:total_entries => @total_entries, :per_page => per_page} %> +
        + +<% if @total_entries > 0 %> +<% form_tag(translate_path) do %> +
        + <%= hidden_field_tag(:filter, params[:filter], :id => "hid_filter") %> + <%= hidden_field_tag(:sort_by, params[:sort_by], :id => "hid_sort_by") %> + <%= hidden_field_tag(:key_type, params[:key_type], :id => "hid_key_type") %> + <%= hidden_field_tag(:key_pattern, params[:key_pattern], :id => "hid_key_pattern") %> + <%= hidden_field_tag(:text_type, params[:text_type], :id => "hid_text_type") %> + <%= hidden_field_tag(:text_pattern, params[:text_pattern], :id => "hid_text_pattern") %> +
        +
        +

        Translations from <%= @from_locale %> to <%= @to_locale %>

        +

        + <%= submit_tag "Save Translations" %> +

        + <% @paginated_keys.each do |key| + from_text = lookup(@from_locale, key) + to_text = lookup(@to_locale, key) + line_size = 100 + n_lines = n_lines(from_text, line_size) + field_name = "key[#{key}]" + %> +
        + <% if from_text.present? %> +

        + <%= simple_format(h(from_text)) %> +

        + <% end %> +

        + <% if n_lines > 1 %> + <%= text_area_tag(field_name, to_text, :size => "#{line_size}x#{n_lines}", :id => key) %> + <% else %> + <%= text_field_tag(field_name, to_text, :size => line_size, :id => key) %> + <% end %> +

        +

        + + <%= link_to_function 'Auto Translate', "getGoogleTranslation('#{key}', \"#{escape_javascript(from_text)}\", '#{@from_locale}', '#{@to_locale}')", :style => 'padding: 0; margin: 0;' %> +
        + Key:<%=h key %>
        + <% if @files[key] %> + File:<%= @files[key].join("
        ") %> + <% end %> +
        +

        +
        +<% end %> +

        + <%= submit_tag "Save Translations" %> +

        +
        +<% end %> +<% end %> + +
        + <%= render :partial => 'pagination', :locals => {:total_entries => @total_entries, :per_page => per_page} %> +
        \ No newline at end of file diff --git a/backup.rails2.3/production.rb.rails2 b/backup.rails2.3/production.rb.rails2 new file mode 100644 index 00000000..56470f47 --- /dev/null +++ b/backup.rails2.3/production.rb.rails2 @@ -0,0 +1,17 @@ +# The production environment is meant for finished, "live" apps. +# Code is not reloaded between requests +config.cache_classes = true + +# Use a different logger for distributed setups +# config.logger = SyslogLogger.new + + +# Full error reports are disabled and caching is turned on +config.action_controller.consider_all_requests_local = false +config.action_controller.perform_caching = true + +# Enable serving of images, stylesheets, and javascripts from an asset server +# config.action_controller.asset_host = "http://assets.example.com" + +# Disable delivery errors if you bad email addresses should just be ignored +# config.action_mailer.raise_delivery_errors = false \ No newline at end of file diff --git a/backup.rails2.3/routes.rb.rails2 b/backup.rails2.3/routes.rb.rails2 new file mode 100644 index 00000000..ec0ed738 --- /dev/null +++ b/backup.rails2.3/routes.rb.rails2 @@ -0,0 +1,113 @@ +ActionController::Routing::Routes.draw do |map| + map.resources :users, + :member => {:change_password => :get, :update_password => :post, + :change_auth_type => :get, :update_auth_type => :post, :complete => :get, + :refresh_token => :post } + + map.with_options :controller => :users do |users| + users.signup 'signup', :action => "new" + end + + map.resources :contexts, :collection => {:order => :post, :done => :get}, :member => {:done_todos => :get, :all_done_todos => :get} do |contexts| + contexts.resources :todos, :name_prefix => "context_" + end + + map.resources :projects, + :collection => {:order => :post, :alphabetize => :post, :actionize => :post, :done => :get}, + :member => {:done_todos => :get, :all_done_todos => :get, :set_reviewed => :get} do |projects| + projects.resources :todos, :name_prefix => "project_" + end + + map.with_options :controller => :projects do |projects| + projects.review 'review', :action => :review + end + + map.resources :notes + + map.resources :todos, + :member => {:toggle_check => :put, :toggle_star => :put, :defer => :put}, + :collection => {:check_deferred => :post, :filter_to_context => :post, :filter_to_project => :post, :done => :get, :all_done => :get + } + + map.with_options :controller => :todos do |todos| + todos.home '', :action => "index" + todos.tickler 'tickler.:format', :action => "list_deferred" + todos.mobile_tickler 'tickler.m', :action => "list_deferred", :format => 'm' + + # This route works for tags with dots like /todos/tag/version1.5 + # please note that this pattern consumes everything after /todos/tag + # so /todos/tag/version1.5.xml will result in :name => 'version1.5.xml' + # UPDATE: added support for mobile view. All tags ending on .m will be + # routed to mobile view of tags. + todos.mobile_tag 'todos/tag/:name.m', :action => "tag", :format => 'm' + todos.text_tag 'todos/tag/:name.txt', :action => "tag", :format => 'txt' + todos.tag 'todos/tag/:name', :action => "tag", :name => /.*/ + todos.done_tag 'todos/done/tag/:name', :action => "done_tag" + todos.all_done_tag 'todos/all_done/tag/:name', :action => "all_done_tag" + + todos.tags 'tags.autocomplete', :action => "tags", :format => 'autocomplete' + todos.auto_complete_for_predecessor 'auto_complete_for_predecessor', :action => 'auto_complete_for_predecessor' + + todos.calendar 'calendar.ics', :action => "calendar", :format => 'ics' + todos.calendar 'calendar.xml', :action => "calendar", :format => 'xml' + todos.calendar 'calendar', :action => "calendar" + + todos.hidden 'hidden.xml', :action => "list_hidden", :format => 'xml' + + todos.mobile 'mobile', :action => "index", :format => 'm' + todos.mobile_abbrev 'm', :action => "index", :format => 'm' + todos.mobile_abbrev_new 'm/new', :action => "new", :format => 'm' + + todos.mobile_todo_show_notes 'todos/notes/:id.m', :action => "show_notes", :format => 'm' + todos.todo_show_notes 'todos/notes/:id', :action => "show_notes" + todos.done_todos 'todos/done', :action => :done + todos.all_done_todos 'todos/all_done', :action => :all_done + end + map.root :controller => 'todos' # Make OpenID happy because it needs #root_url defined + + map.resources :recurring_todos, :collection => {:done => :get}, + :member => {:toggle_check => :put, :toggle_star => :put} + map.with_options :controller => :recurring_todos do |rt| + rt.recurring_todos 'recurring_todos', :action => 'index' + end + + map.with_options :controller => :login do |login| + login.login 'login', :action => 'login' + login.login_cas 'login_cas', :action => 'login_cas' + login.formatted_login 'login.:format', :action => 'login' + login.logout 'logout', :action => 'logout' + login.formatted_logout 'logout.:format', :action => 'logout' + end + + map.with_options :controller => :feedlist do |fl| + fl.mobile_feeds 'feeds.m', :action => 'index', :format => 'm' + fl.feeds 'feeds', :action => 'index' + end + + map.with_options :controller => :integrations do |i| + i.integrations 'integrations', :action => 'index' + i.rest_api_docs 'integrations/rest_api', :action => "rest_api" + i.search_plugin 'integrations/search_plugin.xml', :action => 'search_plugin', :format => 'xml' + i.google_gadget 'integrations/google_gadget.xml', :action => 'google_gadget', :format => 'xml' + i.cloudmailin 'integrations/cloudmailin', :action => 'cloudmailin' + end + + map.with_options :controller => :preferences do |p| + p.preferences 'preferences', :action => 'index' + p.preferences_date_format 'preferences/render_date_format', :action => 'render_date_format' + end + + map.with_options :controller => :stats do |stats| + stats.stats 'stats', :action => 'index' + stats.done_overview 'done', :action => 'done' + end + + map.search 'search', :controller => 'search', :action => 'index' + map.data 'data', :controller => 'data', :action => 'index' + + Translate::Routes.translation_ui(map) if Rails.env != "production" + + # Install the default route as the lowest priority. + map.connect ':controller/:action/:id' + +end diff --git a/config/initializers/tracks.rb b/config/initializers/tracks.rb new file mode 100644 index 00000000..9d139286 --- /dev/null +++ b/config/initializers/tracks.rb @@ -0,0 +1,45 @@ +#require 'name_part_finder' +#require 'tracks/todo_list' +#require 'tracks/config' +#require 'tagging_extensions' # Needed for tagging-specific extensions +# require 'digest/sha1' #Needed to support 'rake db:fixtures:load' on some ruby installs: http://dev.rousette.org.uk/ticket/557 + +# TODO: move to devise for authentication which handles ldap, cas and openid +if ( SITE_CONFIG['authentication_schemes'].include? 'ldap') + require 'net/ldap' #requires ruby-net-ldap gem be installed + require 'simple_ldap_authenticator' + ldap = SITE_CONFIG['ldap'] + SimpleLdapAuthenticator.ldap_library = ldap['library'] + SimpleLdapAuthenticator.servers = ldap['servers'] + SimpleLdapAuthenticator.use_ssl = ldap['ssl'] + SimpleLdapAuthenticator.login_format = ldap['login_format'] +end + +# OpenID is not supported currently! +# +# if ( SITE_CONFIG['authentication_schemes'].include? 'open_id') +# #requires ruby-openid gem to be installed +# OpenID::Util.logger = RAILS_DEFAULT_LOGGER +# end + +if ( SITE_CONFIG['authentication_schemes'].include? 'cas') + #requires rubycas-client gem to be installed + if defined? CASClient + require 'casclient/frameworks/rails/filter' + CASClient::Frameworks::Rails::Filter.configure( + :cas_base_url => SITE_CONFIG['cas_server'] , + :cas_server_logout => SITE_CONFIG['cas_server_logout'] + ) + end +end + +# changed in development.rb to show under_construction bar +NOTIFY_BAR = "" unless defined?(NOTIFY_BAR) + +tracks_version='2.2devel' +# comment out next two lines if you do not want (or can not) the date of the +# last git commit in the footer +info=`git log --pretty=format:"%ai" -1` +tracks_version=tracks_version + ' ('+info+')' + +TRACKS_VERSION=tracks_version From 4605b17d3c1e17e2f4ae5eda5ae49123469487f9 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Wed, 11 Apr 2012 17:36:22 +0200 Subject: [PATCH 104/134] home page renders... sort of --- Gemfile | 22 +- Gemfile.lock | 27 +- app/helpers/application_helper.rb | 28 +- .../{_context.rhtml => _context.html.erb} | 0 app/views/layouts/standard.html.erb | 18 +- ...form.rhtml => _add_new_item_form.html.erb} | 0 .../shared/{_flash.rhtml => _flash.html.erb} | 0 .../{_footer.rhtml => _footer.html.erb} | 0 .../{_completed.rhtml => _completed.html.erb} | 0 ...rm.rhtml => _new_multi_todo_form.html.erb} | 10 +- ...odo_form.rhtml => _new_todo_form.html.erb} | 10 +- app/views/todos/index.html.erb | 5 +- app/views/todos/list_deferred.html.erb | 8 +- config/application.rb | 3 +- config/routes.rb | 54 ++++ public/index.html | 241 ------------------ 16 files changed, 131 insertions(+), 295 deletions(-) rename app/views/contexts/{_context.rhtml => _context.html.erb} (100%) rename app/views/shared/{_add_new_item_form.rhtml => _add_new_item_form.html.erb} (100%) rename app/views/shared/{_flash.rhtml => _flash.html.erb} (100%) rename app/views/shared/{_footer.rhtml => _footer.html.erb} (100%) rename app/views/todos/{_completed.rhtml => _completed.html.erb} (100%) rename app/views/todos/{_new_multi_todo_form.rhtml => _new_multi_todo_form.html.erb} (90%) rename app/views/todos/{_new_todo_form.rhtml => _new_todo_form.html.erb} (94%) delete mode 100644 public/index.html diff --git a/Gemfile b/Gemfile index e4e9d0a8..388ce5cd 100644 --- a/Gemfile +++ b/Gemfile @@ -12,24 +12,24 @@ gem "mysql2" gem "highline", "~>1.5.0" gem "RedCloth" -# gem "sanitize", "~>1.2.1" -# gem "will_paginate" -gem "has_many_polymorphs", :git => "git://github.com/lrbalt/has_many_polymorphs.git", :branch => "try" +gem "sanitize", "~>1.2.1" +gem "will_paginate" gem "acts_as_list", "~>0.1.4" gem "aasm", "~>2.2.0" # TODO: gem "rubyjedi-actionwebservice", :require => "actionwebservice" # gem "rubycas-client", "~>2.2.1" # gem "ruby-openid", :require => "openid" # gem "open_id_authentication" -# gem 'htmlentities', '~> 4.3.0' -# gem "mail" -# gem "swf_fu" +gem 'htmlentities', '~> 4.3.0' +gem "mail" +gem "swf_fu" +gem "rails_autolink" -# if RUBY_VERSION.to_f >= 1.9 -# gem "soap4r-ruby1.9" -# else -# gem "soap4r", "~>1.5.8" -# end +if RUBY_VERSION.to_f >= 1.9 + gem "soap4r-ruby1.9" +else + gem "soap4r", "~>1.5.8" +end # Gems used only for assets and not required # in production environments by default. diff --git a/Gemfile.lock b/Gemfile.lock index c7d44b87..12caee79 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,11 +1,3 @@ -GIT - remote: git://github.com/lrbalt/has_many_polymorphs.git - revision: bb0a7af8ac7418717954cab42a5476ca9806f858 - branch: try - specs: - has_many_polymorphs (3.0.0.beta1) - activerecord - GEM remote: https://rubygems.org/ specs: @@ -54,6 +46,7 @@ GEM multi_json (~> 1.0) highline (1.5.2) hike (1.2.1) + htmlentities (4.3.1) i18n (0.6.0) journey (1.0.3) jquery-rails (2.0.2) @@ -67,6 +60,7 @@ GEM mime-types (1.18) multi_json (1.2.0) mysql2 (0.3.11) + nokogiri (1.4.7) polyglot (0.3.3) rack (1.4.1) rack-cache (1.2) @@ -83,6 +77,8 @@ GEM activesupport (= 3.2.3) bundler (~> 1.0) railties (= 3.2.3) + rails_autolink (1.0.6) + rails (~> 3.1) railties (3.2.3) actionpack (= 3.2.3) activesupport (= 3.2.3) @@ -93,16 +89,22 @@ GEM rake (0.9.2.2) rdoc (3.12) json (~> 1.4) + sanitize (1.2.1) + nokogiri (~> 1.4.1) sass (3.1.15) sass-rails (3.2.5) railties (~> 3.2.0) sass (>= 3.1.10) tilt (~> 1.3) + soap4r-ruby1.9 (2.0.5) sprockets (2.1.2) hike (~> 1.2) rack (~> 1.0) tilt (~> 1.1, != 1.3.0) sqlite3 (1.3.5) + swf_fu (2.0.1) + coffee-script + rails (~> 3.1) thor (0.14.6) tilt (1.3.3) treetop (1.4.10) @@ -112,6 +114,7 @@ GEM uglifier (1.2.4) execjs (>= 0.3.0) multi_json (>= 1.0.2) + will_paginate (3.0.3) PLATFORMS ruby @@ -122,11 +125,17 @@ DEPENDENCIES acts_as_list (~> 0.1.4) bcrypt-ruby (~> 3.0.0) coffee-rails (~> 3.2.1) - has_many_polymorphs! highline (~> 1.5.0) + htmlentities (~> 4.3.0) jquery-rails + mail mysql2 rails (= 3.2.3) + rails_autolink + sanitize (~> 1.2.1) sass-rails (~> 3.2.3) + soap4r-ruby1.9 sqlite3 + swf_fu uglifier (>= 1.0.3) + will_paginate diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 183b4c31..3e4bf8cc 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -6,17 +6,19 @@ module ApplicationHelper # 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\"" : "" - - "#{name || url}" + link_to name, options, html_options + # TODO: check if this needs to be converted + # 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\"" : "" + # + # "#{name || url}" end def days_from_today(date) @@ -235,7 +237,7 @@ module ApplicationHelper end def determine_done_path - case @controller.controller_name + case controller.controller_name when "contexts" done_todos_context_path(@context) when "projects" @@ -252,7 +254,7 @@ module ApplicationHelper end def determine_all_done_path - case @controller.controller_name + case controller.controller_name when "contexts" all_done_todos_context_path(@context) when "projects" diff --git a/app/views/contexts/_context.rhtml b/app/views/contexts/_context.html.erb similarity index 100% rename from app/views/contexts/_context.rhtml rename to app/views/contexts/_context.html.erb diff --git a/app/views/layouts/standard.html.erb b/app/views/layouts/standard.html.erb index 142ca88a..92af1ebb 100644 --- a/app/views/layouts/standard.html.erb +++ b/app/views/layouts/standard.html.erb @@ -2,22 +2,22 @@ - <%= stylesheet_link_tag 'standard','superfish','niftyCorners', 'jquery-ui-1.8.17.custom', :cache => 'tracks-cached' %> + <%#= stylesheet_link_tag 'standard','superfish','niftyCorners', 'jquery-ui-1.8.17.custom', :cache => 'tracks-cached' %> <%= stylesheet_link_tag "print", :media => "print" %> - <%= javascript_include_tag 'jquery-1.7.1.min', 'jquery-ui-1.8.17.custom.min', + <%#= javascript_include_tag 'jquery-1.7.1.min', 'jquery-ui-1.8.17.custom.min', 'jquery.truncator','jquery.jeditable.mini', 'jquery.cookie', 'jquery.blockUI', 'jquery.form', :cache => 'jquery-cached' %> - <%= javascript_tag_for_i18n_datepicker %> - <%= javascript_include_tag 'hoverIntent','superfish','application', + <%#= javascript_tag_for_i18n_datepicker %> + <%#= javascript_include_tag 'hoverIntent','superfish','application', 'accesskey-hints','niftycube','swfobject', :cache => 'tracks-cached' %> - <%= javascript_include_tag('jquery.simulate.drag-sortable') if ENV['RAILS_ENV']=='cucumber' -%> + <% #= javascript_include_tag('jquery.simulate.drag-sortable') if ENV['RAILS_ENV']=='cucumber' -%> <%= javascript_tag "var AUTH_TOKEN = #{form_authenticity_token.inspect};" if protect_against_forgery? %> - <%= javascript_tag "var SOURCE_VIEW = '#{@source_view}';" %> <%= javascript_tag "var TAG_NAME = '#{@tag_name}';" if @tag_name %> <%= csrf_meta_tag %> - - -
        - - -
        - - - - -
        -

        Getting started

        -

        Here’s how to get rolling:

        - -
          -
        1. -

          Use rails generate to create your models and controllers

          -

          To see all available options, run it without parameters.

          -
        2. - -
        3. -

          Set up a default route and remove public/index.html

          -

          Routes are set up in config/routes.rb.

          -
        4. - -
        5. -

          Create your database

          -

          Run rake db:create to create your database. If you're not using SQLite (the default), edit config/database.yml with your username and password.

          -
        6. -
        -
        -
        - - -
        - - From e9647695533ac289004c494bcaa80af2f3a47b74 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Thu, 12 Apr 2012 17:30:05 +0200 Subject: [PATCH 105/134] home page is restored, so is context view --- Gemfile | 24 +++--- Gemfile.lock | 8 ++ {public => app/assets}/images/accept.png | Bin {public => app/assets}/images/add.png | Bin .../assets}/images/arrows-ffffff.png | Bin .../assets}/images/bigBlackWaiting.gif | Bin {public => app/assets}/images/bigWaiting.gif | Bin .../assets}/images/blackWaiting.gif | Bin {public => app/assets}/images/blank.png | Bin {public => app/assets}/images/bottom_off.png | Bin {public => app/assets}/images/bottom_on.png | Bin {public => app/assets}/images/cancel.png | Bin {public => app/assets}/images/close.gif | Bin {public => app/assets}/images/collapse.png | Bin .../assets}/images/construction.gif | Bin .../assets}/images/container-gradient.png | Bin {public => app/assets}/images/defer_1.png | Bin {public => app/assets}/images/defer_1_off.png | Bin {public => app/assets}/images/defer_2.png | Bin {public => app/assets}/images/defer_2_off.png | Bin {public => app/assets}/images/defer_3.png | Bin {public => app/assets}/images/defer_3_off.png | Bin {public => app/assets}/images/defer_7.png | Bin {public => app/assets}/images/defer_7_off.png | Bin {public => app/assets}/images/delete_off.png | Bin {public => app/assets}/images/delete_on.png | Bin {public => app/assets}/images/done.png | Bin {public => app/assets}/images/down_off.png | Bin {public => app/assets}/images/down_on.png | Bin {public => app/assets}/images/downarrow.png | Bin {public => app/assets}/images/edit_off.png | Bin {public => app/assets}/images/edit_on.png | Bin {public => app/assets}/images/expand.png | Bin {public => app/assets}/images/feed-icon.png | Bin {public => app/assets}/images/grip.png | Bin {public => app/assets}/images/icon_delete.png | Bin {public => app/assets}/images/menuarrow.gif | Bin {public => app/assets}/images/menustar.gif | Bin .../assets}/images/menustar_small.gif | Bin .../assets}/images/mobile_notes.png | Bin .../assets}/images/new-action-gradient.png | Bin {public => app/assets}/images/notes_off.png | Bin {public => app/assets}/images/notes_on.png | Bin .../assets}/images/open-id-login-bg.gif | Bin .../assets}/images/recurring16x16.png | Bin .../assets}/images/recurring24x24.png | Bin .../assets}/images/recurring_menu16x16.png | Bin .../assets}/images/recurring_menu24x24.png | Bin {public => app/assets}/images/reviewed.png | Bin {public => app/assets}/images/shadow.png | Bin {public => app/assets}/images/spinner.gif | Bin {public => app/assets}/images/staricons.png | Bin {public => app/assets}/images/stats.gif | Bin .../assets}/images/successor_off.png | Bin .../assets}/images/successor_on.png | Bin .../assets}/images/system-search.png | Bin .../assets}/images/to_project_off.png | Bin {public => app/assets}/images/top_off.png | Bin {public => app/assets}/images/top_on.png | Bin {public => app/assets}/images/trans70.png | Bin .../assets}/images/ui-anim_basic_16x16.gif | Bin {public => app/assets}/images/up_off.png | Bin {public => app/assets}/images/up_on.png | Bin {public => app/assets}/images/waiting.gif | Bin .../assets}/images/x-office-calendar.png | Bin app/assets/javascripts/application.js | 2 + .../assets/javascripts/tracks.js | 0 app/assets/stylesheets/application.css | 4 +- {public => app/assets}/stylesheets/mobile.css | 0 {public => app/assets}/stylesheets/print.css | 0 .../assets}/stylesheets/scaffold.css | 0 .../assets/stylesheets/tracks.css | 44 +++++------ app/controllers/application_controller.rb | 4 +- app/controllers/contexts_controller.rb | 7 +- app/helpers/application_helper.rb | 7 +- app/helpers/todos_helper.rb | 6 +- app/views/contexts/_context.html.erb | 2 +- app/views/contexts/show.html.erb | 6 +- app/views/layouts/standard.html.erb | 24 ++---- .../{_deferred.rhtml => _deferred.html.erb} | 0 .../{_edit_form.rhtml => _edit_form.html.erb} | 15 +++- app/views/todos/_new_multi_todo_form.html.erb | 2 +- app/views/todos/_new_todo_form.html.erb | 2 +- app/views/todos/index.html.erb | 2 +- app/views/todos/update.js.erb | 9 ++- .../backend_controller.rb | 0 .../hoverIntent.js | 0 .../javascripts => backup.rails2.3}/slider.js | 0 public/javascripts/accesskey-hints.js | 69 ------------------ public/javascripts/jquery-1.7.1.min.js | 4 - .../i18n/jquery.ui.datepicker-cz.js | 0 .../i18n/jquery.ui.datepicker-de.js | 0 .../i18n/jquery.ui.datepicker-es.js | 0 .../i18n/jquery.ui.datepicker-fr.js | 0 .../i18n/jquery.ui.datepicker-he.js | 0 .../i18n/jquery.ui.datepicker-nl.js | 0 .../jquery-ui-1.8.17.custom.min.js | 0 .../assets}/javascripts/jquery.blockUI.js | 0 .../assets}/javascripts/jquery.cookie.js | 0 .../assets}/javascripts/jquery.form.js | 0 .../javascripts/jquery.jeditable.mini.js | 0 .../jquery.simulate.drag-sortable.js | 0 .../assets}/javascripts/jquery.truncator.js | 0 .../assets}/javascripts/niftycube.js | 0 .../assets}/javascripts/superfish.js | 0 .../assets}/javascripts/supersubs.js | 0 .../assets}/javascripts/swfobject.js | 0 ...ui-bg_diagonals-medium_20_d34d17_40x40.png | Bin .../images/ui-bg_flat_30_cccccc_40x100.png | Bin .../images/ui-bg_flat_50_5c5c5c_40x100.png | Bin .../ui-bg_gloss-wave_45_817865_500x100.png | Bin .../ui-bg_gloss-wave_60_fece2f_500x100.png | Bin .../ui-bg_gloss-wave_70_ffdd57_500x100.png | Bin .../ui-bg_gloss-wave_90_fff9e5_500x100.png | Bin .../ui-bg_highlight-soft_100_feeebd_1x100.png | Bin .../ui-bg_inset-soft_30_ffffff_1x100.png | Bin .../images/ui-icons_3d3d3d_256x240.png | Bin .../images/ui-icons_bd7b00_256x240.png | Bin .../images/ui-icons_d19405_256x240.png | Bin .../images/ui-icons_eb990f_256x240.png | Bin .../images/ui-icons_ed9f26_256x240.png | Bin .../images/ui-icons_fadc7a_256x240.png | Bin .../images/ui-icons_ffe180_256x240.png | Bin .../stylesheets/jquery-ui-1.8.17.custom.css | 0 .../assets}/stylesheets/niftyCorners.css | 0 .../assets}/stylesheets/superfish-navbar.css | 0 .../stylesheets/superfish-vertical.css | 0 .../assets}/stylesheets/superfish.css | 0 .../assets}/swfs/expressInstall.swf | Bin .../assets}/swfs/open-flash-chart.swf | Bin 130 files changed, 89 insertions(+), 152 deletions(-) rename {public => app/assets}/images/accept.png (100%) rename {public => app/assets}/images/add.png (100%) rename {public => app/assets}/images/arrows-ffffff.png (100%) rename {public => app/assets}/images/bigBlackWaiting.gif (100%) rename {public => app/assets}/images/bigWaiting.gif (100%) rename {public => app/assets}/images/blackWaiting.gif (100%) rename {public => app/assets}/images/blank.png (100%) rename {public => app/assets}/images/bottom_off.png (100%) rename {public => app/assets}/images/bottom_on.png (100%) rename {public => app/assets}/images/cancel.png (100%) rename {public => app/assets}/images/close.gif (100%) rename {public => app/assets}/images/collapse.png (100%) rename {public => app/assets}/images/construction.gif (100%) rename {public => app/assets}/images/container-gradient.png (100%) rename {public => app/assets}/images/defer_1.png (100%) rename {public => app/assets}/images/defer_1_off.png (100%) rename {public => app/assets}/images/defer_2.png (100%) rename {public => app/assets}/images/defer_2_off.png (100%) rename {public => app/assets}/images/defer_3.png (100%) rename {public => app/assets}/images/defer_3_off.png (100%) rename {public => app/assets}/images/defer_7.png (100%) rename {public => app/assets}/images/defer_7_off.png (100%) rename {public => app/assets}/images/delete_off.png (100%) rename {public => app/assets}/images/delete_on.png (100%) rename {public => app/assets}/images/done.png (100%) rename {public => app/assets}/images/down_off.png (100%) rename {public => app/assets}/images/down_on.png (100%) rename {public => app/assets}/images/downarrow.png (100%) rename {public => app/assets}/images/edit_off.png (100%) rename {public => app/assets}/images/edit_on.png (100%) rename {public => app/assets}/images/expand.png (100%) rename {public => app/assets}/images/feed-icon.png (100%) rename {public => app/assets}/images/grip.png (100%) rename {public => app/assets}/images/icon_delete.png (100%) rename {public => app/assets}/images/menuarrow.gif (100%) rename {public => app/assets}/images/menustar.gif (100%) rename {public => app/assets}/images/menustar_small.gif (100%) rename {public => app/assets}/images/mobile_notes.png (100%) rename {public => app/assets}/images/new-action-gradient.png (100%) rename {public => app/assets}/images/notes_off.png (100%) rename {public => app/assets}/images/notes_on.png (100%) rename {public => app/assets}/images/open-id-login-bg.gif (100%) rename {public => app/assets}/images/recurring16x16.png (100%) rename {public => app/assets}/images/recurring24x24.png (100%) rename {public => app/assets}/images/recurring_menu16x16.png (100%) rename {public => app/assets}/images/recurring_menu24x24.png (100%) rename {public => app/assets}/images/reviewed.png (100%) rename {public => app/assets}/images/shadow.png (100%) rename {public => app/assets}/images/spinner.gif (100%) rename {public => app/assets}/images/staricons.png (100%) rename {public => app/assets}/images/stats.gif (100%) rename {public => app/assets}/images/successor_off.png (100%) rename {public => app/assets}/images/successor_on.png (100%) rename {public => app/assets}/images/system-search.png (100%) rename {public => app/assets}/images/to_project_off.png (100%) rename {public => app/assets}/images/top_off.png (100%) rename {public => app/assets}/images/top_on.png (100%) rename {public => app/assets}/images/trans70.png (100%) rename {public => app/assets}/images/ui-anim_basic_16x16.gif (100%) rename {public => app/assets}/images/up_off.png (100%) rename {public => app/assets}/images/up_on.png (100%) rename {public => app/assets}/images/waiting.gif (100%) rename {public => app/assets}/images/x-office-calendar.png (100%) rename public/javascripts/application.js => app/assets/javascripts/tracks.js (100%) rename {public => app/assets}/stylesheets/mobile.css (100%) rename {public => app/assets}/stylesheets/print.css (100%) rename {public => app/assets}/stylesheets/scaffold.css (100%) rename public/stylesheets/standard.css => app/assets/stylesheets/tracks.css (91%) rename app/views/todos/{_deferred.rhtml => _deferred.html.erb} (100%) rename app/views/todos/{_edit_form.rhtml => _edit_form.html.erb} (90%) rename {app/controllers => backup.rails2.3}/backend_controller.rb (100%) rename {public/javascripts => backup.rails2.3}/hoverIntent.js (100%) rename {public/javascripts => backup.rails2.3}/slider.js (100%) delete mode 100644 public/javascripts/accesskey-hints.js delete mode 100644 public/javascripts/jquery-1.7.1.min.js rename {public => vendor/assets}/javascripts/i18n/jquery.ui.datepicker-cz.js (100%) rename {public => vendor/assets}/javascripts/i18n/jquery.ui.datepicker-de.js (100%) rename {public => vendor/assets}/javascripts/i18n/jquery.ui.datepicker-es.js (100%) rename {public => vendor/assets}/javascripts/i18n/jquery.ui.datepicker-fr.js (100%) rename {public => vendor/assets}/javascripts/i18n/jquery.ui.datepicker-he.js (100%) rename {public => vendor/assets}/javascripts/i18n/jquery.ui.datepicker-nl.js (100%) rename {public => vendor/assets}/javascripts/jquery-ui-1.8.17.custom.min.js (100%) rename {public => vendor/assets}/javascripts/jquery.blockUI.js (100%) rename {public => vendor/assets}/javascripts/jquery.cookie.js (100%) rename {public => vendor/assets}/javascripts/jquery.form.js (100%) rename {public => vendor/assets}/javascripts/jquery.jeditable.mini.js (100%) rename {public => vendor/assets}/javascripts/jquery.simulate.drag-sortable.js (100%) rename {public => vendor/assets}/javascripts/jquery.truncator.js (100%) rename {public => vendor/assets}/javascripts/niftycube.js (100%) rename {public => vendor/assets}/javascripts/superfish.js (100%) rename {public => vendor/assets}/javascripts/supersubs.js (100%) rename {public => vendor/assets}/javascripts/swfobject.js (100%) rename {public => vendor/assets}/stylesheets/images/ui-bg_diagonals-medium_20_d34d17_40x40.png (100%) rename {public => vendor/assets}/stylesheets/images/ui-bg_flat_30_cccccc_40x100.png (100%) rename {public => vendor/assets}/stylesheets/images/ui-bg_flat_50_5c5c5c_40x100.png (100%) rename {public => vendor/assets}/stylesheets/images/ui-bg_gloss-wave_45_817865_500x100.png (100%) rename {public => vendor/assets}/stylesheets/images/ui-bg_gloss-wave_60_fece2f_500x100.png (100%) rename {public => vendor/assets}/stylesheets/images/ui-bg_gloss-wave_70_ffdd57_500x100.png (100%) rename {public => vendor/assets}/stylesheets/images/ui-bg_gloss-wave_90_fff9e5_500x100.png (100%) rename {public => vendor/assets}/stylesheets/images/ui-bg_highlight-soft_100_feeebd_1x100.png (100%) rename {public => vendor/assets}/stylesheets/images/ui-bg_inset-soft_30_ffffff_1x100.png (100%) rename {public => vendor/assets}/stylesheets/images/ui-icons_3d3d3d_256x240.png (100%) rename {public => vendor/assets}/stylesheets/images/ui-icons_bd7b00_256x240.png (100%) rename {public => vendor/assets}/stylesheets/images/ui-icons_d19405_256x240.png (100%) rename {public => vendor/assets}/stylesheets/images/ui-icons_eb990f_256x240.png (100%) rename {public => vendor/assets}/stylesheets/images/ui-icons_ed9f26_256x240.png (100%) rename {public => vendor/assets}/stylesheets/images/ui-icons_fadc7a_256x240.png (100%) rename {public => vendor/assets}/stylesheets/images/ui-icons_ffe180_256x240.png (100%) rename {public => vendor/assets}/stylesheets/jquery-ui-1.8.17.custom.css (100%) rename {public => vendor/assets}/stylesheets/niftyCorners.css (100%) rename {public => vendor/assets}/stylesheets/superfish-navbar.css (100%) rename {public => vendor/assets}/stylesheets/superfish-vertical.css (100%) rename {public => vendor/assets}/stylesheets/superfish.css (100%) rename {public => vendor/assets}/swfs/expressInstall.swf (100%) rename {public => vendor/assets}/swfs/open-flash-chart.swf (100%) diff --git a/Gemfile b/Gemfile index 388ce5cd..f6553fd1 100644 --- a/Gemfile +++ b/Gemfile @@ -57,20 +57,16 @@ gem 'bcrypt-ruby', '~> 3.0.0' # Deploy with Capistrano # gem 'capistrano' -# To use debugger -# gem 'ruby-debug19', :require => 'ruby-debug' - - -# group :development do -# if RUBY_VERSION.to_f >= 1.9 -# gem "ruby-debug19" -# gem "mongrel", "1.2.0.pre2" -# else -# gem "ruby-debug" -# gem "mongrel" -# end -# gem "yard" -# end +group :development do + if RUBY_VERSION.to_f >= 1.9 +# gem "ruby-debug19", :require => 'ruby-debug' + gem "mongrel", "1.2.0.pre2" + else +# gem "ruby-debug" +# gem "mongrel" + end + gem "yard" +end # # group :test do # gem "test-unit", "1.2.3" diff --git a/Gemfile.lock b/Gemfile.lock index 12caee79..26af276b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -41,9 +41,11 @@ GEM coffee-script-source execjs coffee-script-source (1.3.1) + daemons (1.0.10) erubis (2.7.0) execjs (1.3.0) multi_json (~> 1.0) + gem_plugin (0.2.3) highline (1.5.2) hike (1.2.1) htmlentities (4.3.1) @@ -58,6 +60,9 @@ GEM mime-types (~> 1.16) treetop (~> 1.4.8) mime-types (1.18) + mongrel (1.2.0.pre2) + daemons (~> 1.0.10) + gem_plugin (~> 0.2.3) multi_json (1.2.0) mysql2 (0.3.11) nokogiri (1.4.7) @@ -115,6 +120,7 @@ GEM execjs (>= 0.3.0) multi_json (>= 1.0.2) will_paginate (3.0.3) + yard (0.7.5) PLATFORMS ruby @@ -129,6 +135,7 @@ DEPENDENCIES htmlentities (~> 4.3.0) jquery-rails mail + mongrel (= 1.2.0.pre2) mysql2 rails (= 3.2.3) rails_autolink @@ -139,3 +146,4 @@ DEPENDENCIES swf_fu uglifier (>= 1.0.3) will_paginate + yard diff --git a/public/images/accept.png b/app/assets/images/accept.png similarity index 100% rename from public/images/accept.png rename to app/assets/images/accept.png diff --git a/public/images/add.png b/app/assets/images/add.png similarity index 100% rename from public/images/add.png rename to app/assets/images/add.png diff --git a/public/images/arrows-ffffff.png b/app/assets/images/arrows-ffffff.png similarity index 100% rename from public/images/arrows-ffffff.png rename to app/assets/images/arrows-ffffff.png diff --git a/public/images/bigBlackWaiting.gif b/app/assets/images/bigBlackWaiting.gif similarity index 100% rename from public/images/bigBlackWaiting.gif rename to app/assets/images/bigBlackWaiting.gif diff --git a/public/images/bigWaiting.gif b/app/assets/images/bigWaiting.gif similarity index 100% rename from public/images/bigWaiting.gif rename to app/assets/images/bigWaiting.gif diff --git a/public/images/blackWaiting.gif b/app/assets/images/blackWaiting.gif similarity index 100% rename from public/images/blackWaiting.gif rename to app/assets/images/blackWaiting.gif diff --git a/public/images/blank.png b/app/assets/images/blank.png similarity index 100% rename from public/images/blank.png rename to app/assets/images/blank.png diff --git a/public/images/bottom_off.png b/app/assets/images/bottom_off.png similarity index 100% rename from public/images/bottom_off.png rename to app/assets/images/bottom_off.png diff --git a/public/images/bottom_on.png b/app/assets/images/bottom_on.png similarity index 100% rename from public/images/bottom_on.png rename to app/assets/images/bottom_on.png diff --git a/public/images/cancel.png b/app/assets/images/cancel.png similarity index 100% rename from public/images/cancel.png rename to app/assets/images/cancel.png diff --git a/public/images/close.gif b/app/assets/images/close.gif similarity index 100% rename from public/images/close.gif rename to app/assets/images/close.gif diff --git a/public/images/collapse.png b/app/assets/images/collapse.png similarity index 100% rename from public/images/collapse.png rename to app/assets/images/collapse.png diff --git a/public/images/construction.gif b/app/assets/images/construction.gif similarity index 100% rename from public/images/construction.gif rename to app/assets/images/construction.gif diff --git a/public/images/container-gradient.png b/app/assets/images/container-gradient.png similarity index 100% rename from public/images/container-gradient.png rename to app/assets/images/container-gradient.png diff --git a/public/images/defer_1.png b/app/assets/images/defer_1.png similarity index 100% rename from public/images/defer_1.png rename to app/assets/images/defer_1.png diff --git a/public/images/defer_1_off.png b/app/assets/images/defer_1_off.png similarity index 100% rename from public/images/defer_1_off.png rename to app/assets/images/defer_1_off.png diff --git a/public/images/defer_2.png b/app/assets/images/defer_2.png similarity index 100% rename from public/images/defer_2.png rename to app/assets/images/defer_2.png diff --git a/public/images/defer_2_off.png b/app/assets/images/defer_2_off.png similarity index 100% rename from public/images/defer_2_off.png rename to app/assets/images/defer_2_off.png diff --git a/public/images/defer_3.png b/app/assets/images/defer_3.png similarity index 100% rename from public/images/defer_3.png rename to app/assets/images/defer_3.png diff --git a/public/images/defer_3_off.png b/app/assets/images/defer_3_off.png similarity index 100% rename from public/images/defer_3_off.png rename to app/assets/images/defer_3_off.png diff --git a/public/images/defer_7.png b/app/assets/images/defer_7.png similarity index 100% rename from public/images/defer_7.png rename to app/assets/images/defer_7.png diff --git a/public/images/defer_7_off.png b/app/assets/images/defer_7_off.png similarity index 100% rename from public/images/defer_7_off.png rename to app/assets/images/defer_7_off.png diff --git a/public/images/delete_off.png b/app/assets/images/delete_off.png similarity index 100% rename from public/images/delete_off.png rename to app/assets/images/delete_off.png diff --git a/public/images/delete_on.png b/app/assets/images/delete_on.png similarity index 100% rename from public/images/delete_on.png rename to app/assets/images/delete_on.png diff --git a/public/images/done.png b/app/assets/images/done.png similarity index 100% rename from public/images/done.png rename to app/assets/images/done.png diff --git a/public/images/down_off.png b/app/assets/images/down_off.png similarity index 100% rename from public/images/down_off.png rename to app/assets/images/down_off.png diff --git a/public/images/down_on.png b/app/assets/images/down_on.png similarity index 100% rename from public/images/down_on.png rename to app/assets/images/down_on.png diff --git a/public/images/downarrow.png b/app/assets/images/downarrow.png similarity index 100% rename from public/images/downarrow.png rename to app/assets/images/downarrow.png diff --git a/public/images/edit_off.png b/app/assets/images/edit_off.png similarity index 100% rename from public/images/edit_off.png rename to app/assets/images/edit_off.png diff --git a/public/images/edit_on.png b/app/assets/images/edit_on.png similarity index 100% rename from public/images/edit_on.png rename to app/assets/images/edit_on.png diff --git a/public/images/expand.png b/app/assets/images/expand.png similarity index 100% rename from public/images/expand.png rename to app/assets/images/expand.png diff --git a/public/images/feed-icon.png b/app/assets/images/feed-icon.png similarity index 100% rename from public/images/feed-icon.png rename to app/assets/images/feed-icon.png diff --git a/public/images/grip.png b/app/assets/images/grip.png similarity index 100% rename from public/images/grip.png rename to app/assets/images/grip.png diff --git a/public/images/icon_delete.png b/app/assets/images/icon_delete.png similarity index 100% rename from public/images/icon_delete.png rename to app/assets/images/icon_delete.png diff --git a/public/images/menuarrow.gif b/app/assets/images/menuarrow.gif similarity index 100% rename from public/images/menuarrow.gif rename to app/assets/images/menuarrow.gif diff --git a/public/images/menustar.gif b/app/assets/images/menustar.gif similarity index 100% rename from public/images/menustar.gif rename to app/assets/images/menustar.gif diff --git a/public/images/menustar_small.gif b/app/assets/images/menustar_small.gif similarity index 100% rename from public/images/menustar_small.gif rename to app/assets/images/menustar_small.gif diff --git a/public/images/mobile_notes.png b/app/assets/images/mobile_notes.png similarity index 100% rename from public/images/mobile_notes.png rename to app/assets/images/mobile_notes.png diff --git a/public/images/new-action-gradient.png b/app/assets/images/new-action-gradient.png similarity index 100% rename from public/images/new-action-gradient.png rename to app/assets/images/new-action-gradient.png diff --git a/public/images/notes_off.png b/app/assets/images/notes_off.png similarity index 100% rename from public/images/notes_off.png rename to app/assets/images/notes_off.png diff --git a/public/images/notes_on.png b/app/assets/images/notes_on.png similarity index 100% rename from public/images/notes_on.png rename to app/assets/images/notes_on.png diff --git a/public/images/open-id-login-bg.gif b/app/assets/images/open-id-login-bg.gif similarity index 100% rename from public/images/open-id-login-bg.gif rename to app/assets/images/open-id-login-bg.gif diff --git a/public/images/recurring16x16.png b/app/assets/images/recurring16x16.png similarity index 100% rename from public/images/recurring16x16.png rename to app/assets/images/recurring16x16.png diff --git a/public/images/recurring24x24.png b/app/assets/images/recurring24x24.png similarity index 100% rename from public/images/recurring24x24.png rename to app/assets/images/recurring24x24.png diff --git a/public/images/recurring_menu16x16.png b/app/assets/images/recurring_menu16x16.png similarity index 100% rename from public/images/recurring_menu16x16.png rename to app/assets/images/recurring_menu16x16.png diff --git a/public/images/recurring_menu24x24.png b/app/assets/images/recurring_menu24x24.png similarity index 100% rename from public/images/recurring_menu24x24.png rename to app/assets/images/recurring_menu24x24.png diff --git a/public/images/reviewed.png b/app/assets/images/reviewed.png similarity index 100% rename from public/images/reviewed.png rename to app/assets/images/reviewed.png diff --git a/public/images/shadow.png b/app/assets/images/shadow.png similarity index 100% rename from public/images/shadow.png rename to app/assets/images/shadow.png diff --git a/public/images/spinner.gif b/app/assets/images/spinner.gif similarity index 100% rename from public/images/spinner.gif rename to app/assets/images/spinner.gif diff --git a/public/images/staricons.png b/app/assets/images/staricons.png similarity index 100% rename from public/images/staricons.png rename to app/assets/images/staricons.png diff --git a/public/images/stats.gif b/app/assets/images/stats.gif similarity index 100% rename from public/images/stats.gif rename to app/assets/images/stats.gif diff --git a/public/images/successor_off.png b/app/assets/images/successor_off.png similarity index 100% rename from public/images/successor_off.png rename to app/assets/images/successor_off.png diff --git a/public/images/successor_on.png b/app/assets/images/successor_on.png similarity index 100% rename from public/images/successor_on.png rename to app/assets/images/successor_on.png diff --git a/public/images/system-search.png b/app/assets/images/system-search.png similarity index 100% rename from public/images/system-search.png rename to app/assets/images/system-search.png diff --git a/public/images/to_project_off.png b/app/assets/images/to_project_off.png similarity index 100% rename from public/images/to_project_off.png rename to app/assets/images/to_project_off.png diff --git a/public/images/top_off.png b/app/assets/images/top_off.png similarity index 100% rename from public/images/top_off.png rename to app/assets/images/top_off.png diff --git a/public/images/top_on.png b/app/assets/images/top_on.png similarity index 100% rename from public/images/top_on.png rename to app/assets/images/top_on.png diff --git a/public/images/trans70.png b/app/assets/images/trans70.png similarity index 100% rename from public/images/trans70.png rename to app/assets/images/trans70.png diff --git a/public/images/ui-anim_basic_16x16.gif b/app/assets/images/ui-anim_basic_16x16.gif similarity index 100% rename from public/images/ui-anim_basic_16x16.gif rename to app/assets/images/ui-anim_basic_16x16.gif diff --git a/public/images/up_off.png b/app/assets/images/up_off.png similarity index 100% rename from public/images/up_off.png rename to app/assets/images/up_off.png diff --git a/public/images/up_on.png b/app/assets/images/up_on.png similarity index 100% rename from public/images/up_on.png rename to app/assets/images/up_on.png diff --git a/public/images/waiting.gif b/app/assets/images/waiting.gif similarity index 100% rename from public/images/waiting.gif rename to app/assets/images/waiting.gif diff --git a/public/images/x-office-calendar.png b/app/assets/images/x-office-calendar.png similarity index 100% rename from public/images/x-office-calendar.png rename to app/assets/images/x-office-calendar.png diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 9097d830..52e53829 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -12,4 +12,6 @@ // //= require jquery //= require jquery_ujs +//= require ../../../vendor/assets/javascripts/jquery-ui-1.8.17.custom.min +//= require_tree ../../../vendor/assets/javascripts //= require_tree . diff --git a/public/javascripts/application.js b/app/assets/javascripts/tracks.js similarity index 100% rename from public/javascripts/application.js rename to app/assets/javascripts/tracks.js diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 3b5cc664..8fb1662d 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -9,5 +9,7 @@ * compiled file, but it's generally better to create a new file per style scope. * *= require_self - *= require_tree . + * require_tree . + *= require tracks + *= require_tree ../../../vendor/assets/stylesheets */ diff --git a/public/stylesheets/mobile.css b/app/assets/stylesheets/mobile.css similarity index 100% rename from public/stylesheets/mobile.css rename to app/assets/stylesheets/mobile.css diff --git a/public/stylesheets/print.css b/app/assets/stylesheets/print.css similarity index 100% rename from public/stylesheets/print.css rename to app/assets/stylesheets/print.css diff --git a/public/stylesheets/scaffold.css b/app/assets/stylesheets/scaffold.css similarity index 100% rename from public/stylesheets/scaffold.css rename to app/assets/stylesheets/scaffold.css diff --git a/public/stylesheets/standard.css b/app/assets/stylesheets/tracks.css similarity index 91% rename from public/stylesheets/standard.css rename to app/assets/stylesheets/tracks.css index b7124f62..4274702b 100644 --- a/public/stylesheets/standard.css +++ b/app/assets/stylesheets/tracks.css @@ -106,35 +106,35 @@ h3 { /* Rules for the icon links */ -img.edit_item {background-image: url(../images/edit_off.png); background-repeat: no-repeat; border: none;} -a:hover img.edit_item {background-image: url(../images/edit_on.png); background-color: transparent; background-repeat: no-repeat; border: none;} +img.edit_item {background-image: url(/assets/edit_off.png); background-repeat: no-repeat; border: none;} +a:hover img.edit_item {background-image: url(/assets/edit_on.png); background-color: transparent; background-repeat: no-repeat; border: none;} -img.delete_item {background-image: url(../images/delete_off.png); background-repeat: no-repeat; border: none;} -a:hover img.delete_item {background-image: url(../images/delete_on.png);background-color: transparent;background-repeat: no-repeat; border: none;} +img.delete_item {background-image: url(/assets/delete_off.png); background-repeat: no-repeat; border: none;} +a:hover img.delete_item {background-image: url(/assets/delete_on.png);background-color: transparent;background-repeat: no-repeat; border: none;} a.undecorated_link {background-color:transparent;color:transparent;} -img.todo_star {background-image: url(../images/staricons.png); background-repeat: no-repeat; border:none; background-position: -32px 0px;} +img.todo_star {background-image: url(/assets/staricons.png); background-repeat: no-repeat; border:none; background-position: -32px 0px;} img.todo_star.starred{ background-position: 0px 0px; } a:hover img.todo_star { background-position: -48px 0px;} a:hover img.todo_star.starred { background-position: -16px 0px; } -a.to_top {background: transparent url(../images/top_off.png) no-repeat;} -a.to_top:hover {background: transparent url(../images/top_on.png) no-repeat;} +a.to_top {background: transparent url(/assets/top_off.png) no-repeat;} +a.to_top:hover {background: transparent url(/assets/top_on.png) no-repeat;} -a.up {background: transparent url(../images/up_off.png) no-repeat;} -a.up:hover {background: transparent url(../images/up_on.png) no-repeat;} +a.up {background: transparent url(/assets/up_off.png) no-repeat;} +a.up:hover {background: transparent url(/assets/up_on.png) no-repeat;} -a.down {background: transparent url(../images/down_off.png) no-repeat;} -a.down:hover {background: transparent url(../images/down_on.png) no-repeat;} +a.down {background: transparent url(/assets/down_off.png) no-repeat;} +a.down:hover {background: transparent url(/assets/down_on.png) no-repeat;} -a.to_bottom {background: transparent url(../images/bottom_off.png) no-repeat;} -a.to_bottom:hover {background: transparent url(../images/bottom_on.png) no-repeat;} +a.to_bottom {background: transparent url(/assets/bottom_off.png) no-repeat;} +a.to_bottom:hover {background: transparent url(/assets/bottom_on.png) no-repeat;} -a.show_notes, a.link_to_notes {background-image: url(../images/notes_off.png); background-repeat: no-repeat; padding: 1px; background-color: transparent;} -a.show_notes:hover, a.link_to_notes:hover {background-image: url(../images/notes_on.png); background-repeat: no-repeat; padding: 1px; background-color: transparent;} +a.show_notes, a.link_to_notes {background-image: url(/assets/notes_off.png); background-repeat: no-repeat; padding: 1px; background-color: transparent;} +a.show_notes:hover, a.link_to_notes:hover {background-image: url(/assets/notes_on.png); background-repeat: no-repeat; padding: 1px; background-color: transparent;} -a.show_successors, a.link_to_successors {background-image: url(../images/successor_off.png); background-repeat: no-repeat; padding: 1px; background-color: transparent;} -a.show_successors:hover, a.link_to_successors:hover {background-image: url(../images/successor_on.png); background-repeat: no-repeat; padding: 1px; background-color: transparent;} +a.show_successors, a.link_to_successors {background-image: url(/assets/successor_off.png); background-repeat: no-repeat; padding: 1px; background-color: transparent;} +a.show_successors:hover, a.link_to_successors:hover {background-image: url(/assets/successor_on.png); background-repeat: no-repeat; padding: 1px; background-color: transparent;} /* Structural divs */ @@ -255,7 +255,7 @@ a.show_successors:hover, a.link_to_successors:hover {background-image: url(../im #develop-notify-bar { line-height:0.5; - background-image: url(/images/construction.gif); + background-image: url(/assets/construction.gif); background-repeat: repeat-x; } @@ -384,8 +384,8 @@ ul.predecessor_list li { } /* deleting dependency from new form of a todo */ -img.icon_delete_dep {width: 10px; background-image: url(../images/icon_delete.png); background-repeat: no-repeat; background-position: -9px 0; border: none; color:black;} -a:hover img.icon_delete_dep {width: 10px; background-image: url(../images/icon_delete.png); background-repeat: no-repeat; background-position: 0 0; border: none; color:black; background-color: black;} +img.icon_delete_dep {width: 10px; background-image: url(/assets/icon_delete.png); background-repeat: no-repeat; background-position: -9px 0; border: none; color:black;} +a:hover img.icon_delete_dep {width: 10px; background-image: url(/assets/icon_delete.png); background-repeat: no-repeat; background-position: 0 0; border: none; color:black; background-color: black;} a.icon_delete_dep:hover {width: 10px; background-color: black;} /* deleting dependency from edit form of a todo */ @@ -1161,7 +1161,7 @@ ul#prefs {list-style-type: disc; margin-left: 15px;} } input.open_id { - background: url(../images/open-id-login-bg.gif) no-repeat; + background: url(/assets/open-id-login-bg.gif) no-repeat; background-color: #fff; background-position: 0 50%; color: #000; @@ -1428,5 +1428,5 @@ div.auto_complete ul strong.highlight { } .ui-autocomplete-loading { - background: white url('/images/ui-anim_basic_16x16.gif') right center no-repeat; + background: white url('/assets/ui-anim_basic_16x16.gif') right center no-repeat; } diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 457ac53d..f898a16c 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -95,10 +95,10 @@ class ApplicationController < ActionController::Base if count == 0 && deferred_count > 0 word = deferred_count == 1 ? string.singularize : string.pluralize word = "deferred " + word - deferred_count.to_s + " " + word + return (deferred_count.to_s + " " + word).html_safe else word = count == 1 ? string.singularize : string.pluralize - count.to_s + " " + word + return (count.to_s + " " + word).html_safe end end diff --git a/app/controllers/contexts_controller.rb b/app/controllers/contexts_controller.rb index aff19c89..f99e1715 100644 --- a/app/controllers/contexts_controller.rb +++ b/app/controllers/contexts_controller.rb @@ -263,7 +263,7 @@ class ContextsController < ApplicationController end def set_context_from_params - @context = current_user.contexts.find_by_params(params) + @context = current_user.contexts.find(params[:id]) rescue @context = nil end @@ -276,11 +276,8 @@ class ContextsController < ApplicationController def init_todos set_context_from_params unless @context.nil? - @context.todos.send :with_scope, :find => { :include => Todo::DEFAULT_INCLUDES } do - @done = @context.done_todos - end - @max_completed = current_user.prefs.show_number_completed + @done = @context.todos.completed.all(:limit => @max_completed) # @not_done_todos = @context.not_done_todos TODO: Temporarily doing this # search manually until I can work out a way to do the same thing using diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 3e4bf8cc..f179fd08 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -192,18 +192,17 @@ module ApplicationHelper end def sidebar_html_for_titled_list (list, title) - return content_tag(:h3, title+" (#{list.length})") + - content_tag(:ul, sidebar_html_for_list(list)) + return content_tag(:h3, title+" (#{list.length})") + content_tag(:ul, sidebar_html_for_list(list)) end def sidebar_html_for_list(list) if list.empty? - return content_tag(:li, t('sidebar.list_empty')) + return content_tag(:li, t('sidebar.list_empty')).html_safe else return list.inject("") do |html, item| link = (item.class == "Project") ? link_to_project( item ) : link_to_context(item) html << content_tag(:li, link + " (" + count_undone_todos_phrase(item)+")") - end + end.html_safe end end diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index 20e04191..171d36c5 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -64,7 +64,7 @@ module TodosHelper def collapsed_notes_image(todo) link = link_to(image_tag( 'blank.png', :width=>'16', :height=>'16', :border=>'0' ), "#", {:class => 'show_notes', :title => 'Show notes'}) - notes = content_tag(:div, {:class => "todo_notes", :id => dom_id(todo, 'notes'), :style => "display:none"}) { todo.rendered_notes } + notes = content_tag(:div, {:class => "todo_notes", :id => dom_id(todo, 'notes'), :style => "display:none"}) { todo.rendered_notes.html_safe } return link+notes end @@ -133,7 +133,7 @@ module TodosHelper end def tag_list(todo=@todo, mobile=false) - content_tag(:span, :class => 'tags') { todo.tags.all_except_starred.collect{|tag| tag_span(tag, mobile)}.join('') } + content_tag(:span, :class => 'tags') { todo.tags.all_except_starred.collect{|tag| tag_span(tag, mobile)}.join('').html_safe } end def tag_list_mobile(todo=@todo) @@ -166,7 +166,7 @@ module TodosHelper str << item_link_to_project( todo ) end end - return str + return str.html_safe end # Uses the 'staleness_starts' value from settings.yml (in days) to colour the diff --git a/app/views/contexts/_context.html.erb b/app/views/contexts/_context.html.erb index e9e14ab1..fd0f895a 100644 --- a/app/views/contexts/_context.html.erb +++ b/app/views/contexts/_context.html.erb @@ -1,5 +1,5 @@ <% @not_done = @not_done_todos.select {|t| t.context_id == context.id } %> -
        > +
        ">

        <% if collapsible -%> <%= image_tag("collapse.png") %> diff --git a/app/views/contexts/show.html.erb b/app/views/contexts/show.html.erb index fd323422..41de4b28 100644 --- a/app/views/contexts/show.html.erb +++ b/app/views/contexts/show.html.erb @@ -1,12 +1,12 @@
        -<%= render :partial => "contexts/context", :object => @context, :locals => { :collapsible => false } %> +<%= render :partial => @context, :locals => { :collapsible => false } %> <%= render :partial => "todos/deferred", :object => @deferred, :locals => { :collapsible => false, :append_descriptor => t('contexts.todos_append'), :parent_container_type => 'context', :pending => @pending } %> <% unless @max_completed==0 -%> <%= render :partial => "todos/completed", :object => @done, :locals => { :suppress_context => true, :collapsible => false, :append_descriptor => t('contexts.last_completed_in_context', :number=>prefs.show_number_completed) } %> <% end -%> -
        +

        <%= render :partial => "shared/add_new_item_form" %> <%= render :file => "sidebar/sidebar.html.erb" %> -
        +
        diff --git a/app/views/layouts/standard.html.erb b/app/views/layouts/standard.html.erb index 92af1ebb..85d3c4c9 100644 --- a/app/views/layouts/standard.html.erb +++ b/app/views/layouts/standard.html.erb @@ -2,24 +2,16 @@ - <%#= stylesheet_link_tag 'standard','superfish','niftyCorners', 'jquery-ui-1.8.17.custom', :cache => 'tracks-cached' %> + <%= stylesheet_link_tag "application", :media => "all" %> <%= stylesheet_link_tag "print", :media => "print" %> - <%#= javascript_include_tag 'jquery-1.7.1.min', 'jquery-ui-1.8.17.custom.min', - 'jquery.truncator','jquery.jeditable.mini', 'jquery.cookie', 'jquery.blockUI', - 'jquery.form', - :cache => 'jquery-cached' %> - <%#= javascript_tag_for_i18n_datepicker %> - <%#= javascript_include_tag 'hoverIntent','superfish','application', - 'accesskey-hints','niftycube','swfobject', - :cache => 'tracks-cached' %> - <% #= javascript_include_tag('jquery.simulate.drag-sortable') if ENV['RAILS_ENV']=='cucumber' -%> - <%= javascript_tag "var AUTH_TOKEN = #{form_authenticity_token.inspect};" if protect_against_forgery? %> - <%= javascript_tag "var TAG_NAME = '#{@tag_name}';" if @tag_name %> + <%= javascript_include_tag "application" %> <%= csrf_meta_tag %> - */ -var accessKeyHintsAdder = { - - run : function() { - var elemTypes = new Array('a','area','button','input','label','legend','textarea'); - for(var i = 0; i < elemTypes.length; i++) - { - accessKeyHintsAdder.addHint(document.getElementsByTagName(elemTypes[i])); - } - }, - - addHint : function(elems) { - var elem; - var i = 0; - - processElements: - while(elem = elems.item(i++)) - { - var accessKey = elem.getAttributeNode("accesskey"); - if (!accessKey || !accessKey.value) - continue processElements; - - var title = elem.getAttributeNode("title"); - if (title && title.value) - { - var overrides = new Array('accesskey','alt+','ctrl+'); - for (var j=0; j < overrides.length; j++) - { - if (title.value.toLowerCase().indexOf(overrides[j]) != -1) - continue processElements; - } - elem.setAttribute("title", title.value + ' (' + this.getHintText(accessKey.value) + ')'); - } - else - { - elem.setAttribute("title", this.getHintText(accessKey.value)); - } - } - }, - - getHintText : function(accessKey) { - return this.getModifier() + '+' + accessKey.toUpperCase(); - }, - - getModifier : function() { - var ua = navigator.userAgent.toLowerCase(); - if (ua.indexOf('mac') == -1) - return 'Alt'; - else - return 'Ctrl'; - } - -} - -$(accessKeyHintsAdder.run); diff --git a/public/javascripts/jquery-1.7.1.min.js b/public/javascripts/jquery-1.7.1.min.js deleted file mode 100644 index 198b3ff0..00000000 --- a/public/javascripts/jquery-1.7.1.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v1.7.1 jquery.com | jquery.org/license */ -(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"":"")+""),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;g=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
        a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="
        "+""+"
        ",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="
        t
        ",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="
        ",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; -f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&i.push({elem:this,matches:d.slice(e)});for(j=0;j0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

        ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
        ";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
        ","
        "],thead:[1,"","
        "],tr:[2,"","
        "],td:[3,"","
        "],col:[2,"","
        "],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
        ","
        "]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() -{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
        ").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-cz.js b/vendor/assets/javascripts/i18n/jquery.ui.datepicker-cz.js similarity index 100% rename from public/javascripts/i18n/jquery.ui.datepicker-cz.js rename to vendor/assets/javascripts/i18n/jquery.ui.datepicker-cz.js diff --git a/public/javascripts/i18n/jquery.ui.datepicker-de.js b/vendor/assets/javascripts/i18n/jquery.ui.datepicker-de.js similarity index 100% rename from public/javascripts/i18n/jquery.ui.datepicker-de.js rename to vendor/assets/javascripts/i18n/jquery.ui.datepicker-de.js diff --git a/public/javascripts/i18n/jquery.ui.datepicker-es.js b/vendor/assets/javascripts/i18n/jquery.ui.datepicker-es.js similarity index 100% rename from public/javascripts/i18n/jquery.ui.datepicker-es.js rename to vendor/assets/javascripts/i18n/jquery.ui.datepicker-es.js diff --git a/public/javascripts/i18n/jquery.ui.datepicker-fr.js b/vendor/assets/javascripts/i18n/jquery.ui.datepicker-fr.js similarity index 100% rename from public/javascripts/i18n/jquery.ui.datepicker-fr.js rename to vendor/assets/javascripts/i18n/jquery.ui.datepicker-fr.js diff --git a/public/javascripts/i18n/jquery.ui.datepicker-he.js b/vendor/assets/javascripts/i18n/jquery.ui.datepicker-he.js similarity index 100% rename from public/javascripts/i18n/jquery.ui.datepicker-he.js rename to vendor/assets/javascripts/i18n/jquery.ui.datepicker-he.js diff --git a/public/javascripts/i18n/jquery.ui.datepicker-nl.js b/vendor/assets/javascripts/i18n/jquery.ui.datepicker-nl.js similarity index 100% rename from public/javascripts/i18n/jquery.ui.datepicker-nl.js rename to vendor/assets/javascripts/i18n/jquery.ui.datepicker-nl.js diff --git a/public/javascripts/jquery-ui-1.8.17.custom.min.js b/vendor/assets/javascripts/jquery-ui-1.8.17.custom.min.js similarity index 100% rename from public/javascripts/jquery-ui-1.8.17.custom.min.js rename to vendor/assets/javascripts/jquery-ui-1.8.17.custom.min.js diff --git a/public/javascripts/jquery.blockUI.js b/vendor/assets/javascripts/jquery.blockUI.js similarity index 100% rename from public/javascripts/jquery.blockUI.js rename to vendor/assets/javascripts/jquery.blockUI.js diff --git a/public/javascripts/jquery.cookie.js b/vendor/assets/javascripts/jquery.cookie.js similarity index 100% rename from public/javascripts/jquery.cookie.js rename to vendor/assets/javascripts/jquery.cookie.js diff --git a/public/javascripts/jquery.form.js b/vendor/assets/javascripts/jquery.form.js similarity index 100% rename from public/javascripts/jquery.form.js rename to vendor/assets/javascripts/jquery.form.js diff --git a/public/javascripts/jquery.jeditable.mini.js b/vendor/assets/javascripts/jquery.jeditable.mini.js similarity index 100% rename from public/javascripts/jquery.jeditable.mini.js rename to vendor/assets/javascripts/jquery.jeditable.mini.js diff --git a/public/javascripts/jquery.simulate.drag-sortable.js b/vendor/assets/javascripts/jquery.simulate.drag-sortable.js similarity index 100% rename from public/javascripts/jquery.simulate.drag-sortable.js rename to vendor/assets/javascripts/jquery.simulate.drag-sortable.js diff --git a/public/javascripts/jquery.truncator.js b/vendor/assets/javascripts/jquery.truncator.js similarity index 100% rename from public/javascripts/jquery.truncator.js rename to vendor/assets/javascripts/jquery.truncator.js diff --git a/public/javascripts/niftycube.js b/vendor/assets/javascripts/niftycube.js similarity index 100% rename from public/javascripts/niftycube.js rename to vendor/assets/javascripts/niftycube.js diff --git a/public/javascripts/superfish.js b/vendor/assets/javascripts/superfish.js similarity index 100% rename from public/javascripts/superfish.js rename to vendor/assets/javascripts/superfish.js diff --git a/public/javascripts/supersubs.js b/vendor/assets/javascripts/supersubs.js similarity index 100% rename from public/javascripts/supersubs.js rename to vendor/assets/javascripts/supersubs.js diff --git a/public/javascripts/swfobject.js b/vendor/assets/javascripts/swfobject.js similarity index 100% rename from public/javascripts/swfobject.js rename to vendor/assets/javascripts/swfobject.js diff --git a/public/stylesheets/images/ui-bg_diagonals-medium_20_d34d17_40x40.png b/vendor/assets/stylesheets/images/ui-bg_diagonals-medium_20_d34d17_40x40.png similarity index 100% rename from public/stylesheets/images/ui-bg_diagonals-medium_20_d34d17_40x40.png rename to vendor/assets/stylesheets/images/ui-bg_diagonals-medium_20_d34d17_40x40.png diff --git a/public/stylesheets/images/ui-bg_flat_30_cccccc_40x100.png b/vendor/assets/stylesheets/images/ui-bg_flat_30_cccccc_40x100.png similarity index 100% rename from public/stylesheets/images/ui-bg_flat_30_cccccc_40x100.png rename to vendor/assets/stylesheets/images/ui-bg_flat_30_cccccc_40x100.png diff --git a/public/stylesheets/images/ui-bg_flat_50_5c5c5c_40x100.png b/vendor/assets/stylesheets/images/ui-bg_flat_50_5c5c5c_40x100.png similarity index 100% rename from public/stylesheets/images/ui-bg_flat_50_5c5c5c_40x100.png rename to vendor/assets/stylesheets/images/ui-bg_flat_50_5c5c5c_40x100.png diff --git a/public/stylesheets/images/ui-bg_gloss-wave_45_817865_500x100.png b/vendor/assets/stylesheets/images/ui-bg_gloss-wave_45_817865_500x100.png similarity index 100% rename from public/stylesheets/images/ui-bg_gloss-wave_45_817865_500x100.png rename to vendor/assets/stylesheets/images/ui-bg_gloss-wave_45_817865_500x100.png diff --git a/public/stylesheets/images/ui-bg_gloss-wave_60_fece2f_500x100.png b/vendor/assets/stylesheets/images/ui-bg_gloss-wave_60_fece2f_500x100.png similarity index 100% rename from public/stylesheets/images/ui-bg_gloss-wave_60_fece2f_500x100.png rename to vendor/assets/stylesheets/images/ui-bg_gloss-wave_60_fece2f_500x100.png diff --git a/public/stylesheets/images/ui-bg_gloss-wave_70_ffdd57_500x100.png b/vendor/assets/stylesheets/images/ui-bg_gloss-wave_70_ffdd57_500x100.png similarity index 100% rename from public/stylesheets/images/ui-bg_gloss-wave_70_ffdd57_500x100.png rename to vendor/assets/stylesheets/images/ui-bg_gloss-wave_70_ffdd57_500x100.png diff --git a/public/stylesheets/images/ui-bg_gloss-wave_90_fff9e5_500x100.png b/vendor/assets/stylesheets/images/ui-bg_gloss-wave_90_fff9e5_500x100.png similarity index 100% rename from public/stylesheets/images/ui-bg_gloss-wave_90_fff9e5_500x100.png rename to vendor/assets/stylesheets/images/ui-bg_gloss-wave_90_fff9e5_500x100.png diff --git a/public/stylesheets/images/ui-bg_highlight-soft_100_feeebd_1x100.png b/vendor/assets/stylesheets/images/ui-bg_highlight-soft_100_feeebd_1x100.png similarity index 100% rename from public/stylesheets/images/ui-bg_highlight-soft_100_feeebd_1x100.png rename to vendor/assets/stylesheets/images/ui-bg_highlight-soft_100_feeebd_1x100.png diff --git a/public/stylesheets/images/ui-bg_inset-soft_30_ffffff_1x100.png b/vendor/assets/stylesheets/images/ui-bg_inset-soft_30_ffffff_1x100.png similarity index 100% rename from public/stylesheets/images/ui-bg_inset-soft_30_ffffff_1x100.png rename to vendor/assets/stylesheets/images/ui-bg_inset-soft_30_ffffff_1x100.png diff --git a/public/stylesheets/images/ui-icons_3d3d3d_256x240.png b/vendor/assets/stylesheets/images/ui-icons_3d3d3d_256x240.png similarity index 100% rename from public/stylesheets/images/ui-icons_3d3d3d_256x240.png rename to vendor/assets/stylesheets/images/ui-icons_3d3d3d_256x240.png diff --git a/public/stylesheets/images/ui-icons_bd7b00_256x240.png b/vendor/assets/stylesheets/images/ui-icons_bd7b00_256x240.png similarity index 100% rename from public/stylesheets/images/ui-icons_bd7b00_256x240.png rename to vendor/assets/stylesheets/images/ui-icons_bd7b00_256x240.png diff --git a/public/stylesheets/images/ui-icons_d19405_256x240.png b/vendor/assets/stylesheets/images/ui-icons_d19405_256x240.png similarity index 100% rename from public/stylesheets/images/ui-icons_d19405_256x240.png rename to vendor/assets/stylesheets/images/ui-icons_d19405_256x240.png diff --git a/public/stylesheets/images/ui-icons_eb990f_256x240.png b/vendor/assets/stylesheets/images/ui-icons_eb990f_256x240.png similarity index 100% rename from public/stylesheets/images/ui-icons_eb990f_256x240.png rename to vendor/assets/stylesheets/images/ui-icons_eb990f_256x240.png diff --git a/public/stylesheets/images/ui-icons_ed9f26_256x240.png b/vendor/assets/stylesheets/images/ui-icons_ed9f26_256x240.png similarity index 100% rename from public/stylesheets/images/ui-icons_ed9f26_256x240.png rename to vendor/assets/stylesheets/images/ui-icons_ed9f26_256x240.png diff --git a/public/stylesheets/images/ui-icons_fadc7a_256x240.png b/vendor/assets/stylesheets/images/ui-icons_fadc7a_256x240.png similarity index 100% rename from public/stylesheets/images/ui-icons_fadc7a_256x240.png rename to vendor/assets/stylesheets/images/ui-icons_fadc7a_256x240.png diff --git a/public/stylesheets/images/ui-icons_ffe180_256x240.png b/vendor/assets/stylesheets/images/ui-icons_ffe180_256x240.png similarity index 100% rename from public/stylesheets/images/ui-icons_ffe180_256x240.png rename to vendor/assets/stylesheets/images/ui-icons_ffe180_256x240.png diff --git a/public/stylesheets/jquery-ui-1.8.17.custom.css b/vendor/assets/stylesheets/jquery-ui-1.8.17.custom.css similarity index 100% rename from public/stylesheets/jquery-ui-1.8.17.custom.css rename to vendor/assets/stylesheets/jquery-ui-1.8.17.custom.css diff --git a/public/stylesheets/niftyCorners.css b/vendor/assets/stylesheets/niftyCorners.css similarity index 100% rename from public/stylesheets/niftyCorners.css rename to vendor/assets/stylesheets/niftyCorners.css diff --git a/public/stylesheets/superfish-navbar.css b/vendor/assets/stylesheets/superfish-navbar.css similarity index 100% rename from public/stylesheets/superfish-navbar.css rename to vendor/assets/stylesheets/superfish-navbar.css diff --git a/public/stylesheets/superfish-vertical.css b/vendor/assets/stylesheets/superfish-vertical.css similarity index 100% rename from public/stylesheets/superfish-vertical.css rename to vendor/assets/stylesheets/superfish-vertical.css diff --git a/public/stylesheets/superfish.css b/vendor/assets/stylesheets/superfish.css similarity index 100% rename from public/stylesheets/superfish.css rename to vendor/assets/stylesheets/superfish.css diff --git a/public/swfs/expressInstall.swf b/vendor/assets/swfs/expressInstall.swf similarity index 100% rename from public/swfs/expressInstall.swf rename to vendor/assets/swfs/expressInstall.swf diff --git a/public/swfs/open-flash-chart.swf b/vendor/assets/swfs/open-flash-chart.swf similarity index 100% rename from public/swfs/open-flash-chart.swf rename to vendor/assets/swfs/open-flash-chart.swf From fd4fb6df9e617f8c7e5fb38073a4f02077585ef5 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Tue, 17 Apr 2012 16:47:37 +0200 Subject: [PATCH 106/134] get all unit tests running again. Seems we have some pretty old code in there :-) --- app/controllers/login_controller.rb | 1 - app/controllers/users_controller.rb | 2 +- app/models/context.rb | 3 - app/models/message_gateway.rb | 13 +- app/models/tag.rb | 4 + app/models/tagging.rb | 8 +- app/models/todo.rb | 29 ++-- app/models/user.rb | 52 ++----- config/environment.rb | 2 +- config/initializers/wrap_parameters.rb | 2 +- config/locales/en.yml | 6 +- .../message_gateway_test.rb | 6 +- test/test_helper.rb | 43 ++++++ test/unit/context_test.rb | 53 ++----- test/unit/project_test.rb | 131 +++++++----------- test/unit/recurring_todo_test.rb | 45 +++--- test/unit/todo_create_params_helper_test.rb | 56 ++++---- test/unit/todo_test.rb | 36 +++-- test/unit/user_test.rb | 47 +++---- 19 files changed, 255 insertions(+), 284 deletions(-) rename test/{unit => functional}/message_gateway_test.rb (92%) diff --git a/app/controllers/login_controller.rb b/app/controllers/login_controller.rb index fed1dc3a..9aa3b83e 100644 --- a/app/controllers/login_controller.rb +++ b/app/controllers/login_controller.rb @@ -1,7 +1,6 @@ class LoginController < ApplicationController layout 'login' - filter_parameter_logging :user_password skip_before_filter :set_session_expiration skip_before_filter :login_required before_filter :login_optional diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 77a9984a..f14ef68f 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,5 +1,5 @@ class UsersController < ApplicationController - filter_parameter_logging "password" + before_filter :admin_login_required, :only => [ :index, :show, :destroy ] skip_before_filter :login_required, :only => [ :new, :create ] skip_before_filter :check_for_deprecated_password_hash, diff --git a/app/models/context.rb b/app/models/context.rb index ee97a134..35adab3e 100644 --- a/app/models/context.rb +++ b/app/models/context.rb @@ -9,15 +9,12 @@ class Context < ActiveRecord::Base scope :hidden, :conditions => { :hide => true } acts_as_list :scope => :user, :top_of_list => 0 - # extend NamePartFinder - # include Tracks::TodoList 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 comma (',') character" def self.feed_options(user) # TODO: move to view or helper diff --git a/app/models/message_gateway.rb b/app/models/message_gateway.rb index af67a782..69a924b8 100644 --- a/app/models/message_gateway.rb +++ b/app/models/message_gateway.rb @@ -1,8 +1,9 @@ class MessageGateway < ActionMailer::Base - include ActionView::Helpers::SanitizeHelper - extend ActionView::Helpers::SanitizeHelper::ClassMethods + # include ActionView::Helpers::SanitizeHelper + # extend ActionView::Helpers::SanitizeHelper::ClassMethods def receive(email) + puts "email = #{email}" address = '' if SITE_CONFIG['email_dispatch'] == 'to' address = email.to[0] @@ -10,9 +11,9 @@ class MessageGateway < ActionMailer::Base address = email.from[0] end - user = User.find(:first, :include => [:preference], :conditions => ["preferences.sms_email = ?", address.strip]) + user = User.where("preferences.sms_email" => address.strip).first(:include => [:preference]) if user.nil? - user = User.find(:first, :include => [:preference], :conditions => ["preferences.sms_email = ?", address.strip[1,100]]) + user = User.where("preferences.sms_email" => address.strip[1.100]).first(:include => [:preference]) end return if user.nil? context = user.prefs.sms_context @@ -25,7 +26,7 @@ class MessageGateway < ActionMailer::Base body_part = email.parts.find{|m| m.content_type == "text/plain"} notes = sanitize body_part.body.strip else - if email.subject.empty? + if email.subject && email.subject.blank? description = sanitize email.body.strip notes = nil else @@ -35,7 +36,7 @@ class MessageGateway < ActionMailer::Base end # stupid T-Mobile often sends the same message multiple times - return if user.todos.find(:first, :conditions => {:description => description}) + return if user.todos.where(:description => description).first todo = Todo.from_rich_message(user, context.id, description, notes) todo.save! diff --git a/app/models/tag.rb b/app/models/tag.rb index bb39407a..92bdaa20 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -11,6 +11,10 @@ class Tag < ActiveRecord::Base validates_presence_of :name validates_uniqueness_of :name, :case_sensitive => false + attr_accessible :name + + before_create :before_create + # Callback to strip extra spaces from the tagname before saving it. If you # allow tags to be renamed later, you might want to use the # before_save callback instead. diff --git a/app/models/tagging.rb b/app/models/tagging.rb index 46291f6a..95e14516 100644 --- a/app/models/tagging.rb +++ b/app/models/tagging.rb @@ -2,12 +2,18 @@ # The Tagging join model. class Tagging < ActiveRecord::Base + + attr_accessible :taggable_id, :tag belongs_to :tag belongs_to :taggable, :polymorphic => true + + after_destroy :after_destroy + + private # This callback makes sure that an orphaned Tag is deleted if it no longer tags anything. def after_destroy - tag.destroy_without_callbacks if tag and tag.taggings.count == 0 + tag.destroy if tag and tag.taggings.count == 0 end end diff --git a/app/models/todo.rb b/app/models/todo.rb index 75f1fef4..ea2297ea 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -104,7 +104,23 @@ class Todo < ActiveRecord::Base validates_length_of :notes, :maximum => 60000, :allow_nil => true validates_presence_of :show_from, :if => :deferred? validates_presence_of :context + validate :check_show_from_in_future + validate :check_circular_dependencies + def check_show_from_in_future + if !show_from.blank? && show_from < user.date + errors.add("show_from", I18n.t('models.todo.error_date_must_be_future')) + end + end + + def check_circular_dependencies + unless @predecessor_array.nil? # Only validate predecessors if they changed + @predecessor_array.each do |todo| + errors.add("Depends on:", "Adding '#{todo.specification}' would create a circular dependency") if is_successor?(todo) + end + end + end + def initialize(*args) super(*args) @predecessor_array = nil # Used for deferred save of predecessors @@ -121,7 +137,7 @@ class Todo < ActiveRecord::Base end def uncompleted_predecessors? - return !uncompleted_predecessors.all(true).empty? + return !uncompleted_predecessors.all.empty? end # Returns a string with description @@ -130,17 +146,6 @@ class Todo < ActiveRecord::Base return "\'#{self.description}\' <\'#{self.context.title}\'; \'#{project_name}\'>" end - def validate - if !show_from.blank? && show_from < user.date - errors.add("show_from", I18n.t('models.todo.error_date_must_be_future')) - end - unless @predecessor_array.nil? # Only validate predecessors if they changed - @predecessor_array.each do |todo| - errors.add("Depends on:", "Adding '#{h(todo.specification)}' would create a circular dependency") if is_successor?(todo) - end - end - end - def save_predecessors unless @predecessor_array.nil? # Only save predecessors if they changed current_array = self.predecessors diff --git a/app/models/user.rb b/app/models/user.rb index 2dcaf367..4db04e0a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -9,9 +9,9 @@ class User < ActiveRecord::Base has_many :contexts, :order => 'position ASC', :dependent => :delete_all do - # def find_by_params(params) - # find(params['id'] || params['context_id']) || nil - # end + def find_by_params(params) + find(params['id'] || params['context_id']) || nil + end def update_positions(context_ids) context_ids.each_with_index {|id, position| context = self.detect { |c| c.id == id.to_i } @@ -23,9 +23,9 @@ class User < ActiveRecord::Base has_many :projects, :order => 'projects.position ASC', :dependent => :delete_all do - # def find_by_params(params) - # find(params['id'] || params['project_id']) - # end + def find_by_params(params) + find(params['id'] || params['project_id']) + end def update_positions(project_ids) project_ids.each_with_index {|id, position| project = self.detect { |p| p.id == id.to_i } @@ -100,17 +100,16 @@ class User < ActiveRecord::Base validates_confirmation_of :password validates_length_of :login, :within => 3..80 validates_uniqueness_of :login, :on => :create - # validates_presence_of :open_id_url, :if => :using_openid? + validate :validate_auth_type before_create :crypt_password, :generate_token before_update :crypt_password - # before_save :normalize_open_id_url #for will_paginate plugin cattr_accessor :per_page @@per_page = 5 - def validate + def validate_auth_type unless Tracks::Config.auth_schemes.include?(auth_type) errors.add("auth_type", "not a valid authentication type (#{auth_type})") end @@ -137,25 +136,15 @@ class User < ActiveRecord::Base return candidate if candidate.auth_type.eql?("cas") end - if Tracks::Config.auth_schemes.include?('open_id') - # hope the user enters the correct data - return candidate if candidate.auth_type.eql?("open_id") - end - return nil end - # def self.find_by_open_id_url(raw_identity_url) - # normalized_open_id_url = OpenIdAuthentication.normalize_identifier(raw_identity_url) - # find(:first, :conditions => ['open_id_url = ?', normalized_open_id_url]) - # end - def self.no_users_yet? count == 0 end def self.find_admin - find(:first, :conditions => [ "is_admin = ?", true ]) + where(:is_admin => true).first end def to_param @@ -230,37 +219,22 @@ class User < ActiveRecord::Base end def sha1(s) - Digest::SHA1.hexdigest salted s + Digest::SHA1.hexdigest(salted(s)) end - def hash(s) - BCrypt::Password.create s + def create_hash(s) + BCrypt::Password.create(s) end protected def crypt_password return if password.blank? - write_attribute("crypted_password", hash(password)) if password == password_confirmation + write_attribute("crypted_password", self.create_hash(password)) if password == password_confirmation end def password_required? auth_type == 'database' && crypted_password.blank? || !password.blank? end - # def using_openid? - # auth_type == 'open_id' - # end - # - # def normalize_open_id_url - # return if open_id_url.nil? - # - # # fixup empty url value - # if open_id_url.empty? - # self.open_id_url = nil - # return - # end - # - # self.open_id_url = OpenIdAuthentication.normalize_identifier(open_id_url) - # end end diff --git a/config/environment.rb b/config/environment.rb index 8e8e1fdb..6f9bda48 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -2,4 +2,4 @@ require File.expand_path('../application', __FILE__) # Initialize the rails application -Tracksapp::Application.initialize! +Tracksapp::Application.initialize! \ No newline at end of file diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb index 999df201..c948e063 100644 --- a/config/initializers/wrap_parameters.rb +++ b/config/initializers/wrap_parameters.rb @@ -5,7 +5,7 @@ # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. ActiveSupport.on_load(:action_controller) do - wrap_parameters format: [:json] + wrap_parameters(:format => [:json]) end # Disable root element in JSON by default. diff --git a/config/locales/en.yml b/config/locales/en.yml index 429368a5..e23261df 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -136,9 +136,9 @@ en: next: Next todo: todo note: - zero: no notes - one: 1 note - other: %{count} notes + zero: "no notes" + one: "1 note" + other: "%{count} notes" context: Context drag_handle: DRAG description: Description diff --git a/test/unit/message_gateway_test.rb b/test/functional/message_gateway_test.rb similarity index 92% rename from test/unit/message_gateway_test.rb rename to test/functional/message_gateway_test.rb index 7f94cb4e..6e7c3e3e 100644 --- a/test/unit/message_gateway_test.rb +++ b/test/functional/message_gateway_test.rb @@ -9,7 +9,7 @@ class MessageGatewayTest < ActiveSupport::TestCase end def load_message(filename) - MessageGateway.receive(File.read(File.join(RAILS_ROOT, 'test', 'fixtures', filename))) + MessageGateway.receive(File.read(File.join(Rails.root, 'test', 'fixtures', filename))) end def test_sms_with_no_subject @@ -51,14 +51,14 @@ class MessageGatewayTest < ActiveSupport::TestCase def test_no_user todo_count = Todo.count - badmessage = File.read(File.join(RAILS_ROOT, 'test', 'fixtures', 'sample_sms.txt')) + badmessage = File.read(File.join(Rails.root, 'test', 'fixtures', 'sample_sms.txt')) badmessage.gsub!("5555555555", "notauser") MessageGateway.receive(badmessage) assert_equal(todo_count, Todo.count) end def test_direct_to_context - message = File.read(File.join(RAILS_ROOT, 'test', 'fixtures', 'sample_sms.txt')) + message = File.read(File.join(Rails.root, 'test', 'fixtures', 'sample_sms.txt')) valid_context_msg = message.gsub('message_content', 'this is a task @ anothercontext') invalid_context_msg = message.gsub('message_content', 'this is also a task @ notacontext') diff --git a/test/test_helper.rb b/test/test_helper.rb index 8bf1192f..75ec7e1c 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -11,3 +11,46 @@ class ActiveSupport::TestCase # Add more helper methods to be used by all tests here... end + +module Tracks + class Config + def self.salt + "change-me" + end + def self.auth_schemes + return ["database","open_id"] + end + end +end + +class ActiveSupport::TestCase + + # Generates a random string of ascii characters (a-z, "1 0") + # of a given length for testing assignment to fields + # for validation purposes + # + def generate_random_string(length) + string = "" + characters = %w(a b c d e f g h i j k l m n o p q r s t u v w z y z 1\ 0) + length.times do + pick = characters[rand(26)] + string << pick + end + return string + end + + def assert_equal_dmy(date1, date2) + assert_equal date1.strftime("%d-%m-%y"), date2.strftime("%d-%m-%y") + end + +end + +class Test::Unit::TestCase + + def assert_value_changed(object, method = nil) + initial_value = object.send(method) + yield + assert_not_equal initial_value, object.send(method), "#{object}##{method}" + end + +end diff --git a/test/unit/context_test.rb b/test/unit/context_test.rb index 644bf63c..dc5f2559 100644 --- a/test/unit/context_test.rb +++ b/test/unit/context_test.rb @@ -9,18 +9,23 @@ class ContextTest < ActiveSupport::TestCase @library = contexts(:library) end + def test_uses_acts_as_list + # only check that acts_as_list is present in the model + assert @agenda.respond_to?(:move_to_bottom) + end + def test_validate_presence_of_name @agenda.name = "" assert !@agenda.save assert_equal 1, @agenda.errors.count - assert_equal "context must have a name", @agenda.errors.on(:name) + assert_equal "context must have a name", @agenda.errors[:name][0] end def test_validate_name_is_less_than_256 - @agenda.name = "a"*256 + @agenda.name = generate_random_string(256) assert !@agenda.save assert_equal 1, @agenda.errors.count - assert_equal "context name must be less than 256 characters", @agenda.errors.on(:name) + assert_equal "context name must be less than 256 characters", @agenda.errors[:name][0] end def test_validate_name_is_unique @@ -29,29 +34,9 @@ class ContextTest < ActiveSupport::TestCase newcontext.user_id = contexts(:agenda).user_id assert !newcontext.save assert_equal 1, newcontext.errors.count - assert_equal "already exists", newcontext.errors.on(:name) + assert_equal "already exists", newcontext.errors[:name][0] end - - def test_validate_name_does_not_contain_comma - newcontext = Context.new - newcontext.name = "phone,telegraph" - assert !newcontext.save - assert_equal 1, newcontext.errors.count - assert_equal "cannot contain the comma (',') character", newcontext.errors.on(:name) - end - - def test_find_by_namepart_with_exact_match - c = Context.find_by_namepart('agenda') - assert_not_nil c - assert_equal @agenda.id, c.id - end - - def test_find_by_namepart_with_starts_with - c = Context.find_by_namepart('agen') - assert_not_nil c - assert_equal @agenda.id, c.id - end - + def test_delete_context_deletes_todos_within_it assert_equal 7, @agenda.todos.count agenda_todo_ids = @agenda.todos.collect{|t| t.id } @@ -60,23 +45,7 @@ class ContextTest < ActiveSupport::TestCase assert !Todo.exists?(todo_id) end end - - def test_not_done_todos - assert_equal 6, @agenda.not_done_todos.size - t = @agenda.not_done_todos[0] - t.complete! - t.save! - assert_equal 5, Context.find(@agenda.id).not_done_todos.size - end - - def test_done_todos - assert_equal 1, @agenda.done_todos.size - t = @agenda.not_done_todos[0] - t.complete! - t.save! - assert_equal 2, Context.find(@agenda.id).done_todos.size - end - + def test_to_param_returns_id assert_equal '1', @agenda.to_param end diff --git a/test/unit/project_test.rb b/test/unit/project_test.rb index 51179b31..b8570b16 100644 --- a/test/unit/project_test.rb +++ b/test/unit/project_test.rb @@ -8,18 +8,32 @@ class ProjectTest < ActiveSupport::TestCase @moremoney = projects(:moremoney) end + # associations + + def test_has_default_context + assert !@timemachine.default_context.nil? + assert @timemachine.default_context.name == contexts(:lab).name + + p = Project.new + assert_equal '', p.default_context.name + p.default_context = contexts(:agenda) + assert_equal 'agenda', p.default_context.name + end + + # validations + def test_validate_presence_of_name @timemachine.name = "" assert !@timemachine.save assert_equal 1, @timemachine.errors.count - assert_equal "project must have a name", @timemachine.errors.on(:name) + assert_equal "project must have a name", @timemachine.errors[:name][0] end def test_validate_name_is_less_than_256 - @timemachine.name = "a"*256 + @timemachine.name = generate_random_string(256) assert !@timemachine.save assert_equal 1, @timemachine.errors.count - assert_equal "project name must be less than 256 characters", @timemachine.errors.on(:name) + assert_equal "project name must be less than 256 characters", @timemachine.errors[:name][0] end def test_validate_name_is_unique @@ -28,29 +42,10 @@ class ProjectTest < ActiveSupport::TestCase newproj.user_id = projects(:timemachine).user_id assert !newproj.save assert_equal 1, newproj.errors.count - assert_equal "already exists", newproj.errors.on(:name) - end - - def test_validate_name_can_contain_comma - newproj = Project.new - newproj.name = "Buy iPhones for Luke,bsag,David Allen" - assert newproj.save - assert_equal 0, newproj.errors.count - assert_equal "Buy iPhones for Luke,bsag,David Allen", newproj.name - end - - def test_name_removes_extra_spaces - newproj = Project.new - newproj.name = "These Words Have Proximity Issues " - assert newproj.save - assert_equal 0, newproj.errors.count - assert_equal "These Words Have Proximity Issues", newproj.name - - # and on update... - @timemachine.name = " a time machine needs lots of spaaaaaaace " - assert @timemachine.save - assert_equal "a time machine needs lots of spaaaaaaace", @timemachine.name + assert_equal "already exists", newproj.errors[:name][0] end + + # state machine def test_project_initial_state_is_active assert_equal :active, @timemachine.aasm_current_state @@ -69,6 +64,24 @@ class ProjectTest < ActiveSupport::TestCase assert @timemachine.active? end + def test_transition_to_another_state + assert_equal :active, @timemachine.aasm_current_state + @timemachine.transition_to(:hidden) + assert_equal :hidden, @timemachine.aasm_current_state + @timemachine.transition_to(:completed) + assert_equal :completed, @timemachine.aasm_current_state + @timemachine.transition_to(:active) + assert_equal :active, @timemachine.aasm_current_state + end + + def test_transition_to_same_state + assert_equal :active, @timemachine.aasm_current_state + @timemachine.transition_to(:active) + assert_equal :active, @timemachine.aasm_current_state + end + + # other tests + def test_review_project assert_nil @timemachine.last_reviewed assert @timemachine.needs_review?(nil) @@ -88,43 +101,15 @@ class ProjectTest < ActiveSupport::TestCase assert_in_delta Time.now, @timemachine.completed_at, 1 end - def test_find_project_by_namepart_with_exact_match - p = Project.find_by_namepart('Build a working time machine') - assert_not_nil p - assert_equal @timemachine.id, p.id - end - - def test_find_project_by_namepart_with_starts_with - p = Project.find_by_namepart('Build a') - assert_not_nil p - assert_equal @timemachine.id, p.id - end - def test_delete_project_deletes_todos_within_it assert_equal 3, @timemachine.todos.count timemachine_todo_ids = @timemachine.todos.map{ |t| t.id } @timemachine.destroy timemachine_todo_ids.each do |t_id| - assert !Todo.exists?(t_id) + assert !Todo.exists?(t_id) end end - def test_not_done_todos - assert_equal 3, @timemachine.todos.not_completed.size - t = @timemachine.todos.not_completed[0] - t.complete! - t.save! - assert_equal 2, Project.find(@timemachine.id).todos.not_completed.size - end - - def test_done_todos - assert_equal 0, @timemachine.todos.completed.size - t = @timemachine.todos.not_completed[0] - t.complete! - t.save! - assert_equal 1, Project.find(@timemachine.id).todos.completed.size - end - def test_deferred_todos assert_equal 1, @timemachine.todos.deferred.size t = @timemachine.todos.not_completed[0] @@ -149,29 +134,26 @@ class ProjectTest < ActiveSupport::TestCase assert_equal 'Tracks Projects', opts[:title], 'Unexpected value for :title key of feed_options' assert_equal 'Lists all the projects for Admin Schmadmin', opts[:description], 'Unexpected value for :description key of feed_options' end - - def test_transition_to_another_state - assert_equal :active, @timemachine.aasm_current_state - @timemachine.transition_to(:hidden) - assert_equal :hidden, @timemachine.aasm_current_state - @timemachine.transition_to(:completed) - assert_equal :completed, @timemachine.aasm_current_state - @timemachine.transition_to(:active) - assert_equal :active, @timemachine.aasm_current_state + + def test_name_removes_extra_spaces + newproj = Project.new + newproj.name = "These Words Have Proximity Issues " + assert newproj.save + assert_equal 0, newproj.errors.count + assert_equal "These Words Have Proximity Issues", newproj.name + + # and on update... + @timemachine.name = " a time machine needs lots of spaaaaaaace " + assert @timemachine.save + assert_equal "a time machine needs lots of spaaaaaaace", @timemachine.name end - - def test_transition_to_same_state - assert_equal :active, @timemachine.aasm_current_state - @timemachine.transition_to(:active) - assert_equal :active, @timemachine.aasm_current_state - end - + def test_deferred_todo_count assert_equal 1, @timemachine.todos.deferred.count assert_equal 0, @moremoney.todos.deferred.count first_todo = @moremoney.todos[0] - first_todo.show_from = next_week + first_todo.show_from = Time.zone.now + 1.week assert_equal :deferred, @moremoney.todos[0].aasm_current_state assert_equal 1, @moremoney.todos.deferred.count @@ -191,11 +173,4 @@ class ProjectTest < ActiveSupport::TestCase assert_equal 3, @moremoney.todos.not_completed.count end - def test_default_context_name - p = Project.new - assert_equal '', p.default_context.name - p.default_context = contexts(:agenda) - assert_equal 'agenda', p.default_context.name - end - end diff --git a/test/unit/recurring_todo_test.rb b/test/unit/recurring_todo_test.rb index b82bc59e..e01c86c7 100644 --- a/test/unit/recurring_todo_test.rb +++ b/test/unit/recurring_todo_test.rb @@ -1,18 +1,17 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') class RecurringTodoTest < ActiveSupport::TestCase - fixtures :todos, :users, :contexts, :preferences, :tags, :taggings, :recurring_todos def setup - @every_day = RecurringTodo.find(1).reload - @every_workday = RecurringTodo.find(2).reload - @weekly_every_day = RecurringTodo.find(3).reload - @monthly_every_last_friday = RecurringTodo.find(4).reload - @yearly = RecurringTodo.find(5).reload + @every_day = recurring_todos(:call_bill_gates_every_day) + @every_workday = recurring_todos(:call_bill_gates_every_workday) + @weekly_every_day = recurring_todos(:call_bill_gates_every_week) + @monthly_every_last_friday = recurring_todos(:check_with_bill_every_last_friday_of_month) + @yearly = recurring_todos(:birthday_reinier) @today = Time.now.utc @tomorrow = @today + 1.day - @in_three_days = Time.now.utc + 3.days + @in_three_days = @today + 3.days @in_four_days = @in_three_days + 1.day # need a day after start_from @friday = Time.zone.local(2008,6,6) @@ -34,8 +33,8 @@ class RecurringTodoTest < ActiveSupport::TestCase def test_daily_every_day # every_day should return todays date if there was no previous date due_date = @every_day.get_due_date(nil) - # use strftime in compare, because milisec / secs could be different - assert_equal @today.strftime("%d-%m-%y"), due_date.strftime("%d-%m-%y") + # use only day-month-year compare, because milisec / secs could be different + assert_equal_dmy @today, due_date # when the last todo was completed today, the next todo is due tomorrow due_date =@every_day.get_due_date(@today) @@ -44,13 +43,13 @@ class RecurringTodoTest < ActiveSupport::TestCase # do something every 14 days @every_day.every_other1=14 due_date = @every_day.get_due_date(@today) - assert_equal @today+14.days, due_date + assert_equal @today+14.days, due_date end def test_daily_work_days - assert_equal @monday, @every_workday.get_due_date(@friday) - assert_equal @monday, @every_workday.get_due_date(@saturday) - assert_equal @monday, @every_workday.get_due_date(@sunday) + assert_equal @monday, @every_workday.get_due_date(@friday) + assert_equal @monday, @every_workday.get_due_date(@saturday) + assert_equal @monday, @every_workday.get_due_date(@sunday) assert_equal @tuesday, @every_workday.get_due_date(@monday) end @@ -63,7 +62,7 @@ class RecurringTodoTest < ActiveSupport::TestCase assert_equal nil, @every_day.get_due_date(@today-3.days) # check show from get the next day - assert_equal @today, @every_day.get_show_from_date(@today-1.days) + assert_equal_dmy @today, @every_day.get_show_from_date(@today-1.days) assert_equal @today+1.day, @every_day.get_show_from_date(@today) @every_day.target='due_date' @@ -73,7 +72,7 @@ class RecurringTodoTest < ActiveSupport::TestCase @every_day.show_always = false @every_day.show_from_delta=10 - assert_equal @today, @every_day.get_show_from_date(@today+9.days) #today+1+9-10 + assert_equal_dmy @today, @every_day.get_show_from_date(@today+9.days) #today+1+9-10 # when show_from is 0, show_from is the same day it's due @every_day.show_from_delta=0 @@ -140,9 +139,9 @@ class RecurringTodoTest < ActiveSupport::TestCase @weekly_every_day.every_other1 = 1 @weekly_every_day.every_day = ' tw ' due_date = @weekly_every_day.get_due_date(@tuesday) - assert_equal @wednesday, due_date + assert_equal @wednesday, due_date due_date = @weekly_every_day.get_due_date(@wednesday) - assert_equal @tuesday+1.week, due_date + assert_equal @tuesday+1.week, due_date @weekly_every_day.every_day = ' s' due_date = @weekly_every_day.get_due_date(@sunday) @@ -180,7 +179,7 @@ class RecurringTodoTest < ActiveSupport::TestCase def test_yearly_pattern # beginning of same year due_date = @yearly.get_due_date(Time.zone.local(2008,2,10)) # feb 10th - assert_equal @sunday, due_date # june 8th + assert_equal @sunday, due_date # june 8th # same month, previous date due_date = @yearly.get_due_date(@saturday) # june 7th @@ -195,7 +194,7 @@ class RecurringTodoTest < ActiveSupport::TestCase due_date = @yearly.get_due_date(@monday+5.months-2.days) # november 7 assert_equal Time.zone.local(2009,6,8), due_date # june 8th next year - @yearly.recurrence_selector = 1 + @yearly.recurrence_selector = 1 @yearly.every_other3 = 2 # second @yearly.every_count = 3 # wednesday # beginning of same year @@ -213,7 +212,7 @@ class RecurringTodoTest < ActiveSupport::TestCase # test handling of nil as previous # # start_from is way_back - due_date1 = @yearly.get_due_date(nil) + due_date1 = @yearly.get_due_date(nil) due_date2 = @yearly.get_due_date(Time.now.utc + 1.day) assert_equal due_date1, due_date2 @@ -250,7 +249,7 @@ class RecurringTodoTest < ActiveSupport::TestCase # if we give a date in the future for the previous todo, the next to do # should be based on that future date. due_date = @every_day.get_due_date(@in_four_days) - assert_equal @in_four_days+1.day, due_date + assert_equal @in_four_days+1.day, due_date @weekly_every_day.start_from = Time.zone.local(2020,1,1) assert_equal Time.zone.local(2020,1,1), @weekly_every_day.get_due_date(nil) @@ -270,7 +269,7 @@ class RecurringTodoTest < ActiveSupport::TestCase this_year = Time.now.utc.year @yearly.start_from = Time.zone.local(this_year+1,6,12) - due_date = @yearly.get_due_date(nil) + due_date = @yearly.get_due_date(nil) assert_equal due_date.year, this_year+2 end @@ -308,7 +307,7 @@ class RecurringTodoTest < ActiveSupport::TestCase @every_day.inc_occurences assert_equal true, @every_day.has_next_todo(@in_three_days) @every_day.inc_occurences - assert_equal false, @every_day.has_next_todo(@in_three_days) + assert_equal false, @every_day.has_next_todo(@in_three_days) # after completion, when you reactivate the recurring todo, the occurences # count should be reset diff --git a/test/unit/todo_create_params_helper_test.rb b/test/unit/todo_create_params_helper_test.rb index 4aecff69..7b981b88 100644 --- a/test/unit/todo_create_params_helper_test.rb +++ b/test/unit/todo_create_params_helper_test.rb @@ -5,14 +5,14 @@ class TodoCreateParamsHelperTest < ActiveSupport::TestCase def test_works_with_request_as_root_hash_entry params = {'request' => { 'todo' => { 'description' => 'foo'}}} - prefs = flexmock() + prefs = users(:admin_user).prefs params_helper = TodosController::TodoCreateParamsHelper.new(params, prefs) assert_equal({'description' => 'foo'}, params_helper.attributes) end def test_works_with_todo_as_root_hash_entry params = { 'todo' => { 'description' => 'foo'}} - prefs = flexmock() + prefs = users(:admin_user).prefs params_helper = TodosController::TodoCreateParamsHelper.new(params, prefs) assert_equal({'description' => 'foo'}, params_helper.attributes) end @@ -20,7 +20,7 @@ class TodoCreateParamsHelperTest < ActiveSupport::TestCase def test_show_from_accessor expected_date = Time.now params = { 'todo' => { 'show_from' => expected_date}} - prefs = flexmock() + prefs = users(:admin_user).prefs params_helper = TodosController::TodoCreateParamsHelper.new(params, prefs) assert_equal(expected_date, params_helper.show_from) end @@ -28,43 +28,43 @@ class TodoCreateParamsHelperTest < ActiveSupport::TestCase def test_due_accessor expected_date = Time.now params = { 'todo' => { 'due' => expected_date}} - prefs = flexmock() + prefs = users(:admin_user).prefs params_helper = TodosController::TodoCreateParamsHelper.new(params, prefs) assert_equal(expected_date, params_helper.due) end def test_tag_list_accessor params = { 'todo' => { }, 'todo_tag_list' => 'foo, bar'} - prefs = flexmock() + prefs = users(:admin_user).prefs params_helper = TodosController::TodoCreateParamsHelper.new(params, prefs) assert_equal('foo, bar', params_helper.tag_list) end def test_parse_dates_parses_show_from_date_based_on_prefs - params = { 'todo' => { 'show_from' => '5/20/07', 'due' => '5/23/07'}} - prefs = flexmock() - prefs.should_receive(:parse_date).with('5/20/07').and_return(Date.new(2007, 5, 20)) - prefs.should_receive(:parse_date).with('5/23/07').and_return(Date.new(2007, 5, 23)) + params = { 'todo' => { 'show_from' => '20/05/07', 'due' => '23/5/07'}} + + prefs = users(:admin_user).prefs + prefs.date_format = "%d/%m/%y" # make sure the format matches the above + params_helper = TodosController::TodoCreateParamsHelper.new(params, prefs) params_helper.parse_dates() - assert_equal Date.new(2007, 5, 20), params_helper.show_from + assert_equal Date.new(2007, 5, 20), params_helper.show_from.to_date end def test_parse_dates_parses_due_date_based_on_prefs - params = { 'todo' => { 'show_from' => '5/20/07', 'due' => '5/23/07'}} - prefs = flexmock() - prefs.should_receive(:parse_date).with('5/20/07').and_return(Date.new(2007, 5, 20)) - prefs.should_receive(:parse_date).with('5/23/07').and_return(Date.new(2007, 5, 23)) + params = { 'todo' => { 'show_from' => '20/5/07', 'due' => '23/5/07'}} + + prefs = users(:admin_user).prefs + prefs.date_format = "%d/%m/%y" # make sure the format matches the above + params_helper = TodosController::TodoCreateParamsHelper.new(params, prefs) params_helper.parse_dates() - assert_equal Date.new(2007, 5, 23), params_helper.due + assert_equal Date.new(2007, 5, 23), params_helper.due.to_date end def test_parse_dates_sets_due_to_empty_string_if_nil - params = { 'todo' => { 'show_from' => '5/20/07', 'due' => nil}} - prefs = flexmock() - prefs.should_receive(:parse_date).with('5/20/07').and_return(Date.new(2007, 5, 20)) - prefs.should_receive(:parse_date).with(nil).and_return(nil) + params = { 'todo' => { 'show_from' => '20/5/07', 'due' => nil}} + prefs = users(:admin_user).prefs params_helper = TodosController::TodoCreateParamsHelper.new(params, prefs) params_helper.parse_dates() assert_equal '', params_helper.due @@ -72,63 +72,63 @@ class TodoCreateParamsHelperTest < ActiveSupport::TestCase def test_project_name_is_stripped_of_leading_and_trailing_whitespace params = { 'project_name' => ' Visit New Orleans ' } - prefs = flexmock() + prefs = users(:admin_user).prefs params_helper = TodosController::TodoCreateParamsHelper.new(params, prefs) assert_equal 'Visit New Orleans', params_helper.project_name end def test_project_name_is_nil_when_unspecified params = { } - prefs = flexmock() + prefs = users(:admin_user).prefs params_helper = TodosController::TodoCreateParamsHelper.new(params, prefs) assert_nil params_helper.project_name end def test_context_name_is_stripped_of_leading_and_trailing_whitespace params = { 'context_name' => ' mobile phone ' } - prefs = flexmock() + prefs = users(:admin_user).prefs params_helper = TodosController::TodoCreateParamsHelper.new(params, prefs) assert_equal 'mobile phone', params_helper.context_name end def test_context_name_is_nil_when_unspecified params = { } - prefs = flexmock() + prefs = users(:admin_user).prefs params_helper = TodosController::TodoCreateParamsHelper.new(params, prefs) assert_nil params_helper.context_name end def test_project_specified_by_name_is_false_when_project_id_is_specified params = { 'todo' => { 'project_id' => 2 } } - prefs = flexmock() + prefs = users(:admin_user).prefs params_helper = TodosController::TodoCreateParamsHelper.new(params, prefs) assert_equal false, params_helper.project_specified_by_name? end def test_project_specified_by_name_is_false_when_project_name_is_blank params = { 'project_name' => nil, 'todo' => {} } - prefs = flexmock() + prefs = users(:admin_user).prefs params_helper = TodosController::TodoCreateParamsHelper.new(params, prefs) assert_equal false, params_helper.project_specified_by_name? end def test_project_specified_by_name_is_false_when_project_name_is_none params = { 'project_name' => 'None', 'todo' => {} } - prefs = flexmock() + prefs = users(:admin_user).prefs params_helper = TodosController::TodoCreateParamsHelper.new(params, prefs) assert_equal false, params_helper.project_specified_by_name? end def test_context_specified_by_name_is_false_when_context_id_is_specified params = { 'todo' => { 'context_id' => 3 } } - prefs = flexmock() + prefs = users(:admin_user).prefs params_helper = TodosController::TodoCreateParamsHelper.new(params, prefs) assert_equal false, params_helper.context_specified_by_name? end def test_context_specified_by_name_is_false_when_context_name_is_blank params = { 'context_name' => nil, 'todo' => {} } - prefs = flexmock() + prefs = users(:admin_user).prefs params_helper = TodosController::TodoCreateParamsHelper.new(params, prefs) assert_equal false, params_helper.context_specified_by_name? end diff --git a/test/unit/todo_test.rb b/test/unit/todo_test.rb index bfd8116a..cedaaeb7 100644 --- a/test/unit/todo_test.rb +++ b/test/unit/todo_test.rb @@ -47,7 +47,7 @@ class TodoTest < ActiveSupport::TestCase @not_completed2.description = "" assert !@not_completed2.save assert_equal 1, @not_completed2.errors.count - assert_equal "can't be blank", @not_completed2.errors.on(:description) + assert_equal "can't be blank", @not_completed2.errors[:description][0] end def test_validate_length_of_description @@ -55,7 +55,7 @@ class TodoTest < ActiveSupport::TestCase @not_completed2.description = generate_random_string(101) assert !@not_completed2.save assert_equal 1, @not_completed2.errors.count - assert_equal "is too long (maximum is 100 characters)", @not_completed2.errors.on(:description) + assert_equal "is too long (maximum is 100 characters)", @not_completed2.errors[:description][0] end def test_validate_length_of_notes @@ -63,7 +63,7 @@ class TodoTest < ActiveSupport::TestCase @not_completed2.notes = generate_random_string(60001) assert !@not_completed2.save assert_equal 1, @not_completed2.errors.count - assert_equal "is too long (maximum is 60000 characters)", @not_completed2.errors.on(:notes) + assert_equal "is too long (maximum is 60000 characters)", @not_completed2.errors[:notes][0] end def test_validate_show_from_must_be_a_date_in_the_future @@ -72,20 +72,34 @@ class TodoTest < ActiveSupport::TestCase # and actual show_from value appropriately based on the date assert !t.save assert_equal 1, t.errors.count - assert_equal "must be a date in the future", t.errors.on(:show_from) + assert_equal "must be a date in the future", t.errors[:show_from][0] end - - def test_validate_description_can_contain_quote - t = @not_completed2 - t[:description] = "much \"ado\" about nothing" - assert t.save - assert_equal 0, t.errors.count + + def test_validate_circular_dependencies + @completed.activate! + @not_completed3=@completed + + # 2 -> 1 + @not_completed1.add_predecessor(@not_completed2) + assert @not_completed1.save! + assert_equal 1, @not_completed2.successors.count + + # 3 -> 2 -> 1 + @not_completed2.add_predecessor(@not_completed3) + assert @not_completed2.save! + assert_equal 1, @not_completed3.successors.count + + # 1 -> 3 -> 2 -> 1 == circle + @not_completed3.add_predecessor(@not_completed1) + assert !@not_completed3.valid? + error_msg = "Adding ''Call Bill Gates to find out how much he makes per day' <'agenda'; 'Make more money than Billy Gates'>' would create a circular dependency" + assert_equal error_msg, @not_completed3.errors["Depends on:"][0] end def test_defer_an_existing_todo @not_completed2 assert_equal :active, @not_completed2.aasm_current_state - @not_completed2.show_from = next_week + @not_completed2.show_from = Time.zone.now + 1.week assert @not_completed2.save, "should have saved successfully" + @not_completed2.errors.to_xml assert_equal :deferred, @not_completed2.aasm_current_state end diff --git a/test/unit/user_test.rb b/test/unit/user_test.rb index 247ce2c0..d5ab917e 100644 --- a/test/unit/user_test.rb +++ b/test/unit/user_test.rb @@ -28,7 +28,7 @@ class UserTest < ActiveSupport::TestCase end # Test an admin user model - # + # def test_admin assert_kind_of User, @admin_user assert_equal 1, @admin_user.id @@ -57,14 +57,14 @@ class UserTest < ActiveSupport::TestCase def test_validate_short_password assert_no_difference 'User.count' do u = create_user :password => generate_random_string(4) - assert_error_on u, :password, "is too short (minimum is 5 characters)" + assert_equal "is too short (minimum is 5 characters)", u.errors[:password][0] end end def test_validate_long_password assert_no_difference 'User.count' do u = create_user :password => generate_random_string(41) - assert_error_on u, :password, "is too long (maximum is 40 characters)" + assert_equal "is too long (maximum is 40 characters)", u.errors[:password][0] end end @@ -77,22 +77,22 @@ class UserTest < ActiveSupport::TestCase def test_validate_missing_password assert_no_difference 'User.count' do u = create_user :password => '' - assert_errors_on u, :password, ["can't be blank", "is too short (minimum is 5 characters)"] + assert_equal ["can't be blank", "is too short (minimum is 5 characters)"], u.errors[:password] end end def test_validate_short_login assert_no_difference 'User.count' do u = create_user :login => 'ba' - assert_error_on u, :login, "is too short (minimum is 3 characters)" + assert_equal "is too short (minimum is 3 characters)", u.errors[:login][0] end end def test_validate_long_login assert_no_difference 'User.count' do u = create_user :login => generate_random_string(81) - assert_error_on u, :login, "is too long (maximum is 80 characters)" - end + assert_equal "is too long (maximum is 80 characters)", u.errors[:login][0] + end end def test_validate_correct_length_login @@ -104,7 +104,7 @@ class UserTest < ActiveSupport::TestCase def test_validate_missing_login assert_no_difference 'User.count' do u = create_user :login => '' - assert_errors_on u, :login, ["can't be blank", "is too short (minimum is 3 characters)"] + assert_equal ["can't be blank", "is too short (minimum is 3 characters)"], u.errors[:login] end end @@ -192,7 +192,7 @@ class UserTest < ActiveSupport::TestCase @other_user.auth_type = 'dnacheck' assert !@other_user.save assert_equal 1, @other_user.errors.count - assert_equal "not a valid authentication type (dnacheck)", @other_user.errors.on(:auth_type) + assert_equal ["not a valid authentication type (dnacheck)"], @other_user.errors[:auth_type] end def test_authenticate_can_use_ldap @@ -246,9 +246,9 @@ class UserTest < ActiveSupport::TestCase def test_sort_active_projects_alphabetically u = users(:admin_user) u.projects.alphabetize(:state => "active") - assert_equal 1, projects(:timemachine).position + assert_equal 1, projects(:timemachine).position assert_equal 2, projects(:gardenclean).position - assert_equal 3, projects(:moremoney).position + assert_equal 3, projects(:moremoney).position end def test_sort_active_projects_alphabetically_case_insensitive @@ -256,9 +256,9 @@ class UserTest < ActiveSupport::TestCase projects(:timemachine).name = projects(:timemachine).name.downcase projects(:timemachine).save! u.projects.alphabetize(:state => "active") - assert_equal 1, projects(:timemachine).position + assert_equal 1, projects(:timemachine).position assert_equal 2, projects(:gardenclean).position - assert_equal 3, projects(:moremoney).position + assert_equal 3, projects(:moremoney).position end def test_should_create_user @@ -271,21 +271,21 @@ class UserTest < ActiveSupport::TestCase def test_should_require_login assert_no_difference 'User.count' do u = create_user(:login => nil) - assert u.errors.on(:login) + assert u.errors[:login][0] end end def test_should_require_password assert_no_difference 'User.count' do u = create_user(:password => nil) - assert u.errors.on(:password) + assert u.errors[:password][0] end end def test_should_require_password_confirmation assert_no_difference 'User.count' do u = create_user(:password_confirmation => nil) - assert u.errors.on(:password_confirmation) + assert u.errors[:password_confirmation][0] end end @@ -316,21 +316,6 @@ class UserTest < ActiveSupport::TestCase assert_nil users(:other_user).remember_token end - def test_normalizes_open_id_url_on_save - ['www.johndoe.com', 'WWW.JOHNDOE.COM', 'http://www.johndoe.com/', 'http://www.johndoe.com'].each do |initial| - assert_open_id_url_normalized_on_save initial, 'http://www.johndoe.com/' - end - end - - def test_normalizes_open_id_url_on_find - u = users(:other_user) - u.open_id_url = 'http://www.johndoe.com' - u.save - ['www.johndoe.com', 'WWW.JOHNDOE.COM', 'http://www.johndoe.com/', 'http://www.johndoe.com'].each do |raw_open_id_url| - assert_equal u.id, User.find_by_open_id_url(raw_open_id_url).id - end - end - def test_should_discover_using_depracted_password assert_nil @admin_user.uses_deprecated_password? assert_nil @other_user.uses_deprecated_password? From fd433d76d85d1c1841f9e762bc9a55c5ce20c9d3 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Wed, 18 Apr 2012 14:22:58 +0200 Subject: [PATCH 107/134] fix all upgrade warnings from the rails_upgrade plugin --- Gemfile.lock | 12 +- app/controllers/data_controller.rb | 40 +- app/controllers/integrations_controller.rb | 5 +- app/controllers/projects_controller.rb | 20 +- app/controllers/recurring_todos_controller.rb | 23 +- app/controllers/search_controller.rb | 25 +- app/controllers/stats_controller.rb | 80 +-- app/controllers/todos_controller.rb | 279 +++++----- app/controllers/users_controller.rb | 4 +- app/helpers/todos_helper.rb | 6 +- app/models/todo.rb | 6 +- app/models/user.rb | 20 +- app/views/contexts/_new_context_form.rhtml | 2 +- app/views/data/yaml_form.de.html.erb | 2 +- app/views/data/yaml_form.en.html.erb | 6 +- app/views/login/login.html.erb | 16 +- app/views/login/login_mobile.html.erb | 32 +- app/views/preferences/index.html.erb | 2 +- app/views/projects/_new_project_form.rhtml | 2 +- app/views/recurring_todos/_edit_form.html.erb | 2 +- .../recurring_todos/_recurring_todo_form.erb | 2 +- app/views/search/index.rhtml | 2 +- app/views/todos/edit_mobile.html.erb | 2 +- app/views/todos/new.m.erb | 2 +- app/views/users/change_auth_type.html.erb | 2 +- app/views/users/change_password.html.erb | 2 +- app/views/users/new.html.erb | 2 +- .../test_helper.rb.rails2 | 0 test/functional/backend_controller_test.rb | 80 --- test/functional/stats_controller_test.rb | 0 vendor/plugins/rails_upgrade/MIT-LICENSE | 20 - vendor/plugins/rails_upgrade/README.rdoc | 26 - vendor/plugins/rails_upgrade/Rakefile | 22 - vendor/plugins/rails_upgrade/init.rb | 2 - vendor/plugins/rails_upgrade/install.rb | 38 -- .../rails_upgrade/lib/application_checker.rb | 506 ------------------ .../rails_upgrade/lib/gemfile_generator.rb | 95 ---- .../lib/new_configuration_generator.rb | 59 -- .../rails_upgrade/lib/rails_upgrade.rb | 0 .../rails_upgrade/lib/routes_upgrader.rb | 344 ------------ .../lib/tasks/rails_upgrade_tasks.rake | 79 --- .../test/application_checker_test.rb | 344 ------------ .../test/gemfile_generator_test.rb | 72 --- .../test/new_configuration_generator_test.rb | 63 --- .../test/routes_upgrader_test.rb | 218 -------- .../plugins/rails_upgrade/test/test_helper.rb | 5 - vendor/plugins/rails_upgrade/uninstall.rb | 1 - 47 files changed, 288 insertions(+), 2284 deletions(-) rename {test => backup.rails2.3}/test_helper.rb.rails2 (100%) delete mode 100644 test/functional/backend_controller_test.rb mode change 100755 => 100644 test/functional/stats_controller_test.rb delete mode 100644 vendor/plugins/rails_upgrade/MIT-LICENSE delete mode 100644 vendor/plugins/rails_upgrade/README.rdoc delete mode 100644 vendor/plugins/rails_upgrade/Rakefile delete mode 100644 vendor/plugins/rails_upgrade/init.rb delete mode 100644 vendor/plugins/rails_upgrade/install.rb delete mode 100644 vendor/plugins/rails_upgrade/lib/application_checker.rb delete mode 100644 vendor/plugins/rails_upgrade/lib/gemfile_generator.rb delete mode 100644 vendor/plugins/rails_upgrade/lib/new_configuration_generator.rb delete mode 100644 vendor/plugins/rails_upgrade/lib/rails_upgrade.rb delete mode 100644 vendor/plugins/rails_upgrade/lib/routes_upgrader.rb delete mode 100644 vendor/plugins/rails_upgrade/lib/tasks/rails_upgrade_tasks.rake delete mode 100644 vendor/plugins/rails_upgrade/test/application_checker_test.rb delete mode 100644 vendor/plugins/rails_upgrade/test/gemfile_generator_test.rb delete mode 100644 vendor/plugins/rails_upgrade/test/new_configuration_generator_test.rb delete mode 100644 vendor/plugins/rails_upgrade/test/routes_upgrader_test.rb delete mode 100644 vendor/plugins/rails_upgrade/test/test_helper.rb delete mode 100644 vendor/plugins/rails_upgrade/uninstall.rb diff --git a/Gemfile.lock b/Gemfile.lock index 26af276b..cc1b7463 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -41,14 +41,13 @@ GEM coffee-script-source execjs coffee-script-source (1.3.1) - daemons (1.0.10) erubis (2.7.0) execjs (1.3.0) multi_json (~> 1.0) - gem_plugin (0.2.3) highline (1.5.2) hike (1.2.1) htmlentities (4.3.1) + httpclient (2.2.4) i18n (0.6.0) journey (1.0.3) jquery-rails (2.0.2) @@ -60,9 +59,6 @@ GEM mime-types (~> 1.16) treetop (~> 1.4.8) mime-types (1.18) - mongrel (1.2.0.pre2) - daemons (~> 1.0.10) - gem_plugin (~> 0.2.3) multi_json (1.2.0) mysql2 (0.3.11) nokogiri (1.4.7) @@ -101,7 +97,8 @@ GEM railties (~> 3.2.0) sass (>= 3.1.10) tilt (~> 1.3) - soap4r-ruby1.9 (2.0.5) + soap4r (1.5.8) + httpclient (>= 2.1.1) sprockets (2.1.2) hike (~> 1.2) rack (~> 1.0) @@ -135,13 +132,12 @@ DEPENDENCIES htmlentities (~> 4.3.0) jquery-rails mail - mongrel (= 1.2.0.pre2) mysql2 rails (= 3.2.3) rails_autolink sanitize (~> 1.2.1) sass-rails (~> 3.2.3) - soap4r-ruby1.9 + soap4r (~> 1.5.8) sqlite3 swf_fu uglifier (>= 1.0.3) diff --git a/app/controllers/data_controller.rb b/app/controllers/data_controller.rb index 3e87a489..8a530451 100644 --- a/app/controllers/data_controller.rb +++ b/app/controllers/data_controller.rb @@ -18,9 +18,9 @@ class DataController < ApplicationController def yaml_export all_tables = {} - all_tables['todos'] = current_user.todos.find(:all, :include => [:tags]) - all_tables['contexts'] = current_user.contexts.find(:all) - all_tables['projects'] = current_user.projects.find(:all) + all_tables['todos'] = current_user.todos.includes(:tags) + all_tables['contexts'] = current_user.contexts.all + all_tables['projects'] = current_user.projects.all todo_tag_ids = Tag.find_by_sql([ "SELECT DISTINCT tags.id "+ @@ -34,13 +34,13 @@ class DataController < ApplicationController "WHERE recurring_todos.user_id=? "+ "AND tags.id = taggings.tag_id " + "AND taggings.taggable_id = recurring_todos.id ", current_user.id]) - tags = Tag.find(:all, :conditions => ["id IN (?) OR id IN (?)", todo_tag_ids, rec_todo_tag_ids]) - taggings = Tagging.find(:all, :conditions => ["tag_id IN (?) OR tag_id IN(?)", todo_tag_ids, rec_todo_tag_ids]) + tags = Tag.where("id IN (?) OR id IN (?)", todo_tag_ids, rec_todo_tag_ids) + taggings = Tagging.where("tag_id IN (?) OR tag_id IN(?)", todo_tag_ids, rec_todo_tag_ids) all_tables['tags'] = tags all_tables['taggings'] = taggings - all_tables['notes'] = current_user.notes.find(:all) - all_tables['recurring_todos'] = current_user.recurring_todos.find(:all) + all_tables['notes'] = current_user.notes + all_tables['recurring_todos'] = current_user.recurring_todos result = all_tables.to_yaml result.gsub!(/\n/, "\r\n") # TODO: general functionality for line endings @@ -53,7 +53,7 @@ class DataController < ApplicationController csv << ["id", "Context", "Project", "Description", "Notes", "Tags", "Created at", "Due", "Completed at", "User ID", "Show from", "state"] - current_user.todos.find(:all, :include => [:context, :project]).each do |todo| + current_user.todos.include(:context, :project).all.each do |todo| csv << [todo.id, todo.context.name, todo.project_id.nil? ? "" : todo.project.name, todo.description, @@ -78,13 +78,13 @@ class DataController < ApplicationController # had to remove project include because it's association order is leaking # through and causing an ambiguous column ref even with_exclusive_scope # didn't seem to help -JamesKebinger - current_user.notes.find(:all,:order=>"notes.created_at").each do |note| + current_user.notes.order("notes.created_at").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, + 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)] + note.updated_at.to_formatted_s(:db)] end end send_data(result, :filename => "notes.csv", :type => content_type) @@ -103,17 +103,17 @@ class DataController < ApplicationController "WHERE recurring_todos.user_id=? "+ "AND tags.id = taggings.tag_id " + "AND taggings.taggable_id = recurring_todos.id ", current_user.id]) - tags = Tag.find(:all, :conditions => ["id IN (?) OR id IN (?)", todo_tag_ids, rec_todo_tag_ids]) - taggings = Tagging.find(:all, :conditions => ["tag_id IN (?) OR tag_id IN(?)", todo_tag_ids, rec_todo_tag_ids]) + tags = Tag.where("id IN (?) OR id IN (?)", todo_tag_ids, rec_todo_tag_ids) + taggings = Tagging.where("tag_id IN (?) OR tag_id IN(?)", todo_tag_ids, rec_todo_tag_ids) result = "" - result << current_user.todos.find(:all).to_xml(:skip_instruct => true) - result << current_user.contexts.find(:all).to_xml(:skip_instruct => true) - result << current_user.projects.find(:all).to_xml(:skip_instruct => true) + result << current_user.todos.to_xml(:skip_instruct => true) + result << current_user.contexts.to_xml(:skip_instruct => true) + result << current_user.projects.to_xml(:skip_instruct => true) result << tags.to_xml(:skip_instruct => true) result << taggings.to_xml(:skip_instruct => true) - result << current_user.notes.find(:all).to_xml(:skip_instruct => true) - result << current_user.recurring_todos.find(:all).to_xml(:skip_instruct => true) + result << current_user.notes.to_xml(:skip_instruct => true) + result << current_user.recurring_todos.to_xml(:skip_instruct => true) result << "" send_data(result, :filename => "tracks_data.xml", :type => 'text/xml') end @@ -126,7 +126,7 @@ class DataController < ApplicationController def adjust_time(timestring) if (timestring=='') or ( timestring == nil) return nil - else + else return Time.parse(timestring + 'UTC') end end @@ -186,7 +186,7 @@ class DataController < ApplicationController case item.ivars['attributes']['state'] when 'active' then newitem.activate! when 'project_hidden' then newitem.hide! - when 'completed' + when 'completed' newitem.complete! newitem.completed_at = adjust_time(item.ivars['attributes']['completed_at']) when 'deferred' then newitem.defer! diff --git a/app/controllers/integrations_controller.rb b/app/controllers/integrations_controller.rb index 70c93b17..9daaa5ec 100644 --- a/app/controllers/integrations_controller.rb +++ b/app/controllers/integrations_controller.rb @@ -27,7 +27,8 @@ class IntegrationsController < ApplicationController end def search_plugin - @icon_data = [File.open(RAILS_ROOT + '/public/images/done.png').read]. + # TODO: ASSET PATH!! + @icon_data = [File.open(Rails.root + '/public/images/done.png').read]. pack('m').gsub(/\n/, '') render :layout => false @@ -52,7 +53,7 @@ class IntegrationsController < ApplicationController message = Mail.new(params[:message]) # find user - user = User.find(:first, :include => [:preference], :conditions => ["preferences.sms_email = ?", message.from]) + user = User.where("preferences.sms_email = ?", message.from).includes(:preferences).first if user.nil? render :text => "No user found", :status => 404 return false diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 24aa5eac..243fe2ee 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -13,13 +13,13 @@ class ProjectsController < ApplicationController if params[:projects_and_actions] projects_and_actions else - @contexts = current_user.contexts.all + @contexts = current_user.contexts init_not_done_counts(['project']) init_project_hidden_todo_counts(['project']) if params[:only_active_with_no_next_actions] @projects = current_user.projects.active.select { |p| count_undone_todos(p) == 0 } else - @projects = current_user.projects.all + @projects = current_user.projects end respond_to do |format| format.html &render_projects_html @@ -101,15 +101,15 @@ class ProjectsController < ApplicationController init_data_for_sidebar unless mobile? @page_title = t('projects.page_title', :project => @project.name) - @not_done = @project.todos.active_or_hidden(:include => Todo::DEFAULT_INCLUDES) - @deferred = @project.todos.deferred(:include => Todo::DEFAULT_INCLUDES) - @pending = @project.todos.pending(:include => Todo::DEFAULT_INCLUDES) + @not_done = @project.todos.active_or_hidden.includes(Todo::DEFAULT_INCLUDES) + @deferred = @project.todos.deferred.includes(Todo::DEFAULT_INCLUDES) + @pending = @project.todos.pending.includes(Todo::DEFAULT_INCLUDES) @done = {} - @done = @project.todos.find_in_state(:all, :completed, - :order => "todos.completed_at DESC", - :limit => current_user.prefs.show_number_completed, - :include => Todo::DEFAULT_INCLUDES) unless current_user.prefs.show_number_completed == 0 + @done = @project.todos.completed. + order("todos.completed_at DESC"). + limit(current_user.prefs.show_number_completed). + includes(Todo::DEFAULT_INCLUDES) unless current_user.prefs.show_number_completed == 0 @count = @not_done.size @down_count = @count + @deferred.size + @pending.size @@ -318,7 +318,7 @@ class ProjectsController < ApplicationController @count = current_user.projects.count @active_projects = current_user.projects.active @hidden_projects = current_user.projects.hidden - @completed_projects = current_user.projects.completed.find(:all, :limit => 10) + @completed_projects = current_user.projects.completed.limit(10) @completed_count = current_user.projects.completed.count @no_projects = current_user.projects.empty? current_user.projects.cache_note_counts diff --git a/app/controllers/recurring_todos_controller.rb b/app/controllers/recurring_todos_controller.rb index 69517597..2937bac5 100644 --- a/app/controllers/recurring_todos_controller.rb +++ b/app/controllers/recurring_todos_controller.rb @@ -9,12 +9,12 @@ class RecurringTodosController < ApplicationController @page_title = t('todos.recurring_actions_title') @source_view = params['_source_view'] || 'recurring_todo' find_and_inactivate - @recurring_todos = current_user.recurring_todos.active.find(:all, :include => [:tags, :taggings]) - @completed_recurring_todos = current_user.recurring_todos.completed.find(:all, :limit => 10, :include => [:tags, :taggings]) + @recurring_todos = current_user.recurring_todos.active.includes(:tags, :taggings) + @completed_recurring_todos = current_user.recurring_todos.completed.limit(10).includes(:tags, :taggings) - @no_recurring_todos = @recurring_todos.size == 0 - @no_completed_recurring_todos = @completed_recurring_todos.size == 0 - @count = @recurring_todos.size + @no_recurring_todos = @recurring_todos.count == 0 + @no_completed_recurring_todos = @completed_recurring_todos.count == 0 + @count = @recurring_todos.count @new_recurring_todo = RecurringTodo.new end @@ -271,8 +271,8 @@ class RecurringTodosController < ApplicationController end @xth_day = [[t('common.first'),1],[t('common.second'),2],[t('common.third'),3],[t('common.fourth'),4],[t('common.last'),5]] - @projects = current_user.projects.find(:all, :include => [:default_context]) - @contexts = current_user.contexts.find(:all) + @projects = current_user.projects.includes(:default_context) + @contexts = current_user.contexts end def get_recurring_todo_from_param @@ -282,10 +282,11 @@ class RecurringTodosController < ApplicationController def find_and_inactivate # find active recurring todos without active todos and inactivate them - current_user.recurring_todos.active.all( - :select => "recurring_todos.id, recurring_todos.state", - :joins => "LEFT JOIN todos fai_todos ON (recurring_todos.id = fai_todos.recurring_todo_id) AND (NOT fai_todos.state='completed')", - :conditions => "fai_todos.id IS NULL").each { |rt| current_user.recurring_todos.find(rt.id).toggle_completion! } + current_user.recurring_todos.active. + select("recurring_todos.id, recurring_todos.state"). + joins("LEFT JOIN todos fai_todos ON (recurring_todos.id = fai_todos.recurring_todo_id) AND (NOT fai_todos.state='completed')"). + where("fai_todos.id IS NULL"). + each { |rt| current_user.recurring_todos.find(rt.id).toggle_completion! } end end diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 6bb67311..d7804887 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -7,19 +7,22 @@ class SearchController < ApplicationController @page_title = "TRACKS::Search Results for #{params[:search]}" terms = '%' + params[:search] + '%' - @found_not_complete_todos = current_user.todos.find(:all, - :conditions => ["(todos.description LIKE ? OR todos.notes LIKE ?) AND todos.completed_at IS NULL", terms, terms], - :include => Todo::DEFAULT_INCLUDES, - :order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC") - @found_complete_todos = current_user.todos.find(:all, - :conditions => ["(todos.description LIKE ? OR todos.notes LIKE ?) AND NOT (todos.completed_at IS NULL)", terms, terms], - :include => Todo::DEFAULT_INCLUDES, - :order => "todos.completed_at DESC") + @found_not_complete_todos = current_user.todos. + where("(todos.description LIKE ? OR todos.notes LIKE ?) AND todos.completed_at IS NULL", terms, terms). + includes(Todo::DEFAULT_INCLUDES). + order("todos.due IS NULL, todos.due ASC, todos.created_at ASC") + + @found_complete_todos = current_user.todos. + where("(todos.description LIKE ? OR todos.notes LIKE ?) AND NOT (todos.completed_at IS NULL)", terms, terms). + includes(Todo::DEFAULT_INCLUDES). + order("todos.completed_at DESC") + @found_todos = @found_not_complete_todos + @found_complete_todos - @found_projects = current_user.projects.find(:all, :conditions => ["name LIKE ? OR description LIKE ?", terms, terms]) - @found_notes = current_user.notes.find(:all, :conditions => ["body LIKE ?", terms]) - @found_contexts = current_user.contexts.find(:all, :conditions => ["name LIKE ?", terms]) + @found_projects = current_user.projects.where("name LIKE ? OR description LIKE ?", terms, terms) + @found_notes = current_user.notes.where("body LIKE ?", terms) + @found_contexts = current_user.contexts.where("name LIKE ?", terms) + # TODO: limit search to tags on todos @found_tags = Tagging.find_by_sql([ "SELECT DISTINCT tags.name as name "+ diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index 00081499..863c3a28 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -1,8 +1,7 @@ class StatsController < ApplicationController helper :todos, :projects, :recurring_todos - - append_before_filter :init, :exclude => [] + append_before_filter :init def index @page_title = t('stats.index_title') @@ -10,7 +9,7 @@ class StatsController < ApplicationController @tags_count = get_total_number_of_tags_of_user @unique_tags_count = get_unique_tags_of_user.size @hidden_contexts = current_user.contexts.hidden - @first_action = current_user.todos.find(:first, :order => "created_at ASC") + @first_action = current_user.todos.order("created_at ASC").first get_stats_actions get_stats_contexts @@ -23,10 +22,10 @@ class StatsController < ApplicationController def actions_done_last12months_data # get actions created and completed in the past 12+3 months. +3 for running # average - @actions_done_last12months = current_user.todos.completed_after(@cut_off_year).find(:all, { :select => "completed_at" }) - @actions_created_last12months = current_user.todos.created_after(@cut_off_year).find(:all, { :select => "created_at"}) - @actions_done_last12monthsPlus3 = current_user.todos.completed_after(@cut_off_year_plus3).find(:all, { :select => "completed_at" }) - @actions_created_last12monthsPlus3 = current_user.todos.created_after(@cut_off_year_plus3).find(:all, { :select => "created_at"}) + @actions_done_last12months = current_user.todos.completed_after(@cut_off_year).select("completed_at" ) + @actions_created_last12months = current_user.todos.created_after(@cut_off_year).select("created_at") + @actions_done_last12monthsPlus3 = current_user.todos.completed_after(@cut_off_year_plus3).select("completed_at" ) + @actions_created_last12monthsPlus3 = current_user.todos.created_after(@cut_off_year_plus3).select("created_at") # convert to array and fill in non-existing months @actions_done_last12months_array = convert_to_months_from_today_array(@actions_done_last12months, 13, :completed_at) @@ -56,8 +55,8 @@ class StatsController < ApplicationController end def actions_done_lastyears_data - @actions_done_last_months = current_user.todos.completed.find(:all, { :select => "completed_at", :order => "completed_at DESC" }) - @actions_created_last_months = current_user.todos.find(:all, { :select => "created_at", :order => "created_at DESC" }) + @actions_done_last_months = current_user.todos.completed.select("completed_at").order("completed_at DESC") + @actions_created_last_months = current_user.todos.select("created_at").order("created_at DESC" ) # query is sorted, so use last todo to calculate number of months @month_count = [difference_in_months(@today, @actions_created_last_months.last.created_at), @@ -88,8 +87,8 @@ class StatsController < ApplicationController def actions_done_last30days_data # get actions created and completed in the past 30 days. - @actions_done_last30days = current_user.todos.completed_after(@cut_off_month).find(:all, { :select => "completed_at" }) - @actions_created_last30days = current_user.todos.created_after(@cut_off_month).find(:all, { :select => "created_at" }) + @actions_done_last30days = current_user.todos.completed_after(@cut_off_month).select("completed_at") + @actions_created_last30days = current_user.todos.created_after(@cut_off_month).select("created_at") # convert to array. 30+1 to have 30 complete days and one current day [0] @actions_done_last30days_array = convert_to_days_from_today_array(@actions_done_last30days, 31, :completed_at) @@ -102,7 +101,7 @@ class StatsController < ApplicationController end def actions_completion_time_data - @actions_completion_time = current_user.todos.completed.find(:all, { :select => "completed_at, created_at", :order => "completed_at DESC" }) + @actions_completion_time = current_user.todos.completed.select("completed_at, created_at").order("completed_at DESC" ) # convert to array and fill in non-existing weeks with 0 @max_weeks = difference_in_weeks(@today, @actions_completion_time.last.completed_at) @@ -122,7 +121,7 @@ class StatsController < ApplicationController end def actions_running_time_data - @actions_running_time = current_user.todos.not_completed.find(:all, { :select => "created_at", :order => "created_at DESC" }) + @actions_running_time = current_user.todos.not_completed.select("created_at").order("created_at DESC") # convert to array and fill in non-existing weeks with 0 @max_weeks = difference_in_weeks(@today, @actions_running_time.last.created_at) @@ -150,8 +149,9 @@ class StatsController < ApplicationController # - actions not deferred (show_from must be null) # - actions not pending/blocked - @actions_running_time = current_user.todos.not_completed.not_hidden.not_deferred_or_blocked.find( - :all, :select => "todos.created_at", :order => "todos.created_at DESC") + @actions_running_time = current_user.todos.not_completed.not_hidden.not_deferred_or_blocked. + select("todos.created_at"). + order("todos.created_at DESC") @max_weeks = difference_in_weeks(@today, @actions_running_time.last.created_at) @actions_running_per_week_array = convert_to_weeks_from_today_array(@actions_running_time, @max_weeks+1, :created_at) @@ -170,8 +170,9 @@ class StatsController < ApplicationController end def actions_open_per_week_data - @actions_started = current_user.todos.created_after(@today-53.weeks).find(:all, - :select => "todos.created_at, todos.completed_at",:order => "todos.created_at DESC") + @actions_started = current_user.todos.created_after(@today-53.weeks). + select("todos.created_at, todos.completed_at"). + order("todos.created_at DESC") @max_weeks = difference_in_weeks(@today, @actions_started.last.created_at) @@ -259,8 +260,8 @@ class StatsController < ApplicationController end def actions_day_of_week_all_data - @actions_creation_day = current_user.todos.find(:all, { :select => "created_at" }) - @actions_completion_day = current_user.todos.completed.find(:all, { :select => "completed_at" }) + @actions_creation_day = current_user.todos.select("created_at") + @actions_completion_day = current_user.todos.completed.select("completed_at") # convert to array and fill in non-existing days @actions_creation_day_array = Array.new(7) { |i| 0} @@ -276,8 +277,8 @@ class StatsController < ApplicationController end def actions_day_of_week_30days_data - @actions_creation_day = current_user.todos.created_after(@cut_off_month).find(:all, { :select => "created_at" }) - @actions_completion_day = current_user.todos.completed_after(@cut_off_month).find(:all, { :select => "completed_at" }) + @actions_creation_day = current_user.todos.created_after(@cut_off_month).select("created_at") + @actions_completion_day = current_user.todos.completed_after(@cut_off_month).select("completed_at") # convert to hash to be able to fill in non-existing days @max=0 @@ -294,8 +295,8 @@ class StatsController < ApplicationController end def actions_time_of_day_all_data - @actions_creation_hour = current_user.todos.find(:all, { :select => "created_at" }) - @actions_completion_hour = current_user.todos.completed.find(:all, { :select => "completed_at" }) + @actions_creation_hour = current_user.todos.select("created_at") + @actions_completion_hour = current_user.todos.completed.select("completed_at") # convert to hash to be able to fill in non-existing days @actions_creation_hour_array = Array.new(24) { |i| 0} @@ -311,8 +312,8 @@ class StatsController < ApplicationController end def actions_time_of_day_30days_data - @actions_creation_hour = current_user.todos.created_after(@cut_off_month).find(:all, { :select => "created_at" }) - @actions_completion_hour = current_user.todos.completed_after(@cut_off_month).find(:all, { :select => "completed_at" }) + @actions_creation_hour = current_user.todos.created_after(@cut_off_month).select("created_at") + @actions_completion_hour = current_user.todos.completed_after(@cut_off_month).select("completed_at") # convert to hash to be able to fill in non-existing days @actions_creation_hour_array = Array.new(24) { |i| 0} @@ -355,11 +356,12 @@ class StatsController < ApplicationController end # get all running actions that are visible - @actions_running_time = current_user.todos.not_completed.not_hidden.not_deferred_or_blocked.find( - :all, :select => "todos.id, todos.created_at", :order => "todos.created_at DESC") + @actions_running_time = current_user.todos.not_completed.not_hidden.not_deferred_or_blocked. + select("todos.id, todos.created_at"). + order("todos.created_at DESC") selected_todo_ids = get_ids_from(@actions_running_time, week_from, week_to, params['id']== 'avrt_end') - @selected_actions = selected_todo_ids.size == 0 ? [] : current_user.todos.find(:all, { :conditions => "id in (" + selected_todo_ids.join(",") + ")" }) + @selected_actions = selected_todo_ids.size == 0 ? [] : current_user.todos.where("id in (" + selected_todo_ids.join(",") + ")") @count = @selected_actions.size render :action => "show_selection_from_chart" @@ -379,10 +381,10 @@ class StatsController < ApplicationController end # get all running actions - @actions_running_time = current_user.todos.not_completed.find(:all, { :select => "id, created_at" }) + @actions_running_time = current_user.todos.not_completed.select("id, created_at") selected_todo_ids = get_ids_from(@actions_running_time, week_from, week_to, params['id']=='art_end') - @selected_actions = selected_todo_ids.size == 0 ? [] : current_user.todos.find(:all, { :conditions => "id in (" + selected_todo_ids.join(",") + ")" }) + @selected_actions = selected_todo_ids.size == 0 ? [] : current_user.todos.where("id in (#{selected_todo_ids.join(",")})") @count = @selected_actions.size render :action => "show_selection_from_chart" @@ -397,10 +399,10 @@ class StatsController < ApplicationController init_not_done_counts - @done_recently = current_user.todos.completed.all(:limit => 10, :order => 'completed_at DESC', :include => Todo::DEFAULT_INCLUDES) - @last_completed_projects = current_user.projects.completed.all(:limit => 10, :order => 'completed_at DESC', :include => [:todos, :notes]) + @done_recently = current_user.todos.completed.limit(10).order('completed_at DESC').includes(Todo::DEFAULT_INCLUDES) + @last_completed_projects = current_user.projects.completed.limit(10).order('completed_at DESC').includes(:todos, :notes) @last_completed_contexts = [] - @last_completed_recurring_todos = current_user.recurring_todos.completed.all(:limit => 10, :order => 'completed_at DESC', :include => [:tags, :taggings]) + @last_completed_recurring_todos = current_user.recurring_todos.completed.limit(10).order('completed_at DESC').includes(:tags, :taggings) #TODO: @last_completed_contexts = current_user.contexts.completed.all(:limit => 10, :order => 'completed_at DESC') end @@ -415,7 +417,7 @@ class StatsController < ApplicationController "AND todos.user_id = #{current_user.id}"]) tags_ids_s = tag_ids.map(&:id).sort.join(",") return {} if tags_ids_s.blank? # return empty hash for .size to work - return Tag.find(:all, :conditions => "id in (" + tags_ids_s + ")") + return Tag.where("id in (#{tags_ids_s})") end def get_total_number_of_tags_of_user @@ -452,7 +454,7 @@ class StatsController < ApplicationController def get_stats_actions # time to complete - @completed_actions = current_user.todos.completed.find(:all, { :select => "completed_at, created_at" }) + @completed_actions = current_user.todos.completed.select("completed_at, created_at") actions_sum, actions_max = 0,0 actions_min = @completed_actions.first ? @completed_actions.first.completed_at - @completed_actions.first.created_at : 0 @@ -475,12 +477,12 @@ class StatsController < ApplicationController @actions_min_ttc_sec = (actions_min / @seconds_per_day).round.to_s + " days " + @actions_min_ttc_sec if actions_min > @seconds_per_day # get count of actions created and actions done in the past 30 days. - @sum_actions_done_last30days = current_user.todos.completed.completed_after(@cut_off_month).count(:all) - @sum_actions_created_last30days = current_user.todos.created_after(@cut_off_month).count(:all) + @sum_actions_done_last30days = current_user.todos.completed.completed_after(@cut_off_month).count + @sum_actions_created_last30days = current_user.todos.created_after(@cut_off_month).count # get count of actions done in the past 12 months. - @sum_actions_done_last12months = current_user.todos.completed.completed_after(@cut_off_year).count(:all) - @sum_actions_created_last12months = current_user.todos.created_after(@cut_off_year).count(:all) + @sum_actions_done_last12months = current_user.todos.completed.completed_after(@cut_off_year).count + @sum_actions_created_last12months = current_user.todos.created_after(@cut_off_year).count end def get_stats_contexts diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 3ae8c5ed..895db3fb 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -18,7 +18,7 @@ class TodosController < ApplicationController extend ActionView::Helpers::SanitizeHelper::ClassMethods def index - @projects = current_user.projects.all(:include => [:default_context]) + @projects = current_user.projects.includes(:default_context) @contexts = current_user.contexts @contexts_to_show = current_user.contexts.active @@ -36,7 +36,7 @@ class TodosController < ApplicationController def new @projects = current_user.projects.active - @contexts = current_user.contexts.find(:all) + @contexts = current_user.contexts respond_to do |format| format.m { @new_mobile = true @@ -126,16 +126,16 @@ class TodosController < ApplicationController if @saved redirect_to @return_path else - @projects = current_user.projects.find(:all) - @contexts = current_user.contexts.find(:all) + @projects = current_user.projects + @contexts = current_user.contexts render :action => "new" end end format.js do if @saved determine_down_count - @contexts = current_user.contexts.find(:all) if @new_context_created - @projects = current_user.projects.find(:all) if @new_project_created + @contexts = current_user.contexts if @new_context_created + @projects = current_user.projects if @new_project_created @initial_context_name = params['default_context_name'] @initial_project_name = params['default_project_name'] @initial_tags = params['initial_tag_list'] @@ -225,8 +225,8 @@ class TodosController < ApplicationController format.html { redirect_to :action => "index" } format.js do determine_down_count if @saved - @contexts = current_user.contexts.find(:all) if @new_context_created - @projects = current_user.projects.find(:all) if @new_project_created + @contexts = current_user.contexts if @new_context_created + @projects = current_user.projects if @new_project_created @initial_context_name = params['default_context_name'] @initial_project_name = params['default_project_name'] @initial_tags = params['initial_tag_list'] @@ -255,14 +255,14 @@ class TodosController < ApplicationController end def edit - @todo = current_user.todos.find(params['id'], :include => Todo::DEFAULT_INCLUDES) + @todo = current_user.todos.find_by_id(params['id']).includes(Todo::DEFAULT_INCLUDES) @source_view = params['_source_view'] || 'todo' @tag_name = params['_tag_name'] respond_to do |format| format.js format.m { @projects = current_user.projects.active - @contexts = current_user.contexts.find(:all) + @contexts = current_user.contexts @edit_mobile = true @return_path=cookies[:mobile_url] ? cookies[:mobile_url] : mobile_path render :template => "/todos/edit_mobile.html.erb" @@ -271,7 +271,7 @@ class TodosController < ApplicationController end def show - @todo = current_user.todos.find(params['id']) + @todo = current_user.todos.find_by_id(params['id']) respond_to do |format| format.m { render :action => 'show' } format.xml { render :xml => @todo.to_xml( *to_xml_params ) } @@ -280,9 +280,9 @@ class TodosController < ApplicationController def add_predecessor @source_view = params['_source_view'] || 'todo' - @predecessor = current_user.todos.find(params['predecessor']) + @predecessor = current_user.todos.find_by_id(params['predecessor']) @predecessors = @predecessor.predecessors - @todo = current_user.todos.find(params['successor'], :include => Todo::DEFAULT_INCLUDES) + @todo = current_user.todos.find_by_id(params['successor']).includes(Todo::DEFAULT_INCLUDES) @original_state = @todo.state unless @predecessor.completed? @todo.add_predecessor(@predecessor) @@ -301,8 +301,8 @@ class TodosController < ApplicationController def remove_predecessor @source_view = params['_source_view'] || 'todo' - @todo = current_user.todos.find(params['id'], :include => Todo::DEFAULT_INCLUDES) - @predecessor = current_user.todos.find(params['predecessor']) + @todo = current_user.todos.find_by_id(params['id']).includes(Todo::DEFAULT_INCLUDES) + @predecessor = current_user.todos.find_by_id(params['predecessor']) @predecessors = @predecessor.predecessors @successor = @todo @removed = @successor.remove_predecessor(@predecessor) @@ -315,7 +315,7 @@ class TodosController < ApplicationController # Toggles the 'done' status of the action # def toggle_check - @todo = current_user.todos.find(params['id']) + @todo = current_user.todos.find_by_id(params['id']) @source_view = params['_source_view'] || 'todo' @original_item_due = @todo.due @original_item_was_deferred = @todo.deferred? @@ -385,7 +385,7 @@ class TodosController < ApplicationController end def toggle_star - @todo = current_user.todos.find(params['id']) + @todo = current_user.todos.find_by_id(params['id']) @todo.toggle_star! @saved = true # cannot determine error respond_to do |format| @@ -408,9 +408,9 @@ class TodosController < ApplicationController def change_context # TODO: is this method used? - @todo = Todo.find(params[:todo][:id]) + @todo = Todo.find_by_id(params[:todo][:id]) @original_item_context_id = @todo.context_id - @context = Context.find(params[:todo][:context_id]) + @context = Context.find_by_id(params[:todo][:context_id]) @todo.context = @context @saved = @todo.save @@ -426,7 +426,7 @@ class TodosController < ApplicationController end def update - @todo = current_user.todos.find(params['id']) + @todo = current_user.todos.find_by_id(params['id']) @source_view = params['_source_view'] || 'todo' init_data_for_sidebar unless mobile? @@ -480,7 +480,7 @@ class TodosController < ApplicationController def destroy @source_view = params['_source_view'] || 'todo' - @todo = current_user.todos.find(params['id']) + @todo = current_user.todos.find_by_id(params['id']) @original_item_due = @todo.due @context_id = @todo.context_id @project_id = @todo.project_id @@ -565,7 +565,7 @@ class TodosController < ApplicationController @source_view = 'done' @page_title = t('todos.completed_tasks_title') - @done = current_user.todos.completed.paginate :page => params[:page], :per_page => 20, :order => 'completed_at DESC', :include => Todo::DEFAULT_INCLUDES + @done = current_user.todos.completed.includes(Todo::DEFAULT_INCLUDES).order('completed_at DESC').paginate :page => params[:page], :per_page => 20 @count = @done.size end @@ -577,7 +577,7 @@ class TodosController < ApplicationController includes = params[:format]=='xml' ? [:context, :project] : Todo::DEFAULT_INCLUDES - @not_done_todos = current_user.todos.deferred(:include => includes) + current_user.todos.pending(:include => includes) + @not_done_todos = current_user.todos.deferred.includes(includes) + current_user.todos.pending.includes(includes) @down_count = @count = @not_done_todos.size respond_to do |format| @@ -587,8 +587,8 @@ class TodosController < ApplicationController end end - # Check for any due tickler items, activate them Called by - # periodically_call_remote + # Check for any due tickler items, activate them + # Called by periodically_call_remote def check_deferred @due_tickles = current_user.deferred_todos.find_and_activate_ready respond_to do |format| @@ -598,12 +598,12 @@ class TodosController < ApplicationController end def filter_to_context - context = current_user.contexts.find(params['context']['id']) + context = current_user.contexts.find_by_id(params['context']['id']) redirect_to context_todos_path(context, :format => 'm') end def filter_to_project - project = current_user.projects.find(params['project']['id']) + project = current_user.projects.find_by_id(params['project']['id']) redirect_to project_todos_path(project, :format => 'm') end @@ -622,21 +622,29 @@ class TodosController < ApplicationController todos_with_tag_ids = find_todos_with_tag_expr(@tag_expr) - @not_done_todos = todos_with_tag_ids.active.not_hidden.find(:all, - :order => 'todos.due IS NULL, todos.due ASC, todos.created_at ASC', :include => Todo::DEFAULT_INCLUDES) - @hidden_todos = todos_with_tag_ids.hidden.find(:all, - :include => Todo::DEFAULT_INCLUDES, - :order => 'todos.completed_at DESC, todos.created_at DESC') - @deferred = todos_with_tag_ids.deferred.find(:all, - :order => 'todos.show_from ASC, todos.created_at DESC', :include => Todo::DEFAULT_INCLUDES) - @pending = todos_with_tag_ids.blocked.find(:all, - :order => 'todos.show_from ASC, todos.created_at DESC', :include => Todo::DEFAULT_INCLUDES) + @not_done_todos = todos_with_tag_ids. + active.not_hidden. + order('todos.due IS NULL, todos.due ASC, todos.created_at ASC'). + includes(Todo::DEFAULT_INCLUDES) + @hidden_todos = todos_with_tag_ids. + hidden. + order('todos.completed_at DESC, todos.created_at DESC'). + includes(Todo::DEFAULT_INCLUDES) + @deferred = todos_with_tag_ids. + deferred. + order('todos.show_from ASC, todos.created_at DESC'). + includes(Todo::DEFAULT_INCLUDES) + @pending = todos_with_tag_ids. + blocked. + order('todos.show_from ASC, todos.created_at DESC'). + includes(Todo::DEFAULT_INCLUDES) # If you've set no_completed to zero, the completed items box isn't shown on # the tag page - @done = todos_with_tag_ids.completed.find(:all, - :limit => current_user.prefs.show_number_completed, - :order => 'todos.completed_at DESC', :include => Todo::DEFAULT_INCLUDES) + @done = todos_with_tag_ids.completed. + limit(current_user.prefs.show_number_completed). + order('todos.completed_at DESC'). + includes(Todo::DEFAULT_INCLUDES) @projects = current_user.projects @contexts = current_user.contexts @@ -688,15 +696,15 @@ class TodosController < ApplicationController @tag = Tag.find_by_name(@tag_name) @tag = Tag.new(:name => @tag_name) if @tag.nil? - @done = current_user.todos.completed.with_tag(@tag.id).paginate :page => params[:page], :per_page => 20, :order => 'completed_at DESC', :include => Todo::DEFAULT_INCLUDES + @done = current_user.todos.completed.with_tag(@tag.id).order('completed_at DESC').includes(Todo::DEFAULT_INCLUDES).paginate :page => params[:page], :per_page => 20 @count = @done.size render :template => 'todos/all_done' end def tags # TODO: limit to current_user - tags_beginning = Tag.find(:all, :conditions => ['name like ?', params[:term]+'%']) - tags_all = Tag.find(:all, :conditions =>['name like ?', '%'+params[:term]+'%']) + tags_beginning = Tag.where('name like ?', params[:term]+'%') + tags_all = Tag.where('name like ?', '%'+params[:term]+'%') tags_all= tags_all - tags_beginning respond_to do |format| @@ -708,7 +716,7 @@ class TodosController < ApplicationController @source_view = params['_source_view'] || 'todo' numdays = params['days'].to_i - @todo = current_user.todos.find(params[:id]) + @todo = current_user.todos.find_by_id(params[:id]) @original_item_context_id = @todo.context_id @todo_deferred_state_changed = true @new_context_created = false @@ -725,7 +733,7 @@ class TodosController < ApplicationController determine_remaining_in_context_count(@todo.context_id) source_view do |page| page.project { - @remaining_undone_in_project = current_user.projects.find(@todo.project_id).todos.not_completed.count + @remaining_undone_in_project = current_user.projects.find_by_id(@todo.project_id).todos.not_completed.count @original_item_project_id = @todo.project_id } page.tag { @@ -753,45 +761,45 @@ class TodosController < ApplicationController @source_view = params['_source_view'] || 'calendar' @page_title = t('todos.calendar_page_title') - @projects = current_user.projects.find(:all) + @projects = current_user.projects due_today_date = Time.zone.now - due_this_week_date = Time.zone.now.end_of_week + due_this_week_date = due_today_date.end_of_week due_next_week_date = due_this_week_date + 7.days - due_this_month_date = Time.zone.now.end_of_month + due_this_month_date = due_today_date.end_of_month included_tables = Todo::DEFAULT_INCLUDES - @due_today = current_user.todos.not_completed.find(:all, - :include => included_tables, - :conditions => ['todos.due <= ?', due_today_date], - :order => "due") - @due_this_week = current_user.todos.not_completed.find(:all, - :include => included_tables, - :conditions => ['todos.due > ? AND todos.due <= ?', due_today_date, due_this_week_date], - :order => "due") - @due_next_week = current_user.todos.not_completed.find(:all, - :include => included_tables, - :conditions => ['todos.due > ? AND todos.due <= ?', due_this_week_date, due_next_week_date], - :order => "due") - @due_this_month = current_user.todos.not_completed.find(:all, - :include => included_tables, - :conditions => ['todos.due > ? AND todos.due <= ?', due_next_week_date, due_this_month_date], - :order => "due") - @due_after_this_month = current_user.todos.not_completed.find(:all, - :include => included_tables, - :conditions => ['todos.due > ?', due_this_month_date], - :order => "due") + @due_today = current_user.todos.not_completed. + where('todos.due <= ?', due_today_date). + includes(included_tables). + order("due") + @due_this_week = current_user.todos.not_completed. + where('todos.due > ? AND todos.due <= ?', due_today_date, due_this_week_date). + includes(included_tables). + order("due") + @due_next_week = current_user.todos.not_completed. + where('todos.due > ? AND todos.due <= ?', due_this_week_date, due_next_week_date). + includes(included_tables). + order("due") + @due_this_month = current_user.todos.not_completed. + where('todos.due > ? AND todos.due <= ?', due_next_week_date, due_this_month_date). + includes(included_tables). + order("due") + @due_after_this_month = current_user.todos.not_completed. + where('todos.due > ?', due_this_month_date). + includes(included_tables). + order("due") @count = current_user.todos.not_completed.are_due.count respond_to do |format| format.html format.ics { - @due_all = current_user.todos.not_completed.are_due.find(:all, :order => "due") + @due_all = current_user.todos.not_completed.are_due.order("due") render :action => 'calendar', :layout => false, :content_type => Mime::ICS } format.xml { - @due_all = current_user.todos.not_completed.are_due.find(:all, :order => "due") + @due_all = current_user.todos.not_completed.are_due.order("due") render :xml => @due_all.to_xml( *to_xml_params ) } end @@ -810,40 +818,36 @@ class TodosController < ApplicationController unless params['id'].nil? get_todo_from_params # Begin matching todos in current project, excluding @todo itself - @items = @todo.project.todos.not_completed.find(:all, - :include => [:context, :project], - :conditions => ['(LOWER(todos.description) LIKE ?) AND NOT(todos.id=?)', "%#{params[:term].downcase}%", @todo.id], - :order => 'description ASC', - :limit => 10 - ) unless @todo.project.nil? + @items = @todo.project.todos.not_completed. + where('(LOWER(todos.description) LIKE ?) AND NOT(todos.id=?)', "%#{params[:term].downcase}%", @todo.id). + includes(:context, :project). + order('description ASC'). + limit(10) unless @todo.project.nil? # Then look in the current context, excluding @todo itself - @items = @todo.context.todos.not_completed.find(:all, - :include => [:context, :project], - :conditions => ['(LOWER(todos.description) LIKE ?) AND NOT(todos.id=?)', "%#{params[:term].downcase}%", @todo.id], - :order => 'description ASC', - :limit => 10 - ) unless !@items.empty? || @todo.context.nil? + @items = @todo.context.todos.not_completed + where('(LOWER(todos.description) LIKE ?) AND NOT(todos.id=?)', "%#{params[:term].downcase}%", @todo.id). + includes(:context, :project). + order('description ASC'). + limit(10) unless !@items.empty? || @todo.context.nil? # Match todos in other projects, excluding @todo itself - @items = current_user.todos.not_completed.find(:all, - :include => [:context, :project], - :conditions => ['(LOWER(todos.description) LIKE ?) AND NOT(todos.id=?)', "%#{params[:term].downcase}%", @todo.id], - :order => 'description ASC', - :limit => 10 - ) unless !@items.empty? + @items = current_user.todos.not_completed. + where('(LOWER(todos.description) LIKE ?) AND NOT(todos.id=?)', "%#{params[:term].downcase}%", @todo.id). + includes(:context, :project). + order('description ASC'). + limit(10) unless !@items.empty? else # New todo - TODO: Filter on current project in project view - @items = current_user.todos.not_completed.find(:all, - :include => [:context, :project], - :conditions => ['(LOWER(todos.description) LIKE ?)', "%#{params[:term].downcase}%"], - :order => 'description ASC', - :limit => 10 - ) + @items = current_user.todos.not_completed. + where('(LOWER(todos.description) LIKE ?)', "%#{params[:term].downcase}%"). + includes(:context, :project). + order('description ASC'). + limit(10) end render :inline => format_dependencies_as_json_for_auto_complete(@items) end def convert_to_project - @todo = current_user.todos.find(params[:id]) + @todo = current_user.todos.find_by_id(params[:id]) @project = current_user.projects.new(:name => @todo.description, :description => @todo.notes, :default_context => @todo.context) @@ -858,7 +862,7 @@ class TodosController < ApplicationController end def show_notes - @todo = current_user.todos.find(params['id']) + @todo = current_user.todos.find_by_id(params['id']) @return_path=cookies[:mobile_url] ? cookies[:mobile_url] : mobile_path respond_to do |format| format.html { @@ -883,7 +887,7 @@ class TodosController < ApplicationController def get_todo_from_params # TODO: this was a :append_before but was removed to tune performance per # method. Reconsider re-enabling it - @todo = current_user.todos.find(params['id']) + @todo = current_user.todos.find_by_id(params['id']) end def find_and_activate_ready @@ -898,7 +902,7 @@ class TodosController < ApplicationController def with_feed_query_scope(&block) unless TodosController.is_feed_request(request) - Todo.send(:with_scope, :find => {:conditions => ['todos.state = ?', 'active']}) do + Todo.send(:where, ['todos.state = ?', 'active']) do yield return end @@ -939,7 +943,7 @@ class TodosController < ApplicationController condition_builder.add('taggings.tag_id = ?', tag.id) end - Todo.send :with_scope, :find => {:conditions => condition_builder.to_conditions} do + Todo.send :where, condition_builder.to_conditions do yield end @@ -950,14 +954,14 @@ class TodosController < ApplicationController if (params[:context_id]) @context = current_user.contexts.find_by_params(params) @feed_title = @feed_title + t('todos.feed_title_in_context', :context => @context.name) - Todo.send :with_scope, :find => {:conditions => ['todos.context_id = ?', @context.id]} do + Todo.send :where, ['todos.context_id = ?', @context.id] do yield end elsif (params[:project_id]) @project = current_user.projects.find_by_params(params) @feed_title = @feed_title + t('todos.feed_title_in_project', :project => @project.name) @project_feed = true - Todo.send :with_scope, :find => {:conditions => ['todos.project_id = ?', @project.id]} do + Todo.send :where, ['todos.project_id = ?', @project.id] do yield end else @@ -995,13 +999,13 @@ class TodosController < ApplicationController # current_users.todos.find but that broke with_scope for :limit # Exclude hidden projects from count on home page - @todos = current_user.todos.find(:all, :include => Todo::DEFAULT_INCLUDES) + @todos = current_user.todos.includes(Todo::DEFAULT_INCLUDES) # Exclude hidden projects from the home page - @not_done_todos = current_user.todos.find(:all, - :conditions => ['contexts.hide = ? AND (projects.state = ? OR todos.project_id IS NULL)', false, 'active'], - :order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC", - :include => Todo::DEFAULT_INCLUDES) + @not_done_todos = current_user.todos. + where('contexts.hide = ? AND (projects.state = ? OR todos.project_id IS NULL)', false, 'active'). + order("todos.due IS NULL, todos.due ASC, todos.created_at ASC"). + includes(Todo::DEFAULT_INCLUDES) end end @@ -1014,10 +1018,10 @@ class TodosController < ApplicationController # but that broke with_scope for :limit # Exclude hidden projects from the home page - @not_done_todos = current_user.todos.find(:all, - :conditions => ['todos.state = ? AND contexts.hide = ? AND (projects.state = ? OR todos.project_id IS NULL)', 'active', false, 'active'], - :order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC", - :include => [ :project, :context, :tags ]) + @not_done_todos = current_user.todos. + where('todos.state = ? AND contexts.hide = ? AND (projects.state = ? OR todos.project_id IS NULL)', 'active', false, 'active'). + order("todos.due IS NULL, todos.due ASC, todos.created_at ASC"). + includes(:project, :context, :tags) end def tag_title(tag_expr) @@ -1079,23 +1083,23 @@ class TodosController < ApplicationController end from.context do context_id = @original_item_context_id || @todo.context_id - todos = current_user.contexts.find(context_id).todos.not_completed + todos = current_user.contexts.find_by_id(context_id).todos.not_completed if @todo.context.hide? # include hidden todos - @down_count = todos.count(:all) + @down_count = todos.count else # exclude hidden_todos - @down_count = todos.not_hidden.count(:all) + @down_count = todos.not_hidden.count end end from.project do unless @todo.project_id == nil - @down_count = current_user.projects.find(@todo.project_id).todos.active_or_hidden.count + @down_count = current_user.projects.find_by_id(@todo.project_id).todos.active_or_hidden.count end end from.deferred do - @down_count = current_user.todos.deferred_or_blocked.count(:all) + @down_count = current_user.todos.deferred_or_blocked.count end from.tag do @tag_name = params['_tag_name'] @@ -1112,8 +1116,8 @@ class TodosController < ApplicationController source_view do |from| from.deferred { # force reload to todos to get correct count and not a cached one - @remaining_in_context = current_user.contexts.find(context_id).todos.deferred_or_blocked.count - @target_context_count = current_user.contexts.find(@todo.context_id).todos.deferred_or_blocked.count + @remaining_in_context = current_user.contexts.find_by_id(context_id).todos.deferred_or_blocked.count + @target_context_count = current_user.contexts.find_by_id(@todo.context_id).todos.deferred_or_blocked.count } from.tag { tag = Tag.find_by_name(params['_tag_name']) @@ -1121,27 +1125,27 @@ class TodosController < ApplicationController tag = Tag.new(:name => params['tag']) end @remaining_deferred_or_pending_count = current_user.todos.with_tag(tag.id).deferred_or_blocked.count - @remaining_in_context = current_user.contexts.find(context_id).todos.active.not_hidden.with_tag(tag.id).count - @target_context_count = current_user.contexts.find(@todo.context_id).todos.active.not_hidden.with_tag(tag.id).count + @remaining_in_context = current_user.contexts.find_by_id(context_id).todos.active.not_hidden.with_tag(tag.id).count + @target_context_count = current_user.contexts.find_by_id(@todo.context_id).todos.active.not_hidden.with_tag(tag.id).count @remaining_hidden_count = current_user.todos.hidden.with_tag(tag.id).count } from.project { project_id = @project_changed ? @original_item_project_id : @todo.project_id - @remaining_deferred_or_pending_count = current_user.projects.find(project_id).todos.deferred_or_blocked.count + @remaining_deferred_or_pending_count = current_user.projects.find_by_id(project_id).todos.deferred_or_blocked.count if @todo_was_completed_from_deferred_or_blocked_state @remaining_in_context = @remaining_deferred_or_pending_count else - @remaining_in_context = current_user.projects.find(project_id).todos.active_or_hidden.count + @remaining_in_context = current_user.projects.find_by_id(project_id).todos.active_or_hidden.count end - @target_context_count = current_user.projects.find(project_id).todos.active.count + @target_context_count = current_user.projects.find_by_id(project_id).todos.active.count } from.calendar { @target_context_count = @new_due_id.blank? ? 0 : count_old_due_empty(@new_due_id) } from.context { - context = current_user.contexts.find(context_id) + context = current_user.contexts.find_by_id(context_id) @remaining_deferred_or_pending_count = context.todos.deferred_or_blocked.count remaining_actions_in_context = context.todos(true).active @@ -1149,7 +1153,7 @@ class TodosController < ApplicationController @remaining_in_context = remaining_actions_in_context.count if @todo_was_deferred_or_blocked - actions_in_target = current_user.contexts.find(@todo.context_id).todos(true).active + actions_in_target = current_user.contexts.find_by_id(@todo.context_id).todos(true).active actions_in_target = actions_in_target.not_hidden if !context.hide? else actions_in_target = @todo.context.todos.deferred_or_blocked @@ -1157,8 +1161,8 @@ class TodosController < ApplicationController @target_context_count = actions_in_target.count } end - @remaining_in_context = current_user.contexts.find(context_id).todos(true).active.not_hidden.count if !@remaining_in_context - @target_context_count = current_user.contexts.find(@todo.context_id).todos(true).active.not_hidden.count if !@target_context_count + @remaining_in_context = current_user.contexts.find_by_id(context_id).todos(true).active.not_hidden.count if !@remaining_in_context + @target_context_count = current_user.contexts.find_by_id(@todo.context_id).todos(true).active.not_hidden.count if !@target_context_count end def determine_completed_count @@ -1167,13 +1171,13 @@ class TodosController < ApplicationController @completed_count = current_user.todos.not_hidden.completed.count end from.context do - todos = current_user.contexts.find(@todo.context_id).todos.completed + todos = current_user.contexts.find_by_id(@todo.context_id).todos.completed todos = todos.not_hidden if !@todo.context.hidden? @completed_count = todos.count end from.project do unless @todo.project_id == nil - todos = current_user.projects.find(@todo.project_id).todos.completed + todos = current_user.projects.find_by_id(@todo.project_id).todos.completed todos = todos.not_hidden if !@todo.project.hidden? @completed_count = todos.count end @@ -1197,7 +1201,7 @@ class TodosController < ApplicationController # If you've set no_completed to zero, the completed items box isn't shown # on the home page max_completed = current_user.prefs.show_number_completed - @done = current_user.todos.completed.find(:all, :limit => max_completed, :include => Todo::DEFAULT_INCLUDES) unless max_completed == 0 + @done = current_user.todos.completed.limit(max_completed).includes(Todo::DEFAULT_INCLUDES) unless max_completed == 0 # Set count badge to number of not-done, not hidden context items @count = current_user.todos.active.not_hidden.count(:all) @@ -1212,7 +1216,7 @@ class TodosController < ApplicationController @home = true max_completed = current_user.prefs.show_number_completed - @done = current_user.todos.completed.find(:all, :limit => max_completed, :include => Todo::DEFAULT_INCLUDES) unless max_completed == 0 + @done = current_user.todos.completed.limit(max_completed).includes(Todo::DEFAULT_INCLUDES) unless max_completed == 0 cookies[:mobile_url]= { :value => request.request_uri, :secure => SITE_CONFIG['secure_cookies']} determine_down_count @@ -1349,20 +1353,15 @@ class TodosController < ApplicationController due_this_month_date = Time.zone.now.end_of_month case id when "due_today" - return current_user.todos.not_completed.count(:all, - :conditions => ['todos.due <= ?', due_today_date]) + return current_user.todos.not_completed.where('todos.due <= ?', due_today_date).count when "due_this_week" - return current_user.todos.not_completed.count(:all, - :conditions => ['todos.due > ? AND todos.due <= ?', due_today_date, due_this_week_date]) + return current_user.todos.not_completed.where('todos.due > ? AND todos.due <= ?', due_today_date, due_this_week_date).count when "due_next_week" - return current_user.todos.not_completed.count(:all, - :conditions => ['todos.due > ? AND todos.due <= ?', due_this_week_date, due_next_week_date]) + return current_user.todos.not_completed.where('todos.due > ? AND todos.due <= ?', due_this_week_date, due_next_week_date).count when "due_this_month" - return current_user.todos.not_completed.count(:all, - :conditions => ['todos.due > ? AND todos.due <= ?', due_next_week_date, due_this_month_date]) + return current_user.todos.not_completed.where('todos.due > ? AND todos.due <= ?', due_next_week_date, due_this_month_date).count when "due_after_this_month" - return current_user.todos.not_completed.count(:all, - :conditions => ['todos.due > ?', due_this_month_date]) + return current_user.todos.not_completed.where('todos.due > ?', due_this_month_date).count else raise Exception.new, "unknown due id for calendar: '#{id}'" end @@ -1402,7 +1401,7 @@ class TodosController < ApplicationController def update_todo_state_if_project_changed if ( @project_changed ) then @todo.update_state_from_project - @remaining_undone_in_project = current_user.projects.find(@original_item_project_id).todos.active.count if source_view_is :project + @remaining_undone_in_project = current_user.projects.find_by_id(@original_item_project_id).todos.active.count if source_view_is :project end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index f14ef68f..44f8ac0d 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -18,7 +18,7 @@ class UsersController < ApplicationController store_location end format.xml do - @users = User.find(:all, :order => 'login') + @users = User.order('login').all render :xml => @users.to_xml(:except => [ :password ]) end end @@ -139,7 +139,7 @@ class UsersController < ApplicationController def destroy @deleted_user = User.find_by_id(params[:id]) @saved = @deleted_user.destroy - @total_users = User.find(:all).size + @total_users = User.all.size respond_to do |format| format.html do diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index 171d36c5..4bc10054 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -110,7 +110,7 @@ module TodosHelper def successors_span(todo=@todo) unless todo.pending_successors.empty? - pending_count = todo.pending_successors.length + pending_count = todo.pending_successors.count title = "#{t('todos.has_x_pending', :count => pending_count)}: #{todo.pending_successors.map(&:description).join(', ')}" image_tag( 'successor_off.png', :width=>'10', :height=>'16', :border=>'0', :title => title ) end @@ -272,12 +272,12 @@ module TodosHelper end def default_contexts_for_autocomplete - projects = current_user.projects.uncompleted.find(:all, :include => [:default_context], :conditions => ['NOT(default_context_id IS NULL)']) + projects = current_user.projects.uncompleted.includes(:default_context).where('NOT(default_context_id IS NULL)') Hash[*projects.map{ |p| [escape_javascript(p.name), escape_javascript(p.default_context.name)] }.flatten].to_json end def default_tags_for_autocomplete - projects = current_user.projects.uncompleted.find(:all, :conditions => ["default_tags != ''"]) + projects = current_user.projects.uncompleted.where("NOT(default_tags = '')") Hash[*projects.map{ |p| [escape_javascript(p.name), p.default_tags] }.flatten].to_json end diff --git a/app/models/todo.rb b/app/models/todo.rb index ea2297ea..dc92eb39 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -295,14 +295,14 @@ class Todo < ActiveRecord::Base # activate todos that should be activated if the current todo is completed def activate_pending_todos - pending_todos = successors.find_all {|t| t.uncompleted_predecessors.empty?} + pending_todos = successors.select {|t| t.uncompleted_predecessors.empty?} pending_todos.each {|t| t.activate! } return pending_todos end # Return todos that should be blocked if the current todo is undone def block_successors - active_successors = successors.find_all {|t| t.active? or t.deferred?} + active_successors = successors.select {|t| t.active? or t.deferred?} active_successors.each {|t| t.block!} return active_successors end @@ -320,7 +320,7 @@ class Todo < ActiveRecord::Base # value will be a string. In that case convert to array deps = [deps] unless deps.class == Array - deps.each { |dep| self.add_predecessor(self.user.todos.find(dep.to_i)) unless dep.blank? } + deps.each { |dep| self.add_predecessor(self.user.todos.find_by_id(dep.to_i)) unless dep.blank? } end alias_method :original_context=, :context= diff --git a/app/models/user.rb b/app/models/user.rb index 4db04e0a..41f8ae4a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -10,7 +10,7 @@ class User < ActiveRecord::Base :order => 'position ASC', :dependent => :delete_all do def find_by_params(params) - find(params['id'] || params['context_id']) || nil + find_by_id(params['id'] || params['context_id']) || nil end def update_positions(context_ids) context_ids.each_with_index {|id, position| @@ -24,7 +24,7 @@ class User < ActiveRecord::Base :order => 'projects.position ASC', :dependent => :delete_all do def find_by_params(params) - find(params['id'] || params['project_id']) + find_by_id(params['id'] || params['project_id']) end def update_positions(project_ids) project_ids.each_with_index {|id, position| @@ -34,7 +34,7 @@ class User < ActiveRecord::Base } end def projects_in_state_by_position(state) - self.sort{ |a,b| a.position <=> b.position }.select{ |p| p.state == state } + self.sort{ |a,b| a.position <=> b.position }.select{ |p| p.state == state } end def next_from(project) self.offset_from(project, 1) @@ -49,29 +49,29 @@ class User < ActiveRecord::Base projects.at( position + offset) end def cache_note_counts - project_note_counts = Note.count(:group => 'project_id') + project_note_counts = Note.group(:project_id).count self.each do |project| project.cached_note_count = project_note_counts[project.id] || 0 end end def alphabetize(scope_conditions = {}) - projects = find(:all, :conditions => scope_conditions) + projects = where(scope_conditions) projects.sort!{ |x,y| x.name.downcase <=> y.name.downcase } self.update_positions(projects.map{ |p| p.id }) return projects end def actionize(scope_conditions = {}) - todos_in_project = find(:all, :conditions => scope_conditions, :include => [:todos]) + todos_in_project = where(scope_conditions).includes(:todos) todos_in_project.sort!{ |x, y| -(x.todos.active.count <=> y.todos.active.count) } todos_in_project.reject{ |p| p.todos.active.count > 0 } sorted_project_ids = todos_in_project.map {|p| p.id} - all_project_ids = find(:all).map {|p| p.id} + all_project_ids = all.map {|p| p.id} other_project_ids = all_project_ids - sorted_project_ids update_positions(sorted_project_ids + other_project_ids) - return find(:all, :conditions => scope_conditions) + return where(scope_conditions) end end has_many :todos, @@ -85,7 +85,7 @@ class User < ActiveRecord::Base :conditions => [ 'state = ?', 'deferred' ], :order => 'show_from ASC, todos.created_at DESC' do def find_and_activate_ready - find(:all, :conditions => ['show_from <= ?', Time.zone.now ]).collect { |t| t.activate! } + where('show_from <= ?', Time.zone.now).collect { |t| t.activate! } end end has_many :notes, :order => "created_at DESC", :dependent => :delete_all @@ -119,7 +119,7 @@ class User < ActiveRecord::Base def self.authenticate(login, pass) return nil if login.blank? - candidate = find(:first, :conditions => ["login = ?", login]) + candidate = where("login = ?", login).first return nil if candidate.nil? if Tracks::Config.auth_schemes.include?('database') diff --git a/app/views/contexts/_new_context_form.rhtml b/app/views/contexts/_new_context_form.rhtml index f8b6f811..96de88ed 100644 --- a/app/views/contexts/_new_context_form.rhtml +++ b/app/views/contexts/_new_context_form.rhtml @@ -6,7 +6,7 @@
        - <% form_for(@new_context, :html => {:id => 'context-form',:name=>'context',:class => "inline-form", :method => :post }) do -%> + <%= form_for(@new_context, :html => {:id => 'context-form',:name=>'context',:class => "inline-form", :method => :post }) do -%>
        <%= error_messages_for('context') %>
        diff --git a/app/views/data/yaml_form.de.html.erb b/app/views/data/yaml_form.de.html.erb index 7f6baeb7..a1827241 100644 --- a/app/views/data/yaml_form.de.html.erb +++ b/app/views/data/yaml_form.de.html.erb @@ -8,7 +8,7 @@

        Fügen Sie den Inhalt der kopierten YAML Datei in das untenstehende Formular ein:

        - <% form_for :import, @import, :url => {:controller => 'data', :action => 'yaml_import'} do |f| %> + <%= form_for :import, @import, :url => {:controller => 'data', :action => 'yaml_import'} do |f| %> <%= f.text_area :yaml %>
        <% end %> diff --git a/app/views/data/yaml_form.en.html.erb b/app/views/data/yaml_form.en.html.erb index 1b89a9db..c7f04165 100644 --- a/app/views/data/yaml_form.en.html.erb +++ b/app/views/data/yaml_form.en.html.erb @@ -1,14 +1,14 @@

        -

        Beware: all your current data will be destroyed before importing - the YAML file, so if you have access to the database, we strongly recommend +

        Beware: all your current data will be destroyed before importing + the YAML file, so if you have access to the database, we strongly recommend backing up the database right now in case that anything goes wrong.

        Paste the contents of the YAML file you exported into the text box below:

        - <% form_for :import, @import, :url => {:controller => 'data', :action => 'yaml_import'} do |f| %> + <%= form_for :import, @import, :url => {:controller => 'data', :action => 'yaml_import'} do |f| %> <%= f.text_area :yaml %>
        <% end %> diff --git a/app/views/login/login.html.erb b/app/views/login/login.html.erb index c22eb6ab..367cbeed 100644 --- a/app/views/login/login.html.erb +++ b/app/views/login/login.html.erb @@ -11,21 +11,21 @@

        <%= t('login.please_login') %>:

        <% if show_database_form %>
        "> - <% form_tag :action=> 'login' do %> + <%= form_tag :action=> 'login' do %>
        - + - + - + @@ -36,17 +36,17 @@ <% if show_openid_form %>
        "> - <% form_tag :action=> 'login' do %> + <%= form_tag :action=> 'login' do %>
        - + - + @@ -59,7 +59,7 @@
        ">
        - - <%= observe_field( :user_auth_type, :function => "$('#open_id')[0].style.display = value == 'open_id' ? 'table-row' : 'none'") %> <%end%> diff --git a/spec/controllers/projects_controller_spec.rb b/backup.rails2.3/spec/controllers/projects_controller_spec.rb similarity index 100% rename from spec/controllers/projects_controller_spec.rb rename to backup.rails2.3/spec/controllers/projects_controller_spec.rb diff --git a/spec/controllers/todos_controller_spec.rb b/backup.rails2.3/spec/controllers/todos_controller_spec.rb similarity index 100% rename from spec/controllers/todos_controller_spec.rb rename to backup.rails2.3/spec/controllers/todos_controller_spec.rb diff --git a/spec/factories/factories.rb b/backup.rails2.3/spec/factories/factories.rb similarity index 100% rename from spec/factories/factories.rb rename to backup.rails2.3/spec/factories/factories.rb diff --git a/spec/fixtures/contexts.yml b/backup.rails2.3/spec/fixtures/contexts.yml similarity index 100% rename from spec/fixtures/contexts.yml rename to backup.rails2.3/spec/fixtures/contexts.yml diff --git a/spec/fixtures/preferences.yml b/backup.rails2.3/spec/fixtures/preferences.yml similarity index 100% rename from spec/fixtures/preferences.yml rename to backup.rails2.3/spec/fixtures/preferences.yml diff --git a/spec/fixtures/todos.yml b/backup.rails2.3/spec/fixtures/todos.yml similarity index 100% rename from spec/fixtures/todos.yml rename to backup.rails2.3/spec/fixtures/todos.yml diff --git a/spec/fixtures/users.yml b/backup.rails2.3/spec/fixtures/users.yml similarity index 100% rename from spec/fixtures/users.yml rename to backup.rails2.3/spec/fixtures/users.yml diff --git a/spec/models/context_spec.rb b/backup.rails2.3/spec/models/context_spec.rb similarity index 100% rename from spec/models/context_spec.rb rename to backup.rails2.3/spec/models/context_spec.rb diff --git a/spec/models/message_gateway_spec.rb b/backup.rails2.3/spec/models/message_gateway_spec.rb similarity index 100% rename from spec/models/message_gateway_spec.rb rename to backup.rails2.3/spec/models/message_gateway_spec.rb diff --git a/spec/models/todo_spec.rb b/backup.rails2.3/spec/models/todo_spec.rb similarity index 100% rename from spec/models/todo_spec.rb rename to backup.rails2.3/spec/models/todo_spec.rb diff --git a/spec/models/user_spec.rb b/backup.rails2.3/spec/models/user_spec.rb similarity index 100% rename from spec/models/user_spec.rb rename to backup.rails2.3/spec/models/user_spec.rb diff --git a/spec/rcov.opts b/backup.rails2.3/spec/rcov.opts similarity index 100% rename from spec/rcov.opts rename to backup.rails2.3/spec/rcov.opts diff --git a/spec/spec.opts b/backup.rails2.3/spec/spec.opts similarity index 100% rename from spec/spec.opts rename to backup.rails2.3/spec/spec.opts diff --git a/spec/spec_helper.rb b/backup.rails2.3/spec/spec_helper.rb similarity index 100% rename from spec/spec_helper.rb rename to backup.rails2.3/spec/spec_helper.rb diff --git a/spec/support/should_validate_length_of.rb b/backup.rails2.3/spec/support/should_validate_length_of.rb similarity index 100% rename from spec/support/should_validate_length_of.rb rename to backup.rails2.3/spec/support/should_validate_length_of.rb diff --git a/spec/views/login/login_mobile.html.erb_spec.rb b/backup.rails2.3/spec/views/login/login_mobile.html.erb_spec.rb similarity index 100% rename from spec/views/login/login_mobile.html.erb_spec.rb rename to backup.rails2.3/spec/views/login/login_mobile.html.erb_spec.rb diff --git a/spec/views/notes/_notes.rhtml_spec.rb b/backup.rails2.3/spec/views/notes/_notes.rhtml_spec.rb similarity index 100% rename from spec/views/notes/_notes.rhtml_spec.rb rename to backup.rails2.3/spec/views/notes/_notes.rhtml_spec.rb diff --git a/config/routes.rb b/config/routes.rb index 7aec1df6..a12fb3cb 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -60,9 +60,8 @@ Tracksapp::Application.routes.draw do match "tickler" => "todos#list_deferred" match 'review' => "projects#review" - match 'login' => 'users#login' - match 'login_cas' => 'users#login_cas' - match 'logout' => 'users#logout' + match 'login' => 'login#login' + match 'logout' => 'login#logout' match 'calendar' => "todos#calendar" match 'stats' => 'stats#index' match 'done' => "stats#done", :as => 'done_overview' @@ -75,14 +74,15 @@ Tracksapp::Application.routes.draw do match 'preferences/render_date_format' => "preferences#render_date_format" resources :contexts do - collection do - post 'order' - get 'done' - end member do get 'done_todos' get 'all_done_todos' end + collection do + post 'order' + get 'done' + end + resources :todos end resources :projects do @@ -97,6 +97,7 @@ Tracksapp::Application.routes.draw do post 'alphabetize' post 'actionize' end + resources :todos end resources :todos do diff --git a/test/functional/stats_controller_test.rb b/test/functional/stats_controller_test.rb index 47515637..00238f6f 100644 --- a/test/functional/stats_controller_test.rb +++ b/test/functional/stats_controller_test.rb @@ -424,7 +424,6 @@ class StatsControllerTest < ActionController::TestCase assert_equal 2, assigns['count'] end - private def given_todos_for_stats diff --git a/test/functional/todos_controller_test.rb b/test/functional/todos_controller_test.rb index 861e8c97..4887e020 100644 --- a/test/functional/todos_controller_test.rb +++ b/test/functional/todos_controller_test.rb @@ -135,7 +135,7 @@ class TodosControllerTest < ActionController::TestCase put :create, :format => "xml", "request" => { "project_name"=>"Build a working time machine", "todo"=>{"notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006"}, "tag_list"=>"foo bar" } - assert_response 422 + assert_response 409 assert_xml_select "errors" do assert_xml_select "error", "Context can't be blank" end diff --git a/test/integration/context_xml_api_test.rb b/test/integration/context_xml_api_test.rb index 660a3c97..7049a693 100644 --- a/test/integration/context_xml_api_test.rb +++ b/test/integration/context_xml_api_test.rb @@ -1,60 +1,39 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') -require 'contexts_controller' - -# Re-raise errors caught by the controller. -class ContextsController; def rescue_action(e) raise e end; end class ContextXmlApiTest < ActionController::IntegrationTest - fixtures :users, :contexts, :preferences @@context_name = "@newcontext" - @@valid_postdata = "#{@@context_name}" + @@valid_postdata = "#{@@context_name}" - def setup - assert_test_environment_ok - end - - def test_fails_with_invalid_xml_format - # Fails too hard for test to catch - # authenticated_post_xml_to_context_create "" - # assert_equal 500, @integration_session.status - end + # def test_fails_with_invalid_xml_format + # # Fails too hard for test to catch + # authenticated_post_xml_to_context_create "" + # assert_response 500 + # end - def test_fails_with_invalid_xml_format2 - authenticated_post_xml_to_context_create "" - assert_404_invalid_xml - end - def test_xml_simple_param_parsing authenticated_post_xml_to_context_create - assert @controller.params.has_key?(:request) - assert @controller.params[:request].has_key?(:context) - assert @controller.params[:request][:context].has_key?(:name) - assert_equal @@context_name, @controller.params[:request][:context][:name] + assert @controller.params.has_key?(:context) + assert @controller.params[:context].has_key?(:name) + assert_equal @@context_name, @controller.params[:context][:name] end + def test_fails_gracefully_with_invalid_xml_format + authenticated_post_xml_to_context_create "" + assert_responses_with_error 'Name context must have a name' + end + def test_fails_with_too_long_name - invalid_with_long_name_postdata = "foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoo arfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoo arfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfo barfoobarfoobarfoobarfoobarfoobarfoobar" + invalid_with_long_name_postdata = "foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoo arfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoo arfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfo barfoobarfoobarfoobarfoobarfoobarfoobar" authenticated_post_xml_to_context_create invalid_with_long_name_postdata - assert_response 409 - assert_xml_select 'errors' do - assert_select 'error', 1, 'Name context name must be less than 256 characters' - end + assert_responses_with_error 'Name context name must be less than 256 characters' end - def test_fails_with_comma_in_name - authenticated_post_xml_to_context_create "foo,bar" - assert_response 409 - assert_xml_select 'errors' do - assert_select 'error', 1, 'Name cannot contain the comma (\',\') character' - end - end - - def test_fails_with_401_if_not_authorized_user + def test_fails_with_401_if_not_authorized_user authenticated_post_xml_to_context_create @@valid_postdata, 'nobody', 'nohow' assert_response 401 end - + def test_creates_new_context assert_difference 'Context.count' do authenticated_post_xml_to_context_create @@ -67,11 +46,7 @@ class ContextXmlApiTest < ActionController::IntegrationTest private def authenticated_post_xml_to_context_create(postdata = @@valid_postdata, user = users(:other_user).login, password = 'sesame') - authenticated_post_xml "/contexts", user, password, postdata + authenticated_post_xml "/contexts.xml", user, password, postdata end - def assert_404_invalid_xml - assert_response_and_body 400, "Expected post format is valid xml like so: context name." - end - end diff --git a/test/integration/feed_smoke_test.rb b/test/integration/feed_smoke_test.rb index fff1d7d9..e69b2a8f 100644 --- a/test/integration/feed_smoke_test.rb +++ b/test/integration/feed_smoke_test.rb @@ -1,28 +1,15 @@ require File.expand_path( File.dirname(__FILE__) + '/../test_helper') -require 'projects_controller' -require 'contexts_controller' -require 'todos_controller' - -# Re-raise errors caught by the controller. -class ProjectsController; def rescue_action(e) raise e end; end -class ContextsController; def rescue_action(e) raise e end; end -class TodosController; def rescue_action(e) raise e end; end class FeedSmokeTest < ActionController::IntegrationTest - fixtures :users, :preferences, :projects, :contexts, :todos, :recurring_todos, :notes - - def setup - assert_test_environment_ok - end def test_last_15_actions_rss assert_success "/todos.rss?token=#{ users(:admin_user).token }&limit=15" end - + def test_last_15_actions_atom assert_success "/todos.atom?token=#{ users(:admin_user).token }&limit=15" end - + def test_last_15_actions_txt assert_success "/todos.txt?token=#{ users(:admin_user).token }&limit=15" end @@ -34,39 +21,39 @@ class FeedSmokeTest < ActionController::IntegrationTest def test_all_actions_rss assert_success "/todos.rss?token=#{ users(:admin_user).token }" end - + def test_all_actions_txt assert_success "/todos.txt?token=#{ users(:admin_user).token }" end - + def test_all_actions_ical assert_success "/todos.ics?token=#{ users(:admin_user).token }" end - + def test_all_actions_in_context_rss assert_success "/contexts/1/todos.rss?token=#{ users(:admin_user).token }" end - + def test_all_actions_in_context_txt assert_success "/contexts/1/todos.txt?token=#{ users(:admin_user).token }" end - + def test_all_actions_in_context_ical assert_success "/contexts/1/todos.ics?token=#{ users(:admin_user).token }" end - + def test_all_actions_in_project_rss assert_success "/projects/1/todos.rss?token=#{ users(:admin_user).token }" end - + def test_all_actions_in_project_txt assert_success "/projects/1/todos.txt?token=#{ users(:admin_user).token }" end - + def test_all_actions_in_project_ical assert_success "/projects/1/todos.ics?token=#{ users(:admin_user).token }" end - + def test_all_actions_due_today_or_earlier_rss assert_success "/todos.rss?token=#{ users(:admin_user).token }&due=0" end @@ -98,27 +85,27 @@ class FeedSmokeTest < ActionController::IntegrationTest def test_all_actions_completed_in_last_7_days_txt assert_success "/todos.txt?token=#{ users(:admin_user).token }&done=7" end - + def test_all_contexts_rss assert_success "/contexts.rss?token=#{ users(:admin_user).token }" end - + def test_all_contexts_txt assert_success "/contexts.txt?token=#{ users(:admin_user).token }" end - + def test_all_projects_rss assert_success "/projects.rss?token=#{ users(:admin_user).token }" end - + def test_all_projects_txt assert_success "/projects.txt?token=#{ users(:admin_user).token }" end - + def test_calendar_ics assert_success "/calendar.ics?token=#{ users(:admin_user).token }" end - + def test_all_projects_txt_with_hidden_project p = projects(:timemachine) p.hide! diff --git a/test/integration/ldap_auth_test.rb b/test/integration/ldap_auth_test.rb deleted file mode 100755 index 76866740..00000000 --- a/test/integration/ldap_auth_test.rb +++ /dev/null @@ -1,145 +0,0 @@ -require File.expand_path( File.dirname(__FILE__) + '/../test_helper') -require 'tempfile' - -module Tracks - class Config - def self.salt - "change-me" - end - def self.auth_schemes - ['database','ldap'] - end - end -end - -class LdapAuthTest < ActionController::IntegrationTest - - fixtures :users - - RUN_LDAP_TESTS = ENV['RUN_TRACKS_LDAP_TESTS'] || false - SLAPD_BIN = "/usr/libexec/slapd" #You may need to adjust this - SLAPD_SCHEMA_DIR = "/etc/openldap/schema/" #You may need to adjust this - SLAPD_TEST_PORT = 10389 - OUTPUT_DEBUG_INFO = false - - begin - require 'net/ldap' #requires ruby-net-ldap gem be installed - require 'simple_ldap_authenticator' - end if RUN_LDAP_TESTS - - SimpleLdapAuthenticator.ldap_library = 'net/ldap' - SimpleLdapAuthenticator.servers = %w'localhost' - SimpleLdapAuthenticator.use_ssl = false - SimpleLdapAuthenticator.login_format = 'cn=%s,dc=lukemelia,dc=com' - SimpleLdapAuthenticator.port = 10389 - SimpleLdapAuthenticator.logger = RAILS_DEFAULT_LOGGER - - def setup - assert_equal "test", ENV['RAILS_ENV'] - assert_equal "change-me", Tracks::Config.salt - - if RUN_LDAP_TESTS - setup_ldap_server_conf - start_ldap_server - end - end - - def teardown - stop_ldap_server if RUN_LDAP_TESTS - end - - def test_authenticate_against_ldap - add_ldap_user_to_ldap_repository - assert SimpleLdapAuthenticator.valid?('john', 'deere') - user = User.authenticate('john', 'deere') - assert_not_nil(user) - assert_equal user.login, 'john' - end - - private :test_authenticate_against_ldap unless RUN_LDAP_TESTS - - def setup_ldap_server_conf - @slapd_conf = create_slapd_conf() - open(@slapd_conf.path) { |f| f.read } - unless File.exist?(SLAPD_BIN) - assert false, "slapd could not be found at #{SLAPD_BIN}. Adjust the path in #{__FILE__}" - end - end - - def start_ldap_server - t = Thread.new(@slapd_conf.path) do |slapd_conf_path| - puts "starting slapd..." if OUTPUT_DEBUG_INFO - run_cmd %Q{/usr/libexec/slapd -f #{slapd_conf_path} -h "ldap://127.0.0.1:10389/" -d0} - end - sleep(2) - run_cmd %Q{ldapsearch -H "ldap://127.0.0.1:10389/" -x -b '' -s base '(objectclass=*)' namingContexts} - end - - def add_ldap_user_to_ldap_repository - ldif_file = create_ldif() - run_cmd %Q{ldapadd -H "ldap://127.0.0.1:10389/" -f #{ldif_file.path} -cxv -D "cn=Manager,dc=lukemelia,dc=com" -w secret} - puts `cat #{ldif_file.path}` if OUTPUT_DEBUG_INFO - end - - def stop_ldap_server - pid = open(get_pid_file_path(@slapd_conf)) { |f| f.read } - run_cmd "kill -TERM #{pid}" - end - - def create_slapd_conf - slapd_conf = Tempfile.new("slapd.conf") - slapd_conf.path - data_dir = slapd_conf.path + '-data' - pid_file = get_pid_file_path(slapd_conf) - Dir.mkdir(data_dir) - encrypted_password = `slappasswd -s secret` - open(slapd_conf.path, 'w') do |f| - f.puts %Q{include #{SLAPD_SCHEMA_DIR}core.schema -pidfile #{pid_file} -database ldbm -suffix "dc=lukemelia,dc=com" -rootdn "cn=Manager,dc=lukemelia,dc=com" -rootpw #{encrypted_password} -directory #{data_dir} - -access to * - by self write - by users read - by anonymous auth -} - end - puts `cat #{slapd_conf.path}` if OUTPUT_DEBUG_INFO - slapd_conf - end - - def create_ldif - ldif_file = Tempfile.new("ldap_user.ldif") - encrypted_password = `slappasswd -s deere` - open(ldif_file.path, 'w') do |f| - f.puts %Q{dn: dc=lukemelia,dc=com -objectclass: dcObject -objectclass: organization -o: Luke Melia DotCom -dc: lukemelia - -dn: cn=john,dc=lukemelia,dc=com -cn: john -sn: john -objectclass: person -userPassword: #{encrypted_password} -} - end - ldif_file - end - - def run_cmd(cmd) - puts cmd if OUTPUT_DEBUG_INFO - cmd_out = `#{cmd}` - puts cmd_out if OUTPUT_DEBUG_INFO - end - - def get_pid_file_path(tempfile) - tempfile.path + '.pid' - end - -end diff --git a/test/integration/project_xml_api_test.rb b/test/integration/project_xml_api_test.rb index 47b6f734..43287eaf 100644 --- a/test/integration/project_xml_api_test.rb +++ b/test/integration/project_xml_api_test.rb @@ -1,21 +1,11 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') -require 'projects_controller' - -# Re-raise errors caught by the controller. -class ProjectsController; def rescue_action(e) raise e end; end class ProjectXmlApiTest < ActionController::IntegrationTest - fixtures :users, :projects - @@project_name = "My New Project" - @@valid_postdata = "#{@@project_name}" - - def setup - assert_test_environment_ok - end + @@valid_postdata = "#{@@project_name}" def test_retrieve_project - authenticated_get_xml "/projects/1", users(:admin_user).login, 'abracadabra', {} + authenticated_get_xml "/projects/1.xml", users(:admin_user).login, 'abracadabra', {} assert_tag :tag => "project" assert_tag :tag => "project", :child => {:tag => "not_done" } assert_tag :tag => "project", :child => {:tag => "deferred" } @@ -32,30 +22,29 @@ class ProjectXmlApiTest < ActionController::IntegrationTest def test_fails_with_invalid_xml_format2 authenticated_post_xml_to_project_create "" - assert_404_invalid_xml + assert_responses_with_error 'Name project must have a name' end def test_xml_simple_param_parsing authenticated_post_xml_to_project_create - assert @controller.params.has_key?(:request) - assert @controller.params[:request].has_key?(:project) - assert @controller.params[:request][:project].has_key?(:name) - assert_equal @@project_name, @controller.params[:request][:project][:name] + assert @controller.params.has_key?(:project) + assert @controller.params[:project].has_key?(:name) + assert_equal @@project_name, @controller.params[:project][:name] end - def test_fails_with_401_if_not_authorized_user + def test_fails_with_401_if_not_authorized_user authenticated_post_xml_to_project_create @@valid_postdata, 'nobody', 'nohow' assert_response 401 end def test_fails_with_too_long_name - invalid_with_long_name_postdata = "foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoo arfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoo arfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfo barfoobarfoobarfoobarfoobarfoobarfoobar" + invalid_with_long_name_postdata = "foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoo arfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoo arfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfo barfoobarfoobarfoobarfoobarfoobarfoobar" authenticated_post_xml_to_project_create invalid_with_long_name_postdata - assert_response_and_body 404, "Name project name must be less than 256 characters" + assert_responses_with_error 'Name context name must be less than 256 characters' end def test_fails_with_comma_in_name - authenticated_post_xml_to_project_create "foo,bar" + authenticated_post_xml_to_project_create "foo,bar" assert_response :created project1 = Project.find_by_name("foo,bar") assert_not_nil project1, "expected project 'foo,bar' to be created" @@ -73,11 +62,11 @@ class ProjectXmlApiTest < ActionController::IntegrationTest private def authenticated_post_xml_to_project_create(postdata = @@valid_postdata, user = users(:other_user).login, password = 'sesame') - authenticated_post_xml "/projects", user, password, postdata + authenticated_post_xml "/projects.xml", user, password, postdata end def assert_404_invalid_xml - assert_response_and_body 404, "Expected post format is valid xml like so: project name." + assert_response_and_body 404, "Expected post format is valid xml like so: project name." end end diff --git a/test/integration/recurring_todos_test.rb b/test/integration/recurring_todos_test.rb index 9cf4707d..004e6840 100644 --- a/test/integration/recurring_todos_test.rb +++ b/test/integration/recurring_todos_test.rb @@ -1,9 +1,6 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') -require 'todos_controller' -require 'recurring_todos_controller' class RecurringTodosTest < ActionController::IntegrationTest - fixtures :users, :preferences, :projects, :contexts, :todos, :tags, :taggings, :recurring_todos def logs_in_as(user,plain_pass) @user = user @@ -16,22 +13,21 @@ class RecurringTodosTest < ActionController::IntegrationTest assert_template "todos/index" end - def test_deleting_recurring_todo_clears_reference_from_related_todos logs_in_as(users(:admin_user), 'abracadabra') rt = RecurringTodo.find(1) assert !rt.nil? # given there is a recurring todo - assert rt.todos.size, 1 # and it has one todos referencing it + assert_equal 1, rt.todos.size # and it has one todo referencing it # when I toggle the todo complete todo = Todo.find_by_recurring_todo_id(1) - post "/todos/toggle_check/#{todo.id}", :_source_view => 'todo' + put "/todos/#{todo.id}/toggle_check", :_source_view => 'todo' todo.reload assert todo.completed? rt.reload # then there should be two todos referencing - assert rt.todos.size, 2 + assert_equal 2, rt.todos.size todo2 = Todo.find(:first, :conditions => {:recurring_todo_id => rt.id, :state => 'active'}) assert_not_equal todo2.id, todo.id # and the todos should be different diff --git a/test/integration/stories_test.rb b/test/integration/stories_test.rb index 109e9ca1..4a9ce419 100644 --- a/test/integration/stories_test.rb +++ b/test/integration/stories_test.rb @@ -1,11 +1,6 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') class StoriesTest < ActionController::IntegrationTest - fixtures :users, :preferences, :projects, :contexts, :todos, :recurring_todos, :notes - - def setup - assert_test_environment_ok - end # #################################################### # Testing login and signup by different kinds of users @@ -13,7 +8,7 @@ class StoriesTest < ActionController::IntegrationTest def test_signup_new_user_by_admin admin = new_session_as(:admin_user,"abracadabra") admin.goes_to_signup - admin.signs_up_with(:user => {:login => "newbie", + admin.signs_up_with(:user => {:login => "newbie", :password => "newbiepass", :password_confirmation => "newbiepass"}) end @@ -31,8 +26,8 @@ class StoriesTest < ActionController::IntegrationTest def logs_in_as(user,plain_pass) @user = user - post "/login", :user_login => @user.login, - :user_password => plain_pass, + post "/login", :user_login => @user.login, + :user_password => plain_pass, :user_noexpiry => 'n' assert_response :redirect follow_redirect! diff --git a/test/integration/todo_xml_api_test.rb b/test/integration/todo_xml_api_test.rb index 0f88e52c..69510d5d 100644 --- a/test/integration/todo_xml_api_test.rb +++ b/test/integration/todo_xml_api_test.rb @@ -1,19 +1,15 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') -require 'todos_controller' class TodoXmlApiTest < ActionController::IntegrationTest - fixtures :users, :contexts, :preferences, :todos, :projects - @@valid_postdata = "this will succeed104" def setup - assert_test_environment_ok @user = users(:admin_user) @password = 'abracadabra' end def test_get_tickler_succeeds - authenticated_get_xml "/tickler", @user.login, @password, {} + authenticated_get_xml "/tickler.xml", @user.login, @password, {} assert_response 200 end @@ -21,18 +17,18 @@ class TodoXmlApiTest < ActionController::IntegrationTest get '/tickler.xml', {}, {} assert_response 401 - get "/tickler", {}, {'AUTHORIZATION' => "Basic " + Base64.encode64("wrong:wrong"),'ACCEPT' => 'application/xml'} + get "/tickler.xml", {}, {'HTT_AUTHORIZATION' => "Basic " + Base64.encode64("wrong:wrong"),'ACCEPT' => 'application/xml'} assert_response 401 end def test_get_tickler_returns_all_deferred_and_pending_todos number = @user.todos.deferred.count + @user.todos.pending.count - authenticated_get_xml "/tickler", @user.login, @password, {} + authenticated_get_xml "/tickler.xml", @user.login, @password, {} assert_tag :tag => "todos", :children => { :count => number } end def test_get_tickler_omits_user_id - authenticated_get_xml "/tickler", @user.login, @password, {} + authenticated_get_xml "/tickler.xml", @user.login, @password, {} assert_no_tag :tag => "user_id" end @@ -225,7 +221,7 @@ class TodoXmlApiTest < ActionController::IntegrationTest assert_not_nil todo assert_not_nil todo.project assert_equal projects(:timemachine).name, todo.project.name - assert 1, @user.projects.all(:conditions => ["projects.name = ?", projects(:timemachine).name]).count # no duplication of project + assert_equal 1, @user.projects.where("projects.name" => projects(:timemachine).name).count # no duplication of project end def test_post_create_todo_with_wrong_project_and_context_id @@ -235,7 +231,7 @@ class TodoXmlApiTest < ActionController::IntegrationTest -16 -11 " - assert_response 422 + assert_response 409 assert_xml_select 'errors' do assert_select 'error', 2 end @@ -249,7 +245,7 @@ class TodoXmlApiTest < ActionController::IntegrationTest private def authenticated_post_xml_to_todo_create(postdata = @@valid_postdata, user = @user.login, password = @password) - authenticated_post_xml "/todos", user, password, postdata + authenticated_post_xml "/todos.xml", user, password, postdata end end \ No newline at end of file diff --git a/test/integration/users_xml_api_test.rb b/test/integration/users_xml_api_test.rb index 25cb5b2e..5fbc56f1 100644 --- a/test/integration/users_xml_api_test.rb +++ b/test/integration/users_xml_api_test.rb @@ -1,18 +1,9 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') -require 'users_controller' - -# Re-raise errors caught by the controller. -class UsersController; def rescue_action(e) raise e end; end class UsersXmlApiTest < ActionController::IntegrationTest - fixtures :users - @@foobar_postdata = "foobar" - @@johnny_postdata = "johnnybarracuda" - - def setup - assert_test_environment_ok - end + @@foobar_postdata = "foobar" + @@johnny_postdata = "johnnybarracuda" def test_fails_with_401_if_not_authorized_user authenticated_post_xml_to_user_create @@foobar_postdata, 'nobody', 'nohow' @@ -26,7 +17,7 @@ class UsersXmlApiTest < ActionController::IntegrationTest def test_content_type_must_be_xml authenticated_post_xml_to_user_create @@foobar_postdata, users(:admin_user).login, 'abracadabra', {'CONTENT_TYPE' => "application/x-www-form-urlencoded"} - assert_404_invalid_xml + assert_response 400, "Expected response 400" end # Fails too hard for test to catch @@ -36,43 +27,43 @@ class UsersXmlApiTest < ActionController::IntegrationTest # end def test_fails_with_invalid_xml_format2 - authenticated_post_xml_to_user_create "foo" - assert_404_invalid_xml + authenticated_post_xml_to_user_create "foo" + assert_response_and_body 400, "Expected post format is valid xml like so: usernameabc123." end def test_xml_simple_param_parsing authenticated_post_xml_to_user_create - assert @controller.params.has_key?(:request) - assert @controller.params[:request].has_key?(:login) - assert @controller.params[:request].has_key?(:password) - assert_equal 'foo', @controller.params[:request][:login] - assert_equal 'bar', @controller.params[:request][:password] + assert @controller.params.has_key?(:user) + assert @controller.params['user'].has_key?(:login) + assert @controller.params['user'].has_key?(:password) + assert_equal 'foo', @controller.params['user'][:login] + assert_equal 'bar', @controller.params['user'][:password] end def test_fails_with_too_short_password authenticated_post_xml_to_user_create - assert_response_and_body 404, "\n\n Password is too short (minimum is 5 characters)\n\n" + assert_responses_with_error "Password is too short (minimum is 5 characters" end def test_fails_with_nonunique_login existing_login = users(:other_user).login - authenticated_post_xml_to_user_create "#{existing_login}barracuda" - assert_response_and_body 404, "\n\n Login has already been taken\n\n" + authenticated_post_xml_to_user_create "#{existing_login}barracuda" + assert_responses_with_error "Login has already been taken" end def test_creates_new_user - initial_count = User.count - authenticated_post_xml_to_user_create @@johnny_postdata - assert_response_and_body 200, "User created." - assert_equal initial_count + 1, User.count + assert_difference 'User.count' do + authenticated_post_xml_to_user_create @@johnny_postdata + assert_response_and_body 200, "User created." + end johnny1 = User.find_by_login('johnny') assert_not_nil johnny1, "expected user johnny to be created" johnny2 = User.authenticate('johnny','barracuda') - assert_not_nil johnny2, "expected user johnny to be created" + assert_not_nil johnny2, "expected user johnny to be authenticated" end def test_fails_with_get_verb - authenticated_get_xml "/users", users(:admin_user).login, 'abracadabra', {} + authenticated_get_xml "/users.xml", users(:admin_user).login, 'abracadabra', {} end def test_get_users_as_xml @@ -93,15 +84,10 @@ class UsersXmlApiTest < ActionController::IntegrationTest private def basic_auth_headers(username = users(:admin_user).login, password = 'abracadabra') - {'AUTHORIZATION' => "Basic " + Base64.encode64("#{username}:#{password}") } + {'HTTP_AUTHORIZATION' => "Basic " + Base64.encode64("#{username}:#{password}") } end def authenticated_post_xml_to_user_create(postdata = @@foobar_postdata, user = users(:admin_user).login, password = 'abracadabra', headers = {}) - authenticated_post_xml "/users", user, password, postdata, headers + authenticated_post_xml "/users.xml", user, password, postdata, headers end - - def assert_404_invalid_xml - assert_response_and_body 404, "Expected post format is valid xml like so: usernameabc123." - end - end diff --git a/test/test_helper.rb b/test/test_helper.rb index 48338644..78d3af96 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -36,6 +36,14 @@ class ActiveSupport::TestCase assert_equal date1.strftime("%d-%m-%y"), date2.strftime("%d-%m-%y") end + def xml_document + @xml_document ||= HTML::Document.new(@response.body, false, true) + end + + def assert_xml_select(*args, &block) + @html_document = xml_document + assert_select(*args, &block) + end end class ActionController::TestCase @@ -68,10 +76,6 @@ class ActionController::TestCase private - def xml_document - @xml_document ||= HTML::Document.new(@response.body, false, true) - end - def get_model_class @controller.class.to_s.tableize.split("_")[0].camelcase.singularize #don't ask... converts ContextsController to Context end @@ -80,4 +84,49 @@ class ActionController::TestCase eval("#{get_model_class}.count") end +end + +class ActionController::IntegrationTest + + def authenticated_post_xml(url, username, password, parameters, headers = {}) + post url, parameters, + { 'HTTP_AUTHORIZATION' => "Basic " + Base64.encode64("#{username}:#{password}"), + 'ACCEPT' => 'application/xml', + 'CONTENT_TYPE' => 'application/xml' + }.merge(headers) + end + + def authenticated_get_xml(url, username, password, parameters, headers = {}) + get url, parameters, + { 'HTTP_AUTHORIZATION' => "Basic " + Base64.encode64("#{username}:#{password}"), + 'ACCEPT' => 'application/xml', + 'CONTENT_TYPE' => 'application/xml' + }.merge(headers) + end + + def assert_response_and_body(type, body, message = nil) + assert_equal body, @response.body, message + assert_response type, message + end + + def assert_response_and_body_matches(type, body_regex, message = nil) + assert_response type, message + assert_match body_regex, @response.body, message + end + + def assert_401_unauthorized + assert_response_and_body 401, "401 Unauthorized: You are not authorized to interact with Tracks." + end + + def assert_401_unauthorized_admin + assert_response_and_body 401, "401 Unauthorized: Only admin users are allowed access to this function." + end + + def assert_responses_with_error(error_msg) + assert_response 409 + assert_xml_select 'errors' do + assert_select 'error', 1, error_msg + end + end + end \ No newline at end of file diff --git a/test/unit/todo_test.rb b/test/unit/todo_test.rb index 4d3acf6c..b025b3c8 100644 --- a/test/unit/todo_test.rb +++ b/test/unit/todo_test.rb @@ -120,12 +120,6 @@ class TodoTest < ActiveSupport::TestCase assert_equal :deferred, todo.aasm_current_state end - def test_feed_options - opts = Todo.feed_options(users(:admin_user)) - assert_equal 'Tracks Actions', opts[:title], 'Unexpected value for :title key of feed_options' - assert_equal 'Actions for Admin Schmadmin', opts[:description], 'Unexpected value for :description key of feed_options' - end - def test_toggle_completion t = @not_completed1 assert_equal :active, t.aasm_current_state From 393eae193722c71473900de610ff73aa5f366f37 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Fri, 27 Apr 2012 16:13:29 +0200 Subject: [PATCH 113/134] clean up gemfile and remove vendored aruba gem --- Gemfile | 29 +-- Gemfile.lock | 95 ++++++-- vendor/gems/aruba-0.2.2/.bundle/config | 2 - vendor/gems/aruba-0.2.2/.document | 5 - vendor/gems/aruba-0.2.2/.gitignore | 23 -- vendor/gems/aruba-0.2.2/.specification | 89 ------- vendor/gems/aruba-0.2.2/Gemfile | 5 - vendor/gems/aruba-0.2.2/History.txt | 84 ------- vendor/gems/aruba-0.2.2/LICENSE | 20 -- vendor/gems/aruba-0.2.2/README.rdoc | 41 ---- vendor/gems/aruba-0.2.2/Rakefile | 13 -- vendor/gems/aruba-0.2.2/aruba.gemspec | 24 -- vendor/gems/aruba-0.2.2/config/.gitignore | 1 - .../features/exit_statuses.feature | 21 -- .../features/file_system_commands.feature | 84 ------- .../gems/aruba-0.2.2/features/output.feature | 96 -------- .../step_definitions/aruba_dev_steps.rb | 24 -- .../gems/aruba-0.2.2/features/support/env.rb | 15 -- vendor/gems/aruba-0.2.2/lib/aruba.rb | 0 vendor/gems/aruba-0.2.2/lib/aruba/api.rb | 220 ------------------ vendor/gems/aruba-0.2.2/lib/aruba/cucumber.rb | 188 --------------- 21 files changed, 87 insertions(+), 992 deletions(-) delete mode 100644 vendor/gems/aruba-0.2.2/.bundle/config delete mode 100644 vendor/gems/aruba-0.2.2/.document delete mode 100644 vendor/gems/aruba-0.2.2/.gitignore delete mode 100644 vendor/gems/aruba-0.2.2/.specification delete mode 100644 vendor/gems/aruba-0.2.2/Gemfile delete mode 100644 vendor/gems/aruba-0.2.2/History.txt delete mode 100644 vendor/gems/aruba-0.2.2/LICENSE delete mode 100644 vendor/gems/aruba-0.2.2/README.rdoc delete mode 100644 vendor/gems/aruba-0.2.2/Rakefile delete mode 100644 vendor/gems/aruba-0.2.2/aruba.gemspec delete mode 100644 vendor/gems/aruba-0.2.2/config/.gitignore delete mode 100644 vendor/gems/aruba-0.2.2/features/exit_statuses.feature delete mode 100644 vendor/gems/aruba-0.2.2/features/file_system_commands.feature delete mode 100644 vendor/gems/aruba-0.2.2/features/output.feature delete mode 100644 vendor/gems/aruba-0.2.2/features/step_definitions/aruba_dev_steps.rb delete mode 100644 vendor/gems/aruba-0.2.2/features/support/env.rb delete mode 100644 vendor/gems/aruba-0.2.2/lib/aruba.rb delete mode 100644 vendor/gems/aruba-0.2.2/lib/aruba/api.rb delete mode 100644 vendor/gems/aruba-0.2.2/lib/aruba/cucumber.rb diff --git a/Gemfile b/Gemfile index 2fe1dd4a..47989c8d 100644 --- a/Gemfile +++ b/Gemfile @@ -10,24 +10,17 @@ gem 'rails', '3.2.3' gem "sqlite3" gem "mysql2" -gem "highline", "~>1.5.0" +# gem "highline", "~>1.5.0" gem "RedCloth" gem "formatize" -gem "sanitize", "~>1.2.1" +gem "sanitize" gem "will_paginate" -gem "acts_as_list", "~>0.1.4" -gem "aasm", "~>2.2.0" -gem 'htmlentities', '~> 4.3.0' -gem "mail" +gem "acts_as_list" +gem "aasm" +gem "htmlentities" gem "swf_fu" gem "rails_autolink" -if RUBY_VERSION.to_f >= 1.9 - gem "soap4r-ruby1.9" -else - gem "soap4r", "~>1.5.8" -end - # Gems used only for assets and not required # in production environments by default. group :assets do @@ -72,13 +65,13 @@ group :test do # gem "hpricot" # gem "hoe" # gem "rspec-rails", "~>1.3.3" -# # TODO: gem "thoughtbot-factory_girl" # gem 'memory_test_fix', '~>0.1.3' -# gem "capybara", ">=0.3.5" -# gem "selenium-webdriver" # Note that > 2.14 has problems: https://code.google.com/p/selenium/issues/detail?id=3075 -# gem "database_cleaner", ">=0.5.0" -# gem "cucumber-rails", "~>0.3.2" -# gem "aruba", "0.2.2", :path => "vendor/gems/aruba-0.2.2" + gem "factory_girl_rails" + gem "capybara" + gem "selenium-webdriver" # Note that > 2.14 has problems: https://code.google.com/p/selenium/issues/detail?id=3075 + gem "database_cleaner" + gem "cucumber-rails" + gem "aruba" # uncomment to use the webkit option. This depends on Qt to be installed #gem "capybara-webkit" diff --git a/Gemfile.lock b/Gemfile.lock index 39cfc5b8..e0bd1fbf 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,7 +2,8 @@ GEM remote: https://rubygems.org/ specs: RedCloth (4.2.9) - aasm (2.2.1) + aasm (3.0.5) + activerecord actionmailer (3.2.3) actionpack (= 3.2.3) mail (~> 2.4.4) @@ -30,11 +31,26 @@ GEM activesupport (3.2.3) i18n (~> 0.6) multi_json (~> 1.0) - acts_as_list (0.1.5) + acts_as_list (0.1.6) + addressable (2.2.7) arel (3.0.2) + aruba (0.4.11) + childprocess (>= 0.2.3) + cucumber (>= 1.1.1) + ffi (>= 1.0.11) + rspec (>= 2.7.0) bcrypt-ruby (3.0.1) bluecloth (2.2.0) builder (3.0.0) + capybara (1.1.2) + mime-types (>= 1.16) + nokogiri (>= 1.3.3) + rack (>= 1.0.0) + rack-test (>= 0.5.4) + selenium-webdriver (~> 2.0) + xpath (~> 0.1.4) + childprocess (0.3.2) + ffi (~> 1.0.6) coffee-rails (3.2.2) coffee-script (>= 2.2.0) railties (~> 3.2.0) @@ -42,16 +58,35 @@ GEM coffee-script-source execjs coffee-script-source (1.3.1) + cucumber (1.1.9) + builder (>= 2.1.2) + diff-lcs (>= 1.1.2) + gherkin (~> 2.9.0) + json (>= 1.4.6) + term-ansicolor (>= 1.0.6) + cucumber-rails (1.3.0) + capybara (>= 1.1.2) + cucumber (>= 1.1.8) + nokogiri (>= 1.5.0) daemons (1.0.10) + database_cleaner (0.7.2) + diff-lcs (1.1.3) erubis (2.7.0) - execjs (1.3.0) + execjs (1.3.1) multi_json (~> 1.0) + factory_girl (3.2.0) + activesupport (>= 3.0.0) + factory_girl_rails (3.2.0) + factory_girl (~> 3.2.0) + railties (>= 3.0.0) + ffi (1.0.11) formatize (1.1.0) RedCloth (~> 4.2) actionpack (~> 3.0) bluecloth (~> 2.2) gem_plugin (0.2.3) - highline (1.5.2) + gherkin (2.9.3) + json (>= 1.4.6) hike (1.2.1) htmlentities (4.3.1) i18n (0.6.0) @@ -60,6 +95,8 @@ GEM railties (>= 3.2.0, < 5.0) thor (~> 0.14) json (1.6.6) + libwebsocket (0.1.3) + addressable mail (2.4.4) i18n (>= 0.4.0) mime-types (~> 1.16) @@ -70,7 +107,7 @@ GEM gem_plugin (~> 0.2.3) multi_json (1.3.2) mysql2 (0.3.11) - nokogiri (1.4.7) + nokogiri (1.5.2) polyglot (0.3.3) rack (1.4.1) rack-cache (1.2) @@ -99,22 +136,37 @@ GEM rake (0.9.2.2) rdoc (3.12) json (~> 1.4) - sanitize (1.2.1) - nokogiri (~> 1.4.1) - sass (3.1.15) + rspec (2.9.0) + rspec-core (~> 2.9.0) + rspec-expectations (~> 2.9.0) + rspec-mocks (~> 2.9.0) + rspec-core (2.9.0) + rspec-expectations (2.9.1) + diff-lcs (~> 1.1.3) + rspec-mocks (2.9.0) + rubyzip (0.9.8) + sanitize (2.0.3) + nokogiri (>= 1.4.4, < 1.6) + sass (3.1.16) sass-rails (3.2.5) railties (~> 3.2.0) sass (>= 3.1.10) tilt (~> 1.3) - soap4r-ruby1.9 (2.0.5) - sprockets (2.1.2) + selenium-webdriver (2.21.2) + childprocess (>= 0.2.5) + ffi (~> 1.0) + libwebsocket (~> 0.1.3) + multi_json (~> 1.0) + rubyzip + sprockets (2.1.3) hike (~> 1.2) rack (~> 1.0) tilt (~> 1.1, != 1.3.0) sqlite3 (1.3.6) - swf_fu (2.0.1) + swf_fu (2.0.2) coffee-script - rails (~> 3.1) + rails (>= 3.1) + term-ansicolor (1.0.7) thor (0.14.6) tilt (1.3.3) treetop (1.4.10) @@ -125,6 +177,8 @@ GEM execjs (>= 0.3.0) multi_json (>= 1.0.2) will_paginate (3.0.3) + xpath (0.1.4) + nokogiri (~> 1.3) yard (0.7.5) PLATFORMS @@ -132,22 +186,25 @@ PLATFORMS DEPENDENCIES RedCloth - aasm (~> 2.2.0) - acts_as_list (~> 0.1.4) + aasm + acts_as_list + aruba bcrypt-ruby (~> 3.0.0) + capybara coffee-rails (~> 3.2.1) + cucumber-rails + database_cleaner + factory_girl_rails formatize - highline (~> 1.5.0) - htmlentities (~> 4.3.0) + htmlentities jquery-rails - mail mongrel (= 1.2.0.pre2) mysql2 rails (= 3.2.3) rails_autolink - sanitize (~> 1.2.1) + sanitize sass-rails (~> 3.2.3) - soap4r-ruby1.9 + selenium-webdriver sqlite3 swf_fu uglifier (>= 1.0.3) diff --git a/vendor/gems/aruba-0.2.2/.bundle/config b/vendor/gems/aruba-0.2.2/.bundle/config deleted file mode 100644 index 8ebbe30e..00000000 --- a/vendor/gems/aruba-0.2.2/.bundle/config +++ /dev/null @@ -1,2 +0,0 @@ ---- -BUNDLE_DISABLE_SHARED_GEMS: "1" diff --git a/vendor/gems/aruba-0.2.2/.document b/vendor/gems/aruba-0.2.2/.document deleted file mode 100644 index ecf36731..00000000 --- a/vendor/gems/aruba-0.2.2/.document +++ /dev/null @@ -1,5 +0,0 @@ -README.rdoc -lib/**/*.rb -bin/* -features/**/*.feature -LICENSE diff --git a/vendor/gems/aruba-0.2.2/.gitignore b/vendor/gems/aruba-0.2.2/.gitignore deleted file mode 100644 index b13347cc..00000000 --- a/vendor/gems/aruba-0.2.2/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -## MAC OS -.DS_Store - -## TEXTMATE -*.tmproj -tmtags - -## EMACS -*~ -\#* -.\#* - -## VIM -*.swp - -## PROJECT::GENERAL -coverage -rdoc -pkg - -## PROJECT::SPECIFIC -tmp -Gemfile.lock \ No newline at end of file diff --git a/vendor/gems/aruba-0.2.2/.specification b/vendor/gems/aruba-0.2.2/.specification deleted file mode 100644 index e696110a..00000000 --- a/vendor/gems/aruba-0.2.2/.specification +++ /dev/null @@ -1,89 +0,0 @@ ---- !ruby/object:Gem::Specification -name: aruba -version: !ruby/object:Gem::Version - hash: 19 - prerelease: - segments: - - 0 - - 2 - - 2 - version: 0.2.2 -platform: ruby -authors: -- "Aslak Helles\xC3\xB8y" -- David Chelimsky -autorequire: -bindir: bin -cert_chain: [] - -date: 2010-09-28 00:00:00 Z -dependencies: -- !ruby/object:Gem::Dependency - name: rspec - prerelease: false - requirement: &id001 !ruby/object:Gem::Requirement - none: false - requirements: - - - ~> - - !ruby/object:Gem::Version - hash: 62196431 - segments: - - 2 - - 0 - - 0 - - beta - - 22 - version: 2.0.0.beta.22 - type: :development - version_requirements: *id001 -description: CLI Steps for Cucumber, hand-crafted for you in Aruba -email: cukes@googlegroups.com -executables: [] - -extensions: [] - -extra_rdoc_files: -- LICENSE -- README.rdoc -- History.txt -files: -- LICENSE -- README.rdoc -- History.txt -homepage: http://github.com/aslakhellesoy/aruba -licenses: [] - -post_install_message: -rdoc_options: -- --charset=UTF-8 -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - none: false - requirements: - - - ">=" - - !ruby/object:Gem::Version - hash: 3 - segments: - - 0 - version: "0" -required_rubygems_version: !ruby/object:Gem::Requirement - none: false - requirements: - - - ">=" - - !ruby/object:Gem::Version - hash: 3 - segments: - - 0 - version: "0" -requirements: [] - -rubyforge_project: -rubygems_version: 1.8.10 -signing_key: -specification_version: 3 -summary: aruba-0.2.2 -test_files: [] - -has_rdoc: - diff --git a/vendor/gems/aruba-0.2.2/Gemfile b/vendor/gems/aruba-0.2.2/Gemfile deleted file mode 100644 index e826fba0..00000000 --- a/vendor/gems/aruba-0.2.2/Gemfile +++ /dev/null @@ -1,5 +0,0 @@ -source "http://rubygems.org" -gemspec - -gem 'cucumber', :path => '../cucumber' if File.directory?(File.dirname(__FILE__) + '/../cucumber') -gem 'gherkin', :path => '../gherkin' if File.directory?(File.dirname(__FILE__) + '/../gherkin') \ No newline at end of file diff --git a/vendor/gems/aruba-0.2.2/History.txt b/vendor/gems/aruba-0.2.2/History.txt deleted file mode 100644 index 44e2a887..00000000 --- a/vendor/gems/aruba-0.2.2/History.txt +++ /dev/null @@ -1,84 +0,0 @@ -== 0.2.2 - -=== New Features -* Added a @bin tag that sets up './bin' first on the path (Aslak Hellesøy) -* Richer API making aruba easier to use from Ruby code. (Mark Nijhof, Aslak Hellesøy) - -=== Removed Features -* No more support for RVM. Use rvm 1.9.2,1.8.7 exec cucumber .... instead. (Mark Nijhof, Aslak Hellesøy) - -== 0.2.1 - -=== Bugfixes -* Always compare with RSpec should =~ instead of should match. This gives a diff when there is no match. (Aslak Hellesøy) - -== 0.2.0 - -=== New Features -* Added aruba.gemspec. (David Chelimsky) - -=== Changed features -* Several step definitions regarding output have changed. (#1 Aslak Hellesøy) - - - /^I should see "([^\"]*)"$/ - + /^the output should contain "([^"]*)"$/ - - - /^I should not see "([^\"]*)"$/ - + /^the output should not contain "([^"]*)"$/ - - - /^I should see:$/ - + /^the output should contain:$/ - - - /^I should not see:$/ - + /^the output should not contain:$/ - - - /^I should see exactly "([^\"]*)"$/ - + /^the output should contain exactly "([^"]*)"$/ - - - /^I should see exactly:$/ - + /^the output should contain exactly:$/ - - - /^I should see matching \/([^\/]*)\/$/ - + /^the output should match \/([^\/]*)\/$/ - - - /^I should see matching:$/ - + /^the output should match:$/ - -== 0.1.9 -* If the GOTGEMS environment variable is set, bundler won't run (faster). (Aslak Hellesøy) - -== 0.1.8 -* Use // instead of "" for "I should see matching" step. (Aslak Hellesøy) -* Replace rvm gemset character '%' with '@' for rvm 0.1.24 (#5 Ashley Moran) -* Support gem bundler, making it easier to specify gems. (Aslak Hellesøy) - -== 0.1.7 -* New @announce-stderr tag (Robert Wahler) -* New "I should see matching" steps using Regexp (Robert Wahler) - -== 0.1.6 -* When /^I successfully run "(.*)"$/ now prints the combined output if exit status is not 0. (Aslak Hellesøy) -* Add bundle to list of common ruby scripts. (Aslak Hellesøy) - -== 0.1.5 -* Added ability to map rvm versions to a specific version with config/aruba-rvm.yml. (Aslak Hellesøy) -* Check for presence of files. (Aslak Hellesøy) -* Allow specification of rvm gemsets. (Aslak Hellesøy) -* Detect ruby commands and use current ruby when rvm is not explicitly used. (Aslak Hellesøy) -* Added support for rvm, making it possible to choose Ruby interpreter. (Aslak Hellesøy) -* Added @announce-cmd, @announce-stdout and @announce tags, useful for seeing what's executed and outputted. (Aslak Hellesøy) - -== 0.1.4 -* New step definition for appending to a file (Aslak Hellesøy) - -== 0.1.3 -* New step definition for cd (change directory) (Aslak Hellesøy) - -== 0.1.2 -* Separated API from Cucumber step definitions, makes this usable without Cucumber. (Aslak Hellesøy) - -== 0.1.1 -* Better Regexp escaping (David Chelimsky) - -== 0.1.0 -* First release (David Chelimsky and Aslak Hellesøy) \ No newline at end of file diff --git a/vendor/gems/aruba-0.2.2/LICENSE b/vendor/gems/aruba-0.2.2/LICENSE deleted file mode 100644 index 546f731b..00000000 --- a/vendor/gems/aruba-0.2.2/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2010 Aslak Hellesøy, David Chelimsky - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/gems/aruba-0.2.2/README.rdoc b/vendor/gems/aruba-0.2.2/README.rdoc deleted file mode 100644 index 2a7781c4..00000000 --- a/vendor/gems/aruba-0.2.2/README.rdoc +++ /dev/null @@ -1,41 +0,0 @@ -= aruba - -Cucumber steps for driving out command line applications. The command line application can be anything, -a compiled C program, a Java program, a Perl script - anything. There is also special support for various -Ruby versions (see below). - -== Usage - - gem install aruba - -Then, just require the library in one of your ruby files under features/support - - require 'aruba' - -You now have a bunch of step definitions that you can use in your features. Look at aruba/cucumber.rb -to see all the step definitions. Look at features/*.feature for examples (which are also testing Aruba -itself). - -== Getting more output with tags. - -Aruba has several tags you can use to see what command actually gets run (useful if you're using the RVM steps), -STDOUT or STDERR. You can put these tags on individual scenarios, or on a feature. The tags are: - -* @announce-cmd -* @announce-stdout -* @announce-stderr -* @announce (does all of the above) - -== Note on Patches/Pull Requests - -* Fork the project. -* Make your feature addition or bug fix. -* Add tests for it. This is important so I don't break it in a - future version unintentionally. -* Commit, do not mess with rakefile, version, or history. - (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull) -* Send me a pull request. Bonus points for topic branches. - -== Copyright - -Copyright (c) 2010 Aslak Hellesøy and David Chelimsky. See LICENSE for details. diff --git a/vendor/gems/aruba-0.2.2/Rakefile b/vendor/gems/aruba-0.2.2/Rakefile deleted file mode 100644 index e4491c79..00000000 --- a/vendor/gems/aruba-0.2.2/Rakefile +++ /dev/null @@ -1,13 +0,0 @@ -# encoding: utf-8 -require 'rubygems' -require 'bundler' -Bundler.setup -Bundler::GemHelper.install_tasks - -require 'cucumber/rake/task' - -Cucumber::Rake::Task.new do |t| - t.cucumber_opts = %w{--tags ~@jruby} unless defined?(JRUBY_VERSION) -end - -task :default => :cucumber diff --git a/vendor/gems/aruba-0.2.2/aruba.gemspec b/vendor/gems/aruba-0.2.2/aruba.gemspec deleted file mode 100644 index a2fef12d..00000000 --- a/vendor/gems/aruba-0.2.2/aruba.gemspec +++ /dev/null @@ -1,24 +0,0 @@ -# -*- encoding: utf-8 -*- -$LOAD_PATH.unshift File.expand_path("../lib", __FILE__) - -Gem::Specification.new do |s| - s.name = 'aruba' - s.version = "0.2.2" - s.authors = ["Aslak Hellesøy", "David Chelimsky"] - s.description = 'CLI Steps for Cucumber, hand-crafted for you in Aruba' - s.summary = "aruba-#{s.version}" - s.email = 'cukes@googlegroups.com' - s.homepage = 'http://github.com/aslakhellesoy/aruba' - - # s.add_dependency 'cucumber', '~> 0.9.0' unless File.directory?(File.dirname(__FILE__) + '/../cucumber') - s.add_development_dependency('rspec', "~> 2.0.0.beta.22") - - s.rubygems_version = "1.3.7" - # s.files = `git ls-files`.split("\n") - # s.test_files = `git ls-files -- {spec,features}/*`.split("\n") - # s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } - s.extra_rdoc_files = ["LICENSE", "README.rdoc", "History.txt"] - s.rdoc_options = ["--charset=UTF-8"] - s.require_path = "lib" -end - diff --git a/vendor/gems/aruba-0.2.2/config/.gitignore b/vendor/gems/aruba-0.2.2/config/.gitignore deleted file mode 100644 index 53c4367d..00000000 --- a/vendor/gems/aruba-0.2.2/config/.gitignore +++ /dev/null @@ -1 +0,0 @@ -aruba-rvm.yml \ No newline at end of file diff --git a/vendor/gems/aruba-0.2.2/features/exit_statuses.feature b/vendor/gems/aruba-0.2.2/features/exit_statuses.feature deleted file mode 100644 index dab0701b..00000000 --- a/vendor/gems/aruba-0.2.2/features/exit_statuses.feature +++ /dev/null @@ -1,21 +0,0 @@ -Feature: exit statuses - - In order to specify expected exit statuses - As a developer using Cucumber - I want to use the "the exit status should be" step - - Scenario: exit status of 0 - When I run "ruby -h" - Then the exit status should be 0 - - Scenario: non-zero exit status - When I run "ruby -e 'exit 56'" - Then the exit status should be 56 - And the exit status should not be 0 - - Scenario: Successfully run something - When I successfully run "ruby -e 'exit 0'" - - Scenario: Unsuccessfully run something - When I do aruba I successfully run "ruby -e 'exit 10'" - Then aruba should fail with "Exit status was 10" diff --git a/vendor/gems/aruba-0.2.2/features/file_system_commands.feature b/vendor/gems/aruba-0.2.2/features/file_system_commands.feature deleted file mode 100644 index 044a520f..00000000 --- a/vendor/gems/aruba-0.2.2/features/file_system_commands.feature +++ /dev/null @@ -1,84 +0,0 @@ -Feature: file system commands - - In order to specify commands that load files - As a developer using Cucumber - I want to create temporary files - - Scenario: create a dir - Given a directory named "foo/bar" - When I run "ruby -e \"puts test ?d, 'foo'\"" - Then the stdout should contain "true" - - Scenario: create a file - Given a file named "foo/bar/example.rb" with: - """ - puts "hello world" - """ - When I run "ruby foo/bar/example.rb" - Then the output should contain "hello world" - - Scenario: append to a file - Given a file named "foo/bar/example.rb" with: - """ - puts "hello world" - """ - When I append to "foo/bar/example.rb" with: - """ - puts "this was appended" - """ - When I run "ruby foo/bar/example.rb" - Then the output should contain "hello world" - And the output should contain "this was appended" - - Scenario: clean up files generated in previous scenario - When I run "ruby foo/bar/example.rb" - Then the exit status should be 1 - And the output should contain "No such file or directory -- foo/bar/example.rb" - - Scenario: change to a subdir - Given a file named "foo/bar/example.rb" with: - """ - puts "hello world" - """ - When I cd to "foo/bar" - And I run "ruby example.rb" - Then the output should contain "hello world" - - Scenario: Reset current directory from previous scenario - When I run "ruby example.rb" - Then the exit status should be 1 - - Scenario: Holler if cd to bad dir - Given a file named "foo/bar/example.rb" with: - """ - puts "hello world" - """ - When I do aruba I cd to "foo/nonexistant" - Then aruba should fail with "tmp/aruba/foo/nonexistant is not a directory" - - Scenario: Check for presence of a subset of files - Given an empty file named "lorem/ipsum/dolor" - Given an empty file named "lorem/ipsum/sit" - Given an empty file named "lorem/ipsum/amet" - Then the following files should exist: - | lorem/ipsum/dolor | - | lorem/ipsum/amet | - - Scenario: Check for absence of files - Then the following files should not exist: - | lorem/ipsum/dolor | - - Scenario: Check for presence of a subset of directories - Given a directory named "foo/bar" - Given a directory named "foo/bla" - Then the following directories should exist: - | foo/bar | - | foo/bla | - - Scenario: Check file contents - Given a file named "foo" with: - """ - hello world - """ - Then the file "foo" should contain "hello world" - And the file "foo" should not contain "HELLO WORLD" diff --git a/vendor/gems/aruba-0.2.2/features/output.feature b/vendor/gems/aruba-0.2.2/features/output.feature deleted file mode 100644 index 82262f9c..00000000 --- a/vendor/gems/aruba-0.2.2/features/output.feature +++ /dev/null @@ -1,96 +0,0 @@ -Feature: Output - - In order to specify expected output - As a developer using Cucumber - I want to use the "the output should contain" step - - Scenario: Run unknown command - When I run "neverever gonna work" - Then the output should contain: - """ - sh: neverever: command not found - """ - - Scenario: Detect subset of one-line output - When I run "ruby -e 'puts \"hello world\"'" - Then the output should contain "hello world" - - Scenario: Detect subset of one-line output - When I run "echo 'hello world'" - Then the output should contain "hello world" - - Scenario: Detect absence of one-line output - When I run "ruby -e 'puts \"hello world\"'" - Then the output should not contain "good-bye" - - Scenario: Detect subset of multiline output - When I run "ruby -e 'puts \"hello\\nworld\"'" - Then the output should contain: - """ - hello - """ - - Scenario: Detect subset of multiline output - When I run "ruby -e 'puts \"hello\\nworld\"'" - Then the output should not contain: - """ - good-bye - """ - - Scenario: Detect exact one-line output - When I run "ruby -e 'puts \"hello world\"'" - Then the output should contain exactly "hello world\n" - - Scenario: Detect exact multiline output - When I run "ruby -e 'puts \"hello\\nworld\"'" - Then the output should contain exactly: - """ - hello - world - - """ - - @announce - Scenario: Detect subset of one-line output with regex - When I run "ruby --version" - Then the output should contain "ruby" - And the output should match /ruby ([\d]+\.[\d]+\.[\d]+)(p\d+)? \(.*$/ - - @announce - Scenario: Detect subset of multiline output with regex - When I run "ruby -e 'puts \"hello\\nworld\\nextra line1\\nextra line2\\nimportant line\"'" - Then the output should match: - """ - he..o - wor.d - .* - important line - """ - - @announce - Scenario: Match passing exit status and partial output - When I run "ruby -e 'puts \"hello\\nworld\"'" - Then it should pass with: - """ - hello - """ - - @announce-stdout - Scenario: Match failing exit status and partial output - When I run "ruby -e 'puts \"hello\\nworld\";exit 99'" - Then it should fail with: - """ - hello - """ - - @announce-cmd - Scenario: Match output in stdout - When I run "ruby -e 'puts \"hello\\nworld\"'" - Then the stdout should contain "hello" - Then the stderr should not contain "hello" - - @announce-stderr - Scenario: Match output in stderr - When I run "ruby -e 'STDERR.puts \"hello\\nworld\";exit 99'" - Then the stderr should contain "hello" - Then the stdout should not contain "hello" diff --git a/vendor/gems/aruba-0.2.2/features/step_definitions/aruba_dev_steps.rb b/vendor/gems/aruba-0.2.2/features/step_definitions/aruba_dev_steps.rb deleted file mode 100644 index d46a4c09..00000000 --- a/vendor/gems/aruba-0.2.2/features/step_definitions/aruba_dev_steps.rb +++ /dev/null @@ -1,24 +0,0 @@ -Given /^I have a local file named "([^"]*)" with:$/ do |filename, content| - File.open(filename, 'w') {|io| io.write(content)} -end - -When /^I do aruba (.*)$/ do |aruba_step| - begin - When(aruba_step) - rescue => e - @aruba_exception = e - end -end - -Then /^the output should contain the JRuby version$/ do - pending "This must be manually run in JRuby" unless defined?(JRUBY_VERSION) - Then %{the output should contain "#{JRUBY_VERSION}"} -end - -Then /^the output should contain the current Ruby version$/ do - Then %{the output should contain "#{RUBY_VERSION}"} -end - -Then /^aruba should fail with "([^"]*)"$/ do |error_message| - @aruba_exception.message.should =~ compile_and_escape(error_message) -end diff --git a/vendor/gems/aruba-0.2.2/features/support/env.rb b/vendor/gems/aruba-0.2.2/features/support/env.rb deleted file mode 100644 index 7031bf51..00000000 --- a/vendor/gems/aruba-0.2.2/features/support/env.rb +++ /dev/null @@ -1,15 +0,0 @@ -$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib') -require 'aruba' -require 'fileutils' - -begin - # rspec-2 - require 'rspec/expectations' -rescue LoadError - # rspec-1 - require 'spec/expectations' -end - -Before do - FileUtils.rm(Dir['config/*.yml']) -end \ No newline at end of file diff --git a/vendor/gems/aruba-0.2.2/lib/aruba.rb b/vendor/gems/aruba-0.2.2/lib/aruba.rb deleted file mode 100644 index e69de29b..00000000 diff --git a/vendor/gems/aruba-0.2.2/lib/aruba/api.rb b/vendor/gems/aruba-0.2.2/lib/aruba/api.rb deleted file mode 100644 index 4f059b55..00000000 --- a/vendor/gems/aruba-0.2.2/lib/aruba/api.rb +++ /dev/null @@ -1,220 +0,0 @@ -require 'tempfile' -require 'rbconfig' - -module Aruba - module Api - def in_current_dir(&block) - _mkdir(current_dir) - Dir.chdir(current_dir, &block) - end - - def current_dir - File.join(*dirs) - end - - def cd(dir) - dirs << dir - raise "#{current_dir} is not a directory." unless File.directory?(current_dir) - end - - def dirs - @dirs ||= ['tmp/aruba'] - end - - def create_file(file_name, file_content, check_presence = false) - in_current_dir do - raise "expected #{file_name} to be present" if check_presence && !File.file?(file_name) - _mkdir(File.dirname(file_name)) - File.open(file_name, 'w') { |f| f << file_content } - end - end - - def append_to_file(file_name, file_content) - in_current_dir do - File.open(file_name, 'a') { |f| f << file_content } - end - end - - def create_dir(dir_name) - in_current_dir do - _mkdir(dir_name) - end - end - - def check_file_presence(paths, expect_presence) - in_current_dir do - paths.each do |path| - if expect_presence - File.should be_file(path) - else - File.should_not be_file(path) - end - end - end - end - - def check_file_content(file, partial_content, expect_match) - regexp = compile_and_escape(partial_content) - in_current_dir do - content = IO.read(file) - if expect_match - content.should =~ regexp - else - content.should_not =~ regexp - end - end - end - - def check_exact_file_content(file, exact_content) - in_current_dir do - IO.read(file).should == exact_content - end - end - - def check_directory_presence(paths, expect_presence) - in_current_dir do - paths.each do |path| - if expect_presence - File.should be_directory(path) - else - File.should_not be_directory(path) - end - end - end - end - - def _mkdir(dir_name) - FileUtils.mkdir_p(dir_name) unless File.directory?(dir_name) - end - - def unescape(string) - eval(%{"#{string}"}) - end - - def compile_and_escape(string) - Regexp.compile(Regexp.escape(string)) - end - - def combined_output - @last_stdout + (@last_stderr == '' ? '' : "\n#{'-'*70}\n#{@last_stderr}") - end - - def assert_partial_output(partial_output) - combined_output.should =~ compile_and_escape(partial_output) - end - - def assert_passing_with(partial_output) - assert_exit_status_and_partial_output(true, partial_output) - end - - def assert_failing_with(partial_output) - assert_exit_status_and_partial_output(false, partial_output) - end - - def assert_exit_status_and_partial_output(expect_to_pass, partial_output) - assert_partial_output(partial_output) - if expect_to_pass - @last_exit_status.should == 0 - else - @last_exit_status.should_not == 0 - end - end - - def install_gems(gemfile) - create_file("Gemfile", gemfile) - if ENV['GOTGEMS'].nil? - run("gem install bundler") - run("bundle --no-color install") - end - end - - def run(cmd, fail_on_error=true) - cmd = detect_ruby(cmd) - - stderr_file = Tempfile.new('cucumber') - stderr_file.close - in_current_dir do - announce_or_puts("$ cd #{Dir.pwd}") if @announce_dir - announce_or_puts("$ #{cmd}") if @announce_cmd - - mode = RUBY_VERSION =~ /^1\.9/ ? {:external_encoding=>"UTF-8"} : 'r' - - IO.popen("#{cmd} 2> #{stderr_file.path}", mode) do |io| - @last_stdout = io.read - announce_or_puts(@last_stdout) if @announce_stdout - end - - @last_exit_status = $?.exitstatus - end - @last_stderr = IO.read(stderr_file.path) - - announce_or_puts(@last_stderr) if @announce_stderr - - if(@last_exit_status != 0 && fail_on_error) - fail("Exit status was #{@last_exit_status}. Output:\n#{combined_output}") - end - - @last_stderr - end - - def announce_or_puts(msg) - if(@puts) - puts(msg) - else - announce(msg) - end - end - - def detect_ruby(cmd) - if cmd =~ /^ruby\s/ - cmd.gsub(/^ruby\s/, "#{current_ruby} ") - else - cmd - end - end - - def current_ruby - File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - end - - def use_clean_gemset(gemset) - run(%{rvm gemset create "#{gemset}"}, true) - if @last_stdout =~ /'#{gemset}' gemset created \((.*)\)\./ - gem_home = $1 - set_env('GEM_HOME', gem_home) - set_env('GEM_PATH', gem_home) - set_env('BUNDLE_PATH', gem_home) - - paths = (ENV['PATH'] || "").split(File::PATH_SEPARATOR) - paths.unshift(File.join(gem_home, 'bin')) - set_env('PATH', paths.uniq.join(File::PATH_SEPARATOR)) - - run("gem install bundler", true) - else - raise "I didn't understand rvm's output: #{@last_stdout}" - end - end - - def unset_bundler_env_vars - %w[RUBYOPT BUNDLE_PATH BUNDLE_BIN_PATH BUNDLE_GEMFILE].each do |key| - set_env(key, nil) - end - end - - def set_env(key, value) - announce_or_puts(%{$ export #{key}="#{value}"}) if @announce_env - original_env[key] = ENV.delete(key) - ENV[key] = value - end - - def restore_env - original_env.each do |key, value| - ENV[key] = value - end - end - - def original_env - @original_env ||= {} - end - end -end diff --git a/vendor/gems/aruba-0.2.2/lib/aruba/cucumber.rb b/vendor/gems/aruba-0.2.2/lib/aruba/cucumber.rb deleted file mode 100644 index 081727fd..00000000 --- a/vendor/gems/aruba-0.2.2/lib/aruba/cucumber.rb +++ /dev/null @@ -1,188 +0,0 @@ -require 'aruba/api' - -World(Aruba::Api) - -Before('@disable-bundler') do - unset_bundler_env_vars -end - -Before('@bin') do - @__aruba_original_paths = (ENV['PATH'] || '').split(File::PATH_SEPARATOR) - ENV['PATH'] = ([File.expand_path('bin')] + @__aruba_original_paths).join(File::PATH_SEPARATOR) -end - -After('@bin') do - ENV['PATH'] = @__aruba_original_paths.join(File::PATH_SEPARATOR) -end - -Before do - FileUtils.rm_rf(current_dir) -end - -Before('@puts') do - @puts = true -end - -Before('@announce-cmd') do - @announce_cmd = true -end - -Before('@announce-stdout') do - @announce_stdout = true -end - -Before('@announce-stderr') do - @announce_stderr = true -end - -Before('@announce-dir') do - @announce_dir = true -end - -Before('@announce-env') do - @announce_env = true -end - -Before('@announce') do - @announce_stdout = true - @announce_stderr = true - @announce_cmd = true - @announce_dir = true - @announce_env = true -end - -After do - restore_env -end - -Given /^I'm using a clean gemset "([^"]*)"$/ do |gemset| - use_clean_gemset(gemset) -end - -Given /^a directory named "([^"]*)"$/ do |dir_name| - create_dir(dir_name) -end - -Given /^a file named "([^"]*)" with:$/ do |file_name, file_content| - create_file(file_name, file_content) -end - -Given /^an empty file named "([^"]*)"$/ do |file_name| - create_file(file_name, "") -end - -When /^I write to "([^"]*)" with:$/ do |file_name, file_content| - create_file(file_name, file_content, false) -end - -When /^I overwrite "([^"]*)" with:$/ do |file_name, file_content| - create_file(file_name, file_content, true) -end - -When /^I append to "([^"]*)" with:$/ do |file_name, file_content| - append_to_file(file_name, file_content) -end - -When /^I cd to "([^"]*)"$/ do |dir| - cd(dir) -end - -When /^I run "(.*)"$/ do |cmd| - run(unescape(cmd), false) -end - -When /^I successfully run "(.*)"$/ do |cmd| - run(unescape(cmd)) -end - -Then /^the output should contain "([^"]*)"$/ do |partial_output| - assert_partial_output(partial_output) -end - -Then /^the output should not contain "([^"]*)"$/ do |partial_output| - combined_output.should_not =~ compile_and_escape(partial_output) -end - -Then /^the output should contain:$/ do |partial_output| - combined_output.should =~ compile_and_escape(partial_output) -end - -Then /^the output should not contain:$/ do |partial_output| - combined_output.should_not =~ compile_and_escape(partial_output) -end - -Then /^the output should contain exactly "([^"]*)"$/ do |exact_output| - combined_output.should == unescape(exact_output) -end - -Then /^the output should contain exactly:$/ do |exact_output| - combined_output.should == exact_output -end - -# "the output should match" allows regex in the partial_output, if -# you don't need regex, use "the output should contain" instead since -# that way, you don't have to escape regex characters that -# appear naturally in the output -Then /^the output should match \/([^\/]*)\/$/ do |partial_output| - combined_output.should =~ /#{partial_output}/ -end - -Then /^the output should match:$/ do |partial_output| - combined_output.should =~ /#{partial_output}/m -end - -Then /^the exit status should be (\d+)$/ do |exit_status| - @last_exit_status.should == exit_status.to_i -end - -Then /^the exit status should not be (\d+)$/ do |exit_status| - @last_exit_status.should_not == exit_status.to_i -end - -Then /^it should (pass|fail) with:$/ do |pass_fail, partial_output| - self.__send__("assert_#{pass_fail}ing_with", partial_output) -end - -Then /^the stderr should contain "([^"]*)"$/ do |partial_output| - @last_stderr.should =~ compile_and_escape(partial_output) -end - -Then /^the stdout should contain "([^"]*)"$/ do |partial_output| - @last_stdout.should =~ compile_and_escape(partial_output) -end - -Then /^the stderr should not contain "([^"]*)"$/ do |partial_output| - @last_stderr.should_not =~ compile_and_escape(partial_output) -end - -Then /^the stdout should not contain "([^"]*)"$/ do |partial_output| - @last_stdout.should_not =~ compile_and_escape(partial_output) -end - -Then /^the following files should exist:$/ do |files| - check_file_presence(files.raw.map{|file_row| file_row[0]}, true) -end - -Then /^the following files should not exist:$/ do |files| - check_file_presence(files.raw.map{|file_row| file_row[0]}, false) -end - -Then /^the following directories should exist:$/ do |directories| - check_directory_presence(directories.raw.map{|directory_row| directory_row[0]}, true) -end - -Then /^the following directories should not exist:$/ do |directories| - check_file_presence(directories.raw.map{|directory_row| directory_row[0]}, false) -end - -Then /^the file "([^"]*)" should contain "([^"]*)"$/ do |file, partial_content| - check_file_content(file, partial_content, true) -end - -Then /^the file "([^"]*)" should not contain "([^"]*)"$/ do |file, partial_content| - check_file_content(file, partial_content, false) -end - -Then /^the file "([^"]*)" should contain exactly:$/ do |file, exact_content| - check_exact_file_content(file, exact_content) -end From c9d64e6f4b9264a89bd01661876e1bb0694c46ec Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Mon, 30 Apr 2012 13:51:42 +0200 Subject: [PATCH 114/134] get the first cucumber feature running: calendar --- .../assets/images}/apple-touch-icon.png | Bin {public => app/assets/images}/favicon.ico | Bin app/controllers/contexts_controller.rb | 9 +- app/controllers/login_controller.rb | 136 +++--------- app/controllers/todos_controller.rb | 5 +- app/helpers/todos_helper.rb | 2 +- app/models/recurring_todo.rb | 2 +- app/views/layouts/login.html.erb | 1 - app/views/layouts/standard.html.erb | 4 +- app/views/login/login.html.erb | 115 +--------- app/views/todos/calendar.html.erb | 12 +- app/views/todos/create.js.erb | 2 +- app/views/todos/index.html.erb | 12 +- backup.rails2.3/env.rb | 70 ++++++ config/application.rb | 1 + config/cucumber.yml | 4 +- config/environment.rb | 3 + config/locales/he.yml | 208 +++++++++--------- features/step_definitions/context_steps.rb | 2 +- features/step_definitions/login_steps.rb | 4 +- .../step_definitions/todo_create_steps.rb | 2 +- features/step_definitions/user_steps.rb | 2 +- features/support/env.rb | 99 ++++----- features/support/factories/factories.rb | 23 ++ features/support/init_factory_girl.rb | 4 +- features/support/tracks_cucumber_settings.rb | 13 ++ lib/tasks/cucumber.rake | 65 ++++++ test/functional/todos_controller_test.rb | 18 +- 28 files changed, 400 insertions(+), 418 deletions(-) rename {public => app/assets/images}/apple-touch-icon.png (100%) rename {public => app/assets/images}/favicon.ico (100%) create mode 100644 backup.rails2.3/env.rb create mode 100644 features/support/factories/factories.rb create mode 100644 features/support/tracks_cucumber_settings.rb create mode 100644 lib/tasks/cucumber.rake diff --git a/public/apple-touch-icon.png b/app/assets/images/apple-touch-icon.png similarity index 100% rename from public/apple-touch-icon.png rename to app/assets/images/apple-touch-icon.png diff --git a/public/favicon.ico b/app/assets/images/favicon.ico similarity index 100% rename from public/favicon.ico rename to app/assets/images/favicon.ico diff --git a/app/controllers/contexts_controller.rb b/app/controllers/contexts_controller.rb index 7d75fa13..e4db6e16 100644 --- a/app/controllers/contexts_controller.rb +++ b/app/controllers/contexts_controller.rb @@ -9,18 +9,14 @@ class ContextsController < ApplicationController prepend_before_filter :login_or_feed_token_required, :only => [:index] def index - # #true is passed here to force an immediate load so that size and empty? - # checks later don't result in separate SQL queries - @active_contexts = current_user.contexts.active(true) - @hidden_contexts = current_user.contexts.hidden(true) + @active_contexts = current_user.contexts.active + @hidden_contexts = current_user.contexts.hidden @new_context = current_user.contexts.build # save all contexts here as @new_context will add an empty one to current_user.contexts @all_contexts = @active_contexts + @hidden_contexts @count = @all_contexts.size - init_not_done_counts(['context']) - respond_to do |format| format.html &render_contexts_html format.m &render_contexts_mobile @@ -200,6 +196,7 @@ class ContextsController < ApplicationController @no_hidden_contexts = @hidden_contexts.empty? @active_count = @active_contexts.size @hidden_count = @hidden_contexts.size + init_not_done_counts(['context']) render end end diff --git a/app/controllers/login_controller.rb b/app/controllers/login_controller.rb index d65af5d5..df44a246 100644 --- a/app/controllers/login_controller.rb +++ b/app/controllers/login_controller.rb @@ -8,60 +8,38 @@ class LoginController < ApplicationController protect_from_forgery :except => [:check_expiry, :login] - if ( SITE_CONFIG['authentication_schemes'].include? 'cas') - # This will allow the user to view the index page without authentication - # but will process CAS authentication data if the user already - # has an SSO session open. - if defined? CASClient - # Only require sub-library if gem is installed and loaded - require 'casclient/frameworks/rails/filter' - before_filter CASClient::Frameworks::Rails::GatewayFilter, :only => :login_cas - - # This requires the user to be authenticated for viewing all other pages. - before_filter CASClient::Frameworks::Rails::Filter, :only => [:login_cas ] - end - end - def login - if cas_enabled? - @username = session[:cas_user] - @login_url = CASClient::Frameworks::Rails::Filter.login_url(self) + @page_title = "TRACKS::Login" + cookies[:preferred_auth] = prefered_auth? unless cookies[:preferred_auth] + case request.method + when 'POST' + if @user = User.authenticate(params['user_login'], params['user_password']) + session['user_id'] = @user.id + # If checkbox on login page checked, we don't expire the session after 1 hour + # of inactivity and we remember this user for future browser sessions + session['noexpiry'] = params['user_noexpiry'] + msg = (should_expire_sessions?) ? "will expire after 1 hour of inactivity." : "will not expire." + notify :notice, "Login successful: session #{msg}" + cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year, :secure => SITE_CONFIG['secure_cookies'] } + unless should_expire_sessions? + @user.remember_me + cookies[:auth_token] = { :value => @user.remember_token , :expires => @user.remember_token_expires_at, :secure => SITE_CONFIG['secure_cookies'] } + end + redirect_back_or_home + return + else + @login = params['user_login'] + notify :warning, t('login.unsuccessful') + end + when 'GET' + if User.no_users_yet? + redirect_to signup_path + return + end end - if cas_enabled? && session[:cas_user] - login_cas - else - @page_title = "TRACKS::Login" - cookies[:preferred_auth] = prefered_auth? unless cookies[:preferred_auth] - case request.method - when 'POST' - if @user = User.authenticate(params['user_login'], params['user_password']) - session['user_id'] = @user.id - # If checkbox on login page checked, we don't expire the session after 1 hour - # of inactivity and we remember this user for future browser sessions - session['noexpiry'] = params['user_noexpiry'] - msg = (should_expire_sessions?) ? "will expire after 1 hour of inactivity." : "will not expire." - notify :notice, "Login successful: session #{msg}" - cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year, :secure => SITE_CONFIG['secure_cookies'] } - unless should_expire_sessions? - @user.remember_me - cookies[:auth_token] = { :value => @user.remember_token , :expires => @user.remember_token_expires_at, :secure => SITE_CONFIG['secure_cookies'] } - end - redirect_back_or_home - return - else - @login = params['user_login'] - notify :warning, t('login.unsuccessful') - end - when 'GET' - if User.no_users_yet? - redirect_to signup_path - return - end - end - respond_to do |format| - format.html - format.m { render :action => 'login_mobile.html.erb', :layout => 'mobile' } - end + respond_to do |format| + format.html + format.m { render :action => 'login_mobile.html.erb', :layout => 'mobile' } end end @@ -108,32 +86,6 @@ class LoginController < ApplicationController format.js end end - - def login_cas - # If checkbox on login page checked, we don't expire the session after 1 hour - # of inactivity and we remember this user for future browser sessions - - session['noexpiry'] ||= params['user_noexpiry'] - if session[:cas_user] - if @user = User.find_by_login(session[:cas_user]) - session['user_id'] = @user.id - msg = (should_expire_sessions?) ? t('login.session_will_expire', :hours => 1) : t('login.session_will_not_expire') - notify :notice, (t('login.successful_with_session_info') + msg) - cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year, :secure => SITE_CONFIG['secure_cookies'] } - unless should_expire_sessions? - @user.remember_me - cookies[:auth_token] = { :value => @user.remember_token, :expires => @user.remember_token_expires_at, :secure => SITE_CONFIG['secure_cookies'] } - end - else - notify :warning, t('login.cas_username_not_found', :username => session[:cas_user]) - redirect_to signup_url ; return - end - else - notify :warning, result.message - end - redirect_back_or_home - - end private @@ -141,32 +93,4 @@ class LoginController < ApplicationController session['noexpiry'] != "on" end - protected - - def login_openid - # If checkbox on login page checked, we don't expire the session after 1 hour - # of inactivity and we remember this user for future browser sessions - session['noexpiry'] ||= params['user_noexpiry'] - authenticate_with_open_id do |result, identity_url| - if result.successful? - if @user = User.find_by_open_id_url(identity_url) - session['user_id'] = @user.id - msg = (should_expire_sessions?) ? t('login.session_will_expire', :hours => 1) : t('login.session_will_not_expire') - notify :notice, (t('login.successful_with_session_info') + msg) - cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year, :secure => SITE_CONFIG['secure_cookies'] } - unless should_expire_sessions? - @user.remember_me - cookies[:auth_token] = { :value => @user.remember_token , :expires => @user.remember_token_expires_at, :secure => SITE_CONFIG['secure_cookies'] } - end - redirect_back_or_home - else - notify :warning, t('login.openid_identity_url_not_found', :identity_url => identity_url) - end - else - notify :warning, result.message - end - end - end - - end diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index d7ec5636..b6619915 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -108,8 +108,7 @@ class TodosController < ApplicationController includes(:project, :context, :tags) else @todos = current_user.todos.includes(Todo::DEFAULT_INCLUDES) - @not_done_todos = current_user.todos. - where('contexts.hide = ? AND (projects.state = ? OR todos.project_id IS NULL)', false, 'active'). + @not_done_todos = current_user.todos.active.not_hidden. reorder("todos.due IS NULL, todos.due ASC, todos.created_at ASC"). includes(Todo::DEFAULT_INCLUDES) end @@ -360,7 +359,7 @@ class TodosController < ApplicationController end def edit - @todo = current_user.todos.find_by_id(params['id']).includes(Todo::DEFAULT_INCLUDES) + @todo = current_user.todos.find(params['id']) @source_view = params['_source_view'] || 'todo' @tag_name = params['_tag_name'] respond_to do |format| diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index f5be24f0..1b092feb 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -447,7 +447,7 @@ module TodosHelper } page.todo { container_id = "c#{@original_item_context_id}empty-nd" if @remaining_in_context == 0 } end - return container_id.blank? ? "" : "$(\"##{container_id}\").slideDown(100);" + return container_id.blank? ? "" : "$(\"##{container_id}\").slideDown(100);".html_safe end def render_animation(animation) diff --git a/app/models/recurring_todo.rb b/app/models/recurring_todo.rb index 8826d07c..82d8e2d0 100644 --- a/app/models/recurring_todo.rb +++ b/app/models/recurring_todo.rb @@ -433,7 +433,7 @@ class RecurringTodo < ActiveRecord::Base end else if self.every_other2>1 - n_months = "#{self.every_other2} " + I18n.t('common.months') + n_months = "#{self.every_other2} #{I18n.t('common.months')}" else n_months = I18n.t('common.month') end diff --git a/app/views/layouts/login.html.erb b/app/views/layouts/login.html.erb index cade0e26..4eb908d2 100644 --- a/app/views/layouts/login.html.erb +++ b/app/views/layouts/login.html.erb @@ -3,7 +3,6 @@ <%= stylesheet_link_tag "scaffold" %> - <%= javascript_include_tag 'jquery-1.7.1.min', 'jquery.cookie' %> <%= @page_title -%> diff --git a/app/views/layouts/standard.html.erb b/app/views/layouts/standard.html.erb index 85d3c4c9..308a5c09 100644 --- a/app/views/layouts/standard.html.erb +++ b/app/views/layouts/standard.html.erb @@ -24,7 +24,7 @@ setup_periodic_check("<%=check_deferred_todos_path(:format => 'js')%>", 10*60, 'POST'); <%= generate_i18n_strings %> - + <%= auto_discovery_link_tag(:rss, {:controller => "todos", :action => "index", :format => 'rss', :token => "#{current_user.token}"}, {:title => t('layouts.next_actions_rss_feed')}) %> <%= @page_title %> @@ -48,7 +48,7 @@  |  <%= link_to(t('layouts.toggle_notes'), "#", {:accesskey => "S", :title => t('layouts.toggle_notes_title'), :id => "toggle-notes-nav"}) %>  |  - <%= link_to( t('common.logout') + " (#{current_user.display_name}) »", logout_path) %> + <%= link_to("#{t('common.logout')} (#{current_user.display_name}) »".html_safe, logout_path) %>
        + <% if @username && @user%>

        <%= t('login.cas_logged_in_greeting', :username => @username) %>

        <% elsif @username %> diff --git a/app/views/login/login_mobile.html.erb b/app/views/login/login_mobile.html.erb index 8fb1edfb..afa28de7 100644 --- a/app/views/login/login_mobile.html.erb +++ b/app/views/login/login_mobile.html.erb @@ -11,21 +11,21 @@ <% if show_database_form %>
        - <% form_tag login_path(:format => 'm') do %> + <%= form_tag login_path(:format => 'm') do %> - + - + - + @@ -34,28 +34,4 @@ <% end %> -<% if show_openid_form %> - -

        <%= t('login.mobile_use_openid') %>:

        - -
        - <% form_tag login_path(:format => 'm') do %> -
         
        - - - - - - - - - - - - -
        - <% end %> -
        - <% end %> - diff --git a/app/views/preferences/index.html.erb b/app/views/preferences/index.html.erb index 65c37c77..ee63c682 100644 --- a/app/views/preferences/index.html.erb +++ b/app/views/preferences/index.html.erb @@ -2,7 +2,7 @@
        <%= error_messages_for(:user) + error_messages_for(:prefs) %>
        - <% form_tag :action => 'update' do %> + <%= form_tag :action => 'update' do %>
        • <%= t('preferences.tabs.profile')%>
        • diff --git a/app/views/projects/_new_project_form.rhtml b/app/views/projects/_new_project_form.rhtml index 12626068..778363f7 100644 --- a/app/views/projects/_new_project_form.rhtml +++ b/app/views/projects/_new_project_form.rhtml @@ -6,7 +6,7 @@
        - <% form_for(@new_project, :html => {:id => 'project_form',:name=>'project',:class => "inline-form", :method => :post }) do -%> + <%= form_for(@new_project, :html => {:id => 'project_form',:name=>'project',:class => "inline-form", :method => :post }) do -%>
        <%= error_messages_for("project") %>

        diff --git a/app/views/recurring_todos/_edit_form.html.erb b/app/views/recurring_todos/_edit_form.html.erb index 2f9f6de8..3714e51e 100644 --- a/app/views/recurring_todos/_edit_form.html.erb +++ b/app/views/recurring_todos/_edit_form.html.erb @@ -1,5 +1,5 @@
        -<% form_for(@recurring_todo, :html=> { :id=>'recurring-todo-form-edit-action', :name=>'recurring_todo', :class => 'inline-form' }) do |f| -%> +<%= form_for(@recurring_todo, :html=> { :id=>'recurring-todo-form-edit-action', :name=>'recurring_todo', :class => 'inline-form' }) do |f| -%>
        <%= error_messages_for("item", :object_name => 'action') %>
        diff --git a/app/views/recurring_todos/_recurring_todo_form.erb b/app/views/recurring_todos/_recurring_todo_form.erb index 668579a3..86fd9730 100644 --- a/app/views/recurring_todos/_recurring_todo_form.erb +++ b/app/views/recurring_todos/_recurring_todo_form.erb @@ -1,6 +1,6 @@ <%- reset_tab_index %>
        -<% form_for(@new_recurring_todo, :html=> { :id=>'recurring-todo-form-new-action', :name=>'recurring_todo', :class => 'inline-form' }) do -%> +<%= form_for(@new_recurring_todo, :html=> { :id=>'recurring-todo-form-new-action', :name=>'recurring_todo', :class => 'inline-form' }) do -%>
        <%= error_messages_for("item", :object_name => 'action') %>
        diff --git a/app/views/search/index.rhtml b/app/views/search/index.rhtml index 9573a90b..392720fd 100644 --- a/app/views/search/index.rhtml +++ b/app/views/search/index.rhtml @@ -1,5 +1,5 @@
        - <%= render :file => "sidebar/sidebar.html.erb" %> + <%= render :file => "sidebar/sidebar" %>
        diff --git a/app/views/feedlist/mobile_index.rhtml b/app/views/feedlist/mobile_index.html.erb similarity index 100% rename from app/views/feedlist/mobile_index.rhtml rename to app/views/feedlist/mobile_index.html.erb diff --git a/app/views/recurring_todos/_recurring_todo_form.erb b/app/views/recurring_todos/_recurring_todo_form.html.erb similarity index 99% rename from app/views/recurring_todos/_recurring_todo_form.erb rename to app/views/recurring_todos/_recurring_todo_form.html.erb index 86fd9730..cdbf9c2a 100644 --- a/app/views/recurring_todos/_recurring_todo_form.erb +++ b/app/views/recurring_todos/_recurring_todo_form.html.erb @@ -1,7 +1,7 @@ <%- reset_tab_index %>
        <%= form_for(@new_recurring_todo, :html=> { :id=>'recurring-todo-form-new-action', :name=>'recurring_todo', :class => 'inline-form' }) do -%> -
        <%= error_messages_for("item", :object_name => 'action') %>
        +
        <%= get_list_of_error_messages_for(@new_recurring_todo) %>
        diff --git a/app/views/stats/_actions.rhtml b/app/views/stats/_actions.html.erb similarity index 100% rename from app/views/stats/_actions.rhtml rename to app/views/stats/_actions.html.erb diff --git a/app/views/stats/_chart.rhtml b/app/views/stats/_chart.html.erb similarity index 100% rename from app/views/stats/_chart.rhtml rename to app/views/stats/_chart.html.erb diff --git a/app/views/stats/_contexts.rhtml b/app/views/stats/_contexts.html.erb similarity index 100% rename from app/views/stats/_contexts.rhtml rename to app/views/stats/_contexts.html.erb diff --git a/app/views/stats/_projects.rhtml b/app/views/stats/_projects.html.erb similarity index 100% rename from app/views/stats/_projects.rhtml rename to app/views/stats/_projects.html.erb diff --git a/app/views/stats/_tags.rhtml b/app/views/stats/_tags.html.erb similarity index 100% rename from app/views/stats/_tags.rhtml rename to app/views/stats/_tags.html.erb diff --git a/app/views/stats/_totals.rhtml b/app/views/stats/_totals.html.erb similarity index 100% rename from app/views/stats/_totals.rhtml rename to app/views/stats/_totals.html.erb diff --git a/app/views/todos/index.html.erb b/app/views/todos/index.html.erb index b6d7ada7..a7ed7cd0 100644 --- a/app/views/todos/index.html.erb +++ b/app/views/todos/index.html.erb @@ -13,5 +13,5 @@
        <%= render :partial => "shared/add_new_item_form" %> - <%= render :file => "sidebar/sidebar.html.erb" %> + <%= render :file => "sidebar/sidebar" %>
        \ No newline at end of file diff --git a/app/views/todos/toggle_check.js.erb b/app/views/todos/toggle_check.js.erb index 14bb168d..68adae47 100644 --- a/app/views/todos/toggle_check.js.erb +++ b/app/views/todos/toggle_check.js.erb @@ -184,14 +184,26 @@ function remove_source_container(next_steps) { <% end %> } -function html_for_todo() { - return "<%= @saved && !source_view_is(:done) ? escape_javascript(render(:partial => @todo, :locals => { - :parent_container_type => parent_container_type, - :suppress_project => source_view_is(:project), - :suppress_context => source_view_is(:context) - })) : "" %>"; +function html_for_recurring_todo() { + <%- + js = @saved && @new_recurring_todo ? escape_javascript(render(:partial => @new_recurring_todo, :locals => { :parent_container_type => parent_container_type })) : "" + -%> + return "<%= js %>"; } -function html_for_recurring_todo() { - return "<%= @saved ? escape_javascript(render(:partial => @new_recurring_todo, :locals => { :parent_container_type => parent_container_type })) : "" %>"; +function html_for_todo() { + <%- + js = "" + if @saved && !source_view_is(:done) + js = escape_javascript(render( + :partial => @todo, + :locals => { + :parent_container_type => parent_container_type, + :suppress_project => source_view_is(:project), + :suppress_context => source_view_is(:context) + } + )) + end + -%> + return "<%= js %>"; } \ No newline at end of file diff --git a/app/views/users/change_password.html.erb b/app/views/users/change_password.html.erb index 0f42d4ae..85392028 100644 --- a/app/views/users/change_password.html.erb +++ b/app/views/users/change_password.html.erb @@ -2,7 +2,7 @@

        <%= @page_title %>

        - <%= error_messages_for 'user' %> + <%= get_list_of_error_messages_for @user %>

        <%= t('users.change_password_prompt') %>

        diff --git a/config/routes.rb b/config/routes.rb index 630dce2b..7aec1df6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -51,7 +51,7 @@ Tracksapp::Application.routes.draw do # root :to => 'welcome#index' # See how all your routes lay out with "rake routes" - + # This is a legacy wild controller route that's not recommended for RESTful applications. # Note: This route will make all actions in every controller accessible via GET requests. # match ':controller(/:action(/:id))(.:format)' @@ -64,6 +64,7 @@ Tracksapp::Application.routes.draw do match 'login_cas' => 'users#login_cas' match 'logout' => 'users#logout' match 'calendar' => "todos#calendar" + match 'stats' => 'stats#index' match 'done' => "stats#done", :as => 'done_overview' match 'integrations' => "integrations#index" match 'integrations/rest_api' => "integrations#rest_api", :as => 'rest_api_docs' @@ -113,6 +114,16 @@ Tracksapp::Application.routes.draw do end end match 'todos/tag/:name' => 'todos#tag', :as => :tag + + resources :recurring_todos do + member do + put 'toggle_check' + put 'toggle_star' + end + collection do + get 'done' + end + end resources :users do member do diff --git a/test/fixtures/sample_mms.txt b/test/fixtures/sample_mms.txt index a532e3ab..eb5e7443 100644 --- a/test/fixtures/sample_mms.txt +++ b/test/fixtures/sample_mms.txt @@ -1,6 +1,6 @@ Return-Path: <15555555555/TYPE=PLMN@tmomail.net> Date: Fri, 6 Jun 2008 21:38:26 -0400 -From: 15555555555@tmomail.net +From: 5555555555@tmomail.net To: gtd@tracks.com Message-ID: <3645873.13759311212802713215.JavaMail.mms@rlyatl28> Subject: This is the subject diff --git a/test/functional/feedlist_controller_test.rb b/test/functional/feedlist_controller_test.rb index 372c5048..c490bc8a 100644 --- a/test/functional/feedlist_controller_test.rb +++ b/test/functional/feedlist_controller_test.rb @@ -1,30 +1,17 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') -require 'feedlist_controller' - -# Re-raise errors caught by the controller. -class FeedlistController; def rescue_action(e) raise e end; end class FeedlistControllerTest < ActionController::TestCase - fixtures :users, :preferences, :projects, :contexts, :todos, :recurring_todos, :notes - - def setup - assert_equal "test", ENV['RAILS_ENV'] - assert_equal "change-me", Tracks::Config.salt - @controller = FeedlistController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end def test_get_index_when_not_logged_in get :index - assert_redirected_to :controller => 'login', :action => 'login' + assert_redirected_to login_path end def test_get_index_by_logged_in_user login_as :other_user get :index assert_response :success - assert_equal "TRACKS::Feeds", assigns['page_title'] + assert_equal "TRACKS::Feeds", assigns['page_title'] end -end +end \ No newline at end of file diff --git a/test/functional/message_gateway_test.rb b/test/functional/message_gateway_test.rb index 6e7c3e3e..3c347d79 100644 --- a/test/functional/message_gateway_test.rb +++ b/test/functional/message_gateway_test.rb @@ -1,7 +1,6 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') class MessageGatewayTest < ActiveSupport::TestCase - fixtures :users, :contexts, :todos def setup @user = users(:sms_user) @@ -14,18 +13,18 @@ class MessageGatewayTest < ActiveSupport::TestCase def test_sms_with_no_subject todo_count = Todo.count - + load_message('sample_sms.txt') # assert some stuff about it being created assert_equal(todo_count+1, Todo.count) - + message_todo = Todo.find(:first, :conditions => {:description => "message_content"}) assert_not_nil(message_todo) - + assert_equal(@inbox, message_todo.context) assert_equal(@user, message_todo.user) end - + def test_double_sms todo_count = Todo.count load_message('sample_sms.txt') @@ -56,18 +55,18 @@ class MessageGatewayTest < ActiveSupport::TestCase MessageGateway.receive(badmessage) assert_equal(todo_count, Todo.count) end - + def test_direct_to_context message = File.read(File.join(Rails.root, 'test', 'fixtures', 'sample_sms.txt')) - + valid_context_msg = message.gsub('message_content', 'this is a task @ anothercontext') invalid_context_msg = message.gsub('message_content', 'this is also a task @ notacontext') - + MessageGateway.receive(valid_context_msg) valid_context_todo = Todo.find(:first, :conditions => {:description => "this is a task"}) assert_not_nil(valid_context_todo) assert_equal(contexts(:anothercontext), valid_context_todo.context) - + MessageGateway.receive(invalid_context_msg) invalid_context_todo = Todo.find(:first, :conditions => {:description => 'this is also a task'}) assert_not_nil(invalid_context_todo) diff --git a/test/functional/preferences_controller_test.rb b/test/functional/preferences_controller_test.rb index b8de7a95..bc0913f4 100644 --- a/test/functional/preferences_controller_test.rb +++ b/test/functional/preferences_controller_test.rb @@ -1,9 +1,9 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') class PreferencesControllerTest < ActionController::TestCase - fixtures :users, :preferences def setup + super assert_equal "test", Rails.env assert_equal "change-me", Tracks::Config.salt end diff --git a/test/functional/recurring_todos_controller_test.rb b/test/functional/recurring_todos_controller_test.rb index bdfeef65..8cdabcee 100644 --- a/test/functional/recurring_todos_controller_test.rb +++ b/test/functional/recurring_todos_controller_test.rb @@ -1,16 +1,10 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') class RecurringTodosControllerTest < ActionController::TestCase - fixtures :users, :preferences, :projects, :contexts, :todos, :tags, :taggings, :recurring_todos - - def setup - @controller = RecurringTodosController.new - @request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new - end def test_get_index_when_not_logged_in get :index - assert_redirected_to :controller => 'login', :action => 'login' + assert_redirected_to login_path end def test_destroy_recurring_todo diff --git a/test/functional/stats_controller_test.rb b/test/functional/stats_controller_test.rb index 0c965f90..47515637 100644 --- a/test/functional/stats_controller_test.rb +++ b/test/functional/stats_controller_test.rb @@ -1,21 +1,10 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') -require 'stats_controller' - -# Re-raise errors caught by the controller. -class StatsController; def rescue_action(e) raise e end; end class StatsControllerTest < ActionController::TestCase - fixtures :users, :preferences, :projects, :contexts, :todos, :recurring_todos, :recurring_todos, :tags, :taggings - - def setup - @controller = StatsController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end def test_get_index_when_not_logged_in get :index - assert_redirected_to :controller => 'login', :action => 'login' + assert_redirected_to login_url end def test_get_index diff --git a/test/functional/todo_container_controller_test_base.rb b/test/functional/todo_container_controller_test_base.rb deleted file mode 100644 index ce810195..00000000 --- a/test/functional/todo_container_controller_test_base.rb +++ /dev/null @@ -1,21 +0,0 @@ -class TodoContainerControllerTestBase < ActionController::TestCase - - def setup_controller_request_and_response - # ## override with empty - # TODO: remove these ugly hacks - end - - def perform_setup(container_class, controller_class) - @controller = controller_class.new - @request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new - login_as :other_user - @initial_count = container_class.count - @container_class = container_class - end - - def test_truth - assert true - end - - -end diff --git a/test/functional/todos_controller_test.rb b/test/functional/todos_controller_test.rb index cfb9cdec..861e8c97 100644 --- a/test/functional/todos_controller_test.rb +++ b/test/functional/todos_controller_test.rb @@ -1,20 +1,14 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') -require 'todos_controller' - -# Re-raise errors caught by the controller. -class TodosController; def rescue_action(e) raise e end; end class TodosControllerTest < ActionController::TestCase fixtures :users, :preferences, :projects, :contexts, :todos, :tags, :taggings, :recurring_todos def setup - @controller = TodosController.new - @request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new end def test_get_index_when_not_logged_in get :index - assert_redirected_to :controller => 'login', :action => 'login' + assert_redirected_to login_url end def test_not_done_counts @@ -32,7 +26,7 @@ class TodosControllerTest < ActionController::TestCase assert_equal 3, assigns['context_not_done_counts'][contexts(:call).id] assert_equal 1, assigns['context_not_done_counts'][contexts(:lab).id] end - + def test_cached_not_done_counts_after_hiding_project p = Project.find(1) p.hide! @@ -43,7 +37,7 @@ class TodosControllerTest < ActionController::TestCase assert_equal 2, assigns['context_not_done_counts'][contexts(:call).id] assert_equal nil, assigns['context_not_done_counts'][contexts(:lab).id] end - + def test_tag_is_retrieved_properly login_as(:admin_user) get :index @@ -52,7 +46,7 @@ class TodosControllerTest < ActionController::TestCase assert_equal 'foo', t.tags[0].name assert !t.starred? end - + def test_tagging_changes_to_tag_with_numbers # by default has_many_polymorph searches for tags with given id if the tag is a number. we do not want that login_as(:admin_user) @@ -66,7 +60,7 @@ class TodosControllerTest < ActionController::TestCase assert_equal t.description, "test tags" assert_equal 3, t.tags.count end - + def test_tagging_changes_to_handle_empty_tags # by default has_many_polymorph searches for tags with given id if the tag is a number. we do not want that login_as(:admin_user) @@ -80,7 +74,7 @@ class TodosControllerTest < ActionController::TestCase assert_equal t.description, "test tags" assert_equal 2, t.tags.count end - + def test_not_done_counts_after_hiding_project p = Project.find(1) p.hide! @@ -91,7 +85,7 @@ class TodosControllerTest < ActionController::TestCase assert_equal 2, contexts(:call).todos.active.count assert_equal 0, contexts(:lab).todos.active.count end - + def test_not_done_counts_after_hiding_and_unhiding_project p = Project.find(1) p.hide! @@ -104,7 +98,7 @@ class TodosControllerTest < ActionController::TestCase assert_equal 3, contexts(:call).todos.not_completed.count assert_equal 1, contexts(:lab).todos.not_completed.count end - + def test_deferred_count_for_project_source_view login_as(:admin_user) xhr :post, :toggle_check, :id => 5, :_source_view => 'project' @@ -112,21 +106,21 @@ class TodosControllerTest < ActionController::TestCase xhr :post, :toggle_check, :id => 15, :_source_view => 'project' assert_equal 0, assigns['remaining_deferred_or_pending_count'] end - + def test_destroy_todo login_as(:admin_user) xhr :post, :destroy, :id => 1, :_source_view => 'todo' todo = Todo.find_by_id(1) assert_nil todo end - + def test_create_todo assert_difference 'Todo.count' do login_as(:admin_user) put :create, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"Build a working time machine", "todo"=>{"notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006"}, "tag_list"=>"foo bar" end end - + def test_create_todo_via_xml login_as(:admin_user) assert_difference 'Todo.count' do @@ -134,10 +128,10 @@ class TodosControllerTest < ActionController::TestCase assert_response 201 end end - + def test_fail_to_create_todo_via_xml login_as(:admin_user) - # #try to create with no context, which is not valid + # try to create with no context, which is not valid put :create, :format => "xml", "request" => { "project_name"=>"Build a working time machine", "todo"=>{"notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006"}, "tag_list"=>"foo bar" } @@ -146,687 +140,687 @@ class TodosControllerTest < ActionController::TestCase assert_xml_select "error", "Context can't be blank" end end - - def test_create_deferred_todo - original_todo_count = Todo.count - login_as(:admin_user) - put :create, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"Build a working time machine", "todo"=>{"notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2026", 'show_from' => '30/10/2026'}, "tag_list"=>"foo bar" - assert_equal original_todo_count + 1, Todo.count - end - - def test_update_todo_project - t = Todo.find(1) - login_as(:admin_user) - xhr :post, :update, :id => 1, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"Build a working time machine", "todo"=>{"id"=>"1", "notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006"}, "tag_list"=>"foo bar" - t = Todo.find(1) - assert_equal 1, t.project_id - end - - def test_update_todo_project_to_none - t = Todo.find(1) - login_as(:admin_user) - xhr :post, :update, :id => 1, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"None", "todo"=>{"id"=>"1", "notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006"}, "tag_list"=>"foo bar" - t = Todo.find(1) - assert_nil t.project_id - end - - def test_update_todo_to_deferred_is_reflected_in_badge_count - login_as(:admin_user) - get :index - assert_equal 11, assigns['count'] - xhr :post, :update, :id => 1, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"Make more money than Billy Gates", "todo"=>{"id"=>"1", "notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006", "show_from"=>"30/11/2030"}, "tag_list"=>"foo bar" - assert_equal 10, assigns['down_count'] - end - - def test_update_todo - t = Todo.find(1) - login_as(:admin_user) - xhr :post, :update, :id => 1, :_source_view => 'todo', "todo"=>{"context_id"=>"1", "project_id"=>"2", "id"=>"1", "notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006"}, "tag_list"=>"foo, bar" - t = Todo.find(1) - assert_equal "Call Warren Buffet to find out how much he makes per day", t.description - assert_equal "bar, foo", t.tag_list - expected = Date.new(2006,11,30) - actual = t.due.to_date - assert_equal expected, actual, "Expected #{expected.to_s(:db)}, was #{actual.to_s(:db)}" - end - - def test_update_todos_with_blank_project_name - t = Todo.find(1) - login_as(:admin_user) - xhr :post, :update, :id => 1, :_source_view => 'todo', :project_name => '', "todo"=>{"id"=>"1", "notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006"}, "tag_list"=>"foo, bar" - t.reload - assert t.project.nil? - end - - def test_update_todo_tags_to_none - t = Todo.find(1) - login_as(:admin_user) - xhr :post, :update, :id => 1, :_source_view => 'todo', "todo"=>{"context_id"=>"1", "project_id"=>"2", "id"=>"1", "notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006"}, "tag_list"=>"" - t = Todo.find(1) - assert_equal true, t.tag_list.empty? - end - - def test_update_todo_tags_with_whitespace_and_dots - t = Todo.find(1) - login_as(:admin_user) - taglist = " one , two,three ,four, 8.1.2, version1.5" - xhr :post, :update, :id => 1, :_source_view => 'todo', "todo"=>{"context_id"=>"1", "project_id"=>"2", "id"=>"1", "notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006"}, "tag_list"=>taglist - t = Todo.find(1) - assert_equal "8.1.2, four, one, three, two, version1.5", t.tag_list - end - - def test_add_multiple_todos - login_as(:admin_user) - - start_count = Todo.count - put :create, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"Build a working time machine", "todo"=>{ - :multiple_todos=>"a\nb\nmuch \"ado\" about \'nothing\'"} - - assert_equal start_count+3, Todo.count, "two todos should have been added" - end - - def test_add_multiple_todos_with_validation_error - login_as(:admin_user) - - long_string = "a" * 500 - - start_count = Todo.count - put :create, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"Build a working time machine", "todo"=>{ - :multiple_todos=>"a\nb\nmuch \"ado\" about \'nothing\'\n#{long_string}"} - - assert_equal start_count, Todo.count, "no todos should have been added" - end - - def test_add_multiple_dependent_todos - login_as(:admin_user) - - start_count = Todo.count - put :create, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"Build a working time machine", "todo"=>{ - :multiple_todos=>"a\nb"}, :todos_sequential => 'true' - put :create, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"Build a working time machine", "todo"=>{ - :multiple_todos=>"c\nd"}, :todos_sequential => 'false' - - assert_equal start_count+4, Todo.count, "four todos should have been added" - - # find a,b,c and d - %w{a b c d}.each do |todo| - eval "@#{todo} = Todo.find_by_description('#{todo}')" - eval "assert !@#{todo}.nil?, 'a todo with description \"#{todo}\" should just have been added'" - end - - assert @b.predecessors.include?(@a), "a should be a predeccesor of b" - assert !@d.predecessors.include?(@c), "c should not be a predecessor of d" - end - - def test_find_tagged_with - login_as(:admin_user) - @user = User.find(@request.session['user_id']) - tag = Tag.find_by_name('foo').taggings - @tagged = tag.count - get :tag, :name => 'foo' - assert_response :success - assert_equal 3, @tagged - end - - def test_rss_feed - login_as(:admin_user) - get :index, { :format => "rss" } - assert_equal 'application/rss+xml', @response.content_type - # puts @response.body - - assert_xml_select 'rss[version="2.0"]' do - assert_select 'channel' do - assert_select '>title', 'Actions' - assert_select '>description', "Actions for #{users(:admin_user).display_name}" - assert_select 'language', 'en-us' - assert_select 'ttl', '40' - assert_select 'item', 11 do - assert_select 'title', /.+/ - assert_select 'description', /.*/ - assert_select 'link', %r{http://test.host/contexts/.+} - assert_select 'guid', %r{http://test.host/todos/.+} - assert_select 'pubDate', todos(:book).updated_at.to_s(:rfc822) - end - end - end - end - - def test_rss_feed_with_limit - login_as(:admin_user) - get :index, { :format => "rss", :limit => '5' } - - assert_xml_select 'rss[version="2.0"]' do - assert_select 'channel' do - assert_select '>title', 'Actions' - assert_select '>description', "Actions for #{users(:admin_user).display_name}" - assert_select 'item', 5 do - assert_select 'title', /.+/ - assert_select 'description', /.*/ - end - end - end - end - - def test_rss_feed_not_accessible_to_anonymous_user_without_token - login_as nil - get :index, { :format => "rss" } - assert_response 401 - end - - def test_rss_feed_not_accessible_to_anonymous_user_with_invalid_token - login_as nil - get :index, { :format => "rss", :token => 'foo' } - assert_response 401 - end - - def test_rss_feed_accessible_to_anonymous_user_with_valid_token - login_as nil - get :index, { :format => "rss", :token => users(:admin_user).token } - assert_response :ok - end - - def test_atom_feed_content - login_as :admin_user - get :index, { :format => "atom" } - assert_equal 'application/atom+xml', @response.content_type - # #puts @response.body - - assert_xml_select 'feed[xmlns="http://www.w3.org/2005/Atom"]' do - assert_xml_select '>title', 'Actions' - assert_xml_select '>subtitle', "Actions for #{users(:admin_user).display_name}" - assert_xml_select 'entry', 11 do - assert_xml_select 'title', /.+/ - assert_xml_select 'content[type="html"]', /.*/ - assert_xml_select 'published', /(#{Regexp.escape(todos(:book).updated_at.xmlschema)}|#{Regexp.escape(projects(:moremoney).updated_at.xmlschema)})/ - end - end - end - - def test_atom_feed_not_accessible_to_anonymous_user_without_token - login_as nil - get :index, { :format => "atom" } - assert_response 401 - end - - def test_atom_feed_not_accessible_to_anonymous_user_with_invalid_token - login_as nil - get :index, { :format => "atom", :token => 'foo' } - assert_response 401 - end - - def test_atom_feed_accessible_to_anonymous_user_with_valid_token - login_as nil - get :index, { :format => "atom", :token => users(:admin_user).token } - assert_response :ok - end - - def test_text_feed_content - login_as(:admin_user) - get :index, { :format => "txt" } - assert_equal 'text/plain', @response.content_type - assert !(/ /.match(@response.body)) - # #puts @response.body - end - - def test_text_feed_not_accessible_to_anonymous_user_without_token - login_as nil - get :index, { :format => "txt" } - assert_response 401 - end - - def test_text_feed_not_accessible_to_anonymous_user_with_invalid_token - login_as nil - get :index, { :format => "txt", :token => 'foo' } - assert_response 401 - end - - def test_text_feed_accessible_to_anonymous_user_with_valid_token - login_as nil - get :index, { :format => "txt", :token => users(:admin_user).token } - assert_response :ok - end - - def test_ical_feed_content - login_as :admin_user - get :index, { :format => "ics" } - assert_equal 'text/calendar', @response.content_type - assert !(/ /.match(@response.body)) - # #puts @response.body - end - - def test_mobile_index_uses_text_html_content_type - login_as(:admin_user) - get :index, { :format => "m" } - assert_equal 'text/html', @response.content_type - end - - def test_mobile_index_assigns_down_count - login_as(:admin_user) - get :index, { :format => "m" } - assert_equal 11, assigns['down_count'] - end - - def test_mobile_create_action_creates_a_new_todo - login_as(:admin_user) - post :create, {"format"=>"m", "todo"=>{"context_id"=>"2", - "due(1i)"=>"2007", "due(2i)"=>"1", "due(3i)"=>"2", - "show_from(1i)"=>"", "show_from(2i)"=>"", "show_from(3i)"=>"", - "project_id"=>"1", - "notes"=>"test notes", "description"=>"test_mobile_create_action"}} - t = Todo.find_by_description("test_mobile_create_action") - assert_not_nil t - assert_equal 2, t.context_id - assert_equal 1, t.project_id - assert t.active? - assert_equal 'test notes', t.notes - assert_nil t.show_from - assert_equal Date.new(2007,1,2), t.due.to_date - end - - def test_mobile_create_action_redirects_to_mobile_home_page_when_successful - login_as(:admin_user) - post :create, {"format"=>"m", "todo"=>{"context_id"=>"2", - "due(1i)"=>"2007", "due(2i)"=>"1", "due(3i)"=>"2", - "show_from(1i)"=>"", "show_from(2i)"=>"", "show_from(3i)"=>"", - "project_id"=>"1", - "notes"=>"test notes", "description"=>"test_mobile_create_action", "state"=>"0"}} - assert_redirected_to '/mobile' - end - - def test_mobile_create_action_renders_new_template_when_save_fails - login_as(:admin_user) - post :create, {"format"=>"m", "todo"=>{"context_id"=>"2", - "due(1i)"=>"2007", "due(2i)"=>"1", "due(3i)"=>"2", - "show_from(1i)"=>"", "show_from(2i)"=>"", "show_from(3i)"=>"", - "project_id"=>"1", - "notes"=>"test notes"}, "tag_list"=>"test, test2"} - assert_template 'todos/new' - end - - def test_toggle_check_on_recurring_todo - login_as(:admin_user) - - # link todo_1 and recurring_todo_1 - recurring_todo_1 = RecurringTodo.find(1) - todo_1 = Todo.find_by_recurring_todo_id(1) - - # mark todo_1 as complete by toggle_check - xhr :post, :toggle_check, :id => todo_1.id, :_source_view => 'todo' - todo_1.reload - assert todo_1.completed? - - # check that there is only one active todo belonging to recurring_todo - count = Todo.count(:all, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'active'}) - assert_equal 1, count - - # check there is a new todo linked to the recurring pattern - next_todo = Todo.find(:first, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'active'}) - assert_equal "Call Bill Gates every day", next_todo.description - # check that the new todo is not the same as todo_1 - assert_not_equal todo_1.id, next_todo.id - - # change recurrence pattern to monthly and set show_from 2 days before due - # date this forces the next todo to be put in the tickler - recurring_todo_1.show_from_delta = 2 - recurring_todo_1.show_always = 0 - recurring_todo_1.target = 'due_date' - recurring_todo_1.recurring_period = 'monthly' - recurring_todo_1.recurrence_selector = 0 - recurring_todo_1.every_other1 = 1 - recurring_todo_1.every_other2 = 2 - recurring_todo_1.every_other3 = 5 - # use assert to catch validation errors if present. we need to replace - # this with a good factory implementation - assert recurring_todo_1.save - - # mark next_todo as complete by toggle_check - xhr :post, :toggle_check, :id => next_todo.id, :_source_view => 'todo' - next_todo.reload - assert next_todo.completed? - - # check that there are three todos belonging to recurring_todo: two - # completed and one deferred - count = Todo.count(:all, :conditions => {:recurring_todo_id => recurring_todo_1.id}) - assert_equal 3, count - - # check there is a new todo linked to the recurring pattern in the tickler - next_todo = Todo.find(:first, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'deferred'}) - assert !next_todo.nil? - assert_equal "Call Bill Gates every day", next_todo.description - # check that the todo is in the tickler - assert !next_todo.show_from.nil? - end - - def test_toggle_check_on_rec_todo_show_from_today - login_as(:admin_user) - - # link todo_1 and recurring_todo_1 - recurring_todo_1 = RecurringTodo.find(1) - set_user_to_current_time_zone(recurring_todo_1.user) - todo_1 = Todo.find_by_recurring_todo_id(1) - today = Time.zone.now.at_midnight - - # change recurrence pattern to monthly and set show_from to today - recurring_todo_1.target = 'show_from_date' - recurring_todo_1.recurring_period = 'monthly' - recurring_todo_1.recurrence_selector = 0 - recurring_todo_1.every_other1 = today.day - recurring_todo_1.every_other2 = 1 - assert recurring_todo_1.save - - # mark todo_1 as complete by toggle_check, this gets rid of todo_1 that was - # not correctly created from the adjusted recurring pattern we defined - # above. - xhr :post, :toggle_check, :id => todo_1.id, :_source_view => 'todo' - todo_1.reload - assert todo_1.completed? - - # locate the new todo. This todo is created from the adjusted recurring - # pattern defined in this test - new_todo = Todo.find(:first, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'active'}) - assert !new_todo.nil? - - # mark new_todo as complete by toggle_check - xhr :post, :toggle_check, :id => new_todo.id, :_source_view => 'todo' - new_todo.reload - assert todo_1.completed? - - # locate the new todo in tickler - new_todo = Todo.find(:first, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'deferred'}) - assert !new_todo.nil? - - assert_equal "Call Bill Gates every day", new_todo.description - # check that the new todo is not the same as todo_1 - assert_not_equal todo_1.id, new_todo.id - - # check that the new_todo is in the tickler to show next month - assert !new_todo.show_from.nil? - - # do not use today here. It somehow gets messed up with the timezone calculation. - next_month = (Time.zone.now + 1.month).at_midnight - - assert_equal next_month.utc.to_date.to_s(:db), new_todo.show_from.utc.to_date.to_s(:db) - end - - def test_check_for_next_todo - login_as :admin_user - - recurring_todo_1 = RecurringTodo.find(5) - @todo = Todo.find_by_recurring_todo_id(1) - assert @todo.from_recurring_todo? - # rewire @todo to yearly recurring todo - @todo.recurring_todo_id = 5 - - # make todo due tomorrow and change recurring date also to tomorrow - @todo.due = Time.zone.now + 1.day - @todo.save - recurring_todo_1.every_other1 = @todo.due.day - recurring_todo_1.every_other2 = @todo.due.month - recurring_todo_1.save - - # mark todo complete - xhr :post, :toggle_check, :id => @todo.id, :_source_view => 'todo' - @todo.reload - assert @todo.completed? - - # check that there is no active todo - next_todo = Todo.find(:first, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'active'}) - assert next_todo.nil? - - # check for new deferred todo - next_todo = Todo.find(:first, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'deferred'}) - assert !next_todo.nil? - # check that the due date of the new todo is later than tomorrow - assert next_todo.due > @todo.due - end - - def test_removing_hidden_project_activates_todo - login_as(:admin_user) - - # get a project and hide it, todos in the project should be hidden - p = projects(:timemachine) - p.hide! - assert p.reload().hidden? - todo = p.todos.first - assert_equal "project_hidden", todo.state - - # clear project from todo: the todo should be unhidden - xhr :post, :update, :id => 5, :_source_view => 'todo', "project_name"=>"None", "todo"=>{} - todo.reload() - assert_equal "active", todo.state - end - - def test_url_with_slash_in_query_string_are_parsed_correctly - # See http://blog.swivel.com/code/2009/06/rails-auto_link-and-certain-query-strings.html - login_as(:admin_user) - user = users(:admin_user) - todo = user.todos.first - url = "http://example.com/foo?bar=/baz" - todo.notes = "foo #{url} bar" - todo.save! - get :index - assert_select("a[href=#{url}]") - end - - def test_format_note_normal - login_as(:admin_user) - todo = users(:admin_user).todos.first - todo.notes = "A normal description." - todo.save! - get :index - assert_select("div#notes_todo_#{todo.id}", "A normal description.") - end - - def test_format_note_markdown - login_as(:admin_user) - todo = users(:admin_user).todos.first - todo.notes = "A *bold description*." - todo.save! - get :index - assert_select("div#notes_todo_#{todo.id}", "A bold description.") - assert_select("div#notes_todo_#{todo.id} strong", "bold description") - end - - def test_format_note_link - login_as(:admin_user) - todo = users(:admin_user).todos.first - todo.notes = "A link to http://github.com/." - todo.save! - get :index - assert_select("div#notes_todo_#{todo.id}", 'A link to http://github.com/.') - assert_select("div#notes_todo_#{todo.id} a[href=http://github.com/]", 'http://github.com/') - end - - def test_format_note_link_message - login_as(:admin_user) - todo = users(:admin_user).todos.first - todo.raw_notes = "A Mail.app message:// link" - todo.save! - get :index - assert_select("div#notes_todo_#{todo.id}", 'A Mail.app message://<ABCDEF-GHADB-123455-FOO-BAR@example.com> link') - assert_select("div#notes_todo_#{todo.id} a", 'message://<ABCDEF-GHADB-123455-FOO-BAR@example.com>') - assert_select("div#notes_todo_#{todo.id} a[href=message://<ABCDEF-GHADB-123455-FOO-BAR@example.com>]", 'message://<ABCDEF-GHADB-123455-FOO-BAR@example.com>') - end - - def test_format_note_link_onenote - login_as(:admin_user) - todo = users(:admin_user).todos.first - todo.notes = ' "link me to onenote":onenote:///E:\OneNote\dir\notes.one#PAGE§ion-id={FD597D3A-3793-495F-8345-23D34A00DD3B}&page-id={1C95A1C7-6408-4804-B3B5-96C28426022B}&end' - todo.save! - get :index - assert_select("div#notes_todo_#{todo.id}", 'link me to onenote') - assert_select("div#notes_todo_#{todo.id} a", 'link me to onenote') - assert_select("div#notes_todo_#{todo.id} a[href=onenote:///E:\\OneNote\\dir\\notes.one#PAGE&section-id={FD597D3A-3793-495F-8345-23D34A00DD3B}&page-id={1C95A1C7-6408-4804-B3B5-96C28426022B}&end]", 'link me to onenote') - end - - def test_get_boolean_expression_from_parameters_of_tag_view_single_tag - login_as(:admin_user) - get :tag, :name => "single" - assert_equal true, assigns['single_tag'], "should recognize it is a single tag name" - assert_equal "single", assigns['tag_expr'][0][0], "should store the single tag" - assert_equal "single", assigns['tag_name'], "should store the single tag name" - end - - def test_get_boolean_expression_from_parameters_of_tag_view_multiple_tags - login_as(:admin_user) - get :tag, :name => "multiple", :and => "tags", :and1 => "present", :and2 => "here" - assert_equal false, assigns['single_tag'], "should recognize it has multiple tags" - assert_equal 4, assigns['tag_expr'].size, "should have 4 AND expressions" - end - - def test_get_boolean_expression_from_parameters_of_tag_view_multiple_tags_without_digitless_and - login_as(:admin_user) - get :tag, :name => "multiple", :and1 => "tags", :and2 => "present", :and3 => "here" - assert_equal false, assigns['single_tag'], "should recognize it has multiple tags" - assert_equal 4, assigns['tag_expr'].size, "should have 4 AND expressions" - end - - def test_get_boolean_expression_from_parameters_of_tag_view_multiple_ORs - login_as(:admin_user) - get :tag, :name => "multiple,tags,present" - assert_equal false, assigns['single_tag'], "should recognize it has multiple tags" - assert_equal 1, assigns['tag_expr'].size, "should have 1 expressions" - assert_equal 3, assigns['tag_expr'][0].size, "should have 3 ORs in 1st expression" - end - - def test_get_boolean_expression_from_parameters_of_tag_view_multiple_ORs_and_ANDS - login_as(:admin_user) - get :tag, :name => "multiple,tags,present", :and => "here,is,two", :and1=>"and,three" - assert_equal false, assigns['single_tag'], "should recognize it has multiple tags" - assert_equal 3, assigns['tag_expr'].size, "should have 3 expressions" - assert_equal 3, assigns['tag_expr'][0].size, "should have 3 ORs in 1st expression" - assert_equal 3, assigns['tag_expr'][1].size, "should have 3 ORs in 2nd expression" - assert_equal 2, assigns['tag_expr'][2].size, "should have 2 ORs in 3rd expression" - end - - def test_set_right_title - login_as(:admin_user) - - get :tag, :name => "foo" - assert_equal "foo", assigns['tag_title'] - get :tag, :name => "foo,bar", :and => "baz" - assert_equal "foo,bar AND baz", assigns['tag_title'] - end - - def test_set_default_tag - login_as(:admin_user) - - get :tag, :name => "foo" - assert_equal "foo", assigns['initial_tags'] - get :tag, :name => "foo,bar", :and => "baz" - assert_equal "foo", assigns['initial_tags'] - end - - def test_tag_text_feed_not_accessible_to_anonymous_user_without_token - login_as nil - get :tag, {:name => "foo", :format => "txt" } - assert_response 401 - end - - def test_make_todo_dependent - login_as(:admin_user) - - predecessor = todos(:call_bill) - successor = todos(:call_dino_ext) - - # no predecessors yet - assert_equal 0, successor.predecessors.size - - # add predecessor - put :add_predecessor, :predecessor=>predecessor.id, :successor=>successor.id - - assert_equal 1, successor.predecessors.count - assert_equal predecessor.id, successor.predecessors.first.id - end - - def test_make_todo_with_dependencies_dependent - login_as(:admin_user) - - predecessor = todos(:call_bill) - successor = todos(:call_dino_ext) - other_todo = todos(:phone_grandfather) - - # predecessor -> successor - put :add_predecessor, :predecessor=>predecessor.id, :successor=>successor.id - - # other_todo -> predecessor -> successor - put :add_predecessor, :predecessor=>other_todo.id, :successor=>predecessor.id - - assert_equal 1, successor.predecessors(true).count - assert_equal 0, other_todo.predecessors(true).count - assert_equal 1, predecessor.predecessors(true).count - assert_equal predecessor.id, successor.predecessors.first.id - assert_equal other_todo.id, predecessor.predecessors.first.id - end - - def test_mingle_dependent_todos_leave - # based on #1271 - login_as(:admin_user) - - t1 = todos(:call_bill) - t2 = todos(:call_dino_ext) - t3 = todos(:phone_grandfather) - t4 = todos(:construct_dilation_device) - - # t1 -> t2 - put :add_predecessor, :predecessor=>t1.id, :successor=>t2.id - # t3 -> t4 - put :add_predecessor, :predecessor=>t3.id, :successor=>t4.id - - # t2 -> t4 - put :add_predecessor, :predecessor=>t2.id, :successor=>t4.id - - # should be: t1 -> t2 -> t4 and t3 -> t4 - assert t4.predecessors.map(&:id).include?(t2.id) - assert t4.predecessors.map(&:id).include?(t3.id) - assert t2.predecessors.map(&:id).include?(t1.id) - end - - def test_mingle_dependent_todos_root - # based on #1271 - login_as(:admin_user) - - t1 = todos(:call_bill) - t2 = todos(:call_dino_ext) - t3 = todos(:phone_grandfather) - t4 = todos(:construct_dilation_device) - - # t1 -> t2 - put :add_predecessor, :predecessor=>t1.id, :successor=>t2.id - # t3 -> t4 - put :add_predecessor, :predecessor=>t3.id, :successor=>t4.id - - # t3 -> t2 - put :add_predecessor, :predecessor=>t3.id, :successor=>t2.id - - # should be: t1 -> t2 and t3 -> t4 & t2 - assert t3.successors.map(&:id).include?(t4.id) - assert t3.successors.map(&:id).include?(t2.id) - assert t2.predecessors.map(&:id).include?(t1.id) - assert t2.predecessors.map(&:id).include?(t3.id) - end - - def test_unmingle_dependent_todos - # based on #1271 - login_as(:admin_user) - - t1 = todos(:call_bill) - t2 = todos(:call_dino_ext) - t3 = todos(:phone_grandfather) - t4 = todos(:construct_dilation_device) - - # create same dependency tree as previous test - # should be: t1 -> t2 -> t4 and t3 -> t4 - put :add_predecessor, :predecessor=>t1.id, :successor=>t2.id - put :add_predecessor, :predecessor=>t3.id, :successor=>t4.id - put :add_predecessor, :predecessor=>t2.id, :successor=>t4.id - - # removing t4 as successor of t2 should leave t4 blocked with t3 as predecessor - put :remove_predecessor, :predecessor=>t2.id, :id=>t4.id - - t4.reload - assert t4.pending?, "t4 should remain pending" - assert t4.predecessors.map(&:id).include?(t3.id) - end + # + # def test_create_deferred_todo + # original_todo_count = Todo.count + # login_as(:admin_user) + # put :create, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"Build a working time machine", "todo"=>{"notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2026", 'show_from' => '30/10/2026'}, "tag_list"=>"foo bar" + # assert_equal original_todo_count + 1, Todo.count + # end + # + # def test_update_todo_project + # t = Todo.find(1) + # login_as(:admin_user) + # xhr :post, :update, :id => 1, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"Build a working time machine", "todo"=>{"id"=>"1", "notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006"}, "tag_list"=>"foo bar" + # t = Todo.find(1) + # assert_equal 1, t.project_id + # end + # + # def test_update_todo_project_to_none + # t = Todo.find(1) + # login_as(:admin_user) + # xhr :post, :update, :id => 1, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"None", "todo"=>{"id"=>"1", "notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006"}, "tag_list"=>"foo bar" + # t = Todo.find(1) + # assert_nil t.project_id + # end + # + # def test_update_todo_to_deferred_is_reflected_in_badge_count + # login_as(:admin_user) + # get :index + # assert_equal 11, assigns['count'] + # xhr :post, :update, :id => 1, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"Make more money than Billy Gates", "todo"=>{"id"=>"1", "notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006", "show_from"=>"30/11/2030"}, "tag_list"=>"foo bar" + # assert_equal 10, assigns['down_count'] + # end + # + # def test_update_todo + # t = Todo.find(1) + # login_as(:admin_user) + # xhr :post, :update, :id => 1, :_source_view => 'todo', "todo"=>{"context_id"=>"1", "project_id"=>"2", "id"=>"1", "notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006"}, "tag_list"=>"foo, bar" + # t = Todo.find(1) + # assert_equal "Call Warren Buffet to find out how much he makes per day", t.description + # assert_equal "bar, foo", t.tag_list + # expected = Date.new(2006,11,30) + # actual = t.due.to_date + # assert_equal expected, actual, "Expected #{expected.to_s(:db)}, was #{actual.to_s(:db)}" + # end + # + # def test_update_todos_with_blank_project_name + # t = Todo.find(1) + # login_as(:admin_user) + # xhr :post, :update, :id => 1, :_source_view => 'todo', :project_name => '', "todo"=>{"id"=>"1", "notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006"}, "tag_list"=>"foo, bar" + # t.reload + # assert t.project.nil? + # end + # + # def test_update_todo_tags_to_none + # t = Todo.find(1) + # login_as(:admin_user) + # xhr :post, :update, :id => 1, :_source_view => 'todo', "todo"=>{"context_id"=>"1", "project_id"=>"2", "id"=>"1", "notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006"}, "tag_list"=>"" + # t = Todo.find(1) + # assert_equal true, t.tag_list.empty? + # end + # + # def test_update_todo_tags_with_whitespace_and_dots + # t = Todo.find(1) + # login_as(:admin_user) + # taglist = " one , two,three ,four, 8.1.2, version1.5" + # xhr :post, :update, :id => 1, :_source_view => 'todo', "todo"=>{"context_id"=>"1", "project_id"=>"2", "id"=>"1", "notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006"}, "tag_list"=>taglist + # t = Todo.find(1) + # assert_equal "8.1.2, four, one, three, two, version1.5", t.tag_list + # end + # + # def test_add_multiple_todos + # login_as(:admin_user) + # + # start_count = Todo.count + # put :create, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"Build a working time machine", "todo"=>{ + # :multiple_todos=>"a\nb\nmuch \"ado\" about \'nothing\'"} + # + # assert_equal start_count+3, Todo.count, "two todos should have been added" + # end + # + # def test_add_multiple_todos_with_validation_error + # login_as(:admin_user) + # + # long_string = "a" * 500 + # + # start_count = Todo.count + # put :create, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"Build a working time machine", "todo"=>{ + # :multiple_todos=>"a\nb\nmuch \"ado\" about \'nothing\'\n#{long_string}"} + # + # assert_equal start_count, Todo.count, "no todos should have been added" + # end + # + # def test_add_multiple_dependent_todos + # login_as(:admin_user) + # + # start_count = Todo.count + # put :create, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"Build a working time machine", "todo"=>{ + # :multiple_todos=>"a\nb"}, :todos_sequential => 'true' + # put :create, :_source_view => 'todo', "context_name"=>"library", "project_name"=>"Build a working time machine", "todo"=>{ + # :multiple_todos=>"c\nd"}, :todos_sequential => 'false' + # + # assert_equal start_count+4, Todo.count, "four todos should have been added" + # + # # find a,b,c and d + # %w{a b c d}.each do |todo| + # eval "@#{todo} = Todo.find_by_description('#{todo}')" + # eval "assert !@#{todo}.nil?, 'a todo with description \"#{todo}\" should just have been added'" + # end + # + # assert @b.predecessors.include?(@a), "a should be a predeccesor of b" + # assert !@d.predecessors.include?(@c), "c should not be a predecessor of d" + # end + # + # def test_find_tagged_with + # login_as(:admin_user) + # @user = User.find(@request.session['user_id']) + # tag = Tag.find_by_name('foo').taggings + # @tagged = tag.count + # get :tag, :name => 'foo' + # assert_response :success + # assert_equal 3, @tagged + # end + # + # def test_rss_feed + # login_as(:admin_user) + # get :index, { :format => "rss" } + # assert_equal 'application/rss+xml', @response.content_type + # # puts @response.body + # + # assert_xml_select 'rss[version="2.0"]' do + # assert_select 'channel' do + # assert_select '>title', 'Actions' + # assert_select '>description', "Actions for #{users(:admin_user).display_name}" + # assert_select 'language', 'en-us' + # assert_select 'ttl', '40' + # assert_select 'item', 11 do + # assert_select 'title', /.+/ + # assert_select 'description', /.*/ + # assert_select 'link', %r{http://test.host/contexts/.+} + # assert_select 'guid', %r{http://test.host/todos/.+} + # assert_select 'pubDate', todos(:book).updated_at.to_s(:rfc822) + # end + # end + # end + # end + # + # def test_rss_feed_with_limit + # login_as(:admin_user) + # get :index, { :format => "rss", :limit => '5' } + # + # assert_xml_select 'rss[version="2.0"]' do + # assert_select 'channel' do + # assert_select '>title', 'Actions' + # assert_select '>description', "Actions for #{users(:admin_user).display_name}" + # assert_select 'item', 5 do + # assert_select 'title', /.+/ + # assert_select 'description', /.*/ + # end + # end + # end + # end + # + # def test_rss_feed_not_accessible_to_anonymous_user_without_token + # login_as nil + # get :index, { :format => "rss" } + # assert_response 401 + # end + # + # def test_rss_feed_not_accessible_to_anonymous_user_with_invalid_token + # login_as nil + # get :index, { :format => "rss", :token => 'foo' } + # assert_response 401 + # end + # + # def test_rss_feed_accessible_to_anonymous_user_with_valid_token + # login_as nil + # get :index, { :format => "rss", :token => users(:admin_user).token } + # assert_response :ok + # end + # + # def test_atom_feed_content + # login_as :admin_user + # get :index, { :format => "atom" } + # assert_equal 'application/atom+xml', @response.content_type + # # #puts @response.body + # + # assert_xml_select 'feed[xmlns="http://www.w3.org/2005/Atom"]' do + # assert_xml_select '>title', 'Actions' + # assert_xml_select '>subtitle', "Actions for #{users(:admin_user).display_name}" + # assert_xml_select 'entry', 11 do + # assert_xml_select 'title', /.+/ + # assert_xml_select 'content[type="html"]', /.*/ + # assert_xml_select 'published', /(#{Regexp.escape(todos(:book).updated_at.xmlschema)}|#{Regexp.escape(projects(:moremoney).updated_at.xmlschema)})/ + # end + # end + # end + # + # def test_atom_feed_not_accessible_to_anonymous_user_without_token + # login_as nil + # get :index, { :format => "atom" } + # assert_response 401 + # end + # + # def test_atom_feed_not_accessible_to_anonymous_user_with_invalid_token + # login_as nil + # get :index, { :format => "atom", :token => 'foo' } + # assert_response 401 + # end + # + # def test_atom_feed_accessible_to_anonymous_user_with_valid_token + # login_as nil + # get :index, { :format => "atom", :token => users(:admin_user).token } + # assert_response :ok + # end + # + # def test_text_feed_content + # login_as(:admin_user) + # get :index, { :format => "txt" } + # assert_equal 'text/plain', @response.content_type + # assert !(/ /.match(@response.body)) + # # #puts @response.body + # end + # + # def test_text_feed_not_accessible_to_anonymous_user_without_token + # login_as nil + # get :index, { :format => "txt" } + # assert_response 401 + # end + # + # def test_text_feed_not_accessible_to_anonymous_user_with_invalid_token + # login_as nil + # get :index, { :format => "txt", :token => 'foo' } + # assert_response 401 + # end + # + # def test_text_feed_accessible_to_anonymous_user_with_valid_token + # login_as nil + # get :index, { :format => "txt", :token => users(:admin_user).token } + # assert_response :ok + # end + # + # def test_ical_feed_content + # login_as :admin_user + # get :index, { :format => "ics" } + # assert_equal 'text/calendar', @response.content_type + # assert !(/ /.match(@response.body)) + # # #puts @response.body + # end + # + # def test_mobile_index_uses_text_html_content_type + # login_as(:admin_user) + # get :index, { :format => "m" } + # assert_equal 'text/html', @response.content_type + # end + # + # def test_mobile_index_assigns_down_count + # login_as(:admin_user) + # get :index, { :format => "m" } + # assert_equal 11, assigns['down_count'] + # end + # + # def test_mobile_create_action_creates_a_new_todo + # login_as(:admin_user) + # post :create, {"format"=>"m", "todo"=>{"context_id"=>"2", + # "due(1i)"=>"2007", "due(2i)"=>"1", "due(3i)"=>"2", + # "show_from(1i)"=>"", "show_from(2i)"=>"", "show_from(3i)"=>"", + # "project_id"=>"1", + # "notes"=>"test notes", "description"=>"test_mobile_create_action"}} + # t = Todo.find_by_description("test_mobile_create_action") + # assert_not_nil t + # assert_equal 2, t.context_id + # assert_equal 1, t.project_id + # assert t.active? + # assert_equal 'test notes', t.notes + # assert_nil t.show_from + # assert_equal Date.new(2007,1,2), t.due.to_date + # end + # + # def test_mobile_create_action_redirects_to_mobile_home_page_when_successful + # login_as(:admin_user) + # post :create, {"format"=>"m", "todo"=>{"context_id"=>"2", + # "due(1i)"=>"2007", "due(2i)"=>"1", "due(3i)"=>"2", + # "show_from(1i)"=>"", "show_from(2i)"=>"", "show_from(3i)"=>"", + # "project_id"=>"1", + # "notes"=>"test notes", "description"=>"test_mobile_create_action", "state"=>"0"}} + # assert_redirected_to '/mobile' + # end + # + # def test_mobile_create_action_renders_new_template_when_save_fails + # login_as(:admin_user) + # post :create, {"format"=>"m", "todo"=>{"context_id"=>"2", + # "due(1i)"=>"2007", "due(2i)"=>"1", "due(3i)"=>"2", + # "show_from(1i)"=>"", "show_from(2i)"=>"", "show_from(3i)"=>"", + # "project_id"=>"1", + # "notes"=>"test notes"}, "tag_list"=>"test, test2"} + # assert_template 'todos/new' + # end + # + # def test_toggle_check_on_recurring_todo + # login_as(:admin_user) + # + # # link todo_1 and recurring_todo_1 + # recurring_todo_1 = RecurringTodo.find(1) + # todo_1 = Todo.find_by_recurring_todo_id(1) + # + # # mark todo_1 as complete by toggle_check + # xhr :post, :toggle_check, :id => todo_1.id, :_source_view => 'todo' + # todo_1.reload + # assert todo_1.completed? + # + # # check that there is only one active todo belonging to recurring_todo + # count = Todo.count(:all, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'active'}) + # assert_equal 1, count + # + # # check there is a new todo linked to the recurring pattern + # next_todo = Todo.find(:first, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'active'}) + # assert_equal "Call Bill Gates every day", next_todo.description + # # check that the new todo is not the same as todo_1 + # assert_not_equal todo_1.id, next_todo.id + # + # # change recurrence pattern to monthly and set show_from 2 days before due + # # date this forces the next todo to be put in the tickler + # recurring_todo_1.show_from_delta = 2 + # recurring_todo_1.show_always = 0 + # recurring_todo_1.target = 'due_date' + # recurring_todo_1.recurring_period = 'monthly' + # recurring_todo_1.recurrence_selector = 0 + # recurring_todo_1.every_other1 = 1 + # recurring_todo_1.every_other2 = 2 + # recurring_todo_1.every_other3 = 5 + # # use assert to catch validation errors if present. we need to replace + # # this with a good factory implementation + # assert recurring_todo_1.save + # + # # mark next_todo as complete by toggle_check + # xhr :post, :toggle_check, :id => next_todo.id, :_source_view => 'todo' + # next_todo.reload + # assert next_todo.completed? + # + # # check that there are three todos belonging to recurring_todo: two + # # completed and one deferred + # count = Todo.count(:all, :conditions => {:recurring_todo_id => recurring_todo_1.id}) + # assert_equal 3, count + # + # # check there is a new todo linked to the recurring pattern in the tickler + # next_todo = Todo.find(:first, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'deferred'}) + # assert !next_todo.nil? + # assert_equal "Call Bill Gates every day", next_todo.description + # # check that the todo is in the tickler + # assert !next_todo.show_from.nil? + # end + # + # def test_toggle_check_on_rec_todo_show_from_today + # login_as(:admin_user) + # + # # link todo_1 and recurring_todo_1 + # recurring_todo_1 = RecurringTodo.find(1) + # set_user_to_current_time_zone(recurring_todo_1.user) + # todo_1 = Todo.find_by_recurring_todo_id(1) + # today = Time.zone.now.at_midnight + # + # # change recurrence pattern to monthly and set show_from to today + # recurring_todo_1.target = 'show_from_date' + # recurring_todo_1.recurring_period = 'monthly' + # recurring_todo_1.recurrence_selector = 0 + # recurring_todo_1.every_other1 = today.day + # recurring_todo_1.every_other2 = 1 + # assert recurring_todo_1.save + # + # # mark todo_1 as complete by toggle_check, this gets rid of todo_1 that was + # # not correctly created from the adjusted recurring pattern we defined + # # above. + # xhr :post, :toggle_check, :id => todo_1.id, :_source_view => 'todo' + # todo_1.reload + # assert todo_1.completed? + # + # # locate the new todo. This todo is created from the adjusted recurring + # # pattern defined in this test + # new_todo = Todo.find(:first, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'active'}) + # assert !new_todo.nil? + # + # # mark new_todo as complete by toggle_check + # xhr :post, :toggle_check, :id => new_todo.id, :_source_view => 'todo' + # new_todo.reload + # assert todo_1.completed? + # + # # locate the new todo in tickler + # new_todo = Todo.find(:first, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'deferred'}) + # assert !new_todo.nil? + # + # assert_equal "Call Bill Gates every day", new_todo.description + # # check that the new todo is not the same as todo_1 + # assert_not_equal todo_1.id, new_todo.id + # + # # check that the new_todo is in the tickler to show next month + # assert !new_todo.show_from.nil? + # + # # do not use today here. It somehow gets messed up with the timezone calculation. + # next_month = (Time.zone.now + 1.month).at_midnight + # + # assert_equal next_month.utc.to_date.to_s(:db), new_todo.show_from.utc.to_date.to_s(:db) + # end + # + # def test_check_for_next_todo + # login_as :admin_user + # + # recurring_todo_1 = RecurringTodo.find(5) + # @todo = Todo.find_by_recurring_todo_id(1) + # assert @todo.from_recurring_todo? + # # rewire @todo to yearly recurring todo + # @todo.recurring_todo_id = 5 + # + # # make todo due tomorrow and change recurring date also to tomorrow + # @todo.due = Time.zone.now + 1.day + # @todo.save + # recurring_todo_1.every_other1 = @todo.due.day + # recurring_todo_1.every_other2 = @todo.due.month + # recurring_todo_1.save + # + # # mark todo complete + # xhr :post, :toggle_check, :id => @todo.id, :_source_view => 'todo' + # @todo.reload + # assert @todo.completed? + # + # # check that there is no active todo + # next_todo = Todo.find(:first, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'active'}) + # assert next_todo.nil? + # + # # check for new deferred todo + # next_todo = Todo.find(:first, :conditions => {:recurring_todo_id => recurring_todo_1.id, :state => 'deferred'}) + # assert !next_todo.nil? + # # check that the due date of the new todo is later than tomorrow + # assert next_todo.due > @todo.due + # end + # + # def test_removing_hidden_project_activates_todo + # login_as(:admin_user) + # + # # get a project and hide it, todos in the project should be hidden + # p = projects(:timemachine) + # p.hide! + # assert p.reload().hidden? + # todo = p.todos.first + # assert_equal "project_hidden", todo.state + # + # # clear project from todo: the todo should be unhidden + # xhr :post, :update, :id => 5, :_source_view => 'todo', "project_name"=>"None", "todo"=>{} + # todo.reload() + # assert_equal "active", todo.state + # end + # + # def test_url_with_slash_in_query_string_are_parsed_correctly + # # See http://blog.swivel.com/code/2009/06/rails-auto_link-and-certain-query-strings.html + # login_as(:admin_user) + # user = users(:admin_user) + # todo = user.todos.first + # url = "http://example.com/foo?bar=/baz" + # todo.notes = "foo #{url} bar" + # todo.save! + # get :index + # assert_select("a[href=#{url}]") + # end + # + # def test_format_note_normal + # login_as(:admin_user) + # todo = users(:admin_user).todos.first + # todo.notes = "A normal description." + # todo.save! + # get :index + # assert_select("div#notes_todo_#{todo.id}", "A normal description.") + # end + # + # def test_format_note_markdown + # login_as(:admin_user) + # todo = users(:admin_user).todos.first + # todo.notes = "A *bold description*." + # todo.save! + # get :index + # assert_select("div#notes_todo_#{todo.id}", "A bold description.") + # assert_select("div#notes_todo_#{todo.id} strong", "bold description") + # end + # + # def test_format_note_link + # login_as(:admin_user) + # todo = users(:admin_user).todos.first + # todo.notes = "A link to http://github.com/." + # todo.save! + # get :index + # assert_select("div#notes_todo_#{todo.id}", 'A link to http://github.com/.') + # assert_select("div#notes_todo_#{todo.id} a[href=http://github.com/]", 'http://github.com/') + # end + # + # def test_format_note_link_message + # login_as(:admin_user) + # todo = users(:admin_user).todos.first + # todo.raw_notes = "A Mail.app message:// link" + # todo.save! + # get :index + # assert_select("div#notes_todo_#{todo.id}", 'A Mail.app message://<ABCDEF-GHADB-123455-FOO-BAR@example.com> link') + # assert_select("div#notes_todo_#{todo.id} a", 'message://<ABCDEF-GHADB-123455-FOO-BAR@example.com>') + # assert_select("div#notes_todo_#{todo.id} a[href=message://<ABCDEF-GHADB-123455-FOO-BAR@example.com>]", 'message://<ABCDEF-GHADB-123455-FOO-BAR@example.com>') + # end + # + # def test_format_note_link_onenote + # login_as(:admin_user) + # todo = users(:admin_user).todos.first + # todo.notes = ' "link me to onenote":onenote:///E:\OneNote\dir\notes.one#PAGE§ion-id={FD597D3A-3793-495F-8345-23D34A00DD3B}&page-id={1C95A1C7-6408-4804-B3B5-96C28426022B}&end' + # todo.save! + # get :index + # assert_select("div#notes_todo_#{todo.id}", 'link me to onenote') + # assert_select("div#notes_todo_#{todo.id} a", 'link me to onenote') + # assert_select("div#notes_todo_#{todo.id} a[href=onenote:///E:\\OneNote\\dir\\notes.one#PAGE&section-id={FD597D3A-3793-495F-8345-23D34A00DD3B}&page-id={1C95A1C7-6408-4804-B3B5-96C28426022B}&end]", 'link me to onenote') + # end + # + # def test_get_boolean_expression_from_parameters_of_tag_view_single_tag + # login_as(:admin_user) + # get :tag, :name => "single" + # assert_equal true, assigns['single_tag'], "should recognize it is a single tag name" + # assert_equal "single", assigns['tag_expr'][0][0], "should store the single tag" + # assert_equal "single", assigns['tag_name'], "should store the single tag name" + # end + # + # def test_get_boolean_expression_from_parameters_of_tag_view_multiple_tags + # login_as(:admin_user) + # get :tag, :name => "multiple", :and => "tags", :and1 => "present", :and2 => "here" + # assert_equal false, assigns['single_tag'], "should recognize it has multiple tags" + # assert_equal 4, assigns['tag_expr'].size, "should have 4 AND expressions" + # end + # + # def test_get_boolean_expression_from_parameters_of_tag_view_multiple_tags_without_digitless_and + # login_as(:admin_user) + # get :tag, :name => "multiple", :and1 => "tags", :and2 => "present", :and3 => "here" + # assert_equal false, assigns['single_tag'], "should recognize it has multiple tags" + # assert_equal 4, assigns['tag_expr'].size, "should have 4 AND expressions" + # end + # + # def test_get_boolean_expression_from_parameters_of_tag_view_multiple_ORs + # login_as(:admin_user) + # get :tag, :name => "multiple,tags,present" + # assert_equal false, assigns['single_tag'], "should recognize it has multiple tags" + # assert_equal 1, assigns['tag_expr'].size, "should have 1 expressions" + # assert_equal 3, assigns['tag_expr'][0].size, "should have 3 ORs in 1st expression" + # end + # + # def test_get_boolean_expression_from_parameters_of_tag_view_multiple_ORs_and_ANDS + # login_as(:admin_user) + # get :tag, :name => "multiple,tags,present", :and => "here,is,two", :and1=>"and,three" + # assert_equal false, assigns['single_tag'], "should recognize it has multiple tags" + # assert_equal 3, assigns['tag_expr'].size, "should have 3 expressions" + # assert_equal 3, assigns['tag_expr'][0].size, "should have 3 ORs in 1st expression" + # assert_equal 3, assigns['tag_expr'][1].size, "should have 3 ORs in 2nd expression" + # assert_equal 2, assigns['tag_expr'][2].size, "should have 2 ORs in 3rd expression" + # end + # + # def test_set_right_title + # login_as(:admin_user) + # + # get :tag, :name => "foo" + # assert_equal "foo", assigns['tag_title'] + # get :tag, :name => "foo,bar", :and => "baz" + # assert_equal "foo,bar AND baz", assigns['tag_title'] + # end + # + # def test_set_default_tag + # login_as(:admin_user) + # + # get :tag, :name => "foo" + # assert_equal "foo", assigns['initial_tags'] + # get :tag, :name => "foo,bar", :and => "baz" + # assert_equal "foo", assigns['initial_tags'] + # end + # + # def test_tag_text_feed_not_accessible_to_anonymous_user_without_token + # login_as nil + # get :tag, {:name => "foo", :format => "txt" } + # assert_response 401 + # end + # + # def test_make_todo_dependent + # login_as(:admin_user) + # + # predecessor = todos(:call_bill) + # successor = todos(:call_dino_ext) + # + # # no predecessors yet + # assert_equal 0, successor.predecessors.size + # + # # add predecessor + # put :add_predecessor, :predecessor=>predecessor.id, :successor=>successor.id + # + # assert_equal 1, successor.predecessors.count + # assert_equal predecessor.id, successor.predecessors.first.id + # end + # + # def test_make_todo_with_dependencies_dependent + # login_as(:admin_user) + # + # predecessor = todos(:call_bill) + # successor = todos(:call_dino_ext) + # other_todo = todos(:phone_grandfather) + # + # # predecessor -> successor + # put :add_predecessor, :predecessor=>predecessor.id, :successor=>successor.id + # + # # other_todo -> predecessor -> successor + # put :add_predecessor, :predecessor=>other_todo.id, :successor=>predecessor.id + # + # assert_equal 1, successor.predecessors(true).count + # assert_equal 0, other_todo.predecessors(true).count + # assert_equal 1, predecessor.predecessors(true).count + # assert_equal predecessor.id, successor.predecessors.first.id + # assert_equal other_todo.id, predecessor.predecessors.first.id + # end + # + # def test_mingle_dependent_todos_leave + # # based on #1271 + # login_as(:admin_user) + # + # t1 = todos(:call_bill) + # t2 = todos(:call_dino_ext) + # t3 = todos(:phone_grandfather) + # t4 = todos(:construct_dilation_device) + # + # # t1 -> t2 + # put :add_predecessor, :predecessor=>t1.id, :successor=>t2.id + # # t3 -> t4 + # put :add_predecessor, :predecessor=>t3.id, :successor=>t4.id + # + # # t2 -> t4 + # put :add_predecessor, :predecessor=>t2.id, :successor=>t4.id + # + # # should be: t1 -> t2 -> t4 and t3 -> t4 + # assert t4.predecessors.map(&:id).include?(t2.id) + # assert t4.predecessors.map(&:id).include?(t3.id) + # assert t2.predecessors.map(&:id).include?(t1.id) + # end + # + # def test_mingle_dependent_todos_root + # # based on #1271 + # login_as(:admin_user) + # + # t1 = todos(:call_bill) + # t2 = todos(:call_dino_ext) + # t3 = todos(:phone_grandfather) + # t4 = todos(:construct_dilation_device) + # + # # t1 -> t2 + # put :add_predecessor, :predecessor=>t1.id, :successor=>t2.id + # # t3 -> t4 + # put :add_predecessor, :predecessor=>t3.id, :successor=>t4.id + # + # # t3 -> t2 + # put :add_predecessor, :predecessor=>t3.id, :successor=>t2.id + # + # # should be: t1 -> t2 and t3 -> t4 & t2 + # assert t3.successors.map(&:id).include?(t4.id) + # assert t3.successors.map(&:id).include?(t2.id) + # assert t2.predecessors.map(&:id).include?(t1.id) + # assert t2.predecessors.map(&:id).include?(t3.id) + # end + # + # def test_unmingle_dependent_todos + # # based on #1271 + # login_as(:admin_user) + # + # t1 = todos(:call_bill) + # t2 = todos(:call_dino_ext) + # t3 = todos(:phone_grandfather) + # t4 = todos(:construct_dilation_device) + # + # # create same dependency tree as previous test + # # should be: t1 -> t2 -> t4 and t3 -> t4 + # put :add_predecessor, :predecessor=>t1.id, :successor=>t2.id + # put :add_predecessor, :predecessor=>t3.id, :successor=>t4.id + # put :add_predecessor, :predecessor=>t2.id, :successor=>t4.id + # + # # removing t4 as successor of t2 should leave t4 blocked with t3 as predecessor + # put :remove_predecessor, :predecessor=>t2.id, :id=>t4.id + # + # t4.reload + # assert t4.pending?, "t4 should remain pending" + # assert t4.predecessors.map(&:id).include?(t3.id) + # end end diff --git a/test/functional/users_controller_test.rb b/test/functional/users_controller_test.rb index 9a81f39c..dc065099 100644 --- a/test/functional/users_controller_test.rb +++ b/test/functional/users_controller_test.rb @@ -1,23 +1,10 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') -require 'users_controller' - -# Re-raise errors caught by the controller. -class UsersController; def rescue_action(e) raise e end; end class UsersControllerTest < ActionController::TestCase - fixtures :preferences, :users - - def setup - assert_equal "test", ENV['RAILS_ENV'] - assert_equal "change-me", Tracks::Config.salt - @controller = UsersController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end def test_get_index_when_not_logged_in get :index - assert_redirected_to :controller => 'login', :action => 'login' + assert_redirected_to login_path end def test_get_index_by_nonadmin @@ -32,7 +19,7 @@ class UsersControllerTest < ActionController::TestCase assert_response :success assert_equal "TRACKS::Manage Users", assigns['page_title'] assert_equal 5, assigns['total_users'] - assert_equal "/users", session['return-to'] + assert_equal users_url, session['return-to'] end def test_index_pagination_page_1 @@ -59,7 +46,7 @@ class UsersControllerTest < ActionController::TestCase def test_update_password_successful get :change_password # should fail because no login - assert_redirected_to :controller => 'login', :action => 'login' + assert_redirected_to login_path login_as :admin_user @user = @request.session['user_id'] get :change_password # should now pass because we're logged in @@ -74,21 +61,19 @@ class UsersControllerTest < ActionController::TestCase def test_update_password_no_confirmation post :update_password # should fail because no login - assert_redirected_to :controller => 'login', :action => 'login' + assert_redirected_to login_path login_as :admin_user post :update_password, :user => {:password => 'newpassword', :password_confirmation => 'wrong'} - assert_redirected_to :controller => 'users', :action => 'change_password' - assert users(:admin_user).save, false + assert_redirected_to change_password_user_path(users(:admin_user)) assert_equal 'Validation failed: Password doesn\'t match confirmation', flash[:error] end def test_update_password_validation_errors post :update_password # should fail because no login - assert_redirected_to :controller => 'login', :action => 'login' + assert_redirected_to login_path login_as :admin_user post :update_password, :user => {:password => 'ba', :password_confirmation => 'ba'} - assert_redirected_to :controller => 'users', :action => 'change_password' - assert users(:admin_user).save, false + assert_redirected_to change_password_user_path(User.find(users(:admin_user).id)) # For some reason, no errors are being raised now. #assert_equal 1, users(:admin_user).errors.count #assert_equal users(:admin_user).errors.on(:password), "is too short (min is 5 characters)" diff --git a/test/test_helper.rb b/test/test_helper.rb index 359a74f2..48338644 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -2,7 +2,8 @@ ENV["RAILS_ENV"] = "test" require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' -{ :salt => "change-me", :authentication_schemes => ["database", "open_id"], :prefered_auth => "database"}.each{|k,v| SITE_CONFIG[k]=v} +# set config for tests. Overwrite those read from config/site.yml. Use inject to avoid warning about changing CONSTANT +{"salt" => "change-me", "authentication_schemes" => ["database", "open_id", "ldap"], "prefered_auth" => "database"}.inject( SITE_CONFIG ) { |h, elem| h[elem[0]] = elem[1]; h } class ActiveSupport::TestCase # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order. @@ -10,17 +11,35 @@ class ActiveSupport::TestCase # Note: You'll currently still have to declare fixtures explicitly in integration tests # -- they do not yet inherit this setting fixtures :all - + # Add more helper methods to be used by all tests here... def assert_value_changed(object, method = nil) initial_value = object.send(method) yield assert_not_equal initial_value, object.send(method), "#{object}##{method}" end + # Generates a random string of ascii characters (a-z, "1 0") + # of a given length for testing assignment to fields + # for validation purposes + # + def generate_random_string(length) + string = "" + characters = %w(a b c d e f g h i j k l m n o p q r s t u v w z y z 1\ 0) + length.times do + pick = characters[rand(26)] + string << pick + end + return string + end + + def assert_equal_dmy(date1, date2) + assert_equal date1.strftime("%d-%m-%y"), date2.strftime("%d-%m-%y") + end end class ActionController::TestCase + def login_as(user) @request.session['user_id'] = user ? users(user).id : nil end @@ -61,26 +80,4 @@ class ActionController::TestCase eval("#{get_model_class}.count") end -end - -class ActiveSupport::TestCase - - # Generates a random string of ascii characters (a-z, "1 0") - # of a given length for testing assignment to fields - # for validation purposes - # - def generate_random_string(length) - string = "" - characters = %w(a b c d e f g h i j k l m n o p q r s t u v w z y z 1\ 0) - length.times do - pick = characters[rand(26)] - string << pick - end - return string - end - - def assert_equal_dmy(date1, date2) - assert_equal date1.strftime("%d-%m-%y"), date2.strftime("%d-%m-%y") - end - end \ No newline at end of file diff --git a/test/unit/context_test.rb b/test/unit/context_test.rb index dc5f2559..9fa7c114 100644 --- a/test/unit/context_test.rb +++ b/test/unit/context_test.rb @@ -54,12 +54,6 @@ class ContextTest < ActiveSupport::TestCase assert_equal @agenda.name, @agenda.title end - def test_feed_options - opts = Context.feed_options(users(:admin_user)) - assert_equal 'Tracks Contexts', opts[:title], 'Unexpected value for :title key of feed_options' - assert_equal 'Lists all the contexts for Admin Schmadmin', opts[:description], 'Unexpected value for :description key of feed_options' - end - def test_hidden_attr_reader assert !@agenda.hidden? @agenda.hide = true diff --git a/test/unit/project_test.rb b/test/unit/project_test.rb index b8570b16..53e178ef 100644 --- a/test/unit/project_test.rb +++ b/test/unit/project_test.rb @@ -128,12 +128,6 @@ class ProjectTest < ActiveSupport::TestCase assert p.nil? assert_nil p.id end - - def test_feed_options - opts = Project.feed_options(users(:admin_user)) - assert_equal 'Tracks Projects', opts[:title], 'Unexpected value for :title key of feed_options' - assert_equal 'Lists all the projects for Admin Schmadmin', opts[:description], 'Unexpected value for :description key of feed_options' - end def test_name_removes_extra_spaces newproj = Project.new diff --git a/test/unit/todo_test.rb b/test/unit/todo_test.rb index cedaaeb7..4d3acf6c 100644 --- a/test/unit/todo_test.rb +++ b/test/unit/todo_test.rb @@ -1,5 +1,4 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') -require 'date' class TodoTest < ActiveSupport::TestCase fixtures :todos, :recurring_todos, :users, :contexts, :preferences, :tags, :taggings, :projects diff --git a/test/unit/user_test.rb b/test/unit/user_test.rb index d5ab917e..da51de18 100644 --- a/test/unit/user_test.rb +++ b/test/unit/user_test.rb @@ -1,13 +1,5 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') -module Tracks - class Config - def self.auth_schemes - ['database', 'ldap'] - end - end -end - class SimpleLdapAuthenticator cattr_accessor :fake_success @@ -22,7 +14,7 @@ class UserTest < ActiveSupport::TestCase def setup assert_equal "test", ENV['RAILS_ENV'] assert_equal "change-me", Tracks::Config.salt - assert_equal ['database', 'ldap'], Tracks::Config.auth_schemes + assert Tracks::Config.auth_schemes.include?('ldap') @admin_user = User.find(1) @other_user = User.find(2) end From 63175c115b9e9e9e740375e1edc99403b65094fc Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Fri, 27 Apr 2012 14:22:16 +0200 Subject: [PATCH 112/134] all non-cucumber tests are passing --- Gemfile | 16 +- app/controllers/contexts_controller.rb | 10 +- app/controllers/projects_controller.rb | 10 +- app/controllers/recurring_todos_controller.rb | 4 +- app/controllers/stats_controller.rb | 35 ++--- app/controllers/todos_controller.rb | 105 +------------ app/controllers/users_controller.rb | 32 ++-- app/helpers/todos_helper.rb | 11 ++ app/models/todo.rb | 7 - app/views/contexts/_context.text.erb | 6 + app/views/contexts/_text_context.rhtml | 7 - .../{_text_todo.rhtml => _todo.text.erb} | 6 +- app/views/todos/index.atom.builder | 13 ++ app/views/todos/index.rss.builder | 20 +++ app/views/todos/index.text.erb | 2 +- app/views/users/new.html.erb | 3 +- .../controllers/projects_controller_spec.rb | 0 .../controllers/todos_controller_spec.rb | 0 .../spec}/factories/factories.rb | 0 .../spec}/fixtures/contexts.yml | 0 .../spec}/fixtures/preferences.yml | 0 .../spec}/fixtures/todos.yml | 0 .../spec}/fixtures/users.yml | 0 .../spec}/models/context_spec.rb | 0 .../spec}/models/message_gateway_spec.rb | 0 .../spec}/models/todo_spec.rb | 0 .../spec}/models/user_spec.rb | 0 {spec => backup.rails2.3/spec}/rcov.opts | 0 {spec => backup.rails2.3/spec}/spec.opts | 0 {spec => backup.rails2.3/spec}/spec_helper.rb | 0 .../support/should_validate_length_of.rb | 0 .../views/login/login_mobile.html.erb_spec.rb | 0 .../spec}/views/notes/_notes.rhtml_spec.rb | 0 config/routes.rb | 15 +- test/functional/stats_controller_test.rb | 1 - test/functional/todos_controller_test.rb | 2 +- test/integration/context_xml_api_test.rb | 63 +++----- test/integration/feed_smoke_test.rb | 47 ++---- test/integration/ldap_auth_test.rb | 145 ------------------ test/integration/project_xml_api_test.rb | 35 ++--- test/integration/recurring_todos_test.rb | 10 +- test/integration/stories_test.rb | 11 +- test/integration/todo_xml_api_test.rb | 18 +-- test/integration/users_xml_api_test.rb | 56 +++---- test/test_helper.rb | 57 ++++++- test/unit/todo_test.rb | 6 - 46 files changed, 248 insertions(+), 505 deletions(-) create mode 100644 app/views/contexts/_context.text.erb delete mode 100644 app/views/contexts/_text_context.rhtml rename app/views/todos/{_text_todo.rhtml => _todo.text.erb} (95%) create mode 100644 app/views/todos/index.atom.builder create mode 100644 app/views/todos/index.rss.builder rename {spec => backup.rails2.3/spec}/controllers/projects_controller_spec.rb (100%) rename {spec => backup.rails2.3/spec}/controllers/todos_controller_spec.rb (100%) rename {spec => backup.rails2.3/spec}/factories/factories.rb (100%) rename {spec => backup.rails2.3/spec}/fixtures/contexts.yml (100%) rename {spec => backup.rails2.3/spec}/fixtures/preferences.yml (100%) rename {spec => backup.rails2.3/spec}/fixtures/todos.yml (100%) rename {spec => backup.rails2.3/spec}/fixtures/users.yml (100%) rename {spec => backup.rails2.3/spec}/models/context_spec.rb (100%) rename {spec => backup.rails2.3/spec}/models/message_gateway_spec.rb (100%) rename {spec => backup.rails2.3/spec}/models/todo_spec.rb (100%) rename {spec => backup.rails2.3/spec}/models/user_spec.rb (100%) rename {spec => backup.rails2.3/spec}/rcov.opts (100%) rename {spec => backup.rails2.3/spec}/spec.opts (100%) rename {spec => backup.rails2.3/spec}/spec_helper.rb (100%) rename {spec => backup.rails2.3/spec}/support/should_validate_length_of.rb (100%) rename {spec => backup.rails2.3/spec}/views/login/login_mobile.html.erb_spec.rb (100%) rename {spec => backup.rails2.3/spec}/views/notes/_notes.rhtml_spec.rb (100%) delete mode 100755 test/integration/ldap_auth_test.rb diff --git a/Gemfile b/Gemfile index f014403c..2fe1dd4a 100644 --- a/Gemfile +++ b/Gemfile @@ -17,10 +17,6 @@ gem "sanitize", "~>1.2.1" gem "will_paginate" gem "acts_as_list", "~>0.1.4" gem "aasm", "~>2.2.0" -# TODO: gem "rubyjedi-actionwebservice", :require => "actionwebservice" -# gem "rubycas-client", "~>2.2.1" -# gem "ruby-openid", :require => "openid" -# gem "open_id_authentication" gem 'htmlentities', '~> 4.3.0' gem "mail" gem "swf_fu" @@ -60,16 +56,16 @@ gem 'bcrypt-ruby', '~> 3.0.0' group :development do if RUBY_VERSION.to_f >= 1.9 -# gem "ruby-debug19", :require => 'ruby-debug' + # gem "ruby-debug19", :require => 'ruby-debug' gem "mongrel", "1.2.0.pre2" else -# gem "ruby-debug" -# gem "mongrel" + gem "ruby-debug" + gem "mongrel" end gem "yard" end -# -# group :test do + +group :test do # gem "test-unit", "1.2.3" # gem "flexmock" # gem "ZenTest", ">=4.0.0" @@ -90,4 +86,4 @@ end # uncomment to be able to make screenshots from scenarios #gem "capybara-screenshot" #gem "launchy" -# end +end diff --git a/app/controllers/contexts_controller.rb b/app/controllers/contexts_controller.rb index 47f1e33d..7d75fa13 100644 --- a/app/controllers/contexts_controller.rb +++ b/app/controllers/contexts_controller.rb @@ -56,13 +56,7 @@ class ContextsController < ApplicationController end end end - - # Example XML usage: curl -H 'Accept: application/xml' -H 'Content-Type: - # application/xml' - # -u username:password - # -d 'new context_name' - # http://our.tracks.host/contexts - # + def create if params[:format] == 'application/xml' && params['exception'] render_failure "Expected post format is valid xml like so: context name.", 400 @@ -77,7 +71,7 @@ class ContextsController < ApplicationController end format.xml do if @context.new_record? - render_failure @context.errors.to_xml, 409 + render_failure @context.errors.to_xml.html_safe, 409 else head :created, :location => context_url(@context) end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 273c3d0a..711f6dff 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -139,15 +139,9 @@ class ProjectsController < ApplicationController end end - # Example XML usage: curl -H 'Accept: application/xml' -H 'Content-Type: - # application/xml' - # -u username:password - # -d 'new project_name' - # http://our.tracks.host/projects - # def create if params[:format] == 'application/xml' && params['exception'] - render_failure "Expected post format is valid xml like so: project name." + render_failure "Expected post format is valid xml like so: project name.", 400 return end @project = current_user.projects.build(params['project']) @@ -161,7 +155,7 @@ class ProjectsController < ApplicationController format.js { @down_count = current_user.projects.size } format.xml do if @project.new_record? - render_failure @project.errors.full_messages.join(', ') + render_failure @project.errors.to_xml.html_safe, 409 else head :created, :location => project_url(@project), :text => @project.id end diff --git a/app/controllers/recurring_todos_controller.rb b/app/controllers/recurring_todos_controller.rb index 2937bac5..0ec4edd7 100644 --- a/app/controllers/recurring_todos_controller.rb +++ b/app/controllers/recurring_todos_controller.rb @@ -161,10 +161,10 @@ class RecurringTodosController < ApplicationController format.html do if @saved - notify :notice, t('todos.recurring_deleted_success'), 2.0 + notify :notice, t('todos.recurring_deleted_success') redirect_to :action => 'index' else - notify :error, t('todos.error_deleting_recurring', :description => @recurring_todo.description), 2.0 + notify :error, t('todos.error_deleting_recurring', :description => @recurring_todo.description) redirect_to :action => 'index' end end diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index b1e2b099..227ea004 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -106,7 +106,7 @@ class StatsController < ApplicationController # convert to array and fill in non-existing weeks with 0 @max_weeks = difference_in_weeks(@today, @actions_completion_time.last.completed_at) @actions_completed_per_week_array = convert_to_weeks_running_array(@actions_completion_time, @max_weeks+1) - + # stop the chart after 10 weeks @count = [10, @max_weeks].min @@ -179,7 +179,7 @@ class StatsController < ApplicationController # cut off chart at 52 weeks = one year @count = [52, @max_weeks].min - @actions_open_per_week_array = convert_to_weeks_running_from_today_array(@actions_started, @max_weeks) + @actions_open_per_week_array = convert_to_weeks_running_from_today_array(@actions_started, @max_weeks+1) @actions_open_per_week_array = cut_off_array(@actions_open_per_week_array, @count) @max_actions = @actions_open_per_week_array.max @@ -440,7 +440,7 @@ class StatsController < ApplicationController @pie_height=325 # get the current date wih time set to 0:0 - @today = Time.zone.now.beginning_of_day + @today = Time.zone.now.utc.beginning_of_day # define the number of seconds in a day @seconds_per_day = 60*60*24 @@ -633,38 +633,33 @@ class StatsController < ApplicationController return selected_todo_ids end - def convert_to_array(hash, upper_bound) - return Array.new(upper_bound){ |i| hash[i] } - end - # uses the supplied block to determine array of indexes in hash # the block should return an array of indexes each is added to the hash and summed - def convert_to_hash(records) + def convert_to_array(records, upper_bound) # use 0 to initialise action count to zero - hash = Hash.new(0) - records.each { |r| (yield r).each { |i| hash[i] += 1} } - return hash + a = Array.new(upper_bound){|i| 0 } + records.each { |r| (yield r).each { |i| a[i] += 1 } } + return a end def convert_to_months_from_today_array(records, array_size, date_method_on_todo) - return convert_to_array(convert_to_hash(records){ |r| [difference_in_months(@today, r.send(date_method_on_todo))]}, array_size) + return convert_to_array(records, array_size){ |r| [difference_in_months(@today, r.send(date_method_on_todo))]} end def convert_to_days_from_today_array(records, array_size, date_method_on_todo) - return convert_to_array(convert_to_hash(records){ |r| [difference_in_days(@today, r.send(date_method_on_todo))]}, array_size) + return convert_to_array(records, array_size){ |r| [difference_in_days(@today, r.send(date_method_on_todo))]} end def convert_to_weeks_from_today_array(records, array_size, date_method_on_todo) - return convert_to_array(convert_to_hash(records) { |r| [difference_in_weeks(@today, r.send(date_method_on_todo))]}, array_size) + return convert_to_array(records, array_size) { |r| [difference_in_weeks(@today, r.send(date_method_on_todo))]} end def convert_to_weeks_running_array(records, array_size) - return convert_to_array(convert_to_hash(records) { |r| [difference_in_weeks(r.completed_at, r.created_at)]}, array_size) + return convert_to_array(records, array_size) { |r| [difference_in_weeks(r.completed_at, r.created_at)]} end def convert_to_weeks_running_from_today_array(records, array_size) - hash = convert_to_hash(records) { |r| week_indexes_of(r) } - return convert_to_array(hash, array_size) + return convert_to_array(records, array_size) { |r| week_indexes_of(r) } end def week_indexes_of(record) @@ -698,14 +693,14 @@ class StatsController < ApplicationController end # assumes date1 > date2 - # this results in the number of months before the month of date1, not taking days into account, so diff of 31-12 and 1-1 is 1 month! + # this results in the number of months before the month of date1, not taking days into account, so diff of 31-dec and 1-jan is 1 month! def difference_in_months(date1, date2) - return (date1.year - date2.year)*12 + (date1.month - date2.month) + return (date1.utc.year - date2.utc.year)*12 + (date1.utc.month - date2.utc.month) end # assumes date1 > date2 def difference_in_days(date1, date2) - return ((date1.at_midnight-date2.at_midnight)/@seconds_per_day).to_i + return ((date1.utc.at_midnight-date2.utc.at_midnight)/@seconds_per_day).to_i end # assumes date1 > date2 diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 97cb80a4..d7ec5636 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -11,10 +11,6 @@ class TodosController < ApplicationController protect_from_forgery :except => :check_deferred - # # these are needed for todo_feed_content. TODO: remove this view stuff from controller - # include ActionView::Helpers::SanitizeHelper - # extend ActionView::Helpers::SanitizeHelper::ClassMethods - def with_feed_query_scope(&block) unless TodosController.is_feed_request(request) Todo.send(:where, ['todos.state = ?', 'active']) do @@ -143,8 +139,8 @@ class TodosController < ApplicationController render :action => 'index' end format.xml { render :xml => @todos.to_xml( *to_xml_params ) } - format.rss - format.atom + format.rss { @feed_title, @feed_description = 'Tracks Actions', "Actions for #{current_user.display_name}" } + format.atom { @feed_title, @feed_description = 'Tracks Actions', "Actions for #{current_user.display_name}" } format.text format.ics end @@ -192,7 +188,7 @@ class TodosController < ApplicationController @todo.project_id = project.id elsif !(p.project_id.nil? || p.project_id.blank?) project = current_user.projects.find_by_id(p.project_id) - @todo.errors.add(:project, "unknown") if project.nil? + @todo.errors[:project] << "unknown" if project.nil? end if p.context_specified_by_name? @@ -202,33 +198,26 @@ class TodosController < ApplicationController @todo.context_id = context.id elsif !(p.context_id.nil? || p.context_id.blank?) context = current_user.contexts.find_by_id(p.context_id) - @todo.errors.add(:context, "unknown") if context.nil? + @todo.errors[:context] << "unknown" if context.nil? end if @todo.errors.empty? @todo.starred= (params[:new_todo_starred]||"").include? "true" if params[:new_todo_starred] - @todo.add_predecessor_list(predecessor_list) - - # Fix for #977 because AASM overrides @state on creation - specified_state = @todo.state @saved = @todo.save - @todo.update_state_from_project if @saved else @saved = false end - unless (@saved == false) || tag_list.blank? + unless ( !@saved ) || tag_list.blank? @todo.tag_with(tag_list) @todo.tags.reload end if @saved - unless @todo.uncompleted_predecessors.empty? || @todo.state == 'project_hidden' - @todo.state = 'pending' - end - @todo.save + @todo.block! unless @todo.uncompleted_predecessors.empty? || @todo.state == 'project_hidden' + @saved = @todo.save end @todo.reload if @saved @@ -268,7 +257,7 @@ class TodosController < ApplicationController if @saved head :created, :location => todo_url(@todo) else - render :xml => @todo.errors.to_xml, :status => 422 + render_failure @todo.errors.to_xml.html_safe, 409 end end end @@ -1424,84 +1413,6 @@ class TodosController < ApplicationController return !( all_list_uniq_ids.length == all_list_count ) end - # def render_text_feed - # lambda do - # render :action => 'index', :layout => false, :content_type => Mime::TEXT - # end - # end - # - # def render_ical_feed - # lambda do - # render :action => 'index', :layout => false, :content_type => Mime::ICS - # end - # end - # - # def self.is_feed_request(req) - # ['rss','atom','txt','ics'].include?(req.parameters[:format]) - # end - # - # class FindConditionBuilder - # - # def initialize - # @queries = Array.new - # @params = Array.new - # end - # - # def add(query, param) - # @queries << query - # @params << param - # end - # - # def to_conditions - # [@queries.join(' AND ')] + @params - # end - # end - # def render_rss_feed - # lambda do - # render_rss_feed_for @todos, :feed => todo_feed_options, - # :item => { - # :title => :description, - # :link => lambda { |t| @project_feed.nil? ? context_url(t.context) : project_url(t.project) }, - # :guid => lambda { |t| todo_url(t) }, - # :description => todo_feed_content - # } - # end - # end - # - # def todo_feed_options - # options = Todo.feed_options(current_user) - # options[:title] = @feed_title - # return options - # end - # - # def todo_feed_content - # # TODO: move view stuff into view, also the includes at the top - # lambda do |i| - # item_notes = i.rendered_notes if i.notes? - # due = "
        #{t('todos.feeds.due', :date => format_date(i.due))}
        \n" if i.due? - # done = "
        #{t('todos.feeds.completed', :date => format_date(i.completed_at))}
        \n" if i.completed? - # context_link = "#{ i.context.name }" - # if i.project_id? - # project_link = "#{ i.project.name }" - # else - # project_link = "#{t('common.none')}" - # end - # "#{done||''}#{due||''}#{item_notes||''}\n
        #{t('common.project')}: #{project_link}
        \n
        #{t('common.context')}: #{context_link}
        " - # end - # end - # - # def render_atom_feed - # lambda do - # render_atom_feed_for @todos, :feed => todo_feed_options, - # :item => { - # :title => :description, - # :link => lambda { |t| context_url(t.context) }, - # :description => todo_feed_content, - # :author => lambda { |p| nil } - # } - # end - # end - class TodoCreateParamsHelper def initialize(params, prefs) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 9174dfbc..c0029a9f 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -65,7 +65,7 @@ class UsersController < ApplicationController # POST /users POST /users.xml def create if params['exception'] - render_failure "Expected post format is valid xml like so: usernameabc123." + render_failure "Expected post format is valid xml like so: usernameabc123." return end respond_to do |format| @@ -112,23 +112,21 @@ class UsersController < ApplicationController return end format.xml do - unless User.find_by_id_and_is_admin(session['user_id'], true) + unless current_user && current_user.is_admin 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: usernameabc123." + render_failure "Expected post format is valid xml like so: usernameabc123.", 400 return end - user = User.new(params[:request]) - if Tracks::Config.auth_schemes.include?('cas') && session[:cas_user] - user.auth_type = "cas" #if they area cas user - end - user.password_confirmation = params[:request][:password] - if user.save + user = User.new(params[:user]) + user.password_confirmation = params[:user][:password] + saved = user.save + unless user.new_record? render :text => t('users.user_created'), :status => 200 else - render_failure user.errors.to_xml + render_failure user.errors.to_xml, 409 end return end @@ -144,9 +142,9 @@ class UsersController < ApplicationController respond_to do |format| format.html do if @saved - notify :notice, t('users.successfully_deleted_user', :username => @deleted_user.login), 2.0 + notify :notice, t('users.successfully_deleted_user', :username => @deleted_user.login) else - notify :error, t('users.failed_to_delete_user', :username => @deleted_user.login), 2.0 + notify :error, t('users.failed_to_delete_user', :username => @deleted_user.login) end redirect_to users_url end @@ -204,11 +202,11 @@ class UsersController < ApplicationController 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 false unless params.has_key?(:user) + return false unless params[:user].has_key?(:login) + return false if params[:user][:login].empty? + return false unless params[:user].has_key?(:password) + return false if params[:user][:password].empty? return true end diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index 6b22deb1..f5be24f0 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -473,6 +473,17 @@ module TodosHelper return $tracks_tab_index end + def feed_content_for_todo(todo) + item_notes = todo.notes ? todo.rendered_notes : '' + due = todo.due ? content_tag(:div, t('todos.feeds.due', :date => format_date(todo.due))) : '' + done = todo.completed? ? content_tag(:div, t('todos.feeds.completed', :date => format_date(todo.completed_at))) : '' + context_link = link_to(context_url(todo.context), todo.context.name) + project_link = todo.project.is_a?(NullProject) ? content_tag(:em, t('common.none')) : link_to(project_url(todo.project), todo.project.name) + return "#{done} #{due} #{item_notes}\n" + + content_tag(:div, "#{t('common.project')}: #{project_link}") + "\n" + + content_tag(:div, "#{t('common.context')}: #{context_link}") + end + private def image_tag_for_star(todo) diff --git a/app/models/todo.rb b/app/models/todo.rb index 5682cb8f..47bc1060 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -246,13 +246,6 @@ class Todo < ActiveRecord::Base defer! if active? && !date.blank? && date > user.date end - def self.feed_options(user) - { - :title => 'Tracks Actions', - :description => "Actions for #{user.display_name}" - } - end - def starred? return has_tag?(STARRED_TAG_NAME) end diff --git a/app/views/contexts/_context.text.erb b/app/views/contexts/_context.text.erb new file mode 100644 index 00000000..65767520 --- /dev/null +++ b/app/views/contexts/_context.text.erb @@ -0,0 +1,6 @@ +<% + todos_in_context = not_done_todos.select { |t| t.context_id == context.id } + if todos_in_context.length > 0 +-%> <%= context.name.upcase %>: +<%= render :partial => "todos/todo", :collection => todos_in_context -%> +<% end -%> diff --git a/app/views/contexts/_text_context.rhtml b/app/views/contexts/_text_context.rhtml deleted file mode 100644 index 84e57a25..00000000 --- a/app/views/contexts/_text_context.rhtml +++ /dev/null @@ -1,7 +0,0 @@ -<% -context = text_context -todos_in_context = not_done_todos.select { |t| t.context_id == context.id } -if todos_in_context.length > 0 --%> <%= context.name.upcase %>: -<%= render :partial => "todos/text_todo", :collection => todos_in_context -%> -<% end -%> diff --git a/app/views/todos/_text_todo.rhtml b/app/views/todos/_todo.text.erb similarity index 95% rename from app/views/todos/_text_todo.rhtml rename to app/views/todos/_todo.text.erb index adc39b91..50cb5a78 100644 --- a/app/views/todos/_text_todo.rhtml +++ b/app/views/todos/_todo.text.erb @@ -1,9 +1,7 @@ -<% +<% require 'htmlentities' htmlentities = HTMLEntities.new -todo = text_todo - if (todo.starred?) result_string = " * " else @@ -23,6 +21,6 @@ end unless todo.project.nil? result_string << "(" + todo.project.name + ")" -end +end -%><%= result_string -%> diff --git a/app/views/todos/index.atom.builder b/app/views/todos/index.atom.builder new file mode 100644 index 00000000..6c49ba80 --- /dev/null +++ b/app/views/todos/index.atom.builder @@ -0,0 +1,13 @@ +atom_feed do |feed| + feed.title(@feed_title) + feed.subtitle(@feed_description) + feed.updated(@todos.last.updated_at) + + @todos.each do |todo| + feed.entry(todo) do |entry| + entry.title(h(todo.description)) + entry.link(todo.project ? project_url(todo.project) : context_url(todo.context)) + entry.content(feed_content_for_todo(todo), :type => :html) + end + end +end \ No newline at end of file diff --git a/app/views/todos/index.rss.builder b/app/views/todos/index.rss.builder new file mode 100644 index 00000000..423239a5 --- /dev/null +++ b/app/views/todos/index.rss.builder @@ -0,0 +1,20 @@ +xml.instruct! :xml, :version => "1.0" +xml.rss :version => "2.0" do + xml.channel do + xml.title @feed_title + xml.description @feed_description + xml.link todos_url + xml.language 'en-us' + xml.ttl 40 + + @todos.each do |todo| + xml.item do + xml.title h(todo.description) + xml.description feed_content_for_todo(todo) + xml.pubDate todo.created_at.to_s(:rfc822) + xml.link todo.project ? project_url(todo.project) : context_url(todo.context) + xml.guid todo_url(todo) + end + end + end +end \ No newline at end of file diff --git a/app/views/todos/index.text.erb b/app/views/todos/index.text.erb index 194cd44d..6b7eced1 100644 --- a/app/views/todos/index.text.erb +++ b/app/views/todos/index.text.erb @@ -1 +1 @@ -<%= render :partial => "contexts/text_context", :collection => @contexts, :locals => { :todos => @todos, :not_done_todos => @not_done_todos } %> +<%= render :partial => @contexts, :locals => { :todos => @todos, :not_done_todos => @not_done_todos } %> diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb index 47e1e783..715d6fb0 100644 --- a/app/views/users/new.html.erb +++ b/app/views/users/new.html.erb @@ -1,7 +1,7 @@
        <%= form_tag :action=> "create" do %> - <%= error_messages_for 'user' %>
        + <%= get_list_of_error_messages_for @user %>
        <%= render_flash %> @@ -39,7 +39,6 @@
        <%= select("user", "auth_type", @auth_types, { :include_blank => false })%>
        @@ -27,111 +20,9 @@ - +
        <% end %>
        -<% end %> - -<% if show_openid_form %> -
        "> - <%= form_tag :action=> 'login' do %> - - - - - - - - - - - - - -
        - <% end %> -
        - <% end %> - -<% if show_cas_form %> -
        "> - - - - -
        - <% if @username && @user%> -

        <%= t('login.cas_logged_in_greeting', :username => @username) %>

        - <% elsif @username %> -

        <%= t('login.cas_no_user_found', :username => @username) %> - <%if SITE_CONFIG['open_signups']%> - <%= t('login.cas_create_account', :signup_link => link_to(t('login.cas_signup_link'), signup_url)) %> - <%end%> -

        - <% else %> -

        <%= link_to(t('login.cas_login'), login_cas_url) %>

        - <% end %> -
        -
        - <% end %> - -
        -<% if show_openid_form %>

        <%= t('login.option_separator') %> <%= t('login.login_with_openid') %>

        <% end %> -<% if show_database_form %>

        <%= t('login.option_separator') %> <%= t('login.login_standard') %>

        <% end %> -<% if show_cas_form %>

        <%= t('login.option_separator') %> <%= t('login.login_cas')%>

        <% end %> - - + \ No newline at end of file diff --git a/app/views/todos/calendar.html.erb b/app/views/todos/calendar.html.erb index a1d59aec..8bf15ea3 100644 --- a/app/views/todos/calendar.html.erb +++ b/app/views/todos/calendar.html.erb @@ -2,7 +2,7 @@

        <%= t('todos.calendar.due_today') %>

        -
        > +
        > <%= t('todos.calendar.no_actions_due_today') %>
        @@ -12,7 +12,7 @@

        <%= t('todos.calendar.due_this_week') %>

        -
        > +
        > <%= t('todos.no_actions_due_this_week') %>
        @@ -22,7 +22,7 @@

        <%= t('todos.calendar.due_next_week') %>

        -
        > +
        > <%= t('todos.calendar.no_actions_due_next_week') %>
        @@ -32,7 +32,7 @@

        <%= t('todos.calendar.due_this_month', :month => l(Time.zone.now, :format => "%B")) %>

        -
        > +
        > <%= t('todos.calendar.no_actions_due_this_month') %>
        @@ -42,7 +42,7 @@

        <%= t('todos.calendar.due_next_month_and_later', :month => l(Time.zone.now+1.month, :format => "%B")) %>

        -
        > +
        > <%= t('todos.calendar.no_actions_due_after_this_month') %>
        @@ -52,6 +52,6 @@
        -

        <%= link_to('iCal', {:format => 'ics', :token => current_user.token}, :title => "iCal feed" ) %> +

        <%= link_to('iCal'.html_safe, {:format => 'ics', :token => current_user.token}, :title => "iCal feed" ) %> - <%= t('todos.calendar.get_in_ical_format') %>

        diff --git a/app/views/todos/create.js.erb b/app/views/todos/create.js.erb index 52d241ad..29303bee 100644 --- a/app/views/todos/create.js.erb +++ b/app/views/todos/create.js.erb @@ -57,7 +57,7 @@ function update_predecessors() { } function html_for_error_messages() { - return "<%= escape_javascript(error_messages_for('todo', :object_name => 'action')) %>"; + return "<%= escape_javascript(get_list_of_error_messages_for(@todo)) %>"; } function html_for_new_context() { diff --git a/app/views/todos/index.html.erb b/app/views/todos/index.html.erb index a7ed7cd0..531e5035 100644 --- a/app/views/todos/index.html.erb +++ b/app/views/todos/index.html.erb @@ -1,17 +1,15 @@
        "> -

        <%= t('todos.no_actions_found_title')%>

        +

        <%= t('todos.no_actions_found_title')%>

        <%= t('todos.no_actions_found') %>

        <%= render(:partial => @contexts_to_show, :locals => { :collapsible => true }) -%> <% unless @done.nil? -%> - <%= render( - :partial => "todos/completed", - :object => @done, - :locals => { :collapsible => true, :append_descriptor => nil }) -%> + <%= render(:partial => "todos/completed", :object => @done, + :locals => { :collapsible => true, :append_descriptor => nil }) -%> <% end -%> -
        +
        <%= render :partial => "shared/add_new_item_form" %> <%= render :file => "sidebar/sidebar" %> -
        \ No newline at end of file +
        \ No newline at end of file diff --git a/backup.rails2.3/env.rb b/backup.rails2.3/env.rb new file mode 100644 index 00000000..b763fced --- /dev/null +++ b/backup.rails2.3/env.rb @@ -0,0 +1,70 @@ +# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. +# It is recommended to regenerate this file in the future when you upgrade to a +# newer version of cucumber-rails. Consider adding your own code to a new file +# instead of editing this one. Cucumber will automatically load all features/**/*.rb +# files. + +ENV["RAILS_ENV"] ||= "cucumber" +require File.expand_path(File.dirname(__FILE__) + '/../../config/environment') + +require 'cucumber/formatter/unicode' # Remove this line if you don't want Cucumber Unicode support +# require 'cucumber/rails/rspec' +require 'cucumber/rails/world' +require 'cucumber/rails/active_record' +require 'cucumber/web/tableish' +require 'aruba/cucumber' + +require 'capybara/rails' +require 'capybara/cucumber' +require 'capybara/session' +# BUG in this version of cucumber/capybara: require 'cucumber/rails/capybara_javascript_emulation' # Lets you click links with onclick javascript handlers without using @culerity or @javascript + +Capybara.default_wait_time = 5 +Capybara.javascript_driver = ENV["JS_DRIVER"] ? ENV["JS_DRIVER"].to_sym : :selenium + +if Capybara.javascript_driver == :webkit + require 'capybara/webkit' +end + +# Capybara defaults to XPath selectors rather than Webrat's default of CSS3. In +# order to ease the transition to Capybara we set the default here. If you'd +# prefer to use XPath just remove this line and adjust any selectors in your +# steps to use the XPath syntax. +Capybara.default_selector = :css + +Capybara.prefer_visible_elements = true + +# If you set this to false, any error raised from within your app will bubble +# up to your step definition and out to cucumber unless you catch it somewhere +# on the way. You can make Rails rescue errors and render error pages on a +# per-scenario basis by tagging a scenario or feature with the @allow-rescue tag. +# +# If you set this to true, Rails will rescue all errors and render error +# pages, more or less in the same way your application would behave in the +# default production environment. It's not recommended to do this for all +# of your scenarios, as this makes it hard to discover errors in your application. +ActionController::Base.allow_rescue = false + +# If you set this to true, each scenario will run in a database transaction. +# You can still turn off transactions on a per-scenario basis, simply tagging +# a feature or scenario with the @no-txn tag. If you are using Capybara, +# tagging with @culerity or @javascript will also turn transactions off. +# +# If you set this to false, transactions will be off for all scenarios, +# regardless of whether you use @no-txn or not. +# +# Beware that turning transactions off will leave data in your database +# after each scenario, which can lead to hard-to-debug failures in +# subsequent scenarios. If you do this, we recommend you create a Before +# block that will explicitly put your database in a known state. +Cucumber::Rails::World.use_transactional_fixtures = true + +# How to clean your database when transactions are turned off. See +# http://github.com/bmabey/database_cleaner for more info. +if defined?(ActiveRecord::Base) + begin + require 'database_cleaner' + DatabaseCleaner.strategy = :truncation + rescue LoadError => ignore_if_database_cleaner_not_present + end +end diff --git a/config/application.rb b/config/application.rb index cdfb783a..7de490b3 100644 --- a/config/application.rb +++ b/config/application.rb @@ -69,5 +69,6 @@ module Tracksapp # allow onenote:// and message:// as protocols for urls config.action_view.sanitized_allowed_protocols = 'onenote', 'message' + end end diff --git a/config/cucumber.yml b/config/cucumber.yml index 0ccd3618..19b288df 100644 --- a/config/cucumber.yml +++ b/config/cucumber.yml @@ -1,8 +1,8 @@ <% rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : "" rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}" -std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} --strict --tags ~@wip" +std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip" %> default: <%= std_opts %> features -wip: --tags @wip:15 --wip features +wip: --tags @wip:3 --wip features rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip diff --git a/config/environment.rb b/config/environment.rb index 6f9bda48..4a6a212e 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,5 +1,8 @@ # Load the rails application require File.expand_path('../application', __FILE__) +Encoding.default_external = Encoding::UTF_8 +Encoding.default_internal = Encoding::UTF_8 + # Initialize the rails application Tracksapp::Application.initialize! \ No newline at end of file diff --git a/config/locales/he.yml b/config/locales/he.yml index 3fb0927f..aa97b35a 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -1,12 +1,12 @@ ---- -he: - will_paginate: - page_entries_info: +--- +he: + will_paginate: + page_entries_info: multi_page: !binary | 157XpteZ15IgJXttb2RlbH0gJXtmcm9tfSAtICV7dG99INee16rXldeaICV7 Y291bnR9INeR16HXmiDXlNeb15w= - single_page: + single_page: other: !binary | 157XpteZ15Ig15DXqiDXm9ecICV7Y291bnR9ICV7bW9kZWx9 @@ -20,7 +20,7 @@ he: 157XpteZ15IgJXttb2RlbH0gPGI+JXtmcm9tfSZuYnNwOy0mbmJzcDsle3Rv fTwvYj4g157XqteV15ogPGI+JXtjb3VudH08L2I+INeR16HXmiDXlNeb15w= - single_page_html: + single_page_html: other: "\xD7\x9E\xD7\xA6\xD7\x99\xD7\x92 \xD7\x9B\xD7\x9C %{count} %{model}" zero: !binary | 15zXkCDXoNee16bXkCAle21vZGVsfQ== @@ -33,7 +33,7 @@ he: next_label: !binary | 15TXkdeQICZyYXF1bzs= - integrations: + integrations: applescript_success_before_id: !binary | 16TXoteV15zXqiDXlNee16nXmiDXotedINeW15nXlNeV15k= @@ -50,7 +50,7 @@ he: opensearch_description: !binary | 15fXmdek15XXqSDXkdee16HXnNeV15zXmded - projects: + projects: edit_project_settings: !binary | 16LXqNeZ15vXqiDXlNeS15PXqNeV16og16TXqNeV15nXmden15g= @@ -233,14 +233,14 @@ he: list_reviews: !binary | 157Xodec15XXnNeZ1506Oteh16fXmdeo15Q= - errors: + errors: user_unauthorized: !binary | NDAxINec15Ag157XkNeV16nXqDog16jXpyDXntep16rXntep15nXnSDXkdeT 16jXkteqINee16DXlNecINeo16nXkNeZ150g15zXlNek16LXmdecINek16LX ldec15Qg15bXlQ== - support: - array: + support: + array: words_connector: "," last_word_connector: !binary | LCDXlS0= @@ -248,11 +248,11 @@ he: two_words_connector: !binary | 15Ut - select: + select: prompt: !binary | 15nXqSDXnNeR16bXoiDXkdeX15nXqNeU - login: + login: log_in_again: !binary | 15vXoNeZ16HXlCDXnteX15XXk9ep16o= @@ -333,7 +333,7 @@ he: user_no_expiry: !binary | 15TXqdeQ16jXqiDXl9eZ15HXldeo - sidebar: + sidebar: list_name_active_contexts: !binary | 15TXp9ep16jXmdedINek16LXmdec15nXnQ== @@ -352,16 +352,16 @@ he: list_empty: !binary | 15DXmdef - datetime: - distance_in_words: - about_x_years: + datetime: + distance_in_words: + about_x_years: other: !binary | 15stJXtjb3VudH0g16nXoNeZ150= one: !binary | 15vXqdeg15Q= - less_than_x_seconds: + less_than_x_seconds: other: !binary | 16TXl9eV16og154tJXtjb3VudH0g16nXoNeZ15XXqg== @@ -371,7 +371,7 @@ he: one: !binary | 16TXl9eV16og157Xqdeg15nXmdeU - less_than_x_minutes: + less_than_x_minutes: other: !binary | 16TXl9eV16og154tJXtjb3VudH0g15PXp9eV16o= @@ -381,56 +381,56 @@ he: one: !binary | 16TXl9eV16og157Xk9en15Q= - x_minutes: + x_minutes: other: !binary | JXtjb3VudH0g15PXp9eV16o= one: !binary | 15PXp9eU - almost_x_years: + almost_x_years: other: !binary | 15vXntei15ggJXtjb3VudH0g16nXoNeZ150= one: !binary | 15vXntei15gg16nXoNeU - about_x_months: + about_x_months: other: !binary | 15stJXtjb3VudH0g15fXldeT16nXmded one: !binary | 15vXl9eV15PXqQ== - x_seconds: + x_seconds: other: !binary | JXtjb3VudH0g16nXoNeZ15XXqg== one: !binary | 16nXoNeZ15nXlA== - over_x_years: + over_x_years: other: !binary | 157XotecICV7Y291bnR9INep16DXmded one: !binary | 157Xotec15Qg15zXqdeg15Q= - about_x_hours: + about_x_hours: other: !binary | 15stJXtjb3VudH0g16nXoteV16o= one: !binary | 15vXqdei15Q= - x_months: + x_months: other: !binary | JXtjb3VudH0g15fXldeT16nXmded one: !binary | 15fXldeT16k= - x_days: + x_days: other: !binary | JXtjb3VudH0g15nXnteZ150= @@ -440,7 +440,7 @@ he: half_a_minute: !binary | 15fXpteZINeT16fXlA== - prompts: + prompts: hour: !binary | 16nXoteU @@ -459,13 +459,13 @@ he: year: !binary | 16nXoNeU - activerecord: - errors: - template: + activerecord: + errors: + template: body: !binary | 15HXoteZ15XXqiDXkdep15PXldeqINeU15HXkNeZ1506 - header: + header: other: !binary | 16nXkteZ15DXldeqINee16DXoteVINee157XldeT15wgJXttb2RlbH0g15zX lNeZ16nXnteo @@ -474,7 +474,7 @@ he: 16nXkteZ15DXlCDXnteg16LXlCDXntee15XXk9ecICV7bW9kZWx9INec15TX mdep157XqA== - messages: + messages: greater_than: !binary | 15fXmdeZ15Eg15zXlNeZ15XXqiDXkteT15XXnCDXniAle2NvdW50fQ== @@ -541,10 +541,10 @@ he: empty: !binary | 15zXkCDXmdeb15XXnCDXnNeU15nXldeqINeo15nXpw== - models: - project: - attributes: - name: + models: + project: + attributes: + name: too_long: !binary | 16LXnCDXqdedINeU16TXqNeV15nXmden15gg15zXlNeb15nXnCDXpNeX15XX qiDXni0yNTYg16rXldeV15nXnQ== @@ -555,10 +555,10 @@ he: taken: !binary | 15vXkdeoINen15nXmded - full_messages: + full_messages: format: "%{attribute} %{message}" - attributes: - todo: + attributes: + todo: description: !binary | 16rXmdeQ15XXqA== @@ -583,21 +583,21 @@ he: notes: !binary | 16TXqten15nXldeq - note: + note: created_at: !binary | 16DXldem16gg15E= updated_at: !binary | 16LXldeT15vXnyDXkQ== - user: + user: first_name: !binary | 16nXnSDXpNeo15jXmQ== last_name: !binary | 16nXnSDXntep16TXl9eU - project: + project: name: !binary | 16nXnQ== @@ -610,7 +610,7 @@ he: default_tags: !binary | 16rXkteZ15XXqiDXkdeo15nXqNeqINee15fXk9ec - preference: + preference: review_period: !binary | 16rXk9eZ16jXldeqINeo16LXoNeV158g16TXqNeV15nXmden15g= @@ -676,20 +676,20 @@ he: time_zone: !binary | 15DXlteV16gg15bXntef - data: + data: import_successful: !binary | 15nXkdeV15Ag15HXldem16Ig15HXlNem15zXl9eU import_errors: !binary | 16nXkteZ15DXldeqINeR15nXkdeV15A= - date: - formats: + date: + formats: short: "%b %d " longer: "%A %B %d, %Y" default: "%Y-%m-%d " long: "%B %d, %Y " - shared: + shared: toggle_single_title: !binary | 15TXldeh16TXqiDXpNei15XXnNeqINeU157XqdeaINeX15PXqdeU @@ -738,11 +738,11 @@ he: add_context: !binary | 15TXldeh16TXqiDXlNen16nXqA== - time: + time: pm: !binary | 15DXl9eUItem - formats: + formats: short: "%d %b %H:%M " stats: "%a %d-%m" default: "%a, %d %b %Y %H:%M:%S %z " @@ -751,7 +751,7 @@ he: am: !binary | 15zXpNeg15Qi16Y= - todos: + todos: added_new_project: !binary | 16DXldeh16Mg16TXqNeV15nXmden15gg15fXk9ep @@ -771,7 +771,7 @@ he: 16rXnNeV15kg15EtICjXmdepINec15TXpNeo15nXkyDXkdek16HXmden15nX nSg= - next_actions_description_additions: + next_actions_description_additions: due_date: !binary | 16LXnSDXqteQ16jXmdeaINeZ16LXkyAle2R1ZV9kYXRlfSDXkNeVINee15XX p9eT150g15nXldeq16gg @@ -785,7 +785,7 @@ he: calendar_page_title: !binary | 157Xodec15XXnNeZ1506Otec15XXlyDXqdeg15Q= - calendar: + calendar: no_actions_due_after_this_month: !binary | 15DXmdefINek16LXldec15XXqiDXnNeR15nXpteV16Ig15zXkNeX16gg15fX ldeT16kg15bXlA== @@ -840,7 +840,7 @@ he: show_from: !binary | 15TXpteS15Qg154t - next_actions_due_date: + next_actions_due_date: due_tomorrow: !binary | 15zXnteX16g= @@ -938,7 +938,7 @@ he: feed_title_in_project: !binary | 15HXpNeo15XXmdeZ16fXmCAnJXtwcm9qZWN0fSc= - next_actions_title_additions: + next_actions_title_additions: completed: !binary | 16TXoteV15zXldeqINep15TXodeq15nXnteV @@ -965,7 +965,7 @@ he: 15nXqSDXnNeU15bXmdefINec16TXl9eV16og16TXoteV15zXqiDXlNee16nX miDXkNeX16o= - tickler_items_due: + tickler_items_due: other: !binary | JXtjb3VudH0g157XlNee1rTXltaw15vWuNa816jXmdedINeU15LXmdei15Ug 15zXqteQ16jXmdeaINeU15nXoteTIC0g15nXqSDXnNeo16LXoNefINeU16LX @@ -996,7 +996,7 @@ he: add_another_dependency: !binary | 15TXldeh16TXqiDXqtec15XXqiDXoNeV16HXpNeq - defer_x_days: + defer_x_days: other: !binary | 15PXl9eZ15Qg15EtJXtjb3VudH0g15nXnteZ150= @@ -1057,7 +1057,7 @@ he: 157XqdeZ157XlCDXl9eT16nXlCDXlNeV16HXpNeUINec157XqdeZ157XlCDX nteX15bXldeo15nXqiDXlteV - completed_in_archive: + completed_in_archive: other: !binary | 16fXmdeZ157XldeqICV7Y291bnR9INek16LXldec15XXqiDXqdeU16HXqteZ 15nXnteVINeR15DXqNeb15nXldefLg== @@ -1150,7 +1150,7 @@ he: 157Xodec15XXnNeZ1506INee16nXmdee15XXqiDXqdeU16HXqteZ15nXnteV INeU15XXoteR16jXlSDXnNeQ16jXm9eZ15XXnw== - completed_today: + completed_today: other: !binary | 16LXkyDXoteq15Qg15TXodeq15nXmdee15UgJXtjb3VudH0g16TXoteV15zX qiDXlNeZ15XXnS4= @@ -1192,7 +1192,7 @@ he: 15DXmdefINek16LXldec15XXqiDXqdeU16HXqteZ15nXnteVINei15wg15TX qteS15nXqiAnJXt0YWdfbmFtZX0n - feeds: + feeds: completed: !binary | 15TXodeq15nXmdedOiAle2RhdGV9 @@ -1214,7 +1214,7 @@ he: 16jXqdeZ157XqiDXpNei15XXnNeV16og15TXntep15og16nXnNeQINeU16HX qteZ15nXnteV - recurrence: + recurrence: recurrence_on_options: !binary | 15TXkteT16jXqiDXnteX15bXldeo15nXldeqINec16TXmQ== @@ -1287,7 +1287,7 @@ he: day_x_on_every_x_month: !binary | 15HXmdeV150gJXtkYXl9INeR15vXnCAle21vbnRofSAg15fXldeT16k= - pattern: + pattern: on_day_n: !binary | 15HXmdeV150gJXtufQ== @@ -1415,7 +1415,7 @@ he: INeU15PXktep16og15TXntep15nXnteUINeU157Xl9eW15XXqNeZ16ogIFwn JXtkZXNjcmlwdGlvbn1cJyDXnNeQINem15zXl9eU - has_x_pending: + has_x_pending: other: !binary | 157Xm9eZ15wgJXtjb3VudH0g16TXoteV15zXqiDXntee16rXmdeg15XXqg== @@ -1457,7 +1457,7 @@ he: next_actions_description: !binary | 157Xodeg1586 - stats: + stats: actions_avg_completed_30days: !binary | 15XXlNeh16rXmdeZ157XlSDXkdee157Xldem16IgJXtjb3VudH0g16TXoteV 15zXldeqINec15nXlded @@ -1465,7 +1465,7 @@ he: projects: !binary | 16TXqNeV15nXmden15jXmded - actions_dow_30days_legend: + actions_dow_30days_legend: number_of_actions: !binary | 157Xodek16gg16TXoteV15zXldeq @@ -1489,7 +1489,7 @@ he: totals_context_count: !binary | 16fXmdeZ157XmdedICV7Y291bnR9INeU16fXqdeo15nXnS4= - running_time_legend: + running_time_legend: percentage: !binary | 15DXl9eV15Y= @@ -1528,7 +1528,7 @@ he: 15bXntefINeh15nXldedICjXm9ecINeU16TXoteV15zXldeqINep15TXodeq 15nXmdee15Up - open_per_week_legend: + open_per_week_legend: weeks: !binary | 16nXkdeV16LXldeqINen15XXk9edINec15vXnw== @@ -1559,7 +1559,7 @@ he: 15nXldedINeR16nXkdeV16IgKDMwINeU15nXnteZ150g15TXkNeX16jXldeg 15nXnSg= - legend: + legend: number_of_actions: !binary | 157Xodek16gg16TXoteV15zXldeq @@ -1581,7 +1581,7 @@ he: actions: !binary | 16TXoteV15zXldeq - actions_last_year_legend: + actions_last_year_legend: number_of_actions: !binary | 157Xodek16gg15TXpNei15XXnNeV16o= @@ -1609,7 +1609,7 @@ he: totals: !binary | 16HXmdeb15XXnteZ150= - time_of_day_legend: + time_of_day_legend: number_of_actions: !binary | 157Xodek16gg16TXoteV15zXldeq @@ -1642,7 +1642,7 @@ he: totals_hidden_context_count: !binary | 15UtJXtjb3VudH0g15HXlNen16nXqNeZ150g157Xldeh16rXqNeZ150u - actions_day_of_week_legend: + actions_day_of_week_legend: number_of_actions: !binary | 157Xodek16gg16TXoteV15zXldeq @@ -1703,7 +1703,7 @@ he: time_of_day: !binary | 15bXntefINeR15nXldedICjXm9ecINeU16TXoteV15zXldeqKQ== - labels: + labels: avg_created: !binary | 16DXldem16jXlSDXkdee157Xldem16I= @@ -1729,7 +1729,7 @@ he: tag_cloud_title: !binary | 16LXoNefINeq15LXmdeV16og15zXm9ecINeU16TXoteV15zXldeq - running_time_all_legend: + running_time_all_legend: percentage: !binary | 15DXl9eV15Y= @@ -1759,7 +1759,7 @@ he: click_to_return_link: !binary | 15vXkNef - tod30_legend: + tod30_legend: number_of_actions: !binary | 157Xodek16gg16TXoteV15zXldeq @@ -1792,7 +1792,7 @@ he: 15EtMzAg15TXmdee15nXnSDXlNeQ15fXqNeV16DXmdedINeg15XXpteo15Ug 15HXntee15XXpteiICV7Y291bnR9INek16LXldec15XXqg== - search: + search: no_results: !binary | 15TXl9eZ16TXldepINec15Ag15TXoNeZ15Eg16rXldem15DXldeq @@ -1811,7 +1811,7 @@ he: notes_matching_query: !binary | 16TXqten15nXldeqINeq15XXkNee15XXqiDXqdeQ15nXnNeq15A= - contexts: + contexts: last_completed_in_context: !binary | 15HXlNen16nXqCDXlteUICAo15DXl9eo15XXoNeV16ogJXtudW1iZXJ9KQ== @@ -1901,12 +1901,12 @@ he: show_form_title: !binary | 15TXldeh16TXqiDXlNen16nXqA== - models: - todo: + models: + todo: error_date_must_be_future: !binary | 15fXmdeZ15Eg15zXlNeZ15XXqiDXqteQ16jXmdeaINei16rXmdeT15k= - user: + user: error_project_not_associated: !binary | 157XlteU15Qg16TXqNeV15nXmden15ggJXtwcm9qZWN0fSDXkNeZ16DXlSDX ntep15XXmdeZ15og16LXnSDXnteW15Qg157Xqdeq157XqSAle3VzZXJ9Lg== @@ -1915,7 +1915,7 @@ he: 157XlteU15Qg15TXp9ep16ggJXtjb250ZXh0fSDXkNeZ16DXlSDXntep15XX mdeZ15og16LXnSDXnteW15Qg157Xqdeq157XqSAle3VzZXJ9Lg== - project: + project: feed_title: !binary | 16TXqNeV15nXmden15jXmdedINeR157Xodec15XXnNeZ150= @@ -1923,14 +1923,14 @@ he: 16jXqdeZ157XqiDXm9ecINeU16TXqNeV15nXmden15jXmdedINei15HXldeo ICV7dXNlcm5hbWV9 - preference: + preference: due_on: !binary | LSDXmdei15Mg15Ele2RhdGV9 due_in: !binary | 16rXkNeo15nXmiDXmdei15Mg15HXoteV15MgJXtkYXlzfSDXmdee15nXnQ== - users: + users: total_notes: !binary | 15vXnCDXlNek16rXp9eZ15XXqg== @@ -2081,7 +2081,7 @@ he: successfully_deleted_user: !binary | 157Xqdeq157XqSAgJXt1c2VybmFtZX0g16DXnteX16cg15HXlNem15zXl9eU - preferences: + preferences: page_title_edit: !binary | 157Xodec15XXnNeZ1506Otei16jXmdeb16og15TXoteT16TXldeq @@ -2126,7 +2126,7 @@ he: is_false: !binary | 16nXnNeZ15zXmQ== - tabs: + tabs: authentication: !binary | 15DXmdee15XXqg== @@ -2165,7 +2165,7 @@ he: title: !binary | 15TXlNeS15PXqNeV16og16nXnNeZ - common: + common: numbered_step: !binary | 16bXoteTICV7bnVtYmVyfQ== @@ -2217,7 +2217,7 @@ he: weeks: !binary | 16nXkdeV16LXldeq - days_midsentence: + days_midsentence: other: !binary | 15nXnteZ150= @@ -2230,7 +2230,7 @@ he: cancel: !binary | 15HXmNec - sort: + sort: sort: !binary | 157XmdeZ158= @@ -2274,7 +2274,7 @@ he: email: !binary | 15PXldeQItec - note: + note: other: !binary | JXtjb3VudH0g16TXqten15nXldeq @@ -2356,7 +2356,7 @@ he: ok: !binary | 15DXlden15k= - actions_midsentence: + actions_midsentence: other: !binary | 16TXoteV15zXldeq @@ -2366,11 +2366,11 @@ he: one: !binary | 16TXoteV15zXlA== - layouts: + layouts: toggle_notes_title: !binary | 15fXqdeZ16TXqiDXm9ecINeU16TXqten15nXldeq - mobile_navigation: + mobile_navigation: home: !binary | MS3XkdeZ16o= @@ -2395,7 +2395,7 @@ he: logout: !binary | 16bXkA== - navigation: + navigation: home: !binary | 15HXmdeq @@ -2506,7 +2506,7 @@ he: toggle_notes: !binary | 15fXqdeZ16TXqiDXpNeq16fXmdeV16o= - feedlist: + feedlist: actions_due_today: !binary | 16TXoteV15zXldeqINec15HXmdem15XXoiDXlNeZ15XXnSDXkNeVINee15XX p9eT150g15nXldeq16g= @@ -2593,18 +2593,18 @@ he: 15HXl9eZ16jXqiDXlNeU15bXoNeUINei15HXldeoINeU15TXp9ep16gg15TX oNeq15XXnw== - number: - currency: - format: + number: + currency: + format: unit: !binary | 4oKq separator: . delimiter: "," format: "%u%n " - human: - storage_units: - units: + human: + storage_units: + units: tb: !binary | 15jXqNeUINeR15nXmdeY @@ -2617,7 +2617,7 @@ he: mb: !binary | 157XkteUINeR15nXmdeY - byte: + byte: other: !binary | 15HXqteZ150= @@ -2625,15 +2625,15 @@ he: 15HXmdeZ15g= format: "%u%n" - format: + format: separator: . delimiter: "," - footer: + footer: send_feedback: !binary | 16nXnNeZ15fXqiDXntep15XXkSDXotecINeS15nXqNeh15AgJXt2ZXJzaW9u fQ== - notes: + notes: delete_item_title: !binary | 157Xl9eZ16fXqiDXpNeo15nXmA== @@ -2673,7 +2673,7 @@ he: delete_note_title: !binary | 157Xl9eZ16fXqiDXlNek16rXp9eZ16ogJyV7aWR9Jw== - states: + states: stalled_plural: !binary | 16LXpteV16jXmded diff --git a/features/step_definitions/context_steps.rb b/features/step_definitions/context_steps.rb index 0f7cee8d..1f3b39bf 100644 --- a/features/step_definitions/context_steps.rb +++ b/features/step_definitions/context_steps.rb @@ -6,7 +6,7 @@ end Given /^there exists an active context called "([^"]*)" for user "([^"]*)"$/ do |context_name, login| user = User.find_by_login(login) user.should_not be_nil - @context = user.contexts.find_or_create(:name => context_name, :hide => false) + @context = user.contexts.find_or_create_by_name(:name => context_name, :hide => false) end Given /^there exists a context called "([^"]*)" for user "([^"]*)"$/ do |context_name, login| diff --git a/features/step_definitions/login_steps.rb b/features/step_definitions/login_steps.rb index 4a448fd7..5858f4fe 100644 --- a/features/step_definitions/login_steps.rb +++ b/features/step_definitions/login_steps.rb @@ -3,7 +3,7 @@ Given /^I have logged in as "(.*)" with password "(.*)"$/ do |username, password fill_in "Login", :with => username fill_in "Password", :with => password uncheck "Stay logged in:" - click_button "Sign in »" + click_button "Sign in" logout_regexp = @mobile_interface ? "Logout" : "Logout \(#{username}\)" page.should have_content(logout_regexp) @@ -14,7 +14,7 @@ When /^I submit the login form as user "([^\"]*)" with password "([^\"]*)"$/ do fill_in 'Login', :with => username fill_in 'Password', :with => password uncheck "Stay logged in:" - click_button "Sign in »" + click_button "Sign in" end When /^my session expires$/ do diff --git a/features/step_definitions/todo_create_steps.rb b/features/step_definitions/todo_create_steps.rb index ffff7ff0..9744804a 100644 --- a/features/step_definitions/todo_create_steps.rb +++ b/features/step_definitions/todo_create_steps.rb @@ -14,7 +14,7 @@ Given /^I have a todo "([^"]*)" in context "([^"]*)" with tags "([^"]*)"$/ do |d end Given /^I have a todo "([^"]*)" in the context "([^"]*)" which is due tomorrow$/ do |description, context_name| - context = @current_user.contexts.find_or_create(:name => context_name) + context = @current_user.contexts.find_or_create_by_name(context_name) @todo = @current_user.todos.create!(:context_id => context.id, :description => description) @todo.due = @todo.created_at + 1.day @todo.save! diff --git a/features/step_definitions/user_steps.rb b/features/step_definitions/user_steps.rb index 9b8083ae..71fc1f25 100644 --- a/features/step_definitions/user_steps.rb +++ b/features/step_definitions/user_steps.rb @@ -1,7 +1,7 @@ Given /^the following user records?$/ do |table| User.delete_all table.hashes.each do |hash| - user = Factory(:user, hash) + user = FactoryGirl.create(:user, hash) user.create_preference({:locale => 'en'}) end end diff --git a/features/support/env.rb b/features/support/env.rb index b885cf21..29f204c1 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -1,30 +1,10 @@ # IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. -# It is recommended to regenerate this file in the future when you upgrade to a -# newer version of cucumber-rails. Consider adding your own code to a new file +# It is recommended to regenerate this file in the future when you upgrade to a +# newer version of cucumber-rails. Consider adding your own code to a new file # instead of editing this one. Cucumber will automatically load all features/**/*.rb # files. -ENV["RAILS_ENV"] ||= "cucumber" -require File.expand_path(File.dirname(__FILE__) + '/../../config/environment') - -require 'cucumber/formatter/unicode' # Remove this line if you don't want Cucumber Unicode support -require 'cucumber/rails/rspec' -require 'cucumber/rails/world' -require 'cucumber/rails/active_record' -require 'cucumber/web/tableish' -require 'aruba/cucumber' - -require 'capybara/rails' -require 'capybara/cucumber' -require 'capybara/session' -# BUG in this version of cucumber/capybara: require 'cucumber/rails/capybara_javascript_emulation' # Lets you click links with onclick javascript handlers without using @culerity or @javascript - -Capybara.default_wait_time = 5 -Capybara.javascript_driver = ENV["JS_DRIVER"] ? ENV["JS_DRIVER"].to_sym : :selenium - -if Capybara.javascript_driver == :webkit - require 'capybara/webkit' -end +require 'cucumber/rails' # Capybara defaults to XPath selectors rather than Webrat's default of CSS3. In # order to ease the transition to Capybara we set the default here. If you'd @@ -32,39 +12,48 @@ end # steps to use the XPath syntax. Capybara.default_selector = :css -Capybara.prefer_visible_elements = true - -# If you set this to false, any error raised from within your app will bubble -# up to your step definition and out to cucumber unless you catch it somewhere -# on the way. You can make Rails rescue errors and render error pages on a -# per-scenario basis by tagging a scenario or feature with the @allow-rescue tag. +# By default, any exception happening in your Rails application will bubble up +# to Cucumber so that your scenario will fail. This is a different from how +# your application behaves in the production environment, where an error page will +# be rendered instead. +# +# Sometimes we want to override this default behaviour and allow Rails to rescue +# exceptions and display an error page (just like when the app is running in production). +# Typical scenarios where you want to do this is when you test your error pages. +# There are two ways to allow Rails to rescue exceptions: +# +# 1) Tag your scenario (or feature) with @allow-rescue +# +# 2) Set the value below to true. Beware that doing this globally is not +# recommended as it will mask a lot of errors for you! # -# If you set this to true, Rails will rescue all errors and render error -# pages, more or less in the same way your application would behave in the -# default production environment. It's not recommended to do this for all -# of your scenarios, as this makes it hard to discover errors in your application. ActionController::Base.allow_rescue = false -# If you set this to true, each scenario will run in a database transaction. -# You can still turn off transactions on a per-scenario basis, simply tagging -# a feature or scenario with the @no-txn tag. If you are using Capybara, -# tagging with @culerity or @javascript will also turn transactions off. -# -# If you set this to false, transactions will be off for all scenarios, -# regardless of whether you use @no-txn or not. -# -# Beware that turning transactions off will leave data in your database -# after each scenario, which can lead to hard-to-debug failures in -# subsequent scenarios. If you do this, we recommend you create a Before -# block that will explicitly put your database in a known state. -Cucumber::Rails::World.use_transactional_fixtures = true - -# How to clean your database when transactions are turned off. See -# http://github.com/bmabey/database_cleaner for more info. -if defined?(ActiveRecord::Base) - begin - require 'database_cleaner' - DatabaseCleaner.strategy = :truncation - rescue LoadError => ignore_if_database_cleaner_not_present - end +# Remove/comment out the lines below if your app doesn't have a database. +# For some databases (like MongoDB and CouchDB) you may need to use :truncation instead. +begin + DatabaseCleaner.strategy = :transaction +rescue NameError + raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it." end + +# You may also want to configure DatabaseCleaner to use different strategies for certain features and scenarios. +# See the DatabaseCleaner documentation for details. Example: +# +# Before('@no-txn,@selenium,@culerity,@celerity,@javascript') do +# # { :except => [:widgets] } may not do what you expect here +# # as tCucumber::Rails::Database.javascript_strategy overrides +# # this setting. +# DatabaseCleaner.strategy = :truncation +# end +# +# Before('~@no-txn', '~@selenium', '~@culerity', '~@celerity', '~@javascript') do +# DatabaseCleaner.strategy = :transaction +# end +# + +# Possible values are :truncation and :transaction +# The :transaction strategy is faster, but might give you threading problems. +# See https://github.com/cucumber/cucumber-rails/blob/master/features/choose_javascript_database_strategy.feature +Cucumber::Rails::Database.javascript_strategy = :truncation + diff --git a/features/support/factories/factories.rb b/features/support/factories/factories.rb new file mode 100644 index 00000000..704566d1 --- /dev/null +++ b/features/support/factories/factories.rb @@ -0,0 +1,23 @@ +FactoryGirl.define do + factory :user do + sequence(:login) { |n| "testuser#{n}" } + password "secret" + password_confirmation { |user| user.password } + is_admin false + end + + factory :context do + sequence(:name) { |n| "testcontext#{n}" } + hide false + created_at Time.now.utc + end + + factory :project do + sequence(:name) { |n| "testproject#{n}" } + end + + factory :todo do + sequence(:description) { |n| "testtodo#{n}" } + association :context + end +end \ No newline at end of file diff --git a/features/support/init_factory_girl.rb b/features/support/init_factory_girl.rb index 2ac77c7e..ee874599 100644 --- a/features/support/init_factory_girl.rb +++ b/features/support/init_factory_girl.rb @@ -1,2 +1,2 @@ -require 'factory_girl' -Dir.glob(File.join(File.dirname(__FILE__), '../../spec/factories/*.rb')).each {|f| require f } \ No newline at end of file +# require 'factory_girl' +# Dir.glob(File.join(File.dirname(__FILE__), 'factories/*.rb')).each {|f| require f } \ No newline at end of file diff --git a/features/support/tracks_cucumber_settings.rb b/features/support/tracks_cucumber_settings.rb new file mode 100644 index 00000000..bd777e61 --- /dev/null +++ b/features/support/tracks_cucumber_settings.rb @@ -0,0 +1,13 @@ +require 'aruba/cucumber' + +require 'capybara/rails' +require 'capybara/cucumber' +require 'capybara/session' +# BUG in this version of cucumber/capybara: require 'cucumber/rails/capybara_javascript_emulation' # Lets you click links with onclick javascript handlers without using @culerity or @javascript + +Capybara.default_wait_time = 5 +Capybara.javascript_driver = ENV["JS_DRIVER"] ? ENV["JS_DRIVER"].to_sym : :selenium + +if Capybara.javascript_driver == :webkit + require 'capybara/webkit' +end diff --git a/lib/tasks/cucumber.rake b/lib/tasks/cucumber.rake new file mode 100644 index 00000000..83f79471 --- /dev/null +++ b/lib/tasks/cucumber.rake @@ -0,0 +1,65 @@ +# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. +# It is recommended to regenerate this file in the future when you upgrade to a +# newer version of cucumber-rails. Consider adding your own code to a new file +# instead of editing this one. Cucumber will automatically load all features/**/*.rb +# files. + + +unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks + +vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first +$LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil? + +begin + require 'cucumber/rake/task' + + namespace :cucumber do + Cucumber::Rake::Task.new({:ok => 'db:test:prepare'}, 'Run features that should pass') do |t| + t.binary = vendored_cucumber_bin # If nil, the gem's binary is used. + t.fork = true # You may get faster startup if you set this to false + t.profile = 'default' + end + + Cucumber::Rake::Task.new({:wip => 'db:test:prepare'}, 'Run features that are being worked on') do |t| + t.binary = vendored_cucumber_bin + t.fork = true # You may get faster startup if you set this to false + t.profile = 'wip' + end + + Cucumber::Rake::Task.new({:rerun => 'db:test:prepare'}, 'Record failing features and run only them if any exist') do |t| + t.binary = vendored_cucumber_bin + t.fork = true # You may get faster startup if you set this to false + t.profile = 'rerun' + end + + desc 'Run all features' + task :all => [:ok, :wip] + + task :statsetup do + require 'rails/code_statistics' + ::STATS_DIRECTORIES << %w(Cucumber\ features features) if File.exist?('features') + ::CodeStatistics::TEST_TYPES << "Cucumber features" if File.exist?('features') + end + end + desc 'Alias for cucumber:ok' + task :cucumber => 'cucumber:ok' + + task :default => :cucumber + + task :features => :cucumber do + STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***" + end + + # In case we don't have ActiveRecord, append a no-op task that we can depend upon. + task 'db:test:prepare' do + end + + task :stats => 'cucumber:statsetup' +rescue LoadError + desc 'cucumber rake task not available (cucumber not installed)' + task :cucumber do + abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin' + end +end + +end diff --git a/test/functional/todos_controller_test.rb b/test/functional/todos_controller_test.rb index 4887e020..6cbae911 100644 --- a/test/functional/todos_controller_test.rb +++ b/test/functional/todos_controller_test.rb @@ -1,10 +1,6 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') class TodosControllerTest < ActionController::TestCase - fixtures :users, :preferences, :projects, :contexts, :todos, :tags, :taggings, :recurring_todos - - def setup - end def test_get_index_when_not_logged_in get :index @@ -129,6 +125,20 @@ class TodosControllerTest < ActionController::TestCase end end + def test_create_todo_via_xhr + login_as(:admin_user) + assert_difference 'Todo.count' do + xhr :put, :create, "context_name"=>"library", "project_name"=>"Build a working time machine", "todo"=>{"notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"30/11/2006"}, "tag_list"=>"foo bar" + assert_response 200 + end + end + + def test_get_edit_form_using_xhr + login_as(:admin_user) + xhr :get, :edit, :id => todos(:call_bill).id + assert_response 200 + end + def test_fail_to_create_todo_via_xml login_as(:admin_user) # try to create with no context, which is not valid From 7bce774daaf02ffe65bb2598602f100d23edbe4d Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Tue, 1 May 2012 09:39:53 +0200 Subject: [PATCH 115/134] get context list scenario passing --- app/controllers/application_controller.rb | 23 ++++--------------- app/controllers/contexts_controller.rb | 2 +- app/helpers/application_helper.rb | 6 ++--- app/views/contexts/_context_form.html.erb | 6 ++--- app/views/contexts/_context_listing.html.erb | 2 +- features/context_list.feature | 6 ----- features/step_definitions/context_steps.rb | 10 +++++++- .../step_definitions/todo_create_steps.rb | 4 ++-- test/functional/contexts_controller_test.rb | 6 +++++ 9 files changed, 29 insertions(+), 36 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index eec99129..71620089 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -72,32 +72,19 @@ class ApplicationController < ActionController::Base render :text => message, :status => status end - # def rescue_action(exception) - # log_error(exception) if logger - # respond_to do |format| - # format.html do - # notify :warning, "An error occurred on the server." - # render :action => "index" - # end - # format.js { render :action => 'error' } - # format.xml { render :text => 'An error occurred on the server.' + $! } - # end - # end - # Returns a count of next actions in the given context or project The result # is count and a string descriptor, correctly pluralised if there are no # actions or multiple actions # - def count_undone_todos_phrase(todos_parent, string="actions") + def count_undone_todos_phrase(todos_parent) count = count_undone_todos(todos_parent) deferred_count = count_deferred_todos(todos_parent) if count == 0 && deferred_count > 0 - word = deferred_count == 1 ? string.singularize : string.pluralize - word = "deferred " + word - return (deferred_count.to_s + " " + word).html_safe + word = "#{I18n.t('common.deferred')} #{I18n.t('common.actions_midsentence', :count => deferred_count)}" + return "#{deferred_count.to_s} #{word}".html_safe else - word = count == 1 ? string.singularize : string.pluralize - return (count.to_s + " " + word).html_safe + word = I18n.t('common.actions_midsentence', :count => count) + return "#{count.to_s} #{word}".html_safe end end diff --git a/app/controllers/contexts_controller.rb b/app/controllers/contexts_controller.rb index e4db6e16..6be16f2c 100644 --- a/app/controllers/contexts_controller.rb +++ b/app/controllers/contexts_controller.rb @@ -12,6 +12,7 @@ class ContextsController < ApplicationController @active_contexts = current_user.contexts.active @hidden_contexts = current_user.contexts.hidden @new_context = current_user.contexts.build + init_not_done_counts(['context']) # save all contexts here as @new_context will add an empty one to current_user.contexts @all_contexts = @active_contexts + @hidden_contexts @@ -196,7 +197,6 @@ class ContextsController < ApplicationController @no_hidden_contexts = @hidden_contexts.empty? @active_count = @active_contexts.size @hidden_count = @hidden_contexts.size - init_not_done_counts(['context']) render end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index d559a4a2..38ee306d 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -101,17 +101,17 @@ module ApplicationHelper # actions or multiple actions # def count_undone_todos_phrase(todos_parent) - controller.count_undone_todos_phrase(todos_parent) + controller.count_undone_todos_phrase(todos_parent).html_safe end def count_undone_todos_phrase_text(todos_parent) - count_undone_todos_phrase(todos_parent).gsub(" "," ") + count_undone_todos_phrase(todos_parent).gsub(" "," ").html_safe end def count_undone_todos_and_notes_phrase(project) s = count_undone_todos_phrase(project) s += ", #{t('common.note', :count => project.note_count)}" unless project.note_count == 0 - s + s.html_safe end def link_to_context(context, descriptor = sanitize(context.name)) diff --git a/app/views/contexts/_context_form.html.erb b/app/views/contexts/_context_form.html.erb index a73a2782..228be0c8 100644 --- a/app/views/contexts/_context_form.html.erb +++ b/app/views/contexts/_context_form.html.erb @@ -1,15 +1,13 @@ <% context = context_form -@context = context -%> -<% form_for(context, :html => { +<%= form_for(context, :html => { :id => dom_id(context, 'edit_form'), :class => "inline-form edit-project-form", :method => :put }) do -%> -
        <%= error_messages_for("project") %>
        - +
        <%= get_list_of_error_messages_for(context) %>

        <%= text_field('context', 'name', :class => 'context-name', :tabindex => next_tab_index) %>
        diff --git a/app/views/contexts/_context_listing.html.erb b/app/views/contexts/_context_listing.html.erb index 9266ddb9..06bd864f 100644 --- a/app/views/contexts/_context_listing.html.erb +++ b/app/views/contexts/_context_listing.html.erb @@ -10,7 +10,7 @@ suppress_delete_button ||= false <%= suppress_edit_button ? "" : link_to_edit_context(context, image_tag( "blank.png", :title => t('contexts.edit_context'), :class=>"edit_item")) -%> <%= suppress_drag_handle ? "" : image_tag('grip.png', :width => '7', :height => '16', :border => '0', :title => t('common.drag_handle'), :class => 'grip')-%>
        - <%= link_to_context( context ) %> <%= " (" + count_undone_todos_phrase(context) + ")" %> + <%= link_to_context( context ) %> <%= raw " (#{count_undone_todos_phrase(context)})" %>