Skip to content

Commit

Permalink
feat(checkbox): add disabled option to prevent disabled attribute fro…
Browse files Browse the repository at this point in the history
…m being set for checkboxes
  • Loading branch information
d3m1d0v authored and 3y3 committed Jun 5, 2024
1 parent 39d6be1 commit 30272fe
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 33 deletions.
37 changes: 26 additions & 11 deletions src/transform/plugins/checkbox/checkbox.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
import type MarkdownIt from 'markdown-it';
import type Core from 'markdown-it/lib/parser_core';
import type StateCore from 'markdown-it/lib/rules_core/state_core';
import type Token from 'markdown-it/lib/token';

// eslint-disable-next-line no-useless-escape
const pattern = /^\[(X|\s|\_|\-)\]\s(.*)/i;
export const pattern = /^\[(X|\s|\_|\-)\]\s(.*)/i;
export const CheckboxTokenType = {
Checkbox: 'checkbox',
CheckboxOpen: 'checkbox_open',
CheckboxClose: 'checkbox_close',
CheckboxInput: 'checkbox_input',
CheckboxLabel: 'checkbox_label',
CheckboxLabelOpen: 'checkbox_label_open',
CheckboxLabelClose: 'checkbox_label_close',
} as const;

function matchOpenToken(tokens: Token[], i: number) {
return (
Expand All @@ -16,13 +26,16 @@ function matchOpenToken(tokens: Token[], i: number) {
export type CheckboxOptions = {
idPrefix?: string;
divClass?: string;
/** @default true */
disabled?: boolean;
};

export const checkboxReplace = function (_md: MarkdownIt, opts: CheckboxOptions) {
export const checkboxReplace = function (_md: MarkdownIt, opts?: CheckboxOptions): Core.RuleCore {
let lastId = 0;
const defaults = {
const defaults: Required<CheckboxOptions> = {
divClass: 'checkbox',
idPrefix: 'checkbox',
disabled: true,
};
const options = Object.assign(defaults, opts);

Expand All @@ -33,7 +46,7 @@ export const checkboxReplace = function (_md: MarkdownIt, opts: CheckboxOptions)
/**
* <div class="checkbox">
*/
token = new state.Token('checkbox_open', 'div', 1);
token = new state.Token(CheckboxTokenType.CheckboxOpen, 'div', 1);
token.block = true;
token.map = state.tokens[i].map;
token.attrs = [['class', options.divClass]];
Expand All @@ -44,23 +57,25 @@ export const checkboxReplace = function (_md: MarkdownIt, opts: CheckboxOptions)
*/
const id = options.idPrefix + lastId;
lastId += 1;
token = new state.Token('checkbox_input', 'input', 0);
token = new state.Token(CheckboxTokenType.CheckboxInput, 'input', 0);
token.block = true;
token.map = state.tokens[i].map;
token.attrs = [
['type', 'checkbox'],
['id', id],
['disabled', ''],
];
if (options.disabled) {
token.attrSet('disabled', '');
}
if (checked === true) {
token.attrs.push(['checked', 'true']);
token.attrSet('checked', 'true');
}
nodes.push(token);

/**
* <label for="checkbox{n}">
*/
token = new state.Token('checkbox_label_open', 'label', 1);
token = new state.Token(CheckboxTokenType.CheckboxLabelOpen, 'label', 1);
token.attrs = [['for', id]];
nodes.push(token);

Expand All @@ -73,11 +88,11 @@ export const checkboxReplace = function (_md: MarkdownIt, opts: CheckboxOptions)
/**
* closing tags
*/
token = new state.Token('checkbox_label_close', 'label', -1);
token = new state.Token(CheckboxTokenType.CheckboxLabelClose, 'label', -1);
token.block = true;
token.map = state.tokens[i].map;
nodes.push(token);
token = new state.Token('checkbox_close', 'div', -1);
token = new state.Token(CheckboxTokenType.CheckboxClose, 'div', -1);
token.block = true;
token.map = state.tokens[i].map;
nodes.push(token);
Expand All @@ -93,7 +108,7 @@ export const checkboxReplace = function (_md: MarkdownIt, opts: CheckboxOptions)
}
return createTokens(state, checked, label, i);
};
return function (state: StateCore) {
return function (state) {
const blockTokens = state.tokens;
for (let i = 0; i < blockTokens.length; i++) {
const match = matchOpenToken(blockTokens, i);
Expand Down
4 changes: 2 additions & 2 deletions src/transform/plugins/checkbox/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import MarkdownIt from 'markdown-it';
import type {PluginWithOptions} from 'markdown-it';
import {CheckboxOptions, checkboxReplace} from './checkbox';

/**
* Checkbox plugin for markdown-it.
* Forked from https://github.com/mcecot/markdown-it-checkbox
*/

const checkbox = (md: MarkdownIt, options: CheckboxOptions) => {
const checkbox: PluginWithOptions<CheckboxOptions> = (md, options) => {
md.core.ruler.push('checkbox', checkboxReplace(md, options));

return md;
Expand Down
43 changes: 23 additions & 20 deletions test/checkbox.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import path from 'path';
import transform from '../src/transform';
import plugin from '../src/transform/plugins/checkbox';
import type {CheckboxOptions} from '../src/transform/plugins/checkbox/checkbox';
import MarkdownIt from 'markdown-it';

const generate = require('markdown-it-testgen');
Expand All @@ -17,25 +18,23 @@ const transformYfm = (text: string) => {
return html;
};

describe('markdown-it-checkbox', function () {
describe('markdown-it-checkbox()', function () {
describe('markdown-it-checkbox', () => {
describe('markdown-it-checkbox()', () => {
const md = new MarkdownIt({});

md.use(plugin, {
divWrap: false,
});
generate(path.join(__dirname, 'data/checkbox/checkbox.txt'), md);
return it('should pass irrelevant markdown', function () {
return it('should pass irrelevant markdown', () => {
const res = md.render('# test');
assert.equal(res, '<h1>test</h1>\n');
});
});

describe('markdown-it-checkbox(options)', function () {
it('should optionally wrap arround a div layer', function () {
const md = new MarkdownIt({});

md.use(plugin);
describe('markdown-it-checkbox(options)', () => {
it('should optionally wrap arround a div layer', () => {
const md = new MarkdownIt({}).use(plugin);
const res = md.render('[X] test written');
assert.equal(
res,
Expand All @@ -46,12 +45,8 @@ describe('markdown-it-checkbox', function () {
);
});

it('should optionally change class of div layer', function () {
const md = new MarkdownIt({});

md.use(plugin, {
divClass: 'cb',
});
it('should optionally change class of div layer', () => {
const md = new MarkdownIt({}).use<CheckboxOptions>(plugin, {divClass: 'cb'});
const res = md.render('[X] test written');
assert.equal(
res,
Expand All @@ -62,12 +57,8 @@ describe('markdown-it-checkbox', function () {
);
});

it('should optionally change the id', function () {
const md = new MarkdownIt({});

md.use(plugin, {
idPrefix: 'cb',
});
it('should optionally change the id', () => {
const md = new MarkdownIt({}).use<CheckboxOptions>(plugin, {idPrefix: 'cb'});
const res = md.render('[X] test written');
assert.equal(
res,
Expand All @@ -77,6 +68,18 @@ describe('markdown-it-checkbox', function () {
'</div>\n',
);
});

it('should not set disable attr to checkbox', () => {
const md = new MarkdownIt({}).use<CheckboxOptions>(plugin, {disabled: false});
const res = md.render('[X] check');
assert.equal(
res,
'<div class="checkbox">\n' +
'<input type="checkbox" id="checkbox0" checked="true">\n' +
'<label for="checkbox0">check</label>\n' +
'</div>\n',
);
});
});

it('should parse inline markup in label', () => {
Expand Down

0 comments on commit 30272fe

Please sign in to comment.