+
+<% end %>
diff --git a/app/views/todos/_todo.html.erb b/app/views/todos/_todo.html.erb
index 1600ec91..cade8e29 100644
--- a/app/views/todos/_todo.html.erb
+++ b/app/views/todos/_todo.html.erb
@@ -37,9 +37,7 @@ parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag'
- <% form_remote_tag_edit_todo do -%>
- <% #note: edit form will load here remotely -%>
-
- <% end -%>
+ <% #note: edit form will load here remotely -%>
+
\ No newline at end of file
diff --git a/app/views/todos/check_deferred.js.erb b/app/views/todos/check_deferred.js.erb
index f5cef365..ecd8bed6 100644
--- a/app/views/todos/check_deferred.js.erb
+++ b/app/views/todos/check_deferred.js.erb
@@ -1,4 +1,3 @@
-unless @due_tickles.empty?
- #TODO: why not just add the new items here in addition to notifying?
- page.notify :notice, t('todos.tickler_items_due', :count => @due_tickles.length), 5.0
-end
\ No newline at end of file
+<% unless @due_tickles.empty? -%>
+ TracksPages.page_notify('notice', "<%=t('todos.tickler_items_due', :count => @due_tickles.length)%>", 5);
+<% end -%>
diff --git a/app/views/todos/create.js.erb b/app/views/todos/create.js.erb
index f42079d0..fab9c6b5 100644
--- a/app/views/todos/create.js.erb
+++ b/app/views/todos/create.js.erb
@@ -40,6 +40,7 @@ function insert_new_context_with_new_todo() {
function add_todo_to_existing_context() {
<% if source_view_is_one_of(:todo, :deferred, :tag) -%>
TodoItemsContainer.ensureVisibleWithEffectAppear("c<%=@todo.context_id%>");
+ $('#<%=empty_container_msg_div_id%>').hide();
<% end -%>
$('#<%=item_container_id(@todo)%>').append(html_for_new_todo());
$('#<%= dom_id(@todo)%>').effect('highlight', {}, 2000 );
diff --git a/app/views/todos/edit.js.erb b/app/views/todos/edit.js.erb
index 55c57c34..a836ca32 100644
--- a/app/views/todos/edit.js.erb
+++ b/app/views/todos/edit.js.erb
@@ -1,5 +1,17 @@
-page[dom_id(@todo, 'form')].find('.placeholder').show().replace_html :partial => 'todos/edit_form'
-page[dom_id(@todo, 'edit')].show
-page[dom_id(@todo, 'line')].hide
-page[dom_id(@todo, 'form')].find('input#todo_description').show().focus
-page << "enable_rich_interaction();"
\ No newline at end of file
+hide_todo();
+replace_placeholder_with_form();
+enable_rich_interaction();
+
+function hide_todo() {
+ $('#<%= dom_id(@todo, 'line') %>').hide();
+}
+
+function replace_placeholder_with_form() {
+ $('#<%=dom_id(@todo, 'edit')%>').html(html_for_edit_form());
+ $('#<%=dom_id(@todo, 'edit')%>').show();
+ $('#<%=dom_id(@todo, 'form')%> input#todo_description').focus();
+}
+
+function html_for_edit_form() {
+ return "<%= escape_javascript(render(:partial => 'todos/edit_form', :object => @todo)) %>"
+}
\ No newline at end of file
diff --git a/app/views/todos/update.js.erb b/app/views/todos/update.js.erb
index e6d53500..5970d323 100644
--- a/app/views/todos/update.js.erb
+++ b/app/views/todos/update.js.erb
@@ -1,164 +1,136 @@
-if @saved
- # show update message
- status_message = @todo.deferred? ? t('todos.action_saved_to_tickler') : t('todos.action_saved')
- status_message = t('todos.added_new_project') + ' / ' + status_message if @new_project_created
- status_message = t('todos.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)
- if @context_changed || @todo.deferred? || @todo.pending?
- page[@todo].remove
-
- if (@remaining_in_context == 0)
- # remove context container from page if empty
- if @context_changed
- source_view do |from|
- from.todo { page.visual_effect :fade, "c#{@original_item_context_id}", :duration => 0.4 }
- from.tag { page.visual_effect :fade, "c#{@original_item_context_id}", :duration => 0.4 }
- from.context { page.show "c#{@original_item_context_id}empty-nd" }
- end
- else
- source_view do |from|
- from.todo { page.visual_effect :fade, "c#{@todo.context.id}", :duration => 0.4 }
- from.tag { page.visual_effect :fade, "c#{@todo.context.id}", :duration => 0.4 }
- from.context { page.show "c#{@original_item_context_id}empty-nd" }
- end
- end
- end
+<% if !@saved -%>
+ TracksPages.show_edit_errors(html_for_error_messages());
+<% else
- if source_view_is_one_of(:todo, :tag) && @todo.active?
- page.call "todoItems.ensureVisibleWithEffectAppear", "c#{@todo.context_id}"
- page.call "todoItems.expandNextActionListingByContext", "c#{@todo.context_id}items", true
- page[empty_container_msg_div_id].hide unless empty_container_msg_div_id.nil?
- # show all todos in context
- page.insert_html :bottom, "c#{@todo.context_id}items", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
- end
+ # jquery animations are async, so first collect all animation steps,
+ # then execute them sequential. All steps are functions which are passed a function
+ # with the next animation steps
- if source_view_is(:tag) && @todo.deferred?
- # show todo in deferred container
- page.insert_html :bottom, "tickleritems", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
- page[empty_container_msg_div_id].hide unless empty_container_msg_div_id.nil?
- end
-
- # update badge count
- page.replace_html("badge_count", @remaining_in_context) if source_view_is :context
- page.replace_html("badge_count", @down_count) if source_view_is :todo
-
- # show todo in context
- 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)
- # we go from the deferred container to a context container in tag view
- page[@todo].remove
- page.call "todoItems.ensureVisibleWithEffectAppear", "c#{@todo.context_id}"
- page.call "todoItems.expandNextActionListingByContext", "c#{@todo.context_id}items", true
- page[empty_container_msg_div_id].hide unless empty_container_msg_div_id.nil?
- # show all todos in context
- page.insert_html :bottom, "c#{@todo.context_id}items", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
- page['tickler-empty-nd'].show if @deferred_tag_count == 0
- else
- page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
- end
- page.visual_effect :highlight, dom_id(@todo), :duration => 3
- end
- elsif source_view_is :project
- if @project_changed
- page[@todo].remove
- page.show("p#{@original_item_project_id}empty-nd") if (@remaining_undone_in_project == 0)
- page.replace_html "badge_count", @remaining_undone_in_project
- elsif @todo.deferred?
- page[@todo].remove
- page.show("p#{@original_item_project_id}empty-nd") if (@remaining_undone_in_project == 0)
- page.insert_html :bottom, "tickler", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
- page['tickler-empty-nd'].hide
- page.replace_html "badge_count", @down_count
- elsif @todo_was_activated_from_deferred_state
- page[@todo].remove
- page['tickler-empty-nd'].show if (@deferred_count == 0)
- page.insert_html :bottom, "p#{@todo.project_id}items", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
- page.visual_effect :highlight, dom_id(@todo), :duration => 3
- page["p#{@todo.project_id}empty-nd"].hide
- page.replace_html "badge_count", @down_count
- else
- page.replace_html "p#{@todo.project_id}items", :partial => 'todos/todo', :collection => @todo.project.not_done_todos,
- :locals => { :parent_container_type => parent_container_type }
- page.replace "tickler", :partial => 'todos/deferred', :locals => {
- :deferred => @todo.project.deferred_todos,
- :collapsible => false,
- :append_descriptor => "in this project",
- :parent_container_type => 'project',
- :pending => @todo.project.pending_todos }
- page['tickler-empty-nd'].show if (@deferred_count == 0 and @pending_count == 0)
- page.visual_effect :highlight, dom_id(@todo), :duration => 3
- end
- elsif source_view_is :deferred
- if !@todo.deferred?
- page[@todo].remove
- page.show(empty_container_msg_div_id) if (@down_count == 0)
- page.replace_html "badge_count", @down_count
- elsif @context_changed
- page[@todo].remove
- page.visual_effect(:fade, "c#{@original_item_context_id}", :duration => 0.4) if (@remaining_in_context == 0)
- page.call "todoItems.ensureVisibleWithEffectAppear", "c#{@todo.context_id}"
- page.call "todoItems.expandNextActionListingByContext", "c#{@todo.context_id}items", true
- page[empty_container_msg_div_id].hide unless empty_container_msg_div_id.nil?
- page.insert_html :bottom, "c#{@todo.context_id}items", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
- page.replace_html("badge_count", @down_count)
- page.delay(0.5) do
- page.call "todoItems.ensureContainerHeight", "c#{@original_item_context_id}items"
- page.call "todoItems.ensureContainerHeight", "c#{@todo.context_id}items"
- page.visual_effect :highlight, dom_id(@todo), :duration => 3
- end
- else
- page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
- page.visual_effect :highlight, dom_id(@todo), :duration => 3
- end
- elsif source_view_is :stats
- page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
- page.visual_effect :highlight, dom_id(@todo), :duration => 3
- elsif source_view_is :calendar
- if @due_date_changed
- page[@todo].remove
- page.show "empty_"+@original_item_due_id if @old_due_empty
- page.hide "empty_"+@new_due_id
- page.insert_html :bottom, @new_due_id, :partial => 'todos/todo', :locals => {:todo => @todo}
- page.visual_effect :highlight, dom_id(@todo), :duration => 3
- else
- if @todo.due.nil?
- # due date removed
- page[@todo].remove
- page.show "empty_"+@original_item_due_id if @old_due_empty
- else
- page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
- page.visual_effect :highlight, dom_id(@todo), :duration => 3
- end
- end
- else
- logger.error "unexpected source_view '#{params[:_source_view]}'"
+ animation = []
+ animation << "remove_todo" if update_needs_to_remove_todo_from_container
+ if replace_with_updated_todo
+ animation << "replace_todo"
+ elsif append_updated_todo
+ animation << (@new_context_created ? "insert_new_context_with_updated_todo" : "add_to_existing_container")
end
- # Update predecessors (if they exist and are visible)
- @todo.uncompleted_predecessors.each do |p|
- page << "if ($(\'#{item_container_id(p)}\')) {"
- page[p].replace_html :partial => 'todos/todo',
- :locals => { :todo => p, :parent_container_type => parent_container_type }
- page << "}"
- end
-else
- page.show 'error_status'
- page.replace_html 'error_status', "#{error_messages_for('todo')}"
-end
+ animation << "hide_context" if update_needs_to_hide_context
-page << "enable_rich_interaction();"
+ # update relevant empty messaged
+ source_view do |page|
+ page.context {
+ animation << "show_empty_message_source_container" if (@remaining_in_context == 0)
+ }
+ page.project {
+ animation << "show_empty_message_project" if (@down_count == 0)
+ if @todo_was_activated_from_deferred_state
+ animation << "show_empty_message_tickler" if @deferred_count == 0
+ animation << "hide_empty_message_project"
+ end
+ animation << "hide_empty_message_tickler" if @todo_was_deferred && (@deferred_count == 1)
+ }
+ page.deferred {
+ animation << "show_empty_message_source_container" if (@remaining_in_context == 0)
+ animation << "hide_empty_message_target_container" if (@context_changed && @target_context_count==1)
+ }
+ page.calendar {
+ animation << "show_empty_message_source_container" if @old_due_empty
+ animation << "hide_empty_message_target_container" if @todo.due
+ }
+ end
+ animation << "highlight_updated_todo"
+%>
+
+ <%= render_animation(animation) %>
+ TracksPages.page_notify('notice', '<%=@status_message%>', 5);
+ update_badge_count();
+<% end %>
+
+function remove_todo(next_steps) {
+ $('#<%= dom_id(@todo) %>').fadeOut(400, function() {
+ $('#<%= dom_id(@todo) %>').remove();
+ next_steps.go();
+ });
+}
+
+function replace_todo(next_steps) {
+ $('#<%= dom_id(@todo) %>').html(html_for_todo());
+ 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 highlight_updated_todo(next_steps) {
+ $('#<%= dom_id(@todo)%>').effect('highlight', {}, 2000, function(){ next_steps.go(); });
+}
+
+function add_to_existing_container(next_steps) {
+ $('#<%= item_container_id(@todo) %>').append(html_for_todo());
+ <% if source_view_is_one_of(:project,:calendar) -%>
+ next_steps.go();
+ <% else -%>
+ $('#c<%= @todo.context_id %>').fadeIn(500, function() { next_steps.go(); });
+ <% end -%>
+}
+
+function update_badge_count() {
+ <%
+ count = source_view_is(:context) ? @remaining_in_context : @down_count
+ count = @project_changed ? @remaining_undone_in_project : count
+ -%>
+ TracksPages.set_page_badge(<%= count %>);
+}
+
+function show_empty_message_source_container(next_steps) {
+ <% container_id = source_view_is(:calendar) ? "empty_#{@original_item_due_id}" : "c#{@original_item_context_id}empty-nd" -%>
+ $("#<%= container_id%>").slideDown(100, function() { next_steps.go(); });
+}
+
+function hide_empty_message_target_container(next_steps) {
+ <% container_id = source_view_is(:calendar) ? "empty_#{@new_due_id}" : "c#{@todo.context_id}empty-nd" -%>
+ $("#<%=container_id%>").slideUp(100, function() { next_steps.go(); });
+}
+
+function show_empty_message_project(next_steps) {<%
+ id = updated_todo_changed_deferred_state ? "p#{@todo.project_id}empty-nd" : empty_container_msg_div_id %>
+ $('#<%= id %>').slideDown(100, function() { next_steps.go(); });
+}
+
+function hide_empty_message_project(next_steps) {
+ $('#<%= empty_container_msg_div_id %>').slideUp(100, function() { next_steps.go(); });
+}
+
+function show_empty_message_tickler(next_steps) {
+ $('#tickler-empty-nd').slideDown(100, function() { next_steps.go(); });
+}
+
+function hide_empty_message_tickler(next_steps) {
+ $('#tickler-empty-nd').slideUp(100, function(){ next_steps.go(); });
+}
+
+function insert_new_context_with_updated_todo(next_steps) {
+ $('#display_box').prepend(html_for_new_context());
+ $('#c<%= @todo.context_id %>').fadeIn(500, function() { next_steps.go(); });
+}
+
+function html_for_todo() {
+ return "<%= @saved ? escape_javascript(render(:partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type })) : "" %>";
+}
+
+function html_for_new_context() {
+ return "<%= @saved && @new_context_created ? escape_javascript(render(:partial => 'contexts/context', :locals => { :context => @new_context, :collapsible => true })) : "" %>";
+}
+
+function html_for_error_messages() {
+ return "<%= escape_javascript(error_messages_for('todo')) %>";
+}
+
+function update_predecessors() {
+ <% @todo.uncompleted_predecessors.each do |p| -%>
+ if ($('#<%=item_container_id(p)%>')) {
+ $('#<%=dom_id(p)%>').html('<%=escape_javascript(render(:partial => 'todos/todo', :locals => { :todo => p, :parent_container_type => parent_container_type }))%>');
+ }
+ <% end -%>
+}
\ No newline at end of file
diff --git a/features/context_edit.feature b/features/context_edit.feature
index bc91e689..cd51bf88 100644
--- a/features/context_edit.feature
+++ b/features/context_edit.feature
@@ -18,3 +18,12 @@ Feature: Edit a context
When I go to the contexts page
Then he should see that a context named "Errands" is not present
And he should see that a context named "OutAndAbout" is present
+
+ Scenario: Editing the context of a todo will remove the todo
+ Given this scenario is pending
+
+ Scenario: Editing the description of a a todo will update that todo
+ Given this scenario is pending
+
+ Scenario: Editing the context of the last todo will remove the todo and show empty message
+ Given this scenario is pending
diff --git a/features/edit_a_todo.feature b/features/edit_a_todo.feature
index b0c5a061..40c29f41 100644
--- a/features/edit_a_todo.feature
+++ b/features/edit_a_todo.feature
@@ -27,6 +27,9 @@ Feature: Edit a next action from every page
Scenario: I can mark a completed todo active
Given this is a pending scenario
+ Scenario: I can edit a todo to change its description
+ Given this is a pending scenario
+
Scenario: I can edit a todo to move it to another context
Given this is a pending scenario
@@ -53,3 +56,9 @@ Feature: Edit a next action from every page
Scenario: I can edit the tags of a todo
Given this is a pending scenario
+
+ Scenario: Editing the context of a todo to a new context will show new context
+ Given this scenario is pending # for home and tickler and tag
+
+ Scenario: Making an error when editing a todo will show error message
+ Given this scenario is pending
\ No newline at end of file
diff --git a/features/project_edit.feature b/features/project_edit.feature
index 375c58cf..cdb43ba5 100644
--- a/features/project_edit.feature
+++ b/features/project_edit.feature
@@ -23,15 +23,6 @@ Feature: Edit a project
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
- # Ticket #1043
- @selenium @wip
- 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"
-
@selenium
Scenario: I can edit the project name in place
Given I have a project "release tracks 1.8" with 1 todos
@@ -93,3 +84,21 @@ Feature: Edit a project
Scenario: Cancelling editing a project will restore project settings
Given this scenario is pending
+
+ Scenario: Editing the description of a todo will update todo
+ Given this scenario is pending
+
+ Scenario: Moving the todo to the tickler will move todo to tickler container
+ Given this scenario is pending
+
+ Scenario: Moving the todo out of the tickler will move todo to active container
+ Given this scenario is pending
+
+ # Ticket #1043
+ @selenium @wip
+ 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/tickler.feature.feature b/features/tickler.feature.feature
new file mode 100644
index 00000000..02121f64
--- /dev/null
+++ b/features/tickler.feature.feature
@@ -0,0 +1,20 @@
+Feature: Manage deferred todos
+ In order to hide todos that require attention in the future and not now
+ As a Tracks user
+ I want to defer these and manage them in a tickler
+
+ Background:
+ Given the following user record
+ | login | password | is_admin |
+ | testuser | secret | false |
+ And there exists a project "manage me" for user "testuser"
+ And I have logged in as "testuser" with password "secret"
+
+ Scenario: Editing the description of a todo updated the todo
+ Given this scenario is pending
+
+ Scenario: Editing the context of a todo moves it to the new context
+ Given this scenario is pending
+
+ Scenario: Removing the show from date from a todo removes it from the tickler
+ Given this scenario is pending
diff --git a/public/javascripts/application.js b/public/javascripts/application.js
index e46206ea..caf1739a 100644
--- a/public/javascripts/application.js
+++ b/public/javascripts/application.js
@@ -217,7 +217,7 @@ var TracksPages = {
var TodoItemsContainer = {
// public
ensureVisibleWithEffectAppear: function(elemId){
- $('#'+elemId).fadeIn(400);
+ $('#'+elemId).fadeIn(500);
},
expandNextActionListing: function(itemsElem, skipAnimation) {
itemsElem = $(itemsElem);
@@ -347,14 +347,20 @@ var TodoItems = {
return false;
});
- /* delete button to delete a project from the list
- * :with => "'#{parameters}'",*/
+ /* delete button to delete a project from the list */
$('.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;
});
+
+ /* submit todo form after edit */
+ $("form.edit_todo_form button.positive").live('click', function (ev) {
+ submit_with_ajax_and_block_element('form.edit_todo_form', $(this));
+ return false;
+ });
+
}
}