Как сделать вставку в виде обычного текста в области contentEditable, не прерывая отмену? - PullRequest
10 голосов
/ 23 февраля 2011

Странно конкретный вопрос, но у меня уже есть решение вставить простой текст в <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'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());
    });
});

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

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

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

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

Есть ли способ сделать #clipboard не отменяемым или какие-либо другие предложения о том, как заставить это работать?

Редактировать

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

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

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

Ответы [ 4 ]

1 голос
/ 01 июля 2011

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

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

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

0 голосов
/ 11 августа 2012

В пасте:

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

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

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

  4. В функции времени ожидания извлеките данные из скрытой текстовой области, затем:

    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, вы окажетесь в мире боли ...

0 голосов
/ 12 июля 2011

Вы пробуете это?

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;
});

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

0 голосов
/ 16 марта 2011

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

...