@sertxudeveloper/markdown-editor
Version:
A customizable markdown editor for your projects
145 lines (126 loc) • 5.31 kB
text/typescript
import {
expandSelectedText,
insertText,
isMultipleLines,
newlinesToSurroundSelectedText,
} from '../utils/Utils';
export type BlockStyleArgs = {
prefix?: string;
suffix?: string;
blockPrefix?: string;
blockSuffix?: string;
replaceNext?: string;
prefixSpace?: boolean;
scanFor?: string;
surroundWithNewlines?: boolean;
trimFirst?: boolean;
multiline?: boolean;
};
const defaultBlockStyleArgs: BlockStyleArgs = {
prefix: '',
suffix: '',
blockPrefix: '',
blockSuffix: '',
replaceNext: '',
prefixSpace: false,
scanFor: '',
surroundWithNewlines: false,
trimFirst: false,
multiline: false,
};
export default class BlockStyle {
static applyStyle(textarea: HTMLTextAreaElement, args: BlockStyleArgs): void {
const {
prefix,
suffix,
blockPrefix,
blockSuffix,
replaceNext,
prefixSpace,
scanFor,
surroundWithNewlines,
trimFirst,
multiline,
} = { ...defaultBlockStyleArgs, ...args };
const originalSelectionStart = textarea.selectionStart;
const originalSelectionEnd = textarea.selectionEnd;
let selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
let prefixToUse =
isMultipleLines(selectedText) && blockPrefix.length > 0 ? `${blockPrefix}\n` : prefix;
let suffixToUse =
isMultipleLines(selectedText) && blockSuffix.length > 0 ? `\n${blockSuffix}` : suffix;
if (prefixSpace) {
const beforeSelection = textarea.value[textarea.selectionStart - 1];
if (
textarea.selectionStart !== 0 &&
beforeSelection != null &&
!beforeSelection.match(/\s/)
) {
prefixToUse = ` ${prefixToUse}`;
}
}
selectedText = expandSelectedText(textarea, prefixToUse, suffixToUse, multiline);
let selectionStart = textarea.selectionStart;
let selectionEnd = textarea.selectionEnd;
const hasReplaceNext =
replaceNext.length > 0 &&
suffixToUse.indexOf(replaceNext) > -1 &&
selectedText.length > 0;
let newlinesToAppend;
let newlinesToPrepend;
if (surroundWithNewlines) {
const ref = newlinesToSurroundSelectedText(textarea);
newlinesToAppend = ref.newlinesToAppend;
newlinesToPrepend = ref.newlinesToPrepend;
prefixToUse = newlinesToAppend + prefix;
suffixToUse += newlinesToPrepend;
}
if (selectedText.startsWith(prefixToUse) && selectedText.endsWith(suffixToUse)) {
const replacementText = selectedText.slice(
prefixToUse.length,
selectedText.length - suffixToUse.length
);
if (originalSelectionStart === originalSelectionEnd) {
let position = originalSelectionStart - prefixToUse.length;
position = Math.max(position, selectionStart);
position = Math.min(position, selectionStart + replacementText.length);
selectionStart = selectionEnd = position;
} else {
selectionEnd = selectionStart + replacementText.length;
}
return insertText(textarea, { text: replacementText, selectionStart, selectionEnd });
} else if (!hasReplaceNext) {
let replacementText = prefixToUse + selectedText + suffixToUse;
selectionStart = originalSelectionStart + prefixToUse.length;
selectionEnd = originalSelectionEnd + prefixToUse.length;
const whitespaceEdges = selectedText.match(/^\s*|\s*$/g);
if (trimFirst && whitespaceEdges) {
const leadingWhitespace = whitespaceEdges[0] || '';
const trailingWhitespace = whitespaceEdges[1] || '';
replacementText =
leadingWhitespace +
prefixToUse +
selectedText.trim() +
suffixToUse +
trailingWhitespace;
selectionStart += leadingWhitespace.length;
selectionEnd -= trailingWhitespace.length;
}
return insertText(textarea, { text: replacementText, selectionStart, selectionEnd });
} else if (scanFor.length > 0 && selectedText.match(scanFor)) {
suffixToUse = suffixToUse.replace(replaceNext, selectedText);
const replacementText = prefixToUse + suffixToUse;
selectionStart = selectionEnd = selectionStart + prefixToUse.length;
return insertText(textarea, { text: replacementText, selectionStart, selectionEnd });
} else {
const replacementText = prefixToUse + selectedText + suffixToUse;
selectionStart =
selectionStart +
prefixToUse.length +
selectedText.length +
suffixToUse.indexOf(replaceNext);
selectionEnd = selectionStart + replaceNext.length;
return insertText(textarea, { text: replacementText, selectionStart, selectionEnd });
}
}
}