Is there a way to edit the contents of an input
or textarea
with javascript, and have that change be undo-able with the browser's "undo" command (eg ctrl-Z
)?
I am trying to insert a string, such as "Foo {0} bar", into the value at the selection, and if the user has selected a range, the selected range is inserted into the string in place of the "{0}".
For example if the textarea contains "Example 1 2 3" and the cursor is at "Example 1| 2 3", then the function would change the value to "Example 1Foo blah bar 2 3" (valueIfNothingSelected
being "blah" in this case). If the range "1 2" was selected, the function would instead change the value to "Example Foo 1 2 bar 3".
In Chrome I tested this function out, and it does what it is supposed to, but I cannot reverse the change with undo
.
function insertTextAtCursor(text, valueIfNothingSelected) {
var field = $('textarea[name="task_log_description"]')[0];
var startPos = field.selectionStart;
var endPos = field.selectionEnd;
var processedText;
if (startPos == endPos) {
processedText = text.replace('{0}', valueIfNothingSelected);
field.value = field.value.substring(0, startPos) + processedText + field.value.substring(endPos, field.value.length);
field.selectionStart = startPos + text.indexOf('{0}');
field.selectionEnd = field.selectionStart + valueIfNothingSelected.length;
} else {
var selectedText = field.value.substring(startPos, endPos);
processedText = text.replace('{0}', selectedText);
field.value = field.value.substring(0, startPos) + processedText + field.value.substring(endPos, field.value.length);
field.selectionStart = startPos + text.indexOf('{0}');
field.selectionEnd = field.selectionStart + selectedText.length;
}
field.focus();
}
Is there a way to edit the contents of an input
or textarea
with javascript, and have that change be undo-able with the browser's "undo" command (eg ctrl-Z
)?
I am trying to insert a string, such as "Foo {0} bar", into the value at the selection, and if the user has selected a range, the selected range is inserted into the string in place of the "{0}".
For example if the textarea contains "Example 1 2 3" and the cursor is at "Example 1| 2 3", then the function would change the value to "Example 1Foo blah bar 2 3" (valueIfNothingSelected
being "blah" in this case). If the range "1 2" was selected, the function would instead change the value to "Example Foo 1 2 bar 3".
In Chrome I tested this function out, and it does what it is supposed to, but I cannot reverse the change with undo
.
function insertTextAtCursor(text, valueIfNothingSelected) {
var field = $('textarea[name="task_log_description"]')[0];
var startPos = field.selectionStart;
var endPos = field.selectionEnd;
var processedText;
if (startPos == endPos) {
processedText = text.replace('{0}', valueIfNothingSelected);
field.value = field.value.substring(0, startPos) + processedText + field.value.substring(endPos, field.value.length);
field.selectionStart = startPos + text.indexOf('{0}');
field.selectionEnd = field.selectionStart + valueIfNothingSelected.length;
} else {
var selectedText = field.value.substring(startPos, endPos);
processedText = text.replace('{0}', selectedText);
field.value = field.value.substring(0, startPos) + processedText + field.value.substring(endPos, field.value.length);
field.selectionStart = startPos + text.indexOf('{0}');
field.selectionEnd = field.selectionStart + selectedText.length;
}
field.focus();
}
Share
Improve this question
edited Nov 19, 2014 at 22:16
Marsh
asked Nov 19, 2014 at 21:58
MarshMarsh
8,1259 gold badges54 silver badges86 bronze badges
3
|
3 Answers
Reset to default 21I found a solution that works at https://stackoverflow.com/a/10345596/1021426
By replacing the "field.value = ..." lines with:
document.execCommand("insertText", false, processedText);
...and moving "field.focus()" to before that line, I was able to achieve the undo/redo functionality I desired.
Edit: Firefox now supports execCommand
too. You just need that.
Here's a solution which works in Firefox too, is the most performant one and offers undo functionality everywhere except Firefox (where it just isn't possible natively)
// Solution
function insertText(textarea, text) {
// https://stackoverflow.com/a/55174561/288906
if (!document.execCommand('insertText', false, text)) {
textarea.setRangeText(text);
}
}
// Demo code to add text on click
const textarea = document.querySelector('textarea');
textarea.onclick = () => insertText(
textarea,
'@'
);
<textarea>Click in here to add text</textarea>
I also packaged this up as an npm module, improving consistency across browsers and adding utilities like "insert", "replace", "search and replace", etc
Here's code to replace the contents of a <textarea>
instead of just inserting.
function setValueAndUpdateUndoStack(textarea, text) {
// Must select all, so that the old text is deleted.
textarea.focus();
textarea.select();
// https://stackoverflow.com/a/55174561/3480193
if ( ! document.execCommand('insertText', false, text) ) {
textarea.setRangeText(text);
}
}
Ctrl-z
doesn't work when this method is used. – Marsh Commented Nov 19, 2014 at 22:18