diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 7ed770cd..6c224815 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -236,4 +236,10 @@ module ApplicationHelper source_view_is_one_of(:project, :context) ? "#{@source_view}-#{eval("@#{@source_view}.id")}" : @source_view end + # create a unique object name which can be used in ajax calls returning js + # to prevent concurrent calls with same functions to overwrite each other functions + def unique_object_name_for(name) + "#{name}_#{SecureRandom.hex(5)}" + end + end diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index e7e2649a..a0d18ee0 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -392,15 +392,21 @@ module TodosHelper return 'context' end + # jquery animations are async, so first collect all animation steps that need + # to be run sequential in array animation, then execute them. All steps are + # functions which are passed a function as parameter that should execute the next + # animation steps. + # if the animation needs to be run inside the namespace of an object, set the + # object_name to the name of the object and this name will be prepended to each step def render_animation(animation, object_name=nil) - html = "" - animation.each do |step| - if step.present? - html += (object_name.nil? ? step : "#{object_name}.#{step}") + "({ go: function() {\r\n" - end - end - html += "}}) " * animation.size - return html + ";" + object_name += "." unless object_name.nil? # add dot if object_name is given + + # concatenate all steps into functions that call functions + html = animation.map{ |step| "#{object_name}#{step}({ go: function() {" }.join("\r\n") + # close all functions + html += "}}) " * animation.size + ";" + + return html end def reset_tab_index diff --git a/app/views/contexts/edit.js.erb b/app/views/contexts/edit.js.erb index 5c03f742..0386c152 100644 --- a/app/views/contexts/edit.js.erb +++ b/app/views/contexts/edit.js.erb @@ -1,21 +1,25 @@ -replace_context_with_edit_form(); +<%- object_name = unique_object_name_for("edit_context_#{@context.id}") %> -function replace_context_with_edit_form() { - $('div#<%=dom_id(@context)%>').fadeOut(250, function() { - show_edit_form(); - set_focus(); - }); -} +var <%=object_name%> = { + animate: function() { + <%=object_name%>.replace_context_with_edit_form(); + }, + replace_context_with_edit_form: function() { + $('div#<%=dom_id(@context)%>').fadeOut(250, function() { + <%=object_name%>.show_edit_form(); + <%=object_name%>.set_focus(); + }); + }, + show_edit_form: function() { + $('div#<%=dom_id(@context, 'edit')%>').html(<%=object_name%>.html_for_edit_form()); + $('div#<%=dom_id(@context, 'edit')%>').fadeIn(500); + }, + set_focus: function() { + $('input.context-name').focus(); + }, + html_for_edit_form: function() { + return "<%= escape_javascript(render(:partial => 'context_form', :object => @context)) %>"; + } +}; -function show_edit_form() { - $('div#<%=dom_id(@context, 'edit')%>').html(html_for_edit_form()); - $('div#<%=dom_id(@context, 'edit')%>').fadeIn(500); -} - -function set_focus() { - $('input.context-name').focus(); -} - -function html_for_edit_form() { - return "<%= escape_javascript(render(:partial => 'context_form', :object => @context)) %>" -} \ No newline at end of file +<%= object_name %>.animate(); \ No newline at end of file diff --git a/app/views/contexts/update.js.erb b/app/views/contexts/update.js.erb index a663e2ea..b3492ff7 100644 --- a/app/views/contexts/update.js.erb +++ b/app/views/contexts/update.js.erb @@ -1,47 +1,50 @@ -<% unless @saved -%> - TracksPages.show_edit_errors(html_for_error_messages()); - - function html_for_error_messages() { - return "<%= escape_javascript(get_list_of_error_messages_for(@context)) %>"; - } - -<% else -%> - TracksPages.page_notify('notice', '<%= t('contexts.save_status_message') %>', 5); - - <% if @state_changed -%> - remove_and_re_add_context(); - update_container_states(); +<%- + object_name = unique_object_name_for("update_context_#{@context.id}") +-%> +var <%=object_name%> = { + <% unless @saved -%> + animate: function() { + TracksPages.show_edit_errors(<%=object_name%>.html_for_error_messages()); + }, + html_for_error_messages: function() { + return "<%= escape_javascript(get_list_of_error_messages_for(@context)) %>"; + } <% else -%> - replace_context_form_with_updated_context(); + animate: function() { + TracksPages.page_notify('notice', '<%= t('contexts.save_status_message') %>', 5); + <% if @state_changed -%> + <%=object_name%>.remove_and_re_add_context(); + <%=object_name%>.update_container_states(); + <% else -%> + <%=object_name%>.replace_context_form_with_updated_context(); + <% end -%> + }, + remove_and_re_add_context: function() { + $('#<%=dom_id(@context, 'container')%>').slideUp(500, function() { + $('#<%=dom_id(@context, 'container')%>').remove(); + $('#list-contexts-<%=@new_state%>').append(<%=object_name%>.html_for_context_listing()); + }); + }, + replace_context_form_with_updated_context: function() { + $('#<%=dom_id(@context, 'container')%>').fadeOut(250, function() { + <% + # first add the updated context after the old one, then remove old one + # using html() does not work, because it will replace the _content_ of + # the container instead of the container itself, i.e. you will get + # a container within a container which will break drag-and-drop sorting + -%> + $('#<%=dom_id(@context, 'container')%>').after(<%=object_name%>.html_for_context_listing()); + $('#<%=dom_id(@context, 'container')%>').remove(); + $('#<%=dom_id(@context, 'container')%>').fadeIn(500); + }); + }, + update_container_states: function() { + ContextListPage.update_all_states_count(<%=@active_contexts.count%>, <%=@hidden_contexts.count%>, <%=@closed_contexts.count%>); + }, + html_for_context_listing: function() { + return "<%= escape_javascript(render(:partial => 'context_listing', :object => @context))%>"; + } <% end -%> +} - function remove_and_re_add_context() { - $('#<%=dom_id(@context, 'container')%>').slideUp(500, function() { - $('#<%=dom_id(@context, 'container')%>').remove(); - $('#list-contexts-<%=@new_state%>').append(html_for_context_listing()); - }); - } - - function replace_context_form_with_updated_context() { - $('#<%=dom_id(@context, 'container')%>').fadeOut(250, function() { - <% - # first add the updated context after the old one, then remove old one - # using html() does not work, because it will replace the _content_ of - # the container instead of the container itself, i.e. you will get - # a container within a container which will break drag-and-drop sorting - -%> - $('#<%=dom_id(@context, 'container')%>').after(html_for_context_listing()); - $('#<%=dom_id(@context, 'container')%>').remove(); - $('#<%=dom_id(@context, 'container')%>').fadeIn(500); - }); - } - - function update_container_states() { - ContextListPage.update_all_states_count(<%=@active_contexts.count%>, <%=@hidden_contexts.count%>, <%=@closed_contexts.count%>); - } - - function html_for_context_listing() { - return "<%= escape_javascript(render(:partial => 'context_listing', :object => @context))%>"; - } - -<% end -%> \ No newline at end of file +<%=object_name%>.animate(); \ No newline at end of file diff --git a/app/views/projects/create.js.erb b/app/views/projects/create.js.erb index e639ebdb..33c6bc2f 100644 --- a/app/views/projects/create.js.erb +++ b/app/views/projects/create.js.erb @@ -1,4 +1,10 @@ -<% if @saved -%> +<% unless @saved -%> + TracksPages.show_errors(html_for_error_messages()); + + function html_for_error_messages() { + return "<%= escape_javascript(get_list_of_error_messages_for(@project)) %>"; + } +<% else -%> <% if @go_to_project -%> redirect_to("<%= project_path(@project) -%>") <% else -%> @@ -10,9 +16,6 @@ clear_form(); TracksPages.page_notify('notice', "Created new project '<%= @project.name%>'", 5); <% end -%> -<% else -%> - TracksPages.show_errors(html_for_error_messages()); -<% end -%> /* TODO: make this generic for all pages with lists */ function hide_empty_message() { @@ -36,10 +39,8 @@ function update_active_projects_container() { ProjectListPage.update_state_count('active', <%=@active_projects_count%>); } -function html_for_error_messages() { - return "<%= escape_javascript(get_list_of_error_messages_for(@project)) %>"; -} - function html_for_project_listing() { return "<%= @saved ? escape_javascript(render(:partial => 'project_listing', :object => @project)) : "" %>"; -} \ No newline at end of file +} + +<% end -%> \ No newline at end of file diff --git a/app/views/projects/edit.js.erb b/app/views/projects/edit.js.erb index 1f2cc465..2cbf463a 100644 --- a/app/views/projects/edit.js.erb +++ b/app/views/projects/edit.js.erb @@ -3,27 +3,29 @@ selector_edit = "div.project-edit-current " + selector_edit unless @source_view=="project" selector_project = "div##{dom_id(@project)}" selector_project = "div.project-edit-current " + selector_project unless @source_view=="project" --%> - -function html_for_edit_form() { - return "<%= escape_javascript(render(:partial => 'project_form', :object => @project)) %>"; + object_name = unique_object_name_for("edit_project_#{@project.id}") +-%> +var <%=object_name%> = { + html_for_edit_form: function() { + return "<%= escape_javascript(render(:partial => 'project_form', :object => @project)) %>"; + }, + show_edit_form: function() { + $('<%= selector_edit %>').html(<%=object_name%>.html_for_edit_form()); + $('<%= selector_edit %>').fadeIn(500); + $('span#project_name').editable('disable'); + }, + set_focus: function() { + $('input.project-name').focus(); + }, + replace_project_with_edit_form: function() { + $('<%= selector_project %>').fadeOut(250, function() { + <%=object_name%>.show_edit_form(); + <%=object_name%>.set_focus(); + }); + }, + animate: function() { + <%=object_name%>.replace_project_with_edit_form(); + } } -function show_edit_form() { - $('<%= selector_edit %>').html(html_for_edit_form()); - $('<%= selector_edit %>').fadeIn(500); - $('span#project_name').editable('disable'); -} - -function set_focus() { - $('input.project-name').focus(); -} - -function replace_project_with_edit_form() { - $('<%= selector_project %>').fadeOut(250, function() { - show_edit_form(); - set_focus(); - }); -} - -replace_project_with_edit_form(); \ No newline at end of file +<%=object_name%>.animate(); \ No newline at end of file diff --git a/app/views/projects/update.js.erb b/app/views/projects/update.js.erb index 25e84e81..8af8a202 100644 --- a/app/views/projects/update.js.erb +++ b/app/views/projects/update.js.erb @@ -1,102 +1,98 @@ -<% if @saved -%> - TracksPages.page_notify('notice', '<%=t('projects.project_saved_status')%>', 5); - <% if source_view_is_one_of(:project_list, :review) -%> - update_project_list_page(); - <% else # assume source_view :project +<%- + object_name = unique_object_name_for("update_project_#{@project.id}") +-%> +var <%=object_name%> = { + <% unless @saved -%> + animate: function(){ + TracksPages.show_edit_errors(<%=object_name%>.html_for_error_messages()); + }, + html_for_error_messages: function() { + return "<%= escape_javascript(get_list_of_error_messages_for(@project)) %>"; + } + <%- + else -%> - update_project_page(); - <% end %> -<% else -%> - TracksPages.show_edit_errors(html_for_error_messages()); -<% end %> - -<% if @saved - # only add these js functions if the project is saved --%> - -function update_project_list_page() { - <% if @state_changed -%> - remove_and_re_add_project(); - <% else -%> - replace_project_form_with_updated_project(); - <% end -%> - - ProjectListPage.update_all_states_count(<%=@active_projects_count%>, <%=@hidden_projects_count%>, <%=@completed_projects_count%>); - ProjectListPage.show_or_hide_all_state_containers(<%= @show_active_projects %>, <%= @show_hidden_projects %>, <%= @show_completed_projects %>); - TracksForm.set_project_name_and_default_project_name("<%= escape_javascript(@project.name)%>"); - $('div.project-edit-current').removeClass('project-edit-current'); + animate: function() { + TracksPages.page_notify('notice', '<%=t('projects.project_saved_status')%>', 5); + <% if source_view_is_one_of(:project_list, :review) -%> + <%=object_name%>.update_project_list_page(); + <% else # assume source_view :project -%> + <%=object_name%>.update_project_page(); + <% end %> + }, + update_project_list_page: function() { + <% if @state_changed -%> + <%=object_name%>.remove_and_re_add_project(); + <% else -%> + <%=object_name%>.replace_project_form_with_updated_project(); + <% end -%> + ProjectListPage.update_all_states_count(<%=@active_projects_count%>, <%=@hidden_projects_count%>, <%=@completed_projects_count%>); + ProjectListPage.show_or_hide_all_state_containers(<%= @show_active_projects %>, <%= @show_hidden_projects %>, <%= @show_completed_projects %>); + TracksForm.set_project_name_and_default_project_name("<%= escape_javascript(@project.name)%>"); + $('div.project-edit-current').removeClass('project-edit-current'); + }, + update_project_page: function() { + <%=object_name%>.remove_project_edit_form(); + <%=object_name%>.update_and_show_project_settings(); + TracksForm.set_project_name("<%= escape_javascript(@project.name)%>"); + $("h2 span#project_name").html("<%= escape_javascript(@project.name)%>"); + <% if @project.default_context %> + TracksForm.set_context_name_and_default_context_name("<%= escape_javascript(@project.default_context.name)%>"); + <% end %> + <% if @project.default_tags %> + TracksForm.set_tag_list_and_default_tag_list("<%= escape_javascript(@project.default_tags)%>"); + <% end %> + TracksPages.update_sidebar(<%=object_name%>.html_for_sidebar()); + }, + remove_project_edit_form: function() { + <%- + # do not remove() edit form as this will remove the DIV + # that is needed to replace with the new form, so only empty the DIV + -%> + $('#<%=dom_id(@project, 'edit')%>').hide(500, function() { + $('#<%=dom_id(@project, 'edit')%>').html(""); + }); + }, + update_and_show_project_settings: function() { + $('#<%=dom_id(@project, 'container')%>').html(<%=object_name%>.html_for_project_settings()); + $('#<%=dom_id(@project)%>').show(); + }, + replace_project_form_with_updated_project: function() { + $('div#<%=dom_id(@project, 'container')%>').each(function(index, elem) { + $(this).fadeOut(250, function() { + <% + # first add the updated project after the old one, then remove old one. + # Using html() does not work, because it will replace the _content_ of + # the container instead of the container itself, i.e. you will get + # a container within a container which will break drag-and-drop sorting + -%> + $(this).after(<%=object_name%>.html_for_project_listing()); + $(this).remove(); + $('#<%=dom_id(@project, 'container')%>').fadeIn(500); + }) + }); + }, + remove_and_re_add_project: function() { + $('#<%=dom_id(@project, 'container')%>').slideUp(500, function() { + $('#<%=dom_id(@project, 'container')%>').remove(); + $('#list-<%=@project.state%>-projects').append(<%=object_name%>.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. + -%> + html_for_project_listing: function() { + return "<%= source_view_is_one_of(:project_list, :review) ? escape_javascript(render(:partial => 'project_listing', :object => @project, :locals=>{:suppress_drag_handle => source_view_is(:review)} )) : "" %>"; + }, + html_for_sidebar: function() { + return "<%= source_view_is(:project) ? escape_javascript(render(:file => 'sidebar/sidebar')) : "" %>"; + }, + html_for_project_settings: function() { + return "<%= source_view_is(:project) ? escape_javascript(render(:partial => 'project_settings', :object => @project )) : "" %>"; + } + <% end # if @saved -%> } -function update_project_page() { - remove_project_edit_form(); - update_and_show_project_settings(); - TracksForm.set_project_name("<%= escape_javascript(@project.name)%>"); - $("h2 span#project_name").html("<%= escape_javascript(@project.name)%>"); - <% if @project.default_context %> - TracksForm.set_context_name_and_default_context_name("<%= escape_javascript(@project.default_context.name)%>"); - <% end %> - <% if @project.default_tags %> - TracksForm.set_tag_list_and_default_tag_list("<%= escape_javascript(@project.default_tags)%>"); - <% end %> - TracksPages.update_sidebar(html_for_sidebar()); -} - -function remove_project_edit_form() { -<%- - # do not remove() edit form as this will remove the DIV that is needed to replace with the new form, so only empty the DIV --%> - $('#<%=dom_id(@project, 'edit')%>').hide(500, function() { - $('#<%=dom_id(@project, 'edit')%>').html(""); - }); -} - -function update_and_show_project_settings() { - $('#<%=dom_id(@project, 'container')%>').html(html_for_project_settings()); - $('#<%=dom_id(@project)%>').show(); -} - -function replace_project_form_with_updated_project() { - $('div#<%=dom_id(@project, 'container')%>').each(function(index, elem) { - $(this).fadeOut(250, function() { -<% - # first add the updated project after the old one, then remove old one. - # Using html() does not work, because it will replace the _content_ of - # the container instead of the container itself, i.e. you will get - # a container within a container which will break drag-and-drop sorting --%> - $(this).after(html_for_project_listing()); - $(this).remove(); - $('#<%=dom_id(@project, 'container')%>').fadeIn(500); - })}); -} - -function remove_and_re_add_project() { - $('#<%=dom_id(@project, 'container')%>').slideUp(500, function() { - $('#<%=dom_id(@project, 'container')%>').remove(); - $('#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_one_of(:project_list, :review) ? escape_javascript(render(:partial => 'project_listing', :object => @project, :locals=>{:suppress_drag_handle => source_view_is(:review)} )) : "" %>"; -} - -function html_for_sidebar() { - return "<%= source_view_is(:project) ? escape_javascript(render(:file => 'sidebar/sidebar')) : "" %>"; -} - -function html_for_project_settings() { - return "<%= source_view_is(:project) ? escape_javascript(render(:partial => 'project_settings', :object => @project )) : "" %>"; -} - -<% end # if @saved --%> - -function html_for_error_messages() { - return "<%= escape_javascript(get_list_of_error_messages_for(@project)) %>"; -} \ No newline at end of file +<%=object_name%>.animate(); \ No newline at end of file diff --git a/app/views/recurring_todos/edit.js.erb b/app/views/recurring_todos/edit.js.erb index 29ddc5f6..c8033553 100644 --- a/app/views/recurring_todos/edit.js.erb +++ b/app/views/recurring_todos/edit.js.erb @@ -1,6 +1,11 @@ -$('#edit-recurring-todo').html(html_for_edit_form()); -$('#edit-recurring-todo').dialog( "open" ); - -function html_for_edit_form() { - return "<%= escape_javascript(render(:partial => 'edit_form')) %>"; +<% object_name = unique_object_name_for("edit_rec_todo_#{@recurring_todo.id}") -%> +var <%=object_name%> = { + animate: function() { + $('#edit-recurring-todo').html(<%=object_name%>.html_for_edit_form()); + $('#edit-recurring-todo').dialog( "open" ); + }, + html_for_edit_form: function() { + return "<%= escape_javascript(render(:partial => 'edit_form')) %>"; + } } +<%=object_name%>.animate(); \ No newline at end of file diff --git a/app/views/recurring_todos/toggle_check.js.erb b/app/views/recurring_todos/toggle_check.js.erb index c47127c2..df05d8f4 100644 --- a/app/views/recurring_todos/toggle_check.js.erb +++ b/app/views/recurring_todos/toggle_check.js.erb @@ -1,51 +1,51 @@ -<%- if @saved -%> - TracksPages.set_page_badge(<%= @down_count %>); - remove_old_and_add_updated_recurring_todo(); - inform_if_new_todo_created(); -<%- else -%> +<%- unless @saved -%> TracksPages.page_notify('error', '<%= t('todos.error_completing_todo', :description => @recurring_todo.description) %>', 8); -<%- end -%> - -function inform_if_new_todo_created() { - <%- unless @new_recurring_todo.nil? -%> - TracksPages.page_notify('notice', '<%= t('todos.new_related_todo_created') %>', 5); - <%- end -%> -} - -function remove_old_and_add_updated_recurring_todo() { - $('#<%=dom_id(@recurring_todo)%>').slideUp(1000, function() { - $('#<%=dom_id(@recurring_todo)%>').remove(); - show_empty_messages(); - - <%- if @recurring_todo.completed? -%> - add_recurring_todo_to_completed_container(); - <%- else -%> - add_recurring_todo_to_active_container(); - <%- end -%> - }); -} - -function add_recurring_todo_to_completed_container() { - $('#completed_recurring_todos_container').append(html_for_recurring_todo()); +<%- else + object_name = unique_object_name_for("toggle_check_rec") +-%> +var <%=object_name%> = { + animate: function() { + TracksPages.set_page_badge(<%= @down_count %>); + <%=object_name%>.remove_old_and_add_updated_recurring_todo(); + <%= "#{object_name}.inform_if_new_todo_created();" if @new_recurring_todo -%> + }, + inform_if_new_todo_created: function() { + TracksPages.page_notify('notice', '<%= t('todos.new_related_todo_created') %>', 5); + }, + remove_old_and_add_updated_recurring_todo: function() { + $('#<%=dom_id(@recurring_todo)%>').slideUp(1000, function() { + $('#<%=dom_id(@recurring_todo)%>').remove(); + <%=object_name%>.show_empty_messages(); + + <%- if @recurring_todo.completed? -%> + <%=object_name%>.add_recurring_todo_to_completed_container(); + <%- else -%> + <%=object_name%>.add_recurring_todo_to_active_container(); + <%- end -%> + }); + }, + add_recurring_todo_to_completed_container: function() { + $('#completed_recurring_todos_container').append(<%=object_name%>.html_for_recurring_todo()); $('#<%= dom_id(@recurring_todo)%>').effect('highlight', {}, 2000 ); $('#completed-empty-nd').hide(); -} - -function add_recurring_todo_to_active_container() { - $('#recurring_todos_container').append(html_for_recurring_todo()); + }, + add_recurring_todo_to_active_container: function() { + $('#recurring_todos_container').append(<%=object_name%>.html_for_recurring_todo()); $('#<%= dom_id(@recurring_todo)%>').effect('highlight', {}, 2000 ); $('#recurring-todos-empty-nd').hide(); + }, + show_empty_messages: function() { + <%- if @active_remaining == 0 -%> + $('#recurring-todos-empty-nd').show(); + <%- end -%> + <%- if @completed_remaining == 0 -%> + $('#completed-empty-nd').show(); + <%- end -%> + }, + html_for_recurring_todo: function() { + return "<%= @saved ? escape_javascript(render(:partial => @recurring_todo)) : "" %>"; + } } -function show_empty_messages() { - <%- if @active_remaining == 0 -%> - $('#recurring-todos-empty-nd').show(); - <%- end -%> - <%- if @completed_remaining == 0 -%> - $('#completed-empty-nd').show(); - <%- end -%> -} - -function html_for_recurring_todo() { - return "<%= @saved ? escape_javascript(render(:partial => @recurring_todo)) : "" %>"; -} \ No newline at end of file +<%=object_name%>.animate(); +<%- end -%> \ No newline at end of file diff --git a/app/views/recurring_todos/toggle_star.js.erb b/app/views/recurring_todos/toggle_star.js.erb index 129a67b5..2fe1dd10 100644 --- a/app/views/recurring_todos/toggle_star.js.erb +++ b/app/views/recurring_todos/toggle_star.js.erb @@ -2,4 +2,4 @@ $('div#recurring_todo_<%= @recurring_todo.id %> a.star_item img').toggleClass('starred'); <%- else -%> TracksPages.page_notify('error', '<%= t('todos.error_starring_recurring', :description => @recurring_todo.description) %>', 8); -<%- end -%> +<%- end -%> \ No newline at end of file diff --git a/app/views/todos/edit.js.erb b/app/views/todos/edit.js.erb index ffd71cc4..51279070 100644 --- a/app/views/todos/edit.js.erb +++ b/app/views/todos/edit.js.erb @@ -1,28 +1,40 @@ -hide_todo(); -replace_placeholder_with_form(); -fill_dependency_array(); -enable_rich_interaction(); +<%- object_name = unique_object_name_for("edit_todo_#{@todo.id}") %> -function hide_todo() { - $('#<%= dom_id(@todo, 'line') %>').hide(); +function add_spec(id, spec) { + <%- + # do this outside of object_name to fill spec_of_todo in + # global namespace, not in namespace of object. Otherwise + # spec_of_todo is not available for the js attached to the + # edit form + -%> + spec_of_todo[id] = spec; } -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(); +var <%=object_name%> = { + animate: function() { + <%=object_name%>.hide_todo(); + <%=object_name%>.replace_placeholder_with_form(); + <%=object_name%>.fill_dependency_array(); + enable_rich_interaction(); + }, + hide_todo: function() { + $('#<%= dom_id(@todo, 'line') %>').hide(); + }, + replace_placeholder_with_form: function() { + $('#<%=dom_id(@todo, 'edit')%>').html(<%=object_name%>.html_for_edit_form()); + $('#<%=dom_id(@todo, 'edit')%>').show(); + $('#<%=dom_id(@todo, 'form')%> input#todo_description').focus(); + }, + fill_dependency_array: function() { + spec_of_todo = new Array(); + <% + @todo.predecessors.each do |dep| -%> + add_spec('<%=dep.id%>', "<%= escape_javascript(dep.specification)%>"); + <% end -%> + }, + html_for_edit_form: function() { + return "<%= escape_javascript(render(:partial => 'todos/edit_form', :object => @todo)) %>" + } } -function fill_dependency_array() { - spec_of_todo = new Array(); -<% -@todo.predecessors.each do |dep| -%> - spec_of_todo['<%=dep.id%>'] = "<%= escape_javascript(dep.specification)%>"; -<% end -%> -} - -function html_for_edit_form() { - return "<%= escape_javascript(render(:partial => 'todos/edit_form', :object => @todo)) %>" -} - - +<%=object_name%>.animate(); \ No newline at end of file diff --git a/app/views/todos/toggle_check.js.erb b/app/views/todos/toggle_check.js.erb index af0f3b15..7633833b 100644 --- a/app/views/todos/toggle_check.js.erb +++ b/app/views/todos/toggle_check.js.erb @@ -1,8 +1,8 @@ <% unless @saved -%> TracksPages.page_notify('error', "<%= t('todos.error_toggle_complete') %>", 5); <% else - # create a unique obejct name to prevent concurrent toggles to overwrite each other functions - object_name = "toggle_check_#{SecureRandom.hex(5)}" + # create a unique object name to prevent concurrent toggles to overwrite each other functions + object_name = unique_object_name_for("toggle_check") -%> var <%= object_name %> = { animate: function() { diff --git a/app/views/todos/toggle_star.js.erb b/app/views/todos/toggle_star.js.erb index eaf4a2af..eb559d05 100644 --- a/app/views/todos/toggle_star.js.erb +++ b/app/views/todos/toggle_star.js.erb @@ -2,4 +2,4 @@ $('div#line_todo_<%= @todo.id %> a.star_item img').toggleClass('starred'); <%- else -%> TracksPages.page_notify('error', '<%= t('todos.error_starring', :description => @todo.description) %>', 8); -<%- end -%> +<%- end -%> \ No newline at end of file diff --git a/app/views/todos/update.js.erb b/app/views/todos/update.js.erb index 23187fa4..3481ffd2 100644 --- a/app/views/todos/update.js.erb +++ b/app/views/todos/update.js.erb @@ -1,139 +1,130 @@ -<% 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 - # to be run sequential,then execute them. All steps are functions which are - # passed a function as parameter that will execute the next animation steps - - 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 << ( update_needs_to_add_new_container ? "insert_new_container_with_updated_todo" : "add_to_existing_container") - end - 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, :project, :context) - animation << "update_predecessors" -%> - TracksPages.page_notify('notice', '<%=escape_javascript @status_message%>', 5); - TracksPages.set_page_badge(<%= @down_count %>); - <%= render_animation(animation) %> - -function remove_todo(next_steps) { - $('#<%= dom_id(@todo) %>').fadeOut(400, function() { - $('#<%= dom_id(@todo) %>').remove(); - <% if source_view_is :calendar - # in calendar view it is possible to have a todo twice on the page - -%> - $('#<%= dom_id(@todo) %>').remove(); - <% end %> - <%= show_empty_message_in_source_container -%> - next_steps.go(); - }); -} - -function add_to_existing_container(next_steps) { - $('#<%= item_container_id(@todo) %>_items').append(html_for_todo()); - <% if source_view_is_one_of(:calendar) -%> - next_steps.go(); - <% if (@target_context_count==1) || ( (@todo.deferred? || @todo.pending?) && @remaining_deferred_or_pending_count == 1) -%> - $("#<%= empty_container_msg_div_id %>").slideUp(100); - <% end -%> +<%- + object_name = unique_object_name_for("update_context_#{@context.id}") +-%> +var <%=object_name%> = { + <% unless @saved -%> + animate: function() { + TracksPages.show_edit_errors(html_for_error_messages()); + }, + html_for_error_messages: function() { + return "<%= escape_javascript(get_list_of_error_messages_for(@todo)) %>"; + } <% else -%> - <% unless (@todo_hidden_state_changed && @todo.hidden?) || @todo_was_deferred_from_active_state -%> - $('#<%= item_container_id(@todo) %>').fadeIn(500, function() { + animate: function() { + <%- + 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 << ( update_needs_to_add_new_container ? "insert_new_container_with_updated_todo" : "add_to_existing_container") + end + 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, :project, :context) + animation << "update_predecessors" + -%> + TracksPages.page_notify('notice', '<%=escape_javascript @status_message%>', 5); + TracksPages.set_page_badge(<%= @down_count %>); + <%= render_animation(animation, object_name) %> + }, + remove_todo: function(next_steps) { + $('#<%= dom_id(@todo) %>').fadeOut(400, function() { + $('#<%= dom_id(@todo) %>').remove(); + <% if source_view_is :calendar + # in calendar view it is possible to have a todo on the page twice + -%> + $('#<%= dom_id(@todo) %>').remove(); + <% end -%> + <%= show_empty_message_in_source_container -%> next_steps.go(); - <% if @target_context_count==1 -%> + }); + }, + add_to_existing_container: function(next_steps) { + $('#<%= item_container_id(@todo) %>_items').append(<%=object_name%>.html_for_todo()); + <% if source_view_is_one_of(:calendar) -%> + next_steps.go(); + <% if (@target_context_count==1) || ( (@todo.deferred? || @todo.pending?) && @remaining_deferred_or_pending_count == 1) -%> $("#<%= empty_container_msg_div_id %>").slideUp(100); <% end -%> - }); - <% else -%> - next_steps.go(); - <% if (@target_context_count==1) || - ( (@todo.deferred? || @todo.pending?) && @remaining_deferred_or_pending_count == 1) || - ( @todo.hidden? && @remaining_hidden_count == 1) - -%> - $("#<%= empty_container_msg_div_id %>").slideUp(100); + <% else -%> + <% unless (@todo_hidden_state_changed && @todo.hidden?) || @todo_was_deferred_from_active_state -%> + $('#<%= item_container_id(@todo) %>').fadeIn(500, function() { + next_steps.go(); + <% if @target_context_count==1 -%> + $("#<%= empty_container_msg_div_id %>").slideUp(100); + <% end -%> + }); + <% else -%> + next_steps.go(); + <% if (@target_context_count==1) || + ( (@todo.deferred? || @todo.pending?) && @remaining_deferred_or_pending_count == 1) || + ( @todo.hidden? && @remaining_hidden_count == 1) + -%> + $("#<%= empty_container_msg_div_id %>").slideUp(100); + <% end -%> + <% end -%> <% end -%> - <% end -%> - <% end -%> + }, + replace_todo: function(next_steps) { + $('#<%= dom_id(@todo) %>').html(<%=object_name%>.html_for_todo()); + next_steps.go(); + }, + hide_container: function(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 %> + }, + highlight_updated_todo: function(next_steps) { + $('#<%= dom_id(@todo)%>').effect('highlight', {}, 2000, function(){ }); + next_steps.go(); + }, + update_empty_container: function(next_steps) { + <% if should_show_empty_container -%> + $('div#no_todos_in_view').slideDown(400, function(){ next_steps.go(); }); + <% else -%> + $('div#no_todos_in_view').fadeOut(100, function(){ next_steps.go(); }); + <% end -%> + }, + update_badge_count: function() { + <% + count = source_view_is(:context) ? @remaining_in_context : @down_count + count = @project_changed ? @remaining_undone_in_project : count + -%> + TracksPages.set_page_badge(<%= count %>); + }, + insert_new_container_with_updated_todo: function(next_steps) { + $('#display_box').prepend(<%=object_name%>.html_for_new_container()); + $('#<%= item_container_id(@todo) %>').fadeIn(500, function() { next_steps.go(); }); + }, + html_for_todo: function() { + return "<%= escape_javascript(render(:partial => @todo, :locals => { :parent_container_type => parent_container_type })) %>"; + }, + html_for_new_container: function() { + return "<%= ( @new_context_created || @new_project_created ) ? escape_javascript(render(:partial => @new_container, :locals => { :settings => {:collapsible => true }})) : "" %>"; + }, + update_predecessors: function(next_steps) { + regenerate_predecessor_family(); + <% if @removed_predecessors + @removed_predecessors.each do |p| -%> + if ($('#<%=item_container_id(p)%>')) { + $('#<%=dom_id(p)%>').html('<%=escape_javascript(render(:partial => p, :locals => { :settings => {:parent_container_type => parent_container_type }}))%>'); + } + <% end -%> + <% end -%> + next_steps.go(); + }, + regenerate_predecessor_family: function() { + <% + parents = @todo.predecessors.to_a + until parents.empty? + parent = parents.pop + parents += parent.predecessors + -%> + $('#<%= dom_id(parent) %>').html("<%= escape_javascript(render(:partial => parent, :locals => { :settings => {:parent_container_type => parent_container_type }})) %>"); + <% + end + -%> + } + <% end # if @saved -%> } - -function replace_todo(next_steps) { - $('#<%= dom_id(@todo) %>').html(html_for_todo()); - 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 %> -} - -function highlight_updated_todo(next_steps) { - $('#<%= dom_id(@todo)%>').effect('highlight', {}, 2000, function(){ }); - next_steps.go(); -} - -function update_empty_container(next_steps) { - <% if should_show_empty_container -%> - $('div#no_todos_in_view').slideDown(400, function(){ next_steps.go(); }); - <% else -%> - $('div#no_todos_in_view').fadeOut(100, 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 insert_new_container_with_updated_todo(next_steps) { - $('#display_box').prepend(html_for_new_container()); - $('#<%= item_container_id(@todo) %>').fadeIn(500, function() { next_steps.go(); }); -} - -function html_for_todo() { - return "<%= escape_javascript(render(:partial => @todo, :locals => { :parent_container_type => parent_container_type })) %>"; -} - -function html_for_new_container() { - return "<%= ( @new_context_created || @new_project_created ) ? escape_javascript(render(:partial => @new_container, :locals => { :settings => {:collapsible => true }})) : "" %>"; -} - -function update_predecessors(next_steps) { - regenerate_predecessor_family(); - <% if @removed_predecessors - @removed_predecessors.each do |p| -%> - if ($('#<%=item_container_id(p)%>')) { - $('#<%=dom_id(p)%>').html('<%=escape_javascript(render(:partial => p, :locals => { :settings => {:parent_container_type => parent_container_type }}))%>'); - } - <% end -%> - <% end -%> - next_steps.go(); -} - -function regenerate_predecessor_family() { -<% - parents = @todo.predecessors.to_a - until parents.empty? - parent = parents.pop - parents += parent.predecessors --%> - $('#<%= dom_id(parent) %>').html("<%= escape_javascript(render(:partial => parent, :locals => { :settings => {:parent_container_type => parent_container_type }})) %>"); -<% - end --%> -} - -<% end %> \ No newline at end of file +<%=object_name%>.animate(); \ No newline at end of file