@rg-dev/tinymce-helpers 1.0.12 → 1.0.14

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.
Files changed (3) hide show
  1. package/index.d.mts +16 -11
  2. package/index.mjs +189 -217
  3. package/package.json +1 -1
package/index.d.mts CHANGED
@@ -15,7 +15,7 @@ declare const skinsTable: {
15
15
  skin: string;
16
16
  }>;
17
17
  default: () => Promise<{
18
- css: string;
18
+ css: any;
19
19
  skin: string;
20
20
  }>;
21
21
  };
@@ -26,10 +26,12 @@ type RawEditorOptionsExtended = RawEditorOptions & {
26
26
  };
27
27
  type EditorOpts = Omit<RemoveIndexSignature<RawEditorOptionsExtended>, 'setup' | 'target' | 'selector'> & Record<string, unknown>;
28
28
  /** A partial patch object, or a function that derives one from the defaults. */
29
- type TinyMCEPatch = Partial<EditorOpts> | ((defaults: EditorOpts) => Partial<EditorOpts>);
29
+ type TinyMCEPatch = Partial<EditorOpts> | ((defaults: EditorOpts) => Partial<EditorOpts> | void);
30
30
  declare class ListBuilder {
31
31
  private items;
32
32
  constructor(existing: string);
33
+ /** Remove everything. */
34
+ clear(): this;
33
35
  /** add('btn') appends at the end. add(3, 'btn') inserts at index 3. */
34
36
  add(indexOrItem: number | string, item?: string): this;
35
37
  start(item: string): this;
@@ -38,6 +40,7 @@ declare class ListBuilder {
38
40
  remove(...names: string[]): this;
39
41
  /** Insert a '|' separator at the end, or at a given index. */
40
42
  separator(index?: number): this;
43
+ /** Collapses duplicate / leading / trailing separators left behind by remove(). */
41
44
  toString(): string;
42
45
  }
43
46
  type ListPatch = string | ((t: ListBuilder) => ListBuilder | void);
@@ -49,14 +52,16 @@ type MenuConfig = Record<string, MenuEntry>;
49
52
  declare class MenuBuilder {
50
53
  private menus;
51
54
  constructor(existing: MenuConfig);
55
+ /** Remove every menu. */
56
+ clear(): this;
52
57
  /** Add or replace an entire menu, e.g. m.addMenu('others_menu', { title: 'Others', items: 'foo bar' }) */
53
58
  addMenu(key: string, config: MenuEntry): this;
54
59
  removeMenu(key: string): this;
55
- /** Mutate one menu's items string via the same ListBuilder used for toolbar/contextmenu. */
60
+ /** Edit one menu's items with the same builder API as toolbar/contextmenu. */
56
61
  items(key: string, patch: ListPatch): this;
57
- /** Shorthand: m.addItem('file', 'newitem') / m.addItem('file', 2, 'newitem') */
58
- addItem(key: string, indexOrItem: number | string, item?: string): this;
59
- removeItem(key: string, ...names: string[]): this;
62
+ /** Remove items from one menu, or from every menu if `key` is omitted. */
63
+ removeItem(names: string | string[], key?: string): this;
64
+ /** Empty menus are dropped so TinyMCE never sees a menu with no items. */
60
65
  toObject(): MenuConfig;
61
66
  }
62
67
  type MenuPatch = MenuConfig | ((m: MenuBuilder) => MenuBuilder | void);
@@ -64,24 +69,24 @@ type MyTinymceOpts = {
64
69
  skin?: keyof typeof skinsTable;
65
70
  direction?: 'rtl' | 'ltr';
66
71
  customSetup?: (editor: Editor) => void;
67
- /** Free-form deep-merge patch applied over the default options.
72
+ /** Shallow patch applied over the default options (top-level keys are replaced).
68
73
  * Accepts a plain partial object, or a function of the defaults
69
74
  * that returns a partial object. */
70
75
  overrides?: TinyMCEPatch;
71
- /** Toolbar string, or a builder function: (t) => t.add('btn'), t.after('x','y'), etc. */
76
+ /** Toolbar string, or a builder function: (t) => t.add('btn'), t.after('x','y'), t.clear(), etc. */
72
77
  toolbar?: ListPatch;
73
78
  /** Context menu string, or a builder function, same API as toolbar. */
74
79
  contextmenu?: ListPatch;
75
80
  /** Plugin list string, or a builder function, same API as toolbar.
76
- * Note: this only toggles the string passed to tinymce.init - the
81
+ * Note: this only changes the string passed to tinymce.init - the
77
82
  * underlying plugin JS still needs to be imported at the top of this
78
83
  * file regardless of what's listed here. */
79
84
  plugins?: ListPatch;
80
85
  /** Menubar string (top-level menu keys, e.g. 'file edit view'), or a
81
- * builder function, same API as toolbar. */
86
+ * builder function, same API as toolbar. An empty result hides the menubar. */
82
87
  menubar?: ListPatch;
83
88
  /** Menu config object ({ key: { title, items } }), or a builder
84
- * function: (m) => m.addItem('file','newitem').removeItem('file','print') */
89
+ * function: (m) => m.removeItem('print') / m.clear() */
85
90
  menu?: MenuPatch;
86
91
  };
87
92
  declare class tinymceHelpers {
package/index.mjs CHANGED
@@ -63,11 +63,11 @@ import "tinymce/plugins/preview";
63
63
  import "tinymce/plugins/insertdatetime";
64
64
 
65
65
  // src/client/custom-components/mce.css?raw
66
- var mce_default = ':where(.mce-content-body) {\n --editor-text: #000;\n --editor-link: #000;\n --editor-border: #d6d6d6c9;\n --editor-table-header-text: #6e6e6e;\n --editor-table-row-even: #fafafa;\n --editor-hr: #bbb;\n}\n\n\nli::marker {\n color: var(--editor-link) !important;\n}\n\n::-webkit-scrollbar {\n width: 10px;\n}\n\n::-webkit-scrollbar-track {\n background: var(--editor-table-row-even);\n}\n\n::-webkit-scrollbar-thumb {\n background: var(--editor-link);\n border-radius: 35px;\n}\n\n @media print {\n .mce-content-body {\n --editor-text: #000;\n --editor-link: #000;\n --editor-border: #d6d6d6c9;\n --editor-table-header-text: #000;\n --editor-table-row-even: #fafafa;\n --editor-hr: #000;\n }\n\n .mce-content-body table tr:nth-child(even) {\n background: var(--editor-table-row-even) !important;\n -webkit-print-color-adjust: exact;\n print-color-adjust: exact;\n }\n\n \n .mce-content-body blockquote {\n border-inline-start: none !important;\n background: #f9f9f9 !important;\n\n color: #000 !important;\n -webkit-print-color-adjust: exact !important;\n print-color-adjust: exact !important;\n }\n\n \n\n .mce-content-body td[data-mce-selected]::after,\n .mce-content-body th[data-mce-selected]::after {\n display: none !important;\n}\n}\n\n img {\n padding-block: 7px;\n max-width: 100%;\n }\n\n\n\n .mce-content-body blockquote {\n display: flow-root;\n padding: 15px;\n border-radius: 8px;\n margin: 0px !important;\n margin-block: 20px !important;\n overflow: hidden;\n border: none !important;\n background: var(--editor-table-row-even);\n color: var(--editor-text);\n}\n\n\n\n.mce-content-body blockquote p {\n margin: 0;\n}\n\n* {\n border: 0;\n padding: 0;\n margin: 0;\n background: 0 0;\n color: inherit;\n box-sizing: border-box;\n background-repeat: no-repeat;\n background-position: 50% 50%;\n font-weight: 400;\n}\n\n:focus {\n outline: 0;\n}\n\na {\n text-decoration: none;\n cursor: pointer;\n}\n\nb,\nb *,\nstrong,\nstrong * {\n font-weight: 700;\n}\n\nol,\nul {\n list-style: none;\n}\n\npre {\n font: inherit;\n}\n\nbutton,\ninput,\ninput:not([type]),\ninput[type="button"],\ninput[type="color"],\ninput[type="date"],\ninput[type="datetime-local"],\ninput[type="datetime"],\ninput[type="email"],\ninput[type="month"],\ninput[type="number"],\ninput[type="password"],\ninput[type="reset"],\ninput[type="search"],\ninput[type="submit"],\ninput[type="tel"],\ninput[type="text"],\ninput[type="time"],\ninput[type="url"],\ninput[type="week"],\nselect,\ntextarea {\n font: inherit;\n}\n\n.mce-container textarea {\n display: inline-block !important;\n} \n\n\n.my-custom-styles{\n direction: ltr;\n }\n\n.mce-content-body {\n font-size: 28px;\n font-family: Rubik, Helvetica, Arial, sans-serif;\n padding: 0 25px 25px;\n color: var(--editor-text);\n}\n\n.mce-content-body table {\n width: 100%;\n table-layout: fixed;\n}\n\n\n\n.mce-content-body table td,\n.mce-content-body table th {\n overflow-wrap: anywhere;\n word-break: break-word;\n white-space: normal;\n}\n\n\n.mce-content-body h1 {\n font-size: 34px;\n line-height: 1.4em;\n margin: 25px 0 15px;\n}\n\n.mce-content-body h2 {\n font-size: 30px;\n line-height: 1.4em;\n margin: 25px 0 15px;\n}\n\n.mce-content-body h3 {\n font-size: 26px;\n line-height: 1.4em;\n margin: 25px 0 15px;\n}\n\n.mce-content-body h4 {\n font-size: 22px;\n line-height: 1.4em;\n margin: 25px 0 15px;\n}\n\n.mce-content-body h5 {\n font-size: 18px;\n line-height: 1.4em;\n margin: 25px 0 15px;\n}\n\n.mce-content-body h6 {\n font-size: 14px;\n line-height: 1.4em;\n margin: 25px 0 15px;\n}\n\n.mce-content-body p {\n margin: 25px 0;\n}\n\n.mce-content-body pre {\n font-family: monospace;\n}\n\n.mce-content-body ol,\n.mce-content-body ul {\n margin-left: 15px;\n list-style-position: outside;\n margin-bottom: 20px;\n}\n\n.mce-content-body ol li,\n.mce-content-body ul li {\n margin-left: 10px;\n margin-bottom: 10px;\n color: var(--editor-text);\n}\n\n.mce-content-body ul {\n list-style-type: disc;\n}\n\n.mce-content-body ol {\n list-style-type: decimal;\n}\n\n.mce-content-body a[href] {\n color: var(--editor-link);\n text-decoration: underline;\n}\n\n.mce-content-body table caption,\n.mce-content-body table td,\n.mce-content-body table th {\n padding: 15px 7px;\n font: inherit;\n}\n\n.mce-content-body table td,\n.mce-content-body table th {\n border: 1px solid var(--editor-border) !important;\n border-collapse: collapse;\n}\n\n.mce-content-body table th {\n font-weight: 400;\n color: var(--editor-table-header-text);\n background-position: 100% 100%;\n background-size: 2px 10px;\n background-repeat: no-repeat;\n}\n\n.mce-content-body table {\n width: 100%;\n border-spacing: 0;\n border-collapse: separate;\n \n}\n\n.mce-content-body table tr:nth-child(even) {\n background: var(--editor-table-row-even);\n}\n\n.mce-content-body hr {\n border-top: 2px solid var(--editor-hr);\n}';
66
+ var mce_default = ':where(.mce-content-body) {\n --editor-text: #000;\n --editor-link: #000;\n --editor-border: #d6d6d6c9;\n --editor-table-header-text: #6e6e6e;\n --editor-table-row-even: #fafafa;\n --editor-hr: #bbb;\n}\n\n\nli::marker {\n color: var(--editor-link) !important;\n}\n\n::-webkit-scrollbar {\n width: 10px;\n}\n\n::-webkit-scrollbar-track {\n background: var(--editor-table-row-even);\n}\n\n::-webkit-scrollbar-thumb {\n background: var(--editor-link);\n border-radius: 35px;\n}\n\n @media print {\n .mce-content-body {\n --editor-text: #000;\n --editor-link: #000;\n --editor-border: #d6d6d6c9;\n --editor-table-header-text: #000;\n --editor-table-row-even: #fafafa;\n --editor-hr: #000;\n }\n\n .mce-content-body table tr:nth-child(even) {\n background: var(--editor-table-row-even) !important;\n -webkit-print-color-adjust: exact;\n print-color-adjust: exact;\n }\n\n \n .mce-content-body blockquote {\n border-inline-start: none !important;\n background: #f9f9f9 !important;\n\n color: #000 !important;\n -webkit-print-color-adjust: exact !important;\n print-color-adjust: exact !important;\n }\n\n \n\n .mce-content-body td[data-mce-selected]::after,\n .mce-content-body th[data-mce-selected]::after {\n display: none !important;\n}\n}\n\n img {\n padding-block: 7px;\n max-width: 100%;\n }\n\n\n\n .mce-content-body blockquote {\n display: flow-root;\n padding: 15px;\n border-radius: 8px;\n margin: 0px !important;\n margin-block: 20px !important;\n overflow: hidden;\n border: none !important;\n background: var(--editor-table-row-even);\n color: var(--editor-text);\n}\n\n\n\n.mce-content-body blockquote p {\n margin: 0;\n}\n\n* {\n border: 0;\n padding: 0;\n margin: 0;\n background: 0 0;\n color: inherit;\n box-sizing: border-box;\n background-repeat: no-repeat;\n background-position: 50% 50%;\n font-weight: 400;\n}\n\n:focus {\n outline: 0;\n}\n\na {\n text-decoration: none;\n cursor: pointer;\n}\n\nb,\nb *,\nstrong,\nstrong * {\n font-weight: 700;\n}\n\nol,\nul {\n list-style: none;\n}\n\npre {\n font: inherit;\n}\n\nbutton,\ninput,\ninput:not([type]),\ninput[type="button"],\ninput[type="color"],\ninput[type="date"],\ninput[type="datetime-local"],\ninput[type="datetime"],\ninput[type="email"],\ninput[type="month"],\ninput[type="number"],\ninput[type="password"],\ninput[type="reset"],\ninput[type="search"],\ninput[type="submit"],\ninput[type="tel"],\ninput[type="text"],\ninput[type="time"],\ninput[type="url"],\ninput[type="week"],\nselect,\ntextarea {\n font: inherit;\n}\n\n.mce-container textarea {\n display: inline-block !important;\n} \n\n\n.my-custom-styles{\n direction: ltr;\n }\n\n.mce-content-body {\n font-size: 22px;\n font-family: Rubik, Helvetica, Arial, sans-serif;\n padding: 0 25px 25px;\n color: var(--editor-text);\n}\n\n.mce-content-body table {\n width: 100%;\n table-layout: fixed;\n}\n\n\n\n.mce-content-body table td,\n.mce-content-body table th {\n overflow-wrap: anywhere;\n word-break: break-word;\n white-space: normal;\n}\n\n\n.mce-content-body h1 {\n font-size: 34px;\n line-height: 1.4em;\n margin: 25px 0 15px;\n}\n\n.mce-content-body h2 {\n font-size: 30px;\n line-height: 1.4em;\n margin: 25px 0 15px;\n}\n\n.mce-content-body h3 {\n font-size: 26px;\n line-height: 1.4em;\n margin: 25px 0 15px;\n}\n\n.mce-content-body h4 {\n font-size: 22px;\n line-height: 1.4em;\n margin: 25px 0 15px;\n}\n\n.mce-content-body h5 {\n font-size: 18px;\n line-height: 1.4em;\n margin: 25px 0 15px;\n}\n\n.mce-content-body h6 {\n font-size: 14px;\n line-height: 1.4em;\n margin: 25px 0 15px;\n}\n\n.mce-content-body p {\n margin: 25px 0;\n}\n\n.mce-content-body pre {\n font-family: monospace;\n}\n\n.mce-content-body ol,\n.mce-content-body ul {\n margin-left: 15px;\n list-style-position: outside;\n margin-bottom: 20px;\n}\n\n.mce-content-body ol li,\n.mce-content-body ul li {\n margin-left: 10px;\n margin-bottom: 10px;\n color: var(--editor-text);\n}\n\n.mce-content-body ul {\n list-style-type: disc;\n}\n\n.mce-content-body ol {\n list-style-type: decimal;\n}\n\n.mce-content-body a[href] {\n color: var(--editor-link);\n text-decoration: underline;\n}\n\n.mce-content-body table caption,\n.mce-content-body table td,\n.mce-content-body table th {\n padding: 15px 7px;\n font: inherit;\n}\n\n.mce-content-body table td,\n.mce-content-body table th {\n border: 1px solid var(--editor-border) !important;\n border-collapse: collapse;\n}\n\n.mce-content-body table th {\n font-weight: 400;\n color: var(--editor-table-header-text);\n background-position: 100% 100%;\n background-size: 2px 10px;\n background-repeat: no-repeat;\n}\n\n.mce-content-body table {\n width: 100%;\n border-spacing: 0;\n border-collapse: separate;\n \n}\n\n.mce-content-body table tr:nth-child(even) {\n background: var(--editor-table-row-even);\n}\n\n.mce-content-body hr {\n border-top: 2px solid var(--editor-hr);\n}';
67
67
 
68
68
  // src/client/custom-components/tinymce-helpers.ts
69
69
  import { isNonEmptyString } from "@rg-dev/stdlib/lib/common-env";
70
- async function defaultSkin(document2 = false) {
70
+ async function defaultSkin() {
71
71
  const contentSkin = `default`;
72
72
  const shellSkin = "oxide";
73
73
  await Promise.all([
@@ -76,11 +76,7 @@ async function defaultSkin(document2 = false) {
76
76
  import("tinymce/skins/ui/oxide/skin.js")
77
77
  ]);
78
78
  return {
79
- css: tinymce.Resource.get(`content/${contentSkin}/content.css`) + tinymce.Resource.get(`ui/${shellSkin}/content.css`) + `
80
-
81
-
82
-
83
- `,
79
+ css: tinymce.Resource.get(`content/${contentSkin}/content.css`) + tinymce.Resource.get(`ui/${shellSkin}/content.css`),
84
80
  skin: shellSkin
85
81
  };
86
82
  }
@@ -96,8 +92,6 @@ async function darkSkin() {
96
92
  );
97
93
  return {
98
94
  css: tinymce.Resource.get(`content/${contentSkin}/content.css`) + tinymce.Resource.get(`ui/${shellSkin}/content.css`) + `
99
-
100
-
101
95
  .mce-content-body {
102
96
  --editor-bg: #222f3e;
103
97
  --editor-text: #e4e8ec;
@@ -117,29 +111,27 @@ var skinsTable = {
117
111
  default: () => defaultSkin()
118
112
  };
119
113
  function resolvePatch(defaults, patch) {
114
+ var _a;
120
115
  if (!patch) return {};
121
- const resolved = typeof patch === "function" ? patch(defaults) : patch;
122
- const _a = resolved, { target, setup, selector } = _a, safe = __objRest(_a, ["target", "setup", "selector"]);
123
- return safe;
124
- }
125
- function deepMerge(base, patch) {
126
- const out = __spreadValues({}, base);
127
- for (const key in patch) {
128
- const value = patch[key];
129
- const baseValue = base[key];
130
- const isPlainObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
131
- if (isPlainObject(value) && isPlainObject(baseValue)) {
132
- out[key] = deepMerge(baseValue, value);
133
- } else {
134
- out[key] = value;
135
- }
116
+ let resolved;
117
+ if (typeof patch === "function") {
118
+ const draft = __spreadValues({}, defaults);
119
+ resolved = (_a = patch(draft)) != null ? _a : draft;
120
+ } else {
121
+ resolved = patch;
136
122
  }
137
- return out;
123
+ const _b = resolved || {}, { target, setup, selector } = _b, safe = __objRest(_b, ["target", "setup", "selector"]);
124
+ return safe;
138
125
  }
139
126
  var ListBuilder = class {
140
127
  constructor(existing) {
141
128
  __publicField(this, "items");
142
- this.items = existing.trim().length ? existing.trim().split(/\s+/) : [];
129
+ this.items = existing.trim() ? existing.trim().split(/\s+/) : [];
130
+ }
131
+ /** Remove everything. */
132
+ clear() {
133
+ this.items = [];
134
+ return this;
143
135
  }
144
136
  /** add('btn') appends at the end. add(3, 'btn') inserts at index 3. */
145
137
  add(indexOrItem, item) {
@@ -178,16 +170,23 @@ var ListBuilder = class {
178
170
  }
179
171
  return this;
180
172
  }
173
+ /** Collapses duplicate / leading / trailing separators left behind by remove(). */
181
174
  toString() {
182
- return this.items.join(" ");
175
+ const out = [];
176
+ for (const item of this.items) {
177
+ if (item === "|" && (out.length === 0 || out[out.length - 1] === "|")) continue;
178
+ out.push(item);
179
+ }
180
+ if (out[out.length - 1] === "|") out.pop();
181
+ return out.join(" ");
183
182
  }
184
183
  };
185
184
  function applyListPatch(existing, patch) {
186
- if (!patch) return existing;
185
+ var _a;
186
+ if (patch === void 0) return existing;
187
187
  if (typeof patch === "string") return patch;
188
188
  const builder = new ListBuilder(existing);
189
- const result = patch(builder);
190
- return (result != null ? result : builder).toString();
189
+ return ((_a = patch(builder)) != null ? _a : builder).toString();
191
190
  }
192
191
  var MenuBuilder = class {
193
192
  constructor(existing) {
@@ -196,6 +195,11 @@ var MenuBuilder = class {
196
195
  Object.entries(existing).map(([k, v]) => [k, __spreadValues({}, v)])
197
196
  );
198
197
  }
198
+ /** Remove every menu. */
199
+ clear() {
200
+ this.menus = {};
201
+ return this;
202
+ }
199
203
  /** Add or replace an entire menu, e.g. m.addMenu('others_menu', { title: 'Others', items: 'foo bar' }) */
200
204
  addMenu(key, config) {
201
205
  this.menus[key] = __spreadValues({}, config);
@@ -205,36 +209,36 @@ var MenuBuilder = class {
205
209
  delete this.menus[key];
206
210
  return this;
207
211
  }
208
- /** Mutate one menu's items string via the same ListBuilder used for toolbar/contextmenu. */
212
+ /** Edit one menu's items with the same builder API as toolbar/contextmenu. */
209
213
  items(key, patch) {
210
- const existing = this.menus[key];
211
- if (!existing) {
214
+ const menu = this.menus[key];
215
+ if (!menu) {
212
216
  console.error(`MenuBuilder.items: menu "${key}" does not exist`);
213
217
  return this;
214
218
  }
215
- existing.items = applyListPatch(existing.items, patch);
219
+ menu.items = applyListPatch(menu.items, patch);
216
220
  return this;
217
221
  }
218
- /** Shorthand: m.addItem('file', 'newitem') / m.addItem('file', 2, 'newitem') */
219
- addItem(key, indexOrItem, item) {
220
- return this.items(
221
- key,
222
- (t) => typeof indexOrItem === "number" ? t.add(indexOrItem, item) : t.add(indexOrItem)
223
- );
224
- }
225
- removeItem(key, ...names) {
226
- return this.items(key, (t) => t.remove(...names));
222
+ /** Remove items from one menu, or from every menu if `key` is omitted. */
223
+ removeItem(names, key) {
224
+ const list = Array.isArray(names) ? names : [names];
225
+ const keys = key ? [key] : Object.keys(this.menus);
226
+ for (const k of keys) this.items(k, (t) => t.remove(...list));
227
+ return this;
227
228
  }
229
+ /** Empty menus are dropped so TinyMCE never sees a menu with no items. */
228
230
  toObject() {
229
- return this.menus;
231
+ return Object.fromEntries(
232
+ Object.entries(this.menus).filter(([, m]) => m.items.trim())
233
+ );
230
234
  }
231
235
  };
232
236
  function applyMenuPatch(existing, patch) {
237
+ var _a;
233
238
  if (!patch) return existing;
234
239
  if (typeof patch !== "function") return patch;
235
240
  const builder = new MenuBuilder(existing);
236
- const result = patch(builder);
237
- return (result != null ? result : builder).toObject();
241
+ return ((_a = patch(builder)) != null ? _a : builder).toObject();
238
242
  }
239
243
  var tinymceHelpers = class _tinymceHelpers {
240
244
  constructor() {
@@ -249,7 +253,7 @@ var tinymceHelpers = class _tinymceHelpers {
249
253
  this.editor.insertContent(`<img src="${src}" alt="">`);
250
254
  }
251
255
  async _initMce(el, customOpts = Object()) {
252
- var _a;
256
+ var _a, _b;
253
257
  if (!(el instanceof HTMLElement)) {
254
258
  throw new Error("invalid element");
255
259
  }
@@ -278,14 +282,12 @@ var tinymceHelpers = class _tinymceHelpers {
278
282
  if (parent) {
279
283
  e.preventDefault();
280
284
  e.stopImmediatePropagation();
281
- editor.undoManager.transact(
282
- () => {
283
- const p = editor.dom.create("p", {}, "<br>");
284
- parent.insertBefore(p, blockquote.nextSibling);
285
- editor.selection.select(p, true);
286
- editor.selection.collapse(true);
287
- }
288
- );
285
+ editor.undoManager.transact(() => {
286
+ const p = editor.dom.create("p", {}, "<br>");
287
+ parent.insertBefore(p, blockquote.nextSibling);
288
+ editor.selection.select(p, true);
289
+ editor.selection.collapse(true);
290
+ });
289
291
  editor.nodeChanged();
290
292
  return;
291
293
  }
@@ -295,105 +297,85 @@ var tinymceHelpers = class _tinymceHelpers {
295
297
  editor.getDoc().execCommand("insertParagraph", false, void 0);
296
298
  editor.nodeChanged();
297
299
  }, true);
298
- editor.ui.registry.addMenuItem(
299
- "create-block-below",
300
- {
301
- text: "Create block below",
302
- icon: "plus",
303
- onAction: () => {
304
- const node = editor.selection.getNode();
305
- const body = editor.getBody();
306
- const topBlock = editor.dom.getParent(node, (n) => n.parentNode === body) || node;
307
- const newBlock = editor.dom.create("p", {}, '<br data-mce-bogus="1">');
308
- editor.dom.insertAfter(newBlock, topBlock);
309
- editor.selection.setCursorLocation(newBlock, 0);
310
- editor.focus();
311
- }
300
+ editor.ui.registry.addMenuItem("create-block-below", {
301
+ text: "Create block below",
302
+ icon: "plus",
303
+ onAction: () => {
304
+ const node = editor.selection.getNode();
305
+ const body = editor.getBody();
306
+ const topBlock = editor.dom.getParent(node, (n) => n.parentNode === body) || node;
307
+ const newBlock = editor.dom.create("p", {}, '<br data-mce-bogus="1">');
308
+ editor.dom.insertAfter(newBlock, topBlock);
309
+ editor.selection.setCursorLocation(newBlock, 0);
310
+ editor.focus();
312
311
  }
313
- );
314
- editor.ui.registry.addMenuItem(
315
- "create-block-above",
316
- {
317
- text: "Create block above",
318
- icon: "plus",
319
- onAction: () => {
320
- var _a3;
321
- const node = editor.selection.getNode();
322
- const body = editor.getBody();
323
- const topBlock = editor.dom.getParent(node, (n) => n.parentNode === body) || node;
324
- const newBlock = editor.dom.create("p", {}, '<br data-mce-bogus="1">');
325
- (_a3 = topBlock.parentNode) == null ? void 0 : _a3.insertBefore(newBlock, topBlock);
326
- editor.selection.setCursorLocation(newBlock, 0);
327
- editor.focus();
328
- }
312
+ });
313
+ editor.ui.registry.addMenuItem("create-block-above", {
314
+ text: "Create block above",
315
+ icon: "plus",
316
+ onAction: () => {
317
+ var _a3;
318
+ const node = editor.selection.getNode();
319
+ const body = editor.getBody();
320
+ const topBlock = editor.dom.getParent(node, (n) => n.parentNode === body) || node;
321
+ const newBlock = editor.dom.create("p", {}, '<br data-mce-bogus="1">');
322
+ (_a3 = topBlock.parentNode) == null ? void 0 : _a3.insertBefore(newBlock, topBlock);
323
+ editor.selection.setCursorLocation(newBlock, 0);
324
+ editor.focus();
329
325
  }
330
- );
331
- editor.ui.registry.addMenuItem(
332
- "change-dir",
333
- {
334
- text: "Switch text direction",
335
- onAction: async () => {
336
- that.toggleTextDirection();
337
- }
326
+ });
327
+ editor.ui.registry.addMenuItem("change-dir", {
328
+ text: "Switch text direction",
329
+ onAction: () => {
330
+ that.toggleTextDirection();
338
331
  }
339
- );
340
- editor.ui.registry.addMenuItem(
341
- "toggleEdit",
342
- {
343
- text: "toggle readonly",
344
- onAction: async () => {
345
- that.toggleReadOnly();
346
- }
332
+ });
333
+ editor.ui.registry.addMenuItem("toggleEdit", {
334
+ text: "toggle readonly",
335
+ onAction: () => {
336
+ that.toggleReadOnly();
347
337
  }
348
- );
349
- editor.ui.registry.addMenuItem(
350
- "reset-style-button-img",
351
- {
352
- text: "Reset Image Style",
353
- icon: "resize",
354
- onAction: function() {
355
- const selectedImage = editor.selection.getNode();
356
- if (selectedImage.nodeName === "IMG") {
357
- selectedImage.style.width = "unset";
358
- selectedImage.style.height = "unset";
359
- }
338
+ });
339
+ editor.ui.registry.addMenuItem("reset-style-button-img", {
340
+ text: "Reset Image Style",
341
+ icon: "resize",
342
+ onAction: () => {
343
+ const selectedImage = editor.selection.getNode();
344
+ if (selectedImage.nodeName === "IMG") {
345
+ selectedImage.style.width = "unset";
346
+ selectedImage.style.height = "unset";
360
347
  }
361
348
  }
362
- ), editor.ui.registry.addMenuItem(
363
- "clearTextStyle",
364
- {
365
- text: "Clear formatting",
366
- icon: "removeformat",
367
- onAction: () => {
368
- editor.execCommand("RemoveFormat");
369
- }
349
+ });
350
+ editor.ui.registry.addMenuItem("clearTextStyle", {
351
+ text: "Clear formatting",
352
+ icon: "removeformat",
353
+ onAction: () => {
354
+ editor.execCommand("RemoveFormat");
370
355
  }
371
- );
372
- editor.ui.registry.addMenuItem(
373
- "insert-image",
374
- {
375
- text: "Insert image",
376
- icon: "image",
377
- onAction: () => {
378
- const input = document.createElement("input");
379
- input.type = "file";
380
- input.accept = "image/*";
381
- input.onchange = () => {
382
- var _a3;
383
- const file = (_a3 = input.files) == null ? void 0 : _a3[0];
384
- if (!file) {
385
- return;
386
- }
387
- const reader = new FileReader();
388
- reader.onload = () => {
389
- editor.insertContent(`<img src="${reader.result}" alt="">`);
390
- };
391
- reader.readAsDataURL(file);
356
+ });
357
+ editor.ui.registry.addMenuItem("insert-image", {
358
+ text: "Insert image",
359
+ icon: "image",
360
+ onAction: () => {
361
+ const input = document.createElement("input");
362
+ input.type = "file";
363
+ input.accept = "image/*";
364
+ input.onchange = () => {
365
+ var _a3;
366
+ const file = (_a3 = input.files) == null ? void 0 : _a3[0];
367
+ if (!file) {
368
+ return;
369
+ }
370
+ const reader = new FileReader();
371
+ reader.onload = () => {
372
+ editor.insertContent(`<img src="${reader.result}" alt="">`);
392
373
  };
393
- input.click();
394
- }
374
+ reader.readAsDataURL(file);
375
+ };
376
+ input.click();
395
377
  }
396
- );
378
+ });
397
379
  editor.ui.registry.addButton(
398
380
  "decreaseFontSize",
399
381
  {
@@ -412,6 +394,24 @@ var tinymceHelpers = class _tinymceHelpers {
412
394
  }
413
395
  }
414
396
  );
397
+ editor.ui.registry.addButton(
398
+ "increaseFontSize",
399
+ {
400
+ tooltip: "Increase Font Size",
401
+ icon: "plus",
402
+ onAction: () => {
403
+ const currentSize = editor.queryCommandValue("FontSize");
404
+ let newSize = 16;
405
+ if (currentSize) {
406
+ const sizeNum = parseInt(currentSize.toString());
407
+ if (!isNaN(sizeNum)) {
408
+ newSize = sizeNum + 2;
409
+ }
410
+ }
411
+ editor.execCommand("FontSize", false, newSize + "px");
412
+ }
413
+ }
414
+ );
415
415
  editor.ui.registry.addButton(
416
416
  "myBlockquote",
417
417
  {
@@ -446,31 +446,13 @@ var tinymceHelpers = class _tinymceHelpers {
446
446
  }
447
447
  }
448
448
  );
449
- editor.ui.registry.addButton(
450
- "increaseFontSize",
451
- {
452
- tooltip: "Increase Font Size",
453
- icon: "plus",
454
- onAction: () => {
455
- const currentSize = editor.queryCommandValue("FontSize");
456
- let newSize = 16;
457
- if (currentSize) {
458
- const sizeNum = parseInt(currentSize.toString());
459
- if (!isNaN(sizeNum)) {
460
- newSize = sizeNum + 2;
461
- }
462
- }
463
- editor.execCommand("FontSize", false, newSize + "px");
464
- }
465
- }
466
- );
467
449
  (_a2 = customOpts.customSetup) == null ? void 0 : _a2.call(customOpts, editor);
468
450
  },
469
451
  newline_behavior: "linebreak",
470
452
  id: "tinymce",
471
453
  extended_valid_elements: "img[drawio-diagram|contenteditable|style|class|src]",
472
454
  font_family_formats: "Rubik=Rubik, Helvetica, Arial, sans-serif; Andale Mono=andale mono,times; Arial=arial,helvetica,sans-serif; Arial Black=arial black,avant garde; Book Antiqua=book antiqua,palatino; Comic Sans MS=comic sans ms,sans-serif; Courier New=courier new,courier; Georgia=georgia,palatino; Helvetica=helvetica; Impact=impact,chicago; Symbol=symbol; Tahoma=tahoma,arial,helvetica,sans-serif; Terminal=terminal,monaco; Times New Roman=times new roman,times; Trebuchet MS=trebuchet ms,geneva; Verdana=verdana,geneva; Webdings=webdings; Wingdings=wingdings,zapf dingbats; Afacad=afacad,sans-serif; Marcellus=marcellus,serif; Poppins=poppins,sans-serif; Raleway=raleway,sans-serif;",
473
- "statusbar": false,
455
+ statusbar: false,
474
456
  quickbars_insert_toolbar: "",
475
457
  skin: theSkin.skin,
476
458
  highlight_on_focus: false,
@@ -486,7 +468,7 @@ var tinymceHelpers = class _tinymceHelpers {
486
468
  height: "100%",
487
469
  image_caption: true,
488
470
  quickbars_selection_toolbar: "bold italic | quicklink blockquote quickimage quicktable",
489
- noneditable_noneditable_class: "mceNonEditable",
471
+ noneditable_class: "mceNonEditable",
490
472
  toolbar_mode: "sliding",
491
473
  browser_spellcheck: true,
492
474
  menu: {
@@ -500,33 +482,28 @@ var tinymceHelpers = class _tinymceHelpers {
500
482
  }
501
483
  },
502
484
  menubar: "file edit view insert format tools table others_menu",
503
- //spellchecker_active: true,
504
- // spellchecker_languages: 'US English=en-US,Hebrew=he_IL',
505
- // "spellchecker_rpc_url": "https://spelling.iad.tiny.cloud",
506
- // "spellchecker_rpc_url": "http://10.0.0.13:7777",
507
- // "spellchecker_api_key": "qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc",
508
- // spellchecker_language: 'he_IL',
509
- //tinymcespellchecker
510
485
  plugins: "preview importcss searchreplace autolink directionality code visualblocks visualchars fullscreen image link media codesample table charmap pagebreak nonbreaking anchor insertdatetime advlist lists wordcount charmap quickbars emoticons",
511
- // contextmenu: false,
512
486
  contextmenu: "insert-image link image table create-block-above create-block-below reset-style-button-img clearTextStyle"
513
487
  };
514
- opts = deepMerge(opts, resolvePatch(opts, customOpts.overrides));
515
- if (typeof opts.toolbar === "string") {
516
- opts.toolbar = applyListPatch(opts.toolbar, customOpts.toolbar);
517
- }
518
- if (typeof opts.contextmenu === "string") {
519
- opts.contextmenu = applyListPatch(opts.contextmenu, customOpts.contextmenu);
520
- }
521
- if (typeof opts.plugins === "string") {
522
- opts.plugins = applyListPatch(opts.plugins, customOpts.plugins);
523
- }
524
- if (typeof opts.menubar === "string") {
525
- opts.menubar = applyListPatch(opts.menubar, customOpts.menubar);
488
+ opts = __spreadValues(__spreadValues({}, opts), resolvePatch(opts, customOpts.overrides));
489
+ const listPatches = {
490
+ toolbar: customOpts.toolbar,
491
+ contextmenu: customOpts.contextmenu,
492
+ plugins: customOpts.plugins,
493
+ menubar: customOpts.menubar
494
+ };
495
+ for (const [key, patch] of Object.entries(listPatches)) {
496
+ const current = opts[key];
497
+ if (typeof current === "string") {
498
+ opts[key] = applyListPatch(current, patch);
499
+ }
526
500
  }
527
501
  if (opts.menu) {
528
502
  opts.menu = applyMenuPatch(opts.menu, customOpts.menu);
529
503
  }
504
+ if (typeof opts.menubar === "string" && !opts.menubar.trim()) {
505
+ opts.menubar = false;
506
+ }
530
507
  if (!opts.skin) {
531
508
  throw new Error("no skin");
532
509
  }
@@ -535,6 +512,16 @@ var tinymceHelpers = class _tinymceHelpers {
535
512
  const all = mce.ui.registry.getAll();
536
513
  const availableMenuItems = all.menuItems;
537
514
  const availableButtons = all.buttons;
515
+ const BUILTIN_MENUS = /* @__PURE__ */ new Set(["file", "edit", "view", "insert", "format", "tools", "table", "help"]);
516
+ if (typeof opts.menubar == "string") {
517
+ const menubarItems = opts.menubar.trim().split(/\s+/).filter(Boolean);
518
+ const customMenus = new Set(Object.keys((_a = opts.menu) != null ? _a : {}));
519
+ for (const item of menubarItems) {
520
+ if (!BUILTIN_MENUS.has(item) && !customMenus.has(item)) {
521
+ console.error(`Menubar references unknown menu "${item}"`);
522
+ }
523
+ }
524
+ }
538
525
  if (typeof opts.toolbar == "string") {
539
526
  if (!isNonEmptyString(opts.toolbar.trim())) {
540
527
  console.error("Toolbar is missing items");
@@ -542,9 +529,7 @@ var tinymceHelpers = class _tinymceHelpers {
542
529
  const items = opts.toolbar.trim().split(/\s+/).filter((item) => item !== "|");
543
530
  for (const item of items) {
544
531
  if (!availableButtons[item.toLowerCase()] && !availableMenuItems[item.toLowerCase()]) {
545
- console.error(
546
- `Toolbar references unknown button "${item}"`
547
- );
532
+ console.error(`Toolbar references unknown button "${item}"`);
548
533
  }
549
534
  }
550
535
  }
@@ -555,26 +540,22 @@ var tinymceHelpers = class _tinymceHelpers {
555
540
  } else {
556
541
  const items = opts.contextmenu.trim().split(/\s+/);
557
542
  for (const item of items) {
558
- if (!availableMenuItems[item.toLowerCase()] && !all.contextToolbars[item.toLocaleLowerCase()]) {
559
- console.error(
560
- `Context menu references unknown menu item "${item}"`
561
- );
543
+ if (!availableMenuItems[item.toLowerCase()] && !all.contextToolbars[item.toLowerCase()]) {
544
+ console.error(`Context menu references unknown menu item "${item}"`);
562
545
  }
563
546
  }
564
547
  }
565
548
  }
566
549
  if (opts.menu) {
567
550
  for (const [key, value] of Object.entries(opts.menu)) {
568
- if (!isNonEmptyString((_a = value.items) == null ? void 0 : _a.trim())) {
551
+ if (!isNonEmptyString((_b = value.items) == null ? void 0 : _b.trim())) {
569
552
  console.error(`Menu "${key}" is missing items`);
570
553
  continue;
571
554
  }
572
555
  const items = value.items.trim().split(/\s+/);
573
556
  for (const item of items) {
574
557
  if (!availableMenuItems[item.toLowerCase()]) {
575
- console.error(
576
- `Menu "${key}" references unknown menu item "${item}"`
577
- );
558
+ console.error(`Menu "${key}" references unknown menu item "${item}"`);
578
559
  }
579
560
  }
580
561
  }
@@ -596,11 +577,7 @@ var tinymceHelpers = class _tinymceHelpers {
596
577
  toggleReadOnly(lock) {
597
578
  let curr = this.editor.getBody().isContentEditable;
598
579
  if (lock) {
599
- if (lock == "no") {
600
- curr = false;
601
- } else {
602
- curr = true;
603
- }
580
+ curr = lock !== "no";
604
581
  }
605
582
  const container = this.editor.getContainer();
606
583
  const editorBar = container.querySelector(".tox-editor-header");
@@ -642,14 +619,9 @@ var tinymceHelpers = class _tinymceHelpers {
642
619
  if (!styles) {
643
620
  return;
644
621
  }
645
- let dir = styles.direction == "rtl" ? "ltr" : "rtl";
646
- if (force_dir) {
647
- dir = force_dir;
648
- }
649
- const newDirection = dir;
650
- styles.direction = newDirection;
651
- const tds = this._editor.dom.select("td");
652
- for (let td of tds) {
622
+ const dir = force_dir != null ? force_dir : styles.direction == "rtl" ? "ltr" : "rtl";
623
+ styles.direction = dir;
624
+ for (const td of this._editor.dom.select("td")) {
653
625
  this._editor.dom.setStyle(td, "direction", dir);
654
626
  }
655
627
  }
@@ -681,14 +653,14 @@ var tinymceHelpers = class _tinymceHelpers {
681
653
  color:rgb(255,255,255);
682
654
  cursor:pointer;
683
655
  box-shadow:0 1px 3px rgba(0,0,0,0.2);
684
- `;
685
- btn.style.backgroundColor = getComputedStyle(content).getPropertyValue("--editor-linke").trim() || "black";
686
- btn.addEventListener("click", () => {
687
- this.toggleReadOnly();
688
- });
689
- if (getComputedStyle(container).position === "static") {
690
- container.style.position = "relative";
691
- }
656
+ `;
657
+ btn.style.backgroundColor = getComputedStyle(content).getPropertyValue("--editor-link").trim() || "black";
658
+ btn.addEventListener(
659
+ "click",
660
+ () => {
661
+ this.toggleReadOnly();
662
+ }
663
+ );
692
664
  container.appendChild(btn);
693
665
  this._lockButton = btn;
694
666
  this.updateLockButton();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rg-dev/tinymce-helpers",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {