jodit 4.12.44 → 4.13.3
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 +6 -1
- package/es2015/jodit.css +6 -1
- package/es2015/jodit.fat.min.css +1 -1
- package/es2015/jodit.fat.min.js +14 -14
- package/es2015/jodit.js +156 -17
- package/es2015/jodit.min.css +1 -1
- package/es2015/jodit.min.js +5 -5
- 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 +3 -3
- package/es2018/jodit.min.css +1 -1
- package/es2018/jodit.min.js +5 -5
- package/es2018/plugins/debug/debug.min.js +1 -1
- package/es2018/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es2021/jodit.css +6 -1
- package/es2021/jodit.fat.min.css +1 -1
- package/es2021/jodit.fat.min.js +4 -4
- package/es2021/jodit.js +147 -17
- package/es2021/jodit.min.css +1 -1
- package/es2021/jodit.min.js +6 -6
- 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 +6 -1
- package/es2021.en/jodit.fat.min.css +1 -1
- package/es2021.en/jodit.fat.min.js +5 -5
- package/es2021.en/jodit.js +147 -17
- package/es2021.en/jodit.min.css +1 -1
- package/es2021.en/jodit.min.js +5 -5
- 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 +7 -2
- package/es5/jodit.fat.min.css +1 -1
- package/es5/jodit.fat.min.js +2 -2
- package/es5/jodit.js +192 -17
- 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/core/constants.js +1 -1
- package/esm/core/selection/selection.d.ts +31 -0
- package/esm/core/selection/selection.js +143 -14
- package/esm/core/view/view-with-toolbar.d.ts +6 -0
- package/esm/core/view/view-with-toolbar.js +18 -2
- package/esm/jodit.js +7 -0
- package/esm/types/jodit.d.ts +2 -0
- package/package.json +1 -1
- package/types/core/selection/selection.d.ts +31 -0
- package/types/core/view/view-with-toolbar.d.ts +6 -0
- package/types/types/jodit.d.ts +2 -0
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.
|
|
6
|
+
export const APP_VERSION = "4.13.3";
|
|
7
7
|
// prettier-ignore
|
|
8
8
|
export const ES = "es2020";
|
|
9
9
|
export const IS_ES_MODERN = true;
|
|
@@ -224,6 +224,37 @@ export declare class Selection implements ISelect {
|
|
|
224
224
|
* ```
|
|
225
225
|
*/
|
|
226
226
|
get html(): string;
|
|
227
|
+
/**
|
|
228
|
+
* Splits the boundaries of the current selection and wraps every
|
|
229
|
+
* contiguous run of selected inline content (grouped by block) into a
|
|
230
|
+
* `<font>` element, returning those wrappers in document order.
|
|
231
|
+
*
|
|
232
|
+
* This is a pure-DOM replacement for the old
|
|
233
|
+
* `nativeExecCommand('fontsize', false, '7')` trick which relied on the
|
|
234
|
+
* browser to split the selection into `<font size="7">` fragments.
|
|
235
|
+
*/
|
|
236
|
+
private __wrapSelectionFragments;
|
|
237
|
+
/**
|
|
238
|
+
* Splits the text nodes at both ends of the range so that its boundaries
|
|
239
|
+
* always fall between nodes. Afterwards every node inside the range is
|
|
240
|
+
* fully (not partially) selected.
|
|
241
|
+
*/
|
|
242
|
+
private __splitSelectionBoundaries;
|
|
243
|
+
private __normalizeRangeBoundary;
|
|
244
|
+
/**
|
|
245
|
+
* Collects the highest-level nodes that are completely inside the range,
|
|
246
|
+
* descending into nodes that are only partially selected.
|
|
247
|
+
*/
|
|
248
|
+
private __collectContainedNodes;
|
|
249
|
+
private __isFullyContained;
|
|
250
|
+
/**
|
|
251
|
+
* Wraps every contiguous run of selected inline siblings into a `<font>`
|
|
252
|
+
* element. Block-level nodes are never wrapped themselves - their inline
|
|
253
|
+
* content is wrapped instead, keeping every `<font>` inside a single block.
|
|
254
|
+
*/
|
|
255
|
+
private __wrapSelectionRuns;
|
|
256
|
+
private __isOrContainsBlock;
|
|
257
|
+
private __wrapRunInFont;
|
|
227
258
|
/**
|
|
228
259
|
* Wrap all selected fragments inside Tag or apply some callback
|
|
229
260
|
*/
|
|
@@ -898,6 +898,148 @@ export class Selection {
|
|
|
898
898
|
}
|
|
899
899
|
return '';
|
|
900
900
|
}
|
|
901
|
+
/**
|
|
902
|
+
* Splits the boundaries of the current selection and wraps every
|
|
903
|
+
* contiguous run of selected inline content (grouped by block) into a
|
|
904
|
+
* `<font>` element, returning those wrappers in document order.
|
|
905
|
+
*
|
|
906
|
+
* This is a pure-DOM replacement for the old
|
|
907
|
+
* `nativeExecCommand('fontsize', false, '7')` trick which relied on the
|
|
908
|
+
* browser to split the selection into `<font size="7">` fragments.
|
|
909
|
+
*/
|
|
910
|
+
__wrapSelectionFragments() {
|
|
911
|
+
const range = this.range;
|
|
912
|
+
this.__splitSelectionBoundaries(range);
|
|
913
|
+
let root = range.commonAncestorContainer;
|
|
914
|
+
if (Dom.isText(root)) {
|
|
915
|
+
root = root.parentNode;
|
|
916
|
+
}
|
|
917
|
+
if (!root) {
|
|
918
|
+
return [];
|
|
919
|
+
}
|
|
920
|
+
return this.__wrapSelectionRuns(this.__collectContainedNodes(root, range));
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* Splits the text nodes at both ends of the range so that its boundaries
|
|
924
|
+
* always fall between nodes. Afterwards every node inside the range is
|
|
925
|
+
* fully (not partially) selected.
|
|
926
|
+
*/
|
|
927
|
+
__splitSelectionBoundaries(range) {
|
|
928
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
929
|
+
let { startContainer, endContainer } = range;
|
|
930
|
+
let { startOffset, endOffset } = range;
|
|
931
|
+
if (Dom.isText(endContainer) &&
|
|
932
|
+
endOffset > 0 &&
|
|
933
|
+
endOffset < ((_b = (_a = endContainer.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0)) {
|
|
934
|
+
endContainer.splitText(endOffset);
|
|
935
|
+
endOffset = (_d = (_c = endContainer.nodeValue) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : endOffset;
|
|
936
|
+
}
|
|
937
|
+
if (Dom.isText(startContainer) &&
|
|
938
|
+
startOffset > 0 &&
|
|
939
|
+
startOffset < ((_f = (_e = startContainer.nodeValue) === null || _e === void 0 ? void 0 : _e.length) !== null && _f !== void 0 ? _f : 0)) {
|
|
940
|
+
const middle = startContainer.splitText(startOffset);
|
|
941
|
+
// Selection located inside a single text node - the tail we just
|
|
942
|
+
// cut off is the actual selected fragment.
|
|
943
|
+
if (startContainer === endContainer) {
|
|
944
|
+
endContainer = middle;
|
|
945
|
+
endOffset = (_h = (_g = middle.nodeValue) === null || _g === void 0 ? void 0 : _g.length) !== null && _h !== void 0 ? _h : 0;
|
|
946
|
+
}
|
|
947
|
+
startContainer = middle;
|
|
948
|
+
startOffset = 0;
|
|
949
|
+
}
|
|
950
|
+
range.setStart(startContainer, startOffset);
|
|
951
|
+
range.setEnd(endContainer, endOffset);
|
|
952
|
+
// Normalize text-edge boundaries (e.g. `(text, 0)` or `(text, length)`)
|
|
953
|
+
// to the element level so that containment checks based on
|
|
954
|
+
// `selectNode()` treat a fully selected text node as contained.
|
|
955
|
+
this.__normalizeRangeBoundary(range, true);
|
|
956
|
+
this.__normalizeRangeBoundary(range, false);
|
|
957
|
+
}
|
|
958
|
+
__normalizeRangeBoundary(range, atStart) {
|
|
959
|
+
var _a, _b;
|
|
960
|
+
const container = atStart ? range.startContainer : range.endContainer;
|
|
961
|
+
if (!Dom.isText(container)) {
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
964
|
+
const offset = atStart ? range.startOffset : range.endOffset;
|
|
965
|
+
const length = (_b = (_a = container.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
|
|
966
|
+
if (offset === 0) {
|
|
967
|
+
atStart
|
|
968
|
+
? range.setStartBefore(container)
|
|
969
|
+
: range.setEndBefore(container);
|
|
970
|
+
}
|
|
971
|
+
else if (offset >= length) {
|
|
972
|
+
atStart
|
|
973
|
+
? range.setStartAfter(container)
|
|
974
|
+
: range.setEndAfter(container);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
/**
|
|
978
|
+
* Collects the highest-level nodes that are completely inside the range,
|
|
979
|
+
* descending into nodes that are only partially selected.
|
|
980
|
+
*/
|
|
981
|
+
__collectContainedNodes(root, range) {
|
|
982
|
+
const result = [];
|
|
983
|
+
toArray(root.childNodes).forEach(child => {
|
|
984
|
+
if (this.__isFullyContained(range, child)) {
|
|
985
|
+
result.push(child);
|
|
986
|
+
}
|
|
987
|
+
else if (child.childNodes.length && range.intersectsNode(child)) {
|
|
988
|
+
result.push(...this.__collectContainedNodes(child, range));
|
|
989
|
+
}
|
|
990
|
+
});
|
|
991
|
+
return result;
|
|
992
|
+
}
|
|
993
|
+
__isFullyContained(range, node) {
|
|
994
|
+
const nodeRange = this.createRange();
|
|
995
|
+
nodeRange.selectNode(node);
|
|
996
|
+
return (range.compareBoundaryPoints(Range.START_TO_START, nodeRange) <= 0 &&
|
|
997
|
+
range.compareBoundaryPoints(Range.END_TO_END, nodeRange) >= 0);
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* Wraps every contiguous run of selected inline siblings into a `<font>`
|
|
1001
|
+
* element. Block-level nodes are never wrapped themselves - their inline
|
|
1002
|
+
* content is wrapped instead, keeping every `<font>` inside a single block.
|
|
1003
|
+
*/
|
|
1004
|
+
__wrapSelectionRuns(nodes) {
|
|
1005
|
+
const fonts = [];
|
|
1006
|
+
let run = [];
|
|
1007
|
+
const flush = () => {
|
|
1008
|
+
if (run.length) {
|
|
1009
|
+
fonts.push(this.__wrapRunInFont(run));
|
|
1010
|
+
run = [];
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
1013
|
+
nodes.forEach(node => {
|
|
1014
|
+
if (Dom.isElement(node) && this.__isOrContainsBlock(node)) {
|
|
1015
|
+
flush();
|
|
1016
|
+
fonts.push(...this.__wrapSelectionRuns(toArray(node.childNodes)));
|
|
1017
|
+
}
|
|
1018
|
+
else {
|
|
1019
|
+
if (run.length &&
|
|
1020
|
+
run[run.length - 1].parentNode !== node.parentNode) {
|
|
1021
|
+
flush();
|
|
1022
|
+
}
|
|
1023
|
+
run.push(node);
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
1026
|
+
flush();
|
|
1027
|
+
return fonts;
|
|
1028
|
+
}
|
|
1029
|
+
__isOrContainsBlock(node) {
|
|
1030
|
+
if (Dom.isBlock(node)) {
|
|
1031
|
+
return true;
|
|
1032
|
+
}
|
|
1033
|
+
return toArray(node.childNodes).some(child => this.__isOrContainsBlock(child));
|
|
1034
|
+
}
|
|
1035
|
+
__wrapRunInFont(run) {
|
|
1036
|
+
var _a;
|
|
1037
|
+
const font = this.j.createInside.element('font');
|
|
1038
|
+
const [first] = run;
|
|
1039
|
+
(_a = first.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(font, first);
|
|
1040
|
+
run.forEach(node => font.appendChild(node));
|
|
1041
|
+
return font;
|
|
1042
|
+
}
|
|
901
1043
|
/**
|
|
902
1044
|
* Wrap all selected fragments inside Tag or apply some callback
|
|
903
1045
|
*/
|
|
@@ -912,20 +1054,7 @@ export class Selection {
|
|
|
912
1054
|
Dom.unwrap(font);
|
|
913
1055
|
return;
|
|
914
1056
|
}
|
|
915
|
-
|
|
916
|
-
$$('*[style*=font-size]', this.area).forEach(elm => {
|
|
917
|
-
attr(elm, 'data-font-size', elm.style.fontSize.toString());
|
|
918
|
-
elm.style.removeProperty('font-size');
|
|
919
|
-
});
|
|
920
|
-
this.j.nativeExecCommand('fontsize', false, '7');
|
|
921
|
-
$$('*[data-font-size]', this.area).forEach(elm => {
|
|
922
|
-
const fontSize = attr(elm, 'data-font-size');
|
|
923
|
-
if (fontSize) {
|
|
924
|
-
elm.style.fontSize = fontSize;
|
|
925
|
-
attr(elm, 'data-font-size', null);
|
|
926
|
-
}
|
|
927
|
-
});
|
|
928
|
-
const elms = $$('font[size="7"]', this.area);
|
|
1057
|
+
const elms = this.__wrapSelectionFragments();
|
|
929
1058
|
for (const font of elms) {
|
|
930
1059
|
const { firstChild, lastChild } = font;
|
|
931
1060
|
if (firstChild &&
|
|
@@ -16,6 +16,12 @@ export declare abstract class ViewWithToolbar extends View implements IViewWithT
|
|
|
16
16
|
* Container for toolbar
|
|
17
17
|
*/
|
|
18
18
|
get toolbarContainer(): HTMLElement;
|
|
19
|
+
/**
|
|
20
|
+
* Keep the toolbar box as the first child of the container, except that
|
|
21
|
+
* children flagged with `data-jodit-above-toolbar` (e.g. the `above`
|
|
22
|
+
* workplace slot used for presence bars and banners) stay above it.
|
|
23
|
+
*/
|
|
24
|
+
private __appendToolbarBox;
|
|
19
25
|
/**
|
|
20
26
|
* Change panel container
|
|
21
27
|
*/
|
|
@@ -33,10 +33,26 @@ export class ViewWithToolbar extends View {
|
|
|
33
33
|
(isString(this.o.toolbar) || Dom.isHTMLElement(this.o.toolbar))) {
|
|
34
34
|
return resolveElement(this.o.toolbar, this.o.shadowRoot || this.od);
|
|
35
35
|
}
|
|
36
|
-
this.o.toolbar &&
|
|
37
|
-
Dom.appendChildFirst(this.container, this.__defaultToolbarContainer);
|
|
36
|
+
this.o.toolbar && this.__appendToolbarBox();
|
|
38
37
|
return this.__defaultToolbarContainer;
|
|
39
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Keep the toolbar box as the first child of the container, except that
|
|
41
|
+
* children flagged with `data-jodit-above-toolbar` (e.g. the `above`
|
|
42
|
+
* workplace slot used for presence bars and banners) stay above it.
|
|
43
|
+
*/
|
|
44
|
+
__appendToolbarBox() {
|
|
45
|
+
const box = this.__defaultToolbarContainer;
|
|
46
|
+
let anchor = this.container.firstElementChild;
|
|
47
|
+
while (anchor &&
|
|
48
|
+
anchor !== box &&
|
|
49
|
+
anchor.hasAttribute('data-jodit-above-toolbar')) {
|
|
50
|
+
anchor = anchor.nextElementSibling;
|
|
51
|
+
}
|
|
52
|
+
if (anchor !== box) {
|
|
53
|
+
this.container.insertBefore(box, anchor);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
40
56
|
/**
|
|
41
57
|
* Change panel container
|
|
42
58
|
*/
|
package/esm/jodit.js
CHANGED
|
@@ -1016,6 +1016,12 @@ let Jodit = Jodit_1 = class Jodit extends ViewWithToolbar {
|
|
|
1016
1016
|
element.style.display = 'none';
|
|
1017
1017
|
}
|
|
1018
1018
|
const SLOT = 'workplace-slot';
|
|
1019
|
+
// A slot that always stays ABOVE the toolbar (presence bars, banners…).
|
|
1020
|
+
// The `data-jodit-above-toolbar` attribute tells ViewWithToolbar to keep
|
|
1021
|
+
// the toolbar box below it when (re)attaching the toolbar container.
|
|
1022
|
+
const aboveSlot = this.c.div(this.getFullElName(SLOT, 'above'), NOEDIT);
|
|
1023
|
+
aboveSlot.setAttribute('data-jodit-above-toolbar', '');
|
|
1024
|
+
Dom.appendChildFirst(container, aboveSlot);
|
|
1019
1025
|
const topSlot = this.c.div(this.getFullElName(SLOT, 'top'), NOEDIT);
|
|
1020
1026
|
container.appendChild(topSlot);
|
|
1021
1027
|
const centerSlot = this.c.div(this.getFullElName(SLOT, 'center'), NOEDIT);
|
|
@@ -1048,6 +1054,7 @@ let Jodit = Jodit_1 = class Jodit extends ViewWithToolbar {
|
|
|
1048
1054
|
container,
|
|
1049
1055
|
workplace,
|
|
1050
1056
|
slots: {
|
|
1057
|
+
above: aboveSlot,
|
|
1051
1058
|
top: topSlot,
|
|
1052
1059
|
bottom: bottomPanel,
|
|
1053
1060
|
center: centerSlot,
|
package/esm/types/jodit.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -224,6 +224,37 @@ export declare class Selection implements ISelect {
|
|
|
224
224
|
* ```
|
|
225
225
|
*/
|
|
226
226
|
get html(): string;
|
|
227
|
+
/**
|
|
228
|
+
* Splits the boundaries of the current selection and wraps every
|
|
229
|
+
* contiguous run of selected inline content (grouped by block) into a
|
|
230
|
+
* `<font>` element, returning those wrappers in document order.
|
|
231
|
+
*
|
|
232
|
+
* This is a pure-DOM replacement for the old
|
|
233
|
+
* `nativeExecCommand('fontsize', false, '7')` trick which relied on the
|
|
234
|
+
* browser to split the selection into `<font size="7">` fragments.
|
|
235
|
+
*/
|
|
236
|
+
private __wrapSelectionFragments;
|
|
237
|
+
/**
|
|
238
|
+
* Splits the text nodes at both ends of the range so that its boundaries
|
|
239
|
+
* always fall between nodes. Afterwards every node inside the range is
|
|
240
|
+
* fully (not partially) selected.
|
|
241
|
+
*/
|
|
242
|
+
private __splitSelectionBoundaries;
|
|
243
|
+
private __normalizeRangeBoundary;
|
|
244
|
+
/**
|
|
245
|
+
* Collects the highest-level nodes that are completely inside the range,
|
|
246
|
+
* descending into nodes that are only partially selected.
|
|
247
|
+
*/
|
|
248
|
+
private __collectContainedNodes;
|
|
249
|
+
private __isFullyContained;
|
|
250
|
+
/**
|
|
251
|
+
* Wraps every contiguous run of selected inline siblings into a `<font>`
|
|
252
|
+
* element. Block-level nodes are never wrapped themselves - their inline
|
|
253
|
+
* content is wrapped instead, keeping every `<font>` inside a single block.
|
|
254
|
+
*/
|
|
255
|
+
private __wrapSelectionRuns;
|
|
256
|
+
private __isOrContainsBlock;
|
|
257
|
+
private __wrapRunInFont;
|
|
227
258
|
/**
|
|
228
259
|
* Wrap all selected fragments inside Tag or apply some callback
|
|
229
260
|
*/
|
|
@@ -16,6 +16,12 @@ export declare abstract class ViewWithToolbar extends View implements IViewWithT
|
|
|
16
16
|
* Container for toolbar
|
|
17
17
|
*/
|
|
18
18
|
get toolbarContainer(): HTMLElement;
|
|
19
|
+
/**
|
|
20
|
+
* Keep the toolbar box as the first child of the container, except that
|
|
21
|
+
* children flagged with `data-jodit-above-toolbar` (e.g. the `above`
|
|
22
|
+
* workplace slot used for presence bars and banners) stay above it.
|
|
23
|
+
*/
|
|
24
|
+
private __appendToolbarBox;
|
|
19
25
|
/**
|
|
20
26
|
* Change panel container
|
|
21
27
|
*/
|
package/types/types/jodit.d.ts
CHANGED