Я хотел бы, чтобы текст вставлялся в редактируемый элемент div, но реагировал как текстовое поле.
Обратите внимание, что я хочу сохранить форматирование, как если бы я вставил его в текстовое поле (из слова, Excel...).
Итак.
1) Вставить текст в contenteditable div
2) Я получаю текст из буфера обмена
3) Я помещаю свое значение из буфера обмена в текстовое поле (не знаю, как??)
4) Получите значение из моего текстового поля и поместите его в мой contenteditable div
Есть предложения?
Вставить как обычный текст Contenteditable div & textarea (word/excel)
Ответы (3)
Я основной разработчик CKEditor, и по стечению обстоятельств последние 4 месяца я работал над поддержкой буфера обмена и сопутствующими вещами :) К сожалению, я не смогу полностью описать вам, как обрабатывается вставка, потому что рассказы об имплементации слишком сложно для меня даже после того, как я сам написал impl: D
Тем не менее, вот несколько советов, которые могут вам помочь:
Не пишите wysiwyg-редактор — используйте существующий. Это займет все ваше время, и все равно ваш редактор будет глючить. Мы и ребята из других... два главных редактора (догадайтесь, почему существует только три) работают над этим годами, и у нас до сих пор есть полные списки ошибок ;).
Если вам действительно нужно написать свой собственный редактор, посетите http://dev.ckeditor.com/browser/CKEditor/trunk/_source/plugins/clipboard/plugin.js — это старый импл, до того, как я его переписал, но он работает везде, где это возможно. Код ужасен... но он может вам помочь.
Вы не сможете обработать все браузеры одним событием
paste
. Для обработки всех способов вставки мы используем какbeforepaste
, так иpaste
.Есть ряд (огромное количество: D) причуд браузеров, с которыми вам нужно справиться. Я не могу вам их описать, потому что даже спустя несколько недель я не вспомню их всех. Тем не менее, небольшая выдержка из нашей документации может быть вам полезна:
Команда вставки (используется нестандартной вставкой — например, с нашей панели инструментов)
* fire 'paste' on editable ('beforepaste' for IE) * !canceled && execCommand 'paste' * !success && fire 'pasteDialog' on editor
Вставить из собственного контекстного меню и строки меню
(Fx & Webkits are handled in 'paste' default listner. Opera cannot be handled at all because it doesn't fire any events Special treatment is needed for IE, for which is this part of doc) * listen 'onpaste' * cancel native event * fire 'beforePaste' on editor * !canceled && getClipboardDataByPastebin * execIECommand( 'paste' ) -> this fires another 'paste' event, so cancel it * fire 'paste' on editor * !canceled && fire 'afterPaste' on editor
Остальная часть трюка — в IE мы прослушиваем оба события вставки, в остальных — только
paste
. Нам нужно предотвратить некоторые события в IE, потому что, поскольку мы прослушиваем оба события, иногда это может привести к двойной обработке. Это самая сложная часть, я думаю.#P10#
#P11#См. http://dev.ckeditor.com/browser/CKEditor/trunk/_source/plugins/wysiwygarea/plugin.js#L120 до строки 123 — это последняя часть задачи — вставка содержимого в выделение.
Текущее решение отлично работает в IE/SAF/FF, но все же мне нужно исправить «не» события клавиатуры при вставке щелчком мыши... Текущее решение для событий «вставки» клавиатуры:
$(document).ready(function() {
bind_paste_textarea();
});
function bind_paste_textarea(){
var activeOnPaste = null;
$("#mypastediv").keydown(function(e){
var code = e.which || e.keyCode;
if((code == 86)){
activeOnPaste = $(this);
$("#mytextarea").val("").focus();
}
});
$("#mytextarea").keyup(function(){
if(activeOnPaste != null){
$(activeOnPaste).focus();
activeOnPaste = null;
}
});
}
<h2>DIV</h2>
<div id="mypastediv" contenteditable="true" style="width: 400px; height: 400px; border: 1px solid orange;">
</div>
<h2>TEXTAREA</h2>
<textarea id="mytextarea" style="width: 400px; height: 400px; border: 1px solid red;"></textarea>
Я добился этого, используя библиотеку rangy для сохранения и восстановления выбора.
Я также выполняю некоторую другую работу, используя библиотеку в тех же функциях, которые я убрал из этого примера, так что это не оптимальный код.
HTML
<div><div id="editor"contenteditable="true" type="text"></div><div>
JavaScript
var inputArea = $element.find('#editor');
var debounceInterval = 200;
function highlightExcessCharacters() {
// Bookmark selection so we can restore it later
var sel = rangy.getSelection();
var savedSel = sel.saveCharacterRanges(editor);
// Strip HTML
// Prevent images etc being pasted into textbox
inputArea.text(inputArea[0].innerText);
// Restore the selection
sel.restoreCharacterRanges(editor, savedSel);
}
// Event to handle checking of text changes
var handleEditorChangeEvent = (function () {
var timer;
// Function to run after timer passed
function debouncer() {
if (timer) {
timer = null;
}
highlightExcessCharacters();
}
return function () {
if (timer) {
$timeout.cancel(timer);
}
// Pass the text area we want monitored for exess characters into debouncer here
timer = $timeout(debouncer, debounceInterval);
};
})();
function listen(target, eventName, listener) {
if (target.addEventListener) {
target.addEventListener(eventName, listener, false);
} else if (target.attachEvent) {
target.attachEvent("on" + eventName, listener);
}
}
// Start up library which allows saving of text selections
// This is useful for when you are doing anything that might destroy the original selection
rangy.init();
var editor = inputArea[0];
// Set up debounced event handlers
var editEvents = ["input", "keydown", "keypress", "keyup", "cut", "copy", "paste"];
for (var i = 0, eventName; eventName = editEvents[i++];) {
listen(editor, eventName, handleEditorChangeEvent);
}
paste
слишком поздно для перенаправления фокуса. - person Tim Down   schedule 28.06.2012paste
. Некоторые браузеры запускают событиеbeforepaste
, но обычно это бесполезно. - person Tim Down   schedule 28.06.2012