Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 406edfc

Browse files
authored
Fix link creation with backward selection (#9986)
Fix link creation with backward selection
1 parent 222f8a9 commit 406edfc

File tree

8 files changed

+65
-5
lines changed

8 files changed

+65
-5
lines changed

cypress/e2e/composer/composer.spec.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ describe("Composer", () => {
9898
});
9999
});
100100

101-
describe("WYSIWYG", () => {
101+
describe("Rich text editor", () => {
102102
beforeEach(() => {
103103
cy.enableLabsFeature("feature_wysiwyg_composer");
104104
cy.initTestUser(homeserver, "Janet").then(() => {
@@ -165,5 +165,25 @@ describe("Composer", () => {
165165
cy.contains(".mx_EventTile_body", "my message 3");
166166
});
167167
});
168+
169+
describe("links", () => {
170+
it("create link with a forward selection", () => {
171+
// Type a message
172+
cy.get("div[contenteditable=true]").type("my message 0{selectAll}");
173+
174+
// Open link modal
175+
cy.get('button[aria-label="Link"]').click();
176+
// Fill the link field
177+
cy.get('input[label="Link"]').type("https://matrix.org/");
178+
// Click on save
179+
cy.get('button[type="submit"]').click();
180+
// Send the message
181+
cy.get('div[aria-label="Send message"]').click();
182+
183+
// It was sent
184+
cy.contains(".mx_EventTile_body a", "my message 0");
185+
cy.get(".mx_EventTile_body a").should("have.attr", "href").and("include", "https://matrix.org/");
186+
});
187+
});
168188
});
169189
});

src/components/views/rooms/wysiwyg_composer/ComposerContext.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { SubSelection } from "./types";
2020

2121
export function getDefaultContextValue(): { selection: SubSelection } {
2222
return {
23-
selection: { anchorNode: null, anchorOffset: 0, focusNode: null, focusOffset: 0 },
23+
selection: { anchorNode: null, anchorOffset: 0, focusNode: null, focusOffset: 0, isForward: true },
2424
};
2525
}
2626

src/components/views/rooms/wysiwyg_composer/hooks/useComposerFunctions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export function useComposerFunctions(
4444
anchorOffset: anchorOffset + text.length,
4545
focusNode: ref.current.firstChild,
4646
focusOffset: focusOffset + text.length,
47+
isForward: true,
4748
});
4849
setContent(ref.current.innerHTML);
4950
}

src/components/views/rooms/wysiwyg_composer/hooks/useSelection.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,15 @@ function setSelectionContext(composerContext: ComposerContextState): void {
2323
const selection = document.getSelection();
2424

2525
if (selection) {
26+
const range = selection.getRangeAt(0);
27+
const isForward = range.startContainer === selection.anchorNode && range.startOffset === selection.anchorOffset;
28+
2629
composerContext.selection = {
2730
anchorNode: selection.anchorNode,
2831
anchorOffset: selection.anchorOffset,
2932
focusNode: selection.focusNode,
3033
focusOffset: selection.focusOffset,
34+
isForward,
3135
};
3236
}
3337
}

src/components/views/rooms/wysiwyg_composer/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,6 @@ export type ComposerFunctions = {
1919
insertText: (text: string) => void;
2020
};
2121

22-
export type SubSelection = Pick<Selection, "anchorNode" | "anchorOffset" | "focusNode" | "focusOffset">;
22+
export type SubSelection = Pick<Selection, "anchorNode" | "anchorOffset" | "focusNode" | "focusOffset"> & {
23+
isForward: boolean;
24+
};

src/components/views/rooms/wysiwyg_composer/utils/selection.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,14 @@ import { SubSelection } from "../types";
1919
export function setSelection(selection: SubSelection): Promise<void> {
2020
if (selection.anchorNode && selection.focusNode) {
2121
const range = new Range();
22-
range.setStart(selection.anchorNode, selection.anchorOffset);
23-
range.setEnd(selection.focusNode, selection.focusOffset);
2422

23+
if (selection.isForward) {
24+
range.setStart(selection.anchorNode, selection.anchorOffset);
25+
range.setEnd(selection.focusNode, selection.focusOffset);
26+
} else {
27+
range.setStart(selection.focusNode, selection.focusOffset);
28+
range.setEnd(selection.anchorNode, selection.anchorOffset);
29+
}
2530
document.getSelection()?.removeAllRanges();
2631
document.getSelection()?.addRange(range);
2732
}

test/components/views/rooms/wysiwyg_composer/SendWysiwygComposer-test.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ describe("SendWysiwygComposer", () => {
299299
anchorOffset: 2,
300300
focusNode: textNode,
301301
focusOffset: 2,
302+
isForward: true,
302303
});
303304
// the event is not automatically fired by jest
304305
document.dispatchEvent(new CustomEvent("selectionchange"));
@@ -308,6 +309,32 @@ describe("SendWysiwygComposer", () => {
308309
// Then
309310
await waitFor(() => expect(screen.getByRole("textbox")).toHaveTextContent(/wo🦫rd/));
310311
});
312+
313+
it("Should add an emoji when a word is selected", async () => {
314+
// When
315+
screen.getByRole("textbox").focus();
316+
screen.getByRole("textbox").innerHTML = "word";
317+
fireEvent.input(screen.getByRole("textbox"), {
318+
data: "word",
319+
inputType: "insertText",
320+
});
321+
322+
const textNode = screen.getByRole("textbox").firstChild;
323+
await setSelection({
324+
anchorNode: textNode,
325+
anchorOffset: 3,
326+
focusNode: textNode,
327+
focusOffset: 2,
328+
isForward: false,
329+
});
330+
// the event is not automatically fired by jest
331+
document.dispatchEvent(new CustomEvent("selectionchange"));
332+
333+
emojiButton.click();
334+
335+
// Then
336+
await waitFor(() => expect(screen.getByRole("textbox")).toHaveTextContent(/wo🦫d/));
337+
});
311338
},
312339
);
313340
});

test/components/views/rooms/wysiwyg_composer/components/LinkModal-test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ describe("LinkModal", () => {
3535
anchorNode: null,
3636
focusOffset: 3,
3737
anchorOffset: 4,
38+
isForward: true,
3839
};
3940

4041
const customRender = (isTextEnabled: boolean, onClose: () => void, isEditing = false) => {

0 commit comments

Comments
 (0)