-
Notifications
You must be signed in to change notification settings - Fork 443
Expand file tree
/
Copy pathrouter.ts
More file actions
129 lines (105 loc) · 3.72 KB
/
router.ts
File metadata and controls
129 lines (105 loc) · 3.72 KB
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
import { Application } from "./application"
import { Context } from "./context"
import { Definition } from "./definition"
import { Module } from "./module"
import { Multimap } from "../multimap"
import { Scope } from "./scope"
import { ScopeObserver, ScopeObserverDelegate } from "./scope_observer"
export class Router implements ScopeObserverDelegate {
readonly application: Application
private scopeObserver: ScopeObserver
private scopesByIdentifier: Multimap<string, Scope>
private modulesByIdentifier: Map<string, Module>
constructor(application: Application) {
this.application = application
this.scopeObserver = new ScopeObserver(this.element, this.schema, this)
this.scopesByIdentifier = new Multimap()
this.modulesByIdentifier = new Map()
}
get element() {
return this.application.element
}
get schema() {
return this.application.schema
}
get logger() {
return this.application.logger
}
get controllerAttribute(): string {
return this.schema.controllerAttribute
}
get modules() {
return Array.from(this.modulesByIdentifier.values())
}
get contexts() {
return this.modules.reduce((contexts, module) => contexts.concat(module.contexts), [] as Context[])
}
start() {
this.scopeObserver.start()
}
stop() {
this.scopeObserver.stop()
}
loadDefinition(definition: Definition) {
this.unloadIdentifier(definition.identifier)
const module = new Module(this.application, definition)
this.connectModule(module)
const afterLoad = (definition.controllerConstructor as any).afterLoad
if (afterLoad) {
afterLoad.call(definition.controllerConstructor, definition.identifier, this.application)
}
}
unloadIdentifier(identifier: string) {
const module = this.modulesByIdentifier.get(identifier)
if (module) {
this.disconnectModule(module)
}
}
getContextForElementAndIdentifier(element: Element, identifier: string) {
const module = this.modulesByIdentifier.get(identifier)
if (module) {
return module.contexts.find((context) => context.element == element)
}
}
proposeToConnectScopeForElementAndIdentifier(element: Element, identifier: string) {
const scope = this.scopeObserver.parseValueForElementAndIdentifier(element, identifier)
if (scope) {
this.scopeConnected(scope)
} else {
console.error(`Couldn't find or create scope for identifier: "${identifier}" and element:`, element)
}
}
// Error handler delegate
handleError(error: Error, message: string, detail: any) {
this.application.handleError(error, message, detail)
}
// Scope observer delegate
createScopeForElementAndIdentifier(element: Element, identifier: string) {
return new Scope(this.schema, element, identifier, this.logger)
}
scopeConnected(scope: Scope) {
this.scopesByIdentifier.add(scope.identifier, scope)
const module = this.modulesByIdentifier.get(scope.identifier)
if (module) {
module.connectContextForScope(scope)
}
}
scopeDisconnected(scope: Scope) {
this.scopesByIdentifier.delete(scope.identifier, scope)
const module = this.modulesByIdentifier.get(scope.identifier)
if (module) {
module.disconnectContextForScope(scope)
}
}
// Modules
private connectModule(module: Module) {
this.modulesByIdentifier.set(module.identifier, module)
const scopes = this.scopesByIdentifier.getValuesForKey(module.identifier)
scopes.forEach((scope) => module.connectContextForScope(scope))
}
private disconnectModule(module: Module) {
this.modulesByIdentifier.delete(module.identifier)
const scopes = this.scopesByIdentifier.getValuesForKey(module.identifier)
scopes.forEach((scope) => module.disconnectContextForScope(scope))
}
}