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.
- package/CHANGELOG.md +41 -0
- package/es2015/jodit.css +66 -6
- package/es2015/jodit.fat.min.css +1 -1
- package/es2015/jodit.fat.min.js +36 -11
- package/es2015/jodit.js +1435 -327
- package/es2015/jodit.min.css +1 -1
- package/es2015/jodit.min.js +41 -16
- package/es2015/plugins/debug/debug.css +1 -1
- package/es2015/plugins/debug/debug.js +1 -1
- package/es2015/plugins/debug/debug.min.js +1 -1
- package/es2015/plugins/speech-recognize/speech-recognize.css +1 -1
- package/es2015/plugins/speech-recognize/speech-recognize.js +1 -1
- package/es2015/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es2018/jodit.fat.min.css +1 -1
- package/es2018/jodit.fat.min.js +36 -11
- package/es2018/jodit.min.css +1 -1
- package/es2018/jodit.min.js +36 -11
- package/es2018/plugins/debug/debug.min.js +1 -1
- package/es2018/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es2021/jodit.css +66 -6
- package/es2021/jodit.fat.min.css +1 -1
- package/es2021/jodit.fat.min.js +45 -20
- package/es2021/jodit.js +1365 -271
- package/es2021/jodit.min.css +1 -1
- package/es2021/jodit.min.js +45 -20
- package/es2021/plugins/debug/debug.css +1 -1
- package/es2021/plugins/debug/debug.js +1 -1
- package/es2021/plugins/debug/debug.min.js +1 -1
- package/es2021/plugins/speech-recognize/speech-recognize.css +1 -1
- package/es2021/plugins/speech-recognize/speech-recognize.js +1 -1
- package/es2021/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es2021.en/jodit.css +66 -6
- package/es2021.en/jodit.fat.min.css +1 -1
- package/es2021.en/jodit.fat.min.js +51 -26
- package/es2021.en/jodit.js +1339 -245
- package/es2021.en/jodit.min.css +1 -1
- package/es2021.en/jodit.min.js +51 -26
- package/es2021.en/plugins/debug/debug.css +1 -1
- package/es2021.en/plugins/debug/debug.js +1 -1
- package/es2021.en/plugins/debug/debug.min.js +1 -1
- package/es2021.en/plugins/speech-recognize/speech-recognize.css +1 -1
- package/es2021.en/plugins/speech-recognize/speech-recognize.js +1 -1
- package/es2021.en/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es5/jodit.css +82 -7
- package/es5/jodit.fat.min.css +1 -1
- package/es5/jodit.fat.min.js +2 -2
- package/es5/jodit.js +1629 -354
- package/es5/jodit.min.css +3 -3
- package/es5/jodit.min.js +2 -2
- package/es5/plugins/debug/debug.css +1 -1
- package/es5/plugins/debug/debug.js +1 -1
- package/es5/plugins/debug/debug.min.js +1 -1
- package/es5/plugins/speech-recognize/speech-recognize.css +1 -1
- package/es5/plugins/speech-recognize/speech-recognize.js +1 -1
- package/es5/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es5/polyfills.fat.min.js +1 -1
- package/es5/polyfills.js +1 -1
- package/es5/polyfills.min.js +1 -1
- package/esm/config.d.ts +29 -28
- package/esm/config.js +19 -21
- package/esm/core/constants.js +1 -1
- package/esm/core/helpers/utils/align.d.ts +1 -1
- package/esm/core/helpers/utils/align.js +2 -3
- package/esm/core/helpers/utils/index.d.ts +1 -0
- package/esm/core/helpers/utils/index.js +1 -0
- package/esm/core/helpers/utils/prepare-media.d.ts +19 -0
- package/esm/core/helpers/utils/prepare-media.js +31 -0
- package/esm/core/selection/style/api/wrap-unwrapped-text.js +3 -2
- package/esm/jodit.js +14 -4
- package/esm/langs/ar.d.ts +7 -0
- package/esm/langs/ar.js +8 -1
- package/esm/langs/az.d.ts +7 -0
- package/esm/langs/az.js +8 -1
- package/esm/langs/cs_cz.d.ts +7 -0
- package/esm/langs/cs_cz.js +9 -1
- package/esm/langs/de.d.ts +7 -0
- package/esm/langs/de.js +8 -1
- package/esm/langs/es.d.ts +7 -0
- package/esm/langs/es.js +8 -1
- package/esm/langs/fa.d.ts +7 -0
- package/esm/langs/fa.js +8 -1
- package/esm/langs/fi.d.ts +7 -0
- package/esm/langs/fi.js +8 -1
- package/esm/langs/fr.d.ts +7 -0
- package/esm/langs/fr.js +8 -1
- package/esm/langs/he.d.ts +7 -0
- package/esm/langs/he.js +8 -1
- package/esm/langs/hu.d.ts +7 -0
- package/esm/langs/hu.js +8 -1
- package/esm/langs/id.d.ts +7 -0
- package/esm/langs/id.js +8 -1
- package/esm/langs/it.d.ts +7 -0
- package/esm/langs/it.js +8 -1
- package/esm/langs/ja.d.ts +7 -0
- package/esm/langs/ja.js +8 -1
- package/esm/langs/ko.d.ts +7 -0
- package/esm/langs/ko.js +8 -1
- package/esm/langs/mn.d.ts +7 -0
- package/esm/langs/mn.js +8 -1
- package/esm/langs/nl.d.ts +7 -0
- package/esm/langs/nl.js +8 -1
- package/esm/langs/no.d.ts +7 -0
- package/esm/langs/no.js +8 -1
- package/esm/langs/pl.d.ts +7 -0
- package/esm/langs/pl.js +8 -1
- package/esm/langs/pt_br.d.ts +7 -0
- package/esm/langs/pt_br.js +8 -1
- package/esm/langs/ru.d.ts +7 -0
- package/esm/langs/ru.js +8 -1
- package/esm/langs/sk.d.ts +7 -0
- package/esm/langs/sk.js +8 -1
- package/esm/langs/sv.d.ts +7 -0
- package/esm/langs/sv.js +8 -1
- package/esm/langs/tr.d.ts +7 -0
- package/esm/langs/tr.js +8 -1
- package/esm/langs/ua.d.ts +7 -0
- package/esm/langs/ua.js +8 -1
- package/esm/langs/zh_cn.d.ts +7 -0
- package/esm/langs/zh_cn.js +8 -1
- package/esm/langs/zh_tw.d.ts +7 -0
- package/esm/langs/zh_tw.js +8 -1
- package/esm/modules/history/history.d.ts +17 -2
- package/esm/modules/history/history.js +41 -19
- package/esm/modules/table/table.js +7 -2
- package/esm/modules/widget/file-selector/file-selector.js +2 -2
- package/esm/plugins/all.d.ts +1 -0
- package/esm/plugins/all.js +1 -0
- package/esm/plugins/backspace/backspace.js +4 -0
- package/esm/plugins/clean-html/clean-html.d.ts +7 -0
- package/esm/plugins/clean-html/clean-html.js +17 -0
- package/esm/plugins/clean-html/helpers/visitor/filters/replace-old-tags.js +26 -1
- package/esm/plugins/dtd/before-insert/check-block-nesting.d.ts +2 -1
- package/esm/plugins/dtd/before-insert/check-block-nesting.js +26 -5
- package/esm/plugins/enter/helpers/move-cursor-out-from-specal-tags.js +8 -0
- package/esm/plugins/focus/focus.js +3 -0
- package/esm/plugins/hr/hr.js +21 -5
- package/esm/plugins/iframe/config.js +8 -3
- package/esm/plugins/image-processor/image-processor.d.ts +4 -1
- package/esm/plugins/image-processor/image-processor.js +9 -3
- package/esm/plugins/image-properties/readers/align.d.ts +2 -2
- package/esm/plugins/index.d.ts +1 -0
- package/esm/plugins/inline-popup/config/items/iframe.d.ts +9 -1
- package/esm/plugins/inline-popup/config/items/iframe.js +15 -0
- package/esm/plugins/inline-popup/inline-popup.d.ts +5 -0
- package/esm/plugins/inline-popup/inline-popup.js +26 -2
- package/esm/plugins/link/link.js +5 -2
- package/esm/plugins/media/config.d.ts +2 -1
- package/esm/plugins/media/media.js +37 -9
- package/esm/plugins/paste/helpers.d.ts +8 -0
- package/esm/plugins/paste/helpers.js +18 -1
- package/esm/plugins/paste/paste.js +2 -2
- package/esm/plugins/resizer/config.d.ts +5 -3
- package/esm/plugins/resizer/config.js +8 -2
- package/esm/plugins/resizer/resizer.d.ts +10 -0
- package/esm/plugins/resizer/resizer.js +72 -18
- package/esm/plugins/select-cells/select-cells.d.ts +10 -0
- package/esm/plugins/select-cells/select-cells.js +54 -6
- package/esm/plugins/table/config.js +51 -1
- package/esm/plugins/table-keyboard-navigation/table-keyboard-navigation.js +1 -1
- package/esm/plugins/video/config.d.ts +6 -0
- package/esm/plugins/video/config.js +78 -82
- package/esm/plugins/video-properties/interface.d.ts +31 -0
- package/esm/plugins/video-properties/interface.js +6 -0
- package/esm/plugins/video-properties/readers.d.ts +26 -0
- package/esm/plugins/video-properties/readers.js +65 -0
- package/esm/plugins/video-properties/replace.d.ts +15 -0
- package/esm/plugins/video-properties/replace.js +97 -0
- package/esm/plugins/video-properties/ui/ui-video-form.d.ts +41 -0
- package/esm/plugins/video-properties/ui/ui-video-form.js +228 -0
- package/esm/plugins/video-properties/video-properties.d.ts +37 -0
- package/esm/plugins/video-properties/video-properties.js +175 -0
- package/esm/plugins/video-properties/writers.d.ts +15 -0
- package/esm/plugins/video-properties/writers.js +73 -0
- package/esm/types/types.d.ts +1 -1
- package/package.json +1 -1
- package/types/config.d.ts +29 -28
- package/types/core/helpers/utils/align.d.ts +1 -1
- package/types/core/helpers/utils/index.d.ts +1 -0
- package/types/core/helpers/utils/prepare-media.d.ts +19 -0
- package/types/langs/ar.d.ts +7 -0
- package/types/langs/az.d.ts +7 -0
- package/types/langs/cs_cz.d.ts +7 -0
- package/types/langs/de.d.ts +7 -0
- package/types/langs/es.d.ts +7 -0
- package/types/langs/fa.d.ts +7 -0
- package/types/langs/fi.d.ts +7 -0
- package/types/langs/fr.d.ts +7 -0
- package/types/langs/he.d.ts +7 -0
- package/types/langs/hu.d.ts +7 -0
- package/types/langs/id.d.ts +7 -0
- package/types/langs/it.d.ts +7 -0
- package/types/langs/ja.d.ts +7 -0
- package/types/langs/ko.d.ts +7 -0
- package/types/langs/mn.d.ts +7 -0
- package/types/langs/nl.d.ts +7 -0
- package/types/langs/no.d.ts +7 -0
- package/types/langs/pl.d.ts +7 -0
- package/types/langs/pt_br.d.ts +7 -0
- package/types/langs/ru.d.ts +7 -0
- package/types/langs/sk.d.ts +7 -0
- package/types/langs/sv.d.ts +7 -0
- package/types/langs/tr.d.ts +7 -0
- package/types/langs/ua.d.ts +7 -0
- package/types/langs/zh_cn.d.ts +7 -0
- package/types/langs/zh_tw.d.ts +7 -0
- package/types/modules/history/history.d.ts +17 -2
- package/types/plugins/clean-html/clean-html.d.ts +7 -0
- package/types/plugins/dtd/before-insert/check-block-nesting.d.ts +2 -1
- package/types/plugins/image-processor/image-processor.d.ts +4 -1
- package/types/plugins/image-properties/readers/align.d.ts +2 -2
- package/types/plugins/index.d.ts +1 -0
- package/types/plugins/inline-popup/config/items/iframe.d.ts +9 -1
- package/types/plugins/inline-popup/inline-popup.d.ts +5 -0
- package/types/plugins/media/config.d.ts +2 -1
- package/types/plugins/paste/helpers.d.ts +8 -0
- package/types/plugins/resizer/config.d.ts +5 -3
- package/types/plugins/resizer/resizer.d.ts +10 -0
- package/types/plugins/select-cells/select-cells.d.ts +10 -0
- package/types/plugins/video/config.d.ts +6 -0
- package/types/plugins/video-properties/interface.d.ts +31 -0
- package/types/plugins/video-properties/readers.d.ts +26 -0
- package/types/plugins/video-properties/replace.d.ts +15 -0
- package/types/plugins/video-properties/ui/ui-video-form.d.ts +41 -0
- package/types/plugins/video-properties/video-properties.d.ts +37 -0
- package/types/plugins/video-properties/writers.d.ts +15 -0
- package/types/types/types.d.ts +1 -1
package/esm/plugins/link/link.js
CHANGED
|
@@ -16,7 +16,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
16
16
|
import { autobind } from "../../core/decorators/index.js";
|
|
17
17
|
import { Dom } from "../../core/dom/index.js";
|
|
18
18
|
import { pluginSystem } from "../../core/global.js";
|
|
19
|
-
import { attr, call, convertMediaUrlToVideoEmbed, isString, isURL, refs, stripTags } from "../../core/helpers/index.js";
|
|
19
|
+
import { attr, call, convertMediaUrlToVideoEmbed, isString, isURL, prepareEmbedCode, refs, stripTags } from "../../core/helpers/index.js";
|
|
20
20
|
import { Plugin } from "../../core/plugin/index.js";
|
|
21
21
|
import "./config.js";
|
|
22
22
|
/**
|
|
@@ -85,7 +85,10 @@ export class link extends Plugin {
|
|
|
85
85
|
height: (_d = jodit.o.video) === null || _d === void 0 ? void 0 : _d.defaultHeight
|
|
86
86
|
});
|
|
87
87
|
if (embed !== html) {
|
|
88
|
-
|
|
88
|
+
const media = prepareEmbedCode(jodit, embed);
|
|
89
|
+
return isString(media)
|
|
90
|
+
? jodit.createInside.fromHTML(media)
|
|
91
|
+
: media;
|
|
89
92
|
}
|
|
90
93
|
}
|
|
91
94
|
if (jodit.s.isCollapsed()) {
|
|
@@ -28,7 +28,8 @@ declare module 'jodit/config' {
|
|
|
28
28
|
* - is wrapped in it instead of the editor-only `mediaFakeTag` when its tag
|
|
29
29
|
* is one of `mediaBlocks`, or left in it when it's already in one
|
|
30
30
|
* - goes in inside it when the video popup inserts it, as an upload, a
|
|
31
|
-
* link's embed or embed code that is one element
|
|
31
|
+
* link's embed or embed code that is one element, and when a pasted
|
|
32
|
+
* video link is turned into its embed
|
|
32
33
|
* - opens the media popup for its wrapper when clicked, whose Align and
|
|
33
34
|
* Delete act on the wrapper
|
|
34
35
|
*
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import * as consts from "../../core/constants.js";
|
|
7
7
|
import { Dom } from "../../core/dom/dom.js";
|
|
8
|
-
import { pluginSystem } from "../../core/global.js";
|
|
8
|
+
import { getContainer, pluginSystem } from "../../core/global.js";
|
|
9
9
|
import { $$, attr, dataBind, getMediaWrapper, wrapMedia } from "../../core/helpers/utils/index.js";
|
|
10
10
|
import { css, cssInline } from "../../core/helpers/utils/css.js";
|
|
11
11
|
import "./config.js";
|
|
@@ -26,6 +26,7 @@ export function media(editor) {
|
|
|
26
26
|
(_a = getMediaWrapper(editor, element)) !== null && _a !== void 0 ? _a : wrapMedia(editor, element);
|
|
27
27
|
}
|
|
28
28
|
else if (mediaInFakeBlock) {
|
|
29
|
+
const media = element;
|
|
29
30
|
const wrapper = editor.createInside.element(mediaFakeTag, {
|
|
30
31
|
'data-jodit-temp': 1,
|
|
31
32
|
contenteditable: false,
|
|
@@ -33,13 +34,21 @@ export function media(editor) {
|
|
|
33
34
|
[`data-${keyFake}`]: 1
|
|
34
35
|
});
|
|
35
36
|
attr(wrapper, 'style', attr(element, 'style'));
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
// The wrapper fits the media, whose size changes as its metadata loads
|
|
38
|
+
// and as it's resized. A percentage width is of the line, so it takes that
|
|
39
|
+
const fit = () => {
|
|
40
|
+
css(wrapper, {
|
|
41
|
+
display: cssInline(media, 'display') === 'inline-block'
|
|
42
|
+
? 'inline-block'
|
|
43
|
+
: 'block',
|
|
44
|
+
width: cssInline(media, 'width').endsWith('%')
|
|
45
|
+
? ''
|
|
46
|
+
: 'fit-content',
|
|
47
|
+
height: ''
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
fit();
|
|
51
|
+
editor.e.on(media, 'changesize', fit);
|
|
43
52
|
if (element.parentNode) {
|
|
44
53
|
Dom.before(element, wrapper);
|
|
45
54
|
}
|
|
@@ -49,12 +58,31 @@ export function media(editor) {
|
|
|
49
58
|
else {
|
|
50
59
|
return;
|
|
51
60
|
}
|
|
61
|
+
// Selected, as an image is, so Delete and Backspace remove it
|
|
52
62
|
editor.e
|
|
53
63
|
.off(element, 'mousedown.select touchstart.select')
|
|
54
64
|
.on(element, 'mousedown.select touchstart.select', () => {
|
|
55
|
-
editor.s.
|
|
65
|
+
editor.s.select(element);
|
|
56
66
|
});
|
|
57
67
|
};
|
|
68
|
+
// Media in a wrapper kept in the content let clicks through to it, as
|
|
69
|
+
// jodit-media covers its media, so a click selects the media rather than
|
|
70
|
+
// playing it. An inline wrapper holds it as an inline-block, unless its
|
|
71
|
+
// classes or style give it a display of their own
|
|
72
|
+
const wrappers = Object.values(mediaWrappers);
|
|
73
|
+
if (wrappers.length) {
|
|
74
|
+
editor.e.on('afterInit', () => {
|
|
75
|
+
const selectors = (list) => [...new Set(list)].join(',');
|
|
76
|
+
const scoped = ({ tag, className }) => `.jodit-wysiwyg ${tag}.${className}`;
|
|
77
|
+
const inline = selectors(wrappers
|
|
78
|
+
.filter(({ tag }) => consts.IS_INLINE.test(tag))
|
|
79
|
+
.map(scoped));
|
|
80
|
+
const media = selectors(wrappers.flatMap(wrapper => mediaBlocks.map(tag => `${scoped(wrapper)}>${tag}`)));
|
|
81
|
+
getContainer(editor, 'media-wrappers', 'style', true).innerHTML =
|
|
82
|
+
(inline ? `:where(${inline}){display:inline-block}` : '') +
|
|
83
|
+
`${media}{pointer-events:none}`;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
58
86
|
if (mediaInFakeBlock || Object.keys(mediaWrappers).length) {
|
|
59
87
|
editor.e
|
|
60
88
|
.on('afterGetValueFromEditor', (data) => {
|
|
@@ -8,6 +8,14 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { IDialog, IJodit, InsertMode, IUIOption, Nullable } from "../../types/index";
|
|
10
10
|
import type { PasteEvent } from "./interface";
|
|
11
|
+
/**
|
|
12
|
+
* Google Docs wraps the copied content in
|
|
13
|
+
* `<b style="font-weight:normal;" id="docs-internal-guid-…">`. Kept, the
|
|
14
|
+
* wrapper holds the pasted blocks, and without its style it makes the whole
|
|
15
|
+
* paste bold
|
|
16
|
+
* @private
|
|
17
|
+
*/
|
|
18
|
+
export declare function removeGoogleDocsWrapper(html: string): string;
|
|
11
19
|
/**
|
|
12
20
|
* One insert point for clipboard plugins
|
|
13
21
|
* @private
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { TEXT_PLAIN } from "../../core/constants.js";
|
|
7
7
|
import { Dom } from "../../core/dom/dom.js";
|
|
8
|
+
import { toArray } from "../../core/helpers/array/to-array.js";
|
|
8
9
|
import { isArray, isNumber, isString, isVoid } from "../../core/helpers/checker/index.js";
|
|
9
10
|
import { Button } from "../../core/ui/button/button/button.js";
|
|
10
11
|
/**
|
|
@@ -23,6 +24,22 @@ function removeExtraFragments(html) {
|
|
|
23
24
|
}
|
|
24
25
|
return html;
|
|
25
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Google Docs wraps the copied content in
|
|
29
|
+
* `<b style="font-weight:normal;" id="docs-internal-guid-…">`. Kept, the
|
|
30
|
+
* wrapper holds the pasted blocks, and without its style it makes the whole
|
|
31
|
+
* paste bold
|
|
32
|
+
* @private
|
|
33
|
+
*/
|
|
34
|
+
export function removeGoogleDocsWrapper(html) {
|
|
35
|
+
if (!/<b\s[^>]*docs-internal-guid-/i.test(html)) {
|
|
36
|
+
return html;
|
|
37
|
+
}
|
|
38
|
+
// An inert document: images don't load and handlers don't run
|
|
39
|
+
const { body } = new DOMParser().parseFromString(html, 'text/html');
|
|
40
|
+
toArray(body.querySelectorAll('b[id^="docs-internal-guid-"]')).forEach(Dom.unwrap);
|
|
41
|
+
return body.innerHTML;
|
|
42
|
+
}
|
|
26
43
|
/**
|
|
27
44
|
* @private
|
|
28
45
|
*/
|
|
@@ -46,7 +63,7 @@ export function pasteInsertHtml(e, editor, html) {
|
|
|
46
63
|
html = result;
|
|
47
64
|
}
|
|
48
65
|
if (isString(html)) {
|
|
49
|
-
html = removeExtraFragments(html);
|
|
66
|
+
html = removeExtraFragments(removeGoogleDocsWrapper(html));
|
|
50
67
|
}
|
|
51
68
|
editor.s.insertHTML(html);
|
|
52
69
|
}
|
|
@@ -20,7 +20,7 @@ import { pluginSystem } from "../../core/global.js";
|
|
|
20
20
|
import { cleanFromWord, getDataTransfer, htmlspecialchars, isHTML, isString, LimitedStack, nl2br, stripTags, trim } from "../../core/helpers/index.js";
|
|
21
21
|
import { Plugin } from "../../core/plugin/plugin.js";
|
|
22
22
|
import "./config.js";
|
|
23
|
-
import { askInsertTypeDialog, getAllTypes, pasteInsertHtml } from "./helpers.js";
|
|
23
|
+
import { askInsertTypeDialog, getAllTypes, pasteInsertHtml, removeGoogleDocsWrapper } from "./helpers.js";
|
|
24
24
|
/**
|
|
25
25
|
* Ask before paste HTML source
|
|
26
26
|
*/
|
|
@@ -143,7 +143,7 @@ export class paste extends Plugin {
|
|
|
143
143
|
this.j.buffer.set(CLIPBOARD_ID, html);
|
|
144
144
|
switch (action) {
|
|
145
145
|
case INSERT_CLEAR_HTML:
|
|
146
|
-
html = cleanFromWord(html);
|
|
146
|
+
html = cleanFromWord(removeGoogleDocsWrapper(html));
|
|
147
147
|
break;
|
|
148
148
|
case INSERT_ONLY_TEXT:
|
|
149
149
|
html = stripTags(html, this.j.ed, new Set(this.j.o.pasteExcludeStripTags), this.j.o.nl2brInPlainText);
|
|
@@ -10,7 +10,7 @@ import type { HTMLTagNames } from "../../types/index";
|
|
|
10
10
|
declare module 'jodit/config' {
|
|
11
11
|
interface Config {
|
|
12
12
|
/**
|
|
13
|
-
* Set of HTML tag names whose elements can be resized by the user via drag handles (e.g. images, iframes, tables)
|
|
13
|
+
* Set of HTML tag names whose elements can be resized by the user via drag handles (e.g. images, iframes, tables, videos)
|
|
14
14
|
*/
|
|
15
15
|
allowResizeTags: Set<HTMLTagNames>;
|
|
16
16
|
resizer: {
|
|
@@ -23,14 +23,16 @@ declare module 'jodit/config' {
|
|
|
23
23
|
* Save width and height proportions when resizing
|
|
24
24
|
* ```js
|
|
25
25
|
* Jodit.make('#editor', {
|
|
26
|
-
* allowResizeTags: ['img', 'iframe', 'table', 'jodit'],
|
|
26
|
+
* allowResizeTags: new Set(['img', 'iframe', 'table', 'jodit', 'video']),
|
|
27
27
|
* resizer: {
|
|
28
28
|
* useAspectRatio: false, // don't save,
|
|
29
|
-
* useAspectRatio: ['img'], // save only for images
|
|
29
|
+
* useAspectRatio: new Set(['img']), // save only for images
|
|
30
30
|
* useAspectRatio: true // save for all
|
|
31
31
|
* }
|
|
32
32
|
* });
|
|
33
33
|
* ```
|
|
34
|
+
* Images and videos keep it by default. A video with no height of its
|
|
35
|
+
* own keeps it by being given only a width.
|
|
34
36
|
*/
|
|
35
37
|
useAspectRatio: boolean | Set<HTMLTagNames>;
|
|
36
38
|
/**
|
|
@@ -4,12 +4,18 @@
|
|
|
4
4
|
* Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
5
|
*/
|
|
6
6
|
import { Config } from "../../config.js";
|
|
7
|
-
Config.prototype.allowResizeTags = new Set([
|
|
7
|
+
Config.prototype.allowResizeTags = new Set([
|
|
8
|
+
'img',
|
|
9
|
+
'iframe',
|
|
10
|
+
'table',
|
|
11
|
+
'jodit',
|
|
12
|
+
'video'
|
|
13
|
+
]);
|
|
8
14
|
Config.prototype.resizer = {
|
|
9
15
|
showSize: true,
|
|
10
16
|
hideSizeTimeout: 1000,
|
|
11
17
|
forImageChangeAttributes: true,
|
|
12
18
|
min_width: 10,
|
|
13
19
|
min_height: 10,
|
|
14
|
-
useAspectRatio: new Set(['img'])
|
|
20
|
+
useAspectRatio: new Set(['img', 'video'])
|
|
15
21
|
};
|
|
@@ -26,6 +26,7 @@ export declare class resizer extends Plugin {
|
|
|
26
26
|
private height;
|
|
27
27
|
private ratio;
|
|
28
28
|
private rect;
|
|
29
|
+
private layer;
|
|
29
30
|
private sizeViewer;
|
|
30
31
|
/** @override */
|
|
31
32
|
protected afterInit(editor: IJodit): void;
|
|
@@ -33,6 +34,11 @@ export declare class resizer extends Plugin {
|
|
|
33
34
|
* Click in the editor area
|
|
34
35
|
*/
|
|
35
36
|
protected onEditorClick(e: MouseEvent): void;
|
|
37
|
+
/**
|
|
38
|
+
* What a click on `node` resizes: the media in it when it's a media
|
|
39
|
+
* wrapper (`jodit-media`, or one from `mediaWrappers`), or `node` itself
|
|
40
|
+
*/
|
|
41
|
+
private __resizable;
|
|
36
42
|
protected __afterInsertImage(image: HTMLImageElement): void;
|
|
37
43
|
private addEventListeners;
|
|
38
44
|
private onStartResizing;
|
|
@@ -46,6 +52,10 @@ export declare class resizer extends Plugin {
|
|
|
46
52
|
private onClickOutside;
|
|
47
53
|
private getWorkplacePosition;
|
|
48
54
|
private applySize;
|
|
55
|
+
/**
|
|
56
|
+
* The framed element can go with a wrapper round it, keeping its parent
|
|
57
|
+
*/
|
|
58
|
+
private get isElementInEditor();
|
|
49
59
|
private onDelete;
|
|
50
60
|
private __onChangeEditor;
|
|
51
61
|
/**
|
|
@@ -18,7 +18,7 @@ import { IS_ES_NEXT, IS_IE, KEY_ALT } from "../../core/constants.js";
|
|
|
18
18
|
import { autobind, watch } from "../../core/decorators/index.js";
|
|
19
19
|
import { Dom } from "../../core/dom/dom.js";
|
|
20
20
|
import { eventEmitter, pluginSystem } from "../../core/global.js";
|
|
21
|
-
import { $$, attr, css, dataBind, innerWidth, markOwner, offset } from "../../core/helpers/index.js";
|
|
21
|
+
import { $$, attr, css, dataBind, getWrappedMedia, innerWidth, markOwner, offset } from "../../core/helpers/index.js";
|
|
22
22
|
import { cssInline } from "../../core/helpers/utils/css.js";
|
|
23
23
|
import { Plugin } from "../../core/plugin/plugin.js";
|
|
24
24
|
import "./config.js";
|
|
@@ -36,6 +36,15 @@ function attrPixelSize(element, key) {
|
|
|
36
36
|
}
|
|
37
37
|
return parseFloat(value);
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* A video with no height of its own takes it from its width and its ratio,
|
|
41
|
+
* so resizing it keeps the ratio without setting a height.
|
|
42
|
+
*/
|
|
43
|
+
function heightFollowsWidth(element) {
|
|
44
|
+
return (Dom.isTag(element, 'video') &&
|
|
45
|
+
!attr(element, 'height') &&
|
|
46
|
+
!cssInline(element, 'height'));
|
|
47
|
+
}
|
|
39
48
|
/**
|
|
40
49
|
* The module creates a supporting frame for resizing of the elements img and table
|
|
41
50
|
*/
|
|
@@ -58,6 +67,8 @@ export class resizer extends Plugin {
|
|
|
58
67
|
<div class="jodit-resizer__bottom-left"></div>
|
|
59
68
|
<span>100x100</span>
|
|
60
69
|
</div>`);
|
|
70
|
+
// Clips the frame to the workplace, without the frame making it scroll
|
|
71
|
+
this.layer = this.j.c.div('jodit-resizer-layer');
|
|
61
72
|
this.sizeViewer = this.rect.getElementsByTagName('span')[0];
|
|
62
73
|
this.pointerX = 0;
|
|
63
74
|
this.pointerY = 0;
|
|
@@ -72,6 +83,10 @@ export class resizer extends Plugin {
|
|
|
72
83
|
if (Dom.isTag(this.element, 'img') && !this.element.complete) {
|
|
73
84
|
this.j.e.one(this.element, 'load', this.updateSize);
|
|
74
85
|
}
|
|
86
|
+
if (Dom.isTag(this.element, 'video') &&
|
|
87
|
+
this.element.readyState < HTMLMediaElement.HAVE_METADATA) {
|
|
88
|
+
this.j.e.one(this.element, 'loadedmetadata', this.updateSize);
|
|
89
|
+
}
|
|
75
90
|
}
|
|
76
91
|
};
|
|
77
92
|
this.updateSize = () => {
|
|
@@ -135,14 +150,33 @@ export class resizer extends Plugin {
|
|
|
135
150
|
let node = e.target;
|
|
136
151
|
const { editor, options: { allowResizeTags } } = this.j;
|
|
137
152
|
while (node && node !== editor) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
this.
|
|
153
|
+
const element = this.__resizable(node);
|
|
154
|
+
if (Dom.isTag(element, allowResizeTags)) {
|
|
155
|
+
this.__bind(element);
|
|
156
|
+
this.onClickElement(element);
|
|
141
157
|
return;
|
|
142
158
|
}
|
|
143
159
|
node = node.parentNode;
|
|
144
160
|
}
|
|
145
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* What a click on `node` resizes: the media in it when it's a media
|
|
164
|
+
* wrapper (`jodit-media`, or one from `mediaWrappers`), or `node` itself
|
|
165
|
+
*/
|
|
166
|
+
__resizable(node) {
|
|
167
|
+
var _a;
|
|
168
|
+
const media = (_a = getWrappedMedia(this.j, node)) !== null && _a !== void 0 ? _a : (Dom.isHTMLElement(node) && attr(node, 'data-jodit_fake_wrapper')
|
|
169
|
+
? node.firstElementChild
|
|
170
|
+
: null);
|
|
171
|
+
if (!media) {
|
|
172
|
+
return node;
|
|
173
|
+
}
|
|
174
|
+
// An embed is resized through its own wrapper
|
|
175
|
+
return Dom.isHTMLElement(media.parentNode) &&
|
|
176
|
+
attr(media.parentNode, 'data-jodit_iframe_wrapper')
|
|
177
|
+
? media.parentNode
|
|
178
|
+
: media;
|
|
179
|
+
}
|
|
146
180
|
__afterInsertImage(image) {
|
|
147
181
|
if (this.j.o.resizer.forImageChangeAttributes) {
|
|
148
182
|
return;
|
|
@@ -160,7 +194,8 @@ export class resizer extends Plugin {
|
|
|
160
194
|
.off(editor.ow, '.resizer')
|
|
161
195
|
.on(editor.editor, 'keydown.resizer', (e) => {
|
|
162
196
|
if (this.isShown &&
|
|
163
|
-
e.key === consts.KEY_DELETE
|
|
197
|
+
(e.key === consts.KEY_DELETE ||
|
|
198
|
+
e.key === consts.KEY_BACKSPACE) &&
|
|
164
199
|
this.element &&
|
|
165
200
|
!Dom.isTag(this.element, 'table')) {
|
|
166
201
|
this.onDelete(e);
|
|
@@ -168,17 +203,15 @@ export class resizer extends Plugin {
|
|
|
168
203
|
})
|
|
169
204
|
.on(editor.ow, 'resize.resizer', this.updateSize)
|
|
170
205
|
.on('resize.resizer', this.updateSize)
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
})
|
|
206
|
+
// The frame is outside the content, so it's moved to follow the
|
|
207
|
+
// element as the content scrolls
|
|
208
|
+
.on([editor.ow, editor.editor], 'scroll.resizer', this.updateSize)
|
|
176
209
|
.on(editor.ow, 'keydown.resizer', this.onKeyDown)
|
|
177
210
|
.on(editor.ow, 'keyup.resizer', this.onKeyUp)
|
|
178
211
|
.on(editor.ow, 'mouseup.resizer touchend.resizer', this.onClickOutside);
|
|
179
212
|
}
|
|
180
213
|
onStartResizing(resizeHandle, e) {
|
|
181
|
-
if (!this.element || !this.
|
|
214
|
+
if (!this.element || !this.isElementInEditor) {
|
|
182
215
|
this.hide();
|
|
183
216
|
return false;
|
|
184
217
|
}
|
|
@@ -232,8 +265,9 @@ export class resizer extends Plugin {
|
|
|
232
265
|
const className = this.handle.className;
|
|
233
266
|
let new_w, new_h;
|
|
234
267
|
const uar = this.j.o.resizer.useAspectRatio;
|
|
235
|
-
|
|
236
|
-
(uar === true || (uar && Dom.isTag(this.element, uar)))
|
|
268
|
+
const keepRatio = !this.isAltMode &&
|
|
269
|
+
(uar === true || Boolean(uar && Dom.isTag(this.element, uar)));
|
|
270
|
+
if (keepRatio) {
|
|
237
271
|
if (diff_x) {
|
|
238
272
|
new_w =
|
|
239
273
|
this.width +
|
|
@@ -265,7 +299,8 @@ export class resizer extends Plugin {
|
|
|
265
299
|
this.applySize(this.element, 'width', '100%');
|
|
266
300
|
}
|
|
267
301
|
}
|
|
268
|
-
if (new_h > this.j.o.resizer.min_height
|
|
302
|
+
if (new_h > this.j.o.resizer.min_height &&
|
|
303
|
+
!(keepRatio && heightFollowsWidth(this.element))) {
|
|
269
304
|
this.applySize(this.element, 'height', new_h);
|
|
270
305
|
}
|
|
271
306
|
this.updateSize();
|
|
@@ -311,10 +346,20 @@ export class resizer extends Plugin {
|
|
|
311
346
|
css(element, key, value);
|
|
312
347
|
}
|
|
313
348
|
}
|
|
349
|
+
/**
|
|
350
|
+
* The framed element can go with a wrapper round it, keeping its parent
|
|
351
|
+
*/
|
|
352
|
+
get isElementInEditor() {
|
|
353
|
+
return Boolean(this.element && this.j.editor.contains(this.element));
|
|
354
|
+
}
|
|
314
355
|
onDelete(e) {
|
|
315
356
|
if (!this.element) {
|
|
316
357
|
return;
|
|
317
358
|
}
|
|
359
|
+
if (!this.isElementInEditor) {
|
|
360
|
+
this.hide();
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
318
363
|
if (this.element.tagName !== 'JODIT') {
|
|
319
364
|
this.j.s.select(this.element);
|
|
320
365
|
}
|
|
@@ -326,7 +371,7 @@ export class resizer extends Plugin {
|
|
|
326
371
|
}
|
|
327
372
|
__onChangeEditor() {
|
|
328
373
|
if (this.isShown) {
|
|
329
|
-
if (!this.
|
|
374
|
+
if (!this.isElementInEditor) {
|
|
330
375
|
this.hide();
|
|
331
376
|
}
|
|
332
377
|
else {
|
|
@@ -396,8 +441,12 @@ export class resizer extends Plugin {
|
|
|
396
441
|
})
|
|
397
442
|
.off(element, 'changesize')
|
|
398
443
|
.on(element, 'changesize', () => {
|
|
399
|
-
|
|
400
|
-
|
|
444
|
+
// Only a resize sets the embed's size, and as the plain numbers
|
|
445
|
+
// the attributes take, so a click leaves `width="100%"` alone
|
|
446
|
+
if (this.isResizeMode) {
|
|
447
|
+
attr(iframe, 'width', element.offsetWidth);
|
|
448
|
+
attr(iframe, 'height', element.offsetHeight);
|
|
449
|
+
}
|
|
401
450
|
});
|
|
402
451
|
}
|
|
403
452
|
this.j.e.on(element, 'dragstart', this.hide);
|
|
@@ -434,9 +483,13 @@ export class resizer extends Plugin {
|
|
|
434
483
|
return;
|
|
435
484
|
}
|
|
436
485
|
this.isShown = true;
|
|
486
|
+
if (this.layer.parentNode !== this.j.workplace) {
|
|
487
|
+
markOwner(this.j, this.layer);
|
|
488
|
+
Dom.append(this.j.workplace, this.layer);
|
|
489
|
+
}
|
|
437
490
|
if (!this.rect.parentNode) {
|
|
438
491
|
markOwner(this.j, this.rect);
|
|
439
|
-
Dom.append(this.
|
|
492
|
+
Dom.append(this.layer, this.rect);
|
|
440
493
|
}
|
|
441
494
|
if (this.j.isFullSize) {
|
|
442
495
|
css(this.rect, 'zIndex', css(this.j.container, 'zIndex').toString());
|
|
@@ -457,6 +510,7 @@ export class resizer extends Plugin {
|
|
|
457
510
|
}
|
|
458
511
|
beforeDestruct(jodit) {
|
|
459
512
|
this.hide();
|
|
513
|
+
Dom.safeRemove(this.layer);
|
|
460
514
|
eventEmitter.off('hideHelpers', this.hide);
|
|
461
515
|
jodit.e.off(this.j.ow, '.resizer').off('.resizer');
|
|
462
516
|
}
|
|
@@ -52,10 +52,20 @@ export declare class selectCells extends Plugin {
|
|
|
52
52
|
* Execute custom commands for table
|
|
53
53
|
*/
|
|
54
54
|
private onExecCommand;
|
|
55
|
+
/**
|
|
56
|
+
* The cell that takes the caret when rows or columns are deleted: the next
|
|
57
|
+
* one in the same column (or row) that is not deleted, else the previous one
|
|
58
|
+
*/
|
|
59
|
+
private __nearestCell;
|
|
55
60
|
/**
|
|
56
61
|
* Add some align after native command
|
|
57
62
|
*/
|
|
58
63
|
private onAfterCommand;
|
|
64
|
+
/**
|
|
65
|
+
* Remove the table and put the caret where it stood: at the start of what
|
|
66
|
+
* follows it, else at the end of what precedes it
|
|
67
|
+
*/
|
|
68
|
+
private __removeTable;
|
|
59
69
|
/** @override */
|
|
60
70
|
protected beforeDestruct(jodit: IJodit): void;
|
|
61
71
|
}
|
|
@@ -17,7 +17,7 @@ import { KEY_TAB } from "../../core/constants.js";
|
|
|
17
17
|
import { autobind, watch } from "../../core/decorators/index.js";
|
|
18
18
|
import { Dom } from "../../core/dom/dom.js";
|
|
19
19
|
import { pluginSystem } from "../../core/global.js";
|
|
20
|
-
import { $$, alignElement, position } from "../../core/helpers/index.js";
|
|
20
|
+
import { $$, alignElement, position, toArray } from "../../core/helpers/index.js";
|
|
21
21
|
import { Plugin } from "../../core/plugin/index.js";
|
|
22
22
|
import { Table } from "../../modules/table/table.js";
|
|
23
23
|
import "./config.js";
|
|
@@ -316,15 +316,23 @@ export class selectCells extends Plugin {
|
|
|
316
316
|
this.__tableModule.mergeSelected(table);
|
|
317
317
|
break;
|
|
318
318
|
case 'empty':
|
|
319
|
-
cells.forEach(td =>
|
|
319
|
+
cells.forEach(td => {
|
|
320
|
+
Dom.detach(td);
|
|
321
|
+
Dom.append(td, this.j.createInside.element('br'));
|
|
322
|
+
});
|
|
320
323
|
break;
|
|
321
324
|
case 'bin':
|
|
322
|
-
|
|
325
|
+
this.__removeTable(table);
|
|
323
326
|
break;
|
|
324
327
|
case 'binrow':
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
+
{
|
|
329
|
+
const rows = new Set(cells.map(td => td.parentNode));
|
|
330
|
+
const next = this.__nearestCell(table, cell, toArray(rows).map(row => row.rowIndex), true);
|
|
331
|
+
rows.forEach(row => {
|
|
332
|
+
this.__tableModule.removeRow(table, row.rowIndex);
|
|
333
|
+
});
|
|
334
|
+
next && this.j.s.setCursorIn(next);
|
|
335
|
+
}
|
|
328
336
|
break;
|
|
329
337
|
case 'bincolumn':
|
|
330
338
|
{
|
|
@@ -337,11 +345,13 @@ export class selectCells extends Plugin {
|
|
|
337
345
|
columnsSet.add(col);
|
|
338
346
|
}
|
|
339
347
|
});
|
|
348
|
+
const next = this.__nearestCell(table, cell, columns, false);
|
|
340
349
|
columns
|
|
341
350
|
.sort((a, b) => b - a)
|
|
342
351
|
.forEach(col => {
|
|
343
352
|
this.__tableModule.removeColumn(table, col);
|
|
344
353
|
});
|
|
354
|
+
next && this.j.s.setCursorIn(next);
|
|
345
355
|
}
|
|
346
356
|
break;
|
|
347
357
|
case 'addcolumnafter':
|
|
@@ -353,10 +363,39 @@ export class selectCells extends Plugin {
|
|
|
353
363
|
this.__tableModule.appendRow(table, cell.parentNode, command === 'addrowafter');
|
|
354
364
|
break;
|
|
355
365
|
}
|
|
366
|
+
if (/^bin(row|column)$/.test(command) &&
|
|
367
|
+
!this.__tableModule.getColumnsCount(table)) {
|
|
368
|
+
this.__removeTable(table);
|
|
369
|
+
}
|
|
356
370
|
}
|
|
357
371
|
return false;
|
|
358
372
|
}
|
|
359
373
|
}
|
|
374
|
+
/**
|
|
375
|
+
* The cell that takes the caret when rows or columns are deleted: the next
|
|
376
|
+
* one in the same column (or row) that is not deleted, else the previous one
|
|
377
|
+
*/
|
|
378
|
+
__nearestCell(table, cell, deleted, isRow) {
|
|
379
|
+
const box = this.__tableModule.formalMatrix(table);
|
|
380
|
+
const [row, column] = this.__tableModule.formalCoordinate(table, cell);
|
|
381
|
+
const start = isRow ? row : column;
|
|
382
|
+
const count = isRow ? box.length : box[row].length;
|
|
383
|
+
const find = (i) => (!deleted.includes(i) && (isRow ? box[i][column] : box[row][i])) ||
|
|
384
|
+
null;
|
|
385
|
+
for (let i = start + 1; i < count; i += 1) {
|
|
386
|
+
const next = find(i);
|
|
387
|
+
if (next) {
|
|
388
|
+
return next;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
for (let i = start - 1; i >= 0; i -= 1) {
|
|
392
|
+
const prev = find(i);
|
|
393
|
+
if (prev) {
|
|
394
|
+
return prev;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
360
399
|
/**
|
|
361
400
|
* Add some align after native command
|
|
362
401
|
*/
|
|
@@ -367,6 +406,15 @@ export class selectCells extends Plugin {
|
|
|
367
406
|
.forEach(elm => alignElement(command, elm));
|
|
368
407
|
}
|
|
369
408
|
}
|
|
409
|
+
/**
|
|
410
|
+
* Remove the table and put the caret where it stood: at the start of what
|
|
411
|
+
* follows it, else at the end of what precedes it
|
|
412
|
+
*/
|
|
413
|
+
__removeTable(table) {
|
|
414
|
+
const parent = table.parentNode, next = Dom.findNotEmptySibling(table, false), prev = Dom.findNotEmptySibling(table, true);
|
|
415
|
+
Dom.safeRemove(table);
|
|
416
|
+
this.j.s.setCursorIn(next || prev || parent, Boolean(next));
|
|
417
|
+
}
|
|
370
418
|
/** @override */
|
|
371
419
|
beforeDestruct(jodit) {
|
|
372
420
|
this.__onRemoveSelection();
|
|
@@ -16,6 +16,44 @@ Config.prototype.table = {
|
|
|
16
16
|
useExtraClassesOptions: false
|
|
17
17
|
};
|
|
18
18
|
Icon.set('table', tableIcon);
|
|
19
|
+
/**
|
|
20
|
+
* Elements in `dtd.blockLimits` that hold only rows, cells or list items, so
|
|
21
|
+
* a table can't go directly inside them
|
|
22
|
+
*/
|
|
23
|
+
const ROW_AND_ITEM_HOLDERS = new Set([
|
|
24
|
+
'table',
|
|
25
|
+
'thead',
|
|
26
|
+
'tbody',
|
|
27
|
+
'tfoot',
|
|
28
|
+
'tr',
|
|
29
|
+
'ul',
|
|
30
|
+
'ol',
|
|
31
|
+
'dl'
|
|
32
|
+
]);
|
|
33
|
+
/**
|
|
34
|
+
* The nearest block around the cursor that can hold the new table: an element
|
|
35
|
+
* in `dtd.blockLimits`, such as a table cell, a list item or a `<div>`. The
|
|
36
|
+
* cursor's own block of the `enter` tag is a line, not a container, as in the
|
|
37
|
+
* dtd plugin's `checkBlockNesting`
|
|
38
|
+
*/
|
|
39
|
+
function findTableContainer(editor, current) {
|
|
40
|
+
const line = Dom.closest(current, Dom.isBlock, editor.editor);
|
|
41
|
+
const container = Dom.closest(current, node => {
|
|
42
|
+
var _a;
|
|
43
|
+
if (!Dom.isElement(node) ||
|
|
44
|
+
(node === line && Dom.isTag(node, editor.o.enter))) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
const tag = node.nodeName.toLowerCase();
|
|
48
|
+
return (Boolean((_a = editor.o.dtd) === null || _a === void 0 ? void 0 : _a.blockLimits[tag]) &&
|
|
49
|
+
!ROW_AND_ITEM_HOLDERS.has(tag));
|
|
50
|
+
}, editor.editor);
|
|
51
|
+
// With the cursor between two rows, `current` is the next row's text
|
|
52
|
+
return container &&
|
|
53
|
+
Dom.isOrContains(container, editor.s.range.startContainer)
|
|
54
|
+
? container
|
|
55
|
+
: null;
|
|
56
|
+
}
|
|
19
57
|
Config.prototype.controls.table = {
|
|
20
58
|
data: {
|
|
21
59
|
cols: 10,
|
|
@@ -129,7 +167,13 @@ Config.prototype.controls.table = {
|
|
|
129
167
|
editor.s.removeMarkers();
|
|
130
168
|
editor.editor.normalize();
|
|
131
169
|
editor.history.snapshot.restore(snapshot);
|
|
132
|
-
const
|
|
170
|
+
const current = editor.s.current();
|
|
171
|
+
// The table goes into the cell, list item or box holding the
|
|
172
|
+
// cursor, and only a block inside it is split
|
|
173
|
+
const container = findTableContainer(editor, current);
|
|
174
|
+
const block = container === current
|
|
175
|
+
? null
|
|
176
|
+
: Dom.furthest(current, Dom.isBlock, container !== null && container !== void 0 ? container : editor.editor);
|
|
133
177
|
if (block && Dom.isEmpty(block)) {
|
|
134
178
|
Dom.replace(block, table, undefined, false, true);
|
|
135
179
|
}
|
|
@@ -155,6 +199,12 @@ Config.prototype.controls.table = {
|
|
|
155
199
|
}
|
|
156
200
|
}
|
|
157
201
|
}
|
|
202
|
+
else if (container &&
|
|
203
|
+
!Dom.isEmpty(container) &&
|
|
204
|
+
!editor.o.table.splitBlockOnInsertTable) {
|
|
205
|
+
// With no block to go after, the table goes after the text
|
|
206
|
+
Dom.append(container, table);
|
|
207
|
+
}
|
|
158
208
|
else {
|
|
159
209
|
editor.s.insertNode(table, false);
|
|
160
210
|
}
|