Как веб-приложение может обнаружить событие вставки и извлечь данные для вставки?
Я хотел бы удалить содержимое HTML, прежде чем текст будет вставлен в текстовый редактор.
Очистка текста после последующей вставки работает, но проблема в том, что все предыдущее форматирование потеряно. Например, я могу написать предложение в редакторе и сделать его жирным, но когда я вставляю новый текст, все форматирование теряется. Я хочу очистить только вставленный текст и оставить любое предыдущее форматирование без изменений.
В идеале решение должно работать во всех современных браузерах (например, MSIE, Gecko, Chrome и Safari).
Обратите внимание, что MSIE имеет clipboardData.getData()
, но я не мог найти аналогичные функции для других браузеров.
event.clipboardData.getData('Text')
работал для меня.document.addEventListener('paste'...
работал для меня, но вызывал конфликты, если пользователь хотел иметь возможность вставлять в другом месте на странице. Затем я попыталсяmyCanvasElement.addEventListener('paste'...
, но это не сработало. В конце концов я разобрался,myCanvasElement.parentElement.addEventListener('paste'...
работал.Ответы:
С момента написания этого ответа ситуация изменилась: теперь, когда Firefox добавил поддержку в версии 22, все основные браузеры теперь поддерживают доступ к данным буфера обмена в событии вставки. Посмотрите ответ Нико Бернса для примера.
В прошлом это не было возможно вообще кросс-браузерным способом. Идеально было бы иметь возможность получать вставленный контент через
paste
событие, что возможно в недавних браузерах, но не в некоторых старых браузерах (в частности, Firefox <22).Когда вам нужно поддерживать более старые браузеры, то, что вы можете сделать, довольно сложно, и что-то вроде хака, который будет работать в браузерах Firefox 2+, IE 5.5+ и WebKit, таких как Safari или Chrome. Последние версии TinyMCE и CKEditor используют эту технику:
designMode
выключите и вызовитеfocus()
текстовое поле, перемещая каретку и эффективно перенаправляя вставку.designMode
снова включает , восстанавливает выбор пользователя и вставляет текст в.Обратите внимание, что это будет работать только для событий вставки с клавиатуры, но не для вставки из контекстного меню или меню редактирования. К тому времени, когда происходит событие вставки, уже слишком поздно перенаправлять курсор в текстовую область (по крайней мере, в некоторых браузерах).
В маловероятном случае, когда вам потребуется поддержка Firefox 2, обратите внимание, что вам нужно поместить текстовую область в родительский документ, а не документ iframe редактора WYSIWYG в этом браузере.
источник
designMode
это логическое свойствоdocument
и делает всю страницу редактируемой, когдаtrue
. Редакторы WYSIWYG обычно используют iframe сdesignMode
on в качестве редактируемой панели. Сохранение и восстановление выбора пользователя выполняется одним способом в IE, а другим - в других браузерах, как и вставка содержимого в редактор. Вам нужно получитьTextRange
в IE иRange
в других браузерах.paste
событие, но к тому времени уже слишком поздно, чтобы перенаправить вставку в другой элемент, так что этот хак не будет работать. В большинстве редакторов запасной вариант заключается в отображении диалогового окна, в которое пользователь может вставить данные.paste
событии, однако он позволит вам очистить содержимое элемента (и сохранить его в переменной, чтобы вы могли восстановить его позже). Если этот контейнер являетсяdiv
(он, вероятно,iframe
тоже работает), то вы можете циклически перемещать вставленный контент, используя обычные методы dom, или получить его в виде строки, используяinnerHTML
. Затем вы можете восстановить предыдущее содержимоеdiv
и вставить любое содержимое. О, и вы должны использовать тот же взлом таймера, что и выше. Я удивлен, что TinyMCE не делает этого ...Решение № 1 (только обычный текст, требуется Firefox 22+)
Работает для IE6 +, FF 22+, Chrome, Safari, Edge (протестировано только в IE9 +, но должно работать для более низких версий)
Если вам нужна поддержка для вставки HTML или Firefox <= 22, см. Решение № 2.
HTML
JavaScript
JSFiddle: https://jsfiddle.net/swL8ftLs/12/
Обратите внимание, что это решение использует параметр «Текст» для
getData
функции, который является нестандартным. Тем не менее, он работает во всех браузерах на момент написания.Решение № 2 (HTML и работает для Firefox <= 22)
Протестировано в IE6 +, FF 3.5+, Chrome, Safari, Edge
HTML
JavaScript
JSFiddle: https://jsfiddle.net/nicoburns/wrqmuabo/23/
объяснение
onpaste
Событиеdiv
имеетhandlePaste
функцию , прикрепленную к нему и передается один аргумент:event
объект для события вставки. Особый интерес для нас представляетclipboardData
свойство этого события, которое обеспечивает доступ к буферу обмена в не-браузерах. В IE аналогичныйwindow.clipboardData
, хотя у него немного другой API.Смотрите раздел ресурсов ниже.
handlepaste
Функция:Эта функция имеет две ветви.
Первый проверяет наличие
event.clipboardData
и проверяет,types
содержит ли его свойство 'text / html' (этоtypes
может быть либоDOMStringList
проверяемый с помощьюcontains
метода, либо строка, проверяемая с помощью этогоindexOf
метода). Если все эти условия выполнены, то мы поступаем так же, как в решении № 1, за исключением «text / html» вместо «text / plain». В настоящее время это работает в Chrome и Firefox 22+.Если этот метод не поддерживается (все остальные браузеры), то мы
DocumentFragment
waitForPastedData
функциюwaitforpastedata
Функция:Эта функция сначала запрашивает вставленные данные (один раз в 20 мс), что необходимо, поскольку они не отображаются сразу. Когда появились данные это:
processpaste
Функция:Делает произвольные вещи с вставленными данными. В этом случае мы просто оповещаем данные, вы можете делать все что угодно. Возможно, вы захотите запустить вставленные данные через какой-то процесс очистки данных.
Сохранение и восстановление позиции курсора
В реальной ситуации вы, вероятно, захотите сохранить выделение раньше, а затем восстановить его ( установите позицию курсора на contentEditable <div> ). Затем вы можете вставить вставленные данные в положение, в котором находился курсор, когда пользователь инициировал действие вставки.
Ресурсы:
Спасибо Тиму Дауну за предложение использовать DocumentFragment и облегчить обнаружение ошибки в Firefox из-за использования DOMStringList вместо строки для clipboardData.types
источник
DocumentFragment
скорее, чем использоватьinnerHTML
по нескольким причинам: во-первых, вы сохраните любые существующие обработчики событий; во-вторых, сохранение и восстановлениеinnerHTML
не гарантируют создание идентичной копии предыдущего DOM; в-третьих, вы можете затем сохранить выделение,Range
вместо того, чтобы возиться с добавлением элементов маркера или вычислением смещения текста (что вы должны были бы сделать, если бы использовалиinnerHTML
).DocumentFragment
боли в IE? Это то же самое, что и в других браузерах, если только вы не используете Range и неextractContents()
делаете этого, что в любом случае не более кратко, чем альтернатива. Я реализовал пример вашей техники, используя Rangy, чтобы все было хорошо и единообразно в разных браузерах: jsfiddle.net/bQeWC/4 .waitforpastedata
функцииtext/html
с использованием W3C Clipboard API. В прошлом такая попытка была бы исключением. Так что больше не нужен этот обходной путь / хак для Edge.Простая версия:
С помощью
clipboardData
Демо: http://jsbin.com/nozifexasu/edit?js,output
Edge, Firefox, Chrome, Safari, Opera протестированы.
⚠ Document.execCommand () устарел .
Примечание: не забудьте проверить ввод / вывод также на стороне сервера (например, PHP-теги strip )
источник
window.clipboardData.getData('Text');
e.preventDefault(); if (e.clipboardData) { content = (e.originalEvent || e).clipboardData.getData('text/plain'); document.execCommand('insertText', false, content); } else if (window.clipboardData) { content = window.clipboardData.getData('Text'); document.selection.createRange().pasteHTML(content); }
Live Demo
Проверено на Chrome / FF / IE11
Существует раздражение Chrome / IE, которое заключается в том, что эти браузеры добавляют
<div>
элемент для каждой новой строки. Существует пост об этом здесь и она может быть исправлена путем установки contenteditable элемента , чтобы бытьdisplay:inline-block
Выберите выделенный HTML-код и вставьте его здесь:
источник
Я написал небольшое доказательство концепции для предложения Тима Даунса здесь с текстовой областью за пределами экрана. И здесь идет код:
Просто скопируйте и вставьте весь код в один HTML-файл и попробуйте вставить (используя Ctrl-V) текст из буфера обмена в любом месте документа.
Я протестировал его в IE9 и новых версиях Firefox, Chrome и Opera. Работает довольно хорошо. Также хорошо, что можно использовать любую комбинацию клавиш, которую он предпочитает, чтобы активировать эту функцию. Конечно, не забудьте включить исходники jQuery.
Не стесняйтесь использовать этот код, и если у вас появятся какие-либо улучшения или проблемы, пожалуйста, отправьте их обратно. Также обратите внимание, что я не являюсь разработчиком Javascript, поэтому, возможно, я что-то пропустил (=> сделайте свое собственное тестирование).
источник
На основе l2aelba anwser. Это было проверено на FF, Safari, Chrome, IE (8,9,10 и 11)
источник
Этот не использует setTimeout ().
Я использовал эту замечательную статью для достижения кросс-браузерной поддержки.
Этот код дополнен дескриптором выбора перед вставкой: demo
источник
Для очистки вставленного текста и замены текущего выделенного текста вставленным текстом это довольно тривиально:
JS:
источник
Это должно работать во всех браузерах, которые поддерживают событие onpaste и наблюдателя мутаций.
Это решение выходит за рамки получения только текста, фактически позволяет редактировать вставленный контент до его вставки в элемент.
Он работает с использованием contenteditable, события onpaste (поддерживается всеми основными браузерами) и наблюдателей мутаций (поддерживается Chrome, Firefox и IE11 +)
шаг 1
Создать HTML-элемент с contenteditable
шаг 2
В вашем коде Javascript добавьте следующее событие
Нам нужно связать pasteCallBack, поскольку наблюдатель мутации будет вызываться асинхронно.
шаг 3
Добавьте следующую функцию в ваш код
Что делает код:
пример
Показать фрагмент кода
Большое спасибо Тиму Дауну. Смотрите этот пост для ответа:
Получить вставленный контент в документе при вставке события
источник
Решение, которое работает для меня, - добавление прослушивателя события для вставки события, если вы вставляете текстовый ввод. Так как событие вставки происходит до изменения текста во входных данных, внутри моего обработчика при вставке я создаю отложенную функцию, внутри которой я проверяю изменения в поле ввода, которые произошли при вставке:
источник
Это было слишком долго для комментария к ответу Нико, который, я думаю, больше не работает в Firefox (согласно комментариям), и не работал для меня в Safari как есть.
Во-первых, теперь вы можете читать прямо из буфера обмена. Вместо того чтобы код вроде:
использовать:
потому что Firefox имеет
types
поле, котороеDOMStringList
не реализуетсяtest
.Следующий Firefox не разрешит вставку, если фокус не находится в
contenteditable=true
поле.Наконец, Firefox не позволит надежно вставлять, если фокус находится не на
textarea
(или, возможно, на входе), который не только,contenteditable=true
но и:display:none
visibility:hidden
Я пытался скрыть текстовое поле, чтобы я мог заставить вставку работать через эмулятор JS VNC (то есть он собирался на удаленном клиенте, и на самом деле
textarea
вставлять в него некуда ). Я обнаружил, что попытка скрыть текстовое поле в приведенном выше примере приводила к появлению симптомов, при которых оно иногда срабатывало, но, как правило, не удавалось при второй вставке (или когда поле очищалось, чтобы предотвратить вставку одних и тех же данных дважды), поскольку поле теряло фокус и не восстанавливалось должным образом это несмотря наfocus()
. Решение, которое я придумал, состояло в том, чтобы поставить егоz-order: -1000
, сделать егоdisplay:none
, сделать его размером 1 на 1 пиксель и установить все цвета на прозрачные. Тьфу.На Safari к вам относится вторая часть вышеперечисленного, т.е. вам нужно иметь то,
textarea
чего нетdisplay:none
.источник
Первое, что приходит на ум, - это программа-обработчик закрывающей библиотеки Google http://closure-library.googlecode.com/svn/trunk/closure/goog/demos/pastehandler.html.
источник
Простое решение:
источник
Это сработало для меня:
источник
источник
Вы можете сделать это следующим образом:
используйте этот плагин jQuery для событий до и после вставки:
Теперь вы можете использовать этот плагин ;:
Explaination
Сначала установите uid для всех существующих элементов в качестве атрибута данных.
Затем сравните все узлы события POST PASTE. Таким образом, сравнивая, вы можете идентифицировать только что вставленный, потому что у них будет uid, а затем просто удалить атрибут style / class / id из вновь созданных элементов, чтобы вы могли сохранить старое форматирование.
источник
источник
Просто позвольте браузеру вставлять как обычно в его редактируемый div содержимого, а затем после вставки поменяйте местами любые элементы span, используемые для пользовательских стилей текста, с самим текстом. Кажется, это работает нормально в Internet Explorer и других браузерах, которые я пробовал ...
Это решение предполагает, что вы работаете с jQuery, и вам не нужно форматировать текст в любом редактируемом элементе содержимого .
Плюс в том, что это супер просто.
источник
span
тег? Я думаю, что вопрос был обо всех тегах.Это решение заменяет HTML-тег, оно простое и кросс-браузерное; проверьте этот jsfiddle: http://jsfiddle.net/tomwan/cbp1u2cx/1/ , основной код:
обратите внимание: вы должны сделать некоторую работу с фильтром xss на обратной стороне, потому что это решение не может фильтровать строки вроде '<< >>'
источник
Это существующий код, опубликованный выше, но я обновил его для IE, ошибка заключалась в том, что при выделении и вставке существующего текста выбранный контент не удалялся. Это было исправлено с помощью кода ниже
Смотрите полный код ниже
источник