UNPKG

15.9 kBJavaScriptView Raw
1import { __extends, __read, __spreadArray } from "tslib";
2import { GlobalContainer } from 'mana-syringe';
3import { SceneGraphService } from '../services/SceneGraphService';
4import { Cullable, Geometry, Renderable, Transform, Sortable } from '../components';
5import { Node } from './Node';
6import { ElementEvent } from './interfaces';
7import { formatAttribute, isNil } from '../utils';
8import { MutationEvent } from './MutationEvent';
9var entityCounter = 0;
10/**
11 * Has following capabilities:
12 * * Node insert/remove, eg. appendChild, removeChild, remove...
13 * * Query eg. querySelector getElementById...
14 * * Animation
15 */
16
17var Element =
18/** @class */
19function (_super) {
20 __extends(Element, _super);
21
22 function Element() {
23 var _this = _super !== null && _super.apply(this, arguments) || this;
24
25 _this.sceneGraphService = GlobalContainer.get(SceneGraphService);
26 _this.entity = entityCounter++;
27 _this.renderable = new Renderable();
28 _this.cullable = new Cullable();
29 _this.transformable = new Transform();
30 _this.sortable = new Sortable();
31 _this.geometry = new Geometry();
32 /**
33 * https://developer.mozilla.org/zh-CN/docs/Web/API/Element/namespaceURI
34 */
35
36 _this.namespaceURI = 'g';
37 _this.scrollLeft = 0;
38 _this.scrollTop = 0;
39 /**
40 * We don't support border now
41 * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/clientTop
42 */
43
44 _this.clientTop = 0;
45 _this.clientLeft = 0;
46 /**
47 * is destroyed or not
48 */
49
50 _this.destroyed = false;
51 /**
52 * compatible with `style`
53 * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style
54 */
55
56 _this.style = {};
57 _this.computedStyle = {};
58 _this.parsedStyle = {};
59 /**
60 * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/attributes
61 */
62
63 _this.attributes = {};
64 return _this;
65 }
66
67 Element.isElement = function (target) {
68 return !!target.getAttribute;
69 };
70
71 Object.defineProperty(Element.prototype, "className", {
72 /**
73 * used in `getElementsByClassName`
74 * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName
75 */
76 get: function get() {
77 return this.getAttribute('class') || '';
78 },
79 set: function set(className) {
80 this.setAttribute('class', className);
81 },
82 enumerable: false,
83 configurable: true
84 });
85 Object.defineProperty(Element.prototype, "classList", {
86 /**
87 * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/classList
88 */
89 get: function get() {
90 return this.className.split(' ').filter(function (c) {
91 return c !== '';
92 });
93 },
94 enumerable: false,
95 configurable: true
96 });
97 Object.defineProperty(Element.prototype, "tagName", {
98 get: function get() {
99 return this.nodeName;
100 },
101 enumerable: false,
102 configurable: true
103 });
104 Object.defineProperty(Element.prototype, "children", {
105 get: function get() {
106 return this.childNodes;
107 },
108 enumerable: false,
109 configurable: true
110 });
111 Object.defineProperty(Element.prototype, "childElementCount", {
112 get: function get() {
113 return this.childNodes.length;
114 },
115 enumerable: false,
116 configurable: true
117 });
118 Object.defineProperty(Element.prototype, "firstElementChild", {
119 get: function get() {
120 return this.firstChild;
121 },
122 enumerable: false,
123 configurable: true
124 });
125 Object.defineProperty(Element.prototype, "lastElementChild", {
126 get: function get() {
127 return this.lastChild;
128 },
129 enumerable: false,
130 configurable: true
131 });
132 Object.defineProperty(Element.prototype, "parentElement", {
133 get: function get() {
134 return this.parentNode;
135 },
136 enumerable: false,
137 configurable: true
138 });
139 Object.defineProperty(Element.prototype, "nextSibling", {
140 get: function get() {
141 if (this.parentNode) {
142 var index = this.parentNode.childNodes.indexOf(this);
143 return this.parentNode.childNodes[index + 1] || null;
144 }
145
146 return null;
147 },
148 enumerable: false,
149 configurable: true
150 });
151 Object.defineProperty(Element.prototype, "previousSibling", {
152 get: function get() {
153 if (this.parentNode) {
154 var index = this.parentNode.childNodes.indexOf(this);
155 return this.parentNode.childNodes[index - 1] || null;
156 }
157
158 return null;
159 },
160 enumerable: false,
161 configurable: true
162 }); // eslint-disable-next-line @typescript-eslint/no-unused-vars
163
164 Element.prototype.cloneNode = function (deep) {
165 throw new Error('Method not implemented.');
166 };
167
168 Element.prototype.appendChild = function (child, index) {
169 this.sceneGraphService.attach(child, this, index);
170 this.emit(ElementEvent.CHILD_INSERTED, {
171 child: child
172 }); // child.emit(ElementEvent.INSERTED, {
173 // parent: this,
174 // index,
175 // });
176
177 child.dispatchEvent(new MutationEvent(ElementEvent.INSERTED, this, '', '', '', 0, '', ''));
178 return child;
179 };
180
181 Element.prototype.insertBefore = function (newChild, refChild) {
182 if (!refChild) {
183 this.appendChild(newChild);
184 } else {
185 var index = this.childNodes.indexOf(refChild);
186 this.appendChild(newChild, index - 1);
187 }
188
189 return newChild;
190 };
191
192 Element.prototype.replaceChild = function (newChild, oldChild, destroy) {
193 var index = this.childNodes.indexOf(oldChild);
194 this.removeChild(oldChild, destroy);
195 this.appendChild(newChild, index);
196 return oldChild;
197 };
198
199 Element.prototype.removeChild = function (child, destroy) {
200 // should emit on itself before detach
201 // child.emit(ElementEvent.REMOVED, {
202 // parent: this,
203 // });
204 if (destroy === void 0) {
205 destroy = true;
206 }
207
208 child.dispatchEvent(new MutationEvent(ElementEvent.REMOVED, this, '', '', '', 0, '', '')); // emit destroy event
209
210 if (destroy) {
211 child.emit(ElementEvent.DESTROY, {});
212 child.destroyed = true;
213 } // emit on parent
214
215
216 this.emit(ElementEvent.CHILD_REMOVED, {
217 child: child
218 }); // remove from scene graph
219
220 this.sceneGraphService.detach(child); // cannot emit Destroy event now
221
222 if (destroy) {
223 // this.removeChildren();
224 // remove event listeners
225 child.emitter.removeAllListeners();
226 }
227
228 return child;
229 };
230
231 Element.prototype.removeChildren = function (destroy) {
232 var _this = this;
233
234 if (destroy === void 0) {
235 destroy = true;
236 }
237
238 this.childNodes.slice().forEach(function (child) {
239 _this.removeChild(child, destroy);
240 });
241 };
242 /**
243 * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
244 */
245
246
247 Element.prototype.matches = function (selector) {
248 return this.sceneGraphService.matches(selector, this);
249 };
250
251 Element.prototype.getElementById = function (id) {
252 return this.sceneGraphService.querySelector("#".concat(id), this);
253 };
254
255 Element.prototype.getElementsByName = function (name) {
256 return this.sceneGraphService.querySelectorAll("[name=\"".concat(name, "\"]"), this);
257 };
258
259 Element.prototype.getElementsByClassName = function (className) {
260 return this.sceneGraphService.querySelectorAll(".".concat(className), this);
261 };
262
263 Element.prototype.getElementsByTagName = function (tagName) {
264 return this.sceneGraphService.querySelectorAll(tagName, this);
265 };
266
267 Element.prototype.querySelector = function (selectors) {
268 return this.sceneGraphService.querySelector(selectors, this);
269 };
270
271 Element.prototype.querySelectorAll = function (selectors) {
272 return this.sceneGraphService.querySelectorAll(selectors, this);
273 };
274 /**
275 * search in scene group, but should not include itself
276 */
277
278
279 Element.prototype.find = function (filter) {
280 var _this = this;
281
282 var target = null;
283 this.forEach(function (object) {
284 if (object !== _this && filter(object)) {
285 target = object;
286 return true;
287 }
288
289 return false;
290 });
291 return target;
292 };
293
294 Element.prototype.findAll = function (filter) {
295 var _this = this;
296
297 var objects = [];
298 this.forEach(function (object) {
299 if (object !== _this && filter(object)) {
300 objects.push(object);
301 }
302 });
303 return objects;
304 };
305 /**
306 * @see https://developer.mozilla.org/zh-CN/docs/Web/API/Element/after
307 */
308
309
310 Element.prototype.after = function () {
311 var _this = this;
312
313 var nodes = [];
314
315 for (var _i = 0; _i < arguments.length; _i++) {
316 nodes[_i] = arguments[_i];
317 }
318
319 if (this.parentNode) {
320 var index_1 = this.parentNode.childNodes.indexOf(this);
321 nodes.forEach(function (node, i) {
322 var _a;
323
324 return (_a = _this.parentNode) === null || _a === void 0 ? void 0 : _a.appendChild(node, index_1 + i + 1);
325 });
326 }
327 };
328 /**
329 * @see https://developer.mozilla.org/zh-CN/docs/Web/API/Element/before
330 */
331
332
333 Element.prototype.before = function () {
334 var _a;
335
336 var nodes = [];
337
338 for (var _i = 0; _i < arguments.length; _i++) {
339 nodes[_i] = arguments[_i];
340 }
341
342 if (this.parentNode) {
343 var index = this.parentNode.childNodes.indexOf(this);
344
345 var _b = __read(nodes),
346 first = _b[0],
347 rest = _b.slice(1);
348
349 this.parentNode.appendChild(first, index);
350
351 (_a = first).after.apply(_a, __spreadArray([], __read(rest), false));
352 }
353 };
354 /**
355 * @see https://developer.mozilla.org/zh-CN/docs/Web/API/Element/replaceWith
356 */
357
358
359 Element.prototype.replaceWith = function () {
360 var nodes = [];
361
362 for (var _i = 0; _i < arguments.length; _i++) {
363 nodes[_i] = arguments[_i];
364 }
365
366 this.after.apply(this, __spreadArray([], __read(nodes), false));
367 this.remove();
368 };
369 /**
370 * @see https://developer.mozilla.org/zh-CN/docs/Web/API/Element/append
371 */
372
373
374 Element.prototype.append = function () {
375 var _this = this;
376
377 var nodes = [];
378
379 for (var _i = 0; _i < arguments.length; _i++) {
380 nodes[_i] = arguments[_i];
381 }
382
383 nodes.forEach(function (node) {
384 return _this.appendChild(node);
385 });
386 };
387 /**
388 * @see https://developer.mozilla.org/zh-CN/docs/Web/API/Element/prepend
389 */
390
391
392 Element.prototype.prepend = function () {
393 var _this = this;
394
395 var nodes = [];
396
397 for (var _i = 0; _i < arguments.length; _i++) {
398 nodes[_i] = arguments[_i];
399 }
400
401 nodes.forEach(function (node, i) {
402 return _this.appendChild(node, i);
403 });
404 };
405 /**
406 * @see https://developer.mozilla.org/zh-CN/docs/Web/API/Element/replaceChildren
407 */
408
409
410 Element.prototype.replaceChildren = function () {
411 var nodes = [];
412
413 for (var _i = 0; _i < arguments.length; _i++) {
414 nodes[_i] = arguments[_i];
415 }
416
417 while (this.childNodes.length && this.firstChild) {
418 this.removeChild(this.firstChild);
419 }
420
421 this.append.apply(this, __spreadArray([], __read(nodes), false));
422 };
423 /**
424 * @see https://developer.mozilla.org/zh-CN/docs/Web/API/Element/remove
425 */
426
427
428 Element.prototype.remove = function (destroy) {
429 if (destroy === void 0) {
430 destroy = true;
431 }
432
433 if (this.parentNode) {
434 return this.parentNode.removeChild(this, destroy);
435 }
436
437 return this;
438 };
439
440 Element.prototype.destroy = function () {
441 // destroy itself before remove
442 this.emit(ElementEvent.DESTROY, {}); // remove from scenegraph first
443
444 this.remove(false); // remove event listeners
445
446 this.emitter.removeAllListeners();
447 this.destroyed = true;
448 };
449
450 Element.prototype.getGeometryBounds = function () {
451 return this.sceneGraphService.getGeometryBounds(this);
452 };
453
454 Element.prototype.getRenderBounds = function () {
455 return this.sceneGraphService.getBounds(this, true);
456 };
457 /**
458 * get bounds in world space, account for children
459 */
460
461
462 Element.prototype.getBounds = function () {
463 return this.sceneGraphService.getBounds(this);
464 };
465 /**
466 * get bounds in local space, account for children
467 */
468
469
470 Element.prototype.getLocalBounds = function () {
471 return this.sceneGraphService.getLocalBounds(this);
472 };
473 /**
474 * account for context's bounds in client space,
475 * but not accounting for children
476 * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect
477 */
478
479
480 Element.prototype.getBoundingClientRect = function () {
481 return this.sceneGraphService.getBoundingClientRect(this);
482 };
483 /**
484 * @see https://developer.mozilla.org/zh-CN/docs/Web/API/Element/getClientRects
485 */
486
487
488 Element.prototype.getClientRects = function () {
489 return [this.getBoundingClientRect()];
490 };
491 /**
492 * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/computedStyleMap
493 * eg. circle.computedStyleMap().get('fill');
494 */
495
496
497 Element.prototype.computedStyleMap = function () {
498 return new Map(Object.entries(this.computedStyle));
499 };
500 /**
501 * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttributeNames
502 */
503
504
505 Element.prototype.getAttributeNames = function () {
506 return Object.keys(this.attributes);
507 };
508 /**
509 * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute
510 */
511
512
513 Element.prototype.getAttribute = function (name) {
514 var _a = __read(formatAttribute(name.toString(), ''), 1),
515 attributeName = _a[0];
516
517 var value = this.attributes[attributeName]; // if the given attribute does not exist, the value returned will either be null or ""
518
519 return isNil(value) ? null : value;
520 };
521 /**
522 * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/hasAttribute
523 */
524
525
526 Element.prototype.hasAttribute = function (qualifiedName) {
527 return this.getAttributeNames().includes(qualifiedName);
528 };
529 /**
530 * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/hasAttributes
531 */
532
533
534 Element.prototype.hasAttributes = function () {
535 return !!this.getAttributeNames().length;
536 };
537 /**
538 * should use removeAttribute() instead of setting the attribute value to null either directly or using setAttribute(). Many attributes will not behave as expected if you set them to null.
539 * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/removeAttribute
540 */
541
542
543 Element.prototype.removeAttribute = function (attributeName) {
544 this.setAttribute(attributeName, null);
545 delete this.attributes[attributeName];
546 };
547 /**
548 * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute
549 */
550
551
552 Element.prototype.setAttribute = function (attributeName, value, // eslint-disable-next-line @typescript-eslint/no-unused-vars
553 force) {
554 if (force === void 0) {
555 force = false;
556 }
557
558 this.attributes[attributeName] = value;
559 };
560
561 Element.prototype.getAttributeNS = function (namespace, localName) {
562 throw new Error('Method not implemented.');
563 };
564
565 Element.prototype.getAttributeNode = function (qualifiedName) {
566 throw new Error('Method not implemented.');
567 };
568
569 Element.prototype.getAttributeNodeNS = function (namespace, localName) {
570 throw new Error('Method not implemented.');
571 };
572
573 Element.prototype.hasAttributeNS = function (namespace, localName) {
574 throw new Error('Method not implemented.');
575 };
576
577 Element.prototype.removeAttributeNS = function (namespace, localName) {
578 throw new Error('Method not implemented.');
579 };
580
581 Element.prototype.removeAttributeNode = function (attr) {
582 throw new Error('Method not implemented.');
583 };
584
585 Element.prototype.setAttributeNS = function (namespace, qualifiedName, value) {
586 throw new Error('Method not implemented.');
587 };
588
589 Element.prototype.setAttributeNode = function (attr) {
590 throw new Error('Method not implemented.');
591 };
592
593 Element.prototype.setAttributeNodeNS = function (attr) {
594 throw new Error('Method not implemented.');
595 };
596
597 Element.prototype.toggleAttribute = function (qualifiedName, force) {
598 throw new Error('Method not implemented.');
599 };
600
601 return Element;
602}(Node);
603
604export { Element };
\No newline at end of file