Files
mostlymatter/webapp/channels/src/utils/paste.tsx

100 строки
3.5 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import TurndownService from 'turndown';
import {tables} from '@guyplusplus/turndown-plugin-gfm';
import {splitMessageBasedOnCaretPosition, splitMessageBasedOnTextSelection} from 'utils/post_utils';
type FormatCodeOptions = {
message: string;
clipboardData: DataTransfer;
selectionStart: number | null;
selectionEnd: number | null;
};
export function parseTable(html: string): HTMLTableElement | null {
return new DOMParser().parseFromString(html, 'text/html').querySelector('table');
}
export function getTable(clipboardData: DataTransfer): HTMLTableElement | null {
if (Array.from(clipboardData.types).indexOf('text/html') === -1) {
return null;
}
const html = clipboardData.getData('text/html');
if (!(/<table/i).test(html)) {
return null;
}
const table = parseTable(html);
if (!table) {
return null;
}
return table;
}
export function hasHtmlLink(clipboardData: DataTransfer): boolean {
return Array.from(clipboardData.types).includes('text/html') && (/<a/i).test(clipboardData.getData('text/html'));
}
export function getPlainText(clipboardData: DataTransfer): string | boolean {
if (Array.from(clipboardData.types).indexOf('text/plain') === -1) {
return false;
}
const plainText = clipboardData.getData('text/plain');
return plainText;
}
export function isGitHubCodeBlock(tableClassName: string): boolean {
const result = (/\b(js|blob|diff)-./).test(tableClassName);
return result;
}
function isHeaderlessTable(table: HTMLTableElement): boolean {
return table.querySelectorAll('th').length === 0;
}
export function formatMarkdownMessage(clipboardData: DataTransfer, message?: string, caretPosition?: number): string {
const html = clipboardData.getData('text/html');
//TODO@michel: Instantiate turndown service in a central file instead
const service = new TurndownService({emDelimiter: '*'}).remove('style');
service.use(tables);
let markdownFormattedMessage = service.turndown(html).trim();
const table = getTable(clipboardData);
if (table && isHeaderlessTable(table)) {
markdownFormattedMessage += '\n';
}
if (!message) {
return markdownFormattedMessage;
}
if (typeof caretPosition === 'undefined') {
return `${message}\n\n${markdownFormattedMessage}`;
}
const newMessage = [message.slice(0, caretPosition) + '\n', markdownFormattedMessage, message.slice(caretPosition)];
return newMessage.join('\n');
}
export function formatGithubCodePaste({message, clipboardData, selectionStart, selectionEnd}: FormatCodeOptions): {formattedMessage: string; formattedCodeBlock: string} {
const textSelected = selectionStart !== selectionEnd;
const {firstPiece, lastPiece} = textSelected ?
splitMessageBasedOnTextSelection(selectionStart ?? message.length, selectionEnd ?? message.length, message) :
splitMessageBasedOnCaretPosition(selectionStart ?? message.length, message);
// Add new lines if content exists before or after the cursor.
const requireStartLF = firstPiece === '' ? '' : '\n';
const requireEndLF = lastPiece === '' ? '' : '\n';
const formattedCodeBlock = requireStartLF + '```\n' + getPlainText(clipboardData) + '\n```' + requireEndLF;
const formattedMessage = `${firstPiece}${formattedCodeBlock}${lastPiece}`;
return {formattedMessage, formattedCodeBlock};
}