jodit 4.13.26 → 4.14.0

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 (167) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/es2015/jodit.css +1 -1
  3. package/es2015/jodit.fat.min.js +19 -19
  4. package/es2015/jodit.js +1104 -884
  5. package/es2015/jodit.min.js +20 -20
  6. package/es2015/plugins/debug/debug.css +1 -1
  7. package/es2015/plugins/debug/debug.js +10 -10
  8. package/es2015/plugins/debug/debug.min.js +4 -4
  9. package/es2015/plugins/speech-recognize/speech-recognize.css +1 -1
  10. package/es2015/plugins/speech-recognize/speech-recognize.js +2 -2
  11. package/es2015/plugins/speech-recognize/speech-recognize.min.js +2 -2
  12. package/es2018/jodit.fat.min.js +19 -19
  13. package/es2018/jodit.min.js +19 -19
  14. package/es2018/plugins/debug/debug.min.js +4 -4
  15. package/es2018/plugins/speech-recognize/speech-recognize.min.js +2 -2
  16. package/es2021/jodit.css +1 -1
  17. package/es2021/jodit.fat.min.js +29 -29
  18. package/es2021/jodit.js +1097 -875
  19. package/es2021/jodit.min.js +29 -29
  20. package/es2021/plugins/debug/debug.css +1 -1
  21. package/es2021/plugins/debug/debug.js +10 -10
  22. package/es2021/plugins/debug/debug.min.js +4 -4
  23. package/es2021/plugins/speech-recognize/speech-recognize.css +1 -1
  24. package/es2021/plugins/speech-recognize/speech-recognize.js +2 -2
  25. package/es2021/plugins/speech-recognize/speech-recognize.min.js +2 -2
  26. package/es2021.en/jodit.css +1 -1
  27. package/es2021.en/jodit.fat.min.js +29 -29
  28. package/es2021.en/jodit.js +1097 -875
  29. package/es2021.en/jodit.min.js +29 -29
  30. package/es2021.en/plugins/debug/debug.css +1 -1
  31. package/es2021.en/plugins/debug/debug.js +10 -10
  32. package/es2021.en/plugins/debug/debug.min.js +4 -4
  33. package/es2021.en/plugins/speech-recognize/speech-recognize.css +1 -1
  34. package/es2021.en/plugins/speech-recognize/speech-recognize.js +2 -2
  35. package/es2021.en/plugins/speech-recognize/speech-recognize.min.js +2 -2
  36. package/es5/jodit.css +2 -2
  37. package/es5/jodit.fat.min.js +2 -2
  38. package/es5/jodit.js +1221 -925
  39. package/es5/jodit.min.css +2 -2
  40. package/es5/jodit.min.js +2 -2
  41. package/es5/plugins/debug/debug.css +1 -1
  42. package/es5/plugins/debug/debug.js +10 -10
  43. package/es5/plugins/debug/debug.min.js +2 -2
  44. package/es5/plugins/speech-recognize/speech-recognize.css +1 -1
  45. package/es5/plugins/speech-recognize/speech-recognize.js +2 -2
  46. package/es5/plugins/speech-recognize/speech-recognize.min.js +2 -2
  47. package/es5/polyfills.fat.min.js +1 -1
  48. package/es5/polyfills.js +1 -1
  49. package/es5/polyfills.min.js +1 -1
  50. package/esm/core/constants.js +1 -1
  51. package/esm/core/create/create.js +2 -2
  52. package/esm/core/dom/dom.d.ts +21 -13
  53. package/esm/core/dom/dom.js +58 -87
  54. package/esm/core/global.js +3 -2
  55. package/esm/core/helpers/html/apply-styles.js +14 -10
  56. package/esm/core/helpers/html/clean-from-word.js +8 -4
  57. package/esm/core/helpers/html/safe-html.js +23 -14
  58. package/esm/core/helpers/html/strip-tags.js +9 -4
  59. package/esm/core/helpers/utils/align.d.ts +0 -3
  60. package/esm/core/helpers/utils/align.js +15 -18
  61. package/esm/core/helpers/utils/append-script.js +13 -10
  62. package/esm/core/helpers/utils/attr.d.ts +3 -1
  63. package/esm/core/helpers/utils/attr.js +18 -0
  64. package/esm/core/helpers/utils/css.d.ts +18 -1
  65. package/esm/core/helpers/utils/css.js +15 -0
  66. package/esm/core/helpers/utils/print.js +17 -14
  67. package/esm/core/helpers/utils/reset.js +3 -0
  68. package/esm/core/helpers/utils/selector.js +11 -7
  69. package/esm/core/selection/helpers/move-node-inside-start.js +1 -1
  70. package/esm/core/selection/selection.js +29 -26
  71. package/esm/core/selection/style/api/get-suit-parent.js +10 -0
  72. package/esm/core/selection/style/api/is-same-attributes.js +5 -2
  73. package/esm/core/selection/style/api/toggle-attributes.js +8 -9
  74. package/esm/core/selection/style/api/wrap-unwrapped-text.js +2 -2
  75. package/esm/core/traits/elms.js +11 -3
  76. package/esm/core/ui/button/button/button.js +3 -3
  77. package/esm/core/ui/button/group/group.js +2 -1
  78. package/esm/core/ui/button/tooltip/tooltip.js +2 -2
  79. package/esm/core/ui/element.js +1 -1
  80. package/esm/core/ui/form/inputs/area/area.js +3 -2
  81. package/esm/core/ui/form/inputs/file/file.js +2 -1
  82. package/esm/core/ui/form/inputs/input/input.js +5 -5
  83. package/esm/core/ui/group/group.js +7 -7
  84. package/esm/core/ui/icon.js +2 -2
  85. package/esm/core/ui/popup/popup.js +10 -8
  86. package/esm/core/ui/progress-bar/progress-bar.js +3 -4
  87. package/esm/core/view/view-with-toolbar.js +1 -1
  88. package/esm/core/view/view.js +1 -1
  89. package/esm/jodit.js +30 -28
  90. package/esm/modules/dialog/alert.js +1 -1
  91. package/esm/modules/dialog/confirm.js +3 -2
  92. package/esm/modules/dialog/dialog.d.ts +6 -0
  93. package/esm/modules/dialog/dialog.js +40 -22
  94. package/esm/modules/dialog/prompt.js +4 -3
  95. package/esm/modules/file-browser/builders/context-menu.js +5 -5
  96. package/esm/modules/file-browser/config.js +3 -1
  97. package/esm/modules/file-browser/file-browser.js +7 -4
  98. package/esm/modules/file-browser/listeners/state-listeners.js +6 -6
  99. package/esm/modules/image-editor/image-editor.js +31 -17
  100. package/esm/modules/messages/messages.js +2 -1
  101. package/esm/modules/status-bar/status-bar.js +3 -4
  102. package/esm/modules/table/table.js +22 -18
  103. package/esm/modules/toolbar/button/button.js +4 -4
  104. package/esm/modules/toolbar/button/content.js +12 -4
  105. package/esm/modules/toolbar/collection/collection.js +4 -2
  106. package/esm/modules/uploader/config.js +3 -2
  107. package/esm/modules/uploader/helpers/process-old-browser-drag.js +1 -1
  108. package/esm/modules/uploader/uploader.js +7 -2
  109. package/esm/modules/widget/color-picker/color-picker.js +4 -4
  110. package/esm/modules/widget/file-selector/file-selector.js +6 -6
  111. package/esm/modules/widget/tabs/tabs.js +5 -5
  112. package/esm/plugins/add-new-line/add-new-line.js +8 -7
  113. package/esm/plugins/ai-assistant/ui/ui-ai-assistant.js +4 -4
  114. package/esm/plugins/backspace/cases/check-join-neighbors.js +4 -1
  115. package/esm/plugins/clean-html/helpers/visitor/filters/allow-attributes.js +5 -1
  116. package/esm/plugins/clean-html/helpers/visitor/filters/fill-empty-paragraph.js +1 -1
  117. package/esm/plugins/color/config.js +4 -4
  118. package/esm/plugins/copy-format/copy-format.js +1 -1
  119. package/esm/plugins/delete/delete.js +9 -2
  120. package/esm/plugins/drag-and-drop/drag-and-drop.js +1 -1
  121. package/esm/plugins/drag-and-drop-element/drag-and-drop-element.js +1 -1
  122. package/esm/plugins/enter/helpers/insert-paragraph.js +1 -1
  123. package/esm/plugins/enter/helpers/process-empty-li-leaf.js +2 -2
  124. package/esm/plugins/enter/helpers/wrap-text.js +1 -1
  125. package/esm/plugins/fullsize/fullsize.js +3 -2
  126. package/esm/plugins/iframe/iframe.js +6 -5
  127. package/esm/plugins/image-properties/readers/align.js +6 -5
  128. package/esm/plugins/image-properties/readers/index.js +3 -1
  129. package/esm/plugins/image-properties/ui/ui-image-form.js +2 -1
  130. package/esm/plugins/image-properties/writers/index.js +2 -1
  131. package/esm/plugins/image-properties/writers/link.js +1 -1
  132. package/esm/plugins/indent/config.js +3 -2
  133. package/esm/plugins/indent/indent.js +4 -2
  134. package/esm/plugins/media/media.js +10 -7
  135. package/esm/plugins/mobile/config.js +2 -2
  136. package/esm/plugins/paste-storage/paste-storage.js +5 -5
  137. package/esm/plugins/placeholder/placeholder.js +13 -11
  138. package/esm/plugins/print/print.js +2 -2
  139. package/esm/plugins/resize-cells/resize-cells.js +13 -15
  140. package/esm/plugins/resize-handler/resize-handler.js +3 -4
  141. package/esm/plugins/resizer/resizer.js +11 -10
  142. package/esm/plugins/search/helpers/highlight-text-ranges.js +1 -1
  143. package/esm/plugins/search/ui/search.js +1 -1
  144. package/esm/plugins/select/select.js +2 -2
  145. package/esm/plugins/select-cells/select-cells.js +5 -6
  146. package/esm/plugins/source/editor/engines/ace.js +2 -1
  147. package/esm/plugins/source/editor/engines/area.js +3 -3
  148. package/esm/plugins/source/source.js +2 -2
  149. package/esm/plugins/speech-recognize/speech-recognize.js +1 -1
  150. package/esm/plugins/sticky/sticky.js +1 -1
  151. package/esm/plugins/symbols/config.js +3 -2
  152. package/esm/plugins/symbols/symbols.js +6 -5
  153. package/esm/plugins/tab/cases/on-tab-inside-li.js +2 -2
  154. package/esm/plugins/table/config.js +18 -10
  155. package/esm/plugins/table-keyboard-navigation/table-keyboard-navigation.js +2 -2
  156. package/esm/plugins/wrap-nodes/wrap-nodes.js +2 -2
  157. package/esm/plugins/xpath/xpath.js +2 -3
  158. package/esm/types/index.d.ts +1 -0
  159. package/esm/types/vdom.d.ts +96 -0
  160. package/package.json +1 -1
  161. package/types/core/dom/dom.d.ts +21 -13
  162. package/types/core/helpers/utils/align.d.ts +0 -3
  163. package/types/core/helpers/utils/attr.d.ts +3 -1
  164. package/types/core/helpers/utils/css.d.ts +18 -1
  165. package/types/modules/dialog/dialog.d.ts +6 -0
  166. package/types/types/index.d.ts +1 -0
  167. package/types/types/vdom.d.ts +96 -0
@@ -4,6 +4,7 @@
4
4
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
6
  import * as constants from "../../../../core/constants.js";
7
+ import { Dom } from "../../../../core/dom/dom.js";
7
8
  import { isString, loadNext } from "../../../../core/helpers/index.js";
8
9
  import { SourceEditor } from "../sourceEditor.js";
9
10
  export class AceEditor extends SourceEditor {
@@ -74,7 +75,7 @@ export class AceEditor extends SourceEditor {
74
75
  return;
75
76
  }
76
77
  const fakeMirror = this.j.c.div('jodit-source__mirror-fake');
77
- this.container.appendChild(fakeMirror);
78
+ Dom.append(this.container, fakeMirror);
78
79
  const ace = editor.ow.ace;
79
80
  this.instance = ace.edit(fakeMirror);
80
81
  if (editor.o.direction === 'rtl') {
@@ -11,8 +11,8 @@ export class TextAreaEditor extends SourceEditor {
11
11
  constructor() {
12
12
  super(...arguments);
13
13
  this.autosize = this.j.async.debounce(() => {
14
- this.instance.style.height = 'auto';
15
- this.instance.style.height = this.instance.scrollHeight + 'px';
14
+ css(this.instance, 'height', 'auto');
15
+ css(this.instance, 'height', this.instance.scrollHeight);
16
16
  }, this.j.defaultTimeout, true);
17
17
  }
18
18
  init(editor) {
@@ -20,7 +20,7 @@ export class TextAreaEditor extends SourceEditor {
20
20
  class: 'jodit-source__mirror',
21
21
  dir: editor.o.direction === 'rtl' ? 'rtl' : undefined
22
22
  });
23
- this.container.appendChild(this.instance);
23
+ Dom.append(this.container, this.instance);
24
24
  editor.e
25
25
  .on(this.instance, 'mousedown keydown touchstart input', editor.async.debounce(this.toWYSIWYG, editor.defaultTimeout))
26
26
  .on('setMinHeight.source', (minHeightD) => {
@@ -228,9 +228,9 @@ export class source extends Plugin {
228
228
  /** @override */
229
229
  afterInit(editor) {
230
230
  this.mirrorContainer = editor.c.div('jodit-source');
231
- editor.workplace.appendChild(this.mirrorContainer);
231
+ Dom.append(editor.workplace, this.mirrorContainer);
232
232
  editor.e.on('afterAddPlace changePlace afterInit', () => {
233
- editor.workplace.appendChild(this.mirrorContainer);
233
+ Dom.append(editor.workplace, this.mirrorContainer);
234
234
  });
235
235
  this.sourceEditor = createSourceEditor('area', editor, this.mirrorContainer, this.toWYSIWYG, this.fromWYSIWYG);
236
236
  editor.e.on(editor.ow, 'keydown', (e) => {
@@ -59,7 +59,7 @@ export class SpeechRecognizeNative extends Plugin {
59
59
  if (!this.messagePopup) {
60
60
  this.messagePopup = this.j.create.div('jodit-speech-recognize__popup');
61
61
  }
62
- this.j.workplace.appendChild(this.messagePopup);
62
+ Dom.append(this.j.workplace, this.messagePopup);
63
63
  this.j.async.clearTimeout(this.__hidePopupTimeout);
64
64
  this.__hidePopupTimeout = this.j.async.setTimeout(() => {
65
65
  Dom.safeRemove(this.messagePopup);
@@ -28,7 +28,7 @@ export class sticky extends Plugin {
28
28
  this.__createDummy = (toolbar) => {
29
29
  this.__dummyBox = this.j.c.div();
30
30
  this.__dummyBox.classList.add('jodit_sticky-dummy_toolbar');
31
- this.j.container.insertBefore(this.__dummyBox, toolbar);
31
+ Dom.before(toolbar, this.__dummyBox);
32
32
  };
33
33
  /**
34
34
  * Add sticky
@@ -3,6 +3,7 @@
3
3
  * Released under MIT see LICENSE.txt in the project root for license information.
4
4
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
+ import { Dom } from "../../core/dom/dom.js";
6
7
  import { Icon } from "../../core/ui/icon.js";
7
8
  import { Config } from "../../config.js";
8
9
  import symbolsIcon from "./symbols.svg.js";
@@ -229,14 +230,14 @@ Config.prototype.controls.symbols = {
229
230
  if (editor.o.usePopupForSpecialCharacters) {
230
231
  const box = editor.c.div();
231
232
  box.classList.add('jodit-symbols');
232
- box.appendChild(container);
233
+ Dom.append(box, container);
233
234
  editor.e.on(container, 'close_dialog', close);
234
235
  return box;
235
236
  }
236
237
  editor
237
238
  .alert(container, 'Select Special Character', undefined, 'jodit-symbols')
238
239
  .bindDestruct(editor);
239
- const a = container.querySelector('a');
240
+ const a = Dom.first(container, node => Dom.isTag(node, 'a'));
240
241
  a && a.focus();
241
242
  }
242
243
  return;
@@ -35,8 +35,9 @@ export class symbols extends Plugin {
35
35
  <div class="jodit-symbols__preview"></div>
36
36
  </div>
37
37
  </div>`);
38
- const preview = container.querySelector('.jodit-symbols__preview');
39
- const table = container.querySelector('table');
38
+ const preview = Dom.first(container, node => Dom.isHTMLElement(node) &&
39
+ node.classList.contains('jodit-symbols__preview'));
40
+ const table = Dom.first(container, node => Dom.isTag(node, 'table'));
40
41
  const body = table.tBodies[0];
41
42
  const chars = [];
42
43
  for (let i = 0; i < jodit.o.specialCharacters.length;) {
@@ -50,10 +51,10 @@ export class symbols extends Plugin {
50
51
  tabindex="-1"
51
52
  >${jodit.o.specialCharacters[i]}</a>`);
52
53
  chars.push(a);
53
- td.appendChild(a);
54
- tr.appendChild(td);
54
+ Dom.append(td, a);
55
+ Dom.append(tr, td);
55
56
  }
56
- body.appendChild(tr);
57
+ Dom.append(body, tr);
57
58
  }
58
59
  const self = this;
59
60
  jodit.e
@@ -83,8 +83,8 @@ function appendNestedList(jodit, list, li) {
83
83
  acc[attr.name] = attr.value;
84
84
  return acc;
85
85
  }, {}));
86
- newList.appendChild(li);
87
- lastElm !== newList && previousLi.appendChild(newList);
86
+ Dom.append(newList, li);
87
+ lastElm !== newList && Dom.append(previousLi, newList);
88
88
  }
89
89
  function removeNestedList(jodit, list, li) {
90
90
  const parentLi = Dom.closest(list, 'li', jodit.editor);
@@ -54,7 +54,15 @@ Config.prototype.controls.table = {
54
54
  '<label class="jodit-form__center">' +
55
55
  '<span>1</span> &times; <span>1</span>' +
56
56
  '</label>' +
57
- '</form>'), rows = form.querySelectorAll('span')[0], cols = form.querySelectorAll('span')[1], blocksContainer = form.querySelector('.jodit-form__container'), options = form.querySelector('.jodit-form__options'), cells = [];
57
+ '</form>'), spans = (() => {
58
+ const list = [];
59
+ Dom.each(form, node => {
60
+ Dom.isTag(node, 'span') && list.push(node);
61
+ });
62
+ return list;
63
+ })(), [rows, cols] = spans, blocksContainer = Dom.first(form, node => Dom.isHTMLElement(node) &&
64
+ node.classList.contains('jodit-form__container')), options = Dom.first(form, node => Dom.isHTMLElement(node) &&
65
+ node.classList.contains('jodit-form__options')), cells = [];
58
66
  const cnt = default_rows_count * default_cols_count;
59
67
  attr(blocksContainer, {
60
68
  role: 'grid',
@@ -92,7 +100,7 @@ Config.prototype.controls.table = {
92
100
  const k = parseInt(attr(cell, '-index') || '0', 10);
93
101
  const rows_count = Math.ceil((k + 1) / default_cols_count), cols_count = (k % default_cols_count) + 1;
94
102
  const crt = editor.createInside, tbody = crt.element('tbody'), table = crt.element('table');
95
- table.appendChild(tbody);
103
+ Dom.append(table, tbody);
96
104
  let first_td = null, tr, td;
97
105
  for (let i = 1; i <= rows_count; i += 1) {
98
106
  tr = crt.element('tr');
@@ -102,13 +110,13 @@ Config.prototype.controls.table = {
102
110
  first_td = td;
103
111
  }
104
112
  css(td, 'width', (100 / cols_count).toFixed(4) + '%');
105
- td.appendChild(crt.element('br'));
106
- tr.appendChild(crt.text('\n'));
107
- tr.appendChild(crt.text('\t'));
108
- tr.appendChild(td);
113
+ Dom.append(td, crt.element('br'));
114
+ Dom.append(tr, crt.text('\n'));
115
+ Dom.append(tr, crt.text('\t'));
116
+ Dom.append(tr, td);
109
117
  }
110
- tbody.appendChild(crt.text('\n'));
111
- tbody.appendChild(tr);
118
+ Dom.append(tbody, crt.text('\n'));
119
+ Dom.append(tbody, tr);
112
120
  }
113
121
  $$('input[type=checkbox]:checked', options).forEach((input) => {
114
122
  input.value
@@ -224,9 +232,9 @@ Config.prototype.controls.table = {
224
232
  const row = editor.c.div();
225
233
  attr(row, 'role', 'row');
226
234
  for (let j = 0; j < default_cols_count; j += 1) {
227
- row.appendChild(cells[i * default_cols_count + j]);
235
+ Dom.append(row, cells[i * default_cols_count + j]);
228
236
  }
229
- blocksContainer.appendChild(row);
237
+ Dom.append(blocksContainer, row);
230
238
  }
231
239
  if (cells[0]) {
232
240
  cells[0].className = 'hovered';
@@ -39,7 +39,7 @@ export function tableKeyboardNavigation(editor) {
39
39
  if (!next) {
40
40
  tableModule.appendRow(table, !isPrev
41
41
  ? false
42
- : table.querySelector('tr'), !isPrev);
42
+ : Dom.first(table, node => Dom.isTag(node, 'tr')), !isPrev);
43
43
  next = getNextCell();
44
44
  }
45
45
  break;
@@ -68,7 +68,7 @@ export function tableKeyboardNavigation(editor) {
68
68
  editor.e.fire('hidePopup hideResizer');
69
69
  if (!next.firstChild) {
70
70
  const first = editor.createInside.element('br');
71
- next.appendChild(first);
71
+ Dom.append(next, first);
72
72
  editor.s.setCursorBefore(first);
73
73
  }
74
74
  else {
@@ -83,7 +83,7 @@ class wrapNodes extends Plugin {
83
83
  Dom.before(child, box);
84
84
  while (child && this.isSuitable(child)) {
85
85
  const next = child.nextSibling;
86
- box.appendChild(child);
86
+ Dom.append(box, child);
87
87
  child = next;
88
88
  }
89
89
  box.normalize();
@@ -133,7 +133,7 @@ function checkAloneListLeaf(child, jodit) {
133
133
  !Dom.isList(next.parentElement)) {
134
134
  const nextChild = Dom.findNotEmptySibling(next, false);
135
135
  if (Dom.isTag(result, 'ul')) {
136
- result.appendChild(next);
136
+ Dom.append(result, next);
137
137
  }
138
138
  else {
139
139
  result = Dom.wrap(next, 'ul', jodit.createInside);
@@ -89,7 +89,7 @@ class xpath extends Plugin {
89
89
  });
90
90
  this.selectAllButton.state.size = 'tiny';
91
91
  this.container &&
92
- this.container.insertBefore(this.selectAllButton.container, this.container.firstChild);
92
+ Dom.prepend(this.container, this.selectAllButton.container);
93
93
  };
94
94
  this.calcPathImd = () => {
95
95
  if (this.isDestructed) {
@@ -109,8 +109,7 @@ class xpath extends Plugin {
109
109
  name = elm.nodeName.toLowerCase();
110
110
  xpth = getXPathByElement(elm, this.j.editor).replace(/^\//, '');
111
111
  li = this.tpl(elm, xpth, name, this.j.i18n('Select %s', name));
112
- this.container &&
113
- this.container.insertBefore(li, this.container.firstChild);
112
+ this.container && Dom.prepend(this.container, li);
114
113
  }
115
114
  }, this.j.editor);
116
115
  }
@@ -27,5 +27,6 @@ export * from "./traits";
27
27
  export * from "./types";
28
28
  export * from "./ui";
29
29
  export * from "./uploader";
30
+ export * from "./vdom";
30
31
  export * from "./view";
31
32
  export * from "./messages";
@@ -0,0 +1,96 @@
1
+ /*!
2
+ * Jodit Editor (https://xdsoft.net/jodit/)
3
+ * Released under MIT see LICENSE.txt in the project root for license information.
4
+ * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
+ */
6
+ /**
7
+ * @module types
8
+ */
9
+ /**
10
+ * Virtual DOM interfaces.
11
+ *
12
+ * A minimal structural subset of the browser DOM: every browser `Node`,
13
+ * `Element`, `HTMLElement`, `Text`, `Document` and `DocumentFragment`
14
+ * satisfies the matching interface below, so they can be passed anywhere
15
+ * these types are expected. The `Dom` module (and the low-level helpers)
16
+ * must rely only on this subset — this is the contract that will let the
17
+ * editor switch to virtual-DOM editing without rewriting the call sites.
18
+ *
19
+ * Keep these interfaces as small as possible: add a member only when the
20
+ * `Dom` module (or `attr`/`css` helpers) really needs it.
21
+ */
22
+ /**
23
+ * Minimal subset of the browser `Node`
24
+ */
25
+ export interface VNode {
26
+ readonly nodeType: number;
27
+ readonly nodeName: string;
28
+ nodeValue: string | null;
29
+ textContent: string | null;
30
+ readonly parentNode: VNode | null;
31
+ readonly parentElement: VHTMLElement | null;
32
+ readonly firstChild: VNode | null;
33
+ readonly lastChild: VNode | null;
34
+ readonly previousSibling: VNode | null;
35
+ readonly nextSibling: VNode | null;
36
+ readonly childNodes: ArrayLike<VNode>;
37
+ readonly ownerDocument: VDocument | null;
38
+ appendChild(node: VNode): VNode;
39
+ insertBefore(node: VNode, child: VNode | null): VNode;
40
+ removeChild(child: VNode): VNode;
41
+ replaceChild(node: VNode, child: VNode): VNode;
42
+ contains(other: VNode | null): boolean;
43
+ }
44
+ /**
45
+ * Minimal subset of the browser `Attr`
46
+ */
47
+ export interface VAttr {
48
+ readonly name: string;
49
+ readonly value: string;
50
+ }
51
+ /**
52
+ * Minimal subset of the browser `DOMTokenList`
53
+ */
54
+ export interface VTokenList {
55
+ readonly length: number;
56
+ add(...tokens: string[]): void;
57
+ remove(...tokens: string[]): void;
58
+ contains(token: string): boolean;
59
+ toggle(token: string, force?: boolean): boolean;
60
+ }
61
+ /**
62
+ * Minimal subset of the browser `Element`
63
+ */
64
+ export interface VElement extends VNode {
65
+ readonly tagName: string;
66
+ readonly attributes: ArrayLike<VAttr>;
67
+ readonly classList: VTokenList;
68
+ className: string;
69
+ getAttribute(name: string): string | null;
70
+ setAttribute(name: string, value: string): void;
71
+ removeAttribute(name: string): void;
72
+ hasAttribute(name: string): boolean;
73
+ }
74
+ /**
75
+ * Minimal subset of the browser `CSSStyleDeclaration`
76
+ */
77
+ export interface VStyle {
78
+ getPropertyValue(property: string): string;
79
+ setProperty(property: string, value: string | null): void;
80
+ removeProperty(property: string): string;
81
+ }
82
+ /**
83
+ * Minimal subset of the browser `HTMLElement`
84
+ */
85
+ export interface VHTMLElement extends VElement {
86
+ readonly style: VStyle;
87
+ }
88
+ /**
89
+ * Minimal subset of the browser `Document`. Text nodes and fragments add
90
+ * nothing to `VNode` structurally, so they are typed as `VNode`.
91
+ */
92
+ export interface VDocument {
93
+ createElement(tagName: string): VHTMLElement;
94
+ createTextNode(data: string): VNode;
95
+ createDocumentFragment(): VNode;
96
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jodit",
3
- "version": "4.13.26",
3
+ "version": "4.14.0",
4
4
  "description": "Jodit is an awesome and useful wysiwyg editor with filebrowser",
5
5
  "main": "esm/index.js",
6
6
  "types": "types/index.d.ts",
@@ -8,7 +8,7 @@
8
8
  * @packageDocumentation
9
9
  * @module dom
10
10
  */
11
- import type { HTMLTagNames, ICreate, IDictionary, IJodit, NodeCondition, Nullable } from "../../types/index";
11
+ import type { HTMLTagNames, ICreate, IDictionary, IJodit, NodeCondition, Nullable, VHTMLElement, VNode } from "../../types/index";
12
12
  /**
13
13
  * Module for working with DOM
14
14
  */
@@ -17,7 +17,7 @@ export declare class Dom {
17
17
  /**
18
18
  * Remove all content from element
19
19
  */
20
- static detach(node: Nullable<Node>): void;
20
+ static detach(node: Nullable<VNode>): void;
21
21
  /**
22
22
  * Wrap all inline next siblings
23
23
  */
@@ -32,7 +32,7 @@ export declare class Dom {
32
32
  /**
33
33
  * Remove parent of node and insert this node instead that parent
34
34
  */
35
- static unwrap(node: Node): void;
35
+ static unwrap(node: VNode): void;
36
36
  /**
37
37
  * Call callback for all nodes between `start` and `end` in document order
38
38
  * (`start` and `end` are not included). Iteration stops when the callback returns `true`.
@@ -140,6 +140,11 @@ export declare class Dom {
140
140
  * Get last matched node inside root
141
141
  */
142
142
  static last(root: Nullable<Node>, condition: NodeCondition): Nullable<Node>;
143
+ /**
144
+ * Depth-first search for the first matched node inside root:
145
+ * in document order (`reverse = false`) or in reverse order
146
+ */
147
+ private static __deepMost;
143
148
  /**
144
149
  * Find previous node
145
150
  */
@@ -150,6 +155,7 @@ export declare class Dom {
150
155
  static next<T extends Node = Node>(node: Node, condition: NodeCondition, root: HTMLElement, withChild?: boolean): Nullable<T>;
151
156
  static prevWithClass(node: HTMLElement, className: string): Nullable<HTMLElement>;
152
157
  static nextWithClass(node: HTMLElement, className: string): Nullable<HTMLElement>;
158
+ private static __siblingWithClass;
153
159
  /**
154
160
  * Find next/prev node what `condition(next) === true`
155
161
  */
@@ -197,6 +203,7 @@ export declare class Dom {
197
203
  * Returns the previous (`left = true`) or next sibling of the node
198
204
  */
199
205
  static sibling(node: Node, left?: boolean): Nullable<Node>;
206
+ static sibling(node: VNode, left?: boolean): Nullable<VNode>;
200
207
  /**
201
208
  * It goes through all the elements in ascending order, and checks to see if they meet the predetermined condition
202
209
  *
@@ -219,28 +226,29 @@ export declare class Dom {
219
226
  /**
220
227
  * Append new element in the start of root
221
228
  */
222
- static appendChildFirst(root: HTMLElement, newElement: HTMLElement | DocumentFragment): void;
229
+ static appendChildFirst(root: VNode, newElement: VNode): void;
223
230
  /**
224
231
  * Insert newElement after element
225
232
  */
226
- static after(elm: Node, newElement: Node | DocumentFragment): void;
233
+ static after(elm: VNode, newElement: VNode): void;
227
234
  /**
228
235
  * Insert newElement before element
229
236
  */
230
- static before(elm: Node, newElement: Node | DocumentFragment): void;
237
+ static before(elm: VNode, newElement: VNode): void;
231
238
  /**
232
239
  * Insert newElement as first child inside element
233
240
  */
234
- static prepend(root: Node, newElement: Node | DocumentFragment): void;
241
+ static prepend(root: VNode, newElement: VNode): void;
235
242
  /**
236
243
  * Insert newElement as last child inside element
237
244
  */
238
- static append(root: Node, newElements: Array<Node | DocumentFragment>): void;
239
- static append(root: Node, newElement: Node | DocumentFragment): void;
245
+ static append(root: VNode, newElements: VNode[]): void;
246
+ static append(root: VNode, newElement: VNode): void;
240
247
  /**
241
248
  * Move all content to another element
242
249
  */
243
250
  static moveContent(from: Node, to: Node, inStart?: boolean, filter?: (node: Node) => boolean): void;
251
+ static moveContent(from: VNode, to: VNode, inStart?: boolean, filter?: (node: VNode) => boolean): void;
244
252
  /**
245
253
  * Check root contains child or equal child
246
254
  */
@@ -259,11 +267,11 @@ export declare class Dom {
259
267
  /**
260
268
  * Hide element
261
269
  */
262
- static hide(node: Nullable<HTMLElement>): void;
270
+ static hide(node: Nullable<VHTMLElement>): void;
263
271
  /**
264
272
  * Show element
265
273
  */
266
- static show(node: Nullable<HTMLElement>): void;
274
+ static show(node: Nullable<VHTMLElement>): void;
267
275
  /**
268
276
  * Check if element is some tag
269
277
  */
@@ -286,8 +294,8 @@ export declare class Dom {
286
294
  */
287
295
  static replaceTemporaryFromString(value: string): string;
288
296
  /**
289
- * Get temporary list
290
- * @deprecated Just do not use it, it is not needed anymore
297
+ * Collect the temporary elements (`data-jodit-temp`) inside the root.
298
+ * A plain tree walk on purpose: no selector engine, works on VNode.
291
299
  */
292
300
  static temporaryList(root: HTMLElement): HTMLElement[];
293
301
  }
@@ -15,7 +15,4 @@ export declare function hAlignElement(image: HTMLElement, align: ImageHAlign): v
15
15
  * Remove text-align style for all selected children
16
16
  */
17
17
  export declare function clearAlign(node: Node): void;
18
- /**
19
- * Apply align for element
20
- */
21
18
  export declare function alignElement(command: string, box: HTMLElement): void;
@@ -6,7 +6,7 @@
6
6
  /**
7
7
  * @module helpers/utils
8
8
  */
9
- import type { IDictionary } from "../../../types/index";
9
+ import type { IDictionary, VElement } from "../../../types/index";
10
10
  /**
11
11
  * Get attribute
12
12
  */
@@ -23,3 +23,5 @@ export declare function attr(elm: Element, key: string, value: string | number |
23
23
  * Set or remove several attributes
24
24
  */
25
25
  export declare function attr(elm: Element, attributes: IDictionary<string | number | boolean | null>): null;
26
+ export declare function attrRaw(elm: VElement, name: string): null | string;
27
+ export declare function attrRaw(elm: VElement, name: string, value: string | null): void;
@@ -6,13 +6,30 @@
6
6
  /**
7
7
  * @module helpers/utils
8
8
  */
9
- import type { IStyle, StyleValue } from "../../../types/index";
9
+ import type { IStyle, StyleValue, VHTMLElement } from "../../../types/index";
10
10
  export declare function css(element: HTMLElement, key: 'left' | 'top' | 'bottom' | 'right' | 'width' | 'min' | 'max' | 'height' | 'margin' | 'padding' | 'fontsize' | 'font-size'): number;
11
11
  export declare function css(element: HTMLElement, key: keyof CSSStyleDeclaration): string | number;
12
12
  export declare function css(element: HTMLElement, key: string | IStyle): string | number;
13
13
  export declare function css(element: HTMLElement, key: string | IStyle, value: StyleValue): string | number;
14
+ /**
15
+ * @deprecated Use `cssInline(element, key)` for an exact inline read.
16
+ * The boolean mode still normalizes the value (`'0px'` → `0`, `bold` → `700`).
17
+ */
14
18
  export declare function css(element: HTMLElement, key: string | IStyle, onlyStyleMode: boolean): string | number;
15
19
  /**
16
20
  * Clear center align
17
21
  */
22
+ /**
23
+ * Read the exact inline value of a CSS property (the `style` attribute).
24
+ * Unlike `css()` it never touches computed styles (no layout access) and does
25
+ * not normalize the result, so it is safe for exact string comparisons and
26
+ * save/restore. Returns an empty string when the property is not set inline.
27
+ *
28
+ * @example
29
+ * ```js
30
+ * cssInline(elm, 'zIndex'); // '' or '100'
31
+ * cssInline(elm, 'width'); // '0px' (css(elm, 'width', true) would return 0)
32
+ * ```
33
+ */
34
+ export declare function cssInline(element: VHTMLElement, key: string): string;
18
35
  export declare const clearCenterAlign: (image: HTMLElement) => void;
@@ -124,6 +124,12 @@ export declare class Dialog extends ViewWithToolbar implements IDialog {
124
124
  * ```
125
125
  */
126
126
  setFooter(content: Content): this;
127
+ /**
128
+ * Registry of the currently opened dialogs. Replaces a DOM scan of the
129
+ * whole `destination` (usually `document.body`) for every z-index update.
130
+ */
131
+ private static readonly __opened;
132
+ private __openedSiblings;
127
133
  /**
128
134
  * Get zIndex from dialog
129
135
  */
@@ -27,5 +27,6 @@ export * from "./traits";
27
27
  export * from "./types";
28
28
  export * from "./ui";
29
29
  export * from "./uploader";
30
+ export * from "./vdom";
30
31
  export * from "./view";
31
32
  export * from "./messages";
@@ -0,0 +1,96 @@
1
+ /*!
2
+ * Jodit Editor (https://xdsoft.net/jodit/)
3
+ * Released under MIT see LICENSE.txt in the project root for license information.
4
+ * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
+ */
6
+ /**
7
+ * @module types
8
+ */
9
+ /**
10
+ * Virtual DOM interfaces.
11
+ *
12
+ * A minimal structural subset of the browser DOM: every browser `Node`,
13
+ * `Element`, `HTMLElement`, `Text`, `Document` and `DocumentFragment`
14
+ * satisfies the matching interface below, so they can be passed anywhere
15
+ * these types are expected. The `Dom` module (and the low-level helpers)
16
+ * must rely only on this subset — this is the contract that will let the
17
+ * editor switch to virtual-DOM editing without rewriting the call sites.
18
+ *
19
+ * Keep these interfaces as small as possible: add a member only when the
20
+ * `Dom` module (or `attr`/`css` helpers) really needs it.
21
+ */
22
+ /**
23
+ * Minimal subset of the browser `Node`
24
+ */
25
+ export interface VNode {
26
+ readonly nodeType: number;
27
+ readonly nodeName: string;
28
+ nodeValue: string | null;
29
+ textContent: string | null;
30
+ readonly parentNode: VNode | null;
31
+ readonly parentElement: VHTMLElement | null;
32
+ readonly firstChild: VNode | null;
33
+ readonly lastChild: VNode | null;
34
+ readonly previousSibling: VNode | null;
35
+ readonly nextSibling: VNode | null;
36
+ readonly childNodes: ArrayLike<VNode>;
37
+ readonly ownerDocument: VDocument | null;
38
+ appendChild(node: VNode): VNode;
39
+ insertBefore(node: VNode, child: VNode | null): VNode;
40
+ removeChild(child: VNode): VNode;
41
+ replaceChild(node: VNode, child: VNode): VNode;
42
+ contains(other: VNode | null): boolean;
43
+ }
44
+ /**
45
+ * Minimal subset of the browser `Attr`
46
+ */
47
+ export interface VAttr {
48
+ readonly name: string;
49
+ readonly value: string;
50
+ }
51
+ /**
52
+ * Minimal subset of the browser `DOMTokenList`
53
+ */
54
+ export interface VTokenList {
55
+ readonly length: number;
56
+ add(...tokens: string[]): void;
57
+ remove(...tokens: string[]): void;
58
+ contains(token: string): boolean;
59
+ toggle(token: string, force?: boolean): boolean;
60
+ }
61
+ /**
62
+ * Minimal subset of the browser `Element`
63
+ */
64
+ export interface VElement extends VNode {
65
+ readonly tagName: string;
66
+ readonly attributes: ArrayLike<VAttr>;
67
+ readonly classList: VTokenList;
68
+ className: string;
69
+ getAttribute(name: string): string | null;
70
+ setAttribute(name: string, value: string): void;
71
+ removeAttribute(name: string): void;
72
+ hasAttribute(name: string): boolean;
73
+ }
74
+ /**
75
+ * Minimal subset of the browser `CSSStyleDeclaration`
76
+ */
77
+ export interface VStyle {
78
+ getPropertyValue(property: string): string;
79
+ setProperty(property: string, value: string | null): void;
80
+ removeProperty(property: string): string;
81
+ }
82
+ /**
83
+ * Minimal subset of the browser `HTMLElement`
84
+ */
85
+ export interface VHTMLElement extends VElement {
86
+ readonly style: VStyle;
87
+ }
88
+ /**
89
+ * Minimal subset of the browser `Document`. Text nodes and fragments add
90
+ * nothing to `VNode` structurally, so they are typed as `VNode`.
91
+ */
92
+ export interface VDocument {
93
+ createElement(tagName: string): VHTMLElement;
94
+ createTextNode(data: string): VNode;
95
+ createDocumentFragment(): VNode;
96
+ }