<commit_before>//= require polyline

//-------

var directionsService = new google.maps.DirectionsService();

function initialize() {
  directionsDisplay = new google.maps.DirectionsRenderer();

  mapObject = new MapObject();

  directionsDisplay.setMap(mapObject.map);

  // add a waypoint if it's necessary
  // if (PITSTOP) {
  //   route.waypts.push({
  //       location: coords,
  //       stopover: true});
  // }
  route = new Route(START, END);
}

var MapObject = function(){
  this.mapOptions = {
    zoom: 4,
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };
  this.map = new google.maps.Map(document.getElementById('map_canvas'), this.mapOptions);

  this.drawer = new Drawer();
}

//-------Route----------

var Route = function(start, end, waypts){
  this.start = start;
  this.end = end;
  this.waypts = waypts || [];

  this.calculateRoute();
}

Route.prototype.calculateRoute = function(){
  var waypts = []
  if (PITSTOP) {
    waypts.push({
        location: PITSTOP,
        stopover: true,
    })
  }

  App.Waypoints.items.forEach(function(waypoint) {
    var lng = waypoint.attrData.longlat.coordinates[0];
    var lat = waypoint.attrData.longlat.coordinates[1];
    var coords = new google.maps.LatLng(lat, lng);

    waypts.push({
        location: coords,
        stopover: true,
    });
  });
  this.waypts = waypts;

  var request = {
    origin: this.start,
    destination: this.end,
    waypoints: this.waypts,
    optimizeWaypoints: true,
    travelMode: google.maps.TravelMode.DRIVING
  };

  directionsService.route(request, function(response, status){
    if (status == google.maps.DirectionsStatus.OK) {

      decoder = new PolylineDecoder()
      route.polyline = decoder.decodePolyline(response);
      polygon = new Polygon(route.polyline)
            route.displayRoute(response, true)

      var distance = 0;
      var duration = 0;
      response.routes[0].legs.forEach(function(leg) {
        distance += leg.distance.value;
        duration += leg.duration.value;
      });

      $('#distance-counter').text(Math.round(distance / 1609.34) + " miles")

      $('#duration-counter').text(parseInt(duration / 3600) + " hours " + parseInt((duration % 3600) / 60) + " minutes")
    }
  });
};

Route.prototype.displayRoute = function(response){
  directionsDisplay.setDirections(response);
}

Route.prototype.addWaypoint = function(attraction) {
  App.Waypoints.items.push(attraction);
  route.calculateRoute();
}

Route.prototype.removeWaypoint = function(attraction) {
    var index = App.Waypoints.items.indexOf(attraction);
    if (index >= 0) {
      App.Waypoints.items.splice(index, 1);
      route.calculateRoute();
    }
}

//----polyline decoder-----

var PolylineDecoder = function(response){}

PolylineDecoder.prototype.decodePolyline = function(response){
  var coord_array = polyline.decode(response.routes[0].overview_polyline);
  return coord_array.map(function(coordinate) {
    return [coordinate[1], coordinate[0]];
  })
}

//-------Polygon!------------

var Polygon = function(polyline){
  this.geoJson = this.createGeoJsonFromPolyline(polyline)

  this.searchWithin(this.geoJson)

  mapObject.drawer.draw(this.geoJson);
}

Polygon.prototype.createGeoJsonFromPolyline = function(polyline) {
  var line = {
    type:"Feature",
    geometry:{
      type:"LineString",
      coordinates: polyline
     }
   }

  var polygon = turf.buffer(line, 25, 'miles')
  return polygon
}

Polygon.prototype.searchWithin = function(polygon){
  $.ajax({
    url: '/maps/search',
    type: 'post',
    beforeSend: function(xhr) { xhr.setRequestHeader('X-CSRF-Token', $('meta[name=csrf-token]').attr('content'))},
    contentType: "application/json",
    dataType: "json",
    data: JSON.stringify(polygon),
})
  .success(function(response){
    App.AttractionCollection.add(response.attractions);
  })
}

//---------Draw-er---------------------
var Drawer = function(){
  this.bufferedPolygon = new google.maps.Polygon({});
}

Drawer.prototype.createLatLongObjects = function(geoJsonObject){
  var latLongArray = []
  var coordArray = geoJsonObject.features[0].geometry.coordinates[0]

  coordArray.forEach(function(coord){
    latLongArray.push(new google.maps.LatLng(coord[1], coord[0]))
    return latLongArray
  })

  return latLongArray
}

Drawer.prototype.draw = function(geoJsonObject){
  var coordsToDraw = this.createLatLongObjects(geoJsonObject);

  this.bufferedPolygon.setMap(null);

    this.bufferedPolygon = new google.maps.Polygon({
      paths: coordsToDraw,
      strokeColor: '#FF0000',
      strokeOpacity: 0.8,
      strokeWeight: 2,
      fillColor: '#FF0000',
      fillOpacity: 0.35
  });

  this.bufferedPolygon.setMap(mapObject.map);

}

//------------Markers----------------

// function loadMarkers(attractions){
//     $.each(attractions, function(i,item){
//       loadMarker(item);
//     });
//   }

// function loadMarker(attraction){

//   var latitude = attraction.longlat.coordinates[1];
//   var longitude = attraction.longlat.coordinates[0];
//   var coords = new google.maps.LatLng(latitude, longitude);

//   var marker = new google.maps.Marker({
//     position: coords,
//     map: mapObject.map
//   });

//   // new InfoBox(attraction, marker)
//   new Attraction(attraction, marker, route)
// }

//-----------InfoBox----------------

// var InfoBox = function(attraction, marker){
//   this.contentString ='
' +
//                       '
' +
//                       attraction.name +
//                       '
' +
//                       '
 Interest Areas: ' +
//                       attraction.yelp_categories[0][0] +
//                       '
' +
//                       '
 Rating: ' +
//                       attraction.rating +
//                       '
' +
//                       '
 Number of Reviews: ' +
//                       attraction.review_count +
//                       '
' +
//                       '
',
//   this.popup = new google.maps.InfoWindow({content: this.contentString});
//   this.addClickListener(marker)
// }

// InfoBox.prototype.addClickListener = function(marker){
//   var myThis = this
//   google.maps.event.addDomListener(marker, 'click', function(){
//     myThis.popup.open(mapObject.map, marker);
//   });
// }

//------------misc DOM operations-------------------

google.maps.event.addDomListener(window, 'load', initialize);

google.maps.event.addDomListener(window, "resize", function() {
    var center = mapObject.map.getCenter();
    google.maps.event.trigger(mapObject.map, "resize");
    mapObject.map.setCenter(center);
  });
<commit_msg>adding an attraction to the trip now removes the marker from GMaps, but leaves the default waypoint marker.  Originally there were two, which was confusing from a UI standpoint<commit_after>//= require polyline

//-------

var directionsService = new google.maps.DirectionsService();

function initialize() {
  directionsDisplay = new google.maps.DirectionsRenderer();

  mapObject = new MapObject();

  directionsDisplay.setMap(mapObject.map);

  // add a waypoint if it's necessary
  // if (PITSTOP) {
  //   route.waypts.push({
  //       location: coords,
  //       stopover: true});
  // }
  route = new Route(START, END);
}

var MapObject = function(){
  this.mapOptions = {
    zoom: 4,
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };
  this.map = new google.maps.Map(document.getElementById('map_canvas'), this.mapOptions);

  this.drawer = new Drawer();
}

//-------Route----------

var Route = function(start, end, waypts){
  this.start = start;
  this.end = end;
  this.waypts = waypts || [];

  this.calculateRoute();
}

Route.prototype.calculateRoute = function(){
  var waypts = []
  if (PITSTOP) {
    waypts.push({
        location: PITSTOP,
        stopover: true,
    })
  }

  App.Waypoints.items.forEach(function(waypoint) {
    var lng = waypoint.attrData.longlat.coordinates[0];
    var lat = waypoint.attrData.longlat.coordinates[1];
    var coords = new google.maps.LatLng(lat, lng);

    waypts.push({
        location: coords,
        stopover: true,
    });
  });
  this.waypts = waypts;

  var request = {
    origin: this.start,
    destination: this.end,
    waypoints: this.waypts,
    optimizeWaypoints: true,
    travelMode: google.maps.TravelMode.DRIVING
  };

  directionsService.route(request, function(response, status){
    if (status == google.maps.DirectionsStatus.OK) {

      decoder = new PolylineDecoder()
      route.polyline = decoder.decodePolyline(response);
      polygon = new Polygon(route.polyline)
            route.displayRoute(response, true)

      var distance = 0;
      var duration = 0;
      response.routes[0].legs.forEach(function(leg) {
        distance += leg.distance.value;
        duration += leg.duration.value;
      });

      $('#distance-counter').text(Math.round(distance / 1609.34) + " miles")

      $('#duration-counter').text(parseInt(duration / 3600) + " hours " + parseInt((duration % 3600) / 60) + " minutes")
    }
  });
};

Route.prototype.displayRoute = function(response){
  directionsDisplay.setDirections(response);
}

Route.prototype.addWaypoint = function(attraction) {
  App.Waypoints.items.push(attraction);
  attraction.marker.marker.setMap(null)
  route.calculateRoute();
}

Route.prototype.removeWaypoint = function(attraction) {
    var index = App.Waypoints.items.indexOf(attraction);
    if (index >= 0) {
      App.Waypoints.items.splice(index, 1);
      route.calculateRoute();
    }
}

//----polyline decoder-----

var PolylineDecoder = function(response){}

PolylineDecoder.prototype.decodePolyline = function(response){
  var coord_array = polyline.decode(response.routes[0].overview_polyline);
  return coord_array.map(function(coordinate) {
    return [coordinate[1], coordinate[0]];
  })
}

//-------Polygon!------------

var Polygon = function(polyline){
  this.geoJson = this.createGeoJsonFromPolyline(polyline)

  this.searchWithin(this.geoJson)

  mapObject.drawer.draw(this.geoJson);
}

Polygon.prototype.createGeoJsonFromPolyline = function(polyline) {
  var line = {
    type:"Feature",
    geometry:{
      type:"LineString",
      coordinates: polyline
     }
   }

  var polygon = turf.buffer(line, 25, 'miles')
  return polygon
}

Polygon.prototype.searchWithin = function(polygon){
  $.ajax({
    url: '/maps/search',
    type: 'post',
    beforeSend: function(xhr) { xhr.setRequestHeader('X-CSRF-Token', $('meta[name=csrf-token]').attr('content'))},
    contentType: "application/json",
    dataType: "json",
    data: JSON.stringify(polygon),
})
  .success(function(response){
    App.AttractionCollection.add(response.attractions);
  })
}

//---------Draw-er---------------------
var Drawer = function(){
  this.bufferedPolygon = new google.maps.Polygon({});
}

Drawer.prototype.createLatLongObjects = function(geoJsonObject){
  var latLongArray = []
  var coordArray = geoJsonObject.features[0].geometry.coordinates[0]

  coordArray.forEach(function(coord){
    latLongArray.push(new google.maps.LatLng(coord[1], coord[0]))
    return latLongArray
  })

  return latLongArray
}

Drawer.prototype.draw = function(geoJsonObject){
  var coordsToDraw = this.createLatLongObjects(geoJsonObject);

  this.bufferedPolygon.setMap(null);

    this.bufferedPolygon = new google.maps.Polygon({
      paths: coordsToDraw,
      strokeColor: '#FF0000',
      strokeOpacity: 0.8,
      strokeWeight: 2,
      fillColor: '#FF0000',
      fillOpacity: 0.35
  });

  this.bufferedPolygon.setMap(mapObject.map);

}

//------------Markers----------------

// function loadMarkers(attractions){
//     $.each(attractions, function(i,item){
//       loadMarker(item);
//     });
//   }

// function loadMarker(attraction){

//   var latitude = attraction.longlat.coordinates[1];
//   var longitude = attraction.longlat.coordinates[0];
//   var coords = new google.maps.LatLng(latitude, longitude);

//   var marker = new google.maps.Marker({
//     position: coords,
//     map: mapObject.map
//   });

//   // new InfoBox(attraction, marker)
//   new Attraction(attraction, marker, route)
// }

//-----------InfoBox----------------

// var InfoBox = function(attraction, marker){
//   this.contentString ='
' +
//                       '
' +
//                       attraction.name +
//                       '
' +
//                       '
 Interest Areas: ' +
//                       attraction.yelp_categories[0][0] +
//                       '
' +
//                       '
 Rating: ' +
//                       attraction.rating +
//                       '
' +
//                       '
 Number of Reviews: ' +
//                       attraction.review_count +
//                       '
' +
//                       '
',
//   this.popup = new google.maps.InfoWindow({content: this.contentString});
//   this.addClickListener(marker)
// }

// InfoBox.prototype.addClickListener = function(marker){
//   var myThis = this
//   google.maps.event.addDomListener(marker, 'click', function(){
//     myThis.popup.open(mapObject.map, marker);
//   });
// }

//------------misc DOM operations-------------------

google.maps.event.addDomListener(window, 'load', initialize);

google.maps.event.addDomListener(window, "resize", function() {
    var center = mapObject.map.getCenter();
    google.maps.event.trigger(mapObject.map, "resize");
    mapObject.map.setCenter(center);
  });
<|endoftext|>


<commit_before>$(document).ready(function(){
  $('.menu-toggle').on('mouseenter',function() {
    $('.nav-list').css('display', 'inline')
  });

  $('.menu-toggle').bind('mouseleave', function(){
    $('.nav-list').css('display', 'inline')
    $('.nav-list').hide();
  });
});
<commit_msg>fixed original error, have new one<commit_after>$(document).ready(function(){
  $('.menu-toggle').on('mouseenter',function() {
    $('.nav-list').css('display', 'inline')
  });
  $('.menu-toggle').bind('mouseleave', function(){
    $('.nav-list').css('display', 'inline')
    $('.nav-list').hide();
  });
});
<|endoftext|>


<commit_before>const microcomponent = require('microcomponent')
const html = require('choo/html')
const morph = require('nanomorph')
const css = require('sheetify')
const Nanobounce = require('nanobounce')
const nanobounce = Nanobounce()
// const isEmpty = require('lodash/isEmpty')
// const slug = require('slug/slug-browser')
// const icon = require('./icon.js')
// const translate = require('./translate.js')

const prefix = css('./slider.css')

module.exports = Slider

function Slider () {
  const component = microcomponent({
    progress: 0,
    isMobile: false,
    value: 100,
    state: {
      progress: 0,
      value: 100,
      name: 'slider',
      translations: {}
    }
  })

  component.on('render', render)
  component.on('update', update)
  component.on('load', load)
  component.on('unload', unload)

  return component

  function render () {
    // const self = this
    const state = this.state

    state.name = this.props.name
    state.translations = this.props.translations
    state.progress = this.props.progress
    state.isMobile = this.props.isMobile

    function rangeSlider () {
      return html`

          <input type="range" id="progress" name="percent" ontouchmove=${_onTouchMove} onmousedown=${_mouseDown} onmouseup=${_mouseUp} onmouseout=${_mouseOut} onclick=${_seek} step='0.01' class="seek-bar" value=${state.progress} />

      `
    }

    return html`

        ${!state.isMobile ? rangeSlider() : html`

            <input min="0" max="1000" class="w-100" type="number" onchange=${_distanceKmToProgress} value=${Math.round(10 * state.progress)} />

        `}

    `
  }

  function _distanceKmToProgress (e) {
    const value = e.target.value
    const percent = (value / 1000) * 100
    component.emit('progress', percent)
  }

  function _onTouchMove (e) {
    e.target.addEventListener('touchmove', _seek)
  }

  function _mouseDown (e) {
    e.target.addEventListener('mousemove', _seek)
  }

  function _mouseUp (e) {
    e.target.removeEventListener('mousemove', _seek)
  }

  function _mouseOut (e) {
    e.target.removeEventListener('mousemove', _seek)
  }

  function _computeCss (prop, progress) {
    return `${prop}:${progress}%;`
  }

  function _seek (e) {
    e.preventDefault()

    if (e.offsetX < 0) return false

    const percent = (e.offsetX / e.target.offsetWidth || (e.layerX - e.target.offsetLeft) / e.target.offsetWidth) * 100

    if (percent > 100) return false

    component.state.progress = percent

    nanobounce(function () {
      component.emit('progress', percent)
    })

    component._element.querySelector('.seek-bar').value = component.state.progress
    morph(component._element.querySelector('.range-slider--fill'), html`<div class="range-slider--fill" style=${_computeCss('width', 100 - component.state.progress)}></div>`)
    morph(component._element.querySelector('.range-slider--handle'), html`<div class="range-slider--handle" style=${_computeCss('left', component.state.progress)}></div>`)
  }

  function load () {
    console.log('loaded')
  }

  function unload () {
    console.log('unloaded')
    component._element = null
  }

  function update (props) {
    return props.progress !== component.state.progress ||
      props.isMobile !== component.props.isMobile
  }
}
<commit_msg>Don’t need that<commit_after>const microcomponent = require('microcomponent')
const html = require('choo/html')
const morph = require('nanomorph')
const css = require('sheetify')
const Nanobounce = require('nanobounce')
const nanobounce = Nanobounce()
// const isEmpty = require('lodash/isEmpty')
// const slug = require('slug/slug-browser')
// const icon = require('./icon.js')
// const translate = require('./translate.js')

const prefix = css('./slider.css')

module.exports = Slider

function Slider () {
  const component = microcomponent({
    progress: 0,
    isMobile: false,
    value: 100,
    state: {
      progress: 0,
      value: 100,
      name: 'slider',
      translations: {}
    }
  })

  component.on('render', render)
  component.on('update', update)
  component.on('load', load)
  component.on('unload', unload)

  return component

  function render () {
    // const self = this
    const state = this.state

    state.name = this.props.name
    state.translations = this.props.translations
    state.progress = this.props.progress
    state.isMobile = this.props.isMobile

    function rangeSlider () {
      return html`

          <input type="range" id="progress" name="percent" onmousedown=${_mouseDown} onmouseup=${_mouseUp} onmouseout=${_mouseOut} onclick=${_seek} step='0.01' class="seek-bar" value=${state.progress} />

      `
    }

    return html`

        ${!state.isMobile ? rangeSlider() : html`

            <input min="0" max="1000" class="w-100" type="number" onchange=${_distanceKmToProgress} value=${Math.round(10 * state.progress)} />

        `}

    `
  }

  function _distanceKmToProgress (e) {
    const value = e.target.value
    const percent = (value / 1000) * 100
    component.emit('progress', percent)
  }

  function _mouseDown (e) {
    e.target.addEventListener('mousemove', _seek)
  }

  function _mouseUp (e) {
    e.target.removeEventListener('mousemove', _seek)
  }

  function _mouseOut (e) {
    e.target.removeEventListener('mousemove', _seek)
  }

  function _computeCss (prop, progress) {
    return `${prop}:${progress}%;`
  }

  function _seek (e) {
    e.preventDefault()

    if (e.offsetX < 0) return false

    const percent = (e.offsetX / e.target.offsetWidth || (e.layerX - e.target.offsetLeft) / e.target.offsetWidth) * 100

    if (percent > 100) return false

    component.state.progress = percent

    nanobounce(function () {
      component.emit('progress', percent)
    })

    component._element.querySelector('.seek-bar').value = component.state.progress
    morph(component._element.querySelector('.range-slider--fill'), html`<div class="range-slider--fill" style=${_computeCss('width', 100 - component.state.progress)}></div>`)
    morph(component._element.querySelector('.range-slider--handle'), html`<div class="range-slider--handle" style=${_computeCss('left', component.state.progress)}></div>`)
  }

  function load () {
    console.log('loaded')
  }

  function unload () {
    console.log('unloaded')
    component._element = null
  }

  function update (props) {
    return props.progress !== component.state.progress ||
      props.isMobile !== component.props.isMobile
  }
}
<|endoftext|>


<commit_before>(function () {
  "use strict";

  var SELECTED_RADIUS  = 10;
  var DEFAULT_RADIUS = 6;

  // Utils

  // rounds coordinates before setting to state model
  // https://en.wikipedia.org/wiki/Wikipedia:WikiProject_Geographical_coordinates#Precision_guidelines
  // 0.0001° = 5 - 10m accuracy
  // should be enough and makes urls shorter
  function coordsRound(n) {
    return Math.round(n * 10000) / 10000;
  }

  function pointerEventCoordinates(evt) {
    var isTouch = evt.type.indexOf('touch') === 0;
    if (isTouch) {
      return {
        x: evt.changedTouches[0].pageX,
        y: evt.changedTouches[0].pageY
      };
    } else {
      return {
        x: evt.clientX + window.pageXOffset,
        y: evt.clientY + window.pageYOffset
      };
    }
  }

  function pointerMoved(start, end) {
    if (!start || !end) return false;
    return Math.abs(start.x - end.x) > 5 || Math.abs(start.y - end.y) > 5;
  }

  function colorForSentiment(sentiment) {
    switch (parseInt(sentiment, 10)) {
      case -1:
        return "#f3182c";
      case 1:
        return "#3dbd05";
      default:
        return "#4299ff";
    }
  }

  function makePersistedMarker(comment, latlng) {
    return new L.CircleMarker(latlng, {
      stroke: true,
      color: '#fff',
      opacity: 1,
      weight: 2,
      fill: true,
      fillColor: colorForSentiment(comment.get('sentiment')),
      fillOpacity: 1,
      clickable: true
    }).setRadius(comment.get('selected') ? SELECTED_RADIUS : DEFAULT_RADIUS);
  }

  function makePlaceableMarker(comment, latlng) {
    var icon = L.icon({
        iconUrl: '/bundles/nzzmytown/images/marker-icon-red.png',
        iconSize: [25, 41],
        iconAnchor: [13, 43]
    });

    return new L.Marker(latlng, {
      icon: icon,
      riseOnHover: true,
      draggable: true
    });
  }

  // Class definition
  window.app.views.MapView = Backbone.View.extend({
    events: {
      'mousedown':  'onStartPlaceMarker',
      'mouseup':    'onEndPlaceMarker',
      'touchstart': 'onStartPlaceMarker',
      'touchend':   'onEndPlaceMarker'
    },

    initialize: function() {
      _.bindAll(this, 'initMap', 'onStartPlaceMarker', 'onEndPlaceMarker', 'addMarkerForComment', 'updateMarkerForComment', 'selectMarkerForComment', 'removeMarkerForComment');

      // Keep track of all placed markers
      this.markers = {};

      // Bind event listeners
      this.listenTo(this.model.comments, 'add',    this.addMarkerForComment);
      this.listenTo(this.model.comments, 'remove', this.removeMarkerForComment);
      this.listenTo(this.model.comments, 'change:persisted', this.updateMarkerForComment);
      this.listenTo(this.model.comments, 'change:latitude',  this.updateMarkerForComment);
      this.listenTo(this.model.comments, 'change:longitude', this.updateMarkerForComment);
      this.listenTo(this.model.comments, 'change:selected', this.selectMarkerForComment);
    },

    render: function() {
      _.defer(this.initMap);
      return this;
    },

    initMap: function() {
      var state = this.model.state,
          mapCenter = new L.LatLng(state.get('lat'), state.get('lng'));
      this.map = L.mapbox.map(this.el, app.config.mapboxKey, {
        attributionControl: true,
        zoomControl: false
      });
      this.map.setView(mapCenter, (parseInt(state.get('zoom'), 10) || 12)); // if zoom param is not int fallback to 12

      // Add zoom control
      this.map.addControl(new L.Control.Zoom({
        position: 'topright'
      }));

      // debounced
      var saveState = _.debounce(function() {
        var coords = this.map.getCenter();
        this.model.state.set({
          'lat': coordsRound(coords.lat),
          'lng': coordsRound(coords.lng),
          'zoom': this.map.getZoom()
        });
      }.bind(this), 500);
      this.map.on('moveend', saveState);
      this.map.on('zoomend', saveState);

      // Filter the comment list
      var refreshState = _.debounce(function() {
        this.updateVisibleComments();
      }.bind(this), 50);
      this.map.on('moveend', refreshState);
      this.map.on('zoomend', refreshState);
      this.updateVisibleComments();

      // Add initial markers
      this.model.comments.forEach(this.addMarkerForComment);
    },

    onStartPlaceMarker: function(evt) {
      this._pointerEventStart = pointerEventCoordinates(evt.originalEvent);
    },

    onEndPlaceMarker: function(evt) {
      var comment = this.model.comments.findNew();
      var pointerEnd = pointerEventCoordinates(evt.originalEvent);

      if (comment && !pointerMoved(this._pointerEventStart, pointerEnd)) {
        // Using a Point instead of mouseEventToLatLng because the latter
        // doesn't work with touch events
        var offset = $(this.map.getContainer()).offset();
        var point = new L.Point(pointerEnd.x - offset.left, pointerEnd.y - offset.top);
        var latlng = this.map.containerPointToLatLng(point);
        comment.setLatLng(latlng);
      }
    },

    addMarkerForComment: function(comment) {
      // If a marker already exists, remove it before adding it again
      if (this.markers[comment.cid]) {
        this.removeMarkerForComment(comment);
      }

      var latlng = comment.getLatLng() || this.map.getCenter();
      var comments = this.model.comments;
      var marker;

      if (comment.isPersisted()) {
        marker = makePersistedMarker(comment, latlng);
        marker.on('click', function(evt) {
          comments.selectComment(comment);
          marker.bringToFront();
        });
      } else {
        marker = makePlaceableMarker(comment, latlng);
        marker.on('move', function(evt) {
          comment.setLatLng(evt.latlng);
        });
      }

      comment.setLatLng(latlng);

      marker.addTo(this.map);
      this.markers[comment.cid] = {
        el: marker,
        selected: comment.get('selected'),
        persisted: comment.isPersisted()
      };
    },

    updateMarkerForComment: function(comment) {
      var marker = this.markers[comment.cid];
      if (!marker) return;

      if (marker.persisted == comment.isPersisted()) {
        marker.el.setLatLng(comment.getLatLng());
      } else {
        this.removeMarkerForComment(comment);
        this.addMarkerForComment(comment);
      }
    },

    selectMarkerForComment: function(comment) {
      var marker = this.markers[comment.cid];
      if (!marker || !marker.persisted) return;
      marker.el.setRadius(comment.get('selected') ? SELECTED_RADIUS : DEFAULT_RADIUS);

      if (comment.get('selected')) {
        var defaultZoom = this.model.get('defaultzoom'),
            commentLatLng = comment.getLatLng();
        if(this.map.getZoom() < defaultZoom || !this.map.getBounds().contains(commentLatLng)) {
          this.map.setZoom(defaultZoom, {animate: true});
        }
        this.map.panTo(commentLatLng, {
          animate: true,
          duration: 0.3
        });
      }
    },

    removeMarkerForComment: function(comment) {
      var marker = this.markers[comment.cid];
      this.map.removeLayer(marker.el);
      marker.el.off('click');
      marker.el.off('move');
      delete this.markers[comment.id];
    },

    updateVisibleComments: function() {
      var bounds = this.map.getBounds();
      this.model.comments.each(function(comment) {
      	if (bounds.contains(comment.getLatLng()) || comment.get('selected')) {
          comment.set('visible', true);
      	} else {
          comment.set('visible', false);
      	}
      });
    }
  });
}());
<commit_msg>added credentials on map view<commit_after>(function () {
  "use strict";

  var SELECTED_RADIUS  = 10;
  var DEFAULT_RADIUS = 6;

  // Utils

  // rounds coordinates before setting to state model
  // https://en.wikipedia.org/wiki/Wikipedia:WikiProject_Geographical_coordinates#Precision_guidelines
  // 0.0001° = 5 - 10m accuracy
  // should be enough and makes urls shorter
  function coordsRound(n) {
    return Math.round(n * 10000) / 10000;
  }

  function pointerEventCoordinates(evt) {
    var isTouch = evt.type.indexOf('touch') === 0;
    if (isTouch) {
      return {
        x: evt.changedTouches[0].pageX,
        y: evt.changedTouches[0].pageY
      };
    } else {
      return {
        x: evt.clientX + window.pageXOffset,
        y: evt.clientY + window.pageYOffset
      };
    }
  }

  function pointerMoved(start, end) {
    if (!start || !end) return false;
    return Math.abs(start.x - end.x) > 5 || Math.abs(start.y - end.y) > 5;
  }

  function colorForSentiment(sentiment) {
    switch (parseInt(sentiment, 10)) {
      case -1:
        return "#f3182c";
      case 1:
        return "#3dbd05";
      default:
        return "#4299ff";
    }
  }

  function makePersistedMarker(comment, latlng) {
    return new L.CircleMarker(latlng, {
      stroke: true,
      color: '#fff',
      opacity: 1,
      weight: 2,
      fill: true,
      fillColor: colorForSentiment(comment.get('sentiment')),
      fillOpacity: 1,
      clickable: true
    }).setRadius(comment.get('selected') ? SELECTED_RADIUS : DEFAULT_RADIUS);
  }

  function makePlaceableMarker(comment, latlng) {
    var icon = L.icon({
        iconUrl: '/bundles/nzzmytown/images/marker-icon-red.png',
        iconSize: [25, 41],
        iconAnchor: [13, 43]
    });

    return new L.Marker(latlng, {
      icon: icon,
      riseOnHover: true,
      draggable: true
    });
  }

  // Class definition
  window.app.views.MapView = Backbone.View.extend({
    events: {
      'mousedown':  'onStartPlaceMarker',
      'mouseup':    'onEndPlaceMarker',
      'touchstart': 'onStartPlaceMarker',
      'touchend':   'onEndPlaceMarker'
    },

    initialize: function() {
      _.bindAll(this, 'initMap', 'onStartPlaceMarker', 'onEndPlaceMarker', 'addMarkerForComment', 'updateMarkerForComment', 'selectMarkerForComment', 'removeMarkerForComment');

      // Keep track of all placed markers
      this.markers = {};

      // Bind event listeners
      this.listenTo(this.model.comments, 'add',    this.addMarkerForComment);
      this.listenTo(this.model.comments, 'remove', this.removeMarkerForComment);
      this.listenTo(this.model.comments, 'change:persisted', this.updateMarkerForComment);
      this.listenTo(this.model.comments, 'change:latitude',  this.updateMarkerForComment);
      this.listenTo(this.model.comments, 'change:longitude', this.updateMarkerForComment);
      this.listenTo(this.model.comments, 'change:selected', this.selectMarkerForComment);
    },

    render: function() {
      _.defer(this.initMap);
      return this;
    },

    initMap: function() {
      var state = this.model.state,
          mapCenter = new L.LatLng(state.get('lat'), state.get('lng'));
      this.map = L.mapbox.map(this.el, app.config.mapboxKey, {
        attributionControl: true,
        zoomControl: false
      });
      this.map.attributionControl.addAttribution('© OpenStreetMap, CC-BY-SA');
      this.map.setView(mapCenter, (parseInt(state.get('zoom'), 10) || 12)); // if zoom param is not int fallback to 12

      // Add zoom control
      this.map.addControl(new L.Control.Zoom({
        position: 'topright'
      }));

      // debounced
      var saveState = _.debounce(function() {
        var coords = this.map.getCenter();
        this.model.state.set({
          'lat': coordsRound(coords.lat),
          'lng': coordsRound(coords.lng),
          'zoom': this.map.getZoom()
        });
      }.bind(this), 500);
      this.map.on('moveend', saveState);
      this.map.on('zoomend', saveState);

      // Filter the comment list
      var refreshState = _.debounce(function() {
        this.updateVisibleComments();
      }.bind(this), 50);
      this.map.on('moveend', refreshState);
      this.map.on('zoomend', refreshState);
      this.updateVisibleComments();

      // Add initial markers
      this.model.comments.forEach(this.addMarkerForComment);
    },

    onStartPlaceMarker: function(evt) {
      this._pointerEventStart = pointerEventCoordinates(evt.originalEvent);
    },

    onEndPlaceMarker: function(evt) {
      var comment = this.model.comments.findNew();
      var pointerEnd = pointerEventCoordinates(evt.originalEvent);

      if (comment && !pointerMoved(this._pointerEventStart, pointerEnd)) {
        // Using a Point instead of mouseEventToLatLng because the latter
        // doesn't work with touch events
        var offset = $(this.map.getContainer()).offset();
        var point = new L.Point(pointerEnd.x - offset.left, pointerEnd.y - offset.top);
        var latlng = this.map.containerPointToLatLng(point);
        comment.setLatLng(latlng);
      }
    },

    addMarkerForComment: function(comment) {
      // If a marker already exists, remove it before adding it again
      if (this.markers[comment.cid]) {
        this.removeMarkerForComment(comment);
      }

      var latlng = comment.getLatLng() || this.map.getCenter();
      var comments = this.model.comments;
      var marker;

      if (comment.isPersisted()) {
        marker = makePersistedMarker(comment, latlng);
        marker.on('click', function(evt) {
          comments.selectComment(comment);
          marker.bringToFront();
        });
      } else {
        marker = makePlaceableMarker(comment, latlng);
        marker.on('move', function(evt) {
          comment.setLatLng(evt.latlng);
        });
      }

      comment.setLatLng(latlng);

      marker.addTo(this.map);
      this.markers[comment.cid] = {
        el: marker,
        selected: comment.get('selected'),
        persisted: comment.isPersisted()
      };
    },

    updateMarkerForComment: function(comment) {
      var marker = this.markers[comment.cid];
      if (!marker) return;

      if (marker.persisted == comment.isPersisted()) {
        marker.el.setLatLng(comment.getLatLng());
      } else {
        this.removeMarkerForComment(comment);
        this.addMarkerForComment(comment);
      }
    },

    selectMarkerForComment: function(comment) {
      var marker = this.markers[comment.cid];
      if (!marker || !marker.persisted) return;
      marker.el.setRadius(comment.get('selected') ? SELECTED_RADIUS : DEFAULT_RADIUS);

      if (comment.get('selected')) {
        var defaultZoom = this.model.get('defaultzoom'),
            commentLatLng = comment.getLatLng();
        if(this.map.getZoom() < defaultZoom || !this.map.getBounds().contains(commentLatLng)) {
          this.map.setZoom(defaultZoom, {animate: true});
        }
        this.map.panTo(commentLatLng, {
          animate: true,
          duration: 0.3
        });
      }
    },

    removeMarkerForComment: function(comment) {
      var marker = this.markers[comment.cid];
      this.map.removeLayer(marker.el);
      marker.el.off('click');
      marker.el.off('move');
      delete this.markers[comment.id];
    },

    updateVisibleComments: function() {
      var bounds = this.map.getBounds();
      this.model.comments.each(function(comment) {
      	if (bounds.contains(comment.getLatLng()) || comment.get('selected')) {
          comment.set('visible', true);
      	} else {
          comment.set('visible', false);
      	}
      });
    }
  });
}());
<|endoftext|>


<commit_before>// @flow

import React, { Component, type Node } from 'react';
import Icon from 'app/components/Icon';
import LoadingIndicator from 'app/components/LoadingIndicator';
import { TextInput } from 'app/components/Form';
import { Overlay } from 'react-overlays';
import cx from 'classnames';
import { isEmpty } from 'lodash';
import InfiniteScroll from 'react-infinite-scroller';
import styles from './Table.css';

type sortProps = {
  direction?: 'asc' | 'desc',
  sort?: string
};

type columnProps = {
  dataIndex: string,
  title: string,
  sorter?: (any, any) => number,
  search?: boolean,
  width?: number,
  render?: (any, Object) => Node
};

type Props = {
  rowKey?: string,
  columns: Array<columnProps>,
  data: Array<Object>,
  hasMore: boolean,
  loading: boolean,
  onChange?: (filters: Object, sort: sortProps) => void,
  onLoad?: (filters: Object, sort: sortProps) => void
};

type State = {
  filters: Object,
  isShown: Object,
  sort: sortProps
};

export default class Table extends Component<Props, State> {
  props: Props;
  components: { [string]: ?HTMLDivElement } = {};

  state: State = {
    sort: {},
    filters: {},
    isShown: {}
  };

  static defaultProps = {
    rowKey: 'id'
  };

  toggleSearch = (dataIndex: string) => {
    this.setState({
      isShown: {
        [dataIndex]: !this.state.isShown[dataIndex]
      }
    });
  };

  onSearchInput = ({ target }: SyntheticInputEvent<*>, dataIndex: string) => {
    this.setState(
      { filters: { ...this.state.filters, [dataIndex]: target.value } },
      () => this.onChange()
    );
  };

  renderCell = (column: columnProps, data: Object, index: number) => {
    return (
      <td key={`${column.dataIndex}-${index}-${data.id}`}>
        {column.render
          ? column.render(data[column.dataIndex], data)
          : data[column.dataIndex]}

    );
  };

  renderHeadCell = (
    { dataIndex, search, title, sorter }: columnProps,
    index: number
  ) => {
    const { filters, isShown } = this.state;

    return (
      <th key={`${dataIndex}-${index}`}>
        {title}
        {sorter && (

            <Icon name="arrow-up" />
            <Icon name="arrow-down" />

        )}
        {search && (

 (this.components[dataIndex] = c)}
              className={styles.searchIcon}
            >
              <Icon
                onClick={() => this.toggleSearch(dataIndex)}
                name="search"
                className={cx(
                  styles.icon,
                  ((filters[dataIndex] && filters[dataIndex].length) ||
                    isShown[dataIndex]) &&
                    styles.iconActive
                )}
              />

            <Overlay
              show={isShown[dataIndex]}
              onHide={() => this.toggleSearch(dataIndex)}
              placement="bottom"
              container={this.components[dataIndex]}
              target={() => this.components[dataIndex]}
              rootClose
            >

                <TextInput
                  autoFocus
                  placeholder="Filtrer"
                  value={filters[dataIndex]}
                  onChange={e => this.onSearchInput(e, dataIndex)}
                  onKeyDown={({ keyCode }) => {
                    if (keyCode === 13) {
                      this.toggleSearch(dataIndex);
                    }
                  }}
                />

            </Overlay>

        )}

    );
  };

  filter = (item: Object) => {
    if (isEmpty(this.state.filters)) {
      return true;
    }

    const match = Object.keys(this.state.filters).filter(key => {
      const filter = this.state.filters[key].toLowerCase();

      if (!filter.length) {
        return true;
      }

      return item[key].toLowerCase().includes(filter);
    }).length;

    return match > 0;
  };

  loadMore = () => {
    if (this.props.onLoad && !this.props.loading) {
      this.props.onLoad(this.state.filters, this.state.sort);
    }
  };

  onChange = () => {
    if (this.props.onChange) {
      this.props.onChange(this.state.filters, this.state.sort);
    }
  };

  render() {
    const { columns, data, rowKey, hasMore, loading } = this.props;
    return (

            {columns.map((column, index) => this.renderHeadCell(column, index))}

        <InfiniteScroll
          element="tbody"
          hasMore={hasMore}
          loadMore={this.loadMore}
          threshold={50}
          loader={

                <LoadingIndicator loading={loading} />

          }
        >
          {data
            .filter(this.filter)
            .map((item, index) => (

                {columns.map((column, index) =>
                  this.renderCell(column, item, index)
                )}

            ))}
        </InfiniteScroll>

    );
  }
}
<commit_msg>Use lodash get when resolving data for table<commit_after>// @flow

import React, { Component, type Node } from 'react';
import Icon from 'app/components/Icon';
import LoadingIndicator from 'app/components/LoadingIndicator';
import { TextInput } from 'app/components/Form';
import { Overlay } from 'react-overlays';
import cx from 'classnames';
import { isEmpty } from 'lodash';
import InfiniteScroll from 'react-infinite-scroller';
import styles from './Table.css';
import { get } from 'lodash';

type sortProps = {
  direction?: 'asc' | 'desc',
  sort?: string
};

type columnProps = {
  dataIndex: string,
  title: string,
  sorter?: (any, any) => number,
  search?: boolean,
  width?: number,
  render?: (any, Object) => Node
};

type Props = {
  rowKey?: string,
  columns: Array<columnProps>,
  data: Array<Object>,
  hasMore: boolean,
  loading: boolean,
  onChange?: (filters: Object, sort: sortProps) => void,
  onLoad?: (filters: Object, sort: sortProps) => void
};

type State = {
  filters: Object,
  isShown: Object,
  sort: sortProps
};

export default class Table extends Component<Props, State> {
  props: Props;
  components: { [string]: ?HTMLDivElement } = {};

  state: State = {
    sort: {},
    filters: {},
    isShown: {}
  };

  static defaultProps = {
    rowKey: 'id'
  };

  toggleSearch = (dataIndex: string) => {
    this.setState({
      isShown: {
        [dataIndex]: !this.state.isShown[dataIndex]
      }
    });
  };

  onSearchInput = ({ target }: SyntheticInputEvent<*>, dataIndex: string) => {
    this.setState(
      { filters: { ...this.state.filters, [dataIndex]: target.value } },
      () => this.onChange()
    );
  };

  renderCell = (column: columnProps, data: Object, index: number) => {
    const cellData = get(data, column.dataIndex);
    return (
      <td key={`${column.dataIndex}-${index}-${data.id}`}>
        {column.render ? column.render(cellData, data) : cellData}

    );
  };

  renderHeadCell = (
    { dataIndex, search, title, sorter }: columnProps,
    index: number
  ) => {
    const { filters, isShown } = this.state;

    return (
      <th key={`${dataIndex}-${index}`}>
        {title}
        {sorter && (

            <Icon name="arrow-up" />
            <Icon name="arrow-down" />

        )}
        {search && (

 (this.components[dataIndex] = c)}
              className={styles.searchIcon}
            >
              <Icon
                onClick={() => this.toggleSearch(dataIndex)}
                name="search"
                className={cx(
                  styles.icon,
                  ((filters[dataIndex] && filters[dataIndex].length) ||
                    isShown[dataIndex]) &&
                    styles.iconActive
                )}
              />

            <Overlay
              show={isShown[dataIndex]}
              onHide={() => this.toggleSearch(dataIndex)}
              placement="bottom"
              container={this.components[dataIndex]}
              target={() => this.components[dataIndex]}
              rootClose
            >

                <TextInput
                  autoFocus
                  placeholder="Filtrer"
                  value={filters[dataIndex]}
                  onChange={e => this.onSearchInput(e, dataIndex)}
                  onKeyDown={({ keyCode }) => {
                    if (keyCode === 13) {
                      this.toggleSearch(dataIndex);
                    }
                  }}
                />

            </Overlay>

        )}

    );
  };

  filter = (item: Object) => {
    if (isEmpty(this.state.filters)) {
      return true;
    }

    const match = Object.keys(this.state.filters).filter(key => {
      const filter = this.state.filters[key].toLowerCase();

      if (!filter.length) {
        return true;
      }

      return item[key].toLowerCase().includes(filter);
    }).length;

    return match > 0;
  };

  loadMore = () => {
    if (this.props.onLoad && !this.props.loading) {
      this.props.onLoad(this.state.filters, this.state.sort);
    }
  };

  onChange = () => {
    if (this.props.onChange) {
      this.props.onChange(this.state.filters, this.state.sort);
    }
  };

  render() {
    const { columns, data, rowKey, hasMore, loading } = this.props;
    return (

            {columns.map((column, index) => this.renderHeadCell(column, index))}

        <InfiniteScroll
          element="tbody"
          hasMore={hasMore}
          loadMore={this.loadMore}
          threshold={50}
          loader={

                <LoadingIndicator loading={loading} />

          }
        >
          {data
            .filter(this.filter)
            .map((item, index) => (

                {columns.map((column, index) =>
                  this.renderCell(column, item, index)
                )}

            ))}
        </InfiniteScroll>

    );
  }
}
<|endoftext|>


<commit_before>import Component from '@ember/component';
import { action, computed } from '@ember/object';
import { empty } from '@ember/object/computed';
import { tracked } from '@glimmer/tracking';

import { task } from 'ember-concurrency';

export default class EmailInput extends Component {
  tagName = '';

  value = '';
  @tracked isEditing = false;
  user = null;

  @empty('value') disableSave;

  prevEmail = '';

  @computed('user.email')
  get emailIsNull() {
    let email = this.get('user.email');
    return email == null;
  }

  @computed('user.{email,email_verified}')
  get emailNotVerified() {
    let email = this.get('user.email');
    let verified = this.get('user.email_verified');

    return email != null && !verified;
  }

  isError = false;
  emailError = '';
  disableResend = false;

  @computed('disableResend', 'user.email_verification_sent')
  get resendButtonText() {
    if (this.disableResend) {
      return 'Sent!';
    } else if (this.get('user.email_verification_sent')) {
      return 'Resend';
    } else {
      return 'Send verification email';
    }
  }

  @task(function* () {
    try {
      yield this.user.resendVerificationEmail();
      this.set('disableResend', true);
    } catch (error) {
      if (error.errors) {
        this.set('isError', true);
        this.set('emailError', `Error in resending message: ${error.errors[0].detail}`);
      } else {
        this.set('isError', true);
        this.set('emailError', 'Unknown error in resending message');
      }
    }
  })
  resendEmailTask;

  @action
  editEmail() {
    this.set('value', this.user.email);
    let email = this.value;
    this.set('emailIsNull', email == null);
    this.isEditing = true;
    this.set('prevEmail', this.value);
  }

  @action
  saveEmail() {
    let userEmail = this.value;
    let user = this.user;

    user.changeEmail(userEmail).catch(err => {
      let msg;
      if (err.errors && err.errors[0] && err.errors[0].detail) {
        msg = `An error occurred while saving this email, ${err.errors[0].detail}`;
      } else {
        msg = 'An unknown error occurred while saving this email.';
      }
      user.set('email', this.prevEmail);
      this.set('isError', true);
      this.set('emailError', `Error in saving email: ${msg}`);
    });

    this.isEditing = false;
    this.set('disableResend', false);
  }

  @action
  cancelEdit() {
    this.isEditing = false;
    this.set('value', this.prevEmail);
  }
}
<commit_msg>EmailInput: Remove obsolete `prevEmail` property<commit_after>import Component from '@ember/component';
import { action, computed } from '@ember/object';
import { empty } from '@ember/object/computed';
import { tracked } from '@glimmer/tracking';

import { task } from 'ember-concurrency';

export default class EmailInput extends Component {
  tagName = '';

  value = '';
  @tracked isEditing = false;
  user = null;

  @empty('value') disableSave;

  @computed('user.email')
  get emailIsNull() {
    let email = this.get('user.email');
    return email == null;
  }

  @computed('user.{email,email_verified}')
  get emailNotVerified() {
    let email = this.get('user.email');
    let verified = this.get('user.email_verified');

    return email != null && !verified;
  }

  isError = false;
  emailError = '';
  disableResend = false;

  @computed('disableResend', 'user.email_verification_sent')
  get resendButtonText() {
    if (this.disableResend) {
      return 'Sent!';
    } else if (this.get('user.email_verification_sent')) {
      return 'Resend';
    } else {
      return 'Send verification email';
    }
  }

  @task(function* () {
    try {
      yield this.user.resendVerificationEmail();
      this.set('disableResend', true);
    } catch (error) {
      if (error.errors) {
        this.set('isError', true);
        this.set('emailError', `Error in resending message: ${error.errors[0].detail}`);
      } else {
        this.set('isError', true);
        this.set('emailError', 'Unknown error in resending message');
      }
    }
  })
  resendEmailTask;

  @action
  editEmail() {
    this.set('value', this.user.email);
    let email = this.value;
    this.set('emailIsNull', email == null);
    this.isEditing = true;
  }

  @action
  saveEmail() {
    let userEmail = this.value;
    let user = this.user;

    user.changeEmail(userEmail).catch(err => {
      let msg;
      if (err.errors && err.errors[0] && err.errors[0].detail) {
        msg = `An error occurred while saving this email, ${err.errors[0].detail}`;
      } else {
        msg = 'An unknown error occurred while saving this email.';
      }
      this.set('isError', true);
      this.set('emailError', `Error in saving email: ${msg}`);
    });

    this.isEditing = false;
    this.set('disableResend', false);
  }

  @action
  cancelEdit() {
    this.isEditing = false;
  }
}
<|endoftext|>


<commit_before>import React from 'react';
import Analyzer from 'Parser/Core/Analyzer';

import SPELLS from 'common/SPELLS/HUNTER';
import StatisticBox, { STATISTIC_ORDER } from 'Interface/Others/StatisticBox';
import SpellIcon from 'common/SpellIcon';
import { formatNumber } from 'common/format';
import RESOURCE_TYPES from 'common/RESOURCE_TYPES';
import SpellUsable from 'Parser/Core/Modules/SpellUsable';
import ResourceIcon from 'common/ResourceIcon';
import Abilities from 'Parser/Core/Modules/Abilities';
import SpellLink from 'common/SpellLink';

/**
 * Immediately gain 1 charge of Aimed Shot, and gain 30% Haste for 15 sec.
 * Lasts 15 sec.
 */
class Trueshot extends Analyzer {
  static dependencies = {
    spellUsable: SpellUsable,
    abilities: Abilities,
  };

  trueshotCasts = 0;
  accumulatedFocusAtTSCast = 0;
  aimedShotsPrTS = 0;
  wastedAimedShotCharges = 0;
  startFocusForCombatant = 0;
  prepullTrueshots = 0;

  on_byPlayer_applybuff(event) {
    const buffId = event.ability.guid;
    if (buffId !== SPELLS.TRUESHOT.id || !event.prepull) {
      return;
    }
    //adds 1 to trueshotCasts to properly show that it was cast prepull
    this.trueshotCasts += 1;
    this.prepullTrueshots += 1;
    //starts the cooldown to ensure proper cast efficiency statistics
    this.spellUsable.beginCooldown(SPELLS.TRUESHOT.id, this.owner.fight.start_time);
  }

  on_byPlayer_cast(event) {
    //checks if we had a prepull trueshot, in which case the firstCast done symbolises our starting focus of that one trueshot
    if (this.prepullTrueshots > 0 && this.startFocusForCombatant === 0) {
      event.classResources.forEach(classResource => {
        if (classResource.type === RESOURCE_TYPES.FOCUS.id && classResource.amount > this.startFocusForCombatant) {
          this.startFocusForCombatant += classResource.amount;
          this.accumulatedFocusAtTSCast += this.startFocusForCombatant;
        }
      });
    }
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.TRUESHOT.id && spellId !== SPELLS.AIMED_SHOT.id) {
      return;
    }
    if (spellId === SPELLS.TRUESHOT.id) {
      this.trueshotCasts += 1;
      if (this.spellUsable.isOnCooldown(SPELLS.AIMED_SHOT.id)) {
        const newChargeCDR = this.abilities.getExpectedCooldownDuration(SPELLS.AIMED_SHOT.id) - this.spellUsable.cooldownRemaining(SPELLS.AIMED_SHOT.id);
        this.spellUsable.endCooldown(SPELLS.AIMED_SHOT.id, false, event.timestamp, newChargeCDR);
      } else {
        this.wastedAimedShotCharges++;
      }
      this.accumulatedFocusAtTSCast += event.classResources[0].amount || 0;
    }
    if (spellId === SPELLS.AIMED_SHOT.id && this.selectedCombatant.hasBuff(SPELLS.TRUESHOT.id)) {
      this.aimedShotsPrTS++;
    }
  }

  statistic() {
    return (
      <StatisticBox icon={<SpellIcon id={SPELLS.TRUESHOT.id} />}
        value={(
          <React.Fragment>
            {this.averageAimedShots.toFixed(2)}{' '}
            <SpellIcon
              id={SPELLS.AIMED_SHOT.id}
              style={{
                height: '1.3em',
                marginTop: '-.1em',
              }}
            />
            {'  '}
            {this.averageFocus}{' '}
            <ResourceIcon
              id={RESOURCE_TYPES.FOCUS.id}
              style={{
                height: '1.3em',
                marginTop: '-.1em',
              }}
            />
          </React.Fragment>
        )}
        label="Trueshot info"
        tooltip={`Information regarding your average Trueshot window:

You started your Trueshot windows with an average of ${this.averageFocus} focus.

You hit an average of ${this.averageAimedShots} Aimed Shots inside each Trueshot window.

You gained ${this.trueshotCasts - this.wastedAimedShotCharges} charges of Aimed Shot and lost out on ${this.wastedAimedShotCharges} charges by activating Trueshot whilst Aimed Shot wasn't on cooldown.

You spent an average of ${this.uptimePerCast.toFixed(2)} seconds in Trueshot per cast of Trueshot.

`} />
    );
  }

  get averageAimedShots() {
    return this.aimedShotsPrTS / this.trueshotCasts;
  }
  get averageFocus() {
    return formatNumber(this.accumulatedFocusAtTSCast / this.trueshotCasts);
  }

  get uptimePerCast() {
    return (this.selectedCombatant.getBuffUptime(SPELLS.TRUESHOT.id) / this.trueshotCasts) / 1000;
  }
  get aimedShotThreshold() {
    return {
      actual: this.averageAimedShots,
      isLessThan: {
        minor: 3,
        average: 2.5,
        major: 2,
      },
      style: 'decimal',
    };
  }
  /** to be evaluated later
   * get focusThreshold() {
    return {
      actual: this.averageFocus,
      isLessThan: {
        minor: 90,
        average: 80,
        major: 70,
      },
      style: 'number',
    };
  }*/
  get uptimeThreshold() {
    return {
      actual: this.uptimePerCast,
      isLessThan: {
        minor: 14.9,
        average: 14.7,
        major: 14.5,
      },
      style: 'decimal',
    };
  }
  get aimedShotRechargeThreshold() {
    return {
      actual: this.wastedAimedShotCharges,
      isGreaterThan: {
        minor: 0,
        average: 0.1,
        major: 1.1,
      },
      style: 'number',
    };
  }
  suggestions(when) {
    when(this.aimedShotThreshold).addSuggestion((suggest, actual, recommended) => {
      return suggest(<React.Fragment>You only cast {actual.toFixed(2)} <SpellLink id={SPELLS.AIMED_SHOT.id} />s inside your average <SpellLink id={SPELLS.TRUESHOT.id} /> window. This is your only DPS cooldown, and it's important to maximize it to it's fullest potential by getting as many Aimed Shot squeezed in as possible.</React.Fragment>)
        .icon(SPELLS.TRUESHOT.icon)
        .actual(`Average of ${actual} Aimed Shots per Trueshot.`)
        .recommended(`>${recommended} is recommended`);
    });
    /*when(this.focusThreshold).addSuggestion((suggest, actual, recommended) => {
      return suggest(<React.Fragment>You started your average <SpellLink id={SPELLS.TRUESHOT.id} /> at {actual} focus, try and pool a bit more before casting <SpellLink id={SPELLS.TRUESHOT.id} />. This can be done through casting an additional <SpellLink id={SPELLS.ARCANE_SHOT.id} /> or by monitoring the cooldown of <SpellLink id={SPELLS.TRUESHOT.id} /> and adjusting play to ensure your focus won't be depleted when it comes off cooldown.</React.Fragment>)
        .icon(SPELLS.TRUESHOT.icon)
        .actual(`Average of ${actual > 0 ? actual : this.startFocusForCombatant} focus when starting Trueshot`)
        .recommended(`>${recommended} is recommended`);
    });*/
    when(this.uptimeThreshold).addSuggestion((suggest, actual) => {
      return suggest(<React.Fragment>You should make sure to utilise every possible second of <SpellLink id={SPELLS.TRUESHOT.id} /> uptime as you can. Remember to cast it atleast 15 seconds before the boss dies, so you don't lose out on valuable time, aswell as remember to not cast it until the boss has been engaged.</React.Fragment>)
        .icon(SPELLS.TRUESHOT.icon)
        .actual(`You had an average of ${actual.toFixed(2)} seconds of Trueshot uptime per cast`)
        .recommended(`15 seconds uptime per cast is recommended`);
    });
    when(this.aimedShotRechargeThreshold).addSuggestion((suggest, actual, recommended) => {
      return suggest(<React.Fragment>You should make sure to cast <SpellLink id={SPELLS.TRUESHOT.id} /> while you have 0 charges of <SpellLink id={SPELLS.AIMED_SHOT.id} />, to get the most out of the free charge given by activating <SpellLink id={SPELLS.TRUESHOT.id} />.</React.Fragment>)
        .icon(SPELLS.TRUESHOT.icon)
        .actual(`You lost out on ${actual} Aimed Shot charges`)
        .recommended(`${recommended} is recommended`);
    });
  }
  statisticOrder = STATISTIC_ORDER.CORE(8);
}

export default Trueshot;
<commit_msg>update trueshot module<commit_after>import React from 'react';
import Analyzer from 'Parser/Core/Analyzer';

import SPELLS from 'common/SPELLS/HUNTER';
import StatisticBox, { STATISTIC_ORDER } from 'Interface/Others/StatisticBox';
import SpellIcon from 'common/SpellIcon';
import { formatNumber } from 'common/format';
import RESOURCE_TYPES from 'common/RESOURCE_TYPES';
import SpellUsable from 'Parser/Core/Modules/SpellUsable';
import ResourceIcon from 'common/ResourceIcon';
import Abilities from 'Parser/Core/Modules/Abilities';
import SpellLink from 'common/SpellLink';

/**
 * Immediately gain 1 charge of Aimed Shot, and gain 30% Haste for 15 sec.
 * Lasts 15 sec.
 */
class Trueshot extends Analyzer {
  static dependencies = {
    spellUsable: SpellUsable,
    abilities: Abilities,
  };

  trueshotCasts = 0;
  accumulatedFocusAtTSCast = 0;
  aimedShotsPrTS = 0;
  wastedAimedShotCharges = 0;
  startFocusForCombatant = 0;
  prepullTrueshots = 0;

  on_byPlayer_applybuff(event) {
    const buffId = event.ability.guid;
    if (buffId !== SPELLS.TRUESHOT.id || !event.prepull) {
      return;
    }
    //adds 1 to trueshotCasts to properly show that it was cast prepull
    this.trueshotCasts += 1;
    this.prepullTrueshots += 1;
    //starts the cooldown to ensure proper cast efficiency statistics
    this.spellUsable.beginCooldown(SPELLS.TRUESHOT.id, this.owner.fight.start_time);
  }

  on_byPlayer_cast(event) {
    //checks if we had a prepull trueshot, in which case the firstCast done symbolises our starting focus of that one trueshot
    if (this.prepullTrueshots > 0 && this.startFocusForCombatant === 0) {
      event.classResources.forEach(classResource => {
        if (classResource.type === RESOURCE_TYPES.FOCUS.id && classResource.amount > this.startFocusForCombatant) {
          this.startFocusForCombatant += classResource.amount;
          this.accumulatedFocusAtTSCast += this.startFocusForCombatant;
        }
      });
    }
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.TRUESHOT.id && spellId !== SPELLS.AIMED_SHOT.id) {
      return;
    }
    if (spellId === SPELLS.TRUESHOT.id) {
      this.trueshotCasts += 1;
      if (this.spellUsable.isOnCooldown(SPELLS.AIMED_SHOT.id)) {
        const newChargeCDR = this.abilities.getExpectedCooldownDuration(SPELLS.AIMED_SHOT.id) - this.spellUsable.cooldownRemaining(SPELLS.AIMED_SHOT.id);
        this.spellUsable.endCooldown(SPELLS.AIMED_SHOT.id, false, event.timestamp, newChargeCDR);
      } else {
        this.wastedAimedShotCharges++;
      }
      this.accumulatedFocusAtTSCast += event.classResources[0].amount || 0;
    }
    if (spellId === SPELLS.AIMED_SHOT.id && this.selectedCombatant.hasBuff(SPELLS.TRUESHOT.id)) {
      this.aimedShotsPrTS++;
    }
  }

  statistic() {
    return (
      <StatisticBox icon={<SpellIcon id={SPELLS.TRUESHOT.id} />}
        value={(
          <React.Fragment>
            {this.averageAimedShots.toFixed(2)}{' '}
            <SpellIcon
              id={SPELLS.AIMED_SHOT.id}
              style={{
                height: '1.3em',
                marginTop: '-.1em',
              }}
            />
            {'  '}
            {this.averageFocus}{' '}
            <ResourceIcon
              id={RESOURCE_TYPES.FOCUS.id}
              style={{
                height: '1.3em',
                marginTop: '-.1em',
              }}
            />
          </React.Fragment>
        )}
        label="Trueshot info"
        tooltip={`Information regarding your average Trueshot window:

You started your Trueshot windows with an average of ${this.averageFocus} focus.

You hit an average of ${this.averageAimedShots} Aimed Shots inside each Trueshot window.

You gained ${this.trueshotCasts - this.wastedAimedShotCharges} charges of Aimed Shot and lost out on ${this.wastedAimedShotCharges} charges by activating Trueshot whilst Aimed Shot wasn't on cooldown.

`} />
    );
  }

  get averageAimedShots() {
    return this.aimedShotsPrTS / this.trueshotCasts;
  }
  get averageFocus() {
    return formatNumber(this.accumulatedFocusAtTSCast / this.trueshotCasts);
  }
  get aimedShotThreshold() {
    return {
      actual: this.averageAimedShots,
      isLessThan: {
        minor: 3,
        average: 2.5,
        major: 2,
      },
      style: 'decimal',
    };
  }
  get aimedShotRechargeThreshold() {
    return {
      actual: this.wastedAimedShotCharges,
      isGreaterThan: {
        minor: 0,
        average: 0.1,
        major: 1.1,
      },
      style: 'number',
    };
  }
  suggestions(when) {
    when(this.aimedShotThreshold).addSuggestion((suggest, actual, recommended) => {
      return suggest(<React.Fragment>You only cast {actual.toFixed(2)} <SpellLink id={SPELLS.AIMED_SHOT.id} />s inside your average <SpellLink id={SPELLS.TRUESHOT.id} /> window. This is your only DPS cooldown, and it's important to maximize it to it's fullest potential by getting as many Aimed Shot squeezed in as possible.</React.Fragment>)
        .icon(SPELLS.TRUESHOT.icon)
        .actual(`Average of ${actual} Aimed Shots per Trueshot.`)
        .recommended(`>${recommended} is recommended`);
    });
    when(this.aimedShotRechargeThreshold).addSuggestion((suggest, actual, recommended) => {
      return suggest(<React.Fragment>You should make sure to cast <SpellLink id={SPELLS.TRUESHOT.id} /> while you have 0 charges of <SpellLink id={SPELLS.AIMED_SHOT.id} />, to get the most out of the free charge given by activating <SpellLink id={SPELLS.TRUESHOT.id} />.</React.Fragment>)
        .icon(SPELLS.TRUESHOT.icon)
        .actual(`You lost out on ${actual} Aimed Shot charges`)
        .recommended(`${recommended} is recommended`);
    });
  }
  statisticOrder = STATISTIC_ORDER.CORE(8);
}

export default Trueshot;
<|endoftext|>


<commit_before>import request from 'utils/request';
import {
  DEFAULT_ACTION,
  PLAY_ACTION,
  PAUSE_ACTION,
  BACK_ACTION,
  NEXT_ACTION,
  PAGE_LOADED,
  REFRESH_INFOS,
  START_TIMER,
  TRANSPORT_FETCH_SUCCEEDED,
  TRANSPORT_FETCH_FAILED,
  CURRENT_TRACK_FETCH_SUCCEEDED,
  CURRENT_TRACK_FETCH_FAILED,
} from './constants';

const backendUrl = (window.location.hostname === '172.17.0.3' ?
                    'http://172.17.0.4:5000' : 'http://172.17.0.7:5000');

/*
 * TODO wrap this stuff in a Sonos object in utils/sonos.js
 */
export function sonos(path, options) {
  options = {
    method: 'GET',
    headers: new Headers({
      'content-type': 'application/json',
    }),
    ...options,
  }
  return request(backendUrl + path, options);
}

export function sonosCmd(path, command) {
  return sonos(path, {
    method: 'POST',
    body: JSON.stringify({command}),
  });
}

export function defaultAction() {
  return {
    type: DEFAULT_ACTION,
  };
}

export function playMusic() {
  sonosCmd('/transport_info', 'PLAY');
  return {
    type: PLAY_ACTION,
  };
}

export function pauseMusic() {
  sonosCmd('/transport_info', 'PAUSE');
  return {
    type: PAUSE_ACTION,
  };
}

export function prevSong() {
  sonosCmd('/current_track', 'BACK');
  return {
    type: BACK_ACTION,
  };
}

export function nextSong() {
  sonosCmd('/current_track', 'NEXT');
  return {
    type: NEXT_ACTION,
  };
}

export function pageLoaded() {
  return {
    type: PAGE_LOADED,
  };
}

export function startTimer() {
  return {
    type: START_TIMER,
  };
}

export function refreshInfos() {
  return {
    type: REFRESH_INFOS,
  };
}

export function transportFetchSucceeded(transportInfo) {
  return {
    type: TRANSPORT_FETCH_SUCCEEDED,
    transportInfo,
  };
}

export function transportFetchFailed(message) {
  return {
    type: TRANSPORT_FETCH_FAILED,
    message
  };
}

export function currentTrackFetchSucceeded(currentTrackInfo) {
  return {
    type: CURRENT_TRACK_FETCH_SUCCEEDED,
    currentTrackInfo,
  };
}

export function currentTrackFetchFailed(message) {
  return {
    type: CURRENT_TRACK_FETCH_FAILED,
    message
  };
}
<commit_msg>update backend host:port for jasperodus #5<commit_after>import request from 'utils/request';
import {
  DEFAULT_ACTION,
  PLAY_ACTION,
  PAUSE_ACTION,
  BACK_ACTION,
  NEXT_ACTION,
  PAGE_LOADED,
  REFRESH_INFOS,
  START_TIMER,
  TRANSPORT_FETCH_SUCCEEDED,
  TRANSPORT_FETCH_FAILED,
  CURRENT_TRACK_FETCH_SUCCEEDED,
  CURRENT_TRACK_FETCH_FAILED,
} from './constants';

const backendUrl = (window.location.hostname === '172.17.0.3' ?
                    'http://172.20.1.197:5208' : 'http://172.20.1.197:5209');

/*
 * TODO wrap this stuff in a Sonos object in utils/sonos.js
 */
export function sonos(path, options) {
  options = {
    method: 'GET',
    headers: new Headers({
      'content-type': 'application/json',
    }),
    ...options,
  }
  return request(backendUrl + path, options);
}

export function sonosCmd(path, command) {
  return sonos(path, {
    method: 'POST',
    body: JSON.stringify({command}),
  });
}

export function defaultAction() {
  return {
    type: DEFAULT_ACTION,
  };
}

export function playMusic() {
  sonosCmd('/transport_info', 'PLAY');
  return {
    type: PLAY_ACTION,
  };
}

export function pauseMusic() {
  sonosCmd('/transport_info', 'PAUSE');
  return {
    type: PAUSE_ACTION,
  };
}

export function prevSong() {
  sonosCmd('/current_track', 'BACK');
  return {
    type: BACK_ACTION,
  };
}

export function nextSong() {
  sonosCmd('/current_track', 'NEXT');
  return {
    type: NEXT_ACTION,
  };
}

export function pageLoaded() {
  return {
    type: PAGE_LOADED,
  };
}

export function startTimer() {
  return {
    type: START_TIMER,
  };
}

export function refreshInfos() {
  return {
    type: REFRESH_INFOS,
  };
}

export function transportFetchSucceeded(transportInfo) {
  return {
    type: TRANSPORT_FETCH_SUCCEEDED,
    transportInfo,
  };
}

export function transportFetchFailed(message) {
  return {
    type: TRANSPORT_FETCH_FAILED,
    message
  };
}

export function currentTrackFetchSucceeded(currentTrackInfo) {
  return {
    type: CURRENT_TRACK_FETCH_SUCCEEDED,
    currentTrackInfo,
  };
}

export function currentTrackFetchFailed(message) {
  return {
    type: CURRENT_TRACK_FETCH_FAILED,
    message
  };
}
<|endoftext|>


<commit_before>/*
 *@author: xtx1130
 *@description: 整合projects下面的controller文件夹
 */
'use strict';

const path = require('path');
const assert = require('assert');

const controllerMap = Symbol.for('koas#controllerMap');

let controllerConf = require(path.join(process.cwd(), '/koasConfig')).controller;
(process.env.NODE_ENV=='travis') && (controllerConf = require('../../test/koasConfig').controller);

class Controller {
	constructor() {
		this[controllerMap] = {};
		Object.keys(controllerConf).forEach((key) => {
			this[controllerMap][key] = require(path.join(process.cwd(), controllerConf[key]));
		});
	}
	get jsonMap() {
			return this[controllerMap]
		}
		//map can't change by =
	set jsonMap(val) {
			return this[controllerMap]
		}
		//返回中间件函数，通过router.use让用户可以自由插入到想插入的位置
	slot(block, name) {
		assert(this[controllerMap][block] != null, 'This block is not exists');
		assert((typeof this[controllerMap][block][name]).match('function'), 'This router is not exists or not a function');
		return this[controllerMap][block][name];
	}
}
exports = module.exports = Controller;<commit_msg>del: delete travis env<commit_after>/*
 *@author: xtx1130
 *@description: 整合projects下面的controller文件夹
 */
'use strict';

const path = require('path');
const assert = require('assert');

const controllerMap = Symbol.for('koas#controllerMap');

let controllerConf = require(path.join(process.cwd(), '/koasConfig')).controller;

class Controller {
	constructor() {
		this[controllerMap] = {};
		Object.keys(controllerConf).forEach((key) => {
			this[controllerMap][key] = require(path.join(process.cwd(), controllerConf[key]));
		});
	}
	get jsonMap() {
			return this[controllerMap]
		}
		//map can't change by =
	set jsonMap(val) {
			return this[controllerMap]
		}
		//返回中间件函数，通过router.use让用户可以自由插入到想插入的位置
	slot(block, name) {
		assert(this[controllerMap][block] != null, 'This block is not exists');
		assert((typeof this[controllerMap][block][name]).match('function'), 'This router is not exists or not a function');
		return this[controllerMap][block][name];
	}
}
exports = module.exports = Controller;<|endoftext|>


<commit_before>import Ember from 'ember';

export default Ember.Controller.extend({
  actions: {
    goToNextStep: function () {
      console.log("Next step");
      let next_step = parseInt(this.model.id) + 1;
      this.transitionToRoute('steps.step', next_step);
    }
  },
  prompts: function () {
    this.model.get('prompts');
  }.property('@each.prompts'),
});
<commit_msg>renamed action<commit_after>import Ember from 'ember';

export default Ember.Controller.extend({
  actions: {
    nextStep: function () {
      console.log("Next step");
      let next_step = parseInt(this.model.id) + 1;
      this.transitionToRoute('steps.step', next_step);
    }
  },
  prompts: function () {
    this.model.get('prompts');
  }.property('@each.prompts'),
});
<|endoftext|>


<commit_before>/*
 * This file is part of the Sylius package.
 *
 * (c) Paweł Jędrzejewski
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

import 'semantic-ui-css/components/accordion';
import $ from 'jquery';
import 'jquery.dirtyforms/jquery.dirtyforms';

import 'sylius/ui/app';
import 'sylius/ui/sylius-auto-complete';
import 'sylius/ui/sylius-product-attributes';
import 'sylius/ui/sylius-product-auto-complete';
import 'sylius/ui/sylius-prototype-handler';

import './sylius-compound-form-errors';
import './sylius-lazy-choice-tree';
import './sylius-menu-search';
import './sylius-move-product-variant';
import './sylius-move-taxon';
import './sylius-notification';
import './sylius-product-images-preview';
import './sylius-product-slug';
import './sylius-taxon-slug';

import StatisticsComponent from './sylius-statistics';
import SyliusTaxonomyTree from './sylius-taxon-tree';
import formsList from './sylius-forms-list';

$(document).ready(() => {
  $('#sylius_product_variant_pricingCalculator').handlePrototypes({
    prototypePrefix: 'sylius_product_variant_pricingCalculator',
    containerSelector: '#sylius_calculator_container',
  });

  $('#sylius_customer_createUser').change(() => {
    $('#user-form').toggle();
  });

  $('.sylius-autocomplete').autoComplete();

  $('.product-select.ui.fluid.multiple.search.selection.dropdown').productAutoComplete();
  $('div#attributeChoice > .ui.dropdown.search').productAttributes();

  $('table thead th.sortable').on('click', (event) => {
    window.location = $(event.currentTarget).find('a').attr('href');
  });

  $('.sylius-update-product-variants').moveProductVariant($('.sylius-product-variant-position'));
  $('.sylius-taxon-move-up').taxonMoveUp();
  $('.sylius-taxon-move-down').taxonMoveDown();

  $('#sylius_shipping_method_calculator').handlePrototypes({
    prototypePrefix: 'sylius_shipping_method_calculator_calculators',
    containerSelector: '.configuration',
  });

  $('#actions a[data-form-collection="add"]').on('click', () => {
    setTimeout(() => {
      $('select[name^="sylius_promotion[actions]"][name$="[type]"]').last().change();
    }, 50);
  });
  $('#rules a[data-form-collection="add"]').on('click', (event) => {
    const name = $(event.target).closest('form').attr('name');

    setTimeout(() => {
      $(`select[name^="${name}[rules]"][name$="[type]"]`).last().change();
    }, 50);
  });

  $(document).on('collection-form-add', () => {
    $('.sylius-autocomplete').each((index, element) => {
      if ($._data($(element).get(0), 'events') == undefined) {
        $(element).autoComplete();
      }
    });
  });
  $(document).on('collection-form-update', () => {
    $('.sylius-autocomplete').each((index, element) => {
      if ($._data($(element).get(0), 'events') == undefined) {
        $(element).autoComplete();
      }
    });
  });

  $('.sylius-tabular-form').addTabErrors();
  $('.ui.accordion').addAccordionErrors();
  $('#sylius-product-taxonomy-tree').choiceTree('productTaxon', true, 1);

  $(document).notification();
  $(document).productSlugGenerator();
  $(document).taxonSlugGenerator();
  $(document).previewUploadedImage('#sylius_product_images');
  $(document).previewUploadedImage('#sylius_taxon_images');

  $(document).previewUploadedImage('#add-avatar');

  $('body').on('DOMNodeInserted', '[data-form-collection="item"]', (event) => {
    if ($(event.target).find('.accordion').length > 0) {
      $(event.target).find('.accordion').accordion();
    }
  });

  const taxonomyTree = new SyliusTaxonomyTree();

  $(`${formsList}, .check-unsaved`).dirtyForms();

  $('#more-details').accordion({ exclusive: false });

  $('.variants-accordion__title').on('click', '.icon.button', function(e) {
    $(e.delegateTarget).next('.variants-accordion__content').toggle();
    $(this).find('.dropdown.icon').toggleClass('counterclockwise rotated');
  });

  const dashboardStatistics = new StatisticsComponent(document.querySelector('.stats'));

  $('.sylius-admin-menu').searchable('.sylius-admin-menu-search-input');
});

window.$ = $;
window.jQuery = $;
<commit_msg>bug #12404 Fix nested accordion initialisation (DjLeChuck)<commit_after>/*
 * This file is part of the Sylius package.
 *
 * (c) Paweł Jędrzejewski
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

import 'semantic-ui-css/components/accordion';
import $ from 'jquery';
import 'jquery.dirtyforms/jquery.dirtyforms';

import 'sylius/ui/app';
import 'sylius/ui/sylius-auto-complete';
import 'sylius/ui/sylius-product-attributes';
import 'sylius/ui/sylius-product-auto-complete';
import 'sylius/ui/sylius-prototype-handler';

import './sylius-compound-form-errors';
import './sylius-lazy-choice-tree';
import './sylius-menu-search';
import './sylius-move-product-variant';
import './sylius-move-taxon';
import './sylius-notification';
import './sylius-product-images-preview';
import './sylius-product-slug';
import './sylius-taxon-slug';

import StatisticsComponent from './sylius-statistics';
import SyliusTaxonomyTree from './sylius-taxon-tree';
import formsList from './sylius-forms-list';

$(document).ready(() => {
  $('#sylius_product_variant_pricingCalculator').handlePrototypes({
    prototypePrefix: 'sylius_product_variant_pricingCalculator',
    containerSelector: '#sylius_calculator_container',
  });

  $('#sylius_customer_createUser').change(() => {
    $('#user-form').toggle();
  });

  $('.sylius-autocomplete').autoComplete();

  $('.product-select.ui.fluid.multiple.search.selection.dropdown').productAutoComplete();
  $('div#attributeChoice > .ui.dropdown.search').productAttributes();

  $('table thead th.sortable').on('click', (event) => {
    window.location = $(event.currentTarget).find('a').attr('href');
  });

  $('.sylius-update-product-variants').moveProductVariant($('.sylius-product-variant-position'));
  $('.sylius-taxon-move-up').taxonMoveUp();
  $('.sylius-taxon-move-down').taxonMoveDown();

  $('#sylius_shipping_method_calculator').handlePrototypes({
    prototypePrefix: 'sylius_shipping_method_calculator_calculators',
    containerSelector: '.configuration',
  });

  $('#actions a[data-form-collection="add"]').on('click', () => {
    setTimeout(() => {
      $('select[name^="sylius_promotion[actions]"][name$="[type]"]').last().change();
    }, 50);
  });
  $('#rules a[data-form-collection="add"]').on('click', (event) => {
    const name = $(event.target).closest('form').attr('name');

    setTimeout(() => {
      $(`select[name^="${name}[rules]"][name$="[type]"]`).last().change();
    }, 50);
  });

  $(document).on('collection-form-add', () => {
    $('.sylius-autocomplete').each((index, element) => {
      if ($._data($(element).get(0), 'events') == undefined) {
        $(element).autoComplete();
      }
    });
  });
  $(document).on('collection-form-update', () => {
    $('.sylius-autocomplete').each((index, element) => {
      if ($._data($(element).get(0), 'events') == undefined) {
        $(element).autoComplete();
      }
    });
  });

  $('.sylius-tabular-form').addTabErrors();
  $('.ui.accordion').addAccordionErrors();
  $('#sylius-product-taxonomy-tree').choiceTree('productTaxon', true, 1);

  $(document).notification();
  $(document).productSlugGenerator();
  $(document).taxonSlugGenerator();
  $(document).previewUploadedImage('#sylius_product_images');
  $(document).previewUploadedImage('#sylius_taxon_images');

  $(document).previewUploadedImage('#add-avatar');

  $('body').on('DOMNodeInserted', '[data-form-collection="item"]', (event) => {
    if ($(event.target).find('.ui.accordion').length > 0) {
      $(event.target).find('.ui.accordion').accordion();
    }
  });

  const taxonomyTree = new SyliusTaxonomyTree();

  $(`${formsList}, .check-unsaved`).dirtyForms();

  $('#more-details').accordion({ exclusive: false });

  $('.variants-accordion__title').on('click', '.icon.button', function(e) {
    $(e.delegateTarget).next('.variants-accordion__content').toggle();
    $(this).find('.dropdown.icon').toggleClass('counterclockwise rotated');
  });

  const dashboardStatistics = new StatisticsComponent(document.querySelector('.stats'));

  $('.sylius-admin-menu').searchable('.sylius-admin-menu-search-input');
});

window.$ = $;
window.jQuery = $;
<|endoftext|>


<commit_before>'use strict';

function executeCommand(configuration, db, cmd, options, cb) {
  var Pool = require('../../../lib/connection/pool'),
    f = require('util').format,
    bson = require('bson'),
    Query = require('../../../lib/connection/commands').Query;

  // Optional options
  if (typeof options == 'function') (cb = options), (options = {});
  // Set the default options object if none passed in
  options = options || {};

  // Alternative options
  var host = options.host || configuration.host;
  var port = options.port || configuration.port;

  // Attempt to connect
  var pool = new Pool({
    host: host,
    port: port,
    bson: new bson()
  });

  // Add event listeners
  pool.on('connect', function(_pool) {
    var query = new Query(new bson(), f('%s.$cmd', db), cmd, {
      numberToSkip: 0,
      numberToReturn: 1
    });
    _pool.write(
      query,
      {
        command: true
      },
      function(err, result) {
        if (err) console.log(err.stack);
        // Close the pool
        _pool.destroy();
        // If we have an error return
        if (err) return cb(err);
        // Return the result
        cb(null, result.result);
      }
    );
  });

  pool.connect.apply(pool, options.auth);
}

function locateAuthMethod(configuration, cb) {
  var Pool = require('../../../lib/connection/pool'),
    bson = require('bson'),
    f = require('util').format,
    Query = require('../../../lib/connection/commands').Query;

  // Set up operations
  var db = 'admin';
  var cmd = { ismaster: true };

  // Attempt to connect
  var pool = new Pool({
    host: configuration.host,
    port: configuration.port,
    bson: new bson()
  });

  // Add event listeners
  pool.on('connect', function(_pool) {
    var query = new Query(new bson(), f('%s.$cmd', db), cmd, {
      numberToSkip: 0,
      numberToReturn: 1
    });
    _pool.write(
      query,
      {
        command: true
      },
      function(err, result) {
        if (err) console.log(err.stack);
        // Close the pool
        _pool.destroy();
        // If we have an error return
        if (err) return cb(err);

        // Establish the type of auth method
        if (!result.result.maxWireVersion || result.result.maxWireVersion == 2) {
          cb(null, 'mongocr');
        } else {
          cb(null, 'scram-sha-1');
        }
      }
    );
  });

  pool.connect.apply(pool);
}

const delay = function(timeout) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve();
    }, timeout);
  });
};

module.exports.executeCommand = executeCommand;
module.exports.locateAuthMethod = locateAuthMethod;
module.exports.delay = delay;
<commit_msg>feat(connection-spy): add class for monitoring active connections<commit_after>'use strict';
const EventEmitter = require('events');

function executeCommand(configuration, db, cmd, options, cb) {
  var Pool = require('../../../lib/connection/pool'),
    f = require('util').format,
    bson = require('bson'),
    Query = require('../../../lib/connection/commands').Query;

  // Optional options
  if (typeof options == 'function') (cb = options), (options = {});
  // Set the default options object if none passed in
  options = options || {};

  // Alternative options
  var host = options.host || configuration.host;
  var port = options.port || configuration.port;

  // Attempt to connect
  var pool = new Pool({
    host: host,
    port: port,
    bson: new bson()
  });

  // Add event listeners
  pool.on('connect', function(_pool) {
    var query = new Query(new bson(), f('%s.$cmd', db), cmd, {
      numberToSkip: 0,
      numberToReturn: 1
    });
    _pool.write(
      query,
      {
        command: true
      },
      function(err, result) {
        if (err) console.log(err.stack);
        // Close the pool
        _pool.destroy();
        // If we have an error return
        if (err) return cb(err);
        // Return the result
        cb(null, result.result);
      }
    );
  });

  pool.connect.apply(pool, options.auth);
}

function locateAuthMethod(configuration, cb) {
  var Pool = require('../../../lib/connection/pool'),
    bson = require('bson'),
    f = require('util').format,
    Query = require('../../../lib/connection/commands').Query;

  // Set up operations
  var db = 'admin';
  var cmd = { ismaster: true };

  // Attempt to connect
  var pool = new Pool({
    host: configuration.host,
    port: configuration.port,
    bson: new bson()
  });

  // Add event listeners
  pool.on('connect', function(_pool) {
    var query = new Query(new bson(), f('%s.$cmd', db), cmd, {
      numberToSkip: 0,
      numberToReturn: 1
    });
    _pool.write(
      query,
      {
        command: true
      },
      function(err, result) {
        if (err) console.log(err.stack);
        // Close the pool
        _pool.destroy();
        // If we have an error return
        if (err) return cb(err);

        // Establish the type of auth method
        if (!result.result.maxWireVersion || result.result.maxWireVersion == 2) {
          cb(null, 'mongocr');
        } else {
          cb(null, 'scram-sha-1');
        }
      }
    );
  });

  pool.connect.apply(pool);
}

const delay = function(timeout) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve();
    }, timeout);
  });
};

class ConnectionSpy extends EventEmitter {
  constructor() {
    super();
    this.connections = {};
  }

  addConnection(id, connection) {
    // console.log(`=== added connection ${id} :: ${connection.port}`);

    this.connections[id] = connection;
    this.emit('connectionAdded');
  }

  deleteConnection(id) {
    // console.log(
    //   `=== deleted connection ${id} :: ${this.connections[id] ? this.connections[id].port : ''}`
    // );

    delete this.connections[id];
    this.emit('connectionRemoved');

    if (this.connectionCount() === 0) {
      this.emit('drained');
    }
  }

  connectionCount() {
    return Object.keys(this.connections).length;
  }
}

module.exports.executeCommand = executeCommand;
module.exports.locateAuthMethod = locateAuthMethod;
module.exports.delay = delay;
module.exports.ConnectionSpy = ConnectionSpy;
<|endoftext|>


<commit_before>"use strict";

angular.module('arethusa.core').service('saver', [
  'configurator',
  'notifier',
  'keyCapture',
  'state',
  function(configurator, notifier, keyCapture, state) {
    var self = this;
    var persisters;

    function getPersisters() {
      var persisterConf = configurator.configurationFor('main').persisters;
      persisters = configurator.getPersisters(persisterConf);
    }

    function hasPersisters(args) {
      return !angular.equals({}, persisters);
    }

    function updateStatus() {
      if (hasPersisters() && canEdit()) {
        self.canSave = true;
      }
    }

    function canEdit() {
      return configurator.mode() === 'editor';
    }

    function reset() {
      self.canSave = false;
    }

    function success(res) {
      self.needsSave = false;
      notifier.success('Document saved!');
    }

    function error(res) {
      // Can't figure out why we return 406 from our development server
      // all the time when we do POSTs.
      // The save succeeds anyway - print the success message in such a
      // case as to not confuse the user...
      if (res.status == 406) {
        success();
      } else {
        notifier.error('Failed to save! Try again?');
      }
    }

    this.save = function() {
      notifier.info('Saving...');
      // We only have one persister right now, later we'll want
      // to handle the success notification better.
      angular.forEach(persisters, function(persister, name) {
        persister.saveData(success, error);
      });
    };

    keyCapture.initCaptures(function(kC) {
      return {
        saver: [
          kC.create('save', function() { self.save(); })
        ]
      };
    });

    state.on('tokenChange', function() {
      self.needsSave = true;
    });

    this.init = function(newPersisters) {
      reset();
      getPersisters();
      updateStatus();
    };
  }
]);
<commit_msg>Use state.watch instead of on in saver<commit_after>"use strict";

angular.module('arethusa.core').service('saver', [
  'configurator',
  'notifier',
  'keyCapture',
  'state',
  function(configurator, notifier, keyCapture, state) {
    var self = this;
    var persisters;

    function getPersisters() {
      var persisterConf = configurator.configurationFor('main').persisters;
      persisters = configurator.getPersisters(persisterConf);
    }

    function hasPersisters(args) {
      return !angular.equals({}, persisters);
    }

    function updateStatus() {
      if (hasPersisters() && canEdit()) {
        self.canSave = true;
      }
    }

    function canEdit() {
      return configurator.mode() === 'editor';
    }

    function reset() {
      self.canSave = false;
    }

    function success(res) {
      self.needsSave = false;
      notifier.success('Document saved!');
    }

    function error(res) {
      // Can't figure out why we return 406 from our development server
      // all the time when we do POSTs.
      // The save succeeds anyway - print the success message in such a
      // case as to not confuse the user...
      if (res.status == 406) {
        success();
      } else {
        notifier.error('Failed to save! Try again?');
      }
    }

    this.save = function() {
      notifier.info('Saving...');
      // We only have one persister right now, later we'll want
      // to handle the success notification better.
      angular.forEach(persisters, function(persister, name) {
        persister.saveData(success, error);
      });
    };

    keyCapture.initCaptures(function(kC) {
      return {
        saver: [
          kC.create('save', function() { self.save(); })
        ]
      };
    });

    state.watch('*', function() {
      self.needsSave = true;
    });

    this.init = function(newPersisters) {
      reset();
      getPersisters();
      updateStatus();
    };
  }
]);
<|endoftext|>