Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/447.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript “撤消”仅适用于第一个替换的文本?_Javascript_Jquery_Css - Fatal编程技术网

Javascript “撤消”仅适用于第一个替换的文本?

Javascript “撤消”仅适用于第一个替换的文本?,javascript,jquery,css,Javascript,Jquery,Css,在这里,我使用Ctrl+Z撤销替换的文本,我有一个场景,在文本区域中,我有一个包含多个单词的句子,我选择第一个单词并替换为星形,然后选择另一个单词并替换为星形。但当Ctrl+Z组合键执行时,它只对最近选定的单词起作用,而对以前的单词不起作用 JavaScript: var selection = {}; function undo(e) { var evtobj = window.event? window.event : e; if (evtobj.keyCode ==

在这里,我使用Ctrl+Z撤销替换的文本,我有一个场景,在文本区域中,我有一个包含多个单词的句子,我选择第一个单词并替换为星形,然后选择另一个单词并替换为星形。但当Ctrl+Z组合键执行时,它只对最近选定的单词起作用,而对以前的单词不起作用

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
    };
};
var选择={};
函数撤消(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;
//获取所有文本
var allText=txtarea.value;
selection.text=allText.substring(开始、结束);
selection.start=开始;
selection.finish=完成;
//获取所选文本
var sel=allText.substring(开始、结束);
sel=sel.replace(//[\S]/g,“*”);//追加文本;
var newText=allText.substring(0,开始)+sel+allText.substring(结束,allText.length);
txtarea.value=newText;
$('#newpost').offset({top:0,left:0}).hide();
}
函数closePopUp(){
$('#newpost').offset({top:0,left:0}).hide();
}
$(文档).ready(函数(){
closePopUp();
var newpost=$(“#newpost”);
$('#mytextarea')。在('select',函数(e)上{
var txtarea=document.getElementById(“mytextarea”);
var start=txtarea.selectionStart;
var finish=txtarea.selectionEnd;
offset(getCursorXY(txtarea,start,20)).show();
newpost.find('div').text('replace with stars');
}).on('input',()=>selection.text=null);
document.onkeydown=undo;
});
var getCursorXY=函数getCursorXY(输入、选择点、偏移){
var inputX=input.offsetLeft,
inputY=input.offsetTop;
//创建一个虚拟元素,它将是我们输入的克隆
var div=document.createElement('div');
//获取输入的计算样式,并将其克隆到虚拟元素上
var copyStyle=getComputedStyle(输入);
var\u iteratorNormalCompletion=true;
var _diditorerror=false;
var _iteratorError=未定义;
试一试{
对于(var _iterator=copyStyle[Symbol.iterator](),_step;!(_iteratorNormalCompletion=(_step=_iterator.next()).done);_iteratorNormalCompletion=true){
var prop=_step.value;
div.style[prop]=复制样式[prop];
}
//在填充虚拟元素时,我们需要一个字符来替换空白
//如果是单行线
}捕捉(错误){
_didIteratorError=true;
_迭代器错误=错误;
}最后{
试一试{
if(!\u iteratorNormalCompletion&&u iterator.return){
_return();
}
}最后{
如果(_diditorerror){
抛出迭代错误;
}
}
}
风险值互换=';
var inputValue=input.tagName=='input'?input.value.replace(//g,swap):input.value;
//将div内容设置为文本区域的内容,直到选择为止
var textContent=inputValue.substr(0,selectionPoint);
//设置虚拟元素div的文本内容
div.textContent=textContent;
如果(input.tagName=='TEXTAREA')div.style.height='auto';
//如果是单行输入,则div需要是单行,而不是像文本区域那样断开
如果(input.tagName=='input')div.style.width='auto';
//创建标记元素以获取插入符号位置
var span=document.createElement('span');
//为跨度指定剩余内容的textContent,以便重新创建的虚拟元素
//越近越好
span.textContent=inputValue.substr(selectionPoint)| |';
//将跨度标记附加到div
子类(span);
//将虚拟元素附加到主体
文件.正文.附件(div);
//获取标记位置,这是相对于输入的顶部和左侧插入符号位置
var spanX=span.offsetLeft,
spanY=span.offsetTop;
//最后,删除该虚拟元素
//注意::如果您想查看呈现跨度的位置,可以出于调试目的对此进行注释
文件.正文.删除文件(div);
//返回带有插入符号x和y的对象。输入定位的帐户
//这样就不需要包装输入
返回{
左:inputX+spanX,
顶部:输入+跨距+偏移
};
};

这是我的。

您需要将逻辑从使用单个
选择
对象更改为使用
选择
对象数组,如下所示:

  • 初始化为
    选择
    而不是
    选择

    var selections = [];
    
  • 调用
    getSel()
    时,确保更新到
    push
    到数组:

    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;
    
        selections.push({
          start: start,
          finish: finish,
          text: allText.substring(start, 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();
    }
    
  • 因此,我们需要更新
    undo
    函数,如下所示:

    function undo(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;
            }
        }
    }
    
  • 最后,从
    $(“#mytextarea”)
    中删除('input')事件侦听器上的
    ,因为我认为不需要它


  • 以下是您必须手动控制所有
    文本区域的更改

    在这里,我创建了
    edits
    数组,该数组每隔几秒钟填充
    textarea
    text on change(您可以使用
    saveInterval
    变量控制它)。 您还可以使用
    maxHistorySi设置此数组的最大长度