wake-up-neo.com

Wie kann ich die Cursor-/Caret-Position am besten einstellen?

Wenn ich Inhalte in ein Textfeld einfügen möchte, das von TinyMCE ausgewählt wurde, wie kann ich dann die Position des Cursors/Caret einstellen?

Ich benutze tinyMCE.execCommand("mceInsertRawHTML", false, content);, um den Inhalt einzufügen, und ich möchte die Cursorposition an das Ende des Inhalts setzen.

Sowohl document.selection als auch myField.selectionStart funktionieren dafür nicht und ich glaube, dass dies von TinyMCE unterstützt wird (durch etwas, was ich in ihrem Forum nicht finden kann) oder es wird ein wirklich hässlicher Hack.

Später: Es wird besser; Ich habe gerade herausgefunden, dass, wenn Sie TinyMCE in WordPress laden, der gesamte Editor in einen eingebetteten Iframe geladen wird.

Später (2): Ich kann document.getElementById('content_ifr').contentDocument.getSelection(); verwenden, um die Auswahl als String abzurufen, nicht jedoch ein Auswahlobjekt, für das ich getRangeAt(0) verwenden kann. Nach und nach Fortschritte erzielen.

30

Nachdem ich mehr als 15 Stunden mit diesem Problem verbracht hatte (Widmung, ich weiß), fand ich eine Teillösung, die in FF und Safari funktioniert, aber nicht in IE. Im Moment ist das gut genug für mich, obwohl ich vielleicht in Zukunft weiter daran arbeiten werde.

Die Lösung: Wenn Sie HTML an der aktuellen Position einfügen, ist die beste Funktion:

tinyMCE.activeEditor.selection.setContent(htmlcontent);

In Firefox und Safari fügt diese Funktion den Inhalt an der aktuellen Caret-Position im iframe ein, den WordPress als TinyMCE-Editor verwendet. Das Problem mit IE 7 und 8 ist, dass die Funktion den Inhalt anscheinend oben auf der Seite hinzufügt, nicht im iframe (d. H., Der Texteditor fehlt vollständig). Um dieses Problem zu beheben, habe ich eine bedingte Anweisung basierend auf diesem Code hinzugefügt, die diese Funktion stattdessen für IE verwendet:

tinyMCE.activeEditor.execCommand("mceInsertRawHTML", false, htmlcontent);

Das Problem bei dieser zweiten Funktion ist jedoch, dass die Position des Einfügemarke nach dem Aufrufen auf den Anfang des Postbereichs gesetzt wird (ohne die Hoffnung, sie anhand des Browserbereichs usw. wieder aufzurufen). Irgendwann gegen Ende entdeckte ich, dass diese Funktion funktioniert, um die Position des Einfügemarke am Ende des eingefügten Inhalts mit der ersten Funktion wiederherzustellen:

tinyMCE.activeEditor.focus();

Außerdem wird die Position des Einfügemarke an das Ende des eingefügten Inhalts zurückgesetzt, ohne dass die Länge des eingefügten Texts berechnet werden muss. Der Nachteil ist, dass es nur mit der ersten Einfügefunktion funktioniert, die Probleme in IE 7 und IE 8 zu verursachen scheint (was möglicherweise eher ein WordPress Fehler ist) als TinyMCE).

Eine wortreiche Antwort, ich weiß. Fühlen Sie sich frei, Fragen zur Klärung zu stellen.

25

Zuerst sollten Sie am Ende des Inhalts, den Sie erstellen möchten, einen Bereich hinzufügen.

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]);

Dies ist eine Strategie, die die TinyMCE-Entwickler beim Schreiben von Selection.js selbst verwenden. Das Lesen der zugrunde liegenden Quelle kann für diese Art von Problem äußerst hilfreich sein.

27
Garry Tan

Es ist so einfach, den Mauszeiger an das Ende zu bewegen, sodass ich die schrecklichen Kludges, die an anderer Stelle online gestellt wurden, nicht glauben kann. Die Antwort von Herrn Spocke war anfangs nicht hilfreich, aber am Ende lieferten mir die API-Dokumente die Antwort. "Alle Inhalte auswählen und die Auswahl dann reduzieren":

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

ed.selection.collapse(false);

Ich hoffe, das hilft jemand anderem, da dieser Thread einer der ersten ist, der in Google auftaucht.

15
Peter Wooster

Der beste Weg, den ich gefunden habe, ist, den Inhalt mit einer temporären ID einzufügen und diesen Fokus dann mit Hilfe einiger Tricks zu verwenden, die ich im advlink plugin gefunden habe.

Hoffe das hilft.

            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

Wenn Sie dies von einem Popup aus machen, müssen Sie auch hinzufügen

        tinyMCEPopup.storeSelection();

bevor Sie das Popup schließen.

Für jeden, der versucht, Inhalte aus einer benutzerdefinierten Wordpress-Meta-Box in den TinyMCE-Editor einzufügen, ist dies die Lösung, die funktioniert. Ich habe eine Menge anderer Skripte ausprobiert, darunter ein weiteres auf dieser Seite, die Antwort von Gary Tan, die für mich beim Installieren von benutzerdefinierten TinyMCE-Knöpfen funktionierte, aber in diesem Szenario nicht funktionierte.

6
robyates

Die richtige Lösung ist, die tinyMCE api tinymce.dom.Selection zu verwenden

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

die Syntax ist so etwas wie: 

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);

es funktioniert, ich benutze das selbst.

6
Benibur

Ich füge HTML-Inhalt an der aktuellen Position ein (ohne in diesem übergeordneten HTML-Element zu bleiben):

editor.insertContent( '<div>My html inserted code here...</div>' + '&nbsp;' , {format: 'html'} );

Dieses Leerzeichen am Ende stellt sicher, dass der weiter eingegebene Text außerhalb des eingefügten div-Elements platziert wird.

1
Richard Bdžoch

Ich habe dies von hier plagiiert.

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

Fügen Sie einen DOM-Knoten an der aktuellen Auswahl-/Einfügemarke ein.

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

Ich habe hier nur meine eigenen 2 Cent eingeworfen. Keines davon hat meine Frage beantwortet. Ich habe kein HTML-Element eingefügt, sondern einen Textblock (zum Beispiel [code][/code]) und brauchte den Cursor, um zwischen den beiden zu wechseln.

Mit einem Teil der Antwort von @robyates habe ich ein temporäres HTML-Element zwischen die 2 [code]-Tags eingefügt. Hier ist mein 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

Hier ist also die Lösung aus unserem Projekt. Unser Ziel war es, (+)/(-)/(?)-Zeichenfolgen während der Eingabe in die entsprechenden Bilder "on the fly" zu ändern.

Es gab ein Problem: Jedes Mal, wenn der String in ein Bild geändert wurde, ging der Cursor am Anfang des Bildes und nicht wie erwartet an das Ende.

Wir haben einen Großteil des Codes hinzugefügt, der den Cursor zum Ende des Bildes bewegt, sodass der Benutzer fortlaufend eingeben kann, ohne den "sprunghaften" Cursor zu unterbrechen.

Schlüsselteil: Anstelle von editor.getBody gibt es eine elegantere Methode, um die temporäre Spanne zu erstellen und sie sofort nach den erforderlichen Aktionen zu löschen.

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

In der kleinen Version 5

editor.selection.setCursorLocation(editor.getBody(), editor.getBody().childElementCount);
0
Qrzysio

Dies ist die Lösung, die für mich funktioniert:

// 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