Merge branch 'develop' of github.com:vector-im/element-web into renovate/vector-im

This commit is contained in:
David Langley 2025-08-27 14:05:28 +01:00
commit 9dddaf732c
30 changed files with 127 additions and 10 deletions

View File

@ -100,3 +100,51 @@ test.describe("permalinks", () => {
});
});
});
test.describe("triple-click message selection", () => {
test.use({
displayName: "Alice",
});
test("should select entire message line when triple-clicking on message with pills", async ({
page,
app,
user,
bot,
}) => {
await bot.prepareClient();
const roomId = await app.client.createRoom({ name: "Test Room" });
await app.client.inviteUser(roomId, bot.credentials.userId);
await app.viewRoomByName("Test Room");
// Send a message with user and room pills
await app.client.sendMessage(
roomId,
`Testing triple-click message selection. ` +
`User: ${permalinkPrefix}${bot.credentials.userId}, ` +
`Room: ${permalinkPrefix}${roomId}, ` +
`Message: ${permalinkPrefix}${roomId}/$dummy-event, ` +
`and @room mention.`,
);
const timeline = page.locator(".mx_RoomView_timeline");
const messageTile = timeline.locator(".mx_EventTile").last();
// Triple-click on the message body to select its entire content
const messageBody = messageTile.locator(".mx_EventTile_body");
await messageBody.click({ clickCount: 3 });
// Get the expected text content of the message, including pills
const expectedText = await messageBody.innerText();
// Get the currently selected text from the page
const selectedText = await page.evaluate(() => {
const selection = window.getSelection();
return selection ? selection.toString().trim() : "";
});
// Verify that the selected text exactly matches the message content
expect(selectedText).toBe(expectedText);
});
});

View File

@ -11,8 +11,7 @@ Please see LICENSE files in the repository root for full details.
line-height: $font-17px;
border-radius: $font-16px;
vertical-align: text-top;
display: inline-flex;
align-items: center;
display: inline-block;
box-sizing: border-box;
max-width: 100%;
overflow: hidden;
@ -57,6 +56,8 @@ Please see LICENSE files in the repository root for full details.
margin-inline-start: -0.3em; /* Otherwise the gap is too large */
margin-inline-end: 0.2em;
min-width: $font-16px; /* ensure the avatar is not compressed */
user-select: text;
vertical-align: -2.5px;
}
.mx_Pill_text {

View File

@ -646,12 +646,12 @@
"mode_plain": "Skrýt formátování",
"mode_rich_text": "Zobrazit formátování",
"no_perms_notice": "Nemáte oprávnění zveřejňovat příspěvky v této místnosti",
"placeholder": "Odeslat zprávu…",
"placeholder_encrypted": "Odeslat šifrovanou zprávu…",
"placeholder_reply": "Odpovědět…",
"placeholder_reply_encrypted": "Odeslat šifrovanou odpověď…",
"placeholder_thread": "Odpovědět na vlákno…",
"placeholder_thread_encrypted": "Odpovědět na zašifrované vlákno…",
"placeholder": "Odeslat nešifrovanou zprávu…",
"placeholder_encrypted": "Odeslat zprávu...",
"placeholder_reply": "Odeslat nešifrovanou odpověď…",
"placeholder_reply_encrypted": "Odeslat odpověď…",
"placeholder_thread": "Odpovědět v nešifrovaném vláknu…",
"placeholder_thread_encrypted": "Odpovědět ve vláknu…",
"poll_button": "Hlasování",
"poll_button_no_perms_description": "Nemáte oprávnění zahajovat hlasování v této místnosti.",
"poll_button_no_perms_title": "Vyžaduje oprávnění",
@ -922,7 +922,8 @@
},
"privacy_warning": "Ujistěte se, že tuto obrazovku nikdo nevidí!",
"restoring": "Obnovení klíčů ze zálohy",
"security_key_title": "Klíč pro obnovení"
"security_key_label": "Klíč pro obnovení",
"security_key_title": "Zadejte klíč pro obnovení"
},
"bootstrap_title": "Příprava klíčů",
"confirm_encryption_setup_body": "Kliknutím na tlačítko níže potvrďte nastavení šifrování.",
@ -1367,6 +1368,10 @@
"name_email_mxid_share_space": "Pozvěte někoho pomocí jeho jména, e-mailové adresy, uživatelského jména (například <userId/>) nebo <a>sdílejte tento prostor</a>.",
"name_mxid_share_room": "Pozvěte někoho pomocí svého jména, uživatelského jména (například <userId />) nebo <a>sdílejte tuto místnost</a>.",
"name_mxid_share_space": "Pozvěte někoho pomocí jeho jména, uživatelského jména (například <userId/>) nebo <a>sdílejte tento prostor</a>.",
"progress": {
"dont_close": "Nezavírejte aplikaci, dokud neskončíte.",
"preparing": "Příprava pozvánek..."
},
"recents_section": "Nedávné konverzace",
"room_failed_partial": "Poslali jsme ostatním, ale níže uvedení lidé nemohli být pozváni do <RoomName/>",
"room_failed_partial_title": "Některé pozvánky nebylo možné odeslat",
@ -1535,6 +1540,9 @@
"render_reaction_images_description": "Někdy se označují jako \"vlastní emoji\".",
"report_to_moderators": "Nahlásit moderátorům",
"report_to_moderators_description": "V místnostech, které podporují moderování, můžete pomocí tlačítka \"Nahlásit\" nahlásit zneužití moderátorům místnosti.",
"share_history_on_invite": "Sdílet šifrovanou historii s novými členy",
"share_history_on_invite_description": "Při pozvání uživatele do šifrované místnosti, u které je viditelnost historie nastavena na „sdílená“, sdílet šifrovanou historii s tímto uživatelem a přijmout šifrovanou historii, když jste pozváni do takové místnosti.",
"share_history_on_invite_warning": "Tato funkce je EXPERIMENTÁLNÍ a nejsou v ní implementována všechna bezpečnostní opatření. Neaktivujte ji na produkčních účtech.",
"sliding_sync": "Režim klouzavé synchronizace",
"sliding_sync_description": "V aktivním vývoji, nelze zakázat.",
"sliding_sync_disabled_notice": "Pro vypnutí se odhlaste a znovu přihlaste",
@ -1657,6 +1665,7 @@
"filter_placeholder": "Najít člena místnosti",
"invite_button_no_perms_tooltip": "Nemáte oprávnění zvát uživatele",
"invited_label": "Pozván",
"list_title": "Seznam členů",
"no_matches": "Žádné shody"
},
"member_list_back_action_label": "Členové místnosti",
@ -1761,6 +1770,7 @@
},
"power_level": {
"admin": "Správce",
"creator": "Vlastník",
"custom": "Vlastní (%(level)s)",
"custom_level": "Vlastní úroveň",
"default": "Výchozí",
@ -1914,6 +1924,7 @@
"thread_list": {
"context_menu_label": "Možnosti vláken"
},
"title": "Pravý panel",
"video_room_chat": {
"title": "Chatovat"
}
@ -3400,6 +3411,7 @@
"unable_to_find": "Pokusili jste se načíst bod na časové ose místnosti, ale nepodařilo se ho najít."
},
"m.audio": {
"audio_player": "Audio přehrávač",
"error_downloading_audio": "Chyba při stahování audia",
"error_processing_audio": "Došlo k chybě při zpracovávání hlasové zprávy",
"error_processing_voice_message": "Chyba při zpracování hlasové zprávy",

View File

@ -654,6 +654,7 @@
"poll_button_no_perms_description": "Vous navez pas la permission de démarrer un sondage dans ce salon.",
"poll_button_no_perms_title": "Autorisation requise",
"replying_title": "Répond",
"room_unencrypted": "Les messages dans ce salon ne sont pas chiffrés de bout en bout",
"room_upgraded_link": "La discussion continue ici.",
"room_upgraded_notice": "Ce salon a été remplacé et nest plus actif.",
"send_button_title": "Envoyer le message",
@ -1366,6 +1367,10 @@
"name_email_mxid_share_space": "Invitez quelquun grâce à son nom, adresse e-mail, nom dutilisateur (tel que <userId/>) ou <a>partagez cet espace</a>.",
"name_mxid_share_room": "Invitez quelquun à partir de son nom, pseudo (comme <userId/>) ou <a>partagez ce salon</a>.",
"name_mxid_share_space": "Invitez quelquun grâce à son nom, nom dutilisateur (tel que <userId/>) ou <a>partagez cet espace</a>.",
"progress": {
"dont_close": "Ne fermez pas l\"application tant que l'opération est en cours",
"preparing": "Préparation des invitations..."
},
"recents_section": "Conversations récentes",
"room_failed_partial": "Nous avons envoyé les invitations, mais les personnes ci-dessous nont pas pu être invitées à rejoindre <RoomName/>",
"room_failed_partial_title": "Certaines invitations nont pas pu être envoyées",

View File

@ -654,6 +654,7 @@
"poll_button_no_perms_description": "Du har ikke tillatelse til å starte avstemninger i dette rommet.",
"poll_button_no_perms_title": "Tillatelse kreves",
"replying_title": "Svarer på",
"room_unencrypted": "Meldinger i dette rommet er ikke ende-til-ende krypterte",
"room_upgraded_link": "Samtalen fortsetter her.",
"room_upgraded_notice": "Dette rommet har blitt erstattet og er ikke lenger aktivt.",
"send_button_title": "Send melding",

View File

@ -7,6 +7,7 @@ exports[`dialogTermsInteractionCallback should render a dialog with the expected
class=""
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -12,6 +12,7 @@ exports[`<NewRecoveryMethodDialog /> when key backup is disabled 1`] = `
class="mx_KeyBackupFailedDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -83,6 +84,7 @@ exports[`<NewRecoveryMethodDialog /> when key backup is enabled 1`] = `
class="mx_KeyBackupFailedDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -388,6 +388,7 @@ exports[`<MatrixChat /> with an existing session onAction() room actions leave_r
class="mx_QuestionDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -444,6 +445,7 @@ exports[`<MatrixChat /> with an existing session onAction() room actions leave_r
class="mx_QuestionDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -14,7 +14,12 @@ import BaseDialog from "../../../../../src/components/views/dialogs/BaseDialog.t
describe("BaseDialog", () => {
it("calls onFinished when Escape is pressed", async () => {
const onFinished = jest.fn();
render(<BaseDialog onFinished={onFinished} />);
const { container } = render(<BaseDialog onFinished={onFinished} />);
// Autolock's autofocus in the empty dialog is focusing on the close button and bringing up the tooltip
// So we either need to call escape twice(one for the tooltip and one for the dialog) or focus
// on the dialog first.
const dialog = container.querySelector('[role="dialog"]') as HTMLElement;
dialog?.focus();
await userEvent.keyboard("{Escape}");
await userEvent.keyboard("{Escape}");
expect(onFinished).toHaveBeenCalled();

View File

@ -13,6 +13,7 @@ exports[`<ChangelogDialog /> should fetch github proxy url for each repo with ol
class="mx_QuestionDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -13,6 +13,7 @@ exports[`ConfirmRejectInviteDialog can reject with options selected 1`] = `
class="mx_DeclineAndBlockInviteDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -13,6 +13,7 @@ exports[`ConfirmUserActionDialog renders 1`] = `
class="mx_ConfirmUserActionDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -12,6 +12,7 @@ exports[`DevtoolsDialog renders the devtools dialog 1`] = `
class="mx_QuestionDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -7,6 +7,7 @@ exports[`<ExportDialog /> renders export dialog 1`] = `
class="mx_ExportDialog false mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -13,6 +13,7 @@ exports[`FeedbackDialog should respect feedback config 1`] = `
class="mx_QuestionDialog mx_FeedbackDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -13,6 +13,7 @@ exports[`LogoutDialog Prompts user to go to settings if there is a backup on the
class="mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -101,6 +102,7 @@ exports[`LogoutDialog Prompts user to go to settings if there is no backup on th
class="mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -189,6 +191,7 @@ exports[`LogoutDialog shows a regular dialog when crypto is disabled 1`] = `
class="mx_QuestionDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -12,6 +12,7 @@ exports[`<ManageRestrictedJoinRuleDialog /> should list spaces which are not par
class="mx_ManageRestrictedJoinRuleDialog"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -189,6 +190,7 @@ exports[`<ManageRestrictedJoinRuleDialog /> should render empty state 1`] = `
class="mx_ManageRestrictedJoinRuleDialog"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -13,6 +13,7 @@ exports[`ManualDeviceKeyVerificationDialog should render correctly 1`] = `
class="mx_QuestionDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -12,6 +12,7 @@ exports[`<MessageEditHistory /> should match the snapshot 1`] = `
class="mx_MessageEditHistoryDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -129,6 +130,7 @@ exports[`<MessageEditHistory /> should support events with 1`] = `
class="mx_MessageEditHistoryDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -13,6 +13,7 @@ exports[`ReportRoomDialog displays admin message 1`] = `
class="mx_ReportRoomDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -13,6 +13,7 @@ exports[`<ServerPickerDialog /> should render dialog 1`] = `
class="mx_ServerPickerDialog"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -13,6 +13,7 @@ exports[`ShareDialog should not render the QR code if disabled 1`] = `
class="mx_ShareDialog"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -143,6 +144,7 @@ exports[`ShareDialog should not render the socials if disabled 1`] = `
class="mx_ShareDialog"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -229,6 +231,7 @@ exports[`ShareDialog should render a share dialog for a matrix event 1`] = `
class="mx_ShareDialog"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -402,6 +405,7 @@ exports[`ShareDialog should render a share dialog for a room 1`] = `
class="mx_ShareDialog"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -574,6 +578,7 @@ exports[`ShareDialog should render a share dialog for a room member 1`] = `
class="mx_ShareDialog"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -719,6 +724,7 @@ exports[`ShareDialog should render a share dialog for an URL 1`] = `
class="mx_ShareDialog"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -12,6 +12,7 @@ exports[`<UnpinAllDialog /> should render 1`] = `
class="mx_UnpinAllDialog"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -12,6 +12,7 @@ exports[`<UntrustedDeviceDialog /> should display the dialog for the device of a
class="mx_UntrustedDeviceDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -91,6 +92,7 @@ exports[`<UntrustedDeviceDialog /> should display the dialog for the device of t
class="mx_UntrustedDeviceDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -12,6 +12,7 @@ exports[`CreateSecretStorageDialog handles the happy path 1`] = `
class="mx_CreateSecretStorageDialog"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -140,6 +141,7 @@ exports[`CreateSecretStorageDialog handles the happy path 2`] = `
class="mx_CreateSecretStorageDialog"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -231,6 +233,7 @@ exports[`CreateSecretStorageDialog when there is an error fetching the backup ve
class="mx_CreateSecretStorageDialog"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -12,6 +12,7 @@ exports[`ExportE2eKeysDialog renders 1`] = `
class="mx_exportE2eKeysDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -12,6 +12,7 @@ exports[`ImportE2eKeysDialog renders 1`] = `
class="mx_importE2eKeysDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -12,6 +12,7 @@ exports[`<RestoreKeyBackupDialog /> should display an error when recovery key is
class="mx_RestoreKeyBackupDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -112,6 +113,7 @@ exports[`<RestoreKeyBackupDialog /> should not raise an error when recovery is v
class="mx_RestoreKeyBackupDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -211,6 +213,7 @@ exports[`<RestoreKeyBackupDialog /> should render 1`] = `
class="mx_RestoreKeyBackupDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -310,6 +313,7 @@ exports[`<RestoreKeyBackupDialog /> should restore key backup when Recovery key
class="mx_RestoreKeyBackupDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -375,6 +379,7 @@ exports[`<RestoreKeyBackupDialog /> should restore key backup when passphrase is
class="mx_RestoreKeyBackupDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -440,6 +445,7 @@ exports[`<RestoreKeyBackupDialog /> should restore key backup when the key is ca
class="mx_RestoreKeyBackupDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -506,6 +512,7 @@ exports[`<RestoreKeyBackupDialog /> should restore key backup when the key is in
class="mx_RestoreKeyBackupDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -117,6 +117,7 @@ exports[`<SecurityRoomSettingsTab /> join rule handles error when updating join
class="mx_ErrorDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"
@ -159,6 +160,7 @@ exports[`<SecurityRoomSettingsTab /> join rule warns when trying to make an encr
class="mx_QuestionDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"

View File

@ -13,6 +13,7 @@ exports[`<AddExistingToSpaceDialog /> looks as expected 1`] = `
class="mx_AddExistingToSpaceDialog"
data-focus-lock-disabled="false"
role="dialog"
tabindex="-1"
>
<div
class="mx_Dialog_header"