@bobfrankston/rmfmail 1.2.304 → 1.2.305

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.commitmsg CHANGED
@@ -1,49 +1,40 @@
1
- Ask at the pointer, not in the host's dialog
2
-
3
- "clicking the x is supposed [to] delete the task but seems to do nothing
4
- it eventually puts up a message far from where I clicked" (Bob 2026-09-04,
5
- with both screenshots).
6
-
7
- The × handler called the native `confirm()`. In the WebView that is the host's
8
- own dialog: titled "msger.localhost says", centred in the window rather than
9
- under the pointer, arriving late enough that the click reads as having done
10
- nothing and blocking the WebView event loop the whole time it is up, which is
11
- the hazard message-viewer.ts already refuses `alert()` for. Compose reached the
12
- same conclusion in its own window and wrote an in-page modal; the main window
13
- never got one, so thirteen `confirm()` calls still go to the host.
14
-
15
- `confirmAt(x, y, label)` in context-menu.ts asks the question as a two-item
16
- menu at the pointer. Built on showContextMenu rather than as a new modal, so
17
- there is one menu, one dismissal path, and one piece of stay-on-screen clamping
18
- that clamping in particular was already solved here for narrow Android
19
- screens, and a second implementation would have had to learn it again.
20
-
21
- The label NAMES its target `Delete "Records. Berkowitz"`, never "OK". By the
22
- time a confirmation is read the pointer has moved and the row it came from is
23
- no longer obvious; a named action can be checked, and "OK" cannot. The
24
- explanation the old dialog text carried ("removes it from Google Tasks to
25
- mark done use the checkbox") is now the item's tooltip: worth having, not worth
26
- a dialog.
27
-
28
- Three call sites move: the row ×, the row context menu's Delete, and the batch
29
- delete behind the Delete key / trash button. The batch one has no click to
30
- anchor to, so it asks over the first selected row where the tasks are and
31
- where the user is looking.
32
-
33
- Two supporting changes:
34
-
35
- `ContextMenuOptions.onClose` fires whichever way the menu goes away, so a
36
- promise-shaped menu can answer "cancelled" instead of hanging forever on a
37
- dismissal. An item's click calls closeContextMenu() BEFORE item.action(), so
38
- onClose always runs first; confirmAt defers its cancel by one microtask, and
39
- since the action is synchronous and completes within the same task, a chosen
40
- item has always settled the promise by the time that microtask drains.
41
-
42
- `.ctx-emphasized` now renders. `MenuItem.emphasized` has been passed since the
43
- right-drag menu was written ("Move here" as the default action) and no CSS rule
44
- ever matched it, so it has never once looked different from its neighbours.
45
-
46
- The other ten `confirm()` calls — rebuild, factory reset, permanent delete,
47
- folder move/delete, contact delete, discard draft — are untouched. They are
48
- the same dialog with the same problems and they should follow, but each is a
49
- destructive action worth reading before it moves.
1
+ One click on a task disabled Delete for the whole app
2
+
3
+ "I press del and the message is not deleted whether I'm in the letter or
4
+ summary and trashcan is not working" (Bob 2026-09-05).
5
+
6
+ `deleteSelection()` — the one route for the Delete key, Ctrl+D, and both trash
7
+ buttons gave tasks an unconditional priority: if `getSelectedTaskUuids()` was
8
+ non-empty it deleted tasks and returned, whatever the user was actually looking
9
+ at. A task selection is set by a single click on a task row in the sidebar, is
10
+ never cleared by anything done in the mail panes, and has no indicator outside
11
+ the sidebar. So one stray click on a task turned off Delete and both trash
12
+ buttons for messages, indefinitely, and the only symptom was nothing happening.
13
+ Invisible modal state deciding what a destructive gesture means the same
14
+ fault as a filter that reads as a selection.
15
+
16
+ The daemon log shows it exactly: at the moment of the attempt there is a
17
+ getMessage and an updateFlags and no trashMessages at all. Nothing was slow or
18
+ failing; the gesture never left the client.
19
+
20
+ Routing now follows the pane the user last acted in, tracked on capture-phase
21
+ pointerdown so it lands before any handler that stops propagation and before
22
+ focus moves. The toolbar buttons sit in neither pane, so clicking one leaves
23
+ that reading as the user's last real interaction set it which is the point,
24
+ since the button is how you act on what you were just doing. Select tasks and
25
+ press Delete and the tasks still go, which is what the priority rule was
26
+ written for; the part that was never intended is gone. A delete routed to
27
+ messages also clears any leftover task selection, so the sidebar stops showing
28
+ rows as chosen after the gesture has moved on.
29
+
30
+ I made this worse yesterday and should say so. Before v1.2.304 the swallowed
31
+ delete at least put up the native confirm — misplaced and late, but visible, so
32
+ "my delete went to the tasks" was discoverable. Moving that question to a menu
33
+ anchored over the task pane made the misrouting completely silent whenever the
34
+ sidebar was collapsed or scrolled away. The routing bug was already there; my
35
+ change removed the last evidence of it.
36
+
37
+ Also guarded, from the same cause: the batch confirm measured its anchor with
38
+ getBoundingClientRect on a possibly-hidden sidebar, which is 0x0 at 0,0 — it
39
+ now falls back to the middle of the window rather than asking in a corner
40
+ nobody is looking at.
@@ -6542,6 +6542,7 @@ var init_outbox_view = __esm({
6542
6542
  // client/components/calendar-sidebar.js
6543
6543
  var calendar_sidebar_exports = {};
6544
6544
  __export(calendar_sidebar_exports, {
6545
+ clearTaskSelection: () => clearTaskSelection,
6545
6546
  deleteSelectedTasks: () => deleteSelectedTasks,
6546
6547
  getSelectedTaskUuids: () => getSelectedTaskUuids,
6547
6548
  hideCalendarSidebar: () => hideCalendarSidebar,
@@ -6649,6 +6650,12 @@ async function renderCalendarList() {
6649
6650
  if (lastEvents.length > 0)
6650
6651
  renderEvents(lastEvents);
6651
6652
  }
6653
+ function clearTaskSelection() {
6654
+ if (selectedTaskUuids.size === 0)
6655
+ return;
6656
+ selectedTaskUuids.clear();
6657
+ void renderTasks();
6658
+ }
6652
6659
  function getSelectedTaskUuids() {
6653
6660
  return [...selectedTaskUuids];
6654
6661
  }
@@ -6657,9 +6664,10 @@ async function deleteSelectedTasks() {
6657
6664
  if (uuids.length === 0)
6658
6665
  return;
6659
6666
  const anchorEl = document.querySelector(".cal-side-task.selected") || document.getElementById("cal-side-tasks");
6660
- const r = anchorEl?.getBoundingClientRect();
6667
+ const rect = anchorEl?.getBoundingClientRect();
6668
+ const r = rect && rect.width > 0 && rect.height > 0 ? rect : { left: window.innerWidth / 2 - 60, bottom: window.innerHeight / 3 };
6661
6669
  const label = uuids.length === 1 ? `Delete "${document.querySelector(".cal-side-task.selected .cal-side-task-title")?.textContent || "this task"}"` : `Delete ${uuids.length} tasks`;
6662
- if (!await confirmAt(r ? r.left + 24 : 80, r ? r.bottom : 80, label, { tooltip: TASK_DELETE_NOTE }))
6670
+ if (!await confirmAt(r.left + 24, r.bottom, label, { tooltip: TASK_DELETE_NOTE }))
6663
6671
  return;
6664
6672
  selectedTaskUuids.clear();
6665
6673
  for (const uuid of uuids) {
@@ -10588,13 +10596,21 @@ function popUndo() {
10588
10596
  }
10589
10597
  return null;
10590
10598
  }
10599
+ var lastActionPane = "messages";
10600
+ document.addEventListener("pointerdown", (e) => {
10601
+ const t = e.target;
10602
+ if (!t?.closest) return;
10603
+ if (t.closest("#cal-side-tasks")) lastActionPane = "tasks";
10604
+ else if (t.closest(".message-list, .message-viewer, #ml-body, #message-viewer")) lastActionPane = "messages";
10605
+ }, true);
10591
10606
  async function deleteSelection() {
10592
10607
  try {
10593
10608
  const sidebar = await Promise.resolve().then(() => (init_calendar_sidebar(), calendar_sidebar_exports));
10594
- if (sidebar.getSelectedTaskUuids().length > 0) {
10609
+ if (lastActionPane === "tasks" && sidebar.getSelectedTaskUuids().length > 0) {
10595
10610
  await sidebar.deleteSelectedTasks();
10596
10611
  return;
10597
10612
  }
10613
+ if (sidebar.getSelectedTaskUuids().length > 0) sidebar.clearTaskSelection();
10598
10614
  } catch {
10599
10615
  }
10600
10616
  await deleteSelectedMessages();