Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make a plain text paste in a contentEditable span without breaking undo?

Oddly specific question, but I have a solution already to paste plain text in a <span contentEditable="true"> by using a hidden textarea, which seems to work really well, except that it breaks the browser's undo feature. Right off the bat I'm not worried about a cross-browser solution; I only care about Chrome. My approach looks roughly like this:

$('.editable').live('paste', function()
{
    var $this = $(this);

    //more code here to remember caret position, etc

    $('#clipboard').val('').focus(); //put the focus in the hidden textarea so that, when the paste actually occurs, it's auto-sanitized by the textarea

    setTimeout(function() //then this will be executed immediately after the paste actually occurs
    {
        $this.focus();
        document.execCommand('insertHTML', true, $('#clipboard').val());
    });
});

So this works -- I can paste anything and it's reduced to plain text before going into the my contentEditable field -- but if I try to undo after pasting:

  • First undo undoes the paste.
  • Second undo tries to undo the changes to #clipboard, moving the focus away from my contentEditable.

I've tried everything I can think of to make the browser not try to undo the changes to #clipboard -- toggling display:none when it's not actively in use, toggling readonly and disabled state, destroying it at the end of and recreating it at the beginning of the event above, various other hacks -- but nothing seems to work.

Is this a terrible approach to sanitization? This is the first thing I've managed to really get working -- trying to clean up the markup after the paste occurs didn't work, as there are some things (entire HTML documents) which, when pasted, crash the browser, which I'd like to avoid.

Is there any way to make the #clipboard not undoable, or any other suggestions of how to get this working?

Edit

I managed to improve things a little bit by adding the line

$('#clipboard').val('');

Right after the execCommand line. This seems to neutralize undo completely: the caret no longer leaves the contentEditable field, but nothing gets undone at all. A bit of an improvement, but I'm still searching for a proper solution.

like image 739
Ian Henry Avatar asked Feb 23 '11 03:02

Ian Henry


1 Answers

CodeMirror 1 does this by stripping away formatting after text is pasted. CodeMirror 2 does this by actually having an invisible textarea handle everything, and render the text and cursor manually.

CodeMirror's website describes how it works in more detail: http://codemirror.net/internals.html

Beyond that, there's always the CodeMirror source code. You can decide for yourself whether CodeMirror 1 or CodeMirror 2's approach is more suitable for your purposes. :)

like image 56
Zarel Avatar answered Nov 18 '22 20:11

Zarel