-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Improving edge detection in blocks #3015
Changes from 2 commits
ddc6924
c19d314
5d49715
d397895
0440939
b155f83
f6b8364
6202575
d50f6c6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,50 @@ | ||
const NODE_TEXT_TYPE = 3; | ||
const NODE_ELEMENT_TYPE = 1; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In other modules, we've been using: /**
* Browser dependencies
*/
const { ELEMENT_NODE, TEXT_NODE } = window.Node There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I was hoping it would be somewhere. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
|
||
function getCursorStart( /* node */ ) { | ||
// NOTE: In the future, we may want to skip some non-inhabitable positions in some nodes | ||
return 0; | ||
} | ||
|
||
function getCursorEnd( node ) { | ||
// NOTE: In the future, this might be a place to ignore special characters that browsers ignore | ||
if ( node.nodeType === NODE_TEXT_TYPE ) { | ||
return node.nodeValue.length; | ||
} | ||
|
||
// We may need exceptions for other empty tags as well (e.g. hr, br, input) | ||
if ( node.nodeType === NODE_ELEMENT_TYPE && node.nodeName.toLowerCase() === 'img' ) { | ||
return 1; | ||
} | ||
|
||
// Non text nodes have a last cursor position of their number of children | ||
return node.childNodes.length; | ||
} | ||
|
||
/** | ||
* Check whether the offset is at the start of the node | ||
* | ||
* @param {Element} node the DOM element | ||
* @param {Integer} offset the offset | ||
* @return {Boolean} whether or not the offset is at the first cursor position in node | ||
*/ | ||
export function isAtCursorStart( node, offset ) { | ||
const nodeStart = getCursorStart( node ); | ||
return nodeStart === offset; | ||
} | ||
|
||
/** | ||
* Check whether the offset is at the end of the node | ||
* | ||
* @param {Element} node the DOM element | ||
* @param {Integer} offset the offset | ||
* @return {Boolean} whether or not the offset is at the last cursor position in node | ||
*/ | ||
export function isAtCursorEnd( node, offset ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might it make sense to only introduce one method ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You would, for the tests, but maybe we can test There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With your above change to just use isEdge outside instead of needing to call an internal method, my preference would be to keep the methods for isAtCursorStart, but only expose isEdge. How does that sound? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The major reason is it just increases the likelihood that lots of code won't have to change if it turns out that you have to start ignoring some offsets for start (like empty text nodes). It can get fairly gnarly with text node fragmentation. Having the cursor calculations in one spot helps in the long run. But yep, if we are able to use isEdge the other place I changed, then definitely only expose that one and just test it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's exactly what I mean. :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only isEdge is exposed now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What I also meant though: maybe we can only keep only |
||
const nodeEnd = getCursorEnd( node ); | ||
return nodeEnd === offset; | ||
} | ||
|
||
/** | ||
* Check whether the selection touches an edge of the container | ||
* | ||
|
@@ -34,11 +81,11 @@ export function isEdge( container, start = false ) { | |
return false; | ||
} | ||
|
||
if ( start && offset !== 0 ) { | ||
if ( start && ! isAtCursorStart( node, offset ) ) { | ||
return false; | ||
} | ||
|
||
if ( ! start && offset !== node.textContent.length ) { | ||
if ( ! start && ! isAtCursorEnd( node, offset ) ) { | ||
return false; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we replace these methods entirely?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As is use
isEdge( editor.getBody(), true )
for isStart andisEdge( editor.getBody(), false )
for end ? I think you're right. Nice catch :)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In terms of avoiding the need to understand that boolean, are you OK with me exporting LEFT_EDGE = true and RIGHT_EDGE = false as constants, and then using them in this file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or alternatively exposing isLeftEdge and isRightEdge?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe
isEdge( { container: Element, start: Boolean } )
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll defer to your preference :) I guess it matches the name in the range API for collapsing, which is most likely what you're basing it on. I've always found start a very strange name for a boolean, but that's just person taste.
I'm working on this now, so are you OK with the idea of exposing constants for the second argument or would you prefer passing an object like your last suggestion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think an object might be better for now, since it's just adding the braces. :) But that's just my opinion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used object notation as recommended.