"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.ReachBottomListener = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _scrollPosition = require("./scrollPosition");
var _events = require("@wix/bex-core/events");
const debounceOptions = {
  trailing: true
};
const debounceDelay = 400;
const scrollIdleDelay = 250;
class ReachBottomListener {
  constructor(params) {
    (0, _defineProperty2.default)(this, "scrollPosition", void 0);
    (0, _defineProperty2.default)(this, "offsetPX", void 0);
    (0, _defineProperty2.default)(this, "onReachBottom", void 0);
    (0, _defineProperty2.default)(this, "scrollListener", void 0);
    (0, _defineProperty2.default)(this, "container", void 0);
    (0, _defineProperty2.default)(this, "_target", void 0);
    (0, _defineProperty2.default)(this, "targetScrollingParent", void 0);
    (0, _defineProperty2.default)(this, "triggerListenerIfReached", void 0);
    (0, _defineProperty2.default)(this, "isScrolling", false);
    (0, _defineProperty2.default)(this, "events", new _events.EventEmitter());
    (0, _defineProperty2.default)(this, "debounceSetScrollingIdle", void 0);
    (0, _defineProperty2.default)(this, "handleScroll", async () => {
      const {
        clientHeight,
        scrollHeight,
        scrollTop
      } = this.container;
      this.isScrolling = true;
      this.debounceSetScrollingIdle();
      const newScrollPosition = new _scrollPosition.ScrollPosition({
        clientHeight,
        scrollHeight,
        scrollTop
      });
      const {
        offsetPX,
        onReachBottom,
        scrollPosition,
        bottomX
      } = this;
      if (onReachBottom != null && newScrollPosition.reachingTo(scrollPosition, bottomX, offsetPX)) {
        await onReachBottom();
      }
      this.scrollPosition = newScrollPosition;
    });
    (0, _defineProperty2.default)(this, "resizeListener", () => {
      this.triggerListenerIfReached();
    });
    this.container = params.container;
    this.target = params.target;
    this.offsetPX = params.offsetPX ?? 0;
    this.onReachBottom = params.onReachBottom;
    const delay = Math.max(params.delay || 0, 0);
    const {
      lodash: {
        throttle,
        debounce
      }
    } = params;
    this.scrollListener = delay ? throttle(this.handleScroll, delay) : this.handleScroll;
    this.debounceSetScrollingIdle = debounce(() => {
      this.isScrolling = false;
      this.events.emit('idle');
    }, Math.max(scrollIdleDelay, delay));
    this.triggerListenerIfReached = debounce(async () => {
      this.scrollPosition = this.currentScrollPosition();
      const {
        onReachBottom,
        scrollPosition,
        bottomX,
        offsetPX
      } = this;
      if (onReachBottom != null && scrollPosition.reachedTo(bottomX, offsetPX)) {
        await onReachBottom();
        return true;
      }
      return false;
    }, debounceDelay, debounceOptions);
  }
  set target(value) {
    this._target = value;
    this.targetScrollingParent = null;
    if (this._target != null) {
      let offsetParent = this._target.offsetParent;
      while (offsetParent instanceof HTMLElement && ((_offsetParent = offsetParent) == null ? void 0 : _offsetParent.offsetParent) !== this.container) {
        var _offsetParent;
        offsetParent = offsetParent.offsetParent;
      }
      if (offsetParent instanceof HTMLElement) {
        this.targetScrollingParent = offsetParent;
      }
    }
  }
  get target() {
    return this._target;
  }
  currentScrollPosition() {
    const {
      scrollHeight,
      clientHeight,
      scrollTop
    } = this.container;
    return new _scrollPosition.ScrollPosition({
      clientHeight,
      scrollHeight,
      scrollTop
    });
  }
  get bottomX() {
    // either the container bottom, or the target element offset from the container
    const {
      target,
      targetScrollingParent,
      scrollPosition
    } = this;
    if (target != null && targetScrollingParent != null) {
      return target.offsetTop + targetScrollingParent.offsetTop;
    }
    return scrollPosition.scrollHeight;
  }
  subscribe() {
    this.scrollPosition = this.currentScrollPosition();
    this.container.addEventListener('scroll', this.scrollListener);
    window.addEventListener('resize', this.resizeListener);
    return this;
  }
  unsubscribe() {
    this.container.removeEventListener('scroll', this.scrollListener);
    window.removeEventListener('resize', this.resizeListener);
  }
}
exports.ReachBottomListener = ReachBottomListener;
//# sourceMappingURL=reachBottomListener.js.map