diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index 1bf4eb13..d77a9cd4 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -1,287 +1,239 @@ -module TodosHelper - - # #require 'users_controller' Counts the number of incomplete items in the - # specified context - # - def count_items(context) - count = Todo.find_all("done=0 AND context_id=#{context.id}").length - end - - def form_remote_tag_edit_todo( &block ) - form_tag( - todo_path(@todo), { - :method => :put, - :id => dom_id(@todo, 'form'), - :class => dom_id(@todo, 'form') + " inline-form edit_todo_form" }, - &block ) - apply_behavior 'form.edit_todo_form', make_remote_form( - :method => :put, - :before => "this.down('button.positive').startWaiting()", - :loaded => "this.down('button.positive').stopWaiting()", - :condition => "!(this.down('button.positive').isWaiting())"), - :prevent_default => true - end - - def set_behavior_for_delete_icon - parameters = "_source_view=#{@source_view}" - parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag' - apply_behavior '.item-container a.delete_icon:click', :prevent_default => true do |page| - page.confirming "'Are you sure that you want to ' + this.title + '?'" do - page << "itemContainer = this.up('.item-container'); itemContainer.startWaiting();" - page << remote_to_href(:method => 'delete', :with => "'#{parameters}'", :complete => "itemContainer.stopWaiting();") - end - end - end - - def remote_delete_icon - str = link_to( image_tag_for_delete, - todo_path(@todo), :id => "delete_icon_"+@todo.id.to_s, - :class => "icon delete_icon", :title => "delete the action '#{@todo.description}'") - set_behavior_for_delete_icon - str - end - - def set_behavior_for_star_icon - apply_behavior '.item-container a.star_item:click', - remote_to_href(:method => 'put', :with => "{ _source_view : '#{@source_view}' }"), - :prevent_default => true - end - - def remote_star_icon - str = link_to( image_tag_for_star(@todo), - toggle_star_todo_path(@todo), - :class => "icon star_item", :title => "star the action '#{@todo.description}'") - set_behavior_for_star_icon - str - end - - def set_behavior_for_edit_icon - parameters = "_source_view=#{@source_view}" - parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag' - apply_behavior '.item-container a.edit_icon:click', :prevent_default => true do |page| - page << "Effect.Pulsate(this);" - page << remote_to_href(:method => 'get', :with => "'#{parameters}'") - end - end - - def remote_edit_icon - if !@todo.completed? - str = link_to( image_tag_for_edit(@todo), - edit_todo_path(@todo), - :class => "icon edit_icon") - set_behavior_for_edit_icon - else - str = '' + image_tag("blank.png") + " " - end - str - end - - def set_behavior_for_toggle_checkbox - parameters = "_source_view=#{@source_view}" - parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag' - apply_behavior '.item-container input.item-checkbox:click', - remote_function(:url => javascript_variable('this.value'), :method => 'put', - :with => "'#{parameters}'") - end - - def remote_toggle_checkbox - str = check_box_tag('item_id', toggle_check_todo_path(@todo), @todo.completed?, :class => 'item-checkbox') - set_behavior_for_toggle_checkbox - str - end - - def date_span - if @todo.completed? - "#{format_date( @todo.completed_at )}" - elsif @todo.deferred? - show_date( @todo.show_from ) - else - due_date( @todo.due ) - end - end - - def tag_list_text - @todo.tags.collect{|t| t.name}.join(', ') - end - - def tag_list - tags_except_starred = @todo.tags.reject{|t| t.name == Todo::STARRED_TAG_NAME} - tag_list = tags_except_starred.collect{|t| "" + link_to(t.name, :controller => "todos", :action => "tag", :id => t.name) + ""}.join('') - "#{tag_list}" - end - - def tag_list_mobile - tags_except_starred = @todo.tags.reject{|t| t.name == Todo::STARRED_TAG_NAME} - # removed the link. TODO: add link to mobile view of tagged actions - tag_list = tags_except_starred.collect{|t| - "" + - link_to(t.name, {:action => "tag", :controller => "todos", :id => t.name+".m"}) + - ""}.join('') - if tag_list.empty? then "" else "#{tag_list}" end - end - - def deferred_due_date - if @todo.deferred? && @todo.due - "(action due on #{format_date(@todo.due)})" - end - end - - def project_and_context_links(parent_container_type, opts = {}) - str = '' - if @todo.completed? - str += @todo.context.name unless opts[:suppress_context] - should_suppress_project = opts[:suppress_project] || @todo.project.nil? - str += ", " unless str.blank? || should_suppress_project - str += @todo.project.name unless should_suppress_project - str = "(#{str})" unless str.blank? - else - if (['project', 'tag', 'stats', 'search'].include?(parent_container_type)) - str << item_link_to_context( @todo ) - end - if (['context', 'tickler', 'tag', 'stats', 'search'].include?(parent_container_type)) && @todo.project_id - str << item_link_to_project( @todo ) - end - end - return str - end - - # Uses the 'staleness_starts' value from settings.yml (in days) to colour the - # background of the action appropriately according to the age of the creation - # date: - # * l1: created more than 1 x staleness_starts, but < 2 x staleness_starts - # * l2: created more than 2 x staleness_starts, but < 3 x staleness_starts - # * l3: created more than 3 x staleness_starts - # - def staleness_class(item) - if item.due || item.completed? - return "" - elsif item.created_at < user_time - (prefs.staleness_starts * 3).days - return " stale_l3" - elsif item.created_at < user_time - (prefs.staleness_starts * 2).days - return " stale_l2" - elsif item.created_at < user_time - (prefs.staleness_starts).days - return " stale_l1" - else - return "" - end - end - - # Check show_from date in comparison to today's date Flag up date - # appropriately with a 'traffic light' colour code - # - def show_date(d) - if d == nil - return "" - end - - days = days_from_today(d) - - case days - # overdue or due very soon! sound the alarm! - when -1000..-1 - "Scheduled to show " + (days * -1).to_s + " days ago " - when 0 - "Show Today " - when 1 - "Show Tomorrow " - # due 2-7 days away - when 2..7 - if prefs.due_style == Preference.due_styles[:due_on] - "Show on " + d.strftime("%A") + " " - else - "Show in " + days.to_s + " days " - end - # more than a week away - relax - else - "Show in " + days.to_s + " days " - end - end - - def calendar_setup( input_field ) - str = "Calendar.setup({ ifFormat:\"#{prefs.date_format}\"" - str << ",firstDay:#{prefs.week_starts},showOthers:true,range:[2004, 2010]" - str << ",step:1,inputField:\"" + input_field + "\",cache:true,align:\"TR\" })\n" - javascript_tag str - end - - def item_container_id (todo) - if source_view_is :project - return "p#{todo.project_id}" if todo.active? - return "tickler" if todo.deferred? - end - return "c#{todo.context_id}" - end - - def should_show_new_item - - if @todo.project.nil? == false - # do not show new actions that were added to hidden or completed projects - # on home page and context page - return false if source_view_is(:todo) && (@todo.project.hidden? || @todo.project.completed?) - return false if source_view_is(:context) && (@todo.project.hidden? || @todo.project.completed?) - end - - return true if source_view_is(:deferred) && @todo.deferred? - return true if source_view_is(:project) && @todo.project.hidden? && @todo.project_hidden? - return true if source_view_is(:project) && @todo.deferred? - return true if !source_view_is(:deferred) && @todo.active? - return false - end - - def parent_container_type - return 'tickler' if source_view_is :deferred - return 'project' if source_view_is :project - return 'stats' if source_view_is :stats - return 'context' - end - - def empty_container_msg_div_id - return "tickler-empty-nd" if source_view_is(:project) && @todo.deferred? - return "p#{@todo.project_id}empty-nd" if source_view_is :project - return "c#{@todo.context_id}empty-nd" - end - - def project_names_for_autocomplete - array_or_string_for_javascript( ['None'] + current_user.projects.active.collect{|p| escape_javascript(p.name) } ) - end - - def context_names_for_autocomplete - # #return array_or_string_for_javascript(['Create a new context']) if - # @contexts.empty? - array_or_string_for_javascript( current_user.contexts.collect{|c| escape_javascript(c.name) } ) - end - - def format_ical_notes(notes) - split_notes = notes.split(/\n/) - joined_notes = split_notes.join("\\n") - end - - def formatted_pagination(total) - s = will_paginate(@todos) - (s.gsub(/(<\/[^<]+>)/, '\1 ')).chomp(' ') - end - - def date_field_tag(name, id, value = nil, options = {}) - text_field_tag name, value, {"size" => 12, "id" => id, "class" => "Date", "onfocus" => "Calendar.setup", "autocomplete" => "off"}.update(options.stringify_keys) - end - - private - - def image_tag_for_delete - image_tag("blank.png", :title =>"Delete action", :class=>"delete_item") - end - - def image_tag_for_edit(todo) - image_tag("blank.png", :title =>"Edit action", :class=>"edit_item", :id=> dom_id(todo, 'edit_icon')) - end - - def image_tag_for_star(todo) - class_str = todo.starred? ? "starred_todo" : "unstarred_todo" - image_tag("blank.png", :title =>"Star action", :class => class_str) - end - - def defer_link(days) - link_to_remote image_tag("defer_#{days}.png", :alt => "Defer #{pluralize(days, 'day')}"), :url => {:controller => 'todos', :action => 'defer', :id => @todo.id, :days => days, :_source_view => (@source_view.underscore.gsub(/\s+/,'_') rescue "")} - end - -end +module TodosHelper + + # #require 'users_controller' Counts the number of incomplete items in the + # specified context + # + def count_items(context) + count = Todo.find_all("done=0 AND context_id=#{context.id}").length + end + + def form_remote_tag_edit_todo( &block ) + form_tag( + todo_path(@todo), { + :method => :put, + :id => dom_id(@todo, 'form'), + :class => dom_id(@todo, 'form') + " inline-form edit_todo_form" }, + &block ) + apply_behavior 'form.edit_todo_form', make_remote_form( + :method => :put, + :before => "this.down('button.positive').startWaiting()", + :loaded => "this.down('button.positive').stopWaiting()", + :condition => "!(this.down('button.positive').isWaiting())"), + :prevent_default => true + end + + def set_behavior_for_star_icon + apply_behavior '.item-container a.star_item:click', + remote_to_href(:method => 'put', :with => "{ _source_view : '#{@source_view}' }"), + :prevent_default => true + end + + def remote_star_icon + str = link_to( image_tag_for_star(@todo), + toggle_star_todo_path(@todo), + :class => "icon star_item", :title => "star the action '#{@todo.description}'") + set_behavior_for_star_icon + str + end + + def set_behavior_for_toggle_checkbox + parameters = "_source_view=#{@source_view}" + parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag' + apply_behavior '.item-container input.item-checkbox:click', + remote_function(:url => javascript_variable('this.value'), :method => 'put', + :with => "'#{parameters}'") + end + + def remote_toggle_checkbox + str = check_box_tag('item_id', toggle_check_todo_path(@todo), @todo.completed?, :class => 'item-checkbox') + set_behavior_for_toggle_checkbox + str + end + + def date_span + if @todo.completed? + "#{format_date( @todo.completed_at )}" + elsif @todo.deferred? + show_date( @todo.show_from ) + else + due_date( @todo.due ) + end + end + + def tag_list_text + @todo.tags.collect{|t| t.name}.join(', ') + end + + def tag_list + tags_except_starred = @todo.tags.reject{|t| t.name == Todo::STARRED_TAG_NAME} + tag_list = tags_except_starred.collect{|t| "" + link_to(t.name, :controller => "todos", :action => "tag", :id => t.name) + ""}.join('') + "#{tag_list}" + end + + def tag_list_mobile + tags_except_starred = @todo.tags.reject{|t| t.name == Todo::STARRED_TAG_NAME} + # removed the link. TODO: add link to mobile view of tagged actions + tag_list = tags_except_starred.collect{|t| + "" + + link_to(t.name, {:action => "tag", :controller => "todos", :id => t.name+".m"}) + + ""}.join('') + if tag_list.empty? then "" else "#{tag_list}" end + end + + def deferred_due_date + if @todo.deferred? && @todo.due + "(action due on #{format_date(@todo.due)})" + end + end + + def project_and_context_links(parent_container_type, opts = {}) + str = '' + if @todo.completed? + str += @todo.context.name unless opts[:suppress_context] + should_suppress_project = opts[:suppress_project] || @todo.project.nil? + str += ", " unless str.blank? || should_suppress_project + str += @todo.project.name unless should_suppress_project + str = "(#{str})" unless str.blank? + else + if (['project', 'tag', 'stats', 'search'].include?(parent_container_type)) + str << item_link_to_context( @todo ) + end + if (['context', 'tickler', 'tag', 'stats', 'search'].include?(parent_container_type)) && @todo.project_id + str << item_link_to_project( @todo ) + end + end + return str + end + + # Uses the 'staleness_starts' value from settings.yml (in days) to colour the + # background of the action appropriately according to the age of the creation + # date: + # * l1: created more than 1 x staleness_starts, but < 2 x staleness_starts + # * l2: created more than 2 x staleness_starts, but < 3 x staleness_starts + # * l3: created more than 3 x staleness_starts + # + def staleness_class(item) + if item.due || item.completed? + return "" + elsif item.created_at < user_time - (prefs.staleness_starts * 3).days + return " stale_l3" + elsif item.created_at < user_time - (prefs.staleness_starts * 2).days + return " stale_l2" + elsif item.created_at < user_time - (prefs.staleness_starts).days + return " stale_l1" + else + return "" + end + end + + # Check show_from date in comparison to today's date Flag up date + # appropriately with a 'traffic light' colour code + # + def show_date(d) + if d == nil + return "" + end + + days = days_from_today(d) + + case days + # overdue or due very soon! sound the alarm! + when -1000..-1 + "Scheduled to show " + (days * -1).to_s + " days ago " + when 0 + "Show Today " + when 1 + "Show Tomorrow " + # due 2-7 days away + when 2..7 + if prefs.due_style == Preference.due_styles[:due_on] + "Show on " + d.strftime("%A") + " " + else + "Show in " + days.to_s + " days " + end + # more than a week away - relax + else + "Show in " + days.to_s + " days " + end + end + + def calendar_setup( input_field ) + str = "Calendar.setup({ ifFormat:\"#{prefs.date_format}\"" + str << ",firstDay:#{prefs.week_starts},showOthers:true,range:[2004, 2010]" + str << ",step:1,inputField:\"" + input_field + "\",cache:true,align:\"TR\" })\n" + javascript_tag str + end + + def item_container_id (todo) + if source_view_is :project + return "p#{todo.project_id}" if todo.active? + return "tickler" if todo.deferred? + end + return "c#{todo.context_id}" + end + + def should_show_new_item + + if @todo.project.nil? == false + # do not show new actions that were added to hidden or completed projects + # on home page and context page + return false if source_view_is(:todo) && (@todo.project.hidden? || @todo.project.completed?) + return false if source_view_is(:context) && (@todo.project.hidden? || @todo.project.completed?) + end + + return true if source_view_is(:deferred) && @todo.deferred? + return true if source_view_is(:project) && @todo.project.hidden? && @todo.project_hidden? + return true if source_view_is(:project) && @todo.deferred? + return true if !source_view_is(:deferred) && @todo.active? + return false + end + + def parent_container_type + return 'tickler' if source_view_is :deferred + return 'project' if source_view_is :project + return 'stats' if source_view_is :stats + return 'context' + end + + def empty_container_msg_div_id + return "tickler-empty-nd" if source_view_is(:project) && @todo.deferred? + return "p#{@todo.project_id}empty-nd" if source_view_is :project + return "c#{@todo.context_id}empty-nd" + end + + def project_names_for_autocomplete + array_or_string_for_javascript( ['None'] + current_user.projects.active.collect{|p| escape_javascript(p.name) } ) + end + + def context_names_for_autocomplete + # #return array_or_string_for_javascript(['Create a new context']) if + # @contexts.empty? + array_or_string_for_javascript( current_user.contexts.collect{|c| escape_javascript(c.name) } ) + end + + def format_ical_notes(notes) + split_notes = notes.split(/\n/) + joined_notes = split_notes.join("\\n") + end + + def formatted_pagination(total) + s = will_paginate(@todos) + (s.gsub(/(<\/[^<]+>)/, '\1 ')).chomp(' ') + end + + def date_field_tag(name, id, value = nil, options = {}) + text_field_tag name, value, {"size" => 12, "id" => id, "class" => "Date", "onfocus" => "Calendar.setup", "autocomplete" => "off"}.update(options.stringify_keys) + end + + private + + def image_tag_for_star(todo) + class_str = todo.starred? ? "starred_todo" : "unstarred_todo" + image_tag("blank.png", :title =>"Star action", :class => class_str) + end + + def defer_link(days) + link_to_remote image_tag("defer_#{days}.png", :alt => "Defer #{pluralize(days, 'day')}"), :url => {:controller => 'todos', :action => 'defer', :id => @todo.id, :days => days, :_source_view => (@source_view.underscore.gsub(/\s+/,'_') rescue "")} + end + +end diff --git a/app/views/contexts/_context.rhtml b/app/views/contexts/_context.rhtml index bd90099f..055c89d5 100644 --- a/app/views/contexts/_context.rhtml +++ b/app/views/contexts/_context.rhtml @@ -39,9 +39,7 @@ <%= render :partial => "todos/todo", :collection => @not_done, :locals => { :parent_container_type => "context" } %> <% if @not_done.empty? # fix (hack) for #713 - set_behavior_for_delete_icon set_behavior_for_star_icon - set_behavior_for_edit_icon set_behavior_for_toggle_checkbox end -%> diff --git a/app/views/todos/_todo.html.erb b/app/views/todos/_todo.html.erb index 7b074d3d..d37e8fcc 100644 --- a/app/views/todos/_todo.html.erb +++ b/app/views/todos/_todo.html.erb @@ -2,7 +2,7 @@ @todo = todo suppress_context ||= false suppress_project ||= false -suppress_edit_button ||= false +suppress_edit_button ||= todo.completed? parameters = "_source_view=#{@source_view}" parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag' @z_index_counter = @z_index_counter - 1 # for IE z-index bug @@ -12,10 +12,14 @@ parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag' <%= remote_star_icon %> <%= remote_toggle_checkbox unless source_view_is :deferred %>
<%= date_span -%> diff --git a/doc/CHANGELOG b/doc/CHANGELOG index 40be72e7..6b4ab55e 100644 --- a/doc/CHANGELOG +++ b/doc/CHANGELOG @@ -8,10 +8,15 @@ * Mailing list: http://lists.rousette.org.uk/mailman/listinfo/tracks-discuss * Original developer: bsag (http://www.rousette.org.uk/) * Contributors: http://getontracks.org/wiki/Tracks/Contributing/Contributors -* Version: 1.7 +* Version: 1.8devel * Copyright: (cc) 2004-2009 rousette.org.uk. * License: GNU GPL +== Version 1.7devel + +New features: +1. Redesign of menus and introduction of a context menu per todo + == Version 1.7 New features: