From db29b84f699dfb8665654cc9ac8a012b5c7246a0 Mon Sep 17 00:00:00 2001
From: Reinier Balt
Date: Mon, 1 Jul 2013 15:56:54 +0200
Subject: [PATCH] add keyboard shortcuts and make todos selectable useing j and
k
---
Gemfile.lock | 4 +-
app/assets/javascripts/keybindings.js.coffee | 10 ++-
app/assets/javascripts/tracks.js.coffee | 66 ++++++++++++++++++-
app/assets/stylesheets/tracks.css.scss | 34 ++++++++--
app/helpers/todos_helper.rb | 35 ++--------
app/views/contexts/show.html.erb | 7 +-
app/views/layouts/application.html.erb | 21 +++---
app/views/shared/_footer.html.erb | 2 +-
app/views/shared/_navbar.html.erb | 13 ++--
app/views/todos/_collection.html.erb | 17 ++---
.../todos/_container_empty_message.html.erb | 2 +-
app/views/todos/_container_items.html.erb | 9 ++-
.../todos/_empty_message_container.html.erb | 10 +++
app/views/todos/_todo.html.erb | 41 +++++++-----
app/views/todos/index.html.erb | 19 +++---
app/views/todos/tag.html.erb | 24 +++----
config/locales/en.yml | 2 +
17 files changed, 217 insertions(+), 99 deletions(-)
create mode 100644 app/views/todos/_empty_message_container.html.erb
diff --git a/Gemfile.lock b/Gemfile.lock
index 0d69728e..6978c234 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -7,7 +7,7 @@ GIT
GIT
remote: git://github.com/seyhunak/twitter-bootstrap-rails.git
- revision: dfc45d21fac4178240bc3f6ec037969b49fa54c2
+ revision: 9a0a31096ecee572638132d5ed94bc5500f74330
branch: master
specs:
twitter-bootstrap-rails (2.2.7)
@@ -205,7 +205,7 @@ GEM
will_paginate (3.0.4)
xpath (2.0.0)
nokogiri (~> 1.3)
- yard (0.8.6.1)
+ yard (0.8.6.2)
PLATFORMS
ruby
diff --git a/app/assets/javascripts/keybindings.js.coffee b/app/assets/javascripts/keybindings.js.coffee
index 26a25eda..4d543f2b 100644
--- a/app/assets/javascripts/keybindings.js.coffee
+++ b/app/assets/javascripts/keybindings.js.coffee
@@ -41,8 +41,11 @@ $ ->
mouseTrapRails.toggleHints() if mouseTrapRails.showOnLoad
+ # HELP
Mousetrap.bind '?', -> $('div#tracks-shortcuts-dialog').modal()
- Mousetrap.bind 'a', -> $('div#tracks-add-action-dialog').modal()
+
+ # ADD: a is bound in navbar
+
# GO TO
# Mousetrap.bind 'g h', TracksApp.go_home
Mousetrap.bind 'g c', -> alert("go context")
@@ -50,6 +53,11 @@ $ ->
Mousetrap.bind 'g t', -> alert("go tag")
Mousetrap.bind 'g p', -> alert("go project")
# Mousetrap.bind 'g P', TracksApp.go_projects
+
# VIEW
Mousetrap.bind 'v p', -> alert("group by project")
Mousetrap.bind 'v c', -> alert("group by context")
+
+ # Item Selection
+ Mousetrap.bind 'j', -> TracksApp.selectNext()
+ Mousetrap.bind 'k', -> TracksApp.selectPrev()
\ No newline at end of file
diff --git a/app/assets/javascripts/tracks.js.coffee b/app/assets/javascripts/tracks.js.coffee
index ef577c9e..255a4d17 100644
--- a/app/assets/javascripts/tracks.js.coffee
+++ b/app/assets/javascripts/tracks.js.coffee
@@ -3,4 +3,68 @@
# goto_page: (page) -> window.location.href = page
# go_home: this.goto_page "/"
# go_contexts: this.goto_page "/contexts"
-# go_projects: this.goto_page "/projects"
\ No newline at end of file
+# go_projects: this.goto_page "/projects"
+
+TracksApp =
+ currentPosition: 0
+
+ updateCurrentPosition: ->
+ this.currentPosition = 0
+ $("div.todo-item").each ->
+ if $(this).hasClass("selected-item")
+ return false
+ else
+ this.currentPosition++
+
+ selectTodo: (new_todo) ->
+ $("div.todo-item.selected-item").removeClass("selected-item")
+ new_todo.addClass("selected-item")
+ TracksApp.updateCurrentPosition()
+
+ selectPrevNext: (go_next) ->
+ current = prev = next = null
+ stop = false
+ $("div.todo-item").each ->
+ if stop
+ next = $(this)
+ return false
+
+ prev = current
+ current = $(this)
+
+ if $(this).hasClass("selected-item")
+ stop = true
+
+ if go_next
+ TracksApp.selectTodo(prev) if prev?
+ return prev
+ else
+ TracksApp.selectTodo(next) if next?
+ return next
+
+ selectPrev: ->
+ unless TracksApp.selectPrevNext(true)?
+ TracksApp.selectTodo($("div.todo-item").last())
+
+ selectNext: ->
+ unless TracksApp.selectPrevNext(false)?
+ TracksApp.selectTodo($("div.todo-item").first())
+
+# Make TracksApp globally accessible. From http://stackoverflow.com/questions/4214731/coffeescript-global-variables
+root = exports ? this
+root.TracksApp = TracksApp
+
+$ ->
+ $("a#menu-keyboard-shotcuts").click -> $('div#tracks-shortcuts-dialog').modal()
+
+ $("a.button-add-todo").click -> $('div#tracks-add-action-dialog').modal()
+
+ $("i.icon-book").click ->
+ notes_id = $( this ).attr("data-note-id")
+ notes_div = $("div#" + notes_id )
+ notes_div.toggleClass("hide")
+ todo_item = $(this).parent().parent().parent().parent()
+ TracksApp.selectTodo(todo_item)
+
+ $("div.todo-item-description-container").click ->
+ TracksApp.selectTodo( $(this).parent().parent().parent() )
\ No newline at end of file
diff --git a/app/assets/stylesheets/tracks.css.scss b/app/assets/stylesheets/tracks.css.scss
index a02264d3..4c4731db 100644
--- a/app/assets/stylesheets/tracks.css.scss
+++ b/app/assets/stylesheets/tracks.css.scss
@@ -16,6 +16,9 @@ div.tracks-middle {
.navbar-inner {
border-radius: none;
+ div.btn-toolbar {
+ margin: 0px 15px 0px 0px;
+ }
}
div#tracks-login-navbar {
@@ -42,16 +45,15 @@ span.badge_count {
footer {
margin-top: 50px;
text-align: center;
- background-color: #000;
- background-image: linear-gradient(to bottom, #FFFFFF, #F2F2F2);
+ background-color: #DDD;
}
/* Todo */
div.todo-item {
margin-top: 7px;
- margin-left: 0px;
border: 3px solid #EEE;
- border-width: 0px 0px 1px;
+ border-width: 0px 0px 1px 0px;
+ padding: 0px 3px 0px 3px;
min-height: none;
line-height: none;
@@ -59,6 +61,9 @@ div.todo-item {
min-height: 0px;
}
+ div.row {
+ margin-left: 0px;
+ }
i.icon-check-empty {
margin-right: 10px;
}
@@ -84,6 +89,23 @@ div.todo-item {
display: inline-block;
float:left;
}
+ div.todo-notes {
+ background-color: #EEE;
+ border-radius: 3px;
+ padding: 10px;
+ margin: 0px -3px 0px -3px;
+ }
+}
+
+div.selected-item {
+ border: 3px solid #AAA;
+ border-radius: 3px;
+ .row {
+ font-weight: bold;
+ }
+ .todo-notes {
+ font-weight: normal;
+ }
}
span.tags {
@@ -112,4 +134,8 @@ div.todos-container {
color: #444;
}
}
+}
+
+div.hide_me {
+ display: none;
}
\ No newline at end of file
diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb
index 2da4e780..e6f12e2a 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -2,26 +2,13 @@ module TodosHelper
# === helpers for rendering container
- 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(:h4) { t("todos.no_actions.title", :param=>title_param) } +
- content_tag(:div, :class => "message") do
- 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)
- render partial: "todos/container_empty_message", locals:
- {container_id: container_id, container_name: container_name, show_message: show_message}
- end
-
def show_grouped_todos(settings = {})
collection = (@group_view_by == 'context') ? @contexts_to_show : @projects_to_show
render(:partial => collection, :locals => { :settings => settings.reverse_merge!({
:collapsible => true,
:show_empty_containers => @show_empty_containers,
- :parent_container_type => @group_view_by
+ :parent_container_type => @group_view_by,
+ :show_container => !collection.empty? || settings[:show_empty_containers],
})})
end
@@ -86,32 +73,24 @@ module TodosHelper
}
end
- def todos_container(settings={})
+ def todos_container_settings(settings={})
settings.reverse_merge!({
:id => "#{settings[:container_name]}-container",
:class => "todos-container #{settings[:container_name]}",
+ :title => t("todos.actions.#{settings[:parent_container_type]}_#{settings[:container_name]}", :param => settings[:title_param])
})
if settings[:collapsible]
settings[:class] += " collapsible"
end
-
- content_tag(:div,
- :class=>settings[:class],
- :id=>settings[:id],
- :style => "display:" + (settings[:show_container] ? "block" : "none")) do
- yield
- end
+ return settings
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(:h4) do
toggle = ""
- # toggle = settings[:collapsible] ? container_toggle("toggle_#{settings[:id]}") : ""
+ # TODO: toggle = settings[:collapsible] ? container_toggle("toggle_#{settings[:id]}") : ""
"#{toggle} #{settings[:title]} #{settings[:append_descriptor]}".html_safe
end
header.html_safe
@@ -126,7 +105,7 @@ module TodosHelper
div_id: settings[:id]+"_items",
container_name: settings[:container_name],
todo_id: settings[:id],
- hide_empty_message: collection.empty?,
+ show_empty_message: !collection.empty?,
collection: collection,
settings: settings
}
diff --git a/app/views/contexts/show.html.erb b/app/views/contexts/show.html.erb
index acd791fe..2ca233e1 100644
--- a/app/views/contexts/show.html.erb
+++ b/app/views/contexts/show.html.erb
@@ -1,3 +1,6 @@
+<%# Template Dependency: todos/collection -%>
+<%# Template Dependency: contexts/context -%>
+<%# Template Dependency: projects/project -%>
<%
suffix_completed = t('contexts.last_completed_in_context', :number=>prefs.show_number_completed)
deferred_pending_options = {:append_descriptor => nil, :parent_container_type => 'context'}
@@ -5,7 +8,9 @@
show_empty_containers = (@group_view_by == 'context')
-%>
-<%= empty_message_holder("not_done_context", @not_done_todos.empty?) %>
+<% cache("not_done_context", @not_done_todos.empty?) do -%>
+ <%= render partial: "todos/empty_message_container", locals: {:show => @not_done_todos.empty?, :container_name => "not_done"} %>
+<% end -%>
<%= show_grouped_todos({:collapsible => false, :show_empty_containers => show_empty_containers, :parent_container_type => 'context'}) %>
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 780dd674..4c437e19 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -6,37 +6,32 @@
<%= content_for?(:title) ? yield(:title) : @page_title %>
<%= csrf_meta_tags %>
-
-
<%= stylesheet_link_tag "application", :media => "all" %>
-
<%= favicon_link_tag 'apple-touch-icon-144x144-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png', :sizes => '144x144' %>
-
<%= favicon_link_tag 'apple-touch-icon-114x114-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png', :sizes => '114x114' %>
-
<%= favicon_link_tag 'apple-touch-icon-72x72-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png', :sizes => '72x72' %>
-
<%= favicon_link_tag 'apple-touch-icon-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png' %>
-
<%= favicon_link_tag 'favicon.ico', :rel => 'shortcut icon' %>
- <%= render partial: "shared/navbar" %>
+ <% cache do -%>
+ <%= render partial: "shared/navbar" %>
+ <% end -%>
- <%= render partial: "shared/footer" %>
- <% # dialogs -%>
- <%= render partial: "shared/keyboard_shortcuts" %>
- <%= render partial: "shared/add_new_action" %>
+ <% cache do -%>
+ <%= render partial: "shared/footer" %>
+ <% # dialogs -%>
+ <%= render partial: "shared/keyboard_shortcuts" %>
+ <%= render partial: "shared/add_new_action" %>
+ <% end -%>
<%
# Javascripts
# ==================================================
diff --git a/app/views/shared/_footer.html.erb b/app/views/shared/_footer.html.erb
index a87e7606..2fee6dc8 100644
--- a/app/views/shared/_footer.html.erb
+++ b/app/views/shared/_footer.html.erb
@@ -11,4 +11,4 @@
-
+
\ No newline at end of file
diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb
index c27daba7..94962f81 100644
--- a/app/views/shared/_navbar.html.erb
+++ b/app/views/shared/_navbar.html.erb
@@ -51,20 +51,25 @@
<%= t('layouts.navigation.help') %>
+ -
+
+
-
- - <%= link_to("#{t('common.logout')} (#{current_user.display_name})".html_safe, logout_path) %>
+
- <%= link_to("".html_safe, logout_path, title: "#{t('common.logout')} (#{current_user.display_name})") %>
diff --git a/app/views/todos/_collection.html.erb b/app/views/todos/_collection.html.erb
index 8d79bda0..49484b1d 100644
--- a/app/views/todos/_collection.html.erb
+++ b/app/views/todos/_collection.html.erb
@@ -1,8 +1,9 @@
-<%=
- settings[:show_container] = !collection.empty? || settings[:show_empty_containers]
-
- todos_container(settings) do
- todos_container_header(settings) +
- todos_container_items(collection, settings)
- end
-%>
\ No newline at end of file
+<%
+ # Template Dependency: todos/container_items
+ settings = todos_container_settings(settings)
+ settings[:class] += " hide" if collection.empty? || settings[:show_container]
+-%>
+
+ <%= todos_container_header(settings) %>
+ <%= todos_container_items(collection, settings) %>
+
\ No newline at end of file
diff --git a/app/views/todos/_container_empty_message.html.erb b/app/views/todos/_container_empty_message.html.erb
index 85d7e703..020702eb 100644
--- a/app/views/todos/_container_empty_message.html.erb
+++ b/app/views/todos/_container_empty_message.html.erb
@@ -1,4 +1,4 @@
-
+
<%=t("todos.no_actions.#{container_name}")%>
diff --git a/app/views/todos/_container_items.html.erb b/app/views/todos/_container_items.html.erb
index f51bf9f1..659472d1 100644
--- a/app/views/todos/_container_items.html.erb
+++ b/app/views/todos/_container_items.html.erb
@@ -1,4 +1,11 @@
- <%= todos_container_empty_message(container_name, todo_id, hide_empty_message) %>
+
+ <% cache container_name, show_empty_message do %>
+ <%= render partial: "todos/container_empty_message", locals: {
+ container_id: settings[:container_id],
+ container_name: settings[:container_name],
+ show_empty_message: settings[:show_empty_message]} -%>
+ <% end -%>
+
<%= render(:partial => "todos/todo", :collection => collection, :locals => settings) %>
\ No newline at end of file
diff --git a/app/views/todos/_empty_message_container.html.erb b/app/views/todos/_empty_message_container.html.erb
new file mode 100644
index 00000000..679817e1
--- /dev/null
+++ b/app/views/todos/_empty_message_container.html.erb
@@ -0,0 +1,10 @@
+<%
+ title_param ||= ""
+ hidden_class = show ? "" : " hide"
+%>
+
+
<%= t("todos.no_actions.title", :param=>title_param) %>
+
+
<%= t("todos.no_actions.#{container_name}", :param=>title_param)%>
+
+
\ No newline at end of file
diff --git a/app/views/todos/_todo.html.erb b/app/views/todos/_todo.html.erb
index 68e8005f..e5a8eae7 100644
--- a/app/views/todos/_todo.html.erb
+++ b/app/views/todos/_todo.html.erb
@@ -1,23 +1,32 @@
<%
suppress_context ||= false
suppress_project ||= false
+ cache [todo, current_user.date.strftime("%Y%m%d"), @source_view, current_user.prefs.verbose_action_descriptors] do
-%>
-
-
-
-
">
-
">
+
+
+
+
+ ">
+ ">
+
+
+ <%= todo.description %>
+ <%= content_tag(:i, {class: "icon-refresh"}){} if todo.from_recurring_todo? -%>
+ <%= deferred_due_date(todo) -%>
+ <%= content_tag(:i, {class: "icon-sitemap"}){} if todo.has_pending_successors -%>
+ <%= content_tag(:i, {class: "icon-book", "data-note-id" => dom_id(todo, 'notes')}){} unless todo.notes.blank? %>
+
+
+
+ <%= date_span(todo) -%>
+ <%= tag_list(todo) %>
+
-
-
<%= todo.description %>
- <%= content_tag(:i, {class: "icon-refresh"}){} if todo.from_recurring_todo? %>
- <%= deferred_due_date(todo) %>
- <%= content_tag(:i, {class: "icon-play-sign"}){} if todo.has_pending_successors %>
- <%= content_tag(:i, {class: "icon-book"}){} unless todo.notes.blank? %>
+
+
+ <%=todo.rendered_notes.html_safe%>
+
-
- <%= date_span(todo) -%>
- <%= tag_list(todo) %>
-
-
\ No newline at end of file
+<% end -%>
\ No newline at end of file
diff --git a/app/views/todos/index.html.erb b/app/views/todos/index.html.erb
index 5811f272..8f751fc0 100644
--- a/app/views/todos/index.html.erb
+++ b/app/views/todos/index.html.erb
@@ -1,11 +1,14 @@
-
- <%= empty_message_holder("not_done", @not_done_todos.empty?) %>
+<%# Template Dependency: todos/collection -%>
+<%# Template Dependency: contexts/context -%>
+<%# Template Dependency: projects/project -%>
+<% cache("not_done", @not_done_todos.empty?) do -%>
+ <%= render partial: "empty_message_container", locals: {:show => @not_done_todos.empty?, :container_name => "not_done"} %>
+<% end -%>
- <%= show_grouped_todos %>
+<%= show_grouped_todos %>
- <% if @group_view_by == 'project' -%>
- <%= show_todos_without_project(@todos_without_project) -%>
- <% end -%>
+<% if @group_view_by == 'project' -%>
+<%= show_todos_without_project(@todos_without_project) -%>
+<% end -%>
- <%= show_done_todos(@done, {:parent_container_type => @group_view_by, :collapsible => true}) unless @done.nil? %>
-
\ No newline at end of file
+<%= show_done_todos(@done, {:parent_container_type => @group_view_by, :collapsible => true}) unless @done.nil? %>
\ No newline at end of file
diff --git a/app/views/todos/tag.html.erb b/app/views/todos/tag.html.erb
index bfbdbff7..d545b50e 100644
--- a/app/views/todos/tag.html.erb
+++ b/app/views/todos/tag.html.erb
@@ -1,4 +1,7 @@
<%
+ # Template Dependency: todos/collection
+ # Template Dependency: contexts/context
+ # Template Dependency: projects/project
options = {
:collapsible => false,
:parent_container_type => 'tag',
@@ -8,19 +11,18 @@
hidden_options = options.clone
done_options = options.clone
-%>
-
- <%= empty_message_holder("not_done_with_tag", @not_done_todos.empty?, @tag_name) %>
+<% cache("not_done_with_tag_#{@tag_name}", @not_done_todos.empty?) do -%>
+ <%= render partial: "empty_message_container", locals: {:show => @not_done_todos.empty?, :container_name => "not_done_with_tag"} %>
+<% end -%>
- <%= show_grouped_todos %>
+<%= show_grouped_todos %>
- <% if @group_view_by == 'project' -%>
- <%= show_todos_without_project(@todos_without_project) -%>
- <% end -%>
+<% if @group_view_by == 'project' -%>
+ <%= show_todos_without_project(@todos_without_project) -%>
+<% end -%>
- <%= show_deferred_pending_todos(@deferred_todos, @pending_todos, deferred_pending_options) %>
+<%= show_deferred_pending_todos(@deferred_todos, @pending_todos, deferred_pending_options) %>
- <%= show_hidden_todos(@hidden_todos, hidden_options) unless @hidden_todos.nil? %>
+<%= show_hidden_todos(@hidden_todos, hidden_options) unless @hidden_todos.nil? %>
- <%= show_done_todos(@done, done_options) unless @done.nil? %>
-
-
\ No newline at end of file
+<%= show_done_todos(@done, done_options) unless @done.nil? %>
\ No newline at end of file
diff --git a/config/locales/en.yml b/config/locales/en.yml
index ea6b39c2..cfee0bd7 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -421,6 +421,8 @@ en:
show_empty_containers_project: "Show empty projects"
show_empty_containers_context: "Show empty contexts"
show_empty_containers_title: "Show or hide the empty projects or contexts"
+ keyboard_shortcuts: Keyboard shortcuts
+ keyboard_shortcuts_title: Show the keyboard shortcuts you can use
footer:
send_feedback: Send feedback on %{version}
sidebar: