<commit_before>// Vuex store getters

export function metadata (state) {
  return state.metadata
}

export function selectedSeason (state) {
  return state.selected.season
}

export function selectedRegion (state) {
  return state.selected.region
}

export function selectedWeekIdx (state) {
  return state.selected.week.idx
}

export function selectedWeekName (state) {
  if (state.selected.week.name)
    return state.selected.week.name
  else
    return 'NA'
}

export function selectedChoropleth (state) {
  return state.selected.choropleth
}

export function seasons (state) {
  // Assuming each region has all the seasons
  return state.data[0].seasons.map(s => s.id)
}

export function regions (state) {
  return state.data.map(d => d.region)
}

/**
 * Return choropleth data for model
 */
function modelChoroplethData (state, modelId, dataType, relative = false) {
  let seasonId = selectedSeason(state)

  let output = {
    data: [],
    type: 'sequential'
  }

  state.data.map(r => {
    let preds = r.seasons[seasonId].models[modelId].predictions
    let weeks = getMaxLagData(r.seasons[seasonId].actual).map(d => d.week)
  })
}

/**
 * Return data for choropleth using actual values
 */
function actualChoroplethData (state, relative = false) {
  let seasonId = selectedSeason(state)

  let output = {
    data: [],
    type: 'sequential'
  }

  state.data.map(r => {
    let values = getMaxLagData(r.seasons[seasonId].actual)

    if (relative) {
      if (r.seasons[seasonId].baseline) {
        // Rescale by baseline
        values = values.map(d => {
          return {
            week: d.week,
            data: ((d.data / r.seasons[seasonId].baseline) - 1) * 100
          }
        })
      }
      output.type = 'diverging'
    }
    output.data.push({
      region: r.subId,
      states: r.states,
      value: values
    })
  })

  output.data = output.data.slice(1) // Remove national data

  return output
}

export function choropleths (state) {
  // TODO: Parse from data

  let actualChoropleths = [
    'Actual Weighted ILI (%)',
    'Relative Weighted ILI (%)'
  ]

  modelChoroplethData(state, 0)

  return actualChoropleths
}

export function timeChart (state) {
  return state.timeChart
}

export function choropleth (state) {
  return state.choropleth
}

/**
 * Get data with maximum lag
 * First element of the lag array
 */
function getMaxLagData (actual) {
  return actual.map(d => {
    let dataToReturn = -1
    // Handle zero length values
    if (d.data.length !== 0) {
      dataToReturn = d.data[0].value
    }
    return {
      week: d.week,
      data: dataToReturn
    }
  })
}

/**
 * Trim history data to fit in length 'numWeeks'
 */
function trimHistory (historyActual, numWeeks) {
  let historyTrimmed = historyActual.slice()

  if (numWeeks == 52) {
    // Clip everyone else to remove 53rd week
    historyTrimmed = historyTrimmed.filter(d => d.week % 100 != 53)
  } else if (historyTrimmed.length == 52) {
    // Expand to add 53rd week
    // Adding a dummy year 1000, this will also help identify the adjustment
    historyTrimmed.splice(23, 0, {
      week: 100053,
      data: (historyTrimmed[22].data + historyTrimmed[23].data) / 2.0
    })
  }

  return historyTrimmed
}

/**
 * Return data subset for chart as specified in region/season selected
 */
export function timeChartData (state) {

  let regionSubset = state.data[selectedRegion(state)]
  let currentSeasonId = selectedSeason(state)
  let seasonSubset = regionSubset.seasons[currentSeasonId]

  let selectedWeeksCount = seasonSubset.actual.length

  let historicalData = []

  // Add data from history store
  for (let season of Object.keys(regionSubset.history)) {
    historicalData.push({
      id: season,
      actual: trimHistory(regionSubset.history[season], selectedWeeksCount)
    })
  }

  for (let i = 0; i < currentSeasonId; i++) {
    historicalData.push({
      id: regionSubset.seasons[i].id,
      actual: trimHistory(getMaxLagData(regionSubset.seasons[i].actual),
                          selectedWeeksCount)
    })
  }

  return {
    region: regionSubset.subId, // Submission ids are concise
    observed: seasonSubset.actual,
    actual: getMaxLagData(seasonSubset.actual), // Using this to avoid confusion
    baseline: seasonSubset.baseline,
    models: seasonSubset.models, // All model predictions
    history: historicalData
  }
}

/**
 * Return formatted next week data
 */
export function nextWeek (state) {
  return timeChart(state).getNextWeekData()
}

/**
 * Return formatted previous week data
 */
export function previousWeek (state) {
  return timeChart(state).getPreviousWeekData()
}

/**
 * Return range for choropleth color scale
 */
function choroplethDataRange (state, choroplethId) {
  let maxVals = [],
      minVals = []

  state.data.map(region => {
    region.seasons.map(season => {

      let actual = getMaxLagData(season.actual).map(d => d.data).filter(d => d !== -1)

      if (choroplethId === 1) {
        // Use baseline scaled data
        maxVals.push(Math.max(...actual.map(d => ((d / season.baseline) - 1) * 100)))
        minVals.push(Math.min(...actual.map(d => ((d / season.baseline) - 1) * 100)))
      } else {
        maxVals.push(Math.max(...actual))
        minVals.push(Math.min(...actual))
      }
    })
  })

  return [Math.min(...minVals),
          Math.max(...maxVals)]
}

/**
 * Return actual data for all regions for current selections
 */
export function choroplethData (state) {

  let choroplethId = selectedChoropleth(state),
      seasonId = selectedSeason(state)

  let output = actualChoroplethData(state, choroplethId === 1)

  output.range = choroplethDataRange(state, choroplethId)
  return output
}

export function legendShow (state) {
  return state.toggles.legend
}

// Introduction getters
export function currentIntro (state) {
  return state.intro.data[introStep(state)]
}

export function introStep (state) {
  return state.intro.pointer
}

export function introLength (state) {
  return state.intro.data.length
}

export function introShow (state) {
  return state.toggles.intro
}

export function introAtFirst (state) {
  return introStep(state) === 0
}

export function introAtLast (state) {
  return introStep(state) === introLength(state) - 1
}
<commit_msg>Baseline scale function<commit_after>// Vuex store getters

export function metadata (state) {
  return state.metadata
}

export function selectedSeason (state) {
  return state.selected.season
}

export function selectedRegion (state) {
  return state.selected.region
}

export function selectedWeekIdx (state) {
  return state.selected.week.idx
}

export function selectedWeekName (state) {
  if (state.selected.week.name)
    return state.selected.week.name
  else
    return 'NA'
}

export function selectedChoropleth (state) {
  return state.selected.choropleth
}

export function seasons (state) {
  // Assuming each region has all the seasons
  return state.data[0].seasons.map(s => s.id)
}

export function regions (state) {
  return state.data.map(d => d.region)
}

/**
 * Scale given (week, data) pairs using the baseline
 */
function baselineScale (values, baseline) {
  return values.map(d => {
    return {
      week: d.week,
      data: baseline ? ((d.data / baseline) - 1) * 100 : -1
    }
  })
}

/**
 * Return choropleth data for model
 */
function modelChoroplethData (state, modelId, dataType, relative = false) {
  let seasonId = selectedSeason(state)

  let output = {
    data: [],
    type: 'sequential'
  }

  state.data.map(r => {
    let preds = r.seasons[seasonId].models[modelId].predictions
    let weeks = getMaxLagData(r.seasons[seasonId].actual).map(d => d.week)
  })
}

/**
 * Return data for choropleth using actual values
 */
function actualChoroplethData (state, relative = false) {
  let seasonId = selectedSeason(state)

  let output = {
    data: [],
    type: relative ? 'diverging' : 'sequential'
  }

  state.data.map(r => {
    let values = getMaxLagData(r.seasons[seasonId].actual)

    if (relative)
      values = baselineScale(values, r.seasons[seasonId].baseline)

    output.data.push({
      region: r.subId,
      states: r.states,
      value: values
    })
  })

  output.data = output.data.slice(1) // Remove national data

  return output
}

export function choropleths (state) {
  // TODO: Parse from data

  let actualChoropleths = [
    'Actual Weighted ILI (%)',
    'Relative Weighted ILI (%)'
  ]

  modelChoroplethData(state, 0)

  return actualChoropleths
}

export function timeChart (state) {
  return state.timeChart
}

export function choropleth (state) {
  return state.choropleth
}

/**
 * Get data with maximum lag
 * First element of the lag array
 */
function getMaxLagData (actual) {
  return actual.map(d => {
    let dataToReturn = -1
    // Handle zero length values
    if (d.data.length !== 0) {
      dataToReturn = d.data[0].value
    }
    return {
      week: d.week,
      data: dataToReturn
    }
  })
}

/**
 * Trim history data to fit in length 'numWeeks'
 */
function trimHistory (historyActual, numWeeks) {
  let historyTrimmed = historyActual.slice()

  if (numWeeks == 52) {
    // Clip everyone else to remove 53rd week
    historyTrimmed = historyTrimmed.filter(d => d.week % 100 != 53)
  } else if (historyTrimmed.length == 52) {
    // Expand to add 53rd week
    // Adding a dummy year 1000, this will also help identify the adjustment
    historyTrimmed.splice(23, 0, {
      week: 100053,
      data: (historyTrimmed[22].data + historyTrimmed[23].data) / 2.0
    })
  }

  return historyTrimmed
}

/**
 * Return data subset for chart as specified in region/season selected
 */
export function timeChartData (state) {

  let regionSubset = state.data[selectedRegion(state)]
  let currentSeasonId = selectedSeason(state)
  let seasonSubset = regionSubset.seasons[currentSeasonId]

  let selectedWeeksCount = seasonSubset.actual.length

  let historicalData = []

  // Add data from history store
  for (let season of Object.keys(regionSubset.history)) {
    historicalData.push({
      id: season,
      actual: trimHistory(regionSubset.history[season], selectedWeeksCount)
    })
  }

  for (let i = 0; i < currentSeasonId; i++) {
    historicalData.push({
      id: regionSubset.seasons[i].id,
      actual: trimHistory(getMaxLagData(regionSubset.seasons[i].actual),
                          selectedWeeksCount)
    })
  }

  return {
    region: regionSubset.subId, // Submission ids are concise
    observed: seasonSubset.actual,
    actual: getMaxLagData(seasonSubset.actual), // Using this to avoid confusion
    baseline: seasonSubset.baseline,
    models: seasonSubset.models, // All model predictions
    history: historicalData
  }
}

/**
 * Return formatted next week data
 */
export function nextWeek (state) {
  return timeChart(state).getNextWeekData()
}

/**
 * Return formatted previous week data
 */
export function previousWeek (state) {
  return timeChart(state).getPreviousWeekData()
}

/**
 * Return range for choropleth color scale
 */
function choroplethDataRange (state, choroplethId) {
  let maxVals = [],
      minVals = []

  state.data.map(region => {
    region.seasons.map(season => {

      let actual = getMaxLagData(season.actual).map(d => d.data).filter(d => d !== -1)

      if (choroplethId === 1) {
        // Use baseline scaled data
        maxVals.push(Math.max(...actual.map(d => ((d / season.baseline) - 1) * 100)))
        minVals.push(Math.min(...actual.map(d => ((d / season.baseline) - 1) * 100)))
      } else {
        maxVals.push(Math.max(...actual))
        minVals.push(Math.min(...actual))
      }
    })
  })

  return [Math.min(...minVals),
          Math.max(...maxVals)]
}

/**
 * Return actual data for all regions for current selections
 */
export function choroplethData (state) {

  let choroplethId = selectedChoropleth(state),
      seasonId = selectedSeason(state)

  let output = actualChoroplethData(state, choroplethId === 1)

  output.range = choroplethDataRange(state, choroplethId)
  return output
}

export function legendShow (state) {
  return state.toggles.legend
}

// Introduction getters
export function currentIntro (state) {
  return state.intro.data[introStep(state)]
}

export function introStep (state) {
  return state.intro.pointer
}

export function introLength (state) {
  return state.intro.data.length
}

export function introShow (state) {
  return state.toggles.intro
}

export function introAtFirst (state) {
  return introStep(state) === 0
}

export function introAtLast (state) {
  return introStep(state) === introLength(state) - 1
}
<|endoftext|>


<commit_before>/* global d3 */
;(function () {
  'use strict'

  function drawGraph (type, data, attr) {
    var max_n = 0
    data.forEach(function (d) {
      max_n = Math.max(d.n, max_n)
    })

    var graph = d3.select('#' + type)

    var bars = graph.selectAll('.bar')
      .data(data)
      .enter()
      .append('div').classed('bar', true)

    bars
      .append('div')
      .classed('graph-label', true)
      .append('a')
      .attr('href', function (d) {
        return d.url
      })
      .attr('target', '_blank')
      .text(function (d) {
        return d[ attr ]
      })

    bars
      .append('div')
      .classed('graph-bar', true)
      .style('width', function (d) {
        return (d.n / max_n * 70) + '%'
      })
      .text(function (d) {
        return d.n
      })

    bars
      .append('div')
      .classed('graph-hover', true)
      .text(function (d) {
        return 'last updated on ' + d.formatted_time
      })
  }

  [
    'repos-update-activities-per-programming',
    'events-per-group',
    'events-per-day-of-week',
    'events-per-week-of-month',
    'events-per-duration',
    'events-per-time-of-day',
    'repos-most-active'
  ].forEach(function (type) {
    d3.json('/public/data/' + type + '.json', function (error, data) {
      if (error) {
        console.log(error)
      }

      var attr

      if (type === 'repos-update-activities-per-programming') {
        attr = 'language'
      } else if (type === 'events-per-group') {
        attr = 'group'
      } else if (type === 'events-per-day-of-week') {
        attr = 'day'
      } else if (type === 'events-per-duration') {
        attr = 'duration'
      } else if (type === 'events-per-time-of-day') {
        attr = 'time'
      } else if (type === 'repos-most-active') {
        attr = 'name'
      } else if (type === 'events-per-week-of-month') {
        attr = 'week'
      }

      drawGraph(type, data, attr)
    })
  })
})()
<commit_msg>fix: add last update dat only if there is a formatted_time<commit_after>/* global d3 */
;(function () {
  'use strict'

  function drawGraph (type, data, attr) {
    var max_n = 0
    data.forEach(function (d) {
      max_n = Math.max(d.n, max_n)
    })

    var graph = d3.select('#' + type)

    var bars = graph.selectAll('.bar')
      .data(data)
      .enter()
      .append('div').classed('bar', true)

    bars
      .append('div')
      .classed('graph-label', true)
      .append('a')
      .attr('href', function (d) {
        return d.url
      })
      .attr('target', '_blank')
      .text(function (d) {
        return d[ attr ]
      })

    bars
      .append('div')
      .classed('graph-bar', true)
      .style('width', function (d) {
        return (d.n / max_n * 70) + '%'
      })
      .text(function (d) {
        return d.n
      })

    if (data[0].formatted_time) {
      bars
        .append('div')
        .classed('graph-hover', true)
        .text(function (d) {
          return 'last updated on ' + d.formatted_time
        })
    }
  }

  [
    'repos-update-activities-per-programming',
    'events-per-group',
    'events-per-day-of-week',
    'events-per-week-of-month',
    'events-per-duration',
    'events-per-time-of-day',
    'repos-most-active'
  ].forEach(function (type) {
    d3.json('/public/data/' + type + '.json', function (error, data) {
      if (error) {
        console.log(error)
      }

      var attr

      if (type === 'repos-update-activities-per-programming') {
        attr = 'language'
      } else if (type === 'events-per-group') {
        attr = 'group'
      } else if (type === 'events-per-day-of-week') {
        attr = 'day'
      } else if (type === 'events-per-duration') {
        attr = 'duration'
      } else if (type === 'events-per-time-of-day') {
        attr = 'time'
      } else if (type === 'repos-most-active') {
        attr = 'name'
      } else if (type === 'events-per-week-of-month') {
        attr = 'week'
      }

      drawGraph(type, data, attr)
    })
  })
})()
<|endoftext|>


<commit_before>// indices for input data array
const DATE = 0;
const TIME = 1;
const TYPE = 2;
const LOCATION = 3;
const STREET = 4;
const HOUSE_NUMBER = 5;
const ROAD = 6;
const KILOMETER = 7;
const METER = 8;
const LONGITUDE = 9;
const LATITUDE = 10;
const DEATH = 11;
const DEATH_CHILDREN = 12;
const INJURY = 13;
const INJURY_CHILDREN = 14;
const LONGITUDE_GEOCODE = 15;
const LATITUDE_GEOCODE = 16;
const VALID = 17;
const VALID_STRICT = 18;

const YOSHKAR_OLA = 'Йошкар-Ола';
const DATA_YEAR = 2015;

let map, heatmap, markerCluster;
// widgets
let startDate, endDate, startTime, endTime, invertDateRange, invertTimeRange, injuryFilter;

ymaps.ready(init);

// map and its' objects initialization
function init() {
    map = new ymaps.Map('map', {
        // Yoshkar-Ola
        center: [56.632057, 47.882995],
        zoom: 8,
        controls: ['typeSelector', 'zoomControl', 'rulerControl']
    });

    markerCluster = new ymaps.Clusterer({
        preset: 'islands#blueClusterIcons',
        clusterHideIconOnBalloonOpen: false,
        geoObjectHideIconOnBalloonOpen: false
    });

    ymaps.modules.require(['Heatmap'], function (Heatmap) {
        heatmap = new Heatmap();
        heatmap.setMap(map);
    });
}

// options for layers with different types of data
const layerOptions = [{
    intensityOfMidpoint: 0.15,
    condition: allPoints,
    latitude: LATITUDE,
    longitude: LONGITUDE
}, {
    intensityOfMidpoint: 0.1,
    condition: republicInputData,
    latitude: LATITUDE,
    longitude: LONGITUDE
}, {
    intensityOfMidpoint: 0.06,
    condition: republicGeoData,
    latitude: LATITUDE_GEOCODE,
    longitude: LONGITUDE_GEOCODE
}, {
    intensityOfMidpoint: 0.1,
    condition: republicValidData,
    latitude: LATITUDE,
    longitude: LONGITUDE
}, {
    intensityOfMidpoint: 0.15,
    condition: yoInputData,
    latitude: LATITUDE,
    longitude: LONGITUDE
}, {
    intensityOfMidpoint: 0.06,
    condition: yoGeoData,
    latitude: LATITUDE_GEOCODE,
    longitude: LONGITUDE_GEOCODE
}, {
    intensityOfMidpoint: 0.25,
    condition: yoValidData,
    latitude: LATITUDE,
    longitude: LONGITUDE
}];

// data type conditions

function allPoints(data) {
    return true;
}

function republicInputData(data) {
    return data[VALID] === 1;
}

function republicGeoData(data) {
    return data[LATITUDE_GEOCODE] !== 0;
}

function republicValidData(data) {
    return data[VALID_STRICT] === 1;
}

function yoInputData(data) {
    return data[LOCATION] === YOSHKAR_OLA && republicInputData(data);
}

function yoGeoData(data) {
    return data[LOCATION] === YOSHKAR_OLA && republicGeoData(data);
}

function yoValidData(data) {
    return data[LOCATION] === YOSHKAR_OLA && republicValidData(data);
}

function resetType() {
    $('select#typesFilter :selected').removeAttr('selected');
    updateMap();
}

function updateMap() {
    const layerOption = layerOptions[$('select#dataSelector').val()];

    if ($('input[name=layer]:checked').val() === 'heatmap') {
        markerCluster.removeAll();
        updateHeatmap(layerOption);
    } else {
        heatmap.setData([]);
        drawMarkers(layerOption);
    }
}

function updateHeatmap(heatmapOption) {
    if (heatmapOption != null) {
        heatmap.options.set('intensityOfMidpoint', heatmapOption.intensityOfMidpoint);
        heatmap.setData(generateDataArray(heatmapOption.condition, heatmapOption.latitude, heatmapOption.longitude, true));
    } else {
        heatmap.setData([]);
    }
}

function generateDataArray(datasetCondition, latitudeIndex, longitudeIndex, isHeatmap) {
    const typeFilterValue = $('select#typesFilter :selected').text();
    const dateFilterValue = getDateFilterValue();
    const timeFilterValue = getTimeFilterValue();
    const injuryFilterValue = injuryFilter.val();

    let dataArray = [];
    for (let index = 0; index < data.length; ++index) {
        if (datasetCondition(data[index]) && filter(data[index], typeFilterValue, dateFilterValue, timeFilterValue, injuryFilterValue)) {
            if (isHeatmap) {
                dataArray.push([data[index][latitudeIndex], data[index][longitudeIndex]]);
            } else {
                dataArray.push(createMarker(data[index], latitudeIndex, longitudeIndex));
            }
        }
    }
    return dataArray;
}

function getDateFilterValue() {
    let dateFilterValue = {};

    dateFilterValue.startDate = startDate.datepicker('getDate');
    dateFilterValue.endDate = endDate.datepicker('getDate');
    dateFilterValue.invert = invertDateRange.prop('checked');

    return dateFilterValue;
}

function getTimeFilterValue() {
    let timeFilterValue = [];

    timeFilterValue.startTime = startTime.timepicker('getTime');
    timeFilterValue.endTime = endTime.timepicker('getTime');
    timeFilterValue.invert = invertTimeRange.prop('checked');
    if (timeFilterValue.startTime) {
        timeFilterValue.startTime.setFullYear(DATA_YEAR, 0, 1);
    }
    if (timeFilterValue.endTime) {
        timeFilterValue.endTime.setFullYear(DATA_YEAR, 0, 1);
    }

    return timeFilterValue;
}

// markers clustering

function drawMarkers(layerOption) {
    if (layerOption != null) {
        const markers = generateDataArray(layerOption.condition, layerOption.latitude, layerOption.longitude, false);
        markerCluster.removeAll();
        markerCluster.add(markers);
        map.geoObjects.add(markerCluster);
    } else {
        markerCluster.removeAll();
    }
}

function createMarker(data, latitudeIndex, longitudeIndex) {
    return new ymaps.GeoObject({
        geometry: {
            type: "Point",
            coordinates: [data[latitudeIndex], data[longitudeIndex]]
        },
        properties: {
            clusterCaption: data[DATE] + ' ' + data[TIME],
            balloonContentHeader: 'ДТП ' + data[DATE] + ' ' + data[TIME],
            balloonContentBody: createInfoWindowContent(data)
        }
    });
}

function createInfoWindowContent(data) {
    let content = '
Тип: ' + data[TYPE] + '
';

    let place = data[LOCATION] + ', ';
    if (data[STREET] !== '') {
        place += data[STREET] + ', д. ' + data[HOUSE_NUMBER];
    } else {
        place += data[ROAD] + ' ' + data[KILOMETER] + '-й км. ' + data[METER] + '-й м.';
    }

    content += 'Место: ' + place + '
';
    content += 'Координаты: ' + data[LATITUDE] + ', ' + data[LONGITUDE] + '
';

    if (data[DEATH] !== 0) {
        content += 'Погибло: ' + data[DEATH];
        if (data[DEATH_CHILDREN] !== 0) {
            content += ' (среди них детей: ' + data[DEATH_CHILDREN] + ')';
        }
        content += '
';
    }

    if (data[INJURY] !== 0) {
        content += 'Пострадало: ' + data[INJURY];
        if (data[INJURY_CHILDREN] !== 0) {
            content += ' (среди них детей: ' + data[INJURY_CHILDREN] + ')';
        }
        content += '
';
    }

    return content + '
';
}

// filtering

function filter(data, typeFilterValue, dateFilterValue, timeFilterValue, injuryFilterValue) {
    const dateFilter = filterDate(data, dateFilterValue);
    const timeFilter = filterTime(data, timeFilterValue);
    const typeFilter = typeFilterValue === '' || typeFilterValue.indexOf(data[TYPE]) !== -1;
    const injuryFilter = filterInjury(data, injuryFilterValue);

    return dateFilter && timeFilter && typeFilter && injuryFilter;
}

function filterInjury(data, injuryFilterValue) {
    switch (+injuryFilterValue) {
        case -1:
            return true;
        case 0:
            return data[INJURY] > 0;
        case 1:
            return data[INJURY_CHILDREN] > 0;
        case 2:
            return data[DEATH] > 0;
        case 3:
            return data[DEATH_CHILDREN] > 0;
    }
}

function filterDate(data, dateFilterValue) {
    const date = parseDate(data[DATE]);

    return dateFilterValue.startDate == null && dateFilterValue.endDate == null ||
            !dateFilterValue.invert && (dateFilterValue.startDate == null || dateFilterValue.startDate < date) &&
                (dateFilterValue.endDate == null || dateFilterValue.endDate > date) ||
            dateFilterValue.invert && (dateFilterValue.startDate != null && dateFilterValue.startDate > date ||
                dateFilterValue.endDate != null && dateFilterValue.endDate < date);
}

function filterTime(data, timeFilterValue) {
    const time = parseTime(data[TIME]);

    return timeFilterValue.startTime == null && timeFilterValue.endTime == null ||
            !timeFilterValue.invert && (timeFilterValue.startTime == null || timeFilterValue.startTime < time) &&
                (timeFilterValue.endTime == null || timeFilterValue.endTime > time) ||
            timeFilterValue.invert && (timeFilterValue.startTime != null && timeFilterValue.startTime > time ||
                timeFilterValue.endTime != null && timeFilterValue.endTime < time);
}

function parseDate(dateString) {
    const parts = dateString.split('.');
    return new Date(+parts[2], +parts[1] - 1, +parts[0]);
}

function parseTime(timeString) {
    const parts = timeString.split(':');
    return new Date(DATA_YEAR, 0, 1, +parts[0], +parts[1]);
}

function resetDate() {
    startDate.val('');
    startDate.datepicker('option', {
        minDate: new Date(DATA_YEAR, 0, 1),
        maxDate: new Date(DATA_YEAR, 11, 31)
    });
    endDate.val('');
    endDate.datepicker('option', {
        minDate: new Date(DATA_YEAR, 0, 1),
        maxDate: new Date(DATA_YEAR, 11, 31)
    });
    invertDateRange.removeAttr('checked');
    updateMap();
}

function resetTime() {
    startTime.val('');
    startTime.timepicker('option', {
        minTime: "0:00",
        maxTime: "24:00"
    });
    endTime.val('');
    endTime.timepicker('option', {
        minTime: "0:00",
        maxTime: "24:00"
    });
    invertTimeRange.removeAttr('checked');
    updateMap();
}

// filters widgets initialization
$(function () {
    startDate = $('#startDate');
    endDate = $('#endDate');
    startTime = $('#startTime');
    endTime = $('#endTime');
    invertDateRange = $('#invertDateRange');
    invertTimeRange = $('#invertTimeRange');
    injuryFilter = $('select#injuryFilter');

    startDate.datepicker({
        minDate: new Date(DATA_YEAR, 0, 1),
        maxDate: new Date(DATA_YEAR, 11, 31),
        dateFormat: 'd/m/y',
        onClose: function (selectedDate) {
            endDate.datepicker('option', 'minDate', selectedDate);
        }
    });

    endDate.datepicker({
        minDate: new Date(DATA_YEAR, 0, 1),
        maxDate: new Date(DATA_YEAR, 11, 31),
        dateFormat: 'd/m/y',
        onClose: function (selectedDate) {
            startDate.datepicker('option', 'maxDate', selectedDate);
        }
    });

    startTime.timepicker({
        timeFormat: 'H:i',
        show2400: true,
        minTime: "0:00",
        maxTime: "24:00"
    });
    startTime.on('changeTime', function () {
        endTime.timepicker('option', 'minTime', $(this).val());
    });

    endTime.timepicker({
        timeFormat: 'H:i',
        show2400: true,
        minTime: "0:00",
        maxTime: "24:00"
    });
    endTime.on('changeTime', function () {
        startTime.timepicker('option', 'maxTime', $(this).val());
    });
});<commit_msg>Naming convention fix<commit_after>// indices for input data array
const DATE = 0;
const TIME = 1;
const TYPE = 2;
const LOCATION = 3;
const STREET = 4;
const HOUSE_NUMBER = 5;
const ROAD = 6;
const KILOMETER = 7;
const METER = 8;
const LONGITUDE = 9;
const LATITUDE = 10;
const DEATH = 11;
const DEATH_CHILDREN = 12;
const INJURY = 13;
const INJURY_CHILDREN = 14;
const LONGITUDE_GEOCODE = 15;
const LATITUDE_GEOCODE = 16;
const VALID = 17;
const VALID_STRICT = 18;

const YOSHKAR_OLA = 'Йошкар-Ола';
const DATA_YEAR = 2015;

let map, heatmap, markerCluster;
// widgets
let startDate, endDate, startTime, endTime, invertDateRange, invertTimeRange, injuryFilter;

ymaps.ready(init);

// map and its' objects initialization
function init() {
    map = new ymaps.Map('map', {
        // Yoshkar-Ola
        center: [56.632057, 47.882995],
        zoom: 8,
        controls: ['typeSelector', 'zoomControl', 'rulerControl']
    });

    markerCluster = new ymaps.Clusterer({
        preset: 'islands#blueClusterIcons',
        clusterHideIconOnBalloonOpen: false,
        geoObjectHideIconOnBalloonOpen: false
    });

    ymaps.modules.require(['Heatmap'], function (Heatmap) {
        heatmap = new Heatmap();
        heatmap.setMap(map);
    });
}

// options for layers with different types of data
const LAYER_OPTIONS = [{
    intensityOfMidpoint: 0.15,
    condition: allPoints,
    latitude: LATITUDE,
    longitude: LONGITUDE
}, {
    intensityOfMidpoint: 0.1,
    condition: republicInputData,
    latitude: LATITUDE,
    longitude: LONGITUDE
}, {
    intensityOfMidpoint: 0.06,
    condition: republicGeoData,
    latitude: LATITUDE_GEOCODE,
    longitude: LONGITUDE_GEOCODE
}, {
    intensityOfMidpoint: 0.1,
    condition: republicValidData,
    latitude: LATITUDE,
    longitude: LONGITUDE
}, {
    intensityOfMidpoint: 0.15,
    condition: yoInputData,
    latitude: LATITUDE,
    longitude: LONGITUDE
}, {
    intensityOfMidpoint: 0.06,
    condition: yoGeoData,
    latitude: LATITUDE_GEOCODE,
    longitude: LONGITUDE_GEOCODE
}, {
    intensityOfMidpoint: 0.25,
    condition: yoValidData,
    latitude: LATITUDE,
    longitude: LONGITUDE
}];

// data type conditions

function allPoints(data) {
    return true;
}

function republicInputData(data) {
    return data[VALID] === 1;
}

function republicGeoData(data) {
    return data[LATITUDE_GEOCODE] !== 0;
}

function republicValidData(data) {
    return data[VALID_STRICT] === 1;
}

function yoInputData(data) {
    return data[LOCATION] === YOSHKAR_OLA && republicInputData(data);
}

function yoGeoData(data) {
    return data[LOCATION] === YOSHKAR_OLA && republicGeoData(data);
}

function yoValidData(data) {
    return data[LOCATION] === YOSHKAR_OLA && republicValidData(data);
}

function resetType() {
    $('select#typesFilter :selected').removeAttr('selected');
    updateMap();
}

function updateMap() {
    const layerOption = LAYER_OPTIONS[$('select#dataSelector').val()];

    if ($('input[name=layer]:checked').val() === 'heatmap') {
        markerCluster.removeAll();
        updateHeatmap(layerOption);
    } else {
        heatmap.setData([]);
        drawMarkers(layerOption);
    }
}

function updateHeatmap(heatmapOption) {
    if (heatmapOption != null) {
        heatmap.options.set('intensityOfMidpoint', heatmapOption.intensityOfMidpoint);
        heatmap.setData(generateDataArray(heatmapOption.condition, heatmapOption.latitude, heatmapOption.longitude, true));
    } else {
        heatmap.setData([]);
    }
}

function generateDataArray(datasetCondition, latitudeIndex, longitudeIndex, isHeatmap) {
    const typeFilterValue = $('select#typesFilter :selected').text();
    const dateFilterValue = getDateFilterValue();
    const timeFilterValue = getTimeFilterValue();
    const injuryFilterValue = injuryFilter.val();

    let dataArray = [];
    for (let index = 0; index < data.length; ++index) {
        if (datasetCondition(data[index]) && filter(data[index], typeFilterValue, dateFilterValue, timeFilterValue, injuryFilterValue)) {
            if (isHeatmap) {
                dataArray.push([data[index][latitudeIndex], data[index][longitudeIndex]]);
            } else {
                dataArray.push(createMarker(data[index], latitudeIndex, longitudeIndex));
            }
        }
    }
    return dataArray;
}

function getDateFilterValue() {
    let dateFilterValue = {};

    dateFilterValue.startDate = startDate.datepicker('getDate');
    dateFilterValue.endDate = endDate.datepicker('getDate');
    dateFilterValue.invert = invertDateRange.prop('checked');

    return dateFilterValue;
}

function getTimeFilterValue() {
    let timeFilterValue = [];

    timeFilterValue.startTime = startTime.timepicker('getTime');
    timeFilterValue.endTime = endTime.timepicker('getTime');
    timeFilterValue.invert = invertTimeRange.prop('checked');
    if (timeFilterValue.startTime) {
        timeFilterValue.startTime.setFullYear(DATA_YEAR, 0, 1);
    }
    if (timeFilterValue.endTime) {
        timeFilterValue.endTime.setFullYear(DATA_YEAR, 0, 1);
    }

    return timeFilterValue;
}

// markers clustering

function drawMarkers(layerOption) {
    if (layerOption != null) {
        const markers = generateDataArray(layerOption.condition, layerOption.latitude, layerOption.longitude, false);
        markerCluster.removeAll();
        markerCluster.add(markers);
        map.geoObjects.add(markerCluster);
    } else {
        markerCluster.removeAll();
    }
}

function createMarker(data, latitudeIndex, longitudeIndex) {
    return new ymaps.GeoObject({
        geometry: {
            type: "Point",
            coordinates: [data[latitudeIndex], data[longitudeIndex]]
        },
        properties: {
            clusterCaption: data[DATE] + ' ' + data[TIME],
            balloonContentHeader: 'ДТП ' + data[DATE] + ' ' + data[TIME],
            balloonContentBody: createInfoWindowContent(data)
        }
    });
}

function createInfoWindowContent(data) {
    let content = '
Тип: ' + data[TYPE] + '
';

    let place = data[LOCATION] + ', ';
    if (data[STREET] !== '') {
        place += data[STREET] + ', д. ' + data[HOUSE_NUMBER];
    } else {
        place += data[ROAD] + ' ' + data[KILOMETER] + '-й км. ' + data[METER] + '-й м.';
    }

    content += 'Место: ' + place + '
';
    content += 'Координаты: ' + data[LATITUDE] + ', ' + data[LONGITUDE] + '
';

    if (data[DEATH] !== 0) {
        content += 'Погибло: ' + data[DEATH];
        if (data[DEATH_CHILDREN] !== 0) {
            content += ' (среди них детей: ' + data[DEATH_CHILDREN] + ')';
        }
        content += '
';
    }

    if (data[INJURY] !== 0) {
        content += 'Пострадало: ' + data[INJURY];
        if (data[INJURY_CHILDREN] !== 0) {
            content += ' (среди них детей: ' + data[INJURY_CHILDREN] + ')';
        }
        content += '
';
    }

    return content + '
';
}

// filtering

function filter(data, typeFilterValue, dateFilterValue, timeFilterValue, injuryFilterValue) {
    const dateFilter = filterDate(data, dateFilterValue);
    const timeFilter = filterTime(data, timeFilterValue);
    const typeFilter = typeFilterValue === '' || typeFilterValue.indexOf(data[TYPE]) !== -1;
    const injuryFilter = filterInjury(data, injuryFilterValue);

    return dateFilter && timeFilter && typeFilter && injuryFilter;
}

function filterInjury(data, injuryFilterValue) {
    switch (+injuryFilterValue) {
        case -1:
            return true;
        case 0:
            return data[INJURY] > 0;
        case 1:
            return data[INJURY_CHILDREN] > 0;
        case 2:
            return data[DEATH] > 0;
        case 3:
            return data[DEATH_CHILDREN] > 0;
    }
}

function filterDate(data, dateFilterValue) {
    const date = parseDate(data[DATE]);

    return dateFilterValue.startDate == null && dateFilterValue.endDate == null ||
            !dateFilterValue.invert && (dateFilterValue.startDate == null || dateFilterValue.startDate < date) &&
                (dateFilterValue.endDate == null || dateFilterValue.endDate > date) ||
            dateFilterValue.invert && (dateFilterValue.startDate != null && dateFilterValue.startDate > date ||
                dateFilterValue.endDate != null && dateFilterValue.endDate < date);
}

function filterTime(data, timeFilterValue) {
    const time = parseTime(data[TIME]);

    return timeFilterValue.startTime == null && timeFilterValue.endTime == null ||
            !timeFilterValue.invert && (timeFilterValue.startTime == null || timeFilterValue.startTime < time) &&
                (timeFilterValue.endTime == null || timeFilterValue.endTime > time) ||
            timeFilterValue.invert && (timeFilterValue.startTime != null && timeFilterValue.startTime > time ||
                timeFilterValue.endTime != null && timeFilterValue.endTime < time);
}

function parseDate(dateString) {
    const parts = dateString.split('.');
    return new Date(+parts[2], +parts[1] - 1, +parts[0]);
}

function parseTime(timeString) {
    const parts = timeString.split(':');
    return new Date(DATA_YEAR, 0, 1, +parts[0], +parts[1]);
}

function resetDate() {
    startDate.val('');
    startDate.datepicker('option', {
        minDate: new Date(DATA_YEAR, 0, 1),
        maxDate: new Date(DATA_YEAR, 11, 31)
    });
    endDate.val('');
    endDate.datepicker('option', {
        minDate: new Date(DATA_YEAR, 0, 1),
        maxDate: new Date(DATA_YEAR, 11, 31)
    });
    invertDateRange.removeAttr('checked');
    updateMap();
}

function resetTime() {
    startTime.val('');
    startTime.timepicker('option', {
        minTime: "0:00",
        maxTime: "24:00"
    });
    endTime.val('');
    endTime.timepicker('option', {
        minTime: "0:00",
        maxTime: "24:00"
    });
    invertTimeRange.removeAttr('checked');
    updateMap();
}

// filters widgets initialization
$(function () {
    startDate = $('#startDate');
    endDate = $('#endDate');
    startTime = $('#startTime');
    endTime = $('#endTime');
    invertDateRange = $('#invertDateRange');
    invertTimeRange = $('#invertTimeRange');
    injuryFilter = $('select#injuryFilter');

    startDate.datepicker({
        minDate: new Date(DATA_YEAR, 0, 1),
        maxDate: new Date(DATA_YEAR, 11, 31),
        dateFormat: 'd/m/y',
        onClose: function (selectedDate) {
            endDate.datepicker('option', 'minDate', selectedDate);
        }
    });

    endDate.datepicker({
        minDate: new Date(DATA_YEAR, 0, 1),
        maxDate: new Date(DATA_YEAR, 11, 31),
        dateFormat: 'd/m/y',
        onClose: function (selectedDate) {
            startDate.datepicker('option', 'maxDate', selectedDate);
        }
    });

    startTime.timepicker({
        timeFormat: 'H:i',
        show2400: true,
        minTime: "0:00",
        maxTime: "24:00"
    });
    startTime.on('changeTime', function () {
        endTime.timepicker('option', 'minTime', $(this).val());
    });

    endTime.timepicker({
        timeFormat: 'H:i',
        show2400: true,
        minTime: "0:00",
        maxTime: "24:00"
    });
    endTime.on('changeTime', function () {
        startTime.timepicker('option', 'maxTime', $(this).val());
    });
});<|endoftext|>


<commit_before>// indices for input data array
const DATE = 0;
const TIME = 1;
const TYPE = 2;
const LOCATION = 3;
const STREET = 4;
const HOUSE_NUMBER = 5;
const ROAD = 6;
const KILOMETER = 7;
const METER = 8;
const LONGITUDE = 9;
const LATITUDE = 10;
const DEATH = 11;
const DEATH_CHILDREN = 12;
const INJURY = 13;
const INJURY_CHILDREN = 14;
const LONGITUDE_GEOCODE = 15;
const LATITUDE_GEOCODE = 16;
const VALID = 17;
const VALID_STRICT = 18;

const YOSHKAR_OLA = 'Йошкар-Ола';
const DATA_YEAR = 2015;

let map, heatmap, markerCluster;
// widgets
let startDate, endDate, startTime, endTime, invertDateRange, invertTimeRange, typesFilter, injuryFilter;

ymaps.ready(init);

// map and its' objects initialization
function init() {
    map = new ymaps.Map('map', {
        // Yoshkar-Ola
        center: [56.632057, 47.882995],
        zoom: 8,
        controls: ['typeSelector', 'zoomControl', 'rulerControl']
    });

    markerCluster = new ymaps.Clusterer({
        preset: 'islands#blueClusterIcons',
        clusterHideIconOnBalloonOpen: false,
        geoObjectHideIconOnBalloonOpen: false
    });

    ymaps.modules.require(['Heatmap'], function (Heatmap) {
        heatmap = new Heatmap();
        heatmap.setMap(map);
    });
}

// options for layers with different types of data
const layerOptions = [{
    intensityOfMidpoint: 0.15,
    condition: allPoints,
    latitude: LATITUDE,
    longitude: LONGITUDE
}, {
    intensityOfMidpoint: 0.1,
    condition: republicInputData,
    latitude: LATITUDE,
    longitude: LONGITUDE
}, {
    intensityOfMidpoint: 0.06,
    condition: republicGeoData,
    latitude: LATITUDE_GEOCODE,
    longitude: LONGITUDE_GEOCODE
}, {
    intensityOfMidpoint: 0.1,
    condition: republicValidData,
    latitude: LATITUDE,
    longitude: LONGITUDE
}, {
    intensityOfMidpoint: 0.15,
    condition: yoInputData,
    latitude: LATITUDE,
    longitude: LONGITUDE
}, {
    intensityOfMidpoint: 0.06,
    condition: yoGeoData,
    latitude: LATITUDE_GEOCODE,
    longitude: LONGITUDE_GEOCODE
}, {
    intensityOfMidpoint: 0.25,
    condition: yoValidData,
    latitude: LATITUDE,
    longitude: LONGITUDE
}];

// data type conditions

function allPoints(data) {
    return true;
}

function republicInputData(data) {
    return data[VALID] === 1;
}

function republicGeoData(data) {
    return data[LATITUDE_GEOCODE] !== 0;
}

function republicValidData(data) {
    return data[VALID_STRICT] === 1;
}

function yoInputData(data) {
    return data[LOCATION] === YOSHKAR_OLA && republicInputData(data);
}

function yoGeoData(data) {
    return data[LOCATION] === YOSHKAR_OLA && republicGeoData(data);
}

function yoValidData(data) {
    return data[LOCATION] === YOSHKAR_OLA && republicValidData(data);
}

function resetType() {
    typesFilter.removeAttr('selected');
    updateMap();
}

function updateMap() {
    const layerOption = layerOptions[$('select#dataSelector').val()];

    if ($('input[name=layer]:checked').val() === 'heatmap') {
        markerCluster.removeAll();
        updateHeatmap(layerOption);
    } else {
        heatmap.setData([]);
        drawMarkers(layerOption);
    }
}

function updateHeatmap(heatmapOption) {
    if (heatmapOption != null) {
        heatmap.options.set('intensityOfMidpoint', heatmapOption.intensityOfMidpoint);
        heatmap.setData(generateDataArray(heatmapOption.condition, heatmapOption.latitude, heatmapOption.longitude, true));
    } else {
        heatmap.setData([]);
    }
}

function generateDataArray(datasetCondition, latitudeIndex, longitudeIndex, isHeatmap) {
    const typeFilterValue = typesFilter.text();
    const dateFilterValue = getDateFilterValue();
    const timeFilterValue = getTimeFilterValue();
    const injuryFilterValue = injuryFilter.val();

    let dataArray = [];
    for (let index = 0; index < data.length; ++index) {
        if (datasetCondition(data[index]) && filter(data[index], typeFilterValue, dateFilterValue, timeFilterValue, injuryFilterValue)) {
            if (isHeatmap) {
                dataArray.push([data[index][latitudeIndex], data[index][longitudeIndex]]);
            } else {
                dataArray.push(createMarker(data[index], latitudeIndex, longitudeIndex));
            }
        }
    }
    return dataArray;
}

function getDateFilterValue() {
    let dateFilterValue = {};

    dateFilterValue.startDate = startDate.datepicker('getDate');
    dateFilterValue.endDate = endDate.datepicker('getDate');
    dateFilterValue.invert = invertDateRange.prop('checked');

    return dateFilterValue;
}

function getTimeFilterValue() {
    let timeFilterValue = [];

    timeFilterValue.startTime = startTime.timepicker('getTime');
    timeFilterValue.endTime = endTime.timepicker('getTime');
    timeFilterValue.invert = invertTimeRange.prop('checked');
    if (timeFilterValue.startTime) {
        timeFilterValue.startTime.setFullYear(DATA_YEAR, 0, 1);
    }
    if (timeFilterValue.endTime) {
        timeFilterValue.endTime.setFullYear(DATA_YEAR, 0, 1);
    }

    return timeFilterValue;
}

// markers clustering

function drawMarkers(layerOption) {
    if (layerOption != null) {
        const markers = generateDataArray(layerOption.condition, layerOption.latitude, layerOption.longitude, false);
        markerCluster.removeAll();
        markerCluster.add(markers);
        map.geoObjects.add(markerCluster);
    } else {
        markerCluster.removeAll();
    }
}

function createMarker(data, latitudeIndex, longitudeIndex) {
    return new ymaps.GeoObject({
        geometry: {
            type: "Point",
            coordinates: [data[latitudeIndex], data[longitudeIndex]]
        },
        properties: {
            clusterCaption: data[DATE] + ' ' + data[TIME],
            balloonContentHeader: 'ДТП ' + data[DATE] + ' ' + data[TIME],
            balloonContentBody: createInfoWindowContent(data)
        }
    });
}

function createInfoWindowContent(data) {
    let content = '
Тип: ' + data[TYPE] + '
';

    let place = data[LOCATION] + ', ';
    if (data[STREET] !== '') {
        place += data[STREET] + ', д. ' + data[HOUSE_NUMBER];
    } else {
        place += data[ROAD] + ' ' + data[KILOMETER] + '-й км. ' + data[METER] + '-й м.';
    }

    content += 'Место: ' + place + '
';
    content += 'Координаты: ' + data[LATITUDE] + ', ' + data[LONGITUDE] + '
';

    if (data[DEATH] !== 0) {
        content += 'Погибло: ' + data[DEATH];
        if (data[DEATH_CHILDREN] !== 0) {
            content += ' (среди них детей: ' + data[DEATH_CHILDREN] + ')';
        }
        content += '
';
    }

    if (data[INJURY] !== 0) {
        content += 'Пострадало: ' + data[INJURY];
        if (data[INJURY_CHILDREN] !== 0) {
            content += ' (среди них детей: ' + data[INJURY_CHILDREN] + ')';
        }
        content += '
';
    }

    return content + '
';
}

// filtering

function filter(data, typeFilterValue, dateFilterValue, timeFilterValue, injuryFilterValue) {
    const dateFilter = filterDate(data, dateFilterValue);
    const timeFilter = filterTime(data, timeFilterValue);
    const typeFilter = typeFilterValue === '' || typeFilterValue.indexOf(data[TYPE]) !== -1;
    const injuryFilter = filterInjury(data, injuryFilterValue);

    return dateFilter && timeFilter && typeFilter && injuryFilter;
}

function filterInjury(data, injuryFilterValue) {
    switch (+injuryFilterValue) {
        case -1:
            return true;
        case 0:
            return data[INJURY] > 0;
        case 1:
            return data[INJURY_CHILDREN] > 0;
        case 2:
            return data[DEATH] > 0;
        case 3:
            return data[DEATH_CHILDREN] > 0;
    }
}

function filterDate(data, dateFilterValue) {
    const date = parseDate(data[DATE]);

    return dateFilterValue.startDate == null && dateFilterValue.endDate == null ||
            !dateFilterValue.invert && (dateFilterValue.startDate == null || dateFilterValue.startDate < date) &&
                (dateFilterValue.endDate == null || dateFilterValue.endDate > date) ||
            dateFilterValue.invert && (dateFilterValue.startDate != null && dateFilterValue.startDate > date ||
                dateFilterValue.endDate != null && dateFilterValue.endDate < date);
}

function filterTime(data, timeFilterValue) {
    const time = parseTime(data[TIME]);

    return timeFilterValue.startTime == null && timeFilterValue.endTime == null ||
            !timeFilterValue.invert && (timeFilterValue.startTime == null || timeFilterValue.startTime < time) &&
                (timeFilterValue.endTime == null || timeFilterValue.endTime > time) ||
            timeFilterValue.invert && (timeFilterValue.startTime != null && timeFilterValue.startTime > time ||
                timeFilterValue.endTime != null && timeFilterValue.endTime < time);
}

function parseDate(dateString) {
    const parts = dateString.split('.');
    return new Date(+parts[2], +parts[1] - 1, +parts[0]);
}

function parseTime(timeString) {
    const parts = timeString.split(':');
    return new Date(DATA_YEAR, 0, 1, +parts[0], +parts[1]);
}

function resetDate() {
    startDate.val('');
    startDate.datepicker('option', {
        minDate: new Date(DATA_YEAR, 0, 1),
        maxDate: new Date(DATA_YEAR, 11, 31)
    });
    endDate.val('');
    endDate.datepicker('option', {
        minDate: new Date(DATA_YEAR, 0, 1),
        maxDate: new Date(DATA_YEAR, 11, 31)
    });
    invertDateRange.removeAttr('checked');
    updateMap();
}

function resetTime() {
    startTime.val('');
    startTime.timepicker('option', {
        minTime: "0:00",
        maxTime: "24:00"
    });
    endTime.val('');
    endTime.timepicker('option', {
        minTime: "0:00",
        maxTime: "24:00"
    });
    invertTimeRange.removeAttr('checked');
    updateMap();
}

// filters widgets initialization
$(function () {
    startDate = $('#startDate');
    endDate = $('#endDate');
    startTime = $('#startTime');
    endTime = $('#endTime');
    invertDateRange = $('#invertDateRange');
    invertTimeRange = $('#invertTimeRange');
    typesFilter = $('select#typesFilter :selected');
    injuryFilter = $('select#injuryFilter');

    startDate.datepicker({
        minDate: new Date(DATA_YEAR, 0, 1),
        maxDate: new Date(DATA_YEAR, 11, 31),
        dateFormat: 'd/m/y',
        onClose: function (selectedDate) {
            endDate.datepicker('option', 'minDate', selectedDate);
        }
    });

    endDate.datepicker({
        minDate: new Date(DATA_YEAR, 0, 1),
        maxDate: new Date(DATA_YEAR, 11, 31),
        dateFormat: 'd/m/y',
        onClose: function (selectedDate) {
            startDate.datepicker('option', 'maxDate', selectedDate);
        }
    });

    startTime.timepicker({
        timeFormat: 'H:i',
        show2400: true,
        minTime: "0:00",
        maxTime: "24:00"
    });
    startTime.on('changeTime', function () {
        endTime.timepicker('option', 'minTime', $(this).val());
    });

    endTime.timepicker({
        timeFormat: 'H:i',
        show2400: true,
        minTime: "0:00",
        maxTime: "24:00"
    });
    endTime.on('changeTime', function () {
        startTime.timepicker('option', 'maxTime', $(this).val());
    });
});<commit_msg>Fixed types filter<commit_after>// indices for input data array
const DATE = 0;
const TIME = 1;
const TYPE = 2;
const LOCATION = 3;
const STREET = 4;
const HOUSE_NUMBER = 5;
const ROAD = 6;
const KILOMETER = 7;
const METER = 8;
const LONGITUDE = 9;
const LATITUDE = 10;
const DEATH = 11;
const DEATH_CHILDREN = 12;
const INJURY = 13;
const INJURY_CHILDREN = 14;
const LONGITUDE_GEOCODE = 15;
const LATITUDE_GEOCODE = 16;
const VALID = 17;
const VALID_STRICT = 18;

const YOSHKAR_OLA = 'Йошкар-Ола';
const DATA_YEAR = 2015;

let map, heatmap, markerCluster;
// widgets
let startDate, endDate, startTime, endTime, invertDateRange, invertTimeRange, injuryFilter;

ymaps.ready(init);

// map and its' objects initialization
function init() {
    map = new ymaps.Map('map', {
        // Yoshkar-Ola
        center: [56.632057, 47.882995],
        zoom: 8,
        controls: ['typeSelector', 'zoomControl', 'rulerControl']
    });

    markerCluster = new ymaps.Clusterer({
        preset: 'islands#blueClusterIcons',
        clusterHideIconOnBalloonOpen: false,
        geoObjectHideIconOnBalloonOpen: false
    });

    ymaps.modules.require(['Heatmap'], function (Heatmap) {
        heatmap = new Heatmap();
        heatmap.setMap(map);
    });
}

// options for layers with different types of data
const layerOptions = [{
    intensityOfMidpoint: 0.15,
    condition: allPoints,
    latitude: LATITUDE,
    longitude: LONGITUDE
}, {
    intensityOfMidpoint: 0.1,
    condition: republicInputData,
    latitude: LATITUDE,
    longitude: LONGITUDE
}, {
    intensityOfMidpoint: 0.06,
    condition: republicGeoData,
    latitude: LATITUDE_GEOCODE,
    longitude: LONGITUDE_GEOCODE
}, {
    intensityOfMidpoint: 0.1,
    condition: republicValidData,
    latitude: LATITUDE,
    longitude: LONGITUDE
}, {
    intensityOfMidpoint: 0.15,
    condition: yoInputData,
    latitude: LATITUDE,
    longitude: LONGITUDE
}, {
    intensityOfMidpoint: 0.06,
    condition: yoGeoData,
    latitude: LATITUDE_GEOCODE,
    longitude: LONGITUDE_GEOCODE
}, {
    intensityOfMidpoint: 0.25,
    condition: yoValidData,
    latitude: LATITUDE,
    longitude: LONGITUDE
}];

// data type conditions

function allPoints(data) {
    return true;
}

function republicInputData(data) {
    return data[VALID] === 1;
}

function republicGeoData(data) {
    return data[LATITUDE_GEOCODE] !== 0;
}

function republicValidData(data) {
    return data[VALID_STRICT] === 1;
}

function yoInputData(data) {
    return data[LOCATION] === YOSHKAR_OLA && republicInputData(data);
}

function yoGeoData(data) {
    return data[LOCATION] === YOSHKAR_OLA && republicGeoData(data);
}

function yoValidData(data) {
    return data[LOCATION] === YOSHKAR_OLA && republicValidData(data);
}

function resetType() {
    $('select#typesFilter :selected').removeAttr('selected');
    updateMap();
}

function updateMap() {
    const layerOption = layerOptions[$('select#dataSelector').val()];

    if ($('input[name=layer]:checked').val() === 'heatmap') {
        markerCluster.removeAll();
        updateHeatmap(layerOption);
    } else {
        heatmap.setData([]);
        drawMarkers(layerOption);
    }
}

function updateHeatmap(heatmapOption) {
    if (heatmapOption != null) {
        heatmap.options.set('intensityOfMidpoint', heatmapOption.intensityOfMidpoint);
        heatmap.setData(generateDataArray(heatmapOption.condition, heatmapOption.latitude, heatmapOption.longitude, true));
    } else {
        heatmap.setData([]);
    }
}

function generateDataArray(datasetCondition, latitudeIndex, longitudeIndex, isHeatmap) {
    const typeFilterValue = $('select#typesFilter :selected').text();
    const dateFilterValue = getDateFilterValue();
    const timeFilterValue = getTimeFilterValue();
    const injuryFilterValue = injuryFilter.val();

    let dataArray = [];
    for (let index = 0; index < data.length; ++index) {
        if (datasetCondition(data[index]) && filter(data[index], typeFilterValue, dateFilterValue, timeFilterValue, injuryFilterValue)) {
            if (isHeatmap) {
                dataArray.push([data[index][latitudeIndex], data[index][longitudeIndex]]);
            } else {
                dataArray.push(createMarker(data[index], latitudeIndex, longitudeIndex));
            }
        }
    }
    return dataArray;
}

function getDateFilterValue() {
    let dateFilterValue = {};

    dateFilterValue.startDate = startDate.datepicker('getDate');
    dateFilterValue.endDate = endDate.datepicker('getDate');
    dateFilterValue.invert = invertDateRange.prop('checked');

    return dateFilterValue;
}

function getTimeFilterValue() {
    let timeFilterValue = [];

    timeFilterValue.startTime = startTime.timepicker('getTime');
    timeFilterValue.endTime = endTime.timepicker('getTime');
    timeFilterValue.invert = invertTimeRange.prop('checked');
    if (timeFilterValue.startTime) {
        timeFilterValue.startTime.setFullYear(DATA_YEAR, 0, 1);
    }
    if (timeFilterValue.endTime) {
        timeFilterValue.endTime.setFullYear(DATA_YEAR, 0, 1);
    }

    return timeFilterValue;
}

// markers clustering

function drawMarkers(layerOption) {
    if (layerOption != null) {
        const markers = generateDataArray(layerOption.condition, layerOption.latitude, layerOption.longitude, false);
        markerCluster.removeAll();
        markerCluster.add(markers);
        map.geoObjects.add(markerCluster);
    } else {
        markerCluster.removeAll();
    }
}

function createMarker(data, latitudeIndex, longitudeIndex) {
    return new ymaps.GeoObject({
        geometry: {
            type: "Point",
            coordinates: [data[latitudeIndex], data[longitudeIndex]]
        },
        properties: {
            clusterCaption: data[DATE] + ' ' + data[TIME],
            balloonContentHeader: 'ДТП ' + data[DATE] + ' ' + data[TIME],
            balloonContentBody: createInfoWindowContent(data)
        }
    });
}

function createInfoWindowContent(data) {
    let content = '
Тип: ' + data[TYPE] + '
';

    let place = data[LOCATION] + ', ';
    if (data[STREET] !== '') {
        place += data[STREET] + ', д. ' + data[HOUSE_NUMBER];
    } else {
        place += data[ROAD] + ' ' + data[KILOMETER] + '-й км. ' + data[METER] + '-й м.';
    }

    content += 'Место: ' + place + '
';
    content += 'Координаты: ' + data[LATITUDE] + ', ' + data[LONGITUDE] + '
';

    if (data[DEATH] !== 0) {
        content += 'Погибло: ' + data[DEATH];
        if (data[DEATH_CHILDREN] !== 0) {
            content += ' (среди них детей: ' + data[DEATH_CHILDREN] + ')';
        }
        content += '
';
    }

    if (data[INJURY] !== 0) {
        content += 'Пострадало: ' + data[INJURY];
        if (data[INJURY_CHILDREN] !== 0) {
            content += ' (среди них детей: ' + data[INJURY_CHILDREN] + ')';
        }
        content += '
';
    }

    return content + '
';
}

// filtering

function filter(data, typeFilterValue, dateFilterValue, timeFilterValue, injuryFilterValue) {
    const dateFilter = filterDate(data, dateFilterValue);
    const timeFilter = filterTime(data, timeFilterValue);
    const typeFilter = typeFilterValue === '' || typeFilterValue.indexOf(data[TYPE]) !== -1;
    const injuryFilter = filterInjury(data, injuryFilterValue);

    return dateFilter && timeFilter && typeFilter && injuryFilter;
}

function filterInjury(data, injuryFilterValue) {
    switch (+injuryFilterValue) {
        case -1:
            return true;
        case 0:
            return data[INJURY] > 0;
        case 1:
            return data[INJURY_CHILDREN] > 0;
        case 2:
            return data[DEATH] > 0;
        case 3:
            return data[DEATH_CHILDREN] > 0;
    }
}

function filterDate(data, dateFilterValue) {
    const date = parseDate(data[DATE]);

    return dateFilterValue.startDate == null && dateFilterValue.endDate == null ||
            !dateFilterValue.invert && (dateFilterValue.startDate == null || dateFilterValue.startDate < date) &&
                (dateFilterValue.endDate == null || dateFilterValue.endDate > date) ||
            dateFilterValue.invert && (dateFilterValue.startDate != null && dateFilterValue.startDate > date ||
                dateFilterValue.endDate != null && dateFilterValue.endDate < date);
}

function filterTime(data, timeFilterValue) {
    const time = parseTime(data[TIME]);

    return timeFilterValue.startTime == null && timeFilterValue.endTime == null ||
            !timeFilterValue.invert && (timeFilterValue.startTime == null || timeFilterValue.startTime < time) &&
                (timeFilterValue.endTime == null || timeFilterValue.endTime > time) ||
            timeFilterValue.invert && (timeFilterValue.startTime != null && timeFilterValue.startTime > time ||
                timeFilterValue.endTime != null && timeFilterValue.endTime < time);
}

function parseDate(dateString) {
    const parts = dateString.split('.');
    return new Date(+parts[2], +parts[1] - 1, +parts[0]);
}

function parseTime(timeString) {
    const parts = timeString.split(':');
    return new Date(DATA_YEAR, 0, 1, +parts[0], +parts[1]);
}

function resetDate() {
    startDate.val('');
    startDate.datepicker('option', {
        minDate: new Date(DATA_YEAR, 0, 1),
        maxDate: new Date(DATA_YEAR, 11, 31)
    });
    endDate.val('');
    endDate.datepicker('option', {
        minDate: new Date(DATA_YEAR, 0, 1),
        maxDate: new Date(DATA_YEAR, 11, 31)
    });
    invertDateRange.removeAttr('checked');
    updateMap();
}

function resetTime() {
    startTime.val('');
    startTime.timepicker('option', {
        minTime: "0:00",
        maxTime: "24:00"
    });
    endTime.val('');
    endTime.timepicker('option', {
        minTime: "0:00",
        maxTime: "24:00"
    });
    invertTimeRange.removeAttr('checked');
    updateMap();
}

// filters widgets initialization
$(function () {
    startDate = $('#startDate');
    endDate = $('#endDate');
    startTime = $('#startTime');
    endTime = $('#endTime');
    invertDateRange = $('#invertDateRange');
    invertTimeRange = $('#invertTimeRange');
    injuryFilter = $('select#injuryFilter');

    startDate.datepicker({
        minDate: new Date(DATA_YEAR, 0, 1),
        maxDate: new Date(DATA_YEAR, 11, 31),
        dateFormat: 'd/m/y',
        onClose: function (selectedDate) {
            endDate.datepicker('option', 'minDate', selectedDate);
        }
    });

    endDate.datepicker({
        minDate: new Date(DATA_YEAR, 0, 1),
        maxDate: new Date(DATA_YEAR, 11, 31),
        dateFormat: 'd/m/y',
        onClose: function (selectedDate) {
            startDate.datepicker('option', 'maxDate', selectedDate);
        }
    });

    startTime.timepicker({
        timeFormat: 'H:i',
        show2400: true,
        minTime: "0:00",
        maxTime: "24:00"
    });
    startTime.on('changeTime', function () {
        endTime.timepicker('option', 'minTime', $(this).val());
    });

    endTime.timepicker({
        timeFormat: 'H:i',
        show2400: true,
        minTime: "0:00",
        maxTime: "24:00"
    });
    endTime.on('changeTime', function () {
        startTime.timepicker('option', 'maxTime', $(this).val());
    });
});<|endoftext|>


<commit_before>
$( document ).ready(function() {

	var item;

	$('.episode_action').click(function() {

    	/*
		# Get <select/> element that was clicked on
    	*/
    	action_type = $(this).val(),

    	/*
		# Get <select/> element data-action
    	*/
    	action = $(this).find('option:selected').data('action');

		/*
		# Add class to parent element of the <select/> element
    	*/
    	$(this).parent().closest('tr').prop("class", "selected");

    	if (action_type === "view")
    	{
    		window.location = action;
    	}

    	if (action_type === "delete")
    	{
    		deleteEpisode(action)
    	};

    	if (action_type === "activate")
    	{

    		item = $(this).parent().closest('tr');
    		activateEpisode(action)
    	};
	});

	/*
	# Delete Episode Function
	*/
	function deleteEpisode(episode_id)
	{
		var
		url 		= "/dashboard/episode/delete",
		token 		= document.getElementById('token').value,
		method 		= "DELETE",
		episode_id 	= episode_id,
		functionName =  arguments.callee.name;

	  	var data =
	    {
	        url         : url,
	        method 		: method,
	        parameter   :
	        {
	          _token 	  : token,
	          episode_id  : episode_id
	        }
	    }

		swal(
		{
			title: "Delete Episode",
			text: "You will not be able to recover this episode after this action!",
			type: "warning",
			showCancelButton: true,
			confirmButtonColor: "#DD6B55",
			confirmButtonText: "Yes, delete it!",
			cancelButtonText: "No, cancel!",
			closeOnCancelnConfirm: false,
			closeOnCancel: false
		},
		function(isConfirm)
		{
		  if (isConfirm)
		  {
		    ajaxCall(data, functionName)
		  }
		  else
		  {
			swal("Cancelled", "Your episode is safe :)", "error");
		  }
		});
	}

	/*
	# Delete Episode Function
	*/
	function activateEpisode (episode_id)
	{
		var
		url 			= "/dashboard/episode/activate",
		token 			= document.getElementById('token').value,
		method 			= "PATCH",
		functionName 	=  arguments.callee.name;

	  	var data =
	    {
	        url         : url,
	        method 		: method,
	        parameter   :
	        {
	          _token 	  : token,
	          episode_id  : episode_id
	        }
	    }

		swal(
		{
			title: "Activate Episode",
			text: "This Episode will be visible on your channel",
			type: "warning",
			showCancelButton: true,
			confirmButtonColor: "success",
			confirmButtonText: "Activate",
			cancelButtonText: "Cancel!",
			closeOnConfirm: false,
			closeOnCancel: false
		},
		function(isConfirm)
		{
		  if (isConfirm)
		  {
		    ajaxCall(data, functionName)
		  }
		  else
		  {
			swal("Cancelled", "Your episode is safe :)", "error");
		  }
		});
	}

	/*
	# Ajax
	*/
	function ajaxCall (data, functionName)
	{
		$.ajax({
			url: data.url,
			type: data.method,
			data: data.parameter,
			success: function (response)
			{
				ajaxLogic (response, functionName)
			},
			error: function()
			{
				alert('Are you sure you doing this the right way?');
			},
		});
	}

	function ajaxLogic (response, functionName)
	{
		/*
		# Check if Response.status = 401
		*/
		if (response.status === 401)
		{
			switch (functionName) {
	          case "deleteEpisode" : deleteEpisodeErrorAlert(); break;
	          case "activateEpisode" : activateEpisodeErrorAlert(); break;
	        }
		}

		/*
		# Check if Response.status = 200
		*/
		if (response.status === 200)
		{
			switch (functionName) {
	          case "deleteEpisode" : deleteEpisodeSuccessAlert(); break;
	          case "activateEpisode" : activateEpisodeSuccessAlert(); break;
	        }
		}
	}

	/*
	####################################################################
	# deleteEpisodeErrorAlert Message
	*/
	function deleteEpisodeErrorAlert()
	{
		swal("Hmmmm", "This episode does not exist ", "error");
	}

	/*
	# deleteEpisodeSuccessAlert Message
	*/
	function deleteEpisodeSuccessAlert()
	{
		swal("Deleted!", "Your episode has been deleted.", "success");
		var deleted =  $('.selected');
		deleted.hide();
	}

	/*
	####################################################################
	# activateEpisodeErrorAlert() Message
	*/
	function activateEpisodeErrorAlert()
	{
		swal("Hmmmm", "This episode does not exist ", "error");
	}

	function activateEpisodeSuccessAlert()
	{
		swal("Activated", "Your episode has been Activated.", "success");

		var deleted 	=  $(".selected");
		var new_item 	=  $("#active_section");

		new_item.append(item[0]);

		deleted.show();
	}

});
<commit_msg>[Hotfix] Refactor dashboard.js file<commit_after>
$( document ).ready(function() {

	var item;

	$('.episode_action').click(function() {

    	/*
		# Get <select/> element that was clicked on
    	*/
    	action_type = $(this).val(),

    	/*
		# Get <select/> element data-action
    	*/
    	action = $(this).find('option:selected').data('action');

		/*
		# Add class to parent element of the <select/> element
    	*/
    	$(this).parent().closest('tr').prop("class", "selected");

    	if (action_type === "view")
    	{
    		window.location = action;
    	}

    	if (action_type === "delete")
    	{
    		deleteEpisode(action)
    	};

    	if (action_type === "activate")
    	{

    		item = $(this).parent().closest('tr');
    		activateEpisode(action)
    	};
	});

	/*
	# Delete Episode Function
	*/
	function deleteEpisode(episode_id)
	{
		var
		url 		= "/dashboard/episode/delete",
		token 		= document.getElementById('token').value,
		method 		= "DELETE",
		episode_id 	= episode_id,
		functionName =  arguments.callee.name;

	  	var data =
	    {
	        url         : url,
	        method 		: method,
	        parameter   :
	        {
	          _token 	  : token,
	          episode_id  : episode_id
	        }
	    }

		swal(
		{
			title: "Delete Episode",
			text: "You will not be able to recover this episode after this action!",
			type: "warning",
			showCancelButton: true,
			confirmButtonColor: "#DD6B55",
			confirmButtonText: "Yes, delete it!",
			cancelButtonText: "No, cancel!",
			closeOnCancelnConfirm: false,
			closeOnCancel: false
		},
		function(isConfirm)
		{
		  if (isConfirm)
		  {
		    ajaxCall(data, functionName)
		  }
		  else
		  {
			swal("Cancelled", "Your episode is safe :)", "error");
		  }
		});
	}

	/*
	# Delete Episode Function
	*/
	function activateEpisode (episode_id)
	{
		var
		url 			= "/dashboard/episode/activate",
		token 			= document.getElementById('token').value,
		method 			= "PATCH",
		functionName 	=  arguments.callee.name;

	  	var data =
	    {
	        url         : url,
	        method 		: method,
	        parameter   :
	        {
	          _token 	  : token,
	          episode_id  : episode_id
	        }
	    }

		swal(
		{
			title: "Activate Episode",
			text: "This Episode will be visible on your channel",
			type: "warning",
			showCancelButton: true,
			confirmButtonColor: "success",
			confirmButtonText: "Activate",
			cancelButtonText: "Cancel!",
			closeOnConfirm: false,
			closeOnCancel: false
		},
		function(isConfirm)
		{
		  if (isConfirm)
		  {
		    ajaxCall(data, functionName)
		  }
		  else
		  {
			swal("Cancelled", "Your episode is safe :)", "error");
		  }
		});
	}

	/*
	# Ajax
	*/
	function ajaxCall (data, functionName)
	{
		$.ajax({
			url: data.url,
			type: data.method,
			data: data.parameter,
			success: function (response)
			{
				ajaxLogic (response, functionName)
			},
			error: function()
			{
				alert('Are you sure you doing this the right way?');
			},
		});
	}

	function ajaxLogic (response, functionName)
	{
		/*
		# Check if Response.status = 401
		*/
		if (response.status === 401)
		{
			switch (functionName) {
	          case "deleteEpisode" : deleteEpisodeErrorAlert(); break;
	          case "activateEpisode" : activateEpisodeErrorAlert(); break;
	        }
		}

		/*
		# Check if Response.status = 200
		*/
		if (response.status === 200)
		{
			switch (functionName) {
	          case "deleteEpisode" : deleteEpisodeSuccessAlert(); break;
	          case "activateEpisode" : activateEpisodeSuccessAlert(); break;
	        }
		}
	}

	/*
	####################################################################
	# deleteEpisodeErrorAlert Message
	*/
	function deleteEpisodeErrorAlert()
	{
		swal("Hmmmm", "This episode does not exist ", "error");
	}

	/*
	# deleteEpisodeSuccessAlert Message
	*/
	function deleteEpisodeSuccessAlert()
	{
		swal("Deleted!", "Your episode has been deleted.", "success");
		var deleted =  $('.selected');
		deleted.hide();
	}

	/*
	####################################################################
	# activateEpisodeErrorAlert() Message
	*/
	function activateEpisodeErrorAlert()
	{
		swal("Hmmmm", "This episode does not exist ", "error");
	}

	function activateEpisodeSuccessAlert()
	{
		swal("Activated", "Your episode has been Activated.", "success");

		var deleted 	=  $(".selected");
		var new_item 	=  $("#active_section");

		new_item.append(item[0]);

		deleted.show();
	}

});
<|endoftext|>


<commit_before>
(function() {
    'use strict';
    resetForm('add_expense_form');
})();

function addExpense() {

    let data = serialize('add_expense_form');

    let xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            let response = JSON.parse(this.responseText);
            if ('' !== response.trim()) {
                alert(response);
            } else {
                listExpenses();
                setTotal();
            }
        }
    };
    xhttp.open("POST", "addExpense", true);
    xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xhttp.send(data);

    resetForm('add_expense_form');

    return false;
}

function resetForm(form_name) {
    let form = document.querySelector('#' + form_name);
    if (null !== form) {
        form.reset();
        setDate();
    }

    document.querySelector('#details').addEventListener('click', function() {
        viewExpensesDetails();
    });
}

function serialize(form_id) {
    let response = '';
    let text_inputs = document.querySelectorAll('#' + form_id +' input[type=text]');
    text_inputs.forEach(function(element) {
        let name = encodeURI(element.name);
        let value = encodeURI(element.value);
        response += name + '=' + value + '&';
    });
    let number_inputs = document.querySelectorAll('#' + form_id +' input[type=number]');
    number_inputs.forEach(function(element) {
        let name = encodeURI(element.name);
        let value = encodeURI(element.value);
        response += name + '=' + value + '&';
    });
    let date_inputs = document.querySelectorAll('#' + form_id +' input[type=date]');
    date_inputs.forEach(function(element) {
        let name = encodeURI(element.name);
        let value = encodeURI(element.value);
        response += name + '=' + value + '&';
    });
    let check_inputs = document.querySelectorAll('#' + form_id +' input[type=checkbox]:checked');
    check_inputs.forEach(function(element) {
        let name = encodeURI(element.name);
        let value = encodeURI(element.value);
        response += name + '=' + value + '&';
    });
    let select_inputs = document.querySelectorAll('#' + form_id +' select');
    select_inputs.forEach(function(element) {
        let name = encodeURI(element.name);
        let value = encodeURI(element.value);
        response += name + '=' + value + '&';
    });
    let hidden_inputs = document.querySelectorAll('#' + form_id +' input[type=hidden]');
    hidden_inputs.forEach(function(element) {
        let name = encodeURI(element.name);
        let value = encodeURI(element.value);
        response += name + '=' + value + '&';
    });

    return response;
}

function getCurrentDate() {
    var today = new Date();
    var dd = today.getDate();
    var mm = today.getMonth()+1; //January is 0!
    var yyyy = today.getFullYear();

    if (dd < 10) {
        dd='0'+dd;
    }

    if (mm < 10) {
        mm='0'+mm;
    }

    today = yyyy+'-'+mm+'-'+dd;
    return today;
}

function listExpenses() {
    let html = '';
    let user_id = document.querySelector('#user_id').value;
    let xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            if ('' !== this.responseText) {
                let expenses_list = JSON.parse(this.responseText);
                expenses_list.forEach(function (element) {
                    let date = formatDate(element.date);
                    html += '

'+element.name+': '+element.amount+' € ('+element.paid_by.name+' '+date.toLocaleString()+')';
                    if (element.shared === 0) {
                        html += ' - thief!! -';
                    }
                    html += '

X

';
                });
                document.querySelector('#expenses').innerHTML = html;
            }
        }
    };

    xhttp.open("GET", "expenses/" + user_id, true);
    xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xhttp.send();
}

function deleteExpense(expense_id) {
    var r = confirm("Are you shure?");
    if (r === true) {
        let xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                let response = JSON.parse(this.responseText);
                if ('' !== response.trim()) {
                    alert(response);
                } else {
                    listExpenses();
                    setTotal();
                }
            }
        };

        xhttp.open("GET", "deleteExpense/" + expense_id, true);
        xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xhttp.send();
    }
}

function setTotal() {
    let xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            if ('' !== this.responseText) {
                let total = JSON.parse(this.responseText);
                let html = total.user + " has a debt of " + total.amount+" €";
                document.querySelector('#total').innerHTML = html;
            }
        }
    };

    xhttp.open("GET", "total", true);
    xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xhttp.send();
}

function formatDate(date) {

    var t = date.split(/[- :]/);

    // Apply each element to the Date function
    var my_date = new Date(t[0], t[1]-1, t[2], t[3], t[4], t[5]);

    // let my_date = new Date(date);
    return my_date.getDate()+'/'+my_date.getMonth()+'/'+my_date.getFullYear();
}

function setDate() {
    var date = document.querySelector('#date');
    if (null !== date) {
        date.value = getCurrentDate();
        document.querySelector('#paid_by').value = document.querySelector('#user_id').value;
    }
}

function viewExpensesDetails() {
    let classList = document.querySelector('#expenses').className;
    if (classList.indexOf('hidden') !== -1) {
        document.querySelector('#expenses').className = 'panel-body';
    } else {
        document.querySelector('#expenses').className = 'panel-body hidden';
    }
}

listExpenses();
setTotal();
<commit_msg>Fixed minor bug con shared expenses<commit_after>
(function() {
    'use strict';
    resetForm('add_expense_form');
})();

function addExpense() {

    let data = serialize('add_expense_form');

    let xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            let response = JSON.parse(this.responseText);
            if ('' !== response.trim()) {
                alert(response);
            } else {
                listExpenses();
                setTotal();
            }
        }
    };
    xhttp.open("POST", "addExpense", true);
    xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xhttp.send(data);

    resetForm('add_expense_form');

    return false;
}

function resetForm(form_name) {
    let form = document.querySelector('#' + form_name);
    if (null !== form) {
        form.reset();
        setDate();
    }

    document.querySelector('#details').addEventListener('click', function() {
        viewExpensesDetails();
    });
}

function serialize(form_id) {
    let response = '';
    let text_inputs = document.querySelectorAll('#' + form_id +' input[type=text]');
    text_inputs.forEach(function(element) {
        let name = encodeURI(element.name);
        let value = encodeURI(element.value);
        response += name + '=' + value + '&';
    });
    let number_inputs = document.querySelectorAll('#' + form_id +' input[type=number]');
    number_inputs.forEach(function(element) {
        let name = encodeURI(element.name);
        let value = encodeURI(element.value);
        response += name + '=' + value + '&';
    });
    let date_inputs = document.querySelectorAll('#' + form_id +' input[type=date]');
    date_inputs.forEach(function(element) {
        let name = encodeURI(element.name);
        let value = encodeURI(element.value);
        response += name + '=' + value + '&';
    });
    let check_inputs = document.querySelectorAll('#' + form_id +' input[type=checkbox]:checked');
    check_inputs.forEach(function(element) {
        let name = encodeURI(element.name);
        let value = encodeURI(element.value);
        response += name + '=' + value + '&';
    });
    let select_inputs = document.querySelectorAll('#' + form_id +' select');
    select_inputs.forEach(function(element) {
        let name = encodeURI(element.name);
        let value = encodeURI(element.value);
        response += name + '=' + value + '&';
    });
    let hidden_inputs = document.querySelectorAll('#' + form_id +' input[type=hidden]');
    hidden_inputs.forEach(function(element) {
        let name = encodeURI(element.name);
        let value = encodeURI(element.value);
        response += name + '=' + value + '&';
    });

    return response;
}

function getCurrentDate() {
    var today = new Date();
    var dd = today.getDate();
    var mm = today.getMonth()+1; //January is 0!
    var yyyy = today.getFullYear();

    if (dd < 10) {
        dd='0'+dd;
    }

    if (mm < 10) {
        mm='0'+mm;
    }

    today = yyyy+'-'+mm+'-'+dd;
    return today;
}

function listExpenses() {
    let html = '';
    let user_id = document.querySelector('#user_id').value;
    let xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            if ('' !== this.responseText) {
                let expenses_list = JSON.parse(this.responseText);
                expenses_list.forEach(function (element) {
                    let date = formatDate(element.date);
                    let shared = parseInt(element.shared);

                    html += '

'+element.name+': '+element.amount+' € ('+element.paid_by.name+' '+date.toLocaleString()+')';

                    if (shared === 0) {
                        html += ' - thief!! -';
                    }
                    html += '

X

';
                });
                document.querySelector('#expenses').innerHTML = html;
            }
        }
    };

    xhttp.open("GET", "expenses/" + user_id, true);
    xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xhttp.send();
}

function deleteExpense(expense_id) {
    var r = confirm("Are you shure?");
    if (r === true) {
        let xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                let response = JSON.parse(this.responseText);
                if ('' !== response.trim()) {
                    alert(response);
                } else {
                    listExpenses();
                    setTotal();
                }
            }
        };

        xhttp.open("GET", "deleteExpense/" + expense_id, true);
        xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xhttp.send();
    }
}

function setTotal() {
    let xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            if ('' !== this.responseText) {
                let total = JSON.parse(this.responseText);
                let html = total.user + " has a debt of " + total.amount+" €";
                document.querySelector('#total').innerHTML = html;
            }
        }
    };

    xhttp.open("GET", "total", true);
    xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xhttp.send();
}

function formatDate(date) {

    var t = date.split(/[- :]/);

    // Apply each element to the Date function
    var my_date = new Date(t[0], t[1]-1, t[2], t[3], t[4], t[5]);

    // let my_date = new Date(date);
    return my_date.getDate()+'/'+my_date.getMonth()+'/'+my_date.getFullYear();
}

function setDate() {
    var date = document.querySelector('#date');
    if (null !== date) {
        date.value = getCurrentDate();
        document.querySelector('#paid_by').value = document.querySelector('#user_id').value;
    }
}

function viewExpensesDetails() {
    let classList = document.querySelector('#expenses').className;
    if (classList.indexOf('hidden') !== -1) {
        document.querySelector('#expenses').className = 'panel-body';
    } else {
        document.querySelector('#expenses').className = 'panel-body hidden';
    }
}

listExpenses();
setTotal();
<|endoftext|>


<commit_before>import map from "./map.js";
import bannerNotice from "./banner-notice.js";
import editSelect from "./edit-select.js";
import blogPosts from "./blog-posts.js";
import featuredEntriesCarousel from "./featured-entries-carousel.js";
import homeHero from "./home-hero.js";
import easingFunctions from "./utils/easing-functions.js";
import { CountUp } from "countup.js";
import tracking from "./utils/tracking.js";

const toArray = nodeList => Array.prototype.slice.call(nodeList);

document.addEventListener("DOMContentLoaded", () => {
  map.init();
  editSelect.init();
  blogPosts.init();
  featuredEntriesCarousel.init();
  homeHero.init();
  initSearchForm();
  initStatsAnimations();
  initTracking();
});

function initTracking() {
  const statsLinkEls = toArray(document.querySelectorAll(".js-stats-link"));
  const browseAllLinkEl = document.querySelector(".js-home-hero-browse-all-link");

  if (statsLinkEls) {
    statsLinkEls.forEach(el => {
      el.addEventListener("click", e => {
        e.preventDefault();
        let type = el.getAttribute("data-stats-tracking-name");
        tracking.sendWithCallback("home.hero", "stat_click", type, () => {
          location.href = el.getAttribute("href");
        });
      });
    });
  }

  if(browseAllLinkEl) {
    browseAllLinkEl.addEventListener("click", e => {
      e.preventDefault();
      console.log(e.target.href);
      tracking.sendWithCallback("home.hero", "browse_all_entries_click", "", () => {
        location.href = e.target.href;
      });
    });
  }
}

function initStatsAnimations() {
  const statsEls = toArray(
    document.querySelectorAll(".js-home-hero-stats__stat-number")
  );

  if (!statsEls) return;

  function startAnimation(el) {
    const number = parseInt(el.innerHTML, 10);
    const countUpOptions = {
      useEasing: true,
      duration: 3,
      useGrouping: false,
      easingFn: easingFunctions.easeOutExpo,
    };
    const countUp = new CountUp(el.id, number, countUpOptions);
    countUp.start();
  }
  statsEls.forEach(el => startAnimation(el));
}

function initSearchForm() {
  const searchFormEl = document.querySelector(".js-home-hero-search__form");
  searchFormEl.addEventListener("submit", e => {
    e.preventDefault();
    const selectEl = searchFormEl.querySelector(
      "#js-home-hero-search__edit-select"
    );
    const category = selectEl.options[selectEl.selectedIndex].value;
    const query = searchFormEl.querySelector(".js-home-hero-search__form-input")
      .value;

    let searchUrl = "/search";
    if (category) {
      searchUrl = `${searchUrl}?selectedCategory=${category}`;
    }
    if (category && query) {
      searchUrl = `${searchUrl}&query=${query}`;
    } else if (query) {
      searchUrl = `${searchUrl}?query=${query}`;
    }
    if(query) {
      tracking.send("home.hero", "search_submit", query);
    }

    location.href = searchUrl;
  });
}
<commit_msg>track hero entry title click<commit_after>import map from "./map.js";
import bannerNotice from "./banner-notice.js";
import editSelect from "./edit-select.js";
import blogPosts from "./blog-posts.js";
import featuredEntriesCarousel from "./featured-entries-carousel.js";
import homeHero from "./home-hero.js";
import easingFunctions from "./utils/easing-functions.js";
import { CountUp } from "countup.js";
import tracking from "./utils/tracking.js";

const toArray = nodeList => Array.prototype.slice.call(nodeList);

document.addEventListener("DOMContentLoaded", () => {
  map.init();
  editSelect.init();
  blogPosts.init();
  featuredEntriesCarousel.init();
  homeHero.init();
  initSearchForm();
  initStatsAnimations();
  initTracking();
});

function initTracking() {
  const statsLinkEls = toArray(document.querySelectorAll(".js-stats-link"));
  const browseAllLinkEl = document.querySelector(".js-home-hero-browse-all-link");
  const heroCurrentSlide = document.querySelector(".js-home-hero-image-credit__entry-link");

  if (statsLinkEls) {
    statsLinkEls.forEach(el => {
      el.addEventListener("click", e => {
        e.preventDefault();
        let type = el.getAttribute("data-stats-tracking-name");
        tracking.sendWithCallback("home.hero", "stat_click", type, () => {
          location.href = el.getAttribute("href");
        });
      });
    });
  }

  if(browseAllLinkEl) {
    browseAllLinkEl.addEventListener("click", e => {
      e.preventDefault();
      console.log(e.target.href);
      tracking.sendWithCallback("home.hero", "browse_all_entries_click", "", () => {
        location.href = e.target.href;
      });
    });
  }

  if(heroCurrentSlide) {
    heroCurrentSlide.addEventListener("click", e => {
      e.preventDefault();
      const link = e.target.href;
      const id = parseInt(link.substring(link.lastIndexOf('/') + 1));

      if(!Number.isInteger(id)) return;

      tracking.sendWithCallback("home.hero", "hero_entry_title_click", id, () => {
        location.href = e.target.href;
      });
    });
  }
}

function initStatsAnimations() {
  const statsEls = toArray(
    document.querySelectorAll(".js-home-hero-stats__stat-number")
  );

  if (!statsEls) return;

  function startAnimation(el) {
    const number = parseInt(el.innerHTML, 10);
    const countUpOptions = {
      useEasing: true,
      duration: 3,
      useGrouping: false,
      easingFn: easingFunctions.easeOutExpo,
    };
    const countUp = new CountUp(el.id, number, countUpOptions);
    countUp.start();
  }
  statsEls.forEach(el => startAnimation(el));
}

function initSearchForm() {
  const searchFormEl = document.querySelector(".js-home-hero-search__form");
  searchFormEl.addEventListener("submit", e => {
    e.preventDefault();
    const selectEl = searchFormEl.querySelector(
      "#js-home-hero-search__edit-select"
    );
    const category = selectEl.options[selectEl.selectedIndex].value;
    const query = searchFormEl.querySelector(".js-home-hero-search__form-input")
      .value;

    let searchUrl = "/search";
    if (category) {
      searchUrl = `${searchUrl}?selectedCategory=${category}`;
    }
    if (category && query) {
      searchUrl = `${searchUrl}&query=${query}`;
    } else if (query) {
      searchUrl = `${searchUrl}?query=${query}`;
    }
    if(query) {
      tracking.send("home.hero", "search_submit", query);
    }

    location.href = searchUrl;
  });
}
<|endoftext|>


<commit_before>
import Backbone from 'backbone';
import 'backbone-relational';
import CONST from '../const';
import { uuid } from '../core/utils';

export default Backbone.RelationalModel.extend({
    defaults() {
        return {
            creationDate: new Date().toISOString(),
            modificationDate: new Date().toISOString(),
            uuid: undefined,
            key: undefined,
            type: CONST.tagType.text,
            options: [],
            order: undefined,

            locales: {/*
                fr: {
                    key: '',
                    options: [],
                }
            */},
        };
    },

    localizedAttributes: [
        'key',
    ],

    initialize() {
        if (!this.get('uuid')) {
            this.set('uuid', uuid());
        }
    },

    updateModificationDate() {
        this.set('modificationDate', new Date().toISOString());
    },

    isComboField() {
        return [
            CONST.tagType.combo,
            CONST.tagType.typeCombo,
            CONST.tagType.multiCombo,
        ].indexOf(this.get('type')) > -1;
    },

    getLocaleCompletion(localeCode) {
        const options = this.get('options');
        const locale = this.get('locales')[localeCode];
        const data = {
            items: this.localizedAttributes.length + options.length,
            completed: 0,
        };

        if (!locale) {
            return data;
        }

        for (const attribute of this.localizedAttributes) {
            if (locale[attribute]) {
                data.completed += 1;
            }
        }

        if (this.isComboField()) {
            for (const option of options) {
                if (locale.options && locale.options[option]) {
                    data.completed += 1;
                }
            }
        }

        return data;
    },
});
<commit_msg>Fix the tags translation progression calculation<commit_after>
import Backbone from 'backbone';
import 'backbone-relational';
import CONST from '../const';
import { uuid } from '../core/utils';

export default Backbone.RelationalModel.extend({
    defaults() {
        return {
            creationDate: new Date().toISOString(),
            modificationDate: new Date().toISOString(),
            uuid: undefined,
            key: undefined,
            type: CONST.tagType.text,
            options: [],
            order: undefined,

            locales: {/*
                fr: {
                    key: '',
                    options: [],
                }
            */},
        };
    },

    localizedAttributes: [
        'key',
    ],

    initialize() {
        if (!this.get('uuid')) {
            this.set('uuid', uuid());
        }
    },

    updateModificationDate() {
        this.set('modificationDate', new Date().toISOString());
    },

    isComboField() {
        return [
            CONST.tagType.combo,
            CONST.tagType.typeCombo,
            CONST.tagType.multiCombo,
        ].indexOf(this.get('type')) > -1;
    },

    getLocaleCompletion(localeCode) {
        const options = this.get('options');
        const locale = this.get('locales')[localeCode];
        const data = {
            items: this.localizedAttributes.length,
            completed: 0,
        };

        if (!locale) {
            return data;
        }

        for (const attribute of this.localizedAttributes) {
            if (locale[attribute]) {
                data.completed += 1;
            }
        }

        if (this.isComboField()) {
            data.items += options.length;

            for (const option of options) {
                if (locale.options && locale.options[option]) {
                    data.completed += 1;
                }
            }
        }

        return data;
    },
});
<|endoftext|>