pict-section-formeditor 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +118 -0
  3. package/docs/.nojekyll +0 -0
  4. package/docs/README.md +162 -0
  5. package/docs/_sidebar.md +23 -0
  6. package/docs/_topbar.md +5 -0
  7. package/docs/cover.md +12 -0
  8. package/docs/css/docuserve.css +73 -0
  9. package/docs/index.html +39 -0
  10. package/docs/retold-catalog.json +224 -0
  11. package/docs/retold-keyword-index.json +46846 -0
  12. package/example_applications/form_editor/.quackage.json +10 -0
  13. package/example_applications/form_editor/FormEditor-Example-Application.js +226 -0
  14. package/example_applications/form_editor/html/icon-chooser.html +375 -0
  15. package/example_applications/form_editor/html/index.html +54 -0
  16. package/example_applications/form_editor/package.json +50 -0
  17. package/package.json +55 -0
  18. package/sample_manifests/Complex-Table.json +974 -0
  19. package/sample_manifests/Distill-Example.json +200 -0
  20. package/sample_manifests/Gradebook-Assignment.json +38 -0
  21. package/sample_manifests/Gradebook-Student.json +40 -0
  22. package/sample_manifests/Manyfest-Editor.json +347 -0
  23. package/sample_manifests/Simple-Form.json +232 -0
  24. package/sample_manifests/Simple-Table.json +79 -0
  25. package/source/Pict-Section-FormEditor-DefaultConfiguration.js +3321 -0
  26. package/source/Pict-Section-FormEditor.js +35 -0
  27. package/source/providers/Pict-Provider-ChildPictManager-Application.js +40 -0
  28. package/source/providers/Pict-Provider-ChildPictManager.js +238 -0
  29. package/source/providers/Pict-Provider-FormEditorDocumentation.js +356 -0
  30. package/source/providers/Pict-Provider-FormEditorDragDrop.js +535 -0
  31. package/source/providers/Pict-Provider-FormEditorIconography.js +1002 -0
  32. package/source/providers/Pict-Provider-FormEditorManifestOps.js +1443 -0
  33. package/source/providers/Pict-Provider-FormEditorRendering.js +730 -0
  34. package/source/providers/Pict-Provider-FormEditorUtilities.js +862 -0
  35. package/source/providers/Pict-Provider-PreviewCSS.js +42 -0
  36. package/source/views/PictView-FormEditor-InlineEditing.js +309 -0
  37. package/source/views/PictView-FormEditor-InputTypePicker.js +532 -0
  38. package/source/views/PictView-FormEditor-PropertiesPanel.js +7730 -0
  39. package/source/views/PictView-FormEditor.js +681 -0
  40. package/test/Pict-Section-FormEditor_tests.js +4102 -0
  41. package/user-documentation/.pict_documentation_topics.json +695 -0
  42. package/user-documentation/Getting-Started.md +32 -0
  43. package/user-documentation/Groups.md +52 -0
  44. package/user-documentation/Inputs.md +98 -0
  45. package/user-documentation/Sections.md +36 -0
  46. package/user-documentation/Shortcuts.md +44 -0
  47. package/user-documentation/Solver-Expression-Walkthrough.md +176 -0
  48. package/user-documentation/Solver-Expressions-Advanced.md +344 -0
  49. package/user-documentation/Solver-Functions.md +213 -0
  50. package/user-documentation/Solvers.md +81 -0
  51. package/user-documentation/ToC.md +18 -0
  52. package/user-documentation/solverfunctions/abs.md +84 -0
  53. package/user-documentation/solverfunctions/aggregationhistogram.md +83 -0
  54. package/user-documentation/solverfunctions/aggregationhistogrambyobject.md +64 -0
  55. package/user-documentation/solverfunctions/arrayconcat.md +64 -0
  56. package/user-documentation/solverfunctions/avg.md +81 -0
  57. package/user-documentation/solverfunctions/bucketset.md +69 -0
  58. package/user-documentation/solverfunctions/ceil.md +70 -0
  59. package/user-documentation/solverfunctions/cleanvaluearray.md +66 -0
  60. package/user-documentation/solverfunctions/cleanvalueobject.md +68 -0
  61. package/user-documentation/solverfunctions/colorgroupbackground.md +60 -0
  62. package/user-documentation/solverfunctions/colorinputbackground.md +62 -0
  63. package/user-documentation/solverfunctions/colorinputbackgroundtabular.md +64 -0
  64. package/user-documentation/solverfunctions/colorsectionbackground.md +59 -0
  65. package/user-documentation/solverfunctions/compare.md +72 -0
  66. package/user-documentation/solverfunctions/concat.md +73 -0
  67. package/user-documentation/solverfunctions/concatraw.md +73 -0
  68. package/user-documentation/solverfunctions/cos.md +75 -0
  69. package/user-documentation/solverfunctions/count.md +73 -0
  70. package/user-documentation/solverfunctions/countset.md +65 -0
  71. package/user-documentation/solverfunctions/countsetelements.md +63 -0
  72. package/user-documentation/solverfunctions/createarrayfromabsolutevalues.md +63 -0
  73. package/user-documentation/solverfunctions/createvalueobjectbyhashes.md +69 -0
  74. package/user-documentation/solverfunctions/cumulativesummation.md +96 -0
  75. package/user-documentation/solverfunctions/dateadddays.md +79 -0
  76. package/user-documentation/solverfunctions/dateaddhours.md +74 -0
  77. package/user-documentation/solverfunctions/dateaddmilliseconds.md +65 -0
  78. package/user-documentation/solverfunctions/dateaddminutes.md +72 -0
  79. package/user-documentation/solverfunctions/dateaddmonths.md +74 -0
  80. package/user-documentation/solverfunctions/dateaddseconds.md +66 -0
  81. package/user-documentation/solverfunctions/dateaddweeks.md +73 -0
  82. package/user-documentation/solverfunctions/dateaddyears.md +74 -0
  83. package/user-documentation/solverfunctions/datedaydifference.md +84 -0
  84. package/user-documentation/solverfunctions/datefromparts.md +81 -0
  85. package/user-documentation/solverfunctions/datehourdifference.md +64 -0
  86. package/user-documentation/solverfunctions/datemathadd.md +72 -0
  87. package/user-documentation/solverfunctions/datemilliseconddifference.md +64 -0
  88. package/user-documentation/solverfunctions/dateminutedifference.md +64 -0
  89. package/user-documentation/solverfunctions/datemonthdifference.md +66 -0
  90. package/user-documentation/solverfunctions/dateseconddifference.md +64 -0
  91. package/user-documentation/solverfunctions/dateweekdifference.md +65 -0
  92. package/user-documentation/solverfunctions/dateyeardifference.md +64 -0
  93. package/user-documentation/solverfunctions/differencearrays.md +59 -0
  94. package/user-documentation/solverfunctions/disablesolverordinal.md +58 -0
  95. package/user-documentation/solverfunctions/distributionhistogram.md +96 -0
  96. package/user-documentation/solverfunctions/distributionhistogrambyobject.md +64 -0
  97. package/user-documentation/solverfunctions/enablesolverordinal.md +57 -0
  98. package/user-documentation/solverfunctions/entryinset.md +72 -0
  99. package/user-documentation/solverfunctions/euler.md +77 -0
  100. package/user-documentation/solverfunctions/exp.md +74 -0
  101. package/user-documentation/solverfunctions/findfirstvaluebyexactmatch.md +67 -0
  102. package/user-documentation/solverfunctions/findfirstvaluebystringincludes.md +67 -0
  103. package/user-documentation/solverfunctions/flatten.md +76 -0
  104. package/user-documentation/solverfunctions/floor.md +70 -0
  105. package/user-documentation/solverfunctions/gaussianelimination.md +75 -0
  106. package/user-documentation/solverfunctions/generatearrayofobjectsfromsets.md +70 -0
  107. package/user-documentation/solverfunctions/generatehtmlhexcolor.md +67 -0
  108. package/user-documentation/solverfunctions/getvalue.md +90 -0
  109. package/user-documentation/solverfunctions/getvaluearray.md +64 -0
  110. package/user-documentation/solverfunctions/getvalueobject.md +67 -0
  111. package/user-documentation/solverfunctions/hidesections.md +58 -0
  112. package/user-documentation/solverfunctions/if.md +109 -0
  113. package/user-documentation/solverfunctions/iterativeseries.md +107 -0
  114. package/user-documentation/solverfunctions/join.md +75 -0
  115. package/user-documentation/solverfunctions/joinraw.md +64 -0
  116. package/user-documentation/solverfunctions/largestinset.md +63 -0
  117. package/user-documentation/solverfunctions/leastsquares.md +66 -0
  118. package/user-documentation/solverfunctions/linest.md +58 -0
  119. package/user-documentation/solverfunctions/log.md +74 -0
  120. package/user-documentation/solverfunctions/logvalues.md +65 -0
  121. package/user-documentation/solverfunctions/match.md +71 -0
  122. package/user-documentation/solverfunctions/matrixinverse.md +67 -0
  123. package/user-documentation/solverfunctions/matrixmultiply.md +71 -0
  124. package/user-documentation/solverfunctions/matrixtranspose.md +72 -0
  125. package/user-documentation/solverfunctions/matrixvectormultiply.md +69 -0
  126. package/user-documentation/solverfunctions/max.md +73 -0
  127. package/user-documentation/solverfunctions/mean.md +63 -0
  128. package/user-documentation/solverfunctions/median.md +79 -0
  129. package/user-documentation/solverfunctions/min.md +73 -0
  130. package/user-documentation/solverfunctions/mode.md +66 -0
  131. package/user-documentation/solverfunctions/objectkeystoarray.md +66 -0
  132. package/user-documentation/solverfunctions/objectvaluessortbyexternalobjectarray.md +65 -0
  133. package/user-documentation/solverfunctions/objectvaluestoarray.md +67 -0
  134. package/user-documentation/solverfunctions/percent.md +75 -0
  135. package/user-documentation/solverfunctions/pi.md +77 -0
  136. package/user-documentation/solverfunctions/polynomialregression.md +69 -0
  137. package/user-documentation/solverfunctions/predict.md +71 -0
  138. package/user-documentation/solverfunctions/rad.md +85 -0
  139. package/user-documentation/solverfunctions/randomfloat.md +63 -0
  140. package/user-documentation/solverfunctions/randomfloatbetween.md +72 -0
  141. package/user-documentation/solverfunctions/randomfloatupto.md +65 -0
  142. package/user-documentation/solverfunctions/randominteger.md +56 -0
  143. package/user-documentation/solverfunctions/randomintegerbetween.md +72 -0
  144. package/user-documentation/solverfunctions/randomintegerupto.md +64 -0
  145. package/user-documentation/solverfunctions/refreshtabularsection.md +57 -0
  146. package/user-documentation/solverfunctions/resolvehtmlentities.md +64 -0
  147. package/user-documentation/solverfunctions/round.md +111 -0
  148. package/user-documentation/solverfunctions/runsolvers.md +49 -0
  149. package/user-documentation/solverfunctions/setconcatenate.md +64 -0
  150. package/user-documentation/solverfunctions/setgroupvisibility.md +60 -0
  151. package/user-documentation/solverfunctions/setsectionvisibility.md +59 -0
  152. package/user-documentation/solverfunctions/setsolverordinalenabled.md +59 -0
  153. package/user-documentation/solverfunctions/settabularrowlength.md +57 -0
  154. package/user-documentation/solverfunctions/setvalue.md +65 -0
  155. package/user-documentation/solverfunctions/showsections.md +58 -0
  156. package/user-documentation/solverfunctions/sin.md +83 -0
  157. package/user-documentation/solverfunctions/slice.md +80 -0
  158. package/user-documentation/solverfunctions/smallestinset.md +63 -0
  159. package/user-documentation/solverfunctions/sortarray.md +58 -0
  160. package/user-documentation/solverfunctions/sorthistogram.md +70 -0
  161. package/user-documentation/solverfunctions/sorthistogrambykeys.md +69 -0
  162. package/user-documentation/solverfunctions/sortset.md +75 -0
  163. package/user-documentation/solverfunctions/sqrt.md +85 -0
  164. package/user-documentation/solverfunctions/stdev.md +81 -0
  165. package/user-documentation/solverfunctions/stdeva.md +58 -0
  166. package/user-documentation/solverfunctions/stdevp.md +83 -0
  167. package/user-documentation/solverfunctions/stringcountsegments.md +66 -0
  168. package/user-documentation/solverfunctions/stringgetsegments.md +74 -0
  169. package/user-documentation/solverfunctions/subtractingsummation.md +66 -0
  170. package/user-documentation/solverfunctions/sum.md +78 -0
  171. package/user-documentation/solverfunctions/tan.md +78 -0
  172. package/user-documentation/solverfunctions/tofixed.md +75 -0
  173. package/user-documentation/solverfunctions/unionarrays.md +59 -0
  174. package/user-documentation/solverfunctions/uniquearray.md +58 -0
  175. package/user-documentation/solverfunctions/var.md +67 -0
  176. package/user-documentation/solverfunctions/vara.md +58 -0
  177. package/user-documentation/solverfunctions/varp.md +66 -0
  178. package/user-documentation/solverfunctions/when.md +98 -0
@@ -0,0 +1,681 @@
1
+ const libPictView = require('pict-view');
2
+ const libPictSectionObjectEditor = require('pict-section-objecteditor');
3
+ const libPictSectionCode = require('pict-section-code');
4
+ const libPictSectionContent = require('pict-section-content');
5
+
6
+ const _DefaultConfiguration = require('../Pict-Section-FormEditor-DefaultConfiguration.js');
7
+ const libFormEditorIconography = require('../providers/Pict-Provider-FormEditorIconography.js');
8
+ const libFormEditorUtilities = require('../providers/Pict-Provider-FormEditorUtilities.js');
9
+ const libFormEditorDragDrop = require('../providers/Pict-Provider-FormEditorDragDrop.js');
10
+ const libFormEditorInlineEditing = require('./PictView-FormEditor-InlineEditing.js');
11
+ const libFormEditorInputTypePicker = require('./PictView-FormEditor-InputTypePicker.js');
12
+ const libFormEditorRendering = require('../providers/Pict-Provider-FormEditorRendering.js');
13
+ const libFormEditorManifestOps = require('../providers/Pict-Provider-FormEditorManifestOps.js');
14
+ const libChildPictManager = require('../providers/Pict-Provider-ChildPictManager.js');
15
+ const libPreviewCSS = require('../providers/Pict-Provider-PreviewCSS.js');
16
+ const libFormEditorDocumentation = require('../providers/Pict-Provider-FormEditorDocumentation.js');
17
+
18
+ class PictViewFormEditor extends libPictView
19
+ {
20
+ constructor(pFable, pOptions, pServiceHash)
21
+ {
22
+ let tmpOptions = Object.assign({}, JSON.parse(JSON.stringify(_DefaultConfiguration)), pOptions);
23
+
24
+ if (!tmpOptions.ManifestDataAddress)
25
+ {
26
+ tmpOptions.ManifestDataAddress = 'FormEditor.Manifest';
27
+ }
28
+
29
+ super(pFable, tmpOptions, pServiceHash);
30
+
31
+ this._ActiveTab = tmpOptions.ActiveTab || 'visual';
32
+
33
+ // Child view references
34
+ this._ObjectEditorView = null;
35
+ this._CodeEditorView = null;
36
+ this._SolverCodeEditorView = null;
37
+ this._HelpContentView = null;
38
+ this._HelpContentProvider = null;
39
+ this._DocumentationProvider = null;
40
+
41
+ // Supported Manyfest DataTypes
42
+ this._ManyfestDataTypes =
43
+ [
44
+ 'String',
45
+ 'Number',
46
+ 'Float',
47
+ 'Integer',
48
+ 'PreciseNumber',
49
+ 'Boolean',
50
+ 'Binary',
51
+ 'DateTime',
52
+ 'Array',
53
+ 'Object',
54
+ 'Null'
55
+ ];
56
+
57
+
58
+ // Create the iconography provider
59
+ this._IconographyProvider = new libFormEditorIconography(tmpOptions.Iconography || {});
60
+
61
+ // Create the child pict manager provider for managing any embedded pict instances (e.g. the solver editor)
62
+ let tmpChildPictManagerHash = `${pServiceHash || 'FormEditor'}-ChildPictManager`;
63
+ this._ChildPictManager = this.pict.addProvider(tmpChildPictManagerHash, {}, libChildPictManager );
64
+
65
+ // Create the preview CSS provider so the child pict form preview
66
+ // injects its CSS into a dedicated <style> element rather than #PICT-CSS
67
+ let tmpPreviewCSSHash = `${pServiceHash || 'FormEditor'}-PreviewCSS`;
68
+ this._PreviewCSSProvider = this.pict.addProvider(tmpPreviewCSSHash, {}, libPreviewCSS);
69
+
70
+ // Create the drag-and-drop provider
71
+ let tmpDragDropHash = `${pServiceHash || 'FormEditor'}-DragDrop`;
72
+ this._DragDropProvider = this.pict.addProvider(
73
+ tmpDragDropHash,
74
+ {},
75
+ libFormEditorDragDrop
76
+ );
77
+ this._DragDropProvider._ParentFormEditor = this;
78
+ // Create the utilities provider
79
+ let tmpUtilitiesHash = `${pServiceHash || 'FormEditor'}-Utilities`;
80
+ this._UtilitiesProvider = this.pict.addProvider(
81
+ tmpUtilitiesHash,
82
+ {},
83
+ libFormEditorUtilities
84
+ );
85
+ this._UtilitiesProvider._ParentFormEditor = this;
86
+
87
+ // Create the manifest operations provider
88
+ let tmpManifestOpsHash = `${pServiceHash || 'FormEditor'}-ManifestOps`;
89
+ this._ManifestOpsProvider = this.pict.addProvider(
90
+ tmpManifestOpsHash,
91
+ {},
92
+ libFormEditorManifestOps
93
+ );
94
+ this._ManifestOpsProvider._ParentFormEditor = this;
95
+
96
+ // Create the rendering provider
97
+ let tmpRenderingHash = `${pServiceHash || 'FormEditor'}-Rendering`;
98
+ this._RenderingProvider = this.pict.addProvider(
99
+ tmpRenderingHash,
100
+ {},
101
+ libFormEditorRendering
102
+ );
103
+ this._RenderingProvider._ParentFormEditor = this;
104
+
105
+ // Create the documentation provider for the embedded help system
106
+ let tmpDocumentationHash = `${pServiceHash || 'FormEditor'}-Documentation`;
107
+ this._DocumentationProvider = this.pict.addProvider(
108
+ tmpDocumentationHash,
109
+ {},
110
+ libFormEditorDocumentation
111
+ );
112
+ this._DocumentationProvider._ParentFormEditor = this;
113
+
114
+ // Create the help content provider (PictContentProvider for markdown parsing)
115
+ let tmpHelpContentProviderHash = `${pServiceHash || 'FormEditor'}-HelpContentProvider`;
116
+ this._HelpContentProvider = this.pict.addProvider(
117
+ tmpHelpContentProviderHash,
118
+ {},
119
+ libPictSectionContent.PictContentProvider
120
+ );
121
+
122
+ // Create the inline editing child view
123
+ let tmpInlineEditHash = `${pServiceHash || 'FormEditor'}-InlineEditing`;
124
+ this._InlineEditingView = this.pict.addView(
125
+ tmpInlineEditHash,
126
+ { ViewIdentifier: tmpInlineEditHash, AutoRender: false },
127
+ libFormEditorInlineEditing
128
+ );
129
+ this._InlineEditingView._ParentFormEditor = this;
130
+
131
+ // Create the input type picker child view
132
+ let tmpInputTypePickerHash = `${pServiceHash || 'FormEditor'}-InputTypePicker`;
133
+ this._InputTypePickerView = this.pict.addView(
134
+ tmpInputTypePickerHash,
135
+ { ViewIdentifier: tmpInputTypePickerHash, AutoRender: false },
136
+ libFormEditorInputTypePicker
137
+ );
138
+ this._InputTypePickerView._ParentFormEditor = this;
139
+
140
+ // Build the InputType definitions from defaults + any embedder overrides
141
+ this._InputTypeDefinitions = this._UtilitiesProvider._buildInputTypeDefinitions(tmpOptions);
142
+
143
+ // Drag-and-drop state (opt-in, disabled by default)
144
+ this._DragAndDropEnabled = false;
145
+ this._DragState = null;
146
+
147
+ // Input display mode: 'name' shows Name, 'hash' shows Hash
148
+ this._InputDisplayMode = 'name';
149
+
150
+ // Selected input for the properties panel
151
+ this._SelectedInputIndices = null;
152
+
153
+ // Selected submanifest column for Tabular/RecordSet groups
154
+ this._SelectedTabularColumn = null;
155
+
156
+ // Selected section/group for the properties panel
157
+ this._SelectedSectionIndex = null;
158
+ this._SelectedGroupIndices = null;
159
+
160
+ // Properties panel state
161
+ this._PanelCollapsed = false;
162
+ this._PanelActiveTab = 'form';
163
+ this._PanelWidth = 300;
164
+ this._PanelResizing = false;
165
+
166
+ // Restore panel width from localStorage
167
+ if (typeof localStorage !== 'undefined')
168
+ {
169
+ try
170
+ {
171
+ let tmpStoredWidth = localStorage.getItem('pict-fe-panel-width');
172
+ if (tmpStoredWidth)
173
+ {
174
+ let tmpParsed = parseInt(tmpStoredWidth, 10);
175
+ if (!isNaN(tmpParsed) && tmpParsed >= 240)
176
+ {
177
+ this._PanelWidth = tmpParsed;
178
+ }
179
+ }
180
+ }
181
+ catch (pError)
182
+ {
183
+ // localStorage may throw in restrictive environments
184
+ }
185
+ }
186
+
187
+ // Properties panel child view reference
188
+ this._PropertiesPanelView = null;
189
+ }
190
+
191
+ /* -------------------------------------------------------------------------- */
192
+ /* Code Section: Initialization */
193
+ /* -------------------------------------------------------------------------- */
194
+
195
+ onBeforeInitialize()
196
+ {
197
+ super.onBeforeInitialize();
198
+
199
+ // Ensure the manifest data address exists in AppData
200
+ let tmpManifest = this._resolveManifestData();
201
+ if (!tmpManifest)
202
+ {
203
+ this._setManifestData(this._createEmptyManifest());
204
+ }
205
+ }
206
+
207
+ onAfterInitialize()
208
+ {
209
+ super.onAfterInitialize();
210
+
211
+ // Register the object editor service type if not already registered
212
+ if (!this.fable.servicesMap.hasOwnProperty('PictSectionObjectEditor'))
213
+ {
214
+ this.fable.addServiceType('PictSectionObjectEditor', libPictSectionObjectEditor);
215
+ }
216
+
217
+ // Create the object editor child view
218
+ let tmpViewHash = `${this.Hash}-ObjectEditor`;
219
+ this._ObjectEditorView = this.pict.addView(
220
+ tmpViewHash,
221
+ {
222
+ ViewIdentifier: tmpViewHash,
223
+ ObjectDataAddress: this.options.ManifestDataAddress,
224
+ DefaultDestinationAddress: `#FormEditor-ObjectEditor-Container-${this.Hash}`,
225
+ InitialExpandDepth: 2,
226
+ Editable: true,
227
+ ShowTypeIndicators: true,
228
+ AutoRender: false,
229
+ Renderables:
230
+ [
231
+ {
232
+ RenderableHash: 'ObjectEditor-Container',
233
+ TemplateHash: 'ObjectEditor-Container-Template',
234
+ DestinationAddress: `#FormEditor-ObjectEditor-Container-${this.Hash}`,
235
+ RenderMethod: 'replace'
236
+ }
237
+ ]
238
+ },
239
+ libPictSectionObjectEditor
240
+ );
241
+ this._ObjectEditorView.initialize();
242
+
243
+ // Create the properties panel child view
244
+ let tmpPropertiesPanelView = require('./PictView-FormEditor-PropertiesPanel.js');
245
+ let tmpPropsPanelHash = `${this.Hash}-PropertiesPanel`;
246
+ this._PropertiesPanelView = this.pict.addView(
247
+ tmpPropsPanelHash,
248
+ {
249
+ ViewIdentifier: tmpPropsPanelHash,
250
+ DefaultDestinationAddress: `#FormEditor-PropertiesPanel-${this.Hash}`,
251
+ AutoRender: false
252
+ },
253
+ tmpPropertiesPanelView
254
+ );
255
+ this._PropertiesPanelView._ParentFormEditor = this;
256
+ this._PropertiesPanelView.initialize();
257
+
258
+ // Create the code editor child view (pict-section-code for JSON tab)
259
+ let tmpCodeEditorHash = `${this.Hash}-CodeEditor`;
260
+ this._CodeEditorView = this.pict.addView(
261
+ tmpCodeEditorHash,
262
+ {
263
+ ViewIdentifier: tmpCodeEditorHash,
264
+ TargetElementAddress: `#FormEditor-CodeEditor-Container-${this.Hash}`,
265
+ Language: 'json',
266
+ ReadOnly: false,
267
+ LineNumbers: true,
268
+ DefaultCode: '{}',
269
+ AutoRender: false,
270
+ RenderOnLoad: false,
271
+ DefaultRenderable: 'CodeEditor-Wrap',
272
+ DefaultDestinationAddress: `#FormEditor-CodeEditor-Container-${this.Hash}`,
273
+ Renderables:
274
+ [
275
+ {
276
+ RenderableHash: 'CodeEditor-Wrap',
277
+ TemplateHash: 'CodeEditor-Container',
278
+ DestinationAddress: `#FormEditor-CodeEditor-Container-${this.Hash}`
279
+ }
280
+ ]
281
+ },
282
+ libPictSectionCode
283
+ );
284
+ this._CodeEditorView.initialize();
285
+
286
+ // Override onCodeChange to sync edits back to manifest
287
+ let tmpSelf = this;
288
+ this._CodeEditorView.onCodeChange = function(pCode)
289
+ {
290
+ // Try to parse; silently ignore invalid JSON while user is typing
291
+ try
292
+ {
293
+ let tmpParsed = JSON.parse(pCode);
294
+ tmpSelf._setManifestData(tmpParsed);
295
+ }
296
+ catch (e)
297
+ {
298
+ // JSON not yet valid — no-op until user finishes editing
299
+ }
300
+ };
301
+
302
+ // Create the solver code editor child view (pict-section-code for Solver Editor tab)
303
+ let tmpSolverCodeEditorHash = `${this.Hash}-SolverCodeEditor`;
304
+ this._SolverCodeEditorView = this.pict.addView(
305
+ tmpSolverCodeEditorHash,
306
+ {
307
+ ViewIdentifier: tmpSolverCodeEditorHash,
308
+ TargetElementAddress: `#FormEditor-SolverCodeEditor-Container-${this.Hash}`,
309
+ Language: 'javascript',
310
+ ReadOnly: false,
311
+ LineNumbers: true,
312
+ DefaultCode: '',
313
+ AddClosing: false,
314
+ IndentOn: false,
315
+ MoveToNewLine: false,
316
+ AutoRender: false,
317
+ RenderOnLoad: false,
318
+ DefaultRenderable: 'SolverCodeEditor-Wrap',
319
+ DefaultDestinationAddress: `#FormEditor-SolverCodeEditor-Container-${this.Hash}`,
320
+ Renderables:
321
+ [
322
+ {
323
+ RenderableHash: 'SolverCodeEditor-Wrap',
324
+ TemplateHash: 'CodeEditor-Container',
325
+ DestinationAddress: `#FormEditor-SolverCodeEditor-Container-${this.Hash}`
326
+ }
327
+ ]
328
+ },
329
+ libPictSectionCode
330
+ );
331
+ this._SolverCodeEditorView.initialize();
332
+
333
+ // Set a custom solver DSL highlight function
334
+ this._SolverCodeEditorView.setHighlightFunction(this._buildSolverHighlightFunction());
335
+
336
+ // Create the help content view (PictContentView for rendering parsed markdown)
337
+ let tmpHelpContentViewHash = `${this.Hash}-HelpContentView`;
338
+ this._HelpContentView = this.pict.addView(
339
+ tmpHelpContentViewHash,
340
+ {
341
+ ViewIdentifier: tmpHelpContentViewHash,
342
+ DefaultRenderable: 'HelpContent-Wrap',
343
+ DefaultDestinationAddress: `#FormEditor-Help-Body-${this.Hash}`,
344
+ AutoRender: false,
345
+ Renderables:
346
+ [
347
+ {
348
+ RenderableHash: 'HelpContent-Wrap',
349
+ TemplateHash: 'Pict-Content-Template',
350
+ DestinationAddress: `#FormEditor-Help-Body-${this.Hash}`
351
+ }
352
+ ]
353
+ },
354
+ libPictSectionContent
355
+ );
356
+ this._HelpContentView.initialize();
357
+ }
358
+
359
+ /**
360
+ * Build the custom syntax highlight function for the solver DSL.
361
+ *
362
+ * The function tokenizes the raw code to extract string literals first,
363
+ * then applies keyword/reference/number/operator highlighting to code segments.
364
+ *
365
+ * @returns {function} A highlight function compatible with pict-section-code / CodeJar
366
+ */
367
+ _buildSolverHighlightFunction()
368
+ {
369
+ // Single combined tokenizer that matches all token types in one pass on the raw text.
370
+ // Order matters: strings first, then keywords, then dot-path references, then numbers, then operators.
371
+ // Group 1: string literals
372
+ // Group 2: keyword
373
+ // Group 3: dot-path reference (e.g. Section.Group.Field)
374
+ // Group 4: number
375
+ // Group 5: operator
376
+ let tmpTokenizer = new RegExp(
377
+ '("(?:[^"\\\\]|\\\\.)*"|\'(?:[^\'\\\\]|\\\\.)*\')' + // Group 1: strings
378
+ '|\\b(' +
379
+ // Math
380
+ 'abs|sqrt|round|tofixed|floor|ceil|exp|log|sin|cos|tan|rad|pi|euler|compare|percent' +
381
+ // Stats
382
+ '|sum|avg|mean|median|mode|min|max|var|vara|varp|stdev|stdeva|stdevp|count|countset|countsetelements' +
383
+ // Array/Set
384
+ '|sortset|sortarray|bucketset|uniquearray|unionarrays|differencearrays|arrayconcat|flatten|slice|setconcatenate|entryinset|smallestinset|largestinset' +
385
+ // String
386
+ '|concat|concatraw|join|joinraw|stringcountsegments|stringgetsegments|resolvehtmlentities' +
387
+ // Object/Value
388
+ '|getvalue|setvalue|getvaluearray|getvalueobject|createvalueobjectbyhashes|cleanvaluearray|cleanvalueobject' +
389
+ // Date
390
+ '|datemilliseconddifference|dateseconddifference|dateminutedifference|datehourdifference|datedaydifference|dateweekdifference|datemonthdifference|dateyeardifference|datemathadd|dateaddmilliseconds|dateaddseconds|dateaddminutes|dateaddhours|dateadddays|dateaddweeks|dateaddmonths|dateaddyears|datefromparts' +
391
+ // Conditional
392
+ '|if|when' +
393
+ // Form control
394
+ '|showsections|hidesections|setsectionvisibility|setgroupvisibility|generatehtmlhexcolor|colorsectionbackground|colorgroupbackground|colorinputbackground|colorinputbackgroundtabular|setsolverordinalenabled|enablesolverordinal|disablesolverordinal|settabularrowlength|refreshtabularsection|runsolvers|logvalues' +
395
+ // Regression/Advanced
396
+ '|polynomialregression|leastsquares|linest|matrixtranspose|matrixmultiply|matrixvectormultiply|matrixinverse|gaussianelimination|predict|iterativeseries|cumulativesummation|subtractingsummation' +
397
+ // Random
398
+ '|randominteger|randomintegerbetween|randomintegerupto|randomfloat|randomfloatbetween|randomfloatupto' +
399
+ // Search
400
+ '|findfirstvaluebyexactmatch|findfirstvaluebystringincludes|match' +
401
+ // Histogram
402
+ '|aggregationhistogram|aggregationhistogrambyobject|distributionhistogram|distributionhistogrambyobject|sorthistogram|sorthistogrambykeys|objectkeystoarray|setkeystoarray|histogramkeystoarray|objectvaluestoarray|setvaluestoarray|histogramvaluestoarray|generatearrayofobjectsfromsets|objectvaluessortbyexternalobjectarray' +
403
+ // Curve
404
+ '|bezierpoint|beziercurvefit' +
405
+ ')\\b' + // Group 2: keywords
406
+ '|([a-zA-Z_]\\w*(?:\\.\\w+)+)' + // Group 3: dot-path references
407
+ '|(\\b\\d+\\.?\\d*(?:e[+-]?\\d+)?\\b)' + // Group 4: numbers
408
+ '|([=+\\-*/%^<>!?&|]+)', // Group 5: operators
409
+ 'gi');
410
+
411
+ function escapeHTML(pString)
412
+ {
413
+ return pString
414
+ .replace(/&/g, '&amp;')
415
+ .replace(/</g, '&lt;')
416
+ .replace(/>/g, '&gt;');
417
+ }
418
+
419
+ return function highlightSolverExpression(pElement)
420
+ {
421
+ let tmpCode = pElement.textContent;
422
+
423
+ // Single-pass tokenization on raw text — no cascading regex on HTML
424
+ let tmpResult = '';
425
+ let tmpLastIndex = 0;
426
+ let tmpMatch;
427
+
428
+ tmpTokenizer.lastIndex = 0;
429
+
430
+ while ((tmpMatch = tmpTokenizer.exec(tmpCode)) !== null)
431
+ {
432
+ // Emit any plain text before this token
433
+ if (tmpMatch.index > tmpLastIndex)
434
+ {
435
+ tmpResult += escapeHTML(tmpCode.substring(tmpLastIndex, tmpMatch.index));
436
+ }
437
+
438
+ let tmpFullMatch = tmpMatch[0];
439
+
440
+ if (tmpMatch[1])
441
+ {
442
+ // String literal
443
+ tmpResult += '<span class="string">' + escapeHTML(tmpFullMatch) + '</span>';
444
+ }
445
+ else if (tmpMatch[2])
446
+ {
447
+ // Keyword
448
+ tmpResult += '<span class="keyword">' + escapeHTML(tmpFullMatch) + '</span>';
449
+ }
450
+ else if (tmpMatch[3])
451
+ {
452
+ // Dot-path reference
453
+ tmpResult += '<span class="property">' + escapeHTML(tmpFullMatch) + '</span>';
454
+ }
455
+ else if (tmpMatch[4])
456
+ {
457
+ // Number
458
+ tmpResult += '<span class="number">' + escapeHTML(tmpFullMatch) + '</span>';
459
+ }
460
+ else if (tmpMatch[5])
461
+ {
462
+ // Operator
463
+ tmpResult += '<span class="operator">' + escapeHTML(tmpFullMatch) + '</span>';
464
+ }
465
+
466
+ tmpLastIndex = tmpTokenizer.lastIndex;
467
+ }
468
+
469
+ // Emit any remaining plain text
470
+ if (tmpLastIndex < tmpCode.length)
471
+ {
472
+ tmpResult += escapeHTML(tmpCode.substring(tmpLastIndex));
473
+ }
474
+
475
+ pElement.innerHTML = tmpResult;
476
+ };
477
+ }
478
+
479
+ /* -------------------------------------------------------------------------- */
480
+ /* Code Section: Rendering */
481
+ /* -------------------------------------------------------------------------- */
482
+
483
+ onAfterRender()
484
+ {
485
+ super.onAfterRender();
486
+
487
+ // Inject CSS
488
+ if (this.options.CSS)
489
+ {
490
+ this.pict.CSSMap.injectCSS(this.options.ViewIdentifier, this.options.CSS);
491
+ }
492
+
493
+ // Build the full tab bar and content panels programmatically
494
+ this._RenderingProvider._renderTabShell();
495
+
496
+ this.renderVisualEditor();
497
+ this._syncTabState();
498
+ }
499
+
500
+ renderVisualEditor()
501
+ {
502
+ return this._RenderingProvider.renderVisualEditor();
503
+ }
504
+
505
+ /* -------------------------------------------------------------------------- */
506
+ /* Code Section: Tab Management */
507
+ /* -------------------------------------------------------------------------- */
508
+
509
+ switchTab(pTabName)
510
+ {
511
+ this._ActiveTab = pTabName;
512
+ this._syncTabState();
513
+
514
+ if (pTabName === 'objecteditor')
515
+ {
516
+ // Render the object editor container first, then expand to 2 levels
517
+ this._ObjectEditorView.render();
518
+ this._ObjectEditorView.expandToDepth(2);
519
+ }
520
+ else if (pTabName === 'json')
521
+ {
522
+ this._UtilitiesProvider._updateCodeEditor();
523
+ }
524
+ else if (pTabName === 'visual')
525
+ {
526
+ this.renderVisualEditor();
527
+ }
528
+ else if (pTabName === 'solvereditor')
529
+ {
530
+ if (this._PropertiesPanelView)
531
+ {
532
+ this._PropertiesPanelView.renderSolverEditorTabPanel();
533
+ }
534
+ }
535
+ else if (pTabName === 'solvers')
536
+ {
537
+ if (this._PropertiesPanelView)
538
+ {
539
+ this._PropertiesPanelView.renderSolversTabPanel();
540
+ }
541
+ }
542
+ else if (pTabName === 'listdata')
543
+ {
544
+ if (this._PropertiesPanelView)
545
+ {
546
+ this._PropertiesPanelView.renderListDataTabPanel();
547
+ }
548
+ }
549
+ else if (pTabName === 'entitydata')
550
+ {
551
+ if (this._PropertiesPanelView)
552
+ {
553
+ this._PropertiesPanelView.renderEntityDataTabPanel();
554
+ }
555
+ }
556
+ else if (pTabName === 'preview')
557
+ {
558
+ if (this._PropertiesPanelView)
559
+ {
560
+ this._PropertiesPanelView.renderPreviewTabPanel();
561
+ }
562
+ }
563
+ }
564
+
565
+ _syncTabState()
566
+ {
567
+ let tmpHash = this.Hash;
568
+ let tmpTabs = ['visual', 'solvereditor', 'solvers', 'listdata', 'entitydata', 'objecteditor', 'json', 'preview'];
569
+ let tmpTabNames = ['Visual', 'SolverEditor', 'Solvers', 'ListData', 'EntityData', 'ObjectEditor', 'JSON', 'Preview'];
570
+
571
+ for (let i = 0; i < tmpTabs.length; i++)
572
+ {
573
+ // getElement returns an array; grab the first match
574
+ let tmpTabButtonSet = this.pict.ContentAssignment.getElement(`#FormEditor-Tab-${tmpTabNames[i]}-${tmpHash}`);
575
+ let tmpTabPanelSet = this.pict.ContentAssignment.getElement(`#FormEditor-Panel-${tmpTabNames[i]}-${tmpHash}`);
576
+
577
+ let tmpTabButton = (Array.isArray(tmpTabButtonSet) && tmpTabButtonSet.length > 0) ? tmpTabButtonSet[0] : tmpTabButtonSet;
578
+ let tmpTabPanel = (Array.isArray(tmpTabPanelSet) && tmpTabPanelSet.length > 0) ? tmpTabPanelSet[0] : tmpTabPanelSet;
579
+
580
+ if (tmpTabButton && tmpTabButton.className !== undefined)
581
+ {
582
+ if (tmpTabs[i] === this._ActiveTab)
583
+ {
584
+ tmpTabButton.className = 'pict-fe-tab pict-fe-tab-active';
585
+ }
586
+ else
587
+ {
588
+ tmpTabButton.className = 'pict-fe-tab';
589
+ }
590
+ }
591
+ if (tmpTabPanel && tmpTabPanel.className !== undefined)
592
+ {
593
+ if (tmpTabs[i] === this._ActiveTab)
594
+ {
595
+ tmpTabPanel.className = 'pict-fe-tabcontent pict-fe-tabcontent-active';
596
+ }
597
+ else
598
+ {
599
+ tmpTabPanel.className = 'pict-fe-tabcontent';
600
+ }
601
+ }
602
+ }
603
+ }
604
+
605
+ /* -------------------------------------------------------------------------- */
606
+ /* Code Section: Data Helpers */
607
+ /* -------------------------------------------------------------------------- */
608
+
609
+ _resolveManifestData()
610
+ {
611
+ let tmpAddress = this.options.ManifestDataAddress;
612
+ if (!tmpAddress)
613
+ {
614
+ return null;
615
+ }
616
+
617
+ let tmpSegments = tmpAddress.split('.');
618
+ let tmpCurrent = this.fable;
619
+
620
+ for (let i = 0; i < tmpSegments.length; i++)
621
+ {
622
+ if (tmpCurrent && typeof tmpCurrent === 'object' && tmpCurrent.hasOwnProperty(tmpSegments[i]))
623
+ {
624
+ tmpCurrent = tmpCurrent[tmpSegments[i]];
625
+ }
626
+ else
627
+ {
628
+ return null;
629
+ }
630
+ }
631
+
632
+ return tmpCurrent;
633
+ }
634
+
635
+ _setManifestData(pData)
636
+ {
637
+ let tmpAddress = this.options.ManifestDataAddress;
638
+ if (!tmpAddress)
639
+ {
640
+ return;
641
+ }
642
+
643
+ let tmpSegments = tmpAddress.split('.');
644
+ let tmpCurrent = this.fable;
645
+
646
+ for (let i = 0; i < tmpSegments.length - 1; i++)
647
+ {
648
+ if (!tmpCurrent.hasOwnProperty(tmpSegments[i]) || typeof tmpCurrent[tmpSegments[i]] !== 'object')
649
+ {
650
+ tmpCurrent[tmpSegments[i]] = {};
651
+ }
652
+ tmpCurrent = tmpCurrent[tmpSegments[i]];
653
+ }
654
+
655
+ tmpCurrent[tmpSegments[tmpSegments.length - 1]] = pData;
656
+ }
657
+
658
+ _createEmptyManifest()
659
+ {
660
+ return (
661
+ {
662
+ Scope: 'NewForm',
663
+ Sections: [],
664
+ Descriptors: {},
665
+ ReferenceManifests: {},
666
+ StaticOptionLists: [],
667
+ PickLists: []
668
+ });
669
+ }
670
+
671
+ /* -------------------------------------------------------------------------- */
672
+ /* Code Section: Utility */
673
+ /* -------------------------------------------------------------------------- */
674
+
675
+ _browserViewRef()
676
+ {
677
+ return `${this.pict.browserAddress}.views['${this.Hash}']`;
678
+ }
679
+ }
680
+
681
+ module.exports = PictViewFormEditor;