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

Commit 480efc2

Browse files
committed
Merge pull request #14 from github/non-breaking-space
Support incomplete items with non-breaking spaces
2 parents 69456fa + 3ac620d commit 480efc2

File tree

4 files changed

+82
-10
lines changed

4 files changed

+82
-10
lines changed

app/assets/javascripts/task_lists.coffee

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,28 @@
101101
incomplete = "[ ]"
102102
complete = "[x]"
103103

104+
# Escapes the String for regular expression matching.
105+
escapePattern = (str) ->
106+
str.
107+
replace(/([\[\]])/g, "\\$1"). # escape square brackets
108+
replace(/\s/, "\\s") # match all white space
109+
110+
incompletePattern = ///
111+
#{escapePattern(incomplete)}
112+
///
113+
completePattern = ///
114+
#{escapePattern(complete)}
115+
///
116+
104117
# Pattern used to identify all task list items.
105118
# Useful when you need iterate over all items.
106119
itemPattern = ///
107120
^
108121
(?:\s*[-+*]|(?:\d+\.))? # optional list prefix
109122
\s* # optional whitespace prefix
110123
( # checkbox
111-
#{complete. replace(/([\[\]])/g, "\\$1")}|
112-
#{incomplete.replace(/([\[\]])/g, "\\$1")}
124+
#{escapePattern(complete)}|
125+
#{escapePattern(incomplete)}
113126
)
114127
(?=\s) # followed by whitespace
115128
///
@@ -131,8 +144,8 @@ codeFencesPattern = ///
131144
itemsInParasPattern = ///
132145
^
133146
(
134-
#{complete. replace(/[\[\]]/g, "\\$1")}|
135-
#{incomplete.replace(/[\[\]]/g, "\\$1")}
147+
#{escapePattern(complete)}|
148+
#{escapePattern(incomplete)}
136149
)
137150
.+
138151
$
@@ -152,9 +165,9 @@ updateTaskListItem = (source, itemIndex, checked) ->
152165
if index == itemIndex
153166
line =
154167
if checked
155-
line.replace(incomplete, complete)
168+
line.replace(incompletePattern, complete)
156169
else
157-
line.replace(complete, incomplete)
170+
line.replace(completePattern, incomplete)
158171
line
159172
result.join("\n")
160173

lib/task_list/filter.rb

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,11 @@ def self.filter(*args)
3131
# :task_list_items - An array of TaskList::Item objects.
3232
class Filter < HTML::Pipeline::Filter
3333

34-
Incomplete = "[ ]".freeze
35-
Complete = "[x]".freeze
34+
Incomplete = "[ ]".freeze
35+
Complete = "[x]".freeze
36+
37+
IncompletePattern = /\[[[:space:]]\]/.freeze # matches all whitespace
38+
CompletePattern = Regexp.escape(Complete).freeze
3639

3740
# Pattern used to identify all task list items.
3841
# Useful when you need iterate over all items.
@@ -41,8 +44,8 @@ class Filter < HTML::Pipeline::Filter
4144
(?:\s*[-+*]|(?:\d+\.))? # optional list prefix
4245
\s* # optional whitespace prefix
4346
( # checkbox
44-
#{Regexp.escape(Complete)}|
45-
#{Regexp.escape(Incomplete)}
47+
#{CompletePattern}|
48+
#{IncompletePattern}
4649
)
4750
(?=\s) # followed by whitespace
4851
/x

test/task_list/filter_test.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,26 @@ def test_handles_complicated_nested_items
105105
assert_equal 2, filter(text)[:output].css('.task-list-item .task-list-item .task-list-item').size
106106
end
107107

108+
# NOTE: This is an edge case experienced regularly by users using a Swiss
109+
# German keyboard.
110+
# See: https://github.com/github/github/pull/18362
111+
def test_non_breaking_space_between_brackets
112+
text = "- [\xC2\xA0] ok"
113+
assert item = filter(text)[:output].css('.task-list-item').pop, "item expected"
114+
assert_equal 'ok', item.text.strip
115+
end
116+
117+
# See: https://github.com/github/github/pull/18362
118+
def test_non_breaking_space_between_brackets_in_paras
119+
text = <<-md
120+
- [\xC2\xA0] one
121+
- [\xC2\xA0] this one will be wrapped in a para
122+
123+
- [\xC2\xA0] this one too, wtf
124+
md
125+
assert_equal 3, filter(text)[:output].css(@item_selector).size
126+
end
127+
108128
protected
109129

110130
def filter(input, context = @context, result = nil)

test/unit/test_updates.coffee

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,36 @@ module "TaskList updates",
2020
disabled: true
2121
checked: false
2222

23+
# non-breaking space. See: https://github.com/github/task-lists/pull/14
24+
@nbsp = String.fromCharCode(160)
25+
@incompleteNBSPItem = $ '<li>', class: 'task-list-item'
26+
@incompleteNBSPCheckbox = $ '<input>',
27+
type: 'checkbox'
28+
class: 'task-list-item-checkbox'
29+
disabled: true
30+
checked: false
31+
2332
@field = $ '<textarea>', class: 'js-task-list-field', text: """
2433
- [x] complete
2534
- [ ] incomplete
35+
- [#{@nbsp}] incompleteNBSP
2636
"""
2737

2838
@changes =
2939
toComplete: """
3040
- [ ] complete
3141
- [ ] incomplete
42+
- [#{@nbsp}] incompleteNBSP
3243
"""
3344
toIncomplete: """
3445
- [x] complete
3546
- [x] incomplete
47+
- [#{@nbsp}] incompleteNBSP
48+
"""
49+
toIncompleteNBSP: """
50+
- [x] complete
51+
- [ ] incomplete
52+
- [x] incompleteNBSP
3653
"""
3754

3855
@completeItem.append @completeCheckbox
@@ -43,6 +60,10 @@ module "TaskList updates",
4360
@list.append @incompleteItem
4461
@incompleteItem.expectedIndex = 2
4562

63+
@incompleteNBSPItem.append @incompleteNBSPCheckbox
64+
@list.append @incompleteNBSPItem
65+
@incompleteNBSPItem.expectedIndex = 3
66+
4667
@container.append @list
4768
@container.append @field
4869

@@ -79,3 +100,18 @@ asyncTest "updates the source, marking the complete item as incomplete", ->
79100
, 20
80101

81102
@completeCheckbox.click()
103+
104+
# See: https://github.com/github/task-lists/pull/14
105+
asyncTest "updates the source for items with non-breaking spaces", ->
106+
expect 3
107+
108+
@field.on 'tasklist:changed', (event, index, checked) =>
109+
ok checked
110+
equal index, @incompleteNBSPItem.expectedIndex
111+
equal @field.val(), @changes.toIncompleteNBSP
112+
113+
setTimeout ->
114+
start()
115+
, 20
116+
117+
@incompleteNBSPCheckbox.click()

0 commit comments

Comments
 (0)