private onKeyUpDomEvent()

in packages/roosterjs-editor-plugins/lib/plugins/Picker/PickerPlugin.ts [300:392]


    private onKeyUpDomEvent(event: PluginKeyboardEvent) {
        if (this.isSuggesting) {
            // Word before cursor represents the text prior to the cursor, up to and including the trigger symbol.
            const wordBeforeCursor = this.getWord(event);
            const wordBeforeCursorWithoutTriggerChar = wordBeforeCursor.substring(1);
            const trimmedWordBeforeCursor = wordBeforeCursorWithoutTriggerChar.trim();

            // If we hit a case where wordBeforeCursor is just the trigger character,
            // that means we've gotten a onKeyUp event right after it's been typed.
            // Otherwise, update the query string when:
            // 1. There's an actual value
            // 2. That actual value isn't just pure whitespace
            // 3. That actual value isn't more than 4 words long (at which point we assume the person kept typing)
            // Otherwise, we want to dismiss the picker plugin's UX.
            if (
                wordBeforeCursor == this.pickerOptions.triggerCharacter ||
                (trimmedWordBeforeCursor &&
                    trimmedWordBeforeCursor.length > 0 &&
                    trimmedWordBeforeCursor.split(' ').length <= 4)
            ) {
                this.dataProvider.queryStringUpdated(
                    trimmedWordBeforeCursor,
                    wordBeforeCursorWithoutTriggerChar == trimmedWordBeforeCursor
                );
                this.setLastKnownRange(this.editor.getSelectionRange());
            } else {
                this.setIsSuggesting(false);
            }
        } else {
            let wordBeforeCursor = this.getWordBeforeCursor(event);
            if (!this.blockSuggestions) {
                if (
                    wordBeforeCursor != null &&
                    wordBeforeCursor.split(' ').length <= 4 &&
                    wordBeforeCursor[0] == this.pickerOptions.triggerCharacter
                ) {
                    this.setIsSuggesting(true);
                    const wordBeforeCursorWithoutTriggerChar = wordBeforeCursor.substring(1);
                    let trimmedWordBeforeCursor = wordBeforeCursorWithoutTriggerChar.trim();
                    this.dataProvider.queryStringUpdated(
                        trimmedWordBeforeCursor,
                        wordBeforeCursorWithoutTriggerChar == trimmedWordBeforeCursor
                    );
                    this.setLastKnownRange(this.editor.getSelectionRange());
                    if (this.dataProvider.setCursorPoint) {
                        // Determine the bounding rectangle for the @mention
                        let searcher = this.editor.getContentSearcherOfCursor(event);
                        let rangeNode = this.editor.getDocument().createRange();
                        let nodeBeforeCursor = searcher.getInlineElementBefore().getContainerNode();
                        let rangeStartSuccessfullySet = this.setRangeStart(
                            rangeNode,
                            nodeBeforeCursor,
                            wordBeforeCursor
                        );
                        if (!rangeStartSuccessfullySet) {
                            // VSO 24891: Out of range error is occurring because nodeBeforeCursor
                            // is not including the trigger character. In this case, the node before
                            // the node before cursor is the trigger character, and this is where the range should start.
                            let nodeBeforeNodeBeforeCursor = nodeBeforeCursor.previousSibling;
                            this.setRangeStart(
                                rangeNode,
                                nodeBeforeNodeBeforeCursor,
                                this.pickerOptions.triggerCharacter
                            );
                        }
                        let rect = rangeNode.getBoundingClientRect();

                        // Safari's support for range.getBoundingClientRect is incomplete.
                        // We perform this check to fall back to getClientRects in case it's at the page origin.
                        if (rect.left == 0 && rect.bottom == 0 && rect.top == 0) {
                            rect = rangeNode.getClientRects()[0];
                        }

                        if (rect) {
                            rangeNode.detach();

                            // Display the @mention popup in the correct place
                            let targetPoint = { x: rect.left, y: (rect.bottom + rect.top) / 2 };
                            let bufferZone = (rect.bottom - rect.top) / 2;
                            this.dataProvider.setCursorPoint(targetPoint, bufferZone);
                        }
                    }
                }
            } else {
                if (
                    wordBeforeCursor != null &&
                    wordBeforeCursor[0] != this.pickerOptions.triggerCharacter
                ) {
                    this.blockSuggestions = false;
                }
            }
        }
    }