@bobfrankston/rmfmail 1.0.699 → 1.0.701

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.
@@ -2175,6 +2175,69 @@ var init_folder_picker = __esm({
2175
2175
  }
2176
2176
  });
2177
2177
 
2178
+ // packages/mailx-types/contact-rules.js
2179
+ var init_contact_rules = __esm({
2180
+ "packages/mailx-types/contact-rules.js"() {
2181
+ "use strict";
2182
+ }
2183
+ });
2184
+
2185
+ // packages/mailx-types/groups.js
2186
+ var init_groups = __esm({
2187
+ "packages/mailx-types/groups.js"() {
2188
+ "use strict";
2189
+ }
2190
+ });
2191
+
2192
+ // packages/mailx-types/index.js
2193
+ var FLAG, flagOps;
2194
+ var init_mailx_types = __esm({
2195
+ "packages/mailx-types/index.js"() {
2196
+ "use strict";
2197
+ init_contact_rules();
2198
+ init_groups();
2199
+ FLAG = {
2200
+ SEEN: "\\Seen",
2201
+ FLAGGED: "\\Flagged",
2202
+ DELETED: "\\Deleted",
2203
+ DRAFT: "\\Draft",
2204
+ ANSWERED: "\\Answered",
2205
+ RECENT: "\\Recent"
2206
+ };
2207
+ flagOps = {
2208
+ has(flags, f) {
2209
+ return !!flags && flags.includes(f);
2210
+ },
2211
+ isSeen(flags) {
2212
+ return flagOps.has(flags, FLAG.SEEN);
2213
+ },
2214
+ isFlagged(flags) {
2215
+ return flagOps.has(flags, FLAG.FLAGGED);
2216
+ },
2217
+ isAnswered(flags) {
2218
+ return flagOps.has(flags, FLAG.ANSWERED);
2219
+ },
2220
+ isDraft(flags) {
2221
+ return flagOps.has(flags, FLAG.DRAFT);
2222
+ },
2223
+ /** Return flags with `f` added (dedup). */
2224
+ add(flags, f) {
2225
+ const set = new Set(flags || []);
2226
+ set.add(f);
2227
+ return Array.from(set);
2228
+ },
2229
+ /** Return flags with `f` removed. */
2230
+ remove(flags, f) {
2231
+ return (flags || []).filter((x) => x !== f);
2232
+ },
2233
+ /** Return flags with `f` toggled to `state` (true=present, false=absent). */
2234
+ set(flags, f, state) {
2235
+ return state ? flagOps.add(flags, f) : flagOps.remove(flags, f);
2236
+ }
2237
+ };
2238
+ }
2239
+ });
2240
+
2178
2241
  // client/components/message-list.js
2179
2242
  var message_list_exports = {};
2180
2243
  __export(message_list_exports, {
@@ -2803,7 +2866,7 @@ async function showThreadPopup(pillEl, headMsg) {
2803
2866
  for (const msg of thread) {
2804
2867
  const item = document.createElement("div");
2805
2868
  item.className = "ml-thread-popup-item";
2806
- if (!msg.flags.includes("\\Seen"))
2869
+ if (!flagOps.isSeen(msg.flags))
2807
2870
  item.classList.add("unread");
2808
2871
  const from = document.createElement("span");
2809
2872
  from.className = "ml-thread-popup-from";
@@ -2908,6 +2971,7 @@ var init_message_list = __esm({
2908
2971
  init_message_viewer();
2909
2972
  init_context_menu();
2910
2973
  init_folder_picker();
2974
+ init_mailx_types();
2911
2975
  currentSpecialUse = "";
2912
2976
  lastClickedRow = null;
2913
2977
  loading = false;
@@ -2970,9 +3034,9 @@ var init_message_list = __esm({
2970
3034
  this.el = row;
2971
3035
  row.className = "ml-row";
2972
3036
  row.draggable = true;
2973
- if (!msg.flags.includes("\\Seen"))
3037
+ if (!flagOps.isSeen(msg.flags))
2974
3038
  row.classList.add("unread");
2975
- if (msg.flags.includes("\\Flagged"))
3039
+ if (flagOps.isFlagged(msg.flags))
2976
3040
  row.classList.add("flagged");
2977
3041
  if (!msg.bodyPath)
2978
3042
  row.classList.add("not-downloaded");
@@ -3001,7 +3065,7 @@ var init_message_list = __esm({
3001
3065
  avatar.addEventListener("contextmenu", (e) => this.onAvatarContextMenu(e));
3002
3066
  const flag = document.createElement("span");
3003
3067
  flag.className = "ml-flag";
3004
- flag.textContent = msg.flags.includes("\\Flagged") ? "\u2605" : "\u2606";
3068
+ flag.textContent = flagOps.isFlagged(msg.flags) ? "\u2605" : "\u2606";
3005
3069
  flag.title = "Toggle flag";
3006
3070
  flag.addEventListener("click", (e) => this.onFlagClick(e));
3007
3071
  this.flagEl = flag;
@@ -3097,6 +3161,28 @@ var init_message_list = __esm({
3097
3161
  markBodyCached() {
3098
3162
  this.el.classList.remove("not-downloaded");
3099
3163
  }
3164
+ // Visual-state accessors for flag toggles. Read the *visual* state
3165
+ // (CSS class), not `this.msg.flags`, because the flag array can lag
3166
+ // the rendered class — auto-mark-as-read removes the `unread` class
3167
+ // immediately on click but `\Seen` doesn't land in `msg.flags` until
3168
+ // the auto-mark timer fires (default 2 s). Right-click menus and
3169
+ // keyboard shortcuts ask "what does the user see?" — that's what
3170
+ // these getters answer. Setters keep both visual + flag-array in
3171
+ // sync so the next read by either side agrees.
3172
+ get isSeen() {
3173
+ return !this.el.classList.contains("unread");
3174
+ }
3175
+ set isSeen(yes) {
3176
+ this.setUnreadClass(!yes);
3177
+ this.msg.flags = flagOps.set(this.msg.flags, FLAG.SEEN, yes);
3178
+ }
3179
+ get isFlagged() {
3180
+ return this.el.classList.contains("flagged");
3181
+ }
3182
+ set isFlagged(yes) {
3183
+ this.setFlaggedClass(yes);
3184
+ this.msg.flags = flagOps.set(this.msg.flags, FLAG.FLAGGED, yes);
3185
+ }
3100
3186
  onAvatarClick(e) {
3101
3187
  e.stopPropagation();
3102
3188
  const body = document.getElementById("ml-body");
@@ -3157,7 +3243,7 @@ var init_message_list = __esm({
3157
3243
  e.stopPropagation();
3158
3244
  const isFlagged = this.el.classList.contains("flagged");
3159
3245
  const currentFlags = this.msg.flags || [];
3160
- const newFlags = isFlagged ? currentFlags.filter((f) => f !== "\\Flagged") : [...currentFlags, "\\Flagged"];
3246
+ const newFlags = isFlagged ? flagOps.remove(currentFlags, FLAG.FLAGGED) : flagOps.add(currentFlags, FLAG.FLAGGED);
3161
3247
  try {
3162
3248
  await updateFlags(this.accountId, this.msg.uid, newFlags);
3163
3249
  this.msg.flags = newFlags;
@@ -3288,8 +3374,8 @@ var init_message_list = __esm({
3288
3374
  focusRow(this);
3289
3375
  }
3290
3376
  }
3291
- const isSeen = this.msg.flags.includes("\\Seen");
3292
- const isFlagged = this.msg.flags.includes("\\Flagged");
3377
+ const isSeen = !this.el.classList.contains("unread");
3378
+ const isFlagged = flagOps.isFlagged(this.msg.flags);
3293
3379
  const accountId = this.accountId;
3294
3380
  const msg = this.msg;
3295
3381
  const self = this;
@@ -3297,12 +3383,12 @@ var init_message_list = __esm({
3297
3383
  {
3298
3384
  label: isSeen ? "Mark unread" : "Mark read",
3299
3385
  action: async () => {
3300
- const newFlags = isSeen ? msg.flags.filter((f) => f !== "\\Seen") : [...msg.flags, "\\Seen"];
3386
+ const newFlags = flagOps.set(msg.flags, FLAG.SEEN, !isSeen);
3301
3387
  try {
3302
3388
  await updateFlags(accountId, msg.uid, newFlags);
3303
3389
  msg.flags = newFlags;
3304
3390
  updateMessageFlags(accountId, msg.uid, newFlags);
3305
- self.setUnreadClass(!newFlags.includes("\\Seen"));
3391
+ self.setUnreadClass(!flagOps.isSeen(newFlags));
3306
3392
  } catch {
3307
3393
  }
3308
3394
  }
@@ -3310,11 +3396,11 @@ var init_message_list = __esm({
3310
3396
  {
3311
3397
  label: isFlagged ? "Unflag" : "Flag",
3312
3398
  action: async () => {
3313
- const newFlags = isFlagged ? msg.flags.filter((f) => f !== "\\Flagged") : [...msg.flags, "\\Flagged"];
3399
+ const newFlags = flagOps.set(msg.flags, FLAG.FLAGGED, !isFlagged);
3314
3400
  try {
3315
3401
  await updateFlags(accountId, msg.uid, newFlags);
3316
3402
  msg.flags = newFlags;
3317
- self.setFlaggedClass(newFlags.includes("\\Flagged"));
3403
+ self.setFlaggedClass(flagOps.isFlagged(newFlags));
3318
3404
  } catch {
3319
3405
  }
3320
3406
  }
@@ -5800,6 +5886,7 @@ async function updateFolderCounts() {
5800
5886
 
5801
5887
  // client/app.ts
5802
5888
  init_message_list();
5889
+ init_mailx_types();
5803
5890
  init_message_viewer();
5804
5891
  init_api_client();
5805
5892
  init_message_state();
@@ -6706,13 +6793,13 @@ document.getElementById("btn-tb-spam")?.addEventListener("click", spamSelectedMe
6706
6793
  document.getElementById("btn-flag")?.addEventListener("click", async () => {
6707
6794
  const sel = getCurrentFocused();
6708
6795
  if (!sel) return;
6709
- const isFlagged = sel.flags.includes("\\Flagged");
6710
- const newFlags = isFlagged ? sel.flags.filter((f) => f !== "\\Flagged") : [...sel.flags, "\\Flagged"];
6796
+ const isFlagged = flagOps.isFlagged(sel.flags);
6797
+ const newFlags = isFlagged ? flagOps.remove(sel.flags, FLAG.FLAGGED) : flagOps.add(sel.flags, FLAG.FLAGGED);
6711
6798
  try {
6712
6799
  await updateFlags(sel.accountId, sel.uid, newFlags);
6713
6800
  sel.flags = newFlags;
6714
6801
  updateMessageFlags(sel.accountId, sel.uid, newFlags);
6715
- setRowFlagged(sel.accountId, sel.uid, newFlags.includes("\\Flagged"));
6802
+ setRowFlagged(sel.accountId, sel.uid, flagOps.isFlagged(newFlags));
6716
6803
  } catch (e) {
6717
6804
  console.error(`Flag toggle failed: ${e.message}`);
6718
6805
  }
@@ -6802,13 +6889,13 @@ document.getElementById("btn-compose")?.addEventListener("click", () => openComp
6802
6889
  document.getElementById("btn-mark-unread")?.addEventListener("click", () => {
6803
6890
  const sel = getCurrentFocused();
6804
6891
  if (!sel) return;
6805
- const isSeen = sel.flags.includes("\\Seen");
6806
- const newFlags = isSeen ? sel.flags.filter((f) => f !== "\\Seen") : [...sel.flags, "\\Seen"];
6892
+ const isSeen = flagOps.isSeen(sel.flags);
6893
+ const newFlags = flagOps.set(sel.flags, FLAG.SEEN, !isSeen);
6807
6894
  updateFlags(sel.accountId, sel.uid, newFlags).then(() => {
6808
6895
  sel.flags = newFlags;
6809
6896
  updateMessageFlags(sel.accountId, sel.uid, newFlags);
6810
6897
  const row = document.querySelector(`.ml-row[data-uid="${sel.uid}"][data-account-id="${sel.accountId}"]`);
6811
- if (row) row.classList.toggle("unread", !newFlags.includes("\\Seen"));
6898
+ if (row) row.classList.toggle("unread", !flagOps.isSeen(newFlags));
6812
6899
  }).catch(() => {
6813
6900
  });
6814
6901
  });
@@ -7823,13 +7910,13 @@ document.addEventListener("keydown", (e) => {
7823
7910
  const sel = getCurrentFocused();
7824
7911
  if (!sel) return;
7825
7912
  e.preventDefault();
7826
- const isSeen = sel.flags.includes("\\Seen");
7827
- const newFlags = isSeen ? sel.flags.filter((f) => f !== "\\Seen") : [...sel.flags, "\\Seen"];
7913
+ const isSeen = flagOps.isSeen(sel.flags);
7914
+ const newFlags = flagOps.set(sel.flags, FLAG.SEEN, !isSeen);
7828
7915
  updateFlags(sel.accountId, sel.uid, newFlags).then(() => {
7829
7916
  sel.flags = newFlags;
7830
7917
  updateMessageFlags(sel.accountId, sel.uid, newFlags);
7831
7918
  const row = document.querySelector(`.ml-row[data-uid="${sel.uid}"][data-account-id="${sel.accountId}"]`);
7832
- if (row) row.classList.toggle("unread", !newFlags.includes("\\Seen"));
7919
+ if (row) row.classList.toggle("unread", !flagOps.isSeen(newFlags));
7833
7920
  }).catch(() => {
7834
7921
  });
7835
7922
  }
@@ -9168,7 +9255,7 @@ document.addEventListener("mailx-popout-message", (async (e) => {
9168
9255
  alert(`Couldn't load message: ${err?.message || err}`);
9169
9256
  return;
9170
9257
  }
9171
- const isDraft = Array.isArray(msg?.flags) && msg.flags.includes("\\Draft");
9258
+ const isDraft = Array.isArray(msg?.flags) && flagOps.isDraft(msg.flags);
9172
9259
  if (isDraft) {
9173
9260
  const accts = await getAccounts();
9174
9261
  const init = {