@bobfrankston/rmfmail 1.0.700 → 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;
@@ -3289,7 +3375,7 @@ var init_message_list = __esm({
3289
3375
  }
3290
3376
  }
3291
3377
  const isSeen = !this.el.classList.contains("unread");
3292
- const isFlagged = this.msg.flags.includes("\\Flagged");
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,17 +3383,12 @@ var init_message_list = __esm({
3297
3383
  {
3298
3384
  label: isSeen ? "Mark unread" : "Mark read",
3299
3385
  action: async () => {
3300
- const set = new Set(msg.flags);
3301
- if (isSeen)
3302
- set.delete("\\Seen");
3303
- else
3304
- set.add("\\Seen");
3305
- const newFlags = Array.from(set);
3386
+ const newFlags = flagOps.set(msg.flags, FLAG.SEEN, !isSeen);
3306
3387
  try {
3307
3388
  await updateFlags(accountId, msg.uid, newFlags);
3308
3389
  msg.flags = newFlags;
3309
3390
  updateMessageFlags(accountId, msg.uid, newFlags);
3310
- self.setUnreadClass(!newFlags.includes("\\Seen"));
3391
+ self.setUnreadClass(!flagOps.isSeen(newFlags));
3311
3392
  } catch {
3312
3393
  }
3313
3394
  }
@@ -3315,11 +3396,11 @@ var init_message_list = __esm({
3315
3396
  {
3316
3397
  label: isFlagged ? "Unflag" : "Flag",
3317
3398
  action: async () => {
3318
- const newFlags = isFlagged ? msg.flags.filter((f) => f !== "\\Flagged") : [...msg.flags, "\\Flagged"];
3399
+ const newFlags = flagOps.set(msg.flags, FLAG.FLAGGED, !isFlagged);
3319
3400
  try {
3320
3401
  await updateFlags(accountId, msg.uid, newFlags);
3321
3402
  msg.flags = newFlags;
3322
- self.setFlaggedClass(newFlags.includes("\\Flagged"));
3403
+ self.setFlaggedClass(flagOps.isFlagged(newFlags));
3323
3404
  } catch {
3324
3405
  }
3325
3406
  }
@@ -5805,6 +5886,7 @@ async function updateFolderCounts() {
5805
5886
 
5806
5887
  // client/app.ts
5807
5888
  init_message_list();
5889
+ init_mailx_types();
5808
5890
  init_message_viewer();
5809
5891
  init_api_client();
5810
5892
  init_message_state();
@@ -6711,13 +6793,13 @@ document.getElementById("btn-tb-spam")?.addEventListener("click", spamSelectedMe
6711
6793
  document.getElementById("btn-flag")?.addEventListener("click", async () => {
6712
6794
  const sel = getCurrentFocused();
6713
6795
  if (!sel) return;
6714
- const isFlagged = sel.flags.includes("\\Flagged");
6715
- 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);
6716
6798
  try {
6717
6799
  await updateFlags(sel.accountId, sel.uid, newFlags);
6718
6800
  sel.flags = newFlags;
6719
6801
  updateMessageFlags(sel.accountId, sel.uid, newFlags);
6720
- setRowFlagged(sel.accountId, sel.uid, newFlags.includes("\\Flagged"));
6802
+ setRowFlagged(sel.accountId, sel.uid, flagOps.isFlagged(newFlags));
6721
6803
  } catch (e) {
6722
6804
  console.error(`Flag toggle failed: ${e.message}`);
6723
6805
  }
@@ -6807,13 +6889,13 @@ document.getElementById("btn-compose")?.addEventListener("click", () => openComp
6807
6889
  document.getElementById("btn-mark-unread")?.addEventListener("click", () => {
6808
6890
  const sel = getCurrentFocused();
6809
6891
  if (!sel) return;
6810
- const isSeen = sel.flags.includes("\\Seen");
6811
- 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);
6812
6894
  updateFlags(sel.accountId, sel.uid, newFlags).then(() => {
6813
6895
  sel.flags = newFlags;
6814
6896
  updateMessageFlags(sel.accountId, sel.uid, newFlags);
6815
6897
  const row = document.querySelector(`.ml-row[data-uid="${sel.uid}"][data-account-id="${sel.accountId}"]`);
6816
- if (row) row.classList.toggle("unread", !newFlags.includes("\\Seen"));
6898
+ if (row) row.classList.toggle("unread", !flagOps.isSeen(newFlags));
6817
6899
  }).catch(() => {
6818
6900
  });
6819
6901
  });
@@ -7828,13 +7910,13 @@ document.addEventListener("keydown", (e) => {
7828
7910
  const sel = getCurrentFocused();
7829
7911
  if (!sel) return;
7830
7912
  e.preventDefault();
7831
- const isSeen = sel.flags.includes("\\Seen");
7832
- 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);
7833
7915
  updateFlags(sel.accountId, sel.uid, newFlags).then(() => {
7834
7916
  sel.flags = newFlags;
7835
7917
  updateMessageFlags(sel.accountId, sel.uid, newFlags);
7836
7918
  const row = document.querySelector(`.ml-row[data-uid="${sel.uid}"][data-account-id="${sel.accountId}"]`);
7837
- if (row) row.classList.toggle("unread", !newFlags.includes("\\Seen"));
7919
+ if (row) row.classList.toggle("unread", !flagOps.isSeen(newFlags));
7838
7920
  }).catch(() => {
7839
7921
  });
7840
7922
  }
@@ -9173,7 +9255,7 @@ document.addEventListener("mailx-popout-message", (async (e) => {
9173
9255
  alert(`Couldn't load message: ${err?.message || err}`);
9174
9256
  return;
9175
9257
  }
9176
- const isDraft = Array.isArray(msg?.flags) && msg.flags.includes("\\Draft");
9258
+ const isDraft = Array.isArray(msg?.flags) && flagOps.isDraft(msg.flags);
9177
9259
  if (isDraft) {
9178
9260
  const accts = await getAccounts();
9179
9261
  const init = {