mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix(editor): Render checkboxes in markdown (#9549)
This commit is contained in:
parent
a221215b87
commit
47d774100b
|
@ -51,3 +51,18 @@ Markdown.args = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const TemplateWithCheckboxes: StoryFn = (args, { argTypes }) => ({
|
||||||
|
setup: () => ({ args }),
|
||||||
|
props: Object.keys(argTypes),
|
||||||
|
components: {
|
||||||
|
N8nMarkdown,
|
||||||
|
},
|
||||||
|
template: '<n8n-markdown v-bind="args"></n8n-markdown>',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const WithCheckboxes = TemplateWithCheckboxes.bind({});
|
||||||
|
WithCheckboxes.args = {
|
||||||
|
content: '__TODO__\n- [ ] Buy milk\n- [X] Buy socks\n',
|
||||||
|
loading: false,
|
||||||
|
};
|
||||||
|
|
|
@ -23,7 +23,7 @@ import Markdown from 'markdown-it';
|
||||||
import markdownLink from 'markdown-it-link-attributes';
|
import markdownLink from 'markdown-it-link-attributes';
|
||||||
import markdownEmoji from 'markdown-it-emoji';
|
import markdownEmoji from 'markdown-it-emoji';
|
||||||
import markdownTaskLists from 'markdown-it-task-lists';
|
import markdownTaskLists from 'markdown-it-task-lists';
|
||||||
import xss, { friendlyAttrValue } from 'xss';
|
import xss, { friendlyAttrValue, whiteList } from 'xss';
|
||||||
|
|
||||||
import N8nLoading from '../N8nLoading';
|
import N8nLoading from '../N8nLoading';
|
||||||
import { escapeMarkdown } from '../../utils/markdown';
|
import { escapeMarkdown } from '../../utils/markdown';
|
||||||
|
@ -72,6 +72,7 @@ const props = withDefaults(defineProps<MarkdownProps>(), {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
tasklists: {
|
tasklists: {
|
||||||
|
enabled: true,
|
||||||
label: true,
|
label: true,
|
||||||
labelAfter: true,
|
labelAfter: true,
|
||||||
},
|
},
|
||||||
|
@ -84,6 +85,11 @@ const md = new Markdown(options.markdown)
|
||||||
.use(markdownEmoji)
|
.use(markdownEmoji)
|
||||||
.use(markdownTaskLists, options.tasklists);
|
.use(markdownTaskLists, options.tasklists);
|
||||||
|
|
||||||
|
const xssWhiteList = {
|
||||||
|
...whiteList,
|
||||||
|
label: ['class', 'for'],
|
||||||
|
};
|
||||||
|
|
||||||
const htmlContent = computed(() => {
|
const htmlContent = computed(() => {
|
||||||
if (!props.content) {
|
if (!props.content) {
|
||||||
return '';
|
return '';
|
||||||
|
@ -130,6 +136,13 @@ const htmlContent = computed(() => {
|
||||||
}
|
}
|
||||||
// return nothing, keep tag
|
// return nothing, keep tag
|
||||||
},
|
},
|
||||||
|
onIgnoreTag(tag, tagHTML) {
|
||||||
|
// Allow checkboxes
|
||||||
|
if (tag === 'input' && tagHTML.includes('type="checkbox"')) {
|
||||||
|
return tagHTML;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
whiteList: xssWhiteList,
|
||||||
});
|
});
|
||||||
|
|
||||||
return safeHtml;
|
return safeHtml;
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { render } from '@testing-library/vue';
|
||||||
|
import N8nMarkdown from '../Markdown.vue';
|
||||||
|
|
||||||
|
describe('components', () => {
|
||||||
|
describe('N8nMarkdown', () => {
|
||||||
|
it('should render unchecked checkboxes', () => {
|
||||||
|
const wrapper = render(N8nMarkdown, {
|
||||||
|
props: {
|
||||||
|
content: '__TODO__\n- [ ] Buy milk\n- [ ] Buy socks\n',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const checkboxes = wrapper.getAllByRole('checkbox');
|
||||||
|
expect(checkboxes).toHaveLength(2);
|
||||||
|
checkboxes.forEach((checkbox) => {
|
||||||
|
expect(checkbox).not.toBeChecked();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should render checked checkboxes', () => {
|
||||||
|
const wrapper = render(N8nMarkdown, {
|
||||||
|
props: {
|
||||||
|
content: '__TODO__\n- [X] Buy milk\n- [X] Buy socks\n',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const checkboxes = wrapper.getAllByRole('checkbox');
|
||||||
|
expect(checkboxes).toHaveLength(2);
|
||||||
|
checkboxes.forEach((checkbox) => {
|
||||||
|
expect(checkbox).toBeChecked();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should render inputs as plain text', () => {
|
||||||
|
const wrapper = render(N8nMarkdown, {
|
||||||
|
props: {
|
||||||
|
content:
|
||||||
|
'__TODO__\n- [X] Buy milk\n- <input type="text" data-testid="text-input" value="Something"/>\n',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const checkboxes = wrapper.getAllByRole('checkbox');
|
||||||
|
expect(checkboxes).toHaveLength(1);
|
||||||
|
expect(wrapper.queryByTestId('text-input')).toBeNull();
|
||||||
|
expect(wrapper.html()).toContain(
|
||||||
|
'<input type=“text” data-testid=“text-input” value=“Something”/>',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue