From f782e0f4d4f7cb6073bdfb85bcd663488adec56d Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Tue, 27 Apr 2010 10:18:07 -0400 Subject: [PATCH 01/64] Activate deferred todos before initting @todos --- app/controllers/todos_controller.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 4ad8446e..7d203e59 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -4,6 +4,7 @@ class TodosController < ApplicationController skip_before_filter :login_required, :only => [:index, :calendar] prepend_before_filter :login_or_feed_token_required, :only => [:index, :calendar] + append_before_filter :find_and_activate_ready, :only => [:index, :list_deferred] append_before_filter :init, :except => [ :destroy, :completed, :completed_archive, :check_deferred, :toggle_check, :toggle_star, :edit, :update, :create, :calendar, :auto_complete_for_predecessor, :remove_predecessor, :add_predecessor] @@ -11,7 +12,6 @@ class TodosController < ApplicationController protect_from_forgery :except => [:auto_complete_for_predecessor] def index - current_user.deferred_todos.find_and_activate_ready @projects = current_user.projects.find(:all, :include => [:default_context]) @contexts = current_user.contexts.find(:all) @@ -438,7 +438,6 @@ class TodosController < ApplicationController @projects = current_user.projects.find(:all, :include => [ :todos, :default_context ]) @contexts_to_show = @contexts = current_user.contexts.find(:all, :include => [ :todos ]) - current_user.deferred_todos.find_and_activate_ready @not_done_todos = current_user.deferred_todos + current_user.pending_todos @count = @not_done_todos.size @down_count = @count @@ -652,11 +651,15 @@ class TodosController < ApplicationController def get_todo_from_params @todo = current_user.todos.find(params['id']) end + + def find_and_activate_ready + current_user.deferred_todos.find_and_activate_ready + end def init @source_view = params['_source_view'] || 'todo' init_data_for_sidebar unless mobile? - init_todos + init_todos end def with_feed_query_scope(&block) From e1a92ced7c16119fc89fceccd3c46d9d3e0d45fc Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Tue, 27 Apr 2010 11:03:50 -0400 Subject: [PATCH 02/64] Don't substitute lt and gt symbols Closes #824 (hopefully once and for all?) --- app/models/todo.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/models/todo.rb b/app/models/todo.rb index 7fd64628..8d5cfada 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -287,10 +287,6 @@ class Todo < ActiveRecord::Base return successors.find_all {|t| t.active? or t.deferred?} end - def notes=(value) - super(value.try(:gsub, //, '>')) - end - def raw_notes=(value) self[:notes] = value end From 23977f3f0e3eaf48eb4eaa7f817d8f9164cd7a24 Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Tue, 27 Apr 2010 11:07:28 -0400 Subject: [PATCH 03/64] Don't include completed projects in autocomplete Closes #1026 --- app/controllers/projects_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 2364ea97..9a3b8242 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -26,7 +26,7 @@ class ProjectsController < ApplicationController format.rss &render_rss_feed format.atom &render_atom_feed format.text &render_text_feed - format.autocomplete { render :text => for_autocomplete(@projects, params[:q]) } + format.autocomplete { render :text => for_autocomplete(@projects.reject(&:completed?), params[:q]) } end end end From 0c161be46664858feac1ff362738712eb865a811 Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Tue, 27 Apr 2010 11:16:56 -0400 Subject: [PATCH 04/64] Fix recurring todo autocompleteion * Enable rich interaction on edit (to trigger autocompleter) * Don't try to reset autocomplete lists, since they come from the server now Fixes #1022 --- app/views/recurring_todos/edit.js.rjs | 1 + app/views/recurring_todos/update.js.rjs | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/views/recurring_todos/edit.js.rjs b/app/views/recurring_todos/edit.js.rjs index 9b4706b1..2345f9b6 100644 --- a/app/views/recurring_todos/edit.js.rjs +++ b/app/views/recurring_todos/edit.js.rjs @@ -2,3 +2,4 @@ page << "TracksForm.toggle_overlay();" page['new-recurring-todo'].hide page['edit-recurring-todo'].replace_html :partial => 'recurring_todos/edit_form' page['edit-recurring-todo'].show +page << "enable_rich_interaction();" diff --git a/app/views/recurring_todos/update.js.rjs b/app/views/recurring_todos/update.js.rjs index ad35f1ef..626ba168 100644 --- a/app/views/recurring_todos/update.js.rjs +++ b/app/views/recurring_todos/update.js.rjs @@ -8,10 +8,6 @@ if @saved status_message = 'Added new context / ' + status_message if @new_context_created page.notify :notice, status_message, 5.0 - # update auto completer arrays for context and project - page << "contextAutoCompleter.options.array = #{context_names_for_autocomplete}; contextAutoCompleter.changed = true" if @new_context_created - page << "projectAutoCompleter.options.array = #{project_names_for_autocomplete}; projectAutoCompleter.changed = true" if @new_project_created - # replace old recurring todo with updated todo page.replace dom_id(@recurring_todo), :partial => 'recurring_todos/recurring_todo', :locals => { :recurring_todo => @recurring_todo } page.visual_effect :highlight, dom_id(@recurring_todo), :duration => 3 @@ -19,4 +15,4 @@ if @saved else page.show 'edit_status' page.replace_html 'edit_status', "#{error_messages_for('recurring_todo')}" -end \ No newline at end of file +end From 9d5503a91e638664c0412389e771b6e34c8cf52b Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Sat, 1 May 2010 17:19:28 +0200 Subject: [PATCH 05/64] fix #997. The chart with the visible actions now excludes pending actions. Also some cleanupt to use named_scope --- app/controllers/stats_controller.rb | 3 ++- app/models/todo.rb | 3 +++ app/views/stats/_totals.rhtml | 22 ++++++++++++---------- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index 3847c47a..004b335c 100755 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -319,6 +319,7 @@ class StatsController < ApplicationController # - 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 "+ @@ -326,7 +327,7 @@ class StatsController < ApplicationController "WHERE t.user_id=? "+ "AND t.completed_at IS NULL " + "AND t.show_from IS NULL " + - "AND NOT (p.state='hidden' OR c.hide=?) " + + "AND NOT (p.state='hidden' OR p.state='pending' OR c.hide=?) " + "ORDER BY t.created_at ASC", @user.id, true] ) diff --git a/app/models/todo.rb b/app/models/todo.rb index 7fd64628..e4c60712 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -18,7 +18,10 @@ class Todo < ActiveRecord::Base named_scope :active, :conditions => { :state => 'active' } named_scope :not_completed, :conditions => ['NOT (todos.state = ? )', 'completed'] + named_scope :completed, :conditions => ["NOT completed_at IS NULL"] named_scope :are_due, :conditions => ['NOT (todos.due IS NULL)'] + named_scope :deferred, :conditions => ["completed_at IS NULL AND NOT show_from IS NULL"] + named_scope :blocked, :conditions => ['todos.state = ?', 'pending'] STARRED_TAG_NAME = "starred" RE_TODO = /[^"]+/ diff --git a/app/views/stats/_totals.rhtml b/app/views/stats/_totals.rhtml index 02e2301d..500fde10 100755 --- a/app/views/stats/_totals.rhtml +++ b/app/views/stats/_totals.rhtml @@ -1,19 +1,21 @@

You have <%= @projects.count%> projects. - Of those <%= @projects.count(:conditions => "state = 'active'")%> are active projects, - <%= @projects.count(:conditions => "state = 'hidden'")%> hidden projects and -<%= @projects.count(:conditions => "state = 'completed'")%> completed projects

+ Of those <%= @projects.active.count%> are active projects, + <%= @projects.hidden.count%> hidden projects and +<%= @projects.completed.count%> completed projects

You have <%= @contexts.count%> contexts. -Of those <%= @contexts.count(:conditions => ["hide = ?", false])%> are visible contexts and -<%= @contexts.count(:conditions => ["hide = ?", true]) %> are hidden contexts +Of those <%= @contexts.active.count%> are visible contexts and +<%= @contexts.hidden.count%> are hidden contexts <% unless @actions.empty? -%> -

You have <%= @actions.count(:conditions => "completed_at IS NULL") %> incomplete actions -of which <%= @actions.count(:conditions => "completed_at IS NULL AND NOT show_from IS NULL") %> are deferred actions.

+

Since your first action on <%= format_date(@first_action.created_at) %> +you have a total of <%= @actions.count %> actions. +<%= @actions.completed.count %> of these are completed. -

Since your first action on <%= format_date(@first_action.created_at) %> -you have a total of <%= @actions.count %> actions. -<%= @actions.count(:conditions => "NOT completed_at IS NULL") %> of these are completed. +

You have <%= @actions.not_completed.count %> incomplete actions +of which <%= @actions.deferred.count %> are deferred actions +in the tickler and <%= @actions.blocked.count %> are dependent on the completion of other actions. +.

You have <%= @tags_count-%> tags placed on actions. Of those tags, <%= @unique_tags_count -%> are unique. From fabc15e061ed34f0da6ba48802e391c4bb2775bd Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Sat, 1 May 2010 17:32:55 +0200 Subject: [PATCH 06/64] fix #987 where feeds_path returned the mobile url and not the non-mobile one. --- config/routes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index 7bc7b533..4035cbf0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -58,8 +58,8 @@ ActionController::Routing::Routes.draw do |map| map.root :controller => 'todos' # Make OpenID happy because it needs #root_url defined map.resources :notes - map.feeds 'feeds', :controller => 'feedlist', :action => 'index' map.feeds 'feeds.m', :controller => 'feedlist', :action => 'index', :format => 'm' + map.feeds 'feeds', :controller => 'feedlist', :action => 'index' if Rails.env == 'test' map.connect '/selenium_helper/login', :controller => 'selenium_helper', :action => 'login' From 8bc3a484b270b8d0024e5940ab8c26c9a74086c9 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Sun, 2 May 2010 16:41:45 +0200 Subject: [PATCH 07/64] fix 1018. Added validations for the recurring target of recurring todos --- app/models/recurring_todo.rb | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/app/models/recurring_todo.rb b/app/models/recurring_todo.rb index 86c549f1..9a159c4c 100644 --- a/app/models/recurring_todo.rb +++ b/app/models/recurring_todo.rb @@ -29,13 +29,17 @@ class RecurringTodo < ActiveRecord::Base validates_presence_of :description validates_presence_of :recurring_period + validates_presence_of :target + validates_presence_of :recurring_period + validates_presence_of :ends_on + validates_presence_of :context + validates_length_of :description, :maximum => 100 validates_length_of :notes, :maximum => 60000, :allow_nil => true - validates_presence_of :context - validate :period_specific_validations validate :starts_and_ends_on_validations + validate :set_recurrence_on_validations def period_specific_validations periods = %W[daily weekly monthly yearly] @@ -59,7 +63,6 @@ class RecurringTodo < ActiveRecord::Base something_set = false %w{sunday monday tuesday wednesday thursday friday}.each do |day| something_set ||= self.send("on_#{day}") - end errors.add_to_base("You must specify at least one day on which the todo recurs") if !something_set end @@ -104,6 +107,21 @@ class RecurringTodo < ActiveRecord::Base errors.add_to_base("The end of the recurrence is not selected") unless ends_on == "no_end_date" end end + + def set_recurrence_on_validations + # show always or x days before due date. x not null + case self.target + when 'show_from_date' + # no validations + when 'due_date' + errors.add_to_base("Please select when to show the action") if show_always.nil? + unless show_always + errors.add_to_base("Please fill in the number of days to show the todo before the due date") if show_from_delta.nil? || show_from_delta.blank? + end + else + raise Exception.new, "unexpected value of recurrence target selector '#{self.recurrence_target}'" + end + end # the following recurrence patterns can be stored: # @@ -726,11 +744,7 @@ class RecurringTodo < ActiveRecord::Base end protected - - def validate - errors.add("", "At least one day must be selected in the weekly pattern") if self.every_day == ' ' - end - + def determine_start(previous) if previous.nil? start = self.start_from.nil? ? Time.zone.now : self.start_from From 5c25e4569e6660bd2a2a1e12e7e1bb9367e849d8 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Sun, 2 May 2010 18:16:29 +0200 Subject: [PATCH 08/64] fix #1002. every nth week was off by one week for recurring weekly todos. Thanks Thomas for spotting this. Updated the wrong test too. --- app/models/recurring_todo.rb | 12 +++++------- test/fixtures/recurring_todos.yml | 2 +- test/unit/recurring_todo_test.rb | 8 +++++++- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/app/models/recurring_todo.rb b/app/models/recurring_todo.rb index 9a159c4c..2f6d623b 100644 --- a/app/models/recurring_todo.rb +++ b/app/models/recurring_todo.rb @@ -61,7 +61,7 @@ class RecurringTodo < ActiveRecord::Base errors.add_to_base("Every other nth week may not be empty for recurrence setting") end something_set = false - %w{sunday monday tuesday wednesday thursday friday}.each do |day| + %w{sunday monday tuesday wednesday thursday friday saturday}.each do |day| something_set ||= self.send("on_#{day}") end errors.add_to_base("You must specify at least one day on which the todo recurs") if !something_set @@ -406,9 +406,9 @@ class RecurringTodo < ActiveRecord::Base end def recurrence_pattern + return "invalid repeat pattern" if every_other1.nil? case recurring_period when 'daily' - return "invalid repeat pattern" if every_other1.nil? if only_work_days return "on work days" else @@ -419,21 +419,19 @@ class RecurringTodo < ActiveRecord::Base end end when 'weekly' - return "invalid repeat pattern" if every_other1.nil? if every_other1 > 1 return "every #{every_other1} weeks" else return 'weekly' end when 'monthly' - return "invalid repeat pattern" if every_other1.nil? || every_other2.nil? + return "invalid repeat pattern" if every_other2.nil? if self.recurrence_selector == 0 return "every #{self.every_other2} month#{self.every_other2>1?'s':''} on day #{self.every_other1}" else return "every #{self.xth} #{self.day_of_week} of every #{self.every_other2} month#{self.every_other2>1?'s':''}" end when 'yearly' - return "invalid repeat pattern" if every_other1.nil? if self.recurrence_selector == 0 return "every year on #{self.month_of_year} #{self.every_other1}" else @@ -553,8 +551,8 @@ class RecurringTodo < ActiveRecord::Base start = previous + 1.day if start.wday() == 0 # we went to a new week , go to the nth next week and find first match - # that week - start += self.every_other1.week + # that week. Note that we already went into the next week, so -1 + start += (self.every_other1-1).week end unless self.start_from.nil? # check if the start_from date is later than previous. If so, use diff --git a/test/fixtures/recurring_todos.yml b/test/fixtures/recurring_todos.yml index daffc38c..db630d68 100644 --- a/test/fixtures/recurring_todos.yml +++ b/test/fixtures/recurring_todos.yml @@ -64,7 +64,7 @@ call_bill_gates_every_workday: show_from_delta: ~ recurring_period: daily recurrence_selector: ~ - every_other1: ~ + every_other1: 1 every_other2: ~ every_other3: ~ every_day: ~ diff --git a/test/unit/recurring_todo_test.rb b/test/unit/recurring_todo_test.rb index 6e4c5b0b..8ae3f6da 100644 --- a/test/unit/recurring_todo_test.rb +++ b/test/unit/recurring_todo_test.rb @@ -124,7 +124,9 @@ class RecurringTodoTest < ActiveSupport::TestCase due_date = @weekly_every_day.get_due_date(@sunday) assert_equal @monday, due_date - # saturday is last day in week, so the next date should be sunday + n_weeks + # saturday is last day in week, so the next date should be sunday + n-1 weeks + # n-1 because sunday is already in the next week + @weekly_every_day.every_other1 = 3 due_date = @weekly_every_day.get_due_date(@saturday) assert_equal @sunday + 2.weeks, due_date @@ -141,6 +143,10 @@ class RecurringTodoTest < ActiveSupport::TestCase assert_equal @wednesday, due_date due_date = @weekly_every_day.get_due_date(@wednesday) assert_equal @tuesday+1.week, due_date + + @weekly_every_day.every_day = ' s' + due_date = @weekly_every_day.get_due_date(@sunday) + assert_equal @saturday+1.week, due_date end def test_monthly_pattern From 0198a2fa13ab3f784fa17556e3831343cb9518d7 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Sun, 2 May 2010 18:25:25 +0200 Subject: [PATCH 09/64] fix #936 by adding index on state for todos. Needs migration of database. --- db/migrate/20100502162317_add_index_to_todo_state.rb | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 db/migrate/20100502162317_add_index_to_todo_state.rb diff --git a/db/migrate/20100502162317_add_index_to_todo_state.rb b/db/migrate/20100502162317_add_index_to_todo_state.rb new file mode 100644 index 00000000..6e3d01bf --- /dev/null +++ b/db/migrate/20100502162317_add_index_to_todo_state.rb @@ -0,0 +1,9 @@ +class AddIndexToTodoState < ActiveRecord::Migration + def self.up + add_index :todos, :state + end + + def self.down + remove_index :todos, :state + end +end \ No newline at end of file From 0d7980e87b6123aa040984daecbcc0e91c0c69c9 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Mon, 3 May 2010 21:26:48 +0200 Subject: [PATCH 10/64] migrate selenium for users to cucumber --- app/controllers/login_controller.rb | 2 +- app/controllers/users_controller.rb | 2 +- features/manage_project.feature | 2 +- features/manage_users.feature | 31 ++++++++++++++++++ features/step_definitions/context_steps.rb | 38 +++++++++++----------- features/step_definitions/user_steps.rb | 18 ++++++++++ features/support/paths.rb | 4 ++- test/selenium/users/delete_user.rsel | 7 ---- 8 files changed, 74 insertions(+), 30 deletions(-) create mode 100644 features/manage_users.feature delete mode 100644 test/selenium/users/delete_user.rsel diff --git a/app/controllers/login_controller.rb b/app/controllers/login_controller.rb index 0c1037ed..5106686f 100644 --- a/app/controllers/login_controller.rb +++ b/app/controllers/login_controller.rb @@ -54,7 +54,7 @@ class LoginController < ApplicationController end when :get if User.no_users_yet? - redirect_to :controller => 'users', :action => 'new' + redirect_to signup_path return end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 387c7689..1198837f 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -90,7 +90,7 @@ class UsersController < ApplicationController unless user.valid? session['new_user'] = user - redirect_to :action => 'new' + redirect_to signup_path return end diff --git a/features/manage_project.feature b/features/manage_project.feature index 5db9910e..74eaaeec 100644 --- a/features/manage_project.feature +++ b/features/manage_project.feature @@ -11,7 +11,7 @@ Feature: Manage a project And I have logged in as "testuser" with password "secret" And there exists a project "manage me" for user "testuser" - @selenium + @selenium, @wip Scenario: I can describe the project using markup When I visit the "manage me" project And I edit the project description to "_successfull outcome_: project is *done*" diff --git a/features/manage_users.feature b/features/manage_users.feature new file mode 100644 index 00000000..6d716853 --- /dev/null +++ b/features/manage_users.feature @@ -0,0 +1,31 @@ +Feature: Manage users + + In order to be able to manage the users able to use Tracks + As the administrator of this installed Tracks + I want to add and delete accounts of users + + Background: + Given the following user records + | login | password | is_admin | + | testuser | secret | false | + | admin | secret | true | + And I have logged in as "admin" with password "secret" + + Scenario: Show all accounts + When I go to the manage users page + Then I should see "testuser" + And I should see "admin" + + Scenario: Add new account + When I go to the manage users page + And I follow "Signup new user" + Then I should be on the signup page + When I submit the signup form with username "new.user", password "secret123" and confirm with "secret123" + Then I should be on the manage users page + And I should see "new.user" + + @selenium + Scenario: Delete account from users page + When I go to the manage users page + And I delete the user "testuser" + Then I should see that a user named "testuser" is not present diff --git a/features/step_definitions/context_steps.rb b/features/step_definitions/context_steps.rb index 9bab68a5..fa117871 100644 --- a/features/step_definitions/context_steps.rb +++ b/features/step_definitions/context_steps.rb @@ -2,6 +2,13 @@ Given /^I have a context called "([^\"]*)"$/ do |context_name| @context = @current_user.contexts.create!(:name => context_name) end +Given /^I have a context "([^\"]*)" with (.*) actions$/ do |context_name, number_of_actions| + context = @current_user.contexts.create!(:name => context_name) + 1.upto number_of_actions.to_i do |i| + @current_user.todos.create!(:context_id => context.id, :description => "todo #{i}") + end +end + When /^I visits the context page for "([^\"]*)"$/ do |context_name| context = @current_user.contexts.find_by_name(context_name) context.should_not be_nil @@ -14,25 +21,6 @@ When /^I edit the context name in place to be "([^\"]*)"$/ do |new_context_name| click_button "OK" end -Then /^I should see the context name is "([^\"]*)"$/ do |context_name| - Then "I should see \"#{context_name}\"" -end - -Then /^he should see that a context named "([^\"]*)" is present$/ do |context_name| - Then "I should see \"#{context_name}\"" -end - -Then /^he should see that a context named "([^\"]*)" is not present$/ do |context_name| - Then "I should not see \"#{context_name} (\"" -end - -Given /^I have a context "([^\"]*)" with (.*) actions$/ do |context_name, number_of_actions| - context = @current_user.contexts.create!(:name => context_name) - 1.upto number_of_actions.to_i do |i| - @current_user.todos.create!(:context_id => context.id, :description => "todo #{i}") - end -end - When /^I delete the context "([^\"]*)"$/ do |context_name| context = @current_user.contexts.find_by_name(context_name) context.should_not be_nil @@ -51,3 +39,15 @@ When /^I edit the context to rename it to "([^\"]*)"$/ do |new_name| selenium.is_visible("flash") end end + +Then /^I should see the context name is "([^\"]*)"$/ do |context_name| + Then "I should see \"#{context_name}\"" +end + +Then /^he should see that a context named "([^\"]*)" is present$/ do |context_name| + Then "I should see \"#{context_name}\"" +end + +Then /^he should see that a context named "([^\"]*)" is not present$/ do |context_name| + Then "I should not see \"#{context_name} (\"" +end \ No newline at end of file diff --git a/features/step_definitions/user_steps.rb b/features/step_definitions/user_steps.rb index 834bd20f..05022302 100644 --- a/features/step_definitions/user_steps.rb +++ b/features/step_definitions/user_steps.rb @@ -10,6 +10,24 @@ Given "no users exists" do User.delete_all end +When /^I delete the user "([^\"]*)"$/ do |username| + # click "//tr[@id='user-3']//img" + # assert_confirmation "Warning: this will delete user 'john', all their actions, contexts, project and notes. Are you sure that you want to continue?" + user = User.find_by_login(username) + user.should_not be_nil + + selenium.click "xpath=//tr[@id='user-#{user.id}']//img" + selenium.get_confirmation.should == "Warning: this will delete user '#{user.login}', all their actions, contexts, project and notes. Are you sure that you want to continue?" + wait_for do + !selenium.is_element_present("//tr[@id='user-#{user.id}']//img") + end + +end + +Then /^I should see that a user named "([^\"]*)" is not present$/ do |username| + Then "I should not see \"#{username} (\"" +end + Then "I should be an admin" do # just check on the presence of the menu item for managing users Then "I should see \"Manage users\"" diff --git a/features/support/paths.rb b/features/support/paths.rb index 91222396..cb895557 100644 --- a/features/support/paths.rb +++ b/features/support/paths.rb @@ -9,13 +9,15 @@ module NavigationHelpers when /the statistics page/ stats_path when /the signup page/ - "/users/new" + signup_path when /the login page/ login_path when /the notes page/ notes_path when /the contexts page/ contexts_path + when /the manage users page/ + users_path # Add more page name => path mappings here diff --git a/test/selenium/users/delete_user.rsel b/test/selenium/users/delete_user.rsel deleted file mode 100644 index 32ff3545..00000000 --- a/test/selenium/users/delete_user.rsel +++ /dev/null @@ -1,7 +0,0 @@ -setup :fixtures => :all -login :as => 'admin' -open '/users' -assert_text_present "John Deere" -click "//tr[@id='user-3']//img" -assert_confirmation "Warning: this will delete user 'john', all their actions, contexts, project and notes. Are you sure that you want to continue?" -wait_for_text_not_present "John Deere" \ No newline at end of file From e1b52aeb13b11d0b4cb5905eee7fbf63789ecae8 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Wed, 5 May 2010 13:00:44 +0200 Subject: [PATCH 11/64] replace selenium script with cucumber story for switching recurrence option --- features/recurring_todos.feature | 25 +++++++++++++++++++ .../step_definitions/recurring_todo_steps.rb | 7 ++++++ features/support/paths.rb | 2 ++ .../switch_recurrence_options.rsel | 12 --------- 4 files changed, 34 insertions(+), 12 deletions(-) create mode 100644 features/recurring_todos.feature create mode 100644 features/step_definitions/recurring_todo_steps.rb delete mode 100644 test/selenium/recurring_todos/switch_recurrence_options.rsel diff --git a/features/recurring_todos.feature b/features/recurring_todos.feature new file mode 100644 index 00000000..98d54c82 --- /dev/null +++ b/features/recurring_todos.feature @@ -0,0 +1,25 @@ +Feature: Manage recurring todos + + In order to manage repeating todos + As a Tracks user + I want to view, edit, add, or remove recurrence patterns of repeating todos + + Background: + Given the following user record + | login | password | is_admin | + | testuser | secret | false | + And I have logged in as "testuser" with password "secret" + + @selenium + Scenario: Being able to select daily, weekly, monthly and yearly pattern + When I go to the repeating todos page + And I follow "Add a new recurring action" + Then I should see the form for "Daily" recurrence pattern + When I select "Weekly" recurrence pattern + Then I should see the form for "Weekly" recurrence pattern + When I select "Monthly" recurrence pattern + Then I should see the form for "Monthly" recurrence pattern + When I select "Yearly" recurrence pattern + Then I should see the form for "Yearly" recurrence pattern + When I select "Daily" recurrence pattern + Then I should see the form for "Daily" recurrence pattern \ No newline at end of file diff --git a/features/step_definitions/recurring_todo_steps.rb b/features/step_definitions/recurring_todo_steps.rb new file mode 100644 index 00000000..2982eb26 --- /dev/null +++ b/features/step_definitions/recurring_todo_steps.rb @@ -0,0 +1,7 @@ +When /^I select "([^\"]*)" recurrence pattern$/ do |recurrence_period| + selenium.click("recurring_todo_recurring_period_#{recurrence_period.downcase}") +end + +Then /^I should see the form for "([^\"]*)" recurrence pattern$/ do |recurrence_period| + selenium.is_visible("recurring_#{recurrence_period.downcase}") +end diff --git a/features/support/paths.rb b/features/support/paths.rb index cb895557..51edcca2 100644 --- a/features/support/paths.rb +++ b/features/support/paths.rb @@ -18,6 +18,8 @@ module NavigationHelpers contexts_path when /the manage users page/ users_path + when /the repeating todos page/ + recurring_todos_path # Add more page name => path mappings here diff --git a/test/selenium/recurring_todos/switch_recurrence_options.rsel b/test/selenium/recurring_todos/switch_recurrence_options.rsel deleted file mode 100644 index 073c0f9c..00000000 --- a/test/selenium/recurring_todos/switch_recurrence_options.rsel +++ /dev/null @@ -1,12 +0,0 @@ -setup :fixtures => :users, :clear_tables => [:projects, :contexts, :todos] -login :as => 'admin' -open "/recurring_todos" -click "css=#recurring_new_container a" -click "recurring_todo_recurring_period_daily" -assert_visible "recurring_daily" -click "recurring_todo_recurring_period_weekly" -assert_visible "recurring_weekly" -click "recurring_todo_recurring_period_monthly" -assert_visible "recurring_monthly" -click "recurring_todo_recurring_period_yearly" -assert_visible "recurring_yearly" From f53b386bd1d0a58237c220fcb712c7863bec8a2b Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Wed, 5 May 2010 13:15:00 +0200 Subject: [PATCH 12/64] remove anoying message about login text not found when running cucumber/selenium --- features/step_definitions/login_steps.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/features/step_definitions/login_steps.rb b/features/step_definitions/login_steps.rb index b4d80868..b6f52cfa 100644 --- a/features/step_definitions/login_steps.rb +++ b/features/step_definitions/login_steps.rb @@ -3,6 +3,10 @@ Given /^I have logged in as "(.*)" with password "(.*)"$/ do |username, password fill_in "Login", :with => username fill_in "Password", :with => password click_button + selenium.wait_for_page_to_load(5000) +# wait_for do +# selenium.is_visible("flash") +# end response.should contain(/Login successful/) @current_user = User.find_by_login(username) end From a0b642dab349dd2a61e813a23a862e904df03911 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Wed, 5 May 2010 13:16:54 +0200 Subject: [PATCH 13/64] remove commented lines from last commit --- features/step_definitions/login_steps.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/features/step_definitions/login_steps.rb b/features/step_definitions/login_steps.rb index b6f52cfa..e3db63fd 100644 --- a/features/step_definitions/login_steps.rb +++ b/features/step_definitions/login_steps.rb @@ -4,9 +4,6 @@ Given /^I have logged in as "(.*)" with password "(.*)"$/ do |username, password fill_in "Password", :with => password click_button selenium.wait_for_page_to_load(5000) -# wait_for do -# selenium.is_visible("flash") -# end response.should contain(/Login successful/) @current_user = User.find_by_login(username) end From eef1b6b7a9b148fa253288e2a832125a95af378b Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Wed, 5 May 2010 13:19:26 +0200 Subject: [PATCH 14/64] remove selenium scripts that were already converted to cucumber --- .../context_listing/edit_then_delete.rsel | 15 --------------- test/selenium/context_listing/edit_twice.rsel | 19 ------------------- 2 files changed, 34 deletions(-) delete mode 100644 test/selenium/context_listing/edit_then_delete.rsel delete mode 100644 test/selenium/context_listing/edit_twice.rsel diff --git a/test/selenium/context_listing/edit_then_delete.rsel b/test/selenium/context_listing/edit_then_delete.rsel deleted file mode 100644 index 4f35a28b..00000000 --- a/test/selenium/context_listing/edit_then_delete.rsel +++ /dev/null @@ -1,15 +0,0 @@ -setup :fixtures => :all -login :as => 'admin' -open "/contexts" -click "css=#context_3 .buttons img.edit_item" -wait_for_visible "edit_context_3" -wait_for_not_visible "context_3" -type "//div[@id='edit_context_3'] //input[@name='context[name]']", "telegraph" -click "//div[@id='edit_context_3'] //button" -wait_for_not_visible "edit_context_3" -wait_for_visible "context_3" -click "css=#context_3 .buttons img.delete_item" -assert_confirmation "Are you sure that you want to delete the context 'telegraph'?" -wait_for_visible "flash" -wait_for_text "flash", "Deleted context 'telegraph'" -wait_for_element_not_present "context_3" \ No newline at end of file diff --git a/test/selenium/context_listing/edit_twice.rsel b/test/selenium/context_listing/edit_twice.rsel deleted file mode 100644 index 635a70d3..00000000 --- a/test/selenium/context_listing/edit_twice.rsel +++ /dev/null @@ -1,19 +0,0 @@ -setup :fixtures => :all -login :as => 'admin' -open "/contexts" -click "css=#context_3 .buttons img.edit_item" -wait_for_visible "edit_context_3" -wait_for_not_visible "context_3" -type "//div[@id='edit_context_3'] //input[@name='context[name]']", "telegraph" -click "//div[@id='edit_context_3'] //button" -wait_for_not_visible "edit_context_3" -wait_for_visible "context_3" -assert_text 'css=#context_3 .data a', 'telegraph' -click "css=#context_3 .buttons img.edit_item" -wait_for_visible "edit_context_3" -wait_for_not_visible "context_3" -type "//div[@id='edit_context_3'] //input[@name='context[name]']", "email" -click "//div[@id='edit_context_3'] //button" -wait_for_not_visible "edit_context_3" -wait_for_visible "context_3" -assert_text 'css=#context_3 .data a', 'email' \ No newline at end of file From 44c61d942a3ca6bae36dea989a563b6034af9ba7 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Wed, 5 May 2010 19:08:41 +0200 Subject: [PATCH 15/64] make sure login works for non-selenium cucumber regression since my last commit --- features/step_definitions/login_steps.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/features/step_definitions/login_steps.rb b/features/step_definitions/login_steps.rb index e3db63fd..49995c1d 100644 --- a/features/step_definitions/login_steps.rb +++ b/features/step_definitions/login_steps.rb @@ -3,7 +3,9 @@ Given /^I have logged in as "(.*)" with password "(.*)"$/ do |username, password fill_in "Login", :with => username fill_in "Password", :with => password click_button - selenium.wait_for_page_to_load(5000) + if response.respond_to? :selenium + selenium.wait_for_page_to_load(5000) + end response.should contain(/Login successful/) @current_user = User.find_by_login(username) end From d6e20a76c2d398fd32e580d9d5e215bd5c1e7f0c Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Wed, 5 May 2010 19:09:51 +0200 Subject: [PATCH 16/64] migrate selenium script for integrations page and enhance the story --- features/show_integration_options.feature | 38 +++++++++++++++++++ features/step_definitions/context_steps.rb | 11 ++++++ .../step_definitions/integration_steps.rb | 23 +++++++++++ features/step_definitions/note_steps.rb | 1 - features/support/paths.rb | 2 + .../no_script_if_no_contexts.rsel | 14 ------- 6 files changed, 74 insertions(+), 15 deletions(-) create mode 100644 features/show_integration_options.feature create mode 100644 features/step_definitions/integration_steps.rb delete mode 100644 test/selenium/integrations/no_script_if_no_contexts.rsel diff --git a/features/show_integration_options.feature b/features/show_integration_options.feature new file mode 100644 index 00000000..c77b5562 --- /dev/null +++ b/features/show_integration_options.feature @@ -0,0 +1,38 @@ +Feature: Integrate Tracks in various ways + + In order to use tracks with other software + As a Tracks user + I want to be informed about the various ways to integrate tracks + + 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 cannot see scripts when I do not have a context + Given I have no contexts + When I go to the integrations page + Then I should see a message that you need a context to see scripts + + Scenario: I can see scripts when I have one or more contexts + Given I have a context called "@pc" + When I go to the integrations page + Then I should see scripts + + @selenium + Scenario: When I select a different context the example scripts should change accoordingly + Given I have the following contexts: + | context | + | @pc | + | @home | + | @shops | + | @boss | + When I go to the integrations page + Then I should see a script "applescript1" for "@pc" + When I select "@home" from "applescript1-contexts" + Then I should see a script "applescript1" for "@home" + When I select "@shops" from "applescript2-contexts" + Then I should see a script "applescript2" for "@shops" + When I select "@boss" from "quicksilver-contexts" + Then I should see a script "quicksilver" for "@boss" diff --git a/features/step_definitions/context_steps.rb b/features/step_definitions/context_steps.rb index fa117871..a75f780c 100644 --- a/features/step_definitions/context_steps.rb +++ b/features/step_definitions/context_steps.rb @@ -1,7 +1,18 @@ +Given /^I have no contexts$/ do + # should probably not be needed as you use this given at the start of a scenario + Context.delete_all +end + Given /^I have a context called "([^\"]*)"$/ do |context_name| @context = @current_user.contexts.create!(:name => context_name) end +Given /^I have the following contexts:$/ do |table| + table.hashes.each do |context| + Given 'I have a context called "'+context[:context]+'"' + end +end + Given /^I have a context "([^\"]*)" with (.*) actions$/ do |context_name, number_of_actions| context = @current_user.contexts.create!(:name => context_name) 1.upto number_of_actions.to_i do |i| diff --git a/features/step_definitions/integration_steps.rb b/features/step_definitions/integration_steps.rb new file mode 100644 index 00000000..10d5727d --- /dev/null +++ b/features/step_definitions/integration_steps.rb @@ -0,0 +1,23 @@ +Then /^I should see a message that you need a context to see scripts$/ do + Then 'I should see "You do not have any context yet. The script will be available after you add your first context"' +end + +Then /^I should see scripts$/ do + # check on a small snippet of the first applescript + Then 'I should see "set returnValue to call xmlrpc"' +end + +Then /^I should see a script "([^\"]*)" for "([^\"]*)"$/ do |script, context_name| + selenium.is_visible(script) + context = Context.find_by_name(context_name) + + # wait for the script to refresh + wait_for :timeout => 15 do + selenium.is_text_present("#{context.id} (* #{context_name} *)") + end + + # make sure the text is found within the textarea + script_source = selenium.get_text("//textarea[@id='#{script}']") + script_source.should =~ /#{context.id} \(\* #{context_name} \*\)/ +end + diff --git a/features/step_definitions/note_steps.rb b/features/step_definitions/note_steps.rb index 630f974d..fbc93eb7 100644 --- a/features/step_definitions/note_steps.rb +++ b/features/step_definitions/note_steps.rb @@ -62,7 +62,6 @@ Then /^the first note should disappear$/ do end end - Then /^I should see the note text$/ do Then "I should see \"after 50 characters\"" end diff --git a/features/support/paths.rb b/features/support/paths.rb index 51edcca2..19142887 100644 --- a/features/support/paths.rb +++ b/features/support/paths.rb @@ -20,6 +20,8 @@ module NavigationHelpers users_path when /the repeating todos page/ recurring_todos_path + when /the integrations page/ + integrations_path # Add more page name => path mappings here diff --git a/test/selenium/integrations/no_script_if_no_contexts.rsel b/test/selenium/integrations/no_script_if_no_contexts.rsel deleted file mode 100644 index 4da2ea76..00000000 --- a/test/selenium/integrations/no_script_if_no_contexts.rsel +++ /dev/null @@ -1,14 +0,0 @@ -setup :fixtures => :users, :clear_tables => [:projects, :contexts, :todos] -login :as => 'admin' -open "/integrations" -wait_for_element_present "no_context_msg" - -open "/contexts" -type "context_name", "my first context" -click "context_new_submit" -# wait for new context to appear before navigating away from project page to -# make sure that the changes have been saved -wait_for_text_present 'DRAG' - -open "/integrations" -wait_for_element_present "applescript1-contexts" From fa98c0865e638d28ea69ef36fd859ffb41ac66df Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Sat, 8 May 2010 19:30:58 -0400 Subject: [PATCH 17/64] Override AASM's initial state if specified Fixes #977 --- app/controllers/todos_controller.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 7d203e59..480744fb 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -55,7 +55,7 @@ class TodosController < ApplicationController predecessor_list = p.predecessor_list @todo = current_user.todos.build(p.attributes) - + if p.project_specified_by_name? project = current_user.projects.find_or_create_by_name(p.project_name) @new_project_created = project.new_record_before_save? @@ -70,8 +70,16 @@ class TodosController < ApplicationController end @todo.add_predecessor_list(predecessor_list) + + # Fix for #977 because AASM overrides @state on creation + specified_state = @todo.state + @todo.update_state_from_project @saved = @todo.save + + # Fix for #977 because AASM overrides @state on creation + @todo.update_attribute('state', specified_state) unless specified_state == "immediate" + unless (@saved == false) || tag_list.blank? @todo.tag_with(tag_list) @todo.tags.reload From 86d7724b75be46a0ada3301c252960002372ff31 Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Sun, 9 May 2010 18:57:56 -0400 Subject: [PATCH 18/64] Revert "Move dependency drop target into image" We decided that the small drop target was harder to hit, and the justifcation for the change wasn't worth it. This reverts commit ec68e04f2723682c5d4ab1aa08dbeb49cacf15ad. Conflicts: app/helpers/todos_helper.rb public/javascripts/application.js public/stylesheets/standard.css --- app/helpers/todos_helper.rb | 6 +- artwork/add_successor_on.svg | 179 ---------------------------- artwork/predecessor.svg | 175 --------------------------- public/images/add_successor_off.png | Bin 801 -> 0 bytes public/images/add_successor_on.png | Bin 794 -> 0 bytes public/javascripts/application.js | 4 +- public/stylesheets/standard.css | 13 +- 7 files changed, 7 insertions(+), 370 deletions(-) delete mode 100644 artwork/add_successor_on.svg delete mode 100644 artwork/predecessor.svg delete mode 100644 public/images/add_successor_off.png delete mode 100644 public/images/add_successor_on.png diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index 994fb305..b8ea341e 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -119,10 +119,8 @@ module TodosHelper def grip_span unless @todo.completed? image_tag('grip.png', :width => '7', :height => '16', :border => '0', - :title => 'Drag onto another action to make it depend on that action', - :class => 'grip') + - image_tag('blank.png', :width => 16, :height => 16, :border => 0, - :title => "Drop an action to make it depend on this action", :class => 'successor_target drop_target') + :title => 'Drag onto another action to make it depend on that action', + :class => 'grip') end end diff --git a/artwork/add_successor_on.svg b/artwork/add_successor_on.svg deleted file mode 100644 index b7b3165c..00000000 --- a/artwork/add_successor_on.svg +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/artwork/predecessor.svg b/artwork/predecessor.svg deleted file mode 100644 index 75e1ea1a..00000000 --- a/artwork/predecessor.svg +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/public/images/add_successor_off.png b/public/images/add_successor_off.png deleted file mode 100644 index 183f1326da59fb9ce8dfc4de71f365f9c1e3dad6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 801 zcmV++1K#|JP)A_TU&dEb1w4v{O4RQ_k3<{?vtzz{)F`O^mzOG z`)>>k4BU>#BFA>^5qk^um1XlS?|jYcmjiXs;m7n5siYcEaH z+*VcfLM#?bjE#*&L!nSO6bfCQo}PXKU=skSq9|t_$Eg!SuuLZNdVYTXk!4vK0GOSf zeZRG}b-%T>H5v|w&qX4U#uKqzF4q}`0o%5-rfGgH6biZOAE{I-RbOBK&Fl3>6-5bh z&RYl}@1&GAWsDJB*HJ7MA%qYB>c+>%uc@kf#qD+n7-KC52L~0-xt}pMGdVeVX<}kR ztFbH#x~?Oe%}UcWT~f-NX__AcfqW83NQ=< zLI~Kl4MK=ZO1V8aIC!^MEYjxY=Bs|cADnZf)9H=f-Q9-^3kz>4V+^{kqg*cI_|jw6 z*Vi|PhKBA4A!uV`Zzqt3ASzjS`MtPt|k+S#Jx-=V-iBX zD2no8e}A6?K#gTtFbo5^Tn?Ob{K@k2@`uC2!$`b`(W1 f(&@DPuLa--f+vKa3jVpwx}gdBNaMgZL5u;Go3lJoHJ+6nX`N@YQ)ln-}Uo* zlPB*(gb)CL#oG?Hnx4wNrl)#|&Al#GQVmy8e&sb&mtS1J_!8yd56Gsrw#xY2b$jIC z#=~-O^#apd1=s)>;3{TO_2t=U&1ld0Dd~6TdhbUQWs!etj2aQgm$ngD>N-N&E% zl7lDosS88J$~iNN)uH;bNU3djBs~jvek>zt$q$iOAzSX@)?&l{ne98GSt^H+X90?Msh1*A=)5X%MFb=4d}3 z-1qe1o7L+!A7PfxHGe~xl!}9XW#r84SkJAqLYSOc1#m45I3}oG_;nn3{`lU&lJy%g1;6Xg+aZ$A+aRpFFvd`MDfgQo)1+ z2pi1S@h3tE8xte^4bDm`h-E+sXX3!ZmcQi5p#PPc1TIlJ?g)EW5HU!FBYz#L5dYSI Y?{CsPln#@-BLDyZ07*qoM6N<$f&*G*_W%F@ diff --git a/public/javascripts/application.js b/public/javascripts/application.js index cfe11d2e..4b025f51 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -229,7 +229,7 @@ function enable_rich_interaction(){ /* Drag & Drop for successor/predecessor */ function drop_todo(evt, ui) { dragged_todo = ui.draggable[0].id.split('_')[2]; - dropped_todo = $(this).parents('.item-show').get(0).id.split('_')[2]; + dropped_todo = this.id.split('_')[2]; ui.draggable.remove(); $(this).block({message: null}); $.post(relative_to_root('todos/add_predecessor'), @@ -247,7 +247,7 @@ function enable_rich_interaction(){ start: drag_todo, stop: function() {$('.drop_target').hide();}}); - $('.successor_target').droppable({drop: drop_todo, + $('.item-show').droppable({drop: drop_todo, tolerance: 'pointer', hoverClass: 'hover'}); diff --git a/public/stylesheets/standard.css b/public/stylesheets/standard.css index d214f861..7d2963cc 100644 --- a/public/stylesheets/standard.css +++ b/public/stylesheets/standard.css @@ -943,16 +943,9 @@ div.message { display:none; } -.successor_target { - background-image:url("../images/add_successor_off.png"); - background-repeat: no-repeat; - background-position: center right; -} - -.successor_target.hover { - background-image:url("../images/add_successor_on.png"); - background-repeat: no-repeat; - background-position: center right; +.hover { + background: #EAEAEA; + font-weight: bold; } .context_target { From 92bb54bbf572983aef2a57272fba688fbcc5542c Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Sun, 9 May 2010 18:59:02 -0400 Subject: [PATCH 19/64] Revert "fix cucumber story for drag and drop for dependencies. Was broken since last change of drop target to a hidden img that appears when dragging starts" This reverts commit 8dbf790810e8f2b91e6f20d3897d9f32fb801ef7. Conflicts: app/helpers/todos_helper.rb features/step_definitions/todo_steps.rb --- features/step_definitions/todo_steps.rb | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/features/step_definitions/todo_steps.rb b/features/step_definitions/todo_steps.rb index b2bd9d24..54fec93c 100644 --- a/features/step_definitions/todo_steps.rb +++ b/features/step_definitions/todo_steps.rb @@ -37,15 +37,8 @@ When /^I drag "(.*)" to "(.*)"$/ do |dragged, target| drag_id = Todo.find_by_description(dragged).id drop_id = Todo.find_by_description(target).id drag_name = "xpath=//div[@id='line_todo_#{drag_id}']//img[@class='grip']" - # xpath does not seem to work here... reverting to css - # xpath=//div[@id='line_todo_#{drop_id}']//img[@class='successor_target'] - drop_name = "css=div#line_todo_#{drop_id} img.successor_target" - - # HACK: the target img is hidden until drag starts. We need to show the img or the - # xpath will not find it - js="$('div#line_todo_#{drop_id} img.successor_target').show();" - selenium.get_eval "(function() {with(this) {#{js}}}).call(selenium.browserbot.getCurrentWindow());" - + drop_name = "xpath=//div[@id='line_todo_#{drop_id}']//div[@class='description']" + selenium.drag_and_drop_to_object(drag_name, drop_name) arrow = "xpath=//div[@id='line_todo_#{drop_id}']/div/a[@class='show_successors']/img" From cfc6d117b815c43eccdc65168e0370c23a658adc Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Thu, 13 May 2010 18:24:26 +0200 Subject: [PATCH 20/64] fix #1027. Several tests were broken because of the more strict validations on the recurring_todo model --- app/models/recurring_todo.rb | 1 - test/fixtures/recurring_todos.yml | 14 +++++++++----- test/functional/login_controller_test.rb | 2 +- test/functional/recurring_todos_controller_test.rb | 5 +++++ test/functional/todos_controller_test.rb | 8 ++++++-- test/functional/users_controller_test.rb | 8 ++++---- 6 files changed, 25 insertions(+), 13 deletions(-) diff --git a/app/models/recurring_todo.rb b/app/models/recurring_todo.rb index 2f6d623b..4a916c6d 100644 --- a/app/models/recurring_todo.rb +++ b/app/models/recurring_todo.rb @@ -30,7 +30,6 @@ class RecurringTodo < ActiveRecord::Base validates_presence_of :description validates_presence_of :recurring_period validates_presence_of :target - validates_presence_of :recurring_period validates_presence_of :ends_on validates_presence_of :context diff --git a/test/fixtures/recurring_todos.yml b/test/fixtures/recurring_todos.yml index db630d68..9597d674 100644 --- a/test/fixtures/recurring_todos.yml +++ b/test/fixtures/recurring_todos.yml @@ -1,4 +1,3 @@ -<% def today Time.zone.now.beginning_of_day.to_s(:db) @@ -30,7 +29,7 @@ call_bill_gates_every_day: description: Call Bill Gates every day notes: ~ state: active - start_from: ~ + start_from: <%= last_week %> ends_on: no_end_date end_date: ~ number_of_occurences: ~ @@ -38,6 +37,7 @@ call_bill_gates_every_day: show_from_delta: ~ recurring_period: daily recurrence_selector: ~ + show_always: 0 every_other1: 1 every_other2: ~ every_other3: ~ @@ -62,6 +62,7 @@ call_bill_gates_every_workday: number_of_occurences: ~ target: due_date show_from_delta: ~ + show_always: 0 recurring_period: daily recurrence_selector: ~ every_other1: 1 @@ -82,7 +83,7 @@ call_bill_gates_every_week: description: Call Bill Gates every week notes: ~ state: active - start_from: ~ + start_from: <%= today %> ends_on: no_end_date end_date: ~ number_of_occurences: ~ @@ -90,6 +91,7 @@ call_bill_gates_every_week: show_from_delta: ~ recurring_period: weekly recurrence_selector: ~ + show_always: 0 every_other1: 2 every_other2: ~ every_other3: ~ @@ -108,7 +110,7 @@ check_with_bill_every_last_friday_of_month: description: Check with Bill every last friday of the month notes: ~ state: active - start_from: ~ + start_from: <%= today %> ends_on: no_end_date end_date: ~ number_of_occurences: ~ @@ -116,6 +118,7 @@ check_with_bill_every_last_friday_of_month: show_from_delta: 5 recurring_period: monthly recurrence_selector: 1 + show_always: 0 every_other1: 1 every_other2: 2 every_other3: 5 @@ -134,12 +137,13 @@ birthday_reinier: description: Congratulate Reinier on his birthday notes: ~ state: active - start_from: ~ + start_from: <%= today %> ends_on: no_end_date end_date: ~ number_of_occurences: ~ target: due_date show_from_delta: 5 + show_always: 0 recurring_period: yearly recurrence_selector: 0 every_other1: 8 diff --git a/test/functional/login_controller_test.rb b/test/functional/login_controller_test.rb index 50da6ae8..051bb744 100644 --- a/test/functional/login_controller_test.rb +++ b/test/functional/login_controller_test.rb @@ -51,7 +51,7 @@ class LoginControllerTest < ActionController::TestCase def test_login_with_no_users_redirects_to_signup User.delete_all get :login - assert_redirected_to :controller => 'users', :action => 'new' + assert_redirected_to signup_url end def test_logout diff --git a/test/functional/recurring_todos_controller_test.rb b/test/functional/recurring_todos_controller_test.rb index 394e72d7..ebe64ed0 100644 --- a/test/functional/recurring_todos_controller_test.rb +++ b/test/functional/recurring_todos_controller_test.rb @@ -50,6 +50,7 @@ class RecurringTodosControllerTest < ActionController::TestCase "recurring_period"=>"yearly", "recurring_show_days_before"=>"10", "recurring_target"=>"due_date", + "recurring_show_always" => "1", "start_from"=>"18/08/2008", "weekly_every_x_week"=>"1", "weekly_return_monday"=>"m", @@ -110,6 +111,9 @@ class RecurringTodosControllerTest < ActionController::TestCase @yearly.every_other1 = target_date.day @yearly.every_other2 = target_date.month @yearly.show_from_delta = 10 +# unless @yearly.valid? +# @yearly.errors.each {|obj, error| puts error} +# end assert @yearly.save # toggle twice to force generation of new todo @@ -155,6 +159,7 @@ class RecurringTodosControllerTest < ActionController::TestCase "recurring_period"=>"yearly", "recurring_show_days_before"=>"0", "recurring_target"=>"due_date", + "recurring_show_always" => "1", "start_from"=>"1/10/2012", # adjust after 2012 "weekly_every_x_week"=>"1", "weekly_return_monday"=>"w", diff --git a/test/functional/todos_controller_test.rb b/test/functional/todos_controller_test.rb index 0035f291..ec93e728 100644 --- a/test/functional/todos_controller_test.rb +++ b/test/functional/todos_controller_test.rb @@ -376,12 +376,16 @@ class TodosControllerTest < ActionController::TestCase # 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 - recurring_todo_1.save + # 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' @@ -416,7 +420,7 @@ class TodosControllerTest < ActionController::TestCase recurring_todo_1.recurrence_selector = 0 recurring_todo_1.every_other1 = today.day recurring_todo_1.every_other2 = 1 - recurring_todo_1.save + 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 diff --git a/test/functional/users_controller_test.rb b/test/functional/users_controller_test.rb index e53942cc..e20d9095 100644 --- a/test/functional/users_controller_test.rb +++ b/test/functional/users_controller_test.rb @@ -154,19 +154,19 @@ class UsersControllerTest < ActionController::TestCase def test_create_with_invalid_password_redirects_to_new_user_page login_as :admin_user post :create, :user => {:login => 'newbie', :password => '', :password_confirmation => ''} - assert_redirected_to :controller => 'users', :action => 'new' + assert_redirected_to signup_path end def test_create_with_invalid_login_does_not_add_a_new_user login_as :admin_user post :create, :user => {:login => 'n', :password => 'newbiepass', :password_confirmation => 'newbiepass'} - assert_redirected_to :controller => 'users', :action => 'new' + assert_redirected_to signup_path end def test_create_with_invalid_login_redirects_to_new_user_page login_as :admin_user post :create, :user => {:login => 'n', :password => 'newbiepass', :password_confirmation => 'newbiepass'} - assert_redirected_to :controller => 'users', :action => 'new' + assert_redirected_to signup_path end def test_create_with_duplicate_login_does_not_add_a_new_user @@ -179,7 +179,7 @@ class UsersControllerTest < ActionController::TestCase def test_create_with_duplicate_login_redirects_to_new_user_page login_as :admin_user post :create, :user => {:login => 'jane', :password => 'newbiepass', :password_confirmation => 'newbiepass'} - assert_redirected_to :controller => 'users', :action => 'new' + assert_redirected_to signup_path end end From b50a1ce26f5287d82ed6a5fbc51ee2c304f512b9 Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Mon, 17 May 2010 11:02:23 -0400 Subject: [PATCH 21/64] Fix a couple of test definitions to avoid false test failures State should be unspecified to default to active Fixes #977 (again) --- test/functional/todos_controller_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/todos_controller_test.rb b/test/functional/todos_controller_test.rb index ec93e728..d4f716e7 100644 --- a/test/functional/todos_controller_test.rb +++ b/test/functional/todos_controller_test.rb @@ -320,7 +320,7 @@ class TodosControllerTest < ActionController::TestCase "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"}} + "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 @@ -347,7 +347,7 @@ class TodosControllerTest < ActionController::TestCase "due(1i)"=>"2007", "due(2i)"=>"1", "due(3i)"=>"2", "show_from(1i)"=>"", "show_from(2i)"=>"", "show_from(3i)"=>"", "project_id"=>"1", - "notes"=>"test notes", "state"=>"0"}, "tag_list"=>"test, test2"} + "notes"=>"test notes"}, "tag_list"=>"test, test2"} assert_template 'todos/new' end From d9d08fac35fc11b10fb0b31e6b21b483a6e22450 Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Mon, 17 May 2010 11:36:41 -0400 Subject: [PATCH 22/64] Various improvements to context drag&drop -Don't botch other fields on context change -Better status message -Flash context title on drop -Drop target close to context name -Bolder drop target border Closes #1033 --- app/controllers/todos_controller.rb | 17 +++++++++++++++++ app/views/contexts/_context.rhtml | 2 +- app/views/todos/update.js.rjs | 9 ++++++++- public/javascripts/application.js | 5 ++--- public/stylesheets/standard.css | 2 +- 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 480744fb..81f52b62 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -230,6 +230,23 @@ class TodosController < ApplicationController end end + def change_context + @todo = Todo.find(params[:todo][:id]) + @original_item_context_id = @todo.context_id + @context = Context.find(params[:todo][:context_id]) + @todo.context = @context + @saved = @todo.save + + @context_changed = true + @message = "Context changed to #{@context.name}" + determine_remaining_in_context_count(@original_item_context_id) + + respond_to do |format| + format.js {render :action => :update } + format.xml { render :xml => @todo.to_xml( :except => :user_id ) } + end + end + def update @source_view = params['_source_view'] || 'todo' init_data_for_sidebar unless mobile? diff --git a/app/views/contexts/_context.rhtml b/app/views/contexts/_context.rhtml index 7b33ee9a..105b66bb 100644 --- a/app/views/contexts/_context.rhtml +++ b/app/views/contexts/_context.rhtml @@ -10,11 +10,11 @@ <%= link_to_context( context ) %> <% end %> +

Currently there are no incomplete actions in this context

<%= render :partial => "todos/todo", :collection => @not_done, :locals => { :parent_container_type => "context" } %>
-
diff --git a/app/views/todos/update.js.rjs b/app/views/todos/update.js.rjs index d15595f5..bcc80ccc 100644 --- a/app/views/todos/update.js.rjs +++ b/app/views/todos/update.js.rjs @@ -4,6 +4,7 @@ if @saved status_message += ' to tickler' if @todo.deferred? status_message = 'Added new project / ' + status_message if @new_project_created status_message = 'Added new context / ' + status_message if @new_context_created + status_message = @message || status_message page.notify :notice, status_message, 5.0 if source_view_is_one_of(:todo, :context, :tag) @@ -46,12 +47,18 @@ if @saved page.replace_html("badge_count", @down_count) if source_view_is :todo # show todo in context - page.delay(0.5) do + page.delay(0.3) do page.call "todoItems.ensureContainerHeight", "c#{@original_item_context_id}items" if source_view_is_one_of(:todo, :tag) && @todo.active? page.call "todoItems.ensureContainerHeight", "c#{@todo.context_id}items" page.visual_effect :highlight, dom_id(@todo), :duration => 3 end + if @context_changed + source_view do |from| + from.todo {page << "$('#c#{@todo.context_id} h2').effect('highlight', {}, 3000)" } + from.tag {page << "$('#c#{@todo.context_id} h2').effect('highlight')" } + end + end end else if @original_item_was_deferred && source_view_is(:tag) diff --git a/public/javascripts/application.js b/public/javascripts/application.js index 4b025f51..52acc10f 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -259,9 +259,8 @@ function enable_rich_interaction(){ ui.draggable.remove(); target.block({message: null}); setTimeout(function() {target.show()}, 0); - $.post(relative_to_root('todos/update'), - {id: dragged_todo, - "todo[id]": dragged_todo, + $.post(relative_to_root('todos/change_context'), + {"todo[id]": dragged_todo, "todo[context_id]": context_id}, function(){target.unblock(); target.hide();}, 'script'); } diff --git a/public/stylesheets/standard.css b/public/stylesheets/standard.css index 7d2963cc..069a6ce0 100644 --- a/public/stylesheets/standard.css +++ b/public/stylesheets/standard.css @@ -951,7 +951,7 @@ div.message { .context_target { height: 15px; margin: 4px; - border: thick dotted #CCC; + border: 4px dotted #999; } .context_target.hover { From ac96c5c738a9f0b92ae32ee7fba5b1d828243abd Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Tue, 18 May 2010 09:54:46 -0400 Subject: [PATCH 23/64] Fix small IE8 bug --- public/javascripts/application.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/javascripts/application.js b/public/javascripts/application.js index 52acc10f..45638756 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -231,6 +231,7 @@ function enable_rich_interaction(){ dragged_todo = ui.draggable[0].id.split('_')[2]; dropped_todo = this.id.split('_')[2]; ui.draggable.remove(); + $('.drop_target').hide(); // IE8 doesn't call stop() in this situation $(this).block({message: null}); $.post(relative_to_root('todos/add_predecessor'), {successor: dragged_todo, predecessor: dropped_todo}, From 04fb281ecd28b783dd069df226261fd40967ad2c Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Sun, 4 Jul 2010 16:01:41 -0700 Subject: [PATCH 24/64] Typo that newer Gherkin caught --- features/show_statistics.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/show_statistics.feature b/features/show_statistics.feature index 38bcc788..261afbbe 100644 --- a/features/show_statistics.feature +++ b/features/show_statistics.feature @@ -1,4 +1,4 @@ -Feature Show statistics +Feature: Show statistics In order to see what I have got done As an user I want see my statistics From 92047e86e434664edd2da3db427cc4b079156650 Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Sun, 4 Jul 2010 20:13:32 -0700 Subject: [PATCH 25/64] Test for ticket #1043 --- features/manage_project.feature | 11 ++++++++++- features/step_definitions/todo_steps.rb | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/features/manage_project.feature b/features/manage_project.feature index 74eaaeec..88893ed5 100644 --- a/features/manage_project.feature +++ b/features/manage_project.feature @@ -16,4 +16,13 @@ Feature: Manage a project When I visit the "manage me" project And I edit the project description to "_successfull outcome_: project is *done*" Then I should see the italic text "successfull outcome" in the project description - And I should see the bold text "done" in the project description \ No newline at end of file + And I should see the bold text "done" in the project description + + # Ticket #1043 + @selenium + Scenario: I can move a todo out of the current project + Given I have a project "foo" with 2 todos + When I visit the "foo" project + And I change the project_name field of "Todo 1" to "bar" + Then I should not see the todo "Todo 1" + And I should see the todo "Todo 2" diff --git a/features/step_definitions/todo_steps.rb b/features/step_definitions/todo_steps.rb index 54fec93c..98831bca 100644 --- a/features/step_definitions/todo_steps.rb +++ b/features/step_definitions/todo_steps.rb @@ -59,6 +59,13 @@ Then /^I should see ([0-9]+) todos$/ do |count| end end +When /I change the (.*) field of "([^\"]*)" to "([^\"]*)"$/ do |field, todo_name, new_value| + selenium.click("//span[@class=\"todo.descr\"][.=\"#{todo_name}\"]/../../a[@class=\"icon edit_item\"]", :wait_for => :ajax, :javascript_framework => :jquery) + selenium.type("css=form.edit_todo_form input[name=#{field}]", new_value) + selenium.click("css=button.positive", :wait_for => :ajax, :javascript_framework => :jquery) + sleep(5) +end + Then /^the dependencies of "(.*)" should include "(.*)"$/ do |child_name, parent_name| parent = @current_user.todos.find_by_description(parent_name) parent.should_not be_nil @@ -81,3 +88,11 @@ Then /^I should see "([^\"]*)" within the dependencies of "([^\"]*)"$/ do |succe xpath = "xpath=//div[@id='line_todo_#{todo.id}']//div[@id='successor_line_todo_#{successor.id}']//span" selenium.wait_for_element(xpath, :timeout_in_seconds => 5) end + +Then /^I should see the todo "([^\"]*)"$/ do |todo_description| + selenium.is_element_present("//span[.=\"#{todo_description}\"]").should be_true +end + +Then /^I should not see the todo "([^\"]*)"$/ do |todo_description| + selenium.is_element_present("//span[.=\"#{todo_description}\"]").should be_false +end From e764a75986120f84dec8d76ca06629b37c5bd74a Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Sun, 4 Jul 2010 20:13:47 -0700 Subject: [PATCH 26/64] Case-sensitive compare screwed up source_view Fixes #1043 --- public/javascripts/application.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/javascripts/application.js b/public/javascripts/application.js index 45638756..e607f777 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -49,7 +49,7 @@ $.fn.clearForm = function() { /* Set up authenticity token properly */ $(document).ajaxSend(function(event, request, settings) { - if ( settings.type == 'POST' ) { + if ( settings.type == 'POST' || settings.type == 'post' ) { if(typeof(AUTH_TOKEN) != 'undefined'){ settings.data = (settings.data ? settings.data + "&" : "") + "authenticity_token=" + encodeURIComponent( AUTH_TOKEN ) + "&" From f10a98d8acdad6b1e89f1b64248c885c38eb76f0 Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Mon, 5 Jul 2010 08:24:58 -0700 Subject: [PATCH 27/64] Test for #1041 --- features/manage_project.feature | 8 ++++++++ features/step_definitions/project_steps.rb | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/features/manage_project.feature b/features/manage_project.feature index 88893ed5..f460bd5e 100644 --- a/features/manage_project.feature +++ b/features/manage_project.feature @@ -26,3 +26,11 @@ Feature: Manage a project And I change the project_name field of "Todo 1" to "bar" Then I should not see the todo "Todo 1" And I should see the todo "Todo 2" + + # Ticket #1041 + @selenium + Scenario: I can change the name of the project using the Edit Project Settings form + Given I have a project "bananas" with 1 todos + When I visit the "bananas" project + And I edit the project name to "cherries" + Then the project title should be "cherries" diff --git a/features/step_definitions/project_steps.rb b/features/step_definitions/project_steps.rb index 801104c9..bb200f1a 100644 --- a/features/step_definitions/project_steps.rb +++ b/features/step_definitions/project_steps.rb @@ -27,6 +27,12 @@ When /^I edit the project description to "([^\"]*)"$/ do |new_description| click_button "submit_project_#{@project.id}" end +When /^I edit the project name to "([^\"]*)"$/ do |new_title| + click_link "link_edit_project_#{@project.id}" + fill_in "project[name]", :with => new_title + click_button "submit_project_#{@project.id}" +end + Then /^I should see the bold text "([^\"]*)" in the project description$/ do |bold| xpath="//div[@class='project_description']/p/strong" @@ -44,3 +50,7 @@ Then /^I should see the italic text "([^\"]*)" in the project description$/ do | italic_text.should =~ /#{italic}/ end + +Then /^the project title should be "(.*)"$/ do |title| + selenium.get_text("css=h2#project_name").should == title +end From 1cd748d7a27ce27369986a6afb3250dd131cdff0 Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Mon, 5 Jul 2010 09:58:25 -0700 Subject: [PATCH 28/64] Fix #1041 --- app/views/projects/update.js.rjs | 6 +++++- features/step_definitions/project_steps.rb | 5 ++++- public/javascripts/application.js | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/views/projects/update.js.rjs b/app/views/projects/update.js.rjs index a8b4d3a8..2d554dea 100644 --- a/app/views/projects/update.js.rjs +++ b/app/views/projects/update.js.rjs @@ -28,5 +28,9 @@ else page << "defaultTags = #{default_tags_for_autocomplete};" end -page.replace_html "sidebar", :file => 'sidebar/sidebar.html.erb' +page['default_project_name_id'].value = @project.name +page['todo_project_name'].value = @project.name +page.replace_html "project_name", @project.name +page.replace_html "sidebar", :file => 'sidebar/sidebar.html.erb' +page << "enable_rich_interaction();" diff --git a/features/step_definitions/project_steps.rb b/features/step_definitions/project_steps.rb index bb200f1a..9ec28edc 100644 --- a/features/step_definitions/project_steps.rb +++ b/features/step_definitions/project_steps.rb @@ -30,7 +30,10 @@ end When /^I edit the project name to "([^\"]*)"$/ do |new_title| click_link "link_edit_project_#{@project.id}" fill_in "project[name]", :with => new_title - click_button "submit_project_#{@project.id}" + selenium.click "submit_project_#{@project.id}", + :wait_for => :text, + :element => "flash", + :text => "Project saved" end Then /^I should see the bold text "([^\"]*)" in the project description$/ do |bold| diff --git a/public/javascripts/application.js b/public/javascripts/application.js index e607f777..30d836f5 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -273,6 +273,8 @@ function enable_rich_interaction(){ /* Reset auto updater */ field_touched = false; + + $('h2#project_name').editable(save_project_name, {style: 'padding:0px', submit: "OK"}); } /* Auto-refresh */ @@ -462,8 +464,6 @@ $(document).ready(function() { return(value); }; - $('h2#project_name').editable(save_project_name, {style: 'padding:0px', submit: "OK"}); - $('.alphabetize_link').click(function(evt){ evt.preventDefault(); if(confirm('Are you sure that you want to sort these projects alphabetically? This will replace the existing sort order.')){ From e2443dace452a98944f70306ff3f8f1d6037face Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Mon, 5 Jul 2010 09:58:35 -0700 Subject: [PATCH 29/64] Get rid of some autocomplete leftovers --- app/views/projects/update.js.rjs | 2 -- app/views/projects/update_project_name.js.rjs | 2 -- 2 files changed, 4 deletions(-) diff --git a/app/views/projects/update.js.rjs b/app/views/projects/update.js.rjs index 2d554dea..079b98ee 100644 --- a/app/views/projects/update.js.rjs +++ b/app/views/projects/update.js.rjs @@ -24,8 +24,6 @@ else page['#todo_project_name'].value = @project.name page['tag_list'].value = @project.default_tags if @project.default_tags page << "$('input[name=default_context_name]').val('#{@project.default_context.name}');" if @project.default_context - page << "defaultContexts = #{default_contexts_for_autocomplete};" - page << "defaultTags = #{default_tags_for_autocomplete};" end page['default_project_name_id'].value = @project.name diff --git a/app/views/projects/update_project_name.js.rjs b/app/views/projects/update_project_name.js.rjs index 5a41572c..85ed34e7 100644 --- a/app/views/projects/update_project_name.js.rjs +++ b/app/views/projects/update_project_name.js.rjs @@ -1,8 +1,6 @@ page['default_project_name_id'].value = @project.name page['todo_project_name'].value = @project.name -# renew project auto complete array -page << "var projectNames = #{project_names_for_autocomplete};" page << "enable_rich_interaction();" status_message = "Name of project was changed" From 157595be50b777d4753f472717a61079dd85a200 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Fri, 16 Jul 2010 15:38:34 +0200 Subject: [PATCH 30/64] fix timing issue on context selenium step --- features/step_definitions/context_steps.rb | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/features/step_definitions/context_steps.rb b/features/step_definitions/context_steps.rb index a75f780c..ba025d12 100644 --- a/features/step_definitions/context_steps.rb +++ b/features/step_definitions/context_steps.rb @@ -44,10 +44,20 @@ end When /^I edit the context to rename it to "([^\"]*)"$/ do |new_name| click_link "edit_context_#{@context.id}" - fill_in "context_name", :with => new_name - click_button "submit_context_#{@context.id}" + wait_for do - selenium.is_visible("flash") + selenium.is_element_present("submit_context_#{@context.id}") + end + + fill_in "context_name", :with => new_name + + selenium.click "submit_context_#{@context.id}", + :wait_for => :text, + :element => "flash", + :text => "Context saved" + + wait_for do + selenium.is_element_present("edit_context_#{@context.id}") end end From ceb4529a7c6837ff47000d6d765ad1fed990b4b1 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Mon, 26 Jul 2010 21:36:48 +0200 Subject: [PATCH 31/64] Add warning that deleting a context will also delete all actions within it. Fixes #1049. Thanks edgimar for reporting this. --- app/views/contexts/_context_listing.rhtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/contexts/_context_listing.rhtml b/app/views/contexts/_context_listing.rhtml index df90a138..f4c8ce5c 100644 --- a/app/views/contexts/_context_listing.rhtml +++ b/app/views/contexts/_context_listing.rhtml @@ -26,7 +26,7 @@ :with => "'_source_view=#{@source_view}'", :before => "$('#{dom_id(context)}').block({message:null});", :complete => "$('#{dom_id(context)}').unblock();", - :confirm => "Are you sure that you want to delete the context '#{context.name}'?", + :confirm => "Are you sure that you want to delete the context '#{context.name}'? Be aware that this will also delete all actions in this context!", :html => { :id => dom_id(context, 'delete') } ) %> <%= link_to_remote( From 6334a3f7d74f5f89653bd8a1f8749fa82db7785c Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Mon, 26 Jul 2010 22:09:22 +0200 Subject: [PATCH 32/64] set defaults right when adding a new action on the mobile interface from the context or project page. Fixes #1051. We need tests for this :-) --- app/views/layouts/mobile.m.erb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/layouts/mobile.m.erb b/app/views/layouts/mobile.m.erb index 75cd4049..8bacf7c9 100644 --- a/app/views/layouts/mobile.m.erb +++ b/app/views/layouts/mobile.m.erb @@ -1,5 +1,5 @@ <% - new_todo_params = {} + new_todo_params = {:format => :m} new_todo_params[:from_project] = @mobile_from_project if @mobile_from_project new_todo_params[:from_context] = @mobile_from_context if @mobile_from_context -%> @@ -16,7 +16,7 @@

<%= @down_count %> <%= current_user.time.strftime(@prefs.title_date_format) -%>

diff --git a/app/views/todos/create_multiple.js.rjs b/app/views/todos/create_multiple.js.rjs new file mode 100644 index 00000000..b1c310a7 --- /dev/null +++ b/app/views/todos/create_multiple.js.rjs @@ -0,0 +1,42 @@ +if @saved + page.hide 'status' + + status_message = 'Added new next action' + status_message += 's' if @todos.size > 1 + status_message = 'Added new project / ' + status_message if @new_project_created + status_message = 'Added new context / ' + status_message if @new_context_created + page.notify :notice, status_message, 5.0 + + page['badge_count'].replace_html @down_count + + # reset form and set focus to first field + page.send :record, "$('#todo-form-multi-new-action').clearForm();$('#todo-form-multi-new-action input:text:first').focus();" + + # set defaults of form + page.send :record, "$('#multi_todo_context_name').val('#{@initial_context_name}');" + page.send :record, "$('#multi_todo_project_name').val('#{@initial_project_name}');" + page.send :record, "$('#multi_tag_list').val('#{@default_tags}');" + + if should_show_new_item() + if @new_context_created + page.insert_html :top, 'display_box', :partial => 'contexts/context', :locals => { :context => @todo.context, :collapsible => true } + else + page.call "todoItems.ensureVisibleWithEffectAppear", "c#{@todo.context_id}" if source_view_is_one_of(:todo, :deferred, :tag) + + @todos.each do |todo| + page.insert_html :bottom, item_container_id(todo), :partial => 'todos/todo', :locals => { :todo => todo, :parent_container_type => parent_container_type, :source_view => @source_view } + page.visual_effect :highlight, dom_id(todo), :duration => 3 + end + + page[empty_container_msg_div_id].hide unless empty_container_msg_div_id.nil? + end + if (source_view_is :project and @todo.pending?) or (source_view_is :deferred) + page['tickler-empty-nd'].hide # For some reason this does not work: page['tickler-empty-nd'].hide if (@todo.pending? or (source_view_is :deferred)) + end + end + # make sure the behavior of the new/updated todo is enabled + page << "enable_rich_interaction();" +else + page.show 'status' + page.replace_html 'status', "#{error_messages_for('todo', :object_name => 'action')}" +end \ No newline at end of file diff --git a/public/javascripts/application.js b/public/javascripts/application.js index 67d9d633..cd9e7de1 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -11,7 +11,7 @@ var TracksForm = { toggleLink.text(hideLinkText).attr('title', hideLinkTitle); $('#'+formId+' input:text:first').focus(); } - toggleLink.parent.toggleClass('hide_form'); + toggleLink.parent().toggleClass('hide_form'); }, hide_all_recurring: function () { $.each(['daily', 'weekly', 'monthly', 'yearly'], function(){ @@ -137,8 +137,8 @@ function setup_container_toggles(){ }); } -function askIfNewContextProvided() { - var givenContextName = $('#todo_context_name').val(); +function askIfNewContextProvided(source) { + var givenContextName = $('#'+source+'todo_context_name').val(); var contextNames = []; var contextNamesRequest = $.ajax({url: relative_to_root('contexts.autocomplete'), async: false, diff --git a/public/stylesheets/standard.css b/public/stylesheets/standard.css index d588fbfe..5d604dea 100644 --- a/public/stylesheets/standard.css +++ b/public/stylesheets/standard.css @@ -825,7 +825,7 @@ input#go_to_project, input#context_hide { float: right; } -#todo-form-new-action .submit_box, #project_form .submit_box, #context_form .submit_box, #todo-form-multi-new-acion .submit_box { +#todo-form-new-action .submit_box, #project_form .submit_box, #context_form .submit_box, #todo-form-multi-new-action .submit_box { height: 25px; padding: 5px 0; text-align: center; From 6e5057138de7df7aa7dbe1317e22529512c06a2d Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Wed, 14 Jul 2010 23:34:47 +0200 Subject: [PATCH 42/64] add cucumber scenarios for adding multiple next actions --- app/helpers/todos_helper.rb | 3 + features/shared_add_new_todo.feature | 88 +++++++++++++++++-------- features/step_definitions/todo_steps.rb | 14 ++++ 3 files changed, 79 insertions(+), 26 deletions(-) diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index b8ea341e..32d1bc84 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -251,11 +251,14 @@ module TodosHelper return false if source_view_is(:context) && (@todo.project.hidden? || @todo.project.completed?) end + return false if (source_view_is(:tag) && !@todo.tags.include?(@tag_name)) + return true if source_view_is(:deferred) && @todo.deferred? return true if source_view_is(:project) && @todo.project.hidden? && @todo.project_hidden? return true if source_view_is(:project) && @todo.deferred? return true if !source_view_is(:deferred) && @todo.active? return true if source_view_is(:project) && @todo.pending? + return true if source_view_is(:tag) && @todo.pending? return false end diff --git a/features/shared_add_new_todo.feature b/features/shared_add_new_todo.feature index 6164469e..9955e63e 100644 --- a/features/shared_add_new_todo.feature +++ b/features/shared_add_new_todo.feature @@ -9,8 +9,8 @@ Feature: Add new next action from every page | login | password | is_admin | | testuser | secret | false | And I have logged in as "testuser" with password "secret" - And I have a context called "test" - And I have a project "test" with 1 todos + And I have a context called "test context" + And I have a project "test project" with 1 todos @selenium Scenario Outline: I can hide the input form for single next action on a page @@ -20,12 +20,12 @@ Feature: Add new next action from every page Then the single action form should not be visible Scenarios: - | action | page | - | go to | home page | - | go to | tickler page | - | visit | project page for "test"| - | visit | context page for "test"| - | visit | tag page for "starred" | + | action | page | + | go to | home page | + | go to | tickler page | + | visit | project page for "test project"| + | visit | context page for "test context"| + | visit | tag page for "starred" | @selenium Scenario Outline: I can hide the input form for multiple next actions @@ -38,12 +38,12 @@ Feature: Add new next action from every page And the multiple action form should not be visible Scenarios: - | action | page | - | go to | home page | - | go to | tickler page | - | visit | project page for "test"| - | visit | context page for "test"| - | visit | tag page for "starred" | + | action | page | + | go to | home page | + | go to | tickler page | + | visit | project page for "test project"| + | visit | context page for "test context"| + | visit | tag page for "starred" | @selenium Scenario Outline: I can hide the input form and then choose both input forms @@ -58,12 +58,12 @@ Feature: Add new next action from every page And the multiple action form should not be visible Scenarios: - | action | page | - | go to | home page | - | go to | tickler page | - | visit | project page for "test"| - | visit | context page for "test"| - | visit | tag page for "starred" | + | action | page | + | go to | home page | + | go to | tickler page | + | visit | project page for "test project"| + | visit | context page for "test context"| + | visit | tag page for "starred" | @selenium Scenario Outline: I can switch forms for single next action to multiple next actions @@ -77,9 +77,45 @@ Feature: Add new next action from every page And the multiple action form should not be visible Scenarios: - | action | page | - | go to | home page | - | go to | tickler page | - | visit | project page for "test"| - | visit | context page for "test"| - | visit | tag page for "starred" | + | action | page | + | go to | home page | + | go to | tickler page | + | visit | project page for "test project"| + | visit | context page for "test context"| + | visit | tag page for "starred" | + + @selenium + Scenario Outline: I can add a todo from several pages + When I the + And I submit a new action with description "a new next action" + Then I should "a new next action" + + Scenarios: + | action | page | see | + | go to | home page | see | + | go to | tickler page | not see| + | visit | project page for "test project"| see | + | visit | context page for "test context"| see | + | visit | tag page for "starred" | not see| + + @selenium + Scenario Outline: I can add multiple todos from several pages + When I the + And I follow "Add multiple next actions" + And I submit multiple actions with using + """ + one new next action + another new next action + """ + Then I should "one new next action" + And I should "another new next action" + And the badge should show + And the number of actions should be + + Scenarios: + | action | page | see | badge | count | + | go to | home page | see | 3 | 3 | + | go to | tickler page | not see| 0 | 3 | + | visit | project page for "test project"| see | 3 | 3 | + | visit | context page for "test context"| see | 2 | 3 | + | visit | tag page for "starred" | not see| 0 | 3 | \ No newline at end of file diff --git a/features/step_definitions/todo_steps.rb b/features/step_definitions/todo_steps.rb index 98831bca..e1b183f7 100644 --- a/features/step_definitions/todo_steps.rb +++ b/features/step_definitions/todo_steps.rb @@ -66,6 +66,16 @@ When /I change the (.*) field of "([^\"]*)" to "([^\"]*)"$/ do |field, todo_name sleep(5) end +When /^I submit a new action with description "([^"]*)"$/ do |description| + fill_in "todo[description]", :with => description + selenium.click("xpath=//form[@id='todo-form-new-action']//button[@id='todo_new_action_submit']", :wait_for => :ajax, :javascript_framework => :jquery) +end + +When /^I submit multiple actions with using$/ do |multiple_actions| + fill_in "todo[multiple_todos]", :with => multiple_actions + selenium.click("xpath=//form[@id='todo-form-multi-new-action']//button[@id='todo_multi_new_action_submit']", :wait_for => :ajax, :javascript_framework => :jquery) +end + Then /^the dependencies of "(.*)" should include "(.*)"$/ do |child_name, parent_name| parent = @current_user.todos.find_by_description(parent_name) parent.should_not be_nil @@ -96,3 +106,7 @@ end Then /^I should not see the todo "([^\"]*)"$/ do |todo_description| selenium.is_element_present("//span[.=\"#{todo_description}\"]").should be_false end + +Then /^the number of actions should be (\d+)$/ do |count| + @current_user.todos.count.should == count.to_i +end From abf45246796a1797f10b6a89ad623fd0dc308527 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Fri, 16 Jul 2010 13:11:01 +0200 Subject: [PATCH 43/64] add validation to catch empty descriptions --- app/controllers/todos_controller.rb | 8 +++++++- app/views/shared/_add_new_item_form.rhtml | 2 ++ app/views/todos/create_multiple.js.rjs | 14 +++++++++++--- features/shared_add_new_todo.feature | 18 +++++++++++++++++- features/step_definitions/todo_steps.rb | 19 +++++++++++++++++++ ...todo_tag_steps.rb.rb => todo_tag_steps.rb} | 0 6 files changed, 56 insertions(+), 5 deletions(-) rename features/step_definitions/{todo_tag_steps.rb.rb => todo_tag_steps.rb} (100%) diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 5750ea28..da351990 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -169,7 +169,13 @@ class TodosController < ApplicationController @projects = current_user.projects.find(:all) if @new_project_created @initial_context_name = params['default_context_name'] @initial_project_name = params['default_project_name'] - @default_tags = @todos[0].project.default_tags unless @todos[0].project.nil? + if @todos.size > 0 + @default_tags = @todos[0].project.default_tags unless @todos[0].project.nil? + else + @multiple_error = "You need to submit at least one next action" + @saved = false; + @default_tags = current_user.projects.find_by_name(@initial_project_name).default_tags unless @initial_project_name.blank? + end render :action => 'create_multiple' end format.xml do diff --git a/app/views/shared/_add_new_item_form.rhtml b/app/views/shared/_add_new_item_form.rhtml index 23a98dc0..0007b72b 100644 --- a/app/views/shared/_add_new_item_form.rhtml +++ b/app/views/shared/_add_new_item_form.rhtml @@ -78,6 +78,8 @@ :complete => "$('#todo_multi_new_action_submit').unblock()", :condition => "askIfNewContextProvided('multi_')") do -%> +
<%= error_messages_for("item", :object_name => 'action') %>
+ <%= text_area( "todo", "multiple_todos", "cols" => 29, "rows" => 6, "tabindex" => 2) %> diff --git a/app/views/todos/create_multiple.js.rjs b/app/views/todos/create_multiple.js.rjs index b1c310a7..46146a9c 100644 --- a/app/views/todos/create_multiple.js.rjs +++ b/app/views/todos/create_multiple.js.rjs @@ -1,5 +1,5 @@ if @saved - page.hide 'status' + page.hide 'multiple_status' status_message = 'Added new next action' status_message += 's' if @todos.size > 1 @@ -37,6 +37,14 @@ if @saved # make sure the behavior of the new/updated todo is enabled page << "enable_rich_interaction();" else - page.show 'status' - page.replace_html 'status', "#{error_messages_for('todo', :object_name => 'action')}" + page.show 'multiple_status' + # add error about missing todo description that is not available in @todos + @multiple_error = content_tag(:div, content_tag(:p, @multiple_error), {:class => 'errorExplanation', :id => 'errorExplanation'}) unless @multiple_error.blank? + error_messages = @multiple_error || "" + # add errors of individual @todos + @todos.each do |todo| + @todo_i = todo + error_messages += error_messages_for('todo_i', :object_name => 'action') + end + page.replace_html 'multiple_status', error_messages end \ No newline at end of file diff --git a/features/shared_add_new_todo.feature b/features/shared_add_new_todo.feature index 9955e63e..2ad79377 100644 --- a/features/shared_add_new_todo.feature +++ b/features/shared_add_new_todo.feature @@ -118,4 +118,20 @@ Feature: Add new next action from every page | go to | tickler page | not see| 0 | 3 | | visit | project page for "test project"| see | 3 | 3 | | visit | context page for "test context"| see | 2 | 3 | - | visit | tag page for "starred" | not see| 0 | 3 | \ No newline at end of file + | visit | tag page for "starred" | not see| 0 | 3 | + + @selenium + Scenario: I need to fill in at least one description and a context + When I go to the home page + And I follow "Add multiple next actions" + And I submit the new multiple actions form with "", "", "", "" + Then I should see "You need to submit at least one next action" + When I submit the new multiple actions form with "one", "", "", "" + Then I should see "Context can't be blank" + When I fill the multiple actions form with "", "a project", "a context", "tag" + And I submit the new multiple actions form with + """ + + + """ + Then I should see "You need to submit at least one next action" \ No newline at end of file diff --git a/features/step_definitions/todo_steps.rb b/features/step_definitions/todo_steps.rb index e1b183f7..d5c8020c 100644 --- a/features/step_definitions/todo_steps.rb +++ b/features/step_definitions/todo_steps.rb @@ -76,6 +76,25 @@ When /^I submit multiple actions with using$/ do |multiple_actions| selenium.click("xpath=//form[@id='todo-form-multi-new-action']//button[@id='todo_multi_new_action_submit']", :wait_for => :ajax, :javascript_framework => :jquery) end +When /^I fill the multiple actions form with "([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"$/ do |descriptions, project_name, context_name, tags| + fill_in "todo[multiple_todos]", :with => descriptions + fill_in "multi_todo_project_name", :with => project_name + fill_in "multi_todo_context_name", :with => context_name + fill_in "multi_tag_list", :with => tags +end + +When /^I submit the new multiple actions form with "([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"$/ do |descriptions, project_name, context_name, tags| + When "I fill the multiple actions form with \"#{descriptions}\", \"#{project_name}\", \"#{context_name}\", \"#{tags}\"" + selenium.click("xpath=//form[@id='todo-form-multi-new-action']//button[@id='todo_multi_new_action_submit']", :wait_for => :ajax, :javascript_framework => :jquery) +end + +When /^I submit the new multiple actions form with$/ do |multi_line_descriptions| + fill_in "todo[multiple_todos]", :with => multi_line_descriptions + selenium.click("xpath=//form[@id='todo-form-multi-new-action']//button[@id='todo_multi_new_action_submit']", :wait_for => :ajax, :javascript_framework => :jquery) +end + + + Then /^the dependencies of "(.*)" should include "(.*)"$/ do |child_name, parent_name| parent = @current_user.todos.find_by_description(parent_name) parent.should_not be_nil diff --git a/features/step_definitions/todo_tag_steps.rb.rb b/features/step_definitions/todo_tag_steps.rb similarity index 100% rename from features/step_definitions/todo_tag_steps.rb.rb rename to features/step_definitions/todo_tag_steps.rb From 9c82e9c974ddad86e5ae03783166ba1ee72d64d4 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Fri, 16 Jul 2010 14:41:04 +0200 Subject: [PATCH 44/64] DRY things up a bit --- features/step_definitions/todo_steps.rb | 10 ++++------ features/support/world.rb | 12 ++++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 features/support/world.rb diff --git a/features/step_definitions/todo_steps.rb b/features/step_definitions/todo_steps.rb index d5c8020c..b36a15f8 100644 --- a/features/step_definitions/todo_steps.rb +++ b/features/step_definitions/todo_steps.rb @@ -68,12 +68,12 @@ end When /^I submit a new action with description "([^"]*)"$/ do |description| fill_in "todo[description]", :with => description - selenium.click("xpath=//form[@id='todo-form-new-action']//button[@id='todo_new_action_submit']", :wait_for => :ajax, :javascript_framework => :jquery) + submit_next_action_form end When /^I submit multiple actions with using$/ do |multiple_actions| fill_in "todo[multiple_todos]", :with => multiple_actions - selenium.click("xpath=//form[@id='todo-form-multi-new-action']//button[@id='todo_multi_new_action_submit']", :wait_for => :ajax, :javascript_framework => :jquery) + submit_multiple_next_action_form end When /^I fill the multiple actions form with "([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"$/ do |descriptions, project_name, context_name, tags| @@ -85,16 +85,14 @@ end When /^I submit the new multiple actions form with "([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"$/ do |descriptions, project_name, context_name, tags| When "I fill the multiple actions form with \"#{descriptions}\", \"#{project_name}\", \"#{context_name}\", \"#{tags}\"" - selenium.click("xpath=//form[@id='todo-form-multi-new-action']//button[@id='todo_multi_new_action_submit']", :wait_for => :ajax, :javascript_framework => :jquery) + submit_multiple_next_action_form end When /^I submit the new multiple actions form with$/ do |multi_line_descriptions| fill_in "todo[multiple_todos]", :with => multi_line_descriptions - selenium.click("xpath=//form[@id='todo-form-multi-new-action']//button[@id='todo_multi_new_action_submit']", :wait_for => :ajax, :javascript_framework => :jquery) + submit_multiple_next_action_form end - - Then /^the dependencies of "(.*)" should include "(.*)"$/ do |child_name, parent_name| parent = @current_user.todos.find_by_description(parent_name) parent.should_not be_nil diff --git a/features/support/world.rb b/features/support/world.rb new file mode 100644 index 00000000..7bdf463a --- /dev/null +++ b/features/support/world.rb @@ -0,0 +1,12 @@ +module TracksStepHelper + def submit_multiple_next_action_form + selenium.click("xpath=//form[@id='todo-form-multi-new-action']//button[@id='todo_multi_new_action_submit']", :wait_for => :ajax, :javascript_framework => :jquery) + end + + def submit_next_action_form + selenium.click("xpath=//form[@id='todo-form-new-action']//button[@id='todo_new_action_submit']", :wait_for => :ajax, :javascript_framework => :jquery) + end + +end + +World(TracksStepHelper) \ No newline at end of file From 9a243b015a9a63c839cd1f409f095ed0b8570c9c Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Wed, 28 Jul 2010 16:27:52 +0200 Subject: [PATCH 45/64] creating todos using xml/rest was broken. This fixes it --- app/controllers/todos_controller.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index da351990..425ec678 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -50,7 +50,8 @@ class TodosController < ApplicationController @source_view = params['_source_view'] || 'todo' @tag_name = params['_tag_name'] - unless params[:todo][:multiple_todos].nil? + is_multiple = params[:todo] && params[:todo][:multiple_todos] && !params[:todo][:multiple_todos].nil? + if is_multiple create_multiple else p = TodoCreateParamsHelper.new(params, prefs) From 3d75cd2457813f9ead43ebaa853ae0488705d0f8 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Thu, 29 Jul 2010 16:37:22 +0200 Subject: [PATCH 46/64] Fix #1045. The tests broke because of this fix http://github.com/bsag/tracks/commit/cfc6d117b815c43eccdc65168e0370c23a658adc. This exposed a new corner case that I fixed and created a test for. Also a small refactoring. --- app/models/recurring_todo.rb | 34 +++++++++---------------------- test/fixtures/recurring_todos.yml | 24 +++++++++++++--------- test/unit/recurring_todo_test.rb | 20 ++++++++++++++++-- 3 files changed, 42 insertions(+), 36 deletions(-) diff --git a/app/models/recurring_todo.rb b/app/models/recurring_todo.rb index 4a916c6d..64a95889 100644 --- a/app/models/recurring_todo.rb +++ b/app/models/recurring_todo.rb @@ -511,30 +511,12 @@ class RecurringTodo < ActiveRecord::Base # # assumes self.recurring_period == 'daily' - # determine start - if previous.nil? - start = self.start_from.nil? ? Time.zone.now : self.start_from - else - # use the next day - start = previous + 1.day - - unless self.start_from.nil? - # check if the start_from date is later than previous. If so, use - # start_from as start to search for next date - start = self.start_from if self.start_from > previous - end - end + start = determine_start(previous, 1.day) if self.only_work_days - if start.wday() >= 1 && start.wday() <= 5 # 1=monday; 5=friday - return start - else - if start.wday() == 0 # sunday - return start + 1.day - else # saturday - return start + 2.day - end - end + return start + 2.day if start.wday() == 6 # saturday + return start + 1.day if start.wday() == 0 # sunday + return start else # every nth day; n = every_other1 # if there was no previous todo, do not add n: the first todo starts on # today or on start_from @@ -742,11 +724,15 @@ class RecurringTodo < ActiveRecord::Base protected - def determine_start(previous) + def determine_start(previous, offset=0.day) + # offset needs to be 1.day for daily patterns + if previous.nil? start = self.start_from.nil? ? Time.zone.now : self.start_from + # skip to present + start = Time.zone.now if Time.zone.now > start else - start = previous + start = previous + offset unless self.start_from.nil? # check if the start_from date is later than previous. If so, use diff --git a/test/fixtures/recurring_todos.yml b/test/fixtures/recurring_todos.yml index 9597d674..a9bfb18c 100644 --- a/test/fixtures/recurring_todos.yml +++ b/test/fixtures/recurring_todos.yml @@ -1,22 +1,26 @@ - +<% def today - Time.zone.now.beginning_of_day.to_s(:db) + Time.zone.now.beginning_of_day.to_s(:db) end def next_week - 1.week.from_now.beginning_of_day.to_s(:db) + 1.week.from_now.beginning_of_day.to_s(:db) end def last_week - 1.week.ago.beginning_of_day.to_s(:db) + 1.week.ago.beginning_of_day.to_s(:db) end def two_weeks_ago - 2.weeks.ago.beginning_of_day.to_s(:db) + 2.weeks.ago.beginning_of_day.to_s(:db) end def two_weeks_hence - 2.weeks.from_now.beginning_of_day.to_s(:db) + 2.weeks.from_now.beginning_of_day.to_s(:db) +end + +def way_back + Time.zone.local(2008,1,1) end %> @@ -29,7 +33,7 @@ call_bill_gates_every_day: description: Call Bill Gates every day notes: ~ state: active - start_from: <%= last_week %> + start_from: <%= way_back %> ends_on: no_end_date end_date: ~ number_of_occurences: ~ @@ -83,7 +87,7 @@ call_bill_gates_every_week: description: Call Bill Gates every week notes: ~ state: active - start_from: <%= today %> + start_from: <%= way_back %> ends_on: no_end_date end_date: ~ number_of_occurences: ~ @@ -110,7 +114,7 @@ check_with_bill_every_last_friday_of_month: description: Check with Bill every last friday of the month notes: ~ state: active - start_from: <%= today %> + start_from: <%= way_back %> ends_on: no_end_date end_date: ~ number_of_occurences: ~ @@ -137,7 +141,7 @@ birthday_reinier: description: Congratulate Reinier on his birthday notes: ~ state: active - start_from: <%= today %> + start_from: <%= way_back %> ends_on: no_end_date end_date: ~ number_of_occurences: ~ diff --git a/test/unit/recurring_todo_test.rb b/test/unit/recurring_todo_test.rb index 8ae3f6da..e74b5361 100644 --- a/test/unit/recurring_todo_test.rb +++ b/test/unit/recurring_todo_test.rb @@ -207,11 +207,27 @@ class RecurringTodoTest < ActiveSupport::TestCase # same month, after second wednesday due_date = @yearly.get_due_date(Time.zone.local(2008,6,12)) # june 7th assert_equal Time.zone.local(2009,6,10), due_date # june 10th - - # test handling of nil + end + + def test_next_todo_without_previous_todo + # test handling of nil as previous + # + # start_from is way_back due_date1 = @yearly.get_due_date(nil) due_date2 = @yearly.get_due_date(Time.now.utc + 1.day) assert_equal due_date1, due_date2 + + # start_from is in the future + @yearly.start_from = Time.now.utc + 1.week + due_date1 = @yearly.get_due_date(nil) + due_date2 = @yearly.get_due_date(Time.now.utc + 1.day) + assert_equal due_date1, due_date2 + + # start_from is nil + @yearly.start_from = 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 end def test_last_sunday_of_march From c9be43b2c8134589c5451ba61ec82283aabe522d Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Thu, 29 Jul 2010 18:06:30 +0200 Subject: [PATCH 47/64] add tests for #886. --- app/views/contexts/_context_state_group.rhtml | 2 +- features/contexts_manage.feature | 20 +++++++++++++++ features/step_definitions/context_steps.rb | 25 ++++++++++++++++++- features/support/world.rb | 4 +++ spec/factories/factories.rb | 6 +++++ 5 files changed, 55 insertions(+), 2 deletions(-) diff --git a/app/views/contexts/_context_state_group.rhtml b/app/views/contexts/_context_state_group.rhtml index 835d2f44..58e51cf7 100644 --- a/app/views/contexts/_context_state_group.rhtml +++ b/app/views/contexts/_context_state_group.rhtml @@ -1,4 +1,4 @@ -
+

<%= context_state_group.length %><%= state.titlecase %> Contexts

Currently there are no <%= state %> contexts

diff --git a/features/contexts_manage.feature b/features/contexts_manage.feature index 57002fcf..64cd4ed8 100644 --- a/features/contexts_manage.feature +++ b/features/contexts_manage.feature @@ -48,3 +48,23 @@ Feature: Manage contexts And he should see that a context named "@laptop" is not present And he should see that a context named "@ipad" is present And the badge should show 1 + + @selenium, @wip + Scenario: Add new context + Given I have the following contexts + | name | hide | + | @ipad | true | + | @home | false | + When I go to the contexts page + And I add a new context "@phone" + Then I should see the context "@phone" under "active" + + @selenium, @wip + Scenario: Add new hidden context + Given I have the following contexts + | name | hide | + | @ipad | true | + | @home | false | + When I go to the contexts page + And I add a new hidden context "@hidden" + Then I should see the context "@hidden" under "hidden" diff --git a/features/step_definitions/context_steps.rb b/features/step_definitions/context_steps.rb index 532a9f0d..671b6a70 100644 --- a/features/step_definitions/context_steps.rb +++ b/features/step_definitions/context_steps.rb @@ -20,6 +20,13 @@ Given /^I have a context "([^\"]*)" with (.*) actions$/ do |context_name, number end end +Given /^I have the following contexts$/ do |table| + Context.delete_all + table.hashes.each do |hash| + context = Factory(:context, hash) + end +end + When /^I visit the context page for "([^\"]*)"$/ do |context_name| context = @current_user.contexts.find_by_name(context_name) context.should_not be_nil @@ -61,6 +68,17 @@ When /^I edit the context to rename it to "([^\"]*)"$/ do |new_name| end end +When /^I add a new context "([^"]*)"$/ do |context_name| + fill_in "context[name]", :with => context_name + submit_new_context_form +end + +When /^I add a new hidden context "([^"]*)"$/ do |context_name| + fill_in "context[name]", :with => context_name + check "context_hide" + submit_new_context_form +end + Then /^I should see the context name is "([^\"]*)"$/ do |context_name| Then "I should see \"#{context_name}\"" end @@ -71,4 +89,9 @@ end Then /^he should see that a context named "([^\"]*)" is not present$/ do |context_name| Then "I should not see \"#{context_name} (\"" -end \ No newline at end of file +end + +Then /^I should see the context "([^"]*)" under "([^"]*)"$/ do |context_name, state| + context = Context.find_by_name(context_name) + response.should have_xpath("//div[@id='list-contexts-#{state}']//div[@id='context_#{context.id}']") +end diff --git a/features/support/world.rb b/features/support/world.rb index 7bdf463a..20870a4a 100644 --- a/features/support/world.rb +++ b/features/support/world.rb @@ -7,6 +7,10 @@ module TracksStepHelper selenium.click("xpath=//form[@id='todo-form-new-action']//button[@id='todo_new_action_submit']", :wait_for => :ajax, :javascript_framework => :jquery) end + def submit_new_context_form + selenium.click("xpath=//form[@id='context-form']//button[@id='context_new_submit']", :wait_for => :ajax, :javascript_framework => :jquery) + end + end World(TracksStepHelper) \ No newline at end of file diff --git a/spec/factories/factories.rb b/spec/factories/factories.rb index fb344734..6a230605 100644 --- a/spec/factories/factories.rb +++ b/spec/factories/factories.rb @@ -3,4 +3,10 @@ Factory.define :user do |u| u.password "secret" u.password_confirmation { |user| user.password } u.is_admin false +end + +Factory.define :context do |c| + c.sequence(:name) { |n| "testcontext#{n}" } + c.hide false + c.created_at Time.now.utc end \ No newline at end of file From bb23a4acba2fd6ee72ed8ac9945a1828fcd037f9 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Thu, 29 Jul 2010 18:08:41 +0200 Subject: [PATCH 48/64] forgot to cleanup the last patch --- app/views/contexts/_context_state_group.rhtml | 2 +- features/contexts_manage.feature | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/contexts/_context_state_group.rhtml b/app/views/contexts/_context_state_group.rhtml index 58e51cf7..835d2f44 100644 --- a/app/views/contexts/_context_state_group.rhtml +++ b/app/views/contexts/_context_state_group.rhtml @@ -1,4 +1,4 @@ -
+

<%= context_state_group.length %><%= state.titlecase %> Contexts

Currently there are no <%= state %> contexts

diff --git a/features/contexts_manage.feature b/features/contexts_manage.feature index 64cd4ed8..89c7ff50 100644 --- a/features/contexts_manage.feature +++ b/features/contexts_manage.feature @@ -49,7 +49,7 @@ Feature: Manage contexts And he should see that a context named "@ipad" is present And the badge should show 1 - @selenium, @wip + @selenium Scenario: Add new context Given I have the following contexts | name | hide | @@ -59,7 +59,7 @@ Feature: Manage contexts And I add a new context "@phone" Then I should see the context "@phone" under "active" - @selenium, @wip + @selenium Scenario: Add new hidden context Given I have the following contexts | name | hide | From 65ecb7b01962a5337133971142c1ab6b61fa35eb Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Thu, 29 Jul 2010 21:41:36 +0200 Subject: [PATCH 49/64] migrated flashobject_helper to swf_fu because the first is not maintained anymore. Fixes #796 --- app/views/layouts/standard.html.erb | 2 +- app/views/stats/_chart.rhtml | 7 +- public/javascripts/flashobject.js | 8 - public/javascripts/swfobject.js | 4 + public/swfs/expressInstall.swf | Bin 0 -> 727 bytes public/{swf => swfs}/open-flash-chart.swf | Bin vendor/plugins/flashobject_helper/README | 35 ---- vendor/plugins/flashobject_helper/init.rb | 4 - vendor/plugins/flashobject_helper/install.rb | 5 - .../javascripts/flashobject.js | 8 - .../lib/flashobject_view_helper.rb | 96 --------- 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 | 91 +++++++++ vendor/plugins/swf_fu/Rakefile | 22 ++ .../swf_fu/assets/javascripts/swfobject.js | 4 + .../swf_fu/assets/swfs/expressInstall.swf | Bin 0 -> 727 bytes vendor/plugins/swf_fu/init.rb | 10 + vendor/plugins/swf_fu/install.rb | 24 +++ .../helpers/asset_tag_helper/swf_asset.rb | 61 ++++++ .../lib/action_view/helpers/swf_fu_helper.rb | 188 ++++++++++++++++++ vendor/plugins/swf_fu/test/results.rb | 42 ++++ vendor/plugins/swf_fu/test/swf_fu_test.rb | 152 ++++++++++++++ vendor/plugins/swf_fu/test/test_helper.rb | 20 ++ vendor/plugins/swf_fu/uninstall.rb | 6 + 26 files changed, 737 insertions(+), 158 deletions(-) delete mode 100644 public/javascripts/flashobject.js create mode 100644 public/javascripts/swfobject.js create mode 100755 public/swfs/expressInstall.swf rename public/{swf => swfs}/open-flash-chart.swf (100%) mode change 100755 => 100644 delete mode 100644 vendor/plugins/flashobject_helper/README delete mode 100644 vendor/plugins/flashobject_helper/init.rb delete mode 100644 vendor/plugins/flashobject_helper/install.rb delete mode 100644 vendor/plugins/flashobject_helper/javascripts/flashobject.js delete mode 100644 vendor/plugins/flashobject_helper/lib/flashobject_view_helper.rb create mode 100644 vendor/plugins/swf_fu/CHANGELOG.rdoc create mode 100644 vendor/plugins/swf_fu/FLASH_OBJECT.rdoc create mode 100644 vendor/plugins/swf_fu/LICENSE create mode 100644 vendor/plugins/swf_fu/README.rdoc create mode 100644 vendor/plugins/swf_fu/Rakefile create mode 100644 vendor/plugins/swf_fu/assets/javascripts/swfobject.js create mode 100755 vendor/plugins/swf_fu/assets/swfs/expressInstall.swf create mode 100644 vendor/plugins/swf_fu/init.rb create mode 100644 vendor/plugins/swf_fu/install.rb create mode 100644 vendor/plugins/swf_fu/lib/action_view/helpers/asset_tag_helper/swf_asset.rb create mode 100644 vendor/plugins/swf_fu/lib/action_view/helpers/swf_fu_helper.rb create mode 100644 vendor/plugins/swf_fu/test/results.rb create mode 100644 vendor/plugins/swf_fu/test/swf_fu_test.rb create mode 100644 vendor/plugins/swf_fu/test/test_helper.rb create mode 100644 vendor/plugins/swf_fu/uninstall.rb diff --git a/app/views/layouts/standard.html.erb b/app/views/layouts/standard.html.erb index b7a9c5a3..7154ba43 100644 --- a/app/views/layouts/standard.html.erb +++ b/app/views/layouts/standard.html.erb @@ -9,7 +9,7 @@ 'jquery.blockUI','jquery.jeditable','jquery.autocomplete', 'jquery.truncator', :cache => 'jquery-all' %> <%= javascript_include_tag 'hoverIntent','superfish','application', - 'accesskey-hints','niftycube','flashobject', :cache => 'tracks' %> + 'accesskey-hints','niftycube','swfobject', :cache => 'tracks' %> <%= 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 %> diff --git a/app/views/stats/_chart.rhtml b/app/views/stats/_chart.rhtml index 30d1b755..a627a69f 100755 --- a/app/views/stats/_chart.rhtml +++ b/app/views/stats/_chart.rhtml @@ -1 +1,6 @@ -<%= flashobject_tag "open-flash-chart.swf", :query_params => { 'width' => width, 'height' => height, 'data' => data}, :size => "#{width}x#{height}", :parameters => { 'allowScriptAccess' => 'sameDomain', 'wmode' => 'transparent'}, :class_name => 'open-flash-chart', :flash_id => 'chart' %> \ No newline at end of file +<% @swf_count ||= 0 -%> +
<%= swf_tag "open-flash-chart.swf", + :flashvars => { 'width' => width, 'height' => height, 'data' => data}, + :parameters => { 'allowScriptAccess' => 'sameDomain', 'wmode' => 'transparent'}, + :div_id => "chart_#{@swf_count+=1}", + :size => "#{width}x#{height}" %>
\ No newline at end of file diff --git a/public/javascripts/flashobject.js b/public/javascripts/flashobject.js deleted file mode 100644 index e7edd42c..00000000 --- a/public/javascripts/flashobject.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * SWFObject v1.5: Flash Player detection and embed - http://blog.deconcept.com/swfobject/ - * - * SWFObject is (c) 2007 Geoff Stearns and is released under the MIT License: - * http://www.opensource.org/licenses/mit-license.php - * - */ -if(typeof deconcept=="undefined"){var deconcept=new Object();}if(typeof deconcept.util=="undefined"){deconcept.util=new Object();}if(typeof deconcept.SWFObjectUtil=="undefined"){deconcept.SWFObjectUtil=new Object();}deconcept.SWFObject=function(_1,id,w,h,_5,c,_7,_8,_9,_a){if(!document.getElementById){return;}this.DETECT_KEY=_a?_a:"detectflash";this.skipDetect=deconcept.util.getRequestParameter(this.DETECT_KEY);this.params=new Object();this.variables=new Object();this.attributes=new Array();if(_1){this.setAttribute("swf",_1);}if(id){this.setAttribute("id",id);}if(w){this.setAttribute("width",w);}if(h){this.setAttribute("height",h);}if(_5){this.setAttribute("version",new deconcept.PlayerVersion(_5.toString().split(".")));}this.installedVer=deconcept.SWFObjectUtil.getPlayerVersion();if(!window.opera&&document.all&&this.installedVer.major>7){deconcept.SWFObject.doPrepUnload=true;}if(c){this.addParam("bgcolor",c);}var q=_7?_7:"high";this.addParam("quality",q);this.setAttribute("useExpressInstall",false);this.setAttribute("doExpressInstall",false);var _c=(_8)?_8:window.location;this.setAttribute("xiRedirectUrl",_c);this.setAttribute("redirectUrl","");if(_9){this.setAttribute("redirectUrl",_9);}};deconcept.SWFObject.prototype={useExpressInstall:function(_d){this.xiSWFPath=!_d?"expressinstall.swf":_d;this.setAttribute("useExpressInstall",true);},setAttribute:function(_e,_f){this.attributes[_e]=_f;},getAttribute:function(_10){return this.attributes[_10];},addParam:function(_11,_12){this.params[_11]=_12;},getParams:function(){return this.params;},addVariable:function(_13,_14){this.variables[_13]=_14;},getVariable:function(_15){return this.variables[_15];},getVariables:function(){return this.variables;},getVariablePairs:function(){var _16=new Array();var key;var _18=this.getVariables();for(key in _18){_16[_16.length]=key+"="+_18[key];}return _16;},getSWFHTML:function(){var _19="";if(navigator.plugins&&navigator.mimeTypes&&navigator.mimeTypes.length){if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","PlugIn");this.setAttribute("swf",this.xiSWFPath);}_19="0){_19+="flashvars=\""+_1c+"\"";}_19+="/>";}else{if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","ActiveX");this.setAttribute("swf",this.xiSWFPath);}_19="";_19+="";var _1d=this.getParams();for(var key in _1d){_19+="";}var _1f=this.getVariablePairs().join("&");if(_1f.length>0){_19+="";}_19+="";}return _19;},write:function(_20){if(this.getAttribute("useExpressInstall")){var _21=new deconcept.PlayerVersion([6,0,65]);if(this.installedVer.versionIsValid(_21)&&!this.installedVer.versionIsValid(this.getAttribute("version"))){this.setAttribute("doExpressInstall",true);this.addVariable("MMredirectURL",escape(this.getAttribute("xiRedirectUrl")));document.title=document.title.slice(0,47)+" - Flash Player Installation";this.addVariable("MMdoctitle",document.title);}}if(this.skipDetect||this.getAttribute("doExpressInstall")||this.installedVer.versionIsValid(this.getAttribute("version"))){var n=(typeof _20=="string")?document.getElementById(_20):_20;n.innerHTML=this.getSWFHTML();return true;}else{if(this.getAttribute("redirectUrl")!=""){document.location.replace(this.getAttribute("redirectUrl"));}}return false;}};deconcept.SWFObjectUtil.getPlayerVersion=function(){var _23=new deconcept.PlayerVersion([0,0,0]);if(navigator.plugins&&navigator.mimeTypes.length){var x=navigator.plugins["Shockwave Flash"];if(x&&x.description){_23=new deconcept.PlayerVersion(x.description.replace(/([a-zA-Z]|\s)+/,"").replace(/(\s+r|\s+b[0-9]+)/,".").split("."));}}else{if(navigator.userAgent&&navigator.userAgent.indexOf("Windows CE")>=0){var axo=1;var _26=3;while(axo){try{_26++;axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+_26);_23=new deconcept.PlayerVersion([_26,0,0]);}catch(e){axo=null;}}}else{try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");}catch(e){try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");_23=new deconcept.PlayerVersion([6,0,21]);axo.AllowScriptAccess="always";}catch(e){if(_23.major==6){return _23;}}try{axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");}catch(e){}}if(axo!=null){_23=new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));}}}return _23;};deconcept.PlayerVersion=function(_29){this.major=_29[0]!=null?parseInt(_29[0]):0;this.minor=_29[1]!=null?parseInt(_29[1]):0;this.rev=_29[2]!=null?parseInt(_29[2]):0;};deconcept.PlayerVersion.prototype.versionIsValid=function(fv){if(this.majorfv.major){return true;}if(this.minorfv.minor){return true;}if(this.rev=0;i--){_2f[i].style.display="none";for(var x in _2f[i]){if(typeof _2f[i][x]=="function"){_2f[i][x]=function(){};}}}};if(deconcept.SWFObject.doPrepUnload){if(!deconcept.unloadSet){deconcept.SWFObjectUtil.prepUnload=function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){};window.attachEvent("onunload",deconcept.SWFObjectUtil.cleanupSWFs);};window.attachEvent("onbeforeunload",deconcept.SWFObjectUtil.prepUnload);deconcept.unloadSet=true;}}if(!document.getElementById&&document.all){document.getElementById=function(id){return document.all[id];};}var getQueryParamValue=deconcept.util.getRequestParameter;var FlashObject=deconcept.SWFObject;var SWFObject=deconcept.SWFObject; \ No newline at end of file diff --git a/public/javascripts/swfobject.js b/public/javascripts/swfobject.js new file mode 100644 index 00000000..8eafe9dd --- /dev/null +++ b/public/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 - -or if you only need the flashobject add this: - -<%= javascript_include_tag "flashobject" %> - -The is very simple for add a Flash in your page add this: - -<%= flashobject_tag "/source/of/your/flash.swf" %> - -It's simple. - -You can add some options if you want: - -- div_id: the HTML +id+ of the +div+ element that is used to contain the Flash object; default "flashcontent" -- flash_id: the +id+ of the Flash object itself. -- background_color: the background color of the Flash object; default white -- flash_version: the version of the Flash player that is required; default "7" -- size: the size of the Flash object, in the form "100x100". Defaults to "100%x100%" -- variables: a Hash of initialization variables that are passed to the object; default {:lzproxied => false} -- parameters: a Hash of parameters that configure the display of the object; default {:scale => 'noscale'} -- fallback_html: HTML text that is displayed when the Flash player is not available. - -Example: -<%= flashobject_tag "/source/of/your/flash.swf", :size => "350x320" %> - - -Vist my website: http://blog.lipsiasoft.com \ No newline at end of file diff --git a/vendor/plugins/flashobject_helper/init.rb b/vendor/plugins/flashobject_helper/init.rb deleted file mode 100644 index 68711685..00000000 --- a/vendor/plugins/flashobject_helper/init.rb +++ /dev/null @@ -1,4 +0,0 @@ -# Author:: Davide D'Agostino Aka DAddYE -# WebSite:: http://www.lipsiasoft.com - -require 'flashobject_view_helper' \ No newline at end of file diff --git a/vendor/plugins/flashobject_helper/install.rb b/vendor/plugins/flashobject_helper/install.rb deleted file mode 100644 index 3771c200..00000000 --- a/vendor/plugins/flashobject_helper/install.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'fileutils' - -flashobject = File.dirname(__FILE__) + '/../../../public/javascripts/flashobject.js' -FileUtils.cp File.dirname(__FILE__) + '/javascripts/flashobject.js', flashobject unless File.exist?(flashobject) -puts IO.read(File.join(File.dirname(__FILE__), 'README')) \ No newline at end of file diff --git a/vendor/plugins/flashobject_helper/javascripts/flashobject.js b/vendor/plugins/flashobject_helper/javascripts/flashobject.js deleted file mode 100644 index e7edd42c..00000000 --- a/vendor/plugins/flashobject_helper/javascripts/flashobject.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * SWFObject v1.5: Flash Player detection and embed - http://blog.deconcept.com/swfobject/ - * - * SWFObject is (c) 2007 Geoff Stearns and is released under the MIT License: - * http://www.opensource.org/licenses/mit-license.php - * - */ -if(typeof deconcept=="undefined"){var deconcept=new Object();}if(typeof deconcept.util=="undefined"){deconcept.util=new Object();}if(typeof deconcept.SWFObjectUtil=="undefined"){deconcept.SWFObjectUtil=new Object();}deconcept.SWFObject=function(_1,id,w,h,_5,c,_7,_8,_9,_a){if(!document.getElementById){return;}this.DETECT_KEY=_a?_a:"detectflash";this.skipDetect=deconcept.util.getRequestParameter(this.DETECT_KEY);this.params=new Object();this.variables=new Object();this.attributes=new Array();if(_1){this.setAttribute("swf",_1);}if(id){this.setAttribute("id",id);}if(w){this.setAttribute("width",w);}if(h){this.setAttribute("height",h);}if(_5){this.setAttribute("version",new deconcept.PlayerVersion(_5.toString().split(".")));}this.installedVer=deconcept.SWFObjectUtil.getPlayerVersion();if(!window.opera&&document.all&&this.installedVer.major>7){deconcept.SWFObject.doPrepUnload=true;}if(c){this.addParam("bgcolor",c);}var q=_7?_7:"high";this.addParam("quality",q);this.setAttribute("useExpressInstall",false);this.setAttribute("doExpressInstall",false);var _c=(_8)?_8:window.location;this.setAttribute("xiRedirectUrl",_c);this.setAttribute("redirectUrl","");if(_9){this.setAttribute("redirectUrl",_9);}};deconcept.SWFObject.prototype={useExpressInstall:function(_d){this.xiSWFPath=!_d?"expressinstall.swf":_d;this.setAttribute("useExpressInstall",true);},setAttribute:function(_e,_f){this.attributes[_e]=_f;},getAttribute:function(_10){return this.attributes[_10];},addParam:function(_11,_12){this.params[_11]=_12;},getParams:function(){return this.params;},addVariable:function(_13,_14){this.variables[_13]=_14;},getVariable:function(_15){return this.variables[_15];},getVariables:function(){return this.variables;},getVariablePairs:function(){var _16=new Array();var key;var _18=this.getVariables();for(key in _18){_16[_16.length]=key+"="+_18[key];}return _16;},getSWFHTML:function(){var _19="";if(navigator.plugins&&navigator.mimeTypes&&navigator.mimeTypes.length){if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","PlugIn");this.setAttribute("swf",this.xiSWFPath);}_19="0){_19+="flashvars=\""+_1c+"\"";}_19+="/>";}else{if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","ActiveX");this.setAttribute("swf",this.xiSWFPath);}_19="";_19+="";var _1d=this.getParams();for(var key in _1d){_19+="";}var _1f=this.getVariablePairs().join("&");if(_1f.length>0){_19+="";}_19+="";}return _19;},write:function(_20){if(this.getAttribute("useExpressInstall")){var _21=new deconcept.PlayerVersion([6,0,65]);if(this.installedVer.versionIsValid(_21)&&!this.installedVer.versionIsValid(this.getAttribute("version"))){this.setAttribute("doExpressInstall",true);this.addVariable("MMredirectURL",escape(this.getAttribute("xiRedirectUrl")));document.title=document.title.slice(0,47)+" - Flash Player Installation";this.addVariable("MMdoctitle",document.title);}}if(this.skipDetect||this.getAttribute("doExpressInstall")||this.installedVer.versionIsValid(this.getAttribute("version"))){var n=(typeof _20=="string")?document.getElementById(_20):_20;n.innerHTML=this.getSWFHTML();return true;}else{if(this.getAttribute("redirectUrl")!=""){document.location.replace(this.getAttribute("redirectUrl"));}}return false;}};deconcept.SWFObjectUtil.getPlayerVersion=function(){var _23=new deconcept.PlayerVersion([0,0,0]);if(navigator.plugins&&navigator.mimeTypes.length){var x=navigator.plugins["Shockwave Flash"];if(x&&x.description){_23=new deconcept.PlayerVersion(x.description.replace(/([a-zA-Z]|\s)+/,"").replace(/(\s+r|\s+b[0-9]+)/,".").split("."));}}else{if(navigator.userAgent&&navigator.userAgent.indexOf("Windows CE")>=0){var axo=1;var _26=3;while(axo){try{_26++;axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+_26);_23=new deconcept.PlayerVersion([_26,0,0]);}catch(e){axo=null;}}}else{try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");}catch(e){try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");_23=new deconcept.PlayerVersion([6,0,21]);axo.AllowScriptAccess="always";}catch(e){if(_23.major==6){return _23;}}try{axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");}catch(e){}}if(axo!=null){_23=new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));}}}return _23;};deconcept.PlayerVersion=function(_29){this.major=_29[0]!=null?parseInt(_29[0]):0;this.minor=_29[1]!=null?parseInt(_29[1]):0;this.rev=_29[2]!=null?parseInt(_29[2]):0;};deconcept.PlayerVersion.prototype.versionIsValid=function(fv){if(this.majorfv.major){return true;}if(this.minorfv.minor){return true;}if(this.rev=0;i--){_2f[i].style.display="none";for(var x in _2f[i]){if(typeof _2f[i][x]=="function"){_2f[i][x]=function(){};}}}};if(deconcept.SWFObject.doPrepUnload){if(!deconcept.unloadSet){deconcept.SWFObjectUtil.prepUnload=function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){};window.attachEvent("onunload",deconcept.SWFObjectUtil.cleanupSWFs);};window.attachEvent("onbeforeunload",deconcept.SWFObjectUtil.prepUnload);deconcept.unloadSet=true;}}if(!document.getElementById&&document.all){document.getElementById=function(id){return document.all[id];};}var getQueryParamValue=deconcept.util.getRequestParameter;var FlashObject=deconcept.SWFObject;var SWFObject=deconcept.SWFObject; \ No newline at end of file diff --git a/vendor/plugins/flashobject_helper/lib/flashobject_view_helper.rb b/vendor/plugins/flashobject_helper/lib/flashobject_view_helper.rb deleted file mode 100644 index 0fe38b2d..00000000 --- a/vendor/plugins/flashobject_helper/lib/flashobject_view_helper.rb +++ /dev/null @@ -1,96 +0,0 @@ -# Author:: Davide D'Agostino aka DAddYE -# WebSite:: http://www.lipsiasoft.com -require 'action_view' - -module ActionView #:nodoc: - module Helpers # :nodoc: - module FlashObjectHelper # :nodoc: - def self.included(base) - base.class_eval do - include InstanceMethods - end - end - module InstanceMethods - # Returns a set of tags that display a Flash object within an - # HTML page. - # - # Options: - # * :div_id - the HTML +id+ of the +div+ element that is used to contain the Flash object; default "flashcontent" - # * :flash_id - the +id+ of the Flash object itself. - # * :background_color - the background color of the Flash object; default white - # * :flash_version - the version of the Flash player that is required; default "7" - # * :size - the size of the Flash object, in the form "100x100". Defaults to "100%x100%" - # * :variables - a Hash of initialization variables that are passed to the object; default {:lzproxied => false} - # * :parameters - a Hash of parameters that configure the display of the object; default {:scale => 'noscale'} - # * :fallback_html - HTML text that is displayed when the Flash player is not available. - # - # The following options are for developers. They default to true in - # development mode, and false otherwise. - # * :check_for_javascript_include - if true, the return value will cause the browser to display a diagnostic message if the FlashObject JavaScript was not included. - # * :verify_file_exists - if true, the return value will cause the browser to display a diagnostic message if the Flash object does not exist. - # - # (This method is called flashobject_tag instead of flashobject_tag - # because it returns a *sequence* of HTML tags: a +div+, followed by - # a +script+.) - def flashobject_tag source, options={} - source = flash_path(source) - query_params = '?' + options[:query_params].map{ |key, value| "#{key}=#{value}" }.join('&') if options[:query_params] - div_id = options[:div_id] || "flashcontent_#{rand(1_100)}" - flash_id = options[:flash_id] || File.basename(source, '.swf') + "_#{rand(1_100)}" - width, height = (options[:size]||'100%x100%').scan(/^(\d*%?)x(\d*%?)$/).first - background_color = options[:background_color] || '#ffffff' - flash_version = options[:flash_version] || 7 - class_name = options[:class_name] || 'flash' - variables = options.fetch(:variables, {}) - parameters = options.fetch(:parameters, {:scale => 'noscale'}) - fallback_html = options[:fallback_html] || %q{

Requires the Flash plugin. If the plugin is already installed, click here.

} - if options.fetch(:check_for_javascript_include, ENV['RAILS_ENV'] == 'development') - check_for_javascript ="if (typeof FlashObject == 'undefined') document.getElementById('#{div_id}').innerHTML = 'Warning: FlashObject is undefined. Did you forget to execute rake update_javascripts, or to include <%= javascript_include_tag :defaults %> in your view file?';" - end - return <<-"EOF" -
- #{fallback_html} -
- -EOF - end - - # Computes the path to a flash asset in the public swf directory. - # If the +source+ filename has no extension, .swf will be appended. - # Full paths from the document root will be passed through. - # - # flash_path "movie" # => /swf/movie.swf - # flash_path "dir/movie.swf" # => /swf/dir/movie.swf - # flash_path "/dir/movie" # => /dir/movie.swf - def flash_path(source) - #BROKEN IN RAILS 2.2 -- code below hacked in pending a refresh of this plugin or change to another --luke@lukemelia.com - #compute_public_path(source, 'swf', 'swf', false) - dir = "/swf/" - if source !~ %r{^/} - source = "#{dir}#{source}" - end - - relative_url_root = ActionController::Base.relative_url_root - if source !~ %r{^#{relative_url_root}/} - source = "#{relative_url_root}#{source}" - end - source - end - - end - end - end -end - -ActionView::Base.class_eval do - include ActionView::Helpers::FlashObjectHelper -end - -ActionView::Helpers::AssetTagHelper.register_javascript_include_default 'flashobject' \ No newline at end of file diff --git a/vendor/plugins/swf_fu/CHANGELOG.rdoc b/vendor/plugins/swf_fu/CHANGELOG.rdoc new file mode 100644 index 00000000..7b99496e --- /dev/null +++ b/vendor/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/vendor/plugins/swf_fu/FLASH_OBJECT.rdoc b/vendor/plugins/swf_fu/FLASH_OBJECT.rdoc new file mode 100644 index 00000000..87a0e72f --- /dev/null +++ b/vendor/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/vendor/plugins/swf_fu/LICENSE b/vendor/plugins/swf_fu/LICENSE new file mode 100644 index 00000000..efd683ff --- /dev/null +++ b/vendor/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/vendor/plugins/swf_fu/README.rdoc b/vendor/plugins/swf_fu/README.rdoc new file mode 100644 index 00000000..3a7ad555 --- /dev/null +++ b/vendor/plugins/swf_fu/README.rdoc @@ -0,0 +1,91 @@ += +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] +* :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 new file mode 100644 index 00000000..9898dadb --- /dev/null +++ b/vendor/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/vendor/plugins/swf_fu/assets/javascripts/swfobject.js b/vendor/plugins/swf_fu/assets/javascripts/swfobject.js new file mode 100644 index 00000000..8eafe9dd --- /dev/null +++ b/vendor/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# zsActionView::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 new file mode 100644 index 00000000..ab59f9f3 --- /dev/null +++ b/vendor/plugins/swf_fu/lib/action_view/helpers/swf_fu_helper.rb @@ -0,0 +1,188 @@ +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[:div_id] ||= options[:id]+"_div" + 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 generate(&block) + if block_given? + @options[:alt] = @view.capture(&block) + if 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 + puts 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 \ No newline at end of file diff --git a/vendor/plugins/swf_fu/test/results.rb b/vendor/plugins/swf_fu/test/results.rb new file mode 100644 index 00000000..a7306b0d --- /dev/null +++ b/vendor/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/vendor/plugins/swf_fu/test/swf_fu_test.rb b/vendor/plugins/swf_fu/test/swf_fu_test.rb new file mode 100644 index 00000000..f017e29f --- /dev/null +++ b/vendor/plugins/swf_fu/test/swf_fu_test.rb @@ -0,0 +1,152 @@ +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 "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 new file mode 100644 index 00000000..58d113f8 --- /dev/null +++ b/vendor/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/vendor/plugins/swf_fu/uninstall.rb b/vendor/plugins/swf_fu/uninstall.rb new file mode 100644 index 00000000..bc3c1b57 --- /dev/null +++ b/vendor/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 From 29e007f9c6bccdf615a76e24dd8fcbd18caceea8 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Fri, 30 Jul 2010 21:06:12 +0200 Subject: [PATCH 50/64] update routing and test for authorized access to all tracks pages --- app/views/layouts/standard.html.erb | 2 +- config/routes.rb | 63 ++++++++++++---------- features/contexts_manage.feature | 2 +- features/logging_in.feature | 38 ++++++++++--- features/step_definitions/context_steps.rb | 8 ++- features/step_definitions/project_steps.rb | 10 +++- features/support/paths.rb | 16 ++++++ 7 files changed, 102 insertions(+), 37 deletions(-) diff --git a/app/views/layouts/standard.html.erb b/app/views/layouts/standard.html.erb index 7154ba43..76800ad5 100644 --- a/app/views/layouts/standard.html.erb +++ b/app/views/layouts/standard.html.erb @@ -77,7 +77,7 @@
  • ?
    • <%= link_to 'Integrate Tracks', integrations_path %>
    • -
    • <%= link_to 'REST API Docs', url_for(:controller => 'integrations', :action => 'rest_api') %>
    • +
    • <%= link_to 'REST API Docs', rest_api_docs_path %>
  • <%= navigation_link(image_tag("system-search.png", :size => "16X16", :border => 0), {:controller => "search", :action => "index"}, :title => "Search All Items" ) %>
  • diff --git a/config/routes.rb b/config/routes.rb index 4035cbf0..9fe57d6b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,16 +1,8 @@ ActionController::Routing::Routes.draw do |map| - 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.resources :users, - :member => {:change_password => :get, :update_password => :post, - :change_auth_type => :get, :update_auth_type => :post, :complete => :get, - :refresh_token => :post } + :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 @@ -27,9 +19,11 @@ ActionController::Routing::Routes.draw do |map| projects.resources :todos, :name_prefix => "project_" end + map.resources :notes + map.resources :todos, - :member => {:toggle_check => :put, :toggle_star => :put}, - :collection => {:check_deferred => :post, :filter_to_context => :post, :filter_to_project => :post} + :member => {:toggle_check => :put, :toggle_star => :put}, + :collection => {:check_deferred => :post, :filter_to_context => :post, :filter_to_project => :post} map.with_options :controller => "todos" do |todos| todos.home '', :action => "index" todos.tickler 'tickler', :action => "list_deferred" @@ -56,25 +50,40 @@ ActionController::Routing::Routes.draw do |map| todos.mobile_abbrev_new 'm/new', :action => "new", :format => 'm' end map.root :controller => 'todos' # Make OpenID happy because it needs #root_url defined - - map.resources :notes - map.feeds 'feeds.m', :controller => 'feedlist', :action => 'index', :format => 'm' - map.feeds 'feeds', :controller => 'feedlist', :action => 'index' - - if Rails.env == 'test' - map.connect '/selenium_helper/login', :controller => 'selenium_helper', :action => 'login' - end - - map.preferences 'preferences', :controller => 'preferences', :action => 'index' - map.integrations 'integrations', :controller => 'integrations', :action => 'index' - map.search_plugin '/integrations/search_plugin.xml', :controller => 'integrations', :action => 'search_plugin', :format => 'xml' - map.google_gadget '/integrations/google_gadget.xml', :controller => 'integrations', :action => 'google_gadget', :format => 'xml' - map.stats 'stats', :controller => 'stats', :action => 'index' map.resources :recurring_todos, :member => {:toggle_check => :put, :toggle_star => :put} map.recurring_todos 'recurring_todos', :controller => 'recurring_todos', :action => 'index' + 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', :controller => 'integrations', :action => 'search_plugin', :format => 'xml' + i.google_gadget 'integrations/google_gadget.xml', :controller => 'integrations', :action => 'google_gadget', :format => 'xml' + end + + map.preferences 'preferences', :controller => 'preferences', :action => 'index' + map.stats 'stats', :controller => 'stats', :action => 'index' + map.search 'search', :controller => 'search', :action => 'index' + map.data 'data', :controller => 'data', :action => 'index' + + if Rails.env == 'test' + map.connect '/selenium_helper/login', :controller => 'selenium_helper', :action => 'login' + end + # Install the default route as the lowest priority. map.connect ':controller/:action/:id' diff --git a/features/contexts_manage.feature b/features/contexts_manage.feature index 89c7ff50..8c07cd0d 100644 --- a/features/contexts_manage.feature +++ b/features/contexts_manage.feature @@ -21,7 +21,7 @@ Feature: Manage contexts And he should see that a context named "OutAndAbout" is present @selenium - Scenario: Delete context from context page + Scenario: Delete context from context page should update badge Given I have a context called "@computer" When I go to the contexts page Then the badge should show 1 diff --git a/features/logging_in.feature b/features/logging_in.feature index 9c99eb4b..3c742423 100644 --- a/features/logging_in.feature +++ b/features/logging_in.feature @@ -6,9 +6,9 @@ Feature: Existing user logging in Background: Given the following user records - | login | password | is_admin | - | testuser | secret | false | - | admin | secret | true | + | login | password | is_admin | first_name | last_name | + | testuser | secret | false | Test | User | + | admin | secret | true | Admin | User | Scenario Outline: Succesfull and unsuccesfull login When I go to the login page @@ -21,6 +21,32 @@ Feature: Existing user logging in | admin | secret | redirected to the home page | Login successful | | admin | wrong | on the login page | Login unsuccessful | - Scenario: Accessing a secured page when not logged in - When I go to the home page - Then I should be redirected to the login page \ No newline at end of file + Scenario Outline: Unauthorized users cannot access Tracks and need to log in first + Given there exists a project called "top secret" for user "testuser" + And there exists a context called "@secret location" for user "testuser" + When I go to the + Then I should be redirected to the login page + When I submit the login form as user "testuser" with password "secret" + Then I should be redirected to the + And I should see "" + + Examples: + | page | next page | logout | + | home page | home page | Logout (Test User) | + | contexts page | contexts page | Logout (Test User) | + | projects page | projects page | Logout (Test User) | + | notes page | notes page | Logout (Test User) | + | repeating todos page | repeating todos page | Logout (Test User) | + | statistics page | statistics page | Logout (Test User) | + | manage users page | manage users page | 401 Unauthorized | + | integrations page | integrations page | Logout (Test User) | + | starred page | starred page | Logout (Test User) | + | tickler page | tickler page | Logout (Test User) | + | calendar page | calendar page | Logout (Test User) | + | feeds page | feeds page | Logout (Test User) | + | preference page | preference page | Logout (Test User) | + | export page | export page | Logout (Test User) | + | rest api docs page | rest api docs page | Logout (Test User) | + | search page | search page | Logout (Test User) | + | "top secret" project for user "testuser" | "top secret" project for user "testuser" | Logout (Test User) | + | context page for "@secret location" for user "testuser" | context page for "@secret location" for user "testuser" | Logout (Test User) | diff --git a/features/step_definitions/context_steps.rb b/features/step_definitions/context_steps.rb index 671b6a70..90f24a21 100644 --- a/features/step_definitions/context_steps.rb +++ b/features/step_definitions/context_steps.rb @@ -3,8 +3,14 @@ Given /^I have no contexts$/ do Context.delete_all end +Given /^there exists a context called "([^"]*)" for user "([^"]*)"$/ do |context_name, login| + user = User.find_by_login(login) + user.should_not be_nil + @context = user.contexts.create!(:name => context_name) +end + Given /^I have a context called "([^\"]*)"$/ do |context_name| - @context = @current_user.contexts.create!(:name => context_name) + Given "there exists a context called \"#{context_name}\" for user \"#{@current_user.login}\"" end Given /^I have the following contexts:$/ do |table| diff --git a/features/step_definitions/project_steps.rb b/features/step_definitions/project_steps.rb index ab6d58d2..5adc0e9a 100644 --- a/features/step_definitions/project_steps.rb +++ b/features/step_definitions/project_steps.rb @@ -15,6 +15,15 @@ Given /^there exists a project "([^\"]*)" for user "([^\"]*)"$/ do |project_name user.projects.create!(:name => project_name) end +Given /^there exists a project called "([^"]*)" for user "([^"]*)"$/ do |project_name, login| + # TODO: regexp change to integrate this with the previous since only 'called' is different + Given "there exists a project \"#{project_name}\" for user \"#{login}\"" +end + +Given /^I have a project called "([^"]*)"$/ do |project_name| + Given "there exists a project \"#{project_name}\" for user \"#{@current_user.login}\"" +end + When /^I visit the "([^\"]*)" project$/ do |project_name| @project = Project.find_by_name(project_name) @project.should_not be_nil @@ -25,7 +34,6 @@ When /^I visit the project page for "([^"]*)"$/ do |project_name| When "I visit the \"#{project_name}\" project" end - When /^I edit the project description to "([^\"]*)"$/ do |new_description| click_link "link_edit_project_#{@project.id}" fill_in "project[description]", :with => new_description diff --git a/features/support/paths.rb b/features/support/paths.rb index 1c987fb9..57277a91 100644 --- a/features/support/paths.rb +++ b/features/support/paths.rb @@ -28,6 +28,22 @@ module NavigationHelpers integrations_path when /the tickler page/ tickler_path + when /the export page/ + data_path + when /the preference page/ + preferences_path + when /the rest api docs page/ + rest_api_docs_path + when /the search page/ + search_path + when /the starred page/ + tag_path("starred") + when /the feeds page/ + feeds_path + when /the context page for "([^\"]*)" for user "([^\"]*)"/i + context_path(User.find_by_login($2).contexts.find_by_name($1)) + when /the "([^\"]*)" project for user "([^\"]*)"/i + project_path(User.find_by_login($2).projects.find_by_name($1)) # Add more mappings here. # Here is an example that pulls values out of the Regexp: From a9726766b31cbbfc07c04d257b77ce2bd36c38ef Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Fri, 30 Jul 2010 21:41:52 +0200 Subject: [PATCH 51/64] fix small problems with two features --- features/manage_project.feature | 2 +- features/shared_add_new_todo.feature | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/features/manage_project.feature b/features/manage_project.feature index f460bd5e..68de937b 100644 --- a/features/manage_project.feature +++ b/features/manage_project.feature @@ -11,7 +11,7 @@ Feature: Manage a project And I have logged in as "testuser" with password "secret" And there exists a project "manage me" for user "testuser" - @selenium, @wip + @selenium Scenario: I can describe the project using markup When I visit the "manage me" project And I edit the project description to "_successfull outcome_: project is *done*" diff --git a/features/shared_add_new_todo.feature b/features/shared_add_new_todo.feature index 2ad79377..ad67f6ca 100644 --- a/features/shared_add_new_todo.feature +++ b/features/shared_add_new_todo.feature @@ -128,10 +128,10 @@ Feature: Add new next action from every page Then I should see "You need to submit at least one next action" When I submit the new multiple actions form with "one", "", "", "" Then I should see "Context can't be blank" - When I fill the multiple actions form with "", "a project", "a context", "tag" + When I fill the multiple actions form with "", "a project", "test context", "tag" And I submit the new multiple actions form with """ """ - Then I should see "You need to submit at least one next action" \ No newline at end of file + Then I should see "You need to submit at least one next action" From 6be18a104b97682e1a3f74976525af6740aa2ba6 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Tue, 3 Aug 2010 20:55:07 +0200 Subject: [PATCH 52/64] fix #1042 and create test for it --- app/controllers/projects_controller.rb | 8 +-- app/views/projects/_project_form.rhtml | 2 +- app/views/projects/_project_listing.rhtml | 3 +- app/views/projects/update.js.rjs | 61 ++++++++++++---------- features/manage_project.feature | 19 +++++++ features/step_definitions/project_steps.rb | 16 ++++-- 6 files changed, 72 insertions(+), 37 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 9a3b8242..e3a8bcb4 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -105,7 +105,6 @@ class ProjectsController < ApplicationController if params['project']['state'] @new_state = params['project']['state'] @state_changed = @project.state != @new_state - logger.info "@state_changed: #{@project.state} == #{params['project']['state']} != #{@state_changed}" params['project'].delete('state') end success_text = if params['field'] == 'name' && params['value'] @@ -113,7 +112,8 @@ class ProjectsController < ApplicationController params['project']['name'] = params['value'] end @project.attributes = params['project'] - if @project.save + @saved = @project.save + if @saved @project.transition_to(@new_state) if @state_changed if boolean_param('wants_render') if (@project.hidden?) @@ -149,8 +149,8 @@ class ProjectsController < ApplicationController return end else - notify :warning, "Couldn't update project" - render :text => '' + init_data_for_sidebar + render :template => 'projects/update.js.rjs' return end render :template => 'projects/update.js.rjs' diff --git a/app/views/projects/_project_form.rhtml b/app/views/projects/_project_form.rhtml index a2a386f5..f0338fdf 100644 --- a/app/views/projects/_project_form.rhtml +++ b/app/views/projects/_project_form.rhtml @@ -3,7 +3,7 @@ project = project_form %> <% form_remote_tag(:url => project_path(project), :html => { :id => dom_id(project, 'edit_form'), :class => "inline-form "+dom_id(project, 'edit_form')+"-edit-project-form", :method => :put }) do -%> - +
    <%= error_messages_for("project") %>
    <%= source_view_tag( @source_view ) -%>
    diff --git a/app/views/projects/_project_listing.rhtml b/app/views/projects/_project_listing.rhtml index bfc44ac9..8c35e941 100644 --- a/app/views/projects/_project_listing.rhtml +++ b/app/views/projects/_project_listing.rhtml @@ -27,7 +27,8 @@ suppress_edit_button ||= false :method => 'get', :with => "'_source_view=#{@source_view}'", :before => "$('#{dom_id(project)}').block({message:null});", - :complete => "$('#{dom_id(project)}').unblock();enable_rich_interaction();" + :complete => "$('#{dom_id(project)}').unblock();enable_rich_interaction();", + :html => {:id => "link_edit_#{dom_id(project)}"} ) %> <% end -%> diff --git a/app/views/projects/update.js.rjs b/app/views/projects/update.js.rjs index 079b98ee..82ceea98 100644 --- a/app/views/projects/update.js.rjs +++ b/app/views/projects/update.js.rjs @@ -1,34 +1,39 @@ -status_message = 'Project saved' -page.notify :notice, status_message, 5.0 -if source_view_is :project_list - if @state_changed - page[dom_id(@project, 'container')].remove - page.insert_html :bottom, "list-#{@project.state}-projects", :partial => 'project_listing', :object => @project +if @saved + status_message = 'Project saved' + page.notify :notice, status_message, 5.0 + if source_view_is :project_list + if @state_changed + page[dom_id(@project, 'container')].remove + page.insert_html :bottom, "list-#{@project.state}-projects", :partial => 'project_listing', :object => @project + else + page.replace_html dom_id(@project, 'container'), :partial => 'project_listing', :object => @project + end + page.sortable "list-#{@project.state}-projects", get_listing_sortable_options("list-#{@project.state}-projects") + page.replace_html "active-projects-count", @active_projects_count + page.replace_html "hidden-projects-count", @hidden_projects_count + page.replace_html "completed-projects-count", @completed_projects_count + + page.set_element_visible("list-hidden-projects-container", @hidden_projects_count > 0) + page.set_element_visible("list-active-projects-container", @active_projects_count > 0) + page.set_element_visible("list-completed-projects-container", @completed_projects_count > 0) else - page.replace_html dom_id(@project, 'container'), :partial => 'project_listing', :object => @project + page[dom_id(@project, 'edit')].hide + page.replace_html dom_id(@project, 'container'), :partial => 'project_settings', :locals => { :project => @project } + page[dom_id(@project)].show + + page['todo_context_name'].value = @project.default_context.name if @project.default_context + page['#todo_project_name'].value = @project.name + page['tag_list'].value = @project.default_tags if @project.default_tags + page << "$('input[name=default_context_name]').val('#{@project.default_context.name}');" if @project.default_context end - page.sortable "list-#{@project.state}-projects", get_listing_sortable_options("list-#{@project.state}-projects") - page.replace_html "active-projects-count", @active_projects_count - page.replace_html "hidden-projects-count", @hidden_projects_count - page.replace_html "completed-projects-count", @completed_projects_count - page.set_element_visible("list-hidden-projects-container", @hidden_projects_count > 0) - page.set_element_visible("list-active-projects-container", @active_projects_count > 0) - page.set_element_visible("list-completed-projects-container", @completed_projects_count > 0) + page['default_project_name_id'].value = @project.name + page['todo_project_name'].value = @project.name + page.replace_html "project_name", @project.name + + page.replace_html "sidebar", :file => 'sidebar/sidebar.html.erb' else - page[dom_id(@project, 'edit')].hide - page.replace_html dom_id(@project, 'container'), :partial => 'project_settings', :locals => { :project => @project } - page[dom_id(@project)].show - - page['todo_context_name'].value = @project.default_context.name if @project.default_context - page['#todo_project_name'].value = @project.name - page['tag_list'].value = @project.default_tags if @project.default_tags - page << "$('input[name=default_context_name]').val('#{@project.default_context.name}');" if @project.default_context + page.show 'error_status' + page.replace_html 'error_status', "#{error_messages_for('project')}" end - -page['default_project_name_id'].value = @project.name -page['todo_project_name'].value = @project.name -page.replace_html "project_name", @project.name - -page.replace_html "sidebar", :file => 'sidebar/sidebar.html.erb' page << "enable_rich_interaction();" diff --git a/features/manage_project.feature b/features/manage_project.feature index 68de937b..58307109 100644 --- a/features/manage_project.feature +++ b/features/manage_project.feature @@ -34,3 +34,22 @@ Feature: Manage a project When I visit the "bananas" project And I edit the project name to "cherries" Then the project title should be "cherries" + + # Ticket #1042 + @selenium + Scenario: I cannot change the name of a project in the project view to the name of another existing project + Given I have a project "test" with 1 todos + When I go to the projects page + Then the badge should show 2 # "manage me" and "test" + When I visit the "manage me" project + And I edit the project name to "test" + Then I should see "Name already exists" + + # Ticket #1042 + @selenium + Scenario: I cannot change the name of a project in the project list view to the name of another existing project + Given I have a project "test" with 1 todos + When I go to the projects page + Then the badge should show 2 # "manage me" and "test" + When I edit the project name of "manage me" to "test" + Then I should see "Name already exists" \ No newline at end of file diff --git a/features/step_definitions/project_steps.rb b/features/step_definitions/project_steps.rb index 5adc0e9a..51112c4b 100644 --- a/features/step_definitions/project_steps.rb +++ b/features/step_definitions/project_steps.rb @@ -43,10 +43,20 @@ end When /^I edit the project name to "([^\"]*)"$/ do |new_title| click_link "link_edit_project_#{@project.id}" fill_in "project[name]", :with => new_title + + # changed to make sure selenium waits until the saving has a result either + # positive or negative. Was: :element=>"flash", :text=>"Project saved" + # we may need to change it back if you really need a positive outcome, i.e. + # this step needs to fail if the project was not saved succesfully selenium.click "submit_project_#{@project.id}", :wait_for => :text, - :element => "flash", - :text => "Project saved" + :text => /(Project saved|1 error prohibited this project from being saved)/ +end + +When /^I edit the project name of "([^"]*)" to "([^"]*)"$/ do |project_current_name, project_new_name| + @project = @current_user.projects.find_by_name(project_current_name) + @project.should_not be_nil + When "I edit the project name to \"#{project_new_name}\"" end Then /^I should see the bold text "([^\"]*)" in the project description$/ do |bold| @@ -69,4 +79,4 @@ end Then /^the project title should be "(.*)"$/ do |title| selenium.get_text("css=h2#project_name").should == title -end +end \ No newline at end of file From db7a5bd426fc26ab7ea971ed0e11d1b11b344731 Mon Sep 17 00:00:00 2001 From: Reinier Balt Date: Tue, 3 Aug 2010 21:00:48 +0200 Subject: [PATCH 53/64] Fix formatting issues --- app/views/projects/_project.rhtml | 8 +++--- app/views/projects/_project_listing.rhtml | 28 +++++++++---------- app/views/projects/_project_state_group.rhtml | 12 ++++---- app/views/projects/index.html.erb | 26 ++++++++--------- app/views/todos/update.js.rjs | 15 +++++----- 5 files changed, 45 insertions(+), 44 deletions(-) diff --git a/app/views/projects/_project.rhtml b/app/views/projects/_project.rhtml index 943bb4bb..3fc4aa85 100644 --- a/app/views/projects/_project.rhtml +++ b/app/views/projects/_project.rhtml @@ -1,9 +1,9 @@

    - <% if collapsible -%> - <%= image_tag("collapse.png") %> - <% end -%> - <%= project.name -%>

    + <% if collapsible -%> + <%= image_tag("collapse.png") %> + <% end -%> + <%= project.name -%>
    "> <%= render :partial => "projects/project_settings", :locals => { :project => project, :collapsible => collapsible } %>
    diff --git a/app/views/projects/_project_listing.rhtml b/app/views/projects/_project_listing.rhtml index 8c35e941..bf607d4e 100644 --- a/app/views/projects/_project_listing.rhtml +++ b/app/views/projects/_project_listing.rhtml @@ -15,23 +15,23 @@ suppress_edit_button ||= false
    <%= project.current_state.to_s.upcase %> <%= image_tag( "blank.png", - :title => "Delete project", + :title => "Delete project", :class=>"delete_item") %> - <% unless suppress_edit_button -%> - <%= link_to_remote( - image_tag( "blank.png", :title => "Edit project", :class=>"edit_item"), - :url => {:controller => 'projects', :action => 'edit', :id => project.id}, - :method => 'get', - :with => "'_source_view=#{@source_view}'", - :before => "$('#{dom_id(project)}').block({message:null});", - :complete => "$('#{dom_id(project)}').unblock();enable_rich_interaction();", - :html => {:id => "link_edit_#{dom_id(project)}"} - ) %> - - <% end -%> + <% unless suppress_edit_button -%> + <%= link_to_remote( + image_tag( "blank.png", :title => "Edit project", :class=>"edit_item"), + :url => {:controller => 'projects', :action => 'edit', :id => project.id}, + :method => 'get', + :with => "'_source_view=#{@source_view}'", + :before => "$('#{dom_id(project)}').block({message:null});", + :complete => "$('#{dom_id(project)}').unblock();enable_rich_interaction();", + :html => {:id => "link_edit_#{dom_id(project)}"} + ) %> + + <% end -%>
    diff --git a/app/views/projects/_project_state_group.rhtml b/app/views/projects/_project_state_group.rhtml index 0b1268b0..527f1388 100644 --- a/app/views/projects/_project_state_group.rhtml +++ b/app/views/projects/_project_state_group.rhtml @@ -1,15 +1,15 @@
    >

    <%= project_state_group.length %><%= state.titlecase %> Projects