happy-dom 5.3.3 → 6.0.0

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.

Files changed (144) hide show
  1. package/.eslintrc.js +2 -2
  2. package/lib/base64/Base64.d.ts +23 -0
  3. package/lib/base64/Base64.js +89 -0
  4. package/lib/base64/Base64.js.map +1 -0
  5. package/lib/config/ElementTag.d.ts +2 -1
  6. package/lib/config/ElementTag.js +2 -1
  7. package/lib/config/ElementTag.js.map +1 -1
  8. package/lib/config/NonImplemenetedElementClasses.js +0 -1
  9. package/lib/config/NonImplemenetedElementClasses.js.map +1 -1
  10. package/lib/dom-implementation/DOMImplementation.d.ts +7 -1
  11. package/lib/dom-implementation/DOMImplementation.js +10 -2
  12. package/lib/dom-implementation/DOMImplementation.js.map +1 -1
  13. package/lib/dom-parser/DOMParser.d.ts +9 -4
  14. package/lib/dom-parser/DOMParser.js +13 -2
  15. package/lib/dom-parser/DOMParser.js.map +1 -1
  16. package/lib/exception/DOMExceptionNameEnum.d.ts +5 -1
  17. package/lib/exception/DOMExceptionNameEnum.js +4 -0
  18. package/lib/exception/DOMExceptionNameEnum.js.map +1 -1
  19. package/lib/fetch/Request.d.ts +8 -0
  20. package/lib/fetch/Request.js +15 -6
  21. package/lib/fetch/Request.js.map +1 -1
  22. package/lib/fetch/Response.d.ts +5 -0
  23. package/lib/fetch/Response.js +12 -6
  24. package/lib/fetch/Response.js.map +1 -1
  25. package/lib/file/FileReader.d.ts +7 -2
  26. package/lib/file/FileReader.js +9 -3
  27. package/lib/file/FileReader.js.map +1 -1
  28. package/lib/index.d.ts +4 -1
  29. package/lib/index.js +5 -1
  30. package/lib/index.js.map +1 -1
  31. package/lib/location/URL.js +1 -1
  32. package/lib/location/URL.js.map +1 -1
  33. package/lib/nodes/comment/Comment.d.ts +1 -1
  34. package/lib/nodes/document/Document.d.ts +18 -15
  35. package/lib/nodes/document/Document.js +36 -33
  36. package/lib/nodes/document/Document.js.map +1 -1
  37. package/lib/nodes/document/IDocument.d.ts +7 -0
  38. package/lib/nodes/document-fragment/DocumentFragment.d.ts +1 -1
  39. package/lib/nodes/document-type/DocumentType.d.ts +1 -1
  40. package/lib/nodes/element/DOMRectListFactory.d.ts +23 -0
  41. package/lib/nodes/element/DOMRectListFactory.js +33 -0
  42. package/lib/nodes/element/DOMRectListFactory.js.map +1 -0
  43. package/lib/nodes/element/Element.d.ts +6 -5
  44. package/lib/nodes/element/Element.js +9 -11
  45. package/lib/nodes/element/Element.js.map +1 -1
  46. package/lib/nodes/element/IDOMRectList.d.ts +11 -0
  47. package/lib/nodes/element/IDOMRectList.js +3 -0
  48. package/lib/nodes/element/IDOMRectList.js.map +1 -0
  49. package/lib/nodes/element/IElement.d.ts +5 -4
  50. package/lib/nodes/html-dialog-element/HTMLDialogElement.d.ts +31 -0
  51. package/lib/nodes/html-dialog-element/HTMLDialogElement.js +51 -0
  52. package/lib/nodes/html-dialog-element/HTMLDialogElement.js.map +1 -0
  53. package/lib/nodes/html-dialog-element/IHTMLDialogElement.d.ts +25 -0
  54. package/lib/nodes/html-dialog-element/IHTMLDialogElement.js +3 -0
  55. package/lib/nodes/html-dialog-element/IHTMLDialogElement.js.map +1 -0
  56. package/lib/nodes/html-template-element/HTMLTemplateElement.d.ts +1 -10
  57. package/lib/nodes/html-template-element/HTMLTemplateElement.js +2 -15
  58. package/lib/nodes/html-template-element/HTMLTemplateElement.js.map +1 -1
  59. package/lib/nodes/node/INode.d.ts +8 -6
  60. package/lib/nodes/node/Node.d.ts +20 -17
  61. package/lib/nodes/node/Node.js +19 -15
  62. package/lib/nodes/node/Node.js.map +1 -1
  63. package/lib/nodes/node/NodeTypeEnum.d.ts +10 -0
  64. package/lib/nodes/node/NodeTypeEnum.js +14 -0
  65. package/lib/nodes/node/NodeTypeEnum.js.map +1 -0
  66. package/lib/nodes/node/NodeUtility.d.ts +59 -0
  67. package/lib/nodes/node/NodeUtility.js +123 -0
  68. package/lib/nodes/node/NodeUtility.js.map +1 -0
  69. package/lib/nodes/text/IText.d.ts +9 -0
  70. package/lib/nodes/text/Text.d.ts +10 -1
  71. package/lib/nodes/text/Text.js +24 -0
  72. package/lib/nodes/text/Text.js.map +1 -1
  73. package/lib/range/IRangeBoundaryPoint.d.ts +8 -0
  74. package/lib/range/IRangeBoundaryPoint.js +3 -0
  75. package/lib/range/IRangeBoundaryPoint.js.map +1 -0
  76. package/lib/range/Range.d.ts +249 -0
  77. package/lib/range/Range.js +820 -0
  78. package/lib/range/Range.js.map +1 -0
  79. package/lib/range/RangeHowEnum.d.ts +7 -0
  80. package/lib/range/RangeHowEnum.js +11 -0
  81. package/lib/range/RangeHowEnum.js.map +1 -0
  82. package/lib/range/RangeUtility.d.ts +46 -0
  83. package/lib/range/RangeUtility.js +92 -0
  84. package/lib/range/RangeUtility.js.map +1 -0
  85. package/lib/selection/Selection.d.ts +167 -44
  86. package/lib/selection/Selection.js +369 -58
  87. package/lib/selection/Selection.js.map +1 -1
  88. package/lib/selection/SelectionDirectionEnum.d.ts +6 -0
  89. package/lib/selection/SelectionDirectionEnum.js +10 -0
  90. package/lib/selection/SelectionDirectionEnum.js.map +1 -0
  91. package/lib/window/IWindow.d.ts +22 -0
  92. package/lib/window/Window.d.ts +25 -9
  93. package/lib/window/Window.js +85 -35
  94. package/lib/window/Window.js.map +1 -1
  95. package/lib/xml-parser/XMLParser.d.ts +2 -2
  96. package/lib/xml-parser/XMLParser.js +5 -3
  97. package/lib/xml-parser/XMLParser.js.map +1 -1
  98. package/lib/xml-serializer/XMLSerializer.js +4 -1
  99. package/lib/xml-serializer/XMLSerializer.js.map +1 -1
  100. package/package.json +2 -2
  101. package/src/base64/Base64.ts +97 -0
  102. package/src/config/ElementTag.ts +2 -1
  103. package/src/config/NonImplemenetedElementClasses.ts +0 -1
  104. package/src/dom-implementation/DOMImplementation.ts +13 -2
  105. package/src/dom-parser/DOMParser.ts +20 -7
  106. package/src/exception/DOMExceptionNameEnum.ts +5 -1
  107. package/src/fetch/Request.ts +16 -6
  108. package/src/fetch/Response.ts +13 -6
  109. package/src/file/FileReader.ts +14 -4
  110. package/src/index.ts +7 -1
  111. package/src/location/URL.ts +1 -1
  112. package/src/nodes/document/Document.ts +47 -39
  113. package/src/nodes/document/IDocument.ts +8 -0
  114. package/src/nodes/element/DOMRectListFactory.ts +33 -0
  115. package/src/nodes/element/Element.ts +10 -11
  116. package/src/nodes/element/IDOMRectList.ts +11 -0
  117. package/src/nodes/element/IElement.ts +5 -4
  118. package/src/nodes/html-dialog-element/HTMLDialogElement.ts +47 -0
  119. package/src/nodes/html-dialog-element/IHTMLDialogElement.ts +29 -0
  120. package/src/nodes/html-template-element/HTMLTemplateElement.ts +3 -21
  121. package/src/nodes/node/INode.ts +8 -6
  122. package/src/nodes/node/Node.ts +24 -19
  123. package/src/nodes/node/NodeTypeEnum.ts +11 -0
  124. package/src/nodes/node/NodeUtility.ts +139 -0
  125. package/src/nodes/text/IText.ts +10 -0
  126. package/src/nodes/text/Text.ts +33 -0
  127. package/src/range/IRangeBoundaryPoint.ts +9 -0
  128. package/src/range/Range.ts +1057 -0
  129. package/src/range/RangeHowEnum.ts +8 -0
  130. package/src/range/RangeUtility.ts +114 -0
  131. package/src/selection/Selection.ts +444 -60
  132. package/src/selection/SelectionDirectionEnum.ts +7 -0
  133. package/src/window/IWindow.ts +24 -0
  134. package/src/window/Window.ts +104 -32
  135. package/src/xml-parser/XMLParser.ts +15 -7
  136. package/src/xml-serializer/XMLSerializer.ts +6 -1
  137. package/lib/nodes/element/Range.d.ts +0 -167
  138. package/lib/nodes/element/Range.js +0 -215
  139. package/lib/nodes/element/Range.js.map +0 -1
  140. package/lib/window/WindowBase64.d.ts +0 -19
  141. package/lib/window/WindowBase64.js +0 -88
  142. package/lib/window/WindowBase64.js.map +0 -1
  143. package/src/nodes/element/Range.ts +0 -237
  144. package/src/window/WindowBase64.ts +0 -95
@@ -0,0 +1,820 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const DOMRect_1 = __importDefault(require("../nodes/element/DOMRect"));
7
+ const RangeHowEnum_1 = __importDefault(require("./RangeHowEnum"));
8
+ const DOMException_1 = __importDefault(require("../exception/DOMException"));
9
+ const DOMExceptionNameEnum_1 = __importDefault(require("../exception/DOMExceptionNameEnum"));
10
+ const RangeUtility_1 = __importDefault(require("./RangeUtility"));
11
+ const NodeTypeEnum_1 = __importDefault(require("../nodes/node/NodeTypeEnum"));
12
+ const NodeUtility_1 = __importDefault(require("../nodes/node/NodeUtility"));
13
+ const XMLParser_1 = __importDefault(require("../xml-parser/XMLParser"));
14
+ const DOMRectListFactory_1 = __importDefault(require("../nodes/element/DOMRectListFactory"));
15
+ /**
16
+ * Range.
17
+ *
18
+ * Based on logic from:
19
+ * https://github.com/jsdom/jsdom/blob/master/lib/jsdom/living/range/Range-impl.js
20
+ *
21
+ * Reference:
22
+ * https://developer.mozilla.org/en-US/docs/Web/API/Range.
23
+ */
24
+ class Range {
25
+ /**
26
+ * Constructor.
27
+ */
28
+ constructor() {
29
+ this.END_TO_END = RangeHowEnum_1.default.endToEnd;
30
+ this.END_TO_START = RangeHowEnum_1.default.endToStart;
31
+ this.START_TO_END = RangeHowEnum_1.default.startToEnd;
32
+ this.START_TO_START = RangeHowEnum_1.default.startToStart;
33
+ this._ownerDocument = null;
34
+ this._start = null;
35
+ this._end = null;
36
+ this._ownerDocument = this.constructor._ownerDocument;
37
+ this._start = { node: this._ownerDocument, offset: 0 };
38
+ this._end = { node: this._ownerDocument, offset: 0 };
39
+ }
40
+ /**
41
+ * Returns start container.
42
+ *
43
+ * @see https://dom.spec.whatwg.org/#dom-range-startcontainer
44
+ * @returns Start container.
45
+ */
46
+ get startContainer() {
47
+ return this._start.node;
48
+ }
49
+ /**
50
+ * Returns end container.
51
+ *
52
+ * @see https://dom.spec.whatwg.org/#dom-range-endcontainer
53
+ * @returns End container.
54
+ */
55
+ get endContainer() {
56
+ return this._end.node;
57
+ }
58
+ /**
59
+ * Returns start offset.
60
+ *
61
+ * @see https://dom.spec.whatwg.org/#dom-range-startoffset
62
+ * @returns Start offset.
63
+ */
64
+ get startOffset() {
65
+ if (this._start.offset > 0) {
66
+ const length = NodeUtility_1.default.getNodeLength(this._start.node);
67
+ if (this._start.offset > length) {
68
+ this._start.offset = length;
69
+ }
70
+ else if (length === 0) {
71
+ this._start.offset = 0;
72
+ }
73
+ }
74
+ return this._start.offset;
75
+ }
76
+ /**
77
+ * Returns end offset.
78
+ *
79
+ * @see https://dom.spec.whatwg.org/#dom-range-endoffset
80
+ * @returns End offset.
81
+ */
82
+ get endOffset() {
83
+ if (this._end.offset > 0) {
84
+ const length = NodeUtility_1.default.getNodeLength(this._end.node);
85
+ if (this._end.offset > length) {
86
+ this._end.offset = length;
87
+ }
88
+ else if (length === 0) {
89
+ this._end.offset = 0;
90
+ }
91
+ }
92
+ return this._end.offset;
93
+ }
94
+ /**
95
+ * Returns a boolean value indicating whether the range's start and end points are at the same position.
96
+ *
97
+ * @see https://dom.spec.whatwg.org/#dom-range-collapsed
98
+ * @returns Collapsed.
99
+ */
100
+ get collapsed() {
101
+ return this._start.node === this._end.node && this.startOffset === this.endOffset;
102
+ }
103
+ /**
104
+ * Returns the deepest Node that contains the startContainer and endContainer nodes.
105
+ *
106
+ * @see https://dom.spec.whatwg.org/#dom-range-commonancestorcontainer
107
+ * @returns Node.
108
+ */
109
+ get commonAncestorContainer() {
110
+ let container = this._start.node;
111
+ while (container) {
112
+ if (NodeUtility_1.default.isInclusiveAncestor(container, this._end.node)) {
113
+ return container;
114
+ }
115
+ container = container.parentNode;
116
+ }
117
+ return null;
118
+ }
119
+ /**
120
+ * Returns -1, 0, or 1 depending on whether the referenceNode is before, the same as, or after the Range.
121
+ *
122
+ * @see https://dom.spec.whatwg.org/#dom-range-collapse
123
+ * @param toStart A boolean value: true collapses the Range to its start, false to its end. If omitted, it defaults to false.
124
+ */
125
+ collapse(toStart = false) {
126
+ if (toStart) {
127
+ this._end = Object.assign({}, this._start);
128
+ }
129
+ else {
130
+ this._start = Object.assign({}, this._end);
131
+ }
132
+ }
133
+ /**
134
+ * Compares the boundary points of the Range with those of another range.
135
+ *
136
+ * @see https://dom.spec.whatwg.org/#dom-range-compareboundarypoints
137
+ * @param how How.
138
+ * @param sourceRange Range.
139
+ * @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.
140
+ */
141
+ compareBoundaryPoints(how, sourceRange) {
142
+ if (how !== RangeHowEnum_1.default.startToStart &&
143
+ how !== RangeHowEnum_1.default.startToEnd &&
144
+ how !== RangeHowEnum_1.default.endToEnd &&
145
+ how !== RangeHowEnum_1.default.endToStart) {
146
+ throw new DOMException_1.default(`The comparison method provided must be one of '${RangeHowEnum_1.default.startToStart}', '${RangeHowEnum_1.default.startToEnd}', '${RangeHowEnum_1.default.endToEnd}' or '${RangeHowEnum_1.default.endToStart}'.`, DOMExceptionNameEnum_1.default.notSupportedError);
147
+ }
148
+ if (this._ownerDocument !== sourceRange._ownerDocument) {
149
+ throw new DOMException_1.default(`The two Ranges are not in the same tree.`, DOMExceptionNameEnum_1.default.wrongDocumentError);
150
+ }
151
+ const thisPoint = {
152
+ node: null,
153
+ offset: 0
154
+ };
155
+ const sourcePoint = {
156
+ node: null,
157
+ offset: 0
158
+ };
159
+ switch (how) {
160
+ case RangeHowEnum_1.default.startToStart:
161
+ thisPoint.node = this._start.node;
162
+ thisPoint.offset = this.startOffset;
163
+ sourcePoint.node = sourceRange._start.node;
164
+ sourcePoint.offset = sourceRange.startOffset;
165
+ break;
166
+ case RangeHowEnum_1.default.startToEnd:
167
+ thisPoint.node = this._end.node;
168
+ thisPoint.offset = this.endOffset;
169
+ sourcePoint.node = sourceRange._start.node;
170
+ sourcePoint.offset = sourceRange.startOffset;
171
+ break;
172
+ case RangeHowEnum_1.default.endToEnd:
173
+ thisPoint.node = this._end.node;
174
+ thisPoint.offset = this.endOffset;
175
+ sourcePoint.node = sourceRange._end.node;
176
+ sourcePoint.offset = sourceRange.endOffset;
177
+ break;
178
+ case RangeHowEnum_1.default.endToStart:
179
+ thisPoint.node = this._start.node;
180
+ thisPoint.offset = this.startOffset;
181
+ sourcePoint.node = sourceRange._end.node;
182
+ sourcePoint.offset = sourceRange.endOffset;
183
+ break;
184
+ }
185
+ return RangeUtility_1.default.compareBoundaryPointsPosition(thisPoint, sourcePoint);
186
+ }
187
+ /**
188
+ * Returns -1, 0, or 1 depending on whether the referenceNode is before, the same as, or after the Range.
189
+ *
190
+ * @see https://dom.spec.whatwg.org/#dom-range-comparepoint
191
+ * @param node Reference node.
192
+ * @param offset Offset.
193
+ * @returns -1,0, or 1.
194
+ */
195
+ comparePoint(node, offset) {
196
+ if (node.ownerDocument !== this._ownerDocument) {
197
+ throw new DOMException_1.default(`The two Ranges are not in the same tree.`, DOMExceptionNameEnum_1.default.wrongDocumentError);
198
+ }
199
+ RangeUtility_1.default.validateBoundaryPoint({ node, offset });
200
+ const boundaryPoint = { node, offset };
201
+ if (RangeUtility_1.default.compareBoundaryPointsPosition(boundaryPoint, {
202
+ node: this._start.node,
203
+ offset: this.startOffset
204
+ }) === -1) {
205
+ return -1;
206
+ }
207
+ else if (RangeUtility_1.default.compareBoundaryPointsPosition(boundaryPoint, {
208
+ node: this._end.node,
209
+ offset: this.endOffset
210
+ }) === 1) {
211
+ return 1;
212
+ }
213
+ return 0;
214
+ }
215
+ /**
216
+ * Returns a DocumentFragment copying the objects of type Node included in the Range.
217
+ *
218
+ * @see https://dom.spec.whatwg.org/#concept-range-clone
219
+ * @returns Document fragment.
220
+ */
221
+ cloneContents() {
222
+ const fragment = this._ownerDocument.createDocumentFragment();
223
+ const startOffset = this.startOffset;
224
+ const endOffset = this.endOffset;
225
+ if (this.collapsed) {
226
+ return fragment;
227
+ }
228
+ if (this._start.node === this._end.node &&
229
+ (this._start.node.nodeType === NodeTypeEnum_1.default.textNode ||
230
+ this._start.node.nodeType === NodeTypeEnum_1.default.processingInstructionNode ||
231
+ this._start.node.nodeType === NodeTypeEnum_1.default.commentNode)) {
232
+ const clone = this._start.node.cloneNode(false);
233
+ clone['_data'] = clone.substringData(startOffset, endOffset - startOffset);
234
+ fragment.appendChild(clone);
235
+ return fragment;
236
+ }
237
+ let commonAncestor = this._start.node;
238
+ while (!NodeUtility_1.default.isInclusiveAncestor(commonAncestor, this._end.node)) {
239
+ commonAncestor = commonAncestor.parentNode;
240
+ }
241
+ let firstPartialContainedChild = null;
242
+ if (!NodeUtility_1.default.isInclusiveAncestor(this._start.node, this._end.node)) {
243
+ let candidate = commonAncestor.firstChild;
244
+ while (!firstPartialContainedChild) {
245
+ if (RangeUtility_1.default.isPartiallyContained(candidate, this)) {
246
+ firstPartialContainedChild = candidate;
247
+ }
248
+ candidate = candidate.nextSibling;
249
+ }
250
+ }
251
+ let lastPartiallyContainedChild = null;
252
+ if (!NodeUtility_1.default.isInclusiveAncestor(this._end.node, this._start.node)) {
253
+ let candidate = commonAncestor.lastChild;
254
+ while (!lastPartiallyContainedChild) {
255
+ if (RangeUtility_1.default.isPartiallyContained(candidate, this)) {
256
+ lastPartiallyContainedChild = candidate;
257
+ }
258
+ candidate = candidate.previousSibling;
259
+ }
260
+ }
261
+ const containedChildren = [];
262
+ for (const node of commonAncestor.childNodes) {
263
+ if (RangeUtility_1.default.isContained(node, this)) {
264
+ if (node.nodeType === NodeTypeEnum_1.default.documentTypeNode) {
265
+ throw new DOMException_1.default('Invalid document type element.', DOMExceptionNameEnum_1.default.hierarchyRequestError);
266
+ }
267
+ containedChildren.push(node);
268
+ }
269
+ }
270
+ if (firstPartialContainedChild !== null &&
271
+ (firstPartialContainedChild.nodeType === NodeTypeEnum_1.default.textNode ||
272
+ firstPartialContainedChild.nodeType === NodeTypeEnum_1.default.processingInstructionNode ||
273
+ firstPartialContainedChild.nodeType === NodeTypeEnum_1.default.commentNode)) {
274
+ const clone = this._start.node.cloneNode(false);
275
+ clone['_data'] = clone.substringData(startOffset, NodeUtility_1.default.getNodeLength(this._start.node) - startOffset);
276
+ fragment.appendChild(clone);
277
+ }
278
+ else if (firstPartialContainedChild !== null) {
279
+ const clone = firstPartialContainedChild.cloneNode();
280
+ fragment.appendChild(clone);
281
+ const subRange = new Range();
282
+ subRange._start.node = this._end.node;
283
+ subRange._start.offset = endOffset;
284
+ subRange._end.node = firstPartialContainedChild;
285
+ subRange._end.offset = NodeUtility_1.default.getNodeLength(firstPartialContainedChild);
286
+ const subDocumentFragment = subRange.cloneContents();
287
+ clone.appendChild(subDocumentFragment);
288
+ }
289
+ for (const containedChild of containedChildren) {
290
+ const clone = containedChild.cloneNode(true);
291
+ fragment.appendChild(clone);
292
+ }
293
+ if (lastPartiallyContainedChild !== null &&
294
+ (lastPartiallyContainedChild.nodeType === NodeTypeEnum_1.default.textNode ||
295
+ lastPartiallyContainedChild.nodeType === NodeTypeEnum_1.default.processingInstructionNode ||
296
+ lastPartiallyContainedChild.nodeType === NodeTypeEnum_1.default.commentNode)) {
297
+ const clone = this._end.node.cloneNode(false);
298
+ clone['_data'] = clone.substringData(0, endOffset);
299
+ fragment.appendChild(clone);
300
+ }
301
+ else if (lastPartiallyContainedChild !== null) {
302
+ const clone = lastPartiallyContainedChild.cloneNode(false);
303
+ fragment.appendChild(clone);
304
+ const subRange = new Range();
305
+ subRange._start.node = lastPartiallyContainedChild;
306
+ subRange._start.offset = 0;
307
+ subRange._end.node = this._end.node;
308
+ subRange._end.offset = endOffset;
309
+ const subFragment = subRange.cloneContents();
310
+ clone.appendChild(subFragment);
311
+ }
312
+ return fragment;
313
+ }
314
+ /**
315
+ * Returns a Range object with boundary points identical to the cloned Range.
316
+ *
317
+ * @see https://dom.spec.whatwg.org/#dom-range-clonerange
318
+ * @returns Range.
319
+ */
320
+ cloneRange() {
321
+ const clone = new Range();
322
+ clone._start.node = this._start.node;
323
+ clone._start.offset = this._start.offset;
324
+ clone._end.node = this._end.node;
325
+ clone._end.offset = this._end.offset;
326
+ return clone;
327
+ }
328
+ /**
329
+ * Returns a DocumentFragment by invoking the HTML fragment parsing algorithm or the XML fragment parsing algorithm with the start of the range (the parent of the selected node) as the context node. The HTML fragment parsing algorithm is used if the range belongs to a Document whose HTMLness bit is set. In the HTML case, if the context node would be html, for historical reasons the fragment parsing algorithm is invoked with body as the context instead.
330
+ *
331
+ * @see https://w3c.github.io/DOM-Parsing/#dfn-fragment-parsing-algorithm
332
+ * @param tagString Tag string.
333
+ * @returns Document fragment.
334
+ */
335
+ createContextualFragment(tagString) {
336
+ // TODO: We only have support for HTML in the parser currently, so it is not necessary to check which context it is
337
+ return XMLParser_1.default.parse(this._ownerDocument, tagString);
338
+ }
339
+ /**
340
+ * Removes the contents of the Range from the Document.
341
+ *
342
+ * @see https://dom.spec.whatwg.org/#dom-range-deletecontents
343
+ */
344
+ deleteContents() {
345
+ const startOffset = this.startOffset;
346
+ const endOffset = this.endOffset;
347
+ if (this.collapsed) {
348
+ return;
349
+ }
350
+ if (this._start.node === this._end.node &&
351
+ (this._start.node.nodeType === NodeTypeEnum_1.default.textNode ||
352
+ this._start.node.nodeType === NodeTypeEnum_1.default.processingInstructionNode ||
353
+ this._start.node.nodeType === NodeTypeEnum_1.default.commentNode)) {
354
+ this._start.node.replaceData(startOffset, endOffset - startOffset, '');
355
+ return;
356
+ }
357
+ const nodesToRemove = [];
358
+ let currentNode = this._start.node;
359
+ const endNode = NodeUtility_1.default.nextDecendantNode(this._end.node);
360
+ while (currentNode && currentNode !== endNode) {
361
+ if (RangeUtility_1.default.isContained(currentNode, this) &&
362
+ !RangeUtility_1.default.isContained(currentNode.parentNode, this)) {
363
+ nodesToRemove.push(currentNode);
364
+ }
365
+ currentNode = NodeUtility_1.default.following(currentNode);
366
+ }
367
+ let newNode;
368
+ let newOffset;
369
+ if (NodeUtility_1.default.isInclusiveAncestor(this._start.node, this._end.node)) {
370
+ newNode = this._start.node;
371
+ newOffset = startOffset;
372
+ }
373
+ else {
374
+ let referenceNode = this._start.node;
375
+ while (referenceNode &&
376
+ !NodeUtility_1.default.isInclusiveAncestor(referenceNode.parentNode, this._end.node)) {
377
+ referenceNode = referenceNode.parentNode;
378
+ }
379
+ newNode = referenceNode.parentNode;
380
+ newOffset = referenceNode.parentNode.childNodes.indexOf(referenceNode) + 1;
381
+ }
382
+ if (this._start.node.nodeType === NodeTypeEnum_1.default.textNode ||
383
+ this._start.node.nodeType === NodeTypeEnum_1.default.processingInstructionNode ||
384
+ this._start.node.nodeType === NodeTypeEnum_1.default.commentNode) {
385
+ this._start.node.replaceData(this.startOffset, NodeUtility_1.default.getNodeLength(this._start.node) - this.startOffset, '');
386
+ }
387
+ for (const node of nodesToRemove) {
388
+ const parent = node.parentNode;
389
+ parent.removeChild(node);
390
+ }
391
+ if (this._end.node.nodeType === NodeTypeEnum_1.default.textNode ||
392
+ this._end.node.nodeType === NodeTypeEnum_1.default.processingInstructionNode ||
393
+ this._end.node.nodeType === NodeTypeEnum_1.default.commentNode) {
394
+ this._end.node.replaceData(0, endOffset, '');
395
+ }
396
+ this._start.node = newNode;
397
+ this._start.offset = newOffset;
398
+ this._end.node = newNode;
399
+ this._end.offset = newOffset;
400
+ }
401
+ /**
402
+ * Does nothing. It used to disable the Range object and enable the browser to release associated resources. The method has been kept for compatibility.
403
+ *
404
+ * @see https://dom.spec.whatwg.org/#dom-range-detach
405
+ */
406
+ detach() {
407
+ // Do nothing by spec
408
+ }
409
+ /**
410
+ * Moves contents of the Range from the document tree into a DocumentFragment.
411
+ *
412
+ * @see https://dom.spec.whatwg.org/#dom-range-extractcontents
413
+ * @returns Document fragment.
414
+ */
415
+ extractContents() {
416
+ const fragment = this._ownerDocument.createDocumentFragment();
417
+ const startOffset = this.startOffset;
418
+ const endOffset = this.endOffset;
419
+ if (this.collapsed) {
420
+ return fragment;
421
+ }
422
+ if (this._start.node === this._end.node &&
423
+ (this._start.node.nodeType === NodeTypeEnum_1.default.textNode ||
424
+ this._start.node.nodeType === NodeTypeEnum_1.default.processingInstructionNode ||
425
+ this._start.node.nodeType === NodeTypeEnum_1.default.commentNode)) {
426
+ const clone = this._start.node.cloneNode(false);
427
+ clone['_data'] = clone.substringData(startOffset, endOffset - startOffset);
428
+ fragment.appendChild(clone);
429
+ this._start.node.replaceData(startOffset, endOffset - startOffset, '');
430
+ return fragment;
431
+ }
432
+ let commonAncestor = this._start.node;
433
+ while (!NodeUtility_1.default.isInclusiveAncestor(commonAncestor, this._end.node)) {
434
+ commonAncestor = commonAncestor.parentNode;
435
+ }
436
+ let firstPartialContainedChild = null;
437
+ if (!NodeUtility_1.default.isInclusiveAncestor(this._start.node, this._end.node)) {
438
+ let candidate = commonAncestor.firstChild;
439
+ while (!firstPartialContainedChild) {
440
+ if (RangeUtility_1.default.isPartiallyContained(candidate, this)) {
441
+ firstPartialContainedChild = candidate;
442
+ }
443
+ candidate = candidate.nextSibling;
444
+ }
445
+ }
446
+ let lastPartiallyContainedChild = null;
447
+ if (!NodeUtility_1.default.isInclusiveAncestor(this._end.node, this._start.node)) {
448
+ let candidate = commonAncestor.lastChild;
449
+ while (!lastPartiallyContainedChild) {
450
+ if (RangeUtility_1.default.isPartiallyContained(candidate, this)) {
451
+ lastPartiallyContainedChild = candidate;
452
+ }
453
+ candidate = candidate.previousSibling;
454
+ }
455
+ }
456
+ const containedChildren = [];
457
+ for (const node of commonAncestor.childNodes) {
458
+ if (RangeUtility_1.default.isContained(node, this)) {
459
+ if (node.nodeType === NodeTypeEnum_1.default.documentTypeNode) {
460
+ throw new DOMException_1.default('Invalid document type element.', DOMExceptionNameEnum_1.default.hierarchyRequestError);
461
+ }
462
+ containedChildren.push(node);
463
+ }
464
+ }
465
+ let newNode;
466
+ let newOffset;
467
+ if (NodeUtility_1.default.isInclusiveAncestor(this._start.node, this._end.node)) {
468
+ newNode = this._start.node;
469
+ newOffset = startOffset;
470
+ }
471
+ else {
472
+ let referenceNode = this._start.node;
473
+ while (referenceNode &&
474
+ !NodeUtility_1.default.isInclusiveAncestor(referenceNode.parentNode, this._end.node)) {
475
+ referenceNode = referenceNode.parentNode;
476
+ }
477
+ newNode = referenceNode.parentNode;
478
+ newOffset = referenceNode.parentNode.childNodes.indexOf(referenceNode) + 1;
479
+ }
480
+ if (firstPartialContainedChild !== null &&
481
+ (firstPartialContainedChild.nodeType === NodeTypeEnum_1.default.textNode ||
482
+ firstPartialContainedChild.nodeType === NodeTypeEnum_1.default.processingInstructionNode ||
483
+ firstPartialContainedChild.nodeType === NodeTypeEnum_1.default.commentNode)) {
484
+ const clone = this._start.node.cloneNode(false);
485
+ clone['_data'] = clone.substringData(startOffset, NodeUtility_1.default.getNodeLength(this._start.node) - startOffset);
486
+ fragment.appendChild(clone);
487
+ this._start.node.replaceData(startOffset, NodeUtility_1.default.getNodeLength(this._start.node) - startOffset, '');
488
+ }
489
+ else if (firstPartialContainedChild !== null) {
490
+ const clone = firstPartialContainedChild.cloneNode(false);
491
+ fragment.appendChild(clone);
492
+ const subRange = new Range();
493
+ subRange._start.node = this._start.node;
494
+ subRange._start.offset = startOffset;
495
+ subRange._end.node = firstPartialContainedChild;
496
+ subRange._end.offset = NodeUtility_1.default.getNodeLength(firstPartialContainedChild);
497
+ const subFragment = subRange.extractContents();
498
+ clone.appendChild(subFragment);
499
+ }
500
+ for (const containedChild of containedChildren) {
501
+ fragment.appendChild(containedChild);
502
+ }
503
+ if (lastPartiallyContainedChild !== null &&
504
+ (lastPartiallyContainedChild.nodeType === NodeTypeEnum_1.default.textNode ||
505
+ lastPartiallyContainedChild.nodeType === NodeTypeEnum_1.default.processingInstructionNode ||
506
+ lastPartiallyContainedChild.nodeType === NodeTypeEnum_1.default.commentNode)) {
507
+ const clone = this._end.node.cloneNode(false);
508
+ clone['_data'] = clone.substringData(0, endOffset);
509
+ fragment.appendChild(clone);
510
+ this._end.node.replaceData(0, endOffset, '');
511
+ }
512
+ else if (lastPartiallyContainedChild !== null) {
513
+ const clone = lastPartiallyContainedChild.cloneNode(false);
514
+ fragment.appendChild(clone);
515
+ const subRange = new Range();
516
+ subRange._start.node = lastPartiallyContainedChild;
517
+ subRange._start.offset = 0;
518
+ subRange._end.node = this._end.node;
519
+ subRange._end.offset = endOffset;
520
+ const subFragment = subRange.extractContents();
521
+ clone.appendChild(subFragment);
522
+ }
523
+ this._start.node = newNode;
524
+ this._start.offset = newOffset;
525
+ this._end.node = newNode;
526
+ this._end.offset = newOffset;
527
+ return fragment;
528
+ }
529
+ /**
530
+ * Returns a DOMRect object that bounds the contents of the range; this is a rectangle enclosing the union of the bounding rectangles for all the elements in the range.
531
+ *
532
+ * @returns DOMRect object.
533
+ */
534
+ getBoundingClientRect() {
535
+ // TODO: Not full implementation
536
+ return new DOMRect_1.default();
537
+ }
538
+ /**
539
+ * The Range.getClientRects() method returns a list of DOMRect objects representing the area of the screen occupied by the range. This is created by aggregating the results of calls to Element.getClientRects() for all the elements in the range.
540
+ *
541
+ * @returns DOMRect objects.
542
+ */
543
+ getClientRects() {
544
+ // TODO: Not full implementation
545
+ return DOMRectListFactory_1.default.create();
546
+ }
547
+ /**
548
+ * Returns a boolean indicating whether the given point is in the Range.
549
+ *
550
+ * @see https://dom.spec.whatwg.org/#dom-range-ispointinrange
551
+ * @param node Reference node.
552
+ * @param offset Offset.
553
+ * @returns "true" if in range.
554
+ */
555
+ isPointInRange(node, offset = 0) {
556
+ if (node.ownerDocument !== this._ownerDocument) {
557
+ return false;
558
+ }
559
+ const boundaryPoint = { node, offset };
560
+ RangeUtility_1.default.validateBoundaryPoint(boundaryPoint);
561
+ if (RangeUtility_1.default.compareBoundaryPointsPosition(boundaryPoint, {
562
+ node: this._start.node,
563
+ offset: this.startOffset
564
+ }) === -1 ||
565
+ RangeUtility_1.default.compareBoundaryPointsPosition(boundaryPoint, {
566
+ node: this._end.node,
567
+ offset: this.endOffset
568
+ }) === 1) {
569
+ return false;
570
+ }
571
+ return true;
572
+ }
573
+ /**
574
+ * Inserts a node at the start of the Range.
575
+ *
576
+ * @see https://dom.spec.whatwg.org/#concept-range-insert
577
+ * @param newNode New node.
578
+ */
579
+ insertNode(newNode) {
580
+ if (this._start.node.nodeType === NodeTypeEnum_1.default.processingInstructionNode ||
581
+ this._start.node.nodeType === NodeTypeEnum_1.default.commentNode ||
582
+ (this._start.node.nodeType === NodeTypeEnum_1.default.textNode && !this._start.node.parentNode) ||
583
+ newNode === this._start.node) {
584
+ throw new DOMException_1.default('Invalid start node.', DOMExceptionNameEnum_1.default.hierarchyRequestError);
585
+ }
586
+ let referenceNode = this._start.node.nodeType === NodeTypeEnum_1.default.textNode
587
+ ? this._start.node
588
+ : this._start.node.childNodes[this.startOffset] || null;
589
+ const parent = !referenceNode ? this._start.node : referenceNode.parentNode;
590
+ if (this._start.node.nodeType === NodeTypeEnum_1.default.textNode) {
591
+ referenceNode = this._start.node.splitText(this.startOffset);
592
+ }
593
+ if (newNode === referenceNode) {
594
+ referenceNode = referenceNode.nextSibling;
595
+ }
596
+ const nodeParent = newNode.parentNode;
597
+ if (nodeParent) {
598
+ nodeParent.removeChild(newNode);
599
+ }
600
+ let newOffset = !referenceNode
601
+ ? NodeUtility_1.default.getNodeLength(parent)
602
+ : referenceNode.parentNode.childNodes.indexOf(referenceNode);
603
+ newOffset +=
604
+ newNode.nodeType === NodeTypeEnum_1.default.documentFragmentNode
605
+ ? NodeUtility_1.default.getNodeLength(newNode)
606
+ : 1;
607
+ parent.insertBefore(newNode, referenceNode);
608
+ if (this.collapsed) {
609
+ this._end.node = parent;
610
+ this._end.offset = newOffset;
611
+ }
612
+ }
613
+ /**
614
+ * Returns a boolean indicating whether the given Node intersects the Range.
615
+ *
616
+ * @see https://dom.spec.whatwg.org/#dom-range-intersectsnode
617
+ * @param node Reference node.
618
+ * @returns "true" if it intersects.
619
+ */
620
+ intersectsNode(node) {
621
+ if (node.ownerDocument !== this._ownerDocument) {
622
+ return false;
623
+ }
624
+ const parent = node.parentNode;
625
+ if (!parent) {
626
+ return true;
627
+ }
628
+ const offset = parent.childNodes.indexOf(node);
629
+ return (RangeUtility_1.default.compareBoundaryPointsPosition({ node: parent, offset }, { node: this._end.node, offset: this.endOffset }) === -1 &&
630
+ RangeUtility_1.default.compareBoundaryPointsPosition({ node: parent, offset: offset + 1 }, { node: this._start.node, offset: this.startOffset }) === 1);
631
+ }
632
+ /**
633
+ * Sets the Range to contain the Node and its contents.
634
+ *
635
+ * @see https://dom.spec.whatwg.org/#concept-range-select
636
+ * @param node Reference node.
637
+ */
638
+ selectNode(node) {
639
+ if (!node.parentNode) {
640
+ throw new DOMException_1.default(`The given Node has no parent.`, DOMExceptionNameEnum_1.default.invalidNodeTypeError);
641
+ }
642
+ const index = node.parentNode.childNodes.indexOf(node);
643
+ this._start.node = node.parentNode;
644
+ this._start.offset = index;
645
+ this._end.node = node.parentNode;
646
+ this._end.offset = index + 1;
647
+ }
648
+ /**
649
+ * Sets the Range to contain the contents of a Node.
650
+ *
651
+ * @see https://dom.spec.whatwg.org/#dom-range-selectnodecontents
652
+ * @param node Reference node.
653
+ */
654
+ selectNodeContents(node) {
655
+ if (node.nodeType === NodeTypeEnum_1.default.documentTypeNode) {
656
+ throw new DOMException_1.default("DocumentType Node can't be used as boundary point.", DOMExceptionNameEnum_1.default.invalidNodeTypeError);
657
+ }
658
+ this._start.node = node;
659
+ this._start.offset = 0;
660
+ this._end.node = node;
661
+ this._end.offset = NodeUtility_1.default.getNodeLength(node);
662
+ }
663
+ /**
664
+ * Sets the end position of a Range to be located at the given offset into the specified node x.
665
+ *
666
+ * @see https://dom.spec.whatwg.org/#dom-range-setend
667
+ * @param node End node.
668
+ * @param offset End offset.
669
+ */
670
+ setEnd(node, offset = 0) {
671
+ RangeUtility_1.default.validateBoundaryPoint({ node, offset });
672
+ const boundaryPoint = { node, offset };
673
+ if (node.ownerDocument !== this._ownerDocument ||
674
+ RangeUtility_1.default.compareBoundaryPointsPosition(boundaryPoint, {
675
+ node: this._start.node,
676
+ offset: this.startOffset
677
+ }) === -1) {
678
+ this._start.node = node;
679
+ this._start.offset = offset;
680
+ }
681
+ this._end.node = node;
682
+ this._end.offset = offset;
683
+ }
684
+ /**
685
+ * Sets the start position of a Range.
686
+ *
687
+ * @see https://dom.spec.whatwg.org/#dom-range-setstart
688
+ * @param node Start node.
689
+ * @param offset Start offset.
690
+ */
691
+ setStart(node, offset = 0) {
692
+ RangeUtility_1.default.validateBoundaryPoint({ node, offset });
693
+ const boundaryPoint = { node, offset };
694
+ if (node.ownerDocument !== this._ownerDocument ||
695
+ RangeUtility_1.default.compareBoundaryPointsPosition(boundaryPoint, {
696
+ node: this._end.node,
697
+ offset: this.endOffset
698
+ }) === 1) {
699
+ this._end.node = node;
700
+ this._end.offset = offset;
701
+ }
702
+ this._start.node = node;
703
+ this._start.offset = offset;
704
+ }
705
+ /**
706
+ * Sets the end position of a Range relative to another Node.
707
+ *
708
+ * @see https://dom.spec.whatwg.org/#dom-range-setendafter
709
+ * @param node Reference node.
710
+ */
711
+ setEndAfter(node) {
712
+ if (!node.parentNode) {
713
+ throw new DOMException_1.default('The given Node has no parent.', DOMExceptionNameEnum_1.default.invalidNodeTypeError);
714
+ }
715
+ this.setEnd(node.parentNode, node.parentNode.childNodes.indexOf(node) + 1);
716
+ }
717
+ /**
718
+ * Sets the end position of a Range relative to another Node.
719
+ *
720
+ * @see https://dom.spec.whatwg.org/#dom-range-setendbefore
721
+ * @param node Reference node.
722
+ */
723
+ setEndBefore(node) {
724
+ if (!node.parentNode) {
725
+ throw new DOMException_1.default('The given Node has no parent.', DOMExceptionNameEnum_1.default.invalidNodeTypeError);
726
+ }
727
+ this.setEnd(node.parentNode, node.parentNode.childNodes.indexOf(node));
728
+ }
729
+ /**
730
+ * Sets the start position of a Range relative to a Node.
731
+ *
732
+ * @see https://dom.spec.whatwg.org/#dom-range-setstartafter
733
+ * @param node Reference node.
734
+ */
735
+ setStartAfter(node) {
736
+ if (!node.parentNode) {
737
+ throw new DOMException_1.default('The given Node has no parent.', DOMExceptionNameEnum_1.default.invalidNodeTypeError);
738
+ }
739
+ this.setStart(node.parentNode, node.parentNode.childNodes.indexOf(node) + 1);
740
+ }
741
+ /**
742
+ * Sets the start position of a Range relative to another Node.
743
+ *
744
+ * @see https://dom.spec.whatwg.org/#dom-range-setstartbefore
745
+ * @param node Reference node.
746
+ */
747
+ setStartBefore(node) {
748
+ if (!node.parentNode) {
749
+ throw new DOMException_1.default('The given Node has no parent.', DOMExceptionNameEnum_1.default.invalidNodeTypeError);
750
+ }
751
+ this.setStart(node.parentNode, node.parentNode.childNodes.indexOf(node));
752
+ }
753
+ /**
754
+ * Moves content of the Range into a new node, placing the new node at the start of the specified range.
755
+ *
756
+ * @see https://dom.spec.whatwg.org/#dom-range-surroundcontents
757
+ * @param newParent New parent.
758
+ */
759
+ surroundContents(newParent) {
760
+ let node = this.commonAncestorContainer;
761
+ const endNode = NodeUtility_1.default.nextDecendantNode(node);
762
+ while (node !== endNode) {
763
+ if (node.nodeType !== NodeTypeEnum_1.default.textNode &&
764
+ RangeUtility_1.default.isPartiallyContained(node, this)) {
765
+ throw new DOMException_1.default('The Range has partially contains a non-Text node.', DOMExceptionNameEnum_1.default.invalidStateError);
766
+ }
767
+ node = NodeUtility_1.default.following(node);
768
+ }
769
+ if (newParent.nodeType === NodeTypeEnum_1.default.documentNode ||
770
+ newParent.nodeType === NodeTypeEnum_1.default.documentTypeNode ||
771
+ newParent.nodeType === NodeTypeEnum_1.default.documentFragmentNode) {
772
+ throw new DOMException_1.default('Invalid element type.', DOMExceptionNameEnum_1.default.invalidNodeTypeError);
773
+ }
774
+ const fragment = this.extractContents();
775
+ while (newParent.firstChild) {
776
+ newParent.removeChild(newParent.firstChild);
777
+ }
778
+ this.insertNode(newParent);
779
+ newParent.appendChild(fragment);
780
+ this.selectNode(newParent);
781
+ }
782
+ /**
783
+ * Returns the text of the Range.
784
+ *
785
+ * @see https://dom.spec.whatwg.org/#dom-range-stringifier
786
+ */
787
+ toString() {
788
+ const startOffset = this.startOffset;
789
+ const endOffset = this.endOffset;
790
+ let string = '';
791
+ if (this._start.node === this._end.node &&
792
+ this._start.node.nodeType === NodeTypeEnum_1.default.textNode) {
793
+ return this._start.node.data.slice(startOffset, endOffset);
794
+ }
795
+ if (this._start.node.nodeType === NodeTypeEnum_1.default.textNode) {
796
+ string += this._start.node.data.slice(startOffset);
797
+ }
798
+ const endNode = NodeUtility_1.default.nextDecendantNode(this._end.node);
799
+ let currentNode = this._start.node;
800
+ while (currentNode && currentNode !== endNode) {
801
+ if (currentNode.nodeType === NodeTypeEnum_1.default.textNode &&
802
+ RangeUtility_1.default.isContained(currentNode, this)) {
803
+ string += currentNode.data;
804
+ }
805
+ currentNode = NodeUtility_1.default.following(currentNode);
806
+ }
807
+ if (this._end.node.nodeType === NodeTypeEnum_1.default.textNode) {
808
+ string += this._end.node.data.slice(0, endOffset);
809
+ }
810
+ return string;
811
+ }
812
+ }
813
+ exports.default = Range;
814
+ // Owner document is set by a sub-class in the Window constructor
815
+ Range._ownerDocument = null;
816
+ Range.END_TO_END = RangeHowEnum_1.default.endToEnd;
817
+ Range.END_TO_START = RangeHowEnum_1.default.endToStart;
818
+ Range.START_TO_END = RangeHowEnum_1.default.startToEnd;
819
+ Range.START_TO_START = RangeHowEnum_1.default.startToStart;
820
+ //# sourceMappingURL=Range.js.map