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,535 @@
1
+ const libPictProvider = require('pict-provider');
2
+
3
+ class FormEditorDragDrop extends libPictProvider
4
+ {
5
+ constructor(pFable, pOptions, pServiceHash)
6
+ {
7
+ super(pFable, pOptions, pServiceHash);
8
+
9
+ this.serviceType = 'PictProvider';
10
+
11
+ // Back-reference to the parent FormEditor view (set after construction)
12
+ this._ParentFormEditor = null;
13
+ }
14
+
15
+ /**
16
+ * Enable or disable drag-and-drop reordering.
17
+ *
18
+ * When enabled, drag handles and HTML5 drag attributes are added to sections,
19
+ * groups, rows, and inputs. When disabled, all drag hooks are removed from
20
+ * the DOM. Disabled by default.
21
+ *
22
+ * @param {boolean} pEnabled - true to enable, false to disable
23
+ */
24
+ setDragAndDropEnabled(pEnabled)
25
+ {
26
+ this._ParentFormEditor._DragAndDropEnabled = !!pEnabled;
27
+ this._ParentFormEditor._DragState = null;
28
+ this._ParentFormEditor.renderVisualEditor();
29
+ }
30
+
31
+ onDragStart(pEvent, pType, pIndex0, pIndex1, pIndex2, pIndex3)
32
+ {
33
+ if (!this._ParentFormEditor._DragAndDropEnabled)
34
+ {
35
+ return;
36
+ }
37
+
38
+ // Stop propagation so nested draggable parents don't overwrite _DragState
39
+ if (pEvent && pEvent.stopPropagation)
40
+ {
41
+ pEvent.stopPropagation();
42
+ }
43
+
44
+ this._ParentFormEditor._DragState =
45
+ {
46
+ Type: pType,
47
+ Indices: [pIndex0, pIndex1, pIndex2, pIndex3].filter((pVal) => { return typeof pVal === 'number'; })
48
+ };
49
+
50
+ if (pEvent && pEvent.dataTransfer)
51
+ {
52
+ pEvent.dataTransfer.effectAllowed = 'move';
53
+ // Required for Firefox
54
+ pEvent.dataTransfer.setData('text/plain', '');
55
+ }
56
+
57
+ if (pEvent && pEvent.currentTarget)
58
+ {
59
+ pEvent.currentTarget.classList.add('pict-fe-dragging');
60
+ }
61
+ }
62
+
63
+ onDragOver(pEvent, pType, pIndex0, pIndex1, pIndex2, pIndex3)
64
+ {
65
+ if (!this._ParentFormEditor._DragAndDropEnabled || !this._ParentFormEditor._DragState)
66
+ {
67
+ return;
68
+ }
69
+
70
+ // Only allow drops of the same type
71
+ if (this._ParentFormEditor._DragState.Type !== pType)
72
+ {
73
+ return;
74
+ }
75
+
76
+ // Stop propagation so parent containers don't also highlight
77
+ if (pEvent && pEvent.stopPropagation)
78
+ {
79
+ pEvent.stopPropagation();
80
+ }
81
+
82
+ pEvent.preventDefault();
83
+ if (pEvent && pEvent.dataTransfer)
84
+ {
85
+ pEvent.dataTransfer.dropEffect = 'move';
86
+ }
87
+
88
+ if (pEvent && pEvent.currentTarget)
89
+ {
90
+ pEvent.currentTarget.classList.add('pict-fe-drag-over');
91
+ }
92
+ }
93
+
94
+ onDragLeave(pEvent)
95
+ {
96
+ if (pEvent && pEvent.stopPropagation)
97
+ {
98
+ pEvent.stopPropagation();
99
+ }
100
+
101
+ if (pEvent && pEvent.currentTarget)
102
+ {
103
+ pEvent.currentTarget.classList.remove('pict-fe-drag-over');
104
+ }
105
+ }
106
+
107
+ onDrop(pEvent, pType, pIndex0, pIndex1, pIndex2, pIndex3)
108
+ {
109
+ if (pEvent)
110
+ {
111
+ pEvent.preventDefault();
112
+ if (pEvent.stopPropagation)
113
+ {
114
+ pEvent.stopPropagation();
115
+ }
116
+ }
117
+
118
+ if (!this._ParentFormEditor._DragAndDropEnabled || !this._ParentFormEditor._DragState || this._ParentFormEditor._DragState.Type !== pType)
119
+ {
120
+ this._ParentFormEditor._DragState = null;
121
+ return;
122
+ }
123
+
124
+ let tmpTargetIndices = [pIndex0, pIndex1, pIndex2, pIndex3].filter((pVal) => { return typeof pVal === 'number'; });
125
+ let tmpSourceIndices = this._ParentFormEditor._DragState.Indices;
126
+ this._ParentFormEditor._DragState = null;
127
+
128
+ // Check if source and target are identical
129
+ if (tmpSourceIndices.length === tmpTargetIndices.length && tmpSourceIndices.every((pVal, pIdx) => { return pVal === tmpTargetIndices[pIdx]; }))
130
+ {
131
+ return;
132
+ }
133
+
134
+ let tmpManifest = this._ParentFormEditor._resolveManifestData();
135
+ if (!tmpManifest || !Array.isArray(tmpManifest.Sections))
136
+ {
137
+ return;
138
+ }
139
+
140
+ switch (pType)
141
+ {
142
+ case 'section':
143
+ {
144
+ let tmpFromIdx = tmpSourceIndices[0];
145
+ let tmpToIdx = tmpTargetIndices[0];
146
+ if (tmpFromIdx === tmpToIdx)
147
+ {
148
+ return;
149
+ }
150
+ let tmpItem = tmpManifest.Sections.splice(tmpFromIdx, 1)[0];
151
+ tmpManifest.Sections.splice(tmpToIdx, 0, tmpItem);
152
+ break;
153
+ }
154
+ case 'group':
155
+ {
156
+ let tmpSourceSection = tmpManifest.Sections[tmpSourceIndices[0]];
157
+ let tmpTargetSection = tmpManifest.Sections[tmpTargetIndices[0]];
158
+ if (!tmpSourceSection || !Array.isArray(tmpSourceSection.Groups) || !tmpTargetSection)
159
+ {
160
+ return;
161
+ }
162
+ if (!Array.isArray(tmpTargetSection.Groups))
163
+ {
164
+ tmpTargetSection.Groups = [];
165
+ }
166
+
167
+ let tmpItem = tmpSourceSection.Groups.splice(tmpSourceIndices[1], 1)[0];
168
+
169
+ // If moving within the same section and target index is after source,
170
+ // adjust for the removal
171
+ let tmpInsertIdx = tmpTargetIndices[1];
172
+ if (tmpSourceIndices[0] === tmpTargetIndices[0] && tmpSourceIndices[1] < tmpTargetIndices[1])
173
+ {
174
+ tmpInsertIdx--;
175
+ }
176
+ tmpTargetSection.Groups.splice(tmpInsertIdx, 0, tmpItem);
177
+ break;
178
+ }
179
+ case 'row':
180
+ {
181
+ let tmpSourceSection = tmpManifest.Sections[tmpSourceIndices[0]];
182
+ let tmpTargetSection = tmpManifest.Sections[tmpTargetIndices[0]];
183
+ if (!tmpSourceSection || !Array.isArray(tmpSourceSection.Groups) || !tmpTargetSection || !Array.isArray(tmpTargetSection.Groups))
184
+ {
185
+ return;
186
+ }
187
+ let tmpSourceGroup = tmpSourceSection.Groups[tmpSourceIndices[1]];
188
+ let tmpTargetGroup = tmpTargetSection.Groups[tmpTargetIndices[1]];
189
+ if (!tmpSourceGroup || !Array.isArray(tmpSourceGroup.Rows) || !tmpTargetGroup)
190
+ {
191
+ return;
192
+ }
193
+ if (!Array.isArray(tmpTargetGroup.Rows))
194
+ {
195
+ tmpTargetGroup.Rows = [];
196
+ }
197
+
198
+ let tmpItem = tmpSourceGroup.Rows.splice(tmpSourceIndices[2], 1)[0];
199
+
200
+ let tmpInsertIdx = tmpTargetIndices[2];
201
+ let tmpSameContainer = (tmpSourceIndices[0] === tmpTargetIndices[0]) && (tmpSourceIndices[1] === tmpTargetIndices[1]);
202
+ if (tmpSameContainer && tmpSourceIndices[2] < tmpTargetIndices[2])
203
+ {
204
+ tmpInsertIdx--;
205
+ }
206
+ tmpTargetGroup.Rows.splice(tmpInsertIdx, 0, tmpItem);
207
+
208
+ // Sync row indices on both source and target groups
209
+ this._ParentFormEditor._ManifestOpsProvider._syncRowIndices(tmpManifest, tmpSourceGroup);
210
+ if (!tmpSameContainer)
211
+ {
212
+ this._ParentFormEditor._ManifestOpsProvider._syncRowIndices(tmpManifest, tmpTargetGroup);
213
+ }
214
+ break;
215
+ }
216
+ case 'input':
217
+ {
218
+ let tmpSourceSection = tmpManifest.Sections[tmpSourceIndices[0]];
219
+ let tmpTargetSection = tmpManifest.Sections[tmpTargetIndices[0]];
220
+ if (!tmpSourceSection || !Array.isArray(tmpSourceSection.Groups) || !tmpTargetSection || !Array.isArray(tmpTargetSection.Groups))
221
+ {
222
+ return;
223
+ }
224
+ let tmpSourceGroup = tmpSourceSection.Groups[tmpSourceIndices[1]];
225
+ let tmpTargetGroup = tmpTargetSection.Groups[tmpTargetIndices[1]];
226
+ if (!tmpSourceGroup || !Array.isArray(tmpSourceGroup.Rows) || !tmpTargetGroup || !Array.isArray(tmpTargetGroup.Rows))
227
+ {
228
+ return;
229
+ }
230
+ let tmpSourceRow = tmpSourceGroup.Rows[tmpSourceIndices[2]];
231
+ let tmpTargetRow = tmpTargetGroup.Rows[tmpTargetIndices[2]];
232
+ if (!tmpSourceRow || !Array.isArray(tmpSourceRow.Inputs) || !tmpTargetRow)
233
+ {
234
+ return;
235
+ }
236
+ if (!Array.isArray(tmpTargetRow.Inputs))
237
+ {
238
+ tmpTargetRow.Inputs = [];
239
+ }
240
+
241
+ let tmpAddress = tmpSourceRow.Inputs.splice(tmpSourceIndices[3], 1)[0];
242
+
243
+ let tmpInsertIdx = tmpTargetIndices[3];
244
+ let tmpSameContainer = (tmpSourceIndices[0] === tmpTargetIndices[0]) && (tmpSourceIndices[1] === tmpTargetIndices[1]) && (tmpSourceIndices[2] === tmpTargetIndices[2]);
245
+ if (tmpSameContainer && tmpSourceIndices[3] < tmpTargetIndices[3])
246
+ {
247
+ tmpInsertIdx--;
248
+ }
249
+ tmpTargetRow.Inputs.splice(tmpInsertIdx, 0, tmpAddress);
250
+
251
+ // Update the Descriptor's PictForm metadata for the new location
252
+ if (typeof tmpAddress === 'string' && tmpManifest.Descriptors && tmpManifest.Descriptors[tmpAddress])
253
+ {
254
+ let tmpDescriptor = tmpManifest.Descriptors[tmpAddress];
255
+ if (!tmpDescriptor.PictForm)
256
+ {
257
+ tmpDescriptor.PictForm = {};
258
+ }
259
+ tmpDescriptor.PictForm.Section = tmpTargetSection.Hash || '';
260
+ tmpDescriptor.PictForm.Group = tmpTargetGroup.Hash || '';
261
+ tmpDescriptor.PictForm.Row = tmpTargetIndices[2] + 1;
262
+ }
263
+ break;
264
+ }
265
+ default:
266
+ return;
267
+ }
268
+
269
+ this._ParentFormEditor.renderVisualEditor();
270
+ }
271
+
272
+ onDragEnd(pEvent)
273
+ {
274
+ if (pEvent && pEvent.currentTarget)
275
+ {
276
+ pEvent.currentTarget.classList.remove('pict-fe-dragging');
277
+ }
278
+
279
+ this._ParentFormEditor._DragState = null;
280
+
281
+ // Clean up any leftover drag-over highlights
282
+ let tmpContainer = this.pict.ContentAssignment.getElement(`#FormEditor-Panel-Visual-${this._ParentFormEditor.Hash}`);
283
+ if (tmpContainer && tmpContainer[0])
284
+ {
285
+ let tmpHighlighted = tmpContainer[0].querySelectorAll('.pict-fe-drag-over');
286
+ for (let i = 0; i < tmpHighlighted.length; i++)
287
+ {
288
+ tmpHighlighted[i].classList.remove('pict-fe-drag-over');
289
+ }
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Check whether two index arrays share the same parent container.
295
+ * Utility method — cross-container moves are allowed so this is
296
+ * not used as a gate in onDragOver/onDrop, but it remains available
297
+ * for callers that need to distinguish same-container vs cross-container moves.
298
+ */
299
+ _dragIndicesShareParent(pSourceIndices, pTargetIndices)
300
+ {
301
+ if (pSourceIndices.length !== pTargetIndices.length)
302
+ {
303
+ return false;
304
+ }
305
+
306
+ // Compare all indices except the last one (which is the item's own position)
307
+ for (let i = 0; i < pSourceIndices.length - 1; i++)
308
+ {
309
+ if (pSourceIndices[i] !== pTargetIndices[i])
310
+ {
311
+ return false;
312
+ }
313
+ }
314
+ return true;
315
+ }
316
+
317
+ /**
318
+ * Build the drag attribute string for a container element.
319
+ * Returns an empty string when drag-and-drop is disabled.
320
+ */
321
+ _buildDragAttributes(pType, pIndices)
322
+ {
323
+ if (!this._ParentFormEditor._DragAndDropEnabled)
324
+ {
325
+ return '';
326
+ }
327
+
328
+ let tmpViewRef = this._ParentFormEditor._browserViewRef();
329
+ let tmpArgs = pIndices.join(', ');
330
+
331
+ return ` draggable="true"` +
332
+ ` ondragstart="${tmpViewRef}._DragDropProvider.onDragStart(event, '${pType}', ${tmpArgs})"` +
333
+ ` ondragover="${tmpViewRef}._DragDropProvider.onDragOver(event, '${pType}', ${tmpArgs})"` +
334
+ ` ondragleave="${tmpViewRef}._DragDropProvider.onDragLeave(event)"` +
335
+ ` ondrop="${tmpViewRef}._DragDropProvider.onDrop(event, '${pType}', ${tmpArgs})"` +
336
+ ` ondragend="${tmpViewRef}._DragDropProvider.onDragEnd(event)"`;
337
+ }
338
+
339
+ /**
340
+ * Build drag attributes for a container element that accepts child drops.
341
+ * When a child type is dropped on the container (rather than on a specific
342
+ * sibling), the item is appended to the end of the container's array.
343
+ *
344
+ * @param {string} pChildType - The type of child items this container accepts ('group', 'row', 'input')
345
+ * @param {Array} pContainerIndices - Indices identifying the parent container
346
+ */
347
+ _buildContainerDropAttributes(pChildType, pContainerIndices)
348
+ {
349
+ if (!this._ParentFormEditor._DragAndDropEnabled)
350
+ {
351
+ return '';
352
+ }
353
+
354
+ let tmpViewRef = this._ParentFormEditor._browserViewRef();
355
+ let tmpArgs = pContainerIndices.join(', ');
356
+
357
+ return ` ondragover="${tmpViewRef}._DragDropProvider.onContainerDragOver(event, '${pChildType}')"` +
358
+ ` ondragleave="${tmpViewRef}._DragDropProvider.onDragLeave(event)"` +
359
+ ` ondrop="${tmpViewRef}._DragDropProvider.onContainerDrop(event, '${pChildType}', ${tmpArgs})"`;
360
+ }
361
+
362
+ onContainerDragOver(pEvent, pChildType)
363
+ {
364
+ if (!this._ParentFormEditor._DragAndDropEnabled || !this._ParentFormEditor._DragState)
365
+ {
366
+ return;
367
+ }
368
+
369
+ if (this._ParentFormEditor._DragState.Type !== pChildType)
370
+ {
371
+ return;
372
+ }
373
+
374
+ if (pEvent && pEvent.stopPropagation)
375
+ {
376
+ pEvent.stopPropagation();
377
+ }
378
+
379
+ pEvent.preventDefault();
380
+ if (pEvent && pEvent.dataTransfer)
381
+ {
382
+ pEvent.dataTransfer.dropEffect = 'move';
383
+ }
384
+
385
+ if (pEvent && pEvent.currentTarget)
386
+ {
387
+ pEvent.currentTarget.classList.add('pict-fe-drag-over');
388
+ }
389
+ }
390
+
391
+ onContainerDrop(pEvent, pChildType, pIndex0, pIndex1, pIndex2)
392
+ {
393
+ if (pEvent)
394
+ {
395
+ pEvent.preventDefault();
396
+ if (pEvent.stopPropagation)
397
+ {
398
+ pEvent.stopPropagation();
399
+ }
400
+ }
401
+
402
+ if (!this._ParentFormEditor._DragAndDropEnabled || !this._ParentFormEditor._DragState || this._ParentFormEditor._DragState.Type !== pChildType)
403
+ {
404
+ this._ParentFormEditor._DragState = null;
405
+ return;
406
+ }
407
+
408
+ let tmpContainerIndices = [pIndex0, pIndex1, pIndex2].filter((pVal) => { return typeof pVal === 'number'; });
409
+ let tmpSourceIndices = this._ParentFormEditor._DragState.Indices;
410
+ this._ParentFormEditor._DragState = null;
411
+
412
+ let tmpManifest = this._ParentFormEditor._resolveManifestData();
413
+ if (!tmpManifest || !Array.isArray(tmpManifest.Sections))
414
+ {
415
+ return;
416
+ }
417
+
418
+ switch (pChildType)
419
+ {
420
+ case 'group':
421
+ {
422
+ // Container is a section; indices = [sectionIndex]
423
+ let tmpTargetSectionIdx = tmpContainerIndices[0];
424
+ let tmpSourceSection = tmpManifest.Sections[tmpSourceIndices[0]];
425
+ let tmpTargetSection = tmpManifest.Sections[tmpTargetSectionIdx];
426
+ if (!tmpSourceSection || !Array.isArray(tmpSourceSection.Groups) || !tmpTargetSection)
427
+ {
428
+ return;
429
+ }
430
+ if (!Array.isArray(tmpTargetSection.Groups))
431
+ {
432
+ tmpTargetSection.Groups = [];
433
+ }
434
+
435
+ let tmpItem = tmpSourceSection.Groups.splice(tmpSourceIndices[1], 1)[0];
436
+ tmpTargetSection.Groups.push(tmpItem);
437
+ break;
438
+ }
439
+ case 'row':
440
+ {
441
+ // Container is a group; indices = [sectionIndex, groupIndex]
442
+ let tmpSourceSection = tmpManifest.Sections[tmpSourceIndices[0]];
443
+ let tmpTargetSection = tmpManifest.Sections[tmpContainerIndices[0]];
444
+ if (!tmpSourceSection || !Array.isArray(tmpSourceSection.Groups) || !tmpTargetSection || !Array.isArray(tmpTargetSection.Groups))
445
+ {
446
+ return;
447
+ }
448
+ let tmpSourceGroup = tmpSourceSection.Groups[tmpSourceIndices[1]];
449
+ let tmpTargetGroup = tmpTargetSection.Groups[tmpContainerIndices[1]];
450
+ if (!tmpSourceGroup || !Array.isArray(tmpSourceGroup.Rows) || !tmpTargetGroup)
451
+ {
452
+ return;
453
+ }
454
+ if (!Array.isArray(tmpTargetGroup.Rows))
455
+ {
456
+ tmpTargetGroup.Rows = [];
457
+ }
458
+
459
+ let tmpItem = tmpSourceGroup.Rows.splice(tmpSourceIndices[2], 1)[0];
460
+ tmpTargetGroup.Rows.push(tmpItem);
461
+
462
+ this._ParentFormEditor._ManifestOpsProvider._syncRowIndices(tmpManifest, tmpSourceGroup);
463
+ if (tmpSourceGroup !== tmpTargetGroup)
464
+ {
465
+ this._ParentFormEditor._ManifestOpsProvider._syncRowIndices(tmpManifest, tmpTargetGroup);
466
+ }
467
+ break;
468
+ }
469
+ case 'input':
470
+ {
471
+ // Container is a row; indices = [sectionIndex, groupIndex, rowIndex]
472
+ let tmpSourceSection = tmpManifest.Sections[tmpSourceIndices[0]];
473
+ let tmpTargetSection = tmpManifest.Sections[tmpContainerIndices[0]];
474
+ if (!tmpSourceSection || !Array.isArray(tmpSourceSection.Groups) || !tmpTargetSection || !Array.isArray(tmpTargetSection.Groups))
475
+ {
476
+ return;
477
+ }
478
+ let tmpSourceGroup = tmpSourceSection.Groups[tmpSourceIndices[1]];
479
+ let tmpTargetGroup = tmpTargetSection.Groups[tmpContainerIndices[1]];
480
+ if (!tmpSourceGroup || !Array.isArray(tmpSourceGroup.Rows) || !tmpTargetGroup || !Array.isArray(tmpTargetGroup.Rows))
481
+ {
482
+ return;
483
+ }
484
+ let tmpSourceRow = tmpSourceGroup.Rows[tmpSourceIndices[2]];
485
+ let tmpTargetRow = tmpTargetGroup.Rows[tmpContainerIndices[2]];
486
+ if (!tmpSourceRow || !Array.isArray(tmpSourceRow.Inputs) || !tmpTargetRow)
487
+ {
488
+ return;
489
+ }
490
+ if (!Array.isArray(tmpTargetRow.Inputs))
491
+ {
492
+ tmpTargetRow.Inputs = [];
493
+ }
494
+
495
+ let tmpAddress = tmpSourceRow.Inputs.splice(tmpSourceIndices[3], 1)[0];
496
+ tmpTargetRow.Inputs.push(tmpAddress);
497
+
498
+ // Update Descriptor metadata
499
+ if (typeof tmpAddress === 'string' && tmpManifest.Descriptors && tmpManifest.Descriptors[tmpAddress])
500
+ {
501
+ let tmpDescriptor = tmpManifest.Descriptors[tmpAddress];
502
+ if (!tmpDescriptor.PictForm)
503
+ {
504
+ tmpDescriptor.PictForm = {};
505
+ }
506
+ tmpDescriptor.PictForm.Section = tmpTargetSection.Hash || '';
507
+ tmpDescriptor.PictForm.Group = tmpTargetGroup.Hash || '';
508
+ tmpDescriptor.PictForm.Row = tmpContainerIndices[2] + 1;
509
+ }
510
+ break;
511
+ }
512
+ default:
513
+ return;
514
+ }
515
+
516
+ this._ParentFormEditor.renderVisualEditor();
517
+ }
518
+
519
+ /**
520
+ * Build the drag handle HTML for a container element.
521
+ * Returns an empty string when drag-and-drop is disabled.
522
+ */
523
+ _buildDragHandleHTML(pSize)
524
+ {
525
+ if (!this._ParentFormEditor._DragAndDropEnabled)
526
+ {
527
+ return '';
528
+ }
529
+
530
+ return `<span class="pict-fe-drag-handle">${this._ParentFormEditor._IconographyProvider.getIcon('Action', 'DragHandle', pSize || 12)}</span>`;
531
+ }
532
+ }
533
+
534
+ module.exports = FormEditorDragDrop;
535
+ module.exports.default_configuration = {};