<commit_before>getBoxCSS = (elem, absolute = false) ->
  return {
      'width': elem.width()
      'height': elem.height()
      'top': (if (absolute) then elem.offset().top else elem.position().top)
      'left': (if (absolute) then elem.offset().left else elem.position().left)
    }

defaults = {
  'draggable': true
  'disabled': false
  'labels': true
}

class Area
  @amount: 0
  constructor: (@instance, size, @draggable=true, label=true) ->
    @id = Area.amount++
    @area = $('<div>').addClass('area').css(size)
    if label
      @area.append($('<p>').addClass('name').text(@id))
    @instance.container.append(@area)

    if draggable
      @_make_draggable()

    @_trigger_event('created')

  _trigger_event: (type) ->
    @instance.elem.trigger('area-' + type, {id: @id, size: getBoxCSS(@area)})
    return

  _make_draggable: ->
    dragger = $('<div>')
      .addClass('drag-handle')
      .on 'mouseover', =>
        @area.addClass('over')
        return
      .on 'mouseleave', =>
        @area.removeClass('over')
        return

      .on 'mousedown', (e) =>
        if @instance.isDisabled() then return
        if event.which != 1 then return  # only left mouse btn
        e.stopPropagation()

        offset_x = e.pageX - @area.offset().left
        offset_y = e.pageY - @area.offset().top

        @area
          .on 'mousemove', (e) =>
            e.stopPropagation()

            new_x = e.pageX - @instance.container.offset().left - offset_x
            new_y = e.pageY - @instance.container.offset().top - offset_y
            # respect parent
            if new_x + @area.width() >= @instance.container.width() - 1 or
                new_y + @area.height() >= @instance.container.height() - 1 or
                new_x < 0 or new_y < 0
              return

            @area.css {
              'left': new_x
              'top': new_y
            }
            return

      .on 'mouseup', (e) =>
        if @instance.isDisabled() then return
        e.stopPropagation()

        @area.off 'mousemove'
        @_trigger_event('moved')
        return
    @area
      .addClass('area-draggable')
      .append(dragger)
    return

  getID: ->
    return @id

  getDimensions: ->
    return getBoxCSS(@area)

  isDraggable: ->
    return @draggable

  destroy: ->
    @area.remove()

class SelectAreas
  constructor: (@elem, options = {}) ->
    @options = $.extend(defaults, options)
    @areas = []

    # setup elements
    @selection = null
    @container = $('<div>')
      .addClass('select-areas')
      .css getBoxCSS(@elem, true)
    $('body').append(@container)

    if not @isDisabled()
      @enable()  # enable all interaction

    # register mouse events
    @container
      .on 'mousedown', (e) =>
        if @isDisabled() then return
        if event.which != 1 then return  # only left mouse btn

        # relative to container
        click_x = e.pageX - @container.offset().left
        click_y = e.pageY - @container.offset().top

        @selection = $('<div>')
          .addClass('area-create')
          .css {
            'top':    click_y
            'left':   click_x
            'width':  0
            'height': 0
          }
          .appendTo @container

        @container.on 'mousemove', (e) =>
          move_x = e.pageX - @container.offset().left
          move_y = e.pageY - @container.offset().top
          width  = Math.abs(move_x - click_x)
          height = Math.abs(move_y - click_y)

          new_x = (if (move_x < click_x) then (click_x - width) else click_x)
          new_y = (if (move_y < click_y) then (click_y - height) else click_y)

          @selection.css {
            'width': width
            'height': height
            'top': new_y
            'left': new_x
          }
          return
        return

      .on 'mouseup', (e) =>
        if @isDisabled() then return

        @container.off 'mousemove'
        if not @selection
          return

        size = getBoxCSS(@selection)
        if size.width != 0 and size.height != 0
          @areas.push new Area(@, size, @options.draggable, @options.label)
          @__labelVisibility()

        # cleanup
        @selection.remove()
        @selection = null
        return

  disable: ->
    @options.disabled = true
    @container.removeClass('area-enabled')
    return

  enable: ->
    @options.disabled = false
    @container.addClass('area-enabled')
    return

  showLabels: (show)->
    @options.labels = show
    @__labelVisibility()

  __labelVisibility: ->
    if @options.labels
      $('p.name', @container).removeClass('hide')
    else
      $('p.name', @container).addClass('hide')

  isDisabled: ->
    return @options.disabled

  removeArea: (id) ->
    toBeRemoved = []
    @areas = @areas.filter (e) -> e.getID() != id || !toBeRemoved.push e
    for area in toBeRemoved
      area.destroy()
      @elem.trigger('area-removed', id)

  getAreas: ->
    a = {}
    for area in @areas
      a[area.getID()] = area.getDimensions()
    return a


# export to global namespace
root = exports ? this
root.SelectAreas = SelectAreas


# export as jQuery plugin
jQuery.fn.extend
  selectAreas: (options) ->
    $el = $(@)
    data = $el.data('select-area')

    if not data
      $el.data 'select-area', (data = new SelectAreas(@, options))
    return data
<commit_msg>create area if selection is in progress on mousedown<commit_after>getBoxCSS = (elem, absolute = false) ->
  return {
      'width': elem.width()
      'height': elem.height()
      'top': (if (absolute) then elem.offset().top else elem.position().top)
      'left': (if (absolute) then elem.offset().left else elem.position().left)
    }

defaults = {
  'draggable': true
  'disabled': false
  'labels': true
}

class Area
  @amount: 0
  constructor: (@instance, size, @draggable=true, label=true) ->
    @id = Area.amount++
    @area = $('<div>').addClass('area').css(size)
    if label
      @area.append($('<p>').addClass('name').text(@id))
    @instance.container.append(@area)

    if draggable
      @_make_draggable()

    @_trigger_event('created')

  _trigger_event: (type) ->
    @instance.elem.trigger('area-' + type, {id: @id, size: getBoxCSS(@area)})
    return

  _make_draggable: ->
    dragger = $('<div>')
      .addClass('drag-handle')
      .on 'mouseover', =>
        @area.addClass('over')
        return
      .on 'mouseleave', =>
        @area.removeClass('over')
        return

      .on 'mousedown', (e) =>
        if @instance.isDisabled() then return
        if event.which != 1 then return  # only left mouse btn
        e.stopPropagation()

        offset_x = e.pageX - @area.offset().left
        offset_y = e.pageY - @area.offset().top

        @area
          .on 'mousemove', (e) =>
            e.stopPropagation()

            new_x = e.pageX - @instance.container.offset().left - offset_x
            new_y = e.pageY - @instance.container.offset().top - offset_y
            # respect parent
            if new_x + @area.width() >= @instance.container.width() - 1 or
                new_y + @area.height() >= @instance.container.height() - 1 or
                new_x < 0 or new_y < 0
              return

            @area.css {
              'left': new_x
              'top': new_y
            }
            return

      .on 'mouseup', (e) =>
        if @instance.isDisabled() then return
        e.stopPropagation()

        @area.off 'mousemove'
        @_trigger_event('moved')
        return
    @area
      .addClass('area-draggable')
      .append(dragger)
    return

  getID: ->
    return @id

  getDimensions: ->
    return getBoxCSS(@area)

  isDraggable: ->
    return @draggable

  destroy: ->
    @area.remove()

class SelectAreas
  constructor: (@elem, options = {}) ->
    @options = $.extend(defaults, options)
    @areas = []

    # setup elements
    @selection = null
    @container = $('<div>')
      .addClass('select-areas')
      .css getBoxCSS(@elem, true)
    $('body').append(@container)

    if not @isDisabled()
      @enable()  # enable all interaction

    # register mouse events
    @container
      .on 'mousedown', (e) =>
        if @isDisabled() then return
        if event.which != 1 then return  # only left mouse btn
        if @selection
          @container.trigger 'mouseup'

        # relative to container
        click_x = e.pageX - @container.offset().left
        click_y = e.pageY - @container.offset().top

        @selection = $('<div>')
          .addClass('area-create')
          .css {
            'top':    click_y
            'left':   click_x
            'width':  0
            'height': 0
          }
          .appendTo @container

        @container.on 'mousemove', (e) =>
          move_x = e.pageX - @container.offset().left
          move_y = e.pageY - @container.offset().top
          width  = Math.abs(move_x - click_x)
          height = Math.abs(move_y - click_y)

          new_x = (if (move_x < click_x) then (click_x - width) else click_x)
          new_y = (if (move_y < click_y) then (click_y - height) else click_y)

          @selection.css {
            'width': width
            'height': height
            'top': new_y
            'left': new_x
          }
          return
        return

      .on 'mouseup', (e) =>
        if @isDisabled() then return

        @container.off 'mousemove'
        if not @selection
          return

        size = getBoxCSS(@selection)
        if size.width != 0 and size.height != 0
          @areas.push new Area(@, size, @options.draggable, @options.label)
          @__labelVisibility()

        # cleanup
        @selection.remove()
        @selection = null
        return

  disable: ->
    @options.disabled = true
    @container.removeClass('area-enabled')
    return

  enable: ->
    @options.disabled = false
    @container.addClass('area-enabled')
    return

  showLabels: (show)->
    @options.labels = show
    @__labelVisibility()

  __labelVisibility: ->
    if @options.labels
      $('p.name', @container).removeClass('hide')
    else
      $('p.name', @container).addClass('hide')

  isDisabled: ->
    return @options.disabled

  removeArea: (id) ->
    toBeRemoved = []
    @areas = @areas.filter (e) -> e.getID() != id || !toBeRemoved.push e
    for area in toBeRemoved
      area.destroy()
      @elem.trigger('area-removed', id)

  getAreas: ->
    a = {}
    for area in @areas
      a[area.getID()] = area.getDimensions()
    return a


# export to global namespace
root = exports ? this
root.SelectAreas = SelectAreas


# export as jQuery plugin
jQuery.fn.extend
  selectAreas: (options) ->
    $el = $(@)
    data = $el.data('select-area')

    if not data
      $el.data 'select-area', (data = new SelectAreas(@, options))
    return data

{'fraction_non_alphanumeric': 0.14364075864633694, 'fraction_numerical': 0.002045370026031982, 'mean_word_length': 1.9897165091717621, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 69, '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': '753256', 'n_tokens_mistral': 3419, 'n_tokens_neox': 3329, 'n_words': 792}