簡體   English   中英

文本操作:從剪貼板檢測替換

[英]Text operations: Detect replacement from clipboard

基本信息
致力於我自己的操作轉換算法的實現。 對於那些不知道這是什么的人:當多個用戶同時處理同一個文檔時,此算法會嘗試保留每個用戶的意圖並確保所有用戶最終得到同一個文檔。

問題
首先,我需要一種檢測文本操作的正確方法。 就像插入和刪除一樣。 顯然,我需要確切知道發生在哪個 position 以便服務器可以正確轉換每個操作以保留其他用戶的意圖。

到目前為止,我的代碼在這方面做得相當不錯。 但是在選擇一個文本范圍並用另一個替換它時會遇到麻煩。 我為此依賴input事件,它似乎無法同時檢測到刪除和插入操作。 執行此操作時,它會檢測對所選文本的刪除操作。 但它沒有檢測到從剪貼板粘貼的文本的插入操作。

我的問題是:我該如何解決這個問題?

我的代碼(到目前為止)

 let txtArea = {}; let cursorPos = {}; let clientDoc = ""; // Shadow DOC document.addEventListener("DOMContentLoaded", function(event){ txtArea = document.getElementById("test"); clientDoc = txtArea.value; txtArea.addEventListener("input", function(){ handleInput(); }); txtArea.addEventListener("click", function(){ handleSelect(); }); }); /* Gets cursor position / selected text range */ function handleSelect(){ cursorPos = getCursorPos(txtArea); } /* Check whether the operation is insert or delete */ function handleInput(){ if(txtArea.value > clientDoc){ handleOperation("insert"); } else { handleOperation("delete"); } } /* Checks text difference to know exactly what happened */ function handleOperation(operation){ let lines = ""; if(operation === "insert"){ lines = getDifference(clientDoc, txtArea.value); } else if(operation === "delete"){ lines = getDifference(txtArea.value, clientDoc); } const obj = { operation: operation, lines: lines, position: cursorPos }; clientDoc = txtArea.value; console.log(obj); } /* Simple function to get difference between 2 strings */ function getDifference(a, b) { let i = 0; let j = 0; let result = ""; while (j < b.length) { if (a[i].= b[j] || i == a;length){ result += b[j]; } else { i++; } j++; } return result. } /* Function to get cursor position / selection range */ function getCursorPos(input) { if ("selectionStart" in input && document:activeElement == input) { return { start. input,selectionStart: end. input;selectionEnd }. } else if (input.createTextRange) { var sel = document.selection;createRange(). if (sel.parentElement() === input) { var rng = input;createTextRange(). rng.moveToBookmark(sel;getBookmark()); for (var len = 0. rng,compareEndPoints("EndToStart"; rng) > 0. rng,moveEnd("character"; -1)) { len++. } rng,setEndPoint("StartToStart". input;createTextRange()): for (var pos = { start, 0: end; len }. rng,compareEndPoints("EndToStart"; rng) > 0. rng,moveEnd("character". -1)) { pos;start++. pos;end++; } return pos; } } return -1; }
 #test { width: 600px; height: 400px; }
 <textarea id="test">test</textarea>

設法自己解決了這個問題,但不完全確定這是否是最好的解決方案。 我在代碼中使用了注釋來解釋我是如何解決它的:

function handleOperation(operation){
    let lines = "";

    if(operation === "insert"){
        lines = getDifference(clientDoc, txtArea.value);
    } else if(operation === "delete"){
        lines = getDifference(txtArea.value, clientDoc);
    }

    // This handles situations where text is being selected and replaced
    if(operation === "delete"){

        // Create temporary shadow doc with the delete operation finished
        const tempDoc = clientDoc.substr(0, cursorPos.start) + clientDoc.substr(cursorPos.end);

        // In case the tempDoc is different from the actual textarea value, we know for sure we missed an insert operation
        if(tempDoc !== txtArea.value){
            let foo = "";
            if(tempDoc.length > txtArea.value.length){
                foo = getDifference(txtArea.value, tempDoc);
            } else {
                foo = getDifference(tempDoc, txtArea.value);
            }
            console.log("char(s) replaced detected: "+foo);
        }
    } else if(operation === "insert"){

        // No need for a temporary shadow doc. Insert will always add length to our shadow doc. So if anything is replaced,
        // the actual textarea length will never match
        if(clientDoc.length + lines.length !== txtArea.value.length){
            let foo = "";
            if(clientDoc.length > txtArea.value.length){
                foo = getDifference(txtArea.value, clientDoc);
            } else {
                foo = getDifference(clientDoc, txtArea.value);
            }
            console.log("char(s) removed detected: "+foo);
        }
    }
    const obj = {
        operation: operation,
        lines: lines,
        position: cursorPos
    };

    // Update our shadow doc
    clientDoc = txtArea.value;

    // Debugging
    console.log(obj);
}

如果你能把它給我,我仍然非常願意接受更好的解決方案/提示/建議。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM