pict-section-formeditor 1.0.2 → 1.0.3
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.
- package/package.json +1 -1
- package/source/Pict-Section-FormEditor-DefaultConfiguration.js +36 -1
- package/source/providers/Pict-Provider-FormEditorDragDrop.js +55 -21
- package/source/providers/Pict-Provider-FormEditorManifestOps.js +7 -2
- package/source/views/PictView-FormEditor-InputTypePicker.js +16 -2
- package/source/views/PictView-FormEditor.js +18 -0
- package/test/Pict-Section-FormEditor_tests.js +206 -0
package/package.json
CHANGED
|
@@ -696,6 +696,42 @@ module.exports = (
|
|
|
696
696
|
outline-offset: -2px;
|
|
697
697
|
background: rgba(158, 107, 71, 0.05);
|
|
698
698
|
}
|
|
699
|
+
.pict-fe-drag-insert-before
|
|
700
|
+
{
|
|
701
|
+
position: relative;
|
|
702
|
+
background: rgba(158, 107, 71, 0.03);
|
|
703
|
+
}
|
|
704
|
+
.pict-fe-drag-insert-before::before
|
|
705
|
+
{
|
|
706
|
+
content: '';
|
|
707
|
+
position: absolute;
|
|
708
|
+
top: -1px;
|
|
709
|
+
left: 0;
|
|
710
|
+
right: 0;
|
|
711
|
+
height: 3px;
|
|
712
|
+
background: #9E6B47;
|
|
713
|
+
border-radius: 2px;
|
|
714
|
+
z-index: 10;
|
|
715
|
+
pointer-events: none;
|
|
716
|
+
}
|
|
717
|
+
.pict-fe-drag-insert-after
|
|
718
|
+
{
|
|
719
|
+
position: relative;
|
|
720
|
+
background: rgba(158, 107, 71, 0.03);
|
|
721
|
+
}
|
|
722
|
+
.pict-fe-drag-insert-after::after
|
|
723
|
+
{
|
|
724
|
+
content: '';
|
|
725
|
+
position: absolute;
|
|
726
|
+
bottom: -1px;
|
|
727
|
+
left: 0;
|
|
728
|
+
right: 0;
|
|
729
|
+
height: 3px;
|
|
730
|
+
background: #9E6B47;
|
|
731
|
+
border-radius: 2px;
|
|
732
|
+
z-index: 10;
|
|
733
|
+
pointer-events: none;
|
|
734
|
+
}
|
|
699
735
|
|
|
700
736
|
/* ---- Editor Layout: tab content + toggle + properties panel ---- */
|
|
701
737
|
.pict-fe-editor-layout
|
|
@@ -1316,7 +1352,6 @@ module.exports = (
|
|
|
1316
1352
|
width: 100%;
|
|
1317
1353
|
height: 100%;
|
|
1318
1354
|
z-index: 9999;
|
|
1319
|
-
overflow: hidden;
|
|
1320
1355
|
}
|
|
1321
1356
|
.pict-fe-inputtype-picker
|
|
1322
1357
|
{
|
|
@@ -87,7 +87,24 @@ class FormEditorDragDrop extends libPictProvider
|
|
|
87
87
|
|
|
88
88
|
if (pEvent && pEvent.currentTarget)
|
|
89
89
|
{
|
|
90
|
-
|
|
90
|
+
// Detect whether the cursor is in the top or bottom half of the target
|
|
91
|
+
let tmpRect = pEvent.currentTarget.getBoundingClientRect();
|
|
92
|
+
let tmpMidpoint = tmpRect.top + (tmpRect.height / 2);
|
|
93
|
+
let tmpIsTopHalf = pEvent.clientY < tmpMidpoint;
|
|
94
|
+
|
|
95
|
+
pEvent.currentTarget.classList.remove('pict-fe-drag-insert-before');
|
|
96
|
+
pEvent.currentTarget.classList.remove('pict-fe-drag-insert-after');
|
|
97
|
+
|
|
98
|
+
if (tmpIsTopHalf)
|
|
99
|
+
{
|
|
100
|
+
pEvent.currentTarget.classList.add('pict-fe-drag-insert-before');
|
|
101
|
+
}
|
|
102
|
+
else
|
|
103
|
+
{
|
|
104
|
+
pEvent.currentTarget.classList.add('pict-fe-drag-insert-after');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this._ParentFormEditor._DragState.InsertPosition = tmpIsTopHalf ? 'before' : 'after';
|
|
91
108
|
}
|
|
92
109
|
}
|
|
93
110
|
|
|
@@ -101,6 +118,8 @@ class FormEditorDragDrop extends libPictProvider
|
|
|
101
118
|
if (pEvent && pEvent.currentTarget)
|
|
102
119
|
{
|
|
103
120
|
pEvent.currentTarget.classList.remove('pict-fe-drag-over');
|
|
121
|
+
pEvent.currentTarget.classList.remove('pict-fe-drag-insert-before');
|
|
122
|
+
pEvent.currentTarget.classList.remove('pict-fe-drag-insert-after');
|
|
104
123
|
}
|
|
105
124
|
}
|
|
106
125
|
|
|
@@ -123,6 +142,7 @@ class FormEditorDragDrop extends libPictProvider
|
|
|
123
142
|
|
|
124
143
|
let tmpTargetIndices = [pIndex0, pIndex1, pIndex2, pIndex3].filter((pVal) => { return typeof pVal === 'number'; });
|
|
125
144
|
let tmpSourceIndices = this._ParentFormEditor._DragState.Indices;
|
|
145
|
+
let tmpInsertPosition = this._ParentFormEditor._DragState.InsertPosition || 'before';
|
|
126
146
|
this._ParentFormEditor._DragState = null;
|
|
127
147
|
|
|
128
148
|
// Check if source and target are identical
|
|
@@ -148,7 +168,8 @@ class FormEditorDragDrop extends libPictProvider
|
|
|
148
168
|
return;
|
|
149
169
|
}
|
|
150
170
|
let tmpItem = tmpManifest.Sections.splice(tmpFromIdx, 1)[0];
|
|
151
|
-
|
|
171
|
+
let tmpInsertIdx = this._computeInsertIndex(tmpFromIdx, tmpToIdx, true, tmpInsertPosition);
|
|
172
|
+
tmpManifest.Sections.splice(tmpInsertIdx, 0, tmpItem);
|
|
152
173
|
break;
|
|
153
174
|
}
|
|
154
175
|
case 'group':
|
|
@@ -164,15 +185,9 @@ class FormEditorDragDrop extends libPictProvider
|
|
|
164
185
|
tmpTargetSection.Groups = [];
|
|
165
186
|
}
|
|
166
187
|
|
|
188
|
+
let tmpSameContainer = (tmpSourceIndices[0] === tmpTargetIndices[0]);
|
|
167
189
|
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
|
-
}
|
|
190
|
+
let tmpInsertIdx = this._computeInsertIndex(tmpSourceIndices[1], tmpTargetIndices[1], tmpSameContainer, tmpInsertPosition);
|
|
176
191
|
tmpTargetSection.Groups.splice(tmpInsertIdx, 0, tmpItem);
|
|
177
192
|
break;
|
|
178
193
|
}
|
|
@@ -197,12 +212,8 @@ class FormEditorDragDrop extends libPictProvider
|
|
|
197
212
|
|
|
198
213
|
let tmpItem = tmpSourceGroup.Rows.splice(tmpSourceIndices[2], 1)[0];
|
|
199
214
|
|
|
200
|
-
let tmpInsertIdx = tmpTargetIndices[2];
|
|
201
215
|
let tmpSameContainer = (tmpSourceIndices[0] === tmpTargetIndices[0]) && (tmpSourceIndices[1] === tmpTargetIndices[1]);
|
|
202
|
-
|
|
203
|
-
{
|
|
204
|
-
tmpInsertIdx--;
|
|
205
|
-
}
|
|
216
|
+
let tmpInsertIdx = this._computeInsertIndex(tmpSourceIndices[2], tmpTargetIndices[2], tmpSameContainer, tmpInsertPosition);
|
|
206
217
|
tmpTargetGroup.Rows.splice(tmpInsertIdx, 0, tmpItem);
|
|
207
218
|
|
|
208
219
|
// Sync row indices on both source and target groups
|
|
@@ -240,12 +251,8 @@ class FormEditorDragDrop extends libPictProvider
|
|
|
240
251
|
|
|
241
252
|
let tmpAddress = tmpSourceRow.Inputs.splice(tmpSourceIndices[3], 1)[0];
|
|
242
253
|
|
|
243
|
-
let tmpInsertIdx = tmpTargetIndices[3];
|
|
244
254
|
let tmpSameContainer = (tmpSourceIndices[0] === tmpTargetIndices[0]) && (tmpSourceIndices[1] === tmpTargetIndices[1]) && (tmpSourceIndices[2] === tmpTargetIndices[2]);
|
|
245
|
-
|
|
246
|
-
{
|
|
247
|
-
tmpInsertIdx--;
|
|
248
|
-
}
|
|
255
|
+
let tmpInsertIdx = this._computeInsertIndex(tmpSourceIndices[3], tmpTargetIndices[3], tmpSameContainer, tmpInsertPosition);
|
|
249
256
|
tmpTargetRow.Inputs.splice(tmpInsertIdx, 0, tmpAddress);
|
|
250
257
|
|
|
251
258
|
// Update the Descriptor's PictForm metadata for the new location
|
|
@@ -282,10 +289,12 @@ class FormEditorDragDrop extends libPictProvider
|
|
|
282
289
|
let tmpContainer = this.pict.ContentAssignment.getElement(`#FormEditor-Panel-Visual-${this._ParentFormEditor.Hash}`);
|
|
283
290
|
if (tmpContainer && tmpContainer[0])
|
|
284
291
|
{
|
|
285
|
-
let tmpHighlighted = tmpContainer[0].querySelectorAll('.pict-fe-drag-over');
|
|
292
|
+
let tmpHighlighted = tmpContainer[0].querySelectorAll('.pict-fe-drag-over, .pict-fe-drag-insert-before, .pict-fe-drag-insert-after');
|
|
286
293
|
for (let i = 0; i < tmpHighlighted.length; i++)
|
|
287
294
|
{
|
|
288
295
|
tmpHighlighted[i].classList.remove('pict-fe-drag-over');
|
|
296
|
+
tmpHighlighted[i].classList.remove('pict-fe-drag-insert-before');
|
|
297
|
+
tmpHighlighted[i].classList.remove('pict-fe-drag-insert-after');
|
|
289
298
|
}
|
|
290
299
|
}
|
|
291
300
|
}
|
|
@@ -314,6 +323,31 @@ class FormEditorDragDrop extends libPictProvider
|
|
|
314
323
|
return true;
|
|
315
324
|
}
|
|
316
325
|
|
|
326
|
+
/**
|
|
327
|
+
* Compute the final insert index for a position-aware drag-and-drop.
|
|
328
|
+
*
|
|
329
|
+
* After removing the source item from its array, this method determines the
|
|
330
|
+
* correct splice index based on the user's cursor position (insert before or
|
|
331
|
+
* after the target).
|
|
332
|
+
*
|
|
333
|
+
* @param {number} pSourceIdx - The source item's index within its container
|
|
334
|
+
* @param {number} pTargetIdx - The target item's index within its container
|
|
335
|
+
* @param {boolean} pSameContainer - Whether source and target share the same parent
|
|
336
|
+
* @param {string} pInsertPosition - 'before' or 'after'
|
|
337
|
+
* @returns {number} The index to use with Array.splice after removing the source
|
|
338
|
+
*/
|
|
339
|
+
_computeInsertIndex(pSourceIdx, pTargetIdx, pSameContainer, pInsertPosition)
|
|
340
|
+
{
|
|
341
|
+
let tmpLogicalTarget = (pInsertPosition === 'before') ? pTargetIdx : pTargetIdx + 1;
|
|
342
|
+
|
|
343
|
+
if (pSameContainer && pSourceIdx < tmpLogicalTarget)
|
|
344
|
+
{
|
|
345
|
+
tmpLogicalTarget--;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return tmpLogicalTarget;
|
|
349
|
+
}
|
|
350
|
+
|
|
317
351
|
/**
|
|
318
352
|
* Build the drag attribute string for a container element.
|
|
319
353
|
* Returns an empty string when drag-and-drop is disabled.
|
|
@@ -167,8 +167,13 @@ class FormEditorManifestOps extends libPictProvider
|
|
|
167
167
|
tmpGroup.Rows = [];
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
-
// PictForm.Row is 1-based; pad with empty rows if necessary
|
|
171
|
-
|
|
170
|
+
// PictForm.Row is 1-based; pad with empty rows if necessary.
|
|
171
|
+
// Row may be a number or a string (e.g. "2") in real-world manifests.
|
|
172
|
+
let tmpRowNumber = parseInt(tmpPictForm.Row, 10);
|
|
173
|
+
if (isNaN(tmpRowNumber) || tmpRowNumber < 1)
|
|
174
|
+
{
|
|
175
|
+
tmpRowNumber = 1;
|
|
176
|
+
}
|
|
172
177
|
let tmpRowIndex = tmpRowNumber - 1;
|
|
173
178
|
while (tmpGroup.Rows.length <= tmpRowIndex)
|
|
174
179
|
{
|
|
@@ -103,8 +103,10 @@ class PictViewFormEditorInputTypePicker extends libPictView
|
|
|
103
103
|
}
|
|
104
104
|
}, { passive: false });
|
|
105
105
|
|
|
106
|
-
|
|
106
|
+
// Append overlay and picker as siblings on document.body so the picker
|
|
107
|
+
// is not inside the overlay's stacking context (which can trap pointer events).
|
|
107
108
|
document.body.appendChild(tmpOverlay);
|
|
109
|
+
document.body.appendChild(tmpPickerContainer);
|
|
108
110
|
|
|
109
111
|
// Position the picker using fixed viewport coordinates
|
|
110
112
|
// anchored below the InputType chip (or properties panel button as fallback)
|
|
@@ -320,7 +322,9 @@ class PictViewFormEditorInputTypePicker extends libPictView
|
|
|
320
322
|
{
|
|
321
323
|
let tmpHash = this._ParentFormEditor.Hash;
|
|
322
324
|
let tmpOverlayId = `FormEditor-InputTypePicker-${tmpHash}-Overlay`;
|
|
325
|
+
let tmpPickerId = `FormEditor-InputTypePicker-${tmpHash}`;
|
|
323
326
|
|
|
327
|
+
// Remove the overlay
|
|
324
328
|
let tmpOverlaySet = this.pict.ContentAssignment.getElement(`#${tmpOverlayId}`);
|
|
325
329
|
let tmpOverlay = (Array.isArray(tmpOverlaySet) && tmpOverlaySet.length > 0) ? tmpOverlaySet[0] : tmpOverlaySet;
|
|
326
330
|
if (tmpOverlay && tmpOverlay.parentNode)
|
|
@@ -328,6 +332,14 @@ class PictViewFormEditorInputTypePicker extends libPictView
|
|
|
328
332
|
tmpOverlay.parentNode.removeChild(tmpOverlay);
|
|
329
333
|
}
|
|
330
334
|
|
|
335
|
+
// Remove the picker container (now a sibling of the overlay, not a child)
|
|
336
|
+
let tmpPickerSet = this.pict.ContentAssignment.getElement(`#${tmpPickerId}`);
|
|
337
|
+
let tmpPicker = (Array.isArray(tmpPickerSet) && tmpPickerSet.length > 0) ? tmpPickerSet[0] : tmpPickerSet;
|
|
338
|
+
if (tmpPicker && tmpPicker.parentNode)
|
|
339
|
+
{
|
|
340
|
+
tmpPicker.parentNode.removeChild(tmpPicker);
|
|
341
|
+
}
|
|
342
|
+
|
|
331
343
|
this._InputTypePickerContext = null;
|
|
332
344
|
}
|
|
333
345
|
|
|
@@ -491,8 +503,10 @@ class PictViewFormEditorInputTypePicker extends libPictView
|
|
|
491
503
|
}
|
|
492
504
|
}, { passive: false });
|
|
493
505
|
|
|
494
|
-
|
|
506
|
+
// Append overlay and picker as siblings on document.body so the picker
|
|
507
|
+
// is not inside the overlay's stacking context (which can trap pointer events).
|
|
495
508
|
document.body.appendChild(tmpOverlay);
|
|
509
|
+
document.body.appendChild(tmpPickerContainer);
|
|
496
510
|
|
|
497
511
|
// Position anchored to the InputType button in the properties panel
|
|
498
512
|
let tmpAnchorEl = document.getElementById(`FormEditor-PropsInputTypeBtn-${tmpHash}`);
|
|
@@ -991,6 +991,24 @@ class PictViewFormEditor extends libPictView
|
|
|
991
991
|
{
|
|
992
992
|
return `${this.pict.browserAddress}.views['${this.Hash}']`;
|
|
993
993
|
}
|
|
994
|
+
|
|
995
|
+
// Proxy methods for the InputType picker child view.
|
|
996
|
+
// The picker's inline onclick handlers reference the parent form editor's
|
|
997
|
+
// browser view ref, so these must exist on the parent to route calls through.
|
|
998
|
+
commitEditInputType(pInputTypeHash)
|
|
999
|
+
{
|
|
1000
|
+
this._InputTypePickerView.commitEditInputType(pInputTypeHash);
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
closeInputTypePicker()
|
|
1004
|
+
{
|
|
1005
|
+
this._InputTypePickerView.closeInputTypePicker();
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
_onInputTypePickerSearch(pQuery)
|
|
1009
|
+
{
|
|
1010
|
+
this._InputTypePickerView._onInputTypePickerSearch(pQuery);
|
|
1011
|
+
}
|
|
994
1012
|
}
|
|
995
1013
|
|
|
996
1014
|
module.exports = PictViewFormEditor;
|
|
@@ -2192,6 +2192,212 @@ suite
|
|
|
2192
2192
|
fDone();
|
|
2193
2193
|
}
|
|
2194
2194
|
);
|
|
2195
|
+
test
|
|
2196
|
+
(
|
|
2197
|
+
'Should insert before target when InsertPosition is before (same container)',
|
|
2198
|
+
function (fDone)
|
|
2199
|
+
{
|
|
2200
|
+
let tmpPict = new libPict({ Product: 'TestFormEditor' });
|
|
2201
|
+
tmpPict.AppData.FormConfig =
|
|
2202
|
+
{
|
|
2203
|
+
Scope: 'TestInsertBefore',
|
|
2204
|
+
Sections:
|
|
2205
|
+
[
|
|
2206
|
+
{ Name: 'A', Hash: 'A', Groups: [] },
|
|
2207
|
+
{ Name: 'B', Hash: 'B', Groups: [] },
|
|
2208
|
+
{ Name: 'C', Hash: 'C', Groups: [] }
|
|
2209
|
+
],
|
|
2210
|
+
Descriptors: {}
|
|
2211
|
+
};
|
|
2212
|
+
|
|
2213
|
+
let tmpView = tmpPict.addView('TestInsertBefore',
|
|
2214
|
+
{
|
|
2215
|
+
ViewIdentifier: 'TestInsertBefore',
|
|
2216
|
+
ManifestDataAddress: 'AppData.FormConfig',
|
|
2217
|
+
DefaultDestinationAddress: '#FormEditor-Container',
|
|
2218
|
+
Renderables:
|
|
2219
|
+
[
|
|
2220
|
+
{
|
|
2221
|
+
RenderableHash: 'FormEditor-Container',
|
|
2222
|
+
TemplateHash: 'FormEditor-Container-Template',
|
|
2223
|
+
DestinationAddress: '#FormEditor-Container',
|
|
2224
|
+
RenderMethod: 'replace'
|
|
2225
|
+
}
|
|
2226
|
+
]
|
|
2227
|
+
}, libPictSectionFormEditor);
|
|
2228
|
+
|
|
2229
|
+
tmpView.initialize();
|
|
2230
|
+
tmpView.render();
|
|
2231
|
+
tmpView._DragAndDropEnabled = true;
|
|
2232
|
+
|
|
2233
|
+
// Drag C(2) to A(0), InsertPosition=before → [C, A, B]
|
|
2234
|
+
tmpView._DragState = { Type: 'section', Indices: [2], InsertPosition: 'before' };
|
|
2235
|
+
tmpView._DragDropProvider.onDrop(
|
|
2236
|
+
{ preventDefault: function() {} },
|
|
2237
|
+
'section', 0
|
|
2238
|
+
);
|
|
2239
|
+
|
|
2240
|
+
var tmpManifest = tmpPict.AppData.FormConfig;
|
|
2241
|
+
Expect(tmpManifest.Sections[0].Hash).to.equal('C');
|
|
2242
|
+
Expect(tmpManifest.Sections[1].Hash).to.equal('A');
|
|
2243
|
+
Expect(tmpManifest.Sections[2].Hash).to.equal('B');
|
|
2244
|
+
|
|
2245
|
+
fDone();
|
|
2246
|
+
}
|
|
2247
|
+
);
|
|
2248
|
+
test
|
|
2249
|
+
(
|
|
2250
|
+
'Should insert after target when InsertPosition is after (same container)',
|
|
2251
|
+
function (fDone)
|
|
2252
|
+
{
|
|
2253
|
+
let tmpPict = new libPict({ Product: 'TestFormEditor' });
|
|
2254
|
+
tmpPict.AppData.FormConfig =
|
|
2255
|
+
{
|
|
2256
|
+
Scope: 'TestInsertAfter',
|
|
2257
|
+
Sections:
|
|
2258
|
+
[
|
|
2259
|
+
{ Name: 'A', Hash: 'A', Groups: [] },
|
|
2260
|
+
{ Name: 'B', Hash: 'B', Groups: [] },
|
|
2261
|
+
{ Name: 'C', Hash: 'C', Groups: [] }
|
|
2262
|
+
],
|
|
2263
|
+
Descriptors: {}
|
|
2264
|
+
};
|
|
2265
|
+
|
|
2266
|
+
let tmpView = tmpPict.addView('TestInsertAfter',
|
|
2267
|
+
{
|
|
2268
|
+
ViewIdentifier: 'TestInsertAfter',
|
|
2269
|
+
ManifestDataAddress: 'AppData.FormConfig',
|
|
2270
|
+
DefaultDestinationAddress: '#FormEditor-Container',
|
|
2271
|
+
Renderables:
|
|
2272
|
+
[
|
|
2273
|
+
{
|
|
2274
|
+
RenderableHash: 'FormEditor-Container',
|
|
2275
|
+
TemplateHash: 'FormEditor-Container-Template',
|
|
2276
|
+
DestinationAddress: '#FormEditor-Container',
|
|
2277
|
+
RenderMethod: 'replace'
|
|
2278
|
+
}
|
|
2279
|
+
]
|
|
2280
|
+
}, libPictSectionFormEditor);
|
|
2281
|
+
|
|
2282
|
+
tmpView.initialize();
|
|
2283
|
+
tmpView.render();
|
|
2284
|
+
tmpView._DragAndDropEnabled = true;
|
|
2285
|
+
|
|
2286
|
+
// Drag C(2) to A(0), InsertPosition=after → [A, C, B]
|
|
2287
|
+
tmpView._DragState = { Type: 'section', Indices: [2], InsertPosition: 'after' };
|
|
2288
|
+
tmpView._DragDropProvider.onDrop(
|
|
2289
|
+
{ preventDefault: function() {} },
|
|
2290
|
+
'section', 0
|
|
2291
|
+
);
|
|
2292
|
+
|
|
2293
|
+
var tmpManifest = tmpPict.AppData.FormConfig;
|
|
2294
|
+
Expect(tmpManifest.Sections[0].Hash).to.equal('A');
|
|
2295
|
+
Expect(tmpManifest.Sections[1].Hash).to.equal('C');
|
|
2296
|
+
Expect(tmpManifest.Sections[2].Hash).to.equal('B');
|
|
2297
|
+
|
|
2298
|
+
fDone();
|
|
2299
|
+
}
|
|
2300
|
+
);
|
|
2301
|
+
test
|
|
2302
|
+
(
|
|
2303
|
+
'Should handle forward drag with before and after positions',
|
|
2304
|
+
function (fDone)
|
|
2305
|
+
{
|
|
2306
|
+
// Test forward drag A(0) to C(2) with before → [B, A, C]
|
|
2307
|
+
let tmpPict = new libPict({ Product: 'TestFormEditor' });
|
|
2308
|
+
tmpPict.AppData.FormConfig =
|
|
2309
|
+
{
|
|
2310
|
+
Scope: 'TestForwardBefore',
|
|
2311
|
+
Sections:
|
|
2312
|
+
[
|
|
2313
|
+
{ Name: 'A', Hash: 'A', Groups: [] },
|
|
2314
|
+
{ Name: 'B', Hash: 'B', Groups: [] },
|
|
2315
|
+
{ Name: 'C', Hash: 'C', Groups: [] }
|
|
2316
|
+
],
|
|
2317
|
+
Descriptors: {}
|
|
2318
|
+
};
|
|
2319
|
+
|
|
2320
|
+
let tmpView = tmpPict.addView('TestForwardBefore',
|
|
2321
|
+
{
|
|
2322
|
+
ViewIdentifier: 'TestForwardBefore',
|
|
2323
|
+
ManifestDataAddress: 'AppData.FormConfig',
|
|
2324
|
+
DefaultDestinationAddress: '#FormEditor-Container',
|
|
2325
|
+
Renderables:
|
|
2326
|
+
[
|
|
2327
|
+
{
|
|
2328
|
+
RenderableHash: 'FormEditor-Container',
|
|
2329
|
+
TemplateHash: 'FormEditor-Container-Template',
|
|
2330
|
+
DestinationAddress: '#FormEditor-Container',
|
|
2331
|
+
RenderMethod: 'replace'
|
|
2332
|
+
}
|
|
2333
|
+
]
|
|
2334
|
+
}, libPictSectionFormEditor);
|
|
2335
|
+
|
|
2336
|
+
tmpView.initialize();
|
|
2337
|
+
tmpView.render();
|
|
2338
|
+
tmpView._DragAndDropEnabled = true;
|
|
2339
|
+
|
|
2340
|
+
// Drag A(0) to C(2), InsertPosition=before → [B, A, C]
|
|
2341
|
+
tmpView._DragState = { Type: 'section', Indices: [0], InsertPosition: 'before' };
|
|
2342
|
+
tmpView._DragDropProvider.onDrop(
|
|
2343
|
+
{ preventDefault: function() {} },
|
|
2344
|
+
'section', 2
|
|
2345
|
+
);
|
|
2346
|
+
|
|
2347
|
+
var tmpManifest = tmpPict.AppData.FormConfig;
|
|
2348
|
+
Expect(tmpManifest.Sections[0].Hash).to.equal('B');
|
|
2349
|
+
Expect(tmpManifest.Sections[1].Hash).to.equal('A');
|
|
2350
|
+
Expect(tmpManifest.Sections[2].Hash).to.equal('C');
|
|
2351
|
+
|
|
2352
|
+
// Now test forward drag with after: reset
|
|
2353
|
+
tmpManifest.Sections = [
|
|
2354
|
+
{ Name: 'A', Hash: 'A', Groups: [] },
|
|
2355
|
+
{ Name: 'B', Hash: 'B', Groups: [] },
|
|
2356
|
+
{ Name: 'C', Hash: 'C', Groups: [] }
|
|
2357
|
+
];
|
|
2358
|
+
|
|
2359
|
+
// Drag A(0) to C(2), InsertPosition=after → [B, C, A]
|
|
2360
|
+
tmpView._DragState = { Type: 'section', Indices: [0], InsertPosition: 'after' };
|
|
2361
|
+
tmpView._DragDropProvider.onDrop(
|
|
2362
|
+
{ preventDefault: function() {} },
|
|
2363
|
+
'section', 2
|
|
2364
|
+
);
|
|
2365
|
+
|
|
2366
|
+
Expect(tmpManifest.Sections[0].Hash).to.equal('B');
|
|
2367
|
+
Expect(tmpManifest.Sections[1].Hash).to.equal('C');
|
|
2368
|
+
Expect(tmpManifest.Sections[2].Hash).to.equal('A');
|
|
2369
|
+
|
|
2370
|
+
fDone();
|
|
2371
|
+
}
|
|
2372
|
+
);
|
|
2373
|
+
test
|
|
2374
|
+
(
|
|
2375
|
+
'Should compute insert index correctly via _computeInsertIndex helper',
|
|
2376
|
+
function ()
|
|
2377
|
+
{
|
|
2378
|
+
let tmpPict = new libPict({ Product: 'TestFormEditor' });
|
|
2379
|
+
let tmpView = tmpPict.addView('TestComputeIdx',
|
|
2380
|
+
{
|
|
2381
|
+
ViewIdentifier: 'TestComputeIdx'
|
|
2382
|
+
}, libPictSectionFormEditor);
|
|
2383
|
+
tmpView.initialize();
|
|
2384
|
+
|
|
2385
|
+
let tmpDD = tmpView._DragDropProvider;
|
|
2386
|
+
|
|
2387
|
+
// Same container, backward drag, insert before
|
|
2388
|
+
Expect(tmpDD._computeInsertIndex(2, 0, true, 'before')).to.equal(0);
|
|
2389
|
+
// Same container, backward drag, insert after
|
|
2390
|
+
Expect(tmpDD._computeInsertIndex(2, 0, true, 'after')).to.equal(1);
|
|
2391
|
+
// Same container, forward drag, insert before
|
|
2392
|
+
Expect(tmpDD._computeInsertIndex(0, 2, true, 'before')).to.equal(1);
|
|
2393
|
+
// Same container, forward drag, insert after
|
|
2394
|
+
Expect(tmpDD._computeInsertIndex(0, 2, true, 'after')).to.equal(2);
|
|
2395
|
+
// Cross container, insert before
|
|
2396
|
+
Expect(tmpDD._computeInsertIndex(1, 0, false, 'before')).to.equal(0);
|
|
2397
|
+
// Cross container, insert after
|
|
2398
|
+
Expect(tmpDD._computeInsertIndex(1, 0, false, 'after')).to.equal(1);
|
|
2399
|
+
}
|
|
2400
|
+
);
|
|
2195
2401
|
}
|
|
2196
2402
|
);
|
|
2197
2403
|
suite
|