<commit_before>import Ember from 'ember';
const { Mixin, $, computed, run } = Ember;

export default Mixin.create({
  classNames: ['sortable-item'],
  classNameBindings: ['isDragging'],

  /**
    Group to which the item belongs.

    @property group
    @type SortableGroup
    @default null
  */
  group: null,

  /**
    Model which the item represents.

    @property model
    @type Object
    @default null
  */
  model: null,

  /**
    True if the item is currently being dragged.

    @property isDragging
    @type Boolean
    @default false
  */
  isDragging: false,

  /**
    The frequency with which the group is informed
    that an update is required.

    @property updateInterval
    @type Number
    @default 125
  */
  updateInterval: 125,

  /**
    True if the item transitions with animation.

    @property isAnimated
    @type Boolean
  */
  isAnimated: computed(function() {
    let el = this.$();
    let property = el.css('transition-property');
    let duration = parseFloat(el.css('transition-duration'));

    return property.match(/all|transform/) && duration > 0;
  }).volatile(),

  /**
    Vertical position of the item relative to its offset parent.

    @property y
    @type Number
  */
  y: computed(function(_, value) {
    if (arguments.length === 2) {
      this._y = value;
      this._scheduleApplyPosition();
    }

    if (this._y !== undefined) {
      return this._y;
    } else {
      return this.element.offsetTop;
    }
  }),

  /**
    Height of the item including margins.

    @property height
    @type Number
  */
  height: computed(function() {
    let height = this.$().outerHeight();
    let marginBottom = parseFloat(this.$().css('margin-bottom'));
    return height + marginBottom;
  }).volatile(),

  /**
    @method didInsertElement
  */
  didInsertElement() {
    this._tellGroup('registerItem', this);
  },

  /**
    @method willDestroyElement
  */
  willDestroyElement() {
    this._tellGroup('deregisterItem', this);
  },

  /**
    @method mouseDown
  */
  mouseDown(event) {
    this._startDrag(event);
  },

  /**
    @method touchStart
  */
  touchStart(event) {
    this._startDrag(event);
  },

  /**
    @method _startDrag
    @private
  */
  _startDrag(event) {
    event.preventDefault();
    event.stopPropagation();

    let updateInterval = this.get('updateInterval');
    let originalElementY = this.get('y');
    let dragStartY = getY(event);

    let drag = event => {
      let dy = getY(event) - dragStartY;
      let y = originalElementY + dy;

      this.set('y', y);
      run.throttle(this, '_tellGroup', 'update', updateInterval);
    };

    let drop = () => {
      $(window)
        .off('mousemove touchmove', drag)
        .off('mouseup touchend', drop);

      if (!this.element) { return; }

      this.set('isDragging', false);
      this._tellGroup('update');

      run.next(() => {
        if (this.get('isAnimated')) {
          this.$().one('transitionend', () => {
            this._tellGroup('commit');
          });
        } else {
          this._tellGroup('commit');
        }
      });<commit_msg>Add protection against rapid double-drag<commit_after>import Ember from 'ember';
const { Mixin, $, computed, run } = Ember;

export default Mixin.create({
  classNames: ['sortable-item'],
  classNameBindings: ['isDragging'],

  /**
    Group to which the item belongs.

    @property group
    @type SortableGroup
    @default null
  */
  group: null,

  /**
    Model which the item represents.

    @property model
    @type Object
    @default null
  */
  model: null,

  /**
    True if the item is currently being dragged.

    @property isDragging
    @type Boolean
    @default false
  */
  isDragging: false,

  /**
    True if the item is currently dropping.

    @property isDropping
    @type Boolean
    @default false
  */
  isDropping: false,

  /**
    The frequency with which the group is informed
    that an update is required.

    @property updateInterval
    @type Number
    @default 125
  */
  updateInterval: 125,

  /**
    True if the item transitions with animation.

    @property isAnimated
    @type Boolean
  */
  isAnimated: computed(function() {
    let el = this.$();
    let property = el.css('transition-property');
    let duration = parseFloat(el.css('transition-duration'));

    return property.match(/all|transform/) && duration > 0;
  }).volatile(),

  /**
    Vertical position of the item relative to its offset parent.

    @property y
    @type Number
  */
  y: computed(function(_, value) {
    if (arguments.length === 2) {
      this._y = value;
      this._scheduleApplyPosition();
    }

    if (this._y !== undefined) {
      return this._y;
    } else {
      return this.element.offsetTop;
    }
  }),

  /**
    Height of the item including margins.

    @property height
    @type Number
  */
  height: computed(function() {
    let height = this.$().outerHeight();
    let marginBottom = parseFloat(this.$().css('margin-bottom'));
    return height + marginBottom;
  }).volatile(),

  /**
    @method didInsertElement
  */
  didInsertElement() {
    this._tellGroup('registerItem', this);
  },

  /**
    @method willDestroyElement
  */
  willDestroyElement() {
    this._tellGroup('deregisterItem', this);
  },

  /**
    @method mouseDown
  */
  mouseDown(event) {
    this._startDrag(event);
  },

  /**
    @method touchStart
  */
  touchStart(event) {
    this._startDrag(event);
  },

  /**
    @method _startDrag
    @private
  */
  _startDrag(event) {
    event.preventDefault();
    event.stopPropagation();

    if (this.get('isDragging')) { return; }
    if (this.get('isDropping')) { return; }

    let updateInterval = this.get('updateInterval');
    let originalElementY = this.get('y');
    let dragStartY = getY(event);

    let drag = event => {
      let dy = getY(event) - dragStartY;
      let y = originalElementY + dy;

      this.set('y', y);
      run.throttle(this, '_tellGroup', 'update', updateInterval);
    };

    let drop = () => {
      $(window)
        .off('mousemove touchmove', drag)
        .off('mouseup touchend', drop);

      if (!this.element) { return; }

      this.set('isDragging', false);
      this.set('isDropping', false);

      this._tellGroup('update');

      run.next(() => {
        if (this.get('isAnimated')) {
          this.$().one('transitionend', complete);
        } else {
          complete();
        }
      });
    };

    let complete = () => {
      this.set('isDropping', false);
      this._tellGroup('commit');
{'fraction_non_alphanumeric': 0.14244274809160307, 'fraction_numerical': 0.0024427480916030535, 'mean_word_length': 2.462473572938689, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '6317829', 'n_tokens_mistral': 2057, 'n_tokens_neox': 1960, 'n_words': 496}