1
+ import React from 'react' ;
2
+ import _ from 'underscore' ;
3
+ import { Field } from 'redux-form' ;
4
+
5
+ // component definitions
6
+ export default class ComponentFactory {
7
+
8
+ constructor ( ) {
9
+ // this is expected to contain a property for each supported type
10
+ // and this property's value is expected to be an array of ComponentBuilder
11
+ this . fieldComponentsByType = { } ;
12
+
13
+ // this is expected to contain a property for each component definition
14
+ // and the value is expected to be the component definition itself
15
+ this . fieldComponentsById = { } ;
16
+
17
+ // defaultFieldComponents is expected to contain a property for each supported type
18
+ // and this property's value is expected to be the component definition id
19
+ this . defaultFieldComponents = { } ;
20
+
21
+ // this is expected to contain a property for each component definition
22
+ // and the value is expected to be the component definition itself
23
+ this . groupComponentsById = { } ;
24
+
25
+ // The id of the default component for groups
26
+ this . defaultGroupComponentId = null ;
27
+
28
+ // This this a list of Root components
29
+ this . rootComponentsById = { } ;
30
+
31
+ this . currentRoot = null ;
32
+
33
+ }
34
+
35
+ /**
36
+ * Validates the given metadata
37
+ * @param metadata
38
+ */
39
+ _validateMetadata ( metadata ) {
40
+ if ( ! metadata )
41
+ throw "Metadata should not be null or undefined" ;
42
+ if ( ! metadata . type )
43
+ throw "Metadata should have a type" ;
44
+ if ( ! metadata . name )
45
+ throw "Metadata should have a name" ;
46
+ }
47
+
48
+ /**
49
+ * Registers a component definition
50
+ * @param id
51
+ * @param types
52
+ * @param component
53
+ */
54
+
55
+ registerFieldComponent ( id , types , component ) {
56
+ // registers the component definition in each given type
57
+ for ( var i = 0 ; i < types . length ; i ++ )
58
+ {
59
+ const type = types [ i ] ;
60
+ if ( ! ( type in this . fieldComponentsByType ) )
61
+ this . fieldComponentsByType [ type ] = [ ] ;
62
+ this . fieldComponentsByType [ type ] . push ( component ) ;
63
+ }
64
+ // registers the component definition
65
+ this . fieldComponentsById [ id ] = component ;
66
+ }
67
+
68
+ /**
69
+ * @param id The ComponentBuilder id
70
+ */
71
+ getFieldComponent ( id ) {
72
+ var component = this . fieldComponentsById [ id ] ;
73
+ if ( ! component ) {
74
+ throw `Could not find the given component. Id: ${ id } ` ;
75
+ }
76
+ return this . fieldComponentsById [ id ] ;
77
+ }
78
+
79
+ /**
80
+ * Returns the current component definitions.
81
+ * If a type is specified, returns the definitions for that type only
82
+ * @returns {{}|* }
83
+ */
84
+ getFieldComponents ( type ) {
85
+ if ( ! type )
86
+ return this . fieldComponentsByType ;
87
+ return this . fieldComponentsByType [ type ] ;
88
+ }
89
+
90
+ /**
91
+ * Returns the default component definition for the given type
92
+ * @param type
93
+ */
94
+ getDefaultFieldComponent ( type ) {
95
+ if ( ! type ) throw 'type should have a value' ;
96
+ if ( this . defaultFieldComponents [ type ] )
97
+ return this . getFieldComponent ( this . defaultFieldComponents [ type ] ) ;
98
+ const componentsForType = this . getFieldComponents ( type ) ;
99
+ const component = _ . first ( componentsForType ) ;
100
+ if ( ! component )
101
+ throw new Error ( `Couldn't find any component for the given type. Type: ${ type } . Make sure the proper component was registered in the ComponentFactory.` ) ;
102
+ return component ;
103
+ }
104
+
105
+ /**
106
+ * Sets the default component per type.
107
+ * @param components - An object that should contain a type as a key and a ComponentBuilder as value
108
+ */
109
+ setDefaultFieldComponents ( components ) {
110
+ this . defaultFieldComponents = components ;
111
+ }
112
+
113
+ /**
114
+ * Gets the appropriate component based on the given metadata
115
+ * @param fieldComponentProps
116
+ * @returns {* }
117
+ */
118
+ buildFieldComponent ( fieldComponentProps ) {
119
+ if ( ! fieldComponentProps ) throw Error ( 'Argument \'props\' should be truthy' ) ;
120
+
121
+ this . _validateMetadata ( fieldComponentProps ) ;
122
+ let componentType ;
123
+ if ( fieldComponentProps . component ) {
124
+ // if the metadata explicitly specify a component, let's use it
125
+ componentType = this . getFieldComponent ( fieldComponentProps . component ) ;
126
+ }
127
+ else
128
+ {
129
+ // If the metadata doesn't explicitly specify a component, let's return
130
+ // the default component for type. If there's no default, let's take the first
131
+ // that matches the type
132
+ componentType = this . getDefaultFieldComponent ( fieldComponentProps . type ) ;
133
+ }
134
+ if ( ! componentType )
135
+ throw new Error ( `Could not resolve the component for the type. Type: ${ fieldComponentProps . type } ` ) ;
136
+
137
+ var component = React . createElement ( componentType , Object . assign ( { } , fieldComponentProps , fieldComponentProps . reduxFormProps ) ) ;
138
+
139
+ // if there's a 'reduxFormProps' metadata, it should be merged with the
140
+ return < Field name = { fieldComponentProps . name } component = { component } /> ;
141
+ }
142
+
143
+ /**
144
+ * Registers a group component
145
+ * @param id
146
+ * @param component
147
+ */
148
+ registerGroupComponent ( id , component ) {
149
+ this . groupComponentsById [ id ] = component ;
150
+ }
151
+
152
+ getGroupComponent ( id ) {
153
+ let component = this . groupComponentsById [ id ] ;
154
+ if ( ! component ) {
155
+ throw Error ( `Could not resolve the group component. Component: ${ id } ` ) ;
156
+ }
157
+ return component ;
158
+ }
159
+
160
+ /**
161
+ * Sets the default group component
162
+ * @param id
163
+ */
164
+ setDefaultGroupComponent ( id ) {
165
+ this . defaultGroupComponentId = id ;
166
+ }
167
+
168
+ /**
169
+ * Gets the default group component
170
+ * @returns {* }
171
+ */
172
+ getDefaultGroupComponent ( ) {
173
+ return this . getGroupComponent ( this . defaultGroupComponentId ) ;
174
+ }
175
+
176
+ /**
177
+ * Gets the appropriate component based on the given metadata
178
+ * @param groupComponentProps
179
+ * @returns {* }
180
+ */
181
+ buildGroupComponent ( groupComponentProps ) {
182
+ if ( ! groupComponentProps ) {
183
+ throw Error ( 'The props parameter is required' ) ;
184
+ }
185
+
186
+ let componentType ;
187
+ if ( groupComponentProps . component ) {
188
+ // if the metadata explicitly specify a component, let's use it
189
+ componentType = this . getGroupComponent ( groupComponentProps . component ) ;
190
+ }
191
+ else
192
+ {
193
+ // If the metadata doesn't explicitly specify a component, let's return
194
+ // the default component for type. If there's no default, let's take the first
195
+ // that matches the type
196
+ componentType = this . getDefaultGroupComponent ( ) ;
197
+ }
198
+ if ( ! componentType )
199
+ throw new Error ( `Could not resolve the component for the group` ) ;
200
+
201
+ return React . createElement ( componentType , groupComponentProps ) ;
202
+ }
203
+
204
+
205
+ // Allows to register a new Root component
206
+ registerRootComponent ( id , component ) {
207
+ this . rootComponentsById [ id ] = component ;
208
+ }
209
+
210
+ // Allows to define the id of the current Root component that should be used
211
+ setCurrentRoot ( id ) {
212
+ this . currentRoot = id ;
213
+ }
214
+
215
+ // Return the selected Root component in AutoformInternal
216
+ getRoot ( ) {
217
+ return this . rootComponentsById [ this . currentRoot ] ;
218
+ }
219
+ }
0 commit comments