jodit 4.18.2 → 4.18.4

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 (226) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/es2015/jodit.css +66 -6
  3. package/es2015/jodit.fat.min.css +1 -1
  4. package/es2015/jodit.fat.min.js +36 -11
  5. package/es2015/jodit.js +1435 -327
  6. package/es2015/jodit.min.css +1 -1
  7. package/es2015/jodit.min.js +41 -16
  8. package/es2015/plugins/debug/debug.css +1 -1
  9. package/es2015/plugins/debug/debug.js +1 -1
  10. package/es2015/plugins/debug/debug.min.js +1 -1
  11. package/es2015/plugins/speech-recognize/speech-recognize.css +1 -1
  12. package/es2015/plugins/speech-recognize/speech-recognize.js +1 -1
  13. package/es2015/plugins/speech-recognize/speech-recognize.min.js +1 -1
  14. package/es2018/jodit.fat.min.css +1 -1
  15. package/es2018/jodit.fat.min.js +36 -11
  16. package/es2018/jodit.min.css +1 -1
  17. package/es2018/jodit.min.js +36 -11
  18. package/es2018/plugins/debug/debug.min.js +1 -1
  19. package/es2018/plugins/speech-recognize/speech-recognize.min.js +1 -1
  20. package/es2021/jodit.css +66 -6
  21. package/es2021/jodit.fat.min.css +1 -1
  22. package/es2021/jodit.fat.min.js +45 -20
  23. package/es2021/jodit.js +1365 -271
  24. package/es2021/jodit.min.css +1 -1
  25. package/es2021/jodit.min.js +45 -20
  26. package/es2021/plugins/debug/debug.css +1 -1
  27. package/es2021/plugins/debug/debug.js +1 -1
  28. package/es2021/plugins/debug/debug.min.js +1 -1
  29. package/es2021/plugins/speech-recognize/speech-recognize.css +1 -1
  30. package/es2021/plugins/speech-recognize/speech-recognize.js +1 -1
  31. package/es2021/plugins/speech-recognize/speech-recognize.min.js +1 -1
  32. package/es2021.en/jodit.css +66 -6
  33. package/es2021.en/jodit.fat.min.css +1 -1
  34. package/es2021.en/jodit.fat.min.js +51 -26
  35. package/es2021.en/jodit.js +1339 -245
  36. package/es2021.en/jodit.min.css +1 -1
  37. package/es2021.en/jodit.min.js +51 -26
  38. package/es2021.en/plugins/debug/debug.css +1 -1
  39. package/es2021.en/plugins/debug/debug.js +1 -1
  40. package/es2021.en/plugins/debug/debug.min.js +1 -1
  41. package/es2021.en/plugins/speech-recognize/speech-recognize.css +1 -1
  42. package/es2021.en/plugins/speech-recognize/speech-recognize.js +1 -1
  43. package/es2021.en/plugins/speech-recognize/speech-recognize.min.js +1 -1
  44. package/es5/jodit.css +82 -7
  45. package/es5/jodit.fat.min.css +1 -1
  46. package/es5/jodit.fat.min.js +2 -2
  47. package/es5/jodit.js +1629 -354
  48. package/es5/jodit.min.css +3 -3
  49. package/es5/jodit.min.js +2 -2
  50. package/es5/plugins/debug/debug.css +1 -1
  51. package/es5/plugins/debug/debug.js +1 -1
  52. package/es5/plugins/debug/debug.min.js +1 -1
  53. package/es5/plugins/speech-recognize/speech-recognize.css +1 -1
  54. package/es5/plugins/speech-recognize/speech-recognize.js +1 -1
  55. package/es5/plugins/speech-recognize/speech-recognize.min.js +1 -1
  56. package/es5/polyfills.fat.min.js +1 -1
  57. package/es5/polyfills.js +1 -1
  58. package/es5/polyfills.min.js +1 -1
  59. package/esm/config.d.ts +29 -28
  60. package/esm/config.js +19 -21
  61. package/esm/core/constants.js +1 -1
  62. package/esm/core/helpers/utils/align.d.ts +1 -1
  63. package/esm/core/helpers/utils/align.js +2 -3
  64. package/esm/core/helpers/utils/index.d.ts +1 -0
  65. package/esm/core/helpers/utils/index.js +1 -0
  66. package/esm/core/helpers/utils/prepare-media.d.ts +19 -0
  67. package/esm/core/helpers/utils/prepare-media.js +31 -0
  68. package/esm/core/selection/style/api/wrap-unwrapped-text.js +3 -2
  69. package/esm/jodit.js +14 -4
  70. package/esm/langs/ar.d.ts +7 -0
  71. package/esm/langs/ar.js +8 -1
  72. package/esm/langs/az.d.ts +7 -0
  73. package/esm/langs/az.js +8 -1
  74. package/esm/langs/cs_cz.d.ts +7 -0
  75. package/esm/langs/cs_cz.js +9 -1
  76. package/esm/langs/de.d.ts +7 -0
  77. package/esm/langs/de.js +8 -1
  78. package/esm/langs/es.d.ts +7 -0
  79. package/esm/langs/es.js +8 -1
  80. package/esm/langs/fa.d.ts +7 -0
  81. package/esm/langs/fa.js +8 -1
  82. package/esm/langs/fi.d.ts +7 -0
  83. package/esm/langs/fi.js +8 -1
  84. package/esm/langs/fr.d.ts +7 -0
  85. package/esm/langs/fr.js +8 -1
  86. package/esm/langs/he.d.ts +7 -0
  87. package/esm/langs/he.js +8 -1
  88. package/esm/langs/hu.d.ts +7 -0
  89. package/esm/langs/hu.js +8 -1
  90. package/esm/langs/id.d.ts +7 -0
  91. package/esm/langs/id.js +8 -1
  92. package/esm/langs/it.d.ts +7 -0
  93. package/esm/langs/it.js +8 -1
  94. package/esm/langs/ja.d.ts +7 -0
  95. package/esm/langs/ja.js +8 -1
  96. package/esm/langs/ko.d.ts +7 -0
  97. package/esm/langs/ko.js +8 -1
  98. package/esm/langs/mn.d.ts +7 -0
  99. package/esm/langs/mn.js +8 -1
  100. package/esm/langs/nl.d.ts +7 -0
  101. package/esm/langs/nl.js +8 -1
  102. package/esm/langs/no.d.ts +7 -0
  103. package/esm/langs/no.js +8 -1
  104. package/esm/langs/pl.d.ts +7 -0
  105. package/esm/langs/pl.js +8 -1
  106. package/esm/langs/pt_br.d.ts +7 -0
  107. package/esm/langs/pt_br.js +8 -1
  108. package/esm/langs/ru.d.ts +7 -0
  109. package/esm/langs/ru.js +8 -1
  110. package/esm/langs/sk.d.ts +7 -0
  111. package/esm/langs/sk.js +8 -1
  112. package/esm/langs/sv.d.ts +7 -0
  113. package/esm/langs/sv.js +8 -1
  114. package/esm/langs/tr.d.ts +7 -0
  115. package/esm/langs/tr.js +8 -1
  116. package/esm/langs/ua.d.ts +7 -0
  117. package/esm/langs/ua.js +8 -1
  118. package/esm/langs/zh_cn.d.ts +7 -0
  119. package/esm/langs/zh_cn.js +8 -1
  120. package/esm/langs/zh_tw.d.ts +7 -0
  121. package/esm/langs/zh_tw.js +8 -1
  122. package/esm/modules/history/history.d.ts +17 -2
  123. package/esm/modules/history/history.js +41 -19
  124. package/esm/modules/table/table.js +7 -2
  125. package/esm/modules/widget/file-selector/file-selector.js +2 -2
  126. package/esm/plugins/all.d.ts +1 -0
  127. package/esm/plugins/all.js +1 -0
  128. package/esm/plugins/backspace/backspace.js +4 -0
  129. package/esm/plugins/clean-html/clean-html.d.ts +7 -0
  130. package/esm/plugins/clean-html/clean-html.js +17 -0
  131. package/esm/plugins/clean-html/helpers/visitor/filters/replace-old-tags.js +26 -1
  132. package/esm/plugins/dtd/before-insert/check-block-nesting.d.ts +2 -1
  133. package/esm/plugins/dtd/before-insert/check-block-nesting.js +26 -5
  134. package/esm/plugins/enter/helpers/move-cursor-out-from-specal-tags.js +8 -0
  135. package/esm/plugins/focus/focus.js +3 -0
  136. package/esm/plugins/hr/hr.js +21 -5
  137. package/esm/plugins/iframe/config.js +8 -3
  138. package/esm/plugins/image-processor/image-processor.d.ts +4 -1
  139. package/esm/plugins/image-processor/image-processor.js +9 -3
  140. package/esm/plugins/image-properties/readers/align.d.ts +2 -2
  141. package/esm/plugins/index.d.ts +1 -0
  142. package/esm/plugins/inline-popup/config/items/iframe.d.ts +9 -1
  143. package/esm/plugins/inline-popup/config/items/iframe.js +15 -0
  144. package/esm/plugins/inline-popup/inline-popup.d.ts +5 -0
  145. package/esm/plugins/inline-popup/inline-popup.js +26 -2
  146. package/esm/plugins/link/link.js +5 -2
  147. package/esm/plugins/media/config.d.ts +2 -1
  148. package/esm/plugins/media/media.js +37 -9
  149. package/esm/plugins/paste/helpers.d.ts +8 -0
  150. package/esm/plugins/paste/helpers.js +18 -1
  151. package/esm/plugins/paste/paste.js +2 -2
  152. package/esm/plugins/resizer/config.d.ts +5 -3
  153. package/esm/plugins/resizer/config.js +8 -2
  154. package/esm/plugins/resizer/resizer.d.ts +10 -0
  155. package/esm/plugins/resizer/resizer.js +72 -18
  156. package/esm/plugins/select-cells/select-cells.d.ts +10 -0
  157. package/esm/plugins/select-cells/select-cells.js +54 -6
  158. package/esm/plugins/table/config.js +51 -1
  159. package/esm/plugins/table-keyboard-navigation/table-keyboard-navigation.js +1 -1
  160. package/esm/plugins/video/config.d.ts +6 -0
  161. package/esm/plugins/video/config.js +78 -82
  162. package/esm/plugins/video-properties/interface.d.ts +31 -0
  163. package/esm/plugins/video-properties/interface.js +6 -0
  164. package/esm/plugins/video-properties/readers.d.ts +26 -0
  165. package/esm/plugins/video-properties/readers.js +65 -0
  166. package/esm/plugins/video-properties/replace.d.ts +15 -0
  167. package/esm/plugins/video-properties/replace.js +97 -0
  168. package/esm/plugins/video-properties/ui/ui-video-form.d.ts +41 -0
  169. package/esm/plugins/video-properties/ui/ui-video-form.js +228 -0
  170. package/esm/plugins/video-properties/video-properties.d.ts +37 -0
  171. package/esm/plugins/video-properties/video-properties.js +175 -0
  172. package/esm/plugins/video-properties/writers.d.ts +15 -0
  173. package/esm/plugins/video-properties/writers.js +73 -0
  174. package/esm/types/types.d.ts +1 -1
  175. package/package.json +1 -1
  176. package/types/config.d.ts +29 -28
  177. package/types/core/helpers/utils/align.d.ts +1 -1
  178. package/types/core/helpers/utils/index.d.ts +1 -0
  179. package/types/core/helpers/utils/prepare-media.d.ts +19 -0
  180. package/types/langs/ar.d.ts +7 -0
  181. package/types/langs/az.d.ts +7 -0
  182. package/types/langs/cs_cz.d.ts +7 -0
  183. package/types/langs/de.d.ts +7 -0
  184. package/types/langs/es.d.ts +7 -0
  185. package/types/langs/fa.d.ts +7 -0
  186. package/types/langs/fi.d.ts +7 -0
  187. package/types/langs/fr.d.ts +7 -0
  188. package/types/langs/he.d.ts +7 -0
  189. package/types/langs/hu.d.ts +7 -0
  190. package/types/langs/id.d.ts +7 -0
  191. package/types/langs/it.d.ts +7 -0
  192. package/types/langs/ja.d.ts +7 -0
  193. package/types/langs/ko.d.ts +7 -0
  194. package/types/langs/mn.d.ts +7 -0
  195. package/types/langs/nl.d.ts +7 -0
  196. package/types/langs/no.d.ts +7 -0
  197. package/types/langs/pl.d.ts +7 -0
  198. package/types/langs/pt_br.d.ts +7 -0
  199. package/types/langs/ru.d.ts +7 -0
  200. package/types/langs/sk.d.ts +7 -0
  201. package/types/langs/sv.d.ts +7 -0
  202. package/types/langs/tr.d.ts +7 -0
  203. package/types/langs/ua.d.ts +7 -0
  204. package/types/langs/zh_cn.d.ts +7 -0
  205. package/types/langs/zh_tw.d.ts +7 -0
  206. package/types/modules/history/history.d.ts +17 -2
  207. package/types/plugins/clean-html/clean-html.d.ts +7 -0
  208. package/types/plugins/dtd/before-insert/check-block-nesting.d.ts +2 -1
  209. package/types/plugins/image-processor/image-processor.d.ts +4 -1
  210. package/types/plugins/image-properties/readers/align.d.ts +2 -2
  211. package/types/plugins/index.d.ts +1 -0
  212. package/types/plugins/inline-popup/config/items/iframe.d.ts +9 -1
  213. package/types/plugins/inline-popup/inline-popup.d.ts +5 -0
  214. package/types/plugins/media/config.d.ts +2 -1
  215. package/types/plugins/paste/helpers.d.ts +8 -0
  216. package/types/plugins/resizer/config.d.ts +5 -3
  217. package/types/plugins/resizer/resizer.d.ts +10 -0
  218. package/types/plugins/select-cells/select-cells.d.ts +10 -0
  219. package/types/plugins/video/config.d.ts +6 -0
  220. package/types/plugins/video-properties/interface.d.ts +31 -0
  221. package/types/plugins/video-properties/readers.d.ts +26 -0
  222. package/types/plugins/video-properties/replace.d.ts +15 -0
  223. package/types/plugins/video-properties/ui/ui-video-form.d.ts +41 -0
  224. package/types/plugins/video-properties/video-properties.d.ts +37 -0
  225. package/types/plugins/video-properties/writers.d.ts +15 -0
  226. package/types/types/types.d.ts +1 -1
@@ -72,7 +72,7 @@ export function tableKeyboardNavigation(editor) {
72
72
  editor.s.setCursorBefore(first);
73
73
  }
74
74
  else {
75
- if (key === consts.KEY_TAB) {
75
+ if (key === consts.KEY_TAB && !Dom.isEmpty(next)) {
76
76
  editor.s.select(next, true);
77
77
  }
78
78
  else {
@@ -53,3 +53,9 @@ declare module 'jodit/config' {
53
53
  };
54
54
  }
55
55
  }
56
+ /**
57
+ * The video popup's tabs: Upload, when the uploader is configured, then Link
58
+ * and Code. `insert` runs what a tab inserts, which by default goes in at the
59
+ * selection the popup was opened with.
60
+ */
61
+ export declare function videoTabs(jodit: IJodit, close: () => void, insert?: (run: () => void) => void): HTMLElement;
@@ -3,23 +3,13 @@
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 { call, convertMediaUrlToVideoEmbed, getAlignClasses, hAlignElement, wrapMedia } from "../../core/helpers/index.js";
6
+ import { call, convertMediaUrlToVideoEmbed, prepareEmbedCode, prepareMedia } from "../../core/helpers/index.js";
7
7
  import { Button } from "../../core/ui/button/index.js";
8
8
  import { UIBlock, UIForm, UIInput, UITextArea } from "../../core/ui/form/index.js";
9
9
  import { Icon } from "../../core/ui/icon.js";
10
10
  import { Config } from "../../config.js";
11
11
  import { TabsWidget, UploadTab } from "../../modules/widget/index.js";
12
12
  import videoIcon from "./video.svg.js";
13
- // Media the popup inserts go in their wrapper (see `mediaWrappers`), aligned
14
- // with `mediaDefaultAlign`
15
- function prepareMedia(jodit, element) {
16
- const media = wrapMedia(jodit, element);
17
- const { mediaDefaultAlign } = jodit.o;
18
- if (mediaDefaultAlign && mediaDefaultAlign !== 'normal') {
19
- hAlignElement(media, mediaDefaultAlign, getAlignClasses(jodit, media));
20
- }
21
- return media;
22
- }
23
13
  function insertVideos(data) {
24
14
  var _a;
25
15
  (_a = data.files) === null || _a === void 0 ? void 0 : _a.forEach(file => {
@@ -29,16 +19,6 @@ function insertVideos(data) {
29
19
  })));
30
20
  });
31
21
  }
32
- // Embed code that is one element is prepared as media; other code goes in as
33
- // it is
34
- function prepareEmbedCode(jodit, code) {
35
- const box = jodit.createInside.div();
36
- box.innerHTML = code.trim();
37
- const element = box.firstElementChild;
38
- return element && box.childNodes.length === 1
39
- ? prepareMedia(jodit, element)
40
- : code;
41
- }
42
22
  Config.prototype.video = {
43
23
  parseUrlToVideoEmbed: convertMediaUrlToVideoEmbed,
44
24
  defaultWidth: 400,
@@ -46,69 +26,85 @@ Config.prototype.video = {
46
26
  defaultHandlerSuccess: insertVideos
47
27
  };
48
28
  Icon.set('video', videoIcon);
49
- Config.prototype.controls.video = {
50
- popup: (jodit, current, close) => {
51
- const formLink = new UIForm(jodit, [
52
- new UIBlock(jodit, [
53
- new UIInput(jodit, {
54
- name: 'url',
55
- required: true,
56
- label: 'URL',
57
- placeholder: 'https://',
58
- validators: ['url']
59
- })
60
- ]),
61
- new UIBlock(jodit, [
62
- Button(jodit, '', 'Insert', 'primary').onAction(() => formLink.submit())
63
- ])
64
- ]), formCode = new UIForm(jodit, [
65
- new UIBlock(jodit, [
66
- new UITextArea(jodit, {
67
- name: 'code',
68
- required: true,
69
- label: 'Embed code'
70
- })
71
- ]),
72
- new UIBlock(jodit, [
73
- Button(jodit, '', 'Insert', 'primary').onAction(() => formCode.submit())
74
- ])
75
- ]), tabs = [], insertCode = (code) => {
76
- jodit.s.restore();
77
- jodit.s.insertHTML(prepareEmbedCode(jodit, code));
78
- close();
79
- };
29
+ /**
30
+ * The video popup's tabs: Upload, when the uploader is configured, then Link
31
+ * and Code. `insert` runs what a tab inserts, which by default goes in at the
32
+ * selection the popup was opened with.
33
+ */
34
+ export function videoTabs(jodit, close, insert) {
35
+ const run = insert !== null && insert !== void 0 ? insert : ((fn) => {
36
+ jodit.s.restore();
37
+ fn();
38
+ });
39
+ const formLink = new UIForm(jodit, [
40
+ new UIBlock(jodit, [
41
+ new UIInput(jodit, {
42
+ name: 'url',
43
+ required: true,
44
+ label: 'URL',
45
+ placeholder: 'https://',
46
+ validators: ['url']
47
+ })
48
+ ]),
49
+ new UIBlock(jodit, [
50
+ Button(jodit, '', 'Insert', 'primary').onAction(() => formLink.submit())
51
+ ])
52
+ ]), formCode = new UIForm(jodit, [
53
+ new UIBlock(jodit, [
54
+ new UITextArea(jodit, {
55
+ name: 'code',
56
+ required: true,
57
+ label: 'Embed code'
58
+ })
59
+ ]),
60
+ new UIBlock(jodit, [
61
+ Button(jodit, '', 'Insert', 'primary').onAction(() => formCode.submit())
62
+ ])
63
+ ]), tabs = [], insertCode = (code) => {
64
+ run(() => jodit.s.insertHTML(prepareEmbedCode(jodit, code)));
65
+ close();
66
+ };
67
+ if (!insert) {
80
68
  jodit.s.save();
81
- const { uploader } = jodit.o;
82
- // Base64 alone would put whole video files into the content
83
- if (uploader.showTabInFileSelector !== false &&
84
- (uploader.url || uploader.customUploadFunction)) {
85
- tabs.push(UploadTab(jodit, data => {
69
+ }
70
+ const { uploader } = jodit.o;
71
+ // Base64 alone would put whole video files into the content
72
+ if (uploader.showTabInFileSelector !== false &&
73
+ (uploader.url || uploader.customUploadFunction)) {
74
+ tabs.push(UploadTab(jodit, data => {
75
+ run(() => {
86
76
  var _a, _b;
87
- jodit.s.restore();
88
- ((_b = (_a = jodit.o.video) === null || _a === void 0 ? void 0 : _a.defaultHandlerSuccess) !== null && _b !== void 0 ? _b : insertVideos).call(jodit, data);
89
- }, { label: 'Drop file', accept: 'video/*' }));
90
- }
91
- tabs.push({
92
- icon: 'link',
93
- name: 'Link',
94
- content: formLink.container
95
- }, {
96
- icon: 'source',
97
- name: 'Code',
98
- content: formCode.container
99
- });
100
- formLink.onSubmit(data => {
101
- var _a, _b, _c, _d;
102
- insertCode(call((_b = (_a = jodit.o.video) === null || _a === void 0 ? void 0 : _a.parseUrlToVideoEmbed) !== null && _b !== void 0 ? _b : convertMediaUrlToVideoEmbed, data.url, {
103
- width: (_c = jodit.o.video) === null || _c === void 0 ? void 0 : _c.defaultWidth,
104
- height: (_d = jodit.o.video) === null || _d === void 0 ? void 0 : _d.defaultHeight
105
- }));
106
- });
107
- formCode.onSubmit(data => {
108
- insertCode(data.code);
109
- });
110
- return TabsWidget(jodit, tabs);
111
- },
77
+ return ((_b = (_a = jodit.o.video) === null || _a === void 0 ? void 0 : _a.defaultHandlerSuccess) !== null && _b !== void 0 ? _b : insertVideos).call(jodit, data);
78
+ });
79
+ }, { label: 'Drop file', accept: 'video/*' }));
80
+ }
81
+ tabs.push({
82
+ icon: 'link',
83
+ name: 'Link',
84
+ content: formLink.container
85
+ }, {
86
+ icon: 'source',
87
+ name: 'Code',
88
+ content: formCode.container
89
+ });
90
+ formLink.onSubmit(data => {
91
+ var _a, _b, _c, _d;
92
+ insertCode(call((_b = (_a = jodit.o.video) === null || _a === void 0 ? void 0 : _a.parseUrlToVideoEmbed) !== null && _b !== void 0 ? _b : convertMediaUrlToVideoEmbed, data.url, {
93
+ width: (_c = jodit.o.video) === null || _c === void 0 ? void 0 : _c.defaultWidth,
94
+ height: (_d = jodit.o.video) === null || _d === void 0 ? void 0 : _d.defaultHeight
95
+ }));
96
+ });
97
+ formCode.onSubmit(data => {
98
+ insertCode(data.code);
99
+ });
100
+ const box = TabsWidget(jodit, tabs);
101
+ // Its tabs are sized to their labels, as the file selector's are, since
102
+ // "Upload" doesn't fit a third of the popup
103
+ box.classList.add('jodit-file-selector');
104
+ return box;
105
+ }
106
+ Config.prototype.controls.video = {
107
+ popup: (jodit, current, close) => videoTabs(jodit, close),
112
108
  tags: ['iframe'],
113
109
  tooltip: 'Insert youtube/vimeo video'
114
110
  };
@@ -0,0 +1,31 @@
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 plugins/video-properties
8
+ */
9
+ export type EditedMedia = HTMLVideoElement | HTMLAudioElement | HTMLIFrameElement;
10
+ export interface VideoPropertiesValues {
11
+ width: number | string;
12
+ height: number | string;
13
+ poster: string;
14
+ autoplay: boolean;
15
+ loop: boolean;
16
+ muted: boolean;
17
+ controls: boolean;
18
+ }
19
+ export interface VideoPropertiesState {
20
+ /**
21
+ * What the dialog was opened for: the media, or a wrapper round it
22
+ */
23
+ target: HTMLElement;
24
+ media: EditedMedia;
25
+ ratio: number;
26
+ sizeIsLocked: boolean;
27
+ values: VideoPropertiesValues;
28
+ }
29
+ export interface VideoPropertiesAPI {
30
+ openPosterPopup: (target: HTMLElement) => void;
31
+ }
@@ -0,0 +1,6 @@
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
+ export {};
@@ -0,0 +1,26 @@
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 plugins/video-properties
8
+ */
9
+ import type { Nullable } from "../../types/index";
10
+ import type { EditedMedia, VideoPropertiesState } from "./interface";
11
+ /**
12
+ * The media `target` is, or holds as its wrapper (`jodit-media`, the resizer's
13
+ * `jodit` for an embed, or one from `mediaWrappers`)
14
+ * @private
15
+ */
16
+ export declare function editedMedia(target: HTMLElement): Nullable<EditedMedia>;
17
+ /**
18
+ * The size `media` is given, inline or by its attribute
19
+ * @private
20
+ */
21
+ export declare function ownSize(media: EditedMedia, key: 'width' | 'height'): string;
22
+ /**
23
+ * Read the media's values into the state
24
+ * @private
25
+ */
26
+ export declare function readValues(state: VideoPropertiesState): void;
@@ -0,0 +1,65 @@
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
+ import { Dom } from "../../core/dom/dom.js";
7
+ import { isNumeric } from "../../core/helpers/checker/is-numeric.js";
8
+ import { attr } from "../../core/helpers/utils/attr.js";
9
+ import { cssInline } from "../../core/helpers/utils/css.js";
10
+ import { normalSizeFromString } from "../image-properties/utils/utils.js";
11
+ const mediaSelector = 'video, audio, iframe';
12
+ /**
13
+ * The media `target` is, or holds as its wrapper (`jodit-media`, the resizer's
14
+ * `jodit` for an embed, or one from `mediaWrappers`)
15
+ * @private
16
+ */
17
+ export function editedMedia(target) {
18
+ return (target.matches(mediaSelector)
19
+ ? target
20
+ : target.querySelector(mediaSelector));
21
+ }
22
+ /**
23
+ * The size `media` is given, inline or by its attribute
24
+ * @private
25
+ */
26
+ export function ownSize(media, key) {
27
+ return cssInline(media, key) || attr(media, key) || '';
28
+ }
29
+ const toNumber = (value) => parseFloat(value.toString());
30
+ /**
31
+ * Read the media's values into the state
32
+ * @private
33
+ */
34
+ export function readValues(state) {
35
+ const { media, values } = state;
36
+ const width = ownSize(media, 'width');
37
+ const height = ownSize(media, 'height');
38
+ values.width = width ? normalSizeFromString(width) : media.offsetWidth;
39
+ values.height = height ? normalSizeFromString(height) : '';
40
+ if (Dom.isTag(media, 'video') && media.videoWidth) {
41
+ state.ratio = media.videoWidth / media.videoHeight;
42
+ }
43
+ else if (isNumeric(values.width) && isNumeric(values.height)) {
44
+ state.ratio = toNumber(values.width) / toNumber(values.height);
45
+ }
46
+ else {
47
+ state.ratio = media.offsetWidth / media.offsetHeight || 1;
48
+ }
49
+ // One with no height takes it from its width
50
+ if (!height && isNumeric(values.width)) {
51
+ values.height = Math.round(toNumber(values.width) / state.ratio);
52
+ }
53
+ state.sizeIsLocked =
54
+ isNumeric(values.width) &&
55
+ isNumeric(values.height) &&
56
+ (!height ||
57
+ Math.abs(toNumber(values.width) - toNumber(values.height) * state.ratio) < 1);
58
+ values.poster = attr(media, 'poster') || '';
59
+ values.autoplay = media.hasAttribute('autoplay');
60
+ values.loop = media.hasAttribute('loop');
61
+ // Autoplay's own: turning it off gives the sound back
62
+ values.muted = media.hasAttribute('muted') && !values.autoplay;
63
+ // Without Autoplay it keeps its controls, or it could never be played
64
+ values.controls = media.hasAttribute('controls') || !values.autoplay;
65
+ }
@@ -0,0 +1,15 @@
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 plugins/video-properties
8
+ */
9
+ import type { IJodit } from "../../types/index";
10
+ /**
11
+ * Run `insert`, which inserts media at the cursor, with the cursor after
12
+ * `replaced`, and put what it inserts in place of `replaced`
13
+ * @private
14
+ */
15
+ export declare function replaceMedia(j: IJodit, replaced: HTMLElement, insert: () => void): void;
@@ -0,0 +1,97 @@
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
+ import { Dom } from "../../core/dom/dom.js";
7
+ import { attr } from "../../core/helpers/utils/attr.js";
8
+ import { css } from "../../core/helpers/utils/css.js";
9
+ import { editedMedia, ownSize, readValues } from "./readers.js";
10
+ import { applyValues } from "./writers.js";
11
+ /**
12
+ * Give `media`, in `outer`, the classes, inline styles, size and playback
13
+ * settings of `old`, in `oldOuter`. It keeps its own source and poster.
14
+ */
15
+ function takeOver(j, oldOuter, old, outer, media) {
16
+ var _a;
17
+ const state = {
18
+ target: oldOuter,
19
+ media: old,
20
+ ratio: 1,
21
+ sizeIsLocked: true,
22
+ values: {
23
+ width: '',
24
+ height: '',
25
+ poster: '',
26
+ autoplay: false,
27
+ loop: false,
28
+ muted: false,
29
+ controls: true
30
+ }
31
+ };
32
+ readValues(state);
33
+ const pairs = [[old, media]];
34
+ // A wrapper kept in the content, which holds the alignment
35
+ if (oldOuter !== old &&
36
+ outer !== media &&
37
+ oldOuter.nodeName === outer.nodeName) {
38
+ pairs.push([oldOuter, outer]);
39
+ }
40
+ pairs.forEach(([from, to]) => {
41
+ ['class', 'style'].forEach(name => attr(to, name, attr(from, name)));
42
+ });
43
+ // A video's size is CSS and an embed's its attributes, so the writer sizes
44
+ // one that's a different element
45
+ if (old.nodeName !== media.nodeName) {
46
+ css(media, { width: null, height: null });
47
+ if (!((_a = attr(media, 'style')) === null || _a === void 0 ? void 0 : _a.trim())) {
48
+ attr(media, 'style', null);
49
+ }
50
+ }
51
+ state.media = media;
52
+ state.values.poster = attr(media, 'poster') || '';
53
+ applyValues(j, state, Boolean(ownSize(old, 'width') || ownSize(old, 'height')));
54
+ }
55
+ /**
56
+ * Run `insert`, which inserts media at the cursor, with the cursor after
57
+ * `replaced`, and put what it inserts in place of `replaced`
58
+ * @private
59
+ */
60
+ export function replaceMedia(j, replaced, insert) {
61
+ const inserted = [];
62
+ const collect = (node) => {
63
+ inserted.push(node);
64
+ };
65
+ j.history.snapshot.transaction(() => {
66
+ j.s.focus();
67
+ j.s.setCursorAfter(replaced);
68
+ j.e.on('afterInsertNode', collect);
69
+ try {
70
+ insert();
71
+ }
72
+ finally {
73
+ j.e.off('afterInsertNode', collect);
74
+ }
75
+ const [outer] = inserted;
76
+ if (!Dom.isHTMLElement(outer)) {
77
+ return;
78
+ }
79
+ const old = editedMedia(replaced);
80
+ const media = editedMedia(outer);
81
+ if (old && media) {
82
+ takeOver(j, replaced, old, outer, media);
83
+ }
84
+ // The resizer can have put an embed in its own wrapper already
85
+ const placed = Dom.isHTMLElement(outer.parentElement) &&
86
+ attr(outer.parentElement, 'data-jodit-temp')
87
+ ? outer.parentElement
88
+ : outer;
89
+ // Where the old one was, since media Jodit counts as blocks can be put
90
+ // after the paragraph
91
+ Dom.before(replaced, placed);
92
+ Dom.safeRemove(replaced);
93
+ j.s.setCursorAfter(placed);
94
+ });
95
+ j.synchronizeValues();
96
+ j.e.fire('closeAllPopups');
97
+ }
@@ -0,0 +1,41 @@
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 plugins/video-properties
8
+ */
9
+ import type { IJodit } from "../../../types/index";
10
+ import { UIElement } from "../../../core/ui/element";
11
+ import type { VideoPropertiesAPI, VideoPropertiesState } from "../interface";
12
+ /** @private */
13
+ export declare class UIVideoPropertiesForm extends UIElement<IJodit> {
14
+ private state;
15
+ private handlers;
16
+ className(): string;
17
+ constructor(jodit: IJodit, state: VideoPropertiesState, handlers: VideoPropertiesAPI);
18
+ protected render(): string;
19
+ private input;
20
+ private show;
21
+ /**
22
+ * A video has every field, an embed only its size, and audio only its
23
+ * playback settings
24
+ */
25
+ protected onStateMediaChange(): void;
26
+ private showPreview;
27
+ protected hideChangePoster(): void;
28
+ protected onStatePosterChange(): void;
29
+ protected onPosterChange(): void;
30
+ protected onChangePosterClick(e: MouseEvent): void;
31
+ protected onRemovePosterClick(): void;
32
+ protected onStateSizeIsLockedChange(): void;
33
+ protected onLockSizeClick(): void;
34
+ protected onStateSizeChange(): void;
35
+ protected onSizeInput(e: Event): void;
36
+ /**
37
+ * Autoplay mutes it, and it keeps its controls unless it autoplays
38
+ */
39
+ protected onStateFlagsChange(): void;
40
+ protected onFlagChange(e: Event): void;
41
+ }