File size: 7,370 Bytes
d44b3c1 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
import { power_user } from './power-user.js';
export function initInputMarkdown() {
$(document).on('keydown', 'textarea.mdHotkeys', function (e) {
if (!power_user.enable_md_hotkeys) { return; }
// Ensure that the element is a textarea
let textarea = this;
if (!(textarea instanceof HTMLTextAreaElement)) {
return;
}
// Early return on only control or no control, alt key, and win/cmd key
if (e.key === 'Control' || !e.ctrlKey || e.altKey || e.metaKey || (e.shiftKey && !(e.ctrlKey && e.shiftKey && e.code === 'Backquote'))) {
return;
}
let charsToAdd = '';
let possiblePreviousFormattingMargin = 1;
switch (true) {
case e.ctrlKey && e.shiftKey && e.code === 'Backquote':
e.preventDefault();
e.stopPropagation();
charsToAdd = '~~';
possiblePreviousFormattingMargin = 2;
break;
case e.ctrlKey && e.code === 'KeyB':
e.preventDefault();
e.stopPropagation();
charsToAdd = '**';
possiblePreviousFormattingMargin = 2;
break;
case e.ctrlKey && e.code === 'KeyI':
e.preventDefault();
e.stopPropagation();
charsToAdd = '*';
break;
case e.ctrlKey && e.code === 'KeyU':
e.preventDefault();
e.stopPropagation();
charsToAdd = '__';
possiblePreviousFormattingMargin = 2;
break;
case e.ctrlKey && e.code === 'KeyK':
e.preventDefault();
e.stopPropagation();
charsToAdd = '`';
break;
default:
return; // Early return if no key matches
}
let selectedText = '';
let start = textarea.selectionStart;
let end = textarea.selectionEnd;
let beforeCaret = textarea.value.substring(start - 1, start);
let afterCaret = textarea.value.substring(end, end + 1);
let isTextSelected = (start !== end);
let cursorShift = charsToAdd.length;
let selectedTextandPossibleFormatting = textarea.value.substring(start - possiblePreviousFormattingMargin, end + possiblePreviousFormattingMargin).trim();
if (isTextSelected) { //if text is selected
selectedText = textarea.value.substring(start, end);
if (selectedTextandPossibleFormatting === charsToAdd + selectedText + charsToAdd) {
// If the selected text is already formatted, remove the formatting
let expandedStart = start - charsToAdd.length;
let expandedEnd = end + charsToAdd.length;
// Ensure expanded range is within the bounds of the text
if (expandedStart < 0) expandedStart = 0;
if (expandedEnd > textarea.value.length) expandedEnd = textarea.value.length;
// Select the expanded range
textarea.setSelectionRange(expandedStart, expandedEnd);
// Replace the expanded selection with the original selected text
document.execCommand('insertText', false, selectedText);
// Adjust cursor position
cursorShift = -charsToAdd.length;
} else {
// Add formatting to the selected text
let possibleAddedSpace = '';
if (selectedText.endsWith(' ')) {
possibleAddedSpace = ' ';
selectedText = selectedText.substring(0, selectedText.length - 1);
end--; // Adjust the end index since we removed the space
}
// To add the formatting, we need to select the text first
textarea.focus();
document.execCommand('insertText', false, charsToAdd + selectedText + charsToAdd + possibleAddedSpace);
}
} else {// No text is selected
//check 1 character before and after the cursor for non-space characters
if (beforeCaret !== ' ' && afterCaret !== ' ' && afterCaret !== '' && beforeCaret !== '') { //look for caret in the middle of a word
//expand the selection range until the next space on both sides
let midCaretExpandedStart = start - 1;
let midCaretExpandedEnd = end + 1;
while (midCaretExpandedStart > 0 && textarea.value.substring(midCaretExpandedStart - 1, midCaretExpandedStart) !== ' ') {
midCaretExpandedStart--;
}
while (midCaretExpandedEnd < textarea.value.length && textarea.value.substring(midCaretExpandedEnd, midCaretExpandedEnd + 1) !== ' ') {
midCaretExpandedEnd++;
}
//make a selection of the discovered word
textarea.setSelectionRange(midCaretExpandedStart, midCaretExpandedEnd);
//set variables for comparison
let discoveredWordWithPossibleFormatting = textarea.value.substring(midCaretExpandedStart, midCaretExpandedEnd).trim();
let discoveredWord = '';
if (discoveredWordWithPossibleFormatting.endsWith(charsToAdd) && discoveredWordWithPossibleFormatting.startsWith(charsToAdd)) {
discoveredWord = textarea.value.substring(midCaretExpandedStart + charsToAdd.length, midCaretExpandedEnd - charsToAdd.length).trim();
} else {
discoveredWord = textarea.value.substring(midCaretExpandedStart, midCaretExpandedEnd).trim();
}
if (charsToAdd + discoveredWord + charsToAdd === discoveredWordWithPossibleFormatting) {
// Replace the expanded selection with the original discovered word
textarea.focus();
document.execCommand('insertText', false, discoveredWord);
// Adjust cursor position
cursorShift = -charsToAdd.length;
} else { //format did not previously exist, so add it
textarea.focus();
document.execCommand('insertText', false, charsToAdd + discoveredWord + charsToAdd);
}
} else { //caret is not inside a word, so just add the formatting
textarea.focus();
textarea.setSelectionRange(start, end);
selectedText = textarea.value.substring(start, end);
document.execCommand('insertText', false, charsToAdd + selectedText + charsToAdd);
}
}
// Manually trigger the 'input' event to make undo/redo work
let event = new Event('input', { bubbles: true });
textarea.dispatchEvent(event); // This notifies the browser of a change, allowing undo/redo to function.
// Update the cursor position
if (isTextSelected) {
textarea.selectionStart = start + cursorShift;
textarea.selectionEnd = start + cursorShift + selectedText.length;
} else {
textarea.selectionStart = start + cursorShift;
textarea.selectionEnd = start + cursorShift;
}
});
}
|