<commit_before>import _ from 'underscore';
import Backbone from 'backbone';
import Mn from 'backbone.marionette';

// Similar to _.result, but it passes additional arguments when the property is a method
function execute(target, prop, ...args) {
  return _.isFunction(target[prop]) ? target[prop](...args) : target[prop];
}

Mn.SlidingView = Mn.CollectionView.extend({
  constructor(options = {}) {

    // Throw an error if passed a `collection` option. SlidingView
    // does not follow the same API as CollectionView, so we want
    // to catch errors early on
    if (options.collection) {
      throw new Error('Do not pass a `collection` option to SlidingView.');
    }

    // Store the referenceCollection on the SlidingView
    if (options.referenceCollection) {
      this.referenceCollection = options.referenceCollection;
    }

    // Set the collection to be a new empty collection
    this.collection = new this.collectionClass();

    Mn.CollectionView.prototype.constructor.apply(this, arguments);

    // Get our initial boundaries, and then update the collection
    this._lowerBound = _.result(this, 'initialLowerBound');
    this._upperBound = execute(this, 'initialUpperBound', this._lowerBound);

    this._updateCollection();

    // If no onUpdateEvent was defined, then we set one
    // using the `throttle` method.
    if (!this.onUpdateEvent) {
      this.onUpdateEvent = this.throttle(this.throttledUpdateHandler);
    }

    // Listen to scroll events to continuously update the collection
    this.registerUpdateEvent();
  },

  collectionClass: Backbone.Collection,

  // Register the event that calls the onUpdateEvent method. The default
  // is to listen to the view's own scroll event, but it could just
  // as easily listen to any event.
  registerUpdateEvent() {

    // Execute the throttled callback on scroll
    this.$el.on('scroll', () => {
      this.onUpdateEvent();
    });
  },

  // This method is used to determine whether or not the boundaries have changed since the
  // last scroll event.
  // When dealing more complex charts or visualizations you may use something other than a flat value
  // for your boundaries. Consider if your boundaries are JavaScript objects. This method lets you determine
  // how equality should be calculated.
  compareBoundaries(a, b) {
    return a === b;
  },

  // What we use to throttle the update event callback. Use
  // requestAnimationFrame in your `onUpdateEvent` callback
  // for better performance. Refer to this blog post:
  // http://www.html5rocks.com/en/tutorials/speed/animations/
  // for proper use of rAF.
  throttle(cb) {
    return _.throttle(cb, 1000/60);
  },

  // Called at 60fps whenever the update event occurs
  throttledUpdateHandler() {

    // Pass along our arguments to the methods that calculate our boundaries
    var lowerBound = this.getLowerBound();
    var upperBound = this.getUpperBound(lowerBound);

    // We need to render if either of the boundaries have changed. If this is
    // the case, and there's already a render in the queue, then we cancel out
    // that queued render. This prevents users who are scrolling very fast
    // from getting too many renders at once. It won't render until they've
    // slowed down a bit.
    if (!this.compareBoundaries(lowerBound, this._lowerBound) || !this.compareBoundaries(upperBound, this._upperBound)) {
      if (this._deferredUpdateId) {
        clearTimeout(this._deferredUpdateId);
      }
    }

    // If the boundaries are unchanged, then we bail out early
    if (this.compareBoundaries(lowerBound, this._lowerBound) && this.compareBoundaries(upperBound, this._upperBound)) {
      return;
    }

    // Update our indices
    this._lowerBound = lowerBound;
    this._upperBound = upperBound;

    // Defer an update for 50ms. This prevents many renders when scrolling fast.
    this._deferredUpdateId = setTimeout(() => {
      this._updateCollection();
    }, 50);
  },<commit_msg>Add `isSmallChange` method.<commit_after>import _ from 'underscore';
import Backbone from 'backbone';
import Mn from 'backbone.marionette';

// Similar to _.result, but it passes additional arguments when the property is a method
function execute(target, prop, ...args) {
  return _.isFunction(target[prop]) ? target[prop](...args) : target[prop];
}

Mn.SlidingView = Mn.CollectionView.extend({
  constructor(options = {}) {

    // Throw an error if passed a `collection` option. SlidingView
    // does not follow the same API as CollectionView, so we want
    // to catch errors early on
    if (options.collection) {
      throw new Error('Do not pass a `collection` option to SlidingView.');
    }

    // Store the referenceCollection on the SlidingView
    if (options.referenceCollection) {
      this.referenceCollection = options.referenceCollection;
    }

    // Set the collection to be a new empty collection
    this.collection = new this.collectionClass();

    Mn.CollectionView.prototype.constructor.apply(this, arguments);

    // Get our initial boundaries, and then update the collection
    this._lowerBound = _.result(this, 'initialLowerBound');
    this._upperBound = execute(this, 'initialUpperBound', this._lowerBound);

    this._updateCollection();

    // If no onUpdateEvent was defined, then we set one
    // using the `throttle` method.
    if (!this.onUpdateEvent) {
      this.onUpdateEvent = this.throttle(this.throttledUpdateHandler);
    }

    // Listen to scroll events to continuously update the collection
    this.registerUpdateEvent();
  },

  collectionClass: Backbone.Collection,

  // Register the event that calls the onUpdateEvent method. The default
  // is to listen to the view's own scroll event, but it could just
  // as easily listen to any event.
  registerUpdateEvent() {

    // Execute the throttled callback on scroll
    this.$el.on('scroll', () => {
      this.onUpdateEvent();
    });
  },

  // Whether or not the latest scroll was small enough to be rendered
  // immediately. Accepts a function argument that receives the old and
  // new boundaries as an object. Refer to the docs for more.
  isSmallChange: false,

  // This method is used to determine whether or not the boundaries have changed since the
  // last scroll event.
  // When dealing more complex charts or visualizations you may use something other than a flat value
  // for your boundaries. Consider if your boundaries are JavaScript objects. This method lets you determine
  // how equality should be calculated.
  compareBoundaries(a, b) {
    return a === b;
  },

  // What we use to throttle the update event callback. Use
  // requestAnimationFrame in your `onUpdateEvent` callback
  // for better performance. Refer to this blog post:
  // http://www.html5rocks.com/en/tutorials/speed/animations/
  // for proper use of rAF.
  throttle(cb) {
    return _.throttle(cb, 1000/60);
  },

  // Called at 60fps whenever the update event occurs
  throttledUpdateHandler() {

    // Pass along our arguments to the methods that calculate our boundaries
    var lowerBound = this.getLowerBound();
    var upperBound = this.getUpperBound(lowerBound);

    // We need to render if either of the boundaries have changed. If this is
    // the case, and there's already a render in the queue, then we cancel out
    // that queued render. This prevents users who are scrolling very fast
    // from getting too many renders at once. It won't render until they've
    // slowed down a bit.
    if (!this.compareBoundaries(lowerBound, this._lowerBound) || !this.compareBoundaries(upperBound, this._upperBound)) {
      if (this._deferredUpdateId) {
        clearTimeout(this._deferredUpdateId);
      }
    }

    // If the boundaries are unchanged, then we bail out early
    if (this.compareBoundaries(lowerBound, this._lowerBound) && this.compareBoundaries(upperBound, this._upperBound)) {
      return;
    }

    var oldLowerBound = this._lowerBound;
    var oldUpperBound = this._upperBound;
    this._lowerBound = lowerBound;
    this._upperBound = upperBound;

    // Determine if the change is small enough to be rendered immediately
    var isSmallChange = execute(this, 'isSmallChange', {
      oldLowerBound, oldUpperBound,
      lowerBound, upperBound
    });

    if (isSmallChange) {
      this._updateCollection();
    }

    // Defer an update for 50ms. This prevents many renders when scrolling fast.
    else {
      this._deferredUpdateId = setTimeout(() => {
        this._updateCollection();
      }, 50);
    }
  },
{'fraction_non_alphanumeric': 0.09239957840496545, 'fraction_numerical': 0.0030448530272865677, 'mean_word_length': 3.1862745098039214, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '100756', 'n_tokens_mistral': 2343, 'n_tokens_neox': 2248, 'n_words': 865}