jodit 3.9.6 → 3.11.2
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/.idea/dictionaries/v_chupurnov.xml +1 -0
- package/.idea/workspace.xml +197 -179
- package/CHANGELOG.MD +279 -133
- package/build/jodit.css +185 -130
- package/build/jodit.es2018.css +175 -126
- package/build/jodit.es2018.en.css +175 -126
- package/build/jodit.es2018.en.js +709 -367
- package/build/jodit.es2018.en.min.css +1 -1
- package/build/jodit.es2018.en.min.js +1 -1
- package/build/jodit.es2018.js +709 -367
- package/build/jodit.es2018.min.css +1 -1
- package/build/jodit.es2018.min.js +1 -1
- package/build/jodit.js +1362 -900
- package/build/jodit.min.css +2 -2
- package/build/jodit.min.js +1 -1
- package/package.json +22 -11
- package/src/core/async.ts +4 -0
- package/src/core/component/statuses.ts +6 -6
- package/src/core/dom.ts +25 -5
- package/src/core/events/event-emitter.ts +4 -2
- package/src/core/global.ts +15 -4
- package/src/core/helpers/append-script.ts +14 -0
- package/src/core/helpers/selector.ts +8 -3
- package/src/core/request/ajax.ts +5 -2
- package/src/core/request/response.ts +8 -4
- package/src/core/selection/style/api/toggle/toggle-css.ts +1 -1
- package/src/core/ui/button/button/button.less +8 -8
- package/src/core/ui/button/button/button.ts +9 -9
- package/src/core/ui/button/group/group.ts +2 -2
- package/src/core/ui/element.ts +4 -3
- package/src/core/ui/form/block/block.ts +1 -1
- package/src/core/ui/form/form.ts +8 -0
- package/src/core/ui/form/inputs/area/area.less +5 -0
- package/src/core/ui/form/inputs/area/area.ts +22 -1
- package/src/core/ui/form/inputs/checkbox/checkbox.less +50 -0
- package/src/core/ui/form/inputs/checkbox/checkbox.ts +48 -4
- package/src/core/ui/form/inputs/input/input.less +1 -1
- package/src/core/ui/form/inputs/input/input.ts +14 -4
- package/src/core/ui/icon.ts +2 -1
- package/src/core/ui/list/group.ts +2 -2
- package/src/core/ui/popup/popup.ts +59 -3
- package/src/jodit.ts +17 -14
- package/src/modules/dialog/dialog.less +0 -1
- package/src/modules/dialog/dialog.ts +2 -2
- package/src/modules/toolbar/collection/collection.ts +1 -6
- package/src/modules/toolbar/collection/editor-collection.ts +5 -1
- package/src/modules/widget/file-selector/file-selector.ts +1 -1
- package/src/modules/widget/tabs/tabs.less +1 -1
- package/src/modules/widget/tabs/tabs.ts +5 -3
- package/src/plugins/add-new-line/add-new-line.ts +1 -0
- package/src/plugins/clipboard/paste/paste.ts +1 -1
- package/src/plugins/image/image-properties/image-properties.ts +7 -0
- package/src/plugins/index.ts +1 -1
- package/src/plugins/keyboard/backspace/backspace.ts +183 -0
- package/src/plugins/keyboard/backspace/cases/check-join-neighbors.ts +117 -0
- package/src/plugins/keyboard/backspace/cases/check-join-two-lists.ts +55 -0
- package/src/plugins/keyboard/backspace/cases/check-not-collapsed.ts +27 -0
- package/src/plugins/keyboard/backspace/cases/check-remove-char.ts +191 -0
- package/src/plugins/keyboard/backspace/cases/check-remove-content-not-editable.ts +46 -0
- package/src/plugins/keyboard/backspace/cases/check-remove-empty-neighbor.ts +43 -0
- package/src/plugins/keyboard/backspace/cases/check-remove-empty-parent.ts +80 -0
- package/src/plugins/keyboard/backspace/cases/check-remove-unbreakable-element.ts +46 -0
- package/src/plugins/keyboard/backspace/cases/check-table-cell.ts +30 -0
- package/src/plugins/keyboard/backspace/cases/check-unwrap-first-list-item.ts +57 -0
- package/src/plugins/keyboard/backspace/cases/index.ts +27 -0
- package/src/plugins/keyboard/backspace/config.ts +33 -0
- package/src/plugins/keyboard/backspace/interface.d.ts +7 -0
- package/src/plugins/keyboard/helpers.ts +7 -3
- package/src/plugins/link/template.ts +2 -2
- package/src/plugins/print/preview.ts +103 -55
- package/src/plugins/resizer/resizer.ts +7 -2
- package/src/plugins/select.ts +0 -1
- package/src/plugins/source/const.ts +7 -0
- package/src/plugins/source/editor/engines/ace.ts +5 -0
- package/src/plugins/source/source.ts +19 -7
- package/src/styles/jodit.less +6 -0
- package/src/types/ajax.d.ts +3 -0
- package/src/types/async.d.ts +2 -0
- package/src/types/jodit.d.ts +5 -8
- package/src/types/popup.d.ts +1 -0
- package/src/types/ui.d.ts +23 -4
- package/types/core/async.d.ts +1 -0
- package/types/core/component/component.d.ts +6 -2
- package/types/core/component/statuses.d.ts +6 -6
- package/types/core/dom.d.ts +6 -2
- package/types/core/global.d.ts +1 -1
- package/types/core/helpers/append-script.d.ts +1 -0
- package/types/core/helpers/selector.d.ts +2 -3
- package/types/core/request/response.d.ts +2 -1
- package/types/core/ui/button/button/button.d.ts +3 -3
- package/types/core/ui/form/form.d.ts +1 -0
- package/types/core/ui/form/inputs/area/area.d.ts +7 -1
- package/types/core/ui/form/inputs/checkbox/checkbox.d.ts +10 -3
- package/types/core/ui/icon.d.ts +1 -1
- package/types/core/ui/list/group.d.ts +2 -1
- package/types/core/ui/popup/popup.d.ts +2 -1
- package/types/jodit.d.ts +6 -6
- package/types/modules/toolbar/button/button.d.ts +1 -1
- package/types/modules/widget/tabs/tabs.d.ts +2 -1
- package/types/plugins/index.d.ts +1 -1
- package/types/plugins/keyboard/backspace/backspace.d.ts +28 -0
- package/types/plugins/keyboard/backspace/cases/check-join-neighbors.d.ts +10 -0
- package/types/plugins/keyboard/backspace/cases/check-join-two-lists.d.ts +19 -0
- package/types/plugins/keyboard/backspace/cases/check-not-collapsed.d.ts +19 -0
- package/types/plugins/keyboard/backspace/cases/check-remove-char.d.ts +20 -0
- package/types/plugins/keyboard/backspace/cases/check-remove-content-not-editable.d.ts +10 -0
- package/types/plugins/keyboard/backspace/cases/check-remove-empty-neighbor.d.ts +19 -0
- package/types/plugins/keyboard/backspace/cases/check-remove-empty-parent.d.ts +19 -0
- package/types/plugins/keyboard/backspace/cases/check-remove-unbreakable-element.d.ts +19 -0
- package/types/plugins/keyboard/backspace/cases/check-table-cell.d.ts +19 -0
- package/types/plugins/keyboard/backspace/cases/check-unwrap-first-list-item.d.ts +19 -0
- package/types/plugins/keyboard/backspace/cases/index.d.ts +8 -0
- package/types/plugins/keyboard/backspace/config.d.ts +20 -0
- package/types/plugins/keyboard/helpers.d.ts +2 -2
- package/types/plugins/select.d.ts +0 -1
- package/types/plugins/source/const.d.ts +6 -0
- package/types/plugins/source/editor/engines/ace.d.ts +1 -0
- package/types/plugins/source/source.d.ts +1 -0
- package/types/types/{ajax.d.ts → types/ajax.d.ts} +3 -0
- package/types/types/{async.d.ts → types/async.d.ts} +2 -0
- package/types/types/{context.d.ts → types/context.d.ts} +0 -0
- package/types/types/{core.ts → types/core.ts} +0 -0
- package/types/types/{create.d.ts → types/create.d.ts} +0 -0
- package/types/types/{dialog.d.ts → types/dialog.d.ts} +0 -0
- package/types/types/{events.d.ts → types/events.d.ts} +0 -0
- package/types/types/{file-browser.d.ts → types/file-browser.d.ts} +0 -0
- package/types/types/{form.d.ts → types/form.d.ts} +0 -0
- package/types/types/{index.d.ts → types/index.d.ts} +0 -0
- package/types/types/{jodit.d.ts → types/jodit.d.ts} +5 -8
- package/types/types/{observe.d.ts → types/observe.d.ts} +0 -0
- package/types/types/{plugin.d.ts → types/plugin.d.ts} +0 -0
- package/types/types/{popup.d.ts → types/popup.d.ts} +1 -0
- package/types/types/{select.d.ts → types/select.d.ts} +0 -0
- package/types/types/{source.d.ts → types/source.d.ts} +0 -0
- package/types/types/{storage.ts → types/storage.ts} +0 -0
- package/types/types/{style.d.ts → types/style.d.ts} +0 -0
- package/types/types/{toolbar.d.ts → types/toolbar.d.ts} +0 -0
- package/types/types/{traits.d.ts → types/traits.d.ts} +0 -0
- package/types/types/{types.d.ts → types/types.d.ts} +0 -0
- package/types/types/{ui.d.ts → types/ui.d.ts} +23 -4
- package/types/types/{uploader.d.ts → types/uploader.d.ts} +0 -0
- package/types/types/{view.d.ts → types/view.d.ts} +0 -0
- package/src/plugins/keyboard/delete.ts +0 -746
- package/types/plugins/keyboard/delete.d.ts +0 -161
|
@@ -0,0 +1,117 @@
|
|
|
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-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { IJodit, Nullable } from '../../../../types';
|
|
8
|
+
import { findNotEmptySibling } from '../../helpers';
|
|
9
|
+
import { Dom } from '../../../../core/dom';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Check if two separate elements can be connected
|
|
13
|
+
*/
|
|
14
|
+
export function checkJoinNeighbors(
|
|
15
|
+
jodit: IJodit,
|
|
16
|
+
fakeNode: Node,
|
|
17
|
+
backspace: boolean
|
|
18
|
+
): boolean {
|
|
19
|
+
let nextBox: Nullable<Node> = fakeNode,
|
|
20
|
+
mainClosestBox: Nullable<Node> = nextBox;
|
|
21
|
+
|
|
22
|
+
// Find main big closest element
|
|
23
|
+
while (
|
|
24
|
+
nextBox &&
|
|
25
|
+
!findNotEmptySibling(nextBox, backspace) &&
|
|
26
|
+
nextBox.parentElement !== jodit.editor
|
|
27
|
+
) {
|
|
28
|
+
nextBox = nextBox.parentElement;
|
|
29
|
+
mainClosestBox = nextBox;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (
|
|
33
|
+
Dom.isElement(mainClosestBox) &&
|
|
34
|
+
Dom.isContentEditable(mainClosestBox, jodit.editor)
|
|
35
|
+
) {
|
|
36
|
+
const sibling = findNotEmptySibling(
|
|
37
|
+
mainClosestBox,
|
|
38
|
+
backspace
|
|
39
|
+
) as Nullable<Element>;
|
|
40
|
+
|
|
41
|
+
if (
|
|
42
|
+
sibling &&
|
|
43
|
+
(checkMoveListContent(jodit, mainClosestBox, sibling, backspace) ||
|
|
44
|
+
moveContentAndRemoveEmpty(
|
|
45
|
+
jodit,
|
|
46
|
+
mainClosestBox,
|
|
47
|
+
sibling,
|
|
48
|
+
backspace
|
|
49
|
+
))
|
|
50
|
+
) {
|
|
51
|
+
jodit.s.setCursorBefore(fakeNode);
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function checkMoveListContent(
|
|
60
|
+
jodit: IJodit,
|
|
61
|
+
mainClosestBox: Element,
|
|
62
|
+
sibling: Element,
|
|
63
|
+
backspace: boolean
|
|
64
|
+
): boolean {
|
|
65
|
+
// Process UL/LI/OL cases
|
|
66
|
+
const siblingIsList = Dom.isTag(sibling, ['ol', 'ul']);
|
|
67
|
+
const boxIsList = Dom.isTag(mainClosestBox, ['ol', 'ul']);
|
|
68
|
+
const elementChild = (elm: Element, side: boolean) =>
|
|
69
|
+
side ? elm.firstElementChild : elm.lastElementChild;
|
|
70
|
+
|
|
71
|
+
if (boxIsList) {
|
|
72
|
+
sibling = jodit.createInside.element(jodit.o.enterBlock);
|
|
73
|
+
Dom.before(mainClosestBox, sibling);
|
|
74
|
+
|
|
75
|
+
return moveContentAndRemoveEmpty(
|
|
76
|
+
jodit,
|
|
77
|
+
elementChild(mainClosestBox, backspace),
|
|
78
|
+
sibling,
|
|
79
|
+
backspace
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (sibling && siblingIsList && !boxIsList) {
|
|
84
|
+
return moveContentAndRemoveEmpty(
|
|
85
|
+
jodit,
|
|
86
|
+
mainClosestBox,
|
|
87
|
+
elementChild(sibling, !backspace),
|
|
88
|
+
backspace
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function moveContentAndRemoveEmpty(
|
|
96
|
+
jodit: IJodit,
|
|
97
|
+
mainClosestBox: Nullable<Node>,
|
|
98
|
+
sibling: Nullable<Node>,
|
|
99
|
+
backspace: boolean
|
|
100
|
+
): boolean {
|
|
101
|
+
// Move content and remove empty nodes
|
|
102
|
+
if (mainClosestBox && Dom.isElement(sibling)) {
|
|
103
|
+
Dom.moveContent(mainClosestBox, sibling, !backspace);
|
|
104
|
+
|
|
105
|
+
let remove: Nullable<Node> = mainClosestBox;
|
|
106
|
+
|
|
107
|
+
while (remove && remove !== jodit.editor && Dom.isEmpty(remove)) {
|
|
108
|
+
const parent: Nullable<Node> = remove.parentElement;
|
|
109
|
+
Dom.safeRemove(remove);
|
|
110
|
+
remove = parent;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
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-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { IJodit } from '../../../../types';
|
|
8
|
+
import { Dom } from '../../../../core/dom';
|
|
9
|
+
import { call } from '../../../../core/helpers';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Try join two UL elements
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```html
|
|
16
|
+
* <ul><li>one</li></ul>|<ol><li>two</li></ol>
|
|
17
|
+
* ```
|
|
18
|
+
* Result
|
|
19
|
+
* ```html
|
|
20
|
+
* <ul><li>one|</li><li>two</li></ul>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function checkJoinTwoLists(
|
|
24
|
+
jodit: IJodit,
|
|
25
|
+
fakeNode: Node,
|
|
26
|
+
backspace: boolean
|
|
27
|
+
): boolean {
|
|
28
|
+
const next = Dom.findSibling(fakeNode, backspace),
|
|
29
|
+
prev = Dom.findSibling(fakeNode, !backspace);
|
|
30
|
+
|
|
31
|
+
if (
|
|
32
|
+
!Dom.closest(fakeNode, Dom.isElement, jodit.editor) &&
|
|
33
|
+
Dom.isTag(next, ['ul', 'ol']) &&
|
|
34
|
+
Dom.isTag(prev, ['ul', 'ol']) &&
|
|
35
|
+
Dom.isTag(next.lastElementChild, 'li') &&
|
|
36
|
+
Dom.isTag(prev.firstElementChild, 'li')
|
|
37
|
+
) {
|
|
38
|
+
const { setCursorBefore, setCursorAfter } = jodit.s;
|
|
39
|
+
|
|
40
|
+
const target = next.lastElementChild,
|
|
41
|
+
second = prev.firstElementChild;
|
|
42
|
+
|
|
43
|
+
call(!backspace ? Dom.append : Dom.prepend, second, fakeNode);
|
|
44
|
+
|
|
45
|
+
Dom.moveContent(prev, next, !backspace);
|
|
46
|
+
Dom.safeRemove(prev);
|
|
47
|
+
|
|
48
|
+
call(backspace ? Dom.append : Dom.prepend, target, fakeNode);
|
|
49
|
+
call(backspace ? setCursorBefore : setCursorAfter, fakeNode);
|
|
50
|
+
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
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-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
import type { IJodit } from '../../../../types';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* On Not collapsed selection - should only remove whole selected content
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```html
|
|
13
|
+
* <p>first | stop</p><p>second | stop</p>
|
|
14
|
+
* ```
|
|
15
|
+
* result
|
|
16
|
+
* ```html
|
|
17
|
+
* <p>first | stop</p>
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function checkNotCollapsed(jodit: IJodit): boolean {
|
|
21
|
+
if (!jodit.s.isCollapsed()) {
|
|
22
|
+
jodit.execCommand('Delete');
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
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-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { CanUndef, IJodit, Nullable } from '../../../../types';
|
|
8
|
+
import type { DeleteMode } from '../interface';
|
|
9
|
+
import { findMostNestedNeighbor, getSibling } from '../../helpers';
|
|
10
|
+
import { Dom } from '../../../../core/dom';
|
|
11
|
+
import { call, isVoid, toArray, trimInv } from '../../../../core/helpers';
|
|
12
|
+
import { INVISIBLE_SPACE, NBSP_SPACE } from '../../../../core/constants';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Check possibility the char can be removed
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```html
|
|
19
|
+
* te|st
|
|
20
|
+
* ```
|
|
21
|
+
* result
|
|
22
|
+
* ```html
|
|
23
|
+
* t|st
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function checkRemoveChar(
|
|
27
|
+
jodit: IJodit,
|
|
28
|
+
fakeNode: Node,
|
|
29
|
+
backspace: boolean,
|
|
30
|
+
mode: DeleteMode
|
|
31
|
+
): boolean {
|
|
32
|
+
const step = backspace ? -1 : 1;
|
|
33
|
+
const anotherSibling: Nullable<Node> = getSibling(fakeNode, !backspace);
|
|
34
|
+
|
|
35
|
+
let sibling: Nullable<Node> = getSibling(fakeNode, backspace),
|
|
36
|
+
removeNeighbor: Nullable<Node> = null;
|
|
37
|
+
|
|
38
|
+
let charRemoved: boolean = false,
|
|
39
|
+
removed: CanUndef<string>;
|
|
40
|
+
|
|
41
|
+
while (sibling && (Dom.isText(sibling) || Dom.isInlineBlock(sibling))) {
|
|
42
|
+
while (Dom.isInlineBlock(sibling)) {
|
|
43
|
+
sibling = (
|
|
44
|
+
backspace ? sibling?.lastChild : sibling?.firstChild
|
|
45
|
+
) as Nullable<Node>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!sibling) {
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (sibling.nodeValue?.length) {
|
|
53
|
+
// For Unicode escapes
|
|
54
|
+
let value = toArray(sibling.nodeValue);
|
|
55
|
+
|
|
56
|
+
const length = value.length;
|
|
57
|
+
|
|
58
|
+
let index = backspace ? length - 1 : 0;
|
|
59
|
+
|
|
60
|
+
if (value[index] === INVISIBLE_SPACE) {
|
|
61
|
+
while (value[index] === INVISIBLE_SPACE) {
|
|
62
|
+
index += step;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
removed = value[index];
|
|
67
|
+
|
|
68
|
+
if (value[index + step] === INVISIBLE_SPACE) {
|
|
69
|
+
index += step;
|
|
70
|
+
|
|
71
|
+
while (value[index] === INVISIBLE_SPACE) {
|
|
72
|
+
index += step;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
index += backspace ? 1 : -1;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (backspace && index < 0) {
|
|
79
|
+
value = [];
|
|
80
|
+
} else {
|
|
81
|
+
value = value.slice(
|
|
82
|
+
backspace ? 0 : index + 1,
|
|
83
|
+
backspace ? index : length
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (
|
|
88
|
+
!anotherSibling ||
|
|
89
|
+
!Dom.isText(anotherSibling) ||
|
|
90
|
+
(!backspace ? / $/ : /^ /).test(
|
|
91
|
+
anotherSibling.nodeValue ?? ''
|
|
92
|
+
) ||
|
|
93
|
+
!trimInv(anotherSibling.nodeValue || '').length
|
|
94
|
+
) {
|
|
95
|
+
for (
|
|
96
|
+
let i = backspace ? value.length - 1 : 0;
|
|
97
|
+
backspace ? i >= 0 : i < value.length;
|
|
98
|
+
i += backspace ? -1 : 1
|
|
99
|
+
) {
|
|
100
|
+
if (value[i] === ' ') {
|
|
101
|
+
value[i] = NBSP_SPACE;
|
|
102
|
+
} else {
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
sibling.nodeValue = value.join('');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (!sibling.nodeValue?.length) {
|
|
112
|
+
removeNeighbor = sibling;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (!isVoid(removed) && removed !== INVISIBLE_SPACE) {
|
|
116
|
+
charRemoved = true;
|
|
117
|
+
|
|
118
|
+
call(backspace ? Dom.after : Dom.before, sibling, fakeNode);
|
|
119
|
+
|
|
120
|
+
if (
|
|
121
|
+
mode === 'sentence' ||
|
|
122
|
+
(mode === 'word' && removed !== ' ' && removed !== NBSP_SPACE)
|
|
123
|
+
) {
|
|
124
|
+
checkRemoveChar(jodit, fakeNode, backspace, mode);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
let nextSibling = getSibling(sibling, backspace);
|
|
131
|
+
|
|
132
|
+
if (
|
|
133
|
+
!nextSibling &&
|
|
134
|
+
sibling.parentNode &&
|
|
135
|
+
sibling.parentNode !== jodit.editor
|
|
136
|
+
) {
|
|
137
|
+
nextSibling = findMostNestedNeighbor(
|
|
138
|
+
sibling,
|
|
139
|
+
!backspace,
|
|
140
|
+
jodit.editor,
|
|
141
|
+
true
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (removeNeighbor) {
|
|
146
|
+
Dom.safeRemove(removeNeighbor);
|
|
147
|
+
removeNeighbor = null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
sibling = nextSibling;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (charRemoved) {
|
|
154
|
+
removeEmptyInlineParent(fakeNode);
|
|
155
|
+
addBRInsideEmptyBlock(jodit, fakeNode);
|
|
156
|
+
jodit.s.setCursorBefore(fakeNode);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return charRemoved;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Helper remove all empty inline parents
|
|
164
|
+
*/
|
|
165
|
+
function removeEmptyInlineParent(node: Node): void {
|
|
166
|
+
let parent = node.parentElement;
|
|
167
|
+
|
|
168
|
+
while (parent && Dom.isInlineBlock(parent)) {
|
|
169
|
+
const p = parent.parentElement;
|
|
170
|
+
|
|
171
|
+
if (Dom.isEmpty(parent)) {
|
|
172
|
+
Dom.after(parent, node);
|
|
173
|
+
Dom.safeRemove(parent);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
parent = p;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Helper add BR element inside empty block element
|
|
182
|
+
*/
|
|
183
|
+
function addBRInsideEmptyBlock(jodit: IJodit, node: Node): void {
|
|
184
|
+
if (
|
|
185
|
+
node.parentElement !== jodit.editor &&
|
|
186
|
+
Dom.isBlock(node.parentElement) &&
|
|
187
|
+
Dom.each(node.parentElement, Dom.isEmptyTextNode)
|
|
188
|
+
) {
|
|
189
|
+
Dom.after(node, jodit.createInside.element('br'));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
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-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
import type { IJodit } from '../../../../types';
|
|
7
|
+
import { Dom } from '../../../../core/dom';
|
|
8
|
+
import { call } from '../../../../core/helpers';
|
|
9
|
+
import { normalizeCursorPosition } from '../../helpers';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Проверяет возможность удаления не редактируемго элемента
|
|
13
|
+
*/
|
|
14
|
+
export function checkRemoveContentNotEditable(
|
|
15
|
+
jodit: IJodit,
|
|
16
|
+
fakeNode: Text,
|
|
17
|
+
backspace: boolean
|
|
18
|
+
): boolean {
|
|
19
|
+
let neighbor = Dom.findSibling(fakeNode, backspace);
|
|
20
|
+
|
|
21
|
+
if (
|
|
22
|
+
!neighbor &&
|
|
23
|
+
fakeNode.parentElement &&
|
|
24
|
+
fakeNode.parentElement !== jodit.editor
|
|
25
|
+
) {
|
|
26
|
+
neighbor = Dom.findSibling(fakeNode.parentElement, backspace);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (
|
|
30
|
+
Dom.isElement(neighbor) &&
|
|
31
|
+
!Dom.isContentEditable(neighbor, jodit.editor)
|
|
32
|
+
) {
|
|
33
|
+
call(backspace ? Dom.before : Dom.after, neighbor, fakeNode);
|
|
34
|
+
Dom.safeRemove(neighbor);
|
|
35
|
+
normalizeCursorPosition(jodit, fakeNode, backspace);
|
|
36
|
+
|
|
37
|
+
call(
|
|
38
|
+
backspace ? jodit.s.setCursorBefore : jodit.s.setCursorAfter,
|
|
39
|
+
fakeNode
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
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-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { IJodit } from '../../../../types';
|
|
8
|
+
import { Dom } from '../../../../core/dom';
|
|
9
|
+
import { findNotEmptySibling } from '../../helpers';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Check if it is possible to remove an empty adjacent element.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```html
|
|
16
|
+
* <p><br></p><p>|second stop</p>
|
|
17
|
+
* ```
|
|
18
|
+
* result
|
|
19
|
+
* ```html
|
|
20
|
+
* <p>|second stop</p>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function checkRemoveEmptyNeighbor(
|
|
24
|
+
jodit: IJodit,
|
|
25
|
+
fakeNode: Node,
|
|
26
|
+
backspace: boolean
|
|
27
|
+
): boolean {
|
|
28
|
+
const parent = Dom.closest(fakeNode, Dom.isElement, jodit.editor);
|
|
29
|
+
|
|
30
|
+
if (!parent) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const neighbor = findNotEmptySibling(parent, backspace);
|
|
35
|
+
|
|
36
|
+
if (neighbor && Dom.isEmpty(neighbor)) {
|
|
37
|
+
Dom.safeRemove(neighbor);
|
|
38
|
+
jodit.s.setCursorBefore(fakeNode);
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
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-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { IJodit, Nullable } from '../../../../types';
|
|
8
|
+
import { Dom } from '../../../../core/dom';
|
|
9
|
+
import { findNotEmptyNeighbor } from '../../helpers';
|
|
10
|
+
import { INSEPARABLE_TAGS } from '../../../../core/constants';
|
|
11
|
+
import { checkJoinTwoLists } from './check-join-two-lists';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Check if the current empty item can be removed
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```html
|
|
18
|
+
* <p>first stop</p><p>|<br></p>
|
|
19
|
+
* ```
|
|
20
|
+
* result
|
|
21
|
+
* ```html
|
|
22
|
+
* <p>first stop|</p>
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export function checkRemoveEmptyParent(
|
|
26
|
+
jodit: IJodit,
|
|
27
|
+
fakeNode: Node,
|
|
28
|
+
backspace: boolean
|
|
29
|
+
): boolean {
|
|
30
|
+
let found: boolean = false;
|
|
31
|
+
const { setCursorBefore, setCursorIn } = jodit.s;
|
|
32
|
+
|
|
33
|
+
let prn: Nullable<Node> = Dom.closest(
|
|
34
|
+
fakeNode,
|
|
35
|
+
Dom.isElement,
|
|
36
|
+
jodit.editor
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
if (!prn || !Dom.isEmpty(prn)) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const neighbor = findNotEmptyNeighbor(fakeNode, backspace, jodit.editor);
|
|
44
|
+
|
|
45
|
+
do {
|
|
46
|
+
if (prn && Dom.isEmpty(prn) && !Dom.isCell(prn)) {
|
|
47
|
+
Dom.after(prn, fakeNode);
|
|
48
|
+
|
|
49
|
+
const tmp: Nullable<Node> = Dom.closest(
|
|
50
|
+
prn,
|
|
51
|
+
n => Dom.isElement(n) && n !== prn,
|
|
52
|
+
jodit.editor
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
Dom.safeRemove(prn);
|
|
56
|
+
|
|
57
|
+
found = true;
|
|
58
|
+
|
|
59
|
+
prn = tmp;
|
|
60
|
+
} else {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
} while (prn);
|
|
64
|
+
|
|
65
|
+
if (found && checkJoinTwoLists(jodit, fakeNode, backspace)) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (
|
|
70
|
+
neighbor &&
|
|
71
|
+
!Dom.isText(neighbor) &&
|
|
72
|
+
!Dom.isTag(neighbor, INSEPARABLE_TAGS)
|
|
73
|
+
) {
|
|
74
|
+
setCursorIn(neighbor, !backspace);
|
|
75
|
+
} else {
|
|
76
|
+
setCursorBefore(fakeNode);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return found;
|
|
80
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
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-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { IJodit } from '../../../../types';
|
|
8
|
+
import { Dom } from '../../../../core/dom';
|
|
9
|
+
import { INSEPARABLE_TAGS } from '../../../../core/constants';
|
|
10
|
+
import { checkRemoveEmptyParent } from './check-remove-empty-parent';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Check possibility inseparable Element can be removed (img, hr etc.)
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```html
|
|
17
|
+
* <p>first second <img>| stop</p>
|
|
18
|
+
* ```
|
|
19
|
+
* result
|
|
20
|
+
* ```html
|
|
21
|
+
* <p>first second | stop</p>
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function checkRemoveUnbreakableElement(
|
|
25
|
+
jodit: IJodit,
|
|
26
|
+
fakeNode: Node,
|
|
27
|
+
backspace: boolean
|
|
28
|
+
): boolean {
|
|
29
|
+
const neighbor = Dom.findSibling(fakeNode, backspace);
|
|
30
|
+
|
|
31
|
+
if (
|
|
32
|
+
Dom.isElement(neighbor) &&
|
|
33
|
+
(Dom.isTag(neighbor, INSEPARABLE_TAGS) || Dom.isEmpty(neighbor))
|
|
34
|
+
) {
|
|
35
|
+
Dom.safeRemove(neighbor);
|
|
36
|
+
jodit.s.setCursorBefore(fakeNode);
|
|
37
|
+
|
|
38
|
+
if (Dom.isTag(neighbor, 'br')) {
|
|
39
|
+
checkRemoveEmptyParent(jodit, fakeNode, backspace);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
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-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Dom } from '../../../../core/dom';
|
|
8
|
+
import type { IJodit } from '../../../../types';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Inside the CELL table - nothing to do
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```html
|
|
15
|
+
* <table><tr><td>|test</td></tr></table>
|
|
16
|
+
* ```
|
|
17
|
+
* result
|
|
18
|
+
* ```html
|
|
19
|
+
* <table><tr><td>|test</td></tr></table>
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function checkTableCell(jodit: IJodit, fakeNode: Node): boolean {
|
|
23
|
+
const cell = fakeNode.parentElement;
|
|
24
|
+
|
|
25
|
+
if (Dom.isCell(cell)) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
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-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { IJodit } from '../../../../types';
|
|
8
|
+
import { Dom } from '../../../../core/dom';
|
|
9
|
+
import { call } from '../../../../core/helpers';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* For first item in list on backspace try move his content in new P
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```html
|
|
16
|
+
* <ul><li>|first</li><li>second</li></ul>
|
|
17
|
+
* ```
|
|
18
|
+
* Result
|
|
19
|
+
* ```html
|
|
20
|
+
* <p>|first</p><ul><li>second</li></ul>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function checkUnwrapFirstListItem(
|
|
24
|
+
jodit: IJodit,
|
|
25
|
+
fakeNode: Node,
|
|
26
|
+
backspace: boolean
|
|
27
|
+
): boolean {
|
|
28
|
+
const li = Dom.closest(fakeNode, Dom.isElement, jodit.editor);
|
|
29
|
+
|
|
30
|
+
const { s } = jodit;
|
|
31
|
+
|
|
32
|
+
if (
|
|
33
|
+
Dom.isTag(li, 'li') &&
|
|
34
|
+
li?.parentElement?.[
|
|
35
|
+
backspace ? 'firstElementChild' : 'lastElementChild'
|
|
36
|
+
] === li &&
|
|
37
|
+
s.cursorInTheEdge(backspace, li)
|
|
38
|
+
) {
|
|
39
|
+
const ul = li.parentElement;
|
|
40
|
+
const p = jodit.createInside.element(jodit.o.enterBlock);
|
|
41
|
+
|
|
42
|
+
call(backspace ? Dom.before : Dom.after, ul, p);
|
|
43
|
+
|
|
44
|
+
Dom.moveContent(li, p);
|
|
45
|
+
Dom.safeRemove(li);
|
|
46
|
+
|
|
47
|
+
if (Dom.isEmpty(ul)) {
|
|
48
|
+
Dom.safeRemove(ul);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
call(backspace ? s.setCursorBefore : s.setCursorAfter, fakeNode);
|
|
52
|
+
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return false;
|
|
57
|
+
}
|