Разрешение contenteditable отменить после модификации dom
есть ли способ изменить элементы contenteditable с помощью javascript, чтобы отменить все еще работает?
Алло кажется, что может сделать это хорошо, попробуйте нажать кнопку полужирным шрифтом после выбора текста, я пропустил его источник и понятия не имею, как они это делают, единственное упоминание в halloreundo
который является некоторой панелью инструментов gui.
Я посмотрел на отменить.js но это просто сохраняет html в массиве, что действительно ограничивает размер стек отмены, поэтому я ищу собственное решение, если это возможно.
3 ответов
вы можете обеспечить отмену ваших операций редактирования, выполнив их через document.execCommand()
вместо прямых манипуляций DOM.
проверьте эту мини-демонстрацию, которая показывает полужирный команда (undoable конечно):http://jsfiddle.net/qL6Lpy0c/
этот код сохранит все изменения в contenteditable в массиве. Вы можете вручную сохранить текущее состояние, вызвав save_history()
или присоединить эту функцию к любому событию (в Примере-on keydown
). Я закодировал проверку равенства состояний, поэтому, если вы свяжете save_history на Click event-он не сохранит состояние 10, если вы нажмете 10 раз без каких-либо изменений в Редакторе. Этот код будет работать в каждом браузере, который может запускать jQuery:
//array to store canvas objects history
canvas_history=[];
s_history=true;
cur_history_index=0;
DEBUG=true;
//store every modification of canvas in history array
function save_history(force){
//if we already used undo button and made modification - delete all forward history
if(cur_history_index<canvas_history.length-1){
canvas_history=canvas_history.slice(0,cur_history_index+1);
cur_history_index++;
jQuery('#text_redo').addClass("disabled");
}
var cur_canvas=JSON.stringify(jQuery(editor).html());
//if current state identical to previous don't save identical states
if(cur_canvas!=canvas_history[cur_history_index] || force==1){
canvas_history.push(cur_canvas);
cur_history_index=canvas_history.length-1;
}
DEBUG && console.log('saved '+canvas_history.length+" "+cur_history_index);
jQuery('#text_undo').removeClass("disabled");
}
function history_undo(){
if(cur_history_index>0)
{
s_history=false;
canv_data=JSON.parse(canvas_history[cur_history_index-1]);
jQuery(editor).html(canv_data);
cur_history_index--;
DEBUG && console.log('undo '+canvas_history.length+" "+cur_history_index);
jQuery('#text_redo').removeClass("disabled");
}
else{
jQuery('#text_undo').addClass("disabled");
}
}
function history_redo(){
if(canvas_history[cur_history_index+1])
{
s_history=false;
canv_data=JSON.parse(canvas_history[cur_history_index+1]);
jQuery(editor).html(canv_data);
cur_history_index++;
DEBUG && console.log('redo '+canvas_history.length+" "+cur_history_index);
jQuery('#text_undo').removeClass("disabled");
}
else{
jQuery('#text_redo').addClass("disabled");
}
}
jQuery('body').keydown(function(e){
save_history();
});
jQuery('#text_undo').click(function(e){
history_undo();
});
jQuery('#text_redo').click(function(e){
history_redo();
});
#text_undo.disabled,#text_redo.disabled{
color: #ccc;
}
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<button id="text_undo" class="disabled">Undo</button><button id="text_redo" class="disabled">Redo</button>
<div id="editor" contenteditable="true">Some editable HTML <b>here</b></div>
</body>
</html>
Как заявили другие, короткий ответ-использовать документ.execCommand для сохранения отмены/повтора браузера. Если вам нужно каким-либо образом программно редактировать текст (например, поддерживать отступы многострочных вкладок или другие ярлыки, которые управляют текстом), Вы должны использовать document.execCommand ('insertHTML') или' insertText ' при установке нового состояния текста. insertText создаст новые дети div при редактировании, что может быть хлопотно, в то время как "insertHTML" не будет (но " insertHTML некоторые проблемы поддержки IE, которые вам, возможно,придется решать, хорошо детализированы в другом месте).
эта часть бросила меня на огромный цикл и поэтому я пишу новый ответ, потому что я не нашел его упомянутым в любом месте:
вам также может потребоваться поймать вставить событие и превратите его в execCommand ('insertHTML'), или любые программные изменения выбора, которые вы можете сделать после этой вставки (например, сброс курсора и т. д.), рискуют бросить вам сообщение об ошибке узел недостаточно длинный, чтобы сделать новый выбор, хотя это заметно. DOM как-то не распознает новую длину yourDiv.firstNode после вставки, но он обновит его после использования execCommand ('insertHTML'). Могут быть и другие решения, но это было легко:
$("#myDiv").on( 'paste', function(e) {
e.preventDefault();
var text = e.originalEvent.clipboardData.getData("text/plain");
document.execCommand("insertHTML", false, text);
});