binding.js

import Core from "./core.js"
import EventListener from "./event-listener.js"
import Observable from "./observable.js"

/**
 * @global
 */
class Binding {

	/**
	 * @param {object} properties
	 * @param {EventListener} [eventListener=new EventListener(new Observable())]
	 */
	constructor(properties, eventListener = new EventListener(new Observable())) {
		this._identifier = {}
		this._properties = { ...properties }
		this._parent = null
		this._root = null
		this._model = null
		this._children = []
		this._listeners = []
		this._eventListener = eventListener
	}

	/**
	 * @readonly
	 * @type {object}
	 */
	get identifier() {
		return this._identifier
	}

	/**
	 * @readonly
	 * @type {object}
	 */
	get properties() {
		return this._properties
	}

	/**
	 * @readonly
	 * @type {Node}
	 */
	get root() {
		return this._root
	}

	/**
	 * @readonly
	 * @type {object}
	 */
	get model() {
		return this._model
	}

	/**
	 * @readonly
	 * @type {EventListener}
	 */
	get eventListener() {
		return this._eventListener
	}

	/**
	 * @param {string}   eventName
	 * @param {Function} callback
	 * @param {boolean}  [unshift=false]
	 * @returns {Listener}
	 * @example binding.listen(observable, "myEvent", message => console.log(message))
	 */
	listen(observable, eventName, callback, unshift = false) {
		const listener = observable.listen(eventName, callback, unshift)
		if(unshift) {
			this._listeners.unshift(listener)
		} else {
			this._listeners.push(listener)
		}
		return listener
	}

	/**
	 * @param   {object}  model
	 * @param   {object}  properties
	 * @param   {Element} [properties.parentNode=this.root]
	 * @param   {Binding} properties.binding
	 * @param   {Method}  [properties.method=Core.METHOD.APPEND_CHILD]
	 * @example binding.run(Model, { binding: new Binding() })
	 */
	run(model, properties) {
		properties.binding._parent = this
		this._children.push(properties.binding)
		properties.binding._properties = {
			...this.properties,
			...properties.binding.properties
		}
		Core.run(model, { parentNode: this.root, ...properties })
	}

	remove() {
		const listeners = this._listeners.slice()
		for(const listener of listeners) {
			listener.remove()
		}
		const children = this._children.slice()
		for(const child of children) {
			child.remove()
		}
		if(this._parent !== null) {
			this._parent._children = this._parent._children.filter(child => child !== this)
		}
		this.root.remove()
	}

	/**
		* @abstract
		*/
	onCreated() {

	}

	/**
		* @abstract
		*/
	async onRendered() {

	}

}

export default Binding