@bobfrankston/rmfmail 1.2.194 → 1.2.196
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/client/app.bundle.js +6 -5
- package/client/app.bundle.js.map +2 -2
- package/client/app.js +20 -10
- package/client/app.js.map +1 -1
- package/client/app.ts +18 -10
- package/client/compose/compose.bundle.js +34 -2
- package/client/compose/compose.bundle.js.map +2 -2
- package/client/compose/editor.js +14 -1
- package/client/compose/editor.js.map +1 -1
- package/client/compose/editor.ts +14 -1
- package/client/compose/paste-markdown.js +0 -0
- package/client/compose/paste-markdown.js.map +1 -1
- package/client/compose/paste-markdown.ts +0 -0
- package/client/package.json +1 -1
- package/package.json +1 -1
- /package/packages/mailx-imap/{node_modules.npmglobalize-stash-81836 → node_modules.npmglobalize-stash-50260}/.package-lock.json +0 -0
package/client/app.ts
CHANGED
|
@@ -94,13 +94,17 @@ propagateAppName();
|
|
|
94
94
|
if (e.key === "F5" || e.key === "F3") return true;
|
|
95
95
|
if ((e.ctrlKey || e.metaKey) && (e.key === "r" || e.key === "R")) return true;
|
|
96
96
|
// Browser accelerators bound to Ctrl-letter combos that mailx
|
|
97
|
-
// doesn't want to forward:
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
-
//
|
|
97
|
+
// doesn't want to forward: S (save page), U (view source),
|
|
98
|
+
// J (downloads), L (focus address bar — n/a in WebView but
|
|
99
|
+
// harmless), G (find next). Note: O is "open file" in browsers —
|
|
100
|
+
// mailx uses Ctrl+O nowhere meaningful, so block. P is NOT here:
|
|
101
|
+
// mailx's own Ctrl+P handler prints the focused letter and
|
|
102
|
+
// preventDefaults the browser dialog itself — listing it here
|
|
103
|
+
// stopPropagation'd the event before that handler could run, which
|
|
104
|
+
// is why the print shortcut was dead (Bob 2026-07-30).
|
|
101
105
|
if (e.ctrlKey || e.metaKey) {
|
|
102
106
|
const k = e.key.toLowerCase();
|
|
103
|
-
if (["
|
|
107
|
+
if (["s", "u", "j", "l", "g", "o"].includes(k)) return true;
|
|
104
108
|
}
|
|
105
109
|
// Alt+Left / Alt+Right = browser back / forward. No use in mailx.
|
|
106
110
|
if (e.altKey && (e.key === "ArrowLeft" || e.key === "ArrowRight")) return true;
|
|
@@ -3746,13 +3750,17 @@ document.addEventListener("keydown", (e) => {
|
|
|
3746
3750
|
openCompose("new");
|
|
3747
3751
|
}
|
|
3748
3752
|
// Ctrl+P = Print the focused message. preventDefault stops the host
|
|
3749
|
-
// browser from printing the whole app window instead of the letter
|
|
3753
|
+
// browser from printing the whole app window instead of the letter —
|
|
3754
|
+
// UNCONDITIONALLY, even with focus in a text field: the WebView's
|
|
3755
|
+
// whole-app print dialog is never what the user wants, and ^P should
|
|
3756
|
+
// print the current letter regardless of where the caret sits.
|
|
3750
3757
|
if (e.ctrlKey && (e.key === "p" || e.key === "P") && !e.shiftKey && !e.altKey) {
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
if (!inText) {
|
|
3754
|
-
e.preventDefault();
|
|
3758
|
+
e.preventDefault();
|
|
3759
|
+
if (getCurrentMessage()) {
|
|
3755
3760
|
printCurrentMessage();
|
|
3761
|
+
} else {
|
|
3762
|
+
const s = document.getElementById("status-sync");
|
|
3763
|
+
if (s) s.textContent = "Nothing to print — select a message first.";
|
|
3756
3764
|
}
|
|
3757
3765
|
}
|
|
3758
3766
|
// Ctrl+T = new view tab. The strip is hidden with a single tab (no wasted
|
|
@@ -3568,6 +3568,23 @@ function markdownToEmailHtml(md) {
|
|
|
3568
3568
|
}
|
|
3569
3569
|
return out.join("\n");
|
|
3570
3570
|
}
|
|
3571
|
+
function looksLikeHtml(text) {
|
|
3572
|
+
if (!text || text.length > 5e5)
|
|
3573
|
+
return false;
|
|
3574
|
+
const t = text.trim();
|
|
3575
|
+
if (!t.startsWith("<"))
|
|
3576
|
+
return false;
|
|
3577
|
+
if (!/^<(!doctype|html|head|body|div|p|table|ul|ol|li|h[1-6]|blockquote|section|article|header|footer|span|b|i|strong|em|a|img|br|hr|pre|code|font|center)\b/i.test(t))
|
|
3578
|
+
return false;
|
|
3579
|
+
return /<\/[a-z][a-z0-9]*\s*>/i.test(t) || /^<(img|br|hr|!doctype)\b/i.test(t);
|
|
3580
|
+
}
|
|
3581
|
+
function sanitizeHtmlSource(html) {
|
|
3582
|
+
let t = html;
|
|
3583
|
+
const bm = t.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
|
|
3584
|
+
if (bm)
|
|
3585
|
+
t = bm[1];
|
|
3586
|
+
return t.replace(/<script\b[\s\S]*?<\/script\s*>/gi, "").replace(/<style\b[\s\S]*?<\/style\s*>/gi, "").replace(/\son[a-z]+\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/gi, "").replace(/\s(href|src)\s*=\s*(["']?)\s*javascript:[^"'\s>]*\2/gi, "");
|
|
3587
|
+
}
|
|
3571
3588
|
function wireMarkdownPaste(target, insertHtml) {
|
|
3572
3589
|
target.addEventListener("paste", (e) => {
|
|
3573
3590
|
try {
|
|
@@ -3579,11 +3596,18 @@ function wireMarkdownPaste(target, insertHtml) {
|
|
|
3579
3596
|
if (Array.from(cb.items).some((it) => it.kind === "file"))
|
|
3580
3597
|
return;
|
|
3581
3598
|
const plain = cb.getData("text/plain");
|
|
3582
|
-
if (!plain
|
|
3599
|
+
if (!plain)
|
|
3600
|
+
return;
|
|
3601
|
+
let converted = null;
|
|
3602
|
+
if (looksLikeHtml(plain))
|
|
3603
|
+
converted = sanitizeHtmlSource(plain);
|
|
3604
|
+
else if (looksLikeMarkdown(plain))
|
|
3605
|
+
converted = markdownToEmailHtml(plain);
|
|
3606
|
+
if (converted === null)
|
|
3583
3607
|
return;
|
|
3584
3608
|
e.preventDefault();
|
|
3585
3609
|
e.stopImmediatePropagation();
|
|
3586
|
-
insertHtml(
|
|
3610
|
+
insertHtml(converted);
|
|
3587
3611
|
} catch {
|
|
3588
3612
|
}
|
|
3589
3613
|
}, true);
|
|
@@ -4035,6 +4059,14 @@ function createQuillEditor(container2) {
|
|
|
4035
4059
|
}
|
|
4036
4060
|
return;
|
|
4037
4061
|
}
|
|
4062
|
+
if (plain && looksLikeHtml(plain)) {
|
|
4063
|
+
consume();
|
|
4064
|
+
const range = q.getSelection(true) || { index: q.getLength(), length: 0 };
|
|
4065
|
+
if (range.length > 0)
|
|
4066
|
+
q.deleteText(range.index, range.length);
|
|
4067
|
+
q.clipboard.dangerouslyPasteHTML(range.index, sanitizeHtmlSource(plain));
|
|
4068
|
+
return;
|
|
4069
|
+
}
|
|
4038
4070
|
if (plain && looksLikeMarkdown(plain)) {
|
|
4039
4071
|
consume();
|
|
4040
4072
|
const range = q.getSelection(true) || { index: q.getLength(), length: 0 };
|