-
Notifications
You must be signed in to change notification settings - Fork 12
/
link-manager.ts
154 lines (129 loc) · 4.67 KB
/
link-manager.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { addListener, removeListener } from '@ember/object/events';
import Service, { inject as service } from '@ember/service';
import { BEHAVIOR, prevent } from '../-behavior';
// import { getOwner } from '@ember/owner';
import { getOwner } from '../-owner';
import Link from '../link';
import type { Behavior } from '../-behavior';
import type { RouteModel } from '../-models';
import type { LinkParams } from '../-params';
import type Owner from '@ember/owner';
import type RouteInfo from '@ember/routing/route-info';
import type RouterService from '@ember/routing/router-service';
import type Transition from '@ember/routing/transition';
interface RouterServiceWithRecognize extends RouterService {
recognize(url: string): RouteInfo;
}
export default class LinkManagerService extends Service {
@tracked private internalCurrentTransitionStack?: Transition[];
/**
* The `RouterService` instance to be used by the generated `Link` instances.
*/
@service('router') readonly router!: RouterServiceWithRecognize;
protected [BEHAVIOR]: Behavior = {
open: 'transition',
prevent
};
/**
* Configure the default behavior of _all_ links.
*
* This can be overwritten at a particular link instance
*/
configureBehavior(behavior: Partial<Behavior>) {
this[BEHAVIOR] = {
...this[BEHAVIOR],
...behavior
};
}
/**
* Whether the router has been initialized.
* This will be `false` in render tests.
*
* @see https://github.com/buschtoens/ember-link/issues/126
*/
get isRouterInitialized() {
// Ideally we would use the public `router` service here, but accessing
// the `currentURL` on that service automatically starts the routing layer
// as a side-effect, which is not our intention here. Once or if Ember.js
// provides a flag on the `router` service to figure out if routing was
// already initialized we should switch back to the public service instead.
//
// Inspiration for this workaround was taken from the `currentURL()` test
// helper (see https://github.com/emberjs/ember-test-helpers/blob/v2.1.4/addon-test-support/@ember/test-helpers/setup-application-context.ts#L180)
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line ember/no-private-routing-service
return Boolean(getOwner(this).lookup('router:main').currentURL);
}
/**
* The currently active `Transition` objects.
*/
get currentTransitionStack() {
return this.internalCurrentTransitionStack;
}
/**
* Creates a `Link` instance.
*/
createLink(linkParams: LinkParams): Link {
return new Link(this, linkParams);
}
/**
* Deserializes the `LinkParams` to be passed to `createLink` / `createUILink`
* from a URL.
*
* If the URL cannot be recognized by the router, an error is thrown.
*/
getLinkParamsFromURL(url: string): LinkParams {
const routeInfo = this.router.recognize(url);
return LinkManagerService.getLinkParamsFromRouteInfo(routeInfo);
}
/**
* Converts a `RouteInfo` object into `LinkParams`.
*/
static getLinkParamsFromRouteInfo(routeInfo: RouteInfo): LinkParams {
const models = routeInfo.paramNames.map((name) => routeInfo.params?.[name]) as RouteModel[];
return {
route: routeInfo.name,
query: routeInfo.queryParams,
models
};
}
constructor(owner?: Owner) {
super(owner);
// Ignore `Argument of type '"routeWillChange"' is not assignable to parameter of type ...`
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
addListener(this.router, 'routeWillChange', this.handleRouteWillChange);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
addListener(this.router, 'routeDidChange', this.handleRouteDidChange);
}
willDestroy() {
super.willDestroy();
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
removeListener(this.router, 'routeWillChange', this.handleRouteWillChange);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
removeListener(this.router, 'routeDidChange', this.handleRouteDidChange);
}
@action
handleRouteWillChange(transition: Transition) {
this.internalCurrentTransitionStack = [
...(this.internalCurrentTransitionStack || []),
transition
];
}
@action
handleRouteDidChange() {
this.internalCurrentTransitionStack = undefined;
}
}
declare module '@ember/service' {
interface Registry {
// eslint-disable-next-line @typescript-eslint/naming-convention
'link-manager': LinkManagerService;
}
}