@@ -6,13 +6,17 @@ import { isTabNext } from "@ui5/webcomponents-base/dist/events/PseudoEvents.js";
6
6
import NavigationMode from "@ui5/webcomponents-base/dist/types/NavigationMode.js" ;
7
7
import ListMode from "./types/ListMode.js" ;
8
8
import ListSeparators from "./types/ListSeparators.js" ;
9
+ import BusyIndicator from "./BusyIndicator.js" ;
9
10
10
11
// Template
11
12
import ListTemplate from "./generated/templates/ListTemplate.lit.js" ;
12
13
13
14
// Styles
14
15
import listCss from "./generated/themes/List.css.js" ;
15
16
17
+ const BUSYINDICATOR_HEIGHT = 48 ; // px
18
+ const INFINITE_SCROLL_DEBOUNCE_RATE = 250 ; // ms
19
+
16
20
/**
17
21
* @public
18
22
*/
@@ -128,6 +132,33 @@ const metadata = {
128
132
type : ListSeparators ,
129
133
defaultValue : ListSeparators . All ,
130
134
} ,
135
+
136
+ /**
137
+ * Defines if the component would fire the <code>loadMore</code> event,
138
+ * when the user scrolls to the bottom of the list and help achieving an "infinite scroll" effect
139
+ * by adding new items each time.
140
+ *
141
+ * @type {boolean }
142
+ * @defaultvalue false
143
+ * @public
144
+ * @since 1.0.0-rc.6
145
+ */
146
+ infiniteScroll : {
147
+ type : Boolean ,
148
+ } ,
149
+
150
+ /**
151
+ * Defines if the component would display a loading indicator at the bottom of the list.
152
+ * It's especially useful, when combined with <code>infiniteScroll</code>.
153
+ *
154
+ * @type {boolean }
155
+ * @defaultvalue false
156
+ * @public
157
+ * @since 1.0.0-rc.6
158
+ */
159
+ busy : {
160
+ type : Boolean ,
161
+ } ,
131
162
} ,
132
163
events : /** @lends sap.ui.webcomponents.main.List.prototype */ {
133
164
@@ -176,6 +207,17 @@ const metadata = {
176
207
selectionComponentPressed : { type : Boolean } , // protected, indicates if the user used the selection components to change the selection
177
208
} ,
178
209
} ,
210
+
211
+ /**
212
+ * Fired when the user scrolls to the bottom of the list.
213
+ * <br>
214
+ * <b>Note:</b> The event is fired when the <code>infiniteScroll</code> property is enabled.
215
+ *
216
+ * @event
217
+ * @public
218
+ * @since 1.0.0-rc.6
219
+ */
220
+ loadMore : { } ,
179
221
} ,
180
222
} ;
181
223
@@ -254,6 +296,18 @@ class List extends UI5Element {
254
296
this . addEventListener ( "ui5-_selectionRequested" , this . onSelectionRequested . bind ( this ) ) ;
255
297
}
256
298
299
+ get shouldRenderH1 ( ) {
300
+ return ! this . header . length && this . headerText ;
301
+ }
302
+
303
+ get showNoDataText ( ) {
304
+ return this . items . length === 0 && this . noDataText ;
305
+ }
306
+
307
+ get showBusy ( ) {
308
+ return this . busy || this . infiniteScroll ;
309
+ }
310
+
257
311
onBeforeRendering ( ) {
258
312
this . prepareListItems ( ) ;
259
313
}
@@ -391,6 +445,13 @@ class List extends UI5Element {
391
445
}
392
446
}
393
447
448
+ _onScroll ( event ) {
449
+ if ( ! this . infiniteScroll ) {
450
+ return ;
451
+ }
452
+ this . debounce ( this . loadMore . bind ( this , event . target ) , INFINITE_SCROLL_DEBOUNCE_RATE ) ;
453
+ }
454
+
394
455
_onfocusin ( event ) {
395
456
// If the focusin event does not origin from one of the 'triggers' - ignore it.
396
457
if ( ! this . isForwardElement ( this . getNormalizedTarget ( event . target ) ) ) {
@@ -555,12 +616,32 @@ class List extends UI5Element {
555
616
return focused ;
556
617
}
557
618
558
- get shouldRenderH1 ( ) {
559
- return ! this . header . length && this . headerText ;
619
+ loadMore ( el ) {
620
+ const scrollTop = el . scrollTop ;
621
+ const height = el . offsetHeight ;
622
+ const scrollHeight = el . scrollHeight ;
623
+
624
+ if ( this . previousScrollPosition > scrollTop ) { // skip scrolling upwards
625
+ this . previousScrollPosition = scrollTop ;
626
+ return ;
627
+ }
628
+ this . previousScrollPosition = scrollTop ;
629
+
630
+ if ( scrollHeight - BUSYINDICATOR_HEIGHT <= height + scrollTop ) {
631
+ this . fireEvent ( "loadMore" ) ;
632
+ }
560
633
}
561
634
562
- get showNoDataText ( ) {
563
- return this . items . length === 0 && this . noDataText ;
635
+ debounce ( fn , delay ) {
636
+ clearTimeout ( this . debounceInterval ) ;
637
+ this . debounceInterval = setTimeout ( ( ) => {
638
+ this . debounceInterval = null ;
639
+ fn ( ) ;
640
+ } , delay ) ;
641
+ }
642
+
643
+ static async onDefine ( ) {
644
+ await BusyIndicator . define ( ) ;
564
645
}
565
646
}
566
647
0 commit comments