pseudo-dom 0.16.0 → 0.17.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.
@@ -1,1149 +1,1149 @@
1
- 'use strict'
2
-
3
- require('core-js/modules/esnext.iterator.constructor.js')
4
- require('core-js/modules/esnext.iterator.every.js')
5
- require('core-js/modules/esnext.iterator.find.js')
6
- require('core-js/modules/esnext.iterator.for-each.js')
7
- require('core-js/modules/esnext.iterator.map.js')
8
- require('core-js/modules/esnext.iterator.some.js')
9
- require('core-js/modules/esnext.set.add-all.js')
10
- require('core-js/modules/esnext.set.delete-all.js')
11
- require('core-js/modules/esnext.set.difference.js')
12
- require('core-js/modules/esnext.set.every.js')
13
- require('core-js/modules/esnext.set.filter.js')
14
- require('core-js/modules/esnext.set.find.js')
15
- require('core-js/modules/esnext.set.intersection.js')
16
- require('core-js/modules/esnext.set.is-disjoint-from.js')
17
- require('core-js/modules/esnext.set.is-subset-of.js')
18
- require('core-js/modules/esnext.set.is-superset-of.js')
19
- require('core-js/modules/esnext.set.join.js')
20
- require('core-js/modules/esnext.set.map.js')
21
- require('core-js/modules/esnext.set.reduce.js')
22
- require('core-js/modules/esnext.set.some.js')
23
- require('core-js/modules/esnext.set.symmetric-difference.js')
24
- require('core-js/modules/esnext.set.union.js')
25
- const __importDefault = void 0 && (void 0).__importDefault || function (mod) {
26
- return mod && mod.__esModule
27
- ? mod
28
- : {
29
- default: mod
30
- }
31
- }
32
- Object.defineProperty(exports, '__esModule', {
33
- value: true
34
- })
35
- exports.ElementService = void 0
36
- const createEvent_1 = __importDefault(require('../factories/createEvent'))
37
- const NodeService_1 = require('./NodeService')
38
- const AttrService_1 = require('./AttrService')
39
- const DOMTokenListService_1 = require('./DOMTokenListService')
40
- const NamedNodeMapService_1 = require('./NamedNodeMapService')
41
- const getParentNodesFromAttribute_1 = __importDefault(require('../functions/getParentNodesFromAttribute'))
42
- const HTMLCollectionService_1 = require('./HTMLCollectionService')
43
- const cloneObject_1 = __importDefault(require('si-funciona/dist/helpers/objects/cloneObject'))
44
- const isEqual_1 = __importDefault(require('si-funciona/dist/helpers/objects/isEqual'))
45
- const query_1 = require('../factories/query')
46
- const ShadowRootService_1 = require('./ShadowRootService')
47
- const serializeHTML_1 = require('../factories/serializeHTML')
48
- const zeroRect = () => ({
49
- x: 0,
50
- y: 0,
51
- width: 0,
52
- height: 0,
53
- top: 0,
54
- right: 0,
55
- bottom: 0,
56
- left: 0
57
- })
58
- /**
59
- * Simulate the behaviour of the Element Class when there is no DOM available.
60
- * @author Joshua Heagle <joshuaheagle@gmail.com>
61
- * @class
62
- * @augments PseudoNode
63
- * @property {string} tagName
64
- * @property {string} className
65
- * @property {string} id
66
- * @property {string} innerHtml
67
- * @property {Array} attributes
68
- * @property {function} hasAttribute
69
- * @property {function} setAttribute
70
- * @property {function} getAttribute
71
- * @property {function} removeAttribute
72
- */
73
- class ElementService extends NodeService_1.NodeService {
74
- /**
75
- * @param {Object} [settings={}]
76
- * @param {string} [settings.tagName=''] The name of the tag this element represents
77
- * @param {Array<{name: string, value: *}>} [settings.attributes=[]] The attributes (also assigned as properties) to start with
78
- * @param {PseudoNode|null} [settings.parent=null] The node to add this element to as its last child
79
- * @param {Array<PseudoNode>} [settings.children=[]] The nodes to start as children
80
- * @constructor
81
- */
82
- constructor ({
83
- tagName = '',
84
- attributes = [],
85
- parent = null,
86
- children = []
87
- } = {}) {
88
- super()
89
- /** What getBoundingClientRect() returns - not really computed (there is no layout engine), set this directly. */
90
- this.boundingClientRect = zeroRect()
91
- /** What getClientRects() returns - set this directly. */
92
- this.clientRects = []
93
- /** What getAnimations() returns - set this directly. */
94
- this.animations = []
95
- /** What checkVisibility() returns - set this directly. */
96
- this.isVisible = true
97
- this.capturedPointers = new Set()
98
- this.shadowRootInstance = null
99
- this.defaultEventApplied = false
100
- this.tokenList = new DOMTokenListService_1.DOMTokenListService()
101
- this.tag = tagName
102
- this.attributeList = attributes.concat([{
103
- name: 'className',
104
- value: ''
105
- }, {
106
- name: 'id',
107
- value: ''
108
- },
109
- // Layout is not really computed (there is no rendering engine here): these start at 0, like an unrendered
110
- // element's would, but can be set directly to whatever a test needs code under test to see.
111
- {
112
- name: 'clientHeight',
113
- value: 0
114
- }, {
115
- name: 'clientLeft',
116
- value: 0
117
- }, {
118
- name: 'clientTop',
119
- value: 0
120
- }, {
121
- name: 'clientWidth',
122
- value: 0
123
- }, {
124
- name: 'scrollHeight',
125
- value: 0
126
- }, {
127
- name: 'scrollLeft',
128
- value: 0
129
- }, {
130
- name: 'scrollTop',
131
- value: 0
132
- }, {
133
- name: 'scrollWidth',
134
- value: 0
135
- }])
136
- this.propertyAttributes = this.attributeList.map(({
137
- name
138
- }) => name)
139
- this.attributeList.forEach(({
140
- name,
141
- value
142
- }) => {
143
- this[name] = value
144
- })
145
- children.forEach(child => {
146
- if (!child || typeof child.nodeType !== 'number') {
147
- throw new TypeError('The children of an element must be nodes.')
148
- }
149
- this.appendChild(child)
150
- })
151
- if (parent) {
152
- parent.appendChild(this)
153
- }
154
- }
155
-
156
- /**
157
- * The attributes with the values they have now: the ones which are also properties (className, id, style, ...) can
158
- * have been changed through the property, which does not change the stored list.
159
- * @returns {Array<{name: string, value: *}>}
160
- */
161
- currentAttributes () {
162
- return this.attributeList.map(({
163
- name,
164
- value
165
- }) => ({
166
- name,
167
- value: this.propertyAttributes.indexOf(name) >= 0 ? this[name] : value
168
- }))
169
- }
170
-
171
- get nodeName () {
172
- return this.tag
173
- }
174
-
175
- /**
176
- * A copy of this element without its children: the same tag and attributes (the values which are objects, such as
177
- * style, are copied too rather than shared), but not its parent or listeners.
178
- * @returns {ElementService}
179
- */
180
- cloneShallow () {
181
- const copy = new this.constructor({
182
- tagName: this.tag
183
- })
184
- copy.attributeList.length = 0
185
- this.currentAttributes().forEach(({
186
- name,
187
- value
188
- }) => {
189
- const copied = typeof value === 'object' && value !== null ? (0, cloneObject_1.default)(value) : value
190
- copy.attributeList.push({
191
- name,
192
- value: copied
193
- })
194
- if (copy.propertyAttributes.indexOf(name) >= 0) {
195
- copy[name] = copied
196
- }
197
- })
198
- copy.ownerDocumentStore = this.ownerDocumentStore
199
- return copy
200
- }
201
-
202
- /**
203
- * Elements are equal when they have the same tag and the same attributes (in any order), which is what isEqualNode
204
- * checks before it compares the children.
205
- * @param {NodeService} other The element to compare with
206
- * @returns {boolean}
207
- */
208
- equalsShallow (other) {
209
- const mine = this.currentAttributes()
210
- const theirs = other.currentAttributes()
211
- return this.nodeName === other.nodeName && mine.length === theirs.length && mine.every(({
212
- name,
213
- value
214
- }) => {
215
- const match = theirs.find(attributeOfOther => attributeOfOther.name === name)
216
- return typeof match !== 'undefined' && (0, isEqual_1.default)(value, match.value)
217
- })
218
- }
219
-
220
- get tagName () {
221
- return this.tag
222
- }
223
-
224
- /**
225
- * The local part of the element's qualified name. There is no real namespace parsing here, so this is always the
226
- * same as tagName.
227
- * @returns {string}
228
- */
229
- get localName () {
230
- return this.tag
231
- }
232
-
233
- /**
234
- * The element's namespace prefix, or null when it has none. There is no real namespace parsing here, so this is
235
- * always null.
236
- * @returns {string|null}
237
- */
238
- get prefix () {
239
- return null
240
- }
241
-
242
- /**
243
- * The HTML markup of this element's children. Only the getter is here (the setter, which needs to build new
244
- * elements from parsed HTML, is on HTMLElementService - see its class comment).
245
- * @returns {string}
246
- */
247
- get innerHTML () {
248
- return (0, serializeHTML_1.serializeChildren)(this)
249
- }
250
-
251
- /**
252
- * The HTML markup of this element itself, including its children. Only the getter is here (see innerHTML).
253
- * @returns {string}
254
- */
255
- get outerHTML () {
256
- return (0, serializeHTML_1.serializeOuter)(this)
257
- }
258
-
259
- get nodeType () {
260
- return NodeService_1.NodeService.ELEMENT_NODE
261
- }
262
-
263
- get attributes () {
264
- return new NamedNodeMapService_1.NamedNodeMapService(this.currentAttributes().map(({
265
- name,
266
- value
267
- }) => new AttrService_1.AttrService(name, String(value), this)))
268
- }
269
-
270
- get classList () {
271
- return this.tokenList
272
- }
273
-
274
- get className () {
275
- return this.tokenList.value
276
- }
277
-
278
- set className (className) {
279
- this.tokenList.value = className
280
- }
281
-
282
- /**
283
- * Some elements have default behaviour, this registers it when the element is added.
284
- * @returns {Function}
285
- */
286
- /**
287
- * A live view of this element's element children (text, comments and the like are not included).
288
- * @returns {PseudoHTMLCollection}
289
- */
290
- get children () {
291
- return new HTMLCollectionService_1.HTMLCollectionService(this)
292
- }
293
-
294
- /**
295
- * How many element children this element has.
296
- * @returns {number}
297
- */
298
- get childElementCount () {
299
- return this.children.length
300
- }
301
-
302
- /**
303
- * The first child of this element which is an element, or null when there is none.
304
- * @returns {PseudoElement|null}
305
- */
306
- get firstElementChild () {
307
- return this.children.item(0)
308
- }
309
-
310
- /**
311
- * The last child of this element which is an element, or null when there is none.
312
- * @returns {PseudoElement|null}
313
- */
314
- get lastElementChild () {
315
- const elementChildren = this.children
316
- return elementChildren.item(elementChildren.length - 1)
317
- }
318
-
319
- /**
320
- * The sibling after this one which is an element, or null when there is none.
321
- * @returns {PseudoElement|null}
322
- */
323
- get nextElementSibling () {
324
- let sibling = this.nextSibling
325
- while (sibling && sibling.nodeType !== NodeService_1.NodeService.ELEMENT_NODE) {
326
- sibling = sibling.nextSibling
327
- }
328
- return sibling
329
- }
330
-
331
- /**
332
- * The sibling before this one which is an element, or null when there is none.
333
- * @returns {PseudoElement|null}
334
- */
335
- get previousElementSibling () {
336
- let sibling = this.previousSibling
337
- while (sibling && sibling.nodeType !== NodeService_1.NodeService.ELEMENT_NODE) {
338
- sibling = sibling.previousSibling
339
- }
340
- return sibling
341
- }
342
-
343
- /**
344
- * Put an element at a position relative to this one: beforebegin (before this element, as its previous sibling),
345
- * afterbegin (as this element's first child), beforeend (as this element's last child) or afterend (after this
346
- * element, as its next sibling).
347
- * @param {string} position beforebegin, afterbegin, beforeend or afterend
348
- * @param {ElementService} element The element to insert
349
- * @returns {ElementService|null} The inserted element, or null when the position needed a parent this element does not have
350
- * @throws {Error} When the position is not one of the four above
351
- */
352
- insertAdjacentElement (position, element) {
353
- return this.insertAdjacent(position, element)
354
- }
355
-
356
- /**
357
- * Put text at a position relative to this element, the same as insertAdjacentElement but the text becomes a text node.
358
- * @param {string} position beforebegin, afterbegin, beforeend or afterend
359
- * @param {string} text The text to insert
360
- * @throws {Error} When the position is not one of the four above
361
- */
362
- insertAdjacentText (position, text) {
363
- this.insertAdjacent(position, text)
364
- }
365
-
366
- /**
367
- * Shared implementation for insertAdjacentElement / insertAdjacentText.
368
- * @param {string} position beforebegin, afterbegin, beforeend or afterend
369
- * @param {PseudoNode|string} node The node (or text) to insert
370
- * @returns {PseudoNode|null} The inserted node, or null when the position needed a parent this element does not have
371
- * @throws {Error} When the position is not one of the four above
372
- */
373
- insertAdjacent (position, node) {
374
- switch (position) {
375
- case 'beforebegin':
376
- if (!this.parentNode) {
377
- return null
378
- }
379
- this.before(node)
380
- return node
381
- case 'afterbegin':
382
- this.prepend(node)
383
- return node
384
- case 'beforeend':
385
- this.append(node)
386
- return node
387
- case 'afterend':
388
- if (!this.parentNode) {
389
- return null
390
- }
391
- this.after(node)
392
- return node
393
- default:
394
- throw new Error(`"${position}" is not one of beforebegin, afterbegin, beforeend or afterend.`)
395
- }
396
- }
397
-
398
- /**
399
- * Not implemented yet (HTML parsing is out of scope for now).
400
- * @param {string} position beforebegin, afterbegin, beforeend or afterend
401
- * @param {string} text The markup which would be parsed
402
- * @throws {Error}
403
- */
404
- insertAdjacentHTML (position, text) {
405
- throw new Error('ElementService.insertAdjacentHTML() is not implemented yet.')
406
- }
407
-
408
- /**
409
- * Whether this element itself (not its descendants) matches the given CSS selector.
410
- * @param {string} selectors A CSS selector
411
- * @returns {boolean}
412
- */
413
- matches (selectors) {
414
- return (0, query_1.matches)(this, selectors)
415
- }
416
-
417
- /**
418
- * The nearest ancestor of this element (starting with this element itself) which matches the CSS selector, or
419
- * null when none of them do.
420
- * @param {string} selectors A CSS selector
421
- * @returns {PseudoElement|null}
422
- */
423
- closest (selectors) {
424
- return (0, query_1.closest)(this, selectors)
425
- }
426
-
427
- applyDefaultEvent () {
428
- let callback = event => undefined
429
- if (this.defaultEventApplied) {
430
- return callback
431
- }
432
- switch (this.tagName) {
433
- case 'button':
434
- case 'input':
435
- // Clicking a submit button submits the form it is in: the form gets a submit event, which can be cancelled
436
- callback = event => {
437
- const type = String(this.getAttribute('type') || this.type || '').toLowerCase()
438
- const submits = this.tagName === 'button' ? type !== 'button' && type !== 'reset' : /^(submit|image)$/.test(type)
439
- const forms = (0, getParentNodesFromAttribute_1.default)('tagName', 'form', this)
440
- if (submits && forms.length && !this.hasAttribute('disabled')) {
441
- forms[forms.length - 1].dispatchEvent((0, createEvent_1.default)('submit', {}, {
442
- browser: true,
443
- trusted: event.isTrusted
444
- }))
445
- }
446
- }
447
- super.setDefaultEvent('click', callback)
448
- this.defaultEventApplied = true
449
- }
450
- return callback
451
- }
452
-
453
- /**
454
- * An element which is added as a child gets its default events (for example a submit button submits its form).
455
- * @param {NodeService} child The node which was inserted
456
- */
457
- childInserted (child) {
458
- if (typeof child.applyDefaultEvent === 'function') {
459
- child.applyDefaultEvent()
460
- }
461
- }
462
-
463
- /**
464
- * Check whether the element has an attribute by that name.
465
- * @param {string} attributeName
466
- * @returns {boolean}
467
- */
468
- hasAttribute (attributeName) {
469
- return this.attributeList.some(({
470
- name
471
- }) => name === attributeName)
472
- }
473
-
474
- /**
475
- * Set the value of an attribute, adding the attribute if it did not exist.
476
- * @param {string} attributeName
477
- * @param {string} attributeValue
478
- * @returns {undefined}
479
- */
480
- setAttribute (attributeName, attributeValue) {
481
- const existing = this.attributeList.find(({
482
- name
483
- }) => name === attributeName)
484
- if (existing) {
485
- existing.value = attributeValue
486
- } else {
487
- this.attributeList.push({
488
- name: attributeName,
489
- value: attributeValue
490
- })
491
- }
492
- if (this.propertyAttributes.indexOf(attributeName) >= 0) {
493
- this[attributeName] = attributeValue
494
- }
495
- }
496
-
497
- /**
498
- * Retrieve the value of an attribute.
499
- * @param {string} attributeName
500
- * @returns {string|null} The value, or null when there is no such attribute
501
- */
502
- getAttribute (attributeName) {
503
- const found = this.currentAttributes().find(({
504
- name
505
- }) => name === attributeName)
506
- return found ? found.value : null
507
- }
508
-
509
- /**
510
- * Remove an attribute from the element.
511
- * @param {string} attributeName
512
- * @returns {undefined}
513
- */
514
- removeAttribute (attributeName) {
515
- const index = this.attributeList.findIndex(({
516
- name
517
- }) => name === attributeName)
518
- if (index >= 0) {
519
- this.attributeList.splice(index, 1)
520
- }
521
- }
522
-
523
- /**
524
- * The name of every attribute on the element, in the order they were set.
525
- * @returns {Array<string>}
526
- */
527
- getAttributeNames () {
528
- return this.currentAttributes().map(({
529
- name
530
- }) => name)
531
- }
532
-
533
- /**
534
- * Whether the element has any attributes at all.
535
- * @returns {boolean}
536
- */
537
- hasAttributes () {
538
- return this.attributeList.length > 0
539
- }
540
-
541
- /**
542
- * Retrieve the node representation of an attribute.
543
- * @param {string} attributeName
544
- * @returns {AttrService|null} An Attr for the attribute, or null when there is no such attribute
545
- */
546
- getAttributeNode (attributeName) {
547
- return this.hasAttribute(attributeName) ? new AttrService_1.AttrService(attributeName, this.getAttribute(attributeName) || '', this) : null
548
- }
549
-
550
- /**
551
- * Retrieve the node representation of an attribute. There is no real namespace parsing here, so this ignores
552
- * the namespace and behaves exactly like getAttributeNode.
553
- * @param {string} namespace Ignored
554
- * @param {string} attributeName
555
- * @returns {AttrService|null} An Attr for the attribute, or null when there is no such attribute
556
- */
557
- getAttributeNodeNS (namespace, attributeName) {
558
- return this.getAttributeNode(attributeName)
559
- }
560
-
561
- /**
562
- * Retrieve the value of an attribute. There is no real namespace parsing here, so this ignores the namespace
563
- * and behaves exactly like getAttribute.
564
- * @param {string} namespace Ignored
565
- * @param {string} attributeName
566
- * @returns {string|null} The value, or null when there is no such attribute
567
- */
568
- getAttributeNS (namespace, attributeName) {
569
- return this.getAttribute(attributeName)
570
- }
571
-
572
- /**
573
- * Check whether the element has an attribute by that name. There is no real namespace parsing here, so this
574
- * ignores the namespace and behaves exactly like hasAttribute.
575
- * @param {string} namespace Ignored
576
- * @param {string} attributeName
577
- * @returns {boolean}
578
- */
579
- hasAttributeNS (namespace, attributeName) {
580
- return this.hasAttribute(attributeName)
581
- }
582
-
583
- /**
584
- * Remove the node representation of an attribute from the element, and return it.
585
- * @param {AttrService} attr
586
- * @returns {AttrService} The removed Attr
587
- * @throws {Error} When the element has no attribute matching attr.name
588
- */
589
- removeAttributeNode (attr) {
590
- if (!this.hasAttribute(attr.name)) {
591
- throw new Error(`Failed to execute 'removeAttributeNode': The node provided is owned by another element (no attribute named '${attr.name}')`)
592
- }
593
- const removed = this.getAttributeNode(attr.name)
594
- this.removeAttribute(attr.name)
595
- return removed
596
- }
597
-
598
- /**
599
- * Remove an attribute from the element. There is no real namespace parsing here, so this ignores the namespace
600
- * and behaves exactly like removeAttribute.
601
- * @param {string} namespace Ignored
602
- * @param {string} attributeName
603
- * @returns {undefined}
604
- */
605
- removeAttributeNS (namespace, attributeName) {
606
- this.removeAttribute(attributeName)
607
- }
608
-
609
- /**
610
- * Set the node representation of an attribute, adding the attribute if it did not exist. Returns any previous
611
- * Attr that had the same name, or null when there was none.
612
- * @param {AttrService} attr
613
- * @returns {AttrService|null} The replaced Attr, or null when the attribute was new
614
- */
615
- setAttributeNode (attr) {
616
- const existing = this.getAttributeNode(attr.name)
617
- this.setAttribute(attr.name, attr.value)
618
- return existing
619
- }
620
-
621
- /**
622
- * Set the node representation of an attribute. There is no real namespace parsing here, so this behaves
623
- * exactly like setAttributeNode (Attr.name already carries any prefix).
624
- * @param {AttrService} attr
625
- * @returns {AttrService|null} The replaced Attr, or null when the attribute was new
626
- */
627
- setAttributeNodeNS (attr) {
628
- return this.setAttributeNode(attr)
629
- }
630
-
631
- /**
632
- * Set the value of an attribute, adding the attribute if it did not exist. There is no real namespace parsing
633
- * here, so this ignores the namespace and behaves exactly like setAttribute.
634
- * @param {string} namespace Ignored
635
- * @param {string} attributeName
636
- * @param {string} attributeValue
637
- * @returns {undefined}
638
- */
639
- setAttributeNS (namespace, attributeName, attributeValue) {
640
- this.setAttribute(attributeName, attributeValue)
641
- }
642
-
643
- /**
644
- * Add the attribute (with an empty value) when it is not present, or remove it when it is - unless force says
645
- * which of those to do instead. Returns whether the attribute is present after the call.
646
- * @param {string} attributeName
647
- * @param {boolean} [force]
648
- * @returns {boolean}
649
- */
650
- toggleAttribute (attributeName, force) {
651
- const present = this.hasAttribute(attributeName)
652
- const shouldHave = typeof force === 'boolean' ? force : !present
653
- if (shouldHave && !present) {
654
- this.setAttribute(attributeName, '')
655
- } else if (!shouldHave && present) {
656
- this.removeAttribute(attributeName)
657
- }
658
- return shouldHave
659
- }
660
-
661
- /**
662
- * The size of the element and its position, settable directly - there is no layout engine here to compute it.
663
- * @returns {DOMRect}
664
- */
665
- getBoundingClientRect () {
666
- return this.boundingClientRect
667
- }
668
-
669
- /**
670
- * The bounding rectangles for each line of text in the element, settable directly - there is no layout engine
671
- * here to compute it.
672
- * @returns {Array<DOMRect>}
673
- */
674
- getClientRects () {
675
- return this.clientRects
676
- }
677
-
678
- /**
679
- * The Animation objects currently active on the element, settable directly - there is no animation engine here.
680
- * @returns {Array<*>}
681
- */
682
- getAnimations () {
683
- return this.animations
684
- }
685
-
686
- /**
687
- * Whether the element is expected to be visible, settable directly - there is no rendering here to check it.
688
- * @returns {boolean}
689
- */
690
- checkVisibility () {
691
- return this.isVisible
692
- }
693
-
694
- /**
695
- * A read-only view of the element's own inline style declarations (there is no CSS cascade here, so this is not a
696
- * real computed style - just what the element's own style object holds).
697
- * @returns {{get: function(string): (string|undefined)}}
698
- */
699
- computedStyleMap () {
700
- const style = this.style
701
- return {
702
- get: property => {
703
- const value = style ? style.getPropertyValue(property) : ''
704
- return value === '' ? undefined : value
705
- }
706
- }
707
- }
708
-
709
- /**
710
- * Whether this element currently has capture of the given pointer.
711
- * @param {number} pointerId
712
- * @returns {boolean}
713
- */
714
- hasPointerCapture (pointerId) {
715
- return this.capturedPointers.has(pointerId)
716
- }
717
-
718
- /**
719
- * Give this element capture of the given pointer.
720
- * @param {number} pointerId
721
- * @returns {undefined}
722
- */
723
- setPointerCapture (pointerId) {
724
- this.capturedPointers.add(pointerId)
725
- }
726
-
727
- /**
728
- * Release this element's capture of the given pointer, if it had it.
729
- * @param {number} pointerId
730
- * @returns {undefined}
731
- */
732
- releasePointerCapture (pointerId) {
733
- this.capturedPointers.delete(pointerId)
734
- }
735
-
736
- /**
737
- * Scroll to the given position (or, given an options object, the position(s) it has). There is no real scrollable
738
- * viewport here: this just sets scrollLeft / scrollTop.
739
- * @param {number|{left: number, top: number}} [x=0]
740
- * @param {number} [y=0]
741
- * @returns {undefined}
742
- */
743
- scroll (x = 0, y = 0) {
744
- if (typeof x === 'number') {
745
- this.scrollLeft = x
746
- this.scrollTop = y
747
- return
748
- }
749
- if (typeof x.left === 'number') {
750
- this.scrollLeft = x.left
751
- }
752
- if (typeof x.top === 'number') {
753
- this.scrollTop = x.top
754
- }
755
- }
756
-
757
- /**
758
- * Scroll to the given position. An alias for scroll.
759
- * @param {number|{left: number, top: number}} [x=0]
760
- * @param {number} [y=0]
761
- * @returns {undefined}
762
- */
763
- scrollTo (x = 0, y = 0) {
764
- this.scroll(x, y)
765
- }
766
-
767
- /**
768
- * Scroll by the given amount, relative to the current position.
769
- * @param {number|{left: number, top: number}} [x=0]
770
- * @param {number} [y=0]
771
- * @returns {undefined}
772
- */
773
- scrollBy (x = 0, y = 0) {
774
- if (typeof x === 'number') {
775
- this.scroll(this.scrollLeft + x, this.scrollTop + y)
776
- return
777
- }
778
- this.scroll({
779
- left: this.scrollLeft + (x.left || 0),
780
- top: this.scrollTop + (x.top || 0)
781
- })
782
- }
783
-
784
- /**
785
- * Scroll an ancestor until this element is in view. There is no real viewport here for that to mean anything, so
786
- * this does nothing (override it on an instance in a test which needs to observe the call).
787
- * @returns {undefined}
788
- */
789
- scrollIntoView () {}
790
- /**
791
- * Asynchronously ask for the element to be shown fullscreen. There is no real fullscreen here, so this just
792
- * resolves, like a browser granting the request would.
793
- * @returns {Promise<void>}
794
- */
795
- requestFullscreen () {
796
- return Promise.resolve()
797
- }
798
-
799
- /**
800
- * Asynchronously ask for the pointer to be locked to this element. There is no real pointer lock here, so this
801
- * just resolves, like a browser granting the request would.
802
- * @returns {Promise<void>}
803
- */
804
- requestPointerLock () {
805
- return Promise.resolve()
806
- }
807
-
808
- /**
809
- * Attach a shadow tree to this element and return its ShadowRoot. Throws when it already hosts one.
810
- * @param {{mode: string}} options
811
- * @returns {PseudoShadowRoot}
812
- * @throws {Error}
813
- */
814
- attachShadow (options) {
815
- if (this.shadowRootInstance) {
816
- throw new Error('Shadow root cannot be created on a host which already hosts a shadow tree.')
817
- }
818
- const root = new ShadowRootService_1.ShadowRootService()
819
- root.host = this
820
- root.mode = options.mode
821
- this.shadowRootInstance = root
822
- return root
823
- }
824
-
825
- /**
826
- * This element's shadow root, when it has one attached in 'open' mode, or null (including when the mode is
827
- * 'closed' - it still exists, but is not reachable this way, like the DOM's).
828
- * @returns {PseudoShadowRoot|null}
829
- */
830
- get shadowRoot () {
831
- return this.shadowRootInstance && this.shadowRootInstance.mode === 'open' ? this.shadowRootInstance : null
832
- }
833
-
834
- /**
835
- * Read one of the aria-* reflected properties (see the individual aria* getters/setters below).
836
- * @param {string} attributeName A real aria-* attribute name (aria-label, ...)
837
- * @returns {string}
838
- */
839
- getAriaAttribute (attributeName) {
840
- return this.getAttribute(attributeName) || ''
841
- }
842
-
843
- /**
844
- * Write one of the aria-* reflected properties.
845
- * @param {string} attributeName A real aria-* attribute name (aria-label, ...)
846
- * @param {string} value
847
- * @returns {undefined}
848
- */
849
- setAriaAttribute (attributeName, value) {
850
- this.setAttribute(attributeName, value)
851
- }
852
-
853
- get ariaAtomic () {
854
- return this.getAriaAttribute('aria-atomic')
855
- }
856
-
857
- set ariaAtomic (value) {
858
- this.setAriaAttribute('aria-atomic', value)
859
- }
860
-
861
- get ariaAutoComplete () {
862
- return this.getAriaAttribute('aria-autocomplete')
863
- }
864
-
865
- set ariaAutoComplete (value) {
866
- this.setAriaAttribute('aria-autocomplete', value)
867
- }
868
-
869
- get ariaBusy () {
870
- return this.getAriaAttribute('aria-busy')
871
- }
872
-
873
- set ariaBusy (value) {
874
- this.setAriaAttribute('aria-busy', value)
875
- }
876
-
877
- get ariaChecked () {
878
- return this.getAriaAttribute('aria-checked')
879
- }
880
-
881
- set ariaChecked (value) {
882
- this.setAriaAttribute('aria-checked', value)
883
- }
884
-
885
- get ariaColCount () {
886
- return this.getAriaAttribute('aria-colcount')
887
- }
888
-
889
- set ariaColCount (value) {
890
- this.setAriaAttribute('aria-colcount', value)
891
- }
892
-
893
- get ariaColIndex () {
894
- return this.getAriaAttribute('aria-colindex')
895
- }
896
-
897
- set ariaColIndex (value) {
898
- this.setAriaAttribute('aria-colindex', value)
899
- }
900
-
901
- get ariaColSpan () {
902
- return this.getAriaAttribute('aria-colspan')
903
- }
904
-
905
- set ariaColSpan (value) {
906
- this.setAriaAttribute('aria-colspan', value)
907
- }
908
-
909
- get ariaCurrent () {
910
- return this.getAriaAttribute('aria-current')
911
- }
912
-
913
- set ariaCurrent (value) {
914
- this.setAriaAttribute('aria-current', value)
915
- }
916
-
917
- get ariaDescription () {
918
- return this.getAriaAttribute('aria-description')
919
- }
920
-
921
- set ariaDescription (value) {
922
- this.setAriaAttribute('aria-description', value)
923
- }
924
-
925
- get ariaDisabled () {
926
- return this.getAriaAttribute('aria-disabled')
927
- }
928
-
929
- set ariaDisabled (value) {
930
- this.setAriaAttribute('aria-disabled', value)
931
- }
932
-
933
- get ariaExpanded () {
934
- return this.getAriaAttribute('aria-expanded')
935
- }
936
-
937
- set ariaExpanded (value) {
938
- this.setAriaAttribute('aria-expanded', value)
939
- }
940
-
941
- get ariaHasPopup () {
942
- return this.getAriaAttribute('aria-haspopup')
943
- }
944
-
945
- set ariaHasPopup (value) {
946
- this.setAriaAttribute('aria-haspopup', value)
947
- }
948
-
949
- get ariaHidden () {
950
- return this.getAriaAttribute('aria-hidden')
951
- }
952
-
953
- set ariaHidden (value) {
954
- this.setAriaAttribute('aria-hidden', value)
955
- }
956
-
957
- get ariaKeyShortcuts () {
958
- return this.getAriaAttribute('aria-keyshortcuts')
959
- }
960
-
961
- set ariaKeyShortcuts (value) {
962
- this.setAriaAttribute('aria-keyshortcuts', value)
963
- }
964
-
965
- get ariaLabel () {
966
- return this.getAriaAttribute('aria-label')
967
- }
968
-
969
- set ariaLabel (value) {
970
- this.setAriaAttribute('aria-label', value)
971
- }
972
-
973
- get ariaLevel () {
974
- return this.getAriaAttribute('aria-level')
975
- }
976
-
977
- set ariaLevel (value) {
978
- this.setAriaAttribute('aria-level', value)
979
- }
980
-
981
- get ariaLive () {
982
- return this.getAriaAttribute('aria-live')
983
- }
984
-
985
- set ariaLive (value) {
986
- this.setAriaAttribute('aria-live', value)
987
- }
988
-
989
- get ariaModal () {
990
- return this.getAriaAttribute('aria-modal')
991
- }
992
-
993
- set ariaModal (value) {
994
- this.setAriaAttribute('aria-modal', value)
995
- }
996
-
997
- get ariaMultiline () {
998
- return this.getAriaAttribute('aria-multiline')
999
- }
1000
-
1001
- set ariaMultiline (value) {
1002
- this.setAriaAttribute('aria-multiline', value)
1003
- }
1004
-
1005
- get ariaMultiSelectable () {
1006
- return this.getAriaAttribute('aria-multiselectable')
1007
- }
1008
-
1009
- set ariaMultiSelectable (value) {
1010
- this.setAriaAttribute('aria-multiselectable', value)
1011
- }
1012
-
1013
- get ariaOrientation () {
1014
- return this.getAriaAttribute('aria-orientation')
1015
- }
1016
-
1017
- set ariaOrientation (value) {
1018
- this.setAriaAttribute('aria-orientation', value)
1019
- }
1020
-
1021
- get ariaPlaceholder () {
1022
- return this.getAriaAttribute('aria-placeholder')
1023
- }
1024
-
1025
- set ariaPlaceholder (value) {
1026
- this.setAriaAttribute('aria-placeholder', value)
1027
- }
1028
-
1029
- get ariaPosInSet () {
1030
- return this.getAriaAttribute('aria-posinset')
1031
- }
1032
-
1033
- set ariaPosInSet (value) {
1034
- this.setAriaAttribute('aria-posinset', value)
1035
- }
1036
-
1037
- get ariaPressed () {
1038
- return this.getAriaAttribute('aria-pressed')
1039
- }
1040
-
1041
- set ariaPressed (value) {
1042
- this.setAriaAttribute('aria-pressed', value)
1043
- }
1044
-
1045
- get ariaReadOnly () {
1046
- return this.getAriaAttribute('aria-readonly')
1047
- }
1048
-
1049
- set ariaReadOnly (value) {
1050
- this.setAriaAttribute('aria-readonly', value)
1051
- }
1052
-
1053
- get ariaRequired () {
1054
- return this.getAriaAttribute('aria-required')
1055
- }
1056
-
1057
- set ariaRequired (value) {
1058
- this.setAriaAttribute('aria-required', value)
1059
- }
1060
-
1061
- get ariaRoleDescription () {
1062
- return this.getAriaAttribute('aria-roledescription')
1063
- }
1064
-
1065
- set ariaRoleDescription (value) {
1066
- this.setAriaAttribute('aria-roledescription', value)
1067
- }
1068
-
1069
- get ariaRowCount () {
1070
- return this.getAriaAttribute('aria-rowcount')
1071
- }
1072
-
1073
- set ariaRowCount (value) {
1074
- this.setAriaAttribute('aria-rowcount', value)
1075
- }
1076
-
1077
- get ariaRowIndex () {
1078
- return this.getAriaAttribute('aria-rowindex')
1079
- }
1080
-
1081
- set ariaRowIndex (value) {
1082
- this.setAriaAttribute('aria-rowindex', value)
1083
- }
1084
-
1085
- get ariaRowSpan () {
1086
- return this.getAriaAttribute('aria-rowspan')
1087
- }
1088
-
1089
- set ariaRowSpan (value) {
1090
- this.setAriaAttribute('aria-rowspan', value)
1091
- }
1092
-
1093
- get ariaSelected () {
1094
- return this.getAriaAttribute('aria-selected')
1095
- }
1096
-
1097
- set ariaSelected (value) {
1098
- this.setAriaAttribute('aria-selected', value)
1099
- }
1100
-
1101
- get ariaSetSize () {
1102
- return this.getAriaAttribute('aria-setsize')
1103
- }
1104
-
1105
- set ariaSetSize (value) {
1106
- this.setAriaAttribute('aria-setsize', value)
1107
- }
1108
-
1109
- get ariaSort () {
1110
- return this.getAriaAttribute('aria-sort')
1111
- }
1112
-
1113
- set ariaSort (value) {
1114
- this.setAriaAttribute('aria-sort', value)
1115
- }
1116
-
1117
- get ariaValueMax () {
1118
- return this.getAriaAttribute('aria-valuemax')
1119
- }
1120
-
1121
- set ariaValueMax (value) {
1122
- this.setAriaAttribute('aria-valuemax', value)
1123
- }
1124
-
1125
- get ariaValueMin () {
1126
- return this.getAriaAttribute('aria-valuemin')
1127
- }
1128
-
1129
- set ariaValueMin (value) {
1130
- this.setAriaAttribute('aria-valuemin', value)
1131
- }
1132
-
1133
- get ariaValueNow () {
1134
- return this.getAriaAttribute('aria-valuenow')
1135
- }
1136
-
1137
- set ariaValueNow (value) {
1138
- this.setAriaAttribute('aria-valuenow', value)
1139
- }
1140
-
1141
- get ariaValueText () {
1142
- return this.getAriaAttribute('aria-valuetext')
1143
- }
1144
-
1145
- set ariaValueText (value) {
1146
- this.setAriaAttribute('aria-valuetext', value)
1147
- }
1148
- }
1149
- exports.ElementService = ElementService
1
+ 'use strict'
2
+
3
+ require('core-js/modules/esnext.iterator.constructor.js')
4
+ require('core-js/modules/esnext.iterator.every.js')
5
+ require('core-js/modules/esnext.iterator.find.js')
6
+ require('core-js/modules/esnext.iterator.for-each.js')
7
+ require('core-js/modules/esnext.iterator.map.js')
8
+ require('core-js/modules/esnext.iterator.some.js')
9
+ require('core-js/modules/esnext.set.add-all.js')
10
+ require('core-js/modules/esnext.set.delete-all.js')
11
+ require('core-js/modules/esnext.set.difference.js')
12
+ require('core-js/modules/esnext.set.every.js')
13
+ require('core-js/modules/esnext.set.filter.js')
14
+ require('core-js/modules/esnext.set.find.js')
15
+ require('core-js/modules/esnext.set.intersection.js')
16
+ require('core-js/modules/esnext.set.is-disjoint-from.js')
17
+ require('core-js/modules/esnext.set.is-subset-of.js')
18
+ require('core-js/modules/esnext.set.is-superset-of.js')
19
+ require('core-js/modules/esnext.set.join.js')
20
+ require('core-js/modules/esnext.set.map.js')
21
+ require('core-js/modules/esnext.set.reduce.js')
22
+ require('core-js/modules/esnext.set.some.js')
23
+ require('core-js/modules/esnext.set.symmetric-difference.js')
24
+ require('core-js/modules/esnext.set.union.js')
25
+ const __importDefault = void 0 && (void 0).__importDefault || function (mod) {
26
+ return mod && mod.__esModule
27
+ ? mod
28
+ : {
29
+ default: mod
30
+ }
31
+ }
32
+ Object.defineProperty(exports, '__esModule', {
33
+ value: true
34
+ })
35
+ exports.ElementService = void 0
36
+ const createEvent_1 = __importDefault(require('../factories/createEvent'))
37
+ const NodeService_1 = require('./NodeService')
38
+ const AttrService_1 = require('./AttrService')
39
+ const DOMTokenListService_1 = require('./DOMTokenListService')
40
+ const NamedNodeMapService_1 = require('./NamedNodeMapService')
41
+ const getParentNodesFromAttribute_1 = __importDefault(require('../functions/getParentNodesFromAttribute'))
42
+ const HTMLCollectionService_1 = require('./HTMLCollectionService')
43
+ const cloneObject_1 = __importDefault(require('si-funciona/dist/helpers/objects/cloneObject'))
44
+ const isEqual_1 = __importDefault(require('si-funciona/dist/helpers/objects/isEqual'))
45
+ const query_1 = require('../factories/query')
46
+ const ShadowRootService_1 = require('./ShadowRootService')
47
+ const serializeHTML_1 = require('../factories/serializeHTML')
48
+ const zeroRect = () => ({
49
+ x: 0,
50
+ y: 0,
51
+ width: 0,
52
+ height: 0,
53
+ top: 0,
54
+ right: 0,
55
+ bottom: 0,
56
+ left: 0
57
+ })
58
+ /**
59
+ * Simulate the behaviour of the Element Class when there is no DOM available.
60
+ * @author Joshua Heagle <joshuaheagle@gmail.com>
61
+ * @class
62
+ * @augments PseudoNode
63
+ * @property {string} tagName
64
+ * @property {string} className
65
+ * @property {string} id
66
+ * @property {string} innerHtml
67
+ * @property {Array} attributes
68
+ * @property {function} hasAttribute
69
+ * @property {function} setAttribute
70
+ * @property {function} getAttribute
71
+ * @property {function} removeAttribute
72
+ */
73
+ class ElementService extends NodeService_1.NodeService {
74
+ /**
75
+ * @param {Object} [settings={}]
76
+ * @param {string} [settings.tagName=''] The name of the tag this element represents
77
+ * @param {Array<{name: string, value: *}>} [settings.attributes=[]] The attributes (also assigned as properties) to start with
78
+ * @param {PseudoNode|null} [settings.parent=null] The node to add this element to as its last child
79
+ * @param {Array<PseudoNode>} [settings.children=[]] The nodes to start as children
80
+ * @constructor
81
+ */
82
+ constructor ({
83
+ tagName = '',
84
+ attributes = [],
85
+ parent = null,
86
+ children = []
87
+ } = {}) {
88
+ super()
89
+ /** What getBoundingClientRect() returns - not really computed (there is no layout engine), set this directly. */
90
+ this.boundingClientRect = zeroRect()
91
+ /** What getClientRects() returns - set this directly. */
92
+ this.clientRects = []
93
+ /** What getAnimations() returns - set this directly. */
94
+ this.animations = []
95
+ /** What checkVisibility() returns - set this directly. */
96
+ this.isVisible = true
97
+ this.capturedPointers = new Set()
98
+ this.shadowRootInstance = null
99
+ this.defaultEventApplied = false
100
+ this.tokenList = new DOMTokenListService_1.DOMTokenListService()
101
+ this.tag = tagName
102
+ this.attributeList = attributes.concat([{
103
+ name: 'className',
104
+ value: ''
105
+ }, {
106
+ name: 'id',
107
+ value: ''
108
+ },
109
+ // Layout is not really computed (there is no rendering engine here): these start at 0, like an unrendered
110
+ // element's would, but can be set directly to whatever a test needs code under test to see.
111
+ {
112
+ name: 'clientHeight',
113
+ value: 0
114
+ }, {
115
+ name: 'clientLeft',
116
+ value: 0
117
+ }, {
118
+ name: 'clientTop',
119
+ value: 0
120
+ }, {
121
+ name: 'clientWidth',
122
+ value: 0
123
+ }, {
124
+ name: 'scrollHeight',
125
+ value: 0
126
+ }, {
127
+ name: 'scrollLeft',
128
+ value: 0
129
+ }, {
130
+ name: 'scrollTop',
131
+ value: 0
132
+ }, {
133
+ name: 'scrollWidth',
134
+ value: 0
135
+ }])
136
+ this.propertyAttributes = this.attributeList.map(({
137
+ name
138
+ }) => name)
139
+ this.attributeList.forEach(({
140
+ name,
141
+ value
142
+ }) => {
143
+ this[name] = value
144
+ })
145
+ children.forEach(child => {
146
+ if (!child || typeof child.nodeType !== 'number') {
147
+ throw new TypeError('The children of an element must be nodes.')
148
+ }
149
+ this.appendChild(child)
150
+ })
151
+ if (parent) {
152
+ parent.appendChild(this)
153
+ }
154
+ }
155
+
156
+ /**
157
+ * The attributes with the values they have now: the ones which are also properties (className, id, style, ...) can
158
+ * have been changed through the property, which does not change the stored list.
159
+ * @returns {Array<{name: string, value: *}>}
160
+ */
161
+ currentAttributes () {
162
+ return this.attributeList.map(({
163
+ name,
164
+ value
165
+ }) => ({
166
+ name,
167
+ value: this.propertyAttributes.indexOf(name) >= 0 ? this[name] : value
168
+ }))
169
+ }
170
+
171
+ get nodeName () {
172
+ return this.tag
173
+ }
174
+
175
+ /**
176
+ * A copy of this element without its children: the same tag and attributes (the values which are objects, such as
177
+ * style, are copied too rather than shared), but not its parent or listeners.
178
+ * @returns {ElementService}
179
+ */
180
+ cloneShallow () {
181
+ const copy = new this.constructor({
182
+ tagName: this.tag
183
+ })
184
+ copy.attributeList.length = 0
185
+ this.currentAttributes().forEach(({
186
+ name,
187
+ value
188
+ }) => {
189
+ const copied = typeof value === 'object' && value !== null ? (0, cloneObject_1.default)(value) : value
190
+ copy.attributeList.push({
191
+ name,
192
+ value: copied
193
+ })
194
+ if (copy.propertyAttributes.indexOf(name) >= 0) {
195
+ copy[name] = copied
196
+ }
197
+ })
198
+ copy.ownerDocumentStore = this.ownerDocumentStore
199
+ return copy
200
+ }
201
+
202
+ /**
203
+ * Elements are equal when they have the same tag and the same attributes (in any order), which is what isEqualNode
204
+ * checks before it compares the children.
205
+ * @param {NodeService} other The element to compare with
206
+ * @returns {boolean}
207
+ */
208
+ equalsShallow (other) {
209
+ const mine = this.currentAttributes()
210
+ const theirs = other.currentAttributes()
211
+ return this.nodeName === other.nodeName && mine.length === theirs.length && mine.every(({
212
+ name,
213
+ value
214
+ }) => {
215
+ const match = theirs.find(attributeOfOther => attributeOfOther.name === name)
216
+ return typeof match !== 'undefined' && (0, isEqual_1.default)(value, match.value)
217
+ })
218
+ }
219
+
220
+ get tagName () {
221
+ return this.tag
222
+ }
223
+
224
+ /**
225
+ * The local part of the element's qualified name. There is no real namespace parsing here, so this is always the
226
+ * same as tagName.
227
+ * @returns {string}
228
+ */
229
+ get localName () {
230
+ return this.tag
231
+ }
232
+
233
+ /**
234
+ * The element's namespace prefix, or null when it has none. There is no real namespace parsing here, so this is
235
+ * always null.
236
+ * @returns {string|null}
237
+ */
238
+ get prefix () {
239
+ return null
240
+ }
241
+
242
+ /**
243
+ * The HTML markup of this element's children. Only the getter is here (the setter, which needs to build new
244
+ * elements from parsed HTML, is on HTMLElementService - see its class comment).
245
+ * @returns {string}
246
+ */
247
+ get innerHTML () {
248
+ return (0, serializeHTML_1.serializeChildren)(this)
249
+ }
250
+
251
+ /**
252
+ * The HTML markup of this element itself, including its children. Only the getter is here (see innerHTML).
253
+ * @returns {string}
254
+ */
255
+ get outerHTML () {
256
+ return (0, serializeHTML_1.serializeOuter)(this)
257
+ }
258
+
259
+ get nodeType () {
260
+ return NodeService_1.NodeService.ELEMENT_NODE
261
+ }
262
+
263
+ get attributes () {
264
+ return new NamedNodeMapService_1.NamedNodeMapService(this.currentAttributes().map(({
265
+ name,
266
+ value
267
+ }) => new AttrService_1.AttrService(name, String(value), this)))
268
+ }
269
+
270
+ get classList () {
271
+ return this.tokenList
272
+ }
273
+
274
+ get className () {
275
+ return this.tokenList.value
276
+ }
277
+
278
+ set className (className) {
279
+ this.tokenList.value = className
280
+ }
281
+
282
+ /**
283
+ * Some elements have default behaviour, this registers it when the element is added.
284
+ * @returns {Function}
285
+ */
286
+ /**
287
+ * A live view of this element's element children (text, comments and the like are not included).
288
+ * @returns {PseudoHTMLCollection}
289
+ */
290
+ get children () {
291
+ return new HTMLCollectionService_1.HTMLCollectionService(this)
292
+ }
293
+
294
+ /**
295
+ * How many element children this element has.
296
+ * @returns {number}
297
+ */
298
+ get childElementCount () {
299
+ return this.children.length
300
+ }
301
+
302
+ /**
303
+ * The first child of this element which is an element, or null when there is none.
304
+ * @returns {PseudoElement|null}
305
+ */
306
+ get firstElementChild () {
307
+ return this.children.item(0)
308
+ }
309
+
310
+ /**
311
+ * The last child of this element which is an element, or null when there is none.
312
+ * @returns {PseudoElement|null}
313
+ */
314
+ get lastElementChild () {
315
+ const elementChildren = this.children
316
+ return elementChildren.item(elementChildren.length - 1)
317
+ }
318
+
319
+ /**
320
+ * The sibling after this one which is an element, or null when there is none.
321
+ * @returns {PseudoElement|null}
322
+ */
323
+ get nextElementSibling () {
324
+ let sibling = this.nextSibling
325
+ while (sibling && sibling.nodeType !== NodeService_1.NodeService.ELEMENT_NODE) {
326
+ sibling = sibling.nextSibling
327
+ }
328
+ return sibling
329
+ }
330
+
331
+ /**
332
+ * The sibling before this one which is an element, or null when there is none.
333
+ * @returns {PseudoElement|null}
334
+ */
335
+ get previousElementSibling () {
336
+ let sibling = this.previousSibling
337
+ while (sibling && sibling.nodeType !== NodeService_1.NodeService.ELEMENT_NODE) {
338
+ sibling = sibling.previousSibling
339
+ }
340
+ return sibling
341
+ }
342
+
343
+ /**
344
+ * Put an element at a position relative to this one: beforebegin (before this element, as its previous sibling),
345
+ * afterbegin (as this element's first child), beforeend (as this element's last child) or afterend (after this
346
+ * element, as its next sibling).
347
+ * @param {string} position beforebegin, afterbegin, beforeend or afterend
348
+ * @param {ElementService} element The element to insert
349
+ * @returns {ElementService|null} The inserted element, or null when the position needed a parent this element does not have
350
+ * @throws {Error} When the position is not one of the four above
351
+ */
352
+ insertAdjacentElement (position, element) {
353
+ return this.insertAdjacent(position, element)
354
+ }
355
+
356
+ /**
357
+ * Put text at a position relative to this element, the same as insertAdjacentElement but the text becomes a text node.
358
+ * @param {string} position beforebegin, afterbegin, beforeend or afterend
359
+ * @param {string} text The text to insert
360
+ * @throws {Error} When the position is not one of the four above
361
+ */
362
+ insertAdjacentText (position, text) {
363
+ this.insertAdjacent(position, text)
364
+ }
365
+
366
+ /**
367
+ * Shared implementation for insertAdjacentElement / insertAdjacentText.
368
+ * @param {string} position beforebegin, afterbegin, beforeend or afterend
369
+ * @param {PseudoNode|string} node The node (or text) to insert
370
+ * @returns {PseudoNode|null} The inserted node, or null when the position needed a parent this element does not have
371
+ * @throws {Error} When the position is not one of the four above
372
+ */
373
+ insertAdjacent (position, node) {
374
+ switch (position) {
375
+ case 'beforebegin':
376
+ if (!this.parentNode) {
377
+ return null
378
+ }
379
+ this.before(node)
380
+ return node
381
+ case 'afterbegin':
382
+ this.prepend(node)
383
+ return node
384
+ case 'beforeend':
385
+ this.append(node)
386
+ return node
387
+ case 'afterend':
388
+ if (!this.parentNode) {
389
+ return null
390
+ }
391
+ this.after(node)
392
+ return node
393
+ default:
394
+ throw new Error(`"${position}" is not one of beforebegin, afterbegin, beforeend or afterend.`)
395
+ }
396
+ }
397
+
398
+ /**
399
+ * Not implemented yet (HTML parsing is out of scope for now).
400
+ * @param {string} position beforebegin, afterbegin, beforeend or afterend
401
+ * @param {string} text The markup which would be parsed
402
+ * @throws {Error}
403
+ */
404
+ insertAdjacentHTML (position, text) {
405
+ throw new Error('ElementService.insertAdjacentHTML() is not implemented yet.')
406
+ }
407
+
408
+ /**
409
+ * Whether this element itself (not its descendants) matches the given CSS selector.
410
+ * @param {string} selectors A CSS selector
411
+ * @returns {boolean}
412
+ */
413
+ matches (selectors) {
414
+ return (0, query_1.matches)(this, selectors)
415
+ }
416
+
417
+ /**
418
+ * The nearest ancestor of this element (starting with this element itself) which matches the CSS selector, or
419
+ * null when none of them do.
420
+ * @param {string} selectors A CSS selector
421
+ * @returns {PseudoElement|null}
422
+ */
423
+ closest (selectors) {
424
+ return (0, query_1.closest)(this, selectors)
425
+ }
426
+
427
+ applyDefaultEvent () {
428
+ let callback = event => undefined
429
+ if (this.defaultEventApplied) {
430
+ return callback
431
+ }
432
+ switch (this.tagName) {
433
+ case 'button':
434
+ case 'input':
435
+ // Clicking a submit button submits the form it is in: the form gets a submit event, which can be cancelled
436
+ callback = event => {
437
+ const type = String(this.getAttribute('type') || this.type || '').toLowerCase()
438
+ const submits = this.tagName === 'button' ? type !== 'button' && type !== 'reset' : /^(submit|image)$/.test(type)
439
+ const forms = (0, getParentNodesFromAttribute_1.default)('tagName', 'form', this)
440
+ if (submits && forms.length && !this.hasAttribute('disabled')) {
441
+ forms[forms.length - 1].dispatchEvent((0, createEvent_1.default)('submit', {}, {
442
+ browser: true,
443
+ trusted: event.isTrusted
444
+ }))
445
+ }
446
+ }
447
+ super.setDefaultEvent('click', callback)
448
+ this.defaultEventApplied = true
449
+ }
450
+ return callback
451
+ }
452
+
453
+ /**
454
+ * An element which is added as a child gets its default events (for example a submit button submits its form).
455
+ * @param {NodeService} child The node which was inserted
456
+ */
457
+ childInserted (child) {
458
+ if (typeof child.applyDefaultEvent === 'function') {
459
+ child.applyDefaultEvent()
460
+ }
461
+ }
462
+
463
+ /**
464
+ * Check whether the element has an attribute by that name.
465
+ * @param {string} attributeName
466
+ * @returns {boolean}
467
+ */
468
+ hasAttribute (attributeName) {
469
+ return this.attributeList.some(({
470
+ name
471
+ }) => name === attributeName)
472
+ }
473
+
474
+ /**
475
+ * Set the value of an attribute, adding the attribute if it did not exist.
476
+ * @param {string} attributeName
477
+ * @param {string} attributeValue
478
+ * @returns {undefined}
479
+ */
480
+ setAttribute (attributeName, attributeValue) {
481
+ const existing = this.attributeList.find(({
482
+ name
483
+ }) => name === attributeName)
484
+ if (existing) {
485
+ existing.value = attributeValue
486
+ } else {
487
+ this.attributeList.push({
488
+ name: attributeName,
489
+ value: attributeValue
490
+ })
491
+ }
492
+ if (this.propertyAttributes.indexOf(attributeName) >= 0) {
493
+ this[attributeName] = attributeValue
494
+ }
495
+ }
496
+
497
+ /**
498
+ * Retrieve the value of an attribute.
499
+ * @param {string} attributeName
500
+ * @returns {string|null} The value, or null when there is no such attribute
501
+ */
502
+ getAttribute (attributeName) {
503
+ const found = this.currentAttributes().find(({
504
+ name
505
+ }) => name === attributeName)
506
+ return found ? found.value : null
507
+ }
508
+
509
+ /**
510
+ * Remove an attribute from the element.
511
+ * @param {string} attributeName
512
+ * @returns {undefined}
513
+ */
514
+ removeAttribute (attributeName) {
515
+ const index = this.attributeList.findIndex(({
516
+ name
517
+ }) => name === attributeName)
518
+ if (index >= 0) {
519
+ this.attributeList.splice(index, 1)
520
+ }
521
+ }
522
+
523
+ /**
524
+ * The name of every attribute on the element, in the order they were set.
525
+ * @returns {Array<string>}
526
+ */
527
+ getAttributeNames () {
528
+ return this.currentAttributes().map(({
529
+ name
530
+ }) => name)
531
+ }
532
+
533
+ /**
534
+ * Whether the element has any attributes at all.
535
+ * @returns {boolean}
536
+ */
537
+ hasAttributes () {
538
+ return this.attributeList.length > 0
539
+ }
540
+
541
+ /**
542
+ * Retrieve the node representation of an attribute.
543
+ * @param {string} attributeName
544
+ * @returns {AttrService|null} An Attr for the attribute, or null when there is no such attribute
545
+ */
546
+ getAttributeNode (attributeName) {
547
+ return this.hasAttribute(attributeName) ? new AttrService_1.AttrService(attributeName, this.getAttribute(attributeName) || '', this) : null
548
+ }
549
+
550
+ /**
551
+ * Retrieve the node representation of an attribute. There is no real namespace parsing here, so this ignores
552
+ * the namespace and behaves exactly like getAttributeNode.
553
+ * @param {string} namespace Ignored
554
+ * @param {string} attributeName
555
+ * @returns {AttrService|null} An Attr for the attribute, or null when there is no such attribute
556
+ */
557
+ getAttributeNodeNS (namespace, attributeName) {
558
+ return this.getAttributeNode(attributeName)
559
+ }
560
+
561
+ /**
562
+ * Retrieve the value of an attribute. There is no real namespace parsing here, so this ignores the namespace
563
+ * and behaves exactly like getAttribute.
564
+ * @param {string} namespace Ignored
565
+ * @param {string} attributeName
566
+ * @returns {string|null} The value, or null when there is no such attribute
567
+ */
568
+ getAttributeNS (namespace, attributeName) {
569
+ return this.getAttribute(attributeName)
570
+ }
571
+
572
+ /**
573
+ * Check whether the element has an attribute by that name. There is no real namespace parsing here, so this
574
+ * ignores the namespace and behaves exactly like hasAttribute.
575
+ * @param {string} namespace Ignored
576
+ * @param {string} attributeName
577
+ * @returns {boolean}
578
+ */
579
+ hasAttributeNS (namespace, attributeName) {
580
+ return this.hasAttribute(attributeName)
581
+ }
582
+
583
+ /**
584
+ * Remove the node representation of an attribute from the element, and return it.
585
+ * @param {AttrService} attr
586
+ * @returns {AttrService} The removed Attr
587
+ * @throws {Error} When the element has no attribute matching attr.name
588
+ */
589
+ removeAttributeNode (attr) {
590
+ if (!this.hasAttribute(attr.name)) {
591
+ throw new Error(`Failed to execute 'removeAttributeNode': The node provided is owned by another element (no attribute named '${attr.name}')`)
592
+ }
593
+ const removed = this.getAttributeNode(attr.name)
594
+ this.removeAttribute(attr.name)
595
+ return removed
596
+ }
597
+
598
+ /**
599
+ * Remove an attribute from the element. There is no real namespace parsing here, so this ignores the namespace
600
+ * and behaves exactly like removeAttribute.
601
+ * @param {string} namespace Ignored
602
+ * @param {string} attributeName
603
+ * @returns {undefined}
604
+ */
605
+ removeAttributeNS (namespace, attributeName) {
606
+ this.removeAttribute(attributeName)
607
+ }
608
+
609
+ /**
610
+ * Set the node representation of an attribute, adding the attribute if it did not exist. Returns any previous
611
+ * Attr that had the same name, or null when there was none.
612
+ * @param {AttrService} attr
613
+ * @returns {AttrService|null} The replaced Attr, or null when the attribute was new
614
+ */
615
+ setAttributeNode (attr) {
616
+ const existing = this.getAttributeNode(attr.name)
617
+ this.setAttribute(attr.name, attr.value)
618
+ return existing
619
+ }
620
+
621
+ /**
622
+ * Set the node representation of an attribute. There is no real namespace parsing here, so this behaves
623
+ * exactly like setAttributeNode (Attr.name already carries any prefix).
624
+ * @param {AttrService} attr
625
+ * @returns {AttrService|null} The replaced Attr, or null when the attribute was new
626
+ */
627
+ setAttributeNodeNS (attr) {
628
+ return this.setAttributeNode(attr)
629
+ }
630
+
631
+ /**
632
+ * Set the value of an attribute, adding the attribute if it did not exist. There is no real namespace parsing
633
+ * here, so this ignores the namespace and behaves exactly like setAttribute.
634
+ * @param {string} namespace Ignored
635
+ * @param {string} attributeName
636
+ * @param {string} attributeValue
637
+ * @returns {undefined}
638
+ */
639
+ setAttributeNS (namespace, attributeName, attributeValue) {
640
+ this.setAttribute(attributeName, attributeValue)
641
+ }
642
+
643
+ /**
644
+ * Add the attribute (with an empty value) when it is not present, or remove it when it is - unless force says
645
+ * which of those to do instead. Returns whether the attribute is present after the call.
646
+ * @param {string} attributeName
647
+ * @param {boolean} [force]
648
+ * @returns {boolean}
649
+ */
650
+ toggleAttribute (attributeName, force) {
651
+ const present = this.hasAttribute(attributeName)
652
+ const shouldHave = typeof force === 'boolean' ? force : !present
653
+ if (shouldHave && !present) {
654
+ this.setAttribute(attributeName, '')
655
+ } else if (!shouldHave && present) {
656
+ this.removeAttribute(attributeName)
657
+ }
658
+ return shouldHave
659
+ }
660
+
661
+ /**
662
+ * The size of the element and its position, settable directly - there is no layout engine here to compute it.
663
+ * @returns {DOMRect}
664
+ */
665
+ getBoundingClientRect () {
666
+ return this.boundingClientRect
667
+ }
668
+
669
+ /**
670
+ * The bounding rectangles for each line of text in the element, settable directly - there is no layout engine
671
+ * here to compute it.
672
+ * @returns {Array<DOMRect>}
673
+ */
674
+ getClientRects () {
675
+ return this.clientRects
676
+ }
677
+
678
+ /**
679
+ * The Animation objects currently active on the element, settable directly - there is no animation engine here.
680
+ * @returns {Array<*>}
681
+ */
682
+ getAnimations () {
683
+ return this.animations
684
+ }
685
+
686
+ /**
687
+ * Whether the element is expected to be visible, settable directly - there is no rendering here to check it.
688
+ * @returns {boolean}
689
+ */
690
+ checkVisibility () {
691
+ return this.isVisible
692
+ }
693
+
694
+ /**
695
+ * A read-only view of the element's own inline style declarations (there is no CSS cascade here, so this is not a
696
+ * real computed style - just what the element's own style object holds).
697
+ * @returns {{get: function(string): (string|undefined)}}
698
+ */
699
+ computedStyleMap () {
700
+ const style = this.style
701
+ return {
702
+ get: property => {
703
+ const value = style ? style.getPropertyValue(property) : ''
704
+ return value === '' ? undefined : value
705
+ }
706
+ }
707
+ }
708
+
709
+ /**
710
+ * Whether this element currently has capture of the given pointer.
711
+ * @param {number} pointerId
712
+ * @returns {boolean}
713
+ */
714
+ hasPointerCapture (pointerId) {
715
+ return this.capturedPointers.has(pointerId)
716
+ }
717
+
718
+ /**
719
+ * Give this element capture of the given pointer.
720
+ * @param {number} pointerId
721
+ * @returns {undefined}
722
+ */
723
+ setPointerCapture (pointerId) {
724
+ this.capturedPointers.add(pointerId)
725
+ }
726
+
727
+ /**
728
+ * Release this element's capture of the given pointer, if it had it.
729
+ * @param {number} pointerId
730
+ * @returns {undefined}
731
+ */
732
+ releasePointerCapture (pointerId) {
733
+ this.capturedPointers.delete(pointerId)
734
+ }
735
+
736
+ /**
737
+ * Scroll to the given position (or, given an options object, the position(s) it has). There is no real scrollable
738
+ * viewport here: this just sets scrollLeft / scrollTop.
739
+ * @param {number|{left: number, top: number}} [x=0]
740
+ * @param {number} [y=0]
741
+ * @returns {undefined}
742
+ */
743
+ scroll (x = 0, y = 0) {
744
+ if (typeof x === 'number') {
745
+ this.scrollLeft = x
746
+ this.scrollTop = y
747
+ return
748
+ }
749
+ if (typeof x.left === 'number') {
750
+ this.scrollLeft = x.left
751
+ }
752
+ if (typeof x.top === 'number') {
753
+ this.scrollTop = x.top
754
+ }
755
+ }
756
+
757
+ /**
758
+ * Scroll to the given position. An alias for scroll.
759
+ * @param {number|{left: number, top: number}} [x=0]
760
+ * @param {number} [y=0]
761
+ * @returns {undefined}
762
+ */
763
+ scrollTo (x = 0, y = 0) {
764
+ this.scroll(x, y)
765
+ }
766
+
767
+ /**
768
+ * Scroll by the given amount, relative to the current position.
769
+ * @param {number|{left: number, top: number}} [x=0]
770
+ * @param {number} [y=0]
771
+ * @returns {undefined}
772
+ */
773
+ scrollBy (x = 0, y = 0) {
774
+ if (typeof x === 'number') {
775
+ this.scroll(this.scrollLeft + x, this.scrollTop + y)
776
+ return
777
+ }
778
+ this.scroll({
779
+ left: this.scrollLeft + (x.left || 0),
780
+ top: this.scrollTop + (x.top || 0)
781
+ })
782
+ }
783
+
784
+ /**
785
+ * Scroll an ancestor until this element is in view. There is no real viewport here for that to mean anything, so
786
+ * this does nothing (override it on an instance in a test which needs to observe the call).
787
+ * @returns {undefined}
788
+ */
789
+ scrollIntoView () {}
790
+ /**
791
+ * Asynchronously ask for the element to be shown fullscreen. There is no real fullscreen here, so this just
792
+ * resolves, like a browser granting the request would.
793
+ * @returns {Promise<void>}
794
+ */
795
+ requestFullscreen () {
796
+ return Promise.resolve()
797
+ }
798
+
799
+ /**
800
+ * Asynchronously ask for the pointer to be locked to this element. There is no real pointer lock here, so this
801
+ * just resolves, like a browser granting the request would.
802
+ * @returns {Promise<void>}
803
+ */
804
+ requestPointerLock () {
805
+ return Promise.resolve()
806
+ }
807
+
808
+ /**
809
+ * Attach a shadow tree to this element and return its ShadowRoot. Throws when it already hosts one.
810
+ * @param {{mode: string}} options
811
+ * @returns {PseudoShadowRoot}
812
+ * @throws {Error}
813
+ */
814
+ attachShadow (options) {
815
+ if (this.shadowRootInstance) {
816
+ throw new Error('Shadow root cannot be created on a host which already hosts a shadow tree.')
817
+ }
818
+ const root = new ShadowRootService_1.ShadowRootService()
819
+ root.host = this
820
+ root.mode = options.mode
821
+ this.shadowRootInstance = root
822
+ return root
823
+ }
824
+
825
+ /**
826
+ * This element's shadow root, when it has one attached in 'open' mode, or null (including when the mode is
827
+ * 'closed' - it still exists, but is not reachable this way, like the DOM's).
828
+ * @returns {PseudoShadowRoot|null}
829
+ */
830
+ get shadowRoot () {
831
+ return this.shadowRootInstance && this.shadowRootInstance.mode === 'open' ? this.shadowRootInstance : null
832
+ }
833
+
834
+ /**
835
+ * Read one of the aria-* reflected properties (see the individual aria* getters/setters below).
836
+ * @param {string} attributeName A real aria-* attribute name (aria-label, ...)
837
+ * @returns {string}
838
+ */
839
+ getAriaAttribute (attributeName) {
840
+ return this.getAttribute(attributeName) || ''
841
+ }
842
+
843
+ /**
844
+ * Write one of the aria-* reflected properties.
845
+ * @param {string} attributeName A real aria-* attribute name (aria-label, ...)
846
+ * @param {string} value
847
+ * @returns {undefined}
848
+ */
849
+ setAriaAttribute (attributeName, value) {
850
+ this.setAttribute(attributeName, value)
851
+ }
852
+
853
+ get ariaAtomic () {
854
+ return this.getAriaAttribute('aria-atomic')
855
+ }
856
+
857
+ set ariaAtomic (value) {
858
+ this.setAriaAttribute('aria-atomic', value)
859
+ }
860
+
861
+ get ariaAutoComplete () {
862
+ return this.getAriaAttribute('aria-autocomplete')
863
+ }
864
+
865
+ set ariaAutoComplete (value) {
866
+ this.setAriaAttribute('aria-autocomplete', value)
867
+ }
868
+
869
+ get ariaBusy () {
870
+ return this.getAriaAttribute('aria-busy')
871
+ }
872
+
873
+ set ariaBusy (value) {
874
+ this.setAriaAttribute('aria-busy', value)
875
+ }
876
+
877
+ get ariaChecked () {
878
+ return this.getAriaAttribute('aria-checked')
879
+ }
880
+
881
+ set ariaChecked (value) {
882
+ this.setAriaAttribute('aria-checked', value)
883
+ }
884
+
885
+ get ariaColCount () {
886
+ return this.getAriaAttribute('aria-colcount')
887
+ }
888
+
889
+ set ariaColCount (value) {
890
+ this.setAriaAttribute('aria-colcount', value)
891
+ }
892
+
893
+ get ariaColIndex () {
894
+ return this.getAriaAttribute('aria-colindex')
895
+ }
896
+
897
+ set ariaColIndex (value) {
898
+ this.setAriaAttribute('aria-colindex', value)
899
+ }
900
+
901
+ get ariaColSpan () {
902
+ return this.getAriaAttribute('aria-colspan')
903
+ }
904
+
905
+ set ariaColSpan (value) {
906
+ this.setAriaAttribute('aria-colspan', value)
907
+ }
908
+
909
+ get ariaCurrent () {
910
+ return this.getAriaAttribute('aria-current')
911
+ }
912
+
913
+ set ariaCurrent (value) {
914
+ this.setAriaAttribute('aria-current', value)
915
+ }
916
+
917
+ get ariaDescription () {
918
+ return this.getAriaAttribute('aria-description')
919
+ }
920
+
921
+ set ariaDescription (value) {
922
+ this.setAriaAttribute('aria-description', value)
923
+ }
924
+
925
+ get ariaDisabled () {
926
+ return this.getAriaAttribute('aria-disabled')
927
+ }
928
+
929
+ set ariaDisabled (value) {
930
+ this.setAriaAttribute('aria-disabled', value)
931
+ }
932
+
933
+ get ariaExpanded () {
934
+ return this.getAriaAttribute('aria-expanded')
935
+ }
936
+
937
+ set ariaExpanded (value) {
938
+ this.setAriaAttribute('aria-expanded', value)
939
+ }
940
+
941
+ get ariaHasPopup () {
942
+ return this.getAriaAttribute('aria-haspopup')
943
+ }
944
+
945
+ set ariaHasPopup (value) {
946
+ this.setAriaAttribute('aria-haspopup', value)
947
+ }
948
+
949
+ get ariaHidden () {
950
+ return this.getAriaAttribute('aria-hidden')
951
+ }
952
+
953
+ set ariaHidden (value) {
954
+ this.setAriaAttribute('aria-hidden', value)
955
+ }
956
+
957
+ get ariaKeyShortcuts () {
958
+ return this.getAriaAttribute('aria-keyshortcuts')
959
+ }
960
+
961
+ set ariaKeyShortcuts (value) {
962
+ this.setAriaAttribute('aria-keyshortcuts', value)
963
+ }
964
+
965
+ get ariaLabel () {
966
+ return this.getAriaAttribute('aria-label')
967
+ }
968
+
969
+ set ariaLabel (value) {
970
+ this.setAriaAttribute('aria-label', value)
971
+ }
972
+
973
+ get ariaLevel () {
974
+ return this.getAriaAttribute('aria-level')
975
+ }
976
+
977
+ set ariaLevel (value) {
978
+ this.setAriaAttribute('aria-level', value)
979
+ }
980
+
981
+ get ariaLive () {
982
+ return this.getAriaAttribute('aria-live')
983
+ }
984
+
985
+ set ariaLive (value) {
986
+ this.setAriaAttribute('aria-live', value)
987
+ }
988
+
989
+ get ariaModal () {
990
+ return this.getAriaAttribute('aria-modal')
991
+ }
992
+
993
+ set ariaModal (value) {
994
+ this.setAriaAttribute('aria-modal', value)
995
+ }
996
+
997
+ get ariaMultiline () {
998
+ return this.getAriaAttribute('aria-multiline')
999
+ }
1000
+
1001
+ set ariaMultiline (value) {
1002
+ this.setAriaAttribute('aria-multiline', value)
1003
+ }
1004
+
1005
+ get ariaMultiSelectable () {
1006
+ return this.getAriaAttribute('aria-multiselectable')
1007
+ }
1008
+
1009
+ set ariaMultiSelectable (value) {
1010
+ this.setAriaAttribute('aria-multiselectable', value)
1011
+ }
1012
+
1013
+ get ariaOrientation () {
1014
+ return this.getAriaAttribute('aria-orientation')
1015
+ }
1016
+
1017
+ set ariaOrientation (value) {
1018
+ this.setAriaAttribute('aria-orientation', value)
1019
+ }
1020
+
1021
+ get ariaPlaceholder () {
1022
+ return this.getAriaAttribute('aria-placeholder')
1023
+ }
1024
+
1025
+ set ariaPlaceholder (value) {
1026
+ this.setAriaAttribute('aria-placeholder', value)
1027
+ }
1028
+
1029
+ get ariaPosInSet () {
1030
+ return this.getAriaAttribute('aria-posinset')
1031
+ }
1032
+
1033
+ set ariaPosInSet (value) {
1034
+ this.setAriaAttribute('aria-posinset', value)
1035
+ }
1036
+
1037
+ get ariaPressed () {
1038
+ return this.getAriaAttribute('aria-pressed')
1039
+ }
1040
+
1041
+ set ariaPressed (value) {
1042
+ this.setAriaAttribute('aria-pressed', value)
1043
+ }
1044
+
1045
+ get ariaReadOnly () {
1046
+ return this.getAriaAttribute('aria-readonly')
1047
+ }
1048
+
1049
+ set ariaReadOnly (value) {
1050
+ this.setAriaAttribute('aria-readonly', value)
1051
+ }
1052
+
1053
+ get ariaRequired () {
1054
+ return this.getAriaAttribute('aria-required')
1055
+ }
1056
+
1057
+ set ariaRequired (value) {
1058
+ this.setAriaAttribute('aria-required', value)
1059
+ }
1060
+
1061
+ get ariaRoleDescription () {
1062
+ return this.getAriaAttribute('aria-roledescription')
1063
+ }
1064
+
1065
+ set ariaRoleDescription (value) {
1066
+ this.setAriaAttribute('aria-roledescription', value)
1067
+ }
1068
+
1069
+ get ariaRowCount () {
1070
+ return this.getAriaAttribute('aria-rowcount')
1071
+ }
1072
+
1073
+ set ariaRowCount (value) {
1074
+ this.setAriaAttribute('aria-rowcount', value)
1075
+ }
1076
+
1077
+ get ariaRowIndex () {
1078
+ return this.getAriaAttribute('aria-rowindex')
1079
+ }
1080
+
1081
+ set ariaRowIndex (value) {
1082
+ this.setAriaAttribute('aria-rowindex', value)
1083
+ }
1084
+
1085
+ get ariaRowSpan () {
1086
+ return this.getAriaAttribute('aria-rowspan')
1087
+ }
1088
+
1089
+ set ariaRowSpan (value) {
1090
+ this.setAriaAttribute('aria-rowspan', value)
1091
+ }
1092
+
1093
+ get ariaSelected () {
1094
+ return this.getAriaAttribute('aria-selected')
1095
+ }
1096
+
1097
+ set ariaSelected (value) {
1098
+ this.setAriaAttribute('aria-selected', value)
1099
+ }
1100
+
1101
+ get ariaSetSize () {
1102
+ return this.getAriaAttribute('aria-setsize')
1103
+ }
1104
+
1105
+ set ariaSetSize (value) {
1106
+ this.setAriaAttribute('aria-setsize', value)
1107
+ }
1108
+
1109
+ get ariaSort () {
1110
+ return this.getAriaAttribute('aria-sort')
1111
+ }
1112
+
1113
+ set ariaSort (value) {
1114
+ this.setAriaAttribute('aria-sort', value)
1115
+ }
1116
+
1117
+ get ariaValueMax () {
1118
+ return this.getAriaAttribute('aria-valuemax')
1119
+ }
1120
+
1121
+ set ariaValueMax (value) {
1122
+ this.setAriaAttribute('aria-valuemax', value)
1123
+ }
1124
+
1125
+ get ariaValueMin () {
1126
+ return this.getAriaAttribute('aria-valuemin')
1127
+ }
1128
+
1129
+ set ariaValueMin (value) {
1130
+ this.setAriaAttribute('aria-valuemin', value)
1131
+ }
1132
+
1133
+ get ariaValueNow () {
1134
+ return this.getAriaAttribute('aria-valuenow')
1135
+ }
1136
+
1137
+ set ariaValueNow (value) {
1138
+ this.setAriaAttribute('aria-valuenow', value)
1139
+ }
1140
+
1141
+ get ariaValueText () {
1142
+ return this.getAriaAttribute('aria-valuetext')
1143
+ }
1144
+
1145
+ set ariaValueText (value) {
1146
+ this.setAriaAttribute('aria-valuetext', value)
1147
+ }
1148
+ }
1149
+ exports.ElementService = ElementService