pict-section-form 1.3.4 → 1.3.5

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pict-section-form",
3
- "version": "1.3.4",
3
+ "version": "1.3.5",
4
4
  "description": "Pict dynamic forms",
5
5
  "main": "source/Pict-Section-Form.js",
6
6
  "directories": {
@@ -330,7 +330,7 @@ class DynamicTabularData extends libPictProvider
330
330
  // Render (source + dependent views) BEFORE solving so dependent DynamicColumns tables
331
331
  // don't blank until the next edit, and the solve's DOM side effects survive. Matches
332
332
  // the add/delete handlers' order.
333
- this._repaintAfterRowReorder(tmpGroup);
333
+ this._repaintAfterRowReorder(pView, tmpGroup);
334
334
  }
335
335
  }
336
336
  }
@@ -375,7 +375,7 @@ class DynamicTabularData extends libPictProvider
375
375
  // (e.g. SetGroupVisibility hiding a validation message) act on the freshly rebuilt
376
376
  // DOM and survive, and so dependent DynamicColumns tables don't blank until the next
377
377
  // edit. Matches the add/delete handlers' order.
378
- this._repaintAfterRowReorder(tmpGroup);
378
+ this._repaintAfterRowReorder(pView, tmpGroup);
379
379
  }
380
380
  }
381
381
  }
@@ -425,7 +425,7 @@ class DynamicTabularData extends libPictProvider
425
425
  // (e.g. SetGroupVisibility hiding a validation message) act on the freshly rebuilt
426
426
  // DOM and survive, and so dependent DynamicColumns tables don't blank until the next
427
427
  // edit. Matches the add/delete handlers' order.
428
- this._repaintAfterRowReorder(tmpGroup);
428
+ this._repaintAfterRowReorder(pView, tmpGroup);
429
429
  }
430
430
  }
431
431
  }
@@ -843,43 +843,34 @@ class DynamicTabularData extends libPictProvider
843
843
  *
844
844
  * @param {Object} pGroup - The reordered group (its RecordSetAddress drives dependents).
845
845
  */
846
- _repaintAfterRowReorder(pGroup)
846
+ _repaintAfterRowReorder(pView, pGroup)
847
847
  {
848
- // Render every view that renders this record set as a table (the source table itself
849
- // plus any sibling views bound to the same RecordSetAddress).
850
- let tmpViewsToRender = this.pict.views.PictFormMetacontroller.filterViews(
851
- (pViewToTestForGroup) =>
852
- {
853
- if (!pViewToTestForGroup.isPictSectionForm)
854
- {
855
- return false;
856
- }
857
- let tmpGroupsToTest = pViewToTestForGroup.getGroups();
858
- for (let i = 0; i < tmpGroupsToTest.length; i++)
859
- {
860
- if (tmpGroupsToTest[i].RecordSetAddress == pGroup.RecordSetAddress)
861
- {
862
- return true;
863
- }
864
- }
865
- return false;
866
- });
867
- // Re-rendering an entity-selector table clobbers its selected values in the
868
- // model, so preserve them across the render.
869
- this._renderViewsPreservingRecordSet(pGroup.RecordSetAddress, tmpViewsToRender);
870
-
871
- // Rebuild any OTHER views whose DynamicColumns are sourced from this record set
872
- // HERE, in the render phase -- BEFORE the marshal below -- so the column DOM is
873
- // correct (and re-labeled to the new order) when the marshal fills it. Without
874
- // this the dependent table is only rebuilt mid-marshal (onDataMarshalToForm),
875
- // which renders AFTER the cells were filled and blanks them until the next edit.
848
+ // A reorder (move up/down/set-index) preserves the row COUNT -- the source table's DOM rows
849
+ // already exist; only which row holds which value changes. A full source-view render() would
850
+ // tear down and re-create every cell widget, and each entity-selector select2 re-init costs
851
+ // roughly O(document size), so on a large form that is SECONDS per move. Skip the source
852
+ // render and let the marshal below push the reordered model values into the existing DOM rows
853
+ // in place. (Add/delete change the row count and still render via their own paths.) Skipping
854
+ // the render also removes the need for the snapshot/restore in _renderViewsPreservingRecordSet:
855
+ // with no destructive render, the entity values are never clobbered.
856
+
857
+ // Dependent DynamicColumns views still need their generated column labels re-resolved for the
858
+ // new order (cheap -- those tables carry no entity widgets).
876
859
  this._rebuildDependentDynamicColumnViews(pGroup.RecordSetAddress);
877
860
 
878
- // Run the solver
861
+ // Run the solver, then marshal the model back out to the existing form DOM.
879
862
  this.pict.providers.DynamicSolver.solveViews();
880
-
881
- // We've re-rendered but we don't know what needs to be marshaled based on the solve that ran above so marshal everything
882
863
  this.pict.views.PictFormMetacontroller.marshalFormSections();
864
+
865
+ // marshalFormSections updates simple cells in place, but a stateful widget (an entity
866
+ // selector's select2) will not switch to a reordered value whose <option> isn't the one it
867
+ // currently shows. Ask each input provider to repaint its display for the new row order:
868
+ // entity selectors force their select2 to the row's current value, everything else no-ops.
869
+ // Cheap (in-place value set, no widget teardown) versus the full re-render this replaced.
870
+ if (pView && (typeof pView.runInputProviderFunctions === 'function'))
871
+ {
872
+ pView.runInputProviderFunctions('onTabularRowReorderRepaint', null, null, this.fable.getUUID());
873
+ }
883
874
  }
884
875
  }
885
876
 
@@ -156,6 +156,45 @@ class PictInputExtensionProvider extends libPictProvider
156
156
  return true;
157
157
  }
158
158
 
159
+ /**
160
+ * Repaint this input's rendered display from the model after a tabular row REORDER
161
+ * (move up/down/set-index), which preserves the row count but changes which row holds
162
+ * which value. A plain marshal updates simple inputs in place, but stateful widgets
163
+ * (e.g. an entity-selector's select2) will not switch to a value whose option isn't the
164
+ * one currently shown; those providers override this to force their display to the row's
165
+ * current value. Default is a no-op.
166
+ *
167
+ * @param {Object} pView - The view object.
168
+ * @param {Object} pGroup - The group definition object.
169
+ * @param {number} pRow - The row index.
170
+ * @param {Object} pInput - The input object.
171
+ * @param {any} pValue - The value to display.
172
+ * @param {string} pHTMLSelector - The HTML selector.
173
+ * @param {string} pTransactionGUID - The transaction GUID for the event dispatch.
174
+ * @returns {boolean} - Returns true.
175
+ */
176
+ onTabularRowReorderRepaint(pView, pGroup, pRow, pInput, pValue, pHTMLSelector, pTransactionGUID)
177
+ {
178
+ return true;
179
+ }
180
+
181
+ /**
182
+ * Tabular sibling of onTabularRowReorderRepaint. Default is a no-op.
183
+ *
184
+ * @param {Object} pView - The view object.
185
+ * @param {Object} pGroup - The group definition object.
186
+ * @param {Object} pInput - The input object.
187
+ * @param {any} pValue - The value to display.
188
+ * @param {string} pHTMLSelector - The HTML selector.
189
+ * @param {number} pRowIndex - The row index of the tabular data.
190
+ * @param {string} pTransactionGUID - The transaction GUID for the event dispatch.
191
+ * @returns {boolean} - Returns true.
192
+ */
193
+ onTabularRowReorderRepaintTabular(pView, pGroup, pInput, pValue, pHTMLSelector, pRowIndex, pTransactionGUID)
194
+ {
195
+ return true;
196
+ }
197
+
159
198
  /**
160
199
  * Handles data requests for the Pict-Provider-InputExtension.
161
200
  *
@@ -1764,4 +1764,55 @@ suite('PictSectionForm Tabular Features', () =>
1764
1764
  }, fDone);
1765
1765
  });
1766
1766
  });
1767
+
1768
+ suite('Row reorder performance (move skips the full source re-render)', () =>
1769
+ {
1770
+ test('moveDynamicTableRowUp reorders in place without full-rendering the source view, and repaints inputs via the hook', (fDone) =>
1771
+ {
1772
+ let App = makeApplication({
1773
+ Hash: 'Students',
1774
+ Layout: 'Tabular',
1775
+ RecordSetAddress: 'Students',
1776
+ RecordManifest: 'StudentEditor'
1777
+ });
1778
+ bootstrap(App, (_Pict) =>
1779
+ {
1780
+ let tmpView = _Pict.views['PictSectionForm-Class'];
1781
+ let tmpDTD = _Pict.providers.DynamicTabularData;
1782
+
1783
+ // A move must NOT go through the expensive full source-view render -- that path tears
1784
+ // down and re-initializes every cell widget (each entity-selector select2 re-init is
1785
+ // what made BatchSheetCombined take seconds per move)...
1786
+ let tmpFullRenderCalls = 0;
1787
+ let tmpOriginalRender = tmpDTD._renderViewsPreservingRecordSet;
1788
+ tmpDTD._renderViewsPreservingRecordSet = function (...pArgs)
1789
+ {
1790
+ tmpFullRenderCalls++;
1791
+ return tmpOriginalRender.apply(this, pArgs);
1792
+ };
1793
+ // ...and it MUST ask the input providers to repaint their display for the new order.
1794
+ let tmpRepaintHookCalls = 0;
1795
+ let tmpOriginalRun = tmpView.runInputProviderFunctions;
1796
+ tmpView.runInputProviderFunctions = function (pFunctionName)
1797
+ {
1798
+ if (pFunctionName === 'onTabularRowReorderRepaint') { tmpRepaintHookCalls++; }
1799
+ return tmpOriginalRun.apply(this, arguments);
1800
+ };
1801
+
1802
+ let tmpBefore = _Pict.AppData.Students.map((pRow) => pRow.StudentName);
1803
+ tmpDTD.moveDynamicTableRowUp(tmpView, 0, 1); // 'Bob' (index 1) moves up to index 0
1804
+
1805
+ let tmpAfter = _Pict.AppData.Students.map((pRow) => pRow.StudentName);
1806
+
1807
+ tmpDTD._renderViewsPreservingRecordSet = tmpOriginalRender;
1808
+ tmpView.runInputProviderFunctions = tmpOriginalRun;
1809
+
1810
+ Expect(tmpBefore[0]).to.equal('Alice', 'sanity: row 0 started as Alice');
1811
+ Expect(tmpAfter[0]).to.equal('Bob', 'moved row is now first in the model');
1812
+ Expect(tmpAfter[1]).to.equal('Alice', 'displaced row shifted down');
1813
+ Expect(tmpFullRenderCalls).to.equal(0, 'a reorder must not full-render the source view (the slow select2 teardown)');
1814
+ Expect(tmpRepaintHookCalls).to.equal(1, 'a reorder repaints inputs in place via the onTabularRowReorderRepaint hook');
1815
+ }, fDone);
1816
+ });
1817
+ });
1767
1818
  });