@bobfrankston/rmfmail 1.2.303 → 1.2.304
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 +49 -47
- package/client/app.bundle.js +40 -6
- package/client/app.bundle.js.map +2 -2
- package/client/components/calendar-sidebar.js +18 -5
- package/client/components/calendar-sidebar.js.map +1 -1
- package/client/components/calendar-sidebar.ts +19 -5
- package/client/components/context-menu.js +49 -1
- package/client/components/context-menu.js.map +1 -1
- package/client/components/context-menu.ts +53 -1
- package/client/compose/compose.bundle.js +31 -1
- package/client/compose/compose.bundle.js.map +2 -2
- package/client/styles/components.css +5 -0
- package/npmchanges.md +50 -0
- package/package.json +3 -3
- /package/packages/mailx-imap/{node_modules.npmglobalize-stash-42308 → node_modules.npmglobalize-stash-37088}/.package-lock.json +0 -0
package/.commitmsg
CHANGED
|
@@ -1,47 +1,49 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
`
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
the
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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.
|
package/client/app.bundle.js
CHANGED
|
@@ -1015,6 +1015,7 @@ var init_edit_menu = __esm({
|
|
|
1015
1015
|
var context_menu_exports = {};
|
|
1016
1016
|
__export(context_menu_exports, {
|
|
1017
1017
|
closeContextMenu: () => closeContextMenu,
|
|
1018
|
+
confirmAt: () => confirmAt,
|
|
1018
1019
|
showContextMenu: () => showContextMenu
|
|
1019
1020
|
});
|
|
1020
1021
|
function closeSubmenu() {
|
|
@@ -1029,6 +1030,11 @@ function closeContextMenu() {
|
|
|
1029
1030
|
activeMenu.remove();
|
|
1030
1031
|
activeMenu = null;
|
|
1031
1032
|
}
|
|
1033
|
+
if (closeHandler) {
|
|
1034
|
+
const fn = closeHandler;
|
|
1035
|
+
closeHandler = null;
|
|
1036
|
+
fn();
|
|
1037
|
+
}
|
|
1032
1038
|
if (dismissListener) {
|
|
1033
1039
|
document.removeEventListener("pointerdown", dismissListener, true);
|
|
1034
1040
|
dismissListener = null;
|
|
@@ -1079,6 +1085,7 @@ function openSubmenu(parentRow, items) {
|
|
|
1079
1085
|
}
|
|
1080
1086
|
function showContextMenu(x, y, items, opts = {}) {
|
|
1081
1087
|
closeContextMenu();
|
|
1088
|
+
closeHandler = opts.onClose ?? null;
|
|
1082
1089
|
if (opts.editTarget !== void 0 || opts.editEngine) {
|
|
1083
1090
|
const edit = editMenuItems({ target: opts.editTarget, engine: opts.editEngine }, { onError: opts.onEditError });
|
|
1084
1091
|
if (edit.length > 0) {
|
|
@@ -1168,7 +1175,29 @@ function showContextMenu(x, y, items, opts = {}) {
|
|
|
1168
1175
|
document.addEventListener("keydown", escapeListener, true);
|
|
1169
1176
|
});
|
|
1170
1177
|
}
|
|
1171
|
-
|
|
1178
|
+
function confirmAt(x, y, confirmLabel, opts = {}) {
|
|
1179
|
+
return new Promise((resolve) => {
|
|
1180
|
+
let settled = false;
|
|
1181
|
+
const done = (v) => {
|
|
1182
|
+
if (!settled) {
|
|
1183
|
+
settled = true;
|
|
1184
|
+
resolve(v);
|
|
1185
|
+
}
|
|
1186
|
+
};
|
|
1187
|
+
showContextMenu(x, y, [
|
|
1188
|
+
{ label: confirmLabel, action: () => done(true), emphasized: true, tooltip: opts.tooltip },
|
|
1189
|
+
{ label: "Cancel", action: () => done(false) }
|
|
1190
|
+
], {
|
|
1191
|
+
// An item's click calls closeContextMenu() BEFORE item.action(), so
|
|
1192
|
+
// onClose always runs first. Defer the "cancelled" answer by one
|
|
1193
|
+
// microtask: the action is synchronous and finishes within this
|
|
1194
|
+
// task, so by the time the microtask drains, a chosen item has
|
|
1195
|
+
// already settled the promise and this call is a no-op.
|
|
1196
|
+
onClose: () => queueMicrotask(() => done(false))
|
|
1197
|
+
});
|
|
1198
|
+
});
|
|
1199
|
+
}
|
|
1200
|
+
var activeMenu, dismissListener, escapeListener, activeSubmenu, closeHandler;
|
|
1172
1201
|
var init_context_menu = __esm({
|
|
1173
1202
|
"client/components/context-menu.js"() {
|
|
1174
1203
|
"use strict";
|
|
@@ -1177,6 +1206,7 @@ var init_context_menu = __esm({
|
|
|
1177
1206
|
dismissListener = null;
|
|
1178
1207
|
escapeListener = null;
|
|
1179
1208
|
activeSubmenu = null;
|
|
1209
|
+
closeHandler = null;
|
|
1180
1210
|
document.addEventListener("scroll", closeContextMenu, true);
|
|
1181
1211
|
document.addEventListener("contextmenu", () => {
|
|
1182
1212
|
});
|
|
@@ -6626,7 +6656,10 @@ async function deleteSelectedTasks() {
|
|
|
6626
6656
|
const uuids = [...selectedTaskUuids];
|
|
6627
6657
|
if (uuids.length === 0)
|
|
6628
6658
|
return;
|
|
6629
|
-
|
|
6659
|
+
const anchorEl = document.querySelector(".cal-side-task.selected") || document.getElementById("cal-side-tasks");
|
|
6660
|
+
const r = anchorEl?.getBoundingClientRect();
|
|
6661
|
+
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 }))
|
|
6630
6663
|
return;
|
|
6631
6664
|
selectedTaskUuids.clear();
|
|
6632
6665
|
for (const uuid of uuids) {
|
|
@@ -6914,7 +6947,7 @@ async function renderTasks(prefetched) {
|
|
|
6914
6947
|
row.querySelector(".cal-side-task-delete")?.addEventListener("click", async (e) => {
|
|
6915
6948
|
e.stopPropagation();
|
|
6916
6949
|
const title = tasks.find((t) => t.uuid === uuid)?.title || "this task";
|
|
6917
|
-
if (!
|
|
6950
|
+
if (!await confirmAt(e.clientX, e.clientY, `Delete "${title}"`, { tooltip: TASK_DELETE_NOTE }))
|
|
6918
6951
|
return;
|
|
6919
6952
|
await deleteTask(uuid);
|
|
6920
6953
|
selectedTaskUuids.delete(uuid);
|
|
@@ -6941,9 +6974,9 @@ async function renderTasks(prefetched) {
|
|
|
6941
6974
|
{ label: "View in Google Tasks", action: () => openInBrowser("https://tasks.google.com/") },
|
|
6942
6975
|
{ label: "", action: () => {
|
|
6943
6976
|
}, separator: true },
|
|
6944
|
-
{ label: "Delete task", action: async () => {
|
|
6977
|
+
{ label: "Delete task", tooltip: TASK_DELETE_NOTE, action: async () => {
|
|
6945
6978
|
const title = tasks.find((t) => t.uuid === uuid)?.title || "this task";
|
|
6946
|
-
if (!
|
|
6979
|
+
if (!await confirmAt(e.clientX, e.clientY, `Delete "${title}"`, { tooltip: TASK_DELETE_NOTE }))
|
|
6947
6980
|
return;
|
|
6948
6981
|
await deleteTask(uuid);
|
|
6949
6982
|
renderTasks();
|
|
@@ -7296,7 +7329,7 @@ function initCalendarSidebar() {
|
|
|
7296
7329
|
}
|
|
7297
7330
|
}
|
|
7298
7331
|
}
|
|
7299
|
-
var SIDEBAR_PREF, SHOW_RECURRING_PREF, SHOW_DONE_PREF, HORIZON_DAYS_PREF, HORIZON_DEFAULT_DAYS, HOLIDAY_HORIZON_MS, viewYear, viewMonth, viewDay, lastEvents, lastOverdueTasks, calById, calendarList, hiddenCalendars, selectedTaskUuids;
|
|
7332
|
+
var SIDEBAR_PREF, SHOW_RECURRING_PREF, SHOW_DONE_PREF, HORIZON_DAYS_PREF, HORIZON_DEFAULT_DAYS, HOLIDAY_HORIZON_MS, viewYear, viewMonth, viewDay, lastEvents, lastOverdueTasks, calById, calendarList, hiddenCalendars, selectedTaskUuids, TASK_DELETE_NOTE;
|
|
7300
7333
|
var init_calendar_sidebar = __esm({
|
|
7301
7334
|
"client/components/calendar-sidebar.js"() {
|
|
7302
7335
|
"use strict";
|
|
@@ -7317,6 +7350,7 @@ var init_calendar_sidebar = __esm({
|
|
|
7317
7350
|
calendarList = [];
|
|
7318
7351
|
hiddenCalendars = /* @__PURE__ */ new Set();
|
|
7319
7352
|
selectedTaskUuids = /* @__PURE__ */ new Set();
|
|
7353
|
+
TASK_DELETE_NOTE = "Removes it from Google Tasks. To mark it done instead, use the checkbox.";
|
|
7320
7354
|
}
|
|
7321
7355
|
});
|
|
7322
7356
|
|