UNPKG

91.4 kBJavaScriptView Raw
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/cdk/coercion'), require('@angular/core'), require('rxjs'), require('rxjs/operators'), require('@angular/cdk/platform'), require('@angular/common'), require('@angular/cdk/bidi'), require('@angular/cdk/collections')) :
3 typeof define === 'function' && define.amd ? define('@angular/cdk/scrolling', ['exports', '@angular/cdk/coercion', '@angular/core', 'rxjs', 'rxjs/operators', '@angular/cdk/platform', '@angular/common', '@angular/cdk/bidi', '@angular/cdk/collections'], factory) :
4 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.ng = global.ng || {}, global.ng.cdk = global.ng.cdk || {}, global.ng.cdk.scrolling = {}), global.ng.cdk.coercion, global.ng.core, global.rxjs, global.rxjs.operators, global.ng.cdk.platform, global.ng.common, global.ng.cdk.bidi, global.ng.cdk.collections));
5}(this, (function (exports, coercion, i0, rxjs, operators, i1, i2, bidi, collections) { 'use strict';
6
7 function _interopNamespace(e) {
8 if (e && e.__esModule) return e;
9 var n = Object.create(null);
10 if (e) {
11 Object.keys(e).forEach(function (k) {
12 if (k !== 'default') {
13 var d = Object.getOwnPropertyDescriptor(e, k);
14 Object.defineProperty(n, k, d.get ? d : {
15 enumerable: true,
16 get: function () {
17 return e[k];
18 }
19 });
20 }
21 });
22 }
23 n['default'] = e;
24 return Object.freeze(n);
25 }
26
27 var i0__namespace = /*#__PURE__*/_interopNamespace(i0);
28 var i1__namespace = /*#__PURE__*/_interopNamespace(i1);
29 var i2__namespace = /*#__PURE__*/_interopNamespace(i2);
30
31 /**
32 * @license
33 * Copyright Google LLC All Rights Reserved.
34 *
35 * Use of this source code is governed by an MIT-style license that can be
36 * found in the LICENSE file at https://angular.io/license
37 */
38 /** The injection token used to specify the virtual scrolling strategy. */
39 var VIRTUAL_SCROLL_STRATEGY = new i0.InjectionToken('VIRTUAL_SCROLL_STRATEGY');
40
41 /**
42 * @license
43 * Copyright Google LLC All Rights Reserved.
44 *
45 * Use of this source code is governed by an MIT-style license that can be
46 * found in the LICENSE file at https://angular.io/license
47 */
48 /** Virtual scrolling strategy for lists with items of known fixed size. */
49 var FixedSizeVirtualScrollStrategy = /** @class */ (function () {
50 /**
51 * @param itemSize The size of the items in the virtually scrolling list.
52 * @param minBufferPx The minimum amount of buffer (in pixels) before needing to render more
53 * @param maxBufferPx The amount of buffer (in pixels) to render when rendering more.
54 */
55 function FixedSizeVirtualScrollStrategy(itemSize, minBufferPx, maxBufferPx) {
56 this._scrolledIndexChange = new rxjs.Subject();
57 /** @docs-private Implemented as part of VirtualScrollStrategy. */
58 this.scrolledIndexChange = this._scrolledIndexChange.pipe(operators.distinctUntilChanged());
59 /** The attached viewport. */
60 this._viewport = null;
61 this._itemSize = itemSize;
62 this._minBufferPx = minBufferPx;
63 this._maxBufferPx = maxBufferPx;
64 }
65 /**
66 * Attaches this scroll strategy to a viewport.
67 * @param viewport The viewport to attach this strategy to.
68 */
69 FixedSizeVirtualScrollStrategy.prototype.attach = function (viewport) {
70 this._viewport = viewport;
71 this._updateTotalContentSize();
72 this._updateRenderedRange();
73 };
74 /** Detaches this scroll strategy from the currently attached viewport. */
75 FixedSizeVirtualScrollStrategy.prototype.detach = function () {
76 this._scrolledIndexChange.complete();
77 this._viewport = null;
78 };
79 /**
80 * Update the item size and buffer size.
81 * @param itemSize The size of the items in the virtually scrolling list.
82 * @param minBufferPx The minimum amount of buffer (in pixels) before needing to render more
83 * @param maxBufferPx The amount of buffer (in pixels) to render when rendering more.
84 */
85 FixedSizeVirtualScrollStrategy.prototype.updateItemAndBufferSize = function (itemSize, minBufferPx, maxBufferPx) {
86 if (maxBufferPx < minBufferPx && (typeof ngDevMode === 'undefined' || ngDevMode)) {
87 throw Error('CDK virtual scroll: maxBufferPx must be greater than or equal to minBufferPx');
88 }
89 this._itemSize = itemSize;
90 this._minBufferPx = minBufferPx;
91 this._maxBufferPx = maxBufferPx;
92 this._updateTotalContentSize();
93 this._updateRenderedRange();
94 };
95 /** @docs-private Implemented as part of VirtualScrollStrategy. */
96 FixedSizeVirtualScrollStrategy.prototype.onContentScrolled = function () {
97 this._updateRenderedRange();
98 };
99 /** @docs-private Implemented as part of VirtualScrollStrategy. */
100 FixedSizeVirtualScrollStrategy.prototype.onDataLengthChanged = function () {
101 this._updateTotalContentSize();
102 this._updateRenderedRange();
103 };
104 /** @docs-private Implemented as part of VirtualScrollStrategy. */
105 FixedSizeVirtualScrollStrategy.prototype.onContentRendered = function () { };
106 /** @docs-private Implemented as part of VirtualScrollStrategy. */
107 FixedSizeVirtualScrollStrategy.prototype.onRenderedOffsetChanged = function () { };
108 /**
109 * Scroll to the offset for the given index.
110 * @param index The index of the element to scroll to.
111 * @param behavior The ScrollBehavior to use when scrolling.
112 */
113 FixedSizeVirtualScrollStrategy.prototype.scrollToIndex = function (index, behavior) {
114 if (this._viewport) {
115 this._viewport.scrollToOffset(index * this._itemSize, behavior);
116 }
117 };
118 /** Update the viewport's total content size. */
119 FixedSizeVirtualScrollStrategy.prototype._updateTotalContentSize = function () {
120 if (!this._viewport) {
121 return;
122 }
123 this._viewport.setTotalContentSize(this._viewport.getDataLength() * this._itemSize);
124 };
125 /** Update the viewport's rendered range. */
126 FixedSizeVirtualScrollStrategy.prototype._updateRenderedRange = function () {
127 if (!this._viewport) {
128 return;
129 }
130 var renderedRange = this._viewport.getRenderedRange();
131 var newRange = { start: renderedRange.start, end: renderedRange.end };
132 var viewportSize = this._viewport.getViewportSize();
133 var dataLength = this._viewport.getDataLength();
134 var scrollOffset = this._viewport.measureScrollOffset();
135 // Prevent NaN as result when dividing by zero.
136 var firstVisibleIndex = (this._itemSize > 0) ? scrollOffset / this._itemSize : 0;
137 // If user scrolls to the bottom of the list and data changes to a smaller list
138 if (newRange.end > dataLength) {
139 // We have to recalculate the first visible index based on new data length and viewport size.
140 var maxVisibleItems = Math.ceil(viewportSize / this._itemSize);
141 var newVisibleIndex = Math.max(0, Math.min(firstVisibleIndex, dataLength - maxVisibleItems));
142 // If first visible index changed we must update scroll offset to handle start/end buffers
143 // Current range must also be adjusted to cover the new position (bottom of new list).
144 if (firstVisibleIndex != newVisibleIndex) {
145 firstVisibleIndex = newVisibleIndex;
146 scrollOffset = newVisibleIndex * this._itemSize;
147 newRange.start = Math.floor(firstVisibleIndex);
148 }
149 newRange.end = Math.max(0, Math.min(dataLength, newRange.start + maxVisibleItems));
150 }
151 var startBuffer = scrollOffset - newRange.start * this._itemSize;
152 if (startBuffer < this._minBufferPx && newRange.start != 0) {
153 var expandStart = Math.ceil((this._maxBufferPx - startBuffer) / this._itemSize);
154 newRange.start = Math.max(0, newRange.start - expandStart);
155 newRange.end = Math.min(dataLength, Math.ceil(firstVisibleIndex + (viewportSize + this._minBufferPx) / this._itemSize));
156 }
157 else {
158 var endBuffer = newRange.end * this._itemSize - (scrollOffset + viewportSize);
159 if (endBuffer < this._minBufferPx && newRange.end != dataLength) {
160 var expandEnd = Math.ceil((this._maxBufferPx - endBuffer) / this._itemSize);
161 if (expandEnd > 0) {
162 newRange.end = Math.min(dataLength, newRange.end + expandEnd);
163 newRange.start = Math.max(0, Math.floor(firstVisibleIndex - this._minBufferPx / this._itemSize));
164 }
165 }
166 }
167 this._viewport.setRenderedRange(newRange);
168 this._viewport.setRenderedContentOffset(this._itemSize * newRange.start);
169 this._scrolledIndexChange.next(Math.floor(firstVisibleIndex));
170 };
171 return FixedSizeVirtualScrollStrategy;
172 }());
173 /**
174 * Provider factory for `FixedSizeVirtualScrollStrategy` that simply extracts the already created
175 * `FixedSizeVirtualScrollStrategy` from the given directive.
176 * @param fixedSizeDir The instance of `CdkFixedSizeVirtualScroll` to extract the
177 * `FixedSizeVirtualScrollStrategy` from.
178 */
179 function _fixedSizeVirtualScrollStrategyFactory(fixedSizeDir) {
180 return fixedSizeDir._scrollStrategy;
181 }
182 /** A virtual scroll strategy that supports fixed-size items. */
183 var CdkFixedSizeVirtualScroll = /** @class */ (function () {
184 function CdkFixedSizeVirtualScroll() {
185 this._itemSize = 20;
186 this._minBufferPx = 100;
187 this._maxBufferPx = 200;
188 /** The scroll strategy used by this directive. */
189 this._scrollStrategy = new FixedSizeVirtualScrollStrategy(this.itemSize, this.minBufferPx, this.maxBufferPx);
190 }
191 Object.defineProperty(CdkFixedSizeVirtualScroll.prototype, "itemSize", {
192 /** The size of the items in the list (in pixels). */
193 get: function () { return this._itemSize; },
194 set: function (value) { this._itemSize = coercion.coerceNumberProperty(value); },
195 enumerable: false,
196 configurable: true
197 });
198 Object.defineProperty(CdkFixedSizeVirtualScroll.prototype, "minBufferPx", {
199 /**
200 * The minimum amount of buffer rendered beyond the viewport (in pixels).
201 * If the amount of buffer dips below this number, more items will be rendered. Defaults to 100px.
202 */
203 get: function () { return this._minBufferPx; },
204 set: function (value) { this._minBufferPx = coercion.coerceNumberProperty(value); },
205 enumerable: false,
206 configurable: true
207 });
208 Object.defineProperty(CdkFixedSizeVirtualScroll.prototype, "maxBufferPx", {
209 /**
210 * The number of pixels worth of buffer to render for when rendering new items. Defaults to 200px.
211 */
212 get: function () { return this._maxBufferPx; },
213 set: function (value) { this._maxBufferPx = coercion.coerceNumberProperty(value); },
214 enumerable: false,
215 configurable: true
216 });
217 CdkFixedSizeVirtualScroll.prototype.ngOnChanges = function () {
218 this._scrollStrategy.updateItemAndBufferSize(this.itemSize, this.minBufferPx, this.maxBufferPx);
219 };
220 return CdkFixedSizeVirtualScroll;
221 }());
222 CdkFixedSizeVirtualScroll.decorators = [
223 { type: i0.Directive, args: [{
224 selector: 'cdk-virtual-scroll-viewport[itemSize]',
225 providers: [{
226 provide: VIRTUAL_SCROLL_STRATEGY,
227 useFactory: _fixedSizeVirtualScrollStrategyFactory,
228 deps: [i0.forwardRef(function () { return CdkFixedSizeVirtualScroll; })],
229 }],
230 },] }
231 ];
232 CdkFixedSizeVirtualScroll.propDecorators = {
233 itemSize: [{ type: i0.Input }],
234 minBufferPx: [{ type: i0.Input }],
235 maxBufferPx: [{ type: i0.Input }]
236 };
237
238 /**
239 * @license
240 * Copyright Google LLC All Rights Reserved.
241 *
242 * Use of this source code is governed by an MIT-style license that can be
243 * found in the LICENSE file at https://angular.io/license
244 */
245 /** Time in ms to throttle the scrolling events by default. */
246 var DEFAULT_SCROLL_TIME = 20;
247 /**
248 * Service contained all registered Scrollable references and emits an event when any one of the
249 * Scrollable references emit a scrolled event.
250 */
251 var ScrollDispatcher = /** @class */ (function () {
252 function ScrollDispatcher(_ngZone, _platform, document) {
253 this._ngZone = _ngZone;
254 this._platform = _platform;
255 /** Subject for notifying that a registered scrollable reference element has been scrolled. */
256 this._scrolled = new rxjs.Subject();
257 /** Keeps track of the global `scroll` and `resize` subscriptions. */
258 this._globalSubscription = null;
259 /** Keeps track of the amount of subscriptions to `scrolled`. Used for cleaning up afterwards. */
260 this._scrolledCount = 0;
261 /**
262 * Map of all the scrollable references that are registered with the service and their
263 * scroll event subscriptions.
264 */
265 this.scrollContainers = new Map();
266 this._document = document;
267 }
268 /**
269 * Registers a scrollable instance with the service and listens for its scrolled events. When the
270 * scrollable is scrolled, the service emits the event to its scrolled observable.
271 * @param scrollable Scrollable instance to be registered.
272 */
273 ScrollDispatcher.prototype.register = function (scrollable) {
274 var _this = this;
275 if (!this.scrollContainers.has(scrollable)) {
276 this.scrollContainers.set(scrollable, scrollable.elementScrolled()
277 .subscribe(function () { return _this._scrolled.next(scrollable); }));
278 }
279 };
280 /**
281 * Deregisters a Scrollable reference and unsubscribes from its scroll event observable.
282 * @param scrollable Scrollable instance to be deregistered.
283 */
284 ScrollDispatcher.prototype.deregister = function (scrollable) {
285 var scrollableReference = this.scrollContainers.get(scrollable);
286 if (scrollableReference) {
287 scrollableReference.unsubscribe();
288 this.scrollContainers.delete(scrollable);
289 }
290 };
291 /**
292 * Returns an observable that emits an event whenever any of the registered Scrollable
293 * references (or window, document, or body) fire a scrolled event. Can provide a time in ms
294 * to override the default "throttle" time.
295 *
296 * **Note:** in order to avoid hitting change detection for every scroll event,
297 * all of the events emitted from this stream will be run outside the Angular zone.
298 * If you need to update any data bindings as a result of a scroll event, you have
299 * to run the callback using `NgZone.run`.
300 */
301 ScrollDispatcher.prototype.scrolled = function (auditTimeInMs) {
302 var _this = this;
303 if (auditTimeInMs === void 0) { auditTimeInMs = DEFAULT_SCROLL_TIME; }
304 if (!this._platform.isBrowser) {
305 return rxjs.of();
306 }
307 return new rxjs.Observable(function (observer) {
308 if (!_this._globalSubscription) {
309 _this._addGlobalListener();
310 }
311 // In the case of a 0ms delay, use an observable without auditTime
312 // since it does add a perceptible delay in processing overhead.
313 var subscription = auditTimeInMs > 0 ?
314 _this._scrolled.pipe(operators.auditTime(auditTimeInMs)).subscribe(observer) :
315 _this._scrolled.subscribe(observer);
316 _this._scrolledCount++;
317 return function () {
318 subscription.unsubscribe();
319 _this._scrolledCount--;
320 if (!_this._scrolledCount) {
321 _this._removeGlobalListener();
322 }
323 };
324 });
325 };
326 ScrollDispatcher.prototype.ngOnDestroy = function () {
327 var _this = this;
328 this._removeGlobalListener();
329 this.scrollContainers.forEach(function (_, container) { return _this.deregister(container); });
330 this._scrolled.complete();
331 };
332 /**
333 * Returns an observable that emits whenever any of the
334 * scrollable ancestors of an element are scrolled.
335 * @param elementOrElementRef Element whose ancestors to listen for.
336 * @param auditTimeInMs Time to throttle the scroll events.
337 */
338 ScrollDispatcher.prototype.ancestorScrolled = function (elementOrElementRef, auditTimeInMs) {
339 var ancestors = this.getAncestorScrollContainers(elementOrElementRef);
340 return this.scrolled(auditTimeInMs).pipe(operators.filter(function (target) {
341 return !target || ancestors.indexOf(target) > -1;
342 }));
343 };
344 /** Returns all registered Scrollables that contain the provided element. */
345 ScrollDispatcher.prototype.getAncestorScrollContainers = function (elementOrElementRef) {
346 var _this = this;
347 var scrollingContainers = [];
348 this.scrollContainers.forEach(function (_subscription, scrollable) {
349 if (_this._scrollableContainsElement(scrollable, elementOrElementRef)) {
350 scrollingContainers.push(scrollable);
351 }
352 });
353 return scrollingContainers;
354 };
355 /** Use defaultView of injected document if available or fallback to global window reference */
356 ScrollDispatcher.prototype._getWindow = function () {
357 return this._document.defaultView || window;
358 };
359 /** Returns true if the element is contained within the provided Scrollable. */
360 ScrollDispatcher.prototype._scrollableContainsElement = function (scrollable, elementOrElementRef) {
361 var element = coercion.coerceElement(elementOrElementRef);
362 var scrollableElement = scrollable.getElementRef().nativeElement;
363 // Traverse through the element parents until we reach null, checking if any of the elements
364 // are the scrollable's element.
365 do {
366 if (element == scrollableElement) {
367 return true;
368 }
369 } while (element = element.parentElement);
370 return false;
371 };
372 /** Sets up the global scroll listeners. */
373 ScrollDispatcher.prototype._addGlobalListener = function () {
374 var _this = this;
375 this._globalSubscription = this._ngZone.runOutsideAngular(function () {
376 var window = _this._getWindow();
377 return rxjs.fromEvent(window.document, 'scroll').subscribe(function () { return _this._scrolled.next(); });
378 });
379 };
380 /** Cleans up the global scroll listener. */
381 ScrollDispatcher.prototype._removeGlobalListener = function () {
382 if (this._globalSubscription) {
383 this._globalSubscription.unsubscribe();
384 this._globalSubscription = null;
385 }
386 };
387 return ScrollDispatcher;
388 }());
389 ScrollDispatcher.ɵprov = i0__namespace.ɵɵdefineInjectable({ factory: function ScrollDispatcher_Factory() { return new ScrollDispatcher(i0__namespace.ɵɵinject(i0__namespace.NgZone), i0__namespace.ɵɵinject(i1__namespace.Platform), i0__namespace.ɵɵinject(i2__namespace.DOCUMENT, 8)); }, token: ScrollDispatcher, providedIn: "root" });
390 ScrollDispatcher.decorators = [
391 { type: i0.Injectable, args: [{ providedIn: 'root' },] }
392 ];
393 ScrollDispatcher.ctorParameters = function () { return [
394 { type: i0.NgZone },
395 { type: i1.Platform },
396 { type: undefined, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [i2.DOCUMENT,] }] }
397 ]; };
398
399 /**
400 * @license
401 * Copyright Google LLC All Rights Reserved.
402 *
403 * Use of this source code is governed by an MIT-style license that can be
404 * found in the LICENSE file at https://angular.io/license
405 */
406 /**
407 * Sends an event when the directive's element is scrolled. Registers itself with the
408 * ScrollDispatcher service to include itself as part of its collection of scrolling events that it
409 * can be listened to through the service.
410 */
411 var CdkScrollable = /** @class */ (function () {
412 function CdkScrollable(elementRef, scrollDispatcher, ngZone, dir) {
413 var _this = this;
414 this.elementRef = elementRef;
415 this.scrollDispatcher = scrollDispatcher;
416 this.ngZone = ngZone;
417 this.dir = dir;
418 this._destroyed = new rxjs.Subject();
419 this._elementScrolled = new rxjs.Observable(function (observer) { return _this.ngZone.runOutsideAngular(function () { return rxjs.fromEvent(_this.elementRef.nativeElement, 'scroll').pipe(operators.takeUntil(_this._destroyed))
420 .subscribe(observer); }); });
421 }
422 CdkScrollable.prototype.ngOnInit = function () {
423 this.scrollDispatcher.register(this);
424 };
425 CdkScrollable.prototype.ngOnDestroy = function () {
426 this.scrollDispatcher.deregister(this);
427 this._destroyed.next();
428 this._destroyed.complete();
429 };
430 /** Returns observable that emits when a scroll event is fired on the host element. */
431 CdkScrollable.prototype.elementScrolled = function () {
432 return this._elementScrolled;
433 };
434 /** Gets the ElementRef for the viewport. */
435 CdkScrollable.prototype.getElementRef = function () {
436 return this.elementRef;
437 };
438 /**
439 * Scrolls to the specified offsets. This is a normalized version of the browser's native scrollTo
440 * method, since browsers are not consistent about what scrollLeft means in RTL. For this method
441 * left and right always refer to the left and right side of the scrolling container irrespective
442 * of the layout direction. start and end refer to left and right in an LTR context and vice-versa
443 * in an RTL context.
444 * @param options specified the offsets to scroll to.
445 */
446 CdkScrollable.prototype.scrollTo = function (options) {
447 var el = this.elementRef.nativeElement;
448 var isRtl = this.dir && this.dir.value == 'rtl';
449 // Rewrite start & end offsets as right or left offsets.
450 if (options.left == null) {
451 options.left = isRtl ? options.end : options.start;
452 }
453 if (options.right == null) {
454 options.right = isRtl ? options.start : options.end;
455 }
456 // Rewrite the bottom offset as a top offset.
457 if (options.bottom != null) {
458 options.top =
459 el.scrollHeight - el.clientHeight - options.bottom;
460 }
461 // Rewrite the right offset as a left offset.
462 if (isRtl && i1.getRtlScrollAxisType() != 0 /* NORMAL */) {
463 if (options.left != null) {
464 options.right =
465 el.scrollWidth - el.clientWidth - options.left;
466 }
467 if (i1.getRtlScrollAxisType() == 2 /* INVERTED */) {
468 options.left = options.right;
469 }
470 else if (i1.getRtlScrollAxisType() == 1 /* NEGATED */) {
471 options.left = options.right ? -options.right : options.right;
472 }
473 }
474 else {
475 if (options.right != null) {
476 options.left =
477 el.scrollWidth - el.clientWidth - options.right;
478 }
479 }
480 this._applyScrollToOptions(options);
481 };
482 CdkScrollable.prototype._applyScrollToOptions = function (options) {
483 var el = this.elementRef.nativeElement;
484 if (i1.supportsScrollBehavior()) {
485 el.scrollTo(options);
486 }
487 else {
488 if (options.top != null) {
489 el.scrollTop = options.top;
490 }
491 if (options.left != null) {
492 el.scrollLeft = options.left;
493 }
494 }
495 };
496 /**
497 * Measures the scroll offset relative to the specified edge of the viewport. This method can be
498 * used instead of directly checking scrollLeft or scrollTop, since browsers are not consistent
499 * about what scrollLeft means in RTL. The values returned by this method are normalized such that
500 * left and right always refer to the left and right side of the scrolling container irrespective
501 * of the layout direction. start and end refer to left and right in an LTR context and vice-versa
502 * in an RTL context.
503 * @param from The edge to measure from.
504 */
505 CdkScrollable.prototype.measureScrollOffset = function (from) {
506 var LEFT = 'left';
507 var RIGHT = 'right';
508 var el = this.elementRef.nativeElement;
509 if (from == 'top') {
510 return el.scrollTop;
511 }
512 if (from == 'bottom') {
513 return el.scrollHeight - el.clientHeight - el.scrollTop;
514 }
515 // Rewrite start & end as left or right offsets.
516 var isRtl = this.dir && this.dir.value == 'rtl';
517 if (from == 'start') {
518 from = isRtl ? RIGHT : LEFT;
519 }
520 else if (from == 'end') {
521 from = isRtl ? LEFT : RIGHT;
522 }
523 if (isRtl && i1.getRtlScrollAxisType() == 2 /* INVERTED */) {
524 // For INVERTED, scrollLeft is (scrollWidth - clientWidth) when scrolled all the way left and
525 // 0 when scrolled all the way right.
526 if (from == LEFT) {
527 return el.scrollWidth - el.clientWidth - el.scrollLeft;
528 }
529 else {
530 return el.scrollLeft;
531 }
532 }
533 else if (isRtl && i1.getRtlScrollAxisType() == 1 /* NEGATED */) {
534 // For NEGATED, scrollLeft is -(scrollWidth - clientWidth) when scrolled all the way left and
535 // 0 when scrolled all the way right.
536 if (from == LEFT) {
537 return el.scrollLeft + el.scrollWidth - el.clientWidth;
538 }
539 else {
540 return -el.scrollLeft;
541 }
542 }
543 else {
544 // For NORMAL, as well as non-RTL contexts, scrollLeft is 0 when scrolled all the way left and
545 // (scrollWidth - clientWidth) when scrolled all the way right.
546 if (from == LEFT) {
547 return el.scrollLeft;
548 }
549 else {
550 return el.scrollWidth - el.clientWidth - el.scrollLeft;
551 }
552 }
553 };
554 return CdkScrollable;
555 }());
556 CdkScrollable.decorators = [
557 { type: i0.Directive, args: [{
558 selector: '[cdk-scrollable], [cdkScrollable]'
559 },] }
560 ];
561 CdkScrollable.ctorParameters = function () { return [
562 { type: i0.ElementRef },
563 { type: ScrollDispatcher },
564 { type: i0.NgZone },
565 { type: bidi.Directionality, decorators: [{ type: i0.Optional }] }
566 ]; };
567
568 /*! *****************************************************************************
569 Copyright (c) Microsoft Corporation.
570
571 Permission to use, copy, modify, and/or distribute this software for any
572 purpose with or without fee is hereby granted.
573
574 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
575 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
576 AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
577 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
578 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
579 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
580 PERFORMANCE OF THIS SOFTWARE.
581 ***************************************************************************** */
582 /* global Reflect, Promise */
583 var extendStatics = function (d, b) {
584 extendStatics = Object.setPrototypeOf ||
585 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
586 function (d, b) { for (var p in b)
587 if (Object.prototype.hasOwnProperty.call(b, p))
588 d[p] = b[p]; };
589 return extendStatics(d, b);
590 };
591 function __extends(d, b) {
592 if (typeof b !== "function" && b !== null)
593 throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
594 extendStatics(d, b);
595 function __() { this.constructor = d; }
596 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
597 }
598 var __assign = function () {
599 __assign = Object.assign || function __assign(t) {
600 for (var s, i = 1, n = arguments.length; i < n; i++) {
601 s = arguments[i];
602 for (var p in s)
603 if (Object.prototype.hasOwnProperty.call(s, p))
604 t[p] = s[p];
605 }
606 return t;
607 };
608 return __assign.apply(this, arguments);
609 };
610 function __rest(s, e) {
611 var t = {};
612 for (var p in s)
613 if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
614 t[p] = s[p];
615 if (s != null && typeof Object.getOwnPropertySymbols === "function")
616 for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
617 if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
618 t[p[i]] = s[p[i]];
619 }
620 return t;
621 }
622 function __decorate(decorators, target, key, desc) {
623 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
624 if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
625 r = Reflect.decorate(decorators, target, key, desc);
626 else
627 for (var i = decorators.length - 1; i >= 0; i--)
628 if (d = decorators[i])
629 r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
630 return c > 3 && r && Object.defineProperty(target, key, r), r;
631 }
632 function __param(paramIndex, decorator) {
633 return function (target, key) { decorator(target, key, paramIndex); };
634 }
635 function __metadata(metadataKey, metadataValue) {
636 if (typeof Reflect === "object" && typeof Reflect.metadata === "function")
637 return Reflect.metadata(metadataKey, metadataValue);
638 }
639 function __awaiter(thisArg, _arguments, P, generator) {
640 function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
641 return new (P || (P = Promise))(function (resolve, reject) {
642 function fulfilled(value) { try {
643 step(generator.next(value));
644 }
645 catch (e) {
646 reject(e);
647 } }
648 function rejected(value) { try {
649 step(generator["throw"](value));
650 }
651 catch (e) {
652 reject(e);
653 } }
654 function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
655 step((generator = generator.apply(thisArg, _arguments || [])).next());
656 });
657 }
658 function __generator(thisArg, body) {
659 var _ = { label: 0, sent: function () { if (t[0] & 1)
660 throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
661 return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function () { return this; }), g;
662 function verb(n) { return function (v) { return step([n, v]); }; }
663 function step(op) {
664 if (f)
665 throw new TypeError("Generator is already executing.");
666 while (_)
667 try {
668 if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done)
669 return t;
670 if (y = 0, t)
671 op = [op[0] & 2, t.value];
672 switch (op[0]) {
673 case 0:
674 case 1:
675 t = op;
676 break;
677 case 4:
678 _.label++;
679 return { value: op[1], done: false };
680 case 5:
681 _.label++;
682 y = op[1];
683 op = [0];
684 continue;
685 case 7:
686 op = _.ops.pop();
687 _.trys.pop();
688 continue;
689 default:
690 if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
691 _ = 0;
692 continue;
693 }
694 if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) {
695 _.label = op[1];
696 break;
697 }
698 if (op[0] === 6 && _.label < t[1]) {
699 _.label = t[1];
700 t = op;
701 break;
702 }
703 if (t && _.label < t[2]) {
704 _.label = t[2];
705 _.ops.push(op);
706 break;
707 }
708 if (t[2])
709 _.ops.pop();
710 _.trys.pop();
711 continue;
712 }
713 op = body.call(thisArg, _);
714 }
715 catch (e) {
716 op = [6, e];
717 y = 0;
718 }
719 finally {
720 f = t = 0;
721 }
722 if (op[0] & 5)
723 throw op[1];
724 return { value: op[0] ? op[1] : void 0, done: true };
725 }
726 }
727 var __createBinding = Object.create ? (function (o, m, k, k2) {
728 if (k2 === undefined)
729 k2 = k;
730 Object.defineProperty(o, k2, { enumerable: true, get: function () { return m[k]; } });
731 }) : (function (o, m, k, k2) {
732 if (k2 === undefined)
733 k2 = k;
734 o[k2] = m[k];
735 });
736 function __exportStar(m, o) {
737 for (var p in m)
738 if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p))
739 __createBinding(o, m, p);
740 }
741 function __values(o) {
742 var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
743 if (m)
744 return m.call(o);
745 if (o && typeof o.length === "number")
746 return {
747 next: function () {
748 if (o && i >= o.length)
749 o = void 0;
750 return { value: o && o[i++], done: !o };
751 }
752 };
753 throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
754 }
755 function __read(o, n) {
756 var m = typeof Symbol === "function" && o[Symbol.iterator];
757 if (!m)
758 return o;
759 var i = m.call(o), r, ar = [], e;
760 try {
761 while ((n === void 0 || n-- > 0) && !(r = i.next()).done)
762 ar.push(r.value);
763 }
764 catch (error) {
765 e = { error: error };
766 }
767 finally {
768 try {
769 if (r && !r.done && (m = i["return"]))
770 m.call(i);
771 }
772 finally {
773 if (e)
774 throw e.error;
775 }
776 }
777 return ar;
778 }
779 /** @deprecated */
780 function __spread() {
781 for (var ar = [], i = 0; i < arguments.length; i++)
782 ar = ar.concat(__read(arguments[i]));
783 return ar;
784 }
785 /** @deprecated */
786 function __spreadArrays() {
787 for (var s = 0, i = 0, il = arguments.length; i < il; i++)
788 s += arguments[i].length;
789 for (var r = Array(s), k = 0, i = 0; i < il; i++)
790 for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
791 r[k] = a[j];
792 return r;
793 }
794 function __spreadArray(to, from, pack) {
795 if (pack || arguments.length === 2)
796 for (var i = 0, l = from.length, ar; i < l; i++) {
797 if (ar || !(i in from)) {
798 if (!ar)
799 ar = Array.prototype.slice.call(from, 0, i);
800 ar[i] = from[i];
801 }
802 }
803 return to.concat(ar || from);
804 }
805 function __await(v) {
806 return this instanceof __await ? (this.v = v, this) : new __await(v);
807 }
808 function __asyncGenerator(thisArg, _arguments, generator) {
809 if (!Symbol.asyncIterator)
810 throw new TypeError("Symbol.asyncIterator is not defined.");
811 var g = generator.apply(thisArg, _arguments || []), i, q = [];
812 return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
813 function verb(n) { if (g[n])
814 i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
815 function resume(n, v) { try {
816 step(g[n](v));
817 }
818 catch (e) {
819 settle(q[0][3], e);
820 } }
821 function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
822 function fulfill(value) { resume("next", value); }
823 function reject(value) { resume("throw", value); }
824 function settle(f, v) { if (f(v), q.shift(), q.length)
825 resume(q[0][0], q[0][1]); }
826 }
827 function __asyncDelegator(o) {
828 var i, p;
829 return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
830 function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; }
831 }
832 function __asyncValues(o) {
833 if (!Symbol.asyncIterator)
834 throw new TypeError("Symbol.asyncIterator is not defined.");
835 var m = o[Symbol.asyncIterator], i;
836 return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
837 function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
838 function settle(resolve, reject, d, v) { Promise.resolve(v).then(function (v) { resolve({ value: v, done: d }); }, reject); }
839 }
840 function __makeTemplateObject(cooked, raw) {
841 if (Object.defineProperty) {
842 Object.defineProperty(cooked, "raw", { value: raw });
843 }
844 else {
845 cooked.raw = raw;
846 }
847 return cooked;
848 }
849 ;
850 var __setModuleDefault = Object.create ? (function (o, v) {
851 Object.defineProperty(o, "default", { enumerable: true, value: v });
852 }) : function (o, v) {
853 o["default"] = v;
854 };
855 function __importStar(mod) {
856 if (mod && mod.__esModule)
857 return mod;
858 var result = {};
859 if (mod != null)
860 for (var k in mod)
861 if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k))
862 __createBinding(result, mod, k);
863 __setModuleDefault(result, mod);
864 return result;
865 }
866 function __importDefault(mod) {
867 return (mod && mod.__esModule) ? mod : { default: mod };
868 }
869 function __classPrivateFieldGet(receiver, state, kind, f) {
870 if (kind === "a" && !f)
871 throw new TypeError("Private accessor was defined without a getter");
872 if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
873 throw new TypeError("Cannot read private member from an object whose class did not declare it");
874 return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
875 }
876 function __classPrivateFieldSet(receiver, state, value, kind, f) {
877 if (kind === "m")
878 throw new TypeError("Private method is not writable");
879 if (kind === "a" && !f)
880 throw new TypeError("Private accessor was defined without a setter");
881 if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
882 throw new TypeError("Cannot write private member to an object whose class did not declare it");
883 return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
884 }
885
886 /**
887 * @license
888 * Copyright Google LLC All Rights Reserved.
889 *
890 * Use of this source code is governed by an MIT-style license that can be
891 * found in the LICENSE file at https://angular.io/license
892 */
893 /** Time in ms to throttle the resize events by default. */
894 var DEFAULT_RESIZE_TIME = 20;
895 /**
896 * Simple utility for getting the bounds of the browser viewport.
897 * @docs-private
898 */
899 var ViewportRuler = /** @class */ (function () {
900 function ViewportRuler(_platform, ngZone, document) {
901 var _this = this;
902 this._platform = _platform;
903 /** Stream of viewport change events. */
904 this._change = new rxjs.Subject();
905 /** Event listener that will be used to handle the viewport change events. */
906 this._changeListener = function (event) {
907 _this._change.next(event);
908 };
909 this._document = document;
910 ngZone.runOutsideAngular(function () {
911 if (_platform.isBrowser) {
912 var window = _this._getWindow();
913 // Note that bind the events ourselves, rather than going through something like RxJS's
914 // `fromEvent` so that we can ensure that they're bound outside of the NgZone.
915 window.addEventListener('resize', _this._changeListener);
916 window.addEventListener('orientationchange', _this._changeListener);
917 }
918 // Clear the cached position so that the viewport is re-measured next time it is required.
919 // We don't need to keep track of the subscription, because it is completed on destroy.
920 _this.change().subscribe(function () { return _this._viewportSize = null; });
921 });
922 }
923 ViewportRuler.prototype.ngOnDestroy = function () {
924 if (this._platform.isBrowser) {
925 var window = this._getWindow();
926 window.removeEventListener('resize', this._changeListener);
927 window.removeEventListener('orientationchange', this._changeListener);
928 }
929 this._change.complete();
930 };
931 /** Returns the viewport's width and height. */
932 ViewportRuler.prototype.getViewportSize = function () {
933 if (!this._viewportSize) {
934 this._updateViewportSize();
935 }
936 var output = { width: this._viewportSize.width, height: this._viewportSize.height };
937 // If we're not on a browser, don't cache the size since it'll be mocked out anyway.
938 if (!this._platform.isBrowser) {
939 this._viewportSize = null;
940 }
941 return output;
942 };
943 /** Gets a ClientRect for the viewport's bounds. */
944 ViewportRuler.prototype.getViewportRect = function () {
945 // Use the document element's bounding rect rather than the window scroll properties
946 // (e.g. pageYOffset, scrollY) due to in issue in Chrome and IE where window scroll
947 // properties and client coordinates (boundingClientRect, clientX/Y, etc.) are in different
948 // conceptual viewports. Under most circumstances these viewports are equivalent, but they
949 // can disagree when the page is pinch-zoomed (on devices that support touch).
950 // See https://bugs.chromium.org/p/chromium/issues/detail?id=489206#c4
951 // We use the documentElement instead of the body because, by default (without a css reset)
952 // browsers typically give the document body an 8px margin, which is not included in
953 // getBoundingClientRect().
954 var scrollPosition = this.getViewportScrollPosition();
955 var _a = this.getViewportSize(), width = _a.width, height = _a.height;
956 return {
957 top: scrollPosition.top,
958 left: scrollPosition.left,
959 bottom: scrollPosition.top + height,
960 right: scrollPosition.left + width,
961 height: height,
962 width: width,
963 };
964 };
965 /** Gets the (top, left) scroll position of the viewport. */
966 ViewportRuler.prototype.getViewportScrollPosition = function () {
967 // While we can get a reference to the fake document
968 // during SSR, it doesn't have getBoundingClientRect.
969 if (!this._platform.isBrowser) {
970 return { top: 0, left: 0 };
971 }
972 // The top-left-corner of the viewport is determined by the scroll position of the document
973 // body, normally just (scrollLeft, scrollTop). However, Chrome and Firefox disagree about
974 // whether `document.body` or `document.documentElement` is the scrolled element, so reading
975 // `scrollTop` and `scrollLeft` is inconsistent. However, using the bounding rect of
976 // `document.documentElement` works consistently, where the `top` and `left` values will
977 // equal negative the scroll position.
978 var document = this._document;
979 var window = this._getWindow();
980 var documentElement = document.documentElement;
981 var documentRect = documentElement.getBoundingClientRect();
982 var top = -documentRect.top || document.body.scrollTop || window.scrollY ||
983 documentElement.scrollTop || 0;
984 var left = -documentRect.left || document.body.scrollLeft || window.scrollX ||
985 documentElement.scrollLeft || 0;
986 return { top: top, left: left };
987 };
988 /**
989 * Returns a stream that emits whenever the size of the viewport changes.
990 * This stream emits outside of the Angular zone.
991 * @param throttleTime Time in milliseconds to throttle the stream.
992 */
993 ViewportRuler.prototype.change = function (throttleTime) {
994 if (throttleTime === void 0) { throttleTime = DEFAULT_RESIZE_TIME; }
995 return throttleTime > 0 ? this._change.pipe(operators.auditTime(throttleTime)) : this._change;
996 };
997 /** Use defaultView of injected document if available or fallback to global window reference */
998 ViewportRuler.prototype._getWindow = function () {
999 return this._document.defaultView || window;
1000 };
1001 /** Updates the cached viewport size. */
1002 ViewportRuler.prototype._updateViewportSize = function () {
1003 var window = this._getWindow();
1004 this._viewportSize = this._platform.isBrowser ?
1005 { width: window.innerWidth, height: window.innerHeight } :
1006 { width: 0, height: 0 };
1007 };
1008 return ViewportRuler;
1009 }());
1010 ViewportRuler.ɵprov = i0__namespace.ɵɵdefineInjectable({ factory: function ViewportRuler_Factory() { return new ViewportRuler(i0__namespace.ɵɵinject(i1__namespace.Platform), i0__namespace.ɵɵinject(i0__namespace.NgZone), i0__namespace.ɵɵinject(i2__namespace.DOCUMENT, 8)); }, token: ViewportRuler, providedIn: "root" });
1011 ViewportRuler.decorators = [
1012 { type: i0.Injectable, args: [{ providedIn: 'root' },] }
1013 ];
1014 ViewportRuler.ctorParameters = function () { return [
1015 { type: i1.Platform },
1016 { type: i0.NgZone },
1017 { type: undefined, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [i2.DOCUMENT,] }] }
1018 ]; };
1019
1020 /** Checks if the given ranges are equal. */
1021 function rangesEqual(r1, r2) {
1022 return r1.start == r2.start && r1.end == r2.end;
1023 }
1024 /**
1025 * Scheduler to be used for scroll events. Needs to fall back to
1026 * something that doesn't rely on requestAnimationFrame on environments
1027 * that don't support it (e.g. server-side rendering).
1028 */
1029 var SCROLL_SCHEDULER = typeof requestAnimationFrame !== 'undefined' ? rxjs.animationFrameScheduler : rxjs.asapScheduler;
1030 /** A viewport that virtualizes its scrolling with the help of `CdkVirtualForOf`. */
1031 var CdkVirtualScrollViewport = /** @class */ (function (_super) {
1032 __extends(CdkVirtualScrollViewport, _super);
1033 function CdkVirtualScrollViewport(elementRef, _changeDetectorRef, ngZone, _scrollStrategy, dir, scrollDispatcher, viewportRuler) {
1034 var _this = _super.call(this, elementRef, scrollDispatcher, ngZone, dir) || this;
1035 _this.elementRef = elementRef;
1036 _this._changeDetectorRef = _changeDetectorRef;
1037 _this._scrollStrategy = _scrollStrategy;
1038 /** Emits when the viewport is detached from a CdkVirtualForOf. */
1039 _this._detachedSubject = new rxjs.Subject();
1040 /** Emits when the rendered range changes. */
1041 _this._renderedRangeSubject = new rxjs.Subject();
1042 _this._orientation = 'vertical';
1043 _this._appendOnly = false;
1044 // Note: we don't use the typical EventEmitter here because we need to subscribe to the scroll
1045 // strategy lazily (i.e. only if the user is actually listening to the events). We do this because
1046 // depending on how the strategy calculates the scrolled index, it may come at a cost to
1047 // performance.
1048 /** Emits when the index of the first element visible in the viewport changes. */
1049 _this.scrolledIndexChange = new rxjs.Observable(function (observer) { return _this._scrollStrategy.scrolledIndexChange.subscribe(function (index) { return Promise.resolve().then(function () { return _this.ngZone.run(function () { return observer.next(index); }); }); }); });
1050 /** A stream that emits whenever the rendered range changes. */
1051 _this.renderedRangeStream = _this._renderedRangeSubject;
1052 /**
1053 * The total size of all content (in pixels), including content that is not currently rendered.
1054 */
1055 _this._totalContentSize = 0;
1056 /** A string representing the `style.width` property value to be used for the spacer element. */
1057 _this._totalContentWidth = '';
1058 /** A string representing the `style.height` property value to be used for the spacer element. */
1059 _this._totalContentHeight = '';
1060 /** The currently rendered range of indices. */
1061 _this._renderedRange = { start: 0, end: 0 };
1062 /** The length of the data bound to this viewport (in number of items). */
1063 _this._dataLength = 0;
1064 /** The size of the viewport (in pixels). */
1065 _this._viewportSize = 0;
1066 /** The last rendered content offset that was set. */
1067 _this._renderedContentOffset = 0;
1068 /**
1069 * Whether the last rendered content offset was to the end of the content (and therefore needs to
1070 * be rewritten as an offset to the start of the content).
1071 */
1072 _this._renderedContentOffsetNeedsRewrite = false;
1073 /** Whether there is a pending change detection cycle. */
1074 _this._isChangeDetectionPending = false;
1075 /** A list of functions to run after the next change detection cycle. */
1076 _this._runAfterChangeDetection = [];
1077 /** Subscription to changes in the viewport size. */
1078 _this._viewportChanges = rxjs.Subscription.EMPTY;
1079 if (!_scrollStrategy && (typeof ngDevMode === 'undefined' || ngDevMode)) {
1080 throw Error('Error: cdk-virtual-scroll-viewport requires the "itemSize" property to be set.');
1081 }
1082 _this._viewportChanges = viewportRuler.change().subscribe(function () {
1083 _this.checkViewportSize();
1084 });
1085 return _this;
1086 }
1087 Object.defineProperty(CdkVirtualScrollViewport.prototype, "orientation", {
1088 /** The direction the viewport scrolls. */
1089 get: function () {
1090 return this._orientation;
1091 },
1092 set: function (orientation) {
1093 if (this._orientation !== orientation) {
1094 this._orientation = orientation;
1095 this._calculateSpacerSize();
1096 }
1097 },
1098 enumerable: false,
1099 configurable: true
1100 });
1101 Object.defineProperty(CdkVirtualScrollViewport.prototype, "appendOnly", {
1102 /**
1103 * Whether rendered items should persist in the DOM after scrolling out of view. By default, items
1104 * will be removed.
1105 */
1106 get: function () {
1107 return this._appendOnly;
1108 },
1109 set: function (value) {
1110 this._appendOnly = coercion.coerceBooleanProperty(value);
1111 },
1112 enumerable: false,
1113 configurable: true
1114 });
1115 CdkVirtualScrollViewport.prototype.ngOnInit = function () {
1116 var _this = this;
1117 _super.prototype.ngOnInit.call(this);
1118 // It's still too early to measure the viewport at this point. Deferring with a promise allows
1119 // the Viewport to be rendered with the correct size before we measure. We run this outside the
1120 // zone to avoid causing more change detection cycles. We handle the change detection loop
1121 // ourselves instead.
1122 this.ngZone.runOutsideAngular(function () { return Promise.resolve().then(function () {
1123 _this._measureViewportSize();
1124 _this._scrollStrategy.attach(_this);
1125 _this.elementScrolled()
1126 .pipe(
1127 // Start off with a fake scroll event so we properly detect our initial position.
1128 operators.startWith(null),
1129 // Collect multiple events into one until the next animation frame. This way if
1130 // there are multiple scroll events in the same frame we only need to recheck
1131 // our layout once.
1132 operators.auditTime(0, SCROLL_SCHEDULER))
1133 .subscribe(function () { return _this._scrollStrategy.onContentScrolled(); });
1134 _this._markChangeDetectionNeeded();
1135 }); });
1136 };
1137 CdkVirtualScrollViewport.prototype.ngOnDestroy = function () {
1138 this.detach();
1139 this._scrollStrategy.detach();
1140 // Complete all subjects
1141 this._renderedRangeSubject.complete();
1142 this._detachedSubject.complete();
1143 this._viewportChanges.unsubscribe();
1144 _super.prototype.ngOnDestroy.call(this);
1145 };
1146 /** Attaches a `CdkVirtualScrollRepeater` to this viewport. */
1147 CdkVirtualScrollViewport.prototype.attach = function (forOf) {
1148 var _this = this;
1149 if (this._forOf && (typeof ngDevMode === 'undefined' || ngDevMode)) {
1150 throw Error('CdkVirtualScrollViewport is already attached.');
1151 }
1152 // Subscribe to the data stream of the CdkVirtualForOf to keep track of when the data length
1153 // changes. Run outside the zone to avoid triggering change detection, since we're managing the
1154 // change detection loop ourselves.
1155 this.ngZone.runOutsideAngular(function () {
1156 _this._forOf = forOf;
1157 _this._forOf.dataStream.pipe(operators.takeUntil(_this._detachedSubject)).subscribe(function (data) {
1158 var newLength = data.length;
1159 if (newLength !== _this._dataLength) {
1160 _this._dataLength = newLength;
1161 _this._scrollStrategy.onDataLengthChanged();
1162 }
1163 _this._doChangeDetection();
1164 });
1165 });
1166 };
1167 /** Detaches the current `CdkVirtualForOf`. */
1168 CdkVirtualScrollViewport.prototype.detach = function () {
1169 this._forOf = null;
1170 this._detachedSubject.next();
1171 };
1172 /** Gets the length of the data bound to this viewport (in number of items). */
1173 CdkVirtualScrollViewport.prototype.getDataLength = function () {
1174 return this._dataLength;
1175 };
1176 /** Gets the size of the viewport (in pixels). */
1177 CdkVirtualScrollViewport.prototype.getViewportSize = function () {
1178 return this._viewportSize;
1179 };
1180 // TODO(mmalerba): This is technically out of sync with what's really rendered until a render
1181 // cycle happens. I'm being careful to only call it after the render cycle is complete and before
1182 // setting it to something else, but its error prone and should probably be split into
1183 // `pendingRange` and `renderedRange`, the latter reflecting whats actually in the DOM.
1184 /** Get the current rendered range of items. */
1185 CdkVirtualScrollViewport.prototype.getRenderedRange = function () {
1186 return this._renderedRange;
1187 };
1188 /**
1189 * Sets the total size of all content (in pixels), including content that is not currently
1190 * rendered.
1191 */
1192 CdkVirtualScrollViewport.prototype.setTotalContentSize = function (size) {
1193 if (this._totalContentSize !== size) {
1194 this._totalContentSize = size;
1195 this._calculateSpacerSize();
1196 this._markChangeDetectionNeeded();
1197 }
1198 };
1199 /** Sets the currently rendered range of indices. */
1200 CdkVirtualScrollViewport.prototype.setRenderedRange = function (range) {
1201 var _this = this;
1202 if (!rangesEqual(this._renderedRange, range)) {
1203 if (this.appendOnly) {
1204 range = { start: 0, end: Math.max(this._renderedRange.end, range.end) };
1205 }
1206 this._renderedRangeSubject.next(this._renderedRange = range);
1207 this._markChangeDetectionNeeded(function () { return _this._scrollStrategy.onContentRendered(); });
1208 }
1209 };
1210 /**
1211 * Gets the offset from the start of the viewport to the start of the rendered data (in pixels).
1212 */
1213 CdkVirtualScrollViewport.prototype.getOffsetToRenderedContentStart = function () {
1214 return this._renderedContentOffsetNeedsRewrite ? null : this._renderedContentOffset;
1215 };
1216 /**
1217 * Sets the offset from the start of the viewport to either the start or end of the rendered data
1218 * (in pixels).
1219 */
1220 CdkVirtualScrollViewport.prototype.setRenderedContentOffset = function (offset, to) {
1221 var _this = this;
1222 if (to === void 0) { to = 'to-start'; }
1223 // For a horizontal viewport in a right-to-left language we need to translate along the x-axis
1224 // in the negative direction.
1225 var isRtl = this.dir && this.dir.value == 'rtl';
1226 var isHorizontal = this.orientation == 'horizontal';
1227 var axis = isHorizontal ? 'X' : 'Y';
1228 var axisDirection = isHorizontal && isRtl ? -1 : 1;
1229 var transform = "translate" + axis + "(" + Number(axisDirection * offset) + "px)";
1230 this._renderedContentOffset = offset;
1231 if (to === 'to-end') {
1232 transform += " translate" + axis + "(-100%)";
1233 // The viewport should rewrite this as a `to-start` offset on the next render cycle. Otherwise
1234 // elements will appear to expand in the wrong direction (e.g. `mat-expansion-panel` would
1235 // expand upward).
1236 this._renderedContentOffsetNeedsRewrite = true;
1237 }
1238 if (this._renderedContentTransform != transform) {
1239 // We know this value is safe because we parse `offset` with `Number()` before passing it
1240 // into the string.
1241 this._renderedContentTransform = transform;
1242 this._markChangeDetectionNeeded(function () {
1243 if (_this._renderedContentOffsetNeedsRewrite) {
1244 _this._renderedContentOffset -= _this.measureRenderedContentSize();
1245 _this._renderedContentOffsetNeedsRewrite = false;
1246 _this.setRenderedContentOffset(_this._renderedContentOffset);
1247 }
1248 else {
1249 _this._scrollStrategy.onRenderedOffsetChanged();
1250 }
1251 });
1252 }
1253 };
1254 /**
1255 * Scrolls to the given offset from the start of the viewport. Please note that this is not always
1256 * the same as setting `scrollTop` or `scrollLeft`. In a horizontal viewport with right-to-left
1257 * direction, this would be the equivalent of setting a fictional `scrollRight` property.
1258 * @param offset The offset to scroll to.
1259 * @param behavior The ScrollBehavior to use when scrolling. Default is behavior is `auto`.
1260 */
1261 CdkVirtualScrollViewport.prototype.scrollToOffset = function (offset, behavior) {
1262 if (behavior === void 0) { behavior = 'auto'; }
1263 var options = { behavior: behavior };
1264 if (this.orientation === 'horizontal') {
1265 options.start = offset;
1266 }
1267 else {
1268 options.top = offset;
1269 }
1270 this.scrollTo(options);
1271 };
1272 /**
1273 * Scrolls to the offset for the given index.
1274 * @param index The index of the element to scroll to.
1275 * @param behavior The ScrollBehavior to use when scrolling. Default is behavior is `auto`.
1276 */
1277 CdkVirtualScrollViewport.prototype.scrollToIndex = function (index, behavior) {
1278 if (behavior === void 0) { behavior = 'auto'; }
1279 this._scrollStrategy.scrollToIndex(index, behavior);
1280 };
1281 /**
1282 * Gets the current scroll offset from the start of the viewport (in pixels).
1283 * @param from The edge to measure the offset from. Defaults to 'top' in vertical mode and 'start'
1284 * in horizontal mode.
1285 */
1286 CdkVirtualScrollViewport.prototype.measureScrollOffset = function (from) {
1287 return from ?
1288 _super.prototype.measureScrollOffset.call(this, from) :
1289 _super.prototype.measureScrollOffset.call(this, this.orientation === 'horizontal' ? 'start' : 'top');
1290 };
1291 /** Measure the combined size of all of the rendered items. */
1292 CdkVirtualScrollViewport.prototype.measureRenderedContentSize = function () {
1293 var contentEl = this._contentWrapper.nativeElement;
1294 return this.orientation === 'horizontal' ? contentEl.offsetWidth : contentEl.offsetHeight;
1295 };
1296 /**
1297 * Measure the total combined size of the given range. Throws if the range includes items that are
1298 * not rendered.
1299 */
1300 CdkVirtualScrollViewport.prototype.measureRangeSize = function (range) {
1301 if (!this._forOf) {
1302 return 0;
1303 }
1304 return this._forOf.measureRangeSize(range, this.orientation);
1305 };
1306 /** Update the viewport dimensions and re-render. */
1307 CdkVirtualScrollViewport.prototype.checkViewportSize = function () {
1308 // TODO: Cleanup later when add logic for handling content resize
1309 this._measureViewportSize();
1310 this._scrollStrategy.onDataLengthChanged();
1311 };
1312 /** Measure the viewport size. */
1313 CdkVirtualScrollViewport.prototype._measureViewportSize = function () {
1314 var viewportEl = this.elementRef.nativeElement;
1315 this._viewportSize = this.orientation === 'horizontal' ?
1316 viewportEl.clientWidth : viewportEl.clientHeight;
1317 };
1318 /** Queue up change detection to run. */
1319 CdkVirtualScrollViewport.prototype._markChangeDetectionNeeded = function (runAfter) {
1320 var _this = this;
1321 if (runAfter) {
1322 this._runAfterChangeDetection.push(runAfter);
1323 }
1324 // Use a Promise to batch together calls to `_doChangeDetection`. This way if we set a bunch of
1325 // properties sequentially we only have to run `_doChangeDetection` once at the end.
1326 if (!this._isChangeDetectionPending) {
1327 this._isChangeDetectionPending = true;
1328 this.ngZone.runOutsideAngular(function () { return Promise.resolve().then(function () {
1329 _this._doChangeDetection();
1330 }); });
1331 }
1332 };
1333 /** Run change detection. */
1334 CdkVirtualScrollViewport.prototype._doChangeDetection = function () {
1335 var e_1, _a;
1336 var _this = this;
1337 this._isChangeDetectionPending = false;
1338 // Apply the content transform. The transform can't be set via an Angular binding because
1339 // bypassSecurityTrustStyle is banned in Google. However the value is safe, it's composed of
1340 // string literals, a variable that can only be 'X' or 'Y', and user input that is run through
1341 // the `Number` function first to coerce it to a numeric value.
1342 this._contentWrapper.nativeElement.style.transform = this._renderedContentTransform;
1343 // Apply changes to Angular bindings. Note: We must call `markForCheck` to run change detection
1344 // from the root, since the repeated items are content projected in. Calling `detectChanges`
1345 // instead does not properly check the projected content.
1346 this.ngZone.run(function () { return _this._changeDetectorRef.markForCheck(); });
1347 var runAfterChangeDetection = this._runAfterChangeDetection;
1348 this._runAfterChangeDetection = [];
1349 try {
1350 for (var runAfterChangeDetection_1 = __values(runAfterChangeDetection), runAfterChangeDetection_1_1 = runAfterChangeDetection_1.next(); !runAfterChangeDetection_1_1.done; runAfterChangeDetection_1_1 = runAfterChangeDetection_1.next()) {
1351 var fn = runAfterChangeDetection_1_1.value;
1352 fn();
1353 }
1354 }
1355 catch (e_1_1) { e_1 = { error: e_1_1 }; }
1356 finally {
1357 try {
1358 if (runAfterChangeDetection_1_1 && !runAfterChangeDetection_1_1.done && (_a = runAfterChangeDetection_1.return)) _a.call(runAfterChangeDetection_1);
1359 }
1360 finally { if (e_1) throw e_1.error; }
1361 }
1362 };
1363 /** Calculates the `style.width` and `style.height` for the spacer element. */
1364 CdkVirtualScrollViewport.prototype._calculateSpacerSize = function () {
1365 this._totalContentHeight =
1366 this.orientation === 'horizontal' ? '' : this._totalContentSize + "px";
1367 this._totalContentWidth =
1368 this.orientation === 'horizontal' ? this._totalContentSize + "px" : '';
1369 };
1370 return CdkVirtualScrollViewport;
1371 }(CdkScrollable));
1372 CdkVirtualScrollViewport.decorators = [
1373 { type: i0.Component, args: [{
1374 selector: 'cdk-virtual-scroll-viewport',
1375 template: "<!--\n Wrap the rendered content in an element that will be used to offset it based on the scroll\n position.\n-->\n<div #contentWrapper class=\"cdk-virtual-scroll-content-wrapper\">\n <ng-content></ng-content>\n</div>\n<!--\n Spacer used to force the scrolling container to the correct size for the *total* number of items\n so that the scrollbar captures the size of the entire data set.\n-->\n<div class=\"cdk-virtual-scroll-spacer\"\n [style.width]=\"_totalContentWidth\" [style.height]=\"_totalContentHeight\"></div>\n",
1376 host: {
1377 'class': 'cdk-virtual-scroll-viewport',
1378 '[class.cdk-virtual-scroll-orientation-horizontal]': 'orientation === "horizontal"',
1379 '[class.cdk-virtual-scroll-orientation-vertical]': 'orientation !== "horizontal"',
1380 },
1381 encapsulation: i0.ViewEncapsulation.None,
1382 changeDetection: i0.ChangeDetectionStrategy.OnPush,
1383 providers: [{
1384 provide: CdkScrollable,
1385 useExisting: CdkVirtualScrollViewport,
1386 }],
1387 styles: ["cdk-virtual-scroll-viewport{display:block;position:relative;overflow:auto;contain:strict;transform:translateZ(0);will-change:scroll-position;-webkit-overflow-scrolling:touch}.cdk-virtual-scroll-content-wrapper{position:absolute;top:0;left:0;contain:content}[dir=rtl] .cdk-virtual-scroll-content-wrapper{right:0;left:auto}.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper{min-height:100%}.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>dl:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>ol:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>table:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>ul:not([cdkVirtualFor]){padding-left:0;padding-right:0;margin-left:0;margin-right:0;border-left-width:0;border-right-width:0;outline:none}.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper{min-width:100%}.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>dl:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>ol:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>table:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>ul:not([cdkVirtualFor]){padding-top:0;padding-bottom:0;margin-top:0;margin-bottom:0;border-top-width:0;border-bottom-width:0;outline:none}.cdk-virtual-scroll-spacer{position:absolute;top:0;left:0;height:1px;width:1px;transform-origin:0 0}[dir=rtl] .cdk-virtual-scroll-spacer{right:0;left:auto;transform-origin:100% 0}\n"]
1388 },] }
1389 ];
1390 CdkVirtualScrollViewport.ctorParameters = function () { return [
1391 { type: i0.ElementRef },
1392 { type: i0.ChangeDetectorRef },
1393 { type: i0.NgZone },
1394 { type: undefined, decorators: [{ type: i0.Optional }, { type: i0.Inject, args: [VIRTUAL_SCROLL_STRATEGY,] }] },
1395 { type: bidi.Directionality, decorators: [{ type: i0.Optional }] },
1396 { type: ScrollDispatcher },
1397 { type: ViewportRuler }
1398 ]; };
1399 CdkVirtualScrollViewport.propDecorators = {
1400 orientation: [{ type: i0.Input }],
1401 appendOnly: [{ type: i0.Input }],
1402 scrolledIndexChange: [{ type: i0.Output }],
1403 _contentWrapper: [{ type: i0.ViewChild, args: ['contentWrapper', { static: true },] }]
1404 };
1405
1406 /** Helper to extract the offset of a DOM Node in a certain direction. */
1407 function getOffset(orientation, direction, node) {
1408 var el = node;
1409 if (!el.getBoundingClientRect) {
1410 return 0;
1411 }
1412 var rect = el.getBoundingClientRect();
1413 if (orientation === 'horizontal') {
1414 return direction === 'start' ? rect.left : rect.right;
1415 }
1416 return direction === 'start' ? rect.top : rect.bottom;
1417 }
1418 /**
1419 * A directive similar to `ngForOf` to be used for rendering data inside a virtual scrolling
1420 * container.
1421 */
1422 var CdkVirtualForOf = /** @class */ (function () {
1423 function CdkVirtualForOf(
1424 /** The view container to add items to. */
1425 _viewContainerRef,
1426 /** The template to use when stamping out new items. */
1427 _template,
1428 /** The set of available differs. */
1429 _differs,
1430 /** The strategy used to render items in the virtual scroll viewport. */
1431 _viewRepeater,
1432 /** The virtual scrolling viewport that these items are being rendered in. */
1433 _viewport, ngZone) {
1434 var _this = this;
1435 this._viewContainerRef = _viewContainerRef;
1436 this._template = _template;
1437 this._differs = _differs;
1438 this._viewRepeater = _viewRepeater;
1439 this._viewport = _viewport;
1440 /** Emits when the rendered view of the data changes. */
1441 this.viewChange = new rxjs.Subject();
1442 /** Subject that emits when a new DataSource instance is given. */
1443 this._dataSourceChanges = new rxjs.Subject();
1444 /** Emits whenever the data in the current DataSource changes. */
1445 this.dataStream = this._dataSourceChanges
1446 .pipe(
1447 // Start off with null `DataSource`.
1448 operators.startWith(null),
1449 // Bundle up the previous and current data sources so we can work with both.
1450 operators.pairwise(),
1451 // Use `_changeDataSource` to disconnect from the previous data source and connect to the
1452 // new one, passing back a stream of data changes which we run through `switchMap` to give
1453 // us a data stream that emits the latest data from whatever the current `DataSource` is.
1454 operators.switchMap(function (_a) {
1455 var _b = __read(_a, 2), prev = _b[0], cur = _b[1];
1456 return _this._changeDataSource(prev, cur);
1457 }),
1458 // Replay the last emitted data when someone subscribes.
1459 operators.shareReplay(1));
1460 /** The differ used to calculate changes to the data. */
1461 this._differ = null;
1462 /** Whether the rendered data should be updated during the next ngDoCheck cycle. */
1463 this._needsUpdate = false;
1464 this._destroyed = new rxjs.Subject();
1465 this.dataStream.subscribe(function (data) {
1466 _this._data = data;
1467 _this._onRenderedDataChange();
1468 });
1469 this._viewport.renderedRangeStream.pipe(operators.takeUntil(this._destroyed)).subscribe(function (range) {
1470 _this._renderedRange = range;
1471 ngZone.run(function () { return _this.viewChange.next(_this._renderedRange); });
1472 _this._onRenderedDataChange();
1473 });
1474 this._viewport.attach(this);
1475 }
1476 Object.defineProperty(CdkVirtualForOf.prototype, "cdkVirtualForOf", {
1477 /** The DataSource to display. */
1478 get: function () {
1479 return this._cdkVirtualForOf;
1480 },
1481 set: function (value) {
1482 this._cdkVirtualForOf = value;
1483 if (collections.isDataSource(value)) {
1484 this._dataSourceChanges.next(value);
1485 }
1486 else {
1487 // If value is an an NgIterable, convert it to an array.
1488 this._dataSourceChanges.next(new collections.ArrayDataSource(rxjs.isObservable(value) ? value : Array.from(value || [])));
1489 }
1490 },
1491 enumerable: false,
1492 configurable: true
1493 });
1494 Object.defineProperty(CdkVirtualForOf.prototype, "cdkVirtualForTrackBy", {
1495 /**
1496 * The `TrackByFunction` to use for tracking changes. The `TrackByFunction` takes the index and
1497 * the item and produces a value to be used as the item's identity when tracking changes.
1498 */
1499 get: function () {
1500 return this._cdkVirtualForTrackBy;
1501 },
1502 set: function (fn) {
1503 var _this = this;
1504 this._needsUpdate = true;
1505 this._cdkVirtualForTrackBy = fn ?
1506 function (index, item) { return fn(index + (_this._renderedRange ? _this._renderedRange.start : 0), item); } :
1507 undefined;
1508 },
1509 enumerable: false,
1510 configurable: true
1511 });
1512 Object.defineProperty(CdkVirtualForOf.prototype, "cdkVirtualForTemplate", {
1513 /** The template used to stamp out new elements. */
1514 set: function (value) {
1515 if (value) {
1516 this._needsUpdate = true;
1517 this._template = value;
1518 }
1519 },
1520 enumerable: false,
1521 configurable: true
1522 });
1523 Object.defineProperty(CdkVirtualForOf.prototype, "cdkVirtualForTemplateCacheSize", {
1524 /**
1525 * The size of the cache used to store templates that are not being used for re-use later.
1526 * Setting the cache size to `0` will disable caching. Defaults to 20 templates.
1527 */
1528 get: function () {
1529 return this._viewRepeater.viewCacheSize;
1530 },
1531 set: function (size) {
1532 this._viewRepeater.viewCacheSize = coercion.coerceNumberProperty(size);
1533 },
1534 enumerable: false,
1535 configurable: true
1536 });
1537 /**
1538 * Measures the combined size (width for horizontal orientation, height for vertical) of all items
1539 * in the specified range. Throws an error if the range includes items that are not currently
1540 * rendered.
1541 */
1542 CdkVirtualForOf.prototype.measureRangeSize = function (range, orientation) {
1543 if (range.start >= range.end) {
1544 return 0;
1545 }
1546 if ((range.start < this._renderedRange.start || range.end > this._renderedRange.end) &&
1547 (typeof ngDevMode === 'undefined' || ngDevMode)) {
1548 throw Error("Error: attempted to measure an item that isn't rendered.");
1549 }
1550 // The index into the list of rendered views for the first item in the range.
1551 var renderedStartIndex = range.start - this._renderedRange.start;
1552 // The length of the range we're measuring.
1553 var rangeLen = range.end - range.start;
1554 // Loop over all the views, find the first and land node and compute the size by subtracting
1555 // the top of the first node from the bottom of the last one.
1556 var firstNode;
1557 var lastNode;
1558 // Find the first node by starting from the beginning and going forwards.
1559 for (var i = 0; i < rangeLen; i++) {
1560 var view = this._viewContainerRef.get(i + renderedStartIndex);
1561 if (view && view.rootNodes.length) {
1562 firstNode = lastNode = view.rootNodes[0];
1563 break;
1564 }
1565 }
1566 // Find the last node by starting from the end and going backwards.
1567 for (var i = rangeLen - 1; i > -1; i--) {
1568 var view = this._viewContainerRef.get(i + renderedStartIndex);
1569 if (view && view.rootNodes.length) {
1570 lastNode = view.rootNodes[view.rootNodes.length - 1];
1571 break;
1572 }
1573 }
1574 return firstNode && lastNode ?
1575 getOffset(orientation, 'end', lastNode) - getOffset(orientation, 'start', firstNode) : 0;
1576 };
1577 CdkVirtualForOf.prototype.ngDoCheck = function () {
1578 if (this._differ && this._needsUpdate) {
1579 // TODO(mmalerba): We should differentiate needs update due to scrolling and a new portion of
1580 // this list being rendered (can use simpler algorithm) vs needs update due to data actually
1581 // changing (need to do this diff).
1582 var changes = this._differ.diff(this._renderedItems);
1583 if (!changes) {
1584 this._updateContext();
1585 }
1586 else {
1587 this._applyChanges(changes);
1588 }
1589 this._needsUpdate = false;
1590 }
1591 };
1592 CdkVirtualForOf.prototype.ngOnDestroy = function () {
1593 this._viewport.detach();
1594 this._dataSourceChanges.next(undefined);
1595 this._dataSourceChanges.complete();
1596 this.viewChange.complete();
1597 this._destroyed.next();
1598 this._destroyed.complete();
1599 this._viewRepeater.detach();
1600 };
1601 /** React to scroll state changes in the viewport. */
1602 CdkVirtualForOf.prototype._onRenderedDataChange = function () {
1603 var _this = this;
1604 if (!this._renderedRange) {
1605 return;
1606 }
1607 this._renderedItems = this._data.slice(this._renderedRange.start, this._renderedRange.end);
1608 if (!this._differ) {
1609 // Use a wrapper function for the `trackBy` so any new values are
1610 // picked up automatically without having to recreate the differ.
1611 this._differ = this._differs.find(this._renderedItems).create(function (index, item) {
1612 return _this.cdkVirtualForTrackBy ? _this.cdkVirtualForTrackBy(index, item) : item;
1613 });
1614 }
1615 this._needsUpdate = true;
1616 };
1617 /** Swap out one `DataSource` for another. */
1618 CdkVirtualForOf.prototype._changeDataSource = function (oldDs, newDs) {
1619 if (oldDs) {
1620 oldDs.disconnect(this);
1621 }
1622 this._needsUpdate = true;
1623 return newDs ? newDs.connect(this) : rxjs.of();
1624 };
1625 /** Update the `CdkVirtualForOfContext` for all views. */
1626 CdkVirtualForOf.prototype._updateContext = function () {
1627 var count = this._data.length;
1628 var i = this._viewContainerRef.length;
1629 while (i--) {
1630 var view = this._viewContainerRef.get(i);
1631 view.context.index = this._renderedRange.start + i;
1632 view.context.count = count;
1633 this._updateComputedContextProperties(view.context);
1634 view.detectChanges();
1635 }
1636 };
1637 /** Apply changes to the DOM. */
1638 CdkVirtualForOf.prototype._applyChanges = function (changes) {
1639 var _this = this;
1640 this._viewRepeater.applyChanges(changes, this._viewContainerRef, function (record, _adjustedPreviousIndex, currentIndex) { return _this._getEmbeddedViewArgs(record, currentIndex); }, function (record) { return record.item; });
1641 // Update $implicit for any items that had an identity change.
1642 changes.forEachIdentityChange(function (record) {
1643 var view = _this._viewContainerRef.get(record.currentIndex);
1644 view.context.$implicit = record.item;
1645 });
1646 // Update the context variables on all items.
1647 var count = this._data.length;
1648 var i = this._viewContainerRef.length;
1649 while (i--) {
1650 var view = this._viewContainerRef.get(i);
1651 view.context.index = this._renderedRange.start + i;
1652 view.context.count = count;
1653 this._updateComputedContextProperties(view.context);
1654 }
1655 };
1656 /** Update the computed properties on the `CdkVirtualForOfContext`. */
1657 CdkVirtualForOf.prototype._updateComputedContextProperties = function (context) {
1658 context.first = context.index === 0;
1659 context.last = context.index === context.count - 1;
1660 context.even = context.index % 2 === 0;
1661 context.odd = !context.even;
1662 };
1663 CdkVirtualForOf.prototype._getEmbeddedViewArgs = function (record, index) {
1664 // Note that it's important that we insert the item directly at the proper index,
1665 // rather than inserting it and the moving it in place, because if there's a directive
1666 // on the same node that injects the `ViewContainerRef`, Angular will insert another
1667 // comment node which can throw off the move when it's being repeated for all items.
1668 return {
1669 templateRef: this._template,
1670 context: {
1671 $implicit: record.item,
1672 // It's guaranteed that the iterable is not "undefined" or "null" because we only
1673 // generate views for elements if the "cdkVirtualForOf" iterable has elements.
1674 cdkVirtualForOf: this._cdkVirtualForOf,
1675 index: -1,
1676 count: -1,
1677 first: false,
1678 last: false,
1679 odd: false,
1680 even: false
1681 },
1682 index: index,
1683 };
1684 };
1685 return CdkVirtualForOf;
1686 }());
1687 CdkVirtualForOf.decorators = [
1688 { type: i0.Directive, args: [{
1689 selector: '[cdkVirtualFor][cdkVirtualForOf]',
1690 providers: [
1691 { provide: collections._VIEW_REPEATER_STRATEGY, useClass: collections._RecycleViewRepeaterStrategy },
1692 ]
1693 },] }
1694 ];
1695 CdkVirtualForOf.ctorParameters = function () { return [
1696 { type: i0.ViewContainerRef },
1697 { type: i0.TemplateRef },
1698 { type: i0.IterableDiffers },
1699 { type: collections._RecycleViewRepeaterStrategy, decorators: [{ type: i0.Inject, args: [collections._VIEW_REPEATER_STRATEGY,] }] },
1700 { type: CdkVirtualScrollViewport, decorators: [{ type: i0.SkipSelf }] },
1701 { type: i0.NgZone }
1702 ]; };
1703 CdkVirtualForOf.propDecorators = {
1704 cdkVirtualForOf: [{ type: i0.Input }],
1705 cdkVirtualForTrackBy: [{ type: i0.Input }],
1706 cdkVirtualForTemplate: [{ type: i0.Input }],
1707 cdkVirtualForTemplateCacheSize: [{ type: i0.Input }]
1708 };
1709
1710 /**
1711 * @license
1712 * Copyright Google LLC All Rights Reserved.
1713 *
1714 * Use of this source code is governed by an MIT-style license that can be
1715 * found in the LICENSE file at https://angular.io/license
1716 */
1717 var CdkScrollableModule = /** @class */ (function () {
1718 function CdkScrollableModule() {
1719 }
1720 return CdkScrollableModule;
1721 }());
1722 CdkScrollableModule.decorators = [
1723 { type: i0.NgModule, args: [{
1724 exports: [CdkScrollable],
1725 declarations: [CdkScrollable]
1726 },] }
1727 ];
1728 /**
1729 * @docs-primary-export
1730 */
1731 var ScrollingModule = /** @class */ (function () {
1732 function ScrollingModule() {
1733 }
1734 return ScrollingModule;
1735 }());
1736 ScrollingModule.decorators = [
1737 { type: i0.NgModule, args: [{
1738 imports: [
1739 bidi.BidiModule,
1740 i1.PlatformModule,
1741 CdkScrollableModule
1742 ],
1743 exports: [
1744 bidi.BidiModule,
1745 CdkScrollableModule,
1746 CdkFixedSizeVirtualScroll,
1747 CdkVirtualForOf,
1748 CdkVirtualScrollViewport,
1749 ],
1750 declarations: [
1751 CdkFixedSizeVirtualScroll,
1752 CdkVirtualForOf,
1753 CdkVirtualScrollViewport,
1754 ],
1755 },] }
1756 ];
1757
1758 /**
1759 * @license
1760 * Copyright Google LLC All Rights Reserved.
1761 *
1762 * Use of this source code is governed by an MIT-style license that can be
1763 * found in the LICENSE file at https://angular.io/license
1764 */
1765
1766 /**
1767 * Generated bundle index. Do not edit.
1768 */
1769
1770 exports.CdkFixedSizeVirtualScroll = CdkFixedSizeVirtualScroll;
1771 exports.CdkScrollable = CdkScrollable;
1772 exports.CdkScrollableModule = CdkScrollableModule;
1773 exports.CdkVirtualForOf = CdkVirtualForOf;
1774 exports.CdkVirtualScrollViewport = CdkVirtualScrollViewport;
1775 exports.DEFAULT_RESIZE_TIME = DEFAULT_RESIZE_TIME;
1776 exports.DEFAULT_SCROLL_TIME = DEFAULT_SCROLL_TIME;
1777 exports.FixedSizeVirtualScrollStrategy = FixedSizeVirtualScrollStrategy;
1778 exports.ScrollDispatcher = ScrollDispatcher;
1779 exports.ScrollingModule = ScrollingModule;
1780 exports.VIRTUAL_SCROLL_STRATEGY = VIRTUAL_SCROLL_STRATEGY;
1781 exports.ViewportRuler = ViewportRuler;
1782 exports._fixedSizeVirtualScrollStrategyFactory = _fixedSizeVirtualScrollStrategyFactory;
1783
1784 Object.defineProperty(exports, '__esModule', { value: true });
1785
1786})));
1787//# sourceMappingURL=cdk-scrolling.umd.js.map