chatwoot/app/javascript/shared/helpers
Sivin Varghese 437dd9d38c
fix: prevent Ctrl+Enter adding extra line break on send (Windows) (#14077)
# Pull Request Template

## Description

This PR includes,
On Windows, pressing **Ctrl+Enter** in the reply editor was inserting an
unintended line break before sending. This led to two issues:

* **Unexpected blank lines**
After adding a line break with Shift+Enter and removing it with
Backspace, the editor looked correct. However, sending with Ctrl+Enter
reintroduced a hidden break, resulting in an extra blank line in the
final message.

* **Selected text being replaced**
When text was selected and Ctrl+Enter was pressed, the selection was
replaced with a line break instead of being sent.

Fixes
https://linear.app/chatwoot/issue/CW-6840/newline-bug-in-the-editor


### **Cause**

Two keyboard handlers responded to **Ctrl+Enter** on Windows:

* ProseMirror (`Mod-Enter`) inserted a hard break
* ReplyBox (`$mod+Enter`) triggered send

The existing guard only checked `metaKey` (Cmd), so it never worked on
Windows. As a result, a line break was inserted just before sending.

### **Solution**

Make the modifier check platform-aware so the editor correctly
intercepts the send shortcut:

* Added `detectOS`, `isMac`, and `OS` constants
* Introduced `hasPressedMod` (uses `metaKey` on macOS, `ctrlKey`
elsewhere)

This ensures Ctrl+Enter sends the message without modifying content,
while keeping existing behavior unchanged.


**NB:** macOS behavior with Cmd+Enter remains unchanged



## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## How Has This Been Tested?

**Case 1: line break**

1. Type `hello`
2. Press Shift+Enter, then Backspace
3. Press Ctrl+Enter
   → Message contains an unexpected blank new line

**Case 2: Selection replaced**

1. Type two lines using Shift+Enter
2. Select text on the second line
3. Press Ctrl+Enter
   → Selected text is replaced and not sent

### Screencast

**Before**


https://github.com/user-attachments/assets/d6d285a9-260b-4711-8bbd-d0c8519e8d20

**After**



https://github.com/user-attachments/assets/c0ace1f7-5d22-44a2-8e08-22190ee21e61



## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
2026-04-20 18:16:41 +05:30
..
markdownIt chore: Use markdown-it instead of marked (#6123) 2023-03-03 13:26:54 +05:30
specs fix: prevent Ctrl+Enter adding extra line break on send (Windows) (#14077) 2026-04-20 18:16:41 +05:30
vuex feat: Vite + vue 3 💚 (#10047) 2024-10-02 00:36:30 -07:00
AudioNotificationHelper.js feat: update tool-chain to latest (#7975) 2023-09-27 14:02:34 +05:30
BaseActionCableConnector.js perf: reduce presence update frequency and fix background tab throttling (#13726) 2026-03-09 18:23:44 +05:30
cache.js chore: Add cache to improve widget performance (#11163) 2025-03-24 16:04:49 -07:00
clipboard.js feat: Add the frontend support for MFA (#12372) 2025-09-18 21:16:06 +05:30
colorHelper.js feat: Update public portal colors with new design (#8230) 2023-11-23 08:16:52 +05:30
CustomErrors.js feat: Inline edit support for contact info (#13976) 2026-04-14 16:53:40 +04:00
CustomEventHelper.js feat: Add chatwoot:error sdk event (#3998) 2022-02-21 09:40:11 +05:30
DateHelper.js chore: Remove older UI (#11720) 2025-07-01 09:43:44 +05:30
documentHelper.js feat: add FE changes for captain pdf support for faq generation (#12115) 2025-09-02 19:01:16 +05:30
emoji.js chore: Check for empty strings in name formatter (#5434) 2022-09-14 07:15:04 -07:00
FileHelper.js fix: Prevent unsupported file types on clipboard paste (#13182) 2026-01-14 13:07:46 +04:00
HTMLSanitizer.js fix: Render links with target attribute (#4685) 2022-05-16 11:29:05 +05:30
IntegrationHelper.js feat: Upgrade Dyte apis to v2 (#10706) 2025-02-19 14:47:48 -08:00
KeyboardHelpers.js fix: prevent Ctrl+Enter adding extra line break on send (Windows) (#14077) 2026-04-20 18:16:41 +05:30
localStorage.js feat: Implement reply to for reply editor (#8063) 2023-10-10 19:13:12 +05:30
MessageFormatter.js fix: Prevent template variables from becoming links (#10725) 2025-01-23 18:18:14 +05:30
MessageTypeHelper.js feat: TikTok channel (#12741) 2025-12-17 07:54:50 -08:00
mitt.js chore: Replace eventBus with mitt.js [CW-3275] (#9539) 2024-05-31 15:50:36 +05:30
platform.js fix: prevent Ctrl+Enter adding extra line break on send (Windows) (#14077) 2026-04-20 18:16:41 +05:30
portalHelper.js feat: Sync Popular Articles locale with widget locale (#11754) 2025-06-24 19:52:44 +05:30
ReportsDataHelper.js feat: add Conversation traffic heatmap (#6508) 2023-03-07 09:01:58 +05:30
sanitizeData.js feat: multiple UX improvements to labels (#7358) 2023-06-25 18:49:49 +05:30
sessionStorage.js feat: Prevent saving preferences and status when impersonating (#11164) 2025-05-20 17:34:30 -07:00
timeHelper.js fix: normalize "in less than a minute" to "now" in chat list timestamp (#13874) 2026-03-24 15:40:31 +05:30
Validators.js fix: Handle slug validation errors in Help Center (#11368) 2025-04-24 16:58:05 +05:30