jodit 4.12.20 → 4.12.22
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 +29 -1
- package/es2015/jodit.css +1 -1
- package/es2015/jodit.fat.min.js +8 -8
- package/es2015/jodit.js +155 -36
- package/es2015/jodit.min.js +8 -8
- 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 +8 -8
- package/es2018/jodit.min.js +24 -24
- 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 +9 -9
- package/es2021/jodit.js +154 -35
- package/es2021/jodit.min.js +22 -22
- 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 +9 -9
- package/es2021.en/jodit.js +153 -34
- package/es2021.en/jodit.min.js +11 -11
- 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 +164 -36
- 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/constants.js +1 -1
- package/esm/core/dom/dom.js +6 -4
- package/esm/langs/tr.js +1 -1
- package/esm/modules/dialog/dialog.d.ts +5 -0
- package/esm/modules/dialog/dialog.js +25 -2
- package/esm/plugins/clean-html/clean-html.js +8 -2
- package/esm/plugins/clean-html/helpers/visitor/filters/allow-attributes.js +9 -2
- package/esm/plugins/clipboard/clipboard.js +29 -1
- package/esm/plugins/inline-popup/inline-popup.d.ts +8 -0
- package/esm/plugins/inline-popup/inline-popup.js +43 -2
- package/esm/plugins/limit/limit.js +7 -1
- package/esm/plugins/paste/paste.d.ts +1 -1
- package/esm/plugins/paste/paste.js +7 -5
- package/esm/plugins/resize-handler/resize-handler.js +13 -2
- package/esm/plugins/resizer/resizer.js +5 -1
- package/esm/plugins/source/source.js +9 -0
- package/package.json +1 -1
- package/types/modules/dialog/dialog.d.ts +5 -0
- package/types/plugins/inline-popup/inline-popup.d.ts +8 -0
- package/types/plugins/paste/paste.d.ts +1 -1
package/es5/polyfills.fat.min.js
CHANGED
package/es5/polyfills.js
CHANGED
package/es5/polyfills.min.js
CHANGED
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.22";
|
|
7
7
|
// prettier-ignore
|
|
8
8
|
export const ES = "es2020";
|
|
9
9
|
export const IS_ES_MODERN = true;
|
package/esm/core/dom/dom.js
CHANGED
|
@@ -283,12 +283,12 @@ export class Dom {
|
|
|
283
283
|
* Check if element is element node
|
|
284
284
|
*/
|
|
285
285
|
static isElement(node) {
|
|
286
|
-
var _a;
|
|
287
286
|
if (!Dom.isNode(node)) {
|
|
288
287
|
return false;
|
|
289
288
|
}
|
|
290
|
-
|
|
291
|
-
|
|
289
|
+
// no `defaultView` requirement — nodes of an inert document
|
|
290
|
+
// (`DOMParser`, `implementation.createHTMLDocument`) are still elements
|
|
291
|
+
return node.nodeType === Node.ELEMENT_NODE;
|
|
292
292
|
}
|
|
293
293
|
/**
|
|
294
294
|
* Check if element is document fragment
|
|
@@ -309,8 +309,10 @@ export class Dom {
|
|
|
309
309
|
if (!Dom.isNode(node)) {
|
|
310
310
|
return false;
|
|
311
311
|
}
|
|
312
|
+
// an inert document has no browsing context (`defaultView` is null),
|
|
313
|
+
// but its nodes are same-realm HTMLElements
|
|
312
314
|
const win = (_a = node.ownerDocument) === null || _a === void 0 ? void 0 : _a.defaultView;
|
|
313
|
-
return
|
|
315
|
+
return node instanceof (win ? win.HTMLElement : HTMLElement);
|
|
314
316
|
}
|
|
315
317
|
/**
|
|
316
318
|
* Check element is inline block
|
package/esm/langs/tr.js
CHANGED
|
@@ -85,7 +85,7 @@ export default {
|
|
|
85
85
|
'Insert as Text': 'Yazı olarak ekle',
|
|
86
86
|
'Word Paste Detected': 'Word biçiminde yapıştırma algılandı',
|
|
87
87
|
'The pasted content is coming from a Microsoft Word/Excel document. Do you want to keep the format or clean it up?':
|
|
88
|
-
'
|
|
88
|
+
'Yapıştırılan içerik bir Microsoft Word/Excel belgesinden geliyor. Formatı korumak mı yoksa temizlemek mi istiyorsunuz?',
|
|
89
89
|
'Insert only Text': 'Sadece yazıyı ekle',
|
|
90
90
|
'File Browser': 'Dosya Listeleyici',
|
|
91
91
|
'Error on load list': 'Liste yüklenirken hata oluştu',
|
|
@@ -42,6 +42,11 @@ export declare class Dialog extends ViewWithToolbar implements IDialog {
|
|
|
42
42
|
private __onMouseMove;
|
|
43
43
|
private __onEsc;
|
|
44
44
|
private __onResize;
|
|
45
|
+
/**
|
|
46
|
+
* Minimal size the dialog can be resized to — the header and the footer
|
|
47
|
+
* (with its buttons) must always stay inside the panel
|
|
48
|
+
*/
|
|
49
|
+
private minSize;
|
|
45
50
|
private __onResizerMouseDown;
|
|
46
51
|
private __addGlobalResizeListeners;
|
|
47
52
|
private __removeGlobalResizeListeners;
|
|
@@ -20,7 +20,7 @@ import { autobind, component, hook } from "../../core/decorators/index.js";
|
|
|
20
20
|
import { Dom } from "../../core/dom/dom.js";
|
|
21
21
|
import { eventEmitter, pluginSystem } from "../../core/global.js";
|
|
22
22
|
import { asArray, splitArray, toArray } from "../../core/helpers/array/index.js";
|
|
23
|
-
import { hasContainer, isArray, isBoolean, isFunction, isString, isVoid } from "../../core/helpers/checker/index.js";
|
|
23
|
+
import { hasContainer, isArray, isBoolean, isFunction, isNumber, isString, isVoid } from "../../core/helpers/checker/index.js";
|
|
24
24
|
import { $$, attr, ConfigProto, css } from "../../core/helpers/utils/index.js";
|
|
25
25
|
import { assert } from "../../core/helpers/utils/assert.js";
|
|
26
26
|
import { Icon } from "../../core/ui/index.js";
|
|
@@ -151,7 +151,7 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
|
|
|
151
151
|
e.stopImmediatePropagation();
|
|
152
152
|
}
|
|
153
153
|
if (this.resizable && this.o.resizable) {
|
|
154
|
-
this.setSize(this.startPoint.w + e.clientX - this.startX, this.startPoint.h + e.clientY - this.startY);
|
|
154
|
+
this.setSize(Math.max(this.startPoint.w + e.clientX - this.startX, this.minSize.w), Math.max(this.startPoint.h + e.clientY - this.startY, this.minSize.h));
|
|
155
155
|
if (this.e) {
|
|
156
156
|
/**
|
|
157
157
|
* Fired when dialog box is resized
|
|
@@ -178,11 +178,29 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
|
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
180
|
__onResizerMouseDown(e) {
|
|
181
|
+
var _a, _b, _c;
|
|
181
182
|
this.resizable = true;
|
|
182
183
|
this.startX = e.clientX;
|
|
183
184
|
this.startY = e.clientY;
|
|
184
185
|
this.startPoint.w = this.dialog.offsetWidth;
|
|
185
186
|
this.startPoint.h = this.dialog.offsetHeight;
|
|
187
|
+
const header = this.getElm('header');
|
|
188
|
+
const footer = this.getElm('footer');
|
|
189
|
+
const content = this.getElm('content');
|
|
190
|
+
// the content area does not shrink below its CSS `min-height`,
|
|
191
|
+
// so it is part of the smallest height the panel can take
|
|
192
|
+
const contentMinHeight = content
|
|
193
|
+
? parseFloat(this.ow.getComputedStyle(content).minHeight) || 0
|
|
194
|
+
: 0;
|
|
195
|
+
this.minSize.w = isNumber(this.o.minWidth)
|
|
196
|
+
? this.o.minWidth
|
|
197
|
+
: Math.max(100, (_a = footer === null || footer === void 0 ? void 0 : footer.scrollWidth) !== null && _a !== void 0 ? _a : 0);
|
|
198
|
+
this.minSize.h = isNumber(this.o.minHeight)
|
|
199
|
+
? this.o.minHeight
|
|
200
|
+
: ((_b = header === null || header === void 0 ? void 0 : header.offsetHeight) !== null && _b !== void 0 ? _b : 0) +
|
|
201
|
+
((_c = footer === null || footer === void 0 ? void 0 : footer.offsetHeight) !== null && _c !== void 0 ? _c : 0) +
|
|
202
|
+
contentMinHeight +
|
|
203
|
+
this.resizer.offsetHeight;
|
|
186
204
|
this.lockSelect();
|
|
187
205
|
this.__addGlobalResizeListeners();
|
|
188
206
|
if (this.e) {
|
|
@@ -494,6 +512,11 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
|
|
|
494
512
|
this.setPosition();
|
|
495
513
|
}
|
|
496
514
|
};
|
|
515
|
+
/**
|
|
516
|
+
* Minimal size the dialog can be resized to — the header and the footer
|
|
517
|
+
* (with its buttons) must always stay inside the panel
|
|
518
|
+
*/
|
|
519
|
+
this.minSize = { w: 0, h: 0 };
|
|
497
520
|
this.isModal = false;
|
|
498
521
|
/**
|
|
499
522
|
* True, if dialog was opened
|
|
@@ -86,9 +86,15 @@ export class cleanHtml extends Plugin {
|
|
|
86
86
|
onBeforeSetNativeEditorValue(data) {
|
|
87
87
|
const [sandBox, iframe] = this.j.o.cleanHTML.useIframeSandbox
|
|
88
88
|
? this.j.createInside.sandbox()
|
|
89
|
-
: [
|
|
89
|
+
: [
|
|
90
|
+
// an inert document never loads sub-resources, so the
|
|
91
|
+
// images in the value are not re-requested from the
|
|
92
|
+
// server on every assignment (e.g. on each change in
|
|
93
|
+
// jodit-react). See #1237
|
|
94
|
+
this.j.od.implementation.createHTMLDocument('').body
|
|
95
|
+
];
|
|
90
96
|
sandBox.innerHTML = data.value;
|
|
91
|
-
this.
|
|
97
|
+
this.j.e.fire('safeHTML', sandBox);
|
|
92
98
|
data.value = sandBox.innerHTML;
|
|
93
99
|
safeHTML(sandBox, { safeJavaScriptLink: true, removeOnError: true });
|
|
94
100
|
Dom.safeRemove(iframe);
|
|
@@ -8,12 +8,19 @@ import { Dom } from "../../../../../core/dom/dom.js";
|
|
|
8
8
|
* @private
|
|
9
9
|
*/
|
|
10
10
|
export function allowAttributes(jodit, nodeElm, hadEffect, allow) {
|
|
11
|
-
|
|
11
|
+
const allowedForTag = allow && Dom.isElement(nodeElm) && allow[nodeElm.nodeName];
|
|
12
|
+
if (allow && Dom.isElement(nodeElm) && allowedForTag !== true) {
|
|
13
|
+
// the tag is not in the allow list at all — attributes do not matter,
|
|
14
|
+
// the element itself will be removed by the tags filter. Without this
|
|
15
|
+
// check `allow[nodeName][attr]` threw on e.g. `<meta charset>`. See #1224
|
|
16
|
+
if (!allowedForTag) {
|
|
17
|
+
return hadEffect;
|
|
18
|
+
}
|
|
12
19
|
const attrs = nodeElm.attributes;
|
|
13
20
|
if (attrs && attrs.length) {
|
|
14
21
|
const removeAttrs = [];
|
|
15
22
|
for (let i = 0; i < attrs.length; i += 1) {
|
|
16
|
-
const attr =
|
|
23
|
+
const attr = allowedForTag[attrs[i].name];
|
|
17
24
|
if (!attr || (attr !== true && attr !== attrs[i].value)) {
|
|
18
25
|
removeAttrs.push(attrs[i].name);
|
|
19
26
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { CLIPBOARD_ID, INSERT_AS_HTML, TEXT_HTML, TEXT_PLAIN } from "../../core/constants.js";
|
|
7
7
|
import { cached } from "../../core/decorators/cache/cache.js";
|
|
8
|
+
import { Dom } from "../../core/dom/dom.js";
|
|
8
9
|
import { pluginSystem } from "../../core/global.js";
|
|
9
10
|
import { getDataTransfer, stripTags } from "../../core/helpers/index.js";
|
|
10
11
|
import "./config.js";
|
|
@@ -40,7 +41,7 @@ export class clipboard {
|
|
|
40
41
|
.off(`copy.${CLIPBOARD_ID} cut.${CLIPBOARD_ID}`)
|
|
41
42
|
.on(`copy.${CLIPBOARD_ID} cut.${CLIPBOARD_ID}`, (event) => {
|
|
42
43
|
var _a;
|
|
43
|
-
const selectedText = editor.s.html;
|
|
44
|
+
const selectedText = wrapWithInlineAncestors(editor, editor.s.html);
|
|
44
45
|
const clipboardData = getDataTransfer(event) ||
|
|
45
46
|
getDataTransfer(editor.ew) ||
|
|
46
47
|
getDataTransfer(event.originalEvent);
|
|
@@ -69,4 +70,31 @@ export class clipboard {
|
|
|
69
70
|
(_b = editor === null || editor === void 0 ? void 0 : editor.events) === null || _b === void 0 ? void 0 : _b.off('.' + CLIPBOARD_ID);
|
|
70
71
|
}
|
|
71
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* `Selection.html` clones only the range contents — when the selection sits
|
|
75
|
+
* entirely inside the text of a formatted element (`<strong>te|st|</strong>`),
|
|
76
|
+
* the clone is bare text and the formatting would be lost on paste. Native
|
|
77
|
+
* browser copy keeps that context, so the interception must restore it: wrap
|
|
78
|
+
* the fragment in shallow clones of the inline ancestors of the range. See #1202
|
|
79
|
+
*/
|
|
80
|
+
function wrapWithInlineAncestors(editor, html) {
|
|
81
|
+
if (!html || editor.s.isCollapsed()) {
|
|
82
|
+
return html;
|
|
83
|
+
}
|
|
84
|
+
let node = editor.s.range.commonAncestorContainer;
|
|
85
|
+
if (!Dom.isElement(node)) {
|
|
86
|
+
node = node.parentElement;
|
|
87
|
+
}
|
|
88
|
+
let result = html;
|
|
89
|
+
while (node &&
|
|
90
|
+
node !== editor.editor &&
|
|
91
|
+
Dom.isElement(node) &&
|
|
92
|
+
!Dom.isBlock(node)) {
|
|
93
|
+
const shell = node.cloneNode(false);
|
|
94
|
+
shell.innerHTML = result;
|
|
95
|
+
result = shell.outerHTML;
|
|
96
|
+
node = node.parentElement;
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
72
100
|
pluginSystem.add('clipboard', clipboard);
|
|
@@ -42,6 +42,14 @@ export declare class inlinePopup extends Plugin {
|
|
|
42
42
|
private isExcludedTarget;
|
|
43
43
|
/** @override **/
|
|
44
44
|
protected afterInit(jodit: IJodit): void;
|
|
45
|
+
/**
|
|
46
|
+
* The user pressed a button inside the selection toolbar — after the
|
|
47
|
+
* command fires `closeAllPopups`, the toolbar should be shown again
|
|
48
|
+
* while the selection is still there. See #1238
|
|
49
|
+
*/
|
|
50
|
+
private __reopenSelectionPopup;
|
|
51
|
+
private __onDocumentMouseDown;
|
|
52
|
+
private __onCloseAllPopups;
|
|
45
53
|
private snapRange;
|
|
46
54
|
private onSelectionStart;
|
|
47
55
|
private onSelectionEnd;
|
|
@@ -29,6 +29,12 @@ export class inlinePopup extends Plugin {
|
|
|
29
29
|
constructor() {
|
|
30
30
|
super(...arguments);
|
|
31
31
|
this.type = null;
|
|
32
|
+
/**
|
|
33
|
+
* The user pressed a button inside the selection toolbar — after the
|
|
34
|
+
* command fires `closeAllPopups`, the toolbar should be shown again
|
|
35
|
+
* while the selection is still there. See #1238
|
|
36
|
+
*/
|
|
37
|
+
this.__reopenSelectionPopup = false;
|
|
32
38
|
this.snapRange = null;
|
|
33
39
|
this.elmsList = keys(this.j.o.popup, false).filter(s => !this.isExcludedTarget(s));
|
|
34
40
|
}
|
|
@@ -144,9 +150,36 @@ export class inlinePopup extends Plugin {
|
|
|
144
150
|
this.previousTarget = undefined;
|
|
145
151
|
}
|
|
146
152
|
})
|
|
147
|
-
.on([this.j.ew, this.j.ow], 'mouseup keyup', this.onSelectionEnd)
|
|
153
|
+
.on([this.j.ew, this.j.ow], 'mouseup keyup', this.onSelectionEnd)
|
|
154
|
+
.on([this.j.ew, this.j.ow], 'mousedown touchstart', this.__onDocumentMouseDown)
|
|
155
|
+
.on('closeAllPopups', this.__onCloseAllPopups);
|
|
148
156
|
this.addListenersForElements();
|
|
149
157
|
}
|
|
158
|
+
__onDocumentMouseDown(e) {
|
|
159
|
+
if (this.popup.isOpened &&
|
|
160
|
+
this.type === 'selection' &&
|
|
161
|
+
e.target &&
|
|
162
|
+
UIElement.closestElement(e.target, Popup)) {
|
|
163
|
+
this.__reopenSelectionPopup = true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
__onCloseAllPopups() {
|
|
167
|
+
if (!this.__reopenSelectionPopup) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
this.__reopenSelectionPopup = false;
|
|
171
|
+
if (!this.j.o.toolbarInlineForSelection) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
// a zero timeout would run synchronously — before the popup's own
|
|
175
|
+
// `closeAllPopups` handler closes it; defer to the next macrotask
|
|
176
|
+
this.j.async.setTimeout(() => {
|
|
177
|
+
const sel = this.j.s.sel;
|
|
178
|
+
if (sel && !sel.isCollapsed) {
|
|
179
|
+
this.showPopup(() => this.j.s.range.getBoundingClientRect(), 'selection');
|
|
180
|
+
}
|
|
181
|
+
}, 1);
|
|
182
|
+
}
|
|
150
183
|
onSelectionStart() {
|
|
151
184
|
this.snapRange = this.j.s.range.cloneRange();
|
|
152
185
|
}
|
|
@@ -208,7 +241,9 @@ export class inlinePopup extends Plugin {
|
|
|
208
241
|
beforeDestruct(jodit) {
|
|
209
242
|
jodit.e
|
|
210
243
|
.off('showPopup')
|
|
211
|
-
.off([this.j.ew, this.j.ow], 'mouseup keyup', this.onSelectionEnd)
|
|
244
|
+
.off([this.j.ew, this.j.ow], 'mouseup keyup', this.onSelectionEnd)
|
|
245
|
+
.off([this.j.ew, this.j.ow], 'mousedown touchstart', this.__onDocumentMouseDown)
|
|
246
|
+
.off('closeAllPopups', this.__onCloseAllPopups);
|
|
212
247
|
this.removeListenersForElements();
|
|
213
248
|
}
|
|
214
249
|
_eventsList() {
|
|
@@ -257,6 +292,12 @@ __decorate([
|
|
|
257
292
|
__decorate([
|
|
258
293
|
watch(':outsideClick')
|
|
259
294
|
], inlinePopup.prototype, "onOutsideClick", null);
|
|
295
|
+
__decorate([
|
|
296
|
+
autobind
|
|
297
|
+
], inlinePopup.prototype, "__onDocumentMouseDown", null);
|
|
298
|
+
__decorate([
|
|
299
|
+
autobind
|
|
300
|
+
], inlinePopup.prototype, "__onCloseAllPopups", null);
|
|
260
301
|
__decorate([
|
|
261
302
|
autobind
|
|
262
303
|
], inlinePopup.prototype, "onSelectionStart", null);
|
|
@@ -62,7 +62,13 @@ export class limit extends Plugin {
|
|
|
62
62
|
jodit.e.fire('denyWords.limit limit.limit');
|
|
63
63
|
return true;
|
|
64
64
|
}
|
|
65
|
-
|
|
65
|
+
// with `countTextSpaces` enabled the limiter counts characters the
|
|
66
|
+
// same way as the `stat` plugin's counter — including spaces. See #1144
|
|
67
|
+
const charsCount = jodit.o.countTextSpaces
|
|
68
|
+
? text.replace(INVISIBLE_SPACE_REG_EXP(), '').replace(/[\r\n]/g, '')
|
|
69
|
+
.length
|
|
70
|
+
: words.join('').length;
|
|
71
|
+
const should = Boolean(limitChars && isGt(charsCount, limitChars, strict));
|
|
66
72
|
if (should) {
|
|
67
73
|
jodit.e.fire('denyChars.limit limit.limit');
|
|
68
74
|
}
|
|
@@ -38,9 +38,7 @@ export class paste extends Plugin {
|
|
|
38
38
|
jodit.e
|
|
39
39
|
.on('paste.paste', this.onPaste)
|
|
40
40
|
.on('pasteStack.paste', (item) => this.pasteStack.push(item));
|
|
41
|
-
|
|
42
|
-
this.j.e.on('processPaste.paste', this.onProcessPasteReplaceNl2Br);
|
|
43
|
-
}
|
|
41
|
+
this.j.e.on('processPaste.paste', this.onProcessPasteReplaceNl2Br);
|
|
44
42
|
}
|
|
45
43
|
/** @override **/
|
|
46
44
|
beforeDestruct(jodit) {
|
|
@@ -169,11 +167,15 @@ export class paste extends Plugin {
|
|
|
169
167
|
pasteInsertHtml(e, this.j, html);
|
|
170
168
|
}
|
|
171
169
|
/**
|
|
172
|
-
*
|
|
170
|
+
* Escape plain text and replace all \\n chars with br
|
|
173
171
|
*/
|
|
174
172
|
onProcessPasteReplaceNl2Br(ignore, text, type) {
|
|
175
173
|
if (type === TEXT_PLAIN + ';' && !isHTML(text)) {
|
|
176
|
-
|
|
174
|
+
// the clipboard contains only plain text — escape special chars
|
|
175
|
+
// so a stray `<` is not parsed as an unclosed tag and does not
|
|
176
|
+
// swallow the rest of the string. See #1227
|
|
177
|
+
const escaped = htmlspecialchars(text);
|
|
178
|
+
return this.j.o.nl2brInPlainText ? nl2br(escaped) : escaped;
|
|
177
179
|
}
|
|
178
180
|
}
|
|
179
181
|
}
|
|
@@ -16,6 +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 { offset } from "../../core/helpers/index.js";
|
|
19
20
|
import { Plugin } from "../../core/plugin/index.js";
|
|
20
21
|
import { Icon } from "../../core/ui/index.js";
|
|
21
22
|
import "./config.js";
|
|
@@ -82,11 +83,21 @@ export class resizeHandler extends Plugin {
|
|
|
82
83
|
if (!this.isResized) {
|
|
83
84
|
return;
|
|
84
85
|
}
|
|
86
|
+
let { clientX, clientY } = e;
|
|
87
|
+
if (e.view === this.j.ew && this.j.ew !== this.j.ow) {
|
|
88
|
+
// the event was proxied from the editor's iframe — its client
|
|
89
|
+
// coordinates are relative to the iframe viewport, while the
|
|
90
|
+
// start point was captured on the host-document handle;
|
|
91
|
+
// shift them into the host coordinate space
|
|
92
|
+
const workplacePosition = offset(this.j.workplace, this.j, this.j.od, true);
|
|
93
|
+
clientX += workplacePosition.left;
|
|
94
|
+
clientY += workplacePosition.top;
|
|
95
|
+
}
|
|
85
96
|
if (this.j.o.allowResizeY) {
|
|
86
|
-
this.j.e.fire('setHeight', this.start.h +
|
|
97
|
+
this.j.e.fire('setHeight', this.start.h + clientY - this.start.y);
|
|
87
98
|
}
|
|
88
99
|
if (this.j.o.allowResizeX) {
|
|
89
|
-
this.j.e.fire('setWidth', this.start.w +
|
|
100
|
+
this.j.e.fire('setWidth', this.start.w + clientX - this.start.x);
|
|
90
101
|
}
|
|
91
102
|
this.j.e.fire('resize');
|
|
92
103
|
}
|
|
@@ -202,7 +202,11 @@ export class resizer extends Plugin {
|
|
|
202
202
|
this.pointerX = e.clientX;
|
|
203
203
|
this.pointerY = e.clientY;
|
|
204
204
|
let diff_x, diff_y;
|
|
205
|
-
if (this.j.options.iframe) {
|
|
205
|
+
if (this.j.options.iframe && e.view === this.j.ew) {
|
|
206
|
+
// the event was proxied from the editor's iframe — its client
|
|
207
|
+
// coordinates are relative to the iframe viewport, while
|
|
208
|
+
// `startX/startY` were captured on a host-document handle;
|
|
209
|
+
// shift them into the host coordinate space
|
|
206
210
|
const workplacePosition = this.getWorkplacePosition();
|
|
207
211
|
diff_x = e.clientX + workplacePosition.left - this.startX;
|
|
208
212
|
diff_y = e.clientY + workplacePosition.top - this.startY;
|
|
@@ -134,6 +134,15 @@ export class source extends Plugin {
|
|
|
134
134
|
}
|
|
135
135
|
setFocusToMirror() {
|
|
136
136
|
var _a;
|
|
137
|
+
const active = this.j.od.activeElement;
|
|
138
|
+
// do not steal focus from another editor or control — e.g. when the
|
|
139
|
+
// mode is switched programmatically (a Vue/React wrapper re-render)
|
|
140
|
+
// while the user is already typing elsewhere. See #1356
|
|
141
|
+
if (active &&
|
|
142
|
+
active !== this.j.od.body &&
|
|
143
|
+
!this.j.container.contains(active)) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
137
146
|
(_a = this.sourceEditor) === null || _a === void 0 ? void 0 : _a.focus();
|
|
138
147
|
}
|
|
139
148
|
saveSelection() {
|
package/package.json
CHANGED
|
@@ -42,6 +42,11 @@ export declare class Dialog extends ViewWithToolbar implements IDialog {
|
|
|
42
42
|
private __onMouseMove;
|
|
43
43
|
private __onEsc;
|
|
44
44
|
private __onResize;
|
|
45
|
+
/**
|
|
46
|
+
* Minimal size the dialog can be resized to — the header and the footer
|
|
47
|
+
* (with its buttons) must always stay inside the panel
|
|
48
|
+
*/
|
|
49
|
+
private minSize;
|
|
45
50
|
private __onResizerMouseDown;
|
|
46
51
|
private __addGlobalResizeListeners;
|
|
47
52
|
private __removeGlobalResizeListeners;
|
|
@@ -42,6 +42,14 @@ export declare class inlinePopup extends Plugin {
|
|
|
42
42
|
private isExcludedTarget;
|
|
43
43
|
/** @override **/
|
|
44
44
|
protected afterInit(jodit: IJodit): void;
|
|
45
|
+
/**
|
|
46
|
+
* The user pressed a button inside the selection toolbar — after the
|
|
47
|
+
* command fires `closeAllPopups`, the toolbar should be shown again
|
|
48
|
+
* while the selection is still there. See #1238
|
|
49
|
+
*/
|
|
50
|
+
private __reopenSelectionPopup;
|
|
51
|
+
private __onDocumentMouseDown;
|
|
52
|
+
private __onCloseAllPopups;
|
|
45
53
|
private snapRange;
|
|
46
54
|
private onSelectionStart;
|
|
47
55
|
private onSelectionEnd;
|