do a big refactor of rendering collections of todos for home page, tag page, project page, context page

This commit is contained in:
Reinier Balt 2013-03-10 20:38:10 +01:00
parent f22dfc1f9b
commit 22b371ef8c
20 changed files with 910 additions and 816 deletions

View file

@ -329,6 +329,12 @@ var TracksPages = {
refresh_page();
});
$("a#show_empty_containers").click(function () {
var show = ($(this).attr("x_show_empty_containers") == "true");
$.cookie('show_empty_containers', !show);
refresh_page();
});
/* fade flashes and alerts in automatically */
$(".alert").fadeOut(8000);
}

View file

@ -43,13 +43,13 @@ class ContextsController < ApplicationController
@done = @context.todos.completed.limit(@max_completed).reorder("todos.completed_at DESC, todos.created_at DESC").includes(Todo::DEFAULT_INCLUDES)
@not_done_todos = @context.todos.active.reorder("todos.due IS NULL, todos.due ASC, todos.created_at ASC").includes(Todo::DEFAULT_INCLUDES)
@deferred = @context.todos.deferred.includes(Todo::DEFAULT_INCLUDES)
@pending = @context.todos.pending.includes(Todo::DEFAULT_INCLUDES)
@deferred_todos = @context.todos.deferred.includes(Todo::DEFAULT_INCLUDES)
@pending_todos = @context.todos.pending.includes(Todo::DEFAULT_INCLUDES)
@projects = current_user.projects
@contexts = current_user.contexts
@count = @not_done_todos.count + @deferred.count + @pending.count
@count = @not_done_todos.count + @deferred_todos.count + @pending_todos.count
@page_title = "TRACKS::Context: #{@context.name}"
respond_to do |format|
format.html

View file

@ -9,6 +9,8 @@ class TodosController < ApplicationController
def index
@source_view = params['_source_view'] || 'todo'
@group_view_by = cookies['group_view_by'] || 'context'
@show_empty_containers = (cookies['show_empty_containers']=="true") || false
init_data_for_sidebar unless mobile?
@todos = current_user.todos.includes(Todo::DEFAULT_INCLUDES)
@ -31,6 +33,7 @@ class TodosController < ApplicationController
@page_title = t('todos.task_list_title')
# Set count badge to number of not-done, not hidden context items
@count = current_user.todos.active.not_hidden.count(:all)
@todos_without_project = @not_done_todos.select{|t|t.project.nil?}
end
format.m do
@page_title = t('todos.mobile_todos_page_title')
@ -931,6 +934,7 @@ class TodosController < ApplicationController
@tag_title = @single_tag ? @tag_name : tag_title(@tag_expr)
@group_view_by = cookies['group_view_by'] || 'context'
@show_empty_containers = (cookies['show_empty_containers']=="true") || false
end
def get_ids_from_tag_expr(tag_expr)

View file

@ -17,6 +17,17 @@ module ApplicationHelper
end
end
def show_empty_containers_menu_entry
@show_empty_containers ||= false
@group_view_by ||= 'context'
content_tag(:li) do
link_to(
t("layouts.navigation.show_empty_containers_#{@group_view_by}"),
'#',
{:id => "show_empty_containers", :accesskey => "s", :title => t('layouts.navigation.show_empty_containers_title'), :x_show_empty_containers => @show_empty_containers} )
end
end
def container_toggle(id)
link_to(
image_tag("blank.png", :alt => t('common.collapse_expand')),

View file

@ -15,11 +15,13 @@ module ProjectsHelper
end
def project_next_prev
html = ""
html << link_to_project(@previous_project, "&laquo; #{@previous_project.shortened_name}".html_safe) if @previous_project
html << " | " if @previous_project && @next_project
html << link_to_project(@next_project, "#{@next_project.shortened_name} &raquo;".html_safe) if @next_project
return html.html_safe
content_tag(:div, :id=>"project-next-prev") do
html = ""
html << link_to_project(@previous_project, "&laquo; #{@previous_project.shortened_name}".html_safe) if @previous_project
html << " | " if @previous_project && @next_project
html << link_to_project(@next_project, "#{@next_project.shortened_name} &raquo;".html_safe) if @next_project
html.html_safe
end
end
def project_next_prev_mobile

View file

@ -1,17 +1,112 @@
module TodosHelper
def empty_message_holder(show)
content_tag(:div, :id => "no_todos_in_view", :class => "container context", :style => "display:" + (show ? "block" : "none") ) do
content_tag(:h2) { t('todos.no_actions_found_title') }
def empty_message_holder(container_name, show, title_param=nil)
content_tag(:div, :id => "no_todos_in_view", :class => "container #{container_name}", :style => "display:" + (show ? "block" : "none") ) do
content_tag(:h2) { t("todos.no_actions.title", :param=>title_param) } +
content_tag(:div, :class => "message") do
content_tag(:p) { t('todos.no_actions_found') }
content_tag(:p) { t("todos.no_actions.#{container_name}", :param=>title_param) }
end
end
end
def todos_container_empty_message(container_name, container_id, show_message)
content_tag(:div, :id=>"#{container_id}-empty-d", :style=>"display:#{show_message ? 'block' : 'none'}") do
content_tag(:div, :class=>"message") do
content_tag(:p) do
t("todos.no_actions.#{container_name}")
end
end
end
end
def show_grouped_todos
collection = (@group_view_by == 'context') ? @contexts_to_show : @projects_to_show
render(:partial => collection, :locals => { :collapsible => true })
render(:partial => collection, :locals => { :settings => {:collapsible => true, :show_empty_containers => @show_empty_containers }})
end
def default_collection_settings
{
:suppress_context => false,
:suppress_project => false,
:collapsible => false,
:append_descriptor => nil,
:parent_container_type => nil,
:show_empty_containers => true
}
end
def show_done_todos(done_todos, settings={})
settings[:container_name] = "completed"
settings[:link_in_header] = link_to(t('common.show_all'), determine_done_path)
render :partial => 'todos/collection',
:object => done_todos,
:locals => {:settings => settings.reverse_merge!(default_collection_settings)}
end
def show_hidden_todos(hidden_todos, settings={})
settings[:container_name] = "hidden"
render :partial => 'todos/collection',
:object => hidden_todos,
:locals => {:settings => settings.reverse_merge!(default_collection_settings)}
end
def show_deferred_pending_todos(deferred_todos, pending_todos, settings={})
settings[:pending] = pending_todos
settings[:container_name]="deferred_pending"
render :partial => "todos/collection",
:object => deferred_todos+pending_todos,
:locals => {:settings => settings.reverse_merge!(default_collection_settings)}
end
def show_todos_without_project(todos_without_project)
render :partial => 'todos/collection',
:object => todos_without_project,
:locals => {:settings => {
:collapsible => true,
:container_name => "without_project"
}
}
end
def todos_container(settings={})
container_name = settings[:container_name]
settings.reverse_merge!({
:id => "#{container_name}_container",
:class => "container #{container_name}",
})
content_tag(:div,
:class=>settings[:class],
:id=>settings[:id],
:style => "display:" + (settings[:show_container] ? "block" : "none")) do
yield
end
end
def todos_container_header(settings={})
settings.reverse_merge!({
:title => t("todos.actions.#{settings[:parent_container_type]}_#{settings[:container_name]}", :param => settings[:title_param])
})
header = settings[:link_in_header].nil? ? "" : content_tag(:div, :class=>"add_note_link"){settings[:link_in_header]}
header += content_tag(:h2) do
toggle = settings[:collapsible] ? container_toggle("toggle_#{settings[:container_name]}") : ""
"#{toggle} #{settings[:title]} #{settings[:append_descriptor]}".html_safe
end
header.html_safe
end
def todos_container_items(collection, settings={})
settings.reverse_merge!({:id => "#{settings[:container_name]}"})
# do not pass :class to partial locals
settings.delete(:class)
content_tag(:div, :id =>settings[:id]+"_items", :class=>"items toggle_target") do
todos_container_empty_message(settings[:container_name], settings[:id], collection.empty?) +
render(:partial => "todos/todo", :collection => collection, :locals => settings)
end
end
def remote_star_icon(todo=@todo)

View file

@ -167,4 +167,8 @@ class NullProject
nil
end
def name
""
end
end

View file

@ -4,17 +4,17 @@
# rendering of "due in x days" that change without touching updated at of the todo
cache [context, @source_view, current_user.date.strftime("%Y%m%d"), @tag_name] do
%>
<div id="c<%= context.id %>" class="container context" style="display:<%= (collapsible && @not_done.empty?) ? "none" : "block" %>">
<h2>
<%= container_toggle("toggle_c#{context.id}") %>
<%= show_context_name(context) %>
</h2>
<div id="c_<%=context.id%>_target" class="context_target drop_target"></div>
<div id="c<%= context.id %>items" class="items toggle_target">
<div id="c<%= context.id %>empty-nd" style="display:<%= @not_done.empty? ? 'block' : 'none'%>;">
<div class="message"><p><%= t 'contexts.no_actions' %></p></div>
</div>
<%= render :partial => "todos/todo", :collection => @not_done, :locals => { :parent_container_type => "context" } %>
</div>
</div>
<%=
render :partial => 'todos/collection',
:object => @not_done,
:locals => { :settings => {
:id => "c#{context.id}",
:collapsible => settings[:collapsible],
:container_name => 'context',
:title => show_context_name(context),
:show_empty_containers => @show_empty_containers
}}
%>
<% end %>

View file

@ -1,9 +1,14 @@
<%
suffix_completed = t('contexts.last_completed_in_context', :number=>prefs.show_number_completed)
deferred_pending_options = {:append_descriptor => nil, :parent_container_type => 'context'}
done_todo_options = {:append_descriptor => suffix_completed, :suppress_context => true, :parent_container_type => 'context'}
-%>
<div id="display_box">
<%= render :partial => @context, :locals => { :collapsible => false } %>
<%= render :partial => "todos/deferred", :object => @deferred, :locals => { :collapsible => false, :append_descriptor => t('contexts.todos_append'), :parent_container_type => 'context', :pending => @pending } %>
<% unless @max_completed==0 -%>
<%= render :partial => "todos/completed", :object => @done, :locals => { :suppress_context => true, :collapsible => false, :append_descriptor => t('contexts.last_completed_in_context', :number=>prefs.show_number_completed) } %>
<% end -%>
<%= render :partial => @context, :locals => { :settings => {:collapsible => false }} %>
<%= show_deferred_pending_todos(@deferred_todos, @pending_todos, deferred_pending_options) %>
<%= show_done_todos(@done, done_todo_options) unless @done.nil? %>
</div>
<div id="input_box">

View file

@ -73,6 +73,7 @@
<li><%= navigation_link( t('layouts.navigation.stats'), stats_path, :title => t('layouts.navigation.stats_title')) %></li>
<li><hr/></li>
<%= group_view_by_menu_entry %>
<%= show_empty_containers_menu_entry %>
</ul>
</li>
<li><a href="#"><%= t('layouts.navigation.admin') %></a>

View file

@ -5,18 +5,19 @@
cache [project, @source_view, current_user.date.strftime("%Y%m%d")] do
%>
<%= render :partial => "project_settings_container", :locals => {:project => project} if source_view_is :project %>
<div id="p<%= project.id %>" class="container project" style="display:<%= (collapsible && @not_done.empty?) ? "none" : "block" %>">
<h2>
<%= container_toggle("toggle_p#{project.id}") if collapsible %>
<%= source_view_is(:project) ? t('projects.actions_in_project_title') : show_project_name(project) %>
</h2>
<div id="p<%= project.id %>items" class="items toggle_target">
<div id="p<%= project.id %>empty-nd" style="display:<%= @not_done.empty? ? 'block' : 'none'%>;">
<div class="message"><p><%= t('projects.no_actions_in_project') %></p></div>
</div>
<%= render :partial => "todos/todo", :collection => @not_done, :locals => { :parent_container_type => "project" } %>
</div>
</div>
<%=
title = source_view_is(:project) ? t('projects.actions_in_project_title') : show_project_name(project)
render :partial => 'todos/collection',
:object => @not_done,
:locals => { :settings => {
:id => "p#{project.id}",
:collapsible => settings[:collapsible],
:title => title,
:container_name => 'project',
:show_empty_containers => @show_empty_containers
}}
%>
<% end %>

View file

@ -1,14 +1,20 @@
<%
deferred_pending_options = {:append_descriptor => nil, :parent_container_type => 'project'}
done_todo_options = {
:append_descriptor => t('projects.last_completed_in_project', :number=>prefs.show_number_completed),
:suppress_project => true,
:parent_container_type => 'project'
}
-%>
<div id="display_box">
<div id="project-next-prev">
<%= project_next_prev %>
</div>
<%= project_next_prev %>
<%= render :partial => @project, :locals => {:collapsible => false } %>
<%= render :partial => "todos/deferred", :object => @deferred_todos, :locals => { :collapsible => false, :append_descriptor => t('projects.todos_append'), :parent_container_type => 'project', :pending => @pending_todos } %>
<% unless @max_completed==0 -%>
<%= render :partial => "todos/completed", :object => @done, :locals => { :collapsible => false, :suppress_project => true, :append_descriptor => t('projects.todos_append') } %>
<% end -%>
<%= render :partial => @project, :locals => {:settings => {:collapsible => false }} %>
<%= show_deferred_pending_todos(@deferred_todos, @pending_todos, deferred_pending_options) %>
<%= show_done_todos(@done, done_todo_options) unless @done.nil? %>
<div class="container">
<div id="notes">
<div class="add_note_link"><%= link_to t('projects.add_note'), '#' %> </div>
@ -29,4 +35,4 @@
<div id="input_box">
<%= render :partial => "shared/add_new_item_form" %>
<%= render :file => "sidebar/sidebar" %>
</div><!-- End of input box -->
</div>

View file

@ -0,0 +1,8 @@
<%=
settings[:show_container] = !collection.empty? || settings[:show_empty_containers]
todos_container(settings) do
todos_container_header(settings) +
todos_container_items(collection, settings)
end
%>

View file

@ -1,21 +0,0 @@
<% suffix = append_descriptor ? append_descriptor : ''
suppress_context ||= false
suppress_project ||= false
-%>
<div class="container completed" id="completed_container">
<div class=add_note_link><%= link_to t('common.show_all'), determine_done_path%></div>
<h2>
<% if collapsible %>
<a href="#" class="container_toggle" id="toggle_completed"><%= image_tag("blank.png", :alt => t('common.collapse_expand')) %></a>
<% end %>
<%= t('todos.completed_actions') %> <%= raw suffix %>
</h2>
<div id="completed_containeritems" class="items toggle_target">
<div id="empty-d" style="display:<%= completed.empty? ? 'block' : 'none' %>">
<div class="message"><p><%= t('todos.no_completed_actions') %></p></div>
</div>
<%= render :partial => "todos/todo", :collection => completed, :locals => { :parent_container_type => "completed", :suppress_context => suppress_context, :suppress_project => suppress_project } %>
</div>
</div>

View file

@ -1,18 +0,0 @@
<div class="container tickler" id="tickler">
<h2>
<% if collapsible %>
<a href="#" class="container_toggle" id="toggle_deferred"><%= image_tag("blank.png", :alt => t('common.collapse_expand')) %></a>
<% end %>
<%= t('todos.deferred_pending_actions') %> <%= raw(append_descriptor ? append_descriptor : '') %>
</h2>
<div id="tickleritems" class="items toggle_target">
<div id="tickler-empty-nd" style="display:<%= deferred.empty? && pending.empty? ? 'block' : 'none'%>;">
<div class="message"><p><%= t('todos.no_deferred_pending_actions') %></p></div>
</div>
<%= render :partial => "todos/todo", :collection => deferred, :locals => { :parent_container_type => parent_container_type } %>
<%= render :partial => "todos/todo", :collection => pending, :locals => { :parent_container_type => parent_container_type } %>
</div><!-- [end:items] -->
</div><!-- [end:tickler] -->

View file

@ -1,17 +0,0 @@
<div class="container hidden" id="hidden">
<h2>
<% if collapsible %>
<a href="#" class="container_toggle" id="toggle_deferred"><%= image_tag("blank.png", :alt => t('common.collapse_expand')) %></a>
<% end %>
<%= t('todos.hidden_actions') %> <%= raw(append_descriptor ? append_descriptor : '') %>
</h2>
<div id="hiddenitems" class="items toggle_target">
<div id="hidden-empty-nd" style="display:<%= hidden.empty? ? 'block' : 'none'%>;">
<div class="message"><p><%= t('todos.no_hidden_actions') %></p></div>
</div>
<%= render :partial => "todos/todo", :collection => hidden, :locals => { :parent_container_type => 'tag' } %>
</div><!-- [end:items] -->
</div><!-- [end:tickler] -->

View file

@ -1,12 +1,13 @@
<div id="display_box">
<%= empty_message_holder(@not_done_todos.empty?) %>
<%= empty_message_holder("not_done", @not_done_todos.empty?) %>
<%= show_grouped_todos %>
<% unless @done.nil? -%>
<%= render(:partial => "todos/completed", :object => @done,
:locals => { :collapsible => true, :append_descriptor => nil }) -%>
<% if @group_view_by == 'context' -%>
<%= show_todos_without_project(@todos_with_project) unless @todos_without_project.nil? -%>
<% end -%>
<%= show_done_todos(@done, {:collapsible => true}) unless @done.nil? %>
</div>
<div id="input_box">

View file

@ -1,29 +1,27 @@
<%
options = {
:collapsible => false,
:parent_container_type => 'tag',
:title_param => @tag_title
}
deferred_pending_options=options.clone.merge({:deferred => @deferred_todos, :pending => @pending_todos})
hidden_options = options.clone
done_options = options.clone
-%>
<div id="display_box">
<%= empty_message_holder(@not_done_todos.empty?) %>
<%= empty_message_holder("not_done_with_tag", @not_done_todos.empty?, @tag_name) %>
<%= show_grouped_todos %>
<% unless @deferred_todos.nil? -%>
<%= render :partial => "todos/deferred", :locals => {
:deferred => @deferred_todos,
:pending => @pending_todos,
:collapsible => true,
:append_descriptor => t('todos.tagged_with', :tag_name => @tag_title),
:parent_container_type => 'tag'
} %>
<% end -%>
<%= show_deferred_pending_todos(@deferred_todos, @pending_todos, deferred_pending_options) %>
<% unless @hidden_todos.nil? -%>
<%= render :partial => "todos/hidden", :object => @hidden_todos, :locals => { :collapsible => true, :append_descriptor => t('todos.tagged_with', :tag_name => @tag_title) } %>
<% end -%>
<%= show_hidden_todos(@hidden_todos, hidden_options) unless @hidden_todos.nil? %>
<% unless @done.nil? -%>
<%= render :partial => "todos/completed", :object => @done,
:locals => { :collapsible => true, :append_descriptor => t('todos.tagged_with', :tag_name => @tag_title) } %>
<% end -%>
</div><!-- End of display_box -->
<%= show_done_todos(@done, done_options) unless @done.nil? %>
</div>
<div id="input_box">
<%= render :partial => "shared/add_new_item_form" %>
<%= render :file => "sidebar/sidebar" %>
</div><!-- End of input box -->
</div>

File diff suppressed because it is too large Load diff

View file

@ -14,15 +14,15 @@ class ProjectsControllerTest < ActionController::TestCase
p = projects(:timemachine)
login_as :admin_user
get :show, :id => p.to_param
assert_not_nil assigns['deferred']
assert_equal 1, assigns['deferred'].size
assert_not_nil assigns['deferred_todos']
assert_equal 1, assigns['deferred_todos'].size
t = p.todos.not_completed[0]
t.show_from = 1.days.from_now.utc
t.save!
get :show, :id => p.to_param
assert_equal 2, assigns['deferred'].size
assert_equal 2, assigns['deferred_todos'].size
end
def test_show_exposes_next_project_in_same_state