jodit 4.17.0 → 4.17.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/CHANGELOG.md +12 -0
- package/es2015/jodit.css +1 -1
- package/es2015/jodit.fat.min.js +3 -3
- package/es2015/jodit.js +171 -12
- package/es2015/jodit.min.js +3 -3
- 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 +3 -3
- package/es2018/jodit.min.js +3 -3
- 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 +5 -5
- package/es2021/jodit.js +171 -12
- package/es2021/jodit.min.js +5 -5
- 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 +24 -24
- package/es2021.en/jodit.js +171 -12
- 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 +2 -2
- package/es5/jodit.fat.min.js +2 -2
- package/es5/jodit.js +186 -12
- 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/helpers/html/safe-html.d.ts +1 -1
- package/esm/core/helpers/html/safe-html.js +8 -1
- package/esm/core/selection/helpers/composed-ranges.d.ts +21 -0
- package/esm/core/selection/helpers/composed-ranges.js +45 -0
- package/esm/core/selection/helpers/index.d.ts +1 -0
- package/esm/core/selection/helpers/index.js +1 -0
- package/esm/core/selection/selection.d.ts +23 -0
- package/esm/core/selection/selection.js +80 -4
- package/esm/plugins/drag-and-drop/drag-and-drop.js +16 -4
- package/package.json +1 -1
- package/types/core/helpers/html/safe-html.d.ts +1 -1
- package/types/core/selection/helpers/composed-ranges.d.ts +21 -0
- package/types/core/selection/helpers/index.d.ts +1 -0
- package/types/core/selection/selection.d.ts +23 -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.17.
|
|
6
|
+
export const APP_VERSION = "4.17.2";
|
|
7
7
|
// prettier-ignore
|
|
8
8
|
export const ES = "es2020";
|
|
9
9
|
export const IS_ES_MODERN = true;
|
|
@@ -13,4 +13,4 @@ export type safeOptions = {
|
|
|
13
13
|
* Removes dangerous constructs from HTML
|
|
14
14
|
*/
|
|
15
15
|
export declare function safeHTML(box: HTMLElement | DocumentFragment, options: safeOptions): void;
|
|
16
|
-
export declare function sanitizeHTMLElement(elm: Element | DocumentFragment, { safeJavaScriptLink, removeOnError }?: safeOptions): boolean;
|
|
16
|
+
export declare function sanitizeHTMLElement(elm: Element | DocumentFragment, { safeJavaScriptLink, removeOnError, removeEventAttributes }?: safeOptions): boolean;
|
|
@@ -145,7 +145,7 @@ function isDangerousUrl(value, tagName) {
|
|
|
145
145
|
}
|
|
146
146
|
return (/^data:image\/svg/.test(normalized) && DOCUMENT_EMBED_TAGS.has(tagName));
|
|
147
147
|
}
|
|
148
|
-
export function sanitizeHTMLElement(elm, { safeJavaScriptLink, removeOnError } = {
|
|
148
|
+
export function sanitizeHTMLElement(elm, { safeJavaScriptLink, removeOnError, removeEventAttributes } = {
|
|
149
149
|
safeJavaScriptLink: true,
|
|
150
150
|
removeOnError: true
|
|
151
151
|
}) {
|
|
@@ -153,6 +153,13 @@ export function sanitizeHTMLElement(elm, { safeJavaScriptLink, removeOnError } =
|
|
|
153
153
|
return false;
|
|
154
154
|
}
|
|
155
155
|
let effected = false;
|
|
156
|
+
// Every `on*` handler, not only `onerror`: the clean-html background
|
|
157
|
+
// pass calls this directly, and markup that reached the editable area
|
|
158
|
+
// without `safeHTML` (a drop, a script) kept its handlers otherwise.
|
|
159
|
+
// See GHSA-jhhp-r3r7-v2cg
|
|
160
|
+
if (removeEventAttributes && removeAllEventAttributes(elm)) {
|
|
161
|
+
effected = true;
|
|
162
|
+
}
|
|
156
163
|
if (removeOnError && elm.hasAttribute('onerror')) {
|
|
157
164
|
attr(elm, 'onerror', null);
|
|
158
165
|
effected = true;
|
|
@@ -0,0 +1,21 @@
|
|
|
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-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* @module selection
|
|
8
|
+
*/
|
|
9
|
+
import type { Nullable } from "../../../types/index";
|
|
10
|
+
/**
|
|
11
|
+
* Ranges of a selection that lies inside the given shadow tree.
|
|
12
|
+
*
|
|
13
|
+
* `window.getSelection()` stops at the shadow boundary and reports the host
|
|
14
|
+
* instead of the node the caret is really in. `getComposedRanges` is the
|
|
15
|
+
* standard way to ask past that boundary.
|
|
16
|
+
*
|
|
17
|
+
* @returns `null` when the browser has no `getComposedRanges`, or when neither
|
|
18
|
+
* call shape returned ranges that point inside the shadow tree — in which case
|
|
19
|
+
* there is nothing better to offer than the plain window selection.
|
|
20
|
+
*/
|
|
21
|
+
export declare function composedRanges(selection: Selection, shadowRoot: ShadowRoot): Nullable<StaticRange[]>;
|
|
@@ -0,0 +1,45 @@
|
|
|
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-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
import { isFunction } from "../../helpers/checker/index.js";
|
|
7
|
+
function isInside(node, shadowRoot) {
|
|
8
|
+
return node === shadowRoot || shadowRoot.contains(node);
|
|
9
|
+
}
|
|
10
|
+
function usable(ranges, shadowRoot) {
|
|
11
|
+
return (Array.isArray(ranges) &&
|
|
12
|
+
ranges.length > 0 &&
|
|
13
|
+
ranges.every(range => isInside(range.startContainer, shadowRoot)));
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Ranges of a selection that lies inside the given shadow tree.
|
|
17
|
+
*
|
|
18
|
+
* `window.getSelection()` stops at the shadow boundary and reports the host
|
|
19
|
+
* instead of the node the caret is really in. `getComposedRanges` is the
|
|
20
|
+
* standard way to ask past that boundary.
|
|
21
|
+
*
|
|
22
|
+
* @returns `null` when the browser has no `getComposedRanges`, or when neither
|
|
23
|
+
* call shape returned ranges that point inside the shadow tree — in which case
|
|
24
|
+
* there is nothing better to offer than the plain window selection.
|
|
25
|
+
*/
|
|
26
|
+
export function composedRanges(selection, shadowRoot) {
|
|
27
|
+
const getComposedRanges = selection.getComposedRanges;
|
|
28
|
+
if (!isFunction(getComposedRanges)) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
for (const args of [[{ shadowRoots: [shadowRoot] }], [shadowRoot]]) {
|
|
32
|
+
let ranges;
|
|
33
|
+
try {
|
|
34
|
+
ranges = getComposedRanges.apply(selection, args);
|
|
35
|
+
}
|
|
36
|
+
catch (_a) {
|
|
37
|
+
// A build that only knows the other shape throws on this one.
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (usable(ranges, shadowRoot)) {
|
|
41
|
+
return ranges;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
@@ -3,6 +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 * from "./composed-ranges";
|
|
6
7
|
export * from "./move-node-inside-start";
|
|
7
8
|
export * from "./move-the-node-along-the-edge-outward";
|
|
8
9
|
/**
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { INVISIBLE_SPACE_REG_EXP_END as INV_END, INVISIBLE_SPACE_REG_EXP_START as INV_START } from "../../constants.js";
|
|
10
10
|
import { Dom } from "../../dom/dom.js";
|
|
11
|
+
export * from "./composed-ranges.js";
|
|
11
12
|
export * from "./move-node-inside-start.js";
|
|
12
13
|
export * from "./move-the-node-along-the-edge-outward.js";
|
|
13
14
|
/**
|
|
@@ -37,6 +37,29 @@ export declare class Selection implements ISelect {
|
|
|
37
37
|
* Return current selection object
|
|
38
38
|
*/
|
|
39
39
|
get sel(): ISelect['sel'];
|
|
40
|
+
/**
|
|
41
|
+
* Selection of a shadow tree in a browser without `ShadowRoot.getSelection`.
|
|
42
|
+
*
|
|
43
|
+
* `ShadowRoot.getSelection()` is a non-standard method that WebKit never
|
|
44
|
+
* implemented, and `window.getSelection()` stops at the shadow boundary: for
|
|
45
|
+
* a caret inside the shadow tree it reports the host, or the document
|
|
46
|
+
* itself. Everything downstream then works on the wrong tree, which is why
|
|
47
|
+
* Backspace used to throw `HierarchyRequestError` and Enter did nothing when
|
|
48
|
+
* the editor lived in a shadow root in Safari.
|
|
49
|
+
*
|
|
50
|
+
* The standard replacement is `Selection.getComposedRanges()`, which does
|
|
51
|
+
* reach into a shadow tree it is given. It hands back `StaticRange`s, and
|
|
52
|
+
* the editor mutates ranges constantly, so they are turned into live ones.
|
|
53
|
+
*
|
|
54
|
+
* Reads are answered from those ranges; everything else, including the
|
|
55
|
+
* writes (`addRange`, `removeAllRanges`, `setBaseAndExtent`), goes to the
|
|
56
|
+
* real selection, which does accept nodes inside a shadow tree. Reading is
|
|
57
|
+
* the only side the browser blocks.
|
|
58
|
+
*
|
|
59
|
+
* @returns `null` when the browser offers neither API, so the caller falls
|
|
60
|
+
* back to the plain window selection.
|
|
61
|
+
*/
|
|
62
|
+
private __composedSelection;
|
|
40
63
|
/**
|
|
41
64
|
* Return first selected range or create new
|
|
42
65
|
*/
|
|
@@ -24,7 +24,7 @@ import { assert } from "../helpers/utils/assert.js";
|
|
|
24
24
|
import { moveTheNodeAlongTheEdgeOutward } from "./helpers/move-the-node-along-the-edge-outward.js";
|
|
25
25
|
import "./interface.js";
|
|
26
26
|
import { CommitStyle } from "./style/commit-style.js";
|
|
27
|
-
import { cursorInTheEdgeOfString, findCorrectCurrentNode } from "./helpers/index.js";
|
|
27
|
+
import { composedRanges, cursorInTheEdgeOfString, findCorrectCurrentNode } from "./helpers/index.js";
|
|
28
28
|
export class Selection {
|
|
29
29
|
constructor(jodit) {
|
|
30
30
|
this.jodit = jodit;
|
|
@@ -69,12 +69,88 @@ export class Selection {
|
|
|
69
69
|
* Return current selection object
|
|
70
70
|
*/
|
|
71
71
|
get sel() {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
const { shadowRoot } = this.j.o;
|
|
73
|
+
if (shadowRoot) {
|
|
74
|
+
if (isFunction(shadowRoot.getSelection)) {
|
|
75
|
+
return shadowRoot.getSelection();
|
|
76
|
+
}
|
|
77
|
+
const composed = this.__composedSelection(shadowRoot);
|
|
78
|
+
if (composed) {
|
|
79
|
+
return composed;
|
|
80
|
+
}
|
|
75
81
|
}
|
|
76
82
|
return this.win.getSelection();
|
|
77
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Selection of a shadow tree in a browser without `ShadowRoot.getSelection`.
|
|
86
|
+
*
|
|
87
|
+
* `ShadowRoot.getSelection()` is a non-standard method that WebKit never
|
|
88
|
+
* implemented, and `window.getSelection()` stops at the shadow boundary: for
|
|
89
|
+
* a caret inside the shadow tree it reports the host, or the document
|
|
90
|
+
* itself. Everything downstream then works on the wrong tree, which is why
|
|
91
|
+
* Backspace used to throw `HierarchyRequestError` and Enter did nothing when
|
|
92
|
+
* the editor lived in a shadow root in Safari.
|
|
93
|
+
*
|
|
94
|
+
* The standard replacement is `Selection.getComposedRanges()`, which does
|
|
95
|
+
* reach into a shadow tree it is given. It hands back `StaticRange`s, and
|
|
96
|
+
* the editor mutates ranges constantly, so they are turned into live ones.
|
|
97
|
+
*
|
|
98
|
+
* Reads are answered from those ranges; everything else, including the
|
|
99
|
+
* writes (`addRange`, `removeAllRanges`, `setBaseAndExtent`), goes to the
|
|
100
|
+
* real selection, which does accept nodes inside a shadow tree. Reading is
|
|
101
|
+
* the only side the browser blocks.
|
|
102
|
+
*
|
|
103
|
+
* @returns `null` when the browser offers neither API, so the caller falls
|
|
104
|
+
* back to the plain window selection.
|
|
105
|
+
*/
|
|
106
|
+
__composedSelection(shadowRoot) {
|
|
107
|
+
const selection = this.win.getSelection();
|
|
108
|
+
if (!selection) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
// Firefox has no `ShadowRoot.getSelection` either, but its window
|
|
112
|
+
// selection does see into a shadow tree. Where the plain selection
|
|
113
|
+
// already points at the right node there is nothing to work around, and
|
|
114
|
+
// taking it over would change behaviour that works today.
|
|
115
|
+
const { anchorNode } = selection;
|
|
116
|
+
if (anchorNode && Dom.isOrContains(shadowRoot, anchorNode)) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
const ranges = composedRanges(selection, shadowRoot);
|
|
120
|
+
if (!ranges) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const live = ranges.map(staticRange => {
|
|
124
|
+
const range = this.createRange();
|
|
125
|
+
range.setStart(staticRange.startContainer, staticRange.startOffset);
|
|
126
|
+
range.setEnd(staticRange.endContainer, staticRange.endOffset);
|
|
127
|
+
return range;
|
|
128
|
+
});
|
|
129
|
+
const first = live[0];
|
|
130
|
+
const overrides = {
|
|
131
|
+
rangeCount: live.length,
|
|
132
|
+
getRangeAt: (index) => live[index],
|
|
133
|
+
isCollapsed: live.every(range => range.collapsed),
|
|
134
|
+
// Without these the editor asks the window selection where the
|
|
135
|
+
// caret is, is told "outside the editable area", and resets the
|
|
136
|
+
// caret to the start of it — which is the focus loss that shows up
|
|
137
|
+
// right after a successful Backspace.
|
|
138
|
+
anchorNode: first ? first.startContainer : null,
|
|
139
|
+
anchorOffset: first ? first.startOffset : 0,
|
|
140
|
+
focusNode: first ? first.endContainer : null,
|
|
141
|
+
focusOffset: first ? first.endOffset : 0,
|
|
142
|
+
toString: () => live.map(range => range.toString()).join('')
|
|
143
|
+
};
|
|
144
|
+
return new Proxy(selection, {
|
|
145
|
+
get(target, property) {
|
|
146
|
+
if (isString(property) && property in overrides) {
|
|
147
|
+
return overrides[property];
|
|
148
|
+
}
|
|
149
|
+
const value = Reflect.get(target, property, target);
|
|
150
|
+
return isFunction(value) ? value.bind(target) : value;
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
78
154
|
/**
|
|
79
155
|
* Return first selected range or create new
|
|
80
156
|
*/
|
|
@@ -38,7 +38,13 @@ export class dragAndDrop extends Plugin {
|
|
|
38
38
|
}
|
|
39
39
|
/** @override */
|
|
40
40
|
afterInit() {
|
|
41
|
-
this.j.e
|
|
41
|
+
this.j.e
|
|
42
|
+
.on([window, this.j.ed, this.j.editor], 'dragstart.DragAndDrop', this.onDragStart)
|
|
43
|
+
// Always, not only after a `dragstart` seen in this window: a drop
|
|
44
|
+
// from another window or application never produces one here, and
|
|
45
|
+
// the browser then inserted its HTML natively, unsanitized. Routed
|
|
46
|
+
// through the paste plugin instead. See GHSA-jhhp-r3r7-v2cg
|
|
47
|
+
.on('drop.DragAndDrop', this.onDrop);
|
|
42
48
|
}
|
|
43
49
|
onDragStart(event) {
|
|
44
50
|
let target = event.target;
|
|
@@ -69,13 +75,11 @@ export class dragAndDrop extends Plugin {
|
|
|
69
75
|
addDragListeners() {
|
|
70
76
|
this.j.e
|
|
71
77
|
.on('dragover', this.onDrag)
|
|
72
|
-
.on('drop.DragAndDrop', this.onDrop)
|
|
73
78
|
.on(window, 'dragend.DragAndDrop drop.DragAndDrop mouseup.DragAndDrop', this.onDragEnd);
|
|
74
79
|
}
|
|
75
80
|
removeDragListeners() {
|
|
76
81
|
this.j.e
|
|
77
82
|
.off('dragover', this.onDrag)
|
|
78
|
-
.off('drop.DragAndDrop', this.onDrop)
|
|
79
83
|
.off(window, 'dragend.DragAndDrop drop.DragAndDrop mouseup.DragAndDrop', this.onDragEnd);
|
|
80
84
|
}
|
|
81
85
|
onDrag(event) {
|
|
@@ -144,7 +148,15 @@ export class dragAndDrop extends Plugin {
|
|
|
144
148
|
}
|
|
145
149
|
}
|
|
146
150
|
else if (this.getText(event)) {
|
|
147
|
-
|
|
151
|
+
// Dropped markup takes the same sanitizing pass as pasted and
|
|
152
|
+
// assigned content. See GHSA-jhhp-r3r7-v2cg
|
|
153
|
+
const box = this.j.createInside.div();
|
|
154
|
+
box.innerHTML = this.getText(event);
|
|
155
|
+
this.j.e.fire('safeHTML', box);
|
|
156
|
+
fragment =
|
|
157
|
+
box.firstChild !== box.lastChild || !box.firstChild
|
|
158
|
+
? box
|
|
159
|
+
: box.firstChild;
|
|
148
160
|
}
|
|
149
161
|
return fragment;
|
|
150
162
|
}
|
package/package.json
CHANGED
|
@@ -13,4 +13,4 @@ export type safeOptions = {
|
|
|
13
13
|
* Removes dangerous constructs from HTML
|
|
14
14
|
*/
|
|
15
15
|
export declare function safeHTML(box: HTMLElement | DocumentFragment, options: safeOptions): void;
|
|
16
|
-
export declare function sanitizeHTMLElement(elm: Element | DocumentFragment, { safeJavaScriptLink, removeOnError }?: safeOptions): boolean;
|
|
16
|
+
export declare function sanitizeHTMLElement(elm: Element | DocumentFragment, { safeJavaScriptLink, removeOnError, removeEventAttributes }?: safeOptions): boolean;
|
|
@@ -0,0 +1,21 @@
|
|
|
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-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* @module selection
|
|
8
|
+
*/
|
|
9
|
+
import type { Nullable } from "../../../types/index";
|
|
10
|
+
/**
|
|
11
|
+
* Ranges of a selection that lies inside the given shadow tree.
|
|
12
|
+
*
|
|
13
|
+
* `window.getSelection()` stops at the shadow boundary and reports the host
|
|
14
|
+
* instead of the node the caret is really in. `getComposedRanges` is the
|
|
15
|
+
* standard way to ask past that boundary.
|
|
16
|
+
*
|
|
17
|
+
* @returns `null` when the browser has no `getComposedRanges`, or when neither
|
|
18
|
+
* call shape returned ranges that point inside the shadow tree — in which case
|
|
19
|
+
* there is nothing better to offer than the plain window selection.
|
|
20
|
+
*/
|
|
21
|
+
export declare function composedRanges(selection: Selection, shadowRoot: ShadowRoot): Nullable<StaticRange[]>;
|
|
@@ -3,6 +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 * from "./composed-ranges";
|
|
6
7
|
export * from "./move-node-inside-start";
|
|
7
8
|
export * from "./move-the-node-along-the-edge-outward";
|
|
8
9
|
/**
|
|
@@ -37,6 +37,29 @@ export declare class Selection implements ISelect {
|
|
|
37
37
|
* Return current selection object
|
|
38
38
|
*/
|
|
39
39
|
get sel(): ISelect['sel'];
|
|
40
|
+
/**
|
|
41
|
+
* Selection of a shadow tree in a browser without `ShadowRoot.getSelection`.
|
|
42
|
+
*
|
|
43
|
+
* `ShadowRoot.getSelection()` is a non-standard method that WebKit never
|
|
44
|
+
* implemented, and `window.getSelection()` stops at the shadow boundary: for
|
|
45
|
+
* a caret inside the shadow tree it reports the host, or the document
|
|
46
|
+
* itself. Everything downstream then works on the wrong tree, which is why
|
|
47
|
+
* Backspace used to throw `HierarchyRequestError` and Enter did nothing when
|
|
48
|
+
* the editor lived in a shadow root in Safari.
|
|
49
|
+
*
|
|
50
|
+
* The standard replacement is `Selection.getComposedRanges()`, which does
|
|
51
|
+
* reach into a shadow tree it is given. It hands back `StaticRange`s, and
|
|
52
|
+
* the editor mutates ranges constantly, so they are turned into live ones.
|
|
53
|
+
*
|
|
54
|
+
* Reads are answered from those ranges; everything else, including the
|
|
55
|
+
* writes (`addRange`, `removeAllRanges`, `setBaseAndExtent`), goes to the
|
|
56
|
+
* real selection, which does accept nodes inside a shadow tree. Reading is
|
|
57
|
+
* the only side the browser blocks.
|
|
58
|
+
*
|
|
59
|
+
* @returns `null` when the browser offers neither API, so the caller falls
|
|
60
|
+
* back to the plain window selection.
|
|
61
|
+
*/
|
|
62
|
+
private __composedSelection;
|
|
40
63
|
/**
|
|
41
64
|
* Return first selected range or create new
|
|
42
65
|
*/
|