model/router.event.js

import { EventListener } from "domodel"
import Router from "../object/router.js"
import View from "../object/view.js"
import Match from "../object/match.js"
import Link from "../object/link.js"

/**
 * @global
 */
class RouterEventListener extends EventListener {

	/**
	 * @event RouterEventListener#navigate
	 * @property {Link} link
	 * @example router.emit("navigate", new Link("/path"))
	 */
	navigate(link) {
		let path = link.path
		if(this.properties.router.type === Router.TYPE.HASH) {
			path = `#${link.path}`
		}
		this.root.ownerDocument.defaultView.history.pushState({}, null, `${this.properties.router.basePath}${path}`)
		this.properties.router.emit("browse", link)
	}

	/**
	 * @event RouterEventListener#browse
	 * @property {Link} link
	 * @example router.emit("browse", new Link("/path"))
	 */
	browse(link) {
		const match = this.properties.router.match(link.path)
		if(match) {
			if(match.route.middleware && match.route.middleware(this.properties)) {
				return
			}
			this.properties.router.emit("routeSet", { match, link })
		} else {
			this.properties.router.emit("routeSet", { match: new Match(this.properties.router.errorRoute), link: new Link(link.path, { path: link.path }) })
		}
	}

	/**
	 * @event RouterEventListener#routeSet
	 * @property {object} data
	 * @property {Match}  data.match
	 * @property {Link}   data.link
	 * @example router.emit("routeSet", { match: new Match(...), link: new Link(...) })
	 */
	routeSet(data) {
		const { match, link } = data
		if(this.properties.router.view !== null) {
			if(this.layoutBinding) {
				this.layoutBinding.remove()
				this._layoutBinding = null
			} else {
				this.properties.router.view.binding.remove()
			}
		}
		this.properties.router._path = link.path
		this.properties.router._view = new View(match.parameters)
		this.properties.router.view.binding = new match.route.model.binding({ ...this.properties, ...match.route.model.properties, ...link.properties })
		let model = match.route.model.definition({ ...this.properties, ...match.route.model.properties, ...link.properties })
		let layoutBinding = this
		if(match.route.layout) {
			layoutBinding = new match.route.layout.binding(match.route.layout.properties)
			this.run(match.route.layout.definition, { binding: layoutBinding })
		} else if(this.properties.router.defaultLayout) {
			layoutBinding = new this.properties.router.defaultLayout.binding(this.properties.router.defaultLayout.properties)
			this.run(this.properties.router.defaultLayout.definition, { binding: layoutBinding })
		}
		if(layoutBinding !== this) {
			this._layoutBinding = layoutBinding
		}
		layoutBinding.run(model, { parentNode: layoutBinding.identifier.view, binding: this.properties.router.view.binding })
	}

}

export default RouterEventListener