Skip to content

Commit 36b45d7

Browse files
committed
feat: Grid Multi-Body architecture layout wrappers and sub-grid partitioning (#9487)
1 parent a369a9a commit 36b45d7

4 files changed

Lines changed: 197 additions & 44 deletions

File tree

src/grid/Body.mjs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,11 @@ class GridBody extends Component {
120120
* @reactive
121121
*/
122122
columnPositions_: null,
123+
/**
124+
* @member {Neo.grid.Container|null} gridContainer=null
125+
* @protected
126+
*/
127+
gridContainer: null,
123128
/**
124129
* @member {Boolean} highlightModifiedCells_=false
125130
* @reactive
@@ -676,7 +681,7 @@ class GridBody extends Component {
676681
config = {
677682
module : Row,
678683
appName : me.appName,
679-
gridContainer: me.parent,
684+
gridContainer: me.gridContainer,
680685
id : me.getRowId(current + i),
681686
parentId : me.id,
682687
record : null,
@@ -809,7 +814,7 @@ class GridBody extends Component {
809814
}
810815
}
811816

812-
me.parent.isLoading = false;
817+
me.gridContainer.isLoading = false;
813818

814819
me.updateScrollHeight(true); // silent
815820

@@ -861,7 +866,7 @@ class GridBody extends Component {
861866
record = me.getRecord(id)
862867
}
863868

864-
me.parent.fire(eventName, {body: me, data, dataField, record})
869+
me.gridContainer.fire(eventName, {body: me, data, dataField, record})
865870
}
866871

867872
/**
@@ -885,7 +890,7 @@ class GridBody extends Component {
885890
record = me.getRecord(id)
886891
}
887892

888-
me.parent.fire(eventName, {body: me, data, record})
893+
me.gridContainer.fire(eventName, {body: me, data, record})
889894
}
890895

891896
/**
@@ -930,7 +935,7 @@ class GridBody extends Component {
930935
* @returns {Object|Number|null}
931936
*/
932937
getColumn(field, returnIndex=false) {
933-
let {columns} = this.parent,
938+
let {columns} = this.gridContainer,
934939
column = columns.get(field);
935940

936941
if (column) {
@@ -980,7 +985,7 @@ class GridBody extends Component {
980985
if (cellId.includes('__cell-')) {
981986
let me = this,
982987
poolIndex = parseInt(cellId.split('__cell-')[1]),
983-
columns = me.parent.columns,
988+
columns = me.gridContainer.columns,
984989
{cellPoolSize, mountedColumns} = me,
985990
i = mountedColumns[0],
986991
len = mountedColumns[1],
@@ -1195,7 +1200,7 @@ class GridBody extends Component {
11951200
*/
11961201
onScrollCapture(data) {
11971202
super.onScrollCapture(data);
1198-
this.parent.scrollManager.onBodyScroll(data)
1203+
this.gridContainer.scrollManager.onBodyScroll(data)
11991204
}
12001205

12011206
/**

src/grid/Container.mjs

Lines changed: 169 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,21 @@ class GridContainer extends BaseContainer {
8888
merge : 'deep',
8989
value : null
9090
},
91+
/**
92+
* @member {Neo.grid.Body|null} bodyEnd=null
93+
* @protected
94+
*/
95+
bodyEnd: null,
96+
/**
97+
* @member {Neo.grid.Body|null} bodyStart=null
98+
* @protected
99+
*/
100+
bodyStart: null,
101+
/**
102+
* @member {Neo.container.Base|null} bodyWrapper=null
103+
* @protected
104+
*/
105+
bodyWrapper: null,
91106
/**
92107
* true uses grid.plugin.CellEditing
93108
* @member {Boolean} cellEditing_=false
@@ -124,6 +139,21 @@ class GridContainer extends BaseContainer {
124139
merge : 'deep',
125140
value : null
126141
},
142+
/**
143+
* @member {Neo.grid.header.Toolbar|null} headerEnd=null
144+
* @protected
145+
*/
146+
headerEnd: null,
147+
/**
148+
* @member {Neo.grid.header.Toolbar|null} headerStart=null
149+
* @protected
150+
*/
151+
headerStart: null,
152+
/**
153+
* @member {Neo.container.Base|null} headerWrapper=null
154+
* @protected
155+
*/
156+
headerWrapper: null,
127157
/**
128158
* @member {Object} layout={ntype: 'vbox', align: 'stretch'}
129159
* @reactive
@@ -244,7 +274,30 @@ class GridContainer extends BaseContainer {
244274
let me = this,
245275
{appName, rowHeight, store, windowId} = me;
246276

247-
me.items = [me.headerToolbar, me.body];
277+
me.headerWrapper = Neo.create(BaseContainer, {
278+
appName,
279+
cls : ['neo-header-wrapper'],
280+
flex : 'none',
281+
layout : {ntype: 'hbox', align: 'stretch'},
282+
parentId: me.id,
283+
theme : me.theme,
284+
windowId,
285+
items : [me.headerToolbar]
286+
});
287+
288+
me.bodyWrapper = Neo.create(BaseContainer, {
289+
appName,
290+
cls : ['neo-body-wrapper'],
291+
flex : 1,
292+
layout : {ntype: 'hbox', align: 'stretch'},
293+
parentId: me.id,
294+
style : {overflowY: 'auto'},
295+
theme : me.theme,
296+
windowId,
297+
items : [me.body]
298+
});
299+
300+
me.items = [me.headerWrapper, me.bodyWrapper];
248301

249302
if (me.footerToolbar) {
250303
me.items.push(me.footerToolbar)
@@ -652,7 +705,6 @@ class GridContainer extends BaseContainer {
652705
createColumns(columns) {
653706
let me = this,
654707
{columnDefaults} = me,
655-
headerButtons = [],
656708
sorters = me.store?.sorters,
657709
columnClass, renderer;
658710

@@ -680,8 +732,6 @@ class GridContainer extends BaseContainer {
680732
scope: me
681733
};
682734

683-
headerButtons.push(column);
684-
685735
if (column.component && !column.type) {
686736
column.type = 'component'
687737
}
@@ -697,9 +747,6 @@ class GridContainer extends BaseContainer {
697747
}
698748
}
699749

700-
me.headerToolbar.items = headerButtons;
701-
me.headerToolbar.createItems();
702-
703750
if (Neo.typeOf(me._columns) === 'NeoInstance') {
704751
me._columns.clear();
705752
me._columns.add(columns);
@@ -708,20 +755,119 @@ class GridContainer extends BaseContainer {
708755
me.centerColumns = columns.filter(c => !c.locked);
709756
me.lockedEndColumns = columns.filter(c => c.locked === 'end');
710757

758+
me.createOrUpdateSubGrids();
759+
711760
return me._columns
712761
}
713762

714763
me.lockedStartColumns = columns.filter(c => c.locked === 'start');
715764
me.centerColumns = columns.filter(c => !c.locked);
716765
me.lockedEndColumns = columns.filter(c => c.locked === 'end');
717766

767+
me.createOrUpdateSubGrids();
768+
718769
return Neo.create(Collection, {
719770
keyProperty: 'dataField',
720771
items : columns,
721772
listeners : {mutate: me.onColumnsMutate, scope: me}
722773
})
723774
}
724775

776+
/**
777+
* @protected
778+
*/
779+
createOrUpdateSubGrids() {
780+
let me = this;
781+
782+
// --- Center (Default) ---
783+
if (me.centerColumns.length > 0) {
784+
me.headerToolbar.items = me.centerColumns;
785+
me.headerToolbar.createItems();
786+
}
787+
788+
// --- Start (Left) ---
789+
if (me.lockedStartColumns.length > 0) {
790+
if (!me.headerStart) {
791+
me.headerStart = Neo.create(header.Toolbar, {
792+
...me.headerToolbar.initialConfig,
793+
flex : 'none',
794+
gridContainer: me,
795+
items : me.lockedStartColumns,
796+
layoutLock : 'start',
797+
parentId : me.headerWrapper.id,
798+
theme : me.theme,
799+
windowId : me.windowId
800+
});
801+
802+
me.bodyStart = Neo.create(GridBody, {
803+
...me.body.initialConfig,
804+
flex : 'none',
805+
gridContainer: me,
806+
parentId : me.bodyWrapper.id,
807+
theme : me.theme,
808+
windowId : me.windowId
809+
});
810+
} else {
811+
me.headerStart.items = me.lockedStartColumns;
812+
me.headerStart.createItems();
813+
}
814+
} else if (me.headerStart) {
815+
me.headerStart.destroy();
816+
me.bodyStart.destroy();
817+
me.headerStart = me.bodyStart = null;
818+
}
819+
820+
// --- End (Right) ---
821+
if (me.lockedEndColumns.length > 0) {
822+
if (!me.headerEnd) {
823+
me.headerEnd = Neo.create(header.Toolbar, {
824+
...me.headerToolbar.initialConfig,
825+
flex : 'none',
826+
gridContainer: me,
827+
items : me.lockedEndColumns,
828+
layoutLock : 'end',
829+
parentId : me.headerWrapper.id,
830+
theme : me.theme,
831+
windowId : me.windowId
832+
});
833+
834+
me.bodyEnd = Neo.create(GridBody, {
835+
...me.body.initialConfig,
836+
flex : 'none',
837+
gridContainer: me,
838+
parentId : me.bodyWrapper.id,
839+
theme : me.theme,
840+
windowId : me.windowId
841+
});
842+
} else {
843+
me.headerEnd.items = me.lockedEndColumns;
844+
me.headerEnd.createItems();
845+
}
846+
} else if (me.headerEnd) {
847+
me.headerEnd.destroy();
848+
me.bodyEnd.destroy();
849+
me.headerEnd = me.bodyEnd = null;
850+
}
851+
852+
// Synchronize SubGrids into DOM via Symmetrical Wrappers
853+
let bodyItems = [],
854+
headerItems = [];
855+
856+
if (me.headerStart) headerItems.push(me.headerStart);
857+
if (me.headerToolbar) headerItems.push(me.headerToolbar);
858+
if (me.headerEnd) headerItems.push(me.headerEnd);
859+
860+
if (me.bodyStart) bodyItems.push(me.bodyStart);
861+
if (me.body) bodyItems.push(me.body);
862+
if (me.bodyEnd) bodyItems.push(me.bodyEnd);
863+
864+
me.headerWrapper.items = headerItems;
865+
me.bodyWrapper.items = bodyItems;
866+
867+
me.headerWrapper.createItems();
868+
me.bodyWrapper.createItems();
869+
}
870+
725871
/**
726872
* @param args
727873
*/
@@ -748,39 +894,20 @@ class GridContainer extends BaseContainer {
748894
onColumnLockChange(column) {
749895
let me = this,
750896
columnsArray = [...me.columns.items],
751-
headerToolbar = me.headerToolbar,
752897
sortedColumns = me.sortColumns(columnsArray);
753898

754-
// 1. Sync the Header Toolbar cleanly via public API
755-
// Batched by the framework's core update loop
756-
headerToolbar.silentVdomUpdate = true;
757-
758-
sortedColumns.forEach((col, targetIndex) => {
759-
let btn = headerToolbar.getColumn(col.dataField),
760-
currentIndex = headerToolbar.indexOf(btn);
761-
762-
if (currentIndex !== targetIndex) {
763-
headerToolbar.moveTo(currentIndex, targetIndex)
764-
}
765-
});
766-
767-
headerToolbar.silentVdomUpdate = false;
768-
headerToolbar.update();
769-
770-
// 2. Sync the Collection
771-
// clearSilent() and add() is the safest way to reset internal indices while avoiding duplicate mutate events
899+
// Sync the Collection
900+
// clearSilent() and add() is the safest way to reset internal indices
772901
me.columns.clearSilent();
773902
me.columns.add(sortedColumns);
774903

775-
me.lockedStartColumns = sortedColumns.filter(c => c.locked === 'start');
776-
me.centerColumns = sortedColumns.filter(c => !c.locked);
777-
me.lockedEndColumns = sortedColumns.filter(c => c.locked === 'end');
904+
// Trigger Sub-grid Layout Sync
905+
me.onColumnsMutate();
778906

779-
// 3. Trigger Layout Engine
780-
headerToolbar.passSizeToBody(false);
781-
782-
// 4. Force a full row re-render to apply the new column order and styles
783-
me.body.createViewData();
907+
// Force a full row re-render to apply the new column order and styles
908+
if (me.body) me.body.createViewData();
909+
if (me.bodyStart) me.bodyStart.createViewData();
910+
if (me.bodyEnd) me.bodyEnd.createViewData();
784911

785912
me.scrollManager?.updateColumnScrollPinningAddon()
786913
}
@@ -836,7 +963,14 @@ class GridContainer extends BaseContainer {
836963
* @param {Object} data
837964
*/
838965
onColumnsMutate(data) {
839-
this.updateColCount()
966+
let me = this;
967+
968+
me.lockedStartColumns = me._columns.items.filter(c => c.locked === 'start');
969+
me.centerColumns = me._columns.items.filter(c => !c.locked);
970+
me.lockedEndColumns = me._columns.items.filter(c => c.locked === 'end');
971+
972+
me.createOrUpdateSubGrids();
973+
me.updateColCount()
840974
}
841975

842976
/**

src/grid/Row.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ class Row extends Component {
307307
record = me.record,
308308
rowIndex = me.rowIndex,
309309
gridBody = me.parent, // The Row is an item of Body
310-
gridContainer = gridBody.parent,
310+
gridContainer = gridBody.gridContainer,
311311
vdom = me.vdom,
312312
{columns} = gridContainer,
313313
cellConfig, column, columnPosition, i, isMounted, lastColumnIndex, oldCn, poolIndex, poolSize, pooledCells;

0 commit comments

Comments
 (0)