amis-editor 4.1.0-beta.2 → 4.1.0-beta.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (196) hide show
  1. package/dist/component/Breadcrumb.d.ts +23 -2
  2. package/dist/component/Editor.d.ts +19 -0
  3. package/dist/component/Panel/RenderersPanel.d.ts +1 -2
  4. package/dist/component/RegionWrapper.d.ts +4 -0
  5. package/dist/component/VRenderer.d.ts +4 -0
  6. package/dist/component/base/SearchCustomRendererPanel.d.ts +15 -0
  7. package/dist/component/base/SearchPanel.d.ts +83 -0
  8. package/dist/component/base/SearchRendererPanel.d.ts +2 -42
  9. package/dist/exports.min.js +1 -1
  10. package/dist/index.d.ts +4 -1
  11. package/dist/index.min.js +1 -1
  12. package/dist/manager.d.ts +14 -3
  13. package/dist/plugin/Card.d.ts +1 -0
  14. package/dist/plugin/Cards.d.ts +1 -0
  15. package/dist/plugin/Carousel.d.ts +1 -0
  16. package/dist/plugin/Chart.d.ts +1 -0
  17. package/dist/plugin/Collapse.d.ts +1 -0
  18. package/dist/plugin/Custom.d.ts +3 -0
  19. package/dist/plugin/CustomRegion.d.ts +43 -0
  20. package/dist/plugin/Flex.d.ts +1 -0
  21. package/dist/plugin/Form/Control.d.ts +1 -0
  22. package/dist/plugin/Form/Form.d.ts +19 -3
  23. package/dist/plugin/Form/InputURL.d.ts +1 -0
  24. package/dist/plugin/Form/Switch.d.ts +2 -0
  25. package/dist/plugin/Grid.d.ts +1 -0
  26. package/dist/plugin/HBox.d.ts +1 -0
  27. package/dist/plugin/Json.d.ts +1 -0
  28. package/dist/plugin/List.d.ts +1 -0
  29. package/dist/plugin/Mapping.d.ts +1 -0
  30. package/dist/plugin/Markdown.d.ts +1 -0
  31. package/dist/plugin/Nav.d.ts +1 -0
  32. package/dist/plugin/Panel/Outline.d.ts +8 -0
  33. package/dist/plugin/Progress.d.ts +1 -0
  34. package/dist/plugin/QRCode.d.ts +1 -0
  35. package/dist/plugin/Reset.d.ts +0 -1
  36. package/dist/plugin/Service.d.ts +1 -0
  37. package/dist/plugin/Sparkline.d.ts +1 -0
  38. package/dist/plugin/Status.d.ts +1 -0
  39. package/dist/plugin/Steps.d.ts +1 -0
  40. package/dist/plugin/Submit.d.ts +0 -1
  41. package/dist/plugin/TableView.d.ts +1 -0
  42. package/dist/plugin/Tasks.d.ts +1 -0
  43. package/dist/plugin/TooltipWrapper.d.ts +1 -0
  44. package/dist/plugin/Video.d.ts +1 -0
  45. package/dist/plugin/WebComponent.d.ts +1 -0
  46. package/dist/plugin/Wizard.d.ts +11 -2
  47. package/dist/plugin/Wrapper.d.ts +1 -0
  48. package/dist/plugin.d.ts +2 -2
  49. package/dist/store/editor.d.ts +20 -2
  50. package/dist/store/node.d.ts +6 -0
  51. package/dist/style.css +1 -1
  52. package/dist/util.d.ts +7 -2
  53. package/package.json +6 -3
  54. package/src/component/schemaTpl.tsx +2157 -0
  55. package/src/plugin/Alert.tsx +87 -0
  56. package/src/plugin/AnchorNav.tsx +233 -0
  57. package/src/plugin/Audio.tsx +161 -0
  58. package/src/plugin/Avatar.tsx +77 -0
  59. package/src/plugin/Breadcrumb.tsx +107 -0
  60. package/src/plugin/Button.tsx +283 -0
  61. package/src/plugin/ButtonGroup.tsx +88 -0
  62. package/src/plugin/ButtonToolbar.tsx +89 -0
  63. package/src/plugin/CRUD.tsx +1835 -0
  64. package/src/plugin/Card.tsx +290 -0
  65. package/src/plugin/Cards.tsx +315 -0
  66. package/src/plugin/Carousel.tsx +386 -0
  67. package/src/plugin/Chart.tsx +218 -0
  68. package/src/plugin/CodeView.tsx +60 -0
  69. package/src/plugin/Collapse.tsx +143 -0
  70. package/src/plugin/CollapseGroup.tsx +167 -0
  71. package/src/plugin/Container.tsx +44 -0
  72. package/src/plugin/Custom.tsx +128 -0
  73. package/src/plugin/CustomRegion.tsx +150 -0
  74. package/src/plugin/Date.tsx +81 -0
  75. package/src/plugin/Datetime.tsx +75 -0
  76. package/src/plugin/Dialog.tsx +178 -0
  77. package/src/plugin/Divider.tsx +36 -0
  78. package/src/plugin/Drawer.tsx +217 -0
  79. package/src/plugin/DropDownButton.tsx +234 -0
  80. package/src/plugin/Each.tsx +152 -0
  81. package/src/plugin/ErrorRenderer.tsx +15 -0
  82. package/src/plugin/Flex.tsx +156 -0
  83. package/src/plugin/Form/ButtonGroupSelect.tsx +86 -0
  84. package/src/plugin/Form/ButtonToolbar.tsx +121 -0
  85. package/src/plugin/Form/ChainedSelect.tsx +70 -0
  86. package/src/plugin/Form/Checkbox.tsx +87 -0
  87. package/src/plugin/Form/Checkboxes.tsx +167 -0
  88. package/src/plugin/Form/CodeEditor.tsx +91 -0
  89. package/src/plugin/Form/Combo.tsx +582 -0
  90. package/src/plugin/Form/ConditionBuilder.tsx +324 -0
  91. package/src/plugin/Form/Control.tsx +139 -0
  92. package/src/plugin/Form/DiffEditor.tsx +117 -0
  93. package/src/plugin/Form/FieldSet.tsx +175 -0
  94. package/src/plugin/Form/Form.tsx +692 -0
  95. package/src/plugin/Form/Formula.tsx +91 -0
  96. package/src/plugin/Form/Group.tsx +300 -0
  97. package/src/plugin/Form/Hidden.tsx +56 -0
  98. package/src/plugin/Form/InputArray.tsx +228 -0
  99. package/src/plugin/Form/InputCity.tsx +93 -0
  100. package/src/plugin/Form/InputColor.tsx +123 -0
  101. package/src/plugin/Form/InputDate.tsx +175 -0
  102. package/src/plugin/Form/InputDateRange.tsx +225 -0
  103. package/src/plugin/Form/InputDateTime.tsx +183 -0
  104. package/src/plugin/Form/InputDateTimeRange.tsx +221 -0
  105. package/src/plugin/Form/InputEmail.tsx +33 -0
  106. package/src/plugin/Form/InputExcel.tsx +85 -0
  107. package/src/plugin/Form/InputFile.tsx +228 -0
  108. package/src/plugin/Form/InputGroup.tsx +105 -0
  109. package/src/plugin/Form/InputImage.tsx +277 -0
  110. package/src/plugin/Form/InputKV.tsx +72 -0
  111. package/src/plugin/Form/InputMonth.tsx +35 -0
  112. package/src/plugin/Form/InputMonthRange.tsx +195 -0
  113. package/src/plugin/Form/InputNumber.tsx +97 -0
  114. package/src/plugin/Form/InputPassword.tsx +33 -0
  115. package/src/plugin/Form/InputQuarter.tsx +35 -0
  116. package/src/plugin/Form/InputQuarterRange.tsx +195 -0
  117. package/src/plugin/Form/InputRange.tsx +121 -0
  118. package/src/plugin/Form/InputRating.tsx +78 -0
  119. package/src/plugin/Form/InputRepeat.tsx +69 -0
  120. package/src/plugin/Form/InputRichText.tsx +197 -0
  121. package/src/plugin/Form/InputSubForm.tsx +198 -0
  122. package/src/plugin/Form/InputTable.tsx +434 -0
  123. package/src/plugin/Form/InputTag.tsx +81 -0
  124. package/src/plugin/Form/InputText.tsx +186 -0
  125. package/src/plugin/Form/InputTime.tsx +95 -0
  126. package/src/plugin/Form/InputTree.tsx +240 -0
  127. package/src/plugin/Form/InputURL.tsx +34 -0
  128. package/src/plugin/Form/InputYear.tsx +35 -0
  129. package/src/plugin/Form/Item.tsx +327 -0
  130. package/src/plugin/Form/ListSelect.tsx +84 -0
  131. package/src/plugin/Form/LocationPicker.tsx +75 -0
  132. package/src/plugin/Form/MatrixCheckboxes.tsx +147 -0
  133. package/src/plugin/Form/NestedSelect.tsx +222 -0
  134. package/src/plugin/Form/Picker.tsx +217 -0
  135. package/src/plugin/Form/Radios.tsx +130 -0
  136. package/src/plugin/Form/Select.tsx +233 -0
  137. package/src/plugin/Form/Static.tsx +335 -0
  138. package/src/plugin/Form/Switch.tsx +118 -0
  139. package/src/plugin/Form/TabsTransfer.tsx +270 -0
  140. package/src/plugin/Form/Textarea.tsx +94 -0
  141. package/src/plugin/Form/Transfer.tsx +379 -0
  142. package/src/plugin/Form/TreeSelect.tsx +263 -0
  143. package/src/plugin/Form/UUID.tsx +48 -0
  144. package/src/plugin/Grid.tsx +799 -0
  145. package/src/plugin/HBox.tsx +727 -0
  146. package/src/plugin/IFrame.tsx +72 -0
  147. package/src/plugin/Image.tsx +318 -0
  148. package/src/plugin/Images.tsx +238 -0
  149. package/src/plugin/Json.tsx +76 -0
  150. package/src/plugin/Link.tsx +95 -0
  151. package/src/plugin/List.tsx +278 -0
  152. package/src/plugin/ListItem.tsx +233 -0
  153. package/src/plugin/Log.tsx +52 -0
  154. package/src/plugin/Mapping.tsx +156 -0
  155. package/src/plugin/Markdown.tsx +47 -0
  156. package/src/plugin/Nav.tsx +186 -0
  157. package/src/plugin/Operation.tsx +97 -0
  158. package/src/plugin/Others/Action.tsx +428 -0
  159. package/src/plugin/Others/BasicToolbar.tsx +591 -0
  160. package/src/plugin/Others/DataDebug.tsx +134 -0
  161. package/src/plugin/Others/TableCell.tsx +480 -0
  162. package/src/plugin/Others/Unknown.tsx +37 -0
  163. package/src/plugin/Page.tsx +308 -0
  164. package/src/plugin/Panel/AvailableRenderers.tsx +41 -0
  165. package/src/plugin/Panel/Code.tsx +44 -0
  166. package/src/plugin/Panel/Name.tsx +26 -0
  167. package/src/plugin/Panel/Outline.tsx +40 -0
  168. package/src/plugin/Panel.tsx +243 -0
  169. package/src/plugin/Plain.tsx +91 -0
  170. package/src/plugin/Progress.tsx +132 -0
  171. package/src/plugin/Property.tsx +139 -0
  172. package/src/plugin/QRCode.tsx +98 -0
  173. package/src/plugin/Reset.tsx +23 -0
  174. package/src/plugin/Service.tsx +167 -0
  175. package/src/plugin/Sparkline.tsx +40 -0
  176. package/src/plugin/Status.tsx +78 -0
  177. package/src/plugin/Steps.tsx +140 -0
  178. package/src/plugin/Submit.tsx +23 -0
  179. package/src/plugin/Table.tsx +440 -0
  180. package/src/plugin/TableView.tsx +711 -0
  181. package/src/plugin/Tabs.tsx +364 -0
  182. package/src/plugin/Tasks.tsx +276 -0
  183. package/src/plugin/Time.tsx +75 -0
  184. package/src/plugin/TooltipWrapper.tsx +193 -0
  185. package/src/plugin/Tpl.tsx +162 -0
  186. package/src/plugin/Video.tsx +160 -0
  187. package/src/plugin/WebComponent.tsx +56 -0
  188. package/src/plugin/Wizard.tsx +743 -0
  189. package/src/plugin/Wrapper.tsx +107 -0
  190. package/src/plugin.ts +1046 -0
  191. package/dist/150a58f3318ca7541ed9.png +0 -0
  192. package/dist/471adb97c322b226e589.png +0 -0
  193. package/dist/4de5f42360bc5946c3c2.png +0 -0
  194. package/dist/4e9968bba3855f088fed.png +0 -0
  195. package/dist/7f09c38ebc687fea847a.png +0 -0
  196. package/dist/c94073576487510314ea.png +0 -0
package/src/plugin.ts ADDED
@@ -0,0 +1,1046 @@
1
+ /**
2
+ * @file 定义插件的 interface,以及提供一个 BasePlugin 基类,把一些通用的方法放在这。
3
+ */
4
+ import {BaseSchema, SchemaObject} from 'amis';
5
+ import {MenuDivider, MenuItem} from 'amis/lib/components/ContextMenu';
6
+ import {RendererConfig} from 'amis/lib/factory';
7
+ import {RegionWrapperProps} from './component/RegionWrapper';
8
+ import {EditorManager} from './manager';
9
+ import {EditorStoreType} from './store/editor';
10
+ import {EditorNodeType} from './store/node';
11
+ import {DNDModeInterface} from './dnd/interface';
12
+ import {EditorDNDManager} from './dnd';
13
+ import React from 'react';
14
+ import {DiffChange} from './util';
15
+ import find from 'lodash/find';
16
+
17
+ /**
18
+ * 区域的定义,容器渲染器都需要定义区域信息。
19
+ */
20
+ export interface RegionConfig {
21
+ /**
22
+ * 简单情况,如果区域直接用的 render('region', subSchema)
23
+ * 这种只需要配置 key 就能简单插入 Region 节点。
24
+ */
25
+ key: string;
26
+
27
+ /**
28
+ * 区域用来显示的名字。
29
+ */
30
+ label: string;
31
+
32
+ /**
33
+ * 区域占位字符,用于提示
34
+ */
35
+ placeholder?: string;
36
+
37
+ /**
38
+ * 对于复杂的控件需要用到这个配置。
39
+ * 如果配置了,则遍历 react dom 直到目标节点调换成 Region 节点
40
+ *
41
+ * 如果没有配置这个,但是又配置了 renderMethod 方法,
42
+ * 那就直接将 renderMethod 里面返回的 react dom 直接包一层 Region
43
+ */
44
+ matchRegion?: (
45
+ elem: JSX.Element | undefined | null,
46
+ component: JSX.Element
47
+ ) => boolean;
48
+
49
+ /**
50
+ * 指定要覆盖哪个方法。
51
+ */
52
+ renderMethod?: string;
53
+
54
+ /**
55
+ * 通常是hack 当前渲染器,单有时候当前渲染器其实是组合的别的渲染器。
56
+ */
57
+ rendererName?: string;
58
+
59
+ /**
60
+ * 当配置 renderMethod 的时候会自动把 Region 插入进去。
61
+ * 默认是 outter 模式,有时候可能需要配置成 inner,
62
+ * 比如 renderMethod 为 render 的时候。
63
+ */
64
+ insertPosition?: 'outter' | 'inner';
65
+
66
+ /**
67
+ * 是否为可选容器,如果是可选容器,不会强制自动创建成员
68
+ */
69
+ optional?: boolean;
70
+
71
+ /**
72
+ * 有时候有些包括是需要其他条件的,所以要自己写包裹逻辑。
73
+ * 比如 Panel 里面的 renderBody
74
+ */
75
+ renderMethodOverride?: (
76
+ regions: Array<RegionConfig>,
77
+ insertRegion: (
78
+ component: JSX.Element,
79
+ dom: JSX.Element,
80
+ regions: Array<RegionConfig>,
81
+ info: RendererInfo,
82
+ manager: EditorManager
83
+ ) => JSX.Element
84
+ ) => Function;
85
+
86
+ /**
87
+ * 偏好什么类型的组件?比如表单里面,controls 容器偏向表单项。
88
+ */
89
+ preferTag?: string;
90
+
91
+ /**
92
+ * 用来指定用什么组件包裹,默认是 RegionWrapper
93
+ */
94
+ wrapper?: React.ComponentType<RegionWrapperProps>;
95
+
96
+ /**
97
+ * 返回需要添加 data-region 的 dom 节点。
98
+ */
99
+ wrapperResolve?: (dom: HTMLElement) => HTMLElement;
100
+
101
+ /**
102
+ * 当拖入到这个容器时,是否需要修改一下 ghost 结构?
103
+ */
104
+ modifyGhost?: (ghost: HTMLElement, schema?: any) => void;
105
+
106
+ /**
107
+ * dnd 拖拽模式。比如 table 那种需要配置成 position-h
108
+ */
109
+ dndMode?:
110
+ | 'default'
111
+ | 'position-h'
112
+ | 'position-v'
113
+ | (new (dnd: EditorDNDManager) => DNDModeInterface);
114
+
115
+ /**
116
+ * 可以用来判断是否允许拖入当前节点。
117
+ */
118
+ accept?: (json: any) => boolean;
119
+ }
120
+
121
+ export interface VRendererConfig {
122
+ /**
123
+ * 配置了这些会自动创建编辑面板。
124
+ */
125
+ panelIcon?: string;
126
+ panelTitle?: string;
127
+ /**
128
+ * @deprecated 用 panelBody 代替
129
+ */
130
+ panelControls?: Array<any>;
131
+ panelDefinitions?: any;
132
+ /**
133
+ * @deprecated 用panelBodyCreator 代替
134
+ */
135
+ panelControlsCreator?: (context: BaseEventContext) => Array<any>;
136
+ panelBody?: Array<any>;
137
+ panelBodyCreator?: (context: BaseEventContext) => Array<any>;
138
+
139
+ /**
140
+ * 配置了,要是不在 overides 里面使用也是没用的。
141
+ */
142
+ regions?: {
143
+ [propName: string]: RegionConfig;
144
+ };
145
+ }
146
+
147
+ export interface RendererScaffoldInfo {
148
+ /**
149
+ * 组件名称
150
+ */
151
+ name: string;
152
+
153
+ // 图标
154
+ icon?: string;
155
+
156
+ // 组件描述信息
157
+ description?: string;
158
+
159
+ // 文档链接
160
+ docLink?: string;
161
+
162
+ // 用来生成预览图
163
+ previewSchema?: any;
164
+
165
+ // 分类
166
+ tags?: string | Array<string>;
167
+
168
+ // type 和 scaffold 二选一
169
+ type?: string;
170
+ scaffold?: any;
171
+ }
172
+
173
+ /**
174
+ * 渲染器信息。
175
+ */
176
+ export interface RendererInfo extends RendererScaffoldInfo {
177
+ scaffolds?: Array<Partial<RendererScaffoldInfo>>;
178
+
179
+ rendererName?: string;
180
+
181
+ /**
182
+ * json schema 协议
183
+ */
184
+ $schema?: string;
185
+
186
+ isBaseComponent?: boolean;
187
+
188
+ disabledRendererPlugin?: boolean;
189
+
190
+ /**
191
+ * 配置区域。
192
+ */
193
+ regions?: Array<RegionConfig>;
194
+
195
+ /**
196
+ * 哪些容器属性需要自动转成数组的。如果不配置默认就从 regions 里面读取。
197
+ */
198
+ patchContainers?: Array<string>;
199
+
200
+ /**
201
+ * 覆盖的目标渲染器名称
202
+ */
203
+ overrideTargetRendererName?: string;
204
+
205
+ /**
206
+ * 覆写某些方法,一般用来插入虚拟的渲染器编辑器。
207
+ */
208
+ overrides?: {
209
+ [propName: string]: Function;
210
+ };
211
+
212
+ /**
213
+ * 虚拟渲染器的配置项,有时候需要给那些并不是渲染器的组件添加点选编辑功能。
214
+ * 比如: Tabs 下面的 Tab, 这个并不是个渲染器,但是需要可以点选修改内容。
215
+ */
216
+ vRendererConfig?: VRendererConfig;
217
+
218
+ /**
219
+ * 默认为 BaseWrapper, 容器类的指定为 BaseContainerWrapper 或者再实现一个
220
+ * 暂时没有需要配置的所以注释掉。
221
+ * wrapper?: React.ComponentType<NodeWrapperProps>;
222
+ *
223
+ * 返回哪些 dom 节点,需要自动加上 data-editor-id 属性
224
+ * 目前只有 TableCell 里面用到了,就它需要同时给某一列下所有 td 都加上那个属性。
225
+ */
226
+ wrapperResolve?: (dom: HTMLElement) => HTMLElement | Array<HTMLElement>;
227
+
228
+ /**
229
+ * 默认下发哪些属性,如果要动态下发,请使用 filterProps
230
+ */
231
+ wrapperProps?: any;
232
+
233
+ /**
234
+ * 修改一些属性,一般用来干掉 $$id
235
+ * 这样它的孩子节点就不能直接点选编辑了,比如 Combo。
236
+ */
237
+ filterProps?: (props: any, node: EditorNodeType) => any;
238
+
239
+ /**
240
+ * 有些没有视图的组件,可以自己输出点内容,否则没办法点选编辑。
241
+ */
242
+ renderRenderer?: (props: any, info: RendererInfo) => JSX.Element;
243
+
244
+ /**
245
+ * 是否有多重身份?
246
+ * 比如 CRUD 即是 CRUD 又可能是 Table
247
+ *
248
+ * 表格的列,即是表格列,也可能是其他文本框。
249
+ *
250
+ * 配置了这个后会自动添加多个 Panel 面板来编辑。
251
+ */
252
+ multifactor?: boolean;
253
+
254
+ /**
255
+ * 右键的时候是否出现重新构建,靠这个。
256
+ */
257
+ scaffoldForm?: ScaffoldForm;
258
+
259
+ // 自动填入,不用配置
260
+ id: string;
261
+ plugin: PluginInterface;
262
+ extraPlugin?: PluginInterface; // 辅助插件,看需求。
263
+ renderer: RendererConfig;
264
+ schemaPath: string;
265
+
266
+ // 给 subEditor 用的,别直接配置
267
+ editable?: boolean; // 是否可编辑。
268
+ removable?: boolean; // 是否可被删除
269
+ draggable?: boolean; // 是否可被拖动
270
+ movable?: boolean; // 是否可被移动
271
+ replaceable?: boolean; // 是否可被替换
272
+ duplicatable?: boolean; // 是否可以重复一份
273
+ memberImmutable?: boolean | Array<string>; // 成员节点固定,意味着不能新增成员
274
+ typeMutable?: boolean; // 类型是否可被修改
275
+
276
+ // 如果是虚拟的渲染器
277
+ hostId?: string;
278
+ memberIndex?: number;
279
+ }
280
+
281
+ export type BasicRendererInfo = Omit<
282
+ RendererInfo,
283
+ 'id' | 'plugin' | 'renderer' | 'schemaPath'
284
+ >;
285
+
286
+ export interface PopOverForm {
287
+ title?: string;
288
+
289
+ /**
290
+ * 脚手架配置项。
291
+ */
292
+ body: Array<any>;
293
+
294
+ /**
295
+ * @deprecated 改用 body 代替
296
+ */
297
+ controls?: Array<any>;
298
+ }
299
+
300
+ export interface ScaffoldForm extends PopOverForm {
301
+ mode?: 'normal' | 'horizontal' | 'inline';
302
+
303
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
304
+ initApi?: any;
305
+ api?: any;
306
+
307
+ /**
308
+ * 整体验证脚手架配置,如果有错误返回错误对象。
309
+ * key 是配置的字段名。
310
+ * value 是具体错误信息。
311
+ */
312
+ validate?: (
313
+ values: any
314
+ ) =>
315
+ | void
316
+ | {[propName: string]: string}
317
+ | Promise<void | {[propName: string]: string}>;
318
+
319
+ /**
320
+ * schema 配置转脚手架配置
321
+ */
322
+ pipeIn?: (value: any) => any;
323
+
324
+ /**
325
+ * 脚手架配置转 schema 配置。
326
+ */
327
+ pipeOut?: (value: any) => any;
328
+
329
+ /**
330
+ * 是否允许重新构建;
331
+ */
332
+ canRebuild?: boolean;
333
+ }
334
+
335
+ /**
336
+ * 子渲染器信息
337
+ */
338
+ export interface SubRendererInfo extends RendererScaffoldInfo {
339
+ /**
340
+ * 用于判断是否是平台预置组件,平台预置组件为true。
341
+ */
342
+ isBaseComponent?: boolean;
343
+
344
+ rendererName?: string;
345
+ /**
346
+ * 首次拖入的时候可以用来配置个表单。
347
+ */
348
+ scaffoldForm?: ScaffoldForm;
349
+ /**
350
+ * 新增属性,用于判断是否出现在组件面板中,默认为false,为ture则不展示
351
+ */
352
+ disabledRendererPlugin?: boolean;
353
+
354
+ // 自动填入,不用配置
355
+ plugin: PluginInterface;
356
+ parent: RendererInfo;
357
+ id: string;
358
+ order: number;
359
+ }
360
+
361
+ export type BasicSubRenderInfo = Omit<
362
+ SubRendererInfo,
363
+ 'plugin' | 'parent' | 'id' | 'order'
364
+ > &
365
+ Partial<Pick<SubRendererInfo, 'order'>>;
366
+
367
+ /**
368
+ * 工具按钮信息。
369
+ */
370
+ export interface ToolbarItem {
371
+ label?: string;
372
+ id?: string;
373
+ order: number;
374
+ level?: 'primary' | 'secondary' | 'special';
375
+ className?: string;
376
+ draggable?: boolean;
377
+ onDragStart?: (e: React.DragEvent) => void;
378
+ icon?: string;
379
+ iconSvg?: string; // 自定义icon(svg格式)
380
+ onClick?: (e: React.MouseEvent) => void;
381
+ tooltip?: string;
382
+ placement?: 'top' | 'bottom' | 'right' | 'left';
383
+ }
384
+
385
+ export type BasicToolbarItem = Partial<ToolbarItem>;
386
+
387
+ export type ContextMenuItem = MenuItem | MenuDivider;
388
+
389
+ /**
390
+ * 面板的属性定义
391
+ */
392
+ export interface PanelProps {
393
+ id?: string;
394
+ info?: RendererInfo;
395
+ path?: string;
396
+ node?: EditorNodeType;
397
+ value: BaseSchema;
398
+ onChange: (value: BaseSchema, diff?: Array<DiffChange>) => void;
399
+ store: EditorStoreType;
400
+ manager: EditorManager;
401
+ popOverContainer?: () => HTMLElement | void;
402
+ }
403
+
404
+ /**
405
+ * 面板信息定义
406
+ */
407
+ export interface PanelItem {
408
+ nodeId?: string;
409
+ key: string;
410
+ icon: string;
411
+ title: string | JSX.Element; // 标题
412
+ component?: React.ComponentType<PanelProps | any>;
413
+ order: number;
414
+ position?: 'left' | 'right';
415
+ render?: (props: PanelProps) => JSX.Element;
416
+ menus?: Array<any>;
417
+ }
418
+
419
+ export type BasicPanelItem = Omit<PanelItem, 'order'> &
420
+ Partial<Pick<PanelItem, 'order'>>;
421
+
422
+ export interface EventContext {
423
+ data?: any;
424
+ [propName: string]: any;
425
+ }
426
+
427
+ /**
428
+ * 事件上下文
429
+ */
430
+ export interface BaseEventContext extends EventContext {
431
+ node: EditorNodeType;
432
+ id: string;
433
+ info: RendererInfo;
434
+ path: string;
435
+ schema: any;
436
+ schemaPath: string;
437
+ secondFactor?: boolean;
438
+ }
439
+
440
+ export interface RendererInfoResolveEventContext extends EventContext {
441
+ renderer: RendererConfig;
442
+ path: string;
443
+ schema: any;
444
+ schemaPath: string;
445
+ data?: RendererInfo;
446
+ }
447
+
448
+ export interface RendererJSONSchemaResolveEventContext
449
+ extends BaseEventContext {
450
+ data: string;
451
+ }
452
+
453
+ /**
454
+ * 右键菜单事件的上下文。
455
+ */
456
+ export interface ContextMenuEventContext extends BaseEventContext {
457
+ region: string;
458
+ selections: Array<BaseEventContext>;
459
+ data: Array<ContextMenuItem>;
460
+ }
461
+
462
+ export interface SelectionEventContext extends BaseEventContext {
463
+ selections: Array<BaseEventContext>;
464
+ data: Array<string>;
465
+ }
466
+
467
+ export interface RendererEventContext extends BaseEventContext {
468
+ region?: string;
469
+ }
470
+
471
+ export interface ActiveEventContext extends Partial<BaseEventContext> {
472
+ active?: boolean;
473
+ }
474
+
475
+ export interface DeleteEventContext extends BaseEventContext {
476
+ data?: Array<string>;
477
+ }
478
+
479
+ /**
480
+ * 插入节点的事件上下文信息
481
+ */
482
+ export interface InsertEventContext extends BaseEventContext {
483
+ region: string;
484
+ beforeId?: string;
485
+ index: number;
486
+ data: any;
487
+ subRenderer?: SubRendererInfo;
488
+ dragInfo?: {
489
+ id: string;
490
+ type: string;
491
+ data: any;
492
+ };
493
+ }
494
+
495
+ export interface ReplaceEventContext extends BaseEventContext {
496
+ data: any;
497
+ subRenderer?: SubRendererInfo;
498
+ region?: string;
499
+ }
500
+
501
+ export interface MoveEventContext extends BaseEventContext {
502
+ region: string;
503
+ sourceId: string;
504
+ beforeId?: string;
505
+ direction?: 'up' | 'down';
506
+ }
507
+
508
+ /**
509
+ * 更新节点的事件上下文
510
+ */
511
+ export interface ChangeEventContext extends BaseEventContext {
512
+ value: any;
513
+ readonly diff: Array<DiffChange>;
514
+ }
515
+
516
+ export interface DragEventContext extends EventContext {
517
+ mode: 'move' | 'copy';
518
+ sourceType: 'schema' | 'subrenderer' | string;
519
+ sourceId: string;
520
+ data: any;
521
+
522
+ targetId?: string;
523
+ targetRegion?: string;
524
+ }
525
+
526
+ export interface BuildPanelEventContext extends BaseEventContext {
527
+ data: Array<BasicPanelItem>;
528
+ selections: Array<BaseEventContext>;
529
+ }
530
+
531
+ export interface PreventClickEventContext extends EventContext {
532
+ data: MouseEvent;
533
+ }
534
+
535
+ export interface ResizeMoveEventContext extends EventContext {
536
+ data: Object;
537
+ nativeEvent: MouseEvent;
538
+ dom: HTMLElement;
539
+ resizer: HTMLElement;
540
+ node: EditorNodeType;
541
+ }
542
+
543
+ /**
544
+ * 将事件上下文转成事件对象。
545
+ */
546
+ export type PluginEvent<T, P = any> = {
547
+ context: T;
548
+ type: string;
549
+ preventDefault: () => void;
550
+ stopPropagation: () => void;
551
+ setData: (data: P) => void;
552
+
553
+ // 是否被阻止?
554
+ prevented?: boolean;
555
+ stoped?: boolean;
556
+
557
+ // 当前值
558
+ data?: P;
559
+ };
560
+
561
+ export type PluginEventFn = (e: PluginEvent<EventContext>) => false | void;
562
+
563
+ /**
564
+ * 创建事件。
565
+ * @param type
566
+ * @param context
567
+ */
568
+ export function createEvent<T extends EventContext>(
569
+ type: string,
570
+ context: T
571
+ ): PluginEvent<T> {
572
+ const event = {
573
+ context,
574
+ type,
575
+ prevented: false,
576
+ stoped: false,
577
+ preventDefault() {
578
+ event.prevented = true;
579
+ },
580
+ stopPropagation() {
581
+ event.stoped = true;
582
+ },
583
+ get data() {
584
+ return event.context.data;
585
+ },
586
+ setData(data: any) {
587
+ event.context.data = data;
588
+ }
589
+ };
590
+
591
+ return event;
592
+ }
593
+
594
+ export interface PluginEventListener {
595
+ onActive?: (event: PluginEvent<ActiveEventContext>) => void;
596
+
597
+ /**
598
+ * 事件,当有配置项插入前调用。通过 event.preventDefault() 可以干预。
599
+ */
600
+ beforeInsert?: (event: PluginEvent<InsertEventContext>) => false | void;
601
+ afterInsert?: (event: PluginEvent<InsertEventContext>) => void;
602
+
603
+ /**
604
+ * 面板里面编辑修改的事件。
605
+ */
606
+ beforeUpdate?: (event: PluginEvent<ChangeEventContext>) => false | void;
607
+ afterUpdate?: (event: PluginEvent<ChangeEventContext>) => void;
608
+
609
+ /**
610
+ * 更新渲染器,或者右键粘贴配置。
611
+ */
612
+ beforeReplace?: (event: PluginEvent<ReplaceEventContext>) => false | void;
613
+ afterReplace?: (event: PluginEvent<ReplaceEventContext>) => void;
614
+
615
+ /**
616
+ * 移动节点的时候触发,包括上移,下移
617
+ */
618
+ beforeMove?: (event: PluginEvent<MoveEventContext>) => false | void;
619
+ aftterMove?: (event: PluginEvent<MoveEventContext>) => void;
620
+
621
+ /**
622
+ * 删除的时候触发
623
+ */
624
+ beforeDelete?: (event: PluginEvent<DeleteEventContext>) => false | void;
625
+ afterDelete?: (event: PluginEvent<DeleteEventContext>) => void;
626
+
627
+ beforeResolveEditorInfo?: (
628
+ event: PluginEvent<RendererInfoResolveEventContext>
629
+ ) => false | void;
630
+ afterResolveEditorInfo?: (
631
+ event: PluginEvent<RendererInfoResolveEventContext>
632
+ ) => void;
633
+
634
+ beforeResolveJsonSchema?: (
635
+ event: PluginEvent<RendererJSONSchemaResolveEventContext>
636
+ ) => false | void;
637
+ afterResolveJsonSchema?: (
638
+ event: PluginEvent<RendererJSONSchemaResolveEventContext>
639
+ ) => void;
640
+
641
+ onDndAccept?: (event: PluginEvent<DragEventContext>) => false | void;
642
+
643
+ onBuildPanels?: (event: PluginEvent<BuildPanelEventContext>) => void;
644
+
645
+ onBuildContextMenus?: (event: PluginEvent<ContextMenuEventContext>) => void;
646
+
647
+ onSelectionChange?: (event: PluginEvent<SelectionEventContext>) => void;
648
+
649
+ onPreventClick?: (
650
+ event: PluginEvent<PreventClickEventContext>
651
+ ) => false | void;
652
+
653
+ onWidthChangeStart?: (
654
+ event: PluginEvent<
655
+ ResizeMoveEventContext,
656
+ {
657
+ onMove(e: MouseEvent): void;
658
+ onEnd(e: MouseEvent): void;
659
+ }
660
+ >
661
+ ) => void;
662
+
663
+ onHeightChangeStart?: (
664
+ event: PluginEvent<
665
+ ResizeMoveEventContext,
666
+ {
667
+ onMove(e: MouseEvent): void;
668
+ onEnd(e: MouseEvent): void;
669
+ }
670
+ >
671
+ ) => void;
672
+
673
+ onSizeChangeStart?: (
674
+ event: PluginEvent<
675
+ ResizeMoveEventContext,
676
+ {
677
+ onMove(e: MouseEvent): void;
678
+ onEnd(e: MouseEvent): void;
679
+ }
680
+ >
681
+ ) => void;
682
+ }
683
+
684
+ /**
685
+ * 插件的 interface 定义
686
+ */
687
+ export interface PluginInterface
688
+ extends Partial<BasicRendererInfo>,
689
+ Partial<BasicSubRenderInfo>,
690
+ PluginEventListener {
691
+ readonly manager: EditorManager;
692
+
693
+ order?: number;
694
+
695
+ /**
696
+ * 渲染器的名字,关联后不用自己实现 getRendererInfo 了。
697
+ */
698
+ rendererName?: string;
699
+
700
+ /**
701
+ * 默认的配置面板信息
702
+ */
703
+ panelIcon?: string;
704
+ panelTitle?: string;
705
+
706
+ /**
707
+ * 新增属性,用于判断是否出现在组件面板中,默认为false,为ture则不展示
708
+ */
709
+ disabledRendererPlugin?: boolean;
710
+
711
+ /**
712
+ * @deprecated 用 panelBody
713
+ */
714
+ panelControls?: Array<any>;
715
+ panelBody?: Array<any>;
716
+ panelDefinitions?: any;
717
+ panelApi?: any;
718
+ panelSubmitOnChange?: boolean;
719
+
720
+ /**
721
+ * @deprecated 用 panelBodyCreator
722
+ */
723
+ panelControlsCreator?: (context: BaseEventContext) => Array<any>;
724
+ panelBodyCreator?: (context: BaseEventContext) => Array<any>;
725
+
726
+ popOverBody?: Array<any>;
727
+ popOverBodyCreator?: (context: BaseEventContext) => Array<any>;
728
+
729
+ /**
730
+ * 返回渲染器信息。不是每个插件都需要。
731
+ */
732
+ getRendererInfo?: (
733
+ context: RendererInfoResolveEventContext
734
+ ) => BasicRendererInfo | void;
735
+
736
+ /**
737
+ * 生成节点的 JSON Schema 的 uri 地址。
738
+ */
739
+ buildJSONSchema?: (
740
+ context: RendererJSONSchemaResolveEventContext
741
+ ) => void | string;
742
+
743
+ /**
744
+ * 构建右上角功能按钮集合
745
+ */
746
+ buildEditorToolbar?: (
747
+ context: BaseEventContext,
748
+ toolbars: Array<BasicToolbarItem>
749
+ ) => void;
750
+
751
+ /**
752
+ * 构建右键菜单项
753
+ */
754
+ buildEditorContextMenu?: (
755
+ context: ContextMenuEventContext,
756
+ menus: Array<ContextMenuItem>
757
+ ) => void;
758
+
759
+ /**
760
+ * 构建编辑器面板。
761
+ */
762
+ buildEditorPanel?: (
763
+ context: BuildPanelEventContext,
764
+ panels: Array<BasicPanelItem>
765
+ ) => void;
766
+
767
+ /**
768
+ * 构建子渲染器信息集合。
769
+ */
770
+ buildSubRenderers?: (
771
+ context: RendererEventContext,
772
+ subRenderers: Array<SubRendererInfo>,
773
+ renderers: Array<RendererConfig>
774
+ ) => BasicSubRenderInfo | Array<BasicSubRenderInfo> | void;
775
+
776
+ /**
777
+ * 更新NPM自定义组件分类和排序[异步方法]
778
+ * 备注:目前主要在npm自定义组件的分类和排序更新中使用
779
+ */
780
+ asyncUpdateCustomSubRenderersInfo?: (
781
+ context: RendererEventContext,
782
+ subRenderers: Array<SubRendererInfo>,
783
+ renderers: Array<RendererConfig>
784
+ ) => void;
785
+
786
+ markDom?: (dom: HTMLElement | Array<HTMLElement>, props: any) => void;
787
+ }
788
+
789
+ /**
790
+ * 基类,所有插件都继承这个好了,可以少写些逻辑。
791
+ */
792
+ export abstract class BasePlugin implements PluginInterface {
793
+ constructor(readonly manager: EditorManager) {}
794
+
795
+ /**
796
+ * 如果配置里面有 rendererName 自动返回渲染器信息。
797
+ * @param renderer
798
+ */
799
+ getRendererInfo({
800
+ renderer,
801
+ schema
802
+ }: RendererInfoResolveEventContext): BasicRendererInfo | void {
803
+ const plugin: PluginInterface = this;
804
+
805
+ if (
806
+ schema.$$id &&
807
+ plugin.name &&
808
+ plugin.rendererName &&
809
+ plugin.rendererName === renderer.name // renderer.name 会从 renderer.type 中取值
810
+ ) {
811
+ // 复制部分信息出去
812
+ return {
813
+ name: plugin.name,
814
+ regions: plugin.regions,
815
+ patchContainers: plugin.patchContainers,
816
+ // wrapper: plugin.wrapper,
817
+ vRendererConfig: plugin.vRendererConfig,
818
+ wrapperProps: plugin.wrapperProps,
819
+ wrapperResolve: plugin.wrapperResolve,
820
+ filterProps: plugin.filterProps,
821
+ $schema: plugin.$schema,
822
+ renderRenderer: plugin.renderRenderer,
823
+ multifactor: plugin.multifactor,
824
+ scaffoldForm: plugin.scaffoldForm,
825
+ disabledRendererPlugin: plugin.disabledRendererPlugin,
826
+ isBaseComponent: plugin.isBaseComponent,
827
+ rendererName: plugin.rendererName
828
+ };
829
+ }
830
+ }
831
+
832
+ /**
833
+ * 配置了 panelControls 自动生成配置面板
834
+ * @param context
835
+ * @param panels
836
+ */
837
+ buildEditorPanel(
838
+ context: BuildPanelEventContext,
839
+ panels: Array<BasicPanelItem>
840
+ ) {
841
+ const plugin: PluginInterface = this;
842
+
843
+ // 多选时不处理
844
+ if (context.selections.length) {
845
+ return;
846
+ }
847
+
848
+ if (
849
+ !context.info.hostId &&
850
+ (plugin.panelControls ||
851
+ plugin.panelControlsCreator ||
852
+ plugin.panelBody ||
853
+ plugin.panelBodyCreator) &&
854
+ context.info.plugin === this
855
+ ) {
856
+ panels.push({
857
+ key: 'config',
858
+ icon: plugin.panelIcon || plugin.icon || 'fa fa-cog',
859
+ title: plugin.panelTitle || '设置',
860
+ render: this.manager.makeSchemaFormRender({
861
+ definitions: plugin.panelDefinitions,
862
+ submitOnChange: plugin.panelSubmitOnChange,
863
+ api: plugin.panelApi,
864
+ body: plugin.panelBodyCreator
865
+ ? plugin.panelBodyCreator(context)
866
+ : plugin.panelBody!,
867
+ controls: plugin.panelControlsCreator
868
+ ? plugin.panelControlsCreator(context)
869
+ : plugin.panelControls!
870
+ })
871
+ });
872
+ } else if (
873
+ context.info.plugin === this &&
874
+ context.info.hostId &&
875
+ (plugin.vRendererConfig?.panelControls ||
876
+ plugin.vRendererConfig?.panelControlsCreator ||
877
+ plugin.vRendererConfig?.panelBody ||
878
+ plugin.vRendererConfig?.panelBodyCreator)
879
+ ) {
880
+ panels.push({
881
+ key: context.info.multifactor ? 'vconfig' : 'config',
882
+ icon: plugin.vRendererConfig.panelIcon || 'fa fa-cog',
883
+ title: plugin.vRendererConfig.panelTitle || '设置',
884
+ render: this.manager.makeSchemaFormRender({
885
+ submitOnChange: plugin.panelSubmitOnChange,
886
+ api: plugin.panelApi,
887
+ definitions: plugin.vRendererConfig.panelDefinitions,
888
+ controls: plugin.vRendererConfig.panelControlsCreator
889
+ ? plugin.vRendererConfig.panelControlsCreator(context)
890
+ : plugin.vRendererConfig.panelControls!,
891
+ body: plugin.vRendererConfig.panelBodyCreator
892
+ ? plugin.vRendererConfig.panelBodyCreator(context)
893
+ : plugin.vRendererConfig.panelBody!
894
+ })
895
+ });
896
+ }
897
+
898
+ // 如果是个多重身份证
899
+ if (context.info.plugin === this && context.info.multifactor) {
900
+ const sameIdChild: EditorNodeType = context.node.sameIdChild;
901
+
902
+ if (sameIdChild) {
903
+ const subPanels = this.manager.collectPanels(sameIdChild, false, true);
904
+ subPanels.forEach(panel => {
905
+ if (panel.key === 'code') {
906
+ const exists = panels.some(panel => panel.key === 'code');
907
+ exists || panels.push(panel);
908
+ } else if (panel.key === 'renderers') {
909
+ const exists = panels.some(panel => panel.key === 'renderers');
910
+ exists || panels.push(panel);
911
+ } else if (
912
+ panel.key === 'outline' ||
913
+ panel.key === 'commonConfig' ||
914
+ panel.key === 'name-list'
915
+ ) {
916
+ // do nothing
917
+ } else {
918
+ panels.push({
919
+ ...panel,
920
+ key: `sub-${panel.key}`,
921
+ icon: sameIdChild.info?.plugin?.icon || panel.icon
922
+ });
923
+ }
924
+ });
925
+ }
926
+ }
927
+ }
928
+
929
+ /**
930
+ * 默认什么组件都加入的子组件里面,子类里面可以复写这个改变行为。
931
+ * @param context
932
+ * @param subRenderers
933
+ */
934
+ buildSubRenderers(
935
+ context: RendererEventContext,
936
+ subRenderers: Array<SubRendererInfo>,
937
+ renderers: Array<RendererConfig>
938
+ ): BasicSubRenderInfo | Array<BasicSubRenderInfo> | void {
939
+ const plugin: PluginInterface = this;
940
+
941
+ if (Array.isArray(plugin.scaffolds)) {
942
+ return plugin.scaffolds.map(scaffold => ({
943
+ name: (scaffold.name ?? plugin.name)!,
944
+ icon: scaffold.icon ?? plugin.icon,
945
+ description: scaffold.description ?? plugin.description,
946
+ previewSchema: scaffold.previewSchema ?? plugin.previewSchema,
947
+ tags: scaffold.tags ?? plugin.tags,
948
+ docLink: scaffold.docLink ?? plugin.docLink,
949
+ type: scaffold.type ?? plugin.type,
950
+ scaffold: scaffold.scaffold ?? plugin.scaffold,
951
+ scaffoldForm: plugin.scaffoldForm,
952
+ disabledRendererPlugin: plugin.disabledRendererPlugin,
953
+ isBaseComponent: plugin.isBaseComponent,
954
+ rendererName: plugin.rendererName
955
+ }));
956
+ } else if (plugin.name && plugin.description) {
957
+ return {
958
+ name: plugin.name,
959
+ icon: plugin.icon,
960
+ description: plugin.description,
961
+ previewSchema: plugin.previewSchema,
962
+ tags: plugin.tags,
963
+ docLink: plugin.docLink,
964
+ type: plugin.type,
965
+ scaffold: plugin.scaffold,
966
+ scaffoldForm: plugin.scaffoldForm,
967
+ disabledRendererPlugin: plugin.disabledRendererPlugin,
968
+ isBaseComponent: plugin.isBaseComponent,
969
+ rendererName: plugin.rendererName
970
+ };
971
+ }
972
+ }
973
+
974
+ /**
975
+ * 构建当前选中组件的右键菜单
976
+ * @param id
977
+ * @param schema
978
+ * @param region
979
+ * @param info
980
+ * @param menus
981
+ */
982
+ buildEditorContextMenu(
983
+ {id, schema, region, info, selections}: ContextMenuEventContext,
984
+ menus: Array<ContextMenuItem>
985
+ ) {
986
+ const plugin: PluginInterface = this;
987
+ if (
988
+ info.plugin === plugin &&
989
+ !selections.length &&
990
+ (plugin.scaffoldForm?.canRebuild || info.scaffoldForm?.canRebuild)
991
+ ) {
992
+ menus.push({
993
+ label: `快速构建「${info.plugin.name}」`,
994
+ disabled: schema.$$commonSchema,
995
+ onSelect: () =>
996
+ this.manager.reScaffold(
997
+ id,
998
+ info.scaffoldForm || plugin.scaffoldForm!,
999
+ schema
1000
+ )
1001
+ });
1002
+ }
1003
+ }
1004
+
1005
+ buildEditorToolbar(
1006
+ {id, schema, info}: BaseEventContext,
1007
+ toolbars: Array<BasicToolbarItem>
1008
+ ) {
1009
+ const plugin: PluginInterface = this;
1010
+ if (
1011
+ info.plugin === plugin &&
1012
+ (plugin.scaffoldForm?.canRebuild || info.scaffoldForm?.canRebuild)
1013
+ ) {
1014
+ toolbars.push({
1015
+ iconSvg: 'harmmer',
1016
+ tooltip: `快速构建「${info.plugin.name}」`,
1017
+ placement: 'bottom',
1018
+ onClick: () =>
1019
+ this.manager.reScaffold(
1020
+ id,
1021
+ info.scaffoldForm || plugin.scaffoldForm!,
1022
+ schema
1023
+ )
1024
+ });
1025
+ }
1026
+ }
1027
+
1028
+ renderPlaceholder(text: string, key?: any) {
1029
+ return React.createElement('div', {
1030
+ key,
1031
+ className: 'wrapper-sm b-a b-light m-b-sm',
1032
+ children: React.createElement('span', {
1033
+ className: 'text-muted',
1034
+ children: text
1035
+ })
1036
+ });
1037
+ }
1038
+
1039
+ getPlugin(rendererNameOrKlass: string | typeof BasePlugin) {
1040
+ return find(this.manager.plugins, plugin =>
1041
+ typeof rendererNameOrKlass === 'string'
1042
+ ? plugin.rendererName === rendererNameOrKlass
1043
+ : plugin instanceof rendererNameOrKlass
1044
+ );
1045
+ }
1046
+ }