<commit_before>var d3 = require('d3')
  , update = require('./update')
  , startMs = 300
  , threshold = 10

var Dnd = function (tree) {
  var self = this
  this.tree = tree
  this.updater = update(tree)
  this.timeout = null
  this.traveler = null
  this.maxY = 0

  /*
   * Expose public functions used by the d3 drag listener,
   * passing the node (`this`) into each of our private handlers
   */
  this.start = function (d, i) {
    self._start(d, i, this)
  }

  this.drag = function (d, i) {
    self._drag(d, i, this)
  }

  this.end = function (d, i) {
    self._end(d, i, this)
  }
}

Dnd.prototype._createTraveler = function (d, i, node) {
  this.timeout = null
  var placeholder = d3.select(node)
                       .classed('placeholder', true)

  this.traveler = d3.select(document.createElement('div'))
               .attr('class', 'node traveling-node')
               .classed('forest-traveler', this.tree.options.forest)
               .attr('style', placeholder.attr('style'))
               .html(placeholder.node().innerHTML)
               .datum({
                 _source: d,
                 _initialY: d._y,
                 _initialParent: d.parent && d.parent.id,
                 _initialIndex: d.parent && d.parent._allChildren.indexOf(d),
                 i: i,
                 embedded: false
               })

  this.tree.el.node().appendChild(this.traveler.node())

  if (d.children) {
    this.tree.toggle(d)
  }
}

Dnd.prototype._start = function (d, i, node) {
  if (!this.tree.isEditable()) {
    return
  }

  this.tree.el.select('.tree').classed('dragging', true)
  d3.event.sourceEvent.stopPropagation() // prevent clicks if they are dragging

  if (!this.tree.options.forest && d.y === 0) {
    // prevent the root from moving in non forest trees
    return
  }

  this.timeout = window.setTimeout(this._createTraveler.bind(this, d, i, node), startMs)

  // Set maxY to be the bottom of the tree
  this.maxY = this.tree.node.data()[this.tree.node.data().length - 1]._y
}

Dnd.prototype._drag = function (d, i, node) {
  if (!this.tree.el.select('.tree').classed('dragging')) {
    return
  }

  if (!this.tree.options.forest && d.y === 0) {
    // prevent the root from moving in non forest trees
    return
  }

  if (this.timeout) {
    window.clearTimeout(this.timeout)
    this._createTraveler.call(this, d, i, node)
  }
  var self = this

  this.traveler.datum(function (d) {
    // Set _y to the be max of the root node (so it's not above root) and the center of the node
    //  and the min of that value and the last node's bottom pixel
    var lowerBound = self.maxY + self.tree.options.height
      , upperBound = self.tree.options.forest ? 0 : self.tree.options.height / 2

    d._y = Math.min(Math.max(d3.event.y - (self.tree.options.height / 2), upperBound), lowerBound)
    var prev = d.i
    // Set this index to where it would be in the tree
    d.i = Math.min(~~((d._y + (self.tree.options.height / 2)) / self.tree.options.height), self.tree.node.size() - 1) // can't be greater than the max index

    var source = d._source
      , ci = d.i - prev // change in i
      , before = null
      , dropzone = null
      , embed = false

    if (self.tree.options.forest && d.i === 0) {
      // new top root
      before = {} // mock this thing
      dropzone = d3.select(self.tree.node[0][Math.max(d.i)]).datum()
    } else {
      before = d3.select(self.tree.node[0][Math.max(d.i - 1, 0)]).datum()
      dropzone = d3.select(self.tree.node[0][Math.max(d.i, 0)]).datum()
    }

    var diff = d._y % (before._y + (self.tree.options.height / 2))
    if (diff && diff <= threshold) {
      embed = true
    }

    if (before.children) {
      if (before.children.length > 1) {
        embed = true
      }
      if (before.children.length == 1 && before.children[0] != source) {
        embed = true
      }
    }

    if (ci || d.embedded != embed) {

      // Clean up previous _collapsedChildren on the last parent
      if (source.parent && source.parent._collapsedChildren) {
        source.parent._allChildren = source.parent._collapsedChildren
        source.parent._collapsedChildren = null
        source.parent.collapsed = true
      }

      // Remove the node from its previous parent
      if (self.tree.options.forest && !source.parent) {
        // forest tree w/ no parent means this goes as a new root
        self.tree.root.splice(self.tree.root.indexOf(source), 1)
      } else {
        source.parent._allChildren.splice(source.parent._allChildren.indexOf(source), 1)
      }
<commit_msg>Only remove the node from its parent if it's there.<commit_after>var d3 = require('d3')
  , update = require('./update')
  , startMs = 300
  , threshold = 10

var Dnd = function (tree) {
  var self = this
  this.tree = tree
  this.updater = update(tree)
  this.timeout = null
  this.traveler = null
  this.maxY = 0

  /*
   * Expose public functions used by the d3 drag listener,
   * passing the node (`this`) into each of our private handlers
   */
  this.start = function (d, i) {
    self._start(d, i, this)
  }

  this.drag = function (d, i) {
    self._drag(d, i, this)
  }

  this.end = function (d, i) {
    self._end(d, i, this)
  }
}

Dnd.prototype._createTraveler = function (d, i, node) {
  this.timeout = null
  var placeholder = d3.select(node)
                       .classed('placeholder', true)

  this.traveler = d3.select(document.createElement('div'))
               .attr('class', 'node traveling-node')
               .classed('forest-traveler', this.tree.options.forest)
               .attr('style', placeholder.attr('style'))
               .html(placeholder.node().innerHTML)
               .datum({
                 _source: d,
                 _initialY: d._y,
                 _initialParent: d.parent && d.parent.id,
                 _initialIndex: d.parent && d.parent._allChildren.indexOf(d),
                 i: i,
                 embedded: false
               })

  this.tree.el.node().appendChild(this.traveler.node())

  if (d.children) {
    this.tree.toggle(d)
  }
}

Dnd.prototype._start = function (d, i, node) {
  if (!this.tree.isEditable()) {
    return
  }

  this.tree.el.select('.tree').classed('dragging', true)
  d3.event.sourceEvent.stopPropagation() // prevent clicks if they are dragging

  if (!this.tree.options.forest && d.y === 0) {
    // prevent the root from moving in non forest trees
    return
  }

  this.timeout = window.setTimeout(this._createTraveler.bind(this, d, i, node), startMs)

  // Set maxY to be the bottom of the tree
  this.maxY = this.tree.node.data()[this.tree.node.data().length - 1]._y
}

Dnd.prototype._drag = function (d, i, node) {
  if (!this.tree.el.select('.tree').classed('dragging')) {
    return
  }

  if (!this.tree.options.forest && d.y === 0) {
    // prevent the root from moving in non forest trees
    return
  }

  if (this.timeout) {
    window.clearTimeout(this.timeout)
    this._createTraveler.call(this, d, i, node)
  }
  var self = this

  this.traveler.datum(function (d) {
    // Set _y to the be max of the root node (so it's not above root) and the center of the node
    //  and the min of that value and the last node's bottom pixel
    var lowerBound = self.maxY + self.tree.options.height
      , upperBound = self.tree.options.forest ? 0 : self.tree.options.height / 2

    d._y = Math.min(Math.max(d3.event.y - (self.tree.options.height / 2), upperBound), lowerBound)
    var prev = d.i
    // Set this index to where it would be in the tree
    d.i = Math.min(~~((d._y + (self.tree.options.height / 2)) / self.tree.options.height), self.tree.node.size() - 1) // can't be greater than the max index

    var source = d._source
      , ci = d.i - prev // change in i
      , before = null
      , dropzone = null
      , embed = false

    if (self.tree.options.forest && d.i === 0) {
      // new top root
      before = {} // mock this thing
      dropzone = d3.select(self.tree.node[0][Math.max(d.i)]).datum()
    } else {
      before = d3.select(self.tree.node[0][Math.max(d.i - 1, 0)]).datum()
      dropzone = d3.select(self.tree.node[0][Math.max(d.i, 0)]).datum()
    }

    var diff = d._y % (before._y + (self.tree.options.height / 2))
    if (diff && diff <= threshold) {
      embed = true
    }

    if (before.children) {
      if (before.children.length > 1) {
        embed = true
      }
      if (before.children.length == 1 && before.children[0] != source) {
        embed = true
      }
    }

    if (ci || d.embedded != embed) {

      // Clean up previous _collapsedChildren on the last parent
      if (source.parent && source.parent._collapsedChildren) {
        source.parent._allChildren = source.parent._collapsedChildren
        source.parent._collapsedChildren = null
        source.parent.collapsed = true
      }

      // Remove the node from its previous parent
      if (self.tree.options.forest && !source.parent) {
        // forest tree w/ no parent means this goes as a new root
        self.tree.root.splice(self.tree.root.indexOf(source), 1)
      } else {
        var i = source.parent._allChildren.indexOf(source)
        if (i !== -1) {
          source.parent._allChildren.splice(i, 1)
        }
      }

{'fraction_non_alphanumeric': 0.14154212692224388, 'fraction_numerical': 0.008122157244964262, 'mean_word_length': 2.242626404494382, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, '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': '1239008', 'n_tokens_mistral': 3100, 'n_tokens_neox': 2966, 'n_words': 767}