ng-virtual-list 21.10.2 → 21.10.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/README.md +17 -17
- package/fesm2022/ng-virtual-list.mjs +151 -97
- package/fesm2022/ng-virtual-list.mjs.map +1 -1
- package/package.json +1 -1
- package/types/ng-virtual-list.d.ts +16 -9
package/README.md
CHANGED
|
@@ -101,7 +101,7 @@ npm i ng-virtual-list
|
|
|
101
101
|
|
|
102
102
|
## 🚀 Quick Start
|
|
103
103
|
```html
|
|
104
|
-
<ng-virtual-list [items]="items" [bufferSize]="5" [itemRenderer]="itemRenderer" [itemSize]="64"></ng-virtual-list>
|
|
104
|
+
<ng-virtual-list [items]="items" [bufferSize]="5" [itemRenderer]="itemRenderer" [dynamicSize]="false" [itemSize]="64"></ng-virtual-list>
|
|
105
105
|
|
|
106
106
|
<ng-template #itemRenderer let-data="data">
|
|
107
107
|
@if (data) {
|
|
@@ -124,7 +124,7 @@ items = Array.from({ length: 100000 }, (_, i) => ({ id: i, name: `Item #${i}` })
|
|
|
124
124
|
Template:
|
|
125
125
|
```html
|
|
126
126
|
<ng-virtual-list class="list" direction="horizontal" [items]="horizontalItems" [bufferSize]="1" [maxBufferSize]="5"
|
|
127
|
-
[itemRenderer]="horizontalItemRenderer" [itemSize]="64" [methodForSelecting]="'select'"
|
|
127
|
+
[itemRenderer]="horizontalItemRenderer" [dynamicSize]="false" [itemSize]="64" [methodForSelecting]="'select'"
|
|
128
128
|
[selectedIds]="2" (onSelect)="onSelect($event)" (onItemClick)="onItemClick($event)"></ng-virtual-list>
|
|
129
129
|
|
|
130
130
|
<ng-template #horizontalItemRenderer let-data="data" let-config="config">
|
|
@@ -174,7 +174,7 @@ export class AppComponent {
|
|
|
174
174
|
Template:
|
|
175
175
|
```html
|
|
176
176
|
<ng-virtual-list class="list" direction="horizontal" [items]="horizontalGroupItems" [itemRenderer]="horizontalGroupItemRenderer"
|
|
177
|
-
[bufferSize]="1" [maxBufferSize]="5" [itemConfigMap]="horizontalGroupItemConfigMap" [itemSize]="54" [snap]="true"
|
|
177
|
+
[bufferSize]="1" [maxBufferSize]="5" [itemConfigMap]="horizontalGroupItemConfigMap" [dynamicSize]="false" [itemSize]="54" [snap]="true"
|
|
178
178
|
methodForSelecting="multi-select" [selectedIds]="[3,2]" (onSelect)="onSelect($event)" (onItemClick)="onItemClick($event)"></ng-virtual-list>
|
|
179
179
|
|
|
180
180
|
<ng-template #horizontalGroupItemRenderer let-data="data" let-config="config">
|
|
@@ -248,7 +248,7 @@ export class AppComponent {
|
|
|
248
248
|
Template:
|
|
249
249
|
```html
|
|
250
250
|
<ng-virtual-list class="list simple" [items]="items" [bufferSize]="1" [maxBufferSize]="5" [itemRenderer]="itemRenderer"
|
|
251
|
-
[itemSize]="40"></ng-virtual-list>
|
|
251
|
+
[dynamicSize]="false" [itemSize]="40"></ng-virtual-list>
|
|
252
252
|
|
|
253
253
|
<ng-template #itemRenderer let-data="data">
|
|
254
254
|
@if (data) {
|
|
@@ -289,7 +289,7 @@ export class AppComponent {
|
|
|
289
289
|
Template:
|
|
290
290
|
```html
|
|
291
291
|
<ng-virtual-list class="list simple" [items]="groupItems" [bufferSize]="1" [maxBufferSize]="5" [itemRenderer]="groupItemRenderer"
|
|
292
|
-
[itemConfigMap]="groupItemConfigMap" [itemSize]="40" [snap]="false"></ng-virtual-list>
|
|
292
|
+
[itemConfigMap]="groupItemConfigMap" [dynamicSize]="false" [itemSize]="40" [snap]="false"></ng-virtual-list>
|
|
293
293
|
|
|
294
294
|
<ng-template #groupItemRenderer let-data="data">
|
|
295
295
|
@if (data) {
|
|
@@ -316,7 +316,7 @@ Template:
|
|
|
316
316
|
Template (with snapping):
|
|
317
317
|
```html
|
|
318
318
|
<ng-virtual-list class="list simple" [items]="groupItems" [bufferSize]="1" [maxBufferSize]="5" [itemRenderer]="groupItemRenderer"
|
|
319
|
-
[itemConfigMap]="groupItemConfigMap" [itemSize]="40" [snap]="true"></ng-virtual-list>
|
|
319
|
+
[itemConfigMap]="groupItemConfigMap" [dynamicSize]="false" [itemSize]="40" [snap]="true"></ng-virtual-list>
|
|
320
320
|
|
|
321
321
|
<ng-template #groupItemRenderer let-data="data">
|
|
322
322
|
@if (data) {
|
|
@@ -381,7 +381,7 @@ Template
|
|
|
381
381
|
</div>
|
|
382
382
|
|
|
383
383
|
<ng-virtual-list #virtualList class="list" [items]="items" [itemRenderer]="itemRenderer" [bufferSize]="1" [maxBufferSize]="5"
|
|
384
|
-
[itemSize]="40"></ng-virtual-list>
|
|
384
|
+
[dynamicSize]="false" [itemSize]="40"></ng-virtual-list>
|
|
385
385
|
|
|
386
386
|
<ng-template #itemRenderer let-data="data">
|
|
387
387
|
@if (data) {
|
|
@@ -435,7 +435,7 @@ Virtual list with height-adjustable elements.
|
|
|
435
435
|
Template
|
|
436
436
|
```html
|
|
437
437
|
<ng-virtual-list #dynamicList class="list" [items]="groupDynamicItems" [itemRenderer]="groupItemRenderer" [bufferSize]="1" [maxBufferSize]="5"
|
|
438
|
-
[itemConfigMap]="groupDynamicItemConfigMap" [
|
|
438
|
+
[itemConfigMap]="groupDynamicItemConfigMap" [snap]="true"></ng-virtual-list>
|
|
439
439
|
|
|
440
440
|
<ng-template #groupItemRenderer let-data="data">
|
|
441
441
|
@if (data) {
|
|
@@ -649,7 +649,7 @@ Inputs
|
|
|
649
649
|
|---|---|---|
|
|
650
650
|
| id | number | Readonly. Returns the unique identifier of the component. |
|
|
651
651
|
| items | [IVirtualListCollection](https://github.com/DjonnyX/ng-virtual-list/blob/21.x/projects/ng-virtual-list/src/lib/models/collection.model.ts) | Collection of list items. The collection of elements must be immutable. |
|
|
652
|
-
| itemSize | number? = 24 | If direction = 'vertical', then the height of a typical element. If direction = 'horizontal', then the width of a typical element.
|
|
652
|
+
| itemSize | number? = 24 | If direction = 'vertical', then the height of a typical element. If direction = 'horizontal', then the width of a typical element. If the dynamicSize property is true, the items in the list can have different sizes, and you must specify the itemSize property to adjust the sizes of the items in the unallocated area. |
|
|
653
653
|
| bufferSize | number? = 2 | Number of elements outside the scope of visibility. Default value is 2. |
|
|
654
654
|
| maxBufferSize | number? = 10 | Maximum number of elements outside the scope of visibility. Default value is 10. If maxBufferSize is set to be greater than bufferSize, then adaptive buffer mode is enabled. The greater the scroll size, the more elements are allocated for rendering. |
|
|
655
655
|
| itemRenderer | TemplateRef | Rendering element template. |
|
|
@@ -661,7 +661,7 @@ Inputs
|
|
|
661
661
|
| snap | boolean? = false | Determines whether elements will snap. Default value is "false". |
|
|
662
662
|
| snappingMethod | [SnappingMethod? = 'normal'](https://github.com/DjonnyX/ng-virtual-list/blob/21.x/projects/ng-virtual-list/src/lib/enums/snapping-method.ts) | Snapping method. 'normal' - Normal group rendering. 'advanced' - The group is rendered on a transparent background. 'chat' - The group is rendered on a background. List items below the group are not rendered. |
|
|
663
663
|
| direction | [Direction? = 'vertical'](https://github.com/DjonnyX/ng-virtual-list/blob/21.x/projects/ng-virtual-list/src/lib/enums/direction.ts) | Determines the direction in which elements are placed. Default value is "vertical". |
|
|
664
|
-
| dynamicSize | boolean? =
|
|
664
|
+
| dynamicSize | boolean? = true | If true, items in the list may have different sizes, and the itemSize property must be specified to adjust the sizes of items in the unallocated area. If false then the items in the list have a fixed size specified by the itemSize property. The default value is true. |
|
|
665
665
|
| enabledBufferOptimization | boolean? = true | Experimental! Enables buffer optimization. Can only be used if items in the collection are not added or updated. |
|
|
666
666
|
| trackBy | string? = 'id' | The name of the property by which tracking is performed. |
|
|
667
667
|
| selectedIds | Array<[Id](https://github.com/DjonnyX/ng-virtual-list/blob/21.x/projects/ng-virtual-list/src/lib/types/id.ts)> \| [Id](https://github.com/DjonnyX/ng-virtual-list/blob/21.x/projects/ng-virtual-list/src/lib/types/id.ts) \| undefined | Sets the selected items. |
|
|
@@ -737,13 +737,13 @@ Properties
|
|
|
737
737
|
|
|
738
738
|
| Angular version | ng-virtual-list version | git | npm |
|
|
739
739
|
|--|--|--|--|
|
|
740
|
-
| 20.x | 20.10.
|
|
741
|
-
|
|
|
742
|
-
| 18.x | 18.10.
|
|
743
|
-
| 17.x | 17.10.
|
|
744
|
-
| 16.x | 16.10.
|
|
745
|
-
| 15.x | 15.10.
|
|
746
|
-
| 14.x | 14.10.
|
|
740
|
+
| 20.x | 20.10.4 | [20.x](https://github.com/DjonnyX/ng-virtual-list/tree/20.x) | [20.10.4](https://www.npmjs.com/package/ng-virtual-list/v/20.10.4) |
|
|
741
|
+
| 21.x | 19.10.2 | [21.x](https://github.com/DjonnyX/ng-virtual-list/tree/21.x) | [19.10.2](https://www.npmjs.com/package/ng-virtual-list/v/19.10.2) |
|
|
742
|
+
| 18.x | 18.10.2 | [18.x](https://github.com/DjonnyX/ng-virtual-list/tree/18.x) | [18.10.2](https://www.npmjs.com/package/ng-virtual-list/v/18.10.2) |
|
|
743
|
+
| 17.x | 17.10.2 | [17.x](https://github.com/DjonnyX/ng-virtual-list/tree/17.x) | [17.10.2](https://www.npmjs.com/package/ng-virtual-list/v/17.10.2) |
|
|
744
|
+
| 16.x | 16.10.1 | [16.x](https://github.com/DjonnyX/ng-virtual-list/tree/16.x) | [16.10.1](https://www.npmjs.com/package/ng-virtual-list/v/16.10.1) |
|
|
745
|
+
| 15.x | 15.10.1 | [15.x](https://github.com/DjonnyX/ng-virtual-list/tree/15.x) | [15.10.1](https://www.npmjs.com/package/ng-virtual-list/v/15.10.1) |
|
|
746
|
+
| 14.x | 14.10.2 | [14.x](https://github.com/DjonnyX/ng-virtual-list/tree/14.x) | [14.10.2](https://www.npmjs.com/package/ng-virtual-list/v/14.10.2) |
|
|
747
747
|
<br/>
|
|
748
748
|
|
|
749
749
|
## 🤝 Contributing
|
|
@@ -3,7 +3,7 @@ import { CommonModule } from '@angular/common';
|
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
4
|
import { Injectable, output, inject, ElementRef, DestroyRef, Input, Directive, signal, computed, ChangeDetectionStrategy, Component, viewChild, input, effect, ViewEncapsulation, InjectionToken, ViewChild, NO_ERRORS_SCHEMA, ViewContainerRef } from '@angular/core';
|
|
5
5
|
import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
|
|
6
|
-
import { Subject, tap, fromEvent, race, of, combineLatest, map, filter as filter$1,
|
|
6
|
+
import { Subject, tap, fromEvent, race, of, switchMap as switchMap$1, combineLatest, map, filter as filter$1, delay, takeUntil as takeUntil$1, from, debounceTime, BehaviorSubject as BehaviorSubject$1, distinctUntilChanged, take } from 'rxjs';
|
|
7
7
|
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
|
|
8
8
|
import { switchMap, takeUntil, filter, tap as tap$1 } from 'rxjs/operators';
|
|
9
9
|
import { CdkScrollable } from '@angular/cdk/scrolling';
|
|
@@ -134,7 +134,7 @@ const DEFAULT_SNAP = false;
|
|
|
134
134
|
const DEFAULT_SELECT_BY_CLICK = true;
|
|
135
135
|
const DEFAULT_COLLAPSE_BY_CLICK = true;
|
|
136
136
|
const DEFAULT_ENABLED_BUFFER_OPTIMIZATION = false;
|
|
137
|
-
const DEFAULT_DYNAMIC_SIZE =
|
|
137
|
+
const DEFAULT_DYNAMIC_SIZE = true;
|
|
138
138
|
const DEFAULT_SNAP_TO_END_TRANSITION_INSTANT_OFFSET = 1;
|
|
139
139
|
const DEFAULT_SNAP_SCROLLTO_BOTTOM = false;
|
|
140
140
|
const TRACK_BY_PROPERTY_NAME = 'id';
|
|
@@ -288,6 +288,7 @@ class NgVirtualListService {
|
|
|
288
288
|
$scrollToStart = this._$scrollToStart.asObservable();
|
|
289
289
|
_$scrollToEnd = new Subject();
|
|
290
290
|
$scrollToEnd = this._$scrollToEnd.asObservable();
|
|
291
|
+
lastFocusedItemId = -1;
|
|
291
292
|
scrollStartOffset = 0;
|
|
292
293
|
scrollEndOffset = 0;
|
|
293
294
|
scrollBarSize = 0;
|
|
@@ -634,7 +635,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
634
635
|
args: ['maxClickDistance']
|
|
635
636
|
}], onClick: [{ type: i0.Output, args: ["onClick"] }] } });
|
|
636
637
|
|
|
637
|
-
const ZEROS_POSITION = -1000, ATTR_AREA_SELECTED = 'area-selected', POSITION = 'position', POSITION_ZERO = '0', ID$1 = 'item-id', KEY_SPACE = ' ', KEY_ARR_LEFT = 'ArrowLeft', KEY_ARR_UP = 'ArrowUp', KEY_ARR_RIGHT = 'ArrowRight', KEY_ARR_DOWN = 'ArrowDown', EVENT_FOCUS_IN = 'focusin', EVENT_FOCUS_OUT = 'focusout', EVENT_KEY_DOWN = 'keydown', CLASS_NAME_SNAPPED = 'snapped', CLASS_NAME_SNAPPED_OUT = 'snapped-out', CLASS_NAME_FOCUS = 'focus';
|
|
638
|
+
const ZEROS_POSITION = -1000, NAVIGATE_TO_ATTEMT = 5, ATTR_AREA_SELECTED = 'area-selected', POSITION = 'position', POSITION_ZERO = '0', ID$1 = 'item-id', KEY_SPACE = ' ', KEY_ARR_LEFT = 'ArrowLeft', KEY_ARR_UP = 'ArrowUp', KEY_ARR_RIGHT = 'ArrowRight', KEY_ARR_DOWN = 'ArrowDown', EVENT_FOCUS_IN = 'focusin', EVENT_FOCUS_OUT = 'focusout', EVENT_KEY_DOWN = 'keydown', CLASS_NAME_SNAPPED = 'snapped', CLASS_NAME_SNAPPED_OUT = 'snapped-out', CLASS_NAME_FOCUS = 'focus';
|
|
638
639
|
/**
|
|
639
640
|
* Virtual list component.
|
|
640
641
|
* Maximum performance for extremely large lists.
|
|
@@ -728,6 +729,7 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
|
|
|
728
729
|
(align = FocusAlignments.CENTER) => {
|
|
729
730
|
this.focus(align);
|
|
730
731
|
};
|
|
732
|
+
_destroyRef = inject(DestroyRef);
|
|
731
733
|
constructor() {
|
|
732
734
|
super();
|
|
733
735
|
this._id = this._service.generateComponentId();
|
|
@@ -765,46 +767,43 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
|
|
|
765
767
|
this.focused.set(false);
|
|
766
768
|
this.updateConfig(this._data);
|
|
767
769
|
this.updatePartStr(this._data, this._isSelected, this._isCollapsed);
|
|
768
|
-
})).subscribe()
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
this._service.select(this._data);
|
|
775
|
-
this._service.collapse(this._data);
|
|
776
|
-
break;
|
|
777
|
-
}
|
|
778
|
-
case KEY_ARR_LEFT:
|
|
779
|
-
if (!this.config().isVertical) {
|
|
780
|
-
e.stopImmediatePropagation();
|
|
781
|
-
e.preventDefault();
|
|
782
|
-
this.focusPrev();
|
|
783
|
-
}
|
|
784
|
-
break;
|
|
785
|
-
case KEY_ARR_UP:
|
|
786
|
-
if (this.config().isVertical) {
|
|
787
|
-
e.stopImmediatePropagation();
|
|
788
|
-
e.preventDefault();
|
|
789
|
-
this.focusPrev();
|
|
790
|
-
}
|
|
791
|
-
break;
|
|
792
|
-
case KEY_ARR_RIGHT:
|
|
793
|
-
if (!this.config().isVertical) {
|
|
794
|
-
e.stopImmediatePropagation();
|
|
795
|
-
e.preventDefault();
|
|
796
|
-
this.focusNext();
|
|
797
|
-
}
|
|
798
|
-
break;
|
|
799
|
-
case KEY_ARR_DOWN:
|
|
800
|
-
if (this.config().isVertical) {
|
|
770
|
+
})).subscribe();
|
|
771
|
+
$focused.pipe(takeUntilDestroyed(), switchMap$1(v => {
|
|
772
|
+
if (v) {
|
|
773
|
+
return fromEvent(this.element, EVENT_KEY_DOWN).pipe(takeUntilDestroyed(this._destroyRef), tap(e => {
|
|
774
|
+
switch (e.key) {
|
|
775
|
+
case KEY_SPACE: {
|
|
801
776
|
e.stopImmediatePropagation();
|
|
802
777
|
e.preventDefault();
|
|
803
|
-
this.
|
|
778
|
+
this._service.select(this._data);
|
|
779
|
+
this._service.collapse(this._data);
|
|
780
|
+
break;
|
|
804
781
|
}
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
782
|
+
case KEY_ARR_LEFT:
|
|
783
|
+
if (!this.config().isVertical) {
|
|
784
|
+
this.toPrevItem(e);
|
|
785
|
+
}
|
|
786
|
+
break;
|
|
787
|
+
case KEY_ARR_UP:
|
|
788
|
+
if (this.config().isVertical) {
|
|
789
|
+
this.toPrevItem(e);
|
|
790
|
+
}
|
|
791
|
+
break;
|
|
792
|
+
case KEY_ARR_RIGHT:
|
|
793
|
+
if (!this.config().isVertical) {
|
|
794
|
+
this.toNextItem(e);
|
|
795
|
+
}
|
|
796
|
+
break;
|
|
797
|
+
case KEY_ARR_DOWN:
|
|
798
|
+
if (this.config().isVertical) {
|
|
799
|
+
this.toNextItem(e);
|
|
800
|
+
}
|
|
801
|
+
break;
|
|
802
|
+
}
|
|
803
|
+
}));
|
|
804
|
+
}
|
|
805
|
+
return of(false);
|
|
806
|
+
})).subscribe();
|
|
808
807
|
combineLatest([$data, this._service.$methodOfSelecting, this._service.$selectedIds, this._service.$collapsedIds]).pipe(takeUntilDestroyed(), map(([, m, selectedIds, collapsedIds]) => ({ method: m, selectedIds, collapsedIds })), tap(({ method, selectedIds, collapsedIds }) => {
|
|
809
808
|
switch (method) {
|
|
810
809
|
case MethodsForSelectingTypes.SELECT: {
|
|
@@ -833,19 +832,54 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
|
|
|
833
832
|
this.updateMeasures(this._data);
|
|
834
833
|
})).subscribe();
|
|
835
834
|
}
|
|
835
|
+
toNextItem(e, attempt = NAVIGATE_TO_ATTEMT) {
|
|
836
|
+
const index = this.focusNext();
|
|
837
|
+
if (index > -1) {
|
|
838
|
+
this._service.lastFocusedItemId = index;
|
|
839
|
+
if (!!e && e.cancelable) {
|
|
840
|
+
e.stopImmediatePropagation();
|
|
841
|
+
e.preventDefault();
|
|
842
|
+
}
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
if (this._service.lastFocusedItemId > -1) {
|
|
846
|
+
this.focus(FocusAlignments.CENTER, this._service.lastFocusedItemId);
|
|
847
|
+
}
|
|
848
|
+
if (attempt > 0) {
|
|
849
|
+
this.toNextItem(e, attempt - 1);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
toPrevItem(e, attempt = NAVIGATE_TO_ATTEMT) {
|
|
853
|
+
const index = this.focusPrev();
|
|
854
|
+
if (index > -1) {
|
|
855
|
+
this._service.lastFocusedItemId = index;
|
|
856
|
+
if (!!e && e.cancelable) {
|
|
857
|
+
e.stopImmediatePropagation();
|
|
858
|
+
e.preventDefault();
|
|
859
|
+
}
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
if (this._service.lastFocusedItemId > -1) {
|
|
863
|
+
this.focus(FocusAlignments.CENTER, this._service.lastFocusedItemId);
|
|
864
|
+
}
|
|
865
|
+
if (attempt > 0) {
|
|
866
|
+
this.toPrevItem(e, attempt - 1);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
836
869
|
focusNext() {
|
|
837
870
|
if (this._service.listElement) {
|
|
838
871
|
const tabIndex = this._data?.config?.tabIndex ?? 0, length = this._service.collection?.length ?? 0;
|
|
839
872
|
let index = tabIndex;
|
|
840
873
|
while (index <= length) {
|
|
841
874
|
index++;
|
|
842
|
-
const
|
|
843
|
-
if (
|
|
844
|
-
this._service.focus(
|
|
845
|
-
|
|
875
|
+
const element = this._service.listElement.querySelector(getListElementByIndex(index));
|
|
876
|
+
if (!!element && element.style.visibility !== VISIBILITY_HIDDEN) {
|
|
877
|
+
this._service.focus(element);
|
|
878
|
+
return index;
|
|
846
879
|
}
|
|
847
880
|
}
|
|
848
881
|
}
|
|
882
|
+
return -1;
|
|
849
883
|
}
|
|
850
884
|
focusPrev() {
|
|
851
885
|
if (this._service.listElement) {
|
|
@@ -853,21 +887,22 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
|
|
|
853
887
|
let index = tabIndex;
|
|
854
888
|
while (index >= 0) {
|
|
855
889
|
index--;
|
|
856
|
-
const
|
|
857
|
-
if (
|
|
858
|
-
this._service.focus(
|
|
859
|
-
|
|
890
|
+
const element = this._service.listElement.querySelector(getListElementByIndex(index));
|
|
891
|
+
if (!!element) {
|
|
892
|
+
this._service.focus(element);
|
|
893
|
+
return index;
|
|
860
894
|
}
|
|
861
895
|
}
|
|
862
896
|
}
|
|
897
|
+
return -1;
|
|
863
898
|
}
|
|
864
|
-
focus(align = FocusAlignments.CENTER) {
|
|
899
|
+
focus(align = FocusAlignments.CENTER, index = -1) {
|
|
865
900
|
if (this._service.listElement) {
|
|
866
|
-
const tabIndex = this._data?.config?.tabIndex ?? 0;
|
|
867
|
-
let
|
|
868
|
-
const
|
|
869
|
-
if (
|
|
870
|
-
this._service.focus(
|
|
901
|
+
const tabIndex = index > -1 ? index : this._data?.config?.tabIndex ?? 0;
|
|
902
|
+
let i = tabIndex;
|
|
903
|
+
const element = this._service.listElement.querySelector(getListElementByIndex(i));
|
|
904
|
+
if (!!element) {
|
|
905
|
+
this._service.focus(element, align);
|
|
871
906
|
}
|
|
872
907
|
}
|
|
873
908
|
}
|
|
@@ -2195,14 +2230,16 @@ class TrackBox extends CacheMap {
|
|
|
2195
2230
|
}
|
|
2196
2231
|
}
|
|
2197
2232
|
changes(immediately = false) {
|
|
2198
|
-
if (this.changesDetected()) {
|
|
2199
|
-
return;
|
|
2200
|
-
}
|
|
2201
|
-
this.bumpVersion();
|
|
2202
2233
|
if (immediately) {
|
|
2203
2234
|
this._previousVersion = this._version;
|
|
2204
2235
|
this.dispatch(CACHE_BOX_CHANGE_EVENT_NAME, this.version);
|
|
2205
2236
|
}
|
|
2237
|
+
else {
|
|
2238
|
+
if (this.changesDetected()) {
|
|
2239
|
+
return;
|
|
2240
|
+
}
|
|
2241
|
+
this.bumpVersion();
|
|
2242
|
+
}
|
|
2206
2243
|
}
|
|
2207
2244
|
generateDisplayCollection(items, itemConfigMap, metrics) {
|
|
2208
2245
|
const { offsetY, offsetX, width, height, normalizedItemWidth, normalizedItemHeight, dynamicSize, itemsOnDisplayLength, itemsFromStartToScrollEnd, isVertical, renderItems: renderItemsLength, scrollSize, sizeProperty, snap, snippedPos, startPosition, totalLength, startIndex, typicalItemSize, } = metrics, displayItems = [];
|
|
@@ -3839,10 +3876,10 @@ class NgScrollerComponent extends NgScrollView {
|
|
|
3839
3876
|
this.prepared = false;
|
|
3840
3877
|
}
|
|
3841
3878
|
refresh(fireUpdate = false, updateScrollbar = true) {
|
|
3842
|
-
this.scrollLimits();
|
|
3843
3879
|
if (updateScrollbar) {
|
|
3844
3880
|
this.stopScrolling();
|
|
3845
3881
|
}
|
|
3882
|
+
this.scrollLimits();
|
|
3846
3883
|
if (this.isVertical()) {
|
|
3847
3884
|
this.refreshY(this._y);
|
|
3848
3885
|
}
|
|
@@ -3850,7 +3887,7 @@ class NgScrollerComponent extends NgScrollView {
|
|
|
3850
3887
|
this.refreshX(this._x);
|
|
3851
3888
|
}
|
|
3852
3889
|
if (updateScrollbar) {
|
|
3853
|
-
this.updateScrollBarHandler(
|
|
3890
|
+
this.updateScrollBarHandler(false);
|
|
3854
3891
|
if (this.cdkScrollable) {
|
|
3855
3892
|
this.cdkScrollable.getElementRef().nativeElement.dispatchEvent(SCROLLBAR_SCROLL_EVENT);
|
|
3856
3893
|
}
|
|
@@ -3913,7 +3950,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
3913
3950
|
args: ['scrollBar', { read: NgScrollBarComponent }]
|
|
3914
3951
|
}], scrollbarEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollbarEnabled", required: false }] }], scrollbarInteractive: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollbarInteractive", required: false }] }], focusedElement: [{ type: i0.Input, args: [{ isSignal: true, alias: "focusedElement", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], classes: [{ type: i0.Input, args: [{ isSignal: true, alias: "classes", required: false }] }], startOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "startOffset", required: false }] }], endOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "endOffset", required: false }] }], scrollbarTheme: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollbarTheme", required: false }] }], scrollbarMinSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollbarMinSize", required: false }] }] } });
|
|
3915
3952
|
|
|
3916
|
-
const MIN_SCROLL_TO_START_PIXELS = 10, RANGE_DISPLAY_ITEMS_END_OFFSET = 20,
|
|
3953
|
+
const MIN_SCROLL_TO_START_PIXELS = 10, RANGE_DISPLAY_ITEMS_END_OFFSET = 20, MIN_PREPARE_ITERATIONS = 20, EMPTY_SCROLL_STATE_VERSION = '-1', ROLE_LIST = 'list', ROLE_LIST_BOX = 'listbox', ITEM_ID = 'item-id', ITEM_CONTAINER = 'ngvl-item__container', READY_TO_START = 'ready-to-start', WAIT_FOR_PREPARATION = 'wait-for-preparation';
|
|
3954
|
+
const getScrollStateVersion = (scrollSize, cacheVersion) => {
|
|
3955
|
+
return `${scrollSize}_${cacheVersion}`;
|
|
3956
|
+
};
|
|
3917
3957
|
const validateScrollIteration = (value) => {
|
|
3918
3958
|
return Number.isNaN(value) || (value < 0) ? 0 : value > MAX_SCROLL_TO_ITERATIONS ? MAX_SCROLL_TO_ITERATIONS : value;
|
|
3919
3959
|
}, validateId = (id) => {
|
|
@@ -4435,7 +4475,8 @@ class NgVirtualListComponent {
|
|
|
4435
4475
|
};
|
|
4436
4476
|
/**
|
|
4437
4477
|
* If direction = 'vertical', then the height of a typical element. If direction = 'horizontal', then the width of a typical element.
|
|
4438
|
-
*
|
|
4478
|
+
* If the dynamicSize property is true, the items in the list can have different sizes, and you must specify the itemSize property
|
|
4479
|
+
* to adjust the sizes of the items in the unallocated area.
|
|
4439
4480
|
*/
|
|
4440
4481
|
itemSize = input(DEFAULT_ITEM_SIZE, { ...(ngDevMode ? { debugName: "itemSize" } : {}), ...this._itemSizeOptions });
|
|
4441
4482
|
_dynamicSizeOptions = {
|
|
@@ -4449,8 +4490,9 @@ class NgVirtualListComponent {
|
|
|
4449
4490
|
},
|
|
4450
4491
|
};
|
|
4451
4492
|
/**
|
|
4452
|
-
* If true
|
|
4453
|
-
*
|
|
4493
|
+
* If true, items in the list may have different sizes, and the itemSize property must be specified to adjust
|
|
4494
|
+
* the sizes of items in the unallocated area.
|
|
4495
|
+
* If false then the items in the list have a fixed size specified by the itemSize property. The default value is true.
|
|
4454
4496
|
*/
|
|
4455
4497
|
dynamicSize = input(DEFAULT_DYNAMIC_SIZE, { ...(ngDevMode ? { debugName: "dynamicSize" } : {}), ...this._dynamicSizeOptions });
|
|
4456
4498
|
_directionOptions = {
|
|
@@ -4737,6 +4779,7 @@ class NgVirtualListComponent {
|
|
|
4737
4779
|
[this._isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: pos, behavior,
|
|
4738
4780
|
fireUpdate: true, blending: true, userAction: true, duration: this.animationParams().navigateToItem,
|
|
4739
4781
|
};
|
|
4782
|
+
scroller.refresh(false);
|
|
4740
4783
|
scroller.scrollTo(params);
|
|
4741
4784
|
}
|
|
4742
4785
|
}
|
|
@@ -4771,8 +4814,10 @@ class NgVirtualListComponent {
|
|
|
4771
4814
|
$scrollTo = this._$scrollTo.asObservable();
|
|
4772
4815
|
_$scroll = new Subject();
|
|
4773
4816
|
$scroll = this._$scroll.asObservable();
|
|
4774
|
-
_$
|
|
4775
|
-
$
|
|
4817
|
+
_$fireUpdate = new Subject();
|
|
4818
|
+
$fireUpdate = this._$fireUpdate.asObservable();
|
|
4819
|
+
_$fireUpdateNextFrame = new Subject();
|
|
4820
|
+
$fireUpdateNextFrame = this._$fireUpdateNextFrame.asObservable();
|
|
4776
4821
|
_onTrackBoxResetHandler = (v) => {
|
|
4777
4822
|
if (v && this._scrollerComponent()?.scrollable) {
|
|
4778
4823
|
this._$isResetedReachStart.next(true);
|
|
@@ -4790,9 +4835,7 @@ class NgVirtualListComponent {
|
|
|
4790
4835
|
}
|
|
4791
4836
|
}
|
|
4792
4837
|
};
|
|
4793
|
-
_$updateIteration = new BehaviorSubject$1(0);
|
|
4794
4838
|
_onPreparedHandler = (v) => {
|
|
4795
|
-
this._$updateIteration.next(0);
|
|
4796
4839
|
this._$prepared.next(v);
|
|
4797
4840
|
};
|
|
4798
4841
|
_destroyRef = inject(DestroyRef);
|
|
@@ -4806,6 +4849,9 @@ class NgVirtualListComponent {
|
|
|
4806
4849
|
this._service.initialize(this._trackBox);
|
|
4807
4850
|
this._service.itemToFocus = this.itemToFocus;
|
|
4808
4851
|
this._trackBox.displayComponents = this._displayComponents;
|
|
4852
|
+
this.$fireUpdateNextFrame.pipe(takeUntilDestroyed(), debounceTime(0), tap(e => {
|
|
4853
|
+
this._$fireUpdate.next(e);
|
|
4854
|
+
})).subscribe();
|
|
4809
4855
|
const $scrollToItem = this.$scrollTo.pipe(takeUntilDestroyed()), $mouseDown = fromEvent(this._elementRef.nativeElement, MOUSE_DOWN).pipe(takeUntilDestroyed()), $touchStart = fromEvent(this._elementRef.nativeElement, TOUCH_START).pipe(takeUntilDestroyed());
|
|
4810
4856
|
fromEvent(document, KEY_DOWN).pipe(takeUntilDestroyed(), switchMap$1(e => {
|
|
4811
4857
|
return fromEvent(this._elementRef.nativeElement, FOCUS).pipe(takeUntilDestroyed(this._destroyRef), delay(0), takeUntil$1($scrollToItem), takeUntil$1($mouseDown), takeUntil$1($touchStart), tap(e => {
|
|
@@ -4833,24 +4879,28 @@ class NgVirtualListComponent {
|
|
|
4833
4879
|
this._service.clickDistance = dist;
|
|
4834
4880
|
});
|
|
4835
4881
|
let prepared = false, readyToStart = false, isUserScrolling = false;
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
const isVerrtical = this._isVertical, actualScrollSize = isVerrtical ? (scroller?.actualScrollHeight ?? 0) : (scroller?.actualScrollWidth ?? 0), params = {
|
|
4843
|
-
[isVerrtical ? TOP_PROP_NAME : LEFT_PROP_NAME]: actualScrollSize,
|
|
4844
|
-
blending: false, fireUpdate: true, userAction: false, behavior: BEHAVIOR_INSTANT,
|
|
4845
|
-
};
|
|
4846
|
-
scroller.stopScrolling();
|
|
4847
|
-
scroller.scrollTo(params);
|
|
4848
|
-
this._service.update();
|
|
4882
|
+
let prevScrollStateVersion = EMPTY_SCROLL_STATE_VERSION, updateIterations = 0;
|
|
4883
|
+
const $updateComplete = this.$update.pipe(takeUntilDestroyed(), debounceTime(0), switchMap$1((v) => {
|
|
4884
|
+
if (((prevScrollStateVersion === EMPTY_SCROLL_STATE_VERSION) || (prevScrollStateVersion !== v)) &&
|
|
4885
|
+
(updateIterations < MIN_PREPARE_ITERATIONS)) {
|
|
4886
|
+
if (v !== EMPTY_SCROLL_STATE_VERSION) {
|
|
4887
|
+
prevScrollStateVersion = v;
|
|
4849
4888
|
}
|
|
4889
|
+
this._trackBox.isScrollEnd = true;
|
|
4890
|
+
this._$fireUpdateNextFrame.next();
|
|
4850
4891
|
return of(false);
|
|
4851
4892
|
}
|
|
4893
|
+
if (prevScrollStateVersion === v) {
|
|
4894
|
+
this._trackBox.isScrollEnd = true;
|
|
4895
|
+
if (updateIterations < MIN_PREPARE_ITERATIONS) {
|
|
4896
|
+
updateIterations++;
|
|
4897
|
+
this._$fireUpdateNextFrame.next();
|
|
4898
|
+
return of(false);
|
|
4899
|
+
}
|
|
4900
|
+
}
|
|
4901
|
+
prevScrollStateVersion = v;
|
|
4852
4902
|
return of(true);
|
|
4853
|
-
}), debounceTime(
|
|
4903
|
+
}), debounceTime(0), filter$1(v => !!v)), $items = toObservable(this.items).pipe(map(i => !i ? [] : i)), $dynamicSize = toObservable(this.dynamicSize);
|
|
4854
4904
|
const $snapScrollToBottom = toObservable(this.snapScrollToBottom), $waitForPreparation = toObservable(this.waitForPreparation);
|
|
4855
4905
|
combineLatest([$dynamicSize, $snapScrollToBottom, $waitForPreparation]).pipe(takeUntilDestroyed(), switchMap$1(([dynamicSize, snapScrollToBottom, waitForPreparation]) => {
|
|
4856
4906
|
if (!dynamicSize || !snapScrollToBottom || !waitForPreparation) {
|
|
@@ -4865,7 +4915,6 @@ class NgVirtualListComponent {
|
|
|
4865
4915
|
return of(false);
|
|
4866
4916
|
}
|
|
4867
4917
|
if (!!dynamicSize && !!snapScrollToBottom && !!waitForPreparation) {
|
|
4868
|
-
this._$updateIteration.next(0);
|
|
4869
4918
|
return this.$prepared.pipe(takeUntilDestroyed(this._destroyRef), distinctUntilChanged(), switchMap$1(v => {
|
|
4870
4919
|
if (!v) {
|
|
4871
4920
|
this._$show.next(false);
|
|
@@ -4877,14 +4926,15 @@ class NgVirtualListComponent {
|
|
|
4877
4926
|
scrollerComponent.stopScrolling();
|
|
4878
4927
|
}
|
|
4879
4928
|
this.classes.set({ prepared: v, [READY_TO_START]: false, [WAIT_FOR_PREPARATION]: false });
|
|
4880
|
-
this._$updateIteration.next(0);
|
|
4881
4929
|
this._service.update(true);
|
|
4882
4930
|
return of(false);
|
|
4883
4931
|
}
|
|
4884
4932
|
return of(true).pipe(takeUntilDestroyed(this._destroyRef), switchMap$1(v => {
|
|
4885
4933
|
const waitForPreparation = this.waitForPreparation();
|
|
4886
4934
|
if (waitForPreparation) {
|
|
4887
|
-
|
|
4935
|
+
prevScrollStateVersion = EMPTY_SCROLL_STATE_VERSION;
|
|
4936
|
+
updateIterations = 0;
|
|
4937
|
+
return $updateComplete.pipe(takeUntilDestroyed(this._destroyRef), take(1), tap(() => {
|
|
4888
4938
|
prepared = readyToStart = true;
|
|
4889
4939
|
const waitForPreparation = this.waitForPreparation(), scrollerComponent = this._scrollerComponent();
|
|
4890
4940
|
if (scrollerComponent) {
|
|
@@ -5063,9 +5113,8 @@ class NgVirtualListComponent {
|
|
|
5063
5113
|
const { snapScrollToBottom, bounds, listBounds, scrollEndOffset, items, itemConfigMap, scrollSize, itemSize, bufferSize, maxBufferSize, snap, isVertical, dynamicSize, enabledBufferOptimization, cacheVersion, } = params;
|
|
5064
5114
|
const scroller = this._scrollerComponent();
|
|
5065
5115
|
if (scroller) {
|
|
5066
|
-
let actualScrollSize =
|
|
5067
|
-
(isVertical ? scroller.
|
|
5068
|
-
(isVertical ? scroller.actualScrollTop ?? 0 : scroller.actualScrollLeft ?? 0), totalSize = 0, displayItems;
|
|
5116
|
+
let actualScrollSize = !prepared && snapScrollToBottom ? (isVertical ? scroller.scrollHeight ?? 0 : scroller.scrollWidth ?? 0) :
|
|
5117
|
+
(isVertical ? scroller.scrollTop ?? 0 : scroller.scrollLeft ?? 0), totalSize = 0, displayItems;
|
|
5069
5118
|
const { width, height, x, y } = bounds, viewportSize = (isVertical ? height : width);
|
|
5070
5119
|
let scrollLength = Math.round(this._totalSize()) ?? 0, actualScrollLength = Math.round(scrollLength === 0 ? 0 : scrollLength > viewportSize ? scrollLength - viewportSize : scrollLength), roundedMaxPosition = Math.round(actualScrollLength), scrollPosition = Math.round(actualScrollSize);
|
|
5071
5120
|
const opts = {
|
|
@@ -5102,7 +5151,8 @@ class NgVirtualListComponent {
|
|
|
5102
5151
|
this._isScrollFinished.set(scrollPosition >= roundedMaxPosition);
|
|
5103
5152
|
}
|
|
5104
5153
|
}
|
|
5105
|
-
actualScrollSize = (isVertical ? scroller.
|
|
5154
|
+
actualScrollSize = !prepared && snapScrollToBottom ? (isVertical ? scroller.scrollHeight ?? 0 : scroller.scrollWidth ?? 0) :
|
|
5155
|
+
(isVertical ? scroller.scrollTop ?? 0 : scroller.scrollLeft ?? 0);
|
|
5106
5156
|
const delta = this._trackBox.delta, roundedActualScrollSize = Math.round(actualScrollSize), scrollPositionAfterUpdate = actualScrollSize + delta, roundedScrollPositionAfterUpdate = Math.round(scrollPositionAfterUpdate), roundedMaxPositionAfterUpdate = Math.round(totalSize - viewportSize);
|
|
5107
5157
|
if (this._isSnappingMethodAdvanced) {
|
|
5108
5158
|
this.updateRegularRenderer();
|
|
@@ -5118,12 +5168,14 @@ class NgVirtualListComponent {
|
|
|
5118
5168
|
}
|
|
5119
5169
|
this._trackBox.isScrollEnd = true;
|
|
5120
5170
|
if (roundedMaxPositionAfterUpdate > 0) {
|
|
5121
|
-
const
|
|
5171
|
+
const params = {
|
|
5122
5172
|
[isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: roundedMaxPositionAfterUpdate,
|
|
5123
|
-
fireUpdate:
|
|
5173
|
+
fireUpdate: false, behavior: BEHAVIOR_INSTANT,
|
|
5124
5174
|
blending: false, duration: this.animationParams().scrollToItem,
|
|
5125
5175
|
};
|
|
5126
5176
|
scroller?.scrollTo?.(params);
|
|
5177
|
+
this._$update.next(getScrollStateVersion(this._isVertical ? scroller.scrollTop : scroller.scrollLeft, cacheVersion));
|
|
5178
|
+
return;
|
|
5127
5179
|
}
|
|
5128
5180
|
}
|
|
5129
5181
|
else if (roundedActualScrollSize !== roundedScrollPositionAfterUpdate && scrollPositionAfterUpdate > 0) {
|
|
@@ -5135,18 +5187,20 @@ class NgVirtualListComponent {
|
|
|
5135
5187
|
if (this._scrollSize() !== scrollPositionAfterUpdate) {
|
|
5136
5188
|
const params = {
|
|
5137
5189
|
[isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: scrollPositionAfterUpdate, blending: prepared && readyToStart,
|
|
5138
|
-
fireUpdate:
|
|
5190
|
+
fireUpdate: false, behavior: BEHAVIOR_INSTANT, duration: this.animationParams().scrollToItem,
|
|
5139
5191
|
};
|
|
5140
5192
|
scroller.scrollTo(params);
|
|
5193
|
+
this._$update.next(getScrollStateVersion(this._isVertical ? scroller.scrollTop : scroller.scrollLeft, cacheVersion));
|
|
5194
|
+
return;
|
|
5141
5195
|
}
|
|
5142
5196
|
}
|
|
5143
5197
|
if (!prepared && !readyToStart) {
|
|
5144
|
-
this._$update.next();
|
|
5198
|
+
this._$update.next(getScrollStateVersion(this._isVertical ? scroller.scrollTop : scroller.scrollLeft, cacheVersion));
|
|
5145
5199
|
}
|
|
5146
5200
|
}
|
|
5147
5201
|
};
|
|
5148
5202
|
combineLatest([$snapScrollToBottom, $bounds, $listBounds, $scrollEndOffset, $actualItems, $itemConfigMap, $scrollSize, $itemSize,
|
|
5149
|
-
$bufferSize, $maxBufferSize, $snap, $isVertical, $dynamicSize, $enabledBufferOptimization, $cacheVersion, this.$
|
|
5203
|
+
$bufferSize, $maxBufferSize, $snap, $isVertical, $dynamicSize, $enabledBufferOptimization, $cacheVersion, this.$fireUpdate,
|
|
5150
5204
|
]).pipe(takeUntilDestroyed(), distinctUntilChanged(), tap(([snapScrollToBottom, bounds, listBounds, scrollEndOffset, items, itemConfigMap, scrollSize, itemSize, bufferSize, maxBufferSize, snap, isVertical, dynamicSize, enabledBufferOptimization, cacheVersion,]) => {
|
|
5151
5205
|
update({
|
|
5152
5206
|
snapScrollToBottom, bounds, listBounds, scrollEndOffset, items, itemConfigMap, scrollSize, itemSize,
|
|
@@ -5223,7 +5277,7 @@ class NgVirtualListComponent {
|
|
|
5223
5277
|
this.onScroll.emit(event);
|
|
5224
5278
|
this._$scroll.next(event);
|
|
5225
5279
|
if (userAction && !this.dynamicSize()) {
|
|
5226
|
-
this._$
|
|
5280
|
+
this._$fireUpdate.next(event);
|
|
5227
5281
|
}
|
|
5228
5282
|
}
|
|
5229
5283
|
})).subscribe();
|
|
@@ -5245,7 +5299,7 @@ class NgVirtualListComponent {
|
|
|
5245
5299
|
this.onScrollEnd.emit(event);
|
|
5246
5300
|
this._$scroll.next(event);
|
|
5247
5301
|
if (userAction && !this.dynamicSize()) {
|
|
5248
|
-
this._$
|
|
5302
|
+
this._$fireUpdate.next(event);
|
|
5249
5303
|
}
|
|
5250
5304
|
}
|
|
5251
5305
|
})).subscribe();
|
|
@@ -5413,7 +5467,7 @@ class NgVirtualListComponent {
|
|
|
5413
5467
|
$collapsedIds.pipe(takeUntilDestroyed(), distinctUntilChanged(), tap(v => {
|
|
5414
5468
|
this._service.setCollapsedIds(v);
|
|
5415
5469
|
})).subscribe();
|
|
5416
|
-
this._$
|
|
5470
|
+
this._$fireUpdate.next({
|
|
5417
5471
|
scrollSize: 0,
|
|
5418
5472
|
scrollWeight: 0,
|
|
5419
5473
|
size: 0,
|