views:

3663

answers:

6

If I'm inserting content into a textarea that TinyMCE has co-opted, what's the best way to set the position of the cursor/caret?

I'm using tinyMCE.execCommand("mceInsertRawHTML", false, content); to insert the content, and I'd like set the cursor position to the end of the content.

Both document.selection and myField.selectionStart won't work for this, and I feel as though this is going to be supported by TinyMCE (through something I can't find on their forum) or it's going to be a really ugly hack.

Later: It gets better; I just figured out that, when you load TinyMCE in WordPress, it loads the entire editor in an embedded iframe.

Later (2): I can use document.getElementById('content_ifr').contentDocument.getSelection(); to get the selection as a string, but not a Selection Object that I can use getRangeAt(0) on. Making progress little by little.

A: 

Bit of a hack, but in raw javascript something like this would work for an input.

var myText = document.getElementById("myTextBox");
myText.value = myText.value;
James Wiseman
You'd use this to get the value of the textarea though, right? That's a simple task; it's setting the position of the cursor after I add content that I'm most interested in.
Daniel Bachhuber
A: 

I've plagiarized this from here.

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); 
    } 
}
camomileCase
I think the big issue is that TinyMCE loads the content within an iframe in WordPress. Normally something like this would work, but `getSelection()` only returns a string and not a selection. I'm using .selectionStart when manipulating the textarea that the HTML editor uses, but it doesn't work for the TinyMCE iframe.
Daniel Bachhuber
A: 

Why not look at our API documentation. It provides instructions on how to manipulate the selection of the editor instances.

Spocke
I actually read all through the documentation (and forum) and didn't find any information that applied to my specific use case. Granted, it's a pretty unique case. I thought I solved it earlier but I might be back to having the caret jump to the top of the box. I'll write a fuller synopsis when I figure this out.
Daniel Bachhuber
Having just spent 40 minutes in the TinyMCE docs trying to find an answer for how to reposition the caret at the end of content after inserting list items (as opposed to positioning it inside the inserted LI) it is very frustrating to me that Spocke simply suggests the answer is obvious and easy to find. At the very least a link to the section of the docs referenced would have been polite.
jerrygarciuh
+3  A: 

After spending over 15 hours on this issue (dedication, I know), I found a partial solution that works in FF and Safari, but not in IE. For the moment, this is good enough for me although I might continue working on it in the future.

The solution: When inserting HTML at the current caret position, the best function to use is:

tinyMCE.activeEditor.selection.setContent(htmlcontent);

In Firefox and Safari, this function will insert the content at the current caret position within the iframe that WordPress uses as a TinyMCE editor. The issue with IE 7 and 8 is that the function seems to add the content to the top of the page, not the iframe (i.e. it completely misses the text editor). To address this issue, I added a conditional statement based on this code that will use this function instead for IE:

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

The issue for this second function, however, is that the caret position is set to the beginning of the post area after it has been called (with no hope of recalling it based on the browser range, etc.). Somewhere near the end I discovered that this function works to restore the caret position at the end of the inserted content with the first function:

tinyMCE.activeEditor.focus();

In addition, it restores the caret position to the end of the inserted content without having to calculate the length of the inserted text. The downside is that it only works with the first insertion function which seems to cause problems in IE 7 and IE 8 (which might be more of a WordPress fault than TinyMCE).

A wordy answer, I know. Feel free to ask questions for clarification.

Daniel Bachhuber
A: 

First what you should do is add a at the end of the content you want to create.

<span id="caret_pos_holder"></span>

Then once inserted, do this...

ed.selection.select(ed.dom.select('span#caret_pos_holder')[0]); //select the span
ed.dom.remove(ed.dom.select('span#caret_pos_holder')[0]); //remove the span

This is a strategy used by the TinyMCE developers themselves in writing Selection.js. Reading the underlying source can be massively helpful for this kind of problem.

Garry Tan
A: 

... delete this one... (dupe entry)

Garry Tan