Skip to content

Commit 91a1f7a

Browse files
committed
Github Task Lists
Add support for Github Task Lists under the gfm flag. Changes to API * list(*string* body, *boolean* ordered, *boolean* taskList) * listitem(*string* text, [*boolean* checked]). `checked` is defined when you have a list item which starts with `[ ] ` or `[x] `.If defined its a boolean depending on whether the `x` is present. When checked is defined we add a input type type `checkbox` to the list item and add the class `task-list-item-checkbox`. `taskList` is true if a list has any list items where `checked` is defined. When true we add the class `task-list` to the list. Resolves #107
1 parent 2b5802f commit 91a1f7a

File tree

4 files changed

+60
-11
lines changed

4 files changed

+60
-11
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,8 @@ This code will output the following HTML:
188188
- html(*string* html)
189189
- heading(*string* text, *number* level)
190190
- hr()
191-
- list(*string* body, *boolean* ordered)
191+
- list(*string* body, *boolean* ordered, *boolean* taskList)
192+
- `taskList` true when `gfm` is `true` and there is a list item with a check box
192193
- listitem(*string* text)
193194
- paragraph(*string* text)
194195
- table(*string* header, *string* body)
@@ -211,7 +212,8 @@ This code will output the following HTML:
211212
- codespan(*string* code)
212213
- br()
213214
- del(*string* text)
214-
- link(*string* href, *string* title, *string* text)
215+
- link(*string* href, *string* title, *string* text, [*boolean* checked]).
216+
- `checked` only defined when `gfm` is `true` and there is a check box at the start of the list item (e.g. `* [ ] foo`).
215217
- image(*string* href, *string* title, *string* text)
216218

217219
### gfm

lib/marked.js

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ var block = {
2727
text: /^[^\n]+/
2828
};
2929

30+
block.checkbox = /^\[([ x])\] +/;
3031
block.bullet = /(?:[*+-]|\d+\.)/;
3132
block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
3233
block.item = replace(block.item, 'gm')
@@ -156,7 +157,8 @@ Lexer.prototype.token = function(src, top, bq) {
156157
, item
157158
, space
158159
, i
159-
, l;
160+
, l
161+
, checked;
160162

161163
while (src) {
162164
// newline
@@ -303,6 +305,17 @@ Lexer.prototype.token = function(src, top, bq) {
303305
space = item.length;
304306
item = item.replace(/^ *([*+-]|\d+\.) +/, '');
305307

308+
if (this.options.gfm) {
309+
checked = block.checkbox.exec(item);
310+
311+
if (checked) {
312+
checked = checked[1] === 'x';
313+
item = item.replace(block.checkbox, '');
314+
} else {
315+
checked = undefined;
316+
}
317+
}
318+
306319
// Outdent whatever the
307320
// list item contains. Hacky.
308321
if (~item.indexOf('\n ')) {
@@ -332,6 +345,7 @@ Lexer.prototype.token = function(src, top, bq) {
332345
}
333346

334347
this.tokens.push({
348+
checked: checked,
335349
type: loose
336350
? 'loose_item_start'
337351
: 'list_item_start'
@@ -802,13 +816,23 @@ Renderer.prototype.hr = function() {
802816
return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
803817
};
804818

805-
Renderer.prototype.list = function(body, ordered) {
819+
Renderer.prototype.list = function(body, ordered, taskList) {
806820
var type = ordered ? 'ol' : 'ul';
807-
return '<' + type + '>\n' + body + '</' + type + '>\n';
821+
var classes = taskList ? ' class="task-list"' : '';
822+
return '<' + type + classes + '>\n' + body + '</' + type + '>\n';
808823
};
809824

810-
Renderer.prototype.listitem = function(text) {
811-
return '<li>' + text + '</li>\n';
825+
Renderer.prototype.listitem = function(text, checked) {
826+
if (checked === undefined) {
827+
return '<li>' + text + '</li>\n';
828+
}
829+
830+
return '<li class="task-list-item">'
831+
+ '<input type="checkbox" class="task-list-item-checkbox"'
832+
+ (checked ? ' checked' : '')
833+
+ '> '
834+
+ text
835+
+ '</li>\n';
812836
};
813837

814838
Renderer.prototype.paragraph = function(text) {
@@ -1026,24 +1050,30 @@ Parser.prototype.tok = function() {
10261050
}
10271051
case 'list_start': {
10281052
var body = ''
1053+
, taskList = false
10291054
, ordered = this.token.ordered;
10301055

10311056
while (this.next().type !== 'list_end') {
1057+
if (this.token.checked !== undefined) {
1058+
taskList = true;
1059+
}
1060+
10321061
body += this.tok();
10331062
}
10341063

1035-
return this.renderer.list(body, ordered);
1064+
return this.renderer.list(body, ordered, taskList);
10361065
}
10371066
case 'list_item_start': {
1038-
var body = '';
1067+
var body = ''
1068+
, checked = this.token.checked;
10391069

10401070
while (this.next().type !== 'list_item_end') {
10411071
body += this.token.type === 'text'
10421072
? this.parseText()
10431073
: this.tok();
10441074
}
10451075

1046-
return this.renderer.listitem(body);
1076+
return this.renderer.listitem(body, checked);
10471077
}
10481078
case 'loose_item_start': {
10491079
var body = '';
@@ -1052,7 +1082,7 @@ Parser.prototype.tok = function() {
10521082
body += this.tok();
10531083
}
10541084

1055-
return this.renderer.listitem(body);
1085+
return this.renderer.listitem(body, checked);
10561086
}
10571087
case 'html': {
10581088
var html = !this.token.pre && !this.options.pedantic

test/tests/gfm_task_list.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<ul class="task-list">
2+
<li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox"> foo</li>
3+
<li>bar</li>
4+
<li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" checked> baz</li>
5+
<li>[] bam
6+
<ul class="task-list">
7+
<li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox"> bim</li>
8+
<li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox"> lim</li>
9+
</ul>
10+
</li>
11+
</ul>

test/tests/gfm_task_list.text

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
* [ ] foo
2+
* bar
3+
* [x] baz
4+
* [] bam
5+
* [ ] bim
6+
* [ ] lim

0 commit comments

Comments
 (0)