MM-53006 : Using the "link" button puts the URL after [url] instead of replacing [url] when pasting (#23784)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
887ba95cc1
Коммит
a5867074e5
@@ -401,7 +401,9 @@ function applyBoldItalicMarkdown({selectionEnd, selectionStart, message, markdow
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyLinkMarkdown({selectionEnd, selectionStart, message, url = 'url'}: ApplyLinkMarkdownOptions) {
|
export const DEFAULT_PLACEHOLDER_URL = 'url';
|
||||||
|
|
||||||
|
export function applyLinkMarkdown({selectionEnd, selectionStart, message, url = DEFAULT_PLACEHOLDER_URL}: ApplyLinkMarkdownOptions) {
|
||||||
// <prefix> <selection> <suffix>
|
// <prefix> <selection> <suffix>
|
||||||
const prefix = message.slice(0, selectionStart);
|
const prefix = message.slice(0, selectionStart);
|
||||||
const selection = message.slice(selectionStart, selectionEnd);
|
const selection = message.slice(selectionStart, selectionEnd);
|
||||||
|
|||||||
@@ -170,6 +170,33 @@ describe('formatMarkdownLinkMessage', () => {
|
|||||||
const formatttedMarkdownLinkMessage = formatMarkdownLinkMessage({selectionStart: 0, selectionEnd: 4, message, clipboardData});
|
const formatttedMarkdownLinkMessage = formatMarkdownLinkMessage({selectionStart: 0, selectionEnd: 4, message, clipboardData});
|
||||||
expect(formatttedMarkdownLinkMessage).toEqual('[test](https://example.com/)');
|
expect(formatttedMarkdownLinkMessage).toEqual('[test](https://example.com/)');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Should not add link when pasting inside of a formatted markdown link', () => {
|
||||||
|
const message = '[test](url)';
|
||||||
|
const formatttedMarkdownLinkMessage = formatMarkdownLinkMessage({selectionStart: 7, selectionEnd: 10, message, clipboardData});
|
||||||
|
expect(formatttedMarkdownLinkMessage).toEqual('https://example.com/');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should add link when pasting inside of an improper formatted markdown link', () => {
|
||||||
|
const improperFormattedLinkMessages = [
|
||||||
|
{message: '[test](url)', selection: 'ur', expected: '[ur](https://example.com/)'},
|
||||||
|
{message: '[test](url)', selection: '(url', expected: '[(url](https://example.com/)'},
|
||||||
|
{message: '[test](url)', selection: 'url)', expected: '[url)](https://example.com/)'},
|
||||||
|
{message: '[test](url)', selection: '(url)', expected: '[(url)](https://example.com/)'},
|
||||||
|
{message: '[test](url)', selection: '[test](url', expected: '[[test](url](https://example.com/)'},
|
||||||
|
{message: '[test](url)', selection: 'test](url', expected: '[test](url](https://example.com/)'},
|
||||||
|
{message: '[test](url)', selection: 'test](url)', expected: '[test](url)](https://example.com/)'},
|
||||||
|
{message: '[test](url)', selection: '[test](url)', expected: '[[test](url)](https://example.com/)'},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const {message, selection, expected} of improperFormattedLinkMessages) {
|
||||||
|
const selectionStart = message.indexOf(selection);
|
||||||
|
const selectionEnd = selectionStart + selection.length;
|
||||||
|
|
||||||
|
const formatttedMarkdownLinkMessage = formatMarkdownLinkMessage({selectionStart, selectionEnd, message, clipboardData});
|
||||||
|
expect(formatttedMarkdownLinkMessage).toEqual(expected);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('isTextUrl', () => {
|
describe('isTextUrl', () => {
|
||||||
|
|||||||
@@ -3,13 +3,7 @@
|
|||||||
|
|
||||||
import turndownService from 'utils/turndown';
|
import turndownService from 'utils/turndown';
|
||||||
import {splitMessageBasedOnCaretPosition, splitMessageBasedOnTextSelection} from 'utils/post_utils';
|
import {splitMessageBasedOnCaretPosition, splitMessageBasedOnTextSelection} from 'utils/post_utils';
|
||||||
|
import {DEFAULT_PLACEHOLDER_URL} from 'utils/markdown/apply_markdown';
|
||||||
type FormatMarkdownParams = {
|
|
||||||
message: string;
|
|
||||||
clipboardData: DataTransfer;
|
|
||||||
selectionStart: number | null;
|
|
||||||
selectionEnd: number | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function parseHtmlTable(html: string): HTMLTableElement | null {
|
export function parseHtmlTable(html: string): HTMLTableElement | null {
|
||||||
return new DOMParser().parseFromString(html, 'text/html').querySelector('table');
|
return new DOMParser().parseFromString(html, 'text/html').querySelector('table');
|
||||||
@@ -83,6 +77,13 @@ export function formatMarkdownMessage(clipboardData: DataTransfer, message?: str
|
|||||||
return {formattedMessage, formattedMarkdown};
|
return {formattedMessage, formattedMarkdown};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FormatGithubCodePasteParams = {
|
||||||
|
message: string;
|
||||||
|
clipboardData: DataTransfer;
|
||||||
|
selectionStart: number | null;
|
||||||
|
selectionEnd: number | null;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format the incoming github code paste into a markdown code block.
|
* Format the incoming github code paste into a markdown code block.
|
||||||
* This function assumes that the clipboardData contains a code block.
|
* This function assumes that the clipboardData contains a code block.
|
||||||
@@ -90,7 +91,7 @@ export function formatMarkdownMessage(clipboardData: DataTransfer, message?: str
|
|||||||
* @property {string} formattedMessage - The complete formatted message including the code block.
|
* @property {string} formattedMessage - The complete formatted message including the code block.
|
||||||
* @property {string} formattedCodeBlock - The resulting code block from the clipboard data.
|
* @property {string} formattedCodeBlock - The resulting code block from the clipboard data.
|
||||||
*/
|
*/
|
||||||
export function formatGithubCodePaste({message, clipboardData, selectionStart, selectionEnd}: FormatMarkdownParams): {formattedMessage: string; formattedCodeBlock: string} {
|
export function formatGithubCodePaste({message, clipboardData, selectionStart, selectionEnd}: FormatGithubCodePasteParams): {formattedMessage: string; formattedCodeBlock: string} {
|
||||||
const isTextSelected = selectionStart !== selectionEnd;
|
const isTextSelected = selectionStart !== selectionEnd;
|
||||||
const {firstPiece, lastPiece} = isTextSelected ? splitMessageBasedOnTextSelection(selectionStart ?? message.length, selectionEnd ?? message.length, message) : splitMessageBasedOnCaretPosition(selectionStart ?? message.length, message);
|
const {firstPiece, lastPiece} = isTextSelected ? splitMessageBasedOnTextSelection(selectionStart ?? message.length, selectionEnd ?? message.length, message) : splitMessageBasedOnCaretPosition(selectionStart ?? message.length, message);
|
||||||
|
|
||||||
@@ -104,21 +105,38 @@ export function formatGithubCodePaste({message, clipboardData, selectionStart, s
|
|||||||
return {formattedMessage, formattedCodeBlock};
|
return {formattedMessage, formattedCodeBlock};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FormatMarkdownLinkMessage = {
|
||||||
|
message: string;
|
||||||
|
clipboardData: DataTransfer;
|
||||||
|
selectionStart: number;
|
||||||
|
selectionEnd: number;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats the incoming link paste into a markdown link.
|
* Formats the incoming link paste into a markdown link.
|
||||||
* This function assumes that the clipboardData contains a link.
|
* This function assumes that the clipboardData contains a link.
|
||||||
* @returns The resulting markdown link from the clipboard data.
|
* @returns The resulting markdown link from the clipboard data.
|
||||||
*/
|
*/
|
||||||
export function formatMarkdownLinkMessage({message, clipboardData, selectionStart, selectionEnd}: FormatMarkdownParams) {
|
export function formatMarkdownLinkMessage({message, clipboardData, selectionStart, selectionEnd}: FormatMarkdownLinkMessage) {
|
||||||
const isTextSelected = selectionStart !== selectionEnd;
|
const selectedText = message.slice(selectionStart, selectionEnd);
|
||||||
|
const clipboardUrl = clipboardData.getData('text/plain');
|
||||||
|
|
||||||
let selectedText = '';
|
if (selectedText === DEFAULT_PLACEHOLDER_URL) {
|
||||||
if (isTextSelected) {
|
if (message.length > DEFAULT_PLACEHOLDER_URL.length) {
|
||||||
selectedText = message.slice(selectionStart || 0, selectionEnd || 0);
|
const FORMATTED_LINK_URL_PREFIX = '](';
|
||||||
|
const FORMATTED_LINK_URL_SUFFIX = ')';
|
||||||
|
|
||||||
|
const textBefore = message.slice(selectionStart - FORMATTED_LINK_URL_PREFIX.length, selectionStart);
|
||||||
|
const textAfter = message.slice(selectionEnd, selectionEnd + FORMATTED_LINK_URL_SUFFIX.length);
|
||||||
|
|
||||||
|
// We check "](" "url" ")" to see if user is trying to paste inside of a markdown link
|
||||||
|
// and selection is on "url"
|
||||||
|
if (textBefore === FORMATTED_LINK_URL_PREFIX && textAfter === FORMATTED_LINK_URL_SUFFIX) {
|
||||||
|
return clipboardUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = clipboardData.getData('text/plain');
|
const markdownLink = `[${selectedText}](${clipboardUrl})`;
|
||||||
const markdownLink = `[${selectedText}](${url})`;
|
|
||||||
|
|
||||||
return markdownLink;
|
return markdownLink;
|
||||||
}
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user