jodit 4.12.22 → 4.12.23
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 +18 -0
- package/es2015/jodit.css +1 -1
- package/es2015/jodit.fat.min.js +10 -10
- package/es2015/jodit.js +211 -69
- package/es2015/jodit.min.js +10 -10
- 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.js +10 -10
- package/es2018/jodit.min.js +15 -15
- package/es2018/plugins/debug/debug.min.js +1 -1
- package/es2018/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es2021/jodit.css +1 -1
- package/es2021/jodit.fat.min.js +12 -12
- package/es2021/jodit.js +202 -68
- package/es2021/jodit.min.js +12 -12
- 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 +1 -1
- package/es2021.en/jodit.fat.min.js +13 -13
- package/es2021.en/jodit.js +180 -46
- package/es2021.en/jodit.min.js +12 -12
- 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 +2 -2
- package/es5/jodit.fat.min.js +2 -2
- package/es5/jodit.js +255 -104
- package/es5/jodit.min.css +2 -2
- 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/core/component/view-component.js +8 -0
- package/esm/core/constants.js +1 -1
- package/esm/core/helpers/checker/is-html-from-word.d.ts +1 -1
- package/esm/core/helpers/checker/is-html-from-word.js +12 -1
- package/esm/core/selection/style/api/wrap.js +18 -3
- package/esm/core/ui/popup/popup.js +4 -1
- package/esm/jodit.js +12 -0
- package/esm/modules/toolbar/button/content.d.ts +6 -0
- package/esm/modules/toolbar/button/content.js +26 -1
- package/esm/plugins/add-new-line/add-new-line.js +4 -1
- package/esm/plugins/ai-assistant/ai-assistant.js +7 -1
- package/esm/plugins/backspace/cases/check-join-neighbors.js +15 -1
- package/esm/plugins/color/color.js +21 -21
- package/esm/plugins/inline-popup/inline-popup.d.ts +7 -0
- package/esm/plugins/inline-popup/inline-popup.js +18 -2
- package/esm/plugins/paste/config.js +11 -2
- package/esm/plugins/search/ui/search.js +22 -12
- package/esm/plugins/select-cells/select-cells.js +10 -6
- package/package.json +1 -1
- package/types/core/helpers/checker/is-html-from-word.d.ts +1 -1
- package/types/modules/toolbar/button/content.d.ts +6 -0
- package/types/plugins/inline-popup/inline-popup.d.ts +7 -0
package/es5/polyfills.fat.min.js
CHANGED
package/es5/polyfills.js
CHANGED
package/es5/polyfills.min.js
CHANGED
|
@@ -22,6 +22,14 @@ export class ViewComponent extends Component {
|
|
|
22
22
|
*/
|
|
23
23
|
setParentView(jodit) {
|
|
24
24
|
this.jodit = jodit;
|
|
25
|
+
// Inherit the owner window from the parent view — for an editor
|
|
26
|
+
// created with a custom `ownerWindow` (e.g. inside an iframe) the
|
|
27
|
+
// component default (the global `window`) is wrong: outside-click
|
|
28
|
+
// handlers of dropdowns/popups listened to the wrong window. See
|
|
29
|
+
// https://github.com/xdan/jodit/issues/965
|
|
30
|
+
if (jodit.ow) {
|
|
31
|
+
this.ownerWindow = jodit.ow;
|
|
32
|
+
}
|
|
25
33
|
jodit.components.add(this);
|
|
26
34
|
return this;
|
|
27
35
|
}
|
package/esm/core/constants.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Released under MIT see LICENSE.txt in the project root for license information.
|
|
4
4
|
* Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
5
|
*/
|
|
6
|
-
export const APP_VERSION = "4.12.
|
|
6
|
+
export const APP_VERSION = "4.12.23";
|
|
7
7
|
// prettier-ignore
|
|
8
8
|
export const ES = "es2020";
|
|
9
9
|
export const IS_ES_MODERN = true;
|
|
@@ -7,10 +7,21 @@
|
|
|
7
7
|
* @module helpers/checker
|
|
8
8
|
*/
|
|
9
9
|
/**
|
|
10
|
-
* Detect if string is HTML from MS Word or
|
|
10
|
+
* Detect if string is HTML from MS Word, Excel or LibreOffice/OpenOffice
|
|
11
11
|
*/
|
|
12
12
|
export function isHtmlFromWord(data) {
|
|
13
13
|
return (data.search(/<meta.*?Microsoft Excel\s[\d].*?>/) !== -1 ||
|
|
14
14
|
data.search(/<meta.*?Microsoft Word\s[\d].*?>/) !== -1 ||
|
|
15
|
+
// `<meta name=ProgId content=Word.Document>` — attribute values are
|
|
16
|
+
// unquoted in the raw Word clipboard fragment
|
|
17
|
+
data.search(/<meta[^>]*?ProgId[^>]*?(Word|Excel)\./i) !== -1 ||
|
|
18
|
+
// LibreOffice/OpenOffice Writer & Calc
|
|
19
|
+
data.search(/<meta[^>]*?(LibreOffice|OpenOffice)/i) !== -1 ||
|
|
20
|
+
// Office namespaces on the root element of the clipboard fragment
|
|
21
|
+
data.search(/urn:schemas-microsoft-com:office:(word|excel)/) !== -1 ||
|
|
22
|
+
// `class=MsoNormal` and friends (unquoted/quoted)
|
|
23
|
+
data.search(/<\w[^>]*\sclass=("|')?Mso/) !== -1 ||
|
|
24
|
+
// the raw Word clipboard uses SINGLE quotes: style='mso-…'
|
|
25
|
+
data.search(/style='[^']*mso-/) !== -1 ||
|
|
15
26
|
(data.search(/style="[^"]*mso-/) !== -1 && data.search(/<font/) !== -1));
|
|
16
27
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { Dom } from "../../../dom/index.js";
|
|
7
7
|
import { attr } from "../../../helpers/utils/attr.js";
|
|
8
|
+
import { css } from "../../../helpers/utils/css.js";
|
|
8
9
|
import { wrapList } from "./list/wrap-list.js";
|
|
9
10
|
import { wrapUnwrappedText } from "./wrap-unwrapped-text.js";
|
|
10
11
|
/**
|
|
@@ -13,9 +14,23 @@ import { wrapUnwrappedText } from "./wrap-unwrapped-text.js";
|
|
|
13
14
|
*/
|
|
14
15
|
export function wrap(commitStyle, font, jodit) {
|
|
15
16
|
const wrapper = findOrCreateWrapper(commitStyle, font, jodit);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
if (commitStyle.elementIsList) {
|
|
18
|
+
return wrapList(commitStyle, wrapper, jodit);
|
|
19
|
+
}
|
|
20
|
+
const newWrapper = Dom.replace(wrapper, commitStyle.element, jodit.createInside, true);
|
|
21
|
+
if (commitStyle.elementIsBlock) {
|
|
22
|
+
// Inline font styles left over from pasted content visually override
|
|
23
|
+
// the new block format — e.g. an h2 with `font-weight: normal;
|
|
24
|
+
// font-size: 24px` does not look like a heading at all, so the
|
|
25
|
+
// command seems to do nothing. See
|
|
26
|
+
// https://github.com/xdan/jodit/issues/1063
|
|
27
|
+
css(newWrapper, 'fontSize', null);
|
|
28
|
+
css(newWrapper, 'fontWeight', null);
|
|
29
|
+
if (!attr(newWrapper, 'style')) {
|
|
30
|
+
attr(newWrapper, 'style', null);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return newWrapper;
|
|
19
34
|
}
|
|
20
35
|
const WRAP_NODES = new Set([
|
|
21
36
|
'td',
|
|
@@ -137,8 +137,11 @@ export class Popup extends UIGroup {
|
|
|
137
137
|
* Calculate static bound for point
|
|
138
138
|
*/
|
|
139
139
|
getKeepBound(getBound) {
|
|
140
|
+
var _a;
|
|
140
141
|
const oldBound = getBound();
|
|
141
|
-
|
|
142
|
+
// Inside Shadow DOM `document.elementFromPoint` returns the shadow
|
|
143
|
+
// host, so the lookup must start from the shadow root
|
|
144
|
+
const elmUnderCursor = ((_a = this.j.o.shadowRoot) !== null && _a !== void 0 ? _a : this.od).elementFromPoint(oldBound.left, oldBound.top);
|
|
142
145
|
if (!elmUnderCursor) {
|
|
143
146
|
return getBound;
|
|
144
147
|
}
|
package/esm/jodit.js
CHANGED
|
@@ -1073,6 +1073,18 @@ let Jodit = Jodit_1 = class Jodit extends ViewWithToolbar {
|
|
|
1073
1073
|
(opt.uploader.url || opt.uploader.insertImageAsBase64URI)) {
|
|
1074
1074
|
this.uploader.bind(this.editor);
|
|
1075
1075
|
}
|
|
1076
|
+
else if (!opt.enableDragAndDropFileToEditor) {
|
|
1077
|
+
// Without a bound uploader nobody cancels a file drop, and
|
|
1078
|
+
// Firefox inserts the dropped image natively — the option
|
|
1079
|
+
// must mean "do nothing". See
|
|
1080
|
+
// https://github.com/xdan/jodit/issues/1077
|
|
1081
|
+
this.e.on(editor, 'drop', (e) => {
|
|
1082
|
+
var _a, _b;
|
|
1083
|
+
if ((_b = (_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b.length) {
|
|
1084
|
+
e.preventDefault();
|
|
1085
|
+
}
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
1076
1088
|
// in initEditor - the editor could change
|
|
1077
1089
|
if (!this.__elementToPlace.get(this.editor)) {
|
|
1078
1090
|
this.__elementToPlace.set(this.editor, currentPlace);
|
|
@@ -15,6 +15,12 @@ export declare class ToolbarContent<T extends IViewBased = IViewBased> extends U
|
|
|
15
15
|
className(): string;
|
|
16
16
|
/** @override */
|
|
17
17
|
update(): void;
|
|
18
|
+
/**
|
|
19
|
+
* The content is arbitrary HTML — propagate the disabled state to the
|
|
20
|
+
* nested form controls (e.g. the file input of the Upload button),
|
|
21
|
+
* otherwise they stay interactive.
|
|
22
|
+
*/
|
|
23
|
+
protected onChangeDisabled(): void;
|
|
18
24
|
/** @override */
|
|
19
25
|
protected createContainer(): HTMLElement;
|
|
20
26
|
constructor(jodit: T, control: IControlTypeContent, target?: Nullable<HTMLElement>);
|
|
@@ -24,13 +24,38 @@ let ToolbarContent = class ToolbarContent extends UIButton {
|
|
|
24
24
|
}
|
|
25
25
|
/** @override */
|
|
26
26
|
update() {
|
|
27
|
-
|
|
27
|
+
var _a, _b, _c;
|
|
28
|
+
const { control } = this;
|
|
29
|
+
const content = control.getContent(this.j, this);
|
|
28
30
|
if (isString(content) || content.parentNode !== this.container) {
|
|
29
31
|
Dom.detach(this.container);
|
|
30
32
|
this.container.appendChild(isString(content) ? this.j.create.fromHTML(content) : content);
|
|
31
33
|
}
|
|
34
|
+
// Content controls never went through the ToolbarButton status
|
|
35
|
+
// calculation, so `isDisabled`/`isActive`/`update` declared on the
|
|
36
|
+
// control were silently ignored (e.g. the FileBrowser Upload button
|
|
37
|
+
// ignored the backend permissions). See
|
|
38
|
+
// https://github.com/xdan/jodit/issues/1094
|
|
39
|
+
this.state.disabled = Boolean((_a = control.isDisabled) === null || _a === void 0 ? void 0 : _a.call(control, this.j, this));
|
|
40
|
+
this.state.activated = Boolean((_b = control.isActive) === null || _b === void 0 ? void 0 : _b.call(control, this.j, this));
|
|
41
|
+
(_c = control.update) === null || _c === void 0 ? void 0 : _c.call(control, this.j, this);
|
|
42
|
+
// The first update() runs before the state watchers are attached, so
|
|
43
|
+
// apply the calculated state explicitly (the calls are idempotent)
|
|
44
|
+
this.onChangeDisabled();
|
|
45
|
+
this.onChangeActivated();
|
|
32
46
|
super.update();
|
|
33
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* The content is arbitrary HTML — propagate the disabled state to the
|
|
50
|
+
* nested form controls (e.g. the file input of the Upload button),
|
|
51
|
+
* otherwise they stay interactive.
|
|
52
|
+
*/
|
|
53
|
+
onChangeDisabled() {
|
|
54
|
+
super.onChangeDisabled();
|
|
55
|
+
this.container
|
|
56
|
+
.querySelectorAll('input,button,select,textarea')
|
|
57
|
+
.forEach(elm => attr(elm, 'disabled', this.state.disabled || null));
|
|
58
|
+
}
|
|
34
59
|
/** @override */
|
|
35
60
|
createContainer() {
|
|
36
61
|
return this.j.c.span(this.componentName);
|
|
@@ -151,8 +151,11 @@ export class addNewLine extends Plugin {
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
__onMouseMove(e) {
|
|
154
|
+
var _a;
|
|
154
155
|
const editor = this.j;
|
|
155
|
-
|
|
156
|
+
// Inside Shadow DOM `document.elementFromPoint` returns the shadow
|
|
157
|
+
// host, so the lookup must start from the shadow root
|
|
158
|
+
let currentElement = ((_a = editor.o.shadowRoot) !== null && _a !== void 0 ? _a : editor.ed).elementFromPoint(e.clientX, e.clientY);
|
|
156
159
|
if (!Dom.isHTMLElement(currentElement) ||
|
|
157
160
|
!Dom.isOrContains(editor.editor, currentElement)) {
|
|
158
161
|
return;
|
|
@@ -40,7 +40,13 @@ export class aiAssistant extends Plugin {
|
|
|
40
40
|
return new UiAiAssistant(jodit, {
|
|
41
41
|
onInsertAfter(html) {
|
|
42
42
|
jodit.s.focus();
|
|
43
|
-
|
|
43
|
+
// `current()` returns a node of the selection START, so with
|
|
44
|
+
// several selected paragraphs the result landed after the
|
|
45
|
+
// first one — collapse the range to the END of the selection
|
|
46
|
+
// instead. See https://github.com/xdan/jodit/issues/1263
|
|
47
|
+
const range = jodit.s.range;
|
|
48
|
+
range.collapse(false);
|
|
49
|
+
jodit.s.selectRange(range);
|
|
44
50
|
jodit.s.insertHTML(html);
|
|
45
51
|
__dialog.close();
|
|
46
52
|
},
|
|
@@ -32,13 +32,27 @@ export function checkJoinNeighbors(jodit, fakeNode, backspace) {
|
|
|
32
32
|
}
|
|
33
33
|
if (sibling &&
|
|
34
34
|
(checkMoveListContent(jodit, mainClosestBox, sibling, backspace) ||
|
|
35
|
-
moveContentAndRemoveEmpty(jodit, mainClosestBox, sibling, backspace))) {
|
|
35
|
+
moveContentAndRemoveEmpty(jodit, mainClosestBox, resolveTableSibling(sibling, backspace), backspace))) {
|
|
36
36
|
jodit.s.setCursorBefore(fakeNode);
|
|
37
37
|
return true;
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
return false;
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Content cannot be merged into the `<table>` element itself — it would land
|
|
44
|
+
* between the table sections (after `</tbody>`), which is invalid HTML and
|
|
45
|
+
* gets foster-parented out of the table on the next parse. Merge into the
|
|
46
|
+
* edge cell instead. See https://github.com/xdan/jodit/issues/1064
|
|
47
|
+
* @private
|
|
48
|
+
*/
|
|
49
|
+
function resolveTableSibling(sibling, backspace) {
|
|
50
|
+
if (!Dom.isTag(sibling, 'table')) {
|
|
51
|
+
return sibling;
|
|
52
|
+
}
|
|
53
|
+
const cells = sibling.querySelectorAll('td,th');
|
|
54
|
+
return cells.length ? cells[backspace ? cells.length - 1 : 0] : null;
|
|
55
|
+
}
|
|
42
56
|
function checkMoveListContent(jodit, mainClosestBox, sibling, backspace) {
|
|
43
57
|
// Process UL/LI/OL cases
|
|
44
58
|
const siblingIsList = Dom.isTag(sibling, LIST_TAGS);
|
|
@@ -15,28 +15,28 @@ export function color(editor) {
|
|
|
15
15
|
group: 'color'
|
|
16
16
|
});
|
|
17
17
|
const callback = (command, second, third) => {
|
|
18
|
+
var _a;
|
|
18
19
|
const colorHEX = normalizeColor(third);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
editor.s.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
break;
|
|
20
|
+
const value = !colorHEX ? '' : colorHEX;
|
|
21
|
+
const style = command === 'background'
|
|
22
|
+
? { backgroundColor: value }
|
|
23
|
+
: { color: value };
|
|
24
|
+
// Cells selected with the `select-cells` plugin drop or collapse the
|
|
25
|
+
// native range, so `commitStyle` would paint a pending caret format
|
|
26
|
+
// outside the table instead of the selection the user sees. Apply the
|
|
27
|
+
// style to the content of every selected cell instead. See #1250
|
|
28
|
+
const selectedCells = editor
|
|
29
|
+
.getInstance('Table', editor.o)
|
|
30
|
+
.getAllSelectedCells();
|
|
31
|
+
if (selectedCells.length && editor.s.isCollapsed()) {
|
|
32
|
+
selectedCells.forEach(cell => {
|
|
33
|
+
editor.s.select(cell, true);
|
|
34
|
+
editor.s.commitStyle({ attributes: { style } });
|
|
35
|
+
});
|
|
36
|
+
(_a = editor.s.sel) === null || _a === void 0 ? void 0 : _a.removeAllRanges();
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
editor.s.commitStyle({ attributes: { style } });
|
|
40
40
|
}
|
|
41
41
|
editor.synchronizeValues();
|
|
42
42
|
return false;
|
|
@@ -50,6 +50,13 @@ export declare class inlinePopup extends Plugin {
|
|
|
50
50
|
private __reopenSelectionPopup;
|
|
51
51
|
private __onDocumentMouseDown;
|
|
52
52
|
private __onCloseAllPopups;
|
|
53
|
+
/**
|
|
54
|
+
* The selection rect comes from the editor document — in iframe mode its
|
|
55
|
+
* coordinates are iframe-local, while the popup lives in the host
|
|
56
|
+
* document, so the iframe offset must be added. See
|
|
57
|
+
* https://github.com/xdan/jodit/issues/1058
|
|
58
|
+
*/
|
|
59
|
+
private __selectionBound;
|
|
53
60
|
private snapRange;
|
|
54
61
|
private onSelectionStart;
|
|
55
62
|
private onSelectionEnd;
|
|
@@ -176,10 +176,26 @@ export class inlinePopup extends Plugin {
|
|
|
176
176
|
this.j.async.setTimeout(() => {
|
|
177
177
|
const sel = this.j.s.sel;
|
|
178
178
|
if (sel && !sel.isCollapsed) {
|
|
179
|
-
this.showPopup(() => this.
|
|
179
|
+
this.showPopup(() => this.__selectionBound(), 'selection');
|
|
180
180
|
}
|
|
181
181
|
}, 1);
|
|
182
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* The selection rect comes from the editor document — in iframe mode its
|
|
185
|
+
* coordinates are iframe-local, while the popup lives in the host
|
|
186
|
+
* document, so the iframe offset must be added. See
|
|
187
|
+
* https://github.com/xdan/jodit/issues/1058
|
|
188
|
+
*/
|
|
189
|
+
__selectionBound() {
|
|
190
|
+
const rect = this.j.s.range.getBoundingClientRect();
|
|
191
|
+
let { left, top } = rect;
|
|
192
|
+
if (this.j.iframe) {
|
|
193
|
+
const offset = position(this.j.iframe, this.j, true);
|
|
194
|
+
left += offset.left;
|
|
195
|
+
top += offset.top;
|
|
196
|
+
}
|
|
197
|
+
return { left, top, width: rect.width, height: rect.height };
|
|
198
|
+
}
|
|
183
199
|
onSelectionStart() {
|
|
184
200
|
this.snapRange = this.j.s.range.cloneRange();
|
|
185
201
|
}
|
|
@@ -219,7 +235,7 @@ export class inlinePopup extends Plugin {
|
|
|
219
235
|
if (!node) {
|
|
220
236
|
return;
|
|
221
237
|
}
|
|
222
|
-
this.showPopup(() =>
|
|
238
|
+
this.showPopup(() => this.__selectionBound(), type);
|
|
223
239
|
}
|
|
224
240
|
/**
|
|
225
241
|
* In not collapsed selection - only one image
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Released under MIT see LICENSE.txt in the project root for license information.
|
|
4
4
|
* Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
5
|
*/
|
|
6
|
-
import { CLIPBOARD_ID, INSERT_AS_HTML, INSERT_AS_TEXT, INSERT_ONLY_TEXT, IS_PROD, TEXT_PLAIN } from "../../core/constants.js";
|
|
6
|
+
import { CLIPBOARD_ID, INSERT_AS_HTML, INSERT_AS_TEXT, INSERT_ONLY_TEXT, IS_PROD, TEXT_HTML, TEXT_PLAIN } from "../../core/constants.js";
|
|
7
7
|
import { Config } from "../../config.js";
|
|
8
8
|
import { pasteInsertHtml } from "./helpers.js";
|
|
9
9
|
Config.prototype.askBeforePasteHTML = true;
|
|
@@ -21,6 +21,7 @@ const psKey = 'pasteStorage';
|
|
|
21
21
|
Config.prototype.controls.paste = {
|
|
22
22
|
tooltip: 'Paste from clipboard',
|
|
23
23
|
async exec(editor, _, { control }) {
|
|
24
|
+
var _a;
|
|
24
25
|
if (control.name === psKey) {
|
|
25
26
|
editor.execCommand('showPasteStorage');
|
|
26
27
|
return;
|
|
@@ -31,7 +32,15 @@ Config.prototype.controls.paste = {
|
|
|
31
32
|
try {
|
|
32
33
|
const items = await navigator.clipboard.read();
|
|
33
34
|
if (items && items.length) {
|
|
34
|
-
const
|
|
35
|
+
const item = items[0];
|
|
36
|
+
// Prefer the HTML flavor so the button behaves like the
|
|
37
|
+
// Ctrl+V shortcut (which receives text/html from the
|
|
38
|
+
// native paste event). See
|
|
39
|
+
// https://github.com/xdan/jodit/issues/1061
|
|
40
|
+
const type = ((_a = item.types) === null || _a === void 0 ? void 0 : _a.includes(TEXT_HTML))
|
|
41
|
+
? TEXT_HTML
|
|
42
|
+
: TEXT_PLAIN;
|
|
43
|
+
const textBlob = await item.getType(type);
|
|
35
44
|
text = await new Response(textBlob).text();
|
|
36
45
|
}
|
|
37
46
|
error = false;
|
|
@@ -101,20 +101,30 @@ let UISearch = class UISearch extends UIElement {
|
|
|
101
101
|
.on(this.queryInput, 'input', () => {
|
|
102
102
|
this.setMod('empty-query', !trim(this.queryInput.value).length);
|
|
103
103
|
})
|
|
104
|
-
.on(this.queryInput, 'keydown',
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
.on(this.queryInput, 'keydown', (() => {
|
|
105
|
+
const debounced = this.j.async.debounce(async (e) => {
|
|
106
|
+
switch (e.key) {
|
|
107
|
+
case consts.KEY_ENTER:
|
|
108
|
+
if (await jodit.e.fire('searchNext')) {
|
|
109
|
+
this.close();
|
|
110
|
+
}
|
|
111
|
+
break;
|
|
112
|
+
default:
|
|
113
|
+
jodit.e.fire(this, 'needUpdateCounters');
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}, this.j.defaultTimeout);
|
|
117
|
+
return (e) => {
|
|
118
|
+
// Must be canceled synchronously — inside the debounced
|
|
119
|
+
// handler the browser has already submitted the parent
|
|
120
|
+
// form. See https://github.com/xdan/jodit/issues/918
|
|
121
|
+
if (e.key === consts.KEY_ENTER) {
|
|
107
122
|
e.preventDefault();
|
|
108
123
|
e.stopImmediatePropagation();
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
default:
|
|
114
|
-
jodit.e.fire(this, 'needUpdateCounters');
|
|
115
|
-
break;
|
|
116
|
-
}
|
|
117
|
-
}, this.j.defaultTimeout));
|
|
124
|
+
}
|
|
125
|
+
debounced(e);
|
|
126
|
+
};
|
|
127
|
+
})());
|
|
118
128
|
}
|
|
119
129
|
onEditorKeyDown(e) {
|
|
120
130
|
if (!this.isOpened) {
|
|
@@ -120,14 +120,16 @@ export class selectCells extends Plugin {
|
|
|
120
120
|
* Mouse move inside the table
|
|
121
121
|
*/
|
|
122
122
|
__onMove(table, e) {
|
|
123
|
-
var _a;
|
|
123
|
+
var _a, _b;
|
|
124
124
|
if (this.j.o.readonly && !this.j.isLocked) {
|
|
125
125
|
return;
|
|
126
126
|
}
|
|
127
127
|
if (this.j.isLockedNotBy(key)) {
|
|
128
128
|
return;
|
|
129
129
|
}
|
|
130
|
-
|
|
130
|
+
// Inside Shadow DOM `document.elementFromPoint` returns the shadow
|
|
131
|
+
// host, so the lookup must start from the shadow root
|
|
132
|
+
const node = ((_a = this.j.o.shadowRoot) !== null && _a !== void 0 ? _a : this.j.ed).elementFromPoint(e.clientX, e.clientY);
|
|
131
133
|
if (!node) {
|
|
132
134
|
return;
|
|
133
135
|
}
|
|
@@ -150,7 +152,7 @@ export class selectCells extends Plugin {
|
|
|
150
152
|
}
|
|
151
153
|
const cellsCount = this.__tableModule.getAllSelectedCells().length;
|
|
152
154
|
if (cellsCount > 1) {
|
|
153
|
-
(
|
|
155
|
+
(_b = this.j.s.sel) === null || _b === void 0 ? void 0 : _b.removeAllRanges();
|
|
154
156
|
}
|
|
155
157
|
this.j.e.fire('hidePopup');
|
|
156
158
|
e.stopPropagation();
|
|
@@ -184,13 +186,15 @@ export class selectCells extends Plugin {
|
|
|
184
186
|
* Stop a selection process
|
|
185
187
|
*/
|
|
186
188
|
__onStopSelection(table, e) {
|
|
187
|
-
var _a, _b;
|
|
189
|
+
var _a, _b, _c;
|
|
188
190
|
if (!this.__selectedCell) {
|
|
189
191
|
return;
|
|
190
192
|
}
|
|
191
193
|
this.__isSelectionMode = false;
|
|
192
194
|
this.j.unlock();
|
|
193
|
-
|
|
195
|
+
// Inside Shadow DOM `document.elementFromPoint` returns the shadow
|
|
196
|
+
// host, so the lookup must start from the shadow root
|
|
197
|
+
const node = ((_a = this.j.o.shadowRoot) !== null && _a !== void 0 ? _a : this.j.ed).elementFromPoint(e.clientX, e.clientY);
|
|
194
198
|
if (!node) {
|
|
195
199
|
return;
|
|
196
200
|
}
|
|
@@ -206,7 +210,7 @@ export class selectCells extends Plugin {
|
|
|
206
210
|
cell,
|
|
207
211
|
this.__selectedCell
|
|
208
212
|
]), box = this.__tableModule.formalMatrix(table);
|
|
209
|
-
const max = (
|
|
213
|
+
const max = (_b = box[bound[1][0]]) === null || _b === void 0 ? void 0 : _b[bound[1][1]], min = (_c = box[bound[0][0]]) === null || _c === void 0 ? void 0 : _c[bound[0][1]];
|
|
210
214
|
// `getSelectedBound` keeps its `Infinity` sentinel when none of the
|
|
211
215
|
// selected cells belong to this table's matrix — e.g. after a
|
|
212
216
|
// drag-and-drop that moved/removed the cells, leaving a stale anchor and
|
package/package.json
CHANGED
|
@@ -15,6 +15,12 @@ export declare class ToolbarContent<T extends IViewBased = IViewBased> extends U
|
|
|
15
15
|
className(): string;
|
|
16
16
|
/** @override */
|
|
17
17
|
update(): void;
|
|
18
|
+
/**
|
|
19
|
+
* The content is arbitrary HTML — propagate the disabled state to the
|
|
20
|
+
* nested form controls (e.g. the file input of the Upload button),
|
|
21
|
+
* otherwise they stay interactive.
|
|
22
|
+
*/
|
|
23
|
+
protected onChangeDisabled(): void;
|
|
18
24
|
/** @override */
|
|
19
25
|
protected createContainer(): HTMLElement;
|
|
20
26
|
constructor(jodit: T, control: IControlTypeContent, target?: Nullable<HTMLElement>);
|
|
@@ -50,6 +50,13 @@ export declare class inlinePopup extends Plugin {
|
|
|
50
50
|
private __reopenSelectionPopup;
|
|
51
51
|
private __onDocumentMouseDown;
|
|
52
52
|
private __onCloseAllPopups;
|
|
53
|
+
/**
|
|
54
|
+
* The selection rect comes from the editor document — in iframe mode its
|
|
55
|
+
* coordinates are iframe-local, while the popup lives in the host
|
|
56
|
+
* document, so the iframe offset must be added. See
|
|
57
|
+
* https://github.com/xdan/jodit/issues/1058
|
|
58
|
+
*/
|
|
59
|
+
private __selectionBound;
|
|
53
60
|
private snapRange;
|
|
54
61
|
private onSelectionStart;
|
|
55
62
|
private onSelectionEnd;
|