User:Catrope/W3C Range feature requests

Changing the text contents of a range

edit

Say you're writing a toolbar for a textarea, and you want to replace the selection with something else when the user clicks a toolbar button. In IE, you'd grab a TextRange object and do:

range.text = 'newtext';

whereas in e.g. Firefox you're stuck with something like:

// Get start and end position of selection
textarea.value = textarea.value.substring(0, startPos) + 'newtext' + textarea.value.substring(endPos, textarea.value.length);

which is slow when textarea.value.length is on the order of 100k.

Of course a feature like this is only reasonable when the selection is plain text from a textarea or text box; when the selection is DOM stuff with mixed markup etc. I can see how that complicates things. In such a case, however, the developer should be able to use surroundContents() and DOM manipulation.

Filed W3C bug 11745. —Simetrical (talk • contribs) 00:15, 3 February 2011 (UTC)

I eventually closed the bug. I just don't see why this needs to be slow. Test case:

data:text/html,<!doctype html> 
<textarea></textarea> 
<button onclick=test()>Test</button> 
<script> 
"use strict"; 
var textarea = document.querySelector("textarea"); 
textarea.value = "x"; 
for (var i = 0; i < 17; i++) { 
    textarea.value += textarea.value; 
} 
 
function test() { 
    var pos = Math.random() * textarea.value.length; 
    textarea.value = textarea.value.substr(0, pos) + "test string" + textarea.value.substr(pos); 
} 
</script>

Paste into your URL bar. It seems responsive enough to me on latest Chrome, Firefox, and Opera. Timing shows they all take in the ballpark of 100 ms or less. Adding features for performance doesn't seem necessary given how fast browsers are improving their JS engine speed, and this particular use-case looks fast enough to me. —Simetrical (talk • contribs) 00:54, 21 February 2011 (UTC)

Requirement for the selection to be linked to the caret position

edit

If the selection is empty (collapsed, so that it has only one segment and that segment's start and end points are the same) then the selection's position should equal the caret position

(From [1], emphasis mine.)

Please consider making this requirement stronger. Under certain circumstances in certain browsers (at least Opera, possibly Webkit as well, not quite sure) it's possible for the caret to be blinking somewhere but for selection.rangeCount to be zero, which means there's no way to find out where the cursor is. From my reading of the standard, this behavior is allowed (but recommended against); if that reading is correct, I would like it to be a requirement ("MUST") so it's always possible to locate the caret (unless of course there is none).

I've just updated the spec. (The spec is currently living on someone's Bitbucket account, but it will find its way to somewhere more official-looking at some point.) —Simetrical (talk • contribs) 00:15, 3 February 2011 (UTC)

Unhelpful duality for startOffset/endOffset

edit

This is specifically aimed at W3C Range, because TextRange doesn't have this functionality at all. In W3C Range, one can use the startContainer attribute to find out where the start of the selection is. If the startContainer is a text node, startOffset will be a character offset into this text node. So far so good. However, if startContainer is not a text node, startOffset will be an node offset (i.e. number of child node) into the start node. This indicates the start of the selection being right before startContainer.childNodes[startOffset] IIRC. (Of course the same situation applies to endContainer and endOffset.) This is unhelpful for several reasons:

  • startOffset has different meanings depending on the node type of startContainer, which is generally awkward
  • Instead of simply being able to do something like range.beforeStart to get the node right before the start of the selection, you have to do offset arithmetic and verify the offset is valid (if the selection ends after the last child node, endOffset will be childNodes.length IIRC, which is out of bounds in childNodes[])
  • Getting the character offset into the start node is awkward: you have to loop over all child nodes of startContainer before the startOffset, traverse all of their descendants to find text nodes, and add up their lengths. It would be more helpful to have an attribute that always returns the character offset into startContainer, regardless of whether that happens to be a text node.
Not really fixable; this is a design problem with the API. We're not likely to add redundant properties just to make them easier to use – you can write wrapper functions if it's a problem. There are already way too many redundant properties on Selection and Range. —Simetrical (talk • contribs) 00:15, 3 February 2011 (UTC)

Getting the position (x,y) of the selection

edit

It's pretty much impossible to obtain the (x,y) position or offset of a range. Obtaining the (x,y) offset of the startContainer is possible, but doesn't help very much if it's an element with large dimensions (say an 80x25 textarea). I would like for a range object to have (immutable) top, left, height and width attributes (or even just startTop, startLeft, endTop, endLeft, as ranges aren't necessarily rectangular). The main use case for this (for me) would be to scroll the selected text in a textarea into view. IE allows the latter with range.select();.

This might be tricky, because a Range can actually translate into a collection of boxes scattered all over the screen. Consider floats, RTL text, absolute positioning, display: none, etc. Ranges aren't used for textareas anyway, are they? An API to scroll to a particular text location in a textarea makes sense; are there any other use-cases? —Simetrical (talk • contribs) 00:15, 3 February 2011 (UTC)
I just found this. range.getClientRects() does what you want for Ranges, but it only works on Ranges (so it can't handle selections in textareas). —Simetrical (talk • contribs) 20:17, 30 March 2011 (UTC)

Newline handling in stringification of getSelection()

edit

When the selection is something like <p>Foo bar</p><p>baz quux</p>, stringifying the selection yields bar\nbaz in Gecko (and Webkit IIRC) but barbaz in Opera. From reading the standard it's not clear which one is correct, but the one with the newline seems more intuitive to me.

I'm standardizing this now. (The spec is currently about innerText, but stringification of Selection will use the same algorithm.) The standard behavior will be like Gecko and WebKit, with newlines inserted around block elements. —Simetrical (talk • contribs) 00:15, 3 February 2011 (UTC)
. . . Or maybe it won't. We'll have to see. But there will be something standard, I hope. —Simetrical (talk • contribs) 20:52, 4 February 2011 (UTC)