var Bootstrapper = function()

in lib/Bootstrapper.js [50:309]


var Bootstrapper = function () {

	/**
  * Constructor
  */
	function Bootstrapper() {
		_classCallCheck(this, Bootstrapper);

		// Sanity check
		if (!window || !window && !window.document) {
			throw new Error('React Habitat requires a window but cannot see one :(');
		}

		/**
   * The DOM component selector
   * @type {string}
   */
		this.componentSelector = DEFAULT_HABITAT_SELECTOR;

		/**
   * The container
   * Slashes to avoid super collisions
   * @type {Container|null}
   * @private
   */
		this.__container__ = null;
	}

	/**
  * Apply the container to nodes
  * @param {array}		nodes				- The elements to parse
  * @param {function}	[cb=null]			- Optional callback
  * @private
  */


	_createClass(Bootstrapper, [{
		key: '_apply',
		value: function _apply(nodes) {
			var _this = this;

			var cb = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;

			// const factory = container.domFactory();
			// const id = container.id();
			var resolveQueue = [];

			// Iterate over component elements in the dom

			var _loop = function _loop(i) {
				var ele = nodes[i];

				// Ignore elements that have already been connected
				if (_Habitat2.default.hasHabitat(ele)) {
					return 'continue';
				}

				// Resolve components using promises
				var componentName = ele.getAttribute(_this.componentSelector);
				resolveQueue.push(_this.__container__.resolve(componentName, _this).then(function (registration) {
					// This is an expensive operation so only do on non prod builds
					if (process.env.NODE_ENV !== 'production') {
						if (ele.querySelector('[' + _this.componentSelector + ']')) {
							_Logger2.default.warn('RHW08', 'Component should not contain any nested components.', ele);
						}
					}

					// Generate props
					var props = _Habitat2.default.parseProps(ele);
					if (registration.meta.defaultProps) {
						props = Object.assign({}, registration.meta.defaultProps, props);
					}

					// Options
					var options = registration.meta.options || {};

					// Inject the component
					_this.__container__.factory.inject(registration.component, props, _Habitat2.default.create(ele, _this.__container__.id, options));
				}).catch(function (err) {
					_Logger2.default.error('RHW01', 'Cannot resolve component "' + componentName + '" for element.', err, ele);
				}));
			};

			for (var i = 0; i < nodes.length; ++i) {
				var _ret = _loop(i);

				if (_ret === 'continue') continue;
			}

			// Trigger callback when all promises are finished
			// regardless if some fail
			Promise.all(resolveQueue.map(function (p) {
				return p.catch(function (e) {
					return e;
				});
			})).then(function () {
				_callback(cb);
			}).catch(function (err) {
				// We should never get here.. if we do this is a bug
				throw err;
			});
		}

		/**
   * Set the container
   * @param {object}    container   - The container
   * @param {function}  [cb=null]   - Optional callback
   */

	}, {
		key: 'setContainer',
		value: function setContainer(container) {
			var _this2 = this;

			var cb = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;

			if (this.__container__ !== null) {
				_Logger2.default.error('RHW02', 'A container is already set. ' + 'Please call dispose() before assigning a new one.');
				return;
			}

			if (!container.factory || typeof container.factory.inject !== 'function' || typeof container.factory.dispose !== 'function') {
				_Logger2.default.error('RHE10', 'Incompatible factory');
				return;
			}

			// Set the container
			this.__container__ = container;

			// Wire up the components from the container
			this.update(null, function () {
				_callback(cb, _this2);
			});
		}

		/**
   * The container
   * @returns {Container}
   */

	}, {
		key: 'update',


		/**
  * Apply the container to an updated dom structure
  * @param {node}		node		- Target node to parse or null for entire document body
  * @param {function}		[cb=null]	- Optional callback
  */
		value: function update(node) {
			var _this3 = this;

			var cb = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;

			// Check if we have a container before attempting an update
			if (!this.__container__) {
				_callback(cb);
				return;
			}

			var target = node || window.document.body;
			var query = target.querySelectorAll('[' + this.componentSelector + ']');

			if (!query.length) {
				// Nothing to update
				return;
			}

			// Lifecycle event
			// Hook to allow developers to cancel operation
			if (typeof this.shouldUpdate === 'function') {
				if (this.shouldUpdate(target, query) === false) {
					_callback(cb, this);
					return;
				}
			}

			// Lifecycle event
			if (typeof this.willUpdate === 'function') {
				this.willUpdate(target, query);
			}

			this._apply(query, function () {
				// Lifecycle event
				if (typeof _this3.didUpdate === 'function') {
					_this3.didUpdate(target);
				}

				_callback(cb, _this3);
			});
		}

		/**
   * Unmount all habitat instances for the container
   * @param {function}	[cb=null]	- Optional callback
   */

	}, {
		key: 'unmountHabitats',
		value: function unmountHabitats() {
			var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;


			// Lifecycle event
			if (typeof this.willUnmountHabitats === 'function') {
				this.willUnmountHabitats();
			}

			// Get open habitats for this container
			var habitats = _Habitat2.default.listHabitats(this.__container__.id);

			// Clean up
			for (var i = 0; i < habitats.length; ++i) {
				this.__container__.factory.dispose(habitats[i]);
				_Habitat2.default.destroy(habitats[i]);
			}

			// Lifecycle event
			if (typeof this.didUnmountHabitats === 'function') {
				this.didUnmountHabitats();
			}

			// Handle callback
			_callback(cb, this);
		}

		/**
   * Dispose the container and destroy habitat instances
   * @param {function}	[cb=null]	- Optional callback
   */

	}, {
		key: 'dispose',
		value: function dispose() {
			var _this4 = this;

			var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;

			this.unmountHabitats(function () {
				// Reset and release
				_this4.__container__ = null;

				// Lifecycle event
				if (typeof _this4.didDispose === 'function') {
					_this4.didDispose();
				}

				// Handle callback
				_callback(cb, _this4);
			});
		}
	}, {
		key: 'container',
		get: function get() {
			return this.__container__;
		}
	}]);

	return Bootstrapper;
}();