diff options
Diffstat (limited to 'app/models/concerns/taskable.rb')
-rw-r--r-- | app/models/concerns/taskable.rb | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/app/models/concerns/taskable.rb b/app/models/concerns/taskable.rb new file mode 100644 index 00000000000..410e8dc820b --- /dev/null +++ b/app/models/concerns/taskable.rb @@ -0,0 +1,51 @@ +# Contains functionality for objects that can have task lists in their +# descriptions. Task list items can be added with Markdown like "* [x] Fix +# bugs". +# +# Used by MergeRequest and Issue +module Taskable + TASK_PATTERN_MD = /^(?<bullet> *[*-] *)\[(?<checked>[ xX])\]/.freeze + TASK_PATTERN_HTML = /^<li>\[(?<checked>[ xX])\]/.freeze + + # Change the state of a task list item for this Taskable. Edit the object's + # description by finding the nth task item and changing its checkbox + # placeholder to "[x]" if +checked+ is true, or "[ ]" if it's false. + # Note: task numbering starts with 1 + def update_nth_task(n, checked) + index = 0 + check_char = checked ? 'x' : ' ' + + # Do this instead of using #gsub! so that ActiveRecord detects that a field + # has changed. + self.description = self.description.gsub(TASK_PATTERN_MD) do |match| + index += 1 + case index + when n then "#{$LAST_MATCH_INFO[:bullet]}[#{check_char}]" + else match + end + end + + save + end + + # Return true if this object's description has any task list items. + def tasks? + description && description.match(TASK_PATTERN_MD) + end + + # Return a string that describes the current state of this Taskable's task + # list items, e.g. "20 tasks (12 done, 8 unfinished)" + def task_status + return nil unless description + + num_tasks = 0 + num_done = 0 + + description.scan(TASK_PATTERN_MD) do + num_tasks += 1 + num_done += 1 unless $LAST_MATCH_INFO[:checked] == ' ' + end + + "#{num_tasks} tasks (#{num_done} done, #{num_tasks - num_done} unfinished)" + end +end |