<commit_before># TODO: scope this class to work only inside the element  "#webconference_invitation",
#   otherwise it will run in other cases as well

usersSelector = '#invite_users'
searchUsersUrl = '/users/select?limit=7'
startsOnSelector = '#invite_starts_on'
endsOnSelector = '#invite_ends_on'
durationSelector = '#invite_duration .duration'
defaultDuration = 60*60 # 1h in secs
previousDuration = null

mconf.CustomBigbluebuttonRooms or= {}

class mconf.CustomBigbluebuttonRooms.Invitation

  @bind: ->
    bindUsers()
    bindDates()

  @unbind: ->
    # TODO: can it be done?

bindUsers = ->
  $(usersSelector).select2
    minimumInputLength: 1
    width: 'resolve'
    multiple: true
    formatSearching: -> I18n.t('custom_bigbluebutton_rooms.invitation_form.users.searching')
    formatInputTooShort: -> I18n.t('custom_bigbluebutton_rooms.invitation_form.users.hint')
    formatNoMatches: -> I18n.t('custom_bigbluebutton_rooms.invitation_form.users.no_results')
    tags: true
    tokenSeparators: [",", ";"]
    createSearchChoice: (term, data) ->
      if mconf.Base.validateEmail(term)
        { id: term, text: term }
    formatSelection: (object, container) ->
      if object.name?
        object.name
      else
        object.text
    ajax:
      url: searchUsersUrl
      dataType: "json"
      data: (term, page) ->
        q: term # search term
      results: (data, page) -> # parse the results into the format expected by Select2.
        results: data

# TODO: make this a method in the class, and the inputs class variables
bindDates = ->

  # TODO: find these inputs automatically by putting attrs on them
  inputStartDate = $(startsOnSelector)[0]
  inputStartTime = $(".invite_starts_on_time")[0]
  inputEndDate = $(endsOnSelector)[0]
  inputEndTime = $(".invite_ends_on_time")[0]

  startInput = new mconf.DateTimeInput(inputStartDate, inputStartTime)
  endInput = new mconf.DateTimeInput(inputEndDate, inputEndTime)

  initializeDates(startInput, endInput)

  startInput.on "change", ->
    adjustEndOnStartChange(startInput, endInput)
    endInput.setMinDate(startInput.getDate())
    storeDuration(startInput, endInput)
    updateDuration()

  endInput.on "change", ->
    adjustEndOnEndChange(startInput, endInput)
    storeDuration(startInput, endInput)
    updateDuration()

# Initialize the dates with default values
initializeDates = (startInput, endInput) ->
  start = new Date()

  # start at the current time
  startInput.setDate(start)

  # ends at the current time plus a standard duration
  end = addDuration(start, defaultDuration)
  endInput.setDate(end)

  # the end can never be before the start
  endInput.setMinDate(startInput.getDate())

  # store the initial duration and update the label
  storeDuration(startInput, endInput)
  updateDuration()

# Stores the current duration in seconds
storeDuration = (startInput, endInput) ->
  previousDuration = (endInput.getDate() - startInput.getDate()) / 1000 # in secs

# Updates the text in the label with the duration using the start and end dates
# set in the inputs.
updateDuration = ->
  duration = previousDuration
  duration = ignoreSeconds(new Date(duration * 1000)).getTime()
  if _.isFinite(duration)
    duration = moment.duration(Math.abs(duration))
    text = "#{Math.floor(duration.as("hours"))}h"
    text = text + " #{duration.minutes()}m" unless duration.minutes() is 0
    $(durationSelector).text("#{text}")
    $(durationSelector).removeClass("error")
  else
    $(durationSelector).text("?")

# Adjusts the end date according to the start date when the start date is changed
# by the user. The end can never be lower than the start date, and will also sometimes
# be automatically set to maintain the duration previously specified.
adjustEndOnStartChange = (startInput, endInput) ->

  # setting a start to be after the end, makes the end jump forward and
  # keeps the previous duration (if any)
  if endInput.getDate() < startInput.getDate()
    if previousDuration?
      endInput.setDate(addDuration(startInput.getDate(), previousDuration))
    else
      endInput.setDate(addDuration(startInput.getDate(), defaultDuration))

  # always keep the previous duration if it is set
  else if previousDuration?
    endInput.setDate(addDuration(startInput.getDate(), previousDuration))

  # no previous duration, use the default
  else
    endInput.setDate(addDuration(startInput.getDate(), defaultDuration))

# Adjusts the end date according when the end date input is changed by the user.
adjustEndOnEndChange = (startInput, endInput) ->

  # don't ever let the end be before the start
  if endInput.getDate() < startInput.getDate()
    endInput.setDate(startInput.getDate())


# Adds 'duration' seconds to a Date object 'date'.
addDuration = (date, duration) ->
  moment(date).add(duration, 'seconds').toDate()

# Nullifies the seconds and milliseconds on a Date object
ignoreSeconds = (date) ->
  time = Math.floor(date.getTime() / 60000) * 60000<commit_msg>Restrict the scope of action of the js in invitation to webconfs<commit_after>container = '#webconference-invitation'
usersSelector = '#invite_users'
searchUsersUrl = '/users/select?limit=7'
startsOnSelector = '#invite_starts_on'
endsOnSelector = '#invite_ends_on'
durationSelector = '#invite_duration .duration'
defaultDuration = 60*60 # 1h in secs
previousDuration = null

mconf.CustomBigbluebuttonRooms or= {}

class mconf.CustomBigbluebuttonRooms.Invitation

  @bind: ->
    invitation = new mconf.CustomBigbluebuttonRooms.Invitation()
    invitation.bindUsers()
    invitation.bindDates()

  @unbind: ->
    # TODO: can it be done?

  bindUsers: ->
    $(usersSelector, container).select2
      minimumInputLength: 1
      width: 'resolve'
      multiple: true
      formatSearching: -> I18n.t('custom_bigbluebutton_rooms.invitation_form.users.searching')
      formatInputTooShort: -> I18n.t('custom_bigbluebutton_rooms.invitation_form.users.hint')
      formatNoMatches: -> I18n.t('custom_bigbluebutton_rooms.invitation_form.users.no_results')
      tags: true
      tokenSeparators: [",", ";"]
      createSearchChoice: (term, data) ->
        if mconf.Base.validateEmail(term)
          { id: term, text: term }
      formatSelection: (object, container) ->
        if object.name?
          object.name
        else
          object.text
      ajax:
        url: searchUsersUrl
        dataType: "json"
        data: (term, page) ->
          q: term # search term
        results: (data, page) -> # parse the results into the format expected by Select2.
          results: data

  bindDates: ->
    inputStartDate = $(startsOnSelector, container)[0]
    inputStartTime = $(".invite_starts_on_time", container)[0]
    inputEndDate = $(endsOnSelector, container)[0]
    inputEndTime = $(".invite_ends_on_time", container)[0]

    if inputStartDate && inputStartTime && inputEndDate && inputEndTime

      @startInput = new mconf.DateTimeInput(inputStartDate, inputStartTime)
      @endInput = new mconf.DateTimeInput(inputEndDate, inputEndTime)

      @_initializeDates()

      @startInput.on "change", =>
        @_adjustEndOnStartChange()
        @endInput.setMinDate(@startInput.getDate())
        @_storeDuration()
        @_updateDuration()

      @endInput.on "change", =>
        @_adjustEndOnEndChange()
        @_storeDuration()
        @_updateDuration()


  # Initialize the dates with default values
  _initializeDates: ->
    start = new Date()

    # start at the current time
    @startInput.setDate(start)

    # ends at the current time plus a standard duration
    end = addDuration(start, defaultDuration)
    @endInput.setDate(end)

    # the end can never be before the start
    @endInput.setMinDate(@startInput.getDate())

    # store the initial duration and update the label
    @_storeDuration()
    @_updateDuration()

  # Stores the current duration in seconds
  _storeDuration: ->
    previousDuration = (@endInput.getDate() - @startInput.getDate()) / 1000 # in secs

  # Updates the text in the label with the duration using the start and end dates
  # set in the inputs.
  _updateDuration: ->
    duration = previousDuration
    duration = ignoreSeconds(new Date(duration * 1000)).getTime()
    if _.isFinite(duration)
      duration = moment.duration(Math.abs(duration))
      text = "#{Math.floor(duration.as("hours"))}h"
      text = text + " #{duration.minutes()}m" unless duration.minutes() is 0
      $(durationSelector).text("#{text}")
      $(durationSelector).removeClass("error")
    else
      $(durationSelector).text("?")

  # Adjusts the end date according to the start date when the start date is changed
  # by the user. The end can never be lower than the start date, and will also sometimes
  # be automatically set to maintain the duration previously specified.
  _adjustEndOnStartChange: ->

    # setting a start to be after the end, makes the end jump forward and
    # keeps the previous duration (if any)
    if @endInput.getDate() < @startInput.getDate()
      if previousDuration?
        @endInput.setDate(addDuration(@startInput.getDate(), previousDuration))
      else
        @endInput.setDate(addDuration(@startInput.getDate(), defaultDuration))

    # always keep the previous duration if it is set
    else if previousDuration?
      @endInput.setDate(addDuration(@startInput.getDate(), previousDuration))

    # no previous duration, use the default
    else
      @endInput.setDate(addDuration(@startInput.getDate(), defaultDuration))

  # Adjusts the end date according when the end date input is changed by the user.
  _adjustEndOnEndChange: ->

    # don't ever let the end be before the start
    if @endInput.getDate() < @startInput.getDate()
      @endInput.setDate(@startInput.getDate())


# Adds 'duration' seconds to a Date object 'date'.
addDuration = (date, duration) ->
  moment(date).add(duration, 'seconds').toDate()

# Nullifies the seconds and milliseconds on a Date object
ignoreSeconds = (date) ->
  time = Math.floor(date.getTime() / 60000) * 60000
{'fraction_non_alphanumeric': 0.1042332268370607, 'fraction_numerical': 0.0075878594249201275, 'mean_word_length': 3.7974137931034484, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 43, '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': '7324147', 'n_tokens_mistral': 2985, 'n_tokens_neox': 2885, 'n_words': 835}