UNPKG

23 kBPlain TextView Raw
1import Grid, {
2 GetterSetter,
3 GridFunction, GridItem, GridOptions,
4 GridOutlines, MOUNT_STATE, Properties, PROPERTY_TYPE,
5 RenderOptions, UPDATE_STATE,
6} from "@egjs/grid";
7import { GROUP_TYPE, ITEM_TYPE, STATUS_TYPE } from "./consts";
8import { InfiniteGridItem, InfiniteGridItemStatus } from "./InfiniteGridItem";
9import { LoadingGrid, LOADING_GROUP_KEY } from "./LoadingGrid";
10import { CategorizedGroup, InfiniteGridGroup, InfiniteGridItemInfo } from "./types";
11import {
12 categorize, filterVirtuals, findIndex, findLastIndex,
13 flat,
14 flatGroups, getItemInfo, isNumber, makeKey,
15 range,
16 setPlaceholder,
17 splitGridOptions, splitOptions, splitVirtualGroups,
18} from "./utils";
19
20export interface InfiniteGridGroupStatus {
21 type: GROUP_TYPE;
22 groupKey: string | number;
23 items: InfiniteGridItemStatus[];
24 outlines: GridOutlines;
25}
26
27export interface GroupManagerOptions extends GridOptions {
28 appliedItemChecker?: (item: InfiniteGridItem, grid: Grid) => boolean;
29 gridConstructor: GridFunction | null;
30 gridOptions: Record<string, any>;
31}
32
33export interface GroupManagerStatus {
34 cursors: [number, number];
35 orgCursors: [number, number];
36 itemCursors: [number, number];
37 startGroupKey: number | string;
38 endGroupKey: number | string;
39 groups: InfiniteGridGroupStatus[];
40 outlines: GridOutlines;
41}
42
43@GetterSetter
44export class GroupManager extends Grid<GroupManagerOptions> {
45 public static defaultOptions: Required<GroupManagerOptions> = {
46 ...Grid.defaultOptions,
47 appliedItemChecker: () => false,
48 gridConstructor: null,
49 gridOptions: {},
50 };
51 public static propertyTypes = {
52 ...Grid.propertyTypes,
53 gridConstructor: PROPERTY_TYPE.PROPERTY,
54 gridOptions: PROPERTY_TYPE.PROPERTY,
55 } as const;
56 protected items: InfiniteGridItem[];
57 protected groupItems: InfiniteGridItem[] = [];
58 protected groups: InfiniteGridGroup[] = [];
59 protected itemKeys: Record<string | number, InfiniteGridItem> = {};
60 protected groupKeys: Record<string | number, InfiniteGridGroup> = {};
61 protected startCursor = 0;
62 protected endCursor = 0;
63 private _placeholder: Partial<InfiniteGridItemStatus> | null = null;
64 private _loadingGrid!: LoadingGrid;
65 private _mainGrid!: Grid;
66
67 constructor(container: HTMLElement, options: GroupManagerOptions) {
68 super(container, splitOptions(options));
69
70 this._loadingGrid = new LoadingGrid(container, {
71 externalContainerManager: this.containerManager,
72 useFit: false,
73 autoResize: false,
74 renderOnPropertyChange: false,
75 gap: this.gap,
76 });
77 this._mainGrid = this._makeGrid();
78 }
79 public set gridOptions(options: Record<string, any>) {
80 const {
81 gridOptions,
82 ...otherOptions
83 } = splitGridOptions(options);
84
85 const shouldRender = this._checkShouldRender(options);
86 this.options.gridOptions = {
87 ...this.options.gridOptions,
88 ...gridOptions,
89 };
90 [this._mainGrid, ...this.groups.map(({ grid }) => grid)].forEach((grid) => {
91 for (const name in options) {
92 (grid as any)[name] = options[name];
93 }
94 });
95 for (const name in otherOptions) {
96 this[name] = otherOptions[name];
97 }
98
99 this._loadingGrid.gap = this.gap;
100 if (shouldRender) {
101 this.scheduleRender();
102 }
103 }
104
105 public getItemByKey(key: string | number): InfiniteGridItem | null {
106 return this.itemKeys[key] || null;
107 }
108
109 public getGroupItems(includePlaceholders?: boolean) {
110 return filterVirtuals(this.groupItems, includePlaceholders);
111 }
112 public getVisibleItems(includePlaceholders?: boolean) {
113 return filterVirtuals(this.items, includePlaceholders);
114 }
115
116 public getRenderingItems() {
117 if (this.hasPlaceholder()) {
118 return this.items;
119 } else {
120 return this.items.filter((item) => item.type !== ITEM_TYPE.VIRTUAL);
121 }
122 }
123
124 public getGroups(includePlaceholders?: boolean): InfiniteGridGroup[] {
125 return filterVirtuals(this.groups, includePlaceholders);
126 }
127
128 public hasVisibleVirtualGroups() {
129 return this.getVisibleGroups(true).some((group) => group.type === GROUP_TYPE.VIRTUAL);
130 }
131 public hasPlaceholder() {
132 return !!this._placeholder;
133 }
134 public hasLoadingItem() {
135 return !!this._getLoadingItem();
136 }
137
138 public updateItems(items = this.groupItems, options?: RenderOptions) {
139 return super.updateItems(items, options);
140 }
141 public setPlaceholder(placeholder: Partial<InfiniteGridItemStatus> | null) {
142 this._placeholder = placeholder;
143 this._updatePlaceholder();
144 }
145
146 public getLoadingType() {
147 return this._loadingGrid.type;
148 }
149
150 public startLoading(type: "start" | "end") {
151 this._loadingGrid.type = type;
152 this.items = this._getRenderingItems();
153
154 return true;
155 }
156
157 public endLoading() {
158 const prevType = this._loadingGrid.type;
159
160 this._loadingGrid.type = "";
161 this.items = this._getRenderingItems();
162 return !!prevType;
163 }
164
165 public setLoading(loading: Partial<InfiniteGridItemStatus> | null) {
166 this._loadingGrid.setLoadingItem(loading);
167 this.items = this._getRenderingItems();
168 }
169
170 public getVisibleGroups(includePlaceholders?: boolean): InfiniteGridGroup[] {
171 const groups = this.groups.slice(this.startCursor, this.endCursor + 1);
172
173 return filterVirtuals(groups, includePlaceholders);
174 }
175
176 public getComputedOutlineLength(items = this.items) {
177 return this._mainGrid.getComputedOutlineLength(items);
178 }
179 public getComputedOutlineSize(items = this.items) {
180 return this._mainGrid.getComputedOutlineSize(items);
181 }
182
183 public applyGrid(items: InfiniteGridItem[], direction: "end" | "start", outline: number[]): GridOutlines {
184 const renderingGroups = this.groups.slice();
185
186 if (!renderingGroups.length) {
187 return {
188 start: [],
189 end: [],
190 };
191 }
192
193
194 const loadingGrid = this._loadingGrid;
195
196 if (loadingGrid.getLoadingItem()) {
197 if (loadingGrid.type === "start") {
198 renderingGroups.unshift(this._getLoadingGroup());
199 } else if (loadingGrid.type === "end") {
200 renderingGroups.push(this._getLoadingGroup());
201 }
202 }
203
204 const groups = renderingGroups.slice();
205
206 let nextOutline = outline;
207
208 if (direction === "start") {
209 groups.reverse();
210 }
211
212 const appliedItemChecker = this.options.appliedItemChecker;
213 const groupItems = this.groupItems;
214 const outlineLength = this.getComputedOutlineLength(groupItems);
215 const outlineSize = this.getComputedOutlineSize(groupItems);
216 const itemRenderer = this.itemRenderer;
217
218 groups.forEach((group) => {
219 const grid = group.grid;
220 const gridItems = grid.getItems() as InfiniteGridItem[];
221 const isVirtual = group.type === GROUP_TYPE.VIRTUAL && !gridItems[0];
222
223 grid.outlineLength = outlineLength;
224 grid.outlineSize = outlineSize;
225
226 const appliedItems = gridItems.filter((item) => {
227 if (item.mountState === MOUNT_STATE.UNCHECKED || !item.rect.width) {
228 itemRenderer.updateItem(item, true);
229 }
230 return (item.orgRect.width && item.rect.width) || appliedItemChecker(item, grid);
231 });
232 let gridOutlines: GridOutlines;
233
234 if (isVirtual) {
235 gridOutlines = this._applyVirtualGrid(grid, direction, nextOutline);
236 } else if (appliedItems.length) {
237 gridOutlines = grid.applyGrid(appliedItems, direction, nextOutline);
238 } else {
239 gridOutlines = {
240 start: [...nextOutline],
241 end: [...nextOutline],
242 };
243 }
244 grid.setOutlines(gridOutlines);
245 nextOutline = gridOutlines[direction];
246 });
247
248 return {
249 start: renderingGroups[0].grid.getOutlines().start,
250 end: renderingGroups[renderingGroups.length - 1].grid.getOutlines().end,
251 };
252 }
253
254 public syncItems(nextItemInfos: InfiniteGridItemInfo[]) {
255 const prevItemKeys = this.itemKeys;
256
257 this.itemKeys = {};
258 const nextItems = this._syncItemInfos(nextItemInfos.map((info) => getItemInfo(info)), prevItemKeys);
259 const prevGroupKeys = this.groupKeys;
260 let nextManagerGroups = categorize(nextItems);
261
262 const startVirtualGroups = this._splitVirtualGroups("start", nextManagerGroups);
263 const endVirtualGroups = this._splitVirtualGroups("end", nextManagerGroups);
264 nextManagerGroups = [...startVirtualGroups, ...this._mergeVirtualGroups(nextManagerGroups), ...endVirtualGroups];
265
266 const nextGroups: InfiniteGridGroup[] = nextManagerGroups.map(({ groupKey, items }) => {
267 const isVirtual = !items[0] || items[0].type === ITEM_TYPE.VIRTUAL;
268 const grid = prevGroupKeys[groupKey]?.grid ?? this._makeGrid();
269 const gridItems = isVirtual ? items : items.filter(({ type }) => type === ITEM_TYPE.NORMAL);
270
271 grid.setItems(gridItems);
272
273 return {
274 type: isVirtual ? GROUP_TYPE.VIRTUAL : GROUP_TYPE.NORMAL,
275 groupKey,
276 grid,
277 items: gridItems,
278 renderItems: items,
279 };
280 });
281
282 this._registerGroups(nextGroups);
283 }
284
285 public renderItems(options: RenderOptions = {}) {
286 if (options.useResize) {
287 this.groupItems.forEach((item) => {
288 item.updateState = UPDATE_STATE.NEED_UPDATE;
289 });
290 const loadingItem = this._getLoadingItem();
291
292 if (loadingItem) {
293 loadingItem.updateState = UPDATE_STATE.NEED_UPDATE;
294 }
295 }
296 return super.renderItems(options);
297 }
298
299 public setCursors(startCursor: number, endCursor: number) {
300 this.startCursor = startCursor;
301 this.endCursor = endCursor;
302 this.items = this._getRenderingItems();
303 }
304
305 public getStartCursor() {
306 return this.startCursor;
307 }
308
309 public getEndCursor() {
310 return this.endCursor;
311 }
312
313 public getGroupStatus(type?: STATUS_TYPE, includePlaceholders?: boolean): GroupManagerStatus {
314 const orgStartCursor = this.startCursor;
315 const orgEndCursor = this.endCursor;
316 const orgGroups = this.groups;
317 const startGroup = orgGroups[orgStartCursor];
318 const endGroup = orgGroups[orgEndCursor];
319
320 let startCursor = orgStartCursor;
321 let endCursor = orgEndCursor;
322
323 const isMinimizeItems = type === STATUS_TYPE.MINIMIZE_INVISIBLE_ITEMS;
324 const isMinimizeGroups = type === STATUS_TYPE.MINIMIZE_INVISIBLE_GROUPS;
325 let groups: InfiniteGridGroup[];
326
327 if (type === STATUS_TYPE.REMOVE_INVISIBLE_GROUPS) {
328 groups = this.getVisibleGroups(includePlaceholders);
329 endCursor = groups.length - 1;
330 startCursor = 0;
331 } else {
332 groups = this.getGroups(includePlaceholders);
333
334 if (!includePlaceholders) {
335 startCursor = -1;
336 endCursor = -1;
337
338 for (let orgIndex = orgStartCursor; orgIndex <= orgEndCursor; ++orgIndex) {
339 const orgGroup = orgGroups[orgIndex];
340
341 if (orgGroup && orgGroup.type !== GROUP_TYPE.VIRTUAL) {
342 startCursor = groups.indexOf(orgGroup);
343 break;
344 }
345 }
346 for (let orgIndex = orgEndCursor; orgIndex >= orgStartCursor; --orgIndex) {
347 const orgGroup = orgGroups[orgIndex];
348
349 if (orgGroup && orgGroup.type !== GROUP_TYPE.VIRTUAL) {
350 endCursor = groups.lastIndexOf(orgGroup);
351 break;
352 }
353 }
354 }
355 }
356
357 const groupStatus: InfiniteGridGroupStatus[] = groups.map(({ grid, groupKey }, i) => {
358 const isOutsideCursor = i < startCursor || endCursor < i;
359 const isVirtualItems = isMinimizeItems && isOutsideCursor;
360 const isVirtualGroup = isMinimizeGroups && isOutsideCursor;
361 const gridItems = grid.getItems() as InfiniteGridItem[];
362 const items = isVirtualGroup
363 ? []
364 : gridItems.map((item) => isVirtualItems ? item.getVirtualStatus() : item.getMinimizedStatus());
365
366 return {
367 type: isVirtualGroup || isVirtualItems ? GROUP_TYPE.VIRTUAL : GROUP_TYPE.NORMAL,
368 groupKey: groupKey,
369 outlines: grid.getOutlines(),
370 items,
371 };
372 });
373
374
375 const totalItems = this.getGroupItems();
376
377 const itemStartCursor = totalItems.indexOf(startGroup?.items[0]);
378 const itemEndCursor = totalItems.indexOf(endGroup?.items.slice().reverse()[0]);
379
380 return {
381 cursors: [startCursor, endCursor],
382 orgCursors: [orgStartCursor, orgEndCursor],
383 itemCursors: [itemStartCursor, itemEndCursor],
384 startGroupKey: startGroup?.groupKey,
385 endGroupKey: endGroup?.groupKey,
386 groups: groupStatus,
387 outlines: this.outlines,
388 };
389 }
390 protected fitOutlines(useFit = this.useFit) {
391 const groups = this.groups;
392 const firstGroup = groups[0];
393
394 if (!firstGroup) {
395 return;
396 }
397 const outlines = firstGroup.grid.getOutlines();
398 const startOutline = outlines.start;
399 const outlineOffset = startOutline.length ? Math.min(...startOutline) : 0;
400
401 // If the outline is less than 0, a fit occurs forcibly.
402 if (!useFit && outlineOffset > 0) {
403 return;
404 }
405
406 groups.forEach(({ grid }) => {
407 const { start, end } = grid.getOutlines();
408
409 grid.setOutlines({
410 start: start.map((point) => point - outlineOffset),
411 end: end.map((point) => point - outlineOffset),
412 });
413 });
414
415 this.groupItems.forEach((item) => {
416 const contentPos = item.cssContentPos;
417
418 if (!isNumber(contentPos)) {
419 return;
420 }
421 item.cssContentPos = contentPos - outlineOffset;
422 });
423 }
424 public setGroupStatus(status: GroupManagerStatus) {
425 this.itemKeys = {};
426 this.groupItems = [];
427 this.items = [];
428 const prevGroupKeys = this.groupKeys;
429
430 const nextGroups: InfiniteGridGroup[] = status.groups.map(({
431 type,
432 groupKey,
433 items,
434 outlines,
435 }) => {
436 const nextItems = this._syncItemInfos(items);
437 const grid = prevGroupKeys[groupKey]?.grid ?? this._makeGrid();
438
439 grid.setOutlines(outlines);
440 grid.setItems(nextItems);
441
442 return {
443 type,
444 groupKey,
445 grid,
446 items: nextItems,
447 renderItems: nextItems,
448 };
449 });
450
451 this.setOutlines(status.outlines);
452 this._registerGroups(nextGroups);
453 this._updatePlaceholder();
454 this.setCursors(status.cursors[0], status.cursors[1]);
455 }
456 public appendPlaceholders(items: number | InfiniteGridItemStatus[], groupKey?: string | number) {
457 return this.insertPlaceholders("end", items, groupKey);
458 }
459 public prependPlaceholders(items: number | InfiniteGridItemStatus[], groupKey?: string | number) {
460 return this.insertPlaceholders("start", items, groupKey);
461 }
462 public removePlaceholders(type: "start" | "end" | { groupKey: string | number }) {
463 const groups = this.groups;
464 const length = groups.length;
465
466 if (type === "start") {
467 const index = findIndex(groups, (group) => group.type === GROUP_TYPE.NORMAL);
468
469 groups.splice(0, index);
470
471 } else if (type === "end") {
472 const index = findLastIndex(groups, (group) => group.type === GROUP_TYPE.NORMAL);
473
474 groups.splice(index + 1, length - index - 1);
475 } else {
476 const groupKey = type.groupKey;
477
478 const index = findIndex(groups, (group) => group.groupKey === groupKey);
479
480 if (index > -1) {
481 groups.splice(index, 1);
482 }
483 }
484
485 this.syncItems(flatGroups(this.getGroups()));
486 }
487 public insertPlaceholders(
488 direction: "start" | "end",
489 items: number | InfiniteGridItemStatus[],
490 groupKey: string | number = makeKey(this.groupKeys, "virtual_"),
491 ) {
492
493 let infos: InfiniteGridItemInfo[] = [];
494
495 if (isNumber(items)) {
496 infos = range(items).map(() => ({ type: ITEM_TYPE.VIRTUAL, groupKey }));
497 } else if (Array.isArray(items)) {
498 infos = items.map((status) => ({
499 groupKey,
500 ...status,
501 type: ITEM_TYPE.VIRTUAL,
502 }));
503 }
504 const grid = this._makeGrid();
505 const nextItems = this._syncItemInfos(infos, this.itemKeys);
506
507 this._updatePlaceholder(nextItems);
508 grid.setItems(nextItems);
509
510 const group = {
511 type: GROUP_TYPE.VIRTUAL,
512 groupKey,
513 grid,
514 items: nextItems,
515 renderItems: nextItems,
516 };
517
518 this.groupKeys[groupKey] = group;
519
520 if (direction === "end") {
521 this.groups.push(group);
522 this.groupItems.push(...nextItems);
523 } else {
524 this.groups.splice(0, 0, group);
525 this.groupItems.splice(0, 0, ...nextItems);
526 if (this.startCursor > -1) {
527 ++this.startCursor;
528 ++this.endCursor;
529 }
530 }
531
532
533 return {
534 group,
535 items: nextItems,
536 };
537 }
538
539 public shouldRerenderItems() {
540 let isRerender = false;
541
542 this.getVisibleGroups().forEach((group) => {
543 const items = group.items;
544
545 if (
546 items.length === group.renderItems.length
547 || items.every((item) => item.mountState === MOUNT_STATE.UNCHECKED)
548 ) {
549 return;
550 }
551 isRerender = true;
552 group.renderItems = [...items];
553 });
554 if (isRerender) {
555 this.items = this._getRenderingItems();
556 }
557 return isRerender;
558 }
559
560 protected _updateItems(items: GridItem[]): void {
561 this.itemRenderer.updateEqualSizeItems(items, this.groupItems);
562 }
563
564 private _getGroupItems() {
565 return flatGroups(this.getGroups(true));
566 }
567
568 private _getRenderingItems() {
569 const items = flat(this.getVisibleGroups(true).map((item) => item.renderItems));
570
571
572 const loadingGrid = this._loadingGrid;
573 const loadingItem = loadingGrid.getLoadingItem();
574
575 if (loadingItem) {
576 if (loadingGrid.type === "end") {
577 items.push(loadingItem);
578 } else if (loadingGrid.type === "start") {
579 items.unshift(loadingItem);
580 }
581 }
582
583 return items;
584 }
585
586 private _checkShouldRender(options: Record<string, any>) {
587 const GridConstructor = this.options.gridConstructor!;
588 const prevOptions = this.gridOptions;
589 const propertyTypes = GridConstructor.propertyTypes;
590
591 for (const name in prevOptions) {
592 if (!(name in options) && propertyTypes[name] === PROPERTY_TYPE.RENDER_PROPERTY) {
593 return true;
594 }
595 }
596 for (const name in options) {
597 if (prevOptions[name] !== options[name] && propertyTypes[name] === PROPERTY_TYPE.RENDER_PROPERTY) {
598 return true;
599 }
600 }
601 return false;
602 }
603 private _applyVirtualGrid(grid: Grid, direction: "start" | "end", outline: number[]) {
604 const startOutline = outline.length ? [...outline] : [0];
605 const prevOutlines = grid.getOutlines();
606 const prevOutline = prevOutlines[direction === "end" ? "start" : "end"];
607
608 if (
609 prevOutline.length !== startOutline.length
610 || prevOutline.some((value, i) => value !== startOutline[i])
611 ) {
612 return {
613 start: [...startOutline],
614 end: [...startOutline],
615 };
616 }
617 return prevOutlines;
618 }
619 private _syncItemInfos(
620 nextItemInfos: InfiniteGridItemStatus[],
621 prevItemKeys: Record<string | number, InfiniteGridItem> = {},
622 ) {
623 const horizontal = this.options.horizontal;
624 const nextItemKeys = this.itemKeys;
625
626 nextItemInfos.filter((info) => info.key != null).forEach((info) => {
627 const key = info.key!;
628 const prevItem = prevItemKeys[key];
629
630 if (!prevItem) {
631 nextItemKeys[key] = new InfiniteGridItem(horizontal, {
632 ...info,
633 });
634 } else if (prevItem.type === ITEM_TYPE.VIRTUAL && info.type !== ITEM_TYPE.VIRTUAL) {
635 nextItemKeys[key] = new InfiniteGridItem(horizontal, {
636 orgRect: prevItem.orgRect,
637 rect: prevItem.rect,
638 ...info,
639 });
640 } else {
641 if (info.data) {
642 prevItem.data = info.data;
643 }
644 if (info.groupKey != null) {
645 prevItem.groupKey = info.groupKey!;
646 }
647 if (info.element) {
648 prevItem.element = info.element;
649 }
650 nextItemKeys[key] = prevItem;
651 }
652 });
653 const nextItems = nextItemInfos.map((info) => {
654 let key = info.key!;
655
656 if (info.key == null) {
657 key = makeKey(nextItemKeys, info.type === ITEM_TYPE.VIRTUAL ? "virtual_" : "");
658 }
659 let item = nextItemKeys[key];
660
661 if (!item) {
662 const prevItem = prevItemKeys[key];
663
664 if (prevItem) {
665 item = prevItem;
666
667 if (info.data) {
668 item.data = info.data;
669 }
670 if (info.element) {
671 item.element = info.element;
672 }
673 } else {
674 item = new InfiniteGridItem(horizontal, {
675 ...info,
676 key,
677 });
678 }
679 nextItemKeys[key] = item;
680 }
681 return item;
682 });
683 return nextItems;
684 }
685 private _registerGroups(groups: InfiniteGridGroup[]) {
686 const nextGroupKeys: Record<string | number, InfiniteGridGroup> = {};
687
688 groups.forEach((group) => {
689 nextGroupKeys[group.groupKey] = group;
690 });
691
692 this.groups = groups;
693 this.groupKeys = nextGroupKeys;
694 this.groupItems = this._getGroupItems();
695 }
696 private _splitVirtualGroups(direction: "start" | "end", nextGroups: CategorizedGroup[]) {
697 const groups = splitVirtualGroups(this.groups, direction, nextGroups);
698 const itemKeys = this.itemKeys;
699
700 groups.forEach(({ renderItems }) => {
701 renderItems.forEach((item) => {
702 itemKeys[item.key] = item;
703 });
704 });
705
706 return groups;
707 }
708 private _mergeVirtualGroups(groups: Array<CategorizedGroup<InfiniteGridItem>>) {
709 const itemKeys = this.itemKeys;
710 const groupKeys = this.groupKeys;
711
712 groups.forEach((group) => {
713 const prevGroup = groupKeys[group.groupKey];
714
715 if (!prevGroup) {
716 return;
717 }
718 const items = group.items;
719
720 if (items.every((item) => item.mountState === MOUNT_STATE.UNCHECKED)) {
721 prevGroup.renderItems.forEach((item) => {
722 if (item.type === ITEM_TYPE.VIRTUAL && !itemKeys[item.key]) {
723 items.push(item);
724 itemKeys[item.key] = item;
725 }
726 });
727 }
728 });
729 return groups;
730 }
731
732 private _updatePlaceholder(items = this.groupItems) {
733 const placeholder = this._placeholder;
734
735 if (!placeholder) {
736 return;
737 }
738
739 items.filter((item) => item.type === ITEM_TYPE.VIRTUAL).forEach((item) => {
740 setPlaceholder(item, placeholder);
741 });
742 }
743 private _makeGrid() {
744 const GridConstructor = this.options.gridConstructor!;
745 const gridOptions = this.gridOptions;
746 const container = this.containerElement;
747
748 return new GridConstructor(container, {
749 ...gridOptions,
750 useFit: false,
751 autoResize: false,
752 useResizeObserver: false,
753 observeChildren: false,
754 renderOnPropertyChange: false,
755 externalContainerManager: this.containerManager,
756 externalItemRenderer: this.itemRenderer,
757 });
758 }
759 private _getLoadingGroup(): InfiniteGridGroup {
760 const loadingGrid = this._loadingGrid;
761 const items = loadingGrid.getItems() as InfiniteGridItem[];
762
763 return {
764 groupKey: LOADING_GROUP_KEY,
765 type: GROUP_TYPE.NORMAL,
766 grid: loadingGrid,
767 items,
768 renderItems: items,
769 };
770 }
771 private _getLoadingItem() {
772 return this._loadingGrid.getLoadingItem();
773 }
774}
775
776export interface GroupManager extends Properties<typeof GroupManager> {
777 getItems(): InfiniteGridItem[];
778}