Module: TodosHelper

Defined in:
app/helpers/todos_helper.rb

Instance Method Summary collapse

Instance Method Details

#append_updated_todoObject



552
553
554
555
556
557
558
559
560
561
562
563
# File 'app/helpers/todos_helper.rb', line 552

def append_updated_todo
  source_view do |page|
    page.context  { return @todo_deferred_state_changed || @todo_pending_state_changed }
    page.project  { return @context_changed || @todo_deferred_state_changed || @todo_pending_state_changed }
    page.deferred { return todo_moved_out_of_container && (@todo.deferred? || @todo.pending?) }
    page.calendar { return @due_date_changed && @todo.due }
    page.stats    { return false }
    page.tag      { return update_needs_to_remove_todo_from_container && !@tag_was_removed }
    page.todo     { return todo_moved_out_of_container && !(@todo.deferred? || @todo.pending? || @todo.hidden?) }
  end
  return false
end

#attachment_image(todo) ⇒ Object



208
209
210
211
212
213
214
# File 'app/helpers/todos_helper.rb', line 208

def attachment_image(todo)
  link_to(
    image_tag('blank.png', width: 16, height: 16, border: 0),
    todo.attachments.first.file.url,
    { :class => 'todo_attachment', title: 'Get attachments of this todo' }
  )
end

#collapsed_notes_image(todo) ⇒ Object



216
217
218
219
220
221
222
223
224
225
226
# File 'app/helpers/todos_helper.rb', line 216

def collapsed_notes_image(todo)
  link = link_to(
    image_tag('blank.png', :width => '16', :height => '16', :border => '0'),
    "#",
    { :class => 'show_notes', :title => 'Show notes' })
  notes = (:div, {
    :class => "todo_notes",
    :id => dom_id(todo, 'notes'),
    :style => "display:none" }) { raw render_text(todo.notes) }
  return link + notes
end

#collapsed_successors_image(todo) ⇒ Object



228
229
230
231
232
233
234
235
# File 'app/helpers/todos_helper.rb', line 228

def collapsed_successors_image(todo)
  link = link_to(image_tag('blank.png', :width => '16', :height => '16', :border => '0'), "#", { :class => 'show_successors', :title => 'Show successors' })
  successors = (:div, { :class => "todo_successors", :id => dom_id(todo, 'successors'), :style => "display:none" }) do
    render :partial => "todos/successor", :collection => todo.pending_successors,
      :locals => { :parent_container_type => parent_container_type, :suppress_dependencies => true, :predecessor => todo }
  end
  return link + successors
end

#context_container_empty_id(todo) ⇒ Object



591
592
593
# File 'app/helpers/todos_helper.rb', line 591

def context_container_empty_id(todo)
  return "c#{todo.context_id}-empty-d"
end

#context_container_id(todo) ⇒ Object



577
578
579
# File 'app/helpers/todos_helper.rb', line 577

def context_container_id(todo)
  return "context_#{todo.context_id}"
end

#date_field_tag(name, id, value = nil, options = {}) ⇒ Object



364
365
366
# File 'app/helpers/todos_helper.rb', line 364

def date_field_tag(name, id, value = nil, options = {})
  text_field_tag name, value, { "size" => 12, "id" => id, "class" => "Date", "autocomplete" => "off" }.update(options.stringify_keys)
end

#date_span(todo = @todo) ⇒ Object



259
260
261
262
263
264
265
266
267
268
269
270
# File 'app/helpers/todos_helper.rb', line 259

def date_span(todo = @todo)
  if todo.completed?
    (:span, { :class => :grey }) { format_date(todo.completed_at) }
  elsif todo.pending?
    title = t('todos.depends_on') + ": " + todo.uncompleted_predecessors.to_a.map(&:description).join(', ')
    (:a, { :title => title }) { (:span, { :class => :orange }) { t('todos.pending') } }
  elsif todo.deferred?
    show_date(todo.show_from)
  else
    due_date(todo.due)
  end
end

#default_collection_settingsObject



33
34
35
36
37
38
39
40
41
42
# File 'app/helpers/todos_helper.rb', line 33

def default_collection_settings
  {
    :suppress_context => false,
    :suppress_project => false,
    :collapsible => false,
    :append_descriptor => nil,
    :parent_container_type => nil,
    :show_empty_containers => true
  }
end

#default_contexts_for_autocompleteObject

=== helpers for default layout



382
383
384
385
# File 'app/helpers/todos_helper.rb', line 382

def default_contexts_for_autocomplete
  projects = current_user.projects.uncompleted.includes(:default_context).where('NOT(default_context_id IS NULL)')
  Hash[*projects.map { |p| [escape_javascript(p.name), escape_javascript(p.default_context.name)] }.flatten].to_json
end

#default_tags_for_autocompleteObject



387
388
389
390
# File 'app/helpers/todos_helper.rb', line 387

def default_tags_for_autocomplete
  projects = current_user.projects.uncompleted.where("NOT(default_tags = '')")
  Hash[*projects.map { |p| [escape_javascript(p.name), p.default_tags] }.flatten].to_json
end

#deferred_due_date(todo = @todo) ⇒ Object



304
305
306
# File 'app/helpers/todos_helper.rb', line 304

def deferred_due_date(todo = @todo)
  t('todos.action_due_on', :date => format_date(todo.due)) if todo.deferred? && todo.due
end

#empty_container_msg_div_id(todo = @todo || @successor) ⇒ Object

Raises:

  • (Exception.new)


610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
# File 'app/helpers/todos_helper.rb', line 610

def empty_container_msg_div_id(todo = @todo || @successor)
  raise Exception.new, "no @todo or @successor set" if !todo

  source_view do |page|
    page.project do
      return "deferred_pending_container-empty-d" if empty_criteria_met
      return todo_container_empty_id(todo)
    end
    page.tag do
      return "deferred_pending_container-empty-d" if empty_criteria_met
      return "hidden_container-empty-d"           if @todo.hidden?
      return todo_container_empty_id(todo)
    end
    page.calendar do
      return "deferred_pending_container-empty-d" if empty_criteria_met
      return "#{@new_due_id}_container-empty-d"
    end
    page.context do
      return "deferred_pending_container-empty-d" if empty_criteria_met
      return todo_container_empty_id(todo)
    end
    page.todo { return todo_container_empty_id(todo) }
    page.deferred { return todo_container_empty_id(todo) }
  end

  return context_container_empty_id(todo)
end

#empty_criteria_metObject



638
639
640
641
642
643
644
645
# File 'app/helpers/todos_helper.rb', line 638

def empty_criteria_met
  return @todo_was_deferred_from_active_state ||
    @todo_was_blocked_from_active_state ||
    @todo_was_destroyed_from_deferred_state ||
    @todo_was_created_deferred ||
    @todo_was_blocked_from_completed_state ||
    @todo_was_created_blocked
end

#empty_message_holder(container_name, show, title_param = nil) ⇒ Object

=== helpers for rendering container



5
6
7
8
9
10
11
12
# File 'app/helpers/todos_helper.rb', line 5

def empty_message_holder(container_name, show, title_param = nil)
  (:div, :id => "no_todos_in_view", :class => "container #{container_name}", :style => "display:" + (show ? "block" : "none")) do
    (:h2) { t("todos.no_actions.title", :param => title_param) } +
    (:div, :class => "message") do
      (:p) { t("todos.no_actions.#{container_name}", :param => title_param) }
    end
  end
end

#feed_content_for_todo(todo) ⇒ Object



433
434
435
436
437
438
439
440
441
442
# File 'app/helpers/todos_helper.rb', line 433

def feed_content_for_todo(todo)
  item_notes = todo.notes ? render_text(todo.notes) : ''
  due = todo.due ? (:div, t('todos.feeds.due', :date => format_date(todo.due))) : ''
  done = todo.completed? ? (:div, t('todos.feeds.completed', :date => format_date(todo.completed_at))) : ''
  context_link = link_to(context_url(todo.context), todo.context.name)
  project_link = todo.project.is_a?(NullProject) ? (:em, t('common.none')) : link_to(project_url(todo.project), todo.project.name)
  return "#{done} #{due} #{item_notes}\n" +
    (:div, "#{t('common.project')}:  #{project_link}") + "\n" +
    (:div, "#{t('common.context')}:  #{context_link}")
end

#format_ical_notes(notes) ⇒ Object



399
400
401
402
403
404
405
# File 'app/helpers/todos_helper.rb', line 399

def format_ical_notes(notes)
  if notes.present?
    split_notes = notes.split(/\n/)
    joined_notes = split_notes.join("\\n")
  end
  joined_notes || ""
end

#formatted_pagination(total) ⇒ Object

=== various helpers



394
395
396
397
# File 'app/helpers/todos_helper.rb', line 394

def formatted_pagination(total)
  s = will_paginate(@todos)
  s.gsub(/(<\/[^<]+>)/, '\1 ').chomp(' ')
end

#grip_span(todo = @todo) ⇒ Object



280
281
282
283
284
285
286
# File 'app/helpers/todos_helper.rb', line 280

def grip_span(todo = @todo)
  unless todo.completed?
    image_tag('grip.png', :width => '7', :height => '16', :border => '0',
      :title => t('todos.drag_action_title'),
      :class => 'grip')
  end
end

#image_tag_for_recurring_todo(todo) ⇒ Object



237
238
239
240
241
242
# File 'app/helpers/todos_helper.rb', line 237

def image_tag_for_recurring_todo(todo)
  return link_to(
    image_tag("recurring16x16.png"),
    recurring_todos_path,
    :class => "recurring_icon", :title => recurrence_pattern_as_text(todo.recurring_todo))
end

#image_tag_for_star(todo) ⇒ Object



244
245
246
# File 'app/helpers/todos_helper.rb', line 244

def image_tag_for_star(todo)
  image_tag("blank.png", :title => t('todos.star_action'), :class => "todo_star" + (todo.starred? ? " starred" : ""), :id => "star_img_" + todo.id.to_s)
end


321
322
323
324
325
326
327
# File 'app/helpers/todos_helper.rb', line 321

def include_context_link(todo, parent_container_type)
  return true if ['stats', 'search'].include?(parent_container_type)
  # TODO: remove next line if 'project' supports group_view_by
  return true if parent_container_type == 'project'
  return true if @group_view_by == 'project'
  return false
end


329
330
331
332
333
334
335
336
# File 'app/helpers/todos_helper.rb', line 329

def include_project_link(todo, parent_container_type)
  return false unless todo.has_project?
  return true if ['stats', 'search'].include?(parent_container_type)
  # TODO: remove next line if 'context' supports group_view_by
  return true if parent_container_type == 'context'
  return true if @group_view_by == 'context'
  return false
end

#item_container_id(todo) ⇒ Object



600
601
602
603
604
605
606
607
608
# File 'app/helpers/todos_helper.rb', line 600

def item_container_id (todo)
  return "hidden_container"           if source_view_is(:tag) && todo.hidden?
  return todo_container_id(todo)      if source_view_is :deferred
  return "#{@new_due_id}_container"   if source_view_is :calendar
  return "deferred_pending_container" if !source_view_is(:todo) && (todo.deferred? || todo.pending?)
  return "completed_container"        if todo.completed?
  return project_container_id(todo)   if source_view_is_one_of(:todo, :tag, :project, :context) && @group_view_by == 'project'
  return context_container_id(todo)
end

#parent_container_typeObject



407
408
409
410
411
412
413
# File 'app/helpers/todos_helper.rb', line 407

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 'tag'     if source_view_is :tag
  return 'context'
end


308
309
310
311
312
313
314
315
316
317
318
319
# File 'app/helpers/todos_helper.rb', line 308

def project_and_context_links(todo, parent_container_type, opts = {})
  links = ''
  if todo.completed?
    links << item_link_to_context(todo) unless opts[:suppress_context]
    links << item_link_to_project(todo) unless opts[:suppress_project] || todo.project.nil?
  else
    links << item_link_to_context(todo) if include_context_link(todo, parent_container_type)
    links << item_link_to_project(todo) if include_project_link(todo, parent_container_type)
  end

  links.html_safe
end

#project_container_empty_id(todo) ⇒ Object



586
587
588
589
# File 'app/helpers/todos_helper.rb', line 586

def project_container_empty_id(todo)
  return "p#{todo.project_id}-empty-d" unless todo.project.nil?
  return "without_project_container-empty-d"
end

#project_container_id(todo) ⇒ Object



572
573
574
575
# File 'app/helpers/todos_helper.rb', line 572

def project_container_id(todo)
  return "p#{todo.project_id}"         unless todo.project.nil?
  return "without_project_container"
end

#remote_defer_menu_item(days, todo) ⇒ Object



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'app/helpers/todos_helper.rb', line 175

def remote_defer_menu_item(days, todo)
  url = { :controller => 'todos', :action => 'defer', :id => todo.id, :days => days,
    :_source_view => (@source_view.underscore.gsub(/\s+/, '_') rescue "") }
  url[:_tag_name] = @tag_name if @source_view == 'tag'

  options = { :x_defer_alert => false, :class => "icon_defer_item icon_defer_#{days}_item", :id => "defer_#{days}_#{dom_id(todo)}" }
  if todo.due
    futuredate = (todo.show_from || todo.user.date) + days.days
    if futuredate.at_midnight > todo.due.at_midnight
      options[:x_defer_alert] = true
      options[:x_defer_date_after_due_date] = t('todos.defer_date_after_due_date')
    end
  end

  return link_to(t('todos.defer_x_days', :count => days), url, options)
end

#remote_delete_dependency(todo, predecessor) ⇒ Object



192
193
194
195
196
197
198
# File 'app/helpers/todos_helper.rb', line 192

def remote_delete_dependency(todo, predecessor)
  link_to(
    image_tag("blank.png", :title => t('todos.remove_dependency'), :align => "absmiddle", :class => "delete_item"),
    remove_predecessor_todo_path(todo),
    { :class => "delete_dependency_button", :x_predecessors_id => predecessor.id }
  )
end

#remote_delete_menu_item(todo) ⇒ Object



164
165
166
167
168
169
170
171
172
173
# File 'app/helpers/todos_helper.rb', line 164

def remote_delete_menu_item(todo)
  return link_to(
    t('todos.delete'),
    { :controller => 'todos', :action => 'destroy', :id => todo.id },
    :class => "icon_delete_item",
    :id => dom_id(todo, "delete"),
    :x_confirm_message => t('todos.confirm_delete', :description => todo.description),
    :title => t('todos.delete_action')
  )
end

#remote_edit_button(todo = @todo) ⇒ Object



155
156
157
158
159
160
161
162
# File 'app/helpers/todos_helper.rb', line 155

def remote_edit_button(todo = @todo)
  link_to(
    image_tag("blank.png", :alt => t('todos.edit'), :align => "absmiddle", :id => dom_id(todo, "edit_icon"), :class => 'edit_item'),
    edit_todo_path(todo),
    :class => "icon edit_item",
    :id => dom_id(todo, "icon_edit"),
    :title => t('todos.edit_action_with_description', :description => todo.description))
end

#remote_mobile_checkbox(todo = @todo) ⇒ Object



253
254
255
256
257
# File 'app/helpers/todos_helper.rb', line 253

def remote_mobile_checkbox(todo = @todo)
  form_tag toggle_check_todo_path(@todo, :format => 'm'), :method => :put, :class => "mobile-done", :name => "mobile_complete_#{@todo.id}" do
    check_box_tag('_source_view', 'todo', @todo && @todo.completed?, "onClick" => "document.mobile_complete_#{@todo.id}.submit()")
  end
end

#remote_promote_to_project_menu_item(todo) ⇒ Object



200
201
202
203
204
205
206
# File 'app/helpers/todos_helper.rb', line 200

def remote_promote_to_project_menu_item(todo)
  url = { :controller => 'todos', :action => 'convert_to_project', :id => todo.id,
    :_source_view => (@source_view.underscore.gsub(/\s+/, '_') rescue "") }
  url[:_tag_name] = @tag_name if @source_view == 'tag'

  link_to(t('todos.convert_to_project'), url, { :class => "icon_item_to_project", :id => dom_id(todo, "to_project") })
end

#remote_star_icon(todo = @todo) ⇒ Object

=== helpers for rendering a todo



149
150
151
152
153
# File 'app/helpers/todos_helper.rb', line 149

def remote_star_icon(todo = @todo)
  link_to(image_tag_for_star(todo),
    toggle_star_todo_path(todo),
    :class => "icon star_item", :title => t('todos.star_action_with_description', :description => todo.description))
end

#remote_toggle_checkbox(todo = @todo) ⇒ Object



248
249
250
251
# File 'app/helpers/todos_helper.rb', line 248

def remote_toggle_checkbox(todo = @todo)
  check_box_tag("mark_complete_#{todo.id}", toggle_check_todo_path(todo), todo.completed?, :class => 'item-checkbox',
    :title => todo.pending? ? t('todos.blocked_by', :predecessors => todo.uncompleted_predecessors.to_a.map(&:description).join(', ')) : "", :readonly => todo.pending?)
end

#render_animation(animation, object_name = nil) ⇒ Object

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



421
422
423
424
425
426
427
428
429
430
431
# File 'app/helpers/todos_helper.rb', line 421

def render_animation(animation, object_name = nil)
  # Add dot if object_name is given
  object_name += "." unless object_name.nil?

  # 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

#replace_with_updated_todoObject



538
539
540
541
542
543
544
545
546
547
548
549
550
# File 'app/helpers/todos_helper.rb', line 538

def replace_with_updated_todo
  source_view do |page|
    page.context  { return !update_needs_to_remove_todo_from_container }
    page.project  { return !update_needs_to_remove_todo_from_container }
    page.deferred { return !todo_moved_out_of_container && (@todo.deferred? || @todo.pending?) }
    page.calendar { return !@due_date_changed && @todo.due }
    page.stats    { return !@todo.completed? }
    page.tag      { return !update_needs_to_remove_todo_from_container && !@tag_was_removed }
    page.todo     { return !update_needs_to_remove_todo_from_container }
    page.search   { return true }
  end
  return false
end

#should_add_new_containerObject



470
471
472
473
474
475
476
# File 'app/helpers/todos_helper.rb', line 470

def should_add_new_container
  if @group_view_by == 'project'
    return @new_project_created && !source_view_is(:context)
  else
    return @new_context_created && !source_view_is(:project)
  end
end

#should_make_context_visibleObject



466
467
468
# File 'app/helpers/todos_helper.rb', line 466

def should_make_context_visible
  return @todo.active? && (!@todo.hidden? && !source_view_is(:project) )
end

#should_show_empty_containerObject



565
566
567
568
569
570
# File 'app/helpers/todos_helper.rb', line 565

def should_show_empty_container
  source_view do |page|
    page.context { return @remaining_in_context == 0 }
  end
  return @down_count == 0
end

#should_show_new_item(todo = @todo) ⇒ Object



454
455
456
457
458
459
460
461
462
463
464
# File 'app/helpers/todos_helper.rb', line 454

def should_show_new_item(todo = @todo)
  return false if todo.nil?
  source_view do |page|
    page.todo     { return !todo.hidden? && !todo.deferred? }
    page.deferred { return todo.deferred? || todo.pending? }
    page.tag      { return todo.has_tag?(@tag_name) }
    page.context  { return show_todo_on_current_context_page }
    page.project  { return show_todo_on_current_project_page }
  end
  return false
end

#show_completed_todos_for(period, collection) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
# File 'app/helpers/todos_helper.rb', line 53

def show_completed_todos_for(period, collection)
  settings = {
    :parent_container_type => "completed",
    :container_name => "completed_#{period}",
    :title => t("todos.completed_#{period}"),
    :show_empty_containers => true
  }

  render :partial => "todos/collection",
    :object => collection,
    :locals => { :settings => settings }
end

#show_date(date) ⇒ Object



360
361
362
# File 'app/helpers/todos_helper.rb', line 360

def show_date(date)
  return DateLabelHelper::ShowFromDateView.new(date, prefs).show_from_date_html
end

#show_deferred_pending_todos(deferred_todos, pending_todos, settings = {}) ⇒ Object



74
75
76
77
78
79
80
81
# File 'app/helpers/todos_helper.rb', line 74

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

#show_done_todos(done_todos, settings = {}) ⇒ Object



44
45
46
47
48
49
50
51
# File 'app/helpers/todos_helper.rb', line 44

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

#show_empty_message_in_source_containerObject



654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
# File 'app/helpers/todos_helper.rb', line 654

def show_empty_message_in_source_container
  container_id = ""
  source_view do |page|
    page.deferred { container_id = todo_container_empty_id(@original_item) if @remaining_in_context == 0 }
    page.calendar { container_id = "#{@original_item_due_id}_container-empty-d" if @old_due_empty }
    page.todo { container_id = context_container_empty_id(@original_item) if @remaining_in_context == 0 }
    page.done { container_id = "completed_#{@original_completed_period}_container-empty-d" if @remaining_in_context == 0 }
    page.all_done { container_id = "all-done-empty-nd" if @remaining_in_context == 0 }
    page.project do
      container_id = project_container_empty_id(@original_item) if @remaining_in_context == 0
      container_id = "deferred_pending_container-empty-d" if todo_was_removed_from_deferred_or_blocked_container && @remaining_deferred_or_pending_count == 0
      container_id = "completed_container-empty-d" if @completed_count && @completed_count == 0 && !@todo.completed?
    end
    page.tag do
      container_id = "hidden_container-empty-d" if (@remaining_hidden_count == 0 && !@todo.hidden? && @todo_hidden_state_changed) ||
        (@remaining_hidden_count == 0 && @todo.completed? && @original_item.hidden?)
      container_id = "deferred_pending_container-empty-d" if (todo_was_removed_from_deferred_or_blocked_container && @remaining_deferred_or_pending_count == 0) ||
        (@original_item.deferred? && @remaining_deferred_or_pending_count == 0 && (@todo.completed? || @tag_was_removed))
      container_id = "completed_container-empty-d" if @completed_count && @completed_count == 0 && !@todo.completed?
    end
    page.context do
      container_id = context_container_empty_id(@original_item) if @remaining_in_context == 0
      container_id = "deferred_pending_container-empty-d" if todo_was_removed_from_deferred_or_blocked_container && @remaining_deferred_or_pending_count == 0
      container_id = "completed_container-empty-d" if @completed_count && @completed_count == 0 && !@todo.completed?
    end
  end
  return container_id.blank? ? "" : "$(\"##{container_id}\").slideDown(100);".html_safe
end

#show_grouped_todos(settings = {}) ⇒ Object



24
25
26
27
28
29
30
31
# File 'app/helpers/todos_helper.rb', line 24

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
  }) })
end

#show_hidden_todos(hidden_todos, settings = {}) ⇒ Object



66
67
68
69
70
71
72
# File 'app/helpers/todos_helper.rb', line 66

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

#show_todo_on_current_context_pageObject

=== handle CRUD actions for todos



446
447
448
# File 'app/helpers/todos_helper.rb', line 446

def show_todo_on_current_context_page
  @todo.context_id == @default_context.id && (!@todo.hidden? || @todo.context.hidden?)
end

#show_todo_on_current_project_pageObject



450
451
452
# File 'app/helpers/todos_helper.rb', line 450

def show_todo_on_current_project_page
  @todo.project.id == @default_project.id && (!@todo.hidden? || @todo.project.hidden?)
end

#show_todos_without_project(todos_without_project, settings = {}) ⇒ Object



83
84
85
86
87
88
89
90
91
92
# File 'app/helpers/todos_helper.rb', line 83

def show_todos_without_project(todos_without_project, settings = {})
  render :partial => 'todos/collection',
    :object => todos_without_project,
    :locals => { :settings => settings.reverse_merge!({
      :collapsible => true,
      :container_name => "without_project",
      :parent_container_type => "home"
      })
    }
end

#sort_key(todo) ⇒ Object



368
369
370
371
372
373
374
375
376
377
378
# File 'app/helpers/todos_helper.rb', line 368

def sort_key(todo)
  # actions are sorted using {order("todos.due IS NULL, todos.due ASC, todos.created_at ASC")}
  # the JavaScript frontend sorts using unicode/ascii
  format = "%Y%m%d%H%M%S%L"
  if todo.due?
    sort_by_due = todo.due.strftime format
  else
    sort_by_due = "Z" * 17 # length of format string
  end
  sort_by_due + todo.created_at.strftime(format)
end

#staleness_class(item) ⇒ Object

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


345
346
347
348
349
350
351
352
353
354
355
356
357
358
# File 'app/helpers/todos_helper.rb', line 345

def staleness_class(item)
  days_stale = Staleness.days_stale(item, current_user)
  start = current_user.prefs.staleness_starts
  case days_stale
  when 0...start
    ""
  when start...start * 2
    " stale_l1"
  when start*2...start * 3
    " stale_l2"
  else
    " stale_l3"
  end
end

#successors_span(todo = @todo) ⇒ Object



272
273
274
275
276
277
278
# File 'app/helpers/todos_helper.rb', line 272

def successors_span(todo = @todo)
  unless todo.pending_successors.empty?
    pending_count = todo.pending_successors.count
    title = "#{t('todos.has_x_pending', :count => pending_count)}: #{todo.pending_successors.to_a.map(&:description).join(', ')}"
    image_tag('successor_off.png', :width => '10', :height => '16', :border => '0', :title => title)
  end
end

#tag_list(todo = @todo, mobile = false) ⇒ Object



296
297
298
# File 'app/helpers/todos_helper.rb', line 296

def tag_list(todo=@todo, mobile = false)
  (:span, :class => 'tags') { todo.tags.all_except_starred.collect{ |tag| tag_span(tag, mobile) }.join('').html_safe }
end

#tag_list_mobile(todo = @todo) ⇒ Object



300
301
302
# File 'app/helpers/todos_helper.rb', line 300

def tag_list_mobile(todo = @todo)
  todo.tags.all_except_starred.empty? ? "" : tag_list(todo, true)
end

#tag_list_text(todo = @todo) ⇒ Object



288
289
290
# File 'app/helpers/todos_helper.rb', line 288

def tag_list_text(todo = @todo)
  todo.tags.to_a.join(', ')
end

#tag_span(tag, mobile = false) ⇒ Object



292
293
294
# File 'app/helpers/todos_helper.rb', line 292

def tag_span(tag, mobile = false)
  (:span, :class => "tag #{tag.label}") { link_to(tag.name, tag_path(tag.name, :format => mobile ? :m : nil)) }
end

#todo_container_empty_id(todo) ⇒ Object

Raises:

  • (Exception.new)


595
596
597
598
# File 'app/helpers/todos_helper.rb', line 595

def todo_container_empty_id(todo)
  raise Exception.new, "no todo set in TodosHelper::todo_container_empty_id. You probably did not assign @original_item" if !todo
  @group_view_by == "project" ? project_container_empty_id(todo) : context_container_empty_id(todo)
end

#todo_container_id(todo) ⇒ Object



581
582
583
584
# File 'app/helpers/todos_helper.rb', line 581

def todo_container_id(todo)
  return project_container_id(todo) if @group_view_by == "project"
  return context_container_id(todo)
end

#todo_container_is_emptyObject



478
479
480
481
482
# File 'app/helpers/todos_helper.rb', line 478

def todo_container_is_empty
  default_container_empty = (@down_count == 0)
  deferred_container_empty = (@todo.deferred? && @remaining_deferred_count == 0)
  return default_container_empty || deferred_container_empty
end

#todo_moved_out_of_containerObject



484
485
486
487
488
489
490
491
492
493
# File 'app/helpers/todos_helper.rb', line 484

def todo_moved_out_of_container
  # moved from one project container to another
  moved_project = @project_changed && @group_view_by == 'project'
  # moved from one context container to another
  moved_context = @context_changed && @group_view_by == 'context'
  # moved from actions-without-project container to another
  moved_without_project = @context_changed && @group_view_by == 'project' && @todo.project_id.nil?

  return moved_project || moved_context || moved_without_project
end

#todo_was_removed_from_deferred_or_blocked_containerObject



647
648
649
650
651
652
# File 'app/helpers/todos_helper.rb', line 647

def todo_was_removed_from_deferred_or_blocked_container
  return @todo_was_activated_from_deferred_state ||
    @todo_was_activated_from_pending_state ||
    @todo_was_destroyed_from_deferred_or_pending_state ||
    @todo_was_completed_from_deferred_or_blocked_state
end

#todos_calendar_container(period, collection) ⇒ Object



136
137
138
139
140
141
142
143
144
145
# File 'app/helpers/todos_helper.rb', line 136

def todos_calendar_container(period, collection)
  render :partial => 'todos/collection',
    :object => collection,
    :locals => { :settings => {
      :collapsible => false,
      :show_empty_containers => true,
      :container_name => "#{period}",
      :title => t("todos.calendar.#{period}", :month => l(Time.zone.now, :format => "%B"), :next_month => l(1.month.from_now, :format => "%B"))
    } }
end

#todos_container(settings = {}) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'app/helpers/todos_helper.rb', line 94

def todos_container(settings = {})
  settings.reverse_merge!({
    :id => "#{settings[:container_name]}_container",
    :class => "container #{settings[:container_name]}",
    })

  if settings[:collapsible]
    settings[:class] += " collapsible"
  end

  (:div,
    :class => settings[:class],
    :id => settings[:id],
    :style => "display:" + (settings[:show_container] ? "block" : "none")) do
    yield
  end
end

#todos_container_empty_message(container_name, container_id, show_message) ⇒ Object



14
15
16
17
18
19
20
21
22
# File 'app/helpers/todos_helper.rb', line 14

def todos_container_empty_message(container_name, container_id, show_message)
  (:div, :id => "#{container_id}-empty-d", :style => "display:#{show_message ? 'block' : 'none'}") do
    (:div, :class => "message") do
      (:p) do
        t("todos.no_actions.#{container_name}")
      end
    end
  end
end

#todos_container_header(settings = {}) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
# File 'app/helpers/todos_helper.rb', line 112

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? ? "" : (:div, :class => "link_in_container_header") { settings[:link_in_header] }
  header += (:h2) do
    toggle = settings[:collapsible] ? container_toggle("toggle_#{settings[:id]}") : ""
    "#{toggle} #{settings[:title]} #{settings[:append_descriptor]}".html_safe
  end
  header += (:div, nil, :id => settings[:id] + "_target", :class => "context_target drop_target")
  header.html_safe
end

#todos_container_items(collection, settings = {}) ⇒ Object



125
126
127
128
129
130
131
132
133
134
# File 'app/helpers/todos_helper.rb', line 125

def todos_container_items(collection, settings = {})
  settings.reverse_merge!({ :id => "#{settings[:container_name]}" })
  # do not pass :class to partial locals
  settings.delete(:class)

  (: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

#update_needs_to_add_new_containerObject



532
533
534
535
536
# File 'app/helpers/todos_helper.rb', line 532

def update_needs_to_add_new_container
  needs_new_context = @new_context_created && (@group_view_by == "context")
  needs_new_project = @new_project_created && (@group_view_by == "project")
  return needs_new_project || needs_new_context
end

#update_needs_to_hide_containerObject



495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
# File 'app/helpers/todos_helper.rb', line 495

def update_needs_to_hide_container
  if source_view_is_one_of(:tag, :context, :project)
    return @remaining_in_context == 0 && (
      todo_moved_out_of_container                                                       ||
      (@todo_hidden_state_changed && @todo.hidden?)                                     ||
      @todo_was_deferred_from_active_state                                              ||
      @tag_was_removed                                                                  ||
      @todo_was_destroyed                                                               ||
      (
        @todo.completed? && !(
          @original_item.deferred? ||
          @original_item.hidden? ||
          @original_item.pending?
        )
      )
    )
  end

  return false if source_view_is_one_of(:calendar, :done, :all_done)

  return @remaining_in_context == 0
end

#update_needs_to_remove_todo_from_containerObject



518
519
520
521
522
523
524
525
526
527
528
529
530
# File 'app/helpers/todos_helper.rb', line 518

def update_needs_to_remove_todo_from_container
  source_view do |page|
    page.context  { return @context_changed || @todo_deferred_state_changed || @todo_pending_state_changed || @todo_should_be_hidden }
    page.project  { return @context_changed || @todo_deferred_state_changed || @todo_pending_state_changed || @project_changed }
    page.deferred { return todo_moved_out_of_container || !(@todo.deferred? || @todo.pending?) }
    page.calendar { return @due_date_changed || !@todo.due }
    page.stats    { return @todo.completed? }
    page.tag      { return ((@context_changed | @project_changed) && !@todo.hidden?) || @tag_was_removed || @todo_hidden_state_changed || @todo_deferred_state_changed }
    page.todo     { return todo_moved_out_of_container || @todo.hidden? || @todo.deferred? || @todo.pending? }
    page.search   { return false }
  end
  return false
end