consul/ui/packages/consul-ui/app/components/outlet/index.js

142 lines
3.1 KiB
JavaScript

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;
}
}
class Outlets {
constructor() {
this.map = new Map();
}
sort() {
this.sorted = [...this.map.keys()];
this.sorted.sort((a, b) => {
const al = a.split('.').length;
const bl = b.split('.').length;
switch (true) {
case al > bl:
return -1;
case al < bl:
return 1;
default:
return 0;
}
});
}
set(name, value) {
this.map.set(name, value);
this.sort();
}
get(name) {
return this.map.get(name);
}
delete(name) {
this.map.delete(name);
this.sort();
}
keys() {
return this.sorted;
}
}
const outlets = new Outlets();
export default class Outlet extends Component {
@service('router') router;
@service('dom') dom;
@tracked route;
@tracked state;
@tracked previousState;
constructor() {
super(...arguments);
if (this.args.name === 'application') {
this.setAppState('loading');
this.setAppRoute(this.router.currentRouteName);
}
}
setAppRoute(name) {
const nspace = 'nspace.';
if (name.startsWith(nspace)) {
name = name.substr(nspace.length);
}
if (name !== 'loading') {
const doc = this.dom.root();
if (doc.classList.contains('ember-loading')) {
doc.classList.remove('ember-loading');
}
doc.dataset.route = name;
this.setAppState('idle');
}
}
setAppState(state) {
this.dom.root().dataset.state = state;
}
setOutletRoutes(route) {
const keys = [...outlets.keys()];
const pos = keys.indexOf(this.name);
const key = pos + 1;
const parent = outlets.get(keys[key]);
parent.route = this.args.name;
this.route = route;
}
@action
startLoad(transition) {
const keys = [...outlets.keys()];
const outlet =
keys.find(item => {
return transition.to.name.indexOf(item) !== -1;
}) || 'application';
if (this.args.name === outlet) {
this.previousState = this.state;
this.state = new State('loading');
}
if (this.args.name === 'application') {
this.setAppState('loading');
}
}
@action
endLoad(transition) {
if (this.state.matches('loading')) {
this.setOutletRoutes(transition.to.name);
this.previousState = this.state;
this.state = new State('idle');
}
if (this.args.name === 'application') {
this.setAppRoute(this.router.currentRouteName);
}
}
@action
connect() {
outlets.set(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() {
outlets.delete(this.args.name);
this.router.off('routeWillChange', this.startLoad);
this.router.off('routeDidChange', this.endLoad);
}
}