addons/isl/src/textareaUtils.tsxblame
View source
b69ab311/**
b69ab312 * Copyright (c) Meta Platforms, Inc. and affiliates.
b69ab313 *
b69ab314 * This source code is licensed under the MIT license found in the
b69ab315 * LICENSE file in the root directory of this source tree.
b69ab316 */
b69ab317
b69ab318/**
b69ab319 * Replace text in a text area.
b69ab3110 * Re-adjust cursor & selection to be the same as before the replacement.
b69ab3111 */
b69ab3112export function replaceInTextArea(textArea: HTMLTextAreaElement, oldText: string, newText: string) {
b69ab3113 const {selectionStart, selectionEnd} = textArea;
b69ab3114 const insertionSpot = textArea.value.indexOf(oldText);
b69ab3115 textArea.value = textArea.value.replace(oldText, newText);
b69ab3116 // re-select whatever we had selected before.
b69ab3117 // if the new text is longer, we may need to add additional length
b69ab3118 if (selectionStart) {
b69ab3119 textArea.selectionStart =
b69ab3120 selectionStart > insertionSpot
b69ab3121 ? selectionStart + (newText.length - oldText.length)
b69ab3122 : selectionStart;
b69ab3123 }
b69ab3124 if (selectionEnd) {
b69ab3125 textArea.selectionEnd =
b69ab3126 selectionEnd > insertionSpot
b69ab3127 ? selectionEnd + (newText.length - oldText.length)
b69ab3128 : selectionEnd;
b69ab3129 }
b69ab3130}
b69ab3131
b69ab3132/**
b69ab3133 * Insert text into a text area at the cursor location.
b69ab3134 * Add spaces before/after as necessary so the new text does not neighbor the existing content.
b69ab3135 * If text is selected, replace the selected text with the new text.
b69ab3136 * If nothing is selected, append to the end.
b69ab3137 */
b69ab3138export function insertAtCursor(textArea: HTMLTextAreaElement, text: string) {
b69ab3139 if (textArea.selectionStart != null) {
b69ab3140 const startPos = textArea.selectionStart;
b69ab3141 const endPos = textArea.selectionEnd;
b69ab3142 const nextCharPos = endPos ?? startPos;
b69ab3143 const previousChar = textArea.value[startPos - 1];
b69ab3144 const nextChar = textArea.value[nextCharPos];
b69ab3145 const isWhitespace = (s: string | undefined) => !s || /[ \n\t]/.test(s);
b69ab3146 // if inserting next to whitespace, no need to add more.
b69ab3147 // if inserting next to text, add a space before to avoid the link becoming invalid.
b69ab3148 const prefix = isWhitespace(previousChar) ? '' : ' ';
b69ab3149 // similarly for suffix
b69ab3150 const suffix = isWhitespace(nextChar) ? '' : ' ';
b69ab3151 const totalAddedLength = text.length + prefix.length + suffix.length;
b69ab3152 textArea.value =
b69ab3153 textArea.value.substring(0, startPos) +
b69ab3154 prefix +
b69ab3155 text +
b69ab3156 suffix +
b69ab3157 (endPos != null ? textArea.value.substring(endPos, textArea.value.length) : '');
b69ab3158 const newPos = startPos + totalAddedLength;
b69ab3159 textArea.selectionStart = newPos;
b69ab3160 textArea.selectionEnd = newPos;
b69ab3161 } else {
b69ab3162 // no selection => append to the end
b69ab3163 const prefix = /\s/.test(textArea.value[textArea.value.length - 1]) ? '' : ' ';
b69ab3164 textArea.value += prefix + text;
b69ab3165 }
b69ab3166}