text: import { ChangeDetectorRef, ContentChild, Directive, ElementRef, Input, IterableDiffers, NgZone, Renderer } from '@angular/core';
  import { adjustRendered, calcDimensions, estimateHeight, initReadNodes, processRecords, populateNodeData, updateDimensions, updateNodeContext, writeToNodes } from './virtual-util';
  import { Config } from '../../config/config';
  import { Content } from '../content/content';
  import { DomController } from '../../platform/dom-controller';
  import { isBlank, isFunction, isPresent } from '../../util/util';
  import { Platform } from '../../platform/platform';
  import { ViewController } from '../../navigation/view-controller';
  import { VirtualFooter, VirtualHeader, VirtualItem } from './virtual-item';
  /**
   * \@name VirtualScroll
   * \@description
   * Virtual Scroll displays a virtual, "infinite" list. An array of records
   * is passed to the virtual scroll containing the data to create templates
   * for. The template created for each record, referred to as a cell, can
   * consist of items, headers, and footers.
   *
   * For performance reasons, not every record in the list is rendered at once;
   * instead a small subset of records (enough to fill the viewport) are rendered
   * and reused as the user scrolls.
   *
   * ### The Basics
   *
   * The array of records should be passed to the `virtualScroll` property.
   * The data given to the `virtualScroll` property must be an array. An item
   * template with the `*virtualItem` property is required in the `virtualScroll`.
   * The `virtualScroll` and `*virtualItem` properties can be added to any element.
   *
   * ```html
   * <ion-list [virtualScroll]="items">
   *
   *   <ion-item *virtualItem="let item">
   *     {% raw %}{{ item }}{% endraw %}
   *   </ion-item>
   *
   * </ion-list>
   * ```
   *
   *
   * ### Section Headers and Footers
   *
   * Section headers and footers are optional. They can be dynamically created
   * from developer-defined functions. For example, a large list of contacts
   * usually has a divider for each letter in the alphabet. Developers provide
   * their own custom function to be called on each record. The logic in the
   * custom function should determine whether to create the section template
   * and what data to provide to the template. The custom function should
   * return `null` if a template shouldn't be created.
   *
   * ```html
   * <ion-list [virtualScroll]="items" [headerFn]="myHeaderFn">
   *
   *   <ion-item-divider *virtualHeader="let header">
   *     Header: {% raw %}{{ header }}{% endraw %}
   *   </ion-item-divider>
   *
   *   <ion-item *virtualItem="let item">
   *     Item: {% raw %}{{ item }}{% endraw %}
   *   </ion-item>
   *
   * </ion-list>
   * ```
   *
   * Below is an example of a custom function called on every record. It
   * gets passed the individual record, the record's index number,
   * and the entire array of records. In this example, after every 20
   * records a header will be inserted. So between the 19th and 20th records,
   * between the 39th and 40th, and so on, a `<ion-item-divider>` will
   * be created and the template's data will come from the function's
   * returned data.
   *
   * ```ts
   * myHeaderFn(record, recordIndex, records) {
   *   if (recordIndex % 20 === 0) {
   *     return 'Header ' + recordIndex;
   *   }
   *   return null;
   * }
   * ```
   *
   *
   * ### Approximate Widths and Heights
   *
   * If the height of items in the virtual scroll are not close to the
   * default size of 40px, it is extremely important to provide an value for
   * approxItemHeight height. An exact pixel-perfect size is not necessary,
   * but without an estimate the virtual scroll will not render correctly.
   *
   * The approximate width and height of each template is used to help
   * determine how many cells should be created, and to help calculate
   * the height of the scrollable area. Note that the actual rendered size
   * of each cell comes from the app's CSS, whereas this approximation
   * is only used to help calculate initial dimensions.
   *
   * It's also important to know that Ionic's default item sizes have
   * slightly different heights between platforms, which is perfectly fine.
   *
   *
   * ### Images Within Virtual Scroll
   *
   * HTTP requests, image decoding, and image rendering can cause jank while
   * scrolling. In order to better control images, Ionic provides `<ion-img>`
   * to manage HTTP requests and image rendering. While scrolling through items
   * quickly, `<ion-img>` knows when and when not to make requests, when and
   * when not to render images, and only loads the images that are viewable
   * after scrolling. [Read more about `ion-img`.](../../img/Img/)
   *
   * It's also important for app developers to ensure image sizes are locked in,
   * and after images have fully loaded they do not change size and affect any
   * other element sizes. Simply put, to ensure rendering bugs are not introduced,
   * it's vital that elements within a virtual item does not dynamically change.
   *
   * For virtual scrolling, the natural effects of the `<img>` are not desirable
   * features. We recommend using the `<ion-img>` component over the native
   * `<img>` element because when an `<img>` element is added to the DOM, it
   * immediately makes a HTTP request for the image file. Additionally, `<img>`
   * renders whenever it wants which could be while the user is scrolling. However,
   * `<ion-img>` is governed by the containing `ion-content` and does not render
   * images while scrolling quickly.
   *
   * ```html
   * <ion-list [virtualScroll]="items">
   *
   *   <ion-item *virtualItem="let item">
   *     <ion-avatar item-left>
   *       <ion-img [src]="item.avatarUrl"></ion-img>
   *     </ion-avatar>
   *    {% raw %} {{ item.firstName }} {{ item.lastName }}{% endraw %}
   *   </ion-item>
   *
   * </ion-list>
   * ```
   *
   *
   * ### Custom Components
   *
   * If a custom component is going to be used within Virtual Scroll, it's best
   * to wrap it with a good old `<div>` to ensure the component is rendered
   * correctly. Since each custom component's implementation and internals can be
   * quite different, wrapping within a `<div>` is a safe way to make sure
   * dimensions are measured correctly.
   *
   * ```html
   * <ion-list [virtualScroll]="items">
   *
   *   <div *virtualItem="let item">
   *     <my-custom-item [item]="item">
   *       {% raw %} {{ item }}{% endraw %}
   *     </my-custom-item>
   *   </div>
   *
   * </ion-list>
   * ```
   *
   *
   * ## Virtual Scroll Performance Tips
   *
   * #### iOS Cordova WKWebView
   *
   * When deploying to iOS with Cordova, it's highly recommended to use the
   * [WKWebView plugin](http://blog.ionic.io/cordova-ios-performance-improvements-drop-in-speed-with-wkwebview/)
   * in order to take advantage of iOS's higher performimg webview. Additionally,
   * WKWebView is superior at scrolling efficiently in comparision to the older
   * UIWebView.
   *
   * #### Lock in element dimensions and locations
   *
   * In order for virtual scroll to efficiently size and locate every item, it's
   * very important every element within each virtual item does not dynamically
   * change its dimensions or location. The best way to ensure size and location
   * does not change, it's recommended each virtual item has locked in its size
   * via CSS.
   *
   * #### Use `ion-img` for images
   *
   * When including images within Virtual Scroll, be sure to use
   * [`ion-img`](../img/Img/) rather than the standard `<img>` HTML element.
   * With `ion-img`, images are lazy loaded so only the viewable ones are
   * rendered, and HTTP requests are efficiently controlled while scrolling.
   *
   * #### Set Approximate Widths and Heights
   *
   * As mentioned above, all elements should lock in their dimensions. However,
   * virtual scroll isn't aware of the dimensions until after they have been
   * rendered. For the initial render, virtual scroll still needs to set
   * how many items should be built. With "approx" property inputs, such as
   * `approxItemHeight`, we're able to give virtual sroll an approximate size,
   * therefore allowing virtual scroll to decide how many items should be
   * created.
   *
   * #### Changing dataset should use `virtualTrackBy`
   *
   * It is possible for the identities of elements in the iterator to change
   * while the data does not. This can happen, for example, if the iterator
   * produced from an RPC to the server, and that RPC is re-run. Even if the
   * "data" hasn't changed, the second response will produce objects with
   * different identities, and Ionic will tear down the entire DOM and rebuild
   * it. This is an expensive operation and should be avoided if possible.
   *
   * #### Efficient headers and footer functions
   *
   * Each virtual item must stay extremely efficient, but one way to really
   * kill its performance is to perform any DOM operations within section header
   * and footer functions. These functions are called for every record in the
   * dataset, so please make sure they're performant.
   *
   */
  export var VirtualScroll = (function () {
      /**
       * @param {?} _iterableDiffers
       * @param {?} _elementRef
       * @param {?} _renderer
       * @param {?} _zone
       * @param {?} _cd
       * @param {?} _content
       * @param {?} _plt
       * @param {?} _ctrl
       * @param {?} _config
       * @param {?} _dom
       */
      function VirtualScroll(_iterableDiffers, _elementRef, _renderer, _zone, _cd, _content, _plt, _ctrl, _config, _dom) {
          var _this = this;
          this._iterableDiffers = _iterableDiffers;
          this._elementRef = _elementRef;
          this._renderer = _renderer;
          this._zone = _zone;
          this._cd = _cd;
          this._content = _content;
          this._plt = _plt;
          this._ctrl = _ctrl;
          this._config = _config;
          this._dom = _dom;
          this._records = [];
          this._cells = [];
          this._nodes = [];
          this._vHeight = 0;
          this._lastCheck = 0;
          this._data = {
              scrollTop: 0,
          };
          /**
           * @input {number} The buffer ratio is used to decide how many cells
           * should get created when initially rendered. The number is a
           * multiplier against the viewable area's height. For example, if it
           * takes `20` cells to fill up the height of the viewable area, then
           * with a buffer ratio of `3` it will create `60` cells that are
           * available for reuse while scrolling. For better performance, it's
           * better to have more cells than what are required to fill the
           * viewable area. Default is `3`.
           */
          this.bufferRatio = 3;
          /**
           * @input {string} The approximate width of each item template's cell.
           * This dimension is used to help determine how many cells should
           * be created when initialized, and to help calculate the height of
           * the scrollable area. This value can use either `px` or `%` units.
           * Note that the actual rendered size of each cell comes from the
           * app's CSS, whereas this approximation is used to help calculate
           * initial dimensions before the item has been rendered. Default is
           * `100%`.
           */
          this.approxItemWidth = '100%';
          /**
           * @input {string} The approximate width of each header template's cell.
           * This dimension is used to help determine how many cells should
           * be created when initialized, and to help calculate the height of
           * the scrollable area. This value can use either `px` or `%` units.
           * Note that the actual rendered size of each cell comes from the
           * app's CSS, whereas this approximation is used to help calculate
           * initial dimensions. Default is `100%`.
           */
          this.approxHeaderWidth = '100%';
          /**
           * @input {string} The approximate height of each header template's cell.
           * This dimension is used to help determine how many cells should
           * be created when initialized, and to help calculate the height of
           * the scrollable area. This height value can only use `px` units.
           * Note that the actual rendered size of each cell comes from the
           * app's CSS, whereas this approximation is used to help calculate
           * initial dimensions before the item has been rendered. Default is `40px`.
           */
          this.approxHeaderHeight = '40px';
          /**
           * @input {string} The approximate width of each footer template's cell.
           * This dimension is used to help determine how many cells should
           * be created when initialized, and to help calculate the height of
           * the scrollable area. This value can use either `px` or `%` units.
           * Note that the actual rendered size of each cell comes from the
           * app's CSS, whereas this approximation is used to help calculate
           * initial dimensions before the item has been rendered. Default is `100%`.
           */
          this.approxFooterWidth = '100%';
          /**
           * @input {string} The approximate height of each footer template's cell.
           * This dimension is used to help determine how many cells should
           * be created when initialized, and to help calculate the height of
           * the scrollable area. This height value can only use `px` units.
           * Note that the actual rendered size of each cell comes from the
           * app's CSS, whereas this approximation is used to help calculate
           * initial dimensions before the item has been rendered. Default is `40px`.
           */
          this.approxFooterHeight = '40px';
          // hide the virtual scroll element with opacity so we don't
          // see jank as it loads up, but we're still able to read
          // dimensions because it's still rendered and only opacity hidden
          this._renderer.setElementClass(_elementRef.nativeElement, 'virtual-loading', true);
          // wait for the content to be rendered and has readable dimensions
          _ctrl.readReady.subscribe(function () {
              _this._init = true;
              if (_this._hasChanges()) {
                  _this.readUpdate();
                  // wait for the content to be writable
                  var subscription = _ctrl.writeReady.subscribe(function () {
                      subscription.unsubscribe();
                      _this.writeUpdate();
                  });
              }
              _this._listeners();
          });
      }
      Object.defineProperty(VirtualScroll.prototype, "virtualScroll", {
          /**
           * \@input {array} The data that builds the templates within the virtual scroll.
           * This is the same data that you'd pass to `*ngFor`. It's important to note
           * that when this data has changed, then the entire virtual scroll is reset,
           * which is an expensive operation and should be avoided if possible.
           * @param {?} val
           * @return {?}
           */
          set: function (val) {
              this._records = val;
              if (isBlank(this._differ) && isPresent(val)) {
                  this._differ = this._iterableDiffers.find(val).create(this._cd, this.virtualTrackBy);
              }
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(VirtualScroll.prototype, "headerFn", {
          /**
           * \@input {function} Section headers and the data used within its given
           * template can be dynamically created by passing a function to `headerFn`.
           * For example, a large list of contacts usually has dividers between each
           * letter in the alphabet. App's can provide their own custom `headerFn`
           * which is called with each record within the dataset. The logic within
           * the header function can decide if the header template should be used,
           * and what data to give to the header template. The function must return
           * `null` if a header cell shouldn't be created.
           * @param {?} val
           * @return {?}
           */
          set: function (val) {
              if (isFunction(val)) {
                  this._hdrFn = val.bind((this._ctrl._cmp) || this);
              }
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(VirtualScroll.prototype, "footerFn", {
          /**
           * \@input {function} Section footers and the data used within its given
           * template can be dynamically created by passing a function to `footerFn`.
           * The logic within the footer function can decide if the footer template
           * should be used, and what data to give to the footer template. The function
           * must return `null` if a footer cell shouldn't be created.
           * @param {?} val
           * @return {?}
           */
          set: function (val) {
              if (isFunction(val)) {
                  this._ftrFn = val.bind((this._ctrl._cmp) || this);
              }
          },
          enumerable: true,
          configurable: true
      });
      /**
       * @return {?}
       */
      VirtualScroll.prototype.ngDoCheck = function () {
          if (this._init && this._hasChanges()) {
              // only continue if we've already initialized
              // and if there actually are changes
              this.readUpdate();
              this.writeUpdate();
          }
      };
      /**
       * @return {?}
       */
      VirtualScroll.prototype.readUpdate = function () {
          (void 0) /* console.debug */;
          // reset everything
          this._cells.length = 0;
          this._nodes.length = 0;
          this._itmTmp.viewContainer.clear();
          // ******** DOM READ ****************
          calcDimensions(this._data, this._elementRef.nativeElement, this.approxItemWidth, this.approxItemHeight, this.approxHeaderWidth, this.approxHeaderHeight, this.approxFooterWidth, this.approxFooterHeight, this.bufferRatio);
      };
      /**
       * @return {?}
       */
      VirtualScroll.prototype.writeUpdate = function () {
          (void 0) /* console.debug */;
          processRecords(this._data.renderHeight, this._records, this._cells, this._hdrFn, this._ftrFn, this._data);
          // ******** DOM WRITE ****************
          this.renderVirtual();
      };
      /**
       * @return {?}
       */
      VirtualScroll.prototype._hasChanges = function () {
          return (isPresent(this._records) && isPresent(this._differ) && isPresent(this._differ.diff(this._records)));
      };
      /**
       * DOM WRITE
       * @return {?}
       */
      VirtualScroll.prototype.renderVirtual = function () {
          var _this = this;
          var /** @type {?} */ nodes = this._nodes;
          var /** @type {?} */ cells = this._cells;
          var /** @type {?} */ data = this._data;
          var /** @type {?} */ records = this._records;
          // initialize nodes with the correct cell data
          data.topCell = 0;
          data.bottomCell = (cells.length - 1);
          populateNodeData(0, data.bottomCell, data.viewWidth, true, cells, records, nodes, this._itmTmp.viewContainer, this._itmTmp.templateRef, this._hdrTmp && this._hdrTmp.templateRef, this._ftrTmp && this._ftrTmp.templateRef, true);
          // ******** DOM WRITE ****************
          this._cd.detectChanges();
          // at this point, this fn was called from within another
          // requestAnimationFrame, so the next dom reads/writes within the next frame
          // wait a frame before trying to read and calculate the dimensions
          this._dom.read(function () {
              // ******** DOM READ ****************
              initReadNodes(_this._plt, nodes, cells, data);
          });
          this._dom.write(function () {
              var /** @type {?} */ ele = _this._elementRef.nativeElement;
              var /** @type {?} */ recordsLength = records.length;
              var /** @type {?} */ renderer = _this._renderer;
              // update the bound context for each node
              updateNodeContext(nodes, cells, data);
              // ******** DOM WRITE ****************
              for (var /** @type {?} */ i = 0; i < nodes.length; i++) {
                  ((nodes[i].view)).detectChanges();
              }
              if (!_this._lastEle) {
                  // add an element at the end so :last-child css doesn't get messed up
                  // ******** DOM WRITE ****************
                  var /** @type {?} */ lastEle = renderer.createElement(ele, 'div');
                  lastEle.className = 'virtual-last';
                  _this._lastEle = true;
              }
              // ******** DOM WRITE ****************
              renderer.setElementClass(ele, 'virtual-scroll', true);
              // ******** DOM WRITE ****************
              renderer.setElementClass(ele, 'virtual-loading', false);
              // ******** DOM WRITE ****************
              writeToNodes(_this._plt, nodes, cells, recordsLength);
              // ******** DOM WRITE ****************
              _this._setHeight(estimateHeight(recordsLength, cells[cells.length - 1], _this._vHeight, 0.25));
              _this._content.imgsUpdate();
          });
      };
      /**
       * @param {?} ev
       * @return {?}
       */
      VirtualScroll.prototype.scrollUpdate = function (ev) {
          var _this = this;
          // there is a queue system so that we can
          // spread out the work over multiple frames
          var /** @type {?} */ data = this._data;
          var /** @type {?} */ cells = this._cells;
          var /** @type {?} */ nodes = this._nodes;
          // set the scroll top from the scroll event
          data.scrollTop = ev.scrollTop;
          if (this._queue === SCROLL_QUEUE_DOM_WRITE) {
              // there are DOM writes we need to take care of in this frame
              this._dom.write(function () {
                  var /** @type {?} */ recordsLength = _this._records.length;
                  // ******** DOM WRITE ****************
                  writeToNodes(_this._plt, nodes, cells, recordsLength);
                  // ******** DOM WRITE ****************
                  _this._setHeight(estimateHeight(recordsLength, cells[cells.length - 1], _this._vHeight, 0.25));
                  // we're done here, good work
                  _this._queue = SCROLL_QUEUE_NO_CHANGES;
              });
          }
          else if (this._queue === SCROLL_QUEUE_CHANGE_DETECTION) {
              // we need to do some change detection in this frame
              this._dom.write(function () {
                  // we've got work painting do, let's throw it in the
                  // domWrite callback so everyone plays nice
                  // ******** DOM WRITE ****************
                  for (var /** @type {?} */ i = 0; i < nodes.length; i++) {
                      if (nodes[i].hasChanges) {
                          ((nodes[i].view)).detectChanges();
                      }
                  }
                  // on the next frame we need write to the dom nodes manually
                  _this._queue = SCROLL_QUEUE_DOM_WRITE;
              });
          }
          else {
              // no dom writes or change detection to take care of
              // let's see if we've scroll far enough to require another check
              data.scrollDiff = (data.scrollTop - this._lastCheck);
              if (Math.abs(data.scrollDiff) > SCROLL_DIFFERENCE_MINIMUM) {
                  // don't bother updating if the scrollTop hasn't changed much
                  this._lastCheck = data.scrollTop;
                  if (data.scrollDiff > 0) {
                      // load data we may not have processed yet
                      var /** @type {?} */ stopAtHeight = (data.scrollTop + data.renderHeight);
                      processRecords(stopAtHeight, this._records, cells, this._hdrFn, this._ftrFn, data);
                  }
                  // ******** DOM READ ****************
                  updateDimensions(this._plt, nodes, cells, data, false);
                  adjustRendered(cells, data);
                  var /** @type {?} */ hasChanges = populateNodeData(data.topCell, data.bottomCell, data.viewWidth, data.scrollDiff > 0, cells, this._records, nodes, this._itmTmp.viewContainer, this._itmTmp.templateRef, this._hdrTmp && this._hdrTmp.templateRef, this._ftrTmp && this._ftrTmp.templateRef, false);
                  if (hasChanges) {
                      // queue making updates in the next frame
                      this._queue = SCROLL_QUEUE_CHANGE_DETECTION;
                      // update the bound context for each node
                      updateNodeContext(nodes, cells, data);
                  }
              }
          }
      };
      /**
       * DOM WRITE
       * @param {?} ev
       * @return {?}
       */
      VirtualScroll.prototype.scrollEnd = function (ev) {
          var _this = this;
          var /** @type {?} */ nodes = this._nodes;
          var /** @type {?} */ cells = this._cells;
          var /** @type {?} */ data = this._data;
          // ******** DOM READ ****************
          updateDimensions(this._plt, nodes, cells, data, false);
          adjustRendered(cells, data);
          // ******** DOM READS ABOVE / DOM WRITES BELOW ****************
          this._dom.write(function () {
              var /** @type {?} */ recordsLength = _this._records.length;
              // update the bound context for each node
              updateNodeContext(nodes, cells, data);
              // ******** DOM WRITE ****************
              for (var /** @type {?} */ i = 0; i < nodes.length; i++) {
                  ((nodes[i].view)).detectChanges();
              }
              // ******** DOM WRITE ****************
              writeToNodes(_this._plt, nodes, cells, recordsLength);
              // ******** DOM WRITE ****************
              _this._setHeight(estimateHeight(recordsLength, cells[cells.length - 1], _this._vHeight, 0.05));
              _this._queue = SCROLL_QUEUE_NO_CHANGES;
          });
      };
      /**
       * NO DOM
       * @return {?}
       */
      VirtualScroll.prototype._listeners = function () {
          var _this = this;
          if (!this._scrollSub) {
              if (this._config.getBoolean('virtualScrollEventAssist')) {
                  // use JS scrolling for iOS UIWebView
                  // goal is to completely remove this when iOS
                  // fully supports scroll events
                  // listen to JS scroll events
                  this._content.enableJsScroll();
              }
              this._scrollSub = this._content.ionScroll.subscribe(function (ev) {
                  _this.scrollUpdate(ev);
              });
              this._scrollEndSub = this._content.ionScrollEnd.subscribe(function (ev) {
                  _this.scrollEnd(ev);
              });
          }
      };
      /**
       * DOM WRITE
       * @param {?} newVirtualHeight
       * @return {?}
       */
      VirtualScroll.prototype._setHeight = function (newVirtualHeight) {
          if (newVirtualHeight !== this._vHeight) {
              // ******** DOM WRITE ****************
              this._renderer.setElementStyle(this._elementRef.nativeElement, 'height', newVirtualHeight > 0 ? newVirtualHeight + 'px' : '');
              this._vHeight = newVirtualHeight;
              (void 0) /* console.debug */;
          }
      };
      /**
       * @return {?}
       */
      VirtualScroll.prototype.ngAfterContentInit = function () {
          if (!this._itmTmp) {
              throw 'virtualItem required within virtualScroll';
          }
          if (!this.approxItemHeight) {
              this.approxItemHeight = '40px';
              console.warn('Virtual Scroll: Please provide an "approxItemHeight" input to ensure proper virtual scroll rendering');
          }
      };
      /**
       * @return {?}
       */
      VirtualScroll.prototype.ngOnDestroy = function () {
          this._scrollSub && this._scrollSub.unsubscribe();
          this._scrollEndSub && this._scrollEndSub.unsubscribe();
      };
      VirtualScroll.decorators = [
          { type: Directive, args: [{
                      selector: '[virtualScroll]'
                  },] },
      ];
      /** @nocollapse */
      VirtualScroll.ctorParameters = function () { return [
          { type: IterableDiffers, },
          { type: ElementRef, },
          { type: Renderer, },
          { type: NgZone, },
          { type: ChangeDetectorRef, },
          { type: Content, },
          { type: Platform, },
          { type: ViewController, },
          { type: Config, },
          { type: DomController, },
      ]; };
      VirtualScroll.propDecorators = {
          '_itmTmp': [{ type: ContentChild, args: [VirtualItem,] },],
          '_hdrTmp': [{ type: ContentChild, args: [VirtualHeader,] },],
          '_ftrTmp': [{ type: ContentChild, args: [VirtualFooter,] },],
          'virtualScroll': [{ type: Input },],
          'bufferRatio': [{ type: Input },],
          'approxItemWidth': [{ type: Input },],
          'approxItemHeight': [{ type: Input },],
          'approxHeaderWidth': [{ type: Input },],
          'approxHeaderHeight': [{ type: Input },],
          'approxFooterWidth': [{ type: Input },],
          'approxFooterHeight': [{ type: Input },],
          'headerFn': [{ type: Input },],
          'footerFn': [{ type: Input },],
          'virtualTrackBy': [{ type: Input },],
      };
      return VirtualScroll;
  }());
  function VirtualScroll_tsickle_Closure_declarations() {
      /** @type {?} */
      VirtualScroll.decorators;
      /**
       * @nocollapse
       * @type {?}
       */
      VirtualScroll.ctorParameters;
      /** @type {?} */
      VirtualScroll.propDecorators;
      /** @type {?} */
      VirtualScroll.prototype._differ;
      /** @type {?} */
      VirtualScroll.prototype._scrollSub;
      /** @type {?} */
      VirtualScroll.prototype._scrollEndSub;
      /** @type {?} */
      VirtualScroll.prototype._init;
      /** @type {?} */
      VirtualScroll.prototype._lastEle;
      /** @type {?} */
      VirtualScroll.prototype._hdrFn;
      /** @type {?} */
      VirtualScroll.prototype._ftrFn;
      /** @type {?} */
      VirtualScroll.prototype._records;
      /** @type {?} */
      VirtualScroll.prototype._cells;
      /** @type {?} */
      VirtualScroll.prototype._nodes;
      /** @type {?} */
      VirtualScroll.prototype._vHeight;
      /** @type {?} */
      VirtualScroll.prototype._lastCheck;
      /** @type {?} */
      VirtualScroll.prototype._data;
      /** @type {?} */
      VirtualScroll.prototype._queue;
      /** @type {?} */
      VirtualScroll.prototype._itmTmp;
      /** @type {?} */
      VirtualScroll.prototype._hdrTmp;
      /** @type {?} */
      VirtualScroll.prototype._ftrTmp;
      /**
       * \@input {number} The buffer ratio is used to decide how many cells
       * should get created when initially rendered. The number is a
       * multiplier against the viewable area's height. For example, if it
       * takes `20` cells to fill up the height of the viewable area, then
       * with a buffer ratio of `3` it will create `60` cells that are
       * available for reuse while scrolling. For better performance, it's
       * better to have more cells than what are required to fill the
       * viewable area. Default is `3`.
       * @type {?}
       */
      VirtualScroll.prototype.bufferRatio;
      /**
       * \@input {string} The approximate width of each item template's cell.
       * This dimension is used to help determine how many cells should
       * be created when initialized, and to help calculate the height of
       * the scrollable area. This value can use either `px` or `%` units.
       * Note that the actual rendered size of each cell comes from the
       * app's CSS, whereas this approximation is used to help calculate
       * initial dimensions before the item has been rendered. Default is
       * `100%`.
       * @type {?}
       */
      VirtualScroll.prototype.approxItemWidth;
      /**
       * \@input {string} It is important to provide this
       * if virtual item height will be significantly larger than the default
       * The approximate height of each virtual item template's cell.
       * This dimension is used to help determine how many cells should
       * be created when initialized, and to help calculate the height of
       * the scrollable area. This height value can only use `px` units.
       * Note that the actual rendered size of each cell comes from the
       * app's CSS, whereas this approximation is used to help calculate
       * initial dimensions before the item has been rendered. Default is
       * `40px`.
       * @type {?}
       */
      VirtualScroll.prototype.approxItemHeight;
      /**
       * \@input {string} The approximate width of each header template's cell.
       * This dimension is used to help determine how many cells should
       * be created when initialized, and to help calculate the height of
       * the scrollable area. This value can use either `px` or `%` units.
       * Note that the actual rendered size of each cell comes from the
       * app's CSS, whereas this approximation is used to help calculate
       * initial dimensions. Default is `100%`.
       * @type {?}
       */
      VirtualScroll.prototype.approxHeaderWidth;
      /**
       * \@input {string} The approximate height of each header template's cell.
       * This dimension is used to help determine how many cells should
       * be created when initialized, and to help calculate the height of
       * the scrollable area. This height value can only use `px` units.
       * Note that the actual rendered size of each cell comes from the
       * app's CSS, whereas this approximation is used to help calculate
       * initial dimensions before the item has been rendered. Default is `40px`.
       * @type {?}
       */
      VirtualScroll.prototype.approxHeaderHeight;
      /**
       * \@input {string} The approximate width of each footer template's cell.
       * This dimension is used to help determine how many cells should
       * be created when initialized, and to help calculate the height of
       * the scrollable area. This value can use either `px` or `%` units.
       * Note that the actual rendered size of each cell comes from the
       * app's CSS, whereas this approximation is used to help calculate
       * initial dimensions before the item has been rendered. Default is `100%`.
       * @type {?}
       */
      VirtualScroll.prototype.approxFooterWidth;
      /**
       * \@input {string} The approximate height of each footer template's cell.
       * This dimension is used to help determine how many cells should
       * be created when initialized, and to help calculate the height of
       * the scrollable area. This height value can only use `px` units.
       * Note that the actual rendered size of each cell comes from the
       * app's CSS, whereas this approximation is used to help calculate
       * initial dimensions before the item has been rendered. Default is `40px`.
       * @type {?}
       */
      VirtualScroll.prototype.approxFooterHeight;
      /**
       * \@input {function} Same as `ngForTrackBy` which can be used on `ngFor`.
       * @type {?}
       */
      VirtualScroll.prototype.virtualTrackBy;
      /** @type {?} */
      VirtualScroll.prototype._iterableDiffers;
      /** @type {?} */
      VirtualScroll.prototype._elementRef;
      /** @type {?} */
      VirtualScroll.prototype._renderer;
      /** @type {?} */
      VirtualScroll.prototype._zone;
      /** @type {?} */
      VirtualScroll.prototype._cd;
      /** @type {?} */
      VirtualScroll.prototype._content;
      /** @type {?} */
      VirtualScroll.prototype._plt;
      /** @type {?} */
      VirtualScroll.prototype._ctrl;
      /** @type {?} */
      VirtualScroll.prototype._config;
      /** @type {?} */
      VirtualScroll.prototype._dom;
  }
  var /** @type {?} */ SCROLL_DIFFERENCE_MINIMUM = 40;
  var /** @type {?} */ SCROLL_QUEUE_NO_CHANGES = 1;
  var /** @type {?} */ SCROLL_QUEUE_CHANGE_DETECTION = 2;
  var /** @type {?} */ SCROLL_QUEUE_DOM_WRITE = 3;
  //# sourceMappingURL=virtual-scroll.js.map