Как я могу сделать обычную вставку текста в contentEditable span без нарушения отмены?

Странно заданный вопрос, но у меня есть решение уже вставить обычный текст в <span contentEditable="true"> с помощью скрытого textarea, который, кажется, работает очень хорошо, за исключением того, что он нарушает функцию отмены браузера. С самого начала я не беспокоюсь о кросс-браузерном решении; Я только забочусь о Chrome. Мой подход выглядит примерно так:

$('.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 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());
    });
});

Итак, это работает - я могу вставить что угодно, и он сводится к простому тексту, прежде чем перейти в мое поле contentEditable, но если я попытаюсь отменить после вставки:

  • Первая отмена отменяет пасту.
  • Вторая отмена отменяет изменения в #clipboard, отводя фокус от моего contentEditable.

Я пробовал все, что мог, чтобы браузер не пытался отменить изменения #clipboard - переключать display:none, когда он не активно используется, переключая readonly и disabled состояние, уничтожая он в конце и воссоздает его в начале события выше, различные другие хаки - но ничего не работает.

Это ужасный подход к дезинфекции? Это первая вещь, с которой мне удалось действительно работать - попытка очистить разметку после того, как вставка не работает, так как есть некоторые вещи (целые HTML-документы), которые при вставке вызывают крах браузера, который Я бы хотел избежать.

Можно ли отключить #clipboard или любые другие предложения о том, как это сделать?

Изменить

Мне удалось немного улучшить ситуацию, добавив строку

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

Сразу после строки execCommand. Это, похоже, полностью нейтрализует отмену: карет больше не выходит из поля contentEditable, но ничего не отменяется вообще. Немного улучшения, но я все еще ищу подходящее решение.

Ответ 1

CodeMirror 1 делает это, удаляя форматирование после вставки текста. CodeMirror 2 делает это, фактически имея невидимый textarea обрабатывать все, и визуализировать текст и курсор вручную.

Сайт CodeMirror описывает, как он работает более подробно: http://codemirror.net/internals.html

Помимо этого всегда есть исходный код CodeMirror. Вы можете сами решить, подходит ли подход CodeMirror 1 или CodeMirror 2 для ваших целей.:)

Ответ 2

Вы пытаетесь это сделать?

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

Я думаю, это может помочь. Но я думаю, вы должны использовать объект события. К сожалению, может возникнуть проблема, связанная с соображениями безопасности.

Ответ 3

В onpaste:

  • Сохраните текущий выбор.

    var sel = window.getSelection();
    var range  = selObj.getRangeAt(0).cloneRange;
    // Store the range object somewhere.
    
  • Измените объект выделения, чтобы указать на скрытую текстовую область.

  • Установите тайм-аут с задержкой 0 (происходит сразу после вставки).

  • В функции тайм-аута возьмите данные из скрытого текстового поля, а затем:

    var sel = window.getSelection();
    sel.removeAllRanges();
    var range = // restore the range object from before.
    sel.addRange(range);
    
    document.execCommand("insertHTML", false, /* contents of your textarea here */);
    

Теперь, если вы хотите сделать это для фактического содержимого HTML, вы попадете в мир боли.

Ответ 4

Вставьте <pre contenteditable="true">...</pre>. Насколько я помню, именно то, что я понимаю, вы хотите. (К сожалению, мне еще не разрешено присоединяться ко всем в комментариях, но я полагаю, что это попытка ответить в любом случае.)