22

Is there a way to set the cursor to be at the end of the contents of a CKEditor?

This developer asked too, but received no answers:

http://cksource.com/forums/viewtopic.php?f=11&t=19877&hilit=cursor+end

I would like to set the focus at the end of the text inside a CKEditor. When I use:

ckEditor.focus();

It takes me to the beginning of the text already inside the CKEditor.

halfer
  • 19,824
  • 17
  • 99
  • 186
BrooklynDev
  • 900
  • 2
  • 12
  • 25

9 Answers9

25

Dan's answer got strange results for me, but minor change (in addition to typo fix) made it work:

var range = me.editor.createRange();
range.moveToElementEditEnd( range.root );
me.editor.getSelection().selectRanges( [ range ] );
Peter Tracey
  • 260
  • 3
  • 4
  • 2
    Thanks, same here. Dan's solution did insert the caret for me, but at the right-most point in the editor in line with the expected end point. Yours has fixed it, thanks. – halfer Feb 27 '14 at 16:47
  • 1
    Thanks this works.. now to figure out how to programatically enter the editor (focus doesn't bring a caret up) – Dominic Jul 17 '15 at 10:08
  • in my case, the code set's the caret at the end, but didn't scroll to the end. So I could see only the caret, when I used the scrollbars to go to the end. I helped myself with me.editor.insertHtml(""); and that did the job. – NilsB Jan 08 '22 at 10:51
12

According to the documentation for CKEditor 4, you can do the following once you have the editor object.

var range = editor.createRange();
range.moveToPosition( range.root, CKEDITOR.POSITION_BEFORE_END );
editor.getSelection().selectRanges( [ range ] );

Link: http://docs.ckeditor.com/#!/api/CKEDITOR.dom.selection (under selectRanges function).

Dan
  • 885
  • 6
  • 11
  • What the heck is `[ranges]`?? Is the "s" a typo? – mpen May 23 '13 at 16:10
  • @Mark, thanks for the catch. It should be `range`. That's what I get for not verifying the CKEditor documentation. – Dan May 28 '13 at 16:17
  • I wasn't quite sure because the square-bracket syntax makes it almost look like a placeholder for something different. – mpen May 28 '13 at 23:03
  • Unfortunately, not the cleanest of code. For anyone that's not familiar with JavaScript, `selectRanges` accepts an array of [`CKEDITOR.dom.range`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.range) objects, and `[range]` creates an array with only the `range` object in it. – Dan May 29 '13 at 12:51
  • Yes, I figured that out, but the typo through me off :-) Most of those CKEDITOR objects seem to be thin wrappers around the native equivalents. – mpen May 29 '13 at 16:50
  • @Dan and anyone - whenever you find a bug in the documentation feel free to either report it @ http://dev.ckeditor.com or in case of typos simply create a pull request @ https://github.com/ckeditor/ckeditor-dev – Wiktor Walc Jan 03 '14 at 14:37
  • So where exactly are you guys putting this code at?? – Abela Feb 21 '14 at 12:29
  • @Yokhannan: you can run this in a button click handler if your editor is already initialised - get the editor instance from `CKEDITOR.instances.your_name` if necessary. If you are running this code within page initialisation, you'll need to do it within the `instanceReady` CKEditor event, otherwise it will try to assign focus before the editor is able to accept it. – halfer Feb 27 '14 at 16:51
  • Unfortunatly it doesn't seems to work anymore with 4.4.8. maybe a bug. Not sure. – Clawfire Mar 11 '15 at 10:51
5

After a bit of fiddling, I've got it to work with the following code:

$(document).ready(function() {

    CKEDITOR.on('instanceReady', function(ev) {

        ev.editor.focus();

        var s = ev.editor.getSelection(); // getting selection
        var selected_ranges = s.getRanges(); // getting ranges
        var node = selected_ranges[0].startContainer; // selecting the starting node
        var parents = node.getParents(true);

        node = parents[parents.length - 2].getFirst();

        while (true) {
            var x = node.getNext();
            if (x == null) {
                break;
            }
            node = x;
        }

        s.selectElement(node);
        selected_ranges = s.getRanges();
        selected_ranges[0].collapse(false);  //  false collapses the range to the end of the selected node, true before the node.
        s.selectRanges(selected_ranges);  // putting the current selection there
    }

});

The idea is:

  1. Get the root node (not body)
  2. Advance to next node, until there are no more nodes to advance to.
  3. Select last node.
  4. Collapse it
  5. Set range
Kees C. Bakker
  • 32,294
  • 27
  • 115
  • 203
4

Here's a similar answer to @peter-tracey. In my case my plugin is inserting a citation. If the user has made a selection, I needed to disable the selection and place the cursor at the end of the sentence.

  // Obtain the current selection & range
  var selection = editor.getSelection();
  var ranges = selection.getRanges();
  var range = ranges[0];

  // Create a new range from the editor object
  var newRange = editor.createRange();

  // assign the newRange to move to the end of the current selection
  // using the range.endContainer element.
  var moveToEnd = true;
  newRange.moveToElementEditablePosition(range.endContainer, moveToEnd);

  // change selection
  var newRanges = [newRange];
  selection.selectRanges(newRanges);

  // now I can insert html without erasing the previously selected text.
  editor.insertHtml("<span>Hello World!</span>");
Paul
  • 595
  • 6
  • 6
2

CKEditor 3.x:

on : {
        'instanceReady': function(ev) {
           ev.editor.focus();
           var range = new CKEDITOR.dom.range( ev.editor.document );
           range.collapse(false);
           range.selectNodeContents( ev.editor.document.getBody() );
           range.collapse(false);
           ev.editor.getSelection().selectRanges( [ range ] );
        }
     }

based on pseudo-code provided by the developers here:

https://dev.ckeditor.com/ticket/9546#comment:3

You have to focus editor, get document object, put it in range, collapse range (with false parameter), select body (with selectNodeContents), collapse it (with false parameter) and finally select range. It is best to do it all in instanceReady event.

whereisalext
  • 680
  • 6
  • 12
1

This is the easiest solution provided by the ckeditor API. I have tested it on IE10+, ff, safari and Chrome:

range = editor.createRange();
// the first parameter is the last line text element of the ckeditor instance
range.moveToPosition(new CKEDITOR.dom.node(editor.element.$.children[pos - 1]), CKEDITOR.POSITION_BEFORE_END)
range.collapse()
editor.getSelection().selectRanges([ range ])
Chang
  • 1,658
  • 1
  • 17
  • 23
1

This will work for sure. CKEDITOR.config.startupFocus = 'end';

ARC
  • 1,061
  • 14
  • 33
0

have you tried ckEditor.Selection.Collapse(false);

Adyt
  • 1,442
  • 7
  • 26
  • 38
  • 3
    I'm not seeing what call your talking about exactly. What's the precise syntax? I don't see a Selection field on my ckeditor object. – BrooklynDev Jan 06 '11 at 22:59
0

According to CKEditor 4 documentation, another option is:

const range = this.ckeditor.createRange()
range.moveToElementEditablePosition(range.root, true)
this.ckeditor.getSelection().selectRanges([range])

Link: https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_dom_range.html#method-moveToElementEditablePosition

Imamudin Naseem
  • 1,604
  • 18
  • 21