import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; import { inject as service } from '@ember/service'; class State { constructor(name) { this.name = name; } matches(match) { return this.name === match; } } export default class Outlet extends Component { @service('routlet') routlet; @service('router') router; @tracked element; @tracked routeName; @tracked state; @tracked previousState; @tracked endTransition; get model() { return this.args.model || {}; } setAppRoute(name) { if (name !== 'loading') { const doc = this.element.ownerDocument.documentElement; if (doc.classList.contains('ember-loading')) { doc.classList.remove('ember-loading'); } doc.dataset.route = name; this.setAppState('idle'); } } setAppState(state) { const doc = this.element.ownerDocument.documentElement; doc.dataset.state = state; } @action attributeChanged(prop, value) { switch (prop) { case 'element': this.element = value; if (this.args.name === 'application') { this.setAppState('loading'); this.setAppRoute(this.router.currentRouteName); } break; } } @action transitionEnd($el) { if (typeof this.endTransition === 'function') { this.endTransition(); } } @action startLoad(transition) { const outlet = this.routlet.findOutlet(transition.to.name) || 'application'; if (this.args.name === outlet) { this.previousState = this.state; this.state = new State('loading'); this.endTransition = this.routlet.transition(); // if we have no transition-duration set immediately end the transition const duration = window .getComputedStyle(this.element) .getPropertyValue('transition-duration'); if (parseFloat(duration) === 0) { this.endTransition(); } } if (this.args.name === 'application') { this.setAppState('loading'); } } @action endLoad(transition) { if (this.state.matches('loading')) { this.previousState = this.state; this.state = new State('idle'); } if (this.args.name === 'application') { this.setAppRoute(this.router.currentRouteName); } } @action connect() { this.routlet.addOutlet(this.args.name, this); this.previousState = this.state = new State('idle'); this.router.on('routeWillChange', this.startLoad); this.router.on('routeDidChange', this.endLoad); } @action disconnect() { this.routlet.removeOutlet(this.args.name); this.router.off('routeWillChange', this.startLoad); this.router.off('routeDidChange', this.endLoad); } }