UNPKG

44.7 kBJavaScriptView Raw
1/**
2 * Base functionality
3*/
4import { __extends } from "tslib";
5import { List, ListTemplate } from "./utils/List";
6import { OrderedListTemplate, SortedListTemplate } from "./utils/SortedList";
7import { Dictionary, DictionaryTemplate } from "./utils/Dictionary";
8import { Disposer } from "./utils/Disposer";
9import { EventDispatcher } from "./utils/EventDispatcher";
10import { Adapter } from "./utils/Adapter";
11import { Color, color } from "./utils/Color";
12import { Percent, percent } from "./utils/Percent";
13import { registry } from "./Registry";
14import { cache } from "./utils/Cache";
15import * as $array from "./utils/Array";
16import * as $object from "./utils/Object";
17import * as $type from "./utils/Type";
18//import * as $debug from "./utils/Debug";
19/**
20 * Provides base functionality for all derivative objects, like generating ids,
21 * handling cache, etc.
22 */
23var BaseObject = /** @class */ (function () {
24 //protected _classes: { [index: string]: any } = {};
25 /**
26 * Constructor
27 * * Sets class name
28 */
29 function BaseObject() {
30 /**
31 * Indicates if this object has already been deleted. Any
32 * destruction/disposal code should take this into account when deciding
33 * wheter to run potentially costly disposal operations if they already have
34 * been run.
35 */
36 this._disposed = false;
37 /**
38 * List of IDisposer which will be disposed when the BaseObject is disposed.
39 */
40 this._disposers = [];
41 this.className = "BaseObject";
42 //this.debug();
43 }
44 BaseObject.prototype.debug = function () {
45 //$debug.debug(this);
46 };
47 Object.defineProperty(BaseObject.prototype, "uid", {
48 /**
49 * Returns object's internal unique ID.
50 *
51 * @return Unique ID
52 */
53 get: function () {
54 if (!this._uid) {
55 this._uid = registry.getUniqueId();
56 registry.map.setKey(this._uid, this);
57 }
58 return this._uid;
59 },
60 enumerable: true,
61 configurable: true
62 });
63 Object.defineProperty(BaseObject.prototype, "id", {
64 /**
65 * @return Id
66 */
67 get: function () {
68 return this._id;
69 },
70 /**
71 * Sets the user-defined id of the element.
72 *
73 * @param value Id
74 */
75 set: function (value) {
76 //registry.map.setKey(value, this); // registry.map only stores by uid
77 this._id = value;
78 },
79 enumerable: true,
80 configurable: true
81 });
82 Object.defineProperty(BaseObject.prototype, "map", {
83 /**
84 * Returns a universal collection for mapping ids with objects.
85 *
86 * @ignore Exclude from docs
87 * @return Map collection
88 */
89 get: function () {
90 if (!this._map) {
91 this._map = new Dictionary();
92 }
93 return this._map;
94 },
95 enumerable: true,
96 configurable: true
97 });
98 Object.defineProperty(BaseObject.prototype, "delayedMap", {
99 /**
100 * Returns mapping for objects referenced by id in JSON config that are not yet
101 * available at processing time.
102 *
103 * @ignore Exclude from docs
104 * @return Map collection
105 */
106 get: function () {
107 if (!this._delayedMap) {
108 this._delayedMap = new Dictionary();
109 }
110 return this._delayedMap;
111 },
112 enumerable: true,
113 configurable: true
114 });
115 /**
116 * Logs an id and property of the target element that is not yet available
117 * for later assignment.
118 *
119 * @ignore
120 * @param property Property to set
121 * @param id ID of the target element
122 */
123 BaseObject.prototype.addDelayedMap = function (property, id) {
124 var map = this.delayedMap;
125 if (!map.hasKey(id)) {
126 map.setKey(id, []);
127 }
128 var list = map.getKey(id);
129 list.push({
130 property: property,
131 target: this
132 });
133 };
134 /**
135 * Processes delayed JSON config items.
136 *
137 * @ignore
138 */
139 BaseObject.prototype.processDelayedMap = function () {
140 var _this = this;
141 this.delayedMap.each(function (id, list) {
142 if (_this.map.hasKey(id)) {
143 var target_1 = _this.map.getKey(id);
144 $array.each(list, function (item) {
145 item.target[item.property] = target_1;
146 });
147 _this.delayedMap.removeKey(id);
148 }
149 });
150 };
151 /**
152 * Applies properties from all assigned themes.
153 *
154 * @ignore Exclude from docs
155 */
156 BaseObject.prototype.applyTheme = function () {
157 var _this = this;
158 // TODO is this needed ?
159 if (registry) {
160 var themes = this.getCurrentThemes();
161 // TODO is this needed ?
162 if (themes) {
163 $array.each(themes, function (theme, index) {
164 theme(_this);
165 });
166 }
167 }
168 };
169 Object.defineProperty(BaseObject.prototype, "themes", {
170 /**
171 * @ignore Exclude from docs
172 * @return An array of themes
173 */
174 get: function () {
175 return this._themes;
176 },
177 /**
178 * A list of themes to be used for this element.
179 *
180 * @ignore Exclude from docs
181 * @param value An array of themes
182 */
183 set: function (value) {
184 this._themes = value;
185 },
186 enumerable: true,
187 configurable: true
188 });
189 /**
190 * Returns a list of themes that should be applied to this element. It could
191 * either be a list of themes set explicitly on this element, or system-wide.
192 *
193 * @return List of themes
194 */
195 BaseObject.prototype.getCurrentThemes = function () {
196 return this.themes || registry.themes;
197 };
198 /**
199 * Returns if this object has been already been disposed.
200 *
201 * @return Is disposed?
202 */
203 BaseObject.prototype.isDisposed = function () {
204 return this._disposed;
205 };
206 /**
207 * Destroys this object and all related data.
208 */
209 BaseObject.prototype.dispose = function () {
210 if (!this._disposed) {
211 this._disposed = true;
212 var a = this._disposers;
213 this._disposers = null;
214 while (a.length !== 0) {
215 var disposer = a.shift();
216 disposer.dispose();
217 }
218 // Clear cache
219 this.clearCache();
220 // remove from clones list
221 if (this.clonedFrom) {
222 this.clonedFrom.clones.removeValue(this);
223 }
224 var uid = this._uid;
225 if (uid != null) {
226 registry.map.removeKey(uid);
227 }
228 }
229 };
230 /**
231 * Adds an IDisposer, which will be disposed when this object is disposed.
232 *
233 * @param target Object to dispose
234 * @ignore Exclude from docs
235 */
236 BaseObject.prototype.addDisposer = function (target) {
237 this._disposers.push(target);
238 };
239 /**
240 * Disposes disposable object and removes it from `_disposers`.
241 *
242 * @param target Object to dispose
243 * @ignore Exclude from docs
244 */
245 BaseObject.prototype.removeDispose = function (target) {
246 //if(target){
247 if (!this._disposed) {
248 var index = $array.indexOf(this._disposers, target);
249 if (index > -1) {
250 this._disposers.splice(index, 1);
251 }
252 }
253 target.dispose();
254 //}
255 };
256 /**
257 * Makes a copy of this object and returns the clone. Try to avoid cloning complex objects like chart, create new instances if you need them.
258 *
259 * @param cloneId An id to use for clone (if not set a unique id will be generated)
260 * @returns Clone
261 */
262 BaseObject.prototype.clone = function (cloneId) {
263 if (!cloneId) {
264 cloneId = "clone-" + registry.getUniqueId();
265 }
266 var newObject = new this.constructor();
267 newObject.cloneId = cloneId;
268 newObject.copyFrom(this);
269 // add to clones list
270 // this.clones.push(newObject); // moved this to copyFrom
271 return newObject;
272 };
273 Object.defineProperty(BaseObject.prototype, "clones", {
274 /**
275 * Returns a collection of object's clones.
276 *
277 * @ignore Exclude from docs
278 * @return Clones
279 */
280 get: function () {
281 if (!this._clones) {
282 this._clones = new List();
283 }
284 return this._clones;
285 },
286 enumerable: true,
287 configurable: true
288 });
289 /**
290 * Copies all properties and related data from different element.
291 *
292 * @param object Source element
293 */
294 BaseObject.prototype.copyFrom = function (object) {
295 object.clones.push(this); // do not moveValue, as it is expensive! even if there will be several items in clones list, it's not that bad.
296 this.clonedFrom = object;
297 };
298 Object.defineProperty(BaseObject.prototype, "className", {
299 /**
300 * @ignore Exclude from docs
301 * @return Class name
302 */
303 get: function () {
304 return this._className;
305 },
306 /**
307 * Element's class name. (a class that was used to instantiate the element)
308 *
309 * @ignore Exclude from docs
310 * @param value Class name
311 */
312 set: function (value) {
313 this._className = value;
314 /*if (registry) {
315 registry.registeredClasses[value] = typeof this;
316 }*/
317 },
318 enumerable: true,
319 configurable: true
320 });
321 /**
322 * Caches value in object's cache.
323 *
324 * @ignore Exclude from docs
325 * @param key Key
326 * @param value Value
327 * @param ttl TTL in seconds
328 */
329 BaseObject.prototype.setCache = function (key, value, ttl) {
330 cache.set(this.uid, key, value, ttl);
331 };
332 /**
333 * Retrieves cached value.
334 *
335 * If optional second padarameter is specified, it will return that value
336 * if cache is not available or is expired.
337 *
338 * @ignore Exclude from docs
339 * @param key Key
340 * @param value Value to return if cache is not available
341 * @return Value
342 */
343 BaseObject.prototype.getCache = function (key, value) {
344 if (value === void 0) { value = undefined; }
345 return cache.get(this.uid, key, value);
346 };
347 /**
348 * Clears object's local cache.
349 *
350 * @ignore Exclude from docs
351 */
352 BaseObject.prototype.clearCache = function () {
353 cache.clear(this.uid);
354 };
355 /**
356 * Creates [[Disposer]] for `setTimeout` function call. This ensures that all
357 * timeouts created by the object will be cleared when object itself is
358 * disposed.
359 *
360 * @ignore Exclude from docs
361 * @param fn Callback function
362 * @param delay Timeout (ms)
363 * @return Disposer for timeout
364 */
365 BaseObject.prototype.setTimeout = function (fn, delay) {
366 var _this = this;
367 var id = setTimeout(function () {
368 _this.removeDispose(disposer);
369 fn();
370 }, delay);
371 var disposer = new Disposer(function () {
372 clearTimeout(id);
373 });
374 this._disposers.push(disposer);
375 return disposer;
376 };
377 /**
378 * Creates [[Disposer]] for `setInterval` function call. This ensures that all
379 * timeouts created by the object will be cleared when object itself is
380 * disposed.
381 *
382 * @ignore Exclude from docs
383 * @param fn Callback function
384 * @param delay Timeout (ms)
385 * @return Disposer for timeout
386 */
387 BaseObject.prototype.setInterval = function (fn, delay) {
388 var _this = this;
389 var id = setInterval(function () {
390 _this.removeDispose(disposer);
391 fn();
392 }, delay);
393 var disposer = new Disposer(function () {
394 clearTimeout(id);
395 });
396 this._disposers.push(disposer);
397 return disposer;
398 };
399 Object.defineProperty(BaseObject.prototype, "config", {
400 /**
401 * ==========================================================================
402 * JSON-BASED CONFIG PROCESSING
403 * ==========================================================================
404 * @hidden
405 */
406 /**
407 * Use this property to set JSON-based config. When set, triggers processing
408 * routine, which will go through all properties, and try to apply values,
409 * create instances, etc.
410 *
411 * Use this with caution, as it is a time-consuming process. It's used for
412 * initialchart setup only, not routine operations.
413 *
414 * @param json JSON config
415 */
416 set: function (config) {
417 try {
418 this.processConfig(config);
419 }
420 catch (e) {
421 /*if (this instanceof Sprite) {
422 this.raiseCriticalError(e);
423 }*/
424 this.raiseCriticalError(e);
425 }
426 },
427 enumerable: true,
428 configurable: true
429 });
430 /**
431 * Processes the JSON config.
432 *
433 * @param json JSON config
434 * @ignore Exclude from docs
435 */
436 BaseObject.prototype.processConfig = function (config) {
437 var _this = this;
438 if (!config) {
439 return;
440 }
441 // Get target
442 var target = this;
443 // Iterate through all of the items
444 $object.eachOrdered(config, function (configKey, value) {
445 var configValue = value;
446 // Is this a callback?
447 if (configKey == "callback" && typeof value == "function") {
448 value.call(target);
449 }
450 // Check if there's a property in target
451 if (_this.hasProperty(configKey)) {
452 var item_1;
453 // Do we have instructions to create an object?
454 // We create a new object if "type" key is set, but only if the
455 // target object is of different type.
456 if ($type.isObject(configValue)
457 && $type.hasValue(configValue["type"])
458 && (!$type.isObject(target[configKey])
459 || !$type.hasValue(target[configKey].className)
460 || configValue["forceCreate"]
461 || target[configKey].className != configValue["type"])
462 && !_this.asIs(configKey)) {
463 item_1 = _this.createClassInstance(configValue["type"]);
464 // Create new instance
465 if (item_1) {
466 target[configKey] = item_1;
467 }
468 else {
469 item_1 = target[configKey];
470 }
471 }
472 else {
473 // Get item from the object
474 item_1 = target[configKey];
475 }
476 /**
477 * It is...
478 * --------------------------------------------------------------------
479 */
480 if (item_1 instanceof Adapter) {
481 // ... an Adapter, try to add handlers to it
482 // ------------------------------------------------------------------
483 _this.processAdapters(item_1, configValue);
484 }
485 else if (item_1 instanceof EventDispatcher) {
486 // ... an EventDispatcher, try to add handlers to it
487 // ------------------------------------------------------------------
488 _this.processEvents(item_1, configValue);
489 }
490 else if (configKey == "locale" && $type.isString(configValue)) {
491 // ... a locale specified as string, e.g. "fr_FR"
492 // ------------------------------------------------------------------
493 if (window["am4lang_" + configValue]) {
494 target[configKey] = window["am4lang_" + configValue];
495 }
496 }
497 else if (configKey == "parent" && $type.isString(configValue)) {
498 // ... a parent referred via its it
499 // ------------------------------------------------------------------
500 var parent_1 = _this.map.getKey(configValue);
501 if (parent_1) {
502 target[configKey] = parent_1;
503 }
504 else {
505 _this.addDelayedMap("parent", configValue);
506 }
507 }
508 else if (_this.asIs(configKey)) {
509 // ... a special field, just set it to new value
510 // ------------------------------------------------------------------
511 // (no need to add each indvidual item)
512 target[configKey] = configValue;
513 }
514 else if (_this.asFunction(configKey) && $type.isString(configValue)) {
515 // ... a field indicating function name to look for in registry
516 // ------------------------------------------------------------------
517 if ($type.hasValue(registry.registeredClasses[configValue])) {
518 target[configKey] = registry.registeredClasses[configValue];
519 }
520 else {
521 throw Error("Invalid easing function: " + configValue);
522 }
523 }
524 else if (configValue instanceof BaseObject) {
525 // ... a BaseObject object, we just going to use it as it is
526 // ------------------------------------------------------------------
527 target[configKey] = configValue;
528 }
529 else if (item_1 instanceof BaseObject) {
530 // ... another child BaseObject
531 // ------------------------------------------------------------------
532 // Let's just pass in config part in and let itself deal with it
533 item_1.config = configValue;
534 }
535 else if (item_1 instanceof ListTemplate || item_1 instanceof OrderedListTemplate || item_1 instanceof SortedListTemplate) {
536 // ... a list with template
537 // ------------------------------------------------------------------
538 // Let's see what we can do with it
539 if ($type.isArray(configValue)) {
540 // It's an array.
541 // Create a list item for entry, or try to apply properties to an
542 // existing entry if possible and it is present.
543 if (item_1 instanceof ListTemplate) {
544 _this.processListTemplate(configValue, item_1);
545 }
546 else {
547 _this.processOrderedTemplate(configValue, item_1);
548 }
549 }
550 else if ($type.isObject(configValue)) {
551 // It's a single oject.
552 // Treat it as a template.
553 if (configValue instanceof BaseObject) {
554 // Item is already a BaseObject, no need to process it further
555 item_1.template = configValue;
556 }
557 else {
558 // Now let's find out if the whole object if a template, or we
559 // need to get it from `template` key
560 var templateValue = void 0;
561 if ($type.hasValue(configValue.template)) {
562 templateValue = configValue.template;
563 }
564 else {
565 templateValue = configValue;
566 }
567 if (item_1.template instanceof BaseObject) {
568 // Template is a BaseObject so we will just let its config
569 // deal with the configuration
570 item_1.template.config = templateValue;
571 }
572 else {
573 $object.each(templateValue, function (entryKey, entryValue) {
574 var listItem = item_1.template[entryKey];
575 if (listItem instanceof Adapter) {
576 _this.processAdapters(listItem, entryValue);
577 }
578 else if (listItem instanceof EventDispatcher) {
579 _this.processEvents(listItem, entryValue);
580 }
581 else if (listItem instanceof DictionaryTemplate) {
582 _this.processDictionaryTemplate(listItem, entryValue);
583 }
584 else if (item_1.template[entryKey] instanceof BaseObject) {
585 // Template is a BaseObject. Let it deal with its own config.
586 item_1.template[entryKey].config = entryValue;
587 }
588 else if ($type.isObject(entryValue) && $type.hasValue(entryValue["type"])) {
589 listItem = _this.createClassInstance(entryValue["type"]);
590 if (listItem) {
591 if (listItem instanceof BaseObject) {
592 listItem.config = entryValue;
593 }
594 item_1.template[entryKey] = listItem;
595 }
596 else {
597 item_1.template[entryKey] = entryValue;
598 }
599 }
600 else if (listItem instanceof List) {
601 // It's List, process it
602 _this.processList(entryValue, listItem);
603 }
604 else {
605 // Aything else. Just assing and be done with it.
606 item_1.template[entryKey] = _this.maybeColorOrPercent(entryValue);
607 }
608 });
609 }
610 // Check maybe there are `values` to insert
611 if ($type.hasValue(configValue.values)) {
612 if (item_1 instanceof ListTemplate) {
613 _this.processListTemplate(configValue.values, item_1);
614 }
615 else {
616 _this.processOrderedTemplate(configValue.values, item_1);
617 }
618 }
619 }
620 }
621 else {
622 // Something else?
623 // Not sure what to do with it on a list - ignore
624 }
625 }
626 else if (item_1 instanceof List) {
627 // ... a list
628 // ------------------------------------------------------------------
629 if (configKey == "children") {
630 _this.processList(configValue, item_1, _this);
631 }
632 else {
633 _this.processList(configValue, item_1);
634 }
635 }
636 else if (item_1 instanceof DictionaryTemplate) {
637 // ... a dictionary with template
638 // ------------------------------------------------------------------
639 _this.processDictionaryTemplate(item_1, configValue);
640 }
641 else if (item_1 instanceof Dictionary) {
642 // ... a dictionary
643 // ------------------------------------------------------------------
644 _this.processDictionary(item_1, configValue);
645 }
646 else if (item_1 instanceof Color || item_1 instanceof Percent) {
647 // ... it's a Color or Percent
648 // ------------------------------------------------------------------
649 target[configKey] = _this.maybeColorOrPercent(configValue);
650 }
651 else if ($type.isObject(item_1) && $type.isObject(configValue)) {
652 // ... a regular object
653 // ------------------------------------------------------------------
654 $object.copyAllProperties(configValue, item_1);
655 }
656 else {
657 // ... something else - probably a simple property or object
658 // ------------------------------------------------------------------
659 // Maybe convert to `Percent` or `Color`?
660 configValue = _this.maybeColorOrPercent(configValue);
661 // Assign
662 target[configKey] = configValue;
663 }
664 }
665 else if (!_this.isReserved(configKey)) {
666 // Doesn't have property set. But we're going to assume JSON config
667 // creator knows what he/she is doing and set it anyway.
668 target[configKey] = configValue;
669 }
670 }, this.configOrder);
671 // Any errors?
672 if (this.processingErrors.length) {
673 var errors = this.processingErrors.join("\n");
674 this._processingErrors = [];
675 throw Error(errors);
676 }
677 };
678 /**
679 * Tries to detect if value is color or percent and converts to proper object
680 * if necessary.
681 *
682 * Returns the same source value if no color/percent detected
683 *
684 * @param value Source value
685 * @return Converted value
686 */
687 BaseObject.prototype.maybeColorOrPercent = function (value) {
688 if ($type.isString(value)) {
689 if (value.match(/^[\-]?[0-9.]+\%$/)) {
690 return percent($type.toNumber(value));
691 }
692 else if (value.match(/^\#[0-9abcdef]{3,}$/i)) {
693 return color(value);
694 }
695 }
696 return value;
697 };
698 BaseObject.prototype.processAdapters = function (item, config) {
699 var _this = this;
700 if ($type.isArray(config)) {
701 $array.each(config, function (entry, index) {
702 item.add(entry.key, entry.callback, entry.priority || 0, _this);
703 });
704 }
705 else if ($type.isObject(config)) {
706 $object.each(config, function (key, entry) {
707 if (!item.has(key, entry)) {
708 item.add(key, entry);
709 }
710 });
711 }
712 };
713 BaseObject.prototype.processEvents = function (item, config) {
714 var _this = this;
715 if ($type.isArray(config)) {
716 $array.each(config, function (entry, index) {
717 item.on(entry.type, entry.callback, _this);
718 });
719 }
720 else if ($type.isObject(config)) {
721 $object.each(config, function (key, entry) {
722 if (!item.has(key, entry)) {
723 item.on(key, entry);
724 }
725 });
726 }
727 };
728 /**
729 * Processes JSON config for a [[DictionaryTemplate]] item.
730 *
731 * @todo Description
732 * @param item Item
733 * @param config Config
734 */
735 BaseObject.prototype.processDictionaryTemplate = function (item, config) {
736 // We can only process object
737 // Not sure what to do with other types - ignore
738 if ($type.isObject(config)) {
739 // Create an entry for each item, or override properties for
740 // existing one.
741 $object.each(config, function (entryKey, entryValue) {
742 var listItem;
743 // Get existing one, or create a new one
744 if (entryKey == "template") {
745 listItem = item.template;
746 }
747 else if (item.hasKey(entryKey)) {
748 listItem = item.getKey(entryKey);
749 }
750 else {
751 listItem = item.create(entryKey);
752 }
753 // Set data
754 if (listItem instanceof BaseObject) {
755 listItem.config = entryValue;
756 }
757 else if ($type.isObject(listItem) && $type.isObject(entryValue)) {
758 $object.copyAllProperties(entryValue, listItem);
759 }
760 else {
761 listItem.setKey(entryKey, entryValue);
762 }
763 });
764 }
765 };
766 /**
767 * Processes JSON config for a [[Dictionary]] item.
768 *
769 * @todo Description
770 * @param item Item
771 * @param config Config
772 */
773 BaseObject.prototype.processDictionary = function (item, config) {
774 // We can only process object
775 // Not sure what to do with other types - ignore
776 if ($type.isObject(config)) {
777 // Create an entry for each item, or override properties for
778 // existing one.
779 // @todo support for non-basic types
780 $object.each(config, function (entryKey, entryValue) {
781 item.setKey(entryKey, entryValue);
782 });
783 }
784 };
785 /**
786 * Processes [[ListTemplate]].
787 *
788 * @param configValue Config value
789 * @param item Item
790 */
791 BaseObject.prototype.processListTemplate = function (configValue, item) {
792 var _this = this;
793 $array.each(configValue, function (entry, index) {
794 var type = _this.getConfigEntryType(entry);
795 var listItem;
796 if (item.hasIndex(index) && !entry["forceCreate"]) {
797 listItem = item.getIndex(index);
798 }
799 else if (entry instanceof BaseObject) {
800 // Item is already a BaseObject, no need to process it further
801 item.push(entry);
802 return;
803 }
804 else if (type) {
805 listItem = item.create(type);
806 }
807 else {
808 listItem = item.create();
809 }
810 if (entry === listItem) {
811 // It's already the same item, do nothing
812 }
813 else {
814 if ($type.isObject(entry)) {
815 // If the list item is BaseObject, we just need to let it
816 // deal if its own config
817 if (listItem instanceof BaseObject) {
818 listItem.config = entry;
819 }
820 else if ($type.isObject(listItem) && $type.isObject(entry)) {
821 $object.copyAllProperties(entry, listItem);
822 }
823 else {
824 item.setIndex(item.indexOf(listItem), entry);
825 }
826 }
827 }
828 });
829 // Truncate the list if it contains less items than the config
830 // array
831 while (configValue.length > item.length) {
832 item.pop();
833 }
834 };
835 /**
836 * Processes [[OrdererListTemplate]] or [[SortedListTemplate]].
837 *
838 * @param configValue Config value
839 * @param item Item
840 */
841 BaseObject.prototype.processOrderedTemplate = function (configValue, item) {
842 var _this = this;
843 $array.each(configValue, function (entry, index) {
844 var type = _this.getConfigEntryType(entry);
845 var listItem;
846 if (type) {
847 listItem = item.create(type);
848 }
849 else {
850 listItem = item.create();
851 }
852 if ($type.isObject(entry)) {
853 // If the list item is BaseObject, we just need to let it
854 // deal if its own config
855 if (listItem instanceof BaseObject) {
856 listItem.config = entry;
857 }
858 else if ($type.isObject(listItem) && $type.isObject(entry)) {
859 $object.copyAllProperties(entry, listItem);
860 }
861 else {
862 item.insert(entry);
863 }
864 }
865 });
866 };
867 /**
868 * Processes [[List]].
869 *
870 * @param configValue Config value
871 * @param item Item
872 */
873 BaseObject.prototype.processList = function (configValue, item, parent) {
874 var _this = this;
875 // Convert to array if necessary
876 if (!$type.isArray(configValue)) {
877 configValue = [configValue];
878 }
879 // It's an array
880 // Create a list item for entry
881 var itemCount = item.length;
882 var extraCount = 0;
883 $array.each(configValue, function (entry, index) {
884 if ($type.isObject(entry)) {
885 // An object.
886 //
887 // Let's see if we can instantiate a class out of it, or we need
888 // to push it into list as it is.
889 //
890 // If there are items already at the specified index in the list,
891 // apply properties rather than create a new one.
892 var listItem = void 0;
893 if ((index < itemCount) && !entry["forceCreate"]) {
894 listItem = item.getIndex(index);
895 }
896 else if (entry instanceof BaseObject) {
897 // Item is already a BaseObject, no need to process it further
898 item.push(entry);
899 return;
900 }
901 else {
902 extraCount++;
903 listItem = _this.createEntryInstance(entry);
904 if (parent) {
905 listItem.parent = parent;
906 }
907 else {
908 item.push(listItem);
909 }
910 }
911 // If the list item is BaseObject, we just need to let it
912 // deal if its own config
913 if (listItem instanceof BaseObject) {
914 listItem.config = entry;
915 }
916 else if ($type.isObject(listItem) && $type.isObject(entry)) {
917 $object.copyAllProperties(entry, listItem);
918 }
919 }
920 else {
921 // Basic value.
922 // Just push it into list, or override existing value
923 if (item.hasIndex(index)) {
924 item.setIndex(index, entry);
925 }
926 else {
927 item.push(entry);
928 }
929 }
930 });
931 // Truncate the list if it contains less items than the config
932 // array
933 while (!parent && (configValue.length + extraCount) < item.length) {
934 item.pop();
935 }
936 };
937 /**
938 * This function is used to sort element's JSON config properties, so that
939 * some properties that absolutely need to be processed last, can be put at
940 * the end.
941 *
942 * @ignore Exclude from docs
943 * @param a Element 1
944 * @param b Element 2
945 * @return Sorting number
946 */
947 BaseObject.prototype.configOrder = function (a, b) {
948 if (a == b) {
949 return 0;
950 }
951 // Language must come first, so it's all set up when the rest of the
952 // elements are being instantiated
953 else if (a == "language") {
954 return -1;
955 }
956 else if (b == "language") {
957 return 1;
958 }
959 else {
960 return 0;
961 }
962 };
963 /**
964 * Checks if field should be just assigned as is, without any checking when
965 * processing JSON config.
966 *
967 * Extending functions can override this function to do their own checks.
968 *
969 * @param field Field name
970 * @return Assign as is?
971 */
972 BaseObject.prototype.asIs = function (field) {
973 return $array.indexOf(["locale"], field) != -1;
974 };
975 /**
976 * Checks if field needs to be converted to function, if it is specified
977 * as string.
978 *
979 * @param field Field name
980 * @return Assign as function?
981 */
982 BaseObject.prototype.asFunction = function (field) {
983 return false;
984 };
985 /**
986 * Creates a relevant class instance if such class definition exists.
987 *
988 * @ignore Exclude from docs
989 * @param className Class name
990 * @return Instance
991 */
992 BaseObject.prototype.createClassInstance = function (className) {
993 if ($type.hasValue(registry.registeredClasses[className])) {
994 return new registry.registeredClasses[className]();
995 }
996 else {
997 throw Error("Invalid type: \"" + className + "\".");
998 }
999 };
1000 /**
1001 * Creates a class instance for a config entry using it's type. (as set in
1002 * `type` property)
1003 *
1004 * @ignore Exclude from docs
1005 * @param config Config part
1006 * @return Instance
1007 */
1008 BaseObject.prototype.createEntryInstance = function (config) {
1009 var res;
1010 if ($type.hasValue(config["type"])) {
1011 res = this.createClassInstance(config["type"]);
1012 }
1013 if (!res) {
1014 return config;
1015 }
1016 return res;
1017 };
1018 /**
1019 * Determines config object type.
1020 *
1021 * @ignore Exclude from docs
1022 * @param config Config part
1023 * @return Type
1024 */
1025 BaseObject.prototype.getConfigEntryType = function (config) {
1026 if ($type.hasValue(config["type"])) {
1027 if ($type.hasValue(registry.registeredClasses[config["type"]])) {
1028 return registry.registeredClasses[config["type"]];
1029 }
1030 else {
1031 throw Error("Invalid type: \"" + config["type"] + "\".");
1032 }
1033 }
1034 return;
1035 };
1036 /**
1037 * Checks if this element has a property.
1038 *
1039 * @ignore Exclude from docs
1040 * @param prop Property name
1041 * @return Has property?
1042 */
1043 BaseObject.prototype.hasProperty = function (prop) {
1044 return prop in this ? true : false;
1045 };
1046 /**
1047 * Checkes whether JSON key is a reserved keyword.
1048 *
1049 * @param key Key
1050 * @return Reserved
1051 */
1052 BaseObject.prototype.isReserved = function (key) {
1053 return ["type", "forceCreate"].indexOf(key) !== -1;
1054 };
1055 Object.defineProperty(BaseObject.prototype, "processingErrors", {
1056 /**
1057 * A list of errors that happened during JSON processing.
1058 *
1059 * @return Errors
1060 */
1061 get: function () {
1062 if (!this._processingErrors) {
1063 this._processingErrors = [];
1064 }
1065 return this._processingErrors;
1066 },
1067 enumerable: true,
1068 configurable: true
1069 });
1070 return BaseObject;
1071}());
1072export { BaseObject };
1073;
1074/**
1075 * A version of [[BaseObject]] with events properties and methods.
1076 * Classes that use [[EventDispatcher]] should extend this instead of
1077 * [[BaseObject]] directly.
1078 */
1079var BaseObjectEvents = /** @class */ (function (_super) {
1080 __extends(BaseObjectEvents, _super);
1081 /**
1082 * Constructor
1083 */
1084 function BaseObjectEvents() {
1085 var _this = _super.call(this) || this;
1086 _this.className = "BaseObjectEvents";
1087 return _this;
1088 }
1089 Object.defineProperty(BaseObjectEvents.prototype, "events", {
1090 /**
1091 * An [[EventDispatcher]] instance
1092 */
1093 get: function () {
1094 if (!this._eventDispatcher) {
1095 this._eventDispatcher = new EventDispatcher();
1096 this._disposers.push(this._eventDispatcher);
1097 }
1098 return this._eventDispatcher;
1099 },
1100 enumerable: true,
1101 configurable: true
1102 });
1103 //public set events(value:EventDispatcher<AMEvent<this, this["_events"]>>){
1104 // this._eventDispatcher = value;
1105 //}
1106 /**
1107 * Dispatches an event using own event dispatcher. Will automatically
1108 * populate event data object with event type and target (this element).
1109 * It also checks if there are any handlers registered for this sepecific
1110 * event.
1111 *
1112 * @param eventType Event type (name)
1113 * @param data Data to pass into event handler(s)
1114 */
1115 BaseObjectEvents.prototype.dispatch = function (eventType, data) {
1116 // @todo Implement proper type check
1117 if (this._eventDispatcher) {
1118 if (this.events.isEnabled(eventType)) {
1119 if (data) {
1120 data.type = eventType;
1121 data.target = data.target || this;
1122 this.events.dispatch(eventType, {
1123 type: eventType,
1124 target: this
1125 });
1126 }
1127 else {
1128 this.events.dispatch(eventType, {
1129 type: eventType,
1130 target: this
1131 });
1132 }
1133 }
1134 }
1135 };
1136 /**
1137 * Works like `dispatch`, except event is triggered immediately, without
1138 * waiting for the next frame cycle.
1139 *
1140 * @param eventType Event type (name)
1141 * @param data Data to pass into event handler(s)
1142 */
1143 BaseObjectEvents.prototype.dispatchImmediately = function (eventType, data) {
1144 // @todo Implement proper type check
1145 if (this._eventDispatcher) {
1146 if (this.events.isEnabled(eventType)) {
1147 if (data) {
1148 data.type = eventType;
1149 data.target = data.target || this;
1150 this.events.dispatchImmediately(eventType, data);
1151 }
1152 else {
1153 this.events.dispatchImmediately(eventType, {
1154 type: eventType,
1155 target: this
1156 });
1157 }
1158 }
1159 }
1160 };
1161 /**
1162 * Copies all parameters from another [[Sprite]].
1163 *
1164 * @param source Source object
1165 */
1166 BaseObjectEvents.prototype.copyFrom = function (source) {
1167 _super.prototype.copyFrom.call(this, source);
1168 if (source._eventDispatcher) {
1169 this.events.copyFrom(source._eventDispatcher);
1170 }
1171 };
1172 return BaseObjectEvents;
1173}(BaseObject));
1174export { BaseObjectEvents };
1175//# sourceMappingURL=Base.js.map
\No newline at end of file