6

I'm trying to create a selection that goes from right to left in the text, but it seems the DOM Range API doesn't let me do that. (I don't see anything about this in the spec - not that I read it closely - but all implementations seem to agree on not supporting it.)

For example, given a very minimal document:

data:text/html,<div> this is a test </div>

I can use this script to enable editing and create a normal selection (for example from a bookmarklet, but line wrapping added for clarity):

javascript:document.designMode='on';
var r=document.createRange(),d=document.getElementsByTagName('div')[0]; 
r.setStart(d.firstChild, 3); 
r.setEnd(d.firstChild, 7); 
window.getSelection().addRange(r); void(0);

However, if I swap 3 and 7 no selection is created.

Does anyone know a way to do this?

hallvors
  • 6,069
  • 1
  • 25
  • 43
  • What is the difference between a range that goes left to right, and right to left? As far as I can see, the only difference is the ability to extend the selection with the arrows to the left. – Ruan Mendes Jan 26 '11 at 05:10
  • @Juan: I may be missing some subtleties, but like you, the main difference I can see is arrow key behaviour (all arrow keys, with and without Shift and Ctrl modifier keys). Also, in some environments and browsers, the caret is displayed in addition to the selection, at the focus of the selection (i.e. the point at which the user stopped selecting). – Tim Down Jan 26 '11 at 09:44

1 Answers1

12

It's possible in recent versions of all major browsers except IE via the extend() method of the Selection object. Here's a function that creates a backwards selection from a Range:

function selectRangeBackwards(range) {
    var sel = window.getSelection();
    var endRange = range.cloneRange();
    endRange.collapse(false);
    sel.removeAllRanges();
    sel.addRange(endRange);
    sel.extend(range.startContainer, range.startOffset);
}

This is not possible in any version of IE (up to and including version 11). While IE 9 and later does implement DOM Level 2 Range and HTML5 Text Selection (now migrated to the WHATWG Range spec), the version of the spec at the time they implemented it did not include extend(), so IE 9 does not support it (see also this bug for further discussion of backwards selections).

Here is the request to implement extend() in the IE bug tracker: https://connect.microsoft.com/IE/feedback/details/737106/implement-missing-extend-method-of-selection

In earlier versions of IE, the selection API is completely different and does not have any support for programmatically creating backwards selections either.

Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • Hi Tim, this does not work as I'd expect or I missed something: after the usage of `extend`, the selection properly appears on my screen but if I do `document.getSelection()` the `anchorOffset` is smaller than the `focusOffset` which means the caret is on the right of the selection and not on the left of it. Do you know if there is some improvement so that the anchor and focus are properly set after the usage of `extend`? If I manually do a backward selection, I can see that `focusOffset` is _before_(smaller) `anchorOffset` and that's what I'd like to get. I'm working in a single text node. – sjahan Jan 25 '21 at 17:23
  • @sjahan: Which browser? I just tried it in Firefox and it was fine. – Tim Down Jan 29 '21 at 11:43
  • That was using Chrome! Actually, i solved my problem in a different way which does not need me to apply/check back selections so it's not really a problem :) But definitely, on Chrome, if I do a backward selection programmaticaly, if I check it back with `getSelection()` it has been turn to forward! It only happens when done programmatically, with the mouse, it is properly set backward. Probably a diff in the `extend` implementation! – sjahan Feb 01 '21 at 08:11
  • @sjahan: Works for me on Chrome on Ubuntu too. I would be extremely surprised if `extend()` behaviour was changed in Chrome because it is specified in the [W3C Selection specification](https://w3c.github.io/selection-api/#dom-selection-extend). – Tim Down Feb 01 '21 at 15:39
  • Maybe I do something wrong: check this fiddle: http://jsfiddle.net/739k8deh/ At the end, on Chrome (last version) on MacOS, i get `start at 2, end at 6`, although I expect `start at 6, end at 2`. The selection is fine, but not backward! – sjahan Feb 01 '21 at 17:01
  • I think I didn't get it or didn't set the instructions in the proper order because I get the same result in Firefox too (MacOs) so I think that's me making a mistake either in the implementation or in my understanding of this. – sjahan Feb 01 '21 at 17:09
  • 1
    @sjahan: Possibly. I've amended your fiddle so that it works: http://jsfiddle.net/krg728ud/ – Tim Down Feb 03 '21 at 00:44
  • Thank you very much Tim! Glad to have understood that :) – sjahan Feb 03 '21 at 07:37