Grabbing Edits from two strings

后端 未结 4 1658
死守一世寂寞
死守一世寂寞 2021-01-18 08:48

I\'m going to go a bit in-depth with my problem, you can jump to the TL;DR if you don\'t want to read all of this

What I\'m trying to do

I

4条回答
  •  悲哀的现实
    2021-01-18 09:17

    Edit: Added modified script that can handle more than one text area.

    Here is the JSFiddle for a page with more than one editable text area. (Don't forget to open dev tools to see the edits.) You just need to assign each textarea a unique id. Then, create a map using those id's as keys and each textarea's edits array as the values. Here is the updated script:

    'use strict';
    
    function Edit(type, position, text) {
      this.type = type;
      this.position = position;
      this.text = text;
    }
    
    var ADD = 'add';
    var DELETE = 'delete';
    
    var textAreaEditsMap = {};
    
    var cursorStart = -1;
    var cursorEnd = -1;
    var currentEdit = null;
    var deleteOffset = 1;
    
    window.addEventListener('load', function() {
      var textareas = document.getElementsByClassName('text-editable');
    
      for (var i = 0; i < textareas.length; ++i) {
        var textarea = textareas.item(i);
        var id = textarea.getAttribute('id');
    
        textAreaEditsMap[id] = [];
        textarea.addEventListener('mouseup', handleMouseUp);
        textarea.addEventListener('keydown', handleKeyDown);
        textarea.addEventListener('keypress', handleKeyPress);
      }
    });
    
    function handleMouseUp(event) {
      cursorStart = this.selectionStart;
      cursorEnd = this.selectionEnd;
      currentEdit = null;
    }
    
    function handleKeyDown(event) {
    
      cursorStart = this.selectionStart;
      cursorEnd = this.selectionEnd;
    
      if (event.keyCode >= 35 && event.keyCode <= 40) { // detect cursor movement keys
        currentEdit = null;
      }
    
      // deleting text
      if (event.keyCode === 8 || event.keyCode === 46) {
        if (currentEdit != null && currentEdit.type !== 'delete') {
          currentEdit = null;
        }
    
        if (cursorStart !== cursorEnd) { // Deleting highlighted text
          var edit = new Edit(DELETE, cursorStart, this.innerHTML.substring(cursorStart, cursorEnd));
          textAreaEditsMap[this.getAttribute('id')].push(edit);
          currentEdit = null;
    
        } else if (event.keyCode === 8) { // backspace
          if (currentEdit == null) {
            deleteOffset = 1;
            var edit = new Edit(DELETE, cursorStart, this.innerHTML[cursorStart - 1]);
            textAreaEditsMap[this.getAttribute('id')].push(edit);
            currentEdit = edit;
          } else {
            ++deleteOffset;
            currentEdit.text = this.innerHTML[cursorStart - 1] + currentEdit.text;
          }
    
        } else if (event.keyCode === 46) { // delete
          if (currentEdit == null) {
            deleteOffset = 1;
            var edit = new Edit(DELETE, cursorStart, this.innerHTML[cursorStart]);
            textAreaEditsMap[this.getAttribute('id')].push(edit);
            currentEdit = edit;
    
          } else {
            currentEdit.text += this.innerHTML[cursorStart + deleteOffset++];
          }
        }
      }
    
      console.log(textAreaEditsMap)
    }
    
    function handleKeyPress(event) {
    
      if (currentEdit != null && currentEdit.type !== 'add') {
        currentEdit = null;
      }
    
      if (currentEdit == null) {
        currentEdit = new Edit(ADD, cursorStart, String.fromCharCode(event.charCode));
        textAreaEditsMap[this.getAttribute('id')].push(currentEdit);
      } else {
        currentEdit.text += String.fromCharCode(event.charCode);
      }
    
      console.log(textAreaEditsMap);
    }
    

    Original post with original script that only handles one textarea follows:

    I made an example script that does what you need. I put a working example on JSFiddle. Make sure you press ctrl+shift+J on the JSFiddle example page to open dev tools so you can see the array of edits logged as edits are made. Edits are added to the edits array in chronological order, so you can revert back to the original text by applying the inverse (i.e., add deleted text back; remove added text) in reverse chronological order (i.e., iterate the array backwards). I did not handle copying, pasting, undoing, or redoing from the context menu or through key bindings, but I think that you should be able to use this example as a guide to take care of those things. Here is the script:

    'use strict';
    
    function Edit(type, position, text) {
      this.type = type;
      this.position = position;
      this.text = text;
    }
    
    window.addEventListener('load', function() {
      var ADD = 'add';
      var DELETE = 'delete';
    
      var cursorStart = -1;
      var cursorEnd = -1;
      var edits = [];
      var currentEdit = null;
      var deleteOffset = 1;
    
      var textarea = document.getElementById('saved-text');
    
      textarea.addEventListener('mouseup', function(event) {
        cursorStart = this.selectionStart;
        cursorEnd = this.selectionEnd;
        currentEdit = null;
      });
    
      textarea.addEventListener('keydown', function(event) {
    
        cursorStart = this.selectionStart;
        cursorEnd = this.selectionEnd;
    
        if(event.keyCode >= 35 && event.keyCode <= 40) { // detect cursor movement keys
          currentEdit = null;
        }
    
        // deleting text
        if(event.keyCode === 8 || event.keyCode === 46) {
          if(currentEdit != null && currentEdit.type !== 'delete') {
            currentEdit = null;
          }
    
          if(cursorStart !== cursorEnd) {
            var edit = new Edit(DELETE, cursorStart, textarea.innerHTML.substring(cursorStart, cursorEnd));
            edits.push(edit);
            currentEdit = null;
    
          } else if (event.keyCode === 8) { // backspace
            if (currentEdit == null) {
              deleteOffset = 1;
              var edit = new Edit(DELETE, cursorStart, textarea.innerHTML[cursorStart - 1]);
              edits.push(edit);
              currentEdit = edit;
            } else {
              ++deleteOffset;
              currentEdit.text = textarea.innerHTML[cursorStart - 1] + currentEdit.text;
            }
    
          } else if (event.keyCode === 46) { // delete
            if(currentEdit == null) {
              deleteOffset = 1;
              var edit = new Edit(DELETE, cursorStart, textarea.innerHTML[cursorStart]);
              edits.push(edit);
              currentEdit = edit;
    
            } else {
              currentEdit.text += textarea.innerHTML[cursorStart + deleteOffset++];
            }
          }
        }
    
        console.log(edits)
      });
    
      textarea.addEventListener('keypress', function(event) {
    
        if(currentEdit != null && currentEdit.type !== 'add') {
          currentEdit = null;
        }
    
        // adding text
        if(currentEdit == null) {
          currentEdit = new Edit(ADD, cursorStart, String.fromCharCode(event.charCode));
          edits.push(currentEdit);
        } else {
          currentEdit.text += String.fromCharCode(event.charCode);
        }
    
        console.log(edits);
      });
    
    });
    

提交回复
热议问题