diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index bddd5ebb..e4f2f072 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -3,7 +3,7 @@ class TodosController < ApplicationController skip_before_filter :login_required, :only => [:index, :calendar, :tag] prepend_before_filter :login_or_feed_token_required, :only => [:index, :calendar, :tag] append_before_filter :find_and_activate_ready, :only => [:index, :list_deferred] - append_before_filter :set_group_view_by, :only => [:index, :tag] + append_before_filter :set_group_view_by, :only => [:index, :tag, :create, :list_deferred, :destroy, :defer, :update] protect_from_forgery :except => :check_deferred @@ -93,6 +93,7 @@ class TodosController < ApplicationController if p.project_specified_by_name? project = current_user.projects.where(:name => p.project_name).first_or_create @new_project_created = project.new_record_before_save? + @not_done_todos = [@todo] if @new_project_created @todo.project_id = project.id elsif !(p.project_id.nil? || p.project_id.blank?) project = current_user.projects.where(:id => p.project_id).first @@ -197,12 +198,11 @@ class TodosController < ApplicationController # first build all todos and check if they would validate on save params[:todo][:multiple_todos].split("\n").map do |line| - unless line.blank? - @todo = current_user.todos.build( - :description => line) + unless line.blank? #ignore blank lines + @todo = current_user.todos.build(:description => line) @todo.project_id = @project_id @todo.context_id = @context_id - validates = false if @todo.invalid? + validates &&= @todo.valid? @todos_init << @todo end @@ -358,7 +358,7 @@ class TodosController < ApplicationController respond_to do |format| format.js do if @saved - determine_remaining_in_context_count(@todo.context_id) + determine_remaining_in_container_count(@todo) determine_down_count determine_completed_count determine_deferred_tag_count(params['_tag_name']) if source_view_is(:tag) @@ -441,11 +441,12 @@ class TodosController < ApplicationController end def update - @todo = current_user.todos.find(params['id']) @source_view = params['_source_view'] || 'todo' - # init_data_for_sidebar unless mobile? - cache_attributes_from_before_update + @todo = current_user.todos.find(params['id']) + @original_item = current_user.todos.build(@todo.attributes) # create a (unsaved) copy of the original todo + + cache_attributes_from_before_update # TODO: remove in favor of @orininal_item update_tags update_project @@ -466,7 +467,7 @@ class TodosController < ApplicationController update_todo_state_if_project_changed determine_changes_by_this_update - determine_remaining_in_context_count(@context_changed ? @original_item_context_id : @todo.context_id) + determine_remaining_in_container_count(@context_changed || @project_changed ? @original_item : @todo) determine_down_count determine_deferred_tag_count(params['_tag_name']) if source_view_is(:tag) @@ -495,6 +496,7 @@ class TodosController < ApplicationController @original_item_due = @todo.due @context_id = @todo.context_id @project_id = @todo.project_id + @todo_was_destroyed = true @todo_was_destroyed_from_deferred_state = @todo.deferred? @todo_was_destroyed_from_pending_state = @todo.pending? @todo_was_destroyed_from_deferred_or_pending_state = @todo_was_destroyed_from_deferred_state || @todo_was_destroyed_from_pending_state @@ -540,8 +542,8 @@ class TodosController < ApplicationController format.js do if @saved determine_down_count - if source_view_is_one_of(:todo, :deferred, :project, :context) - determine_remaining_in_context_count(@context_id) + if source_view_is_one_of(:todo, :deferred, :project, :context, :tag) + determine_remaining_in_container_count(@todo) elsif source_view_is :calendar @original_item_due_id = get_due_id_for_calendar(@original_item_due) @old_due_empty = is_old_due_empty(@original_item_due_id) @@ -656,6 +658,7 @@ class TodosController < ApplicationController blocked. reorder('todos.show_from ASC, todos.created_at DESC'). includes(Todo::DEFAULT_INCLUDES) + @todos_without_project = @not_done_todos.select{|t| t.project.nil?} # If you've set no_completed to zero, the completed items box isn't shown on # the tag page @@ -735,6 +738,8 @@ class TodosController < ApplicationController numdays = params['days'].to_i @todo = current_user.todos.find(params[:id]) + @original_item = current_user.todos.build(@todo.attributes) # create a (unsaved) copy of the original todo + @original_item_context_id = @todo.context_id @todo_deferred_state_changed = true @new_context_created = false @@ -748,7 +753,7 @@ class TodosController < ApplicationController @status_message = t('todos.action_saved_to_tickler') determine_down_count - determine_remaining_in_context_count(@todo.context_id) + determine_remaining_in_container_count(@todo) source_view do |page| page.project { @remaining_undone_in_project = current_user.projects.find(@todo.project_id).todos.not_completed.count @@ -886,7 +891,7 @@ class TodosController < ApplicationController private def set_group_view_by - @group_view_by = params['group_view_by'] || cookies['group_view_by'] || 'context' + @group_view_by = params['_group_view_by'] || cookies['group_view_by'] || 'context' end def do_mobile_todo_redirection @@ -1005,21 +1010,48 @@ class TodosController < ApplicationController end end - def determine_remaining_in_context_count(context_id = @todo.context_id) + def find_todos_in_project_container(todo) + if todo.project.nil? + # container with todos without project + todos_in_container = current_user.todos.where(:project_id => nil).active.not_hidden + else + todos_in_container = current_user.projects.find(todo.project_id).todos.active.not_hidden + end + end + + def find_todos_in_container_and_target_container(todo, target_todo) + if @group_view_by == 'context' + todos_in_container = current_user.contexts.find(todo.context_id).todos.active.not_hidden + todos_in_target_container = current_user.contexts.find(@todo.context_id).todos.active.not_hidden + else + todos_in_container = find_todos_in_project_container(todo) + todos_in_target_container = find_todos_in_project_container(@todo) + end + return todos_in_container, todos_in_target_container + end + + def determine_remaining_in_container_count(todo = @todo) source_view do |from| from.deferred { # force reload to todos to get correct count and not a cached one - @remaining_in_context = current_user.contexts.find(context_id).todos.deferred_or_blocked.count + @remaining_in_context = current_user.contexts.find(todo.context_id).todos.deferred_or_blocked.count @target_context_count = current_user.contexts.find(@todo.context_id).todos.deferred_or_blocked.count } + from.todo { + todos_in_container, todos_in_target_container = find_todos_in_container_and_target_container(todo, @todo) + @remaining_in_context = todos_in_container.active.not_hidden.count + @target_context_count = todos_in_target_container.active.not_hidden.count + } from.tag { tag = Tag.where(:name => params['_tag_name']).first tag = Tag.new(:name => params['tag']) if tag.nil? - @remaining_deferred_or_pending_count = current_user.todos.with_tag(tag.id).deferred_or_blocked.count - @remaining_in_context = current_user.contexts.find(context_id).todos.active.not_hidden.with_tag(tag.id).count - @target_context_count = current_user.contexts.find(@todo.context_id).todos.active.not_hidden.with_tag(tag.id).count + todos_in_container, todos_in_target_container = find_todos_in_container_and_target_container(todo, @todo) + + @remaining_in_context = todos_in_container.with_tag(tag.id).count + @target_context_count = todos_in_target_container.with_tag(tag.id).count @remaining_hidden_count = current_user.todos.hidden.with_tag(tag.id).count + @remaining_deferred_or_pending_count = current_user.todos.with_tag(tag.id).deferred_or_blocked.count } from.project { project_id = @project_changed ? @original_item_project_id : @todo.project_id @@ -1037,7 +1069,7 @@ class TodosController < ApplicationController @target_context_count = @new_due_id.blank? ? 0 : count_old_due_empty(@new_due_id) } from.context { - context = current_user.contexts.find(context_id) + context = current_user.contexts.find(todo.context_id) @remaining_deferred_or_pending_count = context.todos.deferred_or_blocked.count remaining_actions_in_context = context.todos(true).active @@ -1056,8 +1088,6 @@ class TodosController < ApplicationController @remaining_in_context = DoneTodos.remaining_in_container(current_user, @original_completed_period) } end - @remaining_in_context = current_user.contexts.find(context_id).todos(true).active.not_hidden.count if @remaining_in_context.nil? - @target_context_count = current_user.contexts.find(@todo.context_id).todos(true).active.not_hidden.count if !@target_context_count.nil? end def determine_completed_count diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index 0b6fd43b..397d0803 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -1,5 +1,7 @@ module TodosHelper + # === helpers for rendering container + def empty_message_holder(container_name, show, title_param=nil) content_tag(:div, :id => "no_todos_in_view", :class => "container #{container_name}", :style => "display:" + (show ? "block" : "none") ) do content_tag(:h2) { t("todos.no_actions.title", :param=>title_param) } + @@ -126,6 +128,8 @@ module TodosHelper end end + # === helpers for rendering a todo + def remote_star_icon(todo=@todo) link_to( image_tag_for_star(todo), toggle_star_todo_path(todo), @@ -212,6 +216,10 @@ module TodosHelper :class => "recurring_icon", :title => recurrence_pattern_as_text(todo.recurring_todo)) end + def image_tag_for_star(todo) + image_tag("blank.png", :title =>t('todos.star_action'), :class => "todo_star"+(todo.starred? ? " starred":""), :id => "star_img_"+todo.id.to_s) + end + def remote_toggle_checkbox(todo=@todo) check_box_tag("mark_complete_#{todo.id}", toggle_check_todo_path(todo), todo.completed?, :class => 'item-checkbox', :title => todo.pending? ? t('todos.blocked_by', :predecessors => todo.uncompleted_predecessors.map(&:description).join(', ')) : "", :readonly => todo.pending?) @@ -348,51 +356,11 @@ module TodosHelper end end - def should_show_new_item - source_view do |page| - page.todo { return !@todo.hidden? } - page.deferred { return @todo.deferred? || @todo.pending? } - page.context { - return @todo.context_id==@default_context.id && ( (@todo.hidden? && @todo.context.hidden?) || (!@todo.hidden?) ) - } - page.tag { - return ( (@todo.pending? && @todo.has_tag?(@tag_name)) || - (@todo.has_tag?(@tag_name)) || - (@todo.starred? && @tag_name == Todo::STARRED_TAG_NAME) - ) - } - page.project { - return (@todo.active? && @todo.project && @todo.project.id == @default_project.id) || - (@todo.project.hidden? && @todo.project_hidden?) || - ( @todo.deferred? && (@todo.project.id == @default_project.id) ) || - @todo.pending? - } - end - - return false + def date_field_tag(name, id, value = nil, options = {}) + text_field_tag name, value, {"size" => 12, "id" => id, "class" => "Date", "autocomplete" => "off"}.update(options.stringify_keys) end - def should_make_context_visible - return @todo.active? && (!@todo.hidden? && !source_view_is(:project) ) - end - - def should_add_new_context - return @new_context_created && !source_view_is(:project) - end - - def parent_container_type - return 'tickler' if source_view_is :deferred - return 'project' if source_view_is :project - return 'stats' if source_view_is :stats - return 'tag' if source_view_is :tag - return 'context' - end - - def todo_container_is_empty - default_container_empty = ( @down_count == 0 ) - deferred_container_empty = ( @todo.deferred? && @remaining_deferred_count == 0) - return default_container_empty || deferred_container_empty - end + # === helpers for default layout def default_contexts_for_autocomplete projects = current_user.projects.uncompleted.includes(:default_context).where('NOT(default_context_id IS NULL)') @@ -404,6 +372,13 @@ module TodosHelper Hash[*projects.map{ |p| [escape_javascript(p.name), p.default_tags] }.flatten].to_json end + # === various helpers + + def formatted_pagination(total) + s = will_paginate(@todos) + (s.gsub(/(<\/[^<]+>)/, '\1 ')).chomp(' ') + end + def format_ical_notes(notes) unless notes.nil? || notes.blank? split_notes = notes.split(/\n/) @@ -412,145 +387,12 @@ module TodosHelper joined_notes || "" end - def formatted_pagination(total) - s = will_paginate(@todos) - (s.gsub(/(<\/[^<]+>)/, '\1 ')).chomp(' ') - end - - def date_field_tag(name, id, value = nil, options = {}) - text_field_tag name, value, {"size" => 12, "id" => id, "class" => "Date", "autocomplete" => "off"}.update(options.stringify_keys) - end - - def update_needs_to_hide_context - return (@remaining_in_context == 0 && (@todo_hidden_state_changed && @todo.hidden?)) || - (@remaining_in_context == 0 && @todo_was_deferred_from_active_state) || - (@remaining_in_context == 0 && @tag_was_removed) || - (@remaining_in_context == 0 && @todo.completed? && !(@original_item_was_deferred || @original_item_was_hidden)) if source_view_is(:tag) - - return false if source_view_is_one_of(:project, :calendar, :done) - - return (@remaining_in_context == 0) && !source_view_is(:context) - end - - def update_needs_to_remove_todo_from_container - source_view do |page| - page.context { return @context_changed || @todo_deferred_state_changed || @todo_pending_state_changed || @todo_should_be_hidden } - page.project { return @todo_deferred_state_changed || @todo_pending_state_changed || @project_changed} - page.deferred { return @context_changed || !(@todo.deferred? || @todo.pending?) } - page.calendar { return @due_date_changed || !@todo.due } - page.stats { return @todo.completed? } - page.tag { return (@context_changed && !@todo.hidden?) || @tag_was_removed || @todo_hidden_state_changed || @todo_deferred_state_changed } - page.todo { return @context_changed || @todo.hidden? || @todo.deferred? || @todo.pending?} - page.search { return false } - end - return false - end - - def replace_with_updated_todo - source_view do |page| - page.context { return !update_needs_to_remove_todo_from_container } - page.project { return !update_needs_to_remove_todo_from_container } - page.deferred { return !@context_changed && (@todo.deferred? || @todo.pending?) } - page.calendar { return !@due_date_changed && @todo.due } - page.stats { return !@todo.completed? } - page.tag { return !update_needs_to_remove_todo_from_container && !@tag_was_removed } - page.todo { return !update_needs_to_remove_todo_from_container } - page.search { return true } - end - return false - end - - def append_updated_todo - source_view do |page| - page.context { return @todo_deferred_state_changed || @todo_pending_state_changed } - page.project { return @todo_deferred_state_changed || @todo_pending_state_changed } - page.deferred { return @context_changed && (@todo.deferred? || @todo.pending?) } - page.calendar { return @due_date_changed && @todo.due } - page.stats { return false } - page.tag { return update_needs_to_remove_todo_from_container && !@tag_was_removed} - page.todo { return @context_changed && !(@todo.deferred? || @todo.pending? || @todo.hidden?) } - end - return false - end - - def item_container_id (todo) - return "hidden_container_items" if source_view_is(:tag) && todo.hidden? - return "c#{todo.context_id}_items" if source_view_is :deferred - return @new_due_id if source_view_is :calendar - return "deferred_pending_container_items" if !source_view_is(:todo) && (todo.deferred? || todo.pending?) - return "completed_container_items" if todo.completed? - return "p#{todo.project_id}_items" if source_view_is :project - return "c#{todo.context_id}_items" - end - - def empty_container_msg_div_id(todo = @todo || @successor) - raise Exception.new, "no @todo or @successor set" if !todo - - source_view do |page| - page.project { - return "deferred_pending_container-empty-d" if empty_criteria_met - return "p#{todo.project_id}-empty-d" - } - page.tag { - return "deferred_pending_container-empty-d" if empty_criteria_met - return "hidden_container-empty-d" if @todo.hidden? - return "c#{todo.context_id}-empty-d" - } - page.calendar { - return "deferred_pending_container-empty-d" if empty_criteria_met - return "empty_#{@new_due_id}" - } - page.context { - return "deferred_pending_container-empty-d" if empty_criteria_met - return "c#{todo.context_id}-empty-d" - } - end - - return "c#{todo.context_id}-empty-d" - end - - def empty_criteria_met - @todo_was_deferred_from_active_state || - @todo_was_blocked_from_active_state || - @todo_was_destroyed_from_deferred_state || - @todo_was_created_deferred || - @todo_was_blocked_from_completed_state || - @todo_was_created_blocked - end - - def todo_was_removed_from_deferred_or_blocked_container - return @todo_was_activated_from_deferred_state || - @todo_was_activated_from_pending_state || - @todo_was_destroyed_from_deferred_or_pending_state || - @todo_was_completed_from_deferred_or_blocked_state - end - - def show_empty_message_in_source_container - container_id = "" - source_view do |page| - page.project { - container_id = "p#{@original_item_project_id}-empty-d" if @remaining_in_context == 0 - container_id = "deferred_pending_container-empty-d" if todo_was_removed_from_deferred_or_blocked_container && @remaining_deferred_or_pending_count == 0 - container_id = "completed_container-empty-d" if @completed_count && @completed_count == 0 && !@todo.completed? - } - page.deferred { container_id = "c#{@original_item_context_id}empty-d" if @remaining_in_context == 0 } - page.calendar { container_id = "empty_#{@original_item_due_id}" if @old_due_empty } - page.tag { - container_id = "hidden_container-empty-d" if (@remaining_hidden_count == 0 && !@todo.hidden? && @todo_hidden_state_changed) || - (@remaining_hidden_count == 0 && @todo.completed? && @original_item_was_hidden) - container_id = "deferred_pending_container-empty-d" if (todo_was_removed_from_deferred_or_blocked_container && @remaining_deferred_or_pending_count == 0) || - (@original_item_was_deferred && @remaining_deferred_or_pending_count == 0 && (@todo.completed? || @tag_was_removed)) - container_id = "completed_container-empty-d" if @completed_count && @completed_count == 0 && !@todo.completed? - } - page.context { - container_id = "c#{@original_item_context_id}-empty-d" if @remaining_in_context == 0 - container_id = "deferred_pending_container-empty-d" if todo_was_removed_from_deferred_or_blocked_container && @remaining_deferred_or_pending_count == 0 - container_id = "completed_container-empty-d" if @completed_count && @completed_count == 0 && !@todo.completed? - } - page.todo { container_id = "c#{@original_item_context_id}-empty-d" if @remaining_in_context == 0 } - page.done { container_id = "completed_#{@original_completed_period}_container-empty-d" if @remaining_in_context == 0 } - end - return container_id.blank? ? "" : "$(\"##{container_id}\").slideDown(100);".html_safe + def parent_container_type + return 'tickler' if source_view_is :deferred + return 'project' if source_view_is :project + return 'stats' if source_view_is :stats + return 'tag' if source_view_is :tag + return 'context' end def render_animation(animation) @@ -587,10 +429,208 @@ module TodosHelper content_tag(:div, "#{t('common.context')}: #{context_link}") end - private + # === handle CRUD actions for todos - def image_tag_for_star(todo) - image_tag("blank.png", :title =>t('todos.star_action'), :class => "todo_star"+(todo.starred? ? " starred":""), :id => "star_img_"+todo.id.to_s) + def show_todo_on_current_context_page + return @todo.context_id==@default_context.id + end + + def todo_should_not_be_hidden_on_context_page + return !@todo.hidden? || # todo is not hidden --> show + (@todo.hidden? && @todo.context.hidden?) # todo is hidden, but context is hidden too --> show + end + + def show_todo_on_current_project_page + return @todo.project.id == @default_project.id + end + + def todo_should_not_be_hidden_on_project_page + return !@todo.hidden? || + (@todo.project_hidden? && @todo.project.hidden?) + end + + def should_show_new_item(todo = @todo) + return false if todo.nil? + source_view do |page| + page.todo { return !todo.hidden? } + page.deferred { return todo.deferred? || todo.pending? } + page.context { return show_todo_on_current_context_page && todo_should_not_be_hidden_on_context_page } + page.tag { return todo.has_tag?(@tag_name) } + page.project { return show_todo_on_current_project_page && todo_should_not_be_hidden_on_project_page } + end + return false + end + + def should_make_context_visible + return @todo.active? && (!@todo.hidden? && !source_view_is(:project) ) + end + + def should_add_new_container + if @group_view_by == 'project' + return @new_project_created && !source_view_is(:context) + else + return @new_context_created && !source_view_is(:project) + end + end + + def todo_container_is_empty + default_container_empty = ( @down_count == 0 ) + deferred_container_empty = ( @todo.deferred? && @remaining_deferred_count == 0) + return default_container_empty || deferred_container_empty + end + + def todo_moved_out_of_container + return (@project_changed && @group_view_by=='project') || (@context_changed && @group_view_by='context') + end + + def update_needs_to_hide_container + return (@remaining_in_context == 0 && todo_moved_out_of_container ) || + (@remaining_in_context == 0 && (@todo_hidden_state_changed && @todo.hidden?)) || + (@remaining_in_context == 0 && @todo_was_deferred_from_active_state) || + (@remaining_in_context == 0 && @tag_was_removed) || + (@remaining_in_context == 0 && @todo_was_destroyed) || + (@remaining_in_context == 0 && @todo.completed? && !(@original_item_was_deferred || @original_item_was_hidden)) if source_view_is(:tag) + + return false if source_view_is_one_of(:project, :calendar, :done) + + return (@remaining_in_context == 0) && !source_view_is(:context) + end + + def update_needs_to_remove_todo_from_container + source_view do |page| + page.context { return @context_changed || @todo_deferred_state_changed || @todo_pending_state_changed || @todo_should_be_hidden } + page.project { return @todo_deferred_state_changed || @todo_pending_state_changed || @project_changed} + page.deferred { return @context_changed || !(@todo.deferred? || @todo.pending?) } + page.calendar { return @due_date_changed || !@todo.due } + page.stats { return @todo.completed? } + page.tag { return ( (@context_changed | @project_changed) && !@todo.hidden?) || @tag_was_removed || @todo_hidden_state_changed || @todo_deferred_state_changed } + page.todo { return todo_moved_out_of_container || @todo.hidden? || @todo.deferred? || @todo.pending?} + page.search { return false } + end + return false + end + + def replace_with_updated_todo + source_view do |page| + page.context { return !update_needs_to_remove_todo_from_container } + page.project { return !update_needs_to_remove_todo_from_container } + page.deferred { return !@context_changed && (@todo.deferred? || @todo.pending?) } + page.calendar { return !@due_date_changed && @todo.due } + page.stats { return !@todo.completed? } + page.tag { return !update_needs_to_remove_todo_from_container && !@tag_was_removed } + page.todo { return !update_needs_to_remove_todo_from_container } + page.search { return true } + end + return false + end + + def append_updated_todo + source_view do |page| + page.context { return @todo_deferred_state_changed || @todo_pending_state_changed } + page.project { return @todo_deferred_state_changed || @todo_pending_state_changed } + page.deferred { return @context_changed && (@todo.deferred? || @todo.pending?) } + page.calendar { return @due_date_changed && @todo.due } + page.stats { return false } + page.tag { return update_needs_to_remove_todo_from_container && !@tag_was_removed} + page.todo { return todo_moved_out_of_container && !(@todo.deferred? || @todo.pending? || @todo.hidden?) } + end + return false + end + + def project_container_id(todo) + return "p#{todo.project_id}" unless todo.project.nil? + return "without_project_container" + end + + def project_container_empty_id(todo) + return "p#{todo.project_id}-empty-d" unless todo.project.nil? + return "without_project_container-empty-d" + end + + def item_container_id (todo) + return "hidden_container_items" if source_view_is(:tag) && todo.hidden? + return "c#{todo.context_id}_items" if source_view_is :deferred + return @new_due_id if source_view_is :calendar + return "deferred_pending_container_items" if !source_view_is(:todo) && (todo.deferred? || todo.pending?) + return "completed_container_items" if todo.completed? + return "p#{todo.project_id}_items" if source_view_is :project + return project_container_id(todo) if source_view_is_one_of(:todo, :tag) && @group_view_by == 'project' + return "c#{todo.context_id}" + end + + def empty_container_msg_div_id(todo = @todo || @successor) + raise Exception.new, "no @todo or @successor set" if !todo + + source_view do |page| + page.project { + return "deferred_pending_container-empty-d" if empty_criteria_met + return "p#{todo.project_id}-empty-d" + } + page.tag { + return "deferred_pending_container-empty-d" if empty_criteria_met + return "hidden_container-empty-d" if @todo.hidden? + return "c#{todo.context_id}-empty-d" if @group_view_by == 'context' + return project_container_empty_id(todo) + } + page.calendar { + return "deferred_pending_container-empty-d" if empty_criteria_met + return "empty_#{@new_due_id}" + } + page.context { + return "deferred_pending_container-empty-d" if empty_criteria_met + return "c#{todo.context_id}-empty-d" + } + page.todo { + return "c#{todo.context_id}-empty-d" if @group_view_by == 'context' + return project_container_empty_id(todo) + } + end + + return "c#{todo.context_id}-empty-d" + end + + def empty_criteria_met + return @todo_was_deferred_from_active_state || + @todo_was_blocked_from_active_state || + @todo_was_destroyed_from_deferred_state || + @todo_was_created_deferred || + @todo_was_blocked_from_completed_state || + @todo_was_created_blocked + end + + def todo_was_removed_from_deferred_or_blocked_container + return @todo_was_activated_from_deferred_state || + @todo_was_activated_from_pending_state || + @todo_was_destroyed_from_deferred_or_pending_state || + @todo_was_completed_from_deferred_or_blocked_state + end + + def show_empty_message_in_source_container + container_id = "" + source_view do |page| + page.project { + container_id = "p#{@original_item_project_id}-empty-d" if @remaining_in_context == 0 + container_id = "deferred_pending_container-empty-d" if todo_was_removed_from_deferred_or_blocked_container && @remaining_deferred_or_pending_count == 0 + container_id = "completed_container-empty-d" if @completed_count && @completed_count == 0 && !@todo.completed? + } + page.deferred { container_id = "c#{@original_item_context_id}empty-d" if @remaining_in_context == 0 } + page.calendar { container_id = "empty_#{@original_item_due_id}" if @old_due_empty } + page.tag { + container_id = "hidden_container-empty-d" if (@remaining_hidden_count == 0 && !@todo.hidden? && @todo_hidden_state_changed) || + (@remaining_hidden_count == 0 && @todo.completed? && @original_item_was_hidden) + container_id = "deferred_pending_container-empty-d" if (todo_was_removed_from_deferred_or_blocked_container && @remaining_deferred_or_pending_count == 0) || + (@original_item_was_deferred && @remaining_deferred_or_pending_count == 0 && (@todo.completed? || @tag_was_removed)) + container_id = "completed_container-empty-d" if @completed_count && @completed_count == 0 && !@todo.completed? + } + page.context { + container_id = "c#{@original_item_context_id}-empty-d" if @remaining_in_context == 0 + container_id = "deferred_pending_container-empty-d" if todo_was_removed_from_deferred_or_blocked_container && @remaining_deferred_or_pending_count == 0 + container_id = "completed_container-empty-d" if @completed_count && @completed_count == 0 && !@todo.completed? + } + page.todo { container_id = "c#{@original_item_context_id}-empty-d" if @remaining_in_context == 0 } + page.done { container_id = "completed_#{@original_completed_period}_container-empty-d" if @remaining_in_context == 0 } + end + return container_id.blank? ? "" : "$(\"##{container_id}\").slideDown(100);".html_safe end end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 46e6a1ae..40e31bbb 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -10,6 +10,7 @@ var SOURCE_VIEW = '<%=@source_view%>'; var AUTH_TOKEN = '<%= raw(protect_against_forgery? ? form_authenticity_token.inspect : "") %>' var TAG_NAME = '<%= @tag_name ? @tag_name : "" %>' + var GROUP_VIEW_BY = '<%= @group_view_by ? @group_view_by : "" %>' var defaultContexts = <%= default_contexts_for_autocomplete.html_safe rescue '{}' %>; var defaultTags = <%= default_tags_for_autocomplete.html_safe rescue '{}' %>; var dateFormat = '<%= date_format_for_date_picker %>'; diff --git a/app/views/projects/_project.html.erb b/app/views/projects/_project.html.erb index b30436c9..df30b52d 100644 --- a/app/views/projects/_project.html.erb +++ b/app/views/projects/_project.html.erb @@ -3,9 +3,10 @@ # invalidate the cache every day because of staleness or # rendering of "due in x days" that change without touching updated at of the todo cache [project, @source_view, current_user.date.strftime("%Y%m%d")] do -%> - <%= render :partial => "project_settings_container", :locals => {:project => project} if source_view_is :project %> - +-%> + <% if source_view_is :project -%> + <%= render :partial => "project_settings_container", :locals => {:project => project} %> + <% end -%> <%= title = source_view_is(:project) ? t('projects.actions_in_project_title') : show_project_name(project) @@ -19,5 +20,4 @@ cache [project, @source_view, current_user.date.strftime("%Y%m%d")] do :show_empty_containers => settings[:show_empty_containers] }} %> - -<% end %> +<% end -%> \ No newline at end of file diff --git a/app/views/todos/create.js.erb b/app/views/todos/create.js.erb index dbf1ff70..27e1a006 100644 --- a/app/views/todos/create.js.erb +++ b/app/views/todos/create.js.erb @@ -1,24 +1,32 @@ <% unless @saved -%> + TracksPages.show_errors(html_for_error_messages()); function html_for_error_messages() { return "<%= escape_javascript(get_list_of_error_messages_for(@todo)) %>"; } -<% else -%> + +<% else + + animation = [] + if should_show_new_item + if should_add_new_container + animation << "insert_new_container_with_new_todo"; + else + animation << "add_todo_to_existing_container"; + end + end + animation << "remove_empty_message_container"; + animation << "update_predecessors"; + animation << "clear_form"; +-%> + + <%= render_animation(animation) %> TracksPages.page_notify('notice', "<%=escape_javascript @status_message%>", 8); TracksPages.hide_errors(); TracksPages.set_page_badge(<%= @down_count %>); - <% if should_show_new_item -%> - <% if should_add_new_context -%> - insert_new_context_with_new_todo(); - <% else -%> - add_todo_to_existing_context(); - <% end -%> - <% end -%> - update_predecessors(); - clear_form(); - function clear_form() { + function clear_form(next_steps) { $('#todo-form-new-action').clearForm(); $('#todo-form-new-action').clearDeps(); TracksForm.set_context_name('<%=escape_javascript @initial_context_name%>'); @@ -27,43 +35,55 @@ $('#todo-form-new-action input:text:first').focus(); $('#new_todo_starred_link .todo_star').removeClass('starred'); $('#new_todo_starred').val('false'); + next_steps.go(); } - function insert_new_context_with_new_todo() { + function insert_new_container_with_new_todo(next_steps) { <%- empty_id = '#no_todos_in_view' empty_id = '#deferred_pending_container-empty-d' if source_view_is :tickler -%> - $('<%=empty_id%>').slideUp(100); - $('#display_box').prepend(html_for_new_context()); + $('<%=empty_id%>').slideUp(100, function() { + $('#display_box').prepend(html_for_new_container()); + next_steps.go(); + }); } - function add_todo_to_existing_context() { - <% if source_view_is_one_of(:todo, :deferred, :tag) -%> - <% unless source_view_is_one_of(:todo, :tag) && (@todo.deferred?||@todo.hidden?) -%> - $('#c<%= @todo.context_id %>').fadeIn(500, function() {}); - $('#no_todos_in_view').slideUp(100); - <%= "$('#deferred_pending_container-empty-nd').slideUp(100);".html_safe if source_view_is(:deferred) && @todo.deferred? %> - <% end -%> - <% end -%> - $('#<%=empty_container_msg_div_id%>').hide(); - $('#<%=item_container_id(@todo)%>').append(html_for_new_todo()); - $('#<%= dom_id(@todo)%>').effect('highlight', {}, 2000 ); + function add_todo_to_existing_container(next_steps) { + $('#<%= empty_container_msg_div_id %>').hide(); + $('#<%= item_container_id(@todo) %>').append(html_for_new_todo()); + $('#<%= item_container_id(@todo) %>').slideDown(500, function() { + $('#<%= dom_id(@todo) %>').effect('highlight', {}, 2000 ); + next_steps.go(); + }); } - function update_predecessors() { + function remove_empty_message_container(next_steps) { + $('#no_todos_in_view').slideUp(100, function() { }); + <%# = "$('#deferred_pending_container-empty-nd').slideUp(100);".html_safe if source_view_is(:deferred) && @todo.deferred? %> + next_steps.go(); + } + + function update_predecessors(next_steps) { <% @todo.uncompleted_predecessors.each do |p| -%> if ($('<%=item_container_id(p)%>')) { $('#<%=dom_id(p)%>').html('<%= escape_javascript(render(:partial => p, :locals => { :parent_container_type => parent_container_type, :source_view => @source_view }))%>'); } <% end -%> + next_steps.go(); } - function html_for_new_context() { - return "<%= @saved && @new_context_created ? escape_javascript(render(:partial => @todo.context, :locals => { :settings => {:collapsible => true} })) : "" %>"; + function html_for_new_container() { + <% + want_render = @group_view_by == 'project' ? @new_project_created : @new_context_created + container = @group_view_by == 'project' ? @todo.project : @todo.context + js = want_render ? escape_javascript(render(:partial => container, :locals => { :settings => {:collapsible => true} })) : "" + %> + return "<%= js %>"; } function html_for_new_todo() { return "<%= @saved ? escape_javascript(render(:partial => @todo, :locals => { :parent_container_type => parent_container_type, :source_view => @source_view })) : "" %>"; } -<% end -%> + +<% end -%> \ No newline at end of file diff --git a/app/views/todos/create_multiple.js.erb b/app/views/todos/create_multiple.js.erb index 44f04bfc..b4a5d4f8 100644 --- a/app/views/todos/create_multiple.js.erb +++ b/app/views/todos/create_multiple.js.erb @@ -1,5 +1,21 @@ -<% if @saved -%> - set_notification(); +<% unless @saved -%> + TracksPages.show_errors_for_multi_add(html_for_error_messages()); + + function html_for_error_messages() { + <% + # 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| + error_messages += get_list_of_error_messages_for(todo) + end + -%> + return "<%= escape_javascript(error_messages.html_safe)%>"; + } + +<% else -%> + TracksPages.page_notify('notice', "<%=@status_message%>", 5); hide_empty_message(); TracksPages.hide_errors(); TracksPages.set_page_badge(<%= @down_count %>); @@ -11,67 +27,44 @@ <% end -%> <% end -%> clear_form(); -<% else -%> - TracksPages.show_errors_for_multi_add(html_for_error_messages()); + + function clear_form() { + $('#todo-form-multi-new-action').clearForm(); + TracksForm.set_context_name_for_multi_add('<%=escape_javascript @initial_context_name%>'); + TracksForm.set_project_name_for_multi_add('<%=escape_javascript @initial_project_name%>'); + TracksForm.set_tag_list_for_multi_add('<%=escape_javascript @initial_tags%>'); + $('#todo-form-multi-new-action input:text:first').focus(); + } + + function insert_new_context_with_new_todo() { + $('#display_box').prepend(html_for_new_context()); + } + + function hide_empty_message() { + <% if (source_view_is :project and @todo.pending?) or (source_view_is :deferred) -%> + $('#deferred_pending_container-empty-d').hide(); + <% else -%> + $('#no_todos_in_view').hide(); + <% end -%> + } + + function add_todo_to_existing_context() { + <% + @todos.each do |todo| + if should_show_new_item(todo) + html = escape_javascript(render(:partial => todo, :locals => { :parent_container_type => parent_container_type, :source_view => @source_view })) + -%> + $('#<%= empty_container_msg_div_id(todo) %>').hide(); + $('#<%= item_container_id(todo) %>').append('<%= html %>'); + $('#<%= item_container_id(todo) %>').fadeIn(500, function() { + $('#<%= dom_id(todo) %>').effect('highlight', {}, 2000 ); + }); + <% end %> + <% end %> + } + + function html_for_new_context() { + return "<%= @saved && @new_context_created ? escape_javascript(render(:partial => @todo.context, :locals => { :settings => {:collapsible => true} })) : "" %>"; + } + <% end -%> - -<% if @saved - # the following functions assume a todo is saved or at least not nil, - # so leave them out in case of an error --%> - -function set_notification() { - TracksPages.page_notify('notice', "<%=@status_message%>", 5); -} - -function clear_form() { - $('#todo-form-multi-new-action').clearForm(); - TracksForm.set_context_name_for_multi_add('<%=escape_javascript @initial_context_name%>'); - TracksForm.set_project_name_for_multi_add('<%=escape_javascript @initial_project_name%>'); - TracksForm.set_tag_list_for_multi_add('<%=escape_javascript @initial_tags%>'); - $('#todo-form-multi-new-action input:text:first').focus(); -} - -function insert_new_context_with_new_todo() { - $('#display_box').prepend(html_for_new_context()); -} - -function hide_empty_message() { - $('#<%=empty_container_msg_div_id%>').hide(); - <% if (source_view_is :project and @todo.pending?) or (source_view_is :deferred) -%> - $('#deferred_pending_container-empty-d').hide(); - <% end -%> -} - -function add_todo_to_existing_context() { - <% if source_view_is_one_of(:todo, :deferred, :tag) -%> - TodoItemsContainer.ensureVisibleWithEffectAppear("c<%=@todo.context_id%>"); - <% end - show = should_show_new_item # to hide html if not necessary - @todos.each do |todo| - html = show ? escape_javascript(render(:partial => todo, :locals => { :parent_container_type => parent_container_type, :source_view => @source_view })) : "" -%> - $('#<%=item_container_id(todo)%>').append('<%= html %>'); - $('#<%= dom_id(todo)%>').effect('highlight', {}, 3000); - <% end %> -} - -function html_for_new_context() { - return "<%= @saved && @new_context_created ? escape_javascript(render(:partial => @todo.context, :locals => { :settings => {:collapsible => true} })) : "" %>"; -} - -<% else # if @saved -%> - -function html_for_error_messages() { - <% - # 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| - error_messages += get_list_of_error_messages_for(todo) - end - -%> - return "<%= escape_javascript(error_messages.html_safe)%>"; -} - -<% end # if @saved -%> \ No newline at end of file diff --git a/app/views/todos/destroy.js.erb b/app/views/todos/destroy.js.erb index 473354d0..5fbb6d03 100644 --- a/app/views/todos/destroy.js.erb +++ b/app/views/todos/destroy.js.erb @@ -1,4 +1,6 @@ -<%- if @saved -%> +<%- unless @saved -%> + TracksPages.page_notify('error', "<%= t('todos.error_deleting_item', :description => @todo.description) %>", 8); +<%- else -%> TracksPages.page_notify('notice', '<%= escape_javascript(t('todos.deleted_success')) %>', 5); TracksPages.set_page_badge(<%=@down_count%>); remove_todo_from_page(); @@ -6,20 +8,14 @@ activate_pending_todos(); update_predecessors(); show_empty_messages(); -<%- else -%> - TracksPages.page_notify('error', "<%= t('todos.error_deleting_item', :description => @todo.description) %>", 8); <%- end -%> -<% if @saved - # do not send the js in case of an error --%> - function show_empty_messages() { <% if @old_due_empty -%> $('#empty_<%=@original_item_due_id%>').slideDown(1000); <% end -%> - <% if empty_container_msg_div_id && todo_container_is_empty -%> + <% if todo_container_is_empty -%> $('#<%=empty_container_msg_div_id%>').slideDown(1000); <% if @down_count == 0 -%> $('#no_todos_in_view').slideDown(1000); @@ -32,10 +28,10 @@ function show_empty_messages() { } function remove_todo_from_page() { - <% if (@remaining_in_context == 0) && update_needs_to_hide_context + <% if (@remaining_in_context == 0) && update_needs_to_hide_container # remove context with deleted todo -%> - $('#c<%=@todo.context_id%>').fadeOut(400, function() { + $('#<%=item_container_id(@todo)%>').fadeOut(400, function() { $('#<%=dom_id(@todo)%>').remove(); }); <%= show_empty_message_in_source_container -%> @@ -104,8 +100,4 @@ function update_predecessors() { function html_for_new_recurring_todo() { return "<%= @saved && @new_recurring_todo ? escape_javascript(render(:partial => @new_recurring_todo, :locals => { :parent_container_type => parent_container_type })) : "" %>"; -} - -<% end - # if @saved --%> +} \ No newline at end of file diff --git a/app/views/todos/index.html.erb b/app/views/todos/index.html.erb index 6a614a1c..f8a4cafe 100644 --- a/app/views/todos/index.html.erb +++ b/app/views/todos/index.html.erb @@ -4,7 +4,7 @@ <%= show_grouped_todos %> <% if @group_view_by == 'project' -%> - <%= show_todos_without_project(@todos_without_project) unless @todos_without_project.nil? -%> + <%= show_todos_without_project(@todos_without_project) -%> <% end -%> <%= show_done_todos(@done, {:parent_container_type => 'home', :collapsible => true}) unless @done.nil? %> diff --git a/app/views/todos/tag.html.erb b/app/views/todos/tag.html.erb index 39196ef4..7eee6668 100644 --- a/app/views/todos/tag.html.erb +++ b/app/views/todos/tag.html.erb @@ -13,6 +13,10 @@ <%= show_grouped_todos %> + <% if @group_view_by == 'project' -%> + <%= show_todos_without_project(@todos_without_project) -%> + <% end -%> + <%= show_deferred_pending_todos(@deferred_todos, @pending_todos, deferred_pending_options) %> <%= show_hidden_todos(@hidden_todos, hidden_options) unless @hidden_todos.nil? %> diff --git a/app/views/todos/toggle_check.js.erb b/app/views/todos/toggle_check.js.erb index 8c47d534..9d18ae46 100644 --- a/app/views/todos/toggle_check.js.erb +++ b/app/views/todos/toggle_check.js.erb @@ -32,7 +32,7 @@ function redirect_after_complete() { } function remove_todo(next_steps) { - <% if (@remaining_in_context == 0) && update_needs_to_hide_context + <% if (@remaining_in_context == 0) && update_needs_to_hide_container # remove context with deleted todo -%> $('#c<%=@todo.context_id%>').fadeOut(400, function() { diff --git a/app/views/todos/update.js.erb b/app/views/todos/update.js.erb index d653f1be..277b64c6 100644 --- a/app/views/todos/update.js.erb +++ b/app/views/todos/update.js.erb @@ -1,5 +1,10 @@ -<% if !@saved -%> +<% unless @saved -%> TracksPages.show_edit_errors(html_for_error_messages()); + + function html_for_error_messages() { + return "<%= escape_javascript(get_list_of_error_messages_for(@todo)) %>"; + } + <% else # jquery animations are async, so first collect all animation steps that need @@ -13,15 +18,14 @@ elsif append_updated_todo animation << (@new_context_created ? "insert_new_context_with_updated_todo" : "add_to_existing_container") end - animation << "hide_context" if update_needs_to_hide_context + animation << "hide_container" if update_needs_to_hide_container animation << "highlight_updated_todo" animation << "update_empty_container" if source_view_is_one_of(:tag, :todo, :deferred) animation << "update_predecessors" %> - - <%= render_animation(animation) %> TracksPages.page_notify('notice', '<%=escape_javascript @status_message%>', 5); TracksPages.set_page_badge(<%= @down_count %>); + <%= render_animation(animation) %> <% end %> function remove_todo(next_steps) { @@ -46,7 +50,7 @@ function add_to_existing_container(next_steps) { <% end -%> <% else -%> <% unless (@todo_hidden_state_changed && @todo.hidden?) || @todo_was_deferred_from_active_state -%> - $('#c<%= @todo.context_id %>').fadeIn(500, function() { + $('#<%= item_container_id(@todo) %>').fadeIn(500, function() { next_steps.go(); <% if @target_context_count==1 -%> $("#<%= empty_container_msg_div_id %>").slideUp(100); @@ -69,9 +73,8 @@ function replace_todo(next_steps) { next_steps.go(); } -function hide_context(next_steps) { - <% context_id = @context_changed ? @original_item_context_id : @todo.context_id -%> - $('#c<%= context_id %>').fadeOut(400, function(){ next_steps.go(); }); +function hide_container(next_steps) { + $('#<%= item_container_id(@original_item) %>').fadeOut(400, function(){ next_steps.go(); }); <%= "$('#deferred_pending_container_empty-nd').slideDown(400);".html_safe if source_view_is(:deferred) && @down_count == 0 %> } @@ -109,10 +112,6 @@ function html_for_new_context() { return "<%= @saved && @new_context_created ? escape_javascript(render(:partial => @new_context, :locals => { :settings => {:collapsible => true }})) : "" %>"; } -function html_for_error_messages() { - return "<%= escape_javascript(get_list_of_error_messages_for(@todo)) %>"; -} - function update_predecessors(next_steps) { regenerate_predecessor_family(); <% if @removed_predecessors diff --git a/features/dependencies.feature b/features/dependencies.feature index 065d7b4c..28537faa 100644 --- a/features/dependencies.feature +++ b/features/dependencies.feature @@ -57,7 +57,7 @@ Feature: dependencies Then I should not see "test 1" within the dependencies of "test 2" And I should not see "test 1" in the deferred container - @javascript @wip + @javascript Scenario: Completing a predecessor will activate successors Given I have a context called "@pc" And I have a project "dependencies" that has the following todos diff --git a/features/shared_add_new_todo.feature b/features/shared_add_new_todo.feature index 1bc1ad2f..6ee5163b 100644 --- a/features/shared_add_new_todo.feature +++ b/features/shared_add_new_todo.feature @@ -85,21 +85,26 @@ Feature: Add new next action from every page @javascript Scenario Outline: I can add a todo from several pages + Given I have selected the view for group by When I go to the - And I submit a new action with description "a new next action" + And I submit a new action with description "a new next action" Then I should the todo "a new next action" Scenarios: - | page | see | - | home page | see | - | tickler page | not see | - | "test project" project | see | - | context page for "test context" | see | - | tag page for "starred" | see | + | page | grouping | see | + | home page | context | see | + | home page | project | see | + | tickler page | context | not see | + | tickler page | project | not see | + | "test project" project | context | see | + | context page for "test context" | context | see | + | tag page for "starred" | context | see | + | tag page for "starred" | project | see | @javascript Scenario Outline: I can add multiple todos from several pages Given I have a project "testing" with 1 todos + And I have selected the view for group by When I go to the And I follow "Add multiple next actions" And I submit multiple actions with using @@ -113,15 +118,18 @@ Feature: Add new next action from every page And the number of actions should be Scenarios: - | page | see | badge | count | - | home page | see | 3 | 3 | - | tickler page | not see | 0 | 3 | - | "testing" project | see | 3 | 3 | - | context page for "test context" | see | 2 | 3 | - | tag page for "starred" | not see | 0 | 3 | + | page | see | badge | count | grouping | + | home page | see | 3 | 3 | context | + | home page | see | 3 | 3 | project | + | tickler page | not see | 0 | 3 | context | + | tickler page | not see | 0 | 3 | project | + | "testing" project | see | 3 | 3 | context | + | context page for "test context" | see | 2 | 3 | context | + | tag page for "starred" | see | 2 | 3 | context | + | tag page for "starred" | see | 2 | 3 | project | @javascript - Scenario: Adding a todo to another project does not show the todo + Scenario: Adding a todo to another project does not show the todo in project view Given I have a project called "another project" When I go to the "test project" project And I submit a new action with description "can you see me?" to project "another project" in the context "test context" @@ -140,7 +148,7 @@ Feature: Add new next action from every page Then I should see the todo "another new next action" @javascript - Scenario Outline: Adding a todo with a new context shows the new context + Scenario Outline: Adding a todo with a new context shows the new context when page groups todos by context When I go to the And I submit a new with description "do at new context" and the tags "starred" in the context "New" Then a confirmation for adding a new context "New" should be asked @@ -155,12 +163,29 @@ Feature: Add new next action from every page | context page for "test context" | action | 1 | not be visible | | tag page for "starred" | action | 1 | be visible | + @javascript + Scenario Outline: Adding a todo with a new project shows the new project when page groups todos by project + And I have selected the view for group by project + When I go to the + And I submit a new with description "do in new project" to project "New" with tags "starred" + Then the container for the project "New" should + And the badge should show + + Scenarios: + | page | todo | badge | visible | + | home page | action | 1 | be visible | + | tickler page | deferred action | 1 | be visible | + | "test project" project | action | 1 | not be visible | + | context page for "test context" | action | 1 | not be visible | + | tag page for "starred" | action | 1 | be visible | + @javascript Scenario Outline: Adding a todo to a hidden project does not show the todo Given I have a hidden project called "hidden project" And I have a project called "visible project" And I have a context called "visible context" And I have a context called "other context" + And I have selected the view for group by When I go to the And I submit a new action with description "hidden todo" to project "hidden project" with tags "test" in the context "visible context" Then I should "hidden todo" @@ -168,17 +193,21 @@ Feature: Add new next action from every page Then I should "visible todo" Scenarios: - | page | see_hidden | see_visible | - | home page | not see | see | - | tickler page | not see | not see | - | "visible project" project | not see | see | - | "hidden project" project | see | not see | - | context page for "visible context" | not see | see | - | context page for "other context" | not see | not see | - | tag page for "starred" | not see | not see | - | tag page for "test" | see | see | + | page | grouping | see_hidden | see_visible | + | home page | context | not see | see | + | home page | project | not see | see | + | tickler page | context | not see | not see | + | tickler page | project | not see | not see | + | "visible project" project | project | not see | see | + | "hidden project" project | project | see | not see | + | context page for "visible context" | context | not see | see | + | context page for "other context" | context | not see | not see | + | tag page for "starred" | context | not see | not see | + | tag page for "starred" | project | not see | not see | + | tag page for "test" | context | see | see | + | tag page for "test" | project | see | see | - @javascript + @javascript Scenario: Adding a todo to a hidden context from home page does not show the todo Given I have a context called "visible context" And I have a hidden context called "hidden context" @@ -200,14 +229,21 @@ Feature: Add new next action from every page Then I should see "another new todo" @javascript - Scenario: Adding a todo to an empty container hides the empty message # TODO: make outline + Scenario Outline: Adding a todo to an empty container hides the empty message Given I have a context called "visible context" + And I have a project called "visible project" + And I have selected the view for group by When I go to the tag page for "test" Then I should see empty message for todos of tag - When I submit a new action with description "a new todo" and the tags "test" in the context "visible context" + When I submit a new action with description "a new todo" to project "visible project" with tags "test" in the context "visible context" Then I should see "a new todo" And I should not see empty message for todos of tag + Scenarios: + | grouping | + | context | + | project | + @javascript Scenario Outline: Adding a dependency to a todo updates the successor Given I have a "test" with 1 todos @@ -224,7 +260,7 @@ Feature: Add new next action from every page | project | | context | - @javascript + @javascript Scenario: Adding a dependency to a todo in another project Given I have a project "testing" with 1 todos And I have a project "another project" @@ -233,8 +269,9 @@ Feature: Add new next action from every page Then I should not see "a new todo" in the project container of "another project" And I should not see empty message for deferred todos of project - @javascript - Scenario: I can add multiple todos in a new project and a new context + @javascript @wip + Scenario Outline: I can add multiple todos in a new project and a new context + Given I have selected the view for group by When I go to the home page And I follow "Add multiple next actions" And I fill the multiple actions form with "", "a next project", "@anywhere", "new tag" @@ -253,7 +290,13 @@ Feature: Add new next action from every page And I should see "b" And I should see "c" - @javascript + Scenarios: + | grouping | + | project | + | context | + + + @javascript 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" diff --git a/features/step_definitions/container_steps.rb b/features/step_definitions/container_steps.rb index 198abbd4..5c22ee9e 100644 --- a/features/step_definitions/container_steps.rb +++ b/features/step_definitions/container_steps.rb @@ -98,7 +98,7 @@ end ####### Project ####### -Then /^I should not see "([^"]*)" in the project container of "([^"]*)"$/ do |todo_description, project_name| +Then /^I should (see|not see) "([^"]*)" in the project container of "([^"]*)"$/ do |visible, todo_description, project_name| todo = @current_user.todos.where(:description => todo_description).first todo.should_not be_nil @@ -106,30 +106,20 @@ Then /^I should not see "([^"]*)" in the project container of "([^"]*)"$/ do |to project.should_not be_nil xpath = "//div[@id='p#{todo.project.id}_items']//div[@id='line_todo_#{todo.id}']" - page.should_not have_xpath(xpath) + page.send( visible=='see' ? :should : :should_not, have_xpath(xpath)) end -Then /^I should see "([^"]*)" in project container for "([^"]*)"$/ do |todo_description, project_name| - todo = @current_user.todos.where(:description => todo_description).first - todo.should_not be_nil - - project = @current_user.projects.where(:name => project_name).first - project.should_not be_nil - - xpath = "//div[@id='p#{project.id}_items']//div[@id='line_todo_#{todo.id}']" - page.should have_xpath(xpath) -end - -Then(/^I should see "(.*?)" in the project container for "(.*?)"$/) do |todo_description, project_name| - step "I should see \"#{todo_description}\" in project container for \"#{project_name}\"" -end - -Then /^I should not see the project container for "([^"]*)"$/ do |project_name| +Then(/^I should (see|not see) the project container for "([^"]*)"$/) do |visible, project_name| project = @current_user.projects.where(:name => project_name).first project.should_not be_nil xpath = "//div[@id='p#{project.id}']" - page.should_not have_xpath(xpath, :visible => true) + page.send( visible=='see' ? :should : :should_not, have_xpath(xpath, :visible => true)) +end + +Then(/^the container for the project "(.*?)" should (be visible|not be visible)$/) do |project_name, visible| + map = { "be visible" => "see", "not be visible" => "not see"} + step("I should #{map[visible]} the project container for \"#{project_name}\"") end ####### Completed ####### diff --git a/features/step_definitions/generic_steps.rb b/features/step_definitions/generic_steps.rb index 673eb0b1..98d4f13f 100644 --- a/features/step_definitions/generic_steps.rb +++ b/features/step_definitions/generic_steps.rb @@ -15,8 +15,8 @@ Given /^the date is "(.*?)"$/ do |date| Timecop.travel(date) end -Given(/^I have selected the view for group by project$/) do - @group_view_by='projects' +Given(/^I have selected the view for group by (project|context)$/) do |grouping| + @group_view_by = grouping end Then /the badge should show (.*)/ do |number| diff --git a/features/step_definitions/todo_create_steps.rb b/features/step_definitions/todo_create_steps.rb index 382000f1..25d7961a 100644 --- a/features/step_definitions/todo_create_steps.rb +++ b/features/step_definitions/todo_create_steps.rb @@ -203,6 +203,23 @@ When /^I submit a new action with description "([^"]*)"$/ do |description| submit_next_action_form end +When /^I submit a new action with description "([^"]*)" in the project "(.*?)"$/ do |description, project_name| + within "form#todo-form-new-action" do + fill_in "todo[description]", :with => description + fill_in "project_name", :with => project_name + end + submit_next_action_form +end + +When(/^I submit a new action with description "([^"]*)" to project "([^"]*)" with tags "([^"]*)"$/) do |description, project_name, tags| + within "form#todo-form-new-action" do + fill_in "todo[description]", :with => description + fill_in "project_name", :with => project_name + fill_in "tag_list", :with => tags + end + submit_next_action_form +end + When /^I submit a new action with description "([^"]*)" with a dependency on "([^"]*)"$/ do |todo_description, predecessor_description| predecessor = @current_user.todos.where(:description => predecessor_description).first predecessor.should_not be_nil @@ -287,6 +304,16 @@ When /^I submit a new deferred action with description "([^"]*)" and the tags "( submit_next_action_form end +When(/^I submit a new deferred action with description "([^"]*)" to project "(.*?)" with tags "([^"]*)"$/) do |description, project_name, tags| + within "form#todo-form-new-action" do + fill_in "todo[description]", :with => description + fill_in "todo_project_name", :with => project_name + fill_in "tag_list", :with => tags + fill_in "todo[show_from]", :with => format_date(@current_user.time + 1.week) + end + submit_next_action_form +end + When /^I submit a new deferred action with description "([^"]*)" to project "([^"]*)" with tags "([^"]*)" in the context "([^"]*)"$/ do |description, project_name, tags, context_name| fill_in "todo[description]", :with => description diff --git a/features/support/paths.rb b/features/support/paths.rb index 6038f3fd..6635016d 100644 --- a/features/support/paths.rb +++ b/features/support/paths.rb @@ -9,7 +9,7 @@ module NavigationHelpers options = {} options[:format] = :m if @mobile_interface options[:locale] = @locale if @locale - options[:group_view_by] = @group_view_by if @group_view_by + options[:_group_view_by] = @group_view_by if @group_view_by @source_view = nil case page_name