I've a HTML table with one CKEditor instance on each row, all works fine until i swap positions between 2 rows. After the swap, values aren't displayed and any use of method setData ends in an JS error.
Basic structure is:
<tr id=1>
<td>...</td>
<td>ckeditor1</td>
</tr>
.
.
<tr id=n>
<td>...</td>
<td>ckeditorn</td>
</tr>
Method used to swap nodes is
Node.prototype.swapNode = function (node) {
var nextSibling = this.nextSibling;
var parentNode = this.parentNode;
node.parentNode.replaceChild(this, node);
parentNode.insertBefore(node, nextSibling);
};
So, i call Node1.swapNode(Node2)
, CKEditor loses it's value, then tried to force the values again on CKEditor instance via CKEditor.instances[1].setData(data,{});
That call ends in this stack trace:
TypeError: this.document.getWindow(...).$ is undefined ckeditor.js:427:29
CKEDITOR.dom.selection.prototype.getNative http://localhost/js/packages/ckeditor/ckeditor.js:427:29
CKEDITOR.dom.selection http://localhost/js/packages/ckeditor/ckeditor.js:425:54
CKEDITOR.editor.prototype.getSelection http://localhost/js/packages/ckeditor/ckeditor.js:422:319
CKEDITOR.plugins.undo.Image http://localhost/js/packages/ckeditor/ckeditor.js:1077:358
b.prototype.save http://localhost/js/packages/ckeditor/ckeditor.js:1072:24
.init/< http://localhost/js/packages/ckeditor/ckeditor.js:1068:269
h http://localhost/js/packages/ckeditor/ckeditor.js:10:68
CKEDITOR.event.prototype</<.fire</< http://localhost/js/packages/ckeditor/ckeditor.js:11:428
CKEDITOR.editor.prototype.fire http://localhost/js/packages/ckeditor/ckeditor.js:13:67
.setData http://localhost/js/packages/ckeditor/ckeditor.js:261:79
Tested on FF 52, Opera 52, Chrome 61 @OpenSuse 42.3
Is it any other way to achieve the swap without losing the values? Or at least not ending in that error?
Regards
Snippet:
Node.prototype.swapNode = function (node) {
var nextSibling = this.nextSibling;
var parentNode = this.parentNode;
node.parentNode.replaceChild(this, node);
parentNode.insertBefore(node, nextSibling);
};
var element1 = new CKEDITOR.dom.element(document.getElementById('doc_content1'));
CKEDITOR.replace(element1);
var element2 = new CKEDITOR.dom.element(document.getElementById('doc_content2'));
CKEDITOR.replace(element2);
<html>
<head>
<script src="https://cdn.ckeditor.com/4.9.2/full/ckeditor.js"></script>
</head>
<body>
<form>
<table>
<tbody>
<tr id='1'>
<td><input name="doc_title1" type="text"></td>
<td><textarea id="doc_content1" name="doc_content1" ></textarea></td>
<td><input type="button" onclick="javascript: this.parentNode.parentNode.swapNode(document.getElementById('2'));" value='change to 2'></td>
</tr>
<tr id='2'>
<td><input name="doc_title2" type="text"></td>
<td><textarea id="doc_content2" name="doc_content2"></textarea></td>
<td><input type="button" onclick="javascript: this.parentNode.parentNode.swapNode(document.getElementById('1'));" value='change to 1'>
</td>
</tr>
</tbody>
</form>
</body>
</html>
You have to destroy the instances first, swap the rows and then recreate the instances. When destroying the instances, their textareas are updated with their data, so when recreating them, the data will not be lost.
Node.prototype.swapNode = function (node) {
var firstInstance = 'doc_content' + node.id;
var secondInstance = 'doc_content' + this.id;
CKEDITOR.instances[firstInstance].destroy();
CKEDITOR.instances[secondInstance].destroy();
var nextSibling = this.nextSibling;
var parentNode = this.parentNode;
node.parentNode.replaceChild(this, node);
parentNode.insertBefore(node, nextSibling);
CKEDITOR.replace(document.getElementById(firstInstance));
CKEDITOR.replace(document.getElementById(secondInstance));
};
CKEDITOR.replace(document.getElementById('doc_content1'));
CKEDITOR.replace(document.getElementById('doc_content2'));