markdown-it-tasks
Version:
Create Task lists with Markdown
122 lines (121 loc) • 4.93 kB
JavaScript
;
// Markdown-it plugin to render GitHub-style task lists; see
//
// https://github.com/blog/1375-task-lists-in-gfm-issues-pulls-comments
// https://github.com/blog/1825-task-lists-in-all-markdown-documents
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
var options = {
enabled: false,
label: false,
labelAfter: false,
labelBefore: false,
containerClass: "task-list",
itemClass: "task-list__item",
labelClass: "task-list__label",
inputClass: "task-list__input",
};
var MarkdownItTasks = function (md, opts) {
options = __assign(__assign({}, options), opts);
md.core.ruler.after("inline", "github-task-lists", function (state) {
var tokens = state.tokens;
for (var i = 2; i < tokens.length; i++) {
if (isTodoItem(tokens, i)) {
createTodo(tokens[i], state.Token);
attrSet(tokens[i - 2], "class", options.itemClass +
(options.enabled ? " " + options.itemClass + "--enabled" : ""));
attrSet(tokens[parentToken(tokens, i - 2)], "class", options.containerClass || "");
}
}
});
};
var attrSet = function (token, name, value) {
var index = token.attrIndex(name);
var attr = [name, value];
if (index < 0)
token.attrPush(attr);
else
token.attrs[index] = attr;
};
var parentToken = function (tokens, index) {
var targetLevel = tokens[index].level - 1;
for (var i = index - 1; i >= 0; i--) {
if (tokens[i].level === targetLevel) {
return i;
}
}
return -1;
};
var isTodoItem = function (tokens, index) {
return (isInline(tokens[index]) &&
isParagraph(tokens[index - 1]) &&
isListItem(tokens[index - 2]) &&
startsWithTodoMarkdown(tokens[index]));
};
var createTodo = function (token, TokenConstructor) {
token.children.unshift(makeCheckbox(token, TokenConstructor));
token.children[1].content = token.children[1].content.slice(3);
token.content = token.content.slice(3);
if (options.label) {
if (options.labelAfter || options.labelBefore) {
token.children.pop();
// Use large random number as id property of the checkbox.
var id = options.itemClass + "--" + Math.ceil(Math.random() * (10000 * 1000) - 1000);
token.children[0].content = token.children[0].content.slice(0, -1) + " id=\"" + id + "\">";
if (options.labelAfter)
token.children.push(singleLabel(token.content, id, TokenConstructor));
else if (options.labelBefore)
token.children.unshift(singleLabel(token.content, id, TokenConstructor));
}
else {
token.children.unshift(beginLabel(TokenConstructor));
token.children.push(endLabel(TokenConstructor));
}
}
};
var makeCheckbox = function (token, TokenConstructor) {
var checkbox = new TokenConstructor("html_inline", "", 0);
var disabledAttr = options.enabled ? "" : " disabled";
var checked = token.content.indexOf("[x] ") === 0 || token.content.indexOf("[X] ") === 0
? " checked"
: "";
checkbox.content = "<input class=\"" + options.inputClass + "\" type=\"checkbox\"" + checked + disabledAttr + ">";
return checkbox;
};
// these next two functions are kind of hacky; probably should really be a
// true block-level token with .tag=='label'
var beginLabel = function (TokenConstructor) {
var token = new TokenConstructor("html_inline", "", 0);
token.content = "<label class=\"" + options.labelClass + "\">";
return token;
};
var endLabel = function (TokenConstructor) {
var token = new TokenConstructor("html_inline", "", 0);
token.content = "</label>";
return token;
};
var singleLabel = function (content, id, TokenConstructor) {
var token = new TokenConstructor("html_inline", "", 0);
token.content = "<label class=\"" + options.labelClass + "\" for=\"" + id + "\">" + content.trim() + "</label>";
token.attrs = [{ for: id }];
return token;
};
var isInline = function (token) { return token.type === "inline"; };
var isParagraph = function (token) { return token.type === "paragraph_open"; };
var isListItem = function (token) { return token.type === "list_item_open"; };
var startsWithTodoMarkdown = function (token) {
return token.content.indexOf("[ ] ") === 0 ||
token.content.indexOf("[x] ") === 0 ||
token.content.indexOf("[X] ") === 0;
};
exports.default = MarkdownItTasks;