1 | import Component, { ComponentEvent } from "@egjs/component";
|
2 | import Grid, {
|
3 | ContainerManager,
|
4 | DEFAULT_GRID_OPTIONS,
|
5 | Properties,
|
6 | RenderOptions,
|
7 | MOUNT_STATE,
|
8 | OnContentError,
|
9 | ItemRenderer,
|
10 | GridItem,
|
11 | ResizeWatcherResizeEvent,
|
12 | getUpdatedItems,
|
13 | } from "@egjs/grid";
|
14 | import {
|
15 | DIRECTION,
|
16 | GROUP_TYPE,
|
17 | INFINITEGRID_EVENTS, INFINITEGRID_PROPERTY_TYPES,
|
18 | ITEM_TYPE, STATUS_TYPE,
|
19 | } from "./consts";
|
20 | import { GroupManager } from "./GroupManager";
|
21 | import {
|
22 | Infinite,
|
23 | OnInfiniteChange,
|
24 | OnInfiniteRequestAppend,
|
25 | OnInfiniteRequestPrepend,
|
26 | } from "./Infinite";
|
27 | import { InfiniteGridItem, InfiniteGridItemStatus } from "./InfiniteGridItem";
|
28 | import { OnRendererUpdated } from "./Renderer/Renderer";
|
29 | import { GridRendererItem, VanillaGridRenderer } from "./Renderer/VanillaGridRenderer";
|
30 | import { ScrollManager } from "./ScrollManager";
|
31 | import {
|
32 | InfiniteGridEvents, InfiniteGridGroup,
|
33 | InfiniteGridInsertedItems, InfiniteGridItemInfo,
|
34 | InfiniteGridOptions,
|
35 | InfiniteGridStatus,
|
36 | InsertedPlaceholdersResult,
|
37 | OnPickedRenderComplete,
|
38 | OnRequestInsert,
|
39 | OnChangeScroll,
|
40 | } from "./types";
|
41 | import {
|
42 | InfiniteGridGetterSetter, toArray, convertInsertedItems, findIndex,
|
43 | findLastIndex, isString,
|
44 | } from "./utils";
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 | @InfiniteGridGetterSetter
|
85 | class InfiniteGrid<Options extends InfiniteGridOptions = InfiniteGridOptions> extends Component<InfiniteGridEvents> {
|
86 | public static defaultOptions = {
|
87 | ...DEFAULT_GRID_OPTIONS,
|
88 | container: false,
|
89 | containerTag: "div",
|
90 | renderer: null,
|
91 | threshold: 100,
|
92 | useRecycle: true,
|
93 | scrollContainer: null,
|
94 | appliedItemChecker: (() => false) as (item: InfiniteGridItem, grid: Grid) => boolean,
|
95 | } as Required<InfiniteGridOptions>;
|
96 | public static propertyTypes = INFINITEGRID_PROPERTY_TYPES;
|
97 | protected wrapperElement: HTMLElement;
|
98 | protected scrollManager: ScrollManager;
|
99 | protected itemRenderer: ItemRenderer;
|
100 | protected containerManager: ContainerManager;
|
101 | protected infinite: Infinite;
|
102 | protected groupManager: GroupManager;
|
103 | protected options: Required<Options>;
|
104 | private _waitType: "" | "start" | "end" = "";
|
105 | |
106 |
|
107 |
|
108 |
|
109 | constructor(wrapper: HTMLElement | string, options: Options) {
|
110 | super();
|
111 | this.options = {
|
112 | ...((this.constructor as typeof InfiniteGrid).defaultOptions as Required<Options>),
|
113 | renderer: new VanillaGridRenderer().on("requestUpdate", () => this._render()),
|
114 | ...options,
|
115 | };
|
116 |
|
117 | const {
|
118 | gridConstructor,
|
119 | containerTag,
|
120 | container,
|
121 | renderer,
|
122 | threshold,
|
123 | useRecycle,
|
124 | scrollContainer,
|
125 | appliedItemChecker,
|
126 | ...gridOptions
|
127 | } = this.options;
|
128 |
|
129 |
|
130 |
|
131 | const {
|
132 | horizontal,
|
133 | attributePrefix,
|
134 | useTransform,
|
135 | percentage,
|
136 | isConstantSize,
|
137 | isEqualSize,
|
138 | autoResize,
|
139 | useResizeObserver,
|
140 | resizeDebounce,
|
141 | maxResizeDebounce,
|
142 | defaultDirection,
|
143 | } = gridOptions;
|
144 | const wrapperElement = isString(wrapper) ? document.querySelector(wrapper) as HTMLElement : wrapper;
|
145 | const scrollManager = new ScrollManager(wrapperElement, {
|
146 | scrollContainer,
|
147 | container,
|
148 | containerTag,
|
149 | horizontal,
|
150 | }).on({
|
151 | scroll: this._onScroll,
|
152 | });
|
153 | const containerElement = scrollManager.getContainer();
|
154 | const containerManager = new ContainerManager(containerElement, {
|
155 | horizontal,
|
156 | autoResize,
|
157 | resizeDebounce,
|
158 | maxResizeDebounce,
|
159 | useResizeObserver,
|
160 | }).on("resize", this._onResize);
|
161 | const itemRenderer = new ItemRenderer({
|
162 | attributePrefix,
|
163 | horizontal,
|
164 | useTransform,
|
165 | percentage,
|
166 | isEqualSize,
|
167 | isConstantSize,
|
168 | });
|
169 | const infinite = new Infinite({
|
170 | defaultDirection,
|
171 | useRecycle,
|
172 | threshold,
|
173 | }).on({
|
174 | "change": this._onChange,
|
175 | "requestAppend": this._onRequestAppend,
|
176 | "requestPrepend": this._onRequestPrepend,
|
177 | });
|
178 |
|
179 | infinite.setSize(scrollManager.getContentSize());
|
180 | const groupManager = new GroupManager(containerElement, {
|
181 | appliedItemChecker: appliedItemChecker!,
|
182 | gridConstructor: gridConstructor!,
|
183 | externalItemRenderer: itemRenderer,
|
184 | externalContainerManager: containerManager,
|
185 | gridOptions,
|
186 | });
|
187 |
|
188 | groupManager.on({
|
189 | "renderComplete": this._onRenderComplete,
|
190 | "contentError": this._onContentError,
|
191 | });
|
192 |
|
193 | renderer!.setContainer(containerElement);
|
194 | renderer!.on("updated", this._onRendererUpdated);
|
195 |
|
196 | this.itemRenderer = itemRenderer;
|
197 | this.groupManager = groupManager;
|
198 | this.wrapperElement = wrapperElement;
|
199 | this.scrollManager = scrollManager;
|
200 | this.containerManager = containerManager;
|
201 | this.infinite = infinite;
|
202 |
|
203 | this.containerManager.resize();
|
204 | }
|
205 | |
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 | public renderItems(options: RenderOptions = {}) {
|
221 | this._renderItems(options);
|
222 | return this;
|
223 | }
|
224 | |
225 |
|
226 |
|
227 |
|
228 | public getWrapperElement() {
|
229 | return this.scrollManager.getWrapper();
|
230 | }
|
231 | |
232 |
|
233 |
|
234 |
|
235 | public getScrollContainerElement() {
|
236 | return this.scrollManager.getScrollContainer();
|
237 | }
|
238 | |
239 |
|
240 |
|
241 |
|
242 | public getContainerElement() {
|
243 | return this.scrollManager.getContainer();
|
244 | }
|
245 | |
246 |
|
247 |
|
248 |
|
249 |
|
250 | public syncItems(items: InfiniteGridItemInfo[]): this {
|
251 | this.groupManager.syncItems(items);
|
252 | this._syncGroups();
|
253 |
|
254 | return this;
|
255 | }
|
256 | |
257 |
|
258 |
|
259 |
|
260 |
|
261 |
|
262 |
|
263 | public setCursors(startCursor: number, endCursor: number, useFirstRender?: boolean): this {
|
264 | this.groupManager.setCursors(startCursor, endCursor);
|
265 | this.infinite.setCursors(startCursor, endCursor);
|
266 |
|
267 | if (useFirstRender) {
|
268 | this._syncItems();
|
269 | } else {
|
270 | this._update();
|
271 | this._checkEndLoading();
|
272 | }
|
273 | return this;
|
274 | }
|
275 | |
276 |
|
277 |
|
278 |
|
279 | public getStartCursor(): number {
|
280 | return this.infinite.getStartCursor();
|
281 | }
|
282 | |
283 |
|
284 |
|
285 |
|
286 | public getEndCursor(): number {
|
287 | return this.infinite.getEndCursor();
|
288 | }
|
289 | |
290 |
|
291 |
|
292 |
|
293 |
|
294 |
|
295 |
|
296 |
|
297 |
|
298 |
|
299 |
|
300 |
|
301 |
|
302 | public append(items: InfiniteGridInsertedItems, groupKey?: string | number): this {
|
303 | return this.insert(-1, items, groupKey);
|
304 | }
|
305 | |
306 |
|
307 |
|
308 |
|
309 |
|
310 |
|
311 |
|
312 |
|
313 |
|
314 |
|
315 |
|
316 |
|
317 |
|
318 | public prepend(items: InfiniteGridInsertedItems, groupKey?: string | number): this {
|
319 | return this.insert(0, items, groupKey);
|
320 | }
|
321 | |
322 |
|
323 |
|
324 |
|
325 |
|
326 |
|
327 |
|
328 |
|
329 |
|
330 |
|
331 |
|
332 |
|
333 |
|
334 |
|
335 | public insert(index: number, items: InfiniteGridInsertedItems, groupKey?: string | number): this {
|
336 | const nextItemInfos: InfiniteGridItemInfo[] = this.groupManager.getGroupItems();
|
337 | const itemInfos = convertInsertedItems(items, groupKey);
|
338 |
|
339 | if (index === -1) {
|
340 | nextItemInfos.push(...itemInfos);
|
341 | } else {
|
342 | nextItemInfos.splice(index, 0, ...itemInfos);
|
343 | }
|
344 | return this.syncItems(nextItemInfos);
|
345 | }
|
346 | |
347 |
|
348 |
|
349 |
|
350 |
|
351 |
|
352 |
|
353 |
|
354 |
|
355 |
|
356 |
|
357 |
|
358 |
|
359 |
|
360 | public insertByGroupIndex(groupIndex: number, items: InfiniteGridInsertedItems, groupKey?: string | number): this {
|
361 | const nextGroupInfos: InfiniteGridGroup[] = this.groupManager.getGroups();
|
362 | const rightGroup = nextGroupInfos[groupIndex];
|
363 |
|
364 | if (!rightGroup) {
|
365 | return this.append(items, groupKey);
|
366 | }
|
367 | const nextItemInfos: InfiniteGridItemInfo[] = this.groupManager.getGroupItems();
|
368 | const rightGroupKey = rightGroup.groupKey;
|
369 | const rightItemIndex = findIndex(nextItemInfos, (item) => item.groupKey === rightGroupKey);
|
370 |
|
371 | return this.insert(rightItemIndex, items, groupKey);
|
372 | }
|
373 | |
374 |
|
375 |
|
376 |
|
377 |
|
378 |
|
379 | public getStatus(type?: STATUS_TYPE, includePlaceholders?: boolean): InfiniteGridStatus {
|
380 | return {
|
381 | containerManager: this.containerManager.getStatus(),
|
382 | itemRenderer: this.itemRenderer.getStatus(),
|
383 | groupManager: this.groupManager.getGroupStatus(type, includePlaceholders),
|
384 | scrollManager: this.scrollManager.getStatus(),
|
385 | };
|
386 | }
|
387 |
|
388 | |
389 |
|
390 |
|
391 |
|
392 |
|
393 | public setPlaceholder(info: Partial<InfiniteGridItemStatus> | null): this {
|
394 | this.groupManager.setPlaceholder(info);
|
395 | return this;
|
396 | }
|
397 | |
398 |
|
399 |
|
400 |
|
401 |
|
402 | public setLoading(info: Partial<InfiniteGridItemStatus> | null): this {
|
403 | this.groupManager.setLoading(info);
|
404 | return this;
|
405 | }
|
406 | |
407 |
|
408 |
|
409 |
|
410 |
|
411 |
|
412 | public appendPlaceholders(
|
413 | items: number | InfiniteGridItemStatus[],
|
414 | groupKey?: string | number,
|
415 | ): InsertedPlaceholdersResult {
|
416 | const result = this.groupManager.appendPlaceholders(items, groupKey);
|
417 |
|
418 | this._syncGroups(true);
|
419 | return {
|
420 | ...result,
|
421 | remove: () => {
|
422 | this.removePlaceholders({ groupKey: result.group.groupKey });
|
423 | },
|
424 | };
|
425 | }
|
426 | |
427 |
|
428 |
|
429 |
|
430 |
|
431 |
|
432 | public prependPlaceholders(
|
433 | items: number | InfiniteGridItemStatus[],
|
434 | groupKey?: string | number,
|
435 | ): InsertedPlaceholdersResult {
|
436 | const result = this.groupManager.prependPlaceholders(items, groupKey);
|
437 |
|
438 | this._syncGroups(true);
|
439 | return {
|
440 | ...result,
|
441 | remove: () => {
|
442 | this.removePlaceholders({ groupKey: result.group.groupKey });
|
443 | },
|
444 | };
|
445 | }
|
446 |
|
447 | |
448 |
|
449 |
|
450 |
|
451 |
|
452 | public removePlaceholders(type: "start" | "end" | { groupKey: string | number }) {
|
453 | this.groupManager.removePlaceholders(type);
|
454 | this._syncGroups(true);
|
455 | }
|
456 |
|
457 | |
458 |
|
459 |
|
460 |
|
461 |
|
462 |
|
463 | public setStatus(status: InfiniteGridStatus, useFirstRender?: boolean): this {
|
464 | this.itemRenderer.setStatus(status.itemRenderer);
|
465 | this.containerManager.setStatus(status.containerManager);
|
466 | this.scrollManager.setStatus(status.scrollManager);
|
467 | const groupManager = this.groupManager;
|
468 | const prevInlineSize = this.containerManager.getInlineSize();
|
469 |
|
470 | groupManager.setGroupStatus(status.groupManager);
|
471 | this._syncInfinite();
|
472 | this.infinite.setCursors(groupManager.getStartCursor(), groupManager.getEndCursor());
|
473 |
|
474 | this._getRenderer().updateKey();
|
475 |
|
476 | const state = {
|
477 | isResize: this.containerManager.getInlineSize() !== prevInlineSize,
|
478 | isRestore: true,
|
479 | };
|
480 | if (useFirstRender) {
|
481 | this._syncItems(state);
|
482 | } else {
|
483 | this._update(state);
|
484 | }
|
485 | return this;
|
486 | }
|
487 | |
488 |
|
489 |
|
490 |
|
491 | public removeGroupByIndex(index: number): this {
|
492 | const nextGroups = this.getGroups();
|
493 |
|
494 | return this.removeGroupByKey(nextGroups[index].groupKey);
|
495 | }
|
496 | |
497 |
|
498 |
|
499 |
|
500 | public removeGroupByKey(key: number | string): this {
|
501 | const nextItemInfos = this.getItems();
|
502 |
|
503 | const firstIndex = findIndex(nextItemInfos, (item) => item.groupKey === key);
|
504 | const lastIndex = findLastIndex(nextItemInfos, (item) => item.groupKey === key);
|
505 |
|
506 | if (firstIndex === -1) {
|
507 | return this;
|
508 | }
|
509 | nextItemInfos.splice(firstIndex, lastIndex - firstIndex + 1);
|
510 | return this.syncItems(nextItemInfos);
|
511 | }
|
512 | |
513 |
|
514 |
|
515 |
|
516 | public removeByIndex(index: number): this {
|
517 | const nextItemInfos = this.getItems(true);
|
518 |
|
519 | nextItemInfos.splice(index, 1);
|
520 |
|
521 | return this.syncItems(nextItemInfos);
|
522 | }
|
523 | |
524 |
|
525 |
|
526 |
|
527 | public removeByKey(key: string | number): this {
|
528 | const nextItemInfos = this.getItems(true);
|
529 | const index = findIndex(nextItemInfos, (item) => item.key === key);
|
530 |
|
531 | return this.removeByIndex(index);
|
532 | }
|
533 | |
534 |
|
535 |
|
536 |
|
537 |
|
538 |
|
539 | public updateItems(items?: InfiniteGridItem[], options: RenderOptions = {}) {
|
540 | this.groupManager.updateItems(items, options);
|
541 | return this;
|
542 | }
|
543 | |
544 |
|
545 |
|
546 |
|
547 |
|
548 | public getItems(includePlaceholders?: boolean): InfiniteGridItem[] {
|
549 | return this.groupManager.getGroupItems(includePlaceholders);
|
550 | }
|
551 | |
552 |
|
553 |
|
554 |
|
555 |
|
556 | public getVisibleItems(includePlaceholders?: boolean): InfiniteGridItem[] {
|
557 | return this.groupManager.getVisibleItems(includePlaceholders);
|
558 | }
|
559 |
|
560 | |
561 |
|
562 |
|
563 |
|
564 | public getRenderingItems(): InfiniteGridItem[] {
|
565 | return this.groupManager.getRenderingItems();
|
566 | }
|
567 | |
568 |
|
569 |
|
570 |
|
571 |
|
572 | public getGroups(includePlaceholders?: boolean): InfiniteGridGroup[] {
|
573 | return this.groupManager.getGroups(includePlaceholders);
|
574 | }
|
575 | |
576 |
|
577 |
|
578 |
|
579 |
|
580 | public getVisibleGroups(includePlaceholders?: boolean): InfiniteGridGroup[] {
|
581 | return this.groupManager.getVisibleGroups(includePlaceholders);
|
582 | }
|
583 | |
584 |
|
585 |
|
586 |
|
587 |
|
588 | public wait(direction: "start" | "end" = DIRECTION.END) {
|
589 | this._waitType = direction;
|
590 | this._checkStartLoading(direction);
|
591 | }
|
592 | |
593 |
|
594 |
|
595 |
|
596 | public ready() {
|
597 | this._waitType = "";
|
598 | }
|
599 | |
600 |
|
601 |
|
602 |
|
603 | public isWait() {
|
604 | return !!this._waitType;
|
605 | }
|
606 | |
607 |
|
608 |
|
609 |
|
610 | public destroy(): void {
|
611 | this.off();
|
612 | this._getRenderer().destroy();
|
613 | this.containerManager.destroy();
|
614 | this.groupManager.destroy();
|
615 | this.scrollManager.destroy();
|
616 | this.infinite.destroy();
|
617 | }
|
618 |
|
619 | private _getRenderer() {
|
620 | return this.options.renderer!;
|
621 | }
|
622 | private _getRendererItems() {
|
623 | return this.getRenderingItems().map((item) => {
|
624 | return {
|
625 | element: item.element,
|
626 | key: `${item.type}_${item.key}`,
|
627 | orgItem: item,
|
628 | };
|
629 | });
|
630 | }
|
631 | private _syncItems(state?: Record<string, any>): void {
|
632 | this._getRenderer().syncItems(this._getRendererItems(), state);
|
633 | }
|
634 | private _render(state?: Record<string, any>): void {
|
635 | this._getRenderer().render(this._getRendererItems(), state);
|
636 | }
|
637 | private _update(state: Record<string, any> = {}): void {
|
638 | this._getRenderer().update(state);
|
639 | }
|
640 | private _resizeScroll() {
|
641 | const scrollManager = this.scrollManager;
|
642 |
|
643 | scrollManager.resize();
|
644 |
|
645 | this.infinite.setSize(scrollManager.getContentSize());
|
646 | }
|
647 | private _syncGroups(isUpdate?: boolean) {
|
648 | const infinite = this.infinite;
|
649 | const scrollManager = this.scrollManager;
|
650 |
|
651 | if (!scrollManager.getContentSize()) {
|
652 | this._resizeScroll();
|
653 | }
|
654 | this._syncInfinite();
|
655 | this.groupManager.setCursors(infinite.getStartCursor(), infinite.getEndCursor());
|
656 | if (isUpdate) {
|
657 | this._update();
|
658 | } else {
|
659 | this._render();
|
660 | }
|
661 | }
|
662 | private _syncInfinite() {
|
663 | this.infinite.syncItems(this.getGroups(true).map(({ groupKey, grid, type }) => {
|
664 | const outlines = grid.getOutlines();
|
665 |
|
666 | return {
|
667 | key: groupKey,
|
668 | isVirtual: type === GROUP_TYPE.VIRTUAL,
|
669 | startOutline: outlines.start,
|
670 | endOutline: outlines.end,
|
671 | };
|
672 | }));
|
673 | }
|
674 | private _scroll() {
|
675 | this.infinite.scroll(this.scrollManager.getRelativeScrollPos());
|
676 | }
|
677 | private _onScroll = ({ direction, scrollPos, relativeScrollPos }: OnChangeScroll): void => {
|
678 | this._scroll();
|
679 | |
680 |
|
681 |
|
682 |
|
683 |
|
684 |
|
685 | this.trigger(new ComponentEvent(INFINITEGRID_EVENTS.CHANGE_SCROLL, {
|
686 | direction,
|
687 | scrollPos,
|
688 | relativeScrollPos,
|
689 | }));
|
690 | }
|
691 |
|
692 | private _onChange = (e: OnInfiniteChange): void => {
|
693 | this.setCursors(e.nextStartCursor, e.nextEndCursor);
|
694 | }
|
695 | private _onRendererUpdated = (e: OnRendererUpdated<GridRendererItem>): void => {
|
696 | const renderedItems = e.items;
|
697 |
|
698 | renderedItems.forEach((item) => {
|
699 |
|
700 | const gridItem = item.orgItem;
|
701 |
|
702 | gridItem.element = item.element as HTMLElement;
|
703 | });
|
704 |
|
705 | if (!e.isChanged) {
|
706 | this._checkEndLoading();
|
707 | this._scroll();
|
708 | return;
|
709 | }
|
710 |
|
711 | const {
|
712 | added,
|
713 | removed,
|
714 | prevList,
|
715 | list,
|
716 | } = e.diffResult;
|
717 |
|
718 | removed.forEach((index) => {
|
719 | const orgItem = prevList[index].orgItem;
|
720 |
|
721 | if (orgItem.mountState !== MOUNT_STATE.UNCHECKED) {
|
722 | orgItem.mountState = MOUNT_STATE.UNMOUNTED;
|
723 | }
|
724 | });
|
725 |
|
726 |
|
727 | const horizontal = this.options.horizontal;
|
728 | const addedItems = added.map((index) => {
|
729 | const gridItem = list[index].orgItem;
|
730 | const element = gridItem.element!;
|
731 |
|
732 | if (gridItem.type === ITEM_TYPE.VIRTUAL) {
|
733 | const cssRect = { ...gridItem.cssRect };
|
734 | const rect = gridItem.rect;
|
735 |
|
736 | if (!cssRect.width && rect.width) {
|
737 | cssRect.width = rect.width;
|
738 | }
|
739 | if (!cssRect.height && rect.height) {
|
740 | cssRect.height = rect.height;
|
741 | }
|
742 |
|
743 | return new GridItem(horizontal!, {
|
744 | element,
|
745 | cssRect,
|
746 | });
|
747 | }
|
748 | return gridItem;
|
749 | });
|
750 |
|
751 | const containerManager = this.containerManager;
|
752 | if (this.options.observeChildren) {
|
753 | containerManager.unobserveChildren(removed.map((index) => prevList[index].element!));
|
754 | containerManager.observeChildren(added.map((index) => list[index].element!));
|
755 | }
|
756 |
|
757 | const {
|
758 | isRestore,
|
759 | isResize,
|
760 | } = e.state;
|
761 |
|
762 | this.itemRenderer.renderItems(addedItems);
|
763 |
|
764 | if (isRestore) {
|
765 | this._onRenderComplete({
|
766 | mounted: added.map((index) => list[index].orgItem),
|
767 | updated: [],
|
768 | isResize: false,
|
769 | direction: this.defaultDirection,
|
770 | });
|
771 | }
|
772 | if (!isRestore || isResize || e.isItemChanged) {
|
773 | this.groupManager.renderItems();
|
774 | }
|
775 | }
|
776 |
|
777 | private _onResize = (e: ResizeWatcherResizeEvent) => {
|
778 | if (e.isResizeContainer) {
|
779 | this._renderItems({ useResize: true }, true);
|
780 | } else {
|
781 | const updatedItems = getUpdatedItems(this.getVisibleItems(), e.childEntries) as InfiniteGridItem[];
|
782 |
|
783 | if (updatedItems.length > 0) {
|
784 | this.updateItems(updatedItems);
|
785 | }
|
786 | }
|
787 | }
|
788 |
|
789 | private _onRequestAppend = (e: OnRequestInsert): void => {
|
790 | |
791 |
|
792 |
|
793 |
|
794 |
|
795 |
|
796 | this._onRequestInsert(DIRECTION.END, INFINITEGRID_EVENTS.REQUEST_APPEND, e);
|
797 | }
|
798 |
|
799 | private _onRequestPrepend = (e: OnInfiniteRequestPrepend): void => {
|
800 | |
801 |
|
802 |
|
803 |
|
804 |
|
805 |
|
806 | this._onRequestInsert(DIRECTION.START, INFINITEGRID_EVENTS.REQUEST_PREPEND, e);
|
807 | }
|
808 |
|
809 | private _onRequestInsert(
|
810 | direction: "start" | "end",
|
811 | eventType: "requestAppend" | "requestPrepend",
|
812 | e: OnInfiniteRequestAppend | OnInfiniteRequestPrepend,
|
813 | ) {
|
814 | if (this._waitType) {
|
815 | this._checkStartLoading(this._waitType);
|
816 | return;
|
817 | }
|
818 | this.trigger(new ComponentEvent(eventType, {
|
819 | groupKey: e.key,
|
820 | nextGroupKey: e.nextKey,
|
821 | nextGroupKeys: e.nextKeys || [],
|
822 | isVirtual: e.isVirtual,
|
823 | wait: () => {
|
824 | this.wait(direction);
|
825 | },
|
826 | ready: () => {
|
827 | this.ready();
|
828 | },
|
829 | }));
|
830 | }
|
831 |
|
832 | private _onContentError = ({ element, target, item, update }: OnContentError): void => {
|
833 | |
834 |
|
835 |
|
836 |
|
837 |
|
838 |
|
839 | this.trigger(new ComponentEvent(INFINITEGRID_EVENTS.CONTENT_ERROR, {
|
840 | element,
|
841 | target,
|
842 | item: item as InfiniteGridItem,
|
843 | update,
|
844 | remove: () => {
|
845 | this.removeByKey(item.key!);
|
846 | },
|
847 | }));
|
848 | }
|
849 |
|
850 | private _onRenderComplete = ({ isResize, mounted, updated, direction }: OnPickedRenderComplete): void => {
|
851 | const infinite = this.infinite;
|
852 | const prevRenderedGroups = infinite.getRenderedVisibleItems();
|
853 | const length = prevRenderedGroups.length;
|
854 | const isDirectionEnd = direction === DIRECTION.END;
|
855 |
|
856 | this._syncInfinite();
|
857 |
|
858 | if (length) {
|
859 | const prevStandardGroup = prevRenderedGroups[isDirectionEnd ? 0 : length - 1];
|
860 | const nextStandardGroup = infinite.getItemByKey(prevStandardGroup.key);
|
861 | const offset = isDirectionEnd
|
862 | ? Math.min(...nextStandardGroup.startOutline) - Math.min(...prevStandardGroup.startOutline)
|
863 | : Math.max(...nextStandardGroup.endOutline) - Math.max(...prevStandardGroup.endOutline);
|
864 |
|
865 | this.scrollManager.scrollBy(offset);
|
866 | }
|
867 |
|
868 | |
869 |
|
870 |
|
871 |
|
872 |
|
873 |
|
874 | this.trigger(new ComponentEvent(INFINITEGRID_EVENTS.RENDER_COMPLETE, {
|
875 | isResize,
|
876 | direction,
|
877 | mounted: (mounted as InfiniteGridItem[]).filter((item) => item.type !== ITEM_TYPE.LOADING),
|
878 | updated: (updated as InfiniteGridItem[]).filter((item) => item.type !== ITEM_TYPE.LOADING),
|
879 | startCursor: this.getStartCursor(),
|
880 | endCursor: this.getEndCursor(),
|
881 | items: this.getVisibleItems(true),
|
882 | groups: this.getVisibleGroups(true),
|
883 | }));
|
884 |
|
885 | if (this.groupManager.shouldRerenderItems()) {
|
886 | this._update();
|
887 | } else {
|
888 | this._checkEndLoading();
|
889 | this._scroll();
|
890 | }
|
891 | }
|
892 | private _renderItems(options: RenderOptions = {}, isTrusted?: boolean) {
|
893 | if (!isTrusted && options.useResize) {
|
894 | this.containerManager.resize();
|
895 | }
|
896 | this._resizeScroll();
|
897 | if (!this.getRenderingItems().length) {
|
898 | const children = toArray(this.getContainerElement().children);
|
899 | if (children.length > 0) {
|
900 | // no items, but has children
|
901 | this.groupManager.syncItems(convertInsertedItems(children));
|
902 | this._syncInfinite();
|
903 | this.setCursors(0, 0, true);
|
904 | this._getRenderer().updated();
|
905 | } else {
|
906 | this.infinite.scroll(0);
|
907 | }
|
908 | return this;
|
909 | }
|
910 | if (!this.getVisibleGroups(true).length) {
|
911 | this.setCursors(0, 0);
|
912 | } else {
|
913 | this.groupManager.renderItems(options);
|
914 | }
|
915 | return this;
|
916 | }
|
917 | private _checkStartLoading(direction: "start" | "end") {
|
918 | const groupManager = this.groupManager;
|
919 | const infinite = this.infinite;
|
920 |
|
921 | if (
|
922 | !groupManager.getLoadingType()
|
923 | && infinite.isLoading(direction)
|
924 | && groupManager.startLoading(direction)
|
925 | && groupManager.hasLoadingItem()
|
926 | ) {
|
927 | this._update();
|
928 | }
|
929 | }
|
930 | private _checkEndLoading() {
|
931 | const groupManager = this.groupManager;
|
932 | const loadingType = this.groupManager.getLoadingType();
|
933 |
|
934 | if (
|
935 | loadingType
|
936 | && (!this._waitType || !this.infinite.isLoading(loadingType))
|
937 | && groupManager.endLoading()
|
938 | && groupManager.hasLoadingItem()
|
939 | ) {
|
940 | this._update();
|
941 | }
|
942 | }
|
943 | }
|
944 |
|
945 | interface InfiniteGrid extends Properties<typeof InfiniteGrid> { }
|
946 |
|
947 | export default InfiniteGrid;
|
948 |
|
\ | No newline at end of file |