Class: TaskList::Filter

Inherits:
HTML::Pipeline::Filter
  • Object
show all
Defined in:
lib/task_list/filter.rb

Overview

TaskList filter replaces task list item markers (‘[ ]` and `[x]`) 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

“‘

Results


The following keys are written to the result hash:

:task_list_items - An array of TaskList::Item objects.

Defined Under Namespace

Classes: XPathSelectorFunction

Constant Summary collapse

Incomplete =
"[ ]".freeze
Complete =
"[x]".freeze
IncompletePattern =

matches all whitespace

/\[[[:space:]]\]/.freeze
CompletePattern =

matches any capitalization

/\[[xX]\]/.freeze
ItemPattern =

Pattern used to identify all task list items. Useful when you need iterate over all items.

/
  \A
  (?:\s*[-+*]|(?:\d+\.))? # optional list prefix
  \s*                     # optional whitespace prefix
  (                       # checkbox
    #{CompletePattern}|
    #{IncompletePattern}
  )
  (?=\s)                  # followed by whitespace
/x
ListItemSelector =
".//li[nokogiri:task_list_item(.)]".freeze
ItemParaSelector =

Selects first P tag of an LI, if present

"./p[1]".freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.item_container(li) ⇒ Object

The the node directly containing the checkbox text



65
66
67
# File 'lib/task_list/filter.rb', line 65

def self.item_container(li)
  li.xpath(ItemParaSelector)[0] || li
end

Instance Method Details

#add_css_class(node, *new_class_names) ⇒ Object

Deprecated: Removed in v3 Private: adds a CSS class name to a node, respecting existing class names.



144
145
146
147
148
149
# File 'lib/task_list/filter.rb', line 144

def add_css_class(node, *new_class_names)
  class_names = (node['class'] || '').split(' ')
  return if new_class_names.all? { |klass| class_names.include?(klass) }
  class_names.concat(new_class_names)
  node['class'] = class_names.uniq.join(' ')
end

#callObject



136
137
138
139
# File 'lib/task_list/filter.rb', line 136

def call
  filter!
  doc
end

#filter!Object

Filters the source for task list items.

Each item is wrapped in HTML to identify, style, and layer useful behavior on top of.

Modifications apply to the parsed document directly.

Returns nothing.



122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/task_list/filter.rb', line 122

def filter!
  list_items(doc).reverse.each do |li|
    outer = self.class.item_container(li)
    inner = outer.inner_html
    checkbox = inner.match(ItemPattern).captures[0]
    item = TaskList::Item.new(checkbox, inner)
    # prepend because we're iterating in reverse
    task_list_items.unshift item
    li.parent.add_class('task-list')
    li.add_class('task-list-item')
    outer.inner_html = render_task_list_item(item)
  end
end

#list_items(container) ⇒ Object

Deprecated: Removed in v3 Public: Select all task list items within ‘container`.

Returns an Array of Nokogiri::XML::Element objects for ordered and unordered lists. The container can either be the entire document (as returned by ‘#doc`) or an Element object.



110
111
112
# File 'lib/task_list/filter.rb', line 110

def list_items(container)
  container.xpath(ListItemSelector, XPathSelectorFunction)
end

#render_item_checkbox(item) ⇒ Object

Renders the item checkbox in a span including the item state.

Returns an HTML-safe String.



80
81
82
83
84
85
86
# File 'lib/task_list/filter.rb', line 80

def render_item_checkbox(item)
  %(<input type="checkbox"
    class="task-list-item-checkbox"
    #{'checked="checked"' if item.complete?}
    disabled="disabled"
  />)
end

#render_task_list_item(item) ⇒ Object

Deprecated: Removed in v3 Public: Marks up the task list item checkbox with metadata and behavior.

NOTE: produces a string that, when assigned to a Node’s ‘inner_html`, will corrupt the string contents’ encodings. Instead, we parse the rendered HTML and explicitly set its encoding so that assignment will not change the encodings.

See [this pull](github.com/github/github/pull/8505) for details.

Returns the marked up task list item Nokogiri::XML::NodeSet object.



99
100
101
102
# File 'lib/task_list/filter.rb', line 99

def render_task_list_item(item)
  Nokogiri::HTML.fragment \
    item.source.sub(ItemPattern, render_item_checkbox(item)), 'utf-8'
end

#task_list_itemsObject

List of ‘TaskList::Item` objects that were recognized in the document. This is available in the result hash as `:task_list_items`.

Returns an Array of TaskList::Item objects.



73
74
75
# File 'lib/task_list/filter.rb', line 73

def task_list_items
  result[:task_list_items] ||= []
end