@bobfrankston/rmfmail 1.2.148 → 1.2.149
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.
|
@@ -2064,7 +2064,12 @@ async function createTinyMceEditor(container2, opts = {}) {
|
|
|
2064
2064
|
// clutters more than it helps in an email composer.
|
|
2065
2065
|
quickbars_selection_toolbar: "bold italic underline | forecolor | quicklink blockquote",
|
|
2066
2066
|
quickbars_insert_toolbar: false,
|
|
2067
|
-
|
|
2067
|
+
// Word-style layout buttons (registered in setup below): in-line
|
|
2068
|
+
// with text, image-left/text-wraps-right, image-right/text-wraps-
|
|
2069
|
+
// left. Replaced the generic alignleft/center/right icons, which
|
|
2070
|
+
// don't communicate wrapping (Bob 2026-07-18: "the align is
|
|
2071
|
+
// confusing, better to use the Word icons for the three cases").
|
|
2072
|
+
quickbars_image_toolbar: "rmfwrapinline rmfwrapleft rmfwrapright",
|
|
2068
2073
|
// Code-sample dropdown languages. TinyMCE's default list omits
|
|
2069
2074
|
// "Text" / plain — every option triggers syntax highlighting
|
|
2070
2075
|
// which mangles unrelated paste content (Bob 2026-05-24).
|
|
@@ -2202,6 +2207,43 @@ async function createTinyMceEditor(container2, opts = {}) {
|
|
|
2202
2207
|
setup: (ed) => {
|
|
2203
2208
|
if (opts.initialHtml)
|
|
2204
2209
|
ed.on("init", () => ed.setContent(opts.initialHtml));
|
|
2210
|
+
const ln = (x1, x2, y) => `<rect x="${x1}" y="${y}" width="${x2 - x1}" height="1.5" rx="0.75" fill="currentColor"/>`;
|
|
2211
|
+
const arch = (cx, base) => `<path d="M ${cx - 4.5} ${base} a 4.5 4.5 0 0 1 9 0 z" fill="currentColor"/>`;
|
|
2212
|
+
const svg = (body) => `<svg width="24" height="24" viewBox="0 0 24 24">${body}</svg>`;
|
|
2213
|
+
ed.ui.registry.addIcon("rmf-wrap-inline", svg(ln(3, 21, 4.5) + ln(3, 6.5, 14.5) + arch(12, 16) + ln(17.5, 21, 14.5) + ln(3, 21, 19.5)));
|
|
2214
|
+
ed.ui.registry.addIcon("rmf-wrap-left", svg(ln(3, 21, 4.5) + arch(7.5, 16) + ln(14, 21, 9.5) + ln(14, 21, 14.5) + ln(3, 21, 19.5)));
|
|
2215
|
+
ed.ui.registry.addIcon("rmf-wrap-right", svg(ln(3, 21, 4.5) + ln(3, 10, 9.5) + ln(3, 10, 14.5) + arch(16.5, 16) + ln(3, 21, 19.5)));
|
|
2216
|
+
const applyWrap = (mode) => {
|
|
2217
|
+
const node = ed.selection.getNode();
|
|
2218
|
+
if (!node || node.nodeName !== "IMG")
|
|
2219
|
+
return;
|
|
2220
|
+
ed.undoManager.transact(() => {
|
|
2221
|
+
ed.dom.setStyles(node, {
|
|
2222
|
+
float: mode === "inline" ? "" : mode,
|
|
2223
|
+
margin: mode === "inline" ? "" : mode === "left" ? "0 12px 8px 0" : "0 0 8px 12px"
|
|
2224
|
+
});
|
|
2225
|
+
});
|
|
2226
|
+
ed.nodeChanged();
|
|
2227
|
+
};
|
|
2228
|
+
const wrapButton = (name, icon, tip, mode) => {
|
|
2229
|
+
ed.ui.registry.addToggleButton(name, {
|
|
2230
|
+
icon,
|
|
2231
|
+
tooltip: tip,
|
|
2232
|
+
onAction: () => applyWrap(mode),
|
|
2233
|
+
onSetup: (api) => {
|
|
2234
|
+
const update = () => {
|
|
2235
|
+
const node = ed.selection.getNode();
|
|
2236
|
+
const f = node?.nodeName === "IMG" ? node.style.float || "inline" : "";
|
|
2237
|
+
api.setActive(f === mode || mode === "inline" && f === "none");
|
|
2238
|
+
};
|
|
2239
|
+
ed.on("NodeChange", update);
|
|
2240
|
+
return () => ed.off("NodeChange", update);
|
|
2241
|
+
}
|
|
2242
|
+
});
|
|
2243
|
+
};
|
|
2244
|
+
wrapButton("rmfwrapinline", "rmf-wrap-inline", "In line with text", "inline");
|
|
2245
|
+
wrapButton("rmfwrapleft", "rmf-wrap-left", "Image left \u2014 text wraps around the right", "left");
|
|
2246
|
+
wrapButton("rmfwrapright", "rmf-wrap-right", "Image right \u2014 text wraps around the left", "right");
|
|
2205
2247
|
ed.on("paste", (e) => {
|
|
2206
2248
|
const cb = e.clipboardData;
|
|
2207
2249
|
if (!cb)
|