blob: f3e39ade2829bc4ec5de05b2a4c75c858f707d42 (
plain)
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
|
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Connects multiple Data Sources with multiple View Models.
* Aggregator owns Data Sources.
* Aggregator weakly refers to View Models.
*/
export class Aggregator {
#sources = [];
#attachedViewModels = [];
attachViewModel(viewModel) {
// Weak reference the View Model so we do not keep it in memory forever
this.#attachedViewModels.push(new WeakRef(viewModel));
}
detachViewModel(viewModel) {
for (let i = this.#attachedViewModels.length - 1; i >= 0; i--) {
const knownViewModel = this.#attachedViewModels[i].deref();
if (viewModel == knownViewModel || !knownViewModel) {
this.#attachedViewModels.splice(i, 1);
}
}
}
/**
* Run action on each of the alive attached view models.
* Remove dead consumers.
*
* @param {Function} action to perform on each alive consumer
*/
forEachViewModel(action) {
for (let i = this.#attachedViewModels.length - 1; i >= 0; i--) {
const viewModel = this.#attachedViewModels[i].deref();
if (viewModel) {
action(viewModel);
} else {
this.#attachedViewModels.splice(i, 1);
}
}
}
*enumerateLines(searchText) {
for (let source of this.#sources) {
yield* source.enumerateLines(searchText);
}
}
/**
*
* @param {Function} createSourceFn (aggregatorApi) used to create Data Source.
* aggregatorApi is the way for Data Source to push data
* to the Aggregator.
*/
addSource(createSourceFn) {
const api = this.#apiForDataSource();
const source = createSourceFn(api);
this.#sources.push(source);
}
callFunction(dataSource, functionName) {
const source = this.#sources.find(
source => source.constructor.name === dataSource
);
if (source && source[functionName]) {
source[functionName]();
}
}
/**
* Exposes interface for a datasource to communicate with Aggregator.
*/
#apiForDataSource() {
const aggregator = this;
return {
refreshSingleLineOnScreen(line) {
aggregator.forEachViewModel(vm => vm.refreshSingleLineOnScreen(line));
},
refreshAllLinesOnScreen() {
aggregator.forEachViewModel(vm => vm.refreshAllLinesOnScreen());
},
setLayout(layout) {
aggregator.forEachViewModel(vm => vm.setLayout(layout));
},
};
}
}
|