@bobfrankston/rmfmail 1.2.286 → 1.2.288
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 +23 -37
- package/client/android-bootstrap.bundle.js +21 -5
- package/client/android-bootstrap.bundle.js.map +2 -2
- package/client/app.bundle.js.map +1 -1
- package/client/compose/compose.bundle.js +169 -39
- package/client/compose/compose.bundle.js.map +3 -3
- package/client/compose/harper-lint.js +125 -42
- package/client/compose/harper-lint.js.map +1 -1
- package/client/compose/harper-lint.ts +120 -40
- package/client/lib/rmf-tiny.js +85 -0
- package/npmchanges.md +82 -0
- package/package.json +8 -8
- package/packages/mailx-imap/package-lock.json +2 -2
- package/packages/mailx-imap/package.json +1 -1
- package/packages/mailx-service/index.d.ts.map +1 -1
- package/packages/mailx-service/index.js +20 -3
- package/packages/mailx-service/index.js.map +1 -1
- package/packages/mailx-settings/package.json +1 -1
- package/packages/mailx-store/package.json +1 -1
- package/packages/mailx-store-web/package.json +1 -1
- package/packages/mailx-types/package.json +1 -1
- package/packages/mailx-types/trust.d.ts.map +1 -1
- package/packages/mailx-types/trust.js +43 -4
- package/packages/mailx-types/trust.js.map +1 -1
- package/packages/mailx-types/trust.ts +50 -5
- /package/packages/mailx-imap/{node_modules.npmglobalize-stash-50896 → node_modules.npmglobalize-stash-39836}/.package-lock.json +0 -0
|
@@ -2686,7 +2686,15 @@ async function createTinyMceEditor(container2, opts = {}) {
|
|
|
2686
2686
|
// window; TinyMCE's fullscreen plugin re-positions the container in
|
|
2687
2687
|
// ways that produce a blank body, so it's not in the plugin list.
|
|
2688
2688
|
menu: {
|
|
2689
|
-
view: { title: "View", items: "rmfsource | visualaid visualchars visualblocks | preview | zoomIn zoomOut zoomReset" }
|
|
2689
|
+
view: { title: "View", items: "rmfsource | visualaid visualchars visualblocks | preview | zoomIn zoomOut zoomReset" },
|
|
2690
|
+
// Insert menu — TinyMCE's default list minus the items whose
|
|
2691
|
+
// plugins we don't load (media, pagebreak, anchor, accordion),
|
|
2692
|
+
// plus the two quoting items. Listed in full because naming a
|
|
2693
|
+
// menu REPLACES its item list; the defaults do not carry over.
|
|
2694
|
+
insert: {
|
|
2695
|
+
title: "Insert",
|
|
2696
|
+
items: "image link inserttable | rmfblockquote rmfquotepaste | rmfcode codesample charmap emoticons | hr nonbreaking insertdatetime"
|
|
2697
|
+
}
|
|
2690
2698
|
},
|
|
2691
2699
|
// Disable the "Get all features" upsell badge that TinyMCE 6+
|
|
2692
2700
|
// injects automatically when no premium plugins are listed.
|
|
@@ -3107,6 +3115,18 @@ async function createTinyMceEditor(container2, opts = {}) {
|
|
|
3107
3115
|
text: "Code block\u2026",
|
|
3108
3116
|
onAction: openCodeDialog
|
|
3109
3117
|
});
|
|
3118
|
+
ed.ui.registry.addMenuItem("rmfblockquote", {
|
|
3119
|
+
icon: "quote",
|
|
3120
|
+
text: "Blockquote",
|
|
3121
|
+
onAction: () => ed.execCommand("mceBlockQuote")
|
|
3122
|
+
});
|
|
3123
|
+
ed.ui.registry.addMenuItem("rmfquotepaste", {
|
|
3124
|
+
icon: "quote",
|
|
3125
|
+
text: "Quoted text (paste)\u2026",
|
|
3126
|
+
onAction: () => {
|
|
3127
|
+
void pasteAsQuote(ed);
|
|
3128
|
+
}
|
|
3129
|
+
});
|
|
3110
3130
|
ed.ui.registry.addMenuItem("rmfsource", {
|
|
3111
3131
|
icon: "sourcecode",
|
|
3112
3132
|
text: "HTML source\u2026",
|
|
@@ -3345,6 +3365,48 @@ async function createTinyMceEditor(container2, opts = {}) {
|
|
|
3345
3365
|
nativeEditor: editor2
|
|
3346
3366
|
};
|
|
3347
3367
|
}
|
|
3368
|
+
async function pasteAsQuote(ed) {
|
|
3369
|
+
const notify = (text, type) => {
|
|
3370
|
+
try {
|
|
3371
|
+
ed.notificationManager.open({ text, type, timeout: 4e3 });
|
|
3372
|
+
} catch {
|
|
3373
|
+
}
|
|
3374
|
+
};
|
|
3375
|
+
const escape = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
3376
|
+
const fragment = (html2) => {
|
|
3377
|
+
const marked = html2.match(/<!--\s*StartFragment\s*-->([\s\S]*?)<!--\s*EndFragment\s*-->/i);
|
|
3378
|
+
const inner = marked ? marked[1] : html2.replace(/[\s\S]*<body[^>]*>|<\/body>[\s\S]*/gi, "");
|
|
3379
|
+
return inner.trim();
|
|
3380
|
+
};
|
|
3381
|
+
let html = "";
|
|
3382
|
+
try {
|
|
3383
|
+
const clip = navigator.clipboard;
|
|
3384
|
+
if (clip?.read) {
|
|
3385
|
+
const items = await clip.read();
|
|
3386
|
+
for (const item of items) {
|
|
3387
|
+
if (!item.types.includes("text/html"))
|
|
3388
|
+
continue;
|
|
3389
|
+
html = fragment(await (await item.getType("text/html")).text());
|
|
3390
|
+
break;
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
if (!html) {
|
|
3394
|
+
const text = await navigator.clipboard?.readText?.() || "";
|
|
3395
|
+
if (text.trim()) {
|
|
3396
|
+
html = text.trim().split(/\n\s*\n/).map((para) => `<p>${escape(para).replace(/\n/g, "<br>")}</p>`).join("");
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3399
|
+
} catch (e) {
|
|
3400
|
+
notify(`Could not read the clipboard: ${e?.message || e}`, "error");
|
|
3401
|
+
return;
|
|
3402
|
+
}
|
|
3403
|
+
if (!html) {
|
|
3404
|
+
notify("There is nothing on the clipboard to quote.", "warning");
|
|
3405
|
+
return;
|
|
3406
|
+
}
|
|
3407
|
+
ed.insertContent(`<blockquote>${html}</blockquote>`);
|
|
3408
|
+
ed.undoManager.add();
|
|
3409
|
+
}
|
|
3348
3410
|
function openSourceDialog(editor2) {
|
|
3349
3411
|
const SENTINEL = "\uE000";
|
|
3350
3412
|
let offset = -1;
|
|
@@ -3710,7 +3772,13 @@ var init_spellcheck = __esm({
|
|
|
3710
3772
|
// client/compose/harper-lint.js
|
|
3711
3773
|
var harper_lint_exports = {};
|
|
3712
3774
|
__export(harper_lint_exports, {
|
|
3713
|
-
|
|
3775
|
+
blockText: () => blockText,
|
|
3776
|
+
caretOffset: () => caretOffset,
|
|
3777
|
+
collectBlocks: () => collectBlocks,
|
|
3778
|
+
initHarperLint: () => initHarperLint,
|
|
3779
|
+
lineBox: () => lineBox,
|
|
3780
|
+
sentenceStart: () => sentenceStart,
|
|
3781
|
+
spanToRange: () => spanToRange
|
|
3714
3782
|
});
|
|
3715
3783
|
function initHarperLint(ed) {
|
|
3716
3784
|
let disposed = false;
|
|
@@ -3735,42 +3803,6 @@ function initHarperLint(ed) {
|
|
|
3735
3803
|
doc.getElementById(OVERLAY_ID2)?.remove();
|
|
3736
3804
|
doc.getElementById(POPUP_ID)?.remove();
|
|
3737
3805
|
};
|
|
3738
|
-
const collectBlocks = (root) => {
|
|
3739
|
-
const kids = Array.from(root.children).filter((c) => c instanceof HTMLElement);
|
|
3740
|
-
const blocks = (kids.length ? kids : [root]).filter((b) => b.tagName !== "BLOCKQUOTE" && !b.closest("blockquote") && !b.querySelector("blockquote"));
|
|
3741
|
-
return blocks;
|
|
3742
|
-
};
|
|
3743
|
-
const blockText = (block, doc) => {
|
|
3744
|
-
const walker = doc.createTreeWalker(block, NodeFilter.SHOW_TEXT);
|
|
3745
|
-
const nodes = [];
|
|
3746
|
-
let text = "";
|
|
3747
|
-
for (let n = walker.nextNode(); n; n = walker.nextNode()) {
|
|
3748
|
-
nodes.push({ node: n, from: text.length });
|
|
3749
|
-
text += n.data;
|
|
3750
|
-
}
|
|
3751
|
-
return { text, nodes };
|
|
3752
|
-
};
|
|
3753
|
-
const spanToRange = (doc, nodes, start, end) => {
|
|
3754
|
-
let a = null;
|
|
3755
|
-
let b = null;
|
|
3756
|
-
for (const e of nodes) {
|
|
3757
|
-
const len = e.node.data.length;
|
|
3758
|
-
if (!a && start >= e.from && start <= e.from + len)
|
|
3759
|
-
a = { node: e.node, off: start - e.from };
|
|
3760
|
-
if (end >= e.from && end <= e.from + len)
|
|
3761
|
-
b = { node: e.node, off: end - e.from };
|
|
3762
|
-
}
|
|
3763
|
-
if (!a || !b)
|
|
3764
|
-
return null;
|
|
3765
|
-
try {
|
|
3766
|
-
const r = doc.createRange();
|
|
3767
|
-
r.setStart(a.node, a.off);
|
|
3768
|
-
r.setEnd(b.node, b.off);
|
|
3769
|
-
return r;
|
|
3770
|
-
} catch {
|
|
3771
|
-
return null;
|
|
3772
|
-
}
|
|
3773
|
-
};
|
|
3774
3806
|
const paint = () => {
|
|
3775
3807
|
if (disposed)
|
|
3776
3808
|
return;
|
|
@@ -3834,9 +3866,13 @@ function initHarperLint(ed) {
|
|
|
3834
3866
|
const tx = texts[i];
|
|
3835
3867
|
if (!tx)
|
|
3836
3868
|
return;
|
|
3869
|
+
const caret = caretOffset(t.doc, tx.nodes);
|
|
3870
|
+
const writingFrom = caret < 0 ? -1 : sentenceStart(tx.text, caret);
|
|
3837
3871
|
for (const l of lints || []) {
|
|
3838
3872
|
if (SKIP_KINDS.has(l.kind))
|
|
3839
3873
|
continue;
|
|
3874
|
+
if (writingFrom >= 0 && l.end > writingFrom && l.start <= caret)
|
|
3875
|
+
continue;
|
|
3840
3876
|
const range = spanToRange(t.doc, tx.nodes, l.start, l.end);
|
|
3841
3877
|
if (range)
|
|
3842
3878
|
next.push({ lint: l, range });
|
|
@@ -3966,7 +4002,7 @@ function initHarperLint(ed) {
|
|
|
3966
4002
|
}
|
|
3967
4003
|
};
|
|
3968
4004
|
}
|
|
3969
|
-
var DEBOUNCE_MS, OVERLAY_ID2, POPUP_ID, SKIP_KINDS;
|
|
4005
|
+
var DEBOUNCE_MS, OVERLAY_ID2, POPUP_ID, SKIP_KINDS, collectBlocks, LINE_BREAKING, blockText, lineBox, caretOffset, sentenceStart, spanToRange;
|
|
3970
4006
|
var init_harper_lint = __esm({
|
|
3971
4007
|
"client/compose/harper-lint.js"() {
|
|
3972
4008
|
"use strict";
|
|
@@ -3975,6 +4011,100 @@ var init_harper_lint = __esm({
|
|
|
3975
4011
|
OVERLAY_ID2 = "harper-overlay";
|
|
3976
4012
|
POPUP_ID = "harper-popup";
|
|
3977
4013
|
SKIP_KINDS = /* @__PURE__ */ new Set(["Spelling"]);
|
|
4014
|
+
collectBlocks = (root) => {
|
|
4015
|
+
const kids = Array.from(root.children).filter((c) => c instanceof HTMLElement);
|
|
4016
|
+
const blocks = (kids.length ? kids : [root]).filter((b) => b.tagName !== "BLOCKQUOTE" && !b.closest("blockquote") && !b.querySelector("blockquote"));
|
|
4017
|
+
return blocks;
|
|
4018
|
+
};
|
|
4019
|
+
LINE_BREAKING = /* @__PURE__ */ new Set([
|
|
4020
|
+
"BR",
|
|
4021
|
+
"P",
|
|
4022
|
+
"DIV",
|
|
4023
|
+
"LI",
|
|
4024
|
+
"UL",
|
|
4025
|
+
"OL",
|
|
4026
|
+
"TR",
|
|
4027
|
+
"TD",
|
|
4028
|
+
"TH",
|
|
4029
|
+
"TABLE",
|
|
4030
|
+
"PRE",
|
|
4031
|
+
"HR",
|
|
4032
|
+
"BLOCKQUOTE",
|
|
4033
|
+
"H1",
|
|
4034
|
+
"H2",
|
|
4035
|
+
"H3",
|
|
4036
|
+
"H4",
|
|
4037
|
+
"H5",
|
|
4038
|
+
"H6",
|
|
4039
|
+
"SECTION",
|
|
4040
|
+
"ARTICLE",
|
|
4041
|
+
"FIGURE"
|
|
4042
|
+
]);
|
|
4043
|
+
blockText = (block, doc) => {
|
|
4044
|
+
const walker = doc.createTreeWalker(block, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT);
|
|
4045
|
+
const nodes = [];
|
|
4046
|
+
let text = "";
|
|
4047
|
+
let pendingBreak = false;
|
|
4048
|
+
for (let n = walker.nextNode(); n; n = walker.nextNode()) {
|
|
4049
|
+
if (n.nodeType === Node.ELEMENT_NODE) {
|
|
4050
|
+
if (LINE_BREAKING.has(n.tagName))
|
|
4051
|
+
pendingBreak = true;
|
|
4052
|
+
continue;
|
|
4053
|
+
}
|
|
4054
|
+
const data = n.data;
|
|
4055
|
+
if (!data)
|
|
4056
|
+
continue;
|
|
4057
|
+
if (pendingBreak && text)
|
|
4058
|
+
text += "\n";
|
|
4059
|
+
pendingBreak = false;
|
|
4060
|
+
nodes.push({ node: n, from: text.length });
|
|
4061
|
+
text += data;
|
|
4062
|
+
}
|
|
4063
|
+
return { text, nodes };
|
|
4064
|
+
};
|
|
4065
|
+
lineBox = (node) => {
|
|
4066
|
+
for (let e = node; e; e = e.parentNode)
|
|
4067
|
+
if (e.nodeType === Node.ELEMENT_NODE && LINE_BREAKING.has(e.tagName))
|
|
4068
|
+
return e;
|
|
4069
|
+
return null;
|
|
4070
|
+
};
|
|
4071
|
+
caretOffset = (doc, nodes) => {
|
|
4072
|
+
const sel = doc.getSelection?.();
|
|
4073
|
+
if (!sel || !sel.focusNode)
|
|
4074
|
+
return -1;
|
|
4075
|
+
for (const e of nodes)
|
|
4076
|
+
if (e.node === sel.focusNode)
|
|
4077
|
+
return e.from + sel.focusOffset;
|
|
4078
|
+
return -1;
|
|
4079
|
+
};
|
|
4080
|
+
sentenceStart = (text, caret) => {
|
|
4081
|
+
const before = text.slice(0, caret);
|
|
4082
|
+
const m = before.match(/[.!?…\n][^.!?…\n]*$/);
|
|
4083
|
+
return m ? caret - (m[0].length - 1) : 0;
|
|
4084
|
+
};
|
|
4085
|
+
spanToRange = (doc, nodes, start, end) => {
|
|
4086
|
+
let a = null;
|
|
4087
|
+
let b = null;
|
|
4088
|
+
for (const e of nodes) {
|
|
4089
|
+
const len = e.node.data.length;
|
|
4090
|
+
if (!a && start >= e.from && start <= e.from + len)
|
|
4091
|
+
a = { node: e.node, off: start - e.from };
|
|
4092
|
+
if (end >= e.from && end <= e.from + len)
|
|
4093
|
+
b = { node: e.node, off: end - e.from };
|
|
4094
|
+
}
|
|
4095
|
+
if (!a || !b)
|
|
4096
|
+
return null;
|
|
4097
|
+
if (lineBox(a.node) !== lineBox(b.node))
|
|
4098
|
+
return null;
|
|
4099
|
+
try {
|
|
4100
|
+
const r = doc.createRange();
|
|
4101
|
+
r.setStart(a.node, a.off);
|
|
4102
|
+
r.setEnd(b.node, b.off);
|
|
4103
|
+
return r;
|
|
4104
|
+
} catch {
|
|
4105
|
+
return null;
|
|
4106
|
+
}
|
|
4107
|
+
};
|
|
3978
4108
|
}
|
|
3979
4109
|
});
|
|
3980
4110
|
|