UNPKG

whs

Version:

Super-fast 3D framework for Web Applications & Games. Based on Three.js

250 lines (214 loc) 6.08 kB
import {extend, transformData} from '../utils/index'; import {ModuleSystem} from './ModuleSystem'; import {ModuleManager} from './ModuleManager'; import {ManagerError} from './errors'; /** * @class Component * @category core * @param {Object} [params] - The parameters object. * @param {Object} [instructions] - The instructions object. * @extends ModuleSystem * @memberof module:core */ class Component extends ModuleSystem { /** * Default values for parameters * @member {Object} module:core.Component#defaults * @static * @default { * modules: [], * manager: true * } */ static defaults = { modules: null, manager: true }; /** * Static instructions * @member {Object} module:core.Component#instructions * @static * @default {} */ static instructions = {}; /** * Array of promises that should be resolved before Component is ready. * @member {Array} module:core.Component#_wait * @private */ _wait = []; // Collection of promises; /** * Collection of `modules`. * @member {Array} module:core.Component#modules * @public */ modules = []; // Collection of modules; /** * Collection of `child` Components. * @member {Array} module:core.Component#children * @public */ children = []; // For keeping children components; constructor(params = {}, defaults = Component.defaults, instructions = Component.instructions) { super(); // Apply polyfilled parameters to .params; this.params = extend(transformData(params, instructions), defaults); if (this.params.manager) this.manager = new ModuleManager(this); this.modules = this.params.modules; this.integrateModules(); } /** * @method wait * @instance * @description Wait for a promise. * @param {Promise} [promise] - The promise that should be added to a queue. * @return {Promise} Promise that is resolved when all promises completed. * @memberof module:core.Component */ wait(promise) { if (promise) this._wait.push(promise); return Promise.all(this._wait); } /** * @method defer * @instance * @description Execute `func` (Callback) when Component is ready. * @param {Function} func - Callback. * @memberof module:core.Component */ defer(func) { if (this.isDeffered) this.wait().then(() => func(this)); else func(this); } // PARAMETERS /** * @method updateParams * @instance * @description Updates parameters of the Component. * @return {Object} Params of this Component * @memberof module:core.Component */ updateParams(params = {}) { this.params = extend(params, this.params); return this.params; } // COPYING & CLONING /** * @method clone * @instance * @description Clone this component * @return {object} a cloned component with all its source component' params copied. * @memberof module:core.Component */ clone() { return new this.constructor(this.params).copy(this); } /** * @method copy * @instance * @description Copy source native and integrate `modules` to it. * @param {Component} source - Source component that is used for `copy()` action. * @param {Function} [customize] - Callback executed before modules integration process. * @return {this} Component * @memberof module:core.Component */ copy(source, customize) { this.params = {...source.params}; if (source.native) this.native = source.native.clone(source.params); if (customize) customize(); this.integrateModules(source); return this; } /** * @method add * @instance * @description Add a child `Component`. * @param {Component} object - Component that should be added as a `child`. * @return {Promise} Resolved when action is done. * @memberof module:core.Component */ add(object) { object.parent = this; return new Promise((resolve, reject) => { this.defer(() => { object.defer(() => { const {native} = object; if (!native) reject(); const addPromise = this.applyBridge({onAdd: object}).onAdd; const resolver = () => { this.native.add(native); this.children.push(object); resolve(object); }; if (addPromise instanceof Promise) addPromise.then(resolver); else resolver(); }); }); }); } /** * @method remove * @instance * @description Remove a child `Component`. * @param {Component} object - Component that should be a **child** of this Component. * @memberof module:core.Component */ remove(object) { object.parent = null; this.native.remove(object.native); } /** * @method addTo * @instance * @description Adds `this` Component to specified `App`/`Component`. * @param {Component} object - Component that will be a parent of `this`. * @memberof module:core.Component */ addTo(object) { return object.add(this); } get(key) { return this.manager.get(key); } use(key) { return this.manager.use(key); } /** * Returns whether the object is `async` (`wait` promises are more than `0`). * @member {Boolean} module:core.Component#isDeffered */ get isDeffered() { return this._wait.length > 0; } /** * Returns the `ModuleManager` used for this component. * @member {ModuleManager} module:core.Component#manager * @throws {ManagerError} */ get manager() { if (this._manager) return this._manager; throw new ManagerError( 'Component', `ModuleManager is not used in this component. 'manager' parameter should be set as 'true'`, this ); } set manager(manager) { this._manager = manager; } /** * Returns the `native` object used for this component. * @member {Object} module:core.Component#native */ get native() { return this._native; } set native(mesh) { this._native = mesh; this._native.component = this; return this._native; } } export { Component };