Skip to content
This repository was archived by the owner on Nov 1, 2017. It is now read-only.

Commit 3ac620d

Browse files
committed
Merge branch 'master' into non-breaking-space
Conflicts: test/task_list/filter_test.rb
2 parents dd204f9 + 69456fa commit 3ac620d

File tree

9 files changed

+60
-44
lines changed

9 files changed

+60
-44
lines changed

app/assets/javascripts/task_lists.coffee

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#= provides tasklist:change
66
#= provides tasklist:changed
77
#
8-
#= require crema/events/fire
98
#= require crema/events/pageupdate
109
#
1110
# Enables Task List update behavior.
@@ -181,10 +180,13 @@ updateTaskList = ($item) ->
181180
index = 1 + $container.find('.task-list-item-checkbox').index($item)
182181
checked = $item.prop 'checked'
183182

184-
$field.fire 'tasklist:change', [index, checked], ->
183+
event = $.Event 'tasklist:change'
184+
$field.trigger event, [index, checked]
185+
186+
unless event.isDefaultPrevented()
185187
$field.val updateTaskListItem($field.val(), index, checked)
186188
$field.trigger 'change'
187-
$field.fire 'tasklist:changed', [index, checked]
189+
$field.trigger 'tasklist:changed', [index, checked]
188190

189191
# When the task list item checkbox is updated, submit the change
190192
$(document).on 'change', '.task-list-item-checkbox', ->

lib/task_list/filter.rb

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,16 @@ class Filter < HTML::Pipeline::Filter
5050
(?=\s) # followed by whitespace
5151
/x
5252

53-
ListSelector = [
54-
# select UL/OL
55-
".//li[starts-with(text(),'[ ]')]/..",
56-
".//li[starts-with(text(),'[x]')]/..",
57-
# and those wrapped in Ps
58-
".//li/p[1][starts-with(text(),'[ ]')]/../..",
59-
".//li/p[1][starts-with(text(),'[x]')]/../.."
60-
].join(' | ').freeze
61-
62-
# Selects all LIs from a TaskList UL/OL
63-
ItemSelector = ".//li".freeze
53+
ListItemSelector = ".//li[task_list_item(.)]".freeze
54+
55+
class XPathSelectorFunction
56+
def self.task_list_item(nodes)
57+
nodes if nodes.text =~ ItemPattern
58+
end
59+
end
6460

6561
# Selects first P tag of an LI, if present
66-
ItemParaSelector = ".//p[1]".freeze
62+
ItemParaSelector = "./p[1]".freeze
6763

6864
# List of `TaskList::Item` objects that were recognized in the document.
6965
# This is available in the result hash as `:task_list_items`.
@@ -103,20 +99,22 @@ def render_task_list_item(item)
10399
#
104100
# Returns an Array of Nokogiri::XML::Element objects for ordered and
105101
# unordered lists.
106-
def task_lists
107-
doc.xpath(ListSelector)
102+
def list_items
103+
doc.xpath(ListItemSelector, XPathSelectorFunction)
108104
end
109105

110-
# Public: filters a Nokogiri::XML::Element ordered/unordered list, marking
111-
# up the list items in order to add behavior and include metadata.
106+
# Filters the source for task list items.
112107
#
113-
# Modifies the provided node.
108+
# Each item is wrapped in HTML to identify, style, and layer
109+
# useful behavior on top of.
110+
#
111+
# Modifications apply to the parsed document directly.
114112
#
115113
# Returns nothing.
116-
def filter_list(node)
117-
add_css_class(node, 'task-list')
114+
def filter!
115+
list_items.reverse.each do |li|
116+
add_css_class(li.parent, 'task-list')
118117

119-
node.xpath(ItemSelector).each do |li|
120118
outer, inner =
121119
if p = li.xpath(ItemParaSelector)[0]
122120
[p, p.inner_html]
@@ -125,28 +123,15 @@ def filter_list(node)
125123
end
126124
if match = (inner.chomp =~ ItemPattern && $1)
127125
item = TaskList::Item.new(match, inner)
128-
task_list_items << item
126+
# prepend because we're iterating in reverse
127+
task_list_items.unshift item
129128

130129
add_css_class(li, 'task-list-item')
131130
outer.inner_html = render_task_list_item(item)
132131
end
133132
end
134133
end
135134

136-
# Filters the source for task list items.
137-
#
138-
# Each item is wrapped in HTML to identify, style, and layer
139-
# useful behavior on top of.
140-
#
141-
# Modifications apply to the parsed document directly.
142-
#
143-
# Returns nothing.
144-
def filter!
145-
task_lists.each do |node|
146-
filter_list node
147-
end
148-
end
149-
150135
def call
151136
filter!
152137
doc
@@ -156,6 +141,7 @@ def call
156141
# names.
157142
def add_css_class(node, *new_class_names)
158143
class_names = (node['class'] || '').split(' ')
144+
return if new_class_names.all? { |klass| class_names.include?(klass) }
159145
class_names.concat(new_class_names)
160146
node['class'] = class_names.uniq.join(' ')
161147
end

lib/task_list/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
class TaskList
2-
VERSION = [0, 2, 0].join('.')
2+
VERSION = [0, 3, 0].join('.')
33
end

task-lists.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,5 @@ Gem::Specification.new do |gem|
2424
gem.add_development_dependency "json"
2525
gem.add_development_dependency "rack"
2626
gem.add_development_dependency "sprockets"
27+
gem.add_development_dependency "minitest", "~> 5.3.2"
2728
end
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
#= require jquery
2-
#= require rails/remote
2+
#= require rails-behaviors/remote
33
#= require task_lists

test/task_list/filter_test.rb

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
require File.expand_path('../../test_helper', __FILE__)
33
require 'task_list/filter'
44

5-
class TaskList::FilterTest < Test::Unit::TestCase
5+
class TaskList::FilterTest < Minitest::Test
66
def setup
77
@pipeline = HTML::Pipeline.new [
88
HTML::Pipeline::MarkdownFilter,
@@ -78,6 +78,33 @@ def test_handles_encoding_correctly
7878
assert_equal unicode, item.text.strip
7979
end
8080

81+
def test_handles_nested_items
82+
text = <<-md
83+
- [ ] one
84+
- [ ] one.one
85+
md
86+
assert item = filter(text)[:output].css('.task-list-item .task-list-item').pop
87+
end
88+
89+
def test_handles_complicated_nested_items
90+
text = <<-md
91+
- [ ] one
92+
- [ ] one.one
93+
- [x] one.two
94+
- [ ] one.two.one
95+
- [ ] one.two.two
96+
- [ ] one.three
97+
- [ ] one.four
98+
- [ ] two
99+
- [x] two.one
100+
- [ ] two.two
101+
- [ ] three
102+
md
103+
104+
assert_equal 6 + 2, filter(text)[:output].css('.task-list-item .task-list-item').size
105+
assert_equal 2, filter(text)[:output].css('.task-list-item .task-list-item .task-list-item').size
106+
end
107+
81108
# NOTE: This is an edge case experienced regularly by users using a Swiss
82109
# German keyboard.
83110
# See: https://github.com/github/github/pull/18362

test/task_list/summary_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
require File.expand_path('../../test_helper', __FILE__)
33
require 'task_list/summary'
44

5-
class TaskList::SummaryTest < Test::Unit::TestCase
5+
class TaskList::SummaryTest < Minitest::Test
66
def setup
77
@complete = make_item "[x]", "complete"
88
@incomplete = make_item "[ ]", "incomplete"

test/task_list_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
require 'task_list'
44
require 'task_list/filter'
55

6-
class TaskListTest < Test::Unit::TestCase
6+
class TaskListTest < Minitest::Test
77
class Record < Struct.new(:body)
88
def task_list_items
99
[]

test/test_helper.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
$:.unshift "lib"
2-
require 'test/unit'
2+
require 'minitest/autorun'
33
require 'task_list'

0 commit comments

Comments
 (0)