@@ -47,20 +47,16 @@ class Filter < HTML::Pipeline::Filter
4747 (?=\s ) # followed by whitespace
4848 /x
4949
50- ListSelector = [
51- # select UL/OL
52- ".//li[starts-with(text(),'[ ]')]/.." ,
53- ".//li[starts-with(text(),'[x]')]/.." ,
54- # and those wrapped in Ps
55- ".//li/p[1][starts-with(text(),'[ ]')]/../.." ,
56- ".//li/p[1][starts-with(text(),'[x]')]/../.."
57- ] . join ( ' | ' ) . freeze
58-
59- # Selects all LIs from a TaskList UL/OL
60- ItemSelector = ".//li" . freeze
50+ ListItemSelector = ".//li[task_list_item(.)]" . freeze
51+
52+ class XPathSelectorFunction
53+ def self . task_list_item ( nodes )
54+ nodes if nodes . text =~ ItemPattern
55+ end
56+ end
6157
6258 # Selects first P tag of an LI, if present
63- ItemParaSelector = ".// p[1]" . freeze
59+ ItemParaSelector = "./p[1]" . freeze
6460
6561 # List of `TaskList::Item` objects that were recognized in the document.
6662 # This is available in the result hash as `:task_list_items`.
@@ -100,20 +96,22 @@ def render_task_list_item(item)
10096 #
10197 # Returns an Array of Nokogiri::XML::Element objects for ordered and
10298 # unordered lists.
103- def task_lists
104- doc . xpath ( ListSelector )
99+ def list_items
100+ doc . xpath ( ListItemSelector , XPathSelectorFunction )
105101 end
106102
107- # Public: filters a Nokogiri::XML::Element ordered/unordered list, marking
108- # up the list items in order to add behavior and include metadata.
103+ # Filters the source for task list items.
109104 #
110- # Modifies the provided node.
105+ # Each item is wrapped in HTML to identify, style, and layer
106+ # useful behavior on top of.
107+ #
108+ # Modifications apply to the parsed document directly.
111109 #
112110 # Returns nothing.
113- def filter_list ( node )
114- add_css_class ( node , 'task-list' )
111+ def filter!
112+ list_items . reverse . each do |li |
113+ add_css_class ( li . parent , 'task-list' )
115114
116- node . xpath ( ItemSelector ) . reverse . each do |li |
117115 outer , inner =
118116 if p = li . xpath ( ItemParaSelector ) [ 0 ]
119117 [ p , p . inner_html ]
@@ -131,20 +129,6 @@ def filter_list(node)
131129 end
132130 end
133131
134- # Filters the source for task list items.
135- #
136- # Each item is wrapped in HTML to identify, style, and layer
137- # useful behavior on top of.
138- #
139- # Modifications apply to the parsed document directly.
140- #
141- # Returns nothing.
142- def filter!
143- task_lists . each do |node |
144- filter_list node
145- end
146- end
147-
148132 def call
149133 filter!
150134 doc
@@ -154,6 +138,7 @@ def call
154138 # names.
155139 def add_css_class ( node , *new_class_names )
156140 class_names = ( node [ 'class' ] || '' ) . split ( ' ' )
141+ return if new_class_names . all? { |klass | class_names . include? ( klass ) }
157142 class_names . concat ( new_class_names )
158143 node [ 'class' ] = class_names . uniq . join ( ' ' )
159144 end
0 commit comments