<commit_before>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2014, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */
var _ = require('lodash');
var bows = require('bows');
var d3 = window.d3;
var React = require('react');
var ReactDOM = require('react-dom');
var sundial = require('sundial');

var Header = require('./header');
var SubNav = require('./modalsubnav');
var Footer = require('./footer');

import SMBGTrends from './smbgtrends';

import * as viz from '@tidepool/viz';
const FocusedCBGSliceHTMLLabels = viz.components.FocusedCBGSliceHTMLLabels;
const FocusedCBGSliceTime = viz.components.FocusedCBGSliceTime;
const TrendsContainer = viz.containers.TrendsContainer;

var Modal = React.createClass({
  chartType: 'modal',
  log: bows('Modal Day'),
  propTypes: {
    bgPrefs: React.PropTypes.object.isRequired,
    chartPrefs: React.PropTypes.object.isRequired,
    timePrefs: React.PropTypes.object.isRequired,
    initialDatetimeLocation: React.PropTypes.string,
    patientData: React.PropTypes.object.isRequired,
    trendsState: React.PropTypes.object.isRequired,
    // refresh handler
    onClickRefresh: React.PropTypes.func.isRequired,
    onSwitchToBasics: React.PropTypes.func.isRequired,
    onSwitchToDaily: React.PropTypes.func.isRequired,
    onSwitchToModal: React.PropTypes.func.isRequired,
    onSwitchToSettings: React.PropTypes.func.isRequired,
    onSwitchToWeekly: React.PropTypes.func.isRequired,
    trackMetric: React.PropTypes.func.isRequired,
    updateChartPrefs: React.PropTypes.func.isRequired,
    updateDatetimeLocation: React.PropTypes.func.isRequired,
    uploadUrl: React.PropTypes.string.isRequired
  },
  getInitialState: function() {
    return {
      atMostRecent: true,
      inTransition: false,
      title: '',
      visibleDays: 0
    };
  },
  componentDidMount: function() {
    if (this.refs.chart) {
      // necessary to get a ref from the redux connect()ed TrendsContainer
      this.chart = this.refs.chart.getWrappedInstance();
    }
  },
  render: function() {
    return (

        {this.renderHeader()}
        {this.renderSubNav()}

                {this.renderChart()}

              {this.renderFocusedCBGTime()}
              {this.renderFocusedCBGHTMLLabels()}

        <Footer
         chartType={this.chartType}
         onClickBoxOverlay={this.toggleBoxOverlay}
         onClickGroup={this.toggleGroup}
         onClickLines={this.toggleLines}
         onClickRefresh={this.props.onClickRefresh}
         onClickBgDataToggle={this.toggleBgDataSource}
         boxOverlay={this.props.chartPrefs.modal.smbgRangeOverlay}
         grouped={this.props.chartPrefs.modal.smbgGrouped}
         showingLines={this.props.chartPrefs.modal.smbgLines}
         showingCbg={this.props.chartPrefs.modal.showingCbg}
         showingSmbg={this.props.chartPrefs.modal.showingSmbg}
        ref="footer" />

    );
  },
  renderHeader: function() {
    return (
      <Header
        chartType={this.chartType}
        inTransition={this.state.inTransition}
        atMostRecent={this.state.atMostRecent}
        title={this.state.title}
        iconBack={'icon-back'}
        iconNext={'icon-next'}
        iconMostRecent={'icon-most-recent'}
        onClickBack={this.handleClickBack}
        onClickBasics={this.props.onSwitchToBasics}
        onClickModal={this.handleClickModal}
        onClickMostRecent={this.handleClickMostRecent}
        onClickNext={this.handleClickForward}
        onClickOneDay={this.handleClickDaily}
        onClickTwoWeeks={this.handleClickWeekly}
        onClickSettings={this.handleClickSettings}
      ref="header" />
    );
  },
  renderSubNav: function() {
    return (
      <SubNav
       activeDays={this.props.chartPrefs.modal.activeDays}
       activeDomain={this.props.chartPrefs.modal.activeDomain}
       extentSize={this.props.chartPrefs.modal.extentSize}
       domainClickHandlers={{
        '1 week': this.handleClickOneWeek,
        '2 weeks': this.handleClickTwoWeeks,
        '4 weeks': this.handleClickFourWeeks
       }}
       onClickDay={this.toggleDay}
       toggleWeekdays={this.toggleWeekdays}
       toggleWeekends={this.toggleWeekends}
      ref="subnav" />
    );
  },
  renderChart: function() {
    const { bgPrefs: { bgClasses, bgUnits } } = this.props;
    let bgBounds = {
      veryHighThreshold: bgClasses.high.boundary,
      targetUpperBound: bgClasses.target.boundary,
      targetLowerBound: bgClasses.low.boundary,
      veryLowThreshold: bgClasses['very-low'].boundary,
    };
    return (
      <TrendsContainer
        activeDays={this.props.chartPrefs.modal.activeDays}
        bgBounds={bgBounds}
        bgClasses={this.props.bgPrefs.bgClasses}
        bgUnits={this.props.bgPrefs.bgUnits}
        extentSize={this.props.chartPrefs.modal.extentSize}
        initialDatetimeLocation={this.props.initialDatetimeLocation}
        showingSmbg={this.props.chartPrefs.modal.showingSmbg}
        showingCbg={this.props.chartPrefs.modal.showingCbg}
        smbgRangeOverlay={this.props.chartPrefs.modal.smbgRangeOverlay}
        smbgGrouped={this.props.chartPrefs.modal.smbgGrouped}
        smbgLines={this.props.chartPrefs.modal.smbgLines}
        smbgTrendsComponent={SMBGTrends}
        timePrefs={this.props.timePrefs}
        // data
        cbgByDate={this.props.patientData.cbgByDate}
        cbgByDayOfWeek={this.props.patientData.cbgByDayOfWeek}
        smbgByDate={this.props.patientData.smbgByDate}
        smbgByDayOfWeek={this.props.patientData.smbgByDayOfWeek}
        // handlers
        onDatetimeLocationChange={this.handleDatetimeLocationChange}
        onSelectDay={this.handleSelectDay}
        onSwitchBgDataSource={this.toggleBgDataSource}
      ref="chart" />
    );
  },
  renderFocusedCBGHTMLLabels: function() {
    if (!this.props.chartPrefs.modal.showingCbg) {
      return null;
    }
    return (
      <FocusedCBGSliceHTMLLabels
        bgUnits={this.props.bgPrefs.bgUnits}
        focusedKeys={this.props.trendsState.focusedCbgSliceKeys}
        focusedSlice={this.props.trendsState.focusedCbgSlice} />
    );
  },
  renderFocusedCBGTime: function() {
    if (!this.props.chartPrefs.modal.showingCbg) {
      return null;
    }
    return (
      <FocusedCBGSliceTime
        focusedSlice={this.props.trendsState.focusedCbgSlice} />
    );
  },
  renderMissingSMBGHeader: function() {
    return (

    );
  },
  formatDate: function(datetime) {
    var timePrefs = this.props.timePrefs, timezone;
    if (!timePrefs.timezoneAware) {
      timezone = 'UTC';
    }
    else {
      timezone = timePrefs.timezoneName || 'UTC';
    }
    return sundial.formatInTimezone(datetime, timezone, 'MMM D, YYYY');
  },
  getTitle: function(datetimeLocationEndpoints) {
    // endpoint is exclusive, so need to subtract a day
    var end = d3.time.day.utc.offset(new Date(datetimeLocationEndpoints[1]), -1);
    return this.formatDate(datetimeLocationEndpoints[0]) + ' - ' + this.formatDate(end);
  },
  getNewDomain: function(current, extent) {
    var timePrefs = this.props.timePrefs, timezone;
    if (!timePrefs.timezoneAware) {
      timezone = 'UTC';
    }
    else {
      timezone = timePrefs.timezoneName || 'UTC';
    }
    current = sundial.ceil(current, 'day', timezone);
    return [d3.time.day.utc.offset(current, -extent).toISOString(), current.toISOString()];
  },
  updateVisibleDays: function() {
    this.setState({
      visibleDays: d3.select('#modalDays').selectAll('g.modalDay').size()
    });
  },
  // handlers
  handleClickBack: function(e) {
    if (e) {
      e.preventDefault();
    }
    this.chart.goBack();
  },
  handleClickForward: function(e) {
    if (e) {
      e.preventDefault();
    }
    if (this.state.atMostRecent) {
      return;
    }
    this.chart.goForward();
  },
  handleClickMostRecent: function(e) {
    if (e) {
      e.preventDefault();
    }
    if (this.state.atMostRecent) {
      return;
    }
    this.chart.goToMostRecent();
  },
  handleClickDaily: function(e) {
    if (e) {
      e.preventDefault();
    }
    var datetime = this.chart ? this.chart.getCurrentDay() : this.props.initialDatetimeLocation;
    this.props.onSwitchToDaily(datetime);
  },
  handleClickModal: function(e) {
    if (e) {
      e.preventDefault();
    }
    // when you're on modal view, clicking modal does nothing
    return;
  },
  handleClickOneWeek: function(e) {
    if (e) {
      e.preventDefault();
    }
    var prefs = _.cloneDeep(this.props.chartPrefs);
    // no change, return early
    if (prefs.activeDomain === '1 week' && prefs.extentSize === 7) {
      return;
    }
    prefs.modal.activeDomain = '1 week';
    prefs.modal.extentSize = 7;
    this.props.updateChartPrefs(prefs);
    var current = new Date(this.chart.getCurrentDay());
    var newDomain = this.getNewDomain(current, 7);
    this.chart.setExtent(newDomain);
    this.handleDatetimeLocationChange(newDomain);
  },
  handleClickTwoWeeks: function(e) {
    if (e) {
      e.preventDefault();
    }
    var prefs = _.cloneDeep(this.props.chartPrefs);
    // no change, return early
    if (prefs.activeDomain === '2 weeks' && prefs.extentSize === 14) {
      return;
    }
    prefs.modal.activeDomain = '2 weeks';
    prefs.modal.extentSize = 14;
    this.props.updateChartPrefs(prefs);
    var current = new Date(this.chart.getCurrentDay());
    var newDomain = this.getNewDomain(current, 14);
    this.chart.setExtent(newDomain);
    this.handleDatetimeLocationChange(newDomain);
  },
  handleClickFourWeeks: function(e) {
    if (e) {
      e.preventDefault();
    }
    var prefs = _.cloneDeep(this.props.chartPrefs);
    // no change, return early
    if (prefs.activeDomain === '4 weeks' && prefs.extentSize === 28) {
      return;
    }
    prefs.modal.activeDomain = '4 weeks';
    prefs.modal.extentSize = 28;
    this.props.updateChartPrefs(prefs);
    var current = new Date(this.chart.getCurrentDay());
    var newDomain = this.getNewDomain(current, 28);
    this.chart.setExtent(newDomain);
    this.handleDatetimeLocationChange(newDomain);
  },
  handleClickWeekly: function(e) {
    if (e) {
      e.preventDefault();
    }
    var datetime = this.chart ? this.chart.getCurrentDay() : this.props.initialDatetimeLocation;
    this.props.onSwitchToWeekly(datetime);
  },
  handleClickSettings: function(e) {
    if (e) {
      e.preventDefault();
    }
    this.props.onSwitchToSettings();
  },
  handleDatetimeLocationChange: function(datetimeLocationEndpoints, atMostRecent) {
    if (this.isMounted()) {
      this.setState({
        atMostRecent: atMostRecent,
        title: this.getTitle(datetimeLocationEndpoints)
      });
      this.props.updateDatetimeLocation(datetimeLocationEndpoints[1]);
    }
  },
  handleSelectDay: function(date) {
    this.props.onSwitchToDaily(date);
  },
  toggleDay: function(day) {
    var self = this;
    return function(e) {
      e.stopPropagation();
      var prefs = _.cloneDeep(self.props.chartPrefs);
      prefs.modal.activeDays[day] = prefs.modal.activeDays[day] ? false : true;
      self.props.updateChartPrefs(prefs);
    };
  },
  toggleBgDataSource: function(e) {
    if (e) {
      e.preventDefault();
    }
    var prefs = _.cloneDeep(this.props.chartPrefs);
    prefs.modal.showingCbg = !prefs.modal.showingCbg;
    prefs.modal.showingSmbg = !prefs.modal.showingSmbg;
    this.props.updateChartPrefs(prefs);
  },
  toggleBoxOverlay: function(e) {
    var prefs = _.cloneDeep(this.props.chartPrefs);
    prefs.modal.smbgRangeOverlay = prefs.modal.smbgRangeOverlay ? false : true;
    this.props.updateChartPrefs(prefs);
  },
  toggleGroup: function(e) {
    var prefs = _.cloneDeep(this.props.chartPrefs);
    prefs.modal.smbgGrouped = prefs.modal.smbgGrouped ? false : true;
    this.props.updateChartPrefs(prefs);
  },
  toggleLines: function(e) {
    var prefs = _.cloneDeep(this.props.chartPrefs);
    prefs.modal.smbgLines = prefs.modal.smbgLines ? false : true;
    this.props.updateChartPrefs(prefs);
  },
  toggleWeekdays: function(allActive) {
    var prefs = _.cloneDeep(this.props.chartPrefs);
    prefs.modal.activeDays = {
      'monday': !allActive,
      'tuesday': !allActive,
      'wednesday': !allActive,
      'thursday': !allActive,
      'friday': !allActive,
      'saturday': prefs.modal.activeDays.saturday,
      'sunday': prefs.modal.activeDays.sunday
    };
    this.props.updateChartPrefs(prefs);
  },
  toggleWeekends: function(allActive) {
    var prefs = _.cloneDeep(this.props.chartPrefs);
    prefs.modal.activeDays = {
      'monday': prefs.modal.activeDays.monday,
      'tuesday': prefs.modal.activeDays.tuesday,
      'wednesday': prefs.modal.activeDays.wednesday,
      'thursday': prefs.modal.activeDays.thursday,
      'friday': prefs.modal.activeDays.friday,
      'saturday': !allActive,
      'sunday': !allActive
    };
    this.props.updateChartPrefs(prefs);
  }
});

module.exports = Modal;<commit_msg>another bugfix re: tracking whether atMostRecent (for disabling right arrow nav)<commit_after>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2014, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */
var _ = require('lodash');
var bows = require('bows');
var d3 = window.d3;
var React = require('react');
var ReactDOM = require('react-dom');
var sundial = require('sundial');

var Header = require('./header');
var SubNav = require('./modalsubnav');
var Footer = require('./footer');

import SMBGTrends from './smbgtrends';

import * as viz from '@tidepool/viz';
const FocusedCBGSliceHTMLLabels = viz.components.FocusedCBGSliceHTMLLabels;
const FocusedCBGSliceTime = viz.components.FocusedCBGSliceTime;
const TrendsContainer = viz.containers.TrendsContainer;

var Modal = React.createClass({
  chartType: 'modal',
  log: bows('Modal Day'),
  propTypes: {
    bgPrefs: React.PropTypes.object.isRequired,
    chartPrefs: React.PropTypes.object.isRequired,
    timePrefs: React.PropTypes.object.isRequired,
    initialDatetimeLocation: React.PropTypes.string,
    patientData: React.PropTypes.object.isRequired,
    trendsState: React.PropTypes.object.isRequired,
    // refresh handler
    onClickRefresh: React.PropTypes.func.isRequired,
    onSwitchToBasics: React.PropTypes.func.isRequired,
    onSwitchToDaily: React.PropTypes.func.isRequired,
    onSwitchToModal: React.PropTypes.func.isRequired,
    onSwitchToSettings: React.PropTypes.func.isRequired,
    onSwitchToWeekly: React.PropTypes.func.isRequired,
    trackMetric: React.PropTypes.func.isRequired,
    updateChartPrefs: React.PropTypes.func.isRequired,
    updateDatetimeLocation: React.PropTypes.func.isRequired,
    uploadUrl: React.PropTypes.string.isRequired
  },
  getInitialState: function() {
    return {
      atMostRecent: true,
      inTransition: false,
      title: '',
      visibleDays: 0
    };
  },
  componentDidMount: function() {
    if (this.refs.chart) {
      // necessary to get a ref from the redux connect()ed TrendsContainer
      this.chart = this.refs.chart.getWrappedInstance();
    }
  },
  render: function() {
    return (

        {this.renderHeader()}
        {this.renderSubNav()}

                {this.renderChart()}

              {this.renderFocusedCBGTime()}
              {this.renderFocusedCBGHTMLLabels()}

        <Footer
         chartType={this.chartType}
         onClickBoxOverlay={this.toggleBoxOverlay}
         onClickGroup={this.toggleGroup}
         onClickLines={this.toggleLines}
         onClickRefresh={this.props.onClickRefresh}
         onClickBgDataToggle={this.toggleBgDataSource}
         boxOverlay={this.props.chartPrefs.modal.smbgRangeOverlay}
         grouped={this.props.chartPrefs.modal.smbgGrouped}
         showingLines={this.props.chartPrefs.modal.smbgLines}
         showingCbg={this.props.chartPrefs.modal.showingCbg}
         showingSmbg={this.props.chartPrefs.modal.showingSmbg}
        ref="footer" />

    );
  },
  renderHeader: function() {
    return (
      <Header
        chartType={this.chartType}
        inTransition={this.state.inTransition}
        atMostRecent={this.state.atMostRecent}
        title={this.state.title}
        iconBack={'icon-back'}
        iconNext={'icon-next'}
        iconMostRecent={'icon-most-recent'}
        onClickBack={this.handleClickBack}
        onClickBasics={this.props.onSwitchToBasics}
        onClickModal={this.handleClickModal}
        onClickMostRecent={this.handleClickMostRecent}
        onClickNext={this.handleClickForward}
        onClickOneDay={this.handleClickDaily}
        onClickTwoWeeks={this.handleClickWeekly}
        onClickSettings={this.handleClickSettings}
      ref="header" />
    );
  },
  renderSubNav: function() {
    return (
      <SubNav
       activeDays={this.props.chartPrefs.modal.activeDays}
       activeDomain={this.props.chartPrefs.modal.activeDomain}
       extentSize={this.props.chartPrefs.modal.extentSize}
       domainClickHandlers={{
        '1 week': this.handleClickOneWeek,
        '2 weeks': this.handleClickTwoWeeks,
        '4 weeks': this.handleClickFourWeeks
       }}
       onClickDay={this.toggleDay}
       toggleWeekdays={this.toggleWeekdays}
       toggleWeekends={this.toggleWeekends}
      ref="subnav" />
    );
  },
  renderChart: function() {
    const { bgPrefs: { bgClasses, bgUnits } } = this.props;
    let bgBounds = {
      veryHighThreshold: bgClasses.high.boundary,
      targetUpperBound: bgClasses.target.boundary,
      targetLowerBound: bgClasses.low.boundary,
      veryLowThreshold: bgClasses['very-low'].boundary,
    };
    return (
      <TrendsContainer
        activeDays={this.props.chartPrefs.modal.activeDays}
        bgBounds={bgBounds}
        bgClasses={this.props.bgPrefs.bgClasses}
        bgUnits={this.props.bgPrefs.bgUnits}
        extentSize={this.props.chartPrefs.modal.extentSize}
        initialDatetimeLocation={this.props.initialDatetimeLocation}
        showingSmbg={this.props.chartPrefs.modal.showingSmbg}
        showingCbg={this.props.chartPrefs.modal.showingCbg}
        smbgRangeOverlay={this.props.chartPrefs.modal.smbgRangeOverlay}
        smbgGrouped={this.props.chartPrefs.modal.smbgGrouped}
        smbgLines={this.props.chartPrefs.modal.smbgLines}
        smbgTrendsComponent={SMBGTrends}
        timePrefs={this.props.timePrefs}
        // data
        cbgByDate={this.props.patientData.cbgByDate}
        cbgByDayOfWeek={this.props.patientData.cbgByDayOfWeek}
        smbgByDate={this.props.patientData.smbgByDate}
        smbgByDayOfWeek={this.props.patientData.smbgByDayOfWeek}
        // handlers
        onDatetimeLocationChange={this.handleDatetimeLocationChange}
        onSelectDay={this.handleSelectDay}
        onSwitchBgDataSource={this.toggleBgDataSource}
      ref="chart" />
    );
  },
  renderFocusedCBGHTMLLabels: function() {
    if (!this.props.chartPrefs.modal.showingCbg) {
      return null;
    }
    return (
      <FocusedCBGSliceHTMLLabels
        bgUnits={this.props.bgPrefs.bgUnits}
        focusedKeys={this.props.trendsState.focusedCbgSliceKeys}
        focusedSlice={this.props.trendsState.focusedCbgSlice} />
    );
  },
  renderFocusedCBGTime: function() {
    if (!this.props.chartPrefs.modal.showingCbg) {
      return null;
    }
    return (
      <FocusedCBGSliceTime
        focusedSlice={this.props.trendsState.focusedCbgSlice} />
    );
  },
  renderMissingSMBGHeader: function() {
    return (

    );
  },
  formatDate: function(datetime) {
    var timePrefs = this.props.timePrefs, timezone;
    if (!timePrefs.timezoneAware) {
      timezone = 'UTC';
    }
    else {
      timezone = timePrefs.timezoneName || 'UTC';
    }
    return sundial.formatInTimezone(datetime, timezone, 'MMM D, YYYY');
  },
  getTitle: function(datetimeLocationEndpoints) {
    // endpoint is exclusive, so need to subtract a day
    var end = d3.time.day.utc.offset(new Date(datetimeLocationEndpoints[1]), -1);
    return this.formatDate(datetimeLocationEndpoints[0]) + ' - ' + this.formatDate(end);
  },
  getNewDomain: function(current, extent) {
    var timePrefs = this.props.timePrefs, timezone;
    if (!timePrefs.timezoneAware) {
      timezone = 'UTC';
    }
    else {
      timezone = timePrefs.timezoneName || 'UTC';
    }
    current = sundial.ceil(current, 'day', timezone);
    return [d3.time.day.utc.offset(current, -extent).toISOString(), current.toISOString()];
  },
  updateVisibleDays: function() {
    this.setState({
      visibleDays: d3.select('#modalDays').selectAll('g.modalDay').size()
    });
  },
  // handlers
  handleClickBack: function(e) {
    if (e) {
      e.preventDefault();
    }
    this.chart.goBack();
  },
  handleClickForward: function(e) {
    if (e) {
      e.preventDefault();
    }
    if (this.state.atMostRecent) {
      return;
    }
    this.chart.goForward();
  },
  handleClickMostRecent: function(e) {
    if (e) {
      e.preventDefault();
    }
    if (this.state.atMostRecent) {
      return;
    }
    this.chart.goToMostRecent();
  },
  handleClickDaily: function(e) {
    if (e) {
      e.preventDefault();
    }
    var datetime = this.chart ? this.chart.getCurrentDay() : this.props.initialDatetimeLocation;
    this.props.onSwitchToDaily(datetime);
  },
  handleClickModal: function(e) {
    if (e) {
      e.preventDefault();
    }
    // when you're on modal view, clicking modal does nothing
    return;
  },
  handleClickOneWeek: function(e) {
    if (e) {
      e.preventDefault();
    }
    var prefs = _.cloneDeep(this.props.chartPrefs);
    // no change, return early
    if (prefs.activeDomain === '1 week' && prefs.extentSize === 7) {
      return;
    }
    prefs.modal.activeDomain = '1 week';
    prefs.modal.extentSize = 7;
    this.props.updateChartPrefs(prefs);
    var current = new Date(this.chart.getCurrentDay());
    var newDomain = this.getNewDomain(current, 7);
    this.chart.setExtent(newDomain);
  },
  handleClickTwoWeeks: function(e) {
    if (e) {
      e.preventDefault();
    }
    var prefs = _.cloneDeep(this.props.chartPrefs);
    // no change, return early
    if (prefs.activeDomain === '2 weeks' && prefs.extentSize === 14) {
      return;
    }
    prefs.modal.activeDomain = '2 weeks';
    prefs.modal.extentSize = 14;
    this.props.updateChartPrefs(prefs);
    var current = new Date(this.chart.getCurrentDay());
    var newDomain = this.getNewDomain(current, 14);
    this.chart.setExtent(newDomain);
  },
  handleClickFourWeeks: function(e) {
    if (e) {
      e.preventDefault();
    }
    var prefs = _.cloneDeep(this.props.chartPrefs);
    // no change, return early
    if (prefs.activeDomain === '4 weeks' && prefs.extentSize === 28) {
      return;
    }
    prefs.modal.activeDomain = '4 weeks';
    prefs.modal.extentSize = 28;
    this.props.updateChartPrefs(prefs);
    var current = new Date(this.chart.getCurrentDay());
    var newDomain = this.getNewDomain(current, 28);
    this.chart.setExtent(newDomain);
  },
  handleClickWeekly: function(e) {
    if (e) {
      e.preventDefault();
    }
    var datetime = this.chart ? this.chart.getCurrentDay() : this.props.initialDatetimeLocation;
    this.props.onSwitchToWeekly(datetime);
  },
  handleClickSettings: function(e) {
    if (e) {
      e.preventDefault();
    }
    this.props.onSwitchToSettings();
  },
  handleDatetimeLocationChange: function(datetimeLocationEndpoints, atMostRecent) {
    if (this.isMounted()) {
      this.setState({
        atMostRecent: atMostRecent,
        title: this.getTitle(datetimeLocationEndpoints)
      });
      this.props.updateDatetimeLocation(datetimeLocationEndpoints[1]);
    }
  },
  handleSelectDay: function(date) {
    this.props.onSwitchToDaily(date);
  },
  toggleDay: function(day) {
    var self = this;
    return function(e) {
      e.stopPropagation();
      var prefs = _.cloneDeep(self.props.chartPrefs);
      prefs.modal.activeDays[day] = prefs.modal.activeDays[day] ? false : true;
      self.props.updateChartPrefs(prefs);
    };
  },
  toggleBgDataSource: function(e) {
    if (e) {
      e.preventDefault();
    }
    var prefs = _.cloneDeep(this.props.chartPrefs);
    prefs.modal.showingCbg = !prefs.modal.showingCbg;
    prefs.modal.showingSmbg = !prefs.modal.showingSmbg;
    this.props.updateChartPrefs(prefs);
  },
  toggleBoxOverlay: function(e) {
    var prefs = _.cloneDeep(this.props.chartPrefs);
    prefs.modal.smbgRangeOverlay = prefs.modal.smbgRangeOverlay ? false : true;
    this.props.updateChartPrefs(prefs);
  },
  toggleGroup: function(e) {
    var prefs = _.cloneDeep(this.props.chartPrefs);
    prefs.modal.smbgGrouped = prefs.modal.smbgGrouped ? false : true;
    this.props.updateChartPrefs(prefs);
  },
  toggleLines: function(e) {
    var prefs = _.cloneDeep(this.props.chartPrefs);
    prefs.modal.smbgLines = prefs.modal.smbgLines ? false : true;
    this.props.updateChartPrefs(prefs);
  },
  toggleWeekdays: function(allActive) {
    var prefs = _.cloneDeep(this.props.chartPrefs);
    prefs.modal.activeDays = {
      'monday': !allActive,
      'tuesday': !allActive,
      'wednesday': !allActive,
      'thursday': !allActive,
      'friday': !allActive,
      'saturday': prefs.modal.activeDays.saturday,
      'sunday': prefs.modal.activeDays.sunday
    };
    this.props.updateChartPrefs(prefs);
  },
  toggleWeekends: function(allActive) {
    var prefs = _.cloneDeep(this.props.chartPrefs);
    prefs.modal.activeDays = {
      'monday': prefs.modal.activeDays.monday,
      'tuesday': prefs.modal.activeDays.tuesday,
      'wednesday': prefs.modal.activeDays.wednesday,
      'thursday': prefs.modal.activeDays.thursday,
      'friday': prefs.modal.activeDays.friday,
      'saturday': !allActive,
      'sunday': !allActive
    };
    this.props.updateChartPrefs(prefs);
  }
});

module.exports = Modal;<|endoftext|>


<commit_before>import Thumbnail from './thumbnail';

import { Lock, Unlock, Activity, Calendar, User, Sliders } from 'react-feather';

import { getUptimeState, roundUptime } from '../../../utils/uptime';

const Thumbnails = ({ is_open, uptime, lastUpdate, owner, rate_limiting }) => {
  return (

      {is_open ? (
        <Thumbnail title="Accès" icon={<Unlock />}>
          API ouvert à tous
        </Thumbnail>
      ) : (
        <Thumbnail title="Accès" icon={<Lock />}>
          Sous habilitation
        </Thumbnail>
      )}
      {uptime && (
        <Thumbnail title="Disponibilité" icon={<Activity />}>

            {roundUptime(0)(uptime)}% actif / dernier mois

        </Thumbnail>
      )}
      <Thumbnail title="Activité" icon={<Calendar />}>
        Dernière modification le {lastUpdate}
      </Thumbnail>
      <Thumbnail title="Producteur" icon={<User />}>
        {owner}
      </Thumbnail>
      {rate_limiting && (
        <Thumbnail title="Limite d’usage" icon={<Sliders />}>

            {rate_limiting.split('/').map(rate => (

                {rate}

            ))}

        </Thumbnail>
      )}

  );
};

export default Thumbnails;
<commit_msg>Fix CSS layout in api page<commit_after>import Thumbnail from './thumbnail';

import { Lock, Unlock, Activity, Calendar, User, Sliders } from 'react-feather';

import { getUptimeState, roundUptime } from '../../../utils/uptime';

const Thumbnails = ({ is_open, uptime, lastUpdate, owner, rate_limiting }) => {
  return (

      {is_open ? (
        <Thumbnail title="Accès" icon={<Unlock />}>
          API ouvert à tous
        </Thumbnail>
      ) : (
        <Thumbnail title="Accès" icon={<Lock />}>
          Sous habilitation
        </Thumbnail>
      )}
      {uptime && (
        <Thumbnail title="Disponibilité" icon={<Activity />}>

            {roundUptime(0)(uptime)}% actif / dernier mois

        </Thumbnail>
      )}
      <Thumbnail title="Activité" icon={<Calendar />}>
        Dernière modification le {lastUpdate}
      </Thumbnail>
      <Thumbnail title="Producteur" icon={<User />}>
        {owner}
      </Thumbnail>
      {rate_limiting && (
        <Thumbnail title="Limite d’usage" icon={<Sliders />}>

            {rate_limiting.split('/').map(rate => (

                {rate}

            ))}

        </Thumbnail>
      )}

  );
};

export default Thumbnails;
<|endoftext|>


<commit_before>M.wrap('github/jillix/bind-filter/dev/filter.js', function (require, module, exports) {
var Bind = require('github/jillix/bind');
var Events = require('github/jillix/events');

var find = require('./find');
var ui = require('./ui');
var validate = require('./validate');

var firstTemplate = true;
var templateCache = {};
var defaultOptions = {
    limit: 17
};
var operatorConfig = {
    '=':        ['',        'mixed'],                                       // or
    '!=':       ['$ne',     ['number', 'string', 'array']],                 // and
    '>':        ['$gt',     ['number']],                                    // and
    '<':        ['$lt',     ['number']],                                    // and
    '>=':       ['$gte',    ['number']],                                    // and
    '<=':       ['$lte',    ['number']],                                    // and
    'in':       ['$in',     ['number', 'string', 'array'],    'split'],     // and ('or' can be achieved by concatenating the arrays)
    'notin':    ['$nin',    ['number', 'string', 'array'],    'split'],     // or ('and' can be achieved by concatenating the arrays)
    'all':      ['$all',    ['array'],    'split'],                         // or ('and' can be achieved by concatenating the arrays)
    'regExp':   ['$regex',  ['string']],                                    // and ('or' is built in the regex syntax)
    'exists':   ['$exists', 'mixed',    'boolean']                          // makes no sense
};

function MergeRecursive(obj1, obj2) {

    for (var p in obj2) {
        if (!obj2.hasOwnProperty(p)) continue;
        try {
            // Property in destination object set; update its value.
            if (obj2[p].constructor == Object) {
                obj1[p] = MergeRecursive(obj1[p], obj2[p]);
            } else {
                obj1[p] = obj2[p];
            }
        } catch(e) {
            // Property in destination object not set; create it and set its value.
            obj1[p] = obj2[p];
        }
    }

    return obj1;
}

function uid (len, uid) {
    uid = "";
    for (var i = 0, l = len || 24; i < l; ++i) {
        uid += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"[0 | Math.random() * 62];
    }
    return uid;
};

function setFilters (filters, reset, dontFetchData) {
    var self = this;

    if (!filters || typeof filters !== "object" || !self.template) {
        return console.error('setFilters: no template set!');;
    }

    // we always reset the skip option
    self.emit('resetSkip');

    // reset filters if reset is true
    if (reset) {
        self.filters = {};
    }

    // create and buffer filters
    for (var i = 0, l = filters.length; i < l; ++i) {

        // validate field
        if (validate.validate.call(self, filters[i])) {

            // convert value from value field
            filters[i] = validate.convert.call(self, filters[i]);

            var hash = filters[i].hash || uid(4);
            self.filters[hash] = self.filters[hash] || {};

            // merge filter
            for (var key in filters[i]) {
                if (!filters[i].hasOwnProperty(key)) continue;
                self.filters[hash][key] = filters[i][key];
            }

            // if field type is string and operator is 'regexp' make it case insensitive
            var field = self.templates[self.template].schema[filters[i].field];
            if (filters[i].operator === 'regExp' && field && field.type === 'string' && !field.casesensitive) {
                self.filters[hash].originalValue = filters[i].value;
                self.filters[hash].value = '(?i)' + filters[i].value;
            } else {
                delete self.filters[hash].originalValue;
            }
        }
    }

    // emit filters cached event
    self.emit('filtersCached', self.filters, reset);

    // find data in db
    if (!dontFetchData) {
        find.call(self);
    }
}

function getTemplates (templates, reset, callback) {
    var self = this;

    // fetch templates from server
    self.emit('find', templates, function (err, result) {

        self.emit('templateResult', err, result);

        if (err || !result) {
            return callback(err || new Error('No templates found.'));
        }

        // reset cache
        if (reset) {
            self.templates = {};
        }

        // merge fetched templates into result templates
        for (var i = 0, l = result.length; i < l; ++i) {
            self.templates[result[i]._id] = result[i];

            // select a template
            if (result[i]._id === templates[0]) {
                self.template = templates[0];
            }
        }

        callback(null);
    });
}

function setTemplates (templates, callback) {
    var self = this;

    if (templates instanceof Array) {
        getTemplates.call(self, templates, true, function (err) {
            if (err) {
                // TODO handle error
                return console.error(err);
            }

            if (callback) {
                callback();
            }

            // emit the templates
            self.emit('template', self.templates[self.template]);
            self.emit('templates', self.templates);
        });
    }
}

// TODO swap force and dontFetchData parameter to have the same syntax everywhere
function setTemplate (template, dontFetchData, force) {
    var self = this;

    // TODO this is a hack until bind knows how select keys in parameters
    var template = typeof template === 'string' ? template : template._id;
    if (!template) {
        // TODO handle error
        return console.error('Wrong template format: ' + typeof template);
    }

    // nothing to do if the same template
    if (!force && self.template === template) {
        return;
    }

    // get template from server or cache
    getTemplates.call(self, [template], false, function (err) {

        if (err || !self.templates[template]) {
            // TODO handle error
            return console.error(err || 'template ' + template + ' not found.');
        }

        // set sort options
        if (self.templates[template].sort) {
            self.emit("setOptions", { sort: self.templates[template].sort });
        }

        setFilters.call(self, (self.config.setFilters || []).concat(self.templates[template].filters || []), true, dontFetchData);

        // emit the template
        self.emit('template', self.templates[template]);
    });
}

function resetSkip () {
    var self = this;

    self.options = self.options || {};
    self.options.skip = 0;
}

function setOptions (options, reset, callFind) {
    var self = this;

    if (typeof options !== 'object') {
        return;
    }

    // when no skip is received, we force it to 0
    //options.skip = options.skip || 0;

    // reset options
    if (reset) {
        self.options = options;
    }
    // merge options
    else {
        for (var option in options) {
            if (!options.hasOwnProperty(option)) continue;

            var value = options[option];

            // option is an array
            //var optionValue = self.options[option];

            // TODO How do we merge objects?
            // switch ((optionValue || {}).constructor) {
            //     case Array:
            //         optionValue.push(value);
            //         break;
            //     case Object:
            //         switch (value.constructor) {
            //             case Object:
            //                 optionValue = MergeRecursive(self.options[option], value);
            //                 break;
            //             default:
            //                 optionValue = value;
            //                 break;
            //         }
            //         break;
            //     default:
            //         optionValue = value;
            // }

            self.options[option] = value;
        }
    }

    // emit options cahed event
    self.emit('optionsCached', self.options, reset);

    // find data in db
    if (callFind) {
        find.call(self);
    }
}

function getFilters (callback) {

    // set self (the module)
    var self = this;

    // filters to send
    var filters = [];

    // each filter from self.filters
    for (var id in self.filters) {

        if (!self.filters.hasOwnProperty(id)) continue;

        // current filter
        var cFilter = self.filters[id];

        // build filter to push
        var filter = {};

        // set only these fields
        var fieldsToSend = ["field", "label", "operator", "originalValue", "value"];

        for (var i = 0; i < fieldsToSend.length; ++i) {

            // get the current field
            var cField = fieldsToSend[i];

            // if is NOT a key from cFilter go to the next one
            if (!cFilter.hasOwnProperty(cField)) continue;

            // set the field in filter
            filter[cField] = cFilter[cField];
        }

        // push the filter in filters
        filters.push(filter);
    }

    // and callback the filters
    callback(filters);
}

function getItem (dataItem, callback) {
    var self = this;

    if (!self.query) { return; }

    if (self.crudFindBusy) {
        return callback('Find is busy.');
    }

    self.crudFindBusy = true;

    var queryWithoutLimit = JSON.parse(JSON.stringify(self.query));
    delete queryWithoutLimit.o.limit;

    self.emit('find', queryWithoutLimit, function (err, data) {
        self.crudFindBusy = false;

        for (var i = 0, l = data.length; i < l; ++i) {
            if (data[i]._id === dataItem._id) {
                data[i].bindFilterMessage = 'show';
                return callback(null, data[i]);
            }
        }

        // TODO How must this look?
        callback(null, {_id: dataItem._id, bindFilterMessage: 'hide'});
    });
}

function initInterface () {
    var self = this;

    // listen to interface events
    self.on('setFilters', setFilters);
    self.on('setTemplate', setTemplate);
    self.on('setTemplates', setTemplates);
    self.on('setOptions', setOptions);
    self.on('getFilters', getFilters);
    self.on('getItem', getItem);
    self.on('refresh', find);
    self.on('resetSkip', resetSkip);
}

function init (config) {

    var self = this;
    // prepare module
    self.config = config;
    self.filters = {};
    self.templates = templateCache;

    // TODO merge options
    self.options = config.options || defaultOptions;
    self.config.operators = operatorConfig;

    if (!config.waitFor) {
        return console.error('At least a CRUD mofule must be a dependency of the bind-filter module.');
    }

    // setup interface
    initInterface.call(self);

    // listen to external events
    Events.call(self, config);

    // run the binds
    for (var i in config.binds) {
        if (!config.binds.hasOwnProperty(i)) continue;

        Bind.call(self, config.binds[i]);
    }

    // i18n for operators
    if (self.config.i18n === true) {

        // cache for translated operators
        self.config.i18n = {};

        var operators = self.config.operators;
        for (var operator in operators) {
            if (!operators.hasOwnProperty(operator)) continue;

            (function (op) {
                self.emit("message", op, function (err, newOperator) {
                    if (err) { return; }
                    // cache the translated operator
                    self.config.i18n[op] = newOperator.message;
                });
            })(operator);
        }
    }

    if (self.config.ui) {
        ui.call(self);
    }

    // init templates
    if (self.config.setTemplates) {
        self.emit('setTemplates', self.config.setTemplates, function () {
            // init template
            if (self.config.template) {
                self.emit('setTemplate', self.config.template);
            }
        });
    // init template
    } else if (self.config.template) {
        self.emit('setTemplate', self.config.template);
    }

    self.emit('ready');
}

module.exports = init;

return module; });
<commit_msg>Get filters from options field.<commit_after>M.wrap('github/jillix/bind-filter/dev/filter.js', function (require, module, exports) {
var Bind = require('github/jillix/bind');
var Events = require('github/jillix/events');

var find = require('./find');
var ui = require('./ui');
var validate = require('./validate');

var firstTemplate = true;
var templateCache = {};
var defaultOptions = {
    limit: 17
};
var operatorConfig = {
    '=':        ['',        'mixed'],                                       // or
    '!=':       ['$ne',     ['number', 'string', 'array']],                 // and
    '>':        ['$gt',     ['number']],                                    // and
    '<':        ['$lt',     ['number']],                                    // and
    '>=':       ['$gte',    ['number']],                                    // and
    '<=':       ['$lte',    ['number']],                                    // and
    'in':       ['$in',     ['number', 'string', 'array'],    'split'],     // and ('or' can be achieved by concatenating the arrays)
    'notin':    ['$nin',    ['number', 'string', 'array'],    'split'],     // or ('and' can be achieved by concatenating the arrays)
    'all':      ['$all',    ['array'],    'split'],                         // or ('and' can be achieved by concatenating the arrays)
    'regExp':   ['$regex',  ['string']],                                    // and ('or' is built in the regex syntax)
    'exists':   ['$exists', 'mixed',    'boolean']                          // makes no sense
};

function MergeRecursive(obj1, obj2) {

    for (var p in obj2) {
        if (!obj2.hasOwnProperty(p)) continue;
        try {
            // Property in destination object set; update its value.
            if (obj2[p].constructor == Object) {
                obj1[p] = MergeRecursive(obj1[p], obj2[p]);
            } else {
                obj1[p] = obj2[p];
            }
        } catch(e) {
            // Property in destination object not set; create it and set its value.
            obj1[p] = obj2[p];
        }
    }

    return obj1;
}

function uid (len, uid) {
    uid = "";
    for (var i = 0, l = len || 24; i < l; ++i) {
        uid += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"[0 | Math.random() * 62];
    }
    return uid;
};

function setFilters (filters, reset, dontFetchData) {
    var self = this;

    if (!filters || typeof filters !== "object" || !self.template) {
        return console.error('setFilters: no template set!');;
    }

    // we always reset the skip option
    self.emit('resetSkip');

    // reset filters if reset is true
    if (reset) {
        self.filters = {};
    }

    // create and buffer filters
    for (var i = 0, l = filters.length; i < l; ++i) {

        // validate field
        if (validate.validate.call(self, filters[i])) {

            // convert value from value field
            filters[i] = validate.convert.call(self, filters[i]);

            var hash = filters[i].hash || uid(4);
            self.filters[hash] = self.filters[hash] || {};

            // merge filter
            for (var key in filters[i]) {
                if (!filters[i].hasOwnProperty(key)) continue;
                self.filters[hash][key] = filters[i][key];
            }

            // if field type is string and operator is 'regexp' make it case insensitive
            var field = self.templates[self.template].schema[filters[i].field];
            if (filters[i].operator === 'regExp' && field && field.type === 'string' && !field.casesensitive) {
                self.filters[hash].originalValue = filters[i].value;
                self.filters[hash].value = '(?i)' + filters[i].value;
            } else {
                delete self.filters[hash].originalValue;
            }
        }
    }

    // emit filters cached event
    self.emit('filtersCached', self.filters, reset);

    // find data in db
    if (!dontFetchData) {
        find.call(self);
    }
}

function getTemplates (templates, reset, callback) {
    var self = this;

    // fetch templates from server
    self.emit('find', templates, function (err, result) {

        self.emit('templateResult', err, result);

        if (err || !result) {
            return callback(err || new Error('No templates found.'));
        }

        // reset cache
        if (reset) {
            self.templates = {};
        }

        // merge fetched templates into result templates
        for (var i = 0, l = result.length; i < l; ++i) {
            self.templates[result[i]._id] = result[i];

            // select a template
            if (result[i]._id === templates[0]) {
                self.template = templates[0];
            }
        }

        callback(null);
    });
}

function setTemplates (templates, callback) {
    var self = this;

    if (templates instanceof Array) {
        getTemplates.call(self, templates, true, function (err) {
            if (err) {
                // TODO handle error
                return console.error(err);
            }

            if (callback) {
                callback();
            }

            // emit the templates
            self.emit('template', self.templates[self.template]);
            self.emit('templates', self.templates);
        });
    }
}

// TODO swap force and dontFetchData parameter to have the same syntax everywhere
function setTemplate (template, dontFetchData, force) {
    var self = this;

    // TODO this is a hack until bind knows how select keys in parameters
    var template = typeof template === 'string' ? template : template._id;
    if (!template) {
        // TODO handle error
        return console.error('Wrong template format: ' + typeof template);
    }

    // nothing to do if the same template
    if (!force && self.template === template) {
        return;
    }

    // get template from server or cache
    getTemplates.call(self, [template], false, function (err) {

        if (err || !self.templates[template]) {
            // TODO handle error
            return console.error(err || 'template ' + template + ' not found.');
        }

        // set sort options
        if (self.templates[template].sort) {
            self.emit("setOptions", { sort: self.templates[template].sort });
        }

        setFilters.call(self, (self.config.setFilters || []).concat((self.templates[template].options || {}).filters || []), true, dontFetchData);

        // emit the template
        self.emit('template', self.templates[template]);
    });
}

function resetSkip () {
    var self = this;

    self.options = self.options || {};
    self.options.skip = 0;
}

function setOptions (options, reset, callFind) {
    var self = this;

    if (typeof options !== 'object') {
        return;
    }

    // when no skip is received, we force it to 0
    //options.skip = options.skip || 0;

    // reset options
    if (reset) {
        self.options = options;
    }
    // merge options
    else {
        for (var option in options) {
            if (!options.hasOwnProperty(option)) continue;

            var value = options[option];

            // option is an array
            //var optionValue = self.options[option];

            // TODO How do we merge objects?
            // switch ((optionValue || {}).constructor) {
            //     case Array:
            //         optionValue.push(value);
            //         break;
            //     case Object:
            //         switch (value.constructor) {
            //             case Object:
            //                 optionValue = MergeRecursive(self.options[option], value);
            //                 break;
            //             default:
            //                 optionValue = value;
            //                 break;
            //         }
            //         break;
            //     default:
            //         optionValue = value;
            // }

            self.options[option] = value;
        }
    }

    // emit options cahed event
    self.emit('optionsCached', self.options, reset);

    // find data in db
    if (callFind) {
        find.call(self);
    }
}

function getFilters (callback) {

    // set self (the module)
    var self = this;

    // filters to send
    var filters = [];

    // each filter from self.filters
    for (var id in self.filters) {

        if (!self.filters.hasOwnProperty(id)) continue;

        // current filter
        var cFilter = self.filters[id];

        // build filter to push
        var filter = {};

        // set only these fields
        var fieldsToSend = ["field", "label", "operator", "originalValue", "value"];

        for (var i = 0; i < fieldsToSend.length; ++i) {

            // get the current field
            var cField = fieldsToSend[i];

            // if is NOT a key from cFilter go to the next one
            if (!cFilter.hasOwnProperty(cField)) continue;

            // set the field in filter
            filter[cField] = cFilter[cField];
        }

        // push the filter in filters
        filters.push(filter);
    }

    // and callback the filters
    callback(filters);
}

function getItem (dataItem, callback) {
    var self = this;

    if (!self.query) { return; }

    if (self.crudFindBusy) {
        return callback('Find is busy.');
    }

    self.crudFindBusy = true;

    var queryWithoutLimit = JSON.parse(JSON.stringify(self.query));
    delete queryWithoutLimit.o.limit;

    self.emit('find', queryWithoutLimit, function (err, data) {
        self.crudFindBusy = false;

        for (var i = 0, l = data.length; i < l; ++i) {
            if (data[i]._id === dataItem._id) {
                data[i].bindFilterMessage = 'show';
                return callback(null, data[i]);
            }
        }

        // TODO How must this look?
        callback(null, {_id: dataItem._id, bindFilterMessage: 'hide'});
    });
}

function initInterface () {
    var self = this;

    // listen to interface events
    self.on('setFilters', setFilters);
    self.on('setTemplate', setTemplate);
    self.on('setTemplates', setTemplates);
    self.on('setOptions', setOptions);
    self.on('getFilters', getFilters);
    self.on('getItem', getItem);
    self.on('refresh', find);
    self.on('resetSkip', resetSkip);
}

function init (config) {

    var self = this;
    // prepare module
    self.config = config;
    self.filters = {};
    self.templates = templateCache;

    // TODO merge options
    self.options = config.options || defaultOptions;
    self.config.operators = operatorConfig;

    if (!config.waitFor) {
        return console.error('At least a CRUD mofule must be a dependency of the bind-filter module.');
    }

    // setup interface
    initInterface.call(self);

    // listen to external events
    Events.call(self, config);

    // run the binds
    for (var i in config.binds) {
        if (!config.binds.hasOwnProperty(i)) continue;

        Bind.call(self, config.binds[i]);
    }

    // i18n for operators
    if (self.config.i18n === true) {

        // cache for translated operators
        self.config.i18n = {};

        var operators = self.config.operators;
        for (var operator in operators) {
            if (!operators.hasOwnProperty(operator)) continue;

            (function (op) {
                self.emit("message", op, function (err, newOperator) {
                    if (err) { return; }
                    // cache the translated operator
                    self.config.i18n[op] = newOperator.message;
                });
            })(operator);
        }
    }

    if (self.config.ui) {
        ui.call(self);
    }

    // init templates
    if (self.config.setTemplates) {
        self.emit('setTemplates', self.config.setTemplates, function () {
            // init template
            if (self.config.template) {
                self.emit('setTemplate', self.config.template);
            }
        });
    // init template
    } else if (self.config.template) {
        self.emit('setTemplate', self.config.template);
    }

    self.emit('ready');
}

module.exports = init;

return module; });
<|endoftext|>


<commit_before>import Item from "~/connectors/item"
import Feed from "~/connectors/feed"

const debug = require("debug")("podcloud-feeds:queries:podcastItem")

const podcastItem = function(obj, args, context, info) {
  return new Promise((resolve, reject) => {
    const findArgs = {
      _id: args._id,
      published_at: {
        $lte: new Date()
      },
      status: "published",
      private: {
        $ne: true
      }
    }

    debug("findArgs", findArgs)

    Item.findOne(findArgs).exec(function(err, item) {
      debug("err:", err)
      debug("item:", item)
      if (err) {
        reject(err)
      } else {
        if (item && item.feed_id) {
          Feed.findOne({ _id: item.feed_id }).exec(function(err, feed) {
            if (err) {
              console.error(err)
              reject(err)
            } else {
              debug("Got a feed", feed)
              item.feed = feed
              resolve(item)
            }
          })
        } else {
          resolve(null)
        }
      }
    })
  })
}

export default podcastItem
<commit_msg>feat: allow to query not yet published podcast item<commit_after>import Item from "~/connectors/item"
import Feed from "~/connectors/feed"

const debug = require("debug")("podcloud-feeds:queries:podcastItem")

const podcastItem = function(obj, args, context, info) {
  return new Promise((resolve, reject) => {
    const findArgs = {
      _id: args._id,
      status: "published",
      private: {
        $ne: true
      }
    }

    debug("findArgs", findArgs)

    Item.findOne(findArgs).exec(function(err, item) {
      debug("err:", err)
      debug("item:", item)
      if (err) {
        reject(err)
      } else {
        if (item && item.feed_id) {
          Feed.findOne({ _id: item.feed_id }).exec(function(err, feed) {
            if (err) {
              console.error(err)
              reject(err)
            } else {
              debug("Got a feed", feed)
              item.feed = feed
              resolve(item)
            }
          })
        } else {
          resolve(null)
        }
      }
    })
  })
}

export default podcastItem
<|endoftext|>


<commit_before>'use strict'

import {Component}   from 'react'
import {Link}        from 'react-router'
import DocumentTitle from 'react-document-title'
import request       from 'request'

import Header        from '../components/Header'

class HomePage extends Component {

  constructor(props) {
    super(props)

    this.state = {
      domainCount: 68000,
      slackUserCount: 2300,
      meetupUserCount: 4923,
      forumUserCount: 250
    }

    this.updateStats = this.updateStats.bind(this)
  }

  componentDidMount() {
    // Get the number of Slack users
    request({
      url: "https://blockstack-site-api.herokuapp.com/v1/stats",
      withCredentials: false
    }, (error, response, body) => {
      if (!error && response.statusCode === 200) {
        this.updateStats(body)
      } else {
        console.log(error)
      }
    })
  }

  updateStats(response) {
    const jsonResponse = JSON.parse(response)
    if (jsonResponse.hasOwnProperty("slack_users") &&
        jsonResponse.hasOwnProperty("meetup_users") &&
        jsonResponse.hasOwnProperty("forum_users") &&
        jsonResponse.hasOwnProperty("domains")) {
      // Set the stats
      this.setState({
        slackUserCount: jsonResponse.slack_users,
        meetupUserCount: jsonResponse.meetup_users,
        forumUserCount: jsonResponse.forum_users,
        domainCount: jsonResponse.domains
      })
    }
  }

  render() {
    return (
      <DocumentTitle title="Blockstack, building the decentralized internet">

                    Build on the New Internet

                    Build decentralized, server-less apps where users control their data.

                    <Link to="http://eepurl.com/cv8gQ1" role="button" target="_blank"
                      className="btn btn-secondary btn-block">
                      Join the Community
                    </Link>
                    <Link to="/docs" className="btn btn-outline-primary hidden-sm-down">
                      Install the Software
                    </Link>

                      <Link to="https://explorer.blockstack.org/names/id"
                            className="link-stats" target="_blank">

                            Domains registered

                            |{this.state.domainCount}

                      </Link>
                      <Link to="http://chat.blockstack.org"
                            className="link-stats" target="_blank">

                            Slack members

                            |{this.state.slackUserCount}

                      </Link>
                      <Link to="http://www.meetup.com/topics/blockstack/"
                            className="link-stats" target="_blank">

                            Meetup members

                            |{this.state.meetupUserCount}

                      </Link>
                      <Link to="https://forum.blockstack.org/users?period=monthly"
                            className="link-stats" target="_blank">

                            Forum members

                            |{this.state.forumUserCount}

                      </Link>

      </DocumentTitle>
    )
  }
}

export default HomePage
<commit_msg>update to home button<commit_after>'use strict'

import {Component}   from 'react'
import {Link}        from 'react-router'
import DocumentTitle from 'react-document-title'
import request       from 'request'

import Header        from '../components/Header'

class HomePage extends Component {

  constructor(props) {
    super(props)

    this.state = {
      domainCount: 68000,
      slackUserCount: 2300,
      meetupUserCount: 4923,
      forumUserCount: 250
    }

    this.updateStats = this.updateStats.bind(this)
  }

  componentDidMount() {
    // Get the number of Slack users
    request({
      url: "https://blockstack-site-api.herokuapp.com/v1/stats",
      withCredentials: false
    }, (error, response, body) => {
      if (!error && response.statusCode === 200) {
        this.updateStats(body)
      } else {
        console.log(error)
      }
    })
  }

  updateStats(response) {
    const jsonResponse = JSON.parse(response)
    if (jsonResponse.hasOwnProperty("slack_users") &&
        jsonResponse.hasOwnProperty("meetup_users") &&
        jsonResponse.hasOwnProperty("forum_users") &&
        jsonResponse.hasOwnProperty("domains")) {
      // Set the stats
      this.setState({
        slackUserCount: jsonResponse.slack_users,
        meetupUserCount: jsonResponse.meetup_users,
        forumUserCount: jsonResponse.forum_users,
        domainCount: jsonResponse.domains
      })
    }
  }

  render() {
    return (
      <DocumentTitle title="Blockstack, building the decentralized internet">

                    Build on the New Internet

                    Build decentralized, server-less apps where users control their data.

                    <Link to="http://eepurl.com/cv8gQ1" role="button" target="_blank"
                      className="btn btn-secondary btn-block">
                      Join the Community
                    </Link>
                    <Link to="/docs" className="btn btn-outline-primary hidden-sm-down">
                      Install Blockstack
                    </Link>

                      <Link to="https://explorer.blockstack.org/names/id"
                            className="link-stats" target="_blank">

                            Domains registered

                            |{this.state.domainCount}

                      </Link>
                      <Link to="http://chat.blockstack.org"
                            className="link-stats" target="_blank">

                            Slack members

                            |{this.state.slackUserCount}

                      </Link>
                      <Link to="http://www.meetup.com/topics/blockstack/"
                            className="link-stats" target="_blank">

                            Meetup members

                            |{this.state.meetupUserCount}

                      </Link>
                      <Link to="https://forum.blockstack.org/users?period=monthly"
                            className="link-stats" target="_blank">

                            Forum members

                            |{this.state.forumUserCount}

                      </Link>

      </DocumentTitle>
    )
  }
}

export default HomePage
<|endoftext|>


<commit_before>window.countFPS = (function () {
  var lastLoop = (new Date()).getMilliseconds();
  var count = 1;
  var fps = 0;

  return function () {
    var currentLoop = (new Date()).getMilliseconds();
    if (lastLoop > currentLoop) {
      fps = count;
      count = 1;
    } else {
      count += 1;
    }
    lastLoop = currentLoop;
    return fps;
  };
}());

 thisAddEventListener = function(element, eventName, eventHandler, scope){

        var scopedEventHandler = scope ? function(e) { eventHandler.apply(scope, [e]); } : eventHandler;
        if(document.addEventListener)
            element.addEventListener(eventName, scopedEventHandler, false);
        else if(document.attachEvent)
            element.attachEvent("on"+eventName, scopedEventHandler);
    }

class Kumiho{
	constructor(CanvasID) {
		this.Canvas = document.getElementById(CanvasID);
		this.$global = {};

		this.input = {

			keyPressed : [],

			MouseX : 0,
			MouseY : 0,

			MouseClick : false,

			keydown: function(e) {
				this.input.keyPressed[e.keyCode] = true;
			},

			keyup: function(e) {
				this.input.keyPressed[e.keyCode] = false;
			},

			mousedown: function(e) {
				this.input.MouseClick = true;
				this.input.MouseX = e.clientX;
				this.input.MouseY = e.clientY;
			},

			mouseup: function(e) {
				this.input.MouseClick = false;
				this.input.MouseX = 0;
				this.input.MouseY = 0;
			},

		};

		this.Context = this.Canvas.getContext("2d");
		this.Camera = new Camera(this.Canvas.width,this.Canvas.height);
		this.counter = 0;

		thisAddEventListener(document, "keydown", this.input.keydown, this);
		thisAddEventListener(document, "keyup", this.input.keyup, this);
		thisAddEventListener(this.Canvas, "mousedown", this.input.mousedown, this);
		thisAddEventListener(this.Canvas, "mouseup", this.input.mouseup, this);

	}

	Text (options) {return new Text(this.Context,this.Camera,options);}

	Regtengel (options) {return new Regtengel(this.Context,this.Camera,options);}

	Scene (Image) {return new Scene(this.Canvas,this.Context,this.Camera,Image);}

	Tileset (options) {return new Tileset(this.Canvas,this.Context,this.Camera,options);}

	Sprite (options) {return new Sprite(this.Canvas,this.Context,this.Camera,options);}

	TileMap (options) {return new TileMap(this.Canvas,this.Context,this.Camera,options);}

	run(game) {
		this.then = Date.now();
		this.game = game;
		this.game.init(this.$global);
		this.loop();
	}

	loop(){
		this.setDelta();
		this.game.update(this.$global);
		this.Context.clearRect(0, 0, this.Canvas.width, this.Canvas.height);
		this.game.draw(this.$global);
		window.requestAnimationFrame(this.loop.bind(this));
	}

	setDelta() {
        this.now = Date.now();
        this.delta = (this.now - this.then) / 1000; // seconds since last frame
        this.then = this.now;
    }

	static random(a, b) {
		return Math.floor(Math.random() * b) + a;
	}

}

class Camera {

	constructor(width,height) {
		this.X = 0;
		this.Y = 0;
		this.width = width;
		this.height = height;
		this.MaxW = width;
		this.MaxH = height;
		this.Speed = 10;
		this.MinX = 0;
		this.MinY = 0;

	}

    fallow(GameObject) {

        var currentX = (GameObject.x - (this.X + (this.width / 2))) + this.X;
        var currentY = (GameObject.y - (this.Y + (this.height / 2))) + this.Y;

        if (currentX >= this.MinX && currentX <= this.MaxW - this.width) {
            this.X = currentX;
        }

        if (currentY >= this.MinY && currentY <= this.MaxH - this.height) {
            this.Y = currentY;
        }

    }

};

class GameObject {
	constructor(Context,Camera,options) {
		this.Context = Context
		this.Camera = Camera
		this.w = options.width;
        this.h = options.height;
        this.speed = options.Speed;
        this.x = options.X;
        this.y = options.Y;

	}

	draw() {}
}

class Regtengel extends GameObject {
	constructor(Context,Camera,options) {
		super(Context,Camera, options);
		this.Color =  options.Color || "#E88813" ;
	}

	draw() {
        this.Context.fillStyle = this.Color;
        this.Context.fillRect(this.x - this.Camera.X, this.y - this.Camera.Y, this.w, this.h);
    }
}

class Text extends GameObject {
	constructor(Context,Camera,options) {
		super(Context,Camera, options);
		this.Color =  options.Color || "#E88813" ;
		this.font = options.font || "30px Arial";;
        this.message = options.message || "";
	}

    draw () {
        this.Context.font = this.font;
        this.Context.fillStyle = this.Color;
        this.Context.fillText(this.message, this.x, this.y);

    };

}

class Sprite extends GameObject {

	constructor(Canvas,Context,Camera,options) {
		super(Context,Camera, options);
        this.tileset = options.tileset;
		this.tileIndex = options.tileIndex;
		this.tileset.x = this.x
		this.tileset.y = this.y
	}

    draw () {
		this.tileset.x = this.x - this.Camera.X;
		this.tileset.y = this.y - this.Camera.Y;
		this.tileset.draw(this.tileIndex)
    }
}

class Scene  {

	constructor(Canvas,Context,Camera,Image) {
		this.Canvas	= Canvas;
		this.Context = Context
		this.Camera = Camera
		this.Image =  Image;
		this.w = this.Image.width;
        this.h = this.Image.height;
		this.speed =  50;

	}

    draw () {

        this.Context.drawImage(
        this.Image,
       (this.Camera.X * this.speed) / 100,
       (this.Camera.Y * this.speed) / 100,
        this.Canvas.width,
        this.Canvas.height,
        0,
        0,
        this.Canvas.width,
        this.Canvas.height);

    }

};

class SpriteCollaction {

	constructor() {
        this.SpriteArray = [];
	}

    add (sprite) {
          this.SpriteArray.push(sprite);
    }

    each (f) {

        for (var i = 0; i < this.SpriteArray.length; i++) {
            let s = this.SpriteArray[i];
            f(s);
		}

   }

   eachWhitIndex (f) {

        for (var i = 0; i < this.SpriteArray.length; i++) {
            let s = this.SpriteArray[i];
            f(s, i);
        }

   }

    remove (sprite) {

        for (var i = this.SpriteArray.length - 1; i >= 0; i--) {

            if (this.SpriteArray[i] == sprite) {
                this.SpriteArray.splice(i, 1);
            }
        }
    }

    draw() {

        for (var i = 0; i < this.SpriteArray.length; i++) {
              this.SpriteArray[i].draw();
        }

    };

    get (index) {

        return this.SpriteArray[index];

    }

    checkCollision (x1, y1, w1, h1, x2, y2, w2, h2) {
        if (x1 + w1 > x2 && x2 + w2 > x1 && y1 + h1 > y2 && y2 + h2 > y1) { return true; }
        return false;
    }

}

class Tileset {

	constructor(Canvas,Context,Camera,options) {
		this.image = options.image;
        this.cols = options.cols;
        this.rows = options.rows;
		this.tileSize = options.tileSize;

		this.Context = Context;
		this.Camera = Camera;
		this.x = 0;
		this.y = 0;
	}

    getCoordinate (value) {

		var xy = {};

		if(value == this.rows * this.cols)
		{
				xy.y = this.rows -1
				xy.x = this.cols -1
		}

		if(value > this.cols)
		{

			if(value % this.cols > 0)
			{
				xy.y = Math.floor(value / this.cols);
				xy.x = value % this.cols -1;
			}
			else
			{
				xy.y = Math.floor(value / this.cols)-1;
				xy.x = this.cols-1;
			}

		}
		else
		{
			xy.y = 0
			xy.x = value -1;
		}

        return xy;
    }

    draw (tileIndex) {

		var Cor = this.getCoordinate(tileIndex)
		this.Context.drawImage(
		this.image,
		Cor.x * this.tileSize,
		Cor.y * this.tileSize,
		this.tileSize,
		this.tileSize,
		this.x,
		this.y,
		this.tileSize,
		this.tileSize);

    }

}

class TileMap {

    constructor(Canvas,Context,Camera,options) {

        this.cols = options.map.cols;
        this.rows = options.map.rows;
        this.tiles = options.map.tiles;
		this.Canvas	= Canvas;
		this.Context = Context
		this.Camera = Camera
        this.Collaction = new SpriteCollaction();
		this.tileset = options.tileset;

        this.Camera.MaxW = this.cols * this.tileset.tileSize;
        this.Camera.MaxH = this.rows * this.tileset.tileSize;

        for (var c = 0; c < this.cols; c++) {
            for (var r = 0; r < this.rows; r++) {
                var tile = this.GetTile(c, r);
                if (tile !== 0) {

                    this.Collaction.add(

						new Sprite(this.Canvas,this.Context,this.Camera,{
							X: c * this.tileset.tileSize,
							Y: r * this.tileset.tileSize,
							Speed:100,
							tileset: this.tileset,
							tileIndex: tile})
						);

                }
            }
        }

    }

    GetTile (col, row) {
        return this.tiles[row * this.cols + col];
    }

    SetTile (col, row, value) {
        this.tiles[row * this.cols + col] = value;
    }

    Remove (col, row) {

        this.SetTile(col, row, 0);
        //Kumiho.TileMap.Collction.Remove();

    }

    Draw () {

        this.Collaction.draw();

    }

};
<commit_msg>animation sınıfı eklendi<commit_after>window.countFPS = (function () {
  var lastLoop = (new Date()).getMilliseconds();
  var count = 1;
  var fps = 0;

  return function () {
    var currentLoop = (new Date()).getMilliseconds();
    if (lastLoop > currentLoop) {
      fps = count;
      count = 1;
    } else {
      count += 1;
    }
    lastLoop = currentLoop;
    return fps;
  };
}());

 thisAddEventListener = function(element, eventName, eventHandler, scope){

        var scopedEventHandler = scope ? function(e) { eventHandler.apply(scope, [e]); } : eventHandler;
        if(document.addEventListener)
            element.addEventListener(eventName, scopedEventHandler, false);
        else if(document.attachEvent)
            element.attachEvent("on"+eventName, scopedEventHandler);
    }

class Kumiho{
	constructor(CanvasID) {
		this.Canvas = document.getElementById(CanvasID);
		this.$global = {};

		this.input = {

			keyPressed : [],

			MouseX : 0,
			MouseY : 0,

			MouseClick : false,

			keydown: function(e) {
				this.input.keyPressed[e.keyCode] = true;
			},

			keyup: function(e) {
				this.input.keyPressed[e.keyCode] = false;
			},

			mousedown: function(e) {
				this.input.MouseClick = true;
				this.input.MouseX = e.clientX;
				this.input.MouseY = e.clientY;
			},

			mouseup: function(e) {
				this.input.MouseClick = false;
				this.input.MouseX = 0;
				this.input.MouseY = 0;
			},

		};

		this.Context = this.Canvas.getContext("2d");
		this.Camera = new Camera(this.Canvas.width,this.Canvas.height);
		this.counter = 0;

		thisAddEventListener(document, "keydown", this.input.keydown, this);
		thisAddEventListener(document, "keyup", this.input.keyup, this);
		thisAddEventListener(this.Canvas, "mousedown", this.input.mousedown, this);
		thisAddEventListener(this.Canvas, "mouseup", this.input.mouseup, this);

	}

	Text (options) {return new Text(this.Context,this.Camera,options);}

	Regtengel (options) {return new Regtengel(this.Context,this.Camera,options);}

	Scene (Image) {return new Scene(this.Canvas,this.Context,this.Camera,Image);}

	Tileset (options) {return new Tileset(this.Canvas,this.Context,this.Camera,options);}

	Sprite (options) {return new Sprite(this.Canvas,this.Context,this.Camera,options);}

	TileMap (options) {return new TileMap(this.Canvas,this.Context,this.Camera,options);}

	run(game) {
		this.then = Date.now();
		this.game = game;
		this.game.init(this.$global);
		this.loop();
	}

	loop(){
		this.setDelta();
		this.game.update(this.$global);
		this.Context.clearRect(0, 0, this.Canvas.width, this.Canvas.height);
		this.game.draw(this.$global);
		window.requestAnimationFrame(this.loop.bind(this));
	}

	setDelta() {
        this.now = Date.now();
        this.delta = (this.now - this.then) / 1000; // seconds since last frame
        this.then = this.now;
    }

	static random(a, b) {
		return Math.floor(Math.random() * b) + a;
	}

}

class Camera {

	constructor(width,height) {
		this.X = 0;
		this.Y = 0;
		this.width = width;
		this.height = height;
		this.MaxW = width;
		this.MaxH = height;
		this.Speed = 10;
		this.MinX = 0;
		this.MinY = 0;

	}

    fallow(GameObject) {

        var currentX = (GameObject.x - (this.X + (this.width / 2))) + this.X;
        var currentY = (GameObject.y - (this.Y + (this.height / 2))) + this.Y;

        if (currentX >= this.MinX && currentX <= this.MaxW - this.width) {
            this.X = currentX;
        }

        if (currentY >= this.MinY && currentY <= this.MaxH - this.height) {
            this.Y = currentY;
        }

    }

};

class GameObject {
	constructor(Context,Camera,options) {
		this.Context = Context
		this.Camera = Camera
		this.w = options.width;
        this.h = options.height;
        this.speed = options.Speed;
        this.x = options.X;
        this.y = options.Y;

	}

	draw() {}
}

class Regtengel extends GameObject {
	constructor(Context,Camera,options) {
		super(Context,Camera, options);
		this.Color =  options.Color || "#E88813" ;
	}

	draw() {
        this.Context.fillStyle = this.Color;
        this.Context.fillRect(this.x - this.Camera.X, this.y - this.Camera.Y, this.w, this.h);
    }
}

class Text extends GameObject {
	constructor(Context,Camera,options) {
		super(Context,Camera, options);
		this.Color =  options.Color || "#E88813" ;
		this.font = options.font || "30px Arial";;
        this.message = options.message || "";
	}

    draw () {
        this.Context.font = this.font;
        this.Context.fillStyle = this.Color;
        this.Context.fillText(this.message, this.x, this.y);

    };

}

class Sprite extends GameObject {

	constructor(Canvas,Context,Camera,options) {
		super(Context,Camera, options);
        this.tileset = options.tileset;
		this.tileIndex = options.tileIndex;
		this.tileset.x = this.x
		this.tileset.y = this.y
	}

    draw () {
		this.tileset.x = this.x - this.Camera.X;
		this.tileset.y = this.y - this.Camera.Y;
		this.tileset.draw(this.tileIndex)
    }
}

class Scene  {

	constructor(Canvas,Context,Camera,Image) {
		this.Canvas	= Canvas;
		this.Context = Context
		this.Camera = Camera
		this.Image =  Image;
		this.w = this.Image.width;
        this.h = this.Image.height;
		this.speed =  50;

	}

    draw () {

        this.Context.drawImage(
        this.Image,
       (this.Camera.X * this.speed) / 100,
       (this.Camera.Y * this.speed) / 100,
        this.Canvas.width,
        this.Canvas.height,
        0,
        0,
        this.Canvas.width,
        this.Canvas.height);

    }

};

class SpriteCollaction {

	constructor() {
        this.SpriteArray = [];
	}

    add (sprite) {
          this.SpriteArray.push(sprite);
    }

    each (f) {

        for (var i = 0; i < this.SpriteArray.length; i++) {
            let s = this.SpriteArray[i];
            f(s);
		}

   }

   eachWhitIndex (f) {

        for (var i = 0; i < this.SpriteArray.length; i++) {
            let s = this.SpriteArray[i];
            f(s, i);
        }

   }

    remove (sprite) {

        for (var i = this.SpriteArray.length - 1; i >= 0; i--) {

            if (this.SpriteArray[i] == sprite) {
                this.SpriteArray.splice(i, 1);
            }
        }
    }

    draw() {

        for (var i = 0; i < this.SpriteArray.length; i++) {
              this.SpriteArray[i].draw();
        }

    };

    get (index) {

        return this.SpriteArray[index];

    }

    checkCollision (x1, y1, w1, h1, x2, y2, w2, h2) {
        if (x1 + w1 > x2 && x2 + w2 > x1 && y1 + h1 > y2 && y2 + h2 > y1) { return true; }
        return false;
    }

}

class Tileset {

	constructor(Canvas,Context,Camera,options) {
		this.image = options.image;
        this.cols = options.cols;
        this.rows = options.rows;
		this.tileSize = options.tileSize;

		this.Context = Context;
		this.Camera = Camera;
		this.x = 0;
		this.y = 0;
	}

    getCoordinate (value) {

		var xy = {};

		if(value == this.rows * this.cols)
		{
				xy.y = this.rows -1
				xy.x = this.cols -1
		}

		if(value > this.cols)
		{

			if(value % this.cols > 0)
			{
				xy.y = Math.floor(value / this.cols);
				xy.x = value % this.cols -1;
			}
			else
			{
				xy.y = Math.floor(value / this.cols)-1;
				xy.x = this.cols-1;
			}

		}
		else
		{
			xy.y = 0
			xy.x = value -1;
		}

        return xy;
    }

    draw (tileIndex) {

		var Cor = this.getCoordinate(tileIndex)
		this.Context.drawImage(
		this.image,
		Cor.x * this.tileSize,
		Cor.y * this.tileSize,
		this.tileSize,
		this.tileSize,
		this.x,
		this.y,
		this.tileSize,
		this.tileSize);

    }

}

class TileMap {

    constructor(Canvas,Context,Camera,options) {

        this.cols = options.map.cols;
        this.rows = options.map.rows;
        this.tiles = options.map.tiles;
		this.Canvas	= Canvas;
		this.Context = Context
		this.Camera = Camera
        this.Collaction = new SpriteCollaction();
		this.tileset = options.tileset;

        this.Camera.MaxW = this.cols * this.tileset.tileSize;
        this.Camera.MaxH = this.rows * this.tileset.tileSize;

        for (var c = 0; c < this.cols; c++) {
            for (var r = 0; r < this.rows; r++) {
                var tile = this.GetTile(c, r);
                if (tile !== 0) {

                    this.Collaction.add(

						new Sprite(this.Canvas,this.Context,this.Camera,{
							X: c * this.tileset.tileSize,
							Y: r * this.tileset.tileSize,
							Speed:100,
							tileset: this.tileset,
							tileIndex: tile})
						);

                }
            }
        }

    }

    GetTile (col, row) {
        return this.tiles[row * this.cols + col];
    }

    SetTile (col, row, value) {
        this.tiles[row * this.cols + col] = value;
    }

    Remove (col, row) {

        this.SetTile(col, row, 0);
        //Kumiho.TileMap.Collction.Remove();

    }

    Draw () {

        this.Collaction.draw();

    }

};

    AnimatedSprite: function(options) {
        var that = {};

        that.Speed = options.Speed;
        that.X = options.X;
        that.Y = options.Y;

        that.Animations = [];
        that.CurrentAnimation = 0;

        that.AddAnimation = function(Animation) {
            that.Animations.push(Animation);
        };

        that.length = function() {
            return that.Animations.length;
        };

        that.update = function() {

            that.Animations[that.CurrentAnimation].update();

        };

        that.Draw = function() {
            that.Animations[that.CurrentAnimation].render(that.X, that.Y);
        };

        return that;
    },

    Animatiton: function(options) {

        var that = {},
            frameIndex = 0,
            currentposition = 0,
            LastFrame = false;

        that.numberOfFrames = options.numberOfFrames || 1;
        that.width = options.width;
        that.height = options.height;
        that.image = options.image;
        that.Loop = options.Loop;
        that.Index = options.Index;
        that.ticksPerSec = options.ticksPerSec;

        that.update = function() {
            currentposition += Kumiho.delta;
            if (currentposition > (that.numberOfFrames / that.ticksPerSec)) { currentposition = currentposition - (that.numberOfFrames / that.ticksPerSec) }
        };

        that.render = function(x, y) {

            frameIndex = Math.floor(currentposition * that.ticksPerSec);

            Kumiho.GameObject.Context.drawImage(
                that.image,
                frameIndex * that.width,
                that.Index * that.height,
                that.width,
                that.height,
                x,
                y,
                that.width,
                that.height);
        };

        return that;
    },

<|endoftext|>


<commit_before>import webpack from 'webpack'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import CleanWebpackPlugin from 'clean-webpack-plugin'
import ManifestPlugin from 'webpack-manifest-plugin'
import OfflinePlugin from 'offline-plugin'
import path from 'path'
import config from '../utils/config'
import baseConfig from './base.config.js'

const { NODE_ENV = 'staging' } = process.env

module.exports = {
  ...baseConfig,
  mode: 'production',
  devtool: 'source-map',
  plugins: [
    config('serviceWorker.enabled') && new OfflinePlugin(),
    config('cleanOnBuild') && new CleanWebpackPlugin(baseConfig.output.path, { root: path.join(__dirname, '..', '..') }),
    new ManifestPlugin(),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(NODE_ENV),
    }),
  ].filter(n => !!n),
  performance: {
    hints: false,
  },
  optimization: {
    minimize: true,
    splitChunks: {
      cacheGroups: {
        commons: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
        },
      },
    },
  },
}
<commit_msg>enable html-webpack-plugin for production<commit_after>import webpack from 'webpack'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import CleanWebpackPlugin from 'clean-webpack-plugin'
import ManifestPlugin from 'webpack-manifest-plugin'
import OfflinePlugin from 'offline-plugin'
import path from 'path'
import config from '../utils/config'
import baseConfig from './base.config.js'

const { NODE_ENV = 'staging' } = process.env

module.exports = {
  ...baseConfig,
  mode: 'production',
  devtool: 'source-map',
  plugins: [
    config('serviceWorker.enabled') && new OfflinePlugin(),
    config('cleanOnBuild') && new CleanWebpackPlugin(baseConfig.output.path, { root: path.join(__dirname, '..', '..') }),
    new HtmlWebpackPlugin({
      inject: true,
      template: path.join(__dirname, '..', 'utils', 'devTemplate.js'),
    }),
    new ManifestPlugin(),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(NODE_ENV),
    }),
  ].filter(n => !!n),
  performance: {
    hints: false,
  },
  optimization: {
    minimize: true,
    splitChunks: {
      cacheGroups: {
        commons: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
        },
      },
    },
  },
}
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import SectionLayout from './Layouts/Section'
import { connect } from 'react-redux'
import CopyToClipboard from 'react-copy-to-clipboard'
import { Button } from 'reactstrap'
import _ from 'lodash'

import { fetchPendingChanges } from '../modules/versioning'

const OSX = 'Mac'
const WIN = 'Win'
const LNX = 'Linux'

const BP_COMMAND = {
  [OSX]: 'darwin command',
  [WIN]: 'windows command',
  [LNX]: 'linux command',
}

class Versioning extends Component {
  state = {
    command: BP_COMMAND[OSX]
  }

  componentDidMount() {
    this.props.fetchPendingChanges()
    this.setBPcommandFromOs()
  }

  setBPcommandFromOs = () => {
    let os = ""
    if (navigator.appVersion.indexOf(WIN) != -1) {
      os = WIN
    } else if (navigator.appVersion.indexOf(OSX) != -1) {
      os = OSX
    } else if (navigator.appVersion.indexOf(LNX) != -1) {
      os = LNX
    }

    this.setState({ command: BP_COMMAND[os] })
  }

  renderMainContent = () => (

      {
        this.props.loading &&
loading

      }
      {
        !this.props.loading && _.isEmpty(this.props.pendingChanges) &&
you're all set

      }
      {
        !this.props.loading && !_.isEmpty(this.props.pendingChanges) &&

Some changes has been made since this server was deployed. Run the botpress pull command to sync server data locally

            {this.state.command}

          <CopyToClipboard text={this.state.command}>
            <Button color="link" size="sm" className="license-infos__icon">
              <svg href="#" id="TooltipCopy" height="15" viewBox="0 0 16 20" xmlns="http://www.w3.org/2000/svg">
                <path
                  d="M3.996 0H16v16h-4.004v4H0V4h3.996V0zM6 2v12h8V2H6zM2 6v12h8v-1.997H3.998V6H2z"
                  fill="#4A4A4A"
                  fillRule="evenodd"
                />
              </svg>
            </Button>
          </CopyToClipboard>

      }

  )

  render() {
    return (
      <SectionLayout
        title="Versioning"
        helpText="Changes on your server"
        activePage="versioning"
        mainContent={this.renderMainContent()}
      />
    )
  }
}

const mapStateToProps = (state) => ({
  ...state.versioning
})

export default connect(mapStateToProps, { fetchPendingChanges })(Versioning)<commit_msg>display command<commit_after>import React, { Component } from 'react'
import SectionLayout from './Layouts/Section'
import { connect } from 'react-redux'
import CopyToClipboard from 'react-copy-to-clipboard'
import { Button } from 'reactstrap'
import _ from 'lodash'

import { fetchPendingChanges } from '../modules/versioning'
import { pullToken } from '../Auth'

class Versioning extends Component {
  state = {
    command: ''
  }

  componentDidMount() {
    this.props.fetchPendingChanges()
    this.setPullCommand()
  }

  setPullCommand = () => {
    let bpcli = navigator.appVersion.indexOf("Win") !== -1 ? "bp.exe" : "bp"

    const { token } = pullToken()
    const host = window.location.origin
    const command = `${bpcli} pull --host ${host} --target { YOUR_DATA_TARGET_DIR } --auth ${token}`
    this.setState({ command })
  }

  renderMainContent = () => (

      {
        this.props.loading &&
loading

      }
      {
        !this.props.loading && _.isEmpty(this.props.pendingChanges) &&
you're all set

      }
      {
        !this.props.loading && !_.isEmpty(this.props.pendingChanges) &&

Some changes has been made since this server was deployed. Run the botpress pull command to sync server data locally

            {this.state.command}

          <CopyToClipboard text={this.state.command}>
            <Button color="link" size="sm" className="license-infos__icon">
              <svg href="#" id="TooltipCopy" height="15" viewBox="0 0 16 20" xmlns="http://www.w3.org/2000/svg">
                <path
                  d="M3.996 0H16v16h-4.004v4H0V4h3.996V0zM6 2v12h8V2H6zM2 6v12h8v-1.997H3.998V6H2z"
                  fill="#4A4A4A"
                  fillRule="evenodd"
                />
              </svg>
            </Button>
          </CopyToClipboard>

      }

  )

  render() {
    return (
      <SectionLayout
        title="Versioning"
        helpText="Changes on your server"
        activePage="versioning"
        mainContent={this.renderMainContent()}
      />
    )
  }
}

const mapStateToProps = (state) => ({
  ...state.versioning
})

export default connect(mapStateToProps, { fetchPendingChanges })(Versioning)<|endoftext|>