module Himekami
module Markdown
module Filters
class Checkbox < HTML::Pipeline::Filter
def call
doc.search("li").each do |li|
if List.has_checkbox?(li)
li = List.new(li)
li.convert!
end
end
doc
end
class List
LI_ATTR_CLASS = 'task-list-item'.freeze
CHECKBOX_ATTR_CLASS = 'task-list-item-checkbox'.freeze
CHECKBOX_OPEN = "[ ] ".freeze
CHECKBOX_CLOSED = "[x] ".freeze
CHECKBOX_PATTERN = /(\[ \]|\[x\])\s+/
class << self
def has_checkbox?(node)
node.text.start_with?(CHECKBOX_OPEN, CHECKBOX_CLOSED)
end
end
def initialize(node)
@node = node
end
def convert!
add_css_class
text_node
add_checkbox_html
end
private
def text_node
return @node.children.find { |node| node.name == 'p' }.children.first if @node.children.any? { |node| node.name == 'p' }
@node.children.first
end
def add_css_class
@node['class'] = LI_ATTR_CLASS if @node['class'].nil? || !@node['class'].include?(LI_ATTR_CLASS)
end
def remove_md
text_node.content = text_node.content.sub(CHECKBOX_PATTERN, '').strip
end
def add_checkbox_html
html = open_checkbox? ? render_open_checkbox_html : render_closed_checkbox_html
remove_md
text_node.add_previous_sibling(html)
end
def render_open_checkbox_html
''
end
def render_closed_checkbox_html
''
end
def open_checkbox?
text_node.content.start_with?(CHECKBOX_OPEN)
end
end
end
end
end
end