1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | import { interfaces, Container } from 'inversify';
|
18 | import { TreeWidget, TreeProps, defaultTreeProps } from './tree-widget';
|
19 | import { TreeModelImpl, TreeModel } from './tree-model';
|
20 | import { TreeImpl, Tree } from './tree';
|
21 | import { TreeSelectionService } from './tree-selection';
|
22 | import { TreeSelectionServiceImpl } from './tree-selection-impl';
|
23 | import { TreeExpansionService, TreeExpansionServiceImpl } from './tree-expansion';
|
24 | import { TreeNavigationService } from './tree-navigation';
|
25 | import { TreeDecoratorService, NoopTreeDecoratorService } from './tree-decorator';
|
26 | import { TreeSearch } from './tree-search';
|
27 | import { FuzzySearch } from './fuzzy-search';
|
28 | import { SearchBox, SearchBoxFactory } from './search-box';
|
29 | import { SearchBoxDebounce } from './search-box-debounce';
|
30 | import { TreeFocusService, TreeFocusServiceImpl } from './tree-focus-service';
|
31 |
|
32 | export function isTreeServices(candidate?: Partial<TreeProps> | Partial<TreeContainerProps>): candidate is TreeContainerProps {
|
33 | if (candidate) {
|
34 | const maybeServices = candidate as TreeContainerProps;
|
35 | for (const key of Object.keys(maybeServices)) {
|
36 |
|
37 | if (key === 'search' && typeof maybeServices[key] === 'boolean') {
|
38 | return false;
|
39 | }
|
40 | if (key in defaultImplementations) {
|
41 | return true;
|
42 | }
|
43 | }
|
44 | }
|
45 | return false;
|
46 | }
|
47 |
|
48 | export function createTreeContainer(parent: interfaces.Container, props?: Partial<TreeContainerProps>): Container;
|
49 |
|
50 |
|
51 |
|
52 |
|
53 | export function createTreeContainer(parent: interfaces.Container, props?: Partial<TreeProps>): Container;
|
54 | export function createTreeContainer(parent: interfaces.Container, props?: Partial<TreeProps> | Partial<TreeContainerProps>): Container {
|
55 | const child = new Container({ defaultScope: 'Singleton' });
|
56 | child.parent = parent;
|
57 | const overrideServices: Partial<TreeContainerProps> = isTreeServices(props) ? props : { props: props as Partial<TreeProps> | undefined };
|
58 | for (const key of Object.keys(serviceIdentifiers) as (keyof TreeIdentifiers)[]) {
|
59 | if (key === 'props') {
|
60 | const { service, identifier } = getServiceAndIdentifier(key, overrideServices);
|
61 | child.bind(identifier).toConstantValue({
|
62 | ...defaultImplementations.props,
|
63 | ...service
|
64 | });
|
65 | } else if (key === 'searchBoxFactory') {
|
66 | const { service, identifier } = getServiceAndIdentifier(key, overrideServices);
|
67 | child.bind(identifier).toFactory(context => service(context));
|
68 | } else {
|
69 | const { service, identifier } = getServiceAndIdentifier(key, overrideServices);
|
70 | child.bind(service).toSelf().inSingletonScope();
|
71 | if (identifier !== service) {
|
72 | child.bind(identifier as interfaces.ServiceIdentifier<typeof service>).toService(service);
|
73 | }
|
74 | }
|
75 | }
|
76 | return child;
|
77 | }
|
78 |
|
79 | function getServiceAndIdentifier<Key extends keyof TreeIdentifiers>(
|
80 | key: Key, overrides: Partial<TreeContainerProps>
|
81 | ): { service: TreeContainerProps[Key], identifier: TreeIdentifiers[Key] } {
|
82 | const override = overrides[key] as TreeContainerProps[Key] | undefined;
|
83 | const service = override ?? defaultImplementations[key];
|
84 | return {
|
85 | service,
|
86 | identifier: serviceIdentifiers[key]
|
87 | };
|
88 | }
|
89 |
|
90 | export interface SearchBoxFactoryFactory {
|
91 | (context: interfaces.Context): SearchBoxFactory;
|
92 | }
|
93 |
|
94 | const defaultSearchBoxFactoryFactory: SearchBoxFactoryFactory = () => options => {
|
95 | const debounce = new SearchBoxDebounce(options);
|
96 | return new SearchBox(options, debounce);
|
97 | };
|
98 |
|
99 | interface TreeConstants {
|
100 | searchBoxFactory: SearchBoxFactory,
|
101 | props: TreeProps,
|
102 | }
|
103 |
|
104 | interface TreeServices {
|
105 | tree: Tree,
|
106 | selectionService: TreeSelectionService,
|
107 | expansionService: TreeExpansionService,
|
108 | navigationService: TreeNavigationService,
|
109 | model: TreeModel,
|
110 | widget: TreeWidget,
|
111 | search: TreeSearch,
|
112 | fuzzy: FuzzySearch,
|
113 | decoratorService: TreeDecoratorService,
|
114 | focusService: TreeFocusService,
|
115 | }
|
116 |
|
117 | interface TreeTypes extends TreeServices, TreeConstants { }
|
118 |
|
119 | export type TreeIdentifiers = { [K in keyof TreeTypes]: interfaces.ServiceIdentifier<TreeTypes[K]>; };
|
120 | type TreeServiceProviders = { [K in keyof TreeServices]: interfaces.Newable<TreeServices[K]> };
|
121 |
|
122 | export interface TreeContainerProps extends TreeServiceProviders {
|
123 | props: Partial<TreeProps>,
|
124 | searchBoxFactory: SearchBoxFactoryFactory;
|
125 | }
|
126 |
|
127 | const defaultImplementations: TreeContainerProps & { props: TreeProps } = {
|
128 | tree: TreeImpl,
|
129 | selectionService: TreeSelectionServiceImpl,
|
130 | expansionService: TreeExpansionServiceImpl,
|
131 | navigationService: TreeNavigationService,
|
132 | model: TreeModelImpl,
|
133 | widget: TreeWidget,
|
134 | search: TreeSearch,
|
135 | fuzzy: FuzzySearch,
|
136 | decoratorService: NoopTreeDecoratorService,
|
137 | focusService: TreeFocusServiceImpl,
|
138 | props: defaultTreeProps,
|
139 | searchBoxFactory: defaultSearchBoxFactoryFactory,
|
140 | };
|
141 |
|
142 | const serviceIdentifiers: TreeIdentifiers = {
|
143 | tree: Tree,
|
144 | selectionService: TreeSelectionService,
|
145 | expansionService: TreeExpansionService,
|
146 | navigationService: TreeNavigationService,
|
147 | model: TreeModel,
|
148 | widget: TreeWidget,
|
149 | props: TreeProps,
|
150 | search: TreeSearch,
|
151 | fuzzy: FuzzySearch,
|
152 | searchBoxFactory: SearchBoxFactory,
|
153 | decoratorService: TreeDecoratorService,
|
154 | focusService: TreeFocusService
|
155 | };
|