Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/moody-eggs-juggle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---

Fixes an issue where the cursor jumped to the wrong position after inserting a mention at the start or middle of a message.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { createComposerAPI } from './createComposerAPI';

jest.mock('../../../../client/lib/chats/uploads', () => ({
createUploadsAPI: () => ({}),
}));

const setupComposer = (initialValue: string, cursor: { start: number; end: number }) => {
const input = document.createElement('textarea');
document.body.appendChild(input);

const composer = createComposerAPI(input, jest.fn(), '', Number.MAX_SAFE_INTEGER, { current: null }, { rid: 'GENERAL' });

input.value = initialValue;
input.setSelectionRange(cursor.start, cursor.end);

return { composer, input };
};

afterEach(() => {
document.body.innerHTML = '';
});

describe('ChatMessages Composer API - replaceText', () => {
it('should place the cursor right after the mention when inserting at the start of the message', () => {
const { composer, input } = setupComposer('@jhello', { start: 2, end: 2 });

composer.replaceText('@john ', { start: 0, end: 2 });

expect(input.value).toBe('@john hello');
expect(input.selectionStart).toBe('@john '.length);
expect(input.selectionEnd).toBe('@john '.length);
});

it('should place the cursor right after the mention when inserting in the middle of the message', () => {
const { composer, input } = setupComposer('hi @jthere', { start: 5, end: 5 });

composer.replaceText('@john ', { start: 3, end: 5 });

expect(input.value).toBe('hi @john there');
expect(input.selectionStart).toBe('hi @john '.length);
expect(input.selectionEnd).toBe('hi @john '.length);
});

it('should place the cursor right after the mention when inserting at the end of the message', () => {
const { composer, input } = setupComposer('hello @j', { start: 8, end: 8 });

composer.replaceText('@john ', { start: 6, end: 8 });

expect(input.value).toBe('hello @john ');
expect(input.selectionStart).toBe('hello @john '.length);
expect(input.selectionEnd).toBe('hello @john '.length);
});

it('should keep the cursor collapsed right after the inserted text', () => {
const { composer, input } = setupComposer('@jhello', { start: 2, end: 2 });

composer.replaceText('@john ', { start: 0, end: 2 });

expect(input.selectionStart).toBe(input.selectionEnd);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,6 @@ export const createComposerAPI = (

// Gets the text that is connected to the cursor and replaces it with the given text
const replaceText = (text: string, selection: { readonly start: number; readonly end: number }): void => {
const { selectionStart, selectionEnd } = input;

// Selects the text that is connected to the cursor
input.setSelectionRange(selection.start ?? 0, selection.end ?? text.length);
const textAreaTxt = input.value;
Expand All @@ -298,11 +296,9 @@ export const createComposerAPI = (
input.value = textAreaTxt.substring(0, selection.start) + text + textAreaTxt.substring(selection.end);
}

input.selectionStart = selectionStart + text.length;
input.selectionEnd = selectionStart + text.length;
if (selectionStart !== selectionEnd) {
input.selectionStart = selectionStart;
}
const cursorPosition = (selection.start ?? 0) + text.length;
input.selectionStart = cursorPosition;
input.selectionEnd = cursorPosition;

triggerEvent(input, 'input');
triggerEvent(input, 'change');
Expand Down
Loading