WYSIWYG Improvements to Nested Lists (#14052)

* indent/outdent working properly

* Add tests

* Latest fixes and tests

* PR comments + comments
This commit is contained in:
Chris LaFreniere
2021-01-27 12:57:23 -08:00
committed by GitHub
parent b3891ff68b
commit 26bb3ca033
2 changed files with 51 additions and 2 deletions

View File

@@ -34,7 +34,7 @@ export class HTMLMarkdownConverter {
private turndownService: TurndownService;
constructor(private notebookUri: URI) {
this.turndownService = new TurndownService({ 'emDelimiter': '_', 'bulletListMarker': '-', 'headingStyle': 'atx' });
this.turndownService = new TurndownService({ 'emDelimiter': '_', 'bulletListMarker': '-', 'headingStyle': 'atx', blankReplacement: blankReplacement });
this.setTurndownOptions();
}
@@ -143,6 +143,39 @@ export class HTMLMarkdownConverter {
return `[${content}](${node.href})`;
}
});
// Only nested list case differs from original turndown rule
// This ensures that tightly coupled lists are treated as such and do not have excess newlines in markdown
this.turndownService.addRule('list', {
filter: ['ul', 'ol'],
replacement: function (content, node) {
let parent = node.parentNode;
if ((parent.nodeName === 'LI' && parent.lastElementChild === node)) {
return '\n' + content;
} else if (parent.nodeName === 'UL' || parent.nodeName === 'OL') { // Nested list case
return '\n' + content + '\n';
} else {
return '\n\n' + content + '\n\n';
}
}
});
this.turndownService.addRule('lineBreak', {
filter: 'br',
replacement: function (content, node, options) {
// For elements that aren't lists, convert <br> into its markdown equivalent
if (node.parentElement?.nodeName !== 'LI') {
return options.br + '\n';
}
// One (and only one) line break is ignored when it's inside of a list item
// Otherwise, a new list will be created due to the looseness of the list
let numberLineBreaks = 0;
(node.parentElement as HTMLElement)?.childNodes?.forEach(n => {
if (n.nodeName === 'BR') {
numberLineBreaks++;
}
});
return numberLineBreaks > 1 ? options.br + '\n' : '';
}
});
this.turndownService.addRule('listItem', {
filter: 'li',
replacement: function (content, node, options) {
@@ -231,6 +264,14 @@ function escapeMarkdown(text) {
);
}
function blankReplacement(content, node) {
// When outdenting a nested list, an empty list will still remain. Need to handle this case.
if (node.nodeName === 'UL' || node.nodeName === 'OL') {
return '\n';
}
return node.isBlock ? '\n\n' : '';
}
export function findPathRelativeToContent(notebookFolder: string, contentPath: URI | undefined): string {
if (notebookFolder) {
if (contentPath?.scheme === 'file') {

View File

@@ -148,10 +148,18 @@ suite('HTML Markdown Converter', function (): void {
test('Should transform <li> tags', () => {
htmlString = '<ul><li>Test</li></ul>';
assert.equal(htmlMarkdownConverter.convert(htmlString), `- Test`, 'Basic unordered list test failed');
htmlString = '<ul><li><span>Test</span><br></li><li>Test2</li></ul>';
assert.equal(htmlMarkdownConverter.convert(htmlString), `- Test\n- Test2`, 'Basic unordered list test with span and line break failed');
htmlString = '<ul><li><span>Test</span><br><br></li><li>Test2</li></ul>';
assert.equal(htmlMarkdownConverter.convert(htmlString), `- Test \n \n \n- Test2`, 'Basic unordered list test with span and line break failed');
htmlString = '<ul><li>Test</li><li>Test2</li></ul>';
assert.equal(htmlMarkdownConverter.convert(htmlString), `- Test\n- Test2`, 'Basic unordered 2 item list test failed');
htmlString = '<ul><li>Test<ul><li>Test2</li></ul><li>Test3</li></ul>';
htmlString = '<ul><li>Test</li><ul><li>Test2</li></ul><li>Test3</li></ul>';
assert.equal(htmlMarkdownConverter.convert(htmlString), `- Test\n - Test2\n- Test3`, 'Nested item list test failed');
htmlString = '<ul><li>Test</li><ul><li>Test2</li></ul><ul></ul><li>Test3</li></ul>';
assert.equal(htmlMarkdownConverter.convert(htmlString), `- Test\n - Test2\n- Test3`, 'Nested item list test empty list failed');
htmlString = '<ul><li><span>Hello</span><br></li><li><span>Hello</span></li></ul>';
assert.equal(htmlMarkdownConverter.convert(htmlString), `- Hello\n- Hello`, 'Nested item list test empty list failed');
htmlString = '<ol><li>Test</li></ol>';
assert.equal(htmlMarkdownConverter.convert(htmlString), `1. Test`, 'Basic ordered item test failed');
htmlString = '<ol><li>Test</li><li>Test2</li></ol>';