Skip to content

Commit bf39349

Browse files
jhollingworthgilbert
authored andcommitted
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 markedjs#107
1 parent 38f1727 commit bf39349

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')
@@ -157,7 +158,8 @@ Lexer.prototype.token = function(src, top, bq) {
157158
, item
158159
, space
159160
, i
160-
, l;
161+
, l
162+
, checked;
161163

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

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

335348
this.tokens.push({
349+
checked: checked,
336350
type: loose
337351
? 'loose_item_start'
338352
: 'list_item_start'
@@ -809,13 +823,23 @@ Renderer.prototype.hr = function() {
809823
return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
810824
};
811825

812-
Renderer.prototype.list = function(body, ordered) {
826+
Renderer.prototype.list = function(body, ordered, taskList) {
813827
var type = ordered ? 'ol' : 'ul';
814-
return '<' + type + '>\n' + body + '</' + type + '>\n';
828+
var classes = taskList ? ' class="task-list"' : '';
829+
return '<' + type + classes + '>\n' + body + '</' + type + '>\n';
815830
};
816831

817-
Renderer.prototype.listitem = function(text) {
818-
return '<li>' + text + '</li>\n';
832+
Renderer.prototype.listitem = function(text, checked) {
833+
if (checked === undefined) {
834+
return '<li>' + text + '</li>\n';
835+
}
836+
837+
return '<li class="task-list-item">'
838+
+ '<input type="checkbox" class="task-list-item-checkbox"'
839+
+ (checked ? ' checked' : '')
840+
+ '> '
841+
+ text
842+
+ '</li>\n';
819843
};
820844

821845
Renderer.prototype.paragraph = function(text) {
@@ -1037,24 +1061,30 @@ Parser.prototype.tok = function() {
10371061
}
10381062
case 'list_start': {
10391063
var body = ''
1064+
, taskList = false
10401065
, ordered = this.token.ordered;
10411066

10421067
while (this.next().type !== 'list_end') {
1068+
if (this.token.checked !== undefined) {
1069+
taskList = true;
1070+
}
1071+
10431072
body += this.tok();
10441073
}
10451074

1046-
return this.renderer.list(body, ordered);
1075+
return this.renderer.list(body, ordered, taskList);
10471076
}
10481077
case 'list_item_start': {
1049-
var body = '';
1078+
var body = ''
1079+
, checked = this.token.checked;
10501080

10511081
while (this.next().type !== 'list_item_end') {
10521082
body += this.token.type === 'text'
10531083
? this.parseText()
10541084
: this.tok();
10551085
}
10561086

1057-
return this.renderer.listitem(body);
1087+
return this.renderer.listitem(body, checked);
10581088
}
10591089
case 'loose_item_start': {
10601090
var body = '';
@@ -1063,7 +1093,7 @@ Parser.prototype.tok = function() {
10631093
body += this.tok();
10641094
}
10651095

1066-
return this.renderer.listitem(body);
1096+
return this.renderer.listitem(body, checked);
10671097
}
10681098
case 'html': {
10691099
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)