text: (function (global, factory) {
  	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('rxjs/observable/of'), require('rxjs/observable/fromEvent'), require('rxjs/operators')) :
  	typeof define === 'function' && define.amd ? define(['exports', '@angular/core', 'rxjs/observable/of', 'rxjs/observable/fromEvent', 'rxjs/operators'], factory) :
  	(factory((global.ng = global.ng || {}, global.ng.ngxInfiniteScroll = global.ng.ngxInfiniteScroll || {}),global.ng.core,global.rxjs_observable_of,global.rxjs_observable_fromEvent,global.rxjs_operators));
  }(this, (function (exports,_angular_core,rxjs_observable_of,rxjs_observable_fromEvent,rxjs_operators) { 'use strict';
  
  /**
   * @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 VerticalProps = {
      clientHeight: "clientHeight",
      offsetHeight: "offsetHeight",
      scrollHeight: "scrollHeight",
      pageYOffset: "pageYOffset",
      offsetTop: "offsetTop",
      scrollTop: "scrollTop",
      top: "top"
  };
  var HorizontalProps = {
      clientHeight: "clientWidth",
      offsetHeight: "offsetWidth",
      scrollHeight: "scrollWidth",
      pageYOffset: "pageXOffset",
      offsetTop: "offsetLeft",
      scrollTop: "scrollLeft",
      top: "left"
  };
  var AxisResolver = /** @class */ (function () {
      /**
       * @param {?=} vertical
       */
      function AxisResolver(vertical) {
          if (vertical === void 0) { vertical = true; }
          this.vertical = vertical;
          this.propsMap = vertical ? VerticalProps : HorizontalProps;
      }
      /**
       * @return {?}
       */
      AxisResolver.prototype.clientHeightKey = function () {
          return this.propsMap.clientHeight;
      };
      /**
       * @return {?}
       */
      AxisResolver.prototype.offsetHeightKey = function () {
          return this.propsMap.offsetHeight;
      };
      /**
       * @return {?}
       */
      AxisResolver.prototype.scrollHeightKey = function () {
          return this.propsMap.scrollHeight;
      };
      /**
       * @return {?}
       */
      AxisResolver.prototype.pageYOffsetKey = function () {
          return this.propsMap.pageYOffset;
      };
      /**
       * @return {?}
       */
      AxisResolver.prototype.offsetTopKey = function () {
          return this.propsMap.offsetTop;
      };
      /**
       * @return {?}
       */
      AxisResolver.prototype.scrollTopKey = function () {
          return this.propsMap.scrollTop;
      };
      /**
       * @return {?}
       */
      AxisResolver.prototype.topKey = function () {
          return this.propsMap.top;
      };
      return AxisResolver;
  }());
  /**
   * @param {?} alwaysCallback
   * @param {?} shouldFireScrollEvent
   * @param {?} isTriggeredCurrentTotal
   * @return {?}
   */
  function shouldTriggerEvents(alwaysCallback, shouldFireScrollEvent, isTriggeredCurrentTotal) {
      return (alwaysCallback || shouldFireScrollEvent) && !isTriggeredCurrentTotal;
  }
  /**
   * @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 {?} */ scrolled = 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, scrolled: scrolled, 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 {?} */ scrolled = container[axis.scrollTopKey()];
      var /** @type {?} */ totalToScroll = container[axis.scrollHeightKey()];
      return { height: height, scrolled: scrolled, 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])) {
          var /** @type {?} */ docElem = getDocumentElement(isWindow, elem);
          return docElem ? docElem[clientHeightKey] : 0;
      }
      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 {?} distance
   * @param {?} scrollingDown
   * @return {?}
   */
  function shouldFireScrollEvent(container, distance, scrollingDown) {
      var /** @type {?} */ remaining;
      var /** @type {?} */ containerBreakpoint;
      var /** @type {?} */ scrolledUntilNow = container.height + container.scrolled;
      if (scrollingDown) {
          remaining = (container.totalToScroll - scrolledUntilNow) / container.totalToScroll;
          containerBreakpoint = distance.down / 10;
      }
      else {
          var /** @type {?} */ totalHiddenContentHeight = container.scrolled + (container.totalToScroll - scrolledUntilNow);
          remaining = container.scrolled / totalHiddenContentHeight;
          containerBreakpoint = distance.up / 10;
      }
      var /** @type {?} */ shouldFireEvent = remaining <= containerBreakpoint;
      return shouldFireEvent;
  }
  /**
   * @param {?} lastScrollPosition
   * @param {?} container
   * @return {?}
   */
  function isScrollingDownwards(lastScrollPosition, container) {
      return lastScrollPosition < container.scrolled;
  }
  /**
   * @param {?} lastScrollPosition
   * @param {?} container
   * @param {?} distance
   * @return {?}
   */
  function getScrollStats(lastScrollPosition, container, distance) {
      var /** @type {?} */ scrollDown = isScrollingDownwards(lastScrollPosition, container);
      return {
          fire: shouldFireScrollEvent(container, distance, scrollDown),
          scrollDown: scrollDown
      };
  }
  /**
   * @param {?} position
   * @param {?} scrollState
   * @return {?}
   */
  function updateScrollPosition(position, scrollState) {
      return (scrollState.lastScrollPosition = position);
  }
  /**
   * @param {?} totalToScroll
   * @param {?} scrollState
   * @return {?}
   */
  function updateTotalToScroll(totalToScroll, scrollState) {
      if (scrollState.lastTotalToScroll !== totalToScroll) {
          scrollState.lastTotalToScroll = scrollState.totalToScroll;
          scrollState.totalToScroll = totalToScroll;
      }
  }
  /**
   * @param {?} scrollState
   * @return {?}
   */
  /**
   * @param {?} scroll
   * @param {?} scrollState
   * @param {?} triggered
   * @param {?} isScrollingDown
   * @return {?}
   */
  function updateTriggeredFlag(scroll, scrollState, triggered, isScrollingDown) {
      if (isScrollingDown) {
          scrollState.triggered.down = scroll;
      }
      else {
          scrollState.triggered.up = scroll;
      }
  }
  /**
   * @param {?} totalToScroll
   * @param {?} scrollState
   * @param {?} isScrollingDown
   * @return {?}
   */
  function isTriggeredScroll(totalToScroll, scrollState, isScrollingDown) {
      return isScrollingDown
          ? scrollState.triggered.down === totalToScroll
          : scrollState.triggered.up === totalToScroll;
  }
  /**
   * @param {?} scrollState
   * @param {?} scrolledUntilNow
   * @param {?} totalToScroll
   * @return {?}
   */
  function updateScrollState(scrollState, scrolledUntilNow, totalToScroll) {
      updateScrollPosition(scrolledUntilNow, scrollState);
      updateTotalToScroll(totalToScroll, scrollState);
      // const isSameTotal = isSameTotalToScroll(scrollState);
      // if (!isSameTotal) {
      //   updateTriggeredFlag(scrollState, false, isScrollingDown);
      // }
  }
  /**
   * @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 startWithTotal = calculatePoints(element, resolver).totalToScroll;
      var /** @type {?} */ scrollState = {
          lastScrollPosition: 0,
          lastTotalToScroll: 0,
          totalToScroll: startWithTotal,
          triggered: {
              down: 0,
              up: 0
          }
      };
      var /** @type {?} */ options = {
          container: resolver.container,
          throttle: config.throttle
      };
      var /** @type {?} */ distance = {
          up: config.upDistance,
          down: config.downDistance
      };
      return attachScrollEvent(options).pipe(rxjs_operators.mergeMap(function (ev) { return rxjs_observable_of.of(calculatePoints(element, resolver)); }), rxjs_operators.map(function (positionStats) { return toInfiniteScrollParams(scrollState.lastScrollPosition, positionStats, distance); }), rxjs_operators.tap(function (_a) {
          var stats = _a.stats, scrollDown = _a.scrollDown;
          return updateScrollState(scrollState, stats.scrolled, stats.totalToScroll);
      }), rxjs_operators.filter(function (_a) {
          var fire = _a.fire, scrollDown = _a.scrollDown, totalToScroll = _a.stats.totalToScroll;
          return shouldTriggerEvents(config.alwaysCallback, fire, isTriggeredScroll(totalToScroll, scrollState, scrollDown));
      }), rxjs_operators.tap(function (_a) {
          var scrollDown = _a.scrollDown, totalToScroll = _a.stats.totalToScroll;
          updateTriggeredFlag(totalToScroll, scrollState, true, scrollDown);
      }), rxjs_operators.map(toInfiniteScrollAction));
  }
  /**
   * @param {?} options
   * @return {?}
   */
  function attachScrollEvent(options) {
      var /** @type {?} */ obs = rxjs_observable_fromEvent.fromEvent(options.container, "scroll");
      // For an unknown reason calling `sampleTime()` causes trouble for many users, even with `options.throttle = 0`.
      // Let's avoid calling the function unless needed.
      // See https://github.com/orizens/ngx-infinite-scroll/issues/198
      if (options.throttle) {
          obs = obs.pipe(rxjs_operators.sampleTime(options.throttle));
      }
      return obs;
  }
  /**
   * @param {?} lastScrollPosition
   * @param {?} stats
   * @param {?} distance
   * @return {?}
   */
  function toInfiniteScrollParams(lastScrollPosition, stats, distance) {
      var _a = getScrollStats(lastScrollPosition, stats, distance), scrollDown = _a.scrollDown, fire = _a.fire;
      return {
          scrollDown: scrollDown,
          fire: fire,
          stats: stats
      };
  }
  var InfiniteScrollActions = {
      DOWN: "[NGX_ISE] DOWN",
      UP: "[NGX_ISE] UP"
  };
  /**
   * @param {?} response
   * @return {?}
   */
  function toInfiniteScrollAction(response) {
      var scrollDown = response.scrollDown, currentScrollPosition = response.stats.scrolled;
      return {
          type: scrollDown ? InfiniteScrollActions.DOWN : InfiniteScrollActions.UP,
          payload: {
              currentScrollPosition: currentScrollPosition
          }
      };
  }
  var InfiniteScrollDirective = /** @class */ (function () {
      /**
       * @param {?} element
       * @param {?} zone
       */
      function InfiniteScrollDirective(element, zone) {
          this.element = element;
          this.zone = zone;
          this.scrolled = new _angular_core.EventEmitter();
          this.scrolledUp = new _angular_core.EventEmitter();
          this.infiniteScrollDistance = 2;
          this.infiniteScrollUpDistance = 1.5;
          this.infiniteScrollThrottle = 150;
          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,
                      horizontal: _this.horizontal,
                      scrollContainer: _this.infiniteScrollContainer,
                      scrollWindow: _this.scrollWindow,
                      throttle: _this.infiniteScrollThrottle,
                      upDistance: _this.infiniteScrollUpDistance
                  }).subscribe(function (payload) { return _this.zone.run(function () { return _this.handleOnScroll(payload); }); });
              });
          }
      };
      /**
       * @param {?} __0
       * @return {?}
       */
      InfiniteScrollDirective.prototype.handleOnScroll = function (_a) {
          var type = _a.type, payload = _a.payload;
          switch (type) {
              case InfiniteScrollActions.DOWN:
                  return this.scrolled.emit(payload);
              case InfiniteScrollActions.UP:
                  return this.scrolledUp.emit(payload);
              default:
                  return;
          }
      };
      /**
       * @return {?}
       */
      InfiniteScrollDirective.prototype.ngOnDestroy = function () {
          this.destroyScroller();
      };
      /**
       * @return {?}
       */
      InfiniteScrollDirective.prototype.destroyScroller = function () {
          if (this.disposeScroller) {
              this.disposeScroller.unsubscribe();
          }
      };
      return InfiniteScrollDirective;
  }());
  InfiniteScrollDirective.decorators = [
      { type: _angular_core.Directive, args: [{
                  selector: '[infiniteScroll], [infinite-scroll], [data-infinite-scroll]'
              },] },
  ];
  /**
   * @nocollapse
   */
  InfiniteScrollDirective.ctorParameters = function () { return [
      { type: _angular_core.ElementRef, },
      { type: _angular_core.NgZone, },
  ]; };
  InfiniteScrollDirective.propDecorators = {
      'scrolled': [{ type: _angular_core.Output },],
      'scrolledUp': [{ type: _angular_core.Output },],
      'infiniteScrollDistance': [{ type: _angular_core.Input },],
      'infiniteScrollUpDistance': [{ type: _angular_core.Input },],
      'infiniteScrollThrottle': [{ type: _angular_core.Input },],
      'infiniteScrollDisabled': [{ type: _angular_core.Input },],
      'infiniteScrollContainer': [{ type: _angular_core.Input },],
      'scrollWindow': [{ type: _angular_core.Input },],
      'immediateCheck': [{ type: _angular_core.Input },],
      'horizontal': [{ type: _angular_core.Input },],
      'alwaysCallback': [{ type: _angular_core.Input },],
      'fromRoot': [{ type: _angular_core.Input },],
  };
  var InfiniteScrollModule = /** @class */ (function () {
      function InfiniteScrollModule() {
      }
      return InfiniteScrollModule;
  }());
  InfiniteScrollModule.decorators = [
      { type: _angular_core.NgModule, args: [{
                  declarations: [InfiniteScrollDirective],
                  exports: [InfiniteScrollDirective],
                  imports: [],
                  providers: []
              },] },
  ];
  /**
   * @nocollapse
   */
  InfiniteScrollModule.ctorParameters = function () { return []; };
  
  exports.InfiniteScrollDirective = InfiniteScrollDirective;
  exports.InfiniteScrollModule = InfiniteScrollModule;
  
  Object.defineProperty(exports, '__esModule', { value: true });
  
  })));
  //# sourceMappingURL=ngx-infinite-scroll.umd.js.map
  