happy-dom 5.4.0 → 6.0.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.
Potentially problematic release.
This version of happy-dom might be problematic. Click here for more details.
- package/.eslintrc.js +2 -2
- package/lib/base64/Base64.d.ts +23 -0
- package/lib/base64/Base64.js +89 -0
- package/lib/base64/Base64.js.map +1 -0
- package/lib/config/NonImplemenetedElementClasses.js +0 -1
- package/lib/config/NonImplemenetedElementClasses.js.map +1 -1
- package/lib/dom-implementation/DOMImplementation.d.ts +7 -1
- package/lib/dom-implementation/DOMImplementation.js +10 -2
- package/lib/dom-implementation/DOMImplementation.js.map +1 -1
- package/lib/dom-parser/DOMParser.d.ts +9 -4
- package/lib/dom-parser/DOMParser.js +13 -2
- package/lib/dom-parser/DOMParser.js.map +1 -1
- package/lib/exception/DOMExceptionNameEnum.d.ts +5 -1
- package/lib/exception/DOMExceptionNameEnum.js +4 -0
- package/lib/exception/DOMExceptionNameEnum.js.map +1 -1
- package/lib/fetch/Request.d.ts +8 -0
- package/lib/fetch/Request.js +15 -6
- package/lib/fetch/Request.js.map +1 -1
- package/lib/fetch/Response.d.ts +5 -0
- package/lib/fetch/Response.js +12 -6
- package/lib/fetch/Response.js.map +1 -1
- package/lib/file/FileReader.d.ts +7 -2
- package/lib/file/FileReader.js +9 -3
- package/lib/file/FileReader.js.map +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -1
- package/lib/nodes/comment/Comment.d.ts +1 -1
- package/lib/nodes/document/Document.d.ts +18 -15
- package/lib/nodes/document/Document.js +36 -33
- package/lib/nodes/document/Document.js.map +1 -1
- package/lib/nodes/document/IDocument.d.ts +7 -0
- package/lib/nodes/document-fragment/DocumentFragment.d.ts +1 -1
- package/lib/nodes/document-type/DocumentType.d.ts +1 -1
- package/lib/nodes/element/DOMRectListFactory.d.ts +23 -0
- package/lib/nodes/element/DOMRectListFactory.js +33 -0
- package/lib/nodes/element/DOMRectListFactory.js.map +1 -0
- package/lib/nodes/element/Element.d.ts +6 -5
- package/lib/nodes/element/Element.js +9 -11
- package/lib/nodes/element/Element.js.map +1 -1
- package/lib/nodes/element/IDOMRectList.d.ts +11 -0
- package/lib/nodes/element/IDOMRectList.js +3 -0
- package/lib/nodes/element/IDOMRectList.js.map +1 -0
- package/lib/nodes/element/IElement.d.ts +5 -4
- package/lib/nodes/html-dialog-element/HTMLDialogElement.d.ts +1 -6
- package/lib/nodes/html-dialog-element/HTMLDialogElement.js +7 -3
- package/lib/nodes/html-dialog-element/HTMLDialogElement.js.map +1 -1
- package/lib/nodes/html-dialog-element/IHTMLDialogElement.d.ts +11 -0
- package/lib/nodes/html-element/DatasetUtility.js +3 -1
- package/lib/nodes/html-element/DatasetUtility.js.map +1 -1
- package/lib/nodes/html-template-element/HTMLTemplateElement.d.ts +1 -10
- package/lib/nodes/html-template-element/HTMLTemplateElement.js +2 -15
- package/lib/nodes/html-template-element/HTMLTemplateElement.js.map +1 -1
- package/lib/nodes/node/INode.d.ts +8 -6
- package/lib/nodes/node/Node.d.ts +20 -17
- package/lib/nodes/node/Node.js +19 -15
- package/lib/nodes/node/Node.js.map +1 -1
- package/lib/nodes/node/NodeTypeEnum.d.ts +10 -0
- package/lib/nodes/node/NodeTypeEnum.js +14 -0
- package/lib/nodes/node/NodeTypeEnum.js.map +1 -0
- package/lib/nodes/node/NodeUtility.d.ts +59 -0
- package/lib/nodes/node/NodeUtility.js +123 -0
- package/lib/nodes/node/NodeUtility.js.map +1 -0
- package/lib/nodes/text/IText.d.ts +9 -0
- package/lib/nodes/text/Text.d.ts +10 -1
- package/lib/nodes/text/Text.js +24 -0
- package/lib/nodes/text/Text.js.map +1 -1
- package/lib/query-selector/SelectorItem.js +3 -2
- package/lib/query-selector/SelectorItem.js.map +1 -1
- package/lib/range/IRangeBoundaryPoint.d.ts +8 -0
- package/lib/range/IRangeBoundaryPoint.js +3 -0
- package/lib/range/IRangeBoundaryPoint.js.map +1 -0
- package/lib/range/Range.d.ts +249 -0
- package/lib/range/Range.js +820 -0
- package/lib/range/Range.js.map +1 -0
- package/lib/range/RangeHowEnum.d.ts +7 -0
- package/lib/range/RangeHowEnum.js +11 -0
- package/lib/range/RangeHowEnum.js.map +1 -0
- package/lib/range/RangeUtility.d.ts +46 -0
- package/lib/range/RangeUtility.js +92 -0
- package/lib/range/RangeUtility.js.map +1 -0
- package/lib/selection/Selection.d.ts +167 -44
- package/lib/selection/Selection.js +369 -58
- package/lib/selection/Selection.js.map +1 -1
- package/lib/selection/SelectionDirectionEnum.d.ts +6 -0
- package/lib/selection/SelectionDirectionEnum.js +10 -0
- package/lib/selection/SelectionDirectionEnum.js.map +1 -0
- package/lib/window/IWindow.d.ts +20 -0
- package/lib/window/Window.d.ts +23 -9
- package/lib/window/Window.js +83 -35
- package/lib/window/Window.js.map +1 -1
- package/lib/xml-parser/XMLParser.d.ts +2 -2
- package/lib/xml-parser/XMLParser.js +5 -3
- package/lib/xml-parser/XMLParser.js.map +1 -1
- package/lib/xml-serializer/XMLSerializer.js +4 -1
- package/lib/xml-serializer/XMLSerializer.js.map +1 -1
- package/package.json +2 -2
- package/src/base64/Base64.ts +97 -0
- package/src/config/NonImplemenetedElementClasses.ts +0 -1
- package/src/dom-implementation/DOMImplementation.ts +13 -2
- package/src/dom-parser/DOMParser.ts +20 -7
- package/src/exception/DOMExceptionNameEnum.ts +5 -1
- package/src/fetch/Request.ts +16 -6
- package/src/fetch/Response.ts +13 -6
- package/src/file/FileReader.ts +14 -4
- package/src/index.ts +2 -0
- package/src/nodes/document/Document.ts +47 -39
- package/src/nodes/document/IDocument.ts +8 -0
- package/src/nodes/element/DOMRectListFactory.ts +33 -0
- package/src/nodes/element/Element.ts +10 -11
- package/src/nodes/element/IDOMRectList.ts +11 -0
- package/src/nodes/element/IElement.ts +5 -4
- package/src/nodes/html-dialog-element/HTMLDialogElement.ts +4 -9
- package/src/nodes/html-dialog-element/IHTMLDialogElement.ts +14 -0
- package/src/nodes/html-element/DatasetUtility.ts +3 -1
- package/src/nodes/html-template-element/HTMLTemplateElement.ts +3 -21
- package/src/nodes/node/INode.ts +8 -6
- package/src/nodes/node/Node.ts +24 -19
- package/src/nodes/node/NodeTypeEnum.ts +11 -0
- package/src/nodes/node/NodeUtility.ts +139 -0
- package/src/nodes/text/IText.ts +10 -0
- package/src/nodes/text/Text.ts +33 -0
- package/src/query-selector/SelectorItem.ts +3 -2
- package/src/range/IRangeBoundaryPoint.ts +9 -0
- package/src/range/Range.ts +1057 -0
- package/src/range/RangeHowEnum.ts +8 -0
- package/src/range/RangeUtility.ts +114 -0
- package/src/selection/Selection.ts +444 -60
- package/src/selection/SelectionDirectionEnum.ts +7 -0
- package/src/window/IWindow.ts +22 -0
- package/src/window/Window.ts +102 -32
- package/src/xml-parser/XMLParser.ts +15 -7
- package/src/xml-serializer/XMLSerializer.ts +6 -1
- package/lib/nodes/element/Range.d.ts +0 -167
- package/lib/nodes/element/Range.js +0 -215
- package/lib/nodes/element/Range.js.map +0 -1
- package/lib/window/WindowBase64.d.ts +0 -19
- package/lib/window/WindowBase64.js +0 -88
- package/lib/window/WindowBase64.js.map +0 -1
- package/src/nodes/element/Range.ts +0 -237
- package/src/window/WindowBase64.ts +0 -95
@@ -0,0 +1,114 @@
|
|
1
|
+
import DOMException from '../exception/DOMException';
|
2
|
+
import DOMExceptionNameEnum from '../exception/DOMExceptionNameEnum';
|
3
|
+
import NodeTypeEnum from '../nodes/node/NodeTypeEnum';
|
4
|
+
import INode from '../nodes/node/INode';
|
5
|
+
import NodeUtility from '../nodes/node/NodeUtility';
|
6
|
+
import Range from './Range';
|
7
|
+
import IRangeBoundaryPoint from './IRangeBoundaryPoint';
|
8
|
+
|
9
|
+
/**
|
10
|
+
* Range utility.
|
11
|
+
*
|
12
|
+
* Based on:
|
13
|
+
* https://github.com/jsdom/jsdom/blob/master/lib/jsdom/living/range/boundary-point.js.
|
14
|
+
*/
|
15
|
+
export default class RangeUtility {
|
16
|
+
/**
|
17
|
+
* Compares boundary points.
|
18
|
+
*
|
19
|
+
* Based on logic from:
|
20
|
+
* https://github.com/jsdom/jsdom/blob/master/lib/jsdom/living/range/boundary-point.js
|
21
|
+
*
|
22
|
+
* @see https://dom.spec.whatwg.org/#concept-range-bp-after
|
23
|
+
* @param pointA Point A.
|
24
|
+
* @param pointB Point B.
|
25
|
+
* @returns A number, -1, 0, or 1, indicating whether the corresponding boundary-point of the Range is respectively before, equal to, or after the corresponding boundary-point of sourceRange.
|
26
|
+
*/
|
27
|
+
public static compareBoundaryPointsPosition(
|
28
|
+
pointA: IRangeBoundaryPoint,
|
29
|
+
pointB: IRangeBoundaryPoint
|
30
|
+
): number {
|
31
|
+
if (pointA.node === pointB.node) {
|
32
|
+
if (pointA.offset === pointB.offset) {
|
33
|
+
return 0;
|
34
|
+
} else if (pointA.offset < pointB.offset) {
|
35
|
+
return -1;
|
36
|
+
}
|
37
|
+
|
38
|
+
return 1;
|
39
|
+
}
|
40
|
+
|
41
|
+
if (NodeUtility.isFollowing(pointA.node, pointB.node)) {
|
42
|
+
return this.compareBoundaryPointsPosition(pointB, pointA) === -1 ? 1 : -1;
|
43
|
+
}
|
44
|
+
|
45
|
+
if (NodeUtility.isInclusiveAncestor(pointA.node, pointB.node)) {
|
46
|
+
let child = pointB.node;
|
47
|
+
|
48
|
+
while (child.parentNode !== pointA.node) {
|
49
|
+
child = child.parentNode;
|
50
|
+
}
|
51
|
+
|
52
|
+
if (child.parentNode.childNodes.indexOf(child) < pointA.offset) {
|
53
|
+
return 1;
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
return -1;
|
58
|
+
}
|
59
|
+
|
60
|
+
/**
|
61
|
+
* Validates a boundary point.
|
62
|
+
*
|
63
|
+
* @throws DOMException
|
64
|
+
* @param point Boundary point.
|
65
|
+
*/
|
66
|
+
public static validateBoundaryPoint(point: IRangeBoundaryPoint): void {
|
67
|
+
if (point.node.nodeType === NodeTypeEnum.documentTypeNode) {
|
68
|
+
throw new DOMException(
|
69
|
+
`DocumentType Node can't be used as boundary point.`,
|
70
|
+
DOMExceptionNameEnum.invalidNodeTypeError
|
71
|
+
);
|
72
|
+
}
|
73
|
+
|
74
|
+
if (point.offset > NodeUtility.getNodeLength(point.node)) {
|
75
|
+
throw new DOMException(`Offset out of bound.`, DOMExceptionNameEnum.indexSizeError);
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
/**
|
80
|
+
* Returns "true" if contained.
|
81
|
+
*
|
82
|
+
* @param node Node.
|
83
|
+
* @param range Range.
|
84
|
+
* @returns "true" if contained.
|
85
|
+
*/
|
86
|
+
public static isContained(node: INode, range: Range): boolean {
|
87
|
+
return (
|
88
|
+
this.compareBoundaryPointsPosition(
|
89
|
+
{ node, offset: 0 },
|
90
|
+
{ node: range.startContainer, offset: range.startOffset }
|
91
|
+
) === 1 &&
|
92
|
+
this.compareBoundaryPointsPosition(
|
93
|
+
{ node, offset: NodeUtility.getNodeLength(node) },
|
94
|
+
{ node: range.endContainer, offset: range.endOffset }
|
95
|
+
) === -1
|
96
|
+
);
|
97
|
+
}
|
98
|
+
|
99
|
+
/**
|
100
|
+
* Returns "true" if partially contained.
|
101
|
+
*
|
102
|
+
* @param node Node.
|
103
|
+
* @param range Range.
|
104
|
+
* @returns "true" if partially contained.
|
105
|
+
*/
|
106
|
+
public static isPartiallyContained(node: INode, range: Range): boolean {
|
107
|
+
return (
|
108
|
+
(NodeUtility.isInclusiveAncestor(node, range.startContainer) &&
|
109
|
+
!NodeUtility.isInclusiveAncestor(node, range.endContainer)) ||
|
110
|
+
(!NodeUtility.isInclusiveAncestor(node, range.startContainer) &&
|
111
|
+
NodeUtility.isInclusiveAncestor(node, range.endContainer))
|
112
|
+
);
|
113
|
+
}
|
114
|
+
}
|
@@ -1,140 +1,524 @@
|
|
1
|
+
import Event from '../event/Event';
|
2
|
+
import DOMException from '../exception/DOMException';
|
3
|
+
import DOMExceptionNameEnum from '../exception/DOMExceptionNameEnum';
|
4
|
+
import IDocument from '../nodes/document/IDocument';
|
1
5
|
import INode from '../nodes/node/INode';
|
6
|
+
import NodeTypeEnum from '../nodes/node/NodeTypeEnum';
|
7
|
+
import NodeUtility from '../nodes/node/NodeUtility';
|
8
|
+
import Range from '../range/Range';
|
9
|
+
import RangeUtility from '../range/RangeUtility';
|
10
|
+
import SelectionDirectionEnum from './SelectionDirectionEnum';
|
2
11
|
|
3
12
|
/**
|
4
13
|
* Selection.
|
5
14
|
*
|
15
|
+
* Based on logic from:
|
16
|
+
* https://github.com/jsdom/jsdom/blob/master/lib/jsdom/living/selection/Selection-impl.js
|
17
|
+
*
|
6
18
|
* Reference:
|
7
19
|
* https://developer.mozilla.org/en-US/docs/Web/API/Selection.
|
8
20
|
*/
|
9
21
|
export default class Selection {
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
public readonly baseOffset: number = 0;
|
14
|
-
public readonly extentNode: INode = null;
|
15
|
-
public readonly extentOffset: number = 0;
|
16
|
-
public readonly focusNode: INode = null;
|
17
|
-
public readonly focusOffset: number = 0;
|
18
|
-
public readonly isCollapsed: boolean = true;
|
19
|
-
public readonly rangeCount: number = 0;
|
20
|
-
public readonly type: string = 'None';
|
22
|
+
private readonly _ownerDocument: IDocument = null;
|
23
|
+
private _range: Range = null;
|
24
|
+
private _direction: SelectionDirectionEnum = SelectionDirectionEnum.directionless;
|
21
25
|
|
22
26
|
/**
|
23
|
-
*
|
27
|
+
* Constructor.
|
24
28
|
*
|
25
|
-
* @param
|
29
|
+
* @param ownerDocument Owner document.
|
26
30
|
*/
|
27
|
-
|
28
|
-
|
31
|
+
constructor(ownerDocument: IDocument) {
|
32
|
+
this._ownerDocument = ownerDocument;
|
29
33
|
}
|
30
34
|
|
31
35
|
/**
|
32
|
-
*
|
36
|
+
* Returns range count.
|
33
37
|
*
|
34
|
-
* @
|
35
|
-
* @
|
38
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-rangecount
|
39
|
+
* @returns Range count.
|
36
40
|
*/
|
37
|
-
public
|
38
|
-
|
41
|
+
public get rangeCount(): number {
|
42
|
+
return this._range ? 1 : 0;
|
39
43
|
}
|
40
44
|
|
41
45
|
/**
|
42
|
-
*
|
46
|
+
* Returns collapsed state.
|
47
|
+
*
|
48
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-iscollapsed
|
49
|
+
* @returns "true" if collapsed.
|
43
50
|
*/
|
44
|
-
public
|
45
|
-
|
51
|
+
public get isCollapsed(): boolean {
|
52
|
+
return this._range === null || this._range.collapsed;
|
46
53
|
}
|
47
54
|
|
48
55
|
/**
|
49
|
-
*
|
56
|
+
* Returns type.
|
57
|
+
*
|
58
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-type
|
59
|
+
* @returns Type.
|
50
60
|
*/
|
51
|
-
public
|
52
|
-
|
61
|
+
public get type(): string {
|
62
|
+
if (!this._range) {
|
63
|
+
return 'None';
|
64
|
+
} else if (this._range.collapsed) {
|
65
|
+
return 'Caret';
|
66
|
+
}
|
67
|
+
|
68
|
+
return 'Range';
|
53
69
|
}
|
54
70
|
|
55
71
|
/**
|
56
|
-
*
|
72
|
+
* Returns anchor node.
|
57
73
|
*
|
58
|
-
* @
|
59
|
-
* @
|
60
|
-
* @returns Always returns "true" for now.
|
74
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-anchornode
|
75
|
+
* @returns Node.
|
61
76
|
*/
|
62
|
-
public
|
63
|
-
|
77
|
+
public get anchorNode(): INode {
|
78
|
+
if (!this._range) {
|
79
|
+
return null;
|
80
|
+
}
|
81
|
+
return this._direction === SelectionDirectionEnum.forwards
|
82
|
+
? this._range.startContainer
|
83
|
+
: this._range.endContainer;
|
64
84
|
}
|
65
85
|
|
66
86
|
/**
|
67
|
-
*
|
87
|
+
* Returns anchor offset.
|
88
|
+
*
|
89
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-anchoroffset
|
90
|
+
* @returns Node.
|
68
91
|
*/
|
69
|
-
public
|
70
|
-
|
92
|
+
public get anchorOffset(): number {
|
93
|
+
if (!this._range) {
|
94
|
+
return null;
|
95
|
+
}
|
96
|
+
return this._direction === SelectionDirectionEnum.forwards
|
97
|
+
? this._range.startOffset
|
98
|
+
: this._range.endOffset;
|
71
99
|
}
|
72
100
|
|
73
101
|
/**
|
74
|
-
*
|
102
|
+
* Returns anchor node.
|
75
103
|
*
|
76
|
-
* @
|
77
|
-
* @
|
104
|
+
* @deprecated
|
105
|
+
* @alias anchorNode
|
106
|
+
* @returns Node.
|
78
107
|
*/
|
79
|
-
public
|
80
|
-
|
108
|
+
public get baseNode(): INode {
|
109
|
+
return this.anchorNode;
|
81
110
|
}
|
82
111
|
|
83
112
|
/**
|
84
|
-
*
|
113
|
+
* Returns anchor offset.
|
114
|
+
*
|
115
|
+
* @deprecated
|
116
|
+
* @alias anchorOffset
|
117
|
+
* @returns Node.
|
118
|
+
*/
|
119
|
+
public get baseOffset(): number {
|
120
|
+
return this.anchorOffset;
|
121
|
+
}
|
122
|
+
|
123
|
+
/**
|
124
|
+
* Returns focus node.
|
125
|
+
*
|
126
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-focusnode
|
127
|
+
* @returns Node.
|
128
|
+
*/
|
129
|
+
public get focusNode(): INode {
|
130
|
+
return this.anchorNode;
|
131
|
+
}
|
132
|
+
|
133
|
+
/**
|
134
|
+
* Returns focus offset.
|
135
|
+
*
|
136
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-focusoffset
|
137
|
+
* @returns Node.
|
138
|
+
*/
|
139
|
+
public get focusOffset(): number {
|
140
|
+
return this.anchorOffset;
|
141
|
+
}
|
142
|
+
|
143
|
+
/**
|
144
|
+
* Returns focus node.
|
145
|
+
*
|
146
|
+
* @deprecated
|
147
|
+
* @alias focusNode
|
148
|
+
* @returns Node.
|
149
|
+
*/
|
150
|
+
public get extentNode(): INode {
|
151
|
+
return this.focusNode;
|
152
|
+
}
|
153
|
+
|
154
|
+
/**
|
155
|
+
* Returns focus offset.
|
156
|
+
*
|
157
|
+
* @deprecated
|
158
|
+
* @alias focusOffset
|
159
|
+
* @returns Node.
|
160
|
+
*/
|
161
|
+
public get extentOffset(): number {
|
162
|
+
return this.focusOffset;
|
163
|
+
}
|
164
|
+
|
165
|
+
/**
|
166
|
+
* Adds a range.
|
85
167
|
*
|
86
|
-
* @
|
168
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-addrange
|
169
|
+
* @param newRange Range.
|
87
170
|
*/
|
88
|
-
public
|
89
|
-
|
171
|
+
public addRange(newRange: Range): void {
|
172
|
+
if (!newRange) {
|
173
|
+
throw new Error('Failed to execute addRange on Selection. Parameter 1 is not of type Range.');
|
174
|
+
}
|
175
|
+
if (!this._range && newRange._ownerDocument === this._ownerDocument) {
|
176
|
+
this._associateRange(newRange);
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
/**
|
181
|
+
* Returns Range.
|
182
|
+
*
|
183
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-getrangeat
|
184
|
+
* @param index Index.
|
185
|
+
* @returns Range.
|
186
|
+
*/
|
187
|
+
public getRangeAt(index: number): Range {
|
188
|
+
if (!this._range || index !== 0) {
|
189
|
+
throw new DOMException('Invalid range index.', DOMExceptionNameEnum.indexSizeError);
|
190
|
+
}
|
191
|
+
|
192
|
+
return this._range;
|
90
193
|
}
|
91
194
|
|
92
195
|
/**
|
93
196
|
* Removes a range from a selection.
|
94
197
|
*
|
95
|
-
* @
|
198
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-removerange
|
199
|
+
* @param range Range.
|
96
200
|
*/
|
97
|
-
public removeRange(
|
98
|
-
|
201
|
+
public removeRange(range: Range): void {
|
202
|
+
if (this._range !== range) {
|
203
|
+
throw new DOMException('Invalid range.', DOMExceptionNameEnum.notFoundError);
|
204
|
+
}
|
205
|
+
this._associateRange(null);
|
99
206
|
}
|
100
207
|
|
101
208
|
/**
|
102
209
|
* Removes all ranges.
|
103
210
|
*/
|
104
211
|
public removeAllRanges(): void {
|
105
|
-
|
212
|
+
this._associateRange(null);
|
213
|
+
}
|
214
|
+
|
215
|
+
/**
|
216
|
+
* Removes all ranges.
|
217
|
+
*
|
218
|
+
* @alias removeAllRanges()
|
219
|
+
*/
|
220
|
+
public empty(): void {
|
221
|
+
this.removeAllRanges();
|
222
|
+
}
|
223
|
+
|
224
|
+
/**
|
225
|
+
* Collapses the current selection to a single point.
|
226
|
+
*
|
227
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-collapse
|
228
|
+
* @param node Node.
|
229
|
+
* @param offset Offset.
|
230
|
+
*/
|
231
|
+
public collapse(node: INode, offset: number): void {
|
232
|
+
if (node === null) {
|
233
|
+
this.removeAllRanges();
|
234
|
+
return;
|
235
|
+
}
|
236
|
+
|
237
|
+
if (node.nodeType === NodeTypeEnum.documentTypeNode) {
|
238
|
+
throw new DOMException(
|
239
|
+
"DocumentType Node can't be used as boundary point.",
|
240
|
+
DOMExceptionNameEnum.invalidNodeTypeError
|
241
|
+
);
|
242
|
+
}
|
243
|
+
|
244
|
+
if (offset > NodeUtility.getNodeLength(node)) {
|
245
|
+
throw new DOMException('Invalid range index.', DOMExceptionNameEnum.indexSizeError);
|
246
|
+
}
|
247
|
+
|
248
|
+
if (node.ownerDocument !== this._ownerDocument) {
|
249
|
+
return;
|
250
|
+
}
|
251
|
+
|
252
|
+
const newRange = new Range();
|
253
|
+
|
254
|
+
newRange._start.node = node;
|
255
|
+
newRange._start.offset = offset;
|
256
|
+
newRange._end.node = node;
|
257
|
+
newRange._end.offset = offset;
|
258
|
+
|
259
|
+
this._associateRange(newRange);
|
260
|
+
}
|
261
|
+
|
262
|
+
/**
|
263
|
+
* Collapses the current selection to a single point.
|
264
|
+
*
|
265
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-setposition
|
266
|
+
* @alias collapse()
|
267
|
+
* @param node Node.
|
268
|
+
* @param offset Offset.
|
269
|
+
*/
|
270
|
+
public setPosition(node: INode, offset: number): void {
|
271
|
+
this.collapse(node, offset);
|
272
|
+
}
|
273
|
+
|
274
|
+
/**
|
275
|
+
* Collapses the selection to the end.
|
276
|
+
*
|
277
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-collapsetoend
|
278
|
+
*/
|
279
|
+
public collapseToEnd(): void {
|
280
|
+
if (this._range === null) {
|
281
|
+
throw new DOMException(
|
282
|
+
'There is no selection to collapse.',
|
283
|
+
DOMExceptionNameEnum.invalidStateError
|
284
|
+
);
|
285
|
+
}
|
286
|
+
|
287
|
+
const { node, offset } = this._range._end;
|
288
|
+
const newRange = new Range();
|
289
|
+
|
290
|
+
newRange._start.node = node;
|
291
|
+
newRange._start.offset = offset;
|
292
|
+
newRange._end.node = node;
|
293
|
+
newRange._end.offset = offset;
|
294
|
+
|
295
|
+
this._associateRange(newRange);
|
296
|
+
}
|
297
|
+
|
298
|
+
/**
|
299
|
+
* Collapses the selection to the start.
|
300
|
+
*
|
301
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-collapsetostart
|
302
|
+
*/
|
303
|
+
public collapseToStart(): void {
|
304
|
+
if (!this._range) {
|
305
|
+
throw new DOMException(
|
306
|
+
'There is no selection to collapse.',
|
307
|
+
DOMExceptionNameEnum.invalidStateError
|
308
|
+
);
|
309
|
+
}
|
310
|
+
|
311
|
+
const { node, offset } = this._range._start;
|
312
|
+
const newRange = new Range();
|
313
|
+
|
314
|
+
newRange._start.node = node;
|
315
|
+
newRange._start.offset = offset;
|
316
|
+
newRange._end.node = node;
|
317
|
+
newRange._end.offset = offset;
|
318
|
+
|
319
|
+
this._associateRange(newRange);
|
320
|
+
}
|
321
|
+
|
322
|
+
/**
|
323
|
+
* Indicates whether a specified node is part of the selection.
|
324
|
+
*
|
325
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-containsnode
|
326
|
+
* @param node Node.
|
327
|
+
* @param [allowPartialContainment] Set to "true" to allow partial containment.
|
328
|
+
* @returns Always returns "true" for now.
|
329
|
+
*/
|
330
|
+
public containsNode(node: INode, allowPartialContainment = false): boolean {
|
331
|
+
if (!this._range || node.ownerDocument !== this._ownerDocument) {
|
332
|
+
return false;
|
333
|
+
}
|
334
|
+
|
335
|
+
const { _start, _end } = this._range;
|
336
|
+
|
337
|
+
const startIsBeforeNode =
|
338
|
+
RangeUtility.compareBoundaryPointsPosition(_start, { node, offset: 0 }) === -1;
|
339
|
+
const endIsAfterNode =
|
340
|
+
RangeUtility.compareBoundaryPointsPosition(_end, {
|
341
|
+
node,
|
342
|
+
offset: NodeUtility.getNodeLength(node)
|
343
|
+
}) === 1;
|
344
|
+
|
345
|
+
return allowPartialContainment
|
346
|
+
? startIsBeforeNode || endIsAfterNode
|
347
|
+
: startIsBeforeNode && endIsAfterNode;
|
348
|
+
}
|
349
|
+
|
350
|
+
/**
|
351
|
+
* Deletes the selected text from the document's DOM.
|
352
|
+
*
|
353
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-deletefromdocument
|
354
|
+
*/
|
355
|
+
public deleteFromDocument(): void {
|
356
|
+
if (this._range) {
|
357
|
+
this._range.deleteContents();
|
358
|
+
}
|
359
|
+
}
|
360
|
+
|
361
|
+
/**
|
362
|
+
* Moves the focus of the selection to a specified point.
|
363
|
+
*
|
364
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-extend
|
365
|
+
* @param node Node.
|
366
|
+
* @param offset Offset.
|
367
|
+
*/
|
368
|
+
public extend(node: INode, offset: number): void {
|
369
|
+
if (node.ownerDocument !== this._ownerDocument) {
|
370
|
+
return;
|
371
|
+
}
|
372
|
+
|
373
|
+
if (!this._range) {
|
374
|
+
throw new DOMException(
|
375
|
+
'There is no selection to extend.',
|
376
|
+
DOMExceptionNameEnum.invalidStateError
|
377
|
+
);
|
378
|
+
}
|
379
|
+
|
380
|
+
const anchorNode = this.anchorNode;
|
381
|
+
const anchorOffset = this.anchorOffset;
|
382
|
+
const newRange = new Range();
|
383
|
+
newRange._start.node = node;
|
384
|
+
newRange._start.offset = 0;
|
385
|
+
newRange._end.node = node;
|
386
|
+
newRange._end.offset = 0;
|
387
|
+
|
388
|
+
if (node.ownerDocument !== this._range._ownerDocument) {
|
389
|
+
newRange._start.offset = offset;
|
390
|
+
newRange._end.offset = offset;
|
391
|
+
} else if (
|
392
|
+
RangeUtility.compareBoundaryPointsPosition(
|
393
|
+
{ node: anchorNode, offset: anchorOffset },
|
394
|
+
{ node, offset }
|
395
|
+
) <= 0
|
396
|
+
) {
|
397
|
+
newRange._start.node = anchorNode;
|
398
|
+
newRange._start.offset = anchorOffset;
|
399
|
+
newRange._end.node = node;
|
400
|
+
newRange._end.offset = offset;
|
401
|
+
} else {
|
402
|
+
newRange._start.node = node;
|
403
|
+
newRange._start.offset = offset;
|
404
|
+
newRange._end.node = anchorNode;
|
405
|
+
newRange._end.offset = anchorOffset;
|
406
|
+
}
|
407
|
+
|
408
|
+
this._associateRange(newRange);
|
409
|
+
this._direction =
|
410
|
+
RangeUtility.compareBoundaryPointsPosition(
|
411
|
+
{ node, offset },
|
412
|
+
{ node: anchorNode, offset: anchorOffset }
|
413
|
+
) === -1
|
414
|
+
? SelectionDirectionEnum.backwards
|
415
|
+
: SelectionDirectionEnum.forwards;
|
106
416
|
}
|
107
417
|
|
108
418
|
/**
|
109
419
|
* Selects all children.
|
110
420
|
*
|
421
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-selectallchildren
|
422
|
+
* @param node
|
111
423
|
* @param _parentNode Parent node.
|
112
424
|
*/
|
113
|
-
public selectAllChildren(
|
114
|
-
|
425
|
+
public selectAllChildren(node: INode): void {
|
426
|
+
if (node.nodeType === NodeTypeEnum.documentTypeNode) {
|
427
|
+
throw new DOMException(
|
428
|
+
"DocumentType Node can't be used as boundary point.",
|
429
|
+
DOMExceptionNameEnum.invalidNodeTypeError
|
430
|
+
);
|
431
|
+
}
|
432
|
+
|
433
|
+
if (node.ownerDocument !== this._ownerDocument) {
|
434
|
+
return;
|
435
|
+
}
|
436
|
+
|
437
|
+
const length = node.childNodes.length;
|
438
|
+
const newRange = new Range();
|
439
|
+
|
440
|
+
newRange._start.node = node;
|
441
|
+
newRange._start.offset = 0;
|
442
|
+
newRange._end.node = node;
|
443
|
+
newRange._end.offset = length;
|
444
|
+
|
445
|
+
this._associateRange(newRange);
|
115
446
|
}
|
116
447
|
|
117
448
|
/**
|
118
449
|
* Sets the selection to be a range including all or parts of two specified DOM nodes, and any content located between them.
|
119
450
|
*
|
120
|
-
* @
|
121
|
-
* @param
|
122
|
-
* @param
|
123
|
-
* @param
|
451
|
+
* @see https://w3c.github.io/selection-api/#dom-selection-setbaseandextent
|
452
|
+
* @param anchorNode Anchor node.
|
453
|
+
* @param anchorOffset Anchor offset.
|
454
|
+
* @param focusNode Focus node.
|
455
|
+
* @param focusOffset Focus offset.
|
124
456
|
*/
|
125
457
|
public setBaseAndExtent(
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
458
|
+
anchorNode: INode,
|
459
|
+
anchorOffset: number,
|
460
|
+
focusNode: INode,
|
461
|
+
focusOffset: number
|
130
462
|
): void {
|
131
|
-
|
463
|
+
if (
|
464
|
+
anchorOffset > NodeUtility.getNodeLength(anchorNode) ||
|
465
|
+
focusOffset > NodeUtility.getNodeLength(focusNode)
|
466
|
+
) {
|
467
|
+
throw new DOMException(
|
468
|
+
'Invalid anchor or focus offset.',
|
469
|
+
DOMExceptionNameEnum.indexSizeError
|
470
|
+
);
|
471
|
+
}
|
472
|
+
|
473
|
+
if (
|
474
|
+
anchorNode.ownerDocument !== this._ownerDocument ||
|
475
|
+
focusNode.ownerDocument !== this._ownerDocument
|
476
|
+
) {
|
477
|
+
return;
|
478
|
+
}
|
479
|
+
|
480
|
+
const anchor = { node: anchorNode, offset: anchorOffset };
|
481
|
+
const focus = { node: focusNode, offset: focusOffset };
|
482
|
+
const newRange = new Range();
|
483
|
+
|
484
|
+
if (RangeUtility.compareBoundaryPointsPosition(anchor, focus) === -1) {
|
485
|
+
newRange._start = anchor;
|
486
|
+
newRange._end = focus;
|
487
|
+
} else {
|
488
|
+
newRange._start = focus;
|
489
|
+
newRange._end = anchor;
|
490
|
+
}
|
491
|
+
|
492
|
+
this._associateRange(newRange);
|
493
|
+
this._direction =
|
494
|
+
RangeUtility.compareBoundaryPointsPosition(focus, anchor) === -1
|
495
|
+
? SelectionDirectionEnum.backwards
|
496
|
+
: SelectionDirectionEnum.forwards;
|
132
497
|
}
|
133
498
|
|
134
499
|
/**
|
135
500
|
* Returns string currently being represented by the selection object.
|
501
|
+
*
|
502
|
+
* @returns Selection as string.
|
136
503
|
*/
|
137
504
|
public toString(): string {
|
138
|
-
return '';
|
505
|
+
return this._range ? this._range.toString() : '';
|
506
|
+
}
|
507
|
+
|
508
|
+
/**
|
509
|
+
* Sets the current range.
|
510
|
+
*
|
511
|
+
* @param range Range.
|
512
|
+
*/
|
513
|
+
protected _associateRange(range: Range): void {
|
514
|
+
const oldRange = this._range;
|
515
|
+
this._range = range;
|
516
|
+
this._direction =
|
517
|
+
range === null ? SelectionDirectionEnum.directionless : SelectionDirectionEnum.forwards;
|
518
|
+
|
519
|
+
if (oldRange !== this._range) {
|
520
|
+
// https://w3c.github.io/selection-api/#selectionchange-event
|
521
|
+
this._ownerDocument.dispatchEvent(new Event('selectionchange'));
|
522
|
+
}
|
139
523
|
}
|
140
524
|
}
|