mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-02 09:35:40 -05:00
Fix for < > (non HTML) tags disappearing in WYSIWYG (#13267)
* Push the latest update for WYSIWYG bug * Improvements to nested lists * OL tests and PR feedback * Fixed all toolbar options for tags * Address PR comments * Ensure style is kept and not escaped * Add all markdown toolbar action tests * Style text edge case fix * Address repeat function and type comment * add more clarifying test
This commit is contained in:
@@ -39,6 +39,7 @@ export class HTMLMarkdownConverter {
|
||||
this.turndownService.addRule('span', {
|
||||
filter: 'span',
|
||||
replacement: function (content, node) {
|
||||
let escapedText = escapeAngleBrackets(node.textContent);
|
||||
// There are certain properties that either don't have equivalents in markdown or whose transformations
|
||||
// don't have actions defined in WYSIWYG yet. To unblock users, leaving these elements alone (including their child elements)
|
||||
// Note: the initial list was generated from our TSG Jupyter Book
|
||||
@@ -74,7 +75,7 @@ export class HTMLMarkdownConverter {
|
||||
beginString = '<u>' + beginString;
|
||||
endString += '</u>';
|
||||
}
|
||||
return beginString + content + endString;
|
||||
return beginString + escapedText + endString;
|
||||
}
|
||||
});
|
||||
this.turndownService.addRule('img', {
|
||||
@@ -99,6 +100,7 @@ export class HTMLMarkdownConverter {
|
||||
const notebookLink = node.href ? URI.parse(node.href) : URI.file(node.title);
|
||||
const notebookFolder = this.notebookUri ? path.join(path.dirname(this.notebookUri.fsPath), path.sep) : '';
|
||||
let relativePath = findPathRelativeToContent(notebookFolder, notebookLink);
|
||||
node.innerText = escapeAngleBrackets(node.innerText);
|
||||
if (relativePath) {
|
||||
return `[${node.innerText}](${relativePath})`;
|
||||
}
|
||||
@@ -112,6 +114,7 @@ export class HTMLMarkdownConverter {
|
||||
.replace(/^\n+/, '') // remove leading newlines
|
||||
.replace(/\n+$/, '\n') // replace trailing newlines with just a single one
|
||||
.replace(/\n/gm, '\n '); // indent
|
||||
content = escapeAngleBrackets(content);
|
||||
let prefix = options.bulletListMarker + ' ';
|
||||
let parent = node.parentNode;
|
||||
let nestedCount = 0;
|
||||
@@ -131,6 +134,72 @@ export class HTMLMarkdownConverter {
|
||||
);
|
||||
}
|
||||
});
|
||||
this.turndownService.addRule('p', {
|
||||
filter: 'p',
|
||||
replacement: function (content, node) {
|
||||
node.childNodes.forEach(c => {
|
||||
if (c.nodeType === Node.TEXT_NODE) {
|
||||
c.nodeValue = escapeAngleBrackets(c.textContent);
|
||||
} else if (c.nodeType === Node.ELEMENT_NODE) {
|
||||
c.innerText = escapeAngleBrackets(c.textContent);
|
||||
}
|
||||
});
|
||||
return '\n\n' + node.innerHTML.replace(/</gi, '<').replace(/>/gi, '>').replace(/ /gi, '') + '\n\n';
|
||||
}
|
||||
});
|
||||
this.turndownService.addRule('heading', {
|
||||
filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
|
||||
replacement: function (content, node, options) {
|
||||
let hLevel = Number(node.nodeName.charAt(1));
|
||||
let escapedText = escapeAngleBrackets(content);
|
||||
if (options.headingStyle === 'setext' && hLevel < 3) {
|
||||
let underline = '#'.repeat(hLevel);
|
||||
return '\n\n' + escapedText + '\n' + underline + '\n\n';
|
||||
} else {
|
||||
return '\n\n' + '#'.repeat(hLevel) + ' ' + escapedText + '\n\n';
|
||||
}
|
||||
}
|
||||
});
|
||||
this.turndownService.addRule('bold', {
|
||||
filter: ['strong', 'b'],
|
||||
replacement: function (content, node, options) {
|
||||
content = escapeAngleBrackets(content);
|
||||
if (!content.trim()) { return ''; }
|
||||
return options.strongDelimiter + content + options.strongDelimiter;
|
||||
}
|
||||
});
|
||||
this.turndownService.addRule('italicize', {
|
||||
filter: ['em', 'i'],
|
||||
replacement: function (content, node, options) {
|
||||
content = escapeAngleBrackets(content);
|
||||
if (!content.trim()) { return ''; }
|
||||
return options.emDelimiter + content + options.emDelimiter;
|
||||
}
|
||||
});
|
||||
this.turndownService.addRule('code', {
|
||||
filter: function (node) {
|
||||
let hasSiblings = node.previousSibling || node.nextSibling;
|
||||
let isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings;
|
||||
|
||||
return node.nodeName === 'CODE' && !isCodeBlock;
|
||||
},
|
||||
replacement: function (content) {
|
||||
content = escapeAngleBrackets(content);
|
||||
if (!content.trim()) { return ''; }
|
||||
|
||||
let delimiter = '`';
|
||||
let leadingSpace = '';
|
||||
let trailingSpace = '';
|
||||
let matches = content.match(/`+/gm);
|
||||
if (matches) {
|
||||
if (/^`/.test(content)) { leadingSpace = ' '; }
|
||||
if (/`$/.test(content)) { trailingSpace = ' '; }
|
||||
while (matches.indexOf(delimiter) !== -1) { delimiter = delimiter + '`'; }
|
||||
}
|
||||
|
||||
return delimiter + leadingSpace + content + trailingSpace + delimiter;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,3 +219,16 @@ export function findPathRelativeToContent(notebookFolder: string, contentPath: U
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
export function escapeAngleBrackets(textContent: string): string {
|
||||
let text: string = textContent;
|
||||
if (text.includes('<u>') || text.includes('<mark>') || (text.includes('style') && !text.includes('<style>'))) {
|
||||
return text;
|
||||
}
|
||||
let mapTags = { '<': '\\<', '>': '\\>' };
|
||||
|
||||
let escapedText = text.replace(/<|>/gi, function (matched) {
|
||||
return mapTags[matched];
|
||||
});
|
||||
return escapedText;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user