gitlab-org--gitlab-foss/lib/banzai/filter/task_list_filter.rb

102 lines
3.2 KiB
Ruby

# frozen_string_literal: true
require 'task_list/filter'
# Generated HTML is transformed back to GFM by:
# - app/assets/javascripts/behaviors/markdown/nodes/ordered_task_list.js
# - app/assets/javascripts/behaviors/markdown/nodes/task_list.js
# - app/assets/javascripts/behaviors/markdown/nodes/task_list_item.js
module Banzai
module Filter
# TaskList filter replaces task list item markers (`[ ]`, `[x]`, and `[~]`)
# with checkboxes, marked up with metadata and behavior.
#
# This should be run on the HTML generated by the Markdown filter, after the
# SanitizationFilter.
#
# Syntax
# ------
#
# Task list items must be in a list format:
#
# ```
# - [ ] incomplete
# - [x] complete
# - [~] inapplicable
# ```
#
# This class overrides TaskList::Filter in the `deckar01-task_list` gem
# to add support for inapplicable task items
class TaskListFilter < TaskList::Filter
extend ::Gitlab::Utils::Override
XPATH = 'descendant-or-self::li[input[@data-inapplicable]] | descendant-or-self::li[p[input[@data-inapplicable]]]'
INAPPLICABLE = '[~]'
INAPPLICABLEPATTERN = /\[~\]/.freeze
# Pattern used to identify all task list items.
# Useful when you need iterate over all items.
NEWITEMPATTERN = /
^
(?:\s*[-+*]|(?:\d+\.))? # optional list prefix
\s* # optional whitespace prefix
( # checkbox
#{CompletePattern}|
#{IncompletePattern}|
#{INAPPLICABLEPATTERN}
)
(?=\s) # followed by whitespace
/x.freeze
# Force the gem's constant to use our new one
superclass.send(:remove_const, :ItemPattern) # rubocop: disable GitlabSecurity/PublicSend
superclass.const_set(:ItemPattern, NEWITEMPATTERN)
def inapplicable?(item)
!!(item.checkbox_text =~ INAPPLICABLEPATTERN)
end
override :render_item_checkbox
def render_item_checkbox(item)
%(<task-button></task-button><input type="checkbox"
class="task-list-item-checkbox"
#{'checked="checked"' if item.complete?}
#{'data-inapplicable' if inapplicable?(item)}
disabled="disabled"/>)
end
override :render_task_list_item
def render_task_list_item(item)
source = item.source
if inapplicable?(item)
# Add a `<s>` tag around the list item text. However because of the
# way tasks are built, the source can include an embedded sublist, like
# `[~] foobar\n<ol><li....`
# The `<s>` should only be added to the main text.
source = source.partition("#{INAPPLICABLE} ")
text = source.last.partition(/\<(ol|ul)/)
text[0] = "<s>#{text[0]}</s>"
source[-1] = text.join
source = source.join
end
Nokogiri::HTML.fragment \
source.sub(ItemPattern, render_item_checkbox(item)), 'utf-8'
end
override :call
def call
super
# add class to li for any inapplicable checkboxes
doc.xpath(XPATH).each do |li|
li.add_class('inapplicable')
end
doc
end
end
end
end