撤消仅适用于首次替换的文本? [英] Undo is working for only first replaced text?

查看:40
本文介绍了撤消仅适用于首次替换的文本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里我使用Ctrl + Z来撤消被替换的文本,我有一个场景,在文本区域,我有一个多个单词的句子,我选择第一个单词并用星号替换,后来我选择另一个单词并用星星代替。但是当它按Ctrl + Z时它只适用于最新选择的单词而不适用于之前的单词。



JavaScript:

  var selection = {}; 

函数undo(e){
var evtobj = window.event? window.event:e;
if(evtobj.keyCode == 90&& evtobj.ctrlKey&& selection.text){
evtobj.preventDefault();
var txtarea = document.getElementById(mytextarea);
var allText = txtarea.value;
var newText = allText.substring(0,selection.start)+ selection.text + allText.substring(selection.finish,allText.length);
txtarea.value = newText;
}
}

函数getSel(){
//获取textarea的对象引用>
var txtarea = document.getElementById(mytextarea);
//获取第一个选定字符的索引
var start = txtarea.selectionStart;
//获取最后一个选定字符的索引
var finish = txtarea.selectionEnd;
//获取所有Text
var allText = txtarea.value;

selection.text = allText.substring(start,finish);
selection.start = start;
selection.finish =完成;

//获取所选文本
var sel = allText.substring(start,finish);
sel = sel.replace(/ [\ S] / g,*); //追加文字;
var newText = allText.substring(0,start)+ sel + allText.substring(finish,allText.length);
txtarea.value = newText;

$('#newpost')。offset({top:0,left:0})。hide();
}
函数closePopUp(){
$('#newpost')。offset({top:0,left:0})。hide();
}

$(文件).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('replace with stars' );
})。on('input',()=> selection.text = null);
document.onkeydown = undo;

});

var getCursorXY = function getCursorXY(input,selectionPoint,offset){
var inputX = input.offsetLeft,
inputY = input.offsetTop;
//创建一个虚拟元素,它将是我们输入的克隆

var div = document.createElement('div');
//获取输入的计算样式并将其克隆到虚拟元素
var copyStyle = getComputedStyle(input);
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;

尝试{
for(var _iterator = copyStyle [Symbol.iterator](),_ step;!(_ iteratorNormalCompletion =(_step = _iterator.next())。done); _iteratorNormalCompletion = true ){
var prop = _step.value;

div.style [prop] = copyStyle [prop];
}
//我们需要一个在填充虚拟元素时替换空格的字符
//如果它是单行< input />
} catch(错误){
_didIteratorError = true;
_iteratorError = err;
}最后{
尝试{
if(!_iteratorNormalCompletion&& _iterator.return){
_iterator.return();
}
} finally {
if(_didIteratorError){
throw _iteratorError;
}
}
}

var swap ='。';
var inputValue = input.tagName ==='INPUT'? input.value.replace(/ / g,swap):input.value;
//将div内容设置为textarea的内容直到选择
var textContent = inputValue.substr(0,selectionPoint);
//设置虚拟元素div的文本内容
div.textContent = textContent;
if(input.tagName ==='TEXTAREA')div.style.height ='auto';
//如果单行输入则div必须是单行而不是像文本区域那样突破
if(input.tagName ==='INPUT')div.style.width ='汽车';
//创建一个标记元素来获取插入位置
var span = document.createElement('span');
//给出span剩余内容的textContent,以便重新创建的虚拟元素
//尽可能接近
span.textContent = inputValue.substr(selectionPoint)|| 。;
//将跨度标记附加到div
div.appendChild(span);
//将虚拟元素附加到正文
document.body.appendChild(div);
//获取标记位置,这是相对于输入
var spanX = span.offsetLeft,
spanY = span.offsetTop的顶部和左侧的插入位置;
//最后,删除那个虚拟元素
//注意::如果你想查看该范围的呈现位置,可以将其注释掉以进行调试

document.body。 removeChild之(DIV);
//返回一个带有插入符号x和y的对象。输入定位的帐户
//这样你就不需要包装输入
返回{
left:inputX + spanX,
top:inputY + spanY + offset
};
};

这是我的 Plunker

解决方案

你必须手动控制你所有的 textarea 更改。



这里我创建了编辑数组,其中填充了 textarea 每隔几秒更改一次文本(可以使用 saveInterval 变量控制它)。
您还可以使用 maxHistorySize 设置此数组的最大长度。当数组已满时,旧的更改将丢失。



  var edits = []; var interval = true; var maxHistorySize = 10; var saveInterval = 3000;函数undo(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; function getSel(){//获取textarea的对象引用> var txtarea = document.getElementById(mytextarea); //获取第一个选定字符的索引var start = txtarea.selectionStart; //获取最后一个选定字符的索引var finish = txtarea.selectionEnd; //获取所有Text var allText = txtarea.value; edits.push(allText); if(edits.length> maxHistorySize)edits.shift(); //获取所选文本var sel = Array(finish  -  start + 1).join(*); //追加文字; var newText = allText.substring(0,start)+ sel + allText.substring(finish,allText.length); txtarea.value = newText; $('#newpost')。offset({top:0,left:0})。hide();} function closePopUp(){$('#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;} ); const getCursorXY =(input,selectionPoint,offset)=> {const {offsetLeft:inputX,offsetTop:inputY,} = input //创建一个虚拟元素,它将是我们输入的克隆const div = document.createElement('div')//获取输入和克隆的计算样式它在虚拟元素const copyStyle = getComputedStyle(input)for(const prop of copyStyle){div.style [prop] = copyStyle [prop]} //我们需要一个在填充虚拟元素时替换空格的字符//如果这是一行< input /> const swap ='。'const inputValue = input.tagName ==='INPUT'? input.value.replace(/ / g,swap):input.value //将div内容设置为textarea的内容,直到选择const textContent = inputValue.substr(0,selectionPoint)//设置虚拟内容的文本内容element div div.textContent = textContent if(input.tagName ==='TEXTAREA')div.style.height ='auto'//如果单行输入则div必须是单行而不是像文本那样突破area if(input.tagName ==='INPUT')div.style.width ='auto'//创建一个标记元素以获取插入符号位置const span = document.createElement('span')//为span提供textContent剩余内容,以便重新创建的虚拟元素//尽可能接近span.textContent = inputValue.substr(selectionPoint)|| '。'//将span标记附加到div div.appendChild(span)//将虚拟元素附加到body document.body.appendChild(div)//获取标记位置,这是顶部和左侧的插入位置相对于输入const {offsetLeft:spanX,offsetTop:spanY} = span //最后,删除该虚拟元素// NOTE ::如果要查看该跨度呈现的位置,可以将其注释用于调试目的。 removeChild(div)//返回一个包含插入符号x和y的对象。考虑输入定位//这样你就不需要包装输入返回{left:inputX + spanX,top:inputY + spanY + offset,}}  

< pre class =snippet-code-css lang-css prettyprint-override> #mytextarea {width:600px;身高:200px;溢出:隐藏;位置:固定} #newpost {position:absolute;背景色:#ffffdc; border:1px solid #DCDCDC;边界半径:10px的;填充右:5像素;宽度:自动;身高:30px;} #newpost span {cursor:pointer;位置:绝对;顶部:0;右:5px; font-size:22px;} #newpost div {color:#0000ff;填充:10px的;保证金权:10px的;宽度:自动; cursor:pointer;}

 < script src =https ://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js>< /脚本>< HTML> < HEAD> < /头> <身体GT; < textArea id =mytextarea>< / textArea> < div id =newpost> < span onclick =closePopUp();>&#735;< / span> < div onclick =getSel()>< / div> < / div>< / body>< / html>  


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,later I select another word and replaced with stars. But when did Ctrl+Z it is only working for latest selected word and not working for previous words.

JavaScript:

   var selection = {};

function undo(e) {
    var evtobj = window.event? window.event : e;
    if (evtobj.keyCode == 90 && evtobj.ctrlKey && selection.text) {
        evtobj.preventDefault();
        var txtarea = document.getElementById("mytextarea");
        var allText = txtarea.value;
        var newText = allText.substring(0, selection.start) + selection.text + allText.substring(selection.finish, allText.length);
        txtarea.value = newText;
    }
}

function getSel() {
    // obtain the object reference for the textarea>
    var txtarea = document.getElementById("mytextarea");
    // obtain the index of the first selected character
    var start = txtarea.selectionStart;
    // obtain the index of the last selected character
    var finish = txtarea.selectionEnd;
    //obtain all Text
    var allText = txtarea.value;

    selection.text = allText.substring(start, finish);
    selection.start = start;
    selection.finish = finish;

    // obtain the selected text
    var 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();
}
function closePopUp() {
    $('#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('replace with stars');
    }).on('input', () => selection.text = null);
    document.onkeydown = undo;

});

var getCursorXY = function getCursorXY(input, selectionPoint, offset) {
    var inputX = input.offsetLeft,
        inputY = input.offsetTop;
    // create a dummy element that will be a clone of our input

    var div = document.createElement('div');
    // get the computed style of the input and clone it onto the dummy element
    var copyStyle = getComputedStyle(input);
    var _iteratorNormalCompletion = true;
    var _didIteratorError = false;
    var _iteratorError = undefined;

    try {
        for (var _iterator = copyStyle[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done) ; _iteratorNormalCompletion = true) {
            var prop = _step.value;

            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/>
    } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
    } finally {
        try {
            if (!_iteratorNormalCompletion && _iterator.return) {
                _iterator.return();
            }
        } finally {
            if (_didIteratorError) {
                throw _iteratorError;
            }
        }
    }

    var swap = '.';
    var inputValue = input.tagName === 'INPUT' ? input.value.replace(/ /g, swap) : input.value;
    // set the div content to that of the textarea up until selection
    var 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 area
    if (input.tagName === 'INPUT') div.style.width = 'auto';
    // create a marker element to obtain caret position
    var 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 body
    document.body.appendChild(div);
    // get the marker position, this is the caret position top and left relative to the input
    var spanX = span.offsetLeft,
        spanY = span.offsetTop;
    // lastly, remove that dummy element
    // NOTE:: can comment this out for debugging purposes if you want to see where that span is rendered

    document.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 input
    return {
        left: inputX + spanX,
        top: inputY + spanY + offset
    };
};

Here is my Plunker.

解决方案

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;

function undo(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;
          }
      }
}

function getSel() {
    // obtain the object reference for the textarea>
    var txtarea = document.getElementById("mytextarea");
    // obtain the index of the first selected character
    var start = txtarea.selectionStart;
    // obtain the index of the last selected character
    var finish = txtarea.selectionEnd;
    //obtain all Text
    var allText = txtarea.value;
    
    edits.push(allText);
    if (edits.length > maxHistorySize) edits.shift();

    // obtain the selected text
    var 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();
}
function closePopUp() {
    $('#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;
});

const getCursorXY = (input, selectionPoint, offset) => {
  const {
    offsetLeft: inputX,
    offsetTop: inputY,
  } = input
  // create a dummy element that will be a clone of our input
  const div = document.createElement('div')
  // get the computed style of the input and clone it onto the dummy element
  const 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 selection
  const 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 area
  if (input.tagName === 'INPUT') div.style.width = 'auto'
  // create a marker element to obtain caret position
  const 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 body
  document.body.appendChild(div)
  // get the marker position, this is the caret position top and left relative to the input
  const { 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 rendered
  document.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 input
  return {
    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;
}
#newpost span {
    cursor:pointer;
    position: absolute;
    top: 0;
    right: 5px;
    font-size: 22px;
}
#newpost div {
    color:#0000ff;
    padding:10px;
    margin-right:10px;
    width: auto;
    cursor:pointer;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
  <head>
  </head>
 <body>
    <textArea id="mytextarea"></textArea>
    <div id="newpost">
        <span onclick="closePopUp();">&#735;</span>
        <div onclick="getSel()"></div>
    </div>
</body>

</html>

这篇关于撤消仅适用于首次替换的文本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆