<commit_before>var moment    = require('moment');
var React     = require('react/addons');
var PropTypes = React.PropTypes;
var _         = require('underscore');

var DEFAULT_ITEM = {
  name     : '',
  classes  : '',
  cellRefs : []
};

var HvReactAgenda = React.createClass({

  propTypes: {
    locale            : PropTypes.string.isRequired,
    startDate         : PropTypes.instanceOf(Date),
    startAtTime       : PropTypes.number.isRequired,
    rowsPerHour       : PropTypes.oneOf([1,2,3,4]).isRequired,
    numberOfDays      : PropTypes.oneOf([1,2,3,4,5,6,7]).isRequired,
    items             : PropTypes.arrayOf(PropTypes.shape({
      name            : PropTypes.string,
      startDateTime   : PropTypes.instanceOf(Date).isRequired,
      endDateTime     : PropTypes.instanceOf(Date).isRequired,
      classes         : PropTypes.string
    })),
    onItemSelect      : PropTypes.func,
    onDateRangeChange : PropTypes.func
  },

  getDefaultProps: function() {
    return {
      locale       : 'en',
      startAtTime  : 8,
      rowsPerHour  : 4,
      numberOfDays : 5
    }
  },

  getInitialState: function() {
    return {
      date              : moment(),
      items             : {},
      itemOverlayStyles : {},
      highlightedCells  : [],
      focusedCell       : null
    }
  },

  componentWillMount: function() {
    if (this.props.startDate) {
      this.setState({date: moment(this.props.startDate)});
    }

    if (this.props.items) {
      this.setState({items: this.mapItems(this.props.items)});
    }
  },

  componentDidMount: function() {
    // move to start time (this only happens once)
    var scrollContainer = this.refs.agendaScrollContainer.getDOMNode();
    var rowToScrollTo   = this.refs["hour-" + this.props.startAtTime].getDOMNode();
    scrollContainer.scrollTop = rowToScrollTo.offsetTop;
  },

  componentWillReceiveProps: function(nextProps) {
    if (nextProps.items) {
      this.setState({items: this.mapItems(nextProps.items)});
    }

    if (nextProps.startDate) {
      this.setState({date: moment(nextProps.startDate)});
    }
  },

  nextRange: function() {
    this.setState({date: this.state.date.add(this.props.numberOfDays, 'days')});

    var newStart = moment(this.state.date);
    var newEnd   = moment(newStart).add(this.props.numberOfDays-1, 'days');

    if (this.props.onDateRangeChange) {
      this.props.onDateRangeChange(
        newStart.toDate(),
        newEnd.toDate()
      );
    }
  },

  prevRange: function() {
    this.setState({date: this.state.date.subtract(this.props.numberOfDays, 'days')});

    var newStart = moment(this.state.date);
    var newEnd   = moment(newStart).add(this.props.numberOfDays-1, 'days');

    if (this.props.onDateRangeChange) {
      this.props.onDateRangeChange(
        newStart.toDate(),
        newEnd.toDate()
      );
    }
  },

  mapItems: function(itemsArray) {
    var itemsMap = {};
    itemsArray.forEach(function(item) {
      var interval      = (60/this.props.rowsPerHour);
      var offsetMinutes = item.startDateTime.getMinutes() % interval;
      var start         = moment(item.startDateTime).subtract(offsetMinutes, "minutes").toDate();
      var end           = item.endDateTime;
      var duration      = moment.duration(moment(end).diff(moment(start)));
      var rows          = Math.ceil(duration.asHours()/(interval/60));

      var cellRefs = [];
      for (var i = 0; i < rows; i++) {
        var ref = moment(start).add(i*interval, 'minutes').format('YYYY-MM-DDTHH:mm:ss');
        cellRefs.push(ref);
      }

      cellRefs.forEach(function(ref) {
        var newItem = _.omit(item, 'classes');
        newItem.classes  = (itemsMap[ref]) ? (itemsMap[ref].classes + ' ' + item.classes) : (item.classes || '');
        newItem.cellRefs = cellRefs;
        itemsMap[ref] = newItem;
      });<commit_msg>Sort item array by date so that item hovering works with item arrays that are out of order.<commit_after>var moment    = require('moment');
var React     = require('react/addons');
var PropTypes = React.PropTypes;
var _         = require('underscore');

var DEFAULT_ITEM = {
  name     : '',
  classes  : '',
  cellRefs : []
};

var HvReactAgenda = React.createClass({

  propTypes: {
    locale            : PropTypes.string.isRequired,
    startDate         : PropTypes.instanceOf(Date),
    startAtTime       : PropTypes.number.isRequired,
    rowsPerHour       : PropTypes.oneOf([1,2,3,4]).isRequired,
    numberOfDays      : PropTypes.oneOf([1,2,3,4,5,6,7]).isRequired,
    items             : PropTypes.arrayOf(PropTypes.shape({
      name            : PropTypes.string,
      startDateTime   : PropTypes.instanceOf(Date).isRequired,
      endDateTime     : PropTypes.instanceOf(Date).isRequired,
      classes         : PropTypes.string
    })),
    onItemSelect      : PropTypes.func,
    onDateRangeChange : PropTypes.func
  },

  getDefaultProps: function() {
    return {
      locale       : 'en',
      startAtTime  : 8,
      rowsPerHour  : 4,
      numberOfDays : 5
    }
  },

  getInitialState: function() {
    return {
      date              : moment(),
      items             : {},
      itemOverlayStyles : {},
      highlightedCells  : [],
      focusedCell       : null
    }
  },

  componentWillMount: function() {
    if (this.props.startDate) {
      this.setState({date: moment(this.props.startDate)});
    }

    if (this.props.items) {
      this.setState({items: this.mapItems(this.props.items)});
    }
  },

  componentDidMount: function() {
    // move to start time (this only happens once)
    var scrollContainer = this.refs.agendaScrollContainer.getDOMNode();
    var rowToScrollTo   = this.refs["hour-" + this.props.startAtTime].getDOMNode();
    scrollContainer.scrollTop = rowToScrollTo.offsetTop;
  },

  componentWillReceiveProps: function(nextProps) {
    if (nextProps.items) {
      this.setState({items: this.mapItems(nextProps.items)});
    }

    if (nextProps.startDate) {
      this.setState({date: moment(nextProps.startDate)});
    }
  },

  nextRange: function() {
    this.setState({date: this.state.date.add(this.props.numberOfDays, 'days')});

    var newStart = moment(this.state.date);
    var newEnd   = moment(newStart).add(this.props.numberOfDays-1, 'days');

    if (this.props.onDateRangeChange) {
      this.props.onDateRangeChange(
        newStart.toDate(),
        newEnd.toDate()
      );
    }
  },

  prevRange: function() {
    this.setState({date: this.state.date.subtract(this.props.numberOfDays, 'days')});

    var newStart = moment(this.state.date);
    var newEnd   = moment(newStart).add(this.props.numberOfDays-1, 'days');

    if (this.props.onDateRangeChange) {
      this.props.onDateRangeChange(
        newStart.toDate(),
        newEnd.toDate()
      );
    }
  },

  mapItems: function(itemsArray) {
    var itemsMap = {};

    itemsArray = itemsArray.sort(function(a, b) {
      return a.startDateTime - b.startDateTime;
    });

    itemsArray.forEach(function(item) {
      var interval      = (60/this.props.rowsPerHour);
      var offsetMinutes = item.startDateTime.getMinutes() % interval;
      var start         = moment(item.startDateTime).subtract(offsetMinutes, "minutes").toDate();
      var end           = item.endDateTime;
      var duration      = moment.duration(moment(end).diff(moment(start)));
      var rows          = Math.ceil(duration.asHours()/(interval/60));

      var cellRefs = [];
      for (var i = 0; i < rows; i++) {
        var ref = moment(start).add(i*interval, 'minutes').format('YYYY-MM-DDTHH:mm:ss');
        cellRefs.push(ref);
      }

      cellRefs.forEach(function(ref) {
        var newItem = _.omit(item, 'classes');
        newItem.classes  = (itemsMap[ref]) ? (itemsMap[ref].classes + ' ' + item.classes) : (item.classes || '');
        newItem.cellRefs = cellRefs;
        itemsMap[ref] = newItem;
      });
{'fraction_non_alphanumeric': 0.14056174089068826, 'fraction_numerical': 0.005313765182186235, 'mean_word_length': 2.5720741075463174, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, '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': '2939280', 'n_tokens_mistral': 2518, 'n_tokens_neox': 2488, 'n_words': 405}