Commit Graph
13 Commits
Author SHA1 Message Date
MarekWoandClaude Opus 5 cbbbcbc8b2 fix(chat): escape message text spliced into action-button handlers
A message containing an apostrophe followed by angle brackets — e.g. a bot
answering "Type 'channel <name>' for a description" — tore the action row
below it apart: the apostrophe closed the single-quoted onclick attribute,
the '<' ended the <button> tag, and the remainder ("...")' title="Quote">)
landed on the page as visible text, with reply and quote dead.

JSON.stringify() produced a valid JS literal but was spliced into markup
raw. jsArg() wraps it in escapeHtmlAttribute(), so quotes and brackets
survive as entities and the JS parser sees the literal only after the HTML
parser decodes the attribute. Applied to the quote/edit buttons in channel
chat and DM, and to the sender-name handlers (reply, map, block) that had
the same defect for a name containing an apostrophe.

Verified in a browser against the local container: all ten test messages
now render six clean buttons with no stray text, and quoting '<>' fills the
composer correctly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 20:57:23 +02:00
MarekWoandClaude Opus 5 2acf6f9f3a feat(chat): render shared contacts, channels and positions as cards
MeshCore clients share contacts, channels and positions as plain text in
ordinary chat messages. Until now those arrived as unreadable raw tokens.
They now render as interactive cards in both the channel chat and DMs.

Three wire formats, none of them ours to choose — they are what the
official app emits, so share-tokens.js stays byte-compatible with it:

  contact   <64-hex-pubkey:type:name>   (compact, not a URI)
  channel   meshcore://channel/add?name=&secret=&region_scope=
  location  bare "lat,lon"

The contact URI form is parsed too (QR codes carry it) but never emitted:
with a name like "MarWoj 💡📱 mobile" it costs 153 bytes and cannot fit a
135-byte channel packet, where the compact token needs 91.

Parsing runs BEFORE HTML escaping, leaving private-use-area placeholders
that the later passes cannot match. Tokens do not survive the existing
pipeline otherwise: escaping breaks a URI's '&', processChannelLinks eats
a '#channel' name, processMentions an '@' in a contact name, and the
token's closing '>' collides with quote syntax.

Cards resolve their action before rendering, so the button states what
will actually happen rather than surprising the user afterwards:
  contact  Add / Update name to X / Already in contacts / Push to device
  channel  Add / Already joined / Name used by a different key
The public key is the identity — a known key under a new name is a
rename, never a second contact.

Shared contacts land in the local cache rather than device memory:
they arrive unsolicited and contact slots are limited, so promotion stays
deliberate. The card offers it inline once cached, so it costs one click
rather than a trip to the Contacts panel. New: manual-add accepts
target=cache, which needs no device connection.

Location cards add distance and bearing from our own advertised position,
plus map/copy/external-map actions. A shared channel's region scope is
carried over on join, since transmitting under the firmware default would
not match the sender.

Coordinate detection is deliberately narrow — both numbers need 3+
decimals, ranges are checked, and matches inside URLs are skipped — so
prose like "1,5 osoby" or "wersja 2,10" and Google Maps links are left
alone.

Verified against real payloads received from another device on #mcwebui,
covering all three formats plus a contact URI and emoji names: 65 parser
assertions, 57 render assertions, i18n check clean at pl 100%, and both
themes screenshotted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 10:57:26 +02:00
MarekWoandClaude Opus 5 75f8b4cfca feat(i18n): translate the message list, channels and map popups (stage 9a)
First slice of app.js: the map popups, resync and channel toasts, the message
bubble (action tooltips, SNR/hops/route meta, echo badge), the route popup,
channel management, and the two joins plus the image-preview modal in
message-utils.js.

Six keys shared with the DM panel move dm.* -> chat.*, the namespace stage 6
opened for chrome the two chats have in common; dm.js follows.

The action-button injection used to find already-rendered buttons with
[title="View in Analyzer"], [title="Edit message"] and [title^="Ignore"].
Those titles are translated now, so every lookup would have missed and the
meta refresh would have appended a second analyzer button on each pass. They
match .btn-msg-analyzer / .btn-msg-edit / .btn-msg-ignore instead.

Verified against the local container: F:\tmp\pwverify\i18n-stage9a.js reports
one identical string across the message list, route popup and channel modal
(an echo badge that is pure data), and i18n-stage9a-buttons.js confirms three
forced meta refreshes leave at most one of each button per bubble.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 11:04:29 +02:00
MarekWoandClaude Opus 5 17398e8e41 feat(chat): quote with the '>' line prefix instead of guillemets
The Quote button produced `@[user] »text« ` — a shape mc-webui invented back
when it could not send newlines, and one that other MeshCore clients neither
write nor understand. It now writes the quote on its own line behind a '>'
and leaves the cursor underneath it, matching the plain-text convention some
users already type by hand.

processQuotes() styles both syntaxes, so messages sent by older builds keep
their formatting. The '>' match is anchored to a line start or a leading
@[mention] badge and looks for the escaped '&gt;', so neither "5 > 3" in
prose nor the brackets of generated tags can trigger it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 11:58:53 +02:00
MarekWo ca4c77da36 feat(chat): require explicit send button on touch devices
Enter on a phone's virtual keyboard now inserts a newline instead of
sending, in both group chat and DM. Detected via the pointer:coarse
media query - no user-facing setting, since accidental sends from a
mistapped Enter were the actual complaint. Desktop keeps Enter-to-send.
2026-06-29 09:31:50 +02:00
MarekWoandClaude Opus 4.7 cbcdbdcae9 fix: prevent duplicate channels from concurrent add/join requests
Two near-simultaneous POSTs to /api/channels/join (observed 7 ms apart
in demo-server logs) each found a different free slot and both
succeeded, producing two entries for the same channel name on the
device. This also shifted the sidebar so each channel rendered the
next one's messages.

- Wrap free-slot detection + set_channel in a module-level lock so
  concurrent requests serialize instead of racing.
- Idempotency: if a channel with this name already exists, return the
  existing slot with already_existed=true instead of creating a
  duplicate. Applies to both POST /api/channels and /api/channels/join
  (skipped when caller targets an explicit index).
- Disable submit buttons on create/join forms while a request is in
  flight, and guard against double-registration of the channel-link
  click delegate to stop a single click from firing N POSTs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 20:45:39 +02:00
MarekWoandClaude Opus 4.7 309efe0ce5 feat: searchable channel picker on narrow screens + DM picker font fix
Replace the native <select> channel picker (used on narrow screens) with
a custom searchable dropdown matching the DM contact picker UX: type to
filter, arrow/Enter keyboard nav, click-outside to close, per-channel
unread badges, muted styling. Wide-screen sidebar (lg+) is unchanged.

Also align the DM picker dropdown font with the wide-screen DM sidebar
(0.88rem / weight 400) — was inheriting larger/bolder from form-control.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 08:32:03 +02:00
MarekWoandClaude Opus 4.5 db6915f53f feat: Improve chat message display
- Add sender name above outgoing messages in group chat
- Display emoji-only messages in larger font size
- Fix leading space before text in quoted replies

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 20:42:27 +01:00
MarekWoandClaude Opus 4.5 2c17c83253 feat: Add clickable #channel links in chat messages
- Auto-detect #channel names in messages and convert to clickable links
- Click existing channel: switch to it via channel selector
- Click non-existing channel: join via API, then switch
- Green styling to distinguish from blue @mentions
- Only active in channel context (not in DMs)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 08:54:50 +01:00
MarekWoandClaude Opus 4.5 5d01f90ba1 refactor: Hide guillemets and add line break after quote
- Guillemets (» «) no longer displayed - styling is sufficient
- Added line break after quoted text for better readability
- Raw message still contains guillemets for compatibility

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 10:43:45 +01:00
MarekWoandClaude Opus 4.5 b2418a50d3 feat: Improve quote format with guillemets and styling
- Changed quote format to: @[Username]: »quoted text«
- Added processQuotes() to detect and style »text« patterns
- Quote styling: italic, gray background, left border
- Different styling for own messages vs others

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 10:29:59 +01:00
MarekWoandClaude Opus 4.5 ffbcd8eead fix: Remove whitespace from image thumbnail template literal
The template literal had newlines and spaces that were preserved by
white-space: pre-wrap CSS, causing unwanted gaps before and after
image previews in chat messages.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 09:48:17 +01:00
MarekWoandClaude Sonnet 4.5 5fc1c5b779 feat: Add mention badges, clickable URLs, and image previews to messages
Implemented comprehensive message content enhancements for both channel messages and DMs:

- **Mention badges**: @[Username] mentions now display as styled badges similar to Android Meshcore app
- **Clickable URLs**: http:// and https:// URLs are automatically converted to clickable links that open in new tabs
- **Image thumbnails**: URLs ending in .jpg, .jpeg, .png, .gif, .webp display as thumbnails with click-to-expand modal preview
- **Mobile responsive**: Image thumbnails adapt size for mobile screens
- **Security**: Proper XSS protection with HTML escaping and attribute sanitization

Technical implementation:
- Created shared message-utils.js module for content processing
- Added CSS styles for badges, links, images, and modal preview
- Updated both app.js and dm.js to use new content processor
- Used event delegation for image click handlers to support dynamic content
- Responsive design with mobile-optimized image sizes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-31 17:21:23 +01:00