text: import { Directive, ElementRef, EventEmitter, Input, NgModule, NgZone, Output } from '@angular/core';
  import 'rxjs/add/observable/fromEvent';
  import 'rxjs/add/observable/of';
  import 'rxjs/add/operator/filter';
  import 'rxjs/add/operator/mergeMap';
  import 'rxjs/add/operator/sampleTime';
  import { Observable } from 'rxjs/Observable';
  /**
   * @param {?} selector
   * @param {?} scrollWindow
   * @param {?} defaultElement
   * @param {?} fromRoot
   * @return {?}
   */
  function resolveContainerElement(selector, scrollWindow, defaultElement, fromRoot) {
      var /** @type {?} */ hasWindow = window && !!window.document && window.document.documentElement;
      var /** @type {?} */ container = hasWindow && scrollWindow ? window : defaultElement;
      if (selector) {
          var /** @type {?} */ containerIsString = selector && hasWindow && typeof selector === 'string';
          container = containerIsString
              ? findElement(selector, defaultElement.nativeElement, fromRoot)
              : selector;
          if (!container) {
              throw new Error('ngx-infinite-scroll {resolveContainerElement()}: selector for');
          }
      }
      return container;
  }
  /**
   * @param {?} selector
   * @param {?} customRoot
   * @param {?} fromRoot
   * @return {?}
   */
  function findElement(selector, customRoot, fromRoot) {
      var /** @type {?} */ rootEl = fromRoot ? window.document : customRoot;
      return rootEl.querySelector(selector);
  }
  /**
   * @param {?} prop
   * @return {?}
   */
  function inputPropChanged(prop) {
      return prop && !prop.firstChange;
  }
  /**
   * @return {?}
   */
  function hasWindowDefined() {
      return typeof window !== 'undefined';
  }
  var AxisResolver = (function () {
      /**
       * @param {?=} vertical
       */
      function AxisResolver(vertical) {
          if (vertical === void 0) { vertical = true; }
          this.vertical = vertical;
      }
      /**
       * @return {?}
       */
      AxisResolver.prototype.clientHeightKey = function () { return this.vertical ? 'clientHeight' : 'clientWidth'; };
      /**
       * @return {?}
       */
      AxisResolver.prototype.offsetHeightKey = function () { return this.vertical ? 'offsetHeight' : 'offsetWidth'; };
      /**
       * @return {?}
       */
      AxisResolver.prototype.scrollHeightKey = function () { return this.vertical ? 'scrollHeight' : 'scrollWidth'; };
      /**
       * @return {?}
       */
      AxisResolver.prototype.pageYOffsetKey = function () { return this.vertical ? 'pageYOffset' : 'pageXOffset'; };
      /**
       * @return {?}
       */
      AxisResolver.prototype.offsetTopKey = function () { return this.vertical ? 'offsetTop' : 'offsetLeft'; };
      /**
       * @return {?}
       */
      AxisResolver.prototype.scrollTopKey = function () { return this.vertical ? 'scrollTop' : 'scrollLeft'; };
      /**
       * @return {?}
       */
      AxisResolver.prototype.topKey = function () { return this.vertical ? 'top' : 'left'; };
      return AxisResolver;
  }());
  /**
   * @param {?} __0
   * @return {?}
   */
  function shouldTriggerEvents(_a) {
      var alwaysCallback = _a.alwaysCallback, shouldFireScrollEvent = _a.shouldFireScrollEvent;
      return (alwaysCallback || shouldFireScrollEvent);
  }
  /**
   * @param {?} callbacks
   * @param {?} isScrollingDown
   * @param {?} scrolledUntilNow
   * @return {?}
   */
  function triggerEvents(callbacks, isScrollingDown, scrolledUntilNow) {
      var /** @type {?} */ eventData = {
          currentScrollPosition: scrolledUntilNow
      };
      var /** @type {?} */ callback = isScrollingDown ? callbacks.down : callbacks.up;
      callback(eventData);
  }
  /**
   * @param {?} __0
   * @return {?}
   */
  function createResolver(_a) {
      var windowElement = _a.windowElement, axis = _a.axis;
      return createResolverWithContainer({ axis: axis, isWindow: isElementWindow(windowElement) }, windowElement);
  }
  /**
   * @param {?} resolver
   * @param {?} windowElement
   * @return {?}
   */
  function createResolverWithContainer(resolver, windowElement) {
      var /** @type {?} */ container = resolver.isWindow || (windowElement && !windowElement.nativeElement)
          ? windowElement
          : windowElement.nativeElement;
      return Object.assign({}, resolver, { container: container });
  }
  /**
   * @param {?} windowElement
   * @return {?}
   */
  function isElementWindow(windowElement) {
      var /** @type {?} */ isWindow = ['Window', 'global'].some(function (obj) { return Object.prototype.toString.call(windowElement).includes(obj); });
      return isWindow;
  }
  /**
   * @param {?} isContainerWindow
   * @param {?} windowElement
   * @return {?}
   */
  function getDocumentElement(isContainerWindow, windowElement) {
      return isContainerWindow ? windowElement.document.documentElement : null;
  }
  /**
   * @param {?} element
   * @param {?} resolver
   * @return {?}
   */
  function calculatePoints(element, resolver) {
      var /** @type {?} */ height = extractHeightForElement(resolver);
      return resolver.isWindow
          ? calculatePointsForWindow(height, element, resolver)
          : calculatePointsForElement(height, element, resolver);
  }
  /**
   * @param {?} height
   * @param {?} element
   * @param {?} resolver
   * @return {?}
   */
  function calculatePointsForWindow(height, element, resolver) {
      var axis = resolver.axis, container = resolver.container, isWindow = resolver.isWindow;
      var _a = extractHeightPropKeys(axis), offsetHeightKey = _a.offsetHeightKey, clientHeightKey = _a.clientHeightKey;
      // scrolled until now / current y point
      var /** @type {?} */ scrolledUntilNow = height +
          getElementPageYOffset(getDocumentElement(isWindow, container), axis, isWindow);
      // total height / most bottom y point
      var /** @type {?} */ nativeElementHeight = getElementHeight(element.nativeElement, isWindow, offsetHeightKey, clientHeightKey);
      var /** @type {?} */ totalToScroll = getElementOffsetTop(element.nativeElement, axis, isWindow) +
          nativeElementHeight;
      return { height: height, scrolledUntilNow: scrolledUntilNow, totalToScroll: totalToScroll };
  }
  /**
   * @param {?} height
   * @param {?} element
   * @param {?} resolver
   * @return {?}
   */
  function calculatePointsForElement(height, element, resolver) {
      var axis = resolver.axis, container = resolver.container;
      // perhaps use container.offsetTop instead of 'scrollTop'
      var /** @type {?} */ scrolledUntilNow = container[axis.scrollTopKey()];
      var /** @type {?} */ totalToScroll = container[axis.scrollHeightKey()];
      return { height: height, scrolledUntilNow: scrolledUntilNow, totalToScroll: totalToScroll };
  }
  /**
   * @param {?} axis
   * @return {?}
   */
  function extractHeightPropKeys(axis) {
      return {
          offsetHeightKey: axis.offsetHeightKey(),
          clientHeightKey: axis.clientHeightKey()
      };
  }
  /**
   * @param {?} __0
   * @return {?}
   */
  function extractHeightForElement(_a) {
      var container = _a.container, isWindow = _a.isWindow, axis = _a.axis;
      var _b = extractHeightPropKeys(axis), offsetHeightKey = _b.offsetHeightKey, clientHeightKey = _b.clientHeightKey;
      return getElementHeight(container, isWindow, offsetHeightKey, clientHeightKey);
  }
  /**
   * @param {?} elem
   * @param {?} isWindow
   * @param {?} offsetHeightKey
   * @param {?} clientHeightKey
   * @return {?}
   */
  function getElementHeight(elem, isWindow, offsetHeightKey, clientHeightKey) {
      if (isNaN(elem[offsetHeightKey])) {
          return getDocumentElement(isWindow, elem)[clientHeightKey];
      }
      else {
          return elem[offsetHeightKey];
      }
  }
  /**
   * @param {?} elem
   * @param {?} axis
   * @param {?} isWindow
   * @return {?}
   */
  function getElementOffsetTop(elem, axis, isWindow) {
      var /** @type {?} */ topKey = axis.topKey();
      // elem = elem.nativeElement;
      if (!elem.getBoundingClientRect) {
          // || elem.css('none')) {
          return;
      }
      return (elem.getBoundingClientRect()[topKey] +
          getElementPageYOffset(elem, axis, isWindow));
  }
  /**
   * @param {?} elem
   * @param {?} axis
   * @param {?} isWindow
   * @return {?}
   */
  function getElementPageYOffset(elem, axis, isWindow) {
      var /** @type {?} */ pageYOffset = axis.pageYOffsetKey();
      var /** @type {?} */ scrollTop = axis.scrollTopKey();
      var /** @type {?} */ offsetTop = axis.offsetTopKey();
      if (isNaN(window[pageYOffset])) {
          return getDocumentElement(isWindow, elem)[scrollTop];
      }
      else if (elem.ownerDocument) {
          return elem.ownerDocument.defaultView[pageYOffset];
      }
      else {
          return elem[offsetTop];
      }
  }
  /**
   * @param {?} container
   * @param {?} config
   * @param {?} scrollingDown
   * @return {?}
   */
  function shouldFireScrollEvent(container, config, scrollingDown) {
      var /** @type {?} */ distance = config.distance;
      var /** @type {?} */ remaining;
      var /** @type {?} */ containerBreakpoint;
      if (scrollingDown) {
          remaining = (container.totalToScroll - container.scrolledUntilNow) / container.totalToScroll;
          containerBreakpoint = distance.down / 10;
      }
      else {
          remaining = container.scrolledUntilNow / container.totalToScroll;
          containerBreakpoint = distance.up / 10;
      }
      var /** @type {?} */ shouldFireEvent = remaining <= containerBreakpoint;
      return shouldFireEvent;
  }
  /**
   * @param {?} lastScrollPosition
   * @param {?} container
   * @return {?}
   */
  function isScrollingDownwards(lastScrollPosition, container) {
      return lastScrollPosition < container.scrolledUntilNow;
  }
  /**
   * @param {?} lastScrollPosition
   * @param {?} container
   * @param {?} config
   * @return {?}
   */
  function getScrollStats(lastScrollPosition, container, config) {
      var /** @type {?} */ isScrollingDown = isScrollingDownwards(lastScrollPosition, container);
      return {
          shouldFireScrollEvent: shouldFireScrollEvent(container, config, isScrollingDown),
          isScrollingDown: isScrollingDown
      };
  }
  /**
   * @param {?} position
   * @param {?} scrollState
   * @return {?}
   */
  function updateScrollPosition(position, scrollState) {
      return (scrollState.lastScrollPosition = position);
  }
  /**
   * @param {?} totalToScroll
   * @param {?} scrollState
   * @return {?}
   */
  function updateTotalToScroll(totalToScroll, scrollState) {
      scrollState.lastTotalToScroll = scrollState.totalToScroll;
      scrollState.totalToScroll = totalToScroll;
  }
  /**
   * @param {?} scrollState
   * @return {?}
   */
  function isSameTotalToScroll(scrollState) {
      return scrollState.totalToScroll === scrollState.lastTotalToScroll;
  }
  /**
   * @param {?} scrollState
   * @param {?} triggered
   * @return {?}
   */
  function updateTriggeredFlag(scrollState, triggered) {
      scrollState.isTriggeredTotal = triggered;
  }
  /**
   * @param {?} scrollState
   * @param {?} scrolledUntilNow
   * @param {?} totalToScroll
   * @return {?}
   */
  function updateScrollState(scrollState, scrolledUntilNow, totalToScroll) {
      updateScrollPosition(scrolledUntilNow, scrollState);
      updateTotalToScroll(totalToScroll, scrollState);
      var /** @type {?} */ isSameTotal = isSameTotalToScroll(scrollState);
      if (!isSameTotal) {
          updateTriggeredFlag(scrollState, false);
      }
  }
  /**
   * @param {?} config
   * @return {?}
   */
  function createScroller(config) {
      var scrollContainer = config.scrollContainer, scrollWindow = config.scrollWindow, element = config.element, fromRoot = config.fromRoot;
      var /** @type {?} */ resolver = createResolver({
          axis: new AxisResolver(!config.horizontal),
          windowElement: resolveContainerElement(scrollContainer, scrollWindow, element, fromRoot)
      });
      var /** @type {?} */ stats = calculatePoints(element, resolver);
      var /** @type {?} */ scrollState = {
          lastScrollPosition: 0,
          lastTotalToScroll: 0,
          totalToScroll: stats.totalToScroll,
          isTriggeredTotal: false
      };
      var /** @type {?} */ options = {
          container: resolver.container,
          mergeMap: function () { return calculatePoints(element, resolver); },
          scrollHandler: function (positionStats) { return handleOnScroll(scrollState, positionStats, config); },
          throttleDuration: config.throttle
      };
      return attachScrollEvent(options);
  }
  /**
   * @param {?} options
   * @return {?}
   */
  function attachScrollEvent(options) {
      return Observable.fromEvent(options.container, 'scroll')
          .sampleTime(options.throttleDuration)
          .mergeMap(function (ev) { return Observable.of(options.mergeMap(ev)); })
          .subscribe(options.scrollHandler);
  }
  /**
   * @param {?} scrollState
   * @param {?} positionStats
   * @param {?} config
   * @return {?}
   */
  function handleOnScroll(scrollState, positionStats, config) {
      var /** @type {?} */ distance = {
          down: config.downDistance,
          up: config.upDistance
      };
      var _a = getScrollStats(scrollState.lastScrollPosition, positionStats, { distance: distance }), isScrollingDown = _a.isScrollingDown, shouldFireScrollEvent$$1 = _a.shouldFireScrollEvent;
      var /** @type {?} */ scrollConfig = {
          alwaysCallback: config.alwaysCallback,
          shouldFireScrollEvent: shouldFireScrollEvent$$1
      };
      updateScrollState(scrollState, positionStats.scrolledUntilNow, positionStats.totalToScroll);
      var /** @type {?} */ shouldTrigger = shouldTriggerEvents(scrollConfig);
      if (shouldTrigger && !scrollState.isTriggeredTotal) {
          updateTriggeredFlag(scrollState, true);
          triggerEvents(config.events, isScrollingDown, positionStats.scrolledUntilNow);
      }
  }
  var InfiniteScrollDirective = (function () {
      /**
       * @param {?} element
       * @param {?} zone
       */
      function InfiniteScrollDirective(element, zone) {
          this.element = element;
          this.zone = zone;
          this.scrolled = new EventEmitter();
          this.scrolledUp = new EventEmitter();
          this.infiniteScrollDistance = 2;
          this.infiniteScrollUpDistance = 1.5;
          this.infiniteScrollThrottle = 300;
          this.infiniteScrollDisabled = false;
          this.infiniteScrollContainer = null;
          this.scrollWindow = true;
          this.immediateCheck = false;
          this.horizontal = false;
          this.alwaysCallback = false;
          this.fromRoot = false;
      }
      /**
       * @return {?}
       */
      InfiniteScrollDirective.prototype.ngAfterViewInit = function () {
          if (!this.infiniteScrollDisabled) {
              this.setup();
          }
      };
      /**
       * @param {?} __0
       * @return {?}
       */
      InfiniteScrollDirective.prototype.ngOnChanges = function (_a) {
          var infiniteScrollContainer = _a.infiniteScrollContainer, infiniteScrollDisabled = _a.infiniteScrollDisabled, infiniteScrollDistance = _a.infiniteScrollDistance;
          var /** @type {?} */ containerChanged = inputPropChanged(infiniteScrollContainer);
          var /** @type {?} */ disabledChanged = inputPropChanged(infiniteScrollDisabled);
          var /** @type {?} */ distanceChanged = inputPropChanged(infiniteScrollDistance);
          var /** @type {?} */ shouldSetup = (!disabledChanged && !this.infiniteScrollDisabled) ||
              (disabledChanged && !infiniteScrollDisabled.currentValue) || distanceChanged;
          if (containerChanged || disabledChanged || distanceChanged) {
              this.destroyScroller();
              if (shouldSetup) {
                  this.setup();
              }
          }
      };
      /**
       * @return {?}
       */
      InfiniteScrollDirective.prototype.setup = function () {
          var _this = this;
          if (hasWindowDefined()) {
              this.zone.runOutsideAngular(function () {
                  _this.disposeScroller = createScroller({
                      fromRoot: _this.fromRoot,
                      alwaysCallback: _this.alwaysCallback,
                      disable: _this.infiniteScrollDisabled,
                      downDistance: _this.infiniteScrollDistance,
                      element: _this.element,
                      events: {
                          // tslint:disable-next-line:arrow-parens
                          down: function (event) { return _this.zone.run(function () { return _this.scrolled.emit(event); }); },
                          // tslint:disable-next-line:arrow-parens
                          up: function (event) { return _this.zone.run(function () { return _this.scrolledUp.emit(event); }); }
                      },
                      horizontal: _this.horizontal,
                      scrollContainer: _this.infiniteScrollContainer,
                      scrollWindow: _this.scrollWindow,
                      throttle: _this.infiniteScrollThrottle,
                      upDistance: _this.infiniteScrollUpDistance
                  });
              });
          }
      };
      /**
       * @return {?}
       */
      InfiniteScrollDirective.prototype.ngOnDestroy = function () {
          this.destroyScroller();
      };
      /**
       * @return {?}
       */
      InfiniteScrollDirective.prototype.destroyScroller = function () {
          if (this.disposeScroller) {
              this.disposeScroller.unsubscribe();
          }
      };
      return InfiniteScrollDirective;
  }());
  InfiniteScrollDirective.decorators = [
      { type: Directive, args: [{
                  selector: '[infiniteScroll], [infinite-scroll], [data-infinite-scroll]'
              },] },
  ];
  /**
   * @nocollapse
   */
  InfiniteScrollDirective.ctorParameters = function () { return [
      { type: ElementRef, },
      { type: NgZone, },
  ]; };
  InfiniteScrollDirective.propDecorators = {
      'scrolled': [{ type: Output },],
      'scrolledUp': [{ type: Output },],
      'infiniteScrollDistance': [{ type: Input },],
      'infiniteScrollUpDistance': [{ type: Input },],
      'infiniteScrollThrottle': [{ type: Input },],
      'infiniteScrollDisabled': [{ type: Input },],
      'infiniteScrollContainer': [{ type: Input },],
      'scrollWindow': [{ type: Input },],
      'immediateCheck': [{ type: Input },],
      'horizontal': [{ type: Input },],
      'alwaysCallback': [{ type: Input },],
      'fromRoot': [{ type: Input },],
  };
  var InfiniteScrollModule = (function () {
      function InfiniteScrollModule() {
      }
      return InfiniteScrollModule;
  }());
  InfiniteScrollModule.decorators = [
      { type: NgModule, args: [{
                  declarations: [InfiniteScrollDirective],
                  exports: [InfiniteScrollDirective],
                  imports: [],
                  providers: []
              },] },
  ];
  /**
   * @nocollapse
   */
  InfiniteScrollModule.ctorParameters = function () { return []; };
  /**
   * Angular library starter.
   * Build an Angular library compatible with AoT compilation & Tree shaking.
   * Written by Roberto Simonetti.
   * MIT license.
   * https://github.com/robisim74/angular-library-starter
   */
  /**
   * Entry point for all public APIs of the package.
   */
  /**
   * Generated bundle index. Do not edit.
   */
  export { InfiniteScrollDirective, InfiniteScrollModule };
  //# sourceMappingURL=ngx-infinite-scroll.es5.js.map
  