Разрешение 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);
});