J'utilise des boîtes de dialogue jquery pour présenter des formulaires (récupérés via AJAX). Sur certains formulaires, j'utilise un éditeur CKE pour les zones de texte. L'éditeur affiche bien lors du premier chargement.
Lorsque l'utilisateur annule la boîte de dialogue, je supprime le contenu afin qu'il soit chargé à nouveau lors d'une demande ultérieure. Le problème est que, une fois la boîte de dialogue rechargée, l'éditeur CKE dit que l'éditeur existe déjà.
uncaught exception: [CKEDITOR.editor] The instance "textarea_name" already exists.
L'API inclut une méthode pour détruire les éditeurs existants, et j'ai vu des gens prétendre que c'était une solution:
if (CKEDITOR.instances['textarea_name']) {
CKEDITOR.instances['textarea_name'].destroy();
}
CKEDITOR.replace('textarea_name');
Cela ne fonctionne pas pour moi car je reçois une nouvelle erreur:
TypeError: Result of expression 'i.contentWindow' [null] is not an object.
Cette erreur semble se produire sur le "destroy ()" plutôt que le "replace ()". Quelqu'un en a-t-il fait l'expérience et a-t-il trouvé une solution différente?
Est-il possible de "re-rendre" l'éditeur existant, plutôt que de le détruire et de le remplacer?
UPDATEDVoici une autre question traitant du même problème, mais il a fourni un cas de test téléchargeable .
Pour que cela fonctionne, vous devez passer le paramètre booléen true lors de la destruction d'une instance:
var editor = CKEDITOR.instances[name];
if (editor) { editor.destroy(true); }
CKEDITOR.replace(name);
function loadEditor(id)
{
var instance = CKEDITOR.instances[id];
if(instance)
{
CKEDITOR.remove(instance);
}
CKEDITOR.replace(id);
}
J'ai eu ce problème aussi, mais je l'ai résolu d'une manière beaucoup plus simple ...
J'utilisais la classe "ckeditor" dans mon script jQuery comme sélecteur pour lequel textareas je voulais utiliser pour CKEditor. Le script JS ckeditor par défaut utilise également cette classe pour identifier les zones de texte à utiliser pour CKEditor.
Cela signifiait qu'il y avait un conflit entre mon script jQuery et le script ckeditor par défaut.
J'ai simplement changé la classe de textarea et mon script jQuery en "do_ckeditor" (vous pouvez utiliser n'importe quoi sauf "ckeditor") et cela a fonctionné.
C'est la solution la plus simple (et unique) qui a fonctionné pour moi:
if(CKEDITOR.instances[editorName])
delete CKEDITOR.instances[editorName];
CKEDITOR.replace(editorName);
La suppression de cette entrée dans la matrice empêche cette vérification de sécurité du formulaire de détruire votre application.
destroy () et remove () n'ont pas fonctionné pour moi.
Cela vous aidera peut-être - j’ai fait quelque chose de similaire avec jquery, sauf que je charge un nombre inconnu d’objets ckeditor. Il m'a fallu un certain temps pour trébucher sur ceci - ce n'est pas clair dans la documentation.
function loadEditors() {
var $editors = $("textarea.ckeditor");
if ($editors.length) {
$editors.each(function() {
var editorID = $(this).attr("id");
var instance = CKEDITOR.instances[editorID];
if (instance) { instance.destroy(true); }
CKEDITOR.replace(editorID);
});
}
}
Et voici ce que je lance pour obtenir le contenu des éditeurs:
var $editors = $("textarea.ckeditor");
if ($editors.length) {
$editors.each(function() {
var instance = CKEDITOR.instances[$(this).attr("id")];
if (instance) { $(this).val(instance.getData()); }
});
}
UPDATE: J'ai changé ma réponse pour utiliser la bonne méthode - qui est .destroy (). .remove () est censé être interne et a été mal documenté à un moment donné.
var e= CKEDITOR.instances['sample'];
e.destroy();
e= null;
Nous avons eu un problème similaire dans lequel nous avions créé plusieurs instances de CKeditor pour le contenu chargé via ajax.
CKEDITOR.remove ()
Gardé le DOM dans la mémoire et n'a pas supprimé toutes les liaisons.
CKEDITOR.instance [instance_id] .destroy ()
A donné l'erreur i.contentWindow error à chaque fois que je crée une nouvelle instance avec de nouvelles données provenant de ajax. Mais ce n’est que jusqu’à ce que j’ai compris que je détruisais l’instance après avoir effacé le DOM.
Utilisez destroy () tant que l'instance et son DOM sont présents sur la page, cela fonctionnera parfaitement.
Pour les demandes ajax,
for(k in CKEDITOR.instances){
var instance = CKEDITOR.instances[k];
instance.destroy()
}
CKEDITOR.replaceAll();
ceci extrait supprime toutes les instances du document. Crée ensuite de nouvelles instances.
C'est ce qui a fonctionné pour moi:
for(name in CKEDITOR.instances)
{
CKEDITOR.instances[name].destroy()
}
L'erreur i.contentWindow is null
semble se produire lors de l'appel de destroy sur une instance de l'éditeur liée à une zone de texte ne figurant plus dans le DOM.
CKEDITORY.destroy
prend un paramètre noUpdate
.
APIdoc déclare:
Si l'instance remplace un élément DOM, ce paramètre indique s'il faut ou non mettre à jour l'élément avec le contenu de l'instance.
Donc, pour éviter l'erreur, appelez destroy avant de supprimer l'élément textarea du DOM ou appelez destory (true) pour éviter d'essayer de mettre à jour l'élément DOM inexistant.
if (CKEDITOR.instances['textarea_name']) {
CKEDITOR.instances['textarea_name'].destroy(true);
}
(avec la version 3.6.2 avec l'adaptateur jQuery)
Vous pouvez supprimer toute instance de ckeditor en supprimant la méthode de ckeditor. L'instance sera id ou nom de la zone de texte.
if (CKEDITOR.instances[instance_name]) {
CKEDITOR.remove(CKEDITOR.instances[instance_name]);
}
j'ai eu le même problème avec les instances, je cherchais partout et finalement cette implémentation me convient
//set my instance id on a variable
myinstance = CKEDITOR.instances['info'];
//check if my instance already exist
if (myinstance) {
CKEDITOR.remove(info)
}
//call ckeditor again
$('#info').ckeditor({
toolbar: 'Basic',
entities: false,
basicEntities: false
});
J'ai préparé ma propre solution basée sur tous les codes ci-dessus.
$("textarea.ckeditor")
.each(function () {
var editorId = $(this).attr("id");
try {
var instance = CKEDITOR.instances[editorId];
if (instance) { instance.destroy(true); }
}
catch(e) {}
finally {
CKEDITOR.replace(editorId);
}
});
Cela fonctionne parfaitement pour moi.
Parfois, après la demande de AJAX, la structure du DOM est incorrecte. Par exemple:
<div id="result">
<div id="result>
//CONTENT
</div>
</div>
Cela causera également un problème et ckEditor ne fonctionnera pas. Assurez-vous donc que vous avez la structure DOM correcte.
CKEDITOR.instances = new Array();
J'utilise ceci avant mes appels pour créer une instance (une par chargement de page). Je ne sais pas comment cela affecte la gestion de la mémoire et ce qui ne l'est pas. Cela ne fonctionnerait que si vous vouliez remplacer toutes les instances d'une page.
En effet, la suppression de la classe ".ckeditor" de votre code résout le problème. La plupart d'entre nous ont suivi l'exemple d'intégration jQuery tiré de la documentation de ckeditor:
$('.jquery_ckeditor')
.ckeditor( function() { /* callback code */ }, { skin : 'office2003' } );
et pensé "... peut-être que je peux juste me débarrasser ou la partie '.jquery_'".
J'ai perdu mon temps à peaufiner la fonction de rappel (car la {skin: 'office2003'} fonctionnait réellement), alors que le problème venait d'ailleurs.
Je pense que la documentation devrait mentionner que l'utilisation de "ckeditor" en tant que nom de classe n'est pas recommandée, car il s'agit d'un mot clé réservé.
À votre santé.
Je suis dans la situation où je dois contrôler ces dialogues, chacun d'entre eux doit avoir un ckeditor intégré dans ces dialogues. Et il se trouve que les zones de texte partagent le même identifiant. (Normalement, c'est une très mauvaise pratique, mais j'ai 2 jqGrid, un des éléments assignés et un autre des éléments non attribués.) Ils partagent une configuration presque identique. Ainsi, j'utilise un code commun pour configurer les deux.
Ainsi, lorsque je charge un dialogue, pour ajouter des lignes ou pour les éditer, à partir de jqGrid; Je dois supprimer toutes les instances de CKEDITOR dans toutes les zones de texte.
$('textarea').each(function()
{
try
{
if(CKEDITOR.instances[$(this)[0].id] != null)
{
CKEDITOR.instances[$(this)[0].id].destroy();
}
}
catch(e)
{
}
});
Cela fera une boucle sur toutes les zones de texte, et s'il y a une instance de CKEDITOR, alors la détruire.
Alternativement, si vous utilisez jQuery pur:
$('textarea').each(function()
{
try
{
$(this).ckeditorGet().destroy();
}
catch(e)
{
}
});
J'ai appris ça
supprimer CKEDITOR.instances [nomEditeur];
par lui-même, effectivement supprimé l'instance. TOUTES les autres méthodes que j'ai lues et vues, y compris ce qui a été trouvé ici chez stackoverflow par ses utilisateurs, ne fonctionnaient pas pour moi.
Dans ma situation, j'utilise un appel ajax pour extraire une copie du contenu enveloppé autour du et du. Le problème est dû au fait que j'utilise un événement jQuery .live pour lier un lien "Modifier ce document", puis que j'applique l'instance de ckeditor après le succès du chargement ajax. Cela signifie que lorsque je clique sur un autre lien avec un autre événement .live, je dois utiliser le fichier delete CKEDITOR.instances [nomEditeur] dans le cadre de ma tâche d'effacement de la fenêtre de contenu (contenant le formulaire), puis de relire à nouveau le contenu détenu. dans la base de données ou une autre ressource.
J'ai choisi de renommer toutes les instances au lieu de détruire/remplacer - car parfois l'instance chargée AJAX ne remplace pas vraiment celle du coeur de la page ... conserve plus de mémoire vive, mais génère moins de conflits de cette façon.
if (CKEDITOR && CKEDITOR.instances) {
for (var oldName in CKEDITOR.instances) {
var newName = "ajax"+oldName;
CKEDITOR.instances[newName] = CKEDITOR.instances[oldName];
CKEDITOR.instances[newName].name = newName;
delete CKEDITOR.instances[oldName];
}
}
J'ai eu le même problème avec un dialogue jQuery.
Pourquoi détruire l'instance si vous voulez simplement supprimer les données précédentes?
function clearEditor(id)
{
var instance = CKEDITOR.instances[id];
if(instance)
{
instance.setData( '' );
}
}
remove class="ckeditor"
, cela aurait pu déclencher l'initialisation de ckeditor
CKeditor 4.2.1
Il y a beaucoup de réponses ici, mais pour moi, j'avais besoin de quelque chose de plus (un peu sale aussi, si quelqu'un peut s'améliorer, s'il vous plaît, faites-le). Pour moi, les modaux sont mon problème.
Je rendais le CKEditor dans un modal, en utilisant Foundation. Dans l’idéal, j’aurais déshonoré le rédacteur en chef à la fermeture, mais je ne voulais pas me mêler de Foundation.
J'ai appelé supprimer, j'ai essayé de supprimer et une autre méthode, mais c'est ce que j'ai finalement réglé avec.
J'utilisais textarea pour peupler pas les DIV.
Ma solution
//hard code the DIV removal (due to duplication of CKeditors on page however they didn't work)
$("#cke_myckeditorname").remove();
if (CKEDITOR.instances['myckeditorname']) {
delete CKEDITOR.instances['myckeditorname'];
CKEDITOR.replace('myckeditorname', GetCKEditorSettings());
} else {
CKEDITOR.replace('myckeditorname', GetCKEditorSettings());
}
c'était ma méthode pour renvoyer ma mise en forme spécifique, ce que vous pourriez ne pas vouloir.
function GetCKEditorSettings()
{
return {
linkShowAdvancedTab: false,
linkShowTargetTab: false,
removePlugins: 'elementspath,magicline',
extraAllowedContent: 'hr blockquote div',
fontSize_sizes: 'small/8px;normal/12px;large/16px;larger/24px;huge/36px;',
toolbar: [
['FontSize'],
['Bold', 'Italic', 'Underline', '-', 'NumberedList', 'BulletedList', '-', 'Link', 'Unlink'],
['Smiley']
]
};
}
J'ai rencontré exactement la même chose et le problème était que le plugin wordcount mettait trop de temps à s'initialiser. 30 secondes et plus. L'utilisateur cliquait dans la vue affichant le ckeditor, puis annulait, chargeant ainsi une nouvelle page dans le répertoire. Le plugin se plaignait parce que l'iframe ou le contenu désigné par contentWindow n'était plus visible au moment où il était prêt à s'ajouter à contentWindow. Vous pouvez le vérifier en cliquant dans votre vue, puis en attendant que le nombre de mots apparaisse en bas à droite de l'éditeur. Si vous annulez maintenant, vous n'aurez pas de problème. Si vous n'attendez pas, vous obtiendrez l'erreur i.contentWindow is null. Pour résoudre ce problème, supprimez simplement le plugin:
if (CKEDITOR.instances['textarea_name'])
{
CKEDITOR.instances['textarea_name'].destroy();
}
CKEDITOR.replace('textarea_name', { removePlugins: "wordcount" } );
Si vous avez besoin d'un compteur Word, enregistrez-vous pour les événements coller et saisir dans l'éditeur avec une fonction qui compte les mots.
Cette fonction fonctionne pour moi dans la version 4.4.5 de CKEditor, elle ne présente aucune fuite de mémoire.
function CKEditor_Render(CkEditor_id) {
var instance = CKEDITOR.instances[CkEditor_id];
if (CKEDITOR.instances.instance) {
CKEDITOR.instances.instance.destroy();
}
CKEDITOR.replace(CkEditor_id);
}
// appelle cette fonction comme ci-dessous
var id = 'ckeditor'; // Id of your textarea
CKEditor_Render(id);
J'ai eu le même problème où je recevais une exception de référence null et le mot "null" serait affiché dans l'éditeur. J'ai essayé une poignée de solutions, y compris la mise à niveau de l'éditeur à la version 3.4.1 sans succès.
J'ai fini par avoir à éditer la source. Aux lignes 416 à 426 environ dans _source\plugins\wysiwygarea\plugin.js, vous trouverez un extrait de code ressemblant à ceci:
iframe = CKEDITOR.dom.element.createFromHtml( '<iframe' + ... + '></iframe>' );
En FF au moins, l'iframe n'est pas complètement instancié par le temps nécessaire. J'ai entouré le reste de la fonction après cette ligne avec une fonction setTimeout:
iframe = CKEDITOR.dom.element.createFromHtml( '<iframe' + ... + '></iframe>' );
setTimeout(function()
{
// Running inside of Firefox chrome the load event doesn't bubble like in a normal page (#5689)
...
}, 1000);
};
// The script that launches the bootstrap logic on 'domReady', so the document
...
Le rendu du texte est maintenant cohérent dans les boîtes de dialogue modales.
C'est le code qui fonctionne parfaitement pour jquery .load () api et ckeditor, dans mon cas, je charge une page avec ckeditor dans div avec des effets jquery. J'espère que cela vous aidera.
$(function() {
runEffect = function(fileload,lessonid,act) {
var selectedEffect = 'drop';
var options = {};
$( "#effect" ).effect( selectedEffect, options, 200, callback(fileload,lessonid,act) );
};
function callback(fileload,lessonid,act) {
setTimeout(function() {//load the page in effect div
$( "#effect" ).load(fileload,{lessonid:lessonid,act:act});
$("#effect").show( "drop",
{direction: "right"}, 200 );
$("#effect").ajaxComplete(function(event, XMLHttpRequest, ajaxOptions) {
loadCKeditor(); //call the function after loading page
});
}, 100 );
};
function loadCKeditor()
{//you need to destroy the instance if already exist
if (CKEDITOR.instances['introduction'])
{
CKEDITOR.instances['introduction'].destroy();
}
CKEDITOR.replace('introduction').getSelection().getSelectedText();
}
});
===================== button for call the function ================================
<input type="button" name="button" id="button" onclick="runEffect('lesson.php','','add')" >
Essaye ça:
for (name in CKEDITOR.instances)
{
CKEDITOR.instances[name].destroy(true);
}
J'ai eu exactement le même problème que Jackboberg. J'utilisais le chargement de formulaire dynamique dans les boîtes de dialogue jQuery, puis j'attachais divers widgets (datepickers, ckeditors, etc.) .
Pour une raison quelconque, ckeditor n’a joint que la première fois que j’ai chargé le formulaire, la deuxième fois que j’ai reçu exactement le même message d’erreur que Jackboberg.
J'ai analysé mon code et découvert que, si vous attachez ckeditor en mode "intermédiaire" alors que le contenu du formulaire n'est toujours pas placé dans la boîte de dialogue, ckeditor n'attachera pas correctement ses liaisons. C'est parce que ckeditor est attaché en "air", la deuxième fois que vous l'attachez en "air" ... pouf ... une erreur est renvoyée car la première instance n'a pas été correctement supprimée de DOM.
C'est mon code qui a provoqué l'erreur:
var $content = $(r.content); // jQuery can create DOM nodes from html text gotten from <xhr response> - so called "mid-air" DOM creation
$('.rte-field',$content).ckeditor(function(){});
$content.dialog();
C'est le correctif qui a fonctionné:
var $content = $(r.content).dialog(); // first create dialog
$('.rte-field',$content).ckeditor(function(){}); // then attach ckeditor widget
Pour ceux qui utilisent "l'adaptateur" jquery et qui ont des problèmes (comme je l'étais), une solution très efficace, mais efficace, consiste à faire quelque chose comme ceci:
// content editor plugin
(function($){
$.fn.contentEditor = function( params ) {
var xParams = $.extend({}, $.fn.contentEditor.defaultParams, params);
return this.each( function() {
var $editor = $(this);
var $params = $.extend({}, xParams, $editor.data());
// if identifier is set, detect type based on identifier in $editor
if( $params.identifier.type ) {
$params.type = $editor.find($params.identifier.type).val();
}
$editor.data('type', $params.type);
// edit functionality
editButton = $('<button>Edit Content</button>').on('click',function(){
// content container
var $cc = $('#' + $editor.data('type'));
// editor window
var $ew = $('<form class="editorWindow" />');
$ew.appendTo('body');
// editor content
$ec = $('<textarea name="editorContent" />').val($cc.html());
$ec.appendTo($ew);
$ec.ckeditor();
//$ec.ckeditorGet().setMode('source');
$ew.dialog({
"autoOpen": true,
"modal": true,
"draggable": false,
"resizable": false,
"width": 850,
"height": 'auto',
"title": "Content Editor",
"buttons": {
'Save': function() {
$cc.html( $ec.val() );
$ec.ckeditorGet().destroy();
$ew.remove();
},
'Cancel / Close': function() {
$ec.ckeditorGet().destroy();
$ew.remove();
}
},
'close': function() {
$ec.ckeditorGet().destroy();
},
'open': function() {
$ew.find('a.cke_button_source').click();
setTimeout(function(){
$ew.find('a.cke_button_source.cke_on').click();
}, 500);
}
});
return false;
});
editButton.appendTo( $editor );
});
}
// set default option values
$.fn.contentEditor.defaultParams = {
'identifier': {
'type': 'input[name="type"]'
}
};
})(jQuery);
$(function(){
$('form.contentEditor').contentEditor();
});
Le point clé étant cette partie:
'open': function() {
$ew.find('a.cke_button_source').click();
setTimeout(function(){
$ew.find('a.cke_button_source.cke_on').click();
}, 500);
}
Cela résout le problème avec le texte de l'éditeur non visible à la prochaine ouverture de la boîte de dialogue. Je me rends compte que c’est très rigolo, mais étant donné que la plupart d’entre eux vont être utilisés comme outils d’administration, je ne pense pas que ce soit une préoccupation aussi grande qu’elle le serait normalement… et cela fonctionne, alors espérons-le temps ;)
C'est assez simple. Dans mon cas, j’ai exécuté la méthode jquery ci-dessous qui détruira les instances de ckeditor lors du chargement d’une page. Cela a fait l'affaire et résolu le problème -
Méthode JQuery -
function resetCkEditorsOnLoad(){
for(var i in CKEDITOR.instances) {
editor = CKEDITOR.instances[i];
editor.destroy();
editor = null;
}
}
$(function() {
$(".form-button").button();
$(".button").button();
resetCkEditorsOnLoad(); // CALLING THE METHOD DURING THE PAGE LOAD
.... blah.. blah.. blah.... // REST OF YOUR BUSINESS LOGIC GOES HERE
});
C'est tout. J'espère que ça t'aide.
Salutations, Sirish.
Si vous connaissez le nom de l'éditeur, c'est très simple.
Par exemple, si le nom de l'éditeur est editor1 (this is the id of div or textarea)
, il vous suffit de cocher la case suivante:
if(CKEDITOR.instances['editor1']){
// Instance present
}else{
// Instance not present
}
Si vous voulez obtenir le nombre d'éditeurs initialisés, faites comme ci-dessous
for(let inst of CKEDITOR.instances){
// inst is an Obj of editor instance
// inst.name will give the name of the editor instance
}
Pour prendre en charge le chargement dynamique (Ajax) de formulaires (sans actualisations de page entre) contenant des zones de texte avec le même (le même formulaire est appelé à nouveau) ou des ID différents (formulaire précédemment non chargé) et les convertir en éléments CKEditor, j’ai procédé comme suit (à l’aide de JQuery adaptateur):
Une fois que la page a terminé chaque appel Ajax qui fournit une zone de texte à convertir, je passe un appel à la fonction suivante:
setupCKeditor()
Cela ressemble à ceci (cela suppose que vos zones de texte soient converties en RTE ont class = "yourCKClass" ):
/* Turns textAreas into TinyMCE Rich Text Editors where
* class: tinymce applied to textarea.
*/
function setupCKeditor(){
// define editor configuration
var config = {skin : 'kama'};
// Remove and recreate any existing CKEditor instances
var count = 0;
if (CKEDITOR.instances !== 'undefined') {
for(var i in CKEDITOR.instances) {
var oEditor = CKEDITOR.instances[i];
var editorName = oEditor.name;
// Get the editor data.
var data = $('#'+editorName).val();
// Check if current instance in loop is the same as the textarea on current page
if ($('textarea.yourCKClass').attr('id') == editorName) {
if(CKEDITOR.instances[editorName]) {
// delete and recreate the editor
delete CKEDITOR.instances[editorName];
$('#'+editorName).ckeditor(function() { },config);
count++;
}
}
}
}
// If no editor's exist in the DOM, create any that are needed.
if (count == 0){
$('textarea.yourCKClass').each( function(index) {
var editorName = $(this).attr('id');
$('#'+editorName).ckeditor(function() { $('#'+editorName).val(data); },config);
});
}
}
Je devrais mentionner que la ligne:
$('#'+editorName).ckeditor(function() { $('#'+editorName).val(data); },config);
pourrait (et devrait) être simplement:
$('#'+editorName).ckeditor(function() { },config);
cependant, j'ai constaté que l'éditeur montrait souvent le contenu correct pendant une seconde après le chargement et les viderait à l'éditeur du contenu souhaité. Donc, cette ligne avec le code de rappel oblige le contenu de CKEditor à être identique au contenu textarea d'origine. Provoque un scintillement lorsqu'il est utilisé. Si vous pouvez éviter de l'utiliser, faites-le.