Skip to content

Commit

Permalink
fix(react-editor): reset focus offset when triple clicking (#4512)
Browse files Browse the repository at this point in the history
* fix(react-editor): reset focus offset when triple clicking

* fix(react editor): remove commented-out code
  • Loading branch information
bytrangle authored Sep 13, 2021
1 parent 2af6868 commit cc7cb62
Showing 1 changed file with 38 additions and 25 deletions.
63 changes: 38 additions & 25 deletions packages/slate-react/src/plugin/react-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -572,36 +572,49 @@ export const ReactEditor = {
// beginning of the next block
if (
IS_CHROME &&
anchorNode?.nodeType !== focusNode?.nodeType &&
anchorNode &&
focusNode &&
anchorNode.nodeType !== focusNode.nodeType &&
domRange.anchorOffset === 0 &&
domRange.focusOffset === 0 &&
focusNode?.nodeValue == null
focusNode.nodeValue == null
) {
// If an anchorNode is an element node when triple clicked, then the focusNode
// should also be the same as anchorNode when triple clicked.
if (anchorNode!.nodeType === 1) {
focusNode = anchorNode
} else {
// Otherwise, anchorNode is a text node and we need to
// - climb up the DOM tree to get the farthest element node that receives
// triple click. It should have atribute 'data-slate-node' = "element"
// - get the last child of that element node
// - climb down the DOM tree to get the text node of the last child
// - this is also the end of the selection aka the focusNode
const anchorElement = anchorNode!.parentNode as HTMLElement
const tripleClickedBlock = anchorElement.closest(
'[data-slate-node="element"]'
)
const focusElement = tripleClickedBlock!.lastElementChild
// Get the element node that holds the focus text node
// Not every Slate element node contains a child node with `data-slate-string`,
// such as void nodes, so the result below could be null.
const innermostFocusElement = focusElement!.querySelector(
'[data-slate-string]'
)
if (innermostFocusElement) {
const lastTextNode = innermostFocusElement.childNodes[0]
focusNode = lastTextNode
// Otherwise, anchorNode is a text node and we need to
// - climb up the DOM tree to get the farthest element node that receives
// triple click. It should have atribute 'data-slate-node' = "element"
// - get the last child of that element node
// - climb down the DOM tree to get the text node of the last child
// - this is also the end of the selection aka the focusNode
const anchorElement = anchorNode.parentNode as HTMLElement
const selectedBlock = anchorElement.closest(
'[data-slate-node="element"]'
)
if (selectedBlock) {
// The Slate Text nodes are leaf-level and contains document's text.
// However, when represented in the DOM, they are actually Element nodes
// and different from the DOM's Text nodes
const { childElementCount: slateTextNodeCount } = selectedBlock
if (slateTextNodeCount === 1) {
focusNode = anchorNode as Text
focusOffset = focusNode.length
} else if (slateTextNodeCount > 1) {
// A element with attribute data-slate-node="element" can have multiple
// children with attribute data-slate-node="text". But these children only have
// one child at each level.
// <span data-slate-node="text">
// <span data-slate-leaf="">
// <span data-slate-string=""></span>
// </span>
// </span>
const focusElement = selectedBlock.lastElementChild as HTMLElement
const nodeIterator = document.createNodeIterator(
focusElement,
NodeFilter.SHOW_TEXT
)
focusNode = nodeIterator.nextNode() as Text
focusOffset = focusNode.length
}
}
}
Expand Down

0 comments on commit cc7cb62

Please sign in to comment.