blob: 4f39a25ff68aa129923a4ac00c63a7e0b7eae06f (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
# 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 = /\[~\]/
# 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
# 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
|