diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 41d2b80e..163263c9 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -125,9 +125,7 @@ class ProjectsController < ApplicationController @project_not_done_counts[@project.id] = @project.reload().not_done_todos_including_hidden.count end @contexts = current_user.contexts - @active_projects_count = current_user.projects.active.count - @hidden_projects_count = current_user.projects.hidden.count - @completed_projects_count = current_user.projects.completed.count + update_state_counts init_data_for_sidebar render :template => 'projects/update.js.erb' return @@ -166,11 +164,12 @@ class ProjectsController < ApplicationController def destroy @project.recurring_todos.each {|rt| rt.remove_from_project!} @project.destroy - @active_projects_count = current_user.projects.active.count - @hidden_projects_count = current_user.projects.hidden.count - @completed_projects_count = current_user.projects.completed.count + respond_to do |format| - format.js { @down_count = current_user.projects.size } + format.js { + @down_count = current_user.projects.size + update_state_counts + } format.xml { render :text => "Deleted project #{@project.name}" } end end @@ -201,7 +200,16 @@ class ProjectsController < ApplicationController end protected - + + def update_state_counts + @active_projects_count = current_user.projects.active.count + @hidden_projects_count = current_user.projects.hidden.count + @completed_projects_count = current_user.projects.completed.count + @show_active_projects = @active_projects_count > 0 + @show_hidden_projects = @hidden_projects_count > 0 + @show_completed_projects = @completed_projects_count > 0 + end + def render_projects_html lambda do @page_title = t('projects.list_projects') diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 8ab0f8f6..75d110be 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -110,6 +110,12 @@ module ApplicationHelper def link_to_project(project, descriptor = sanitize(project.name)) link_to( descriptor, project_path(project), :title => "View project: #{project.name}" ) end + + def link_to_edit_project (project, descriptor = sanitize(project.name)) + link_to(descriptor, + url_for({:controller => 'projects', :action => 'edit', :id => project.id}), + {:id => "link_edit_#{dom_id(project)}", :class => "project_edit_settings"}) + end def link_to_project_mobile(project, accesskey, descriptor = sanitize(project.name)) link_to( descriptor, project_path(project, :format => 'm'), {:title => "View project: #{project.name}", :accesskey => accesskey} ) diff --git a/app/views/projects/_project_listing.rhtml b/app/views/projects/_project_listing.rhtml index b6742ee5..e4e4880d 100644 --- a/app/views/projects/_project_listing.rhtml +++ b/app/views/projects/_project_listing.rhtml @@ -13,24 +13,15 @@ suppress_edit_button ||= false <%= link_to_project( project ) %><%= " (" + count_undone_todos_and_notes_phrase(project,"actions") + ")" %>
- <%= t('states.' + project.current_state.to_s).upcase %> - <%= image_tag( "blank.png", - :title => t('projects.delete_project'), - :class=>"delete_item") %> + <%= project.current_state.to_s.upcase %> + + + <%= image_tag( "blank.png", :title => t('projects.delete_project'), :class=>"delete_item") %> + <% unless suppress_edit_button -%> - <%= link_to_remote( - image_tag( "blank.png", :title => t('projects.edit_project_title'), :class=>"edit_item"), - :url => {:controller => 'projects', :action => 'edit', :id => project.id}, - :method => 'get', - :with => "'_source_view=#{@source_view}'", - :before => "$('#{dom_id(project)}').block({message:null});", - :complete => "$('#{dom_id(project)}').unblock();enable_rich_interaction();", - :html => {:id => "link_edit_#{dom_id(project)}"} - ) %> - + <%= link_to_edit_project(project, image_tag( "blank.png", :title => t('projects.edit_project_title'), :class=>"edit_item")) %> <% end -%>
diff --git a/app/views/projects/_project_settings.rhtml b/app/views/projects/_project_settings.rhtml index cf3e18a1..954a486e 100644 --- a/app/views/projects/_project_settings.rhtml +++ b/app/views/projects/_project_settings.rhtml @@ -14,16 +14,7 @@ <% else -%> '<%= project.default_tags -%>' as the default tags. <% end -%> - Edit Project Settings - <%#= link_to_remote( - "", - :url => {:controller => 'projects', :action => 'edit', :id => project.id}, - :method => 'get', - :with => "'_source_view=#{@source_view}'", - :before => "$('#{dom_id(project)}').block({message: null});", - :complete => "$('#{dom_id(project)}').unblock();enable_rich_interaction();", - :html => {:id => "link_edit_#{dom_id(project)}"} - ) %> + <%= link_to_edit_project(project, "Edit Project Settings") %> <% unless project.description.blank? -%>
<%= format_note(project.description) %>
diff --git a/app/views/projects/destroy.js.erb b/app/views/projects/destroy.js.erb new file mode 100644 index 00000000..38494a21 --- /dev/null +++ b/app/views/projects/destroy.js.erb @@ -0,0 +1,12 @@ +remove_deleted_project(); +ProjectListPage.update_state_count(<%=@active_projects_count%>, <%=@hidden_projects_count%>, <%=@completed_projects_count%>) +ProjectListPage.show_or_hide_state_container(<%= @show_active_projects %>, <%= @show_hidden_projects %>, <%= @show_completed_projects %>); +page_notify('notice', "Deleted project '#{@project.name}'", 5); +set_page_badge(<%=@down_count%>); + +function remove_deleted_project() { + $('div#<%=dom_id(@project, "container")%>').slideUp(1000, + function() { + $('div#<%=dom_id(@project, "container")%>').remove() + }); +} diff --git a/app/views/projects/destroy.js.rjs b/app/views/projects/destroy.js.rjs deleted file mode 100644 index 18e22540..00000000 --- a/app/views/projects/destroy.js.rjs +++ /dev/null @@ -1,13 +0,0 @@ -page.visual_effect :fade, dom_id(@project, "container"), :duration => 0.5 -page.delay(0.5) do - page[dom_id(@project, "container")].remove - page.replace_html "active-projects-count", @active_projects_count - page.replace_html "hidden-projects-count", @hidden_projects_count - page.replace_html "completed-projects-count", @completed_projects_count - page.set_element_visible("list-hidden-projects-container", @hidden_projects_count > 0) - page.set_element_visible("list-active-projects-container", @active_projects_count > 0) - page.set_element_visible("list-completed-projects-container", @completed_projects_count > 0) -end -page.notify :notice, "Deleted project '#{@project.name}'", 5.0 -page['badge_count'].replace_html @down_count -page.hide "busy" diff --git a/app/views/projects/edit.js.erb b/app/views/projects/edit.js.erb index 2d2e7cd2..6c4d3875 100644 --- a/app/views/projects/edit.js.erb +++ b/app/views/projects/edit.js.erb @@ -1,5 +1,5 @@ newHtml = "<%= escape_javascript(render(:partial => 'project_form', :locals => { :project_form => @project })) %>" $('div#<%=dom_id(@project, 'edit')%>').html(newHtml); $('div#<%=dom_id(@project)%>').hide(); -$('div#<%=dom_id(@project, 'edit')%>').show(); +$('div#<%=dom_id(@project, 'edit')%>').show(500); $('input.project-name').focus(); diff --git a/app/views/projects/update.js.erb b/app/views/projects/update.js.erb index c97de018..fb4c7aeb 100644 --- a/app/views/projects/update.js.erb +++ b/app/views/projects/update.js.erb @@ -1,69 +1,101 @@ <% if @saved -%> + pageNotify('notice', '<%=t('projects.project_saved_status')%>', 5); + <% if source_view_is :project_list -%> + <% if @state_changed -%> - <% else # TODO!!!-%> + remove_project(); + add_project(); + <% else -%> + replace_project(); <% end -%> - <% else # source_view must be :project %> - $('#<%=dom_id(@project, 'edit')%>').hide(); - $('#<%=dom_id(@project, 'container')%>').html("<%= escape_javascript(render(:partial => 'project_settings', :locals => { :project => @project })) %> "); - $('#<%=dom_id(@project)%>').show(); - $('input#todo_project_name').val("<%= escape_javascript(@project.name)%>"); + + update_sortable(); + ProjectListPage.update_state_count(<%=@active_projects_count%>, <%=@hidden_projects_count%>, <%=@completed_projects_count%>) + ProjectListPage.show_or_hide_state_container(<%= @show_active_projects %>, <%= @show_hidden_projects %>, <%= @show_completed_projects %>); + + <% else # assume source_view :project %> + + remove_project_edit_form(); + update_and_show_project_settings(); + + TracksForm.set_project_name("<%= escape_javascript(@project.name)%>"); <% if @project.default_context %> - $('input#todo_context_name').val("<%= escape_javascript(@project.default_context.name)%>"); - $('input[name=default_context_name]').val('<%= escape_javascript(@project.default_context.name)%>'); + TracksForm.set_context_name_and_default_context_name("<%= escape_javascript(@project.default_context.name)%>"); <% end %> <% if @project.default_tags %> - $('input#tag_list').val("<%= escape_javascript(@project.default_tags)%>"); + TracksForm.set_tag_list("<%= escape_javascript(@project.default_tags)%>"); <% end %> + + update_sidebar(); + <% end %> - $('#default_project_name_id').val('<%= escape_javascript(@project.name)%>'); - $('input#todo_project_name').val("<%= escape_javascript(@project.name)%>"); - $('#project_name').html("<%= escape_javascript(@project.name)%>"); - $('#sidebar').html("<%= escape_javascript(render(:file => 'sidebar/sidebar.html.erb')) %>"); + + TracksForm.set_project_name_and_default_project_name("<%= escape_javascript(@project.name)%>"); + <% else -%> - $('div#error_status').html("<%= escape_javascript(error_messages_for('project')) %>"); - $('div#error_status').show(); + show_errors(); <% end %> + enable_rich_interaction(); -<%# *page << "console.log(\"hello\");"%> -<%# *if @saved%> -<%# *status_message = 'Project saved'%> -<%# *page.notify :notice, status_message, 5.0%> -<%# *if source_view_is :project_list%> -<%# *if @state_changed%> -<%#*page[dom_id(@project, 'container')].remove%> -<%#*page.insert_html :bottom, "list-#{@project.state}-projects", :partial => 'project_listing', :object => @project%> -<%# *else%> -<%#*page.replace_html dom_id(@project, 'container'), :partial => 'project_listing', :object => @project%> -<%# *end%> -<%#*page.sortable "list-#{@project.state}-projects", get_listing_sortable_options("list-#{@project.state}-projects")%> -<%#*page.replace_html "active-projects-count", @active_projects_count%> -<%#*page.replace_html "hidden-projects-count", @hidden_projects_count%> -<%#*page.replace_html "completed-projects-count", @completed_projects_count%> +function show_errors() { + $('div#error_status').html(html_for_error_messages()); + $('div#error_status').show(); +} -<%#*page.set_element_visible("list-hidden-projects-container", @hidden_projects_count > 0)%> -<%#*page.set_element_visible("list-active-projects-container", @active_projects_count > 0)%> -<%#*page.set_element_visible("list-completed-projects-container", @completed_projects_count > 0)%> -<%# *else%> -<%# *page[dom_id(@project, 'edit')].hide%> -<%# *page.replace_html dom_id(@project, 'container'), :partial => 'project_settings', :locals => { :project => @project }%> -<%# *page[dom_id(@project)].show%> +function remove_project_edit_form() { + $('#<%=dom_id(@project, 'edit')%>').hide(500); +} -<%# *page['todo_context_name'].value = @project.default_context.name if @project.default_context%> -<%# *page['#todo_project_name'].value = @project.name%> -<%# *page['tag_list'].value = @project.default_tags if @project.default_tags%> -<%# *page << "$('input[name=default_context_name]').val('#{@project.default_context.name}');" if @project.default_context%> -<%# *end%> +function update_and_show_project_settings() { + $('#<%=dom_id(@project, 'container')%>').html(html_for_project_settings()); + $('#<%=dom_id(@project)%>').show(); +} -<%# *page['default_project_name_id'].value = @project.name%> -<%# *page['todo_project_name'].value = @project.name%> -<%# *page.replace_html "project_name", @project.name%> +function update_sidebar() { + $('#sidebar').html(); +} -<%# *page.replace_html "sidebar", :file => 'sidebar/sidebar.html.erb'%> -<%# *else%> -<%# *page.show 'error_status'%> -<%# *page.replace_html 'error_status', "#{error_messages_for('project')}"%> -<%# *end%> -<%# *page << "enable_rich_interaction();"%> +function update_sortable() { + <%#* page.sortable "list-#{@project.state}-projects", get_listing_sortable_options("list-#{@project.state}-projects")%> + console.log("Pending: update_sortable() on update project"); +} + +function replace_project() { + $('#<%=dom_id(@project, 'container')%>').fadeOut(500, function() { + $('#<%=dom_id(@project, 'container')%>').html(html_for_project_listing()); + $('#<%=dom_id(@project, 'container')%>').fadeIn(500); + }); +} + +function remove_project() { + $('#<%=dom_id(@project, 'container')%>').slideUp(500, function() { + $('#<%=dom_id(@project, 'container')%>').remove();}); +} + +function add_project() { + $('#list-<%=@project.state%>-projects').append(html_for_project_listing); +} + +<% +# the following functions return empty string if rendering the partial is not +# necessary, for example the sidebar is not on the project list page, so do not +# render it into the function. +-%> +function html_for_project_listing() { + return "<%= source_view_is(:project_list) ? escape_javascript(render(:partial => 'project_listing', :locals => { :project_listing => @project })) : "" %>"; +} + +function html_for_sidebar() { + return "<%= source_view_is(:project) ? escape_javascript(render(:file => 'sidebar/sidebar.html.erb')) : "" %>"; +} + +function html_for_project_settings() { + return "<%= source_view_is(:project) ? escape_javascript(render(:partial => 'project_settings', :locals => { :project => @project })) : "" %>"; +} + +function html_for_error_messages() { + return "<%= escape_javascript(error_messages_for('project')) %>"; +} diff --git a/features/manage_list_of_projects.feature b/features/manage_list_of_projects.feature index 14822f4a..e39cb6b7 100644 --- a/features/manage_list_of_projects.feature +++ b/features/manage_list_of_projects.feature @@ -17,7 +17,7 @@ Feature: Manage the list of projects When I go to the projects page Then I should see "manage me" And I should see "upgrade jquery" - And the badge should show 2 + And the badge should show 3 Scenario: Clicking on a project takes me to the project page When I go to the projects page @@ -27,12 +27,26 @@ Feature: Manage the list of projects @selenium Scenario: Editing a project name will update the list When I go to the projects page - And I edit the project name for "manage me" to "manage him" + And I edit the project name of "manage me" to "manage him" Then I should see "manage him" - Scenario: Dragging a project to change list order of projects + @selenium Scenario: Deleting a project will remove it from the list + When I go to the projects page + And I delete project "manage me" + Then I should not see "manage me" + And the badge should show 2 + And the project list badge for "active" projects should show 2 + + @selenium Scenario: Changing project state will move project to other state list + When I go to the projects page + Then the project "manage me" should be in state list "active" + When I edit the project state of "manage me" to "hidden" + Then the project "manage me" should not be in state list "active" + And the project "manage me" should be in state list "hidden" + + Scenario: Dragging a project to change list order of projects Scenario: Adding a new project Scenario: Adding a new project and take me to the project page Scenario: Hiding and unhiding the new project form diff --git a/features/step_definitions/project_list_steps.rb b/features/step_definitions/project_list_steps.rb new file mode 100644 index 00000000..4390112f --- /dev/null +++ b/features/step_definitions/project_list_steps.rb @@ -0,0 +1,14 @@ +When /^I delete project "([^"]*)"$/ do |project_name| + # from the project list page + project = @current_user.projects.find_by_name(project_name) + project.should_not be_nil + click_link "delete_project_#{project.id}" + selenium.get_confirmation.should == "Are you sure that you want to delete the project '#{project_name}'?" + wait_for do + !selenium.is_element_present("delete_project_#{project.id}") + end +end + +Then /^the project list badge for "([^"]*)" projects should show (\d+)$/ do |state_name, count| + selenium.get_text("css=span##{state_name}-projects-count").should == count +end \ No newline at end of file diff --git a/features/step_definitions/project_steps.rb b/features/step_definitions/project_steps.rb index d1733bfa..d380bc1a 100644 --- a/features/step_definitions/project_steps.rb +++ b/features/step_definitions/project_steps.rb @@ -42,12 +42,14 @@ end When /^I edit the project name to "([^\"]*)"$/ do |new_title| click_link "link_edit_project_#{@project.id}" + + # no need to wait for the form because the AJAX loading should not be async! fill_in "project[name]", :with => new_title # changed to make sure selenium waits until the saving has a result either # positive or negative. Was: :element=>"flash", :text=>"Project saved" # we may need to change it back if you really need a positive outcome, i.e. - # this step needs to fail if the project was not saved succesfully + # this step needs to fail if the project was not saved successfully selenium.click "submit_project_#{@project.id}", :wait_for => :text, :text => /(Project saved|1 error prohibited this project from being saved)/ diff --git a/public/javascripts/application.js b/public/javascripts/application.js index c5f2334b..1ccf4919 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -26,6 +26,37 @@ var TracksForm = { toggle_overlay: function () { el = document.getElementById("overlay"); el.style.visibility = (el.style.visibility == "visible") ? "hidden" : "visible"; + }, + set_project_name: function (name) { + $('input#todo_project_name').val(name); + }, + set_context_name_and_default_context_name: function (name) { + $('input#todo_context_name').val(name); + $('input[name=default_context_name]').val(name); + }, + set_project_name_and_default_project_name: function (name) { + $('#default_project_name_id').val(name); + $('input#todo_project_name').val(); + $('#project_name').html(name); + }, + set_tag_list: function (name) { + $('input#tag_list').val(name); + } +} + +var ProjectListPage = { + update_state_count: function (active, hidden, completed) { + $('#active-projects-count').html(active); + $('#hidden-projects-count').html(hidden); + $('#completed-projects-count').html(completed); + }, + show_or_hide_state_container: function (show_active, show_hidden, show_completed) { + active = $('#list-active-projects-container'); + hidden = $('#list-hidden-projects-container'); + completed = $('#list-completed-projects-container'); + if (show_active) { active.show(); } else { active.hide(); } + if (show_hidden) { hidden.show(); } else { hidden.hide(); } + if (show_completed) { completed.show(); } else { completed.hide(); } } } @@ -282,10 +313,11 @@ function enable_rich_interaction(){ $('h2#project_name').editable(save_project_name, {style: 'padding:0px', submit: "OK"}); - /* set behavior for edit project settings link */ + /* set behavior for edit project settings link */ $("a.project_edit_settings").live('click', function (ev) { $.ajax({ url: this.href, + async: true, project_dom_id: 'project_'+this.id, dataType: 'script', beforeSend: function() {$(this.project_dom_id).block({message: null});}, @@ -314,7 +346,7 @@ function setup_auto_refresh(interval){ }); } -function pageNotify(type, message, fade_duration_in_sec) { +function page_notify(type, message, fade_duration_in_sec) { flash = $('h4#flash'); flash.html("

"+message+"

"); flash = $('h4#flash'); @@ -322,6 +354,10 @@ function pageNotify(type, message, fade_duration_in_sec) { flash.fadeOut(fade_duration_in_sec*1000); } +function set_page_badge(count) { + $('#badge_count').html(count); +} + function setup_periodic_check(url_for_check, interval_in_sec, method) { ajaxMethod = "GET" if (method) { ajaxMethod = method; }