diff --git a/app/controllers/recurring_todos_controller.rb b/app/controllers/recurring_todos_controller.rb index 8bfaaed8..0d17e24b 100644 --- a/app/controllers/recurring_todos_controller.rb +++ b/app/controllers/recurring_todos_controller.rb @@ -112,17 +112,17 @@ class RecurringTodosController < ApplicationController end if @saved - @message = "The recurring todo was saved" + @status_message = "The recurring todo was saved" @todo_saved = create_todo_from_recurring_todo(@recurring_todo).nil? == false if @todo_saved - @message += " / created a new todo" + @status_message += " / created a new todo" else - @message += " / did not create todo" + @status_message += " / did not create todo" end @down_count = current_user.recurring_todos.active.count @new_recurring_todo = RecurringTodo.new else - @message = "Error saving recurring todo" + @status_message = "Error saving recurring todo" end respond_to do |format| diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 8bc89e74..12f5454a 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -118,6 +118,11 @@ class TodosController < ApplicationController @initial_context_name = params['default_context_name'] @initial_project_name = params['default_project_name'] @default_tags = @todo.project.default_tags unless @todo.project.nil? + @status_message = 'Added new next action' + @status_message += ' to tickler' if @todo.deferred? + @status_message += ' in pending state' if @todo.pending? + @status_message = 'Added new project / ' + status_message if @new_project_created + @status_message = 'Added new context / ' + status_message if @new_context_created render :action => 'create' end format.xml do @@ -295,6 +300,7 @@ class TodosController < ApplicationController respond_to do |format| format.js format.xml { render :xml => @todo.to_xml( :except => :user_id ) } + format.html { redirect_to request.referrer} end end @@ -452,6 +458,7 @@ class TodosController < ApplicationController end def destroy + @source_view = params['_source_view'] || 'todo' @todo = get_todo_from_params @original_item_due = @todo.due @context_id = @todo.context_id diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index 9fcd4a6d..cb403092 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -32,15 +32,13 @@ module TodosHelper :title => t('todos.edit_action_with_description', :description => @todo.description)) end - def remote_delete_menu_item(parameters, todo) - return link_to_remote( + def remote_delete_menu_item(todo) + return link_to( image_tag("delete_off.png", :mouseover => "delete_on.png", :alt => t('todos.delete'), :align => "absmiddle")+" "+t('todos.delete'), - :url => {:controller => 'todos', :action => 'destroy', :id => todo.id}, - :method => 'delete', - :with => "'#{parameters}'", - :before => todo_start_waiting_js(todo), - :complete => todo_stop_waiting_js(todo), - :confirm => t('todos.confirm_delete', :description => todo.description)) + {:controller => 'todos', :action => 'destroy', :id => todo.id}, + :class => "icon_delete_item", + :id => "delete_#{dom_id(todo)}", + :title => t('todos.confirm_delete', :description => todo.description)); end def remote_defer_menu_item(days, todo) @@ -264,10 +262,16 @@ module TodosHelper def empty_container_msg_div_id todo = @todo || @successor return "" unless todo # empty id if no todo or successor given - return "tickler-empty-nd" if source_view_is_one_of(:project, :tag) && todo.deferred? + return "tickler-empty-nd" if source_view_is_one_of(:project, :tag, :deferred) && todo.deferred? return "p#{todo.project_id}empty-nd" if source_view_is :project return "c#{todo.context_id}empty-nd" end + + def todo_container_is_empty + default_container_empty = ( @down_count == 0 ) + deferred_container_empty = ( @todo.deferred? && @deferred_count == 0) + return default_container_empty || deferred_container_empty + end def default_contexts_for_autocomplete projects = current_user.projects.find(:all, :conditions => ['default_context_id is not null']) diff --git a/app/views/recurring_todos/create.js.erb b/app/views/recurring_todos/create.js.erb index 8f31ca4d..e2c9428d 100644 --- a/app/views/recurring_todos/create.js.erb +++ b/app/views/recurring_todos/create.js.erb @@ -1,4 +1,5 @@ <% if @saved -%> + TracksPages.page_notify('notice', "<%=@status_message%>", 5); RecurringTodosPage.toggle_overlay(); add_recurring_todo_to_active_container(); replace_form_with_empty_form(); diff --git a/app/views/todos/_todo.html.erb b/app/views/todos/_todo.html.erb index dae70ed6..1600ec91 100644 --- a/app/views/todos/_todo.html.erb +++ b/app/views/todos/_todo.html.erb @@ -11,17 +11,15 @@ parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag'
<%= remote_star_icon %> <%= remote_toggle_checkbox unless source_view_is :deferred %> - <% unless suppress_edit_button %> - <%= remote_edit_button %> - <% end %> + <%= remote_edit_button unless suppress_edit_button %>
- + \ No newline at end of file diff --git a/app/views/todos/_toggle_successors.html.erb b/app/views/todos/_toggle_successors.html.erb index 47efc3df..1d752488 100644 --- a/app/views/todos/_toggle_successors.html.erb +++ b/app/views/todos/_toggle_successors.html.erb @@ -1,9 +1,6 @@ -<% -suppress_button ||= false -%> -<%= link_to(image_tag( 'blank.png', :width=>'16', :height=>'16', :border=>'0' ), "#", {:class => 'show_successors', :title => 'Show successors'}) unless suppress_button %> +<%= link_to(image_tag( 'blank.png', :width=>'16', :height=>'16', :border=>'0' ), "#", {:class => 'show_successors', :title => 'Show successors'}) %> -
> +
<%= render :partial => "todos/successor", :collection => item.pending_successors, :locals => { :todo => item, diff --git a/app/views/todos/create.js.erb b/app/views/todos/create.js.erb index 29797d37..f42079d0 100644 --- a/app/views/todos/create.js.erb +++ b/app/views/todos/create.js.erb @@ -1,5 +1,5 @@ <% if @saved -%> - set_notification(); + TracksPages.page_notify('notice', "<%=@status_message%>", 5); hide_empty_message(); TracksPages.hide_errors(); TracksPages.set_page_badge(<%= @down_count %>); @@ -16,17 +16,6 @@ TracksPages.show_errors(html_for_error_messages()); <% end -%> -function set_notification() { - <%- - status_message = 'Added new next action' - status_message += ' to tickler' if @todo.deferred? - status_message += ' in pending state' if @todo.pending? - status_message = 'Added new project / ' + status_message if @new_project_created - status_message = 'Added new context / ' + status_message if @new_context_created - -%> - TracksPages.page_notify('notice', "<%=status_message%>", 5); -} - function hide_empty_message() { <% if @todo %> $('#<%=empty_container_msg_div_id%>').hide(); diff --git a/app/views/todos/create_multiple.js.erb b/app/views/todos/create_multiple.js.erb index 06f35340..43fb5b0e 100644 --- a/app/views/todos/create_multiple.js.erb +++ b/app/views/todos/create_multiple.js.erb @@ -16,7 +16,8 @@ <% end -%> <% if @saved - # the following functions assume a todo is saved or not nil, so leave them out in case of an error + # 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() { diff --git a/app/views/todos/destroy.js.erb b/app/views/todos/destroy.js.erb index 2468a53e..80f360a2 100644 --- a/app/views/todos/destroy.js.erb +++ b/app/views/todos/destroy.js.erb @@ -1,36 +1,75 @@ -if @saved - page[@todo].remove - page.show "empty_"+@original_item_due_id if @old_due_empty - page['badge_count'].replace_html @down_count - - # remove context if empty - page.visual_effect(:fade, "c#{@todo.context_id}", :duration => 0.4) if (@remaining_in_context == 0) - - # show message if there are no actions - page[empty_container_msg_div_id].show if !empty_container_msg_div_id.nil? && @down_count == 0 - page['tickler-empty-nd'].show if source_view_is(:deferred) && @down_count == 0 - - # show new todo if the completed todo was recurring - if @todo.from_recurring_todo? - unless @new_recurring_todo.nil? || @new_recurring_todo.deferred? - page.call "todoItems.ensureVisibleWithEffectAppear", item_container_id(@new_recurring_todo) - page.insert_html :bottom, item_container_id(@new_recurring_todo), :partial => 'todos/todo', :locals => { :todo => @new_recurring_todo, :parent_container_type => parent_container_type } - page.visual_effect :highlight, dom_id(@new_recurring_todo, 'line'), {'startcolor' => "'#99ff99'"} - page.notify :notice, t('todos.recurring_action_deleted'), 6.0 - else - if @todo.recurring_todo.todos.active.count == 0 - page.notify :notice, t('todos.completed_recurrence_completed'), 6.0 if @new_recurring_todo.nil? - end - end - end - - # Activate pending todos that are successors of the deleted - @pending_to_activate.each do |t| - logger.debug "#300: Removing #{t.description} from pending block and adding it to active" - page[t].remove if source_view_is(:project) or source_view_is(:tag) - page.insert_html :bottom, item_container_id(t), :partial => 'todos/todo', :locals => { :todo => t, :parent_container_type => parent_container_type } - page.visual_effect :highlight, dom_id(t, 'line'), {'startcolor' => "'#99ff99'", :duration => 2} - end -else - page.notify :error, t('todos.error_deleting_item', :description => @todo.description), 8.0 -end +<%- if @saved -%> + TracksPages.page_notify('notice', '<%= escape_javascript("The action was deleted succesfully") %>', 5); + TracksPages.set_page_badge(<%=@down_count%>); + remove_todo_from_page(); + show_new_todo_if_todo_was_recurring(); + activate_pending_todos(); + 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 -%> + $('#<%=empty_container_msg_div_id%>').slideDown(1000); + <% end -%> +} + +function remove_todo_from_page() { + <% if (@remaining_in_context == 0) + # remove context with deleted todo + -%> + $('#c<%=@todo.context_id%>').fadeOut(1000, function() { + $('#<%=dom_id(@todo)%>').remove(); + }); + <% else + # remove only the todo + -%> + $('#<%=dom_id(@todo)%>').slideUp(1000, function() { + $('#<%=dom_id(@todo)%>').remove(); + }); + <% end -%> +} + +function show_new_todo_if_todo_was_recurring() { + <% if @todo.from_recurring_todo? -%> + <% unless @new_recurring_todo.nil? || @new_recurring_todo.deferred? -%> + TodoItemsContainer.ensureVisibleWithEffectAppear("<%=item_container_id(@new_recurring_todo)%>"); + $('#<%=item_container_id(@new_recurring_todo)%>').append(html_for_new_recurring_todo()); + $('#<%= dom_id(@new_recurring_todo, 'line')%>').effect('highlight', {}, 2000 ); + TracksPages.page_notify('notice', "Action was deleted. Because this action is recurring, a new action was added", 5); + <% else -%> + <% if @todo.recurring_todo.todos.active.count == 0 && @new_recurring_todo.nil? -%> + TracksPages.page_notify('notice', "There is no next action after the recurring action you just deleted. The recurrence is completed", 5); + <% end -%> + <% end -%> + <% end -%> +} + +function activate_pending_todos() { + <% # Activate pending todos that are successors of the deleted -%> + <% @pending_to_activate.each do |t| -%> + <% if source_view_is(:project) or source_view_is(:tag) %> + $('#<%=dom_id(t)%>').remove(); + <% end -%> + $('#<%=item_container_id(t)%>').append("<%=escape_javascript(render(:partial => 'todos/todo', :locals => { :todo => t, :parent_container_type => parent_container_type }))%>"); + $('#<%= dom_id(t, 'line')%>').effect('highlight', {}, 2000 ); + <% end -%> +} + +function html_for_new_recurring_todo() { + return "<%= @saved && @new_recurring_todo ? escape_javascript(render(:partial => 'todos/todo', :locals => { :todo => @new_recurring_todo, :parent_container_type => parent_container_type })) : "" %>"; +} + +<% end + # if @saved +-%> +>>>>>>> get destroying of actions working diff --git a/app/views/todos/toggle_star.js.erb b/app/views/todos/toggle_star.js.erb index 0787920d..e760f8e2 100644 --- a/app/views/todos/toggle_star.js.erb +++ b/app/views/todos/toggle_star.js.erb @@ -1,3 +1,5 @@ <% if @saved -%> $('div#line_todo_<%= @todo.id %> a.star_item img').toggleClass('starred_todo').toggleClass('unstarred_todo'); +<% else -%> + TracksPages.page_notify('error', "Could not toggle the star of this todo", 5); <% end -%> diff --git a/features/calendar.feature b/features/calendar.feature new file mode 100644 index 00000000..3e6891f8 --- /dev/null +++ b/features/calendar.feature @@ -0,0 +1,19 @@ +Feature: dependencies + As a Tracks user + In order to keep overview of my due todos + I want to manage due todos in a calendar view + + Background: + Given the following user record + | login | password | is_admin | + | testuser | secret | false | + And I have logged in as "testuser" with password "secret" + + Scenario: Setting due date of a todo will show it in the calendar + Given this is a pending scenario + + Scenario: Clearing the due date of a todo will remove it from the calendar + Given this is a pending scenario + + Scenario: Changing due date of a todo will move it in the calendar + Given this is a pending scenario diff --git a/features/dependencies.feature b/features/dependencies.feature index 6cd6594a..6b5d2af0 100644 --- a/features/dependencies.feature +++ b/features/dependencies.feature @@ -9,7 +9,7 @@ Feature: dependencies | testuser | secret | false | And I have logged in as "testuser" with password "secret" - @selenium + @selenium @wip Scenario: Adding dependency to dependency Given I have a project "dependencies" with 3 todos And "Todo 2" depends on "Todo 1" @@ -35,3 +35,6 @@ Feature: dependencies Then the dependencies of "test me" should include "test,1, 2,3" When I edit the dependency of "test me" to '"test,1, 2,3" <"@pc"; "dependencies">,"test,1, 2,3" <"@pc"; "dependencies">' Then there should not be an error + + Scenario: Deleting a predecessor will activate successors + Given this scenario is pending diff --git a/features/edit_a_todo.feature b/features/edit_a_todo.feature new file mode 100644 index 00000000..b0c5a061 --- /dev/null +++ b/features/edit_a_todo.feature @@ -0,0 +1,55 @@ +Feature: Edit a next action from every page + In order to manage a next action + As a Tracks user + I want to to be able to change the next action from every page + + 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 can toggle the star of a todo + Given this is a pending scenario + + Scenario: I can delete a todo + Given this is a pending scenario + + Scenario: Deleting the last todo in context will hide context + Given this is a pending scenario + + Scenario: Deleting the last todo in container will show empty message + Given this is a pending scenario + + Scenario: I can mark a todo complete + Given this is a pending scenario + + Scenario: I can mark a completed todo active + Given this is a pending scenario + + Scenario: I can edit a todo to move it to another context + Given this is a pending scenario + + Scenario: I can edit a todo to move it to another project + Given this is a pending scenario + + Scenario: I can edit a todo to move it to the tickler + Given this is a pending scenario + + Scenario: I can defer a todo + Given this is a pending scenario + + Scenario: I can make a project from a todo + Given this is a pending scenario + + Scenario: I can show the notes of a todo + Given this is a pending scenario + + Scenario: I can tag a todo + Given this is a pending scenario + + Scenario: Clicking a tag of a todo will go to that tag page + Given this is a pending scenario + + Scenario: I can edit the tags of a todo + Given this is a pending scenario diff --git a/features/manage_users.feature b/features/manage_users.feature index 892f310d..67de4919 100644 --- a/features/manage_users.feature +++ b/features/manage_users.feature @@ -23,7 +23,7 @@ Feature: Manage users Then I should be on the manage users page And I should see "new.user" - @selenium + @selenium @wip Scenario: Delete account from users page When I go to the manage users page And I delete the user "testuser" diff --git a/features/project_edit.feature b/features/project_edit.feature index 33fae5ed..375c58cf 100644 --- a/features/project_edit.feature +++ b/features/project_edit.feature @@ -68,7 +68,7 @@ Feature: Edit a project Then the badge should show 2 # "manage me" and "test" When I try to edit the project name of "manage me" to "test" Then I should see "Name already exists" - + @selenium Scenario: I can add a note to the project Given I have a project called "test" @@ -89,4 +89,7 @@ Feature: Edit a project When I visit the "test" project And I add a note "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890TOO LONG" to the project Then I should not see "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890TOO LONG" - And I should see "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456" \ No newline at end of file + And I should see "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456" + + Scenario: Cancelling editing a project will restore project settings + Given this scenario is pending diff --git a/features/recurring_todos.feature b/features/recurring_todos.feature index 40849d57..2792bec8 100644 --- a/features/recurring_todos.feature +++ b/features/recurring_todos.feature @@ -25,7 +25,7 @@ Feature: Manage recurring todos When I select "Daily" recurrence pattern Then I should see the form for "Daily" recurrence pattern - @selenium + @selenium Scenario: I can mark a repeat pattern as starred When I go to the repeating todos page And I star the pattern "run tests" @@ -54,10 +54,19 @@ Feature: Manage recurring todos And the state list "active" should be empty @selenium - Scenario: I can reactivate a repeat pattern + Scenario: I can reactivate a repeat pattern Given I have a completed repeat pattern "I'm done" When I go to the repeating todos page Then the pattern "I'm done" should be in the state list "completed" When I mark the pattern "I'm done" as active Then the pattern "I'm done" should be in the state list "active" - And the state list "completed" should be empty \ No newline at end of file + And the state list "completed" should be empty + + Scenario: Following the recurring todo link of a todo takes me to the recurring todos page + Given this is a pending scenario + + Scenario: Deleting a recurring todo with ending pattern will show message + Given this is a pending scenario + + Scenario: Deleting a recurring todo with active pattern will show new todo + Given this is a pending scenario diff --git a/features/shared_add_new_todo.feature b/features/shared_add_new_todo.feature index 092ca0d8..de7f9211 100644 --- a/features/shared_add_new_todo.feature +++ b/features/shared_add_new_todo.feature @@ -119,6 +119,24 @@ Feature: Add new next action from every page | visit | context page for "test context" | see | 2 | 3 | | visit | tag page for "starred" | not see | 0 | 3 | + Scenario: Adding a todo to another project does not show the todo + Given this is a pending scenario + + Scenario: Adding a todo to a hidden project does not show the todo + Given this is a pending scenario + + Scenario: Adding a todo with a new context shows the new context + Given this is a pending scenario + + Scenario: Adding a todo to a hidden context does not show the todo + Given this is a pending scenario + + Scenario: Adding a todo to an empty container hides the empty message + Given this is a pending scenario + + Scenario: Adding a dependency to a todo updated the successor + Given this is a pending scenario + @selenium Scenario: I need to fill in at least one description and a context When I go to the home page @@ -133,4 +151,4 @@ Feature: Add new next action from every page """ - 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" diff --git a/public/javascripts/application.js b/public/javascripts/application.js index db04829a..e46206ea 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -203,7 +203,7 @@ var TracksPages = { $(".alert").fadeOut(8000); /* for edit project form and edit todo form - * TODO: refactor to separate calls from project and todo */ + * TODO: refactor to separate calls from project and todo */ $('.edit-form a.negative').live('click', function(){ $(this).parents('.edit-form').fadeOut(200, function () { $(this).parents('.list').find('.project').fadeIn(500); @@ -331,15 +331,14 @@ var TodoItems = { /* set behavior for star icon */ $(".item-container a.star_item").live('click', function (ev){ - $.post(this.href, { - _method: 'put' - }, null, 'script'); + put_with_ajax_and_block_element(this.href, $(this)); return false; }); /* set behavior for toggle checkboxes for Recurring Todos */ $(".item-container input.item-checkbox").live('click', function(ev){ put_with_ajax_and_block_element(this.value, $(this)); + return false; }); /* set behavior for edit icon */ @@ -347,6 +346,15 @@ var TodoItems = { get_with_ajax_and_block_element(this.href, $(this).parents(".item-container")); return false; }); + + /* delete button to delete a project from the list + * :with => "'#{parameters}'",*/ + $('.item-container a.icon_delete_item').live('click', function(evt){ + if(confirm(this.title)){ + delete_with_ajax_and_block_element(this.href, $(this).parents('.project')); + } + return false; + }); } } @@ -383,7 +391,6 @@ var ProjectListPage = { return(value); }, setup_behavior: function() { - /* in-place edit of project name */ $('h2#project_name').editable(ProjectListPage.save_project_name, { style: 'padding:0px', @@ -726,10 +733,11 @@ function generic_get_script_for_list(element, getter, param){ } function default_ajax_options_for_submit(ajax_type, element_to_block) { - return { + options = { type: ajax_type, async: true, context: element_to_block, + data: "_source_view=" + encodeURIComponent( SOURCE_VIEW ), beforeSend: function() { $(this).block({ message: null @@ -743,6 +751,9 @@ function default_ajax_options_for_submit(ajax_type, element_to_block) { TracksPages.page_notify('error', 'There was an error retrieving from server: '+status, 8); } } + if(typeof(TAG_NAME) !== 'undefined') + options.data += "&_tag_name="+ encodeURIComponent (TAG_NAME); + return options; } function default_ajax_options_for_scripts(ajax_type, the_url, element_to_block) { @@ -766,9 +777,7 @@ function post_with_ajax_and_block_element(the_url, element_to_block) { function put_with_ajax_and_block_element(the_url, element_to_block) { options = default_ajax_options_for_scripts('POST', the_url, element_to_block); - options.data = '_method=put'; - if(typeof(TAG_NAME) !== 'undefined') - options.data += "&_tag_name="+ encodeURIComponent (TAG_NAME); + options.data += '&_method=put'; $.ajax(options); } @@ -793,10 +802,7 @@ $(document).ajaxSend(function(event, request, settings) { }); function setup_periodic_check(url_for_check, interval_in_sec, method) { - ajaxMethod = "GET" - if (method) { - ajaxMethod = method; - } + ajaxMethod = (method ? method : "GET"); function check_remote() { $.ajax({