eleven / messenger Public

Composer + Safari push fixes

- Composer: Enter submits again (call send() directly instead of the flaky
  form.requestSubmit()); textarea overflow:hidden (no scrollbar; auto-grow sizes it).
- Safari: request notification permission first-thing in the click gesture (Safari
  rejects requestPermission after an await), so enabling works.
- Blocked-notifications modal: per-browser reset instructions (Chrome/Safari/Firefox).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Paul Campbell 682714360631602e1cd5b80e0fcae52d3cc83d53 parent 773885f
2 files changed, +28 −12
  • web/static/chat.js +27 −11
  • web/static/style.css +1 −1
diff --git a/web/static/chat.js b/web/static/chat.js
index 03271fd..9f96200 100644
--- a/web/static/chat.js
+++ b/web/static/chat.js
@@ -133,6 +133,18 @@ function setupMenu(session) {
}
if (!pushAvailable()) return;
const item = document.getElementById("menu-notif");
+ // Request permission FIRST, still inside the click gesture — Safari rejects
+ // requestPermission() if it's called after an await (e.g. an IndexedDB read).
+ if (Notification.permission === "default") {
+ let perm;
+ try {
+ perm = await Notification.requestPermission();
+ } catch {}
+ if (perm !== "granted") {
+ refreshNotifItem();
+ return;
+ }
+ }
item.textContent = "…";
if ((await isSubscribed()) && pushEnabled()) {
await unsubscribePush();
@@ -204,8 +216,9 @@ function showBlockedInstructions() {
`<h1>Notifications are blocked</h1>` +
`<p>Your browser is blocking notifications for this site. To turn them on:</p>` +
`<ol class="steps">` +
- `<li>Click the lock / site-info icon in the address bar.</li>` +
- `<li>Set <strong>Notifications</strong> to <strong>Allow</strong>.</li>` +
+ `<li><strong>Chrome / Edge:</strong> click the site-info icon left of the address bar → Notifications → Allow.</li>` +
+ `<li><strong>Safari:</strong> Safari → Settings → Websites → Notifications → set this site to Allow.</li>` +
+ `<li><strong>Firefox:</strong> click the lock icon → clear the blocked Notifications permission.</li>` +
`<li>Reload, then choose <strong>Turn on notifications</strong>.</li>` +
`</ol>`
);
@@ -368,15 +381,7 @@ async function start(session) {
input.style.height = "auto";
input.style.height = Math.min(input.scrollHeight, 140) + "px";
};
- input.addEventListener("input", autosize);
- input.addEventListener("keydown", (e) => {
- if (e.key === "Enter" && !e.shiftKey) {
- e.preventDefault();
- form.requestSubmit();
- }
- });
- form.onsubmit = async (e) => {
- e.preventDefault();
+ const send = async () => {
const text = input.value.trim();
if (!text || !ws || ws.readyState !== WebSocket.OPEN) return;
input.value = "";
@@ -384,6 +389,17 @@ async function start(session) {
const blob = await encrypt(key, { name: session.name, text, ts: Date.now() });
ws.send(JSON.stringify({ type: "msg", blob }));
};
+ input.addEventListener("input", autosize);
+ input.addEventListener("keydown", (e) => {
+ if (e.key === "Enter" && !e.shiftKey) {
+ e.preventDefault();
+ send();
+ }
+ });
+ form.addEventListener("submit", (e) => {
+ e.preventDefault();
+ send();
+ });
input.focus();
}
diff --git a/web/static/style.css b/web/static/style.css
index 9f92eb6..920c169 100644
--- a/web/static/style.css
+++ b/web/static/style.css
@@ -181,7 +181,7 @@ input:focus, textarea:focus { outline: 2px solid var(--accent); border-color: tr
line-height: 1.4;
border-radius: 20px;
font-family: inherit;
- overflow-y: auto;
+ overflow: hidden;
}
.composer button { align-self: flex-end; }