2.6 KB67 lines
Blame
1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8/**
9 * Replace text in a text area.
10 * Re-adjust cursor & selection to be the same as before the replacement.
11 */
12export function replaceInTextArea(textArea: HTMLTextAreaElement, oldText: string, newText: string) {
13 const {selectionStart, selectionEnd} = textArea;
14 const insertionSpot = textArea.value.indexOf(oldText);
15 textArea.value = textArea.value.replace(oldText, newText);
16 // re-select whatever we had selected before.
17 // if the new text is longer, we may need to add additional length
18 if (selectionStart) {
19 textArea.selectionStart =
20 selectionStart > insertionSpot
21 ? selectionStart + (newText.length - oldText.length)
22 : selectionStart;
23 }
24 if (selectionEnd) {
25 textArea.selectionEnd =
26 selectionEnd > insertionSpot
27 ? selectionEnd + (newText.length - oldText.length)
28 : selectionEnd;
29 }
30}
31
32/**
33 * Insert text into a text area at the cursor location.
34 * Add spaces before/after as necessary so the new text does not neighbor the existing content.
35 * If text is selected, replace the selected text with the new text.
36 * If nothing is selected, append to the end.
37 */
38export function insertAtCursor(textArea: HTMLTextAreaElement, text: string) {
39 if (textArea.selectionStart != null) {
40 const startPos = textArea.selectionStart;
41 const endPos = textArea.selectionEnd;
42 const nextCharPos = endPos ?? startPos;
43 const previousChar = textArea.value[startPos - 1];
44 const nextChar = textArea.value[nextCharPos];
45 const isWhitespace = (s: string | undefined) => !s || /[ \n\t]/.test(s);
46 // if inserting next to whitespace, no need to add more.
47 // if inserting next to text, add a space before to avoid the link becoming invalid.
48 const prefix = isWhitespace(previousChar) ? '' : ' ';
49 // similarly for suffix
50 const suffix = isWhitespace(nextChar) ? '' : ' ';
51 const totalAddedLength = text.length + prefix.length + suffix.length;
52 textArea.value =
53 textArea.value.substring(0, startPos) +
54 prefix +
55 text +
56 suffix +
57 (endPos != null ? textArea.value.substring(endPos, textArea.value.length) : '');
58 const newPos = startPos + totalAddedLength;
59 textArea.selectionStart = newPos;
60 textArea.selectionEnd = newPos;
61 } else {
62 // no selection => append to the end
63 const prefix = /\s/.test(textArea.value[textArea.value.length - 1]) ? '' : ' ';
64 textArea.value += prefix + text;
65 }
66}
67