-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
caret-based selection movement #27
Comments
I am not sure each of these should behave the same. In the first, the subsequently typed text should not be italic, in the second it should be italic (because it is inside the In practice they won't look the same either because the editor UI usually provides feedback on the style about to be used by showing the style buttons as pressed (the [i] button would be "pushed/on" in the second case.)
I think the default behavior should mimic existing paradigms for editing UIs, so I played with a couple of existing "standard" rich text editors to see how they behaved (Mac's textEdit and Google "Docs".) The result I have so far is as follows. (assume we have entered 'Hello Austria!', and the country name is italic)
With this we can say that the default position of the caret when the user places it at the beginning of an element like
This "default" position for caret should be in effect when user presses arrow keys to move caret around and when the user clicks the mouse to place the cursor at the edge of an element. By the way it turns out this is already the default behavior on the browsers I tested (Safari, Chrome, FF, IE11). |
You are right, the [I]-button would probably be pushed. More importantly though, the user cannot switch between the two places of the caret. The browser will decide where it goes. Defining the default position as you do seems to make the issue go away. However: notice that while this works for i-elements, it's quite different for links, where the default position seem to be:
This difference in behavior should be spec'ed and it should be made clear when which of the two applies. |
I just fired up my old MS Word 2000 and found that they handle links the same way you found in browsers (outside by default). Google docs handles links in the same manner as I can't think of a reason why there should be two different behaviors? Good user interfaces tend to be consistent. My inclination is to specify that the default cursor position is the same regardless of the element. |
Really? That's weird. I tested Google Docs and Gmail using Chrome 39 on Linux, and in both cases it exited the link when typing at the end of it. Same applies to LibreOffice 4.3.3.2. |
I think the behavior should be both consistent across browsers and "reasonable" in the sense that it would correspond to a normal setup for an editor. If one of those two conditions is not given, all editors will constantly have to check where the caret is in relation to its surroundings before executing a character insertion. As for why links are treated differently: Possibly because the makers of browsers thought it easier to exit Take the below test. In Chrome the behavior at the end of the three lines is:
In Firefox the behavior is however;
Source:
|
Actually I take that back. In Google Docs it's outside ~ outside as you've noticed. However, when the cursor is at the end of the link, the U button is depressed and the text-color button indicates the color is blue giving the impression that it's outside-inside. However, once you start typing that all goes away and you're inserting unstyled text. I agree that it's probably because it's easier to cancel a '' than an '' that the behavior is different. I really don't love that there are two behaviors, but it seems that if most existing rich editors do it this way it would be sensible to specify:
Are there other elements/situations to consider? One caveat is that this should only apply to inline elements. For block elements we probably need to think about this some more. Another aspect to look into which is very important is the relationship between the data provided by the getSelection API versus where text actually ends up going upon typing. To me, for the sake of developer experience there is no question it should 1-to-1: text gets inserted wherever the selection API says the caret is. For that to work the selection API has to be able to convey that info accurately under all circumstances. I'm not 100% sure it can do that yet. Need to look into it. |
Not that I can think of. But it doesn't seem very HTML5-like that something is hardcoded to only work on |
I agree. It seems arbitrary. And if it can't be controlled on a per-element basis it's even worse. CSS could maybe be used to help with this. Maybe we should explore other areas of this issue (caret movement around block elements, void elements) as that might make the right solution come to light. |
Ok, true, maybe that leads us somewhere. Check out this example: https://bug873883.bugzilla.mozilla.org/attachment.cgi?id=751510 . All of the elements there should be handled as single characters: SVGs, void elements such as canvas elements, a noneditable element. The possible exception: What should happen when hitting the right arrow?
or
? |
I agree it seems we want to give users the ability to insert text immediately on either side of anything that is in their content but they can't edit. What if we specified the general rule that any visible but non-editable part of the document should be treated in its entirety as a single character as far as caret movement is concerned? A visible but non-editable part of the document could be: an SVG, IMAGE, VIDEO, whatever. Also, it implies the visible characters (and any other dom element) inside a cE=false. Given your first example the result would be this:
Also, by defining behavior in terms of "visible content" we handle some odd edge cases in a manner that I think is best for the user:
Do you think these make sense as default behaviors? |
With "Also, it implies the visible characters (and any other dom element) inside a cE=false." you mean that the caret jumps inside of any cE=true should these exist within a cE=false? Your example result makes me think that. Could you give an example in which a cE=false should be treated "transparently"? With "transparent" you mean that the caret jumps across it together with either the character before or after it, right? But which one of those is ti going to be? And how do you insert text just before AND just after such an invisible element? |
I wonder whether it would be easier to stay consistent if empty SVGs and empty cE=false as well as invisible elements were treated the same as single characters as it's hard to know when they are really empty. But I am not a browser developer. Maybe it's easy for them to distinguish. Imagine for example this case (using webkit css version of cE):
|
Yes, I was going on the assumption that we would want the caret to jump inside a cE=true that is nested inside a cE=false should there be such a situation. It seems if there is an editable area it should be reachable via arrow keys? I'm open on this though. Here's an example of what I meant with "cE=false transparent":
Whether the caret jumps the cE=false with the character before or after it is a matter of picking one and spec'ing that.
If the element is empty or is not visible (display:none) then the user has no way of knowing which side of the element the caret is on anyways. It will seem like pressing the arrow key has no effect (that caret won't physically move between the before and after position).
I agree that UAs will have a hard time really knowing whether an SVG or other element is really empty. Also, empty elements can still have visible borders, and other things that give them a visible presence. So I think you're right it's better to be consistent and treat SVGs the same whether they are empty or not. However, I'm still a bit torn on elements that are display:none. Invisible elements are completely removed from the document layout, and have no possible visible manifestation. The caret would just be "stuck" for a moment with no obvious reason why. Further, the UAs already track that property closely for their layouts, so there is little reason to think this would cause them a problem. |
Hey, I agree on your first point -- one should jump in to the cE=true when moving carets. If we were talking delete/backspace into it, I would however disagree and think it's poorly handled in Webkit/Blink currently, but luckily we will not have to worry about that any more if we don't handle backspace/delete. On your last point: I agree it would be confusing if the caret doesn't move because there is a display:none element there. But it would also be problematic if it would be completely impossible to move the caret either directly before or after it (at least programmaticly). Maybe we should start out by looking at possible use cases for this? The one example I can think of are when using a system to "track changes" but currently hiding them: http://nytimes.github.io/ice/demo/ (click on "Show/Hide changes"). In that case it would indeed make sense to do as you suggest. However, I would probably generally think this is quite advanced usage and possibly should be handled by cE=typing at all. |
The way I see it we are just trying to sort out default behaviors (what the UA does if the user's Intent is allowed to continue without intervention by the editor). I think that editor dev would be able to programmatically set the caret on either side of the display:none element if necessary. Edit: there is also the possibility (although a bit more far fetched) that this behavior would be customziable via CSS: "caret-outside: both | left | right;" However I am not sure we should tackle this in V1. It's bound to be full of edge cases...
Sure! May I turn this around on you? What use case is there where an invisible display:none element should be treated as one character? |
I can't think of a good example. :) Ok, let's at least at least make sure to define the behavior exactly it. Should we say that it should handle the hidden element together with the character that follows it? Or are there good reasons not to go with that? |
I think browsers currently tend to move the caret to the end of text nodes then to offset 1 of the next text node. Seeing as it's kind of arbitrary anyways let's specify this?
|
Caret movement ideas from Olivier http://lists.w3.org/Archives/Public/public-editing-tf/2014Dec/0031.html):
Entry via arrow keys:
Entry via editor's setSelection:
Entry via external factors: If the editable position is removed from DOM or made non-editable, what do we do?
Once an editable selection is set: |
Spec'ing exactly how caret is moved upon arrow keys is hard because different browsers behave differently with respect to bidirectional text. Some would move the caret logically forward & backward whereas some would move the caret visually left or right. However, we can probably specify what kind of DOM positions should be used (e.g. inner most element versus outermost) when UAs DO move the caret in response to user actions. |
Here is what I'm hearing so far:
I agree with most of this. I think 3 doesn't really matter because we want to spec the default behavior of Responsive Input Events, not keyboard events. We should have a good way to indicate the platform agnostic meaning of the relevant beforeSelectionChange events, which is an open question I suppose. I don't think 2 should have special cases. They can be handled in frameworks if they really matter. |
Here is a possible algorithm for move caret. It relies on carets only being allowed in visible text nodes. Note that empty text nodes are fine, they just can't be invisible.
For For |
This discussion so far seems to assume that the selection is empty before and after any change. Some things change if we consider non-empty selections and the ability to extend and shrink selections: |
Re "left-gravity": Please use "left" and "right" only if you're sure they're the right terms, either because you know the current writing direction or because the present use is independent of the writing direction. I think in this case you mean logical "before" or "after". |
Re "determine the next position in the given direction in the current text node if it exists": |
Right, let's not conflate left/right and next/previous. Left and right are visual directions while next and previous are logical directions. Left and right arrow keys may, for example, move caret between lines in vertical writing mode. Since binding a particular key press to a semantic event is precisely what Responsive Input Events are for, we shouldn't talk in terms of key press here. We should only talk in terms of semantic events such as moving forward between characters and lines. Like I mentioned previously, the challenge here is that some caret movements such as of a word boundary depends on implementation-dependent heuristics so we can't precisely define how it works. So we should focus on how normalization works after caret move instead of trying to define what moving to left/right or forwards/backwards do. |
@rniwa : Right. So if I understand you right, you are saying that the way Firefox handles caret movement, where 1 right key + 1 left key does not result in the caret being where it initially was necessarily, is not something that could be spec'ed? |
Right, we can spec that non-editable elements are treated like a single character. The problem with word boundary movements is that the treatment of whitespace is different amongst browsers. e.g. trailing or leading whitespace may or may not be considered as a part of a word. Also, in Chinese and Japanese, word boundaries can only be determined by heuristics. See http://www.quora.com/What-are-some-Japanese-tokenizers-or-tokenization-strategies |
Ok, but this difference in how browsers behave is exactly what we want to stop by spec'ing things, right? The idea is to get behavior which editor developers (and end users) can rely on. If the caret moves an extra space in certain browsers while not in others, that can be the cause of a major headache for editor developers, who may find it easier to just override the word boundary movement mechanism altogether in order to ensure consistent behavior. As for Japanese, Chinese, etc.: Could we spec word boundary movements for all text using the Roman or Greek alphabets? |
The problem is that the difference in how whitespaces are treated come from the difference in the underlying platform convention: Mac and Windows. And I don't feel compelled to spec word boundary movements just for a subset of languages. |
Well, but you do need to define word boundary movement for example for Japanese then, right? That seems like a much smaller subset of languages than all languages using Greek/Latin alphabets. Word boundary movements may not be the most important thing to spec in the world, but that there are languages that have specific rules does not seem like a good reason not to do so. |
No, the point is that we can't define word boundary movement for Japanese because word boundaries can only be guessed via heuristics such as dictionary-based lookups in Japanese. And most of European languages use a space as a word delimiter so we can't define the behavior there either due to the treatment of whitespace being platform-dependent. |
Yes, so the spec for Japanese would include a description a la "space based word boundary movement does not apply. word boundary movement does either not take place at all or follows a dictionary based pattern. If we were talking about a special way the caret has to move around the Danish/Norwegian æ-character, which doesn't apply to any other language, I would agree that maybe it would be overkill to spec that. But for anything related to 8 of the top 10 languages on the internet (Roman/Russian/Greek alphabet based) it seems like this should be something we should be concerned with. Now the issue with different behavior in Mac OS X and Windows may be more complicated and we should find out what to do about that. |
I don't think we can spec. word boundary movement. Also, various browsers support other granularities of caret movements. For example, Safari supports moving the caret by sentences and paragraphs. And I don't think we want to be in the business of defining what a sentence or a paragraph of text means. In general, any attempt to define how selection gets updated in response to a user action won't be fruitful. The thing we can and should spec here is the normalization of Range browsers would apply after the user had changed the selection. |
Why would we not specify hat a sentence and what a paragraph are, if these are important for caret movement? Just because we define it, doesn't mean that all browsers are obliged to implement sentence/paragraph movement as a feature. It's just that once a specific browser decides to implement one of these features, they do so in a predictable manner. The current situation, in which each browsers do a lot of things differently and even differ in their behavior from platform to platform and between browser versions is the main issue we are tying to deal with, as I understand it. Currently many editors need to interrupt caret movements in Javascript and after a number of checks decide whether or not to let the default action go through. This is quite a lot of work just or right/left arrows. If additionally each browser does its own thing, which is unspec'ed (and likely not well documented), it becomes exponentially more difficult to get it right. That being said, I agree that the normalization of the caret placement seems to be the most important thing here. |
I don't think a Web developer should have any expectation as to how a caret moves in response to a given key down/press. It would be entirely platform dependent. Ben's Responsive Input Events should solve the use case you're talking about by providing a new selection/range before the selection is actually changed. A Web site/app can inspect and adjust this new range before it is actually set. |
I agree with @rniwa for not to define caret movements in the spec, especially word/sentence boundaries. Instead, beforeSelectionChange event in Ben's proposal could carry the original intent that caused the selection change. If a framework would like to ignore platform-standard behavior but its own standard behavior, it can trap such events and adjust selections as needed. I suppose framework is easier if the original intent is known, no? Are we also going to define:
|
That there are differences between browsers or operating systems doesn't necessarily preclude a spec. For space handling, we could specify two alternatives, and say that a browser can choose which one to use, but that it has to stick with it at least for the lifetime of the document, and that it cannot invent something different. For word boundaries, we can say that the determination of the word itself is implementation dependent, but then specify the behavior relying on the word boundaries. You can see this in the specification for NumberFormat.prototype.format in the ECMAScript Internationalization API: The spec is very precise as to how to map a number to a string of digits, but then leaves several aspects of the localization of this string implementation dependent, such as which digits to use for which locale, or which decimal and grouping separators to use or where to insert the grouping separators. The idea is that the numeric value should be recognizable in any localized format. The question though is what level if precision would help application developers. |
This is no longer relevant with cE=intentions. |
Reopening the issue since this is still an issue outside of |
The selection Api so far doesn't talk about changing the selection when moving the caret.
This will only apply when cE=typing and cE=true are specified, so it may have to go into another document.
If it's not specified anywhere, and browsers choose to implement it different, we won't be sure so we will need to continue to interrupt each key stroke event to check whether the caret may be at the border of an element before letting it do its default action. Then it may be easier to use a hidden textarea for input instead of cE=typing.
Two issues come to mind:
Caret at the end of an inline element
If the user hits the right-key and then enters a "!", where should that end?
And what is the intermediate step? To the user, these two situations will look the same:
so it seems it would be reasonable that they will behave the same as well.
It should be ensured that the movement of the caret is the same in all browsers.
There are some well-known issues with that now, mostly related to the caret "jumping" another character when moving across inline void elements, foreign elements (SVGs) or elements that are specified as being noneditable or the caret not being able to go certain places (such as before one of the before mentioned elements when these are at the start of a block element). In all these cases, I believe it should be specified that these elements should be treated like single characters in relation to caret movement.
The text was updated successfully, but these errors were encountered: