11

I've ran into an issue with CKEditor 4 and jQuery UI's sortable method where if I sort a container that has a CKEditor instance, it removes the value and throws an error "Uncaught TypeError: Cannot call method 'getSelection' of undefined". It also makes the editor uneditable. I was able to get around this in CKEditor 3 with one of the following hacks found here: CKEditor freezes on jQuery UI Reorder

In looking at the Chrome DOM inspector, it appears that the contents of the iframe are removed.

Below is crude test code:


    <html>
    <head>
        <title>test</title>
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
        <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.24/jquery-ui.min.js"></script>
        <script src="ckeditor.js"></script>
        <script type="text/javascript">
        $(function(){

            var tmpStore = {};
            $('#sortable').sortable({
                cursor: 'move',

                // Hack that use to work on V3 but not on V4:
                // https://stackoverflow.com/questions/3379653/ckeditor-freezes-on-jquery-ui-reorder
                start:function (event,ui) {
                    $('textarea').each(function(){
                        var id = $(this).attr('id');
                        tmpStore[id] = CKEDITOR.instances[id].getData();
                    })
                 },
                stop: function(event, ui) { 
                    $('textarea').each(function(){
                        var id = $(this).attr('id');
                        CKEDITOR.instances[id].setData(tmpStore[id]);
                    })
                  }
            });
            $('textarea').each(function(){
                var ckId = $(this).attr('id');
                config = {};
                CKEDITOR.replace(ckId, config);
            })
        })

        
        
        li { padding: 10px; width: 800px; height: 300px; }
        
    </head>
    <body>
        <ul id="sortable">
            <li><textarea id="test1" name="test1">test1</textarea></li>
            <li><textarea id="test2" name="test1">test2</textarea></li>
            <li><textarea id="test3" name="test1">test3</textarea></li>
        </ul>
    </body>
    </html>

Community
  • 1
  • 1
DMC
  • 184
  • 2
  • 6

7 Answers7

7

I was facing the same problem and have fixed based on answers here. Please see fiddles below

ISSUE: https://jsfiddle.net/33qt24L9/1/

  $(function() {
        $( "#sortable" ).sortable({
      placeholder: "ui-state-highlight"
    });

       CKEDITOR.replace( 'editor1' );
       CKEDITOR.replace( 'editor2' );
       CKEDITOR.replace( 'editor3' );
       CKEDITOR.replace( 'editor4' );

  });

RESOLVED ISSUE: https://jsfiddle.net/57djq2bh/2/

  $(function() {
        $( "#sortable" ).sortable({
      placeholder: "ui-state-highlight",

             start: function (event, ui) 
        {
            var id_textarea = ui.item.find(".ckeditor").attr("id");
            CKEDITOR.instances[id_textarea].destroy();
        },
        stop: function (event, ui) 
        {
            var id_textarea = ui.item.find(".ckeditor").attr("id");
            CKEDITOR.replace(id_textarea);
        }           

    });

       CKEDITOR.replace( 'editor1' );
       CKEDITOR.replace( 'editor2' );
       CKEDITOR.replace( 'editor3' );
       CKEDITOR.replace( 'editor4' );

  });

EDIT: If like me you had seperate configs per editor here's updated code that will help:

start: function (event, ui)
        {
            $('.wysiwyg', ui.item).each(function(){
                var tagId = $(this).attr('id');
                var ckeClone = $(this).next('.cke').clone().addClass('cloned');
                ckeConfigs[tagId] = CKEDITOR.instances[tagId].config;
                CKEDITOR.instances[tagId].destroy();
                $(this).hide().after(ckeClone);
            });
        },

        stop: function(event, ui) {
            // for each textarea init ckeditor anew and remove the clone
            $('.wysiwyg', ui.item).each(function(){
                var tagId = $(this).attr('id');
                CKEDITOR.replace(tagId, ckeConfigs[tagId]);
                $(this).next('.cloned').remove();
            });
        }

Thanks to: https://github.com/trsteel88/TrsteelCkeditorBundle/issues/53

Friendly Code
  • 1,585
  • 1
  • 25
  • 41
3

You have to re-create CKEditor once underlying DOM structure is modified. Save editor data with editor.getData() before editor.destroy() and restore contents with editor.setData( data ) once you create a new instance. There's no other way to fix this since CKEditor strongly depends on the DOM structure.

oleq
  • 15,697
  • 1
  • 38
  • 65
2

The code below works for me, we have to destroy the editor on start and recreate it when the drag is ended getting the value of the textarea which come the data from :

jQuery(function($) 
{
    var panelList = $("#nameofyourdiv");
    panelList.sortable(
    {
        handle: ".classofyourdivforsorting", 
        start: function (event, ui) 
        {
            var id_textarea = ui.item.find("textarea").attr("id");
            CKEDITOR.instances[id_textarea].destroy();
        } 
        stop: function (event, ui) 
        {
            var id_textarea = ui.item.find("textarea").attr("id");
            CKEDITOR.replace(id_textarea);
        }           
    });
});

Hope it helps someone.

Vindic
  • 627
  • 6
  • 8
2

Remove CKEditor start Sortable

var ckeConfigs = [];
$('.ui-sortable').sortable({
 start:function (event,ui) {
  $('.lineItemCommentBox', ui.item).each(function(){
    var tagId = $(this).attr('id');
        ckeConfigs[tagId] = CKEDITOR.instances[tagId].config;
    CKEDITOR.instances[tagId].destroy();
  });
 },
 stop: function(event, ui) {
  $('.lineItemCommentBox', ui.item).each(function(){
   var tagId = $(this).attr('id');
   CKEDITOR.replace(tagId, ckeConfigs[tagId]);
  });
 }
});
0

i ve solved this kind of problem by instantiating the CKEditor after having opened the jquery dialog

0

I had the Similar issue with CKEDITOR , The Code Below worked for me. Destroy the Ckeditor instance and Remove the Ckeditor and when the dragging ends replace the current textarea with Ckeditor again

 $("#sortable").sortable({
        items: '.dynamic',
        start: function (event , ui) {

                var editorId = $(ui.item).find('.ckeditor').attr('id');// get the id of your Ckeditor
                editorInstance = CKEDITOR.instances[editorId]; // Get the Ckeditor Instance
                editorInstance.destroy(); // Destroy it
                CKEDITOR.remove(editorId);// Remove it

        },
        stop: function(event, ui) { 
                var editorId = $(ui.item).find('.ckeditor').attr('id');// Get the Id of your Ckeditor 
                CKEDITOR.replace(editorId);// Replace it
            }
        } 

    });
    $("#sortable").disableSelection();

Here #sortable is the id of the DIV which is sortable and '.dynamic' is the Class assigned to DIV that are eligible to sort and '.ckeditor' is the class for the Textarea .

I got my solution from Here , Hope this helps for someone in future.

Joker
  • 830
  • 2
  • 14
  • 30
-1

I simply use the ckeditorOff() and ckeditorOn() functions to keep data and re/de-instance ckeditor instances during movement.

$('#sortable').sortable({
    cursor: 'move',
    start:function (event,ui) {
        if(typeof ckeditorOff=='function')ckeditorOff();
    },
    stop: function(event, ui) { 
        if(typeof ckeditorOn=='function')ckeditorOn();
    } 
});

I put the typeof ckeditorOff statement to make the code compatible with future versions of ckeditor in case they decide to remove these two functions.

mAsT3RpEE
  • 1,818
  • 1
  • 17
  • 14
  • 2
    Are there specific "ckeditorOff" and "ckeditorOn" functions that CKEditor provides? – DMC Jun 26 '13 at 16:27
  • No I simply pasted the code as is. I think ckeditorOff and On are global commands. I don't see them removing them in the near future. – mAsT3RpEE Sep 10 '13 at 19:24
  • ckeditorOff() and ckeditorOn()? They are native to the ckeditor. When you include the source they are automatically defined by ckeditor js. – mAsT3RpEE Oct 04 '13 at 01:51
  • They aren't unfortunately. Just try to look for them in the [source](http://ckeditor.com/apps/ckeditor/4.2.2/ckeditor.js). Although minified the function names have to be in there somewhere but they aren't. – flu Oct 28 '13 at 14:42
  • 1
    Okay please tell me which version of ckeditor you are using and I'll make a sol that works for the version you are using. I was using the ckeditor that comes with wordpress ckeditor plugin. The theme I was using was dynamically creating the comment field which screwed up ckeditor. I think I can can post a definition of ckeditorOn / Off so everyone else doesn't have to suffer. – mAsT3RpEE Oct 30 '13 at 15:47