web-dev-qa-db-fra.com

Quelle est la meilleure façon de définir la position du curseur/caret?

Si j'insère du contenu dans une zone de texte cooptée par TinyMCE, quel est le meilleur moyen de définir la position du curseur/curseur?

J'utilise tinyMCE.execCommand("mceInsertRawHTML", false, content); pour insérer le contenu et j'aimerais définir la position du curseur à la fin du contenu.

document.selection et myField.selectionStart ne fonctionneront pas pour cela, et je sens que cela va être supporté par TinyMCE (via quelque chose que je ne trouve pas sur leur forum) ou que ce sera un bidouillage vraiment moche.

Plus tard: Ça va mieux; Je viens de comprendre que, lorsque vous chargez TinyMCE dans WordPress, l’éditeur entier est chargé dans un iframe intégré.

Plus tard (2): Je peux utiliser document.getElementById('content_ifr').contentDocument.getSelection(); pour obtenir la sélection sous forme de chaîne, mais pas d'objet Selection sur lequel je peux utiliser getRangeAt(0). Faire des progrès petit à petit.

30
Daniel Bachhuber

Tout d’abord, vous devez ajouter une étendue à la fin du contenu que vous souhaitez créer.

var ed = tinyMCE.activeEditor;

//add an empty span with a unique id
var endId = tinymce.DOM.uniqueId();
ed.dom.add(ed.getBody(), 'span', {'id': endId}, '');

//select that span
var newNode = ed.dom.select('span#' + endId);
ed.selection.select(newNode[0]);

Il s’agit d’une stratégie utilisée par les développeurs TinyMCE eux-mêmes pour écrire Selection.js. La lecture de la source sous-jacente peut s'avérer extrêmement utile pour résoudre ce type de problème.

27
Garry Tan

C'est tellement simple de déplacer le curseur à la fin que je ne peux pas croire les horribles kludges qui ont été postés ailleurs en ligne pour le faire. La réponse de M. Spocke n'était pas utile au départ, mais les documents de l'API m'ont finalement fourni la réponse. "Sélectionner tout le contenu puis réduire la sélection":

ed.selection.select(ed.getBody(), true); // ed is the editor instance

ed.selection.collapse(false);

J'espère que cela aidera quelqu'un d'autre, car ce fil est l'un des premiers à apparaître dans Google.

15
Peter Wooster

Le meilleur moyen que j'ai trouvé est d'insérer le contenu avec un identifiant temporaire, puis de le focaliser à l'aide de trucs trouvés dans le plugin advlink .

J'espère que cela t'aides.

            var ed = tinyMCE.activeEditor;

            ed.execCommand('mceInsertContent', false, '<a id="_mce_temp_rob" href="http://robubu.com">robubu.com</a>');

            //horrible hack to put the cursor in the right spot
            ed.focus(); //give the editor focus
            ed.selection.select(ed.dom.select('#_mce_temp_rob')[0]); //select the inserted element
            ed.selection.collapse(0); //collapses the selection to the end of the range, so the cursor is after the inserted element
            ed.dom.setAttrib('_mce_temp_rob', 'id', ''); //remove the temp id

Si vous faites cela depuis un popup, je pense que vous devez aussi ajouter

        tinyMCEPopup.storeSelection();

avant de fermer le popup.

Pour ceux qui essaient d'insérer du contenu d'une méta-boîte personnalisée Wordpress dans l'éditeur TinyMCE, c'est la solution qui fonctionne. J'ai essayé une tonne d'autres scripts, y compris un autre sur cette page, la réponse ci-dessus de Gary Tan, qui a fonctionné pour moi lors de l'installation des boutons personnalisés de TinyMCE mais n'a pas fonctionné dans ce scénario.

6
robyates

La solution correcte consiste à utiliser le tinyMCE api tinymce.dom.Selection

http://www.tinymce.com/wiki.php/API3:class.tinymce.dom.Selection

la syntaxe est quelque chose comme: 

var rng = tinymce.DOM.createRng();  // the range obj
var newNode = editor.dom.select(...    // find the correct selector so that newNode is the element of your editor text
rng.setStart(newNode.firstChild, 0); // 0 is the offset : here it will be at the beginning of the line.
rng.setEnd(newNode.firstChild, 0);
editor.selection.setRng(rng);

cela fonctionne, je l'utilise moi-même.

6
Benibur

J'ai plagié cela de ici .

function setCaretTo(obj, pos) { 
    if(obj.createTextRange) { 
        /* Create a TextRange, set the internal pointer to
           a specified position and show the cursor at this
           position
        */ 
        var range = obj.createTextRange(); 
        range.move("character", pos); 
        range.select(); 
    } else if(obj.selectionStart) { 
        /* Gecko is a little bit shorter on that. Simply
           focus the element and set the selection to a
           specified position
        */ 
        obj.focus(); 
        obj.setSelectionRange(pos, pos); 
    } 
} 
1
camomileCase

Insérez un nœud DOM à l'emplacement actuel de sélection/caret.

tinyMCE.activeEditor.selection.setNode(tinyMCE.activeEditor.dom.create('img', {src : 'some.gif', title : 'some title'}));
1
Ljubisha

Juste en jetant mes propres 2 cents ici. Aucun de ceux-ci n'a répondu à ma question. Je ne mettais pas dans un élément HTML, mais un bloc de texte ([code][/code] par exemple) et j'avais besoin que le curseur se place entre les deux.

En utilisant une partie de @robyates answer, ce que j’ai fait, c’est de placer un élément HTML temporaire entre les balises 2 [code], de me concentrer sur celui-ci, puis de supprimer complètement l’élément HTML. Voici mon code:

setup : function(ed) {
    // Add a custom button
    ed.addButton('codeblock', {
        title : 'Code Block',
        text : '[code/]',
        icon: false,
        onclick : function() {
            // Add you own code to execute something on click
            ed.focus();
            //ed.selection.setContent('[code][/code]');
            ed.execCommand('mceInsertContent', false, '[code]<span id="_cursor" />[/code]');

            ed.selection.select(ed.dom.select('#_cursor')[0]); //select the inserted element
            ed.selection.collapse(0); //collapses the selection to the end of the range, so the cursor is after the inserted element
            ed.dom.remove('_cursor'); //remove the element
        }
    });
}
1
James

Donc, voici la solution de notre projet. Notre objectif était de remplacer les chaînes (+)/(-)/(?) par les images appropriées "à la volée" lors de la frappe par l'utilisateur.

Il y avait un problème: chaque fois que la chaîne était passée à l'image, le curseur marquait le début de l'image, mais pas jusqu'à la fin, comme prévu.

Nous avons ajouté une grande partie du code qui déplace le curseur à la fin de l'image afin que l'utilisateur puisse taper en continu sans interrompre le curseur "saccadé".

Partie clé: au lieu d’utiliser editor.getBody, il existe un moyen plus élégant de créer l’intervalle temporaire et de le supprimer immédiatement après les actions nécessaires.

if (value.match(/\([+?-]\)/)) {
        // set current cursor via span
        editor.selection.setContent('<span id="temp-span"/>');

        // refresh Content with new span
        value = editor.getContent();

        // changing (+)/(-)/(?) to the appropriate image "on the fly"
        value = value.replace('(+)', ' <img src="https://url_here/static/task_manager/img/add.png">&nbsp;');
        value = value.replace('(-)', ' <img src="https://url_here/static/task_manager/img/forbidden.png">&nbsp;');
        value = value.replace('(?)', ' <img src="https://url_here/static/task_manager/img/help_16.png">&nbsp;');
        if (this.state.editor) {
            editor.setContent(value);

            // move cursor to the latter span
            var newNode = editor.dom.select('span#temp-span');
            editor.selection.select(newNode[0]);
            editor.selection.setContent('');
        }
        // and refreshing content again w/o span
        value = editor.getContent();
    }
1
Pavel Druzhinin

C'est la solution qui fonctionne pour moi:

// params: 
//   $node: jquery node with tinymce loaded 
//   text: text to set at then before caret
function setTextAndCaretToEnd($node, text) {
     var ed = window.tinyMCE.get($node.attr("id"));
     ed.focus();
     ed.selection.setContent(text);
}
0
vfportero