[MM-54474] Fixed behaviour of markdown code button (#24816)

* update webapp/../apply_markdown.ts to support codeblock and inline block markdown correctly & added corresponding unit tests to apply_markdown.test.tsx

* refactor apply_markdown.ts

* refactor applyMarkdownToSelection to support different starting/ending delimiter && delete applyCodeBlockToSelection

* updated apply_markdown.test.tsx

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
This commit is contained in:
Paul Vernin 2023-10-17 22:25:09 +02:00 committed by GitHub
parent 3e6cce5ab5
commit d2d820cb31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 122 additions and 10 deletions

View File

@ -441,4 +441,100 @@ describe('applyMarkdown', () => {
selectionEnd: 14,
});
});
/* ***************
* CODE (inline code and code block)
* ************** */
test('should apply inline code markdown to the selection', () => {
// "Fafda" is selected with ctrl + alt + C hotkey
const result = applyMarkdown({
message: 'Jalebi Fafda & Sambharo',
selectionStart: 7,
selectionEnd: 12,
markdownMode: 'code',
});
expect(result).toEqual({
message: 'Jalebi `Fafda` & Sambharo',
selectionStart: 8,
selectionEnd: 13,
});
});
test('should remove inline code markdown to the selection', () => {
// "Fafda" is selected with ctrl + alt + C hotkey
const result = applyMarkdown({
message: 'Jalebi `Fafda` & Sambharo',
selectionStart: 8,
selectionEnd: 13,
markdownMode: 'code',
});
expect(result).toEqual({
message: 'Jalebi Fafda & Sambharo',
selectionStart: 7,
selectionEnd: 12,
});
});
test('should apply code block markdown to the full message (multi-lines)', () => {
// all message is selected with ctrl + alt + C hotkey
const result = applyMarkdown({
message: 'Jalebi\nFafda\nSambharo',
selectionStart: 0,
selectionEnd: 21,
markdownMode: 'code',
});
expect(result).toEqual({
message: '```\nJalebi\nFafda\nSambharo\n```',
selectionStart: 4,
selectionEnd: 25,
});
});
test('should remove code block markdown to the full message', () => {
// all message is selected with ctrl + alt + C hotkey
const result = applyMarkdown({
message: '```\nJalebi\nFafda\nSambharo\n```',
selectionStart: 4,
selectionEnd: 25,
markdownMode: 'code',
});
expect(result).toEqual({
message: 'Jalebi\nFafda\nSambharo',
selectionStart: 0,
selectionEnd: 21,
});
});
test('should apply code block markdown to the sub-message (multi-lines)', () => {
// "bi\nFaf" is selected with ctrl + alt + C hotkey
const result = applyMarkdown({
message: 'Jalebi\nFafda\nSambharo',
selectionStart: 4,
selectionEnd: 10,
markdownMode: 'code',
});
expect(result).toEqual({
message: 'Jale```\nbi\nFaf\n```da\nSambharo',
selectionStart: 8,
selectionEnd: 14,
});
});
test('should remove code block markdown to the sub-message', () => {
// "bi\nFaf" is selected with ctrl + alt + C hotkey
const result = applyMarkdown({
message: 'Jale```\nbi\nFaf\n```da\nSambharo',
selectionStart: 8,
selectionEnd: 14,
markdownMode: 'code',
});
expect(result).toEqual({
message: 'Jalebi\nFafda\nSambharo',
selectionStart: 4,
selectionEnd: 10,
});
});
});

View File

@ -18,6 +18,8 @@ type ApplyMarkdownReturnValue = {
type ApplySpecificMarkdownOptions = ApplyMarkdownReturnValue & {
delimiter?: string;
delimiterStart?: string;
delimiterEnd?: string;
}
export type ApplyLinkMarkdownOptions = ApplySpecificMarkdownOptions & {
@ -73,8 +75,7 @@ export function applyMarkdown(options: ApplyMarkdownOptions): ApplyMarkdownRetur
delimiter = '~~';
return applyMarkdownToSelection({selectionEnd, selectionStart, message, delimiter});
case 'code':
delimiter = '```';
return applyMarkdownToSelection({selectionEnd, selectionStart, message, delimiter});
return applyCodeMarkdown({selectionEnd, selectionStart, message});
}
throw Error('Unsupported markdown mode: ' + markdownMode);
@ -271,8 +272,12 @@ const applyMarkdownToSelection = ({
selectionStart,
message,
delimiter,
delimiterStart,
delimiterEnd,
}: ApplySpecificMarkdownOptions) => {
if (!delimiter) {
const openingDelimiter = delimiterStart ?? delimiter;
const closingDelimiter = delimiterEnd ?? delimiter;
if (!openingDelimiter || !closingDelimiter) {
/**
* in case no delimiter is set return the values without changing anything
*/
@ -293,7 +298,7 @@ const applyMarkdownToSelection = ({
let suffix = message.slice(selectionEnd);
// Does the selection have current hotkey's markdown?
const hasCurrentMarkdown = prefix.endsWith(delimiter) && suffix.startsWith(delimiter);
const hasCurrentMarkdown = prefix.endsWith(openingDelimiter) && suffix.startsWith(closingDelimiter);
let newValue: string;
let newStart = selectionStart;
@ -313,14 +318,14 @@ const applyMarkdownToSelection = ({
if (hasCurrentMarkdown) {
// selection already has the markdown, so we remove it here
newValue = prefix.slice(0, prefix.length - delimiter.length) + selection + suffix.slice(delimiter.length);
newStart -= delimiter.length;
newEnd -= delimiter.length;
newValue = prefix.slice(0, prefix.length - openingDelimiter.length) + selection + suffix.slice(closingDelimiter.length);
newStart -= openingDelimiter.length;
newEnd -= closingDelimiter.length;
} else {
// add markdown to the selection
newValue = prefix + delimiter + selection + delimiter + suffix;
newStart += delimiter.length;
newEnd += delimiter.length;
newValue = prefix + openingDelimiter + selection + closingDelimiter + suffix;
newStart += openingDelimiter.length;
newEnd += closingDelimiter.length;
}
return {
@ -492,6 +497,13 @@ export function applyLinkMarkdown({selectionEnd, selectionStart, message, url =
};
}
function applyCodeMarkdown({selectionEnd, selectionStart, message}: ApplySpecificMarkdownOptions) {
if (isSelectionMultiline(message, selectionStart, selectionEnd)) {
return applyMarkdownToSelection({selectionEnd, selectionStart, message, delimiterStart: '```\n', delimiterEnd: '\n```'});
}
return applyMarkdownToSelection({selectionEnd, selectionStart, message, delimiter: '`'});
}
function findWordEnd(text: string, start: number) {
const wordEnd = text.indexOf(' ', start);
return wordEnd === -1 ? text.length : wordEnd;
@ -501,3 +513,7 @@ function findWordStart(text: string, start: number) {
const wordStart = text.lastIndexOf(' ', start - 1) + 1;
return wordStart === -1 ? 0 : wordStart;
}
function isSelectionMultiline(message: string, selectionStart: number, selectionEnd: number) {
return message.slice(selectionStart, selectionEnd).includes('\n');
}