Undo Is Working For Only First Replaced Text?
Here I am using Ctrl+Z for undoing the replaced text, I have a scenario that, in text-area, I have a sentence with multiple words, where I select first word and replaced with stars
Solution 1:
You have to manually control all your textarea
changes.
Here I created the edits
array which is populated with textarea
text on change every few seconds (you can control it using the saveInterval
variable).
You also can set the max length of this array using maxHistorySize
. When the array is full, the old changes are lost.
var edits = [""];
var interval = true;
var maxHistorySize = 10;
var saveInterval = 3000;
functionundo(e) {
var evtobj = window.event? window.event : e;
if (evtobj.keyCode == 90 && evtobj.ctrlKey) {
evtobj.preventDefault();
var txtarea = document.getElementById("mytextarea");
var previousText = edits.length === 1 ? edits[0] : edits.pop();
if (previousText !== undefined) {
txtarea.value = previousText;
}
}
}
functiongetSel() {
// obtain the object reference for the textarea>var txtarea = document.getElementById("mytextarea");
// obtain the index of the first selected charactervar start = txtarea.selectionStart;
// obtain the index of the last selected charactervar finish = txtarea.selectionEnd;
//obtain all Textvar allText = txtarea.value;
edits.push(allText);
if (edits.length > maxHistorySize) edits.shift();
// obtain the selected textvar sel = Array(finish - start + 1).join("*");
//append te text;var newText = allText.substring(0, start) + sel + allText.substring(finish, allText.length);
txtarea.value = newText;
$('#newpost').offset({top: 0, left: 0}).hide();
}
functionclosePopUp() {
$('#newpost').offset({top: 0, left: 0}).hide();
}
$(document).ready(function () {
closePopUp();
var newpost = $('#newpost');
$('#mytextarea').on('select', function (e) {
var txtarea = document.getElementById("mytextarea");
var start = txtarea.selectionStart;
var finish = txtarea.selectionEnd;
newpost.offset(getCursorXY(txtarea, start, 20)).show();
newpost.find('div').text(Array(finish - start + 1).join("*"));
}).on('input', function() {
if (interval) {
interval = false;
edits.push($(this).val());
if (edits.length > maxHistorySize) edits.shift();
setTimeout(() => interval = true, saveInterval);
}
});
document.onkeydown = undo;
});
constgetCursorXY = (input, selectionPoint, offset) => {
const {
offsetLeft: inputX,
offsetTop: inputY,
} = input
// create a dummy element that will be a clone of our inputconst div = document.createElement('div')
// get the computed style of the input and clone it onto the dummy elementconst copyStyle = getComputedStyle(input)
for (const prop of copyStyle) {
div.style[prop] = copyStyle[prop]
}
// we need a character that will replace whitespace when filling our dummy element // if it's a single line <input/>const swap = '.'const inputValue = input.tagName === 'INPUT' ? input.value.replace(/ /g, swap) : input.value// set the div content to that of the textarea up until selectionconst textContent = inputValue.substr(0, selectionPoint)
// set the text content of the dummy element div
div.textContent = textContent
if (input.tagName === 'TEXTAREA') div.style.height = 'auto'// if a single line input then the div needs to be single line and not break out like a text areaif (input.tagName === 'INPUT') div.style.width = 'auto'// create a marker element to obtain caret positionconst span = document.createElement('span')
// give the span the textContent of remaining content so that the recreated dummy element // is as close as possible
span.textContent = inputValue.substr(selectionPoint) || '.'// append the span marker to the div
div.appendChild(span)
// append the dummy element to the bodydocument.body.appendChild(div)
// get the marker position, this is the caret position top and left relative to the inputconst { offsetLeft: spanX, offsetTop: spanY } = span
// lastly, remove that dummy element// NOTE:: can comment this out for debugging purposes if you want to see where that span is rendereddocument.body.removeChild(div)
// return an object with the x and y of the caret. account for input positioning // so that you don't need to wrap the inputreturn {
left: inputX + spanX,
top: inputY + spanY + offset,
}
}
#mytextarea {width: 600px; height: 200px; overflow:hidden; position:fixed}
#newpost {
position:absolute;
background-color:#ffffdc;
border:1px solid #DCDCDC;
border-radius:10px;
padding-right:5px;
width: auto;
height: 30px;
}
#newpostspan {
cursor:pointer;
position: absolute;
top: 0;
right: 5px;
font-size: 22px;
}
#newpostdiv {
color:#0000ff;
padding:10px;
margin-right:10px;
width: auto;
cursor:pointer;
}
<scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><html><head></head><body><textAreaid="mytextarea"></textArea><divid="newpost"><spanonclick="closePopUp();">˟</span><divonclick="getSel()"></div></div></body></html>
Solution 2:
You need to change your logic from using a single selection
object to using an array of selection
objects, like this:
Initialize to
selections
instead ofselection
var selections = [];
When
getSel()
is called, make sure you update topush
to array:functiongetSel() { // obtain the object reference for the textarea>var txtarea = document.getElementById("mytextarea"); // obtain the index of the first selected charactervar start = txtarea.selectionStart; // obtain the index of the last selected charactervar finish = txtarea.selectionEnd; //obtain all Textvar allText = txtarea.value; selections.push({ start: start, finish: finish, text: allText.substring(start, finish) }); // obtain the selected textvar sel = allText.substring(start, finish); sel = sel.replace(/[\S]/g, "*"); //append te text;var newText = allText.substring(0, start) + sel + allText.substring(finish, allText.length); txtarea.value = newText; $('#newpost').offset({top: 0, left: 0}).hide(); }
As such, we need to update
undo
function, as follows:functionundo(e) { var evtobj = window.event? window.event : e; if (evtobj.keyCode == 90 && evtobj.ctrlKey) { evtobj.preventDefault(); if (selections.length === 0) alert ("Can't do more undos"); else { var thisSelection = selections.pop(); var txtarea = document.getElementById("mytextarea"); var allText = txtarea.value; var newText = allText.substring(0, thisSelection.start) + thisSelection.text + allText.substring(thisSelection.finish, allText.length); txtarea.value = newText; } } }
Lastly, remove the
on('input')
event listener from$('#mytextarea')
as I don't think it's needed
Post a Comment for "Undo Is Working For Only First Replaced Text?"