|
export default function lexicalMarkSelection( |
|
editor: LexicalEditor, |
|
onReposition?: (node: Array<HTMLElement>) => void, |
|
): () => void { |
|
let previousAnchorNode = null; |
|
let previousAnchorOffset = null; |
|
let previousFocusNode = null; |
|
let previousFocusOffset = null; |
|
let removeRangeListener: () => void = emptyFunction; |
|
function compute(editorState: EditorState) { |
|
editorState.read(() => { |
|
const selection = $getSelection(); |
|
if (!$isRangeSelection(selection)) { |
|
// TODO |
|
previousAnchorNode = null; |
|
previousAnchorOffset = null; |
|
previousFocusNode = null; |
|
previousFocusOffset = null; |
|
removeRangeListener(); |
|
removeRangeListener = emptyFunction; |
|
return; |
|
} |
|
const {anchor, focus} = selection; |
|
const currentAnchorNode = anchor.getNode(); |
|
const currentAnchorNodeKey = currentAnchorNode.getKey(); |
|
const currentAnchorOffset = anchor.offset; |
|
const currentFocusNode = focus.getNode(); |
|
const currentFocusNodeKey = currentFocusNode.getKey(); |
|
const currentFocusOffset = focus.offset; |
|
const currentAnchorNodeDOM = editor.getElementByKey(currentAnchorNodeKey); |
|
const currentFocusNodeDOM = editor.getElementByKey(currentFocusNodeKey); |
|
const differentAnchorDOM = |
|
previousAnchorNode === null || |
|
currentAnchorNodeDOM === null || |
|
currentAnchorOffset !== previousAnchorOffset || |
|
currentAnchorNodeKey !== previousAnchorNode.getKey() || |
|
(currentAnchorNode !== previousAnchorNode && |
|
(!(previousAnchorNode instanceof TextNode) || |
|
currentAnchorNode.updateDOM( |
|
previousAnchorNode, |
|
currentAnchorNodeDOM, |
|
editor._config, |
|
))); |
|
const differentFocusDOM = |
|
previousFocusNode === null || |
|
currentFocusNodeDOM === null || |
|
currentFocusOffset !== previousFocusOffset || |
|
currentFocusNodeKey !== previousFocusNode.getKey() || |
|
(currentFocusNode !== previousFocusNode && |
|
(!(previousFocusNode instanceof TextNode) || |
|
currentFocusNode.updateDOM( |
|
previousFocusNode, |
|
currentFocusNodeDOM, |
|
editor._config, |
|
))); |
|
if (differentAnchorDOM || differentFocusDOM) { |
|
const anchorHTMLElement = editor.getElementByKey( |
|
anchor.getNode().getKey(), |
|
); |
|
const focusHTMLElement = editor.getElementByKey( |
|
focus.getNode().getKey(), |
|
); |
|
// TODO handle selection beyond the common TextNode |
|
if ( |
|
anchorHTMLElement !== null && |
|
focusHTMLElement !== null && |
|
anchorHTMLElement.tagName === 'SPAN' && |
|
focusHTMLElement.tagName === 'SPAN' |
|
) { |
|
const range = document.createRange(); |
|
let firstHTMLElement; |
|
let firstOffset; |
|
let lastHTMLElement; |
|
let lastOffset; |
|
if (focus.isBefore(anchor)) { |
|
firstHTMLElement = focusHTMLElement; |
|
firstOffset = focus.offset; |
|
lastHTMLElement = anchorHTMLElement; |
|
lastOffset = anchor.offset; |
|
} else { |
|
firstHTMLElement = anchorHTMLElement; |
|
firstOffset = anchor.offset; |
|
lastHTMLElement = focusHTMLElement; |
|
lastOffset = focus.offset; |
|
} |
|
range.setStart(nullthrows(firstHTMLElement.firstChild), firstOffset); |
|
range.setEnd(nullthrows(lastHTMLElement.firstChild), lastOffset); |
|
removeRangeListener(); |
|
removeRangeListener = lexicalPositionNodeOnRange( |
|
editor, |
|
range, |
|
domNodes => { |
|
if (onReposition === undefined) { |
|
for (const domNode of domNodes) { |
|
const domNodeStyle = domNode.style; |
|
if (domNodeStyle.background !== 'Highlight') { |
|
domNodeStyle.background = 'Highlight'; |
|
} |
|
if (domNodeStyle.color !== 'HighlightText') { |
|
domNodeStyle.color = 'HighlightText'; |
|
} |
|
if (domNodeStyle.zIndex !== '-1') { |
|
domNodeStyle.zIndex = '-1'; |
|
} |
|
} |
|
} else { |
|
onReposition(domNodes); |
|
} |
|
}, |
|
); |
|
} |
|
} |
|
previousAnchorNode = currentAnchorNode; |
|
previousAnchorOffset = currentAnchorOffset; |
|
previousFocusNode = currentFocusNode; |
|
previousFocusOffset = currentFocusOffset; |
|
}); |
|
} |
|
compute(editor.getEditorState()); |
|
return mergeRegister( |
|
editor.registerUpdateListener(({editorState}) => compute(editorState)), |
|
removeRangeListener, |
|
() => { |
|
removeRangeListener(); |
|
}, |
|
); |
|
} |