-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathComponentFactory.js
198 lines (173 loc) · 6.14 KB
/
ComponentFactory.js
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
import React from 'react';
import _ from 'underscore';
// component definitions
class ComponentFactory {
constructor() {
// this is expected to contain a property for each supported type
// and this property's value is expected to be an array of ComponentBuilder
this.fieldComponentsByType = { };
// this is expected to contain a property for each component definition
// and the value is expected to be the component definition itself
this.fieldComponentsById = { };
// defaultFieldComponents is expected to contain a property for each supported type
// and this property's value is expected to be the component definition id
this.defaultFieldComponents = { }
// this is expected to contain a property for each component definition
// and the value is expected to be the component definition itself
this.groupComponentsById = { };
// The id of the default component for groups
this.defaultGroupComponentId = null;
}
/**
* Validates the given metadata
* @param metadata
*/
_validateMetadata(metadata) {
if(!metadata)
throw "Metadata should not be null or undefined";
if(!metadata.type)
throw "Metadata should have a type";
if(!metadata.name)
throw "Metadata should have a name";
}
/**
* Registers a component definition
* @param id
* @param types
* @param component
*/
registerFieldComponent(id, types, component) {
// registers the component definition in each given type
for(var i = 0; i < types.length; i++)
{
const type = types[i];
if(!(type in this.fieldComponentsByType))
this.fieldComponentsByType[type] = [];
this.fieldComponentsByType[type].push(component);
}
// registers the component definition
this.fieldComponentsById[id] = component;
}
/**
* @param id The ComponentBuilder id
*/
getFieldComponent(id) {
var component = this.fieldComponentsById[id];
if(!component) {
throw `Could not find the given component. Id: ${id}`;
}
return this.fieldComponentsById[id];
}
/**
* Returns the current component definitions.
* If a type is specified, returns the definitions for that type only
* @returns {{}|*}
*/
getFieldComponents(type) {
if(!type)
return this.fieldComponentsByType;
return this.fieldComponentsByType[type];
}
/**
* Returns the default component definition for the given type
* @param type
*/
getDefaultFieldComponent(type) {
if(!type) throw 'type should have a value';
if(this.defaultFieldComponents[type])
return this.getFieldComponent(this.defaultFieldComponents[type]);
const componentsForType = this.getFieldComponents(type);
const component = _.first(componentsForType);
if(!component)
throw new Error(`Couldn't find any component for the given type. Type: ${type}. Make sure the proper component was registered in the ComponentFactory.`);
return component;
}
/**
* Sets the default component per type.
* @param components - An object that should contain a type as a key and a ComponentBuilder as value
*/
setDefaultFieldComponents(components) {
this.defaultFieldComponents = components;
}
/**
* Gets the appropriate component based on the given metadata
* @param props
* @returns {*}
*/
buildFieldComponent(props) {
if(!props) {
throw Error('The props parameter is required');
}
this._validateMetadata(props);
let componentType;
if(props.component) {
// if the metadata explicitly specify a component, let's use it
componentType = this.getFieldComponent(props.component);
}
else
{
// If the metadata doesn't explicitly specify a component, let's return
// the default component for type. If there's no default, let's take the first
// that matches the type
componentType = this.getDefaultFieldComponent(props.type);
}
if(!componentType)
throw new Error(`Could not resolve the component for the type. Type: ${props.type}`);
return React.createElement(componentType, props);
}
/**
* Registers a group component
* @param id
* @param component
*/
registerGroupComponent(id, component) {
this.groupComponentsById[id] = component;
}
getGroupComponent(id) {
let component = this.groupComponentsById[id];
if(!component) {
throw Error(`Could not resolve the group component. Component: ${id}`);
}
return component;
}
/**
* Sets the default group component
* @param id
*/
setDefaultGroupComponent(id) {
this.defaultGroupComponentId = id;
}
/**
* Gets the default group component
* @returns {*}
*/
getDefaultGroupComponent() {
return this.getGroupComponent(this.defaultGroupComponentId);
}
/**
* Gets the appropriate component based on the given metadata
* @param props
* @returns {*}
*/
buildGroupComponent(props) {
if(!props) {
throw Error('The props parameter is required');
}
let componentType;
if(props.component) {
// if the metadata explicitly specify a component, let's use it
componentType = this.getGroupComponent(props.component);
}
else
{
// If the metadata doesn't explicitly specify a component, let's return
// the default component for type. If there's no default, let's take the first
// that matches the type
componentType = this.getDefaultGroupComponent();
}
if(!componentType)
throw new Error(`Could not resolve the component for the group`);
return React.createElement(componentType, props);
}
}
export default new ComponentFactory();