<commit_before>/**
 * @flow
 * @Author: Wahaj Shamim <wahaj>
 * @Date:   2018-02-15T15:05:45+11:00
 * @Email:  inbox.wahaj@gmail.com
 * @Last modified by:   mike
 * @Last modified time: 2018-02-19T14:55:25+11:00
 *
 * dbKoda - a modern, open source code editor, for MongoDB.
 * Copyright (C) 2017-2018 Southbank Software
 *
 * This file is part of dbKoda.
 *
 * dbKoda is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * dbKoda 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
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with dbKoda.  If not, see <http://www.gnu.org/licenses/>.
 */

function timescale(num: number, a, b) {
  if (isNaN(num)) {
    throw new TypeError('expected a number');
  }
  return num * unitTimeValue(a) / unitTimeValue(b);
}

function unitTimeValue(name) {
  switch (name) {
    case 'ns':
      return 1;
    case 'μs':
    case 'us':
      return 1e3;
    case 'ms':
      return 1e6;
    case 's':
      return 1e9;
    case 'm':
      return 6e10;
    case 'h':
      return 36e11;
    case 'd':
      return 864e11;
    case 'w':
      return 6048e11;
    default: {
      throw new Error('"' + name + '" is not a valid unit of time.');
    }
  }
}
export const convertTime = (value: any, unit: string, length: number) => {
  const result = {
    value,
    unit
  };
  if (String(Math.round(value)).length > length) {
    switch (unit) {
      case '/μs':
        result.unit = '/ms';
        result.value = timescale(value, 'μs', 'ms').toFixed(2);
        break;
      case '/ms':
        result.unit = '/s';
        result.value = timescale(value, 'ms', 's').toFixed(2);
        break;
      case '/s':
        result.unit = '/m';
        result.value = timescale(value, 's', 'm').toFixed(2);
        break;
      case '/m':
        result.unit = '/h';
        result.value = timescale(value, 'm', 'h').toFixed(2);
        break;
      case '/h':
        result.unit = '/d';
        result.value = timescale(value, 'h', 'd').toFixed(2);
        break;
      case 'μs/s':
        result.unit = 'ms/s';
        result.value = timescale(value, 'μs', 'ms').toFixed(2);
        break;
      case 'ms/s':
        result.unit = 's/s';
        result.value = timescale(value, 'ms', 's').toFixed(2);
        break;
      default: {
        console.error('"' + unit + '" is not a valid unit of time.');
        return result;
      }
    }
    return convertTime(result.value, result.unit, length);
  }
  result.value = parseFloat(Number(value).toFixed(2));
  return result;
};

export const convertBytes = (value: any, unit: string, length: number) => {
  const result = {
    value,
    unit
  };
  if (String(Math.round(value)).length > length) {
    switch (unit) {
      case 'b':
        result.unit = 'kb';
        break;
      case 'kb':
        result.unit = 'mb';
        break;
      case 'mb':
        result.unit = 'gb';
        break;
      case 'gb':
        result.unit = 'tb';
        break;
      case 'tb':
        result.unit = 'pb';
        break;
      case 'pb':
        result.unit = 'eb';
        break;
      default: {
        console.error('"' + unit + '" is the maximum supported unit of bytes.');
        return result;
      }
    }
    result.value = (value / 1024).toFixed(2);
    return convertBytes(result.value, result.unit, length);
  }
  return result;
};

export const convertUnits = (value: any, unit: string, length: number) => {
  if ('ms/s|μs/s|/μs|/us|/ms|/s|/m|/h'.indexOf(unit) >= 0) {
    return convertTime(value, unit, length);
  } else if ('b|kb|mb|gb|tb|pb|eb'.indexOf(unit) >= 0) {
    return convertBytes(value, unit, length);
  }
  console.log('Unknown unit is provided for conversion (unit=', unit, ').');
  return {
    value: parseFloat(Number(value).toFixed(2)),
    unit
  };
};

export const hofUnitFormatter = (unit: string, length: number) => {
  const unitFormatter = value => {
    const result = convertUnits(value, unit, length);
    return result.value + ' ' + result.unit;
  };
  return unitFormatter;
};
<commit_msg>Flow Fix.<commit_after>/**
 * @flow
 * @Author: Wahaj Shamim <wahaj>
 * @Date:   2018-02-15T15:05:45+11:00
 * @Email:  inbox.wahaj@gmail.com
 * @Last modified by:   mike
 * @Last modified time: 2018-02-19T14:55:25+11:00
 *
 * dbKoda - a modern, open source code editor, for MongoDB.
 * Copyright (C) 2017-2018 Southbank Software
 *
 * This file is part of dbKoda.
 *
 * dbKoda is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * dbKoda 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
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with dbKoda.  If not, see <http://www.gnu.org/licenses/>.
 */

function timescale(num: number, a, b) {
  if (isNaN(num)) {
    throw new TypeError('expected a number');
  }
  return num * unitTimeValue(a) / unitTimeValue(b);
}

function unitTimeValue(name) {
  switch (name) {
    case 'ns':
      return 1;
    case 'μs':
    case 'us':
      return 1e3;
    case 'ms':
      return 1e6;
    case 's':
      return 1e9;
    case 'm':
      return 6e10;
    case 'h':
      return 36e11;
    case 'd':
      return 864e11;
    case 'w':
      return 6048e11;
    default: {
      throw new Error('"' + name + '" is not a valid unit of time.');
    }
  }
}
export const convertTime = (value: any, unit: string, length: number) => {
  const result = {
    value,
    unit
  };
  if (String(Math.round(value)).length > length) {
    switch (unit) {
      case '/μs':
        result.unit = '/ms';
        result.value = timescale(value, 'μs', 'ms').toFixed(2);
        break;
      case '/ms':
        result.unit = '/s';
        result.value = timescale(value, 'ms', 's').toFixed(2);
        break;
      case '/s':
        result.unit = '/m';
        result.value = timescale(value, 's', 'm').toFixed(2);
        break;
      case '/m':
        result.unit = '/h';
        result.value = timescale(value, 'm', 'h').toFixed(2);
        break;
      case '/h':
        result.unit = '/d';
        result.value = timescale(value, 'h', 'd').toFixed(2);
        break;
      case 'μs/s':
        result.unit = 'ms/s';
        result.value = timescale(value, 'μs', 'ms').toFixed(2);
        break;
      case 'ms/s':
        result.unit = 's/s';
        result.value = timescale(value, 'ms', 's').toFixed(2);
        break;
      default: {
        console.error('"' + unit + '" is not a valid unit of time.');
        return result;
      }
    }
    return convertTime(result.value, result.unit, length);
  }
  result.value = parseFloat(Number(value).toFixed(2));
  return result;
};

export const convertBytes = (value: any, unit: string, length: number) => {
  const result = {
    value,
    unit
  };
  if (String(Math.round(value)).length > length) {
    switch (unit) {
      case 'b':
        result.unit = 'kb';
        break;
      case 'kb':
        result.unit = 'mb';
        break;
      case 'mb':
        result.unit = 'gb';
        break;
      case 'gb':
        result.unit = 'tb';
        break;
      case 'tb':
        result.unit = 'pb';
        break;
      case 'pb':
        result.unit = 'eb';
        break;
      default: {
        console.error('"' + unit + '" is the maximum supported unit of bytes.');
        return result;
      }
    }
    result.value = (value / 1024).toFixed(2);
    return convertBytes(result.value, result.unit, length);
  }
  return result;
};

export const convertUnits = (value: any, unit: string, length: number) => {
  if ('ms/s|μs/s|/μs|/us|/ms|/s|/m|/h'.indexOf(unit) >= 0) {
    return convertTime(value, unit, length);
  } else if ('b|kb|mb|gb|tb|pb|eb'.indexOf(unit) >= 0) {
    return convertBytes(value, unit, length);
  }
  console.log('Unknown unit is provided for conversion (unit=', unit, ').');
  return {
    value: parseFloat(Number(value).toFixed(2)),
    unit
  };
};

export const hofUnitFormatter = (unit: string, length: number) => {
  // $FlowFixMe
  const unitFormatter = value => {
    const result = convertUnits(value, unit, length);
    return result.value + ' ' + result.unit;
  };
  return unitFormatter;
};
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react'
import CDGCanvas from './CDGCanvas'
import classes from './CDGPlayer.css'

class CDGPlayer extends React.Component {
  static propTypes = {
    width: PropTypes.number.isRequired,
    height: PropTypes.number.isRequired,
    volume: PropTypes.number.isRequired,
    isPlaying: PropTypes.bool.isRequired,
    song: PropTypes.object.isRequired,
    getMedia: PropTypes.func.isRequired, // action
    getMediaSuccess: PropTypes.func.isRequired, // action
    onMediaError: PropTypes.func.isRequired, // action
    onMediaEnd: PropTypes.func.isRequired, // action
    onStatus: PropTypes.func.isRequired, // action
  }

  state = {
    audioPos: 0, // ms
  }

  isAudioLoaded = false
  isCDGLoaded = false
  cdgData = []

  componentDidMount () {
    this.updateSources()
    this.setVolume(this.props.volume)
  }

  componentDidUpdate (prevProps) {
    if (prevProps.song !== this.props.song) {
      this.updateSources()
    }

    if (prevProps.isPlaying !== this.props.isPlaying) {
      this.updateIsPlaying()
    }

    if (prevProps.volume !== this.props.volume) {
      this.setVolume(this.props.volume)
    }
  }

  render () {
    const { width, height } = this.props
    let canvasScale = Math.floor(width / 300)

    // make sure height would fit the viewport's
    while (height < canvasScale * 300 * .72) {
      canvasScale -= 1
    }

    return (

        <CDGCanvas
          width={canvasScale * 300}
          height={canvasScale * 300 * .72}
          isPlaying={this.props.isPlaying}
          audioPos={this.state.audioPos}
          cdgData={this.cdgData}
        />

        <audio src={'/api/provider/cdg/resource?type=audio&songId='+this.props.song.songId}
          preload='none'
          onCanPlayThrough={this.handleOnCanPlayThrough}
          onTimeUpdate={this.handleOnTimeUpdate}
          onEnded={this.props.onMediaEnd}
          onError={this.handleAudioError}
          ref={(c) => {this.audio = c}}
          controls
        />

    )
  }

  updateSources = () => {
    // notification
    this.props.getMedia(this.audio.src)

    // tell audio element its source updated
    this.audio.load()

    // get cdgData
    const url = '/api/provider/cdg/resource?type=cdg&songId='+this.props.song.songId

    // notification
    this.props.getMedia(this.url)

    fetch(url, fetchConfig)
      .then(checkStatus)
      .then(res => res.arrayBuffer())
      .then(res => {
        // arrayBuffer to Uint8Array to standard Array
        this.cdgData = Array.from(new Uint8Array(res))
      }).then(() => { this.handleOnCdgLoaded() })
      .catch((err) => {
        this.props.onMediaError(err.message)
      })
  }

  setVolume(vol) {
    this.audio.volume = vol
  }

/**
 * <audio> event handlers
 */
  updateIsPlaying = () => {
    if (this.props.isPlaying) {
      this.audio.play()
    } else {
      this.audio.pause()
    }
  }

  handleOnCanPlayThrough = () => {
    this.isAudioLoaded = true

    if (this.isCDGLoaded) {
      this.props.getMediaSuccess()
      this.updateIsPlaying()
    }
  }

  handleOnTimeUpdate = () => {
    this.setState({
      audioPos: this.audio.currentTime * 1000
    })

    this.props.onStatus({
      isPlaying: !this.audio.paused,
      position: this.audio.currentTime,
      volume: this.audio.volume,
    })
  }

  handleAudioError = (err) => {
    this.props.onMediaError('Could not load audio (error '+err.target.error.code+')')
  }

  /**
   * CDGPlayer event handlers
   */
  handleOnCdgLoaded = () => {
    this.isCDGLoaded = true

    if (this.isAudioLoaded) {
      this.props.getMediaSuccess()
      this.updateIsPlaying()
    }
  }
}

export default CDGPlayer

// helpers for fetch response
const fetchConfig = {
  headers: new Headers({
    'Content-Type': 'application/json'
  }),
  // include the cookie that contains our JWT
  credentials: 'same-origin'
}

function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response
  } else {
    return response.text().then((txt) => {
      var error = new Error(txt)
      error.response = response
      throw error
    })
  }
}
<commit_msg>Remove visible HTML audio element controls<commit_after>import React, { PropTypes } from 'react'
import CDGCanvas from './CDGCanvas'
import classes from './CDGPlayer.css'

class CDGPlayer extends React.Component {
  static propTypes = {
    width: PropTypes.number.isRequired,
    height: PropTypes.number.isRequired,
    volume: PropTypes.number.isRequired,
    isPlaying: PropTypes.bool.isRequired,
    song: PropTypes.object.isRequired,
    getMedia: PropTypes.func.isRequired, // action
    getMediaSuccess: PropTypes.func.isRequired, // action
    onMediaError: PropTypes.func.isRequired, // action
    onMediaEnd: PropTypes.func.isRequired, // action
    onStatus: PropTypes.func.isRequired, // action
  }

  state = {
    audioPos: 0, // ms
  }

  isAudioLoaded = false
  isCDGLoaded = false
  cdgData = []

  componentDidMount () {
    this.updateSources()
    this.setVolume(this.props.volume)
  }

  componentDidUpdate (prevProps) {
    if (prevProps.song !== this.props.song) {
      this.updateSources()
    }

    if (prevProps.isPlaying !== this.props.isPlaying) {
      this.updateIsPlaying()
    }

    if (prevProps.volume !== this.props.volume) {
      this.setVolume(this.props.volume)
    }
  }

  render () {
    const { width, height } = this.props
    let canvasScale = Math.floor(width / 300)

    // make sure height would fit the viewport's
    while (height < canvasScale * 300 * .72) {
      canvasScale -= 1
    }

    return (

        <CDGCanvas
          width={canvasScale * 300}
          height={canvasScale * 300 * .72}
          isPlaying={this.props.isPlaying}
          audioPos={this.state.audioPos}
          cdgData={this.cdgData}
        />

        <audio src={'/api/provider/cdg/resource?type=audio&songId='+this.props.song.songId}
          preload='none'
          onCanPlayThrough={this.handleOnCanPlayThrough}
          onTimeUpdate={this.handleOnTimeUpdate}
          onEnded={this.props.onMediaEnd}
          onError={this.handleAudioError}
          ref={(c) => {this.audio = c}}
        />

    )
  }

  updateSources = () => {
    // notification
    this.props.getMedia(this.audio.src)

    // tell audio element its source updated
    this.audio.load()

    // get cdgData
    const url = '/api/provider/cdg/resource?type=cdg&songId='+this.props.song.songId

    // notification
    this.props.getMedia(this.url)

    fetch(url, fetchConfig)
      .then(checkStatus)
      .then(res => res.arrayBuffer())
      .then(res => {
        // arrayBuffer to Uint8Array to standard Array
        this.cdgData = Array.from(new Uint8Array(res))
      }).then(() => { this.handleOnCdgLoaded() })
      .catch((err) => {
        this.props.onMediaError(err.message)
      })
  }

  setVolume(vol) {
    this.audio.volume = vol
  }

/**
 * <audio> event handlers
 */
  updateIsPlaying = () => {
    if (this.props.isPlaying) {
      this.audio.play()
    } else {
      this.audio.pause()
    }
  }

  handleOnCanPlayThrough = () => {
    this.isAudioLoaded = true

    if (this.isCDGLoaded) {
      this.props.getMediaSuccess()
      this.updateIsPlaying()
    }
  }

  handleOnTimeUpdate = () => {
    this.setState({
      audioPos: this.audio.currentTime * 1000
    })

    this.props.onStatus({
      isPlaying: !this.audio.paused,
      position: this.audio.currentTime,
      volume: this.audio.volume,
    })
  }

  handleAudioError = (err) => {
    this.props.onMediaError('Could not load audio (error '+err.target.error.code+')')
  }

  /**
   * CDGPlayer event handlers
   */
  handleOnCdgLoaded = () => {
    this.isCDGLoaded = true

    if (this.isAudioLoaded) {
      this.props.getMediaSuccess()
      this.updateIsPlaying()
    }
  }
}

export default CDGPlayer

// helpers for fetch response
const fetchConfig = {
  headers: new Headers({
    'Content-Type': 'application/json'
  }),
  // include the cookie that contains our JWT
  credentials: 'same-origin'
}

function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response
  } else {
    return response.text().then((txt) => {
      var error = new Error(txt)
      error.response = response
      throw error
    })
  }
}
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react'
import CDGCanvas from './CDGCanvas'
import classes from './CDGPlayer.css'

class CDGPlayer extends React.Component {
  static propTypes = {
    width: PropTypes.number.isRequired,
    height: PropTypes.number.isRequired,
    queueId: PropTypes.number.isRequired,
    volume: PropTypes.number.isRequired,
    isPlaying: PropTypes.bool.isRequired,
    item: PropTypes.object.isRequired,
    getMedia: PropTypes.func.isRequired, // action
    getMediaSuccess: PropTypes.func.isRequired, // action
    onMediaError: PropTypes.func.isRequired, // action
    onMediaEnd: PropTypes.func.isRequired, // action
    onStatus: PropTypes.func.isRequired, // action
  }

  state = {
    audioPos: 0, // ms
  }

  isAudioLoaded = false
  isCDGLoaded = false
  cdgData = []

  componentDidMount () {
    this.updateSources()
  }

  componentDidUpdate (prevProps) {
    if (prevProps.queueId !== this.props.queueId) {
      this.updateSources()
    }

    if (prevProps.isPlaying !== this.props.isPlaying) {
      this.updateIsPlaying()
    }

    if (prevProps.volume !== this.props.volume) {
      this.setVolume(this.props.volume)
    }
  }

  render () {
    const { width, height } = this.props
    let canvasScale = Math.floor(width / 300)

    // make sure height would fit the viewport's
    while (height < canvasScale * 300 * .72) {
      canvasScale -= 1
    }

    return (

        <CDGCanvas
          width={canvasScale * 300}
          height={canvasScale * 300 * .72}
          isPlaying={this.props.isPlaying}
          audioPos={this.state.audioPos}
          cdgData={this.cdgData}
        />

        <audio src={'/api/provider/cdg/resource?type=audio&songId='+this.props.item.songId}
          preload='none'
          onCanPlayThrough={this.handleOnCanPlayThrough}
          onTimeUpdate={this.handleOnTimeUpdate}
          onEnded={this.props.onMediaEnd}
          onError={this.handleAudioError}
          ref={(c) => {this.audio = c}}
          controls
        />

    )
  }

  updateSources = () => {
    // notification
    this.props.getMedia(this.audio.src)

    // tell audio element its source updated
    this.audio.load()

    // get cdgData
    const url = '/api/provider/cdg/resource?type=cdg&songId='+this.props.item.songId

    // notification
    this.props.getMedia(this.url)

    fetch(url, fetchConfig)
      .then(checkStatus)
      .then(res => res.arrayBuffer())
      .then(res => {
        // arrayBuffer to Uint8Array to standard Array
        this.cdgData = Array.from(new Uint8Array(res))
      }).then(() => { this.handleOnCdgLoaded() })
      .catch((err) => {
        this.props.onMediaError(this.props.queueId, err.message)
      })
  }

  setVolume(vol) {
    this.audio.volume = vol
  }

/**
 * <audio> event handlers
 */
  updateIsPlaying = () => {
    if (this.props.isPlaying) {
      this.audio.play()
    } else {
      this.audio.pause()
    }
  }

  handleOnCanPlayThrough = () => {
    this.isAudioLoaded = true

    if (this.isCDGLoaded) {
      this.props.getMediaSuccess()
      this.updateIsPlaying()
    }
  }

  handleOnTimeUpdate = () => {
    this.setState({
      audioPos: this.audio.currentTime * 1000
    })

    this.props.onStatus({
      queueId: this.props.queueId,
      isPlaying: !this.audio.paused,
      position: this.audio.currentTime,
      volume: this.audio.volume,
    })
  }

  handleAudioError = (err) => {
    this.props.onMediaError(this.props.queueId,
      'The audio file could not be loaded (error code '+err.target.error.code+')'
    )
  }

  /**
   * CDGPlayer event handlers
   */
  handleOnCdgLoaded = () => {
    this.isCDGLoaded = true

    if (this.isAudioLoaded) {
      this.props.getMediaSuccess()
      this.updateIsPlaying()
    }
  }
}

export default CDGPlayer

// helpers for fetch response
const fetchConfig = {
  headers: new Headers({
    'Content-Type': 'application/json'
  }),
  // include the cookie that contains our JWT
  credentials: 'same-origin'
}

function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response
  } else {
    return response.text().then((txt) => {
      var error = new Error(txt)
      error.response = response
      throw error
    })
  }
}
<commit_msg>Bring CDG player up to speed<commit_after>import React, { PropTypes } from 'react'
import CDGCanvas from './CDGCanvas'
import classes from './CDGPlayer.css'

class CDGPlayer extends React.Component {
  static propTypes = {
    width: PropTypes.number.isRequired,
    height: PropTypes.number.isRequired,
    volume: PropTypes.number.isRequired,
    isPlaying: PropTypes.bool.isRequired,
    song: PropTypes.object.isRequired,
    getMedia: PropTypes.func.isRequired, // action
    getMediaSuccess: PropTypes.func.isRequired, // action
    onMediaError: PropTypes.func.isRequired, // action
    onMediaEnd: PropTypes.func.isRequired, // action
    onStatus: PropTypes.func.isRequired, // action
  }

  state = {
    audioPos: 0, // ms
  }

  isAudioLoaded = false
  isCDGLoaded = false
  cdgData = []

  componentDidMount () {
    this.updateSources()
  }

  componentDidUpdate (prevProps) {
    if (prevProps.song !== this.props.song) {
      this.updateSources()
    }

    if (prevProps.isPlaying !== this.props.isPlaying) {
      this.updateIsPlaying()
    }

    if (prevProps.volume !== this.props.volume) {
      this.setVolume(this.props.volume)
    }
  }

  render () {
    const { width, height } = this.props
    let canvasScale = Math.floor(width / 300)

    // make sure height would fit the viewport's
    while (height < canvasScale * 300 * .72) {
      canvasScale -= 1
    }

    return (

        <CDGCanvas
          width={canvasScale * 300}
          height={canvasScale * 300 * .72}
          isPlaying={this.props.isPlaying}
          audioPos={this.state.audioPos}
          cdgData={this.cdgData}
        />

        <audio src={'/api/provider/cdg/resource?type=audio&songId='+this.props.song.songId}
          preload='none'
          onCanPlayThrough={this.handleOnCanPlayThrough}
          onTimeUpdate={this.handleOnTimeUpdate}
          onEnded={this.props.onMediaEnd}
          onError={this.handleAudioError}
          ref={(c) => {this.audio = c}}
          controls
        />

    )
  }

  updateSources = () => {
    // notification
    this.props.getMedia(this.audio.src)

    // tell audio element its source updated
    this.audio.load()

    // get cdgData
    const url = '/api/provider/cdg/resource?type=cdg&songId='+this.props.song.songId

    // notification
    this.props.getMedia(this.url)

    fetch(url, fetchConfig)
      .then(checkStatus)
      .then(res => res.arrayBuffer())
      .then(res => {
        // arrayBuffer to Uint8Array to standard Array
        this.cdgData = Array.from(new Uint8Array(res))
      }).then(() => { this.handleOnCdgLoaded() })
      .catch((err) => {
        this.props.onMediaError(err.message)
      })
  }

  setVolume(vol) {
    this.audio.volume = vol
  }

/**
 * <audio> event handlers
 */
  updateIsPlaying = () => {
    if (this.props.isPlaying) {
      this.audio.play()
    } else {
      this.audio.pause()
    }
  }

  handleOnCanPlayThrough = () => {
    this.isAudioLoaded = true

    if (this.isCDGLoaded) {
      this.props.getMediaSuccess()
      this.updateIsPlaying()
    }
  }

  handleOnTimeUpdate = () => {
    this.setState({
      audioPos: this.audio.currentTime * 1000
    })

    this.props.onStatus({
      isPlaying: !this.audio.paused,
      position: this.audio.currentTime,
      volume: this.audio.volume,
    })
  }

  handleAudioError = (err) => {
    this.props.onMediaError('Could not load audio (error '+err.target.error.code+')')
  }

  /**
   * CDGPlayer event handlers
   */
  handleOnCdgLoaded = () => {
    this.isCDGLoaded = true

    if (this.isAudioLoaded) {
      this.props.getMediaSuccess()
      this.updateIsPlaying()
    }
  }
}

export default CDGPlayer

// helpers for fetch response
const fetchConfig = {
  headers: new Headers({
    'Content-Type': 'application/json'
  }),
  // include the cookie that contains our JWT
  credentials: 'same-origin'
}

function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response
  } else {
    return response.text().then((txt) => {
      var error = new Error(txt)
      error.response = response
      throw error
    })
  }
}
<|endoftext|>


<commit_before>!(function( angular ) {
  if ( !angular ) throw new ReferenceError( 'angularjs 1.5+ is required' );

  'use strict';
  angular.module( 'app' )
    .controller( 'eventTypeController', eventTypeController )
    .controller( 'formEventTypeController', formEventTypeController );

  function formEventTypeController( $log, $scope, $location, $routeParams, $q, eventTypeResource, uiAlert ) {
    const
      vm = this,
      { _id } = $routeParams;

    // ===# View Model #=== //
    vm.eventType = {};
    vm.alert = {};
    vm.alertEmitter = uiAlert( vm.alert );
    vm.submitForm = submitForm;

    // ===# Bootstraping data #=== //
    if ( _id ) {
      eventTypeResource
        .get( _id )
        .$promise
        .then( _eventType => vm.eventType = _eventType )
        .catch( error => vm.alertEmitter.danger( error.data ) );
    }

    // ===# Setup #===//
    function submitForm( eventType ) {
      if ( $scope.eventTypeForm.$invalid ) return;

      $q
        .resolve( eventType )
        .then( saveForm )
        .then( redirectToEventTypeList )
        .catch( error => vm.alertEmitter.danger( error.data ) );
    }

    function redirectToEventTypeList() {
      $location.path( '/event/types' );
    }

    function saveForm( eventType ) {
      if ( !_id ) return eventTypeResource.save( eventType );
      return eventTypeResource.update( eventType );
    }

  }

  function eventTypeController( $log, eventTypeResource ) {
    const vm = this;

    // ===# View Model ===# //
    vm.eventType = {};
    vm.setCurrentEventType = setCurrentEventType;
    vm.deleteEventType = deleteEventType;

    // ===# Bootstraping data #=== //
    vm.eventTypeList = eventTypeResource.query();

    // ===# Setup #=== //
    function setCurrentEventType( eventType ) {
      vm.eventType = eventType;
    }

    function deleteEventType( { _id } ) {
      if ( !_id ) return;

      eventTypeResource
        .logicalRemove( _id )
        .then( spliceEventType( _id ) )
        .catch( $log.error );
    }

    function spliceEventType( _id ) {
      return () => {
        vm.eventTypeList = vm.eventTypeList.filter( eventType => eventType._id !== _id );
      };
    }

  }
})( angular );<commit_msg>[UPDATE]: Adicionado construtor DataResource para prover os dados.<commit_after>!(function( angular ) {
  if ( !angular ) throw new ReferenceError( 'angularjs 1.5+ is required' );

  'use strict';
  angular.module( 'app' )
    .controller( 'eventTypeController', eventTypeController )
    .controller( 'formEventTypeController', formEventTypeController );

  function formEventTypeController( $log, $scope, $location, $routeParams, $q, uiAlert, DataResource ) {
    const
      vm = this,
      eventTypeResource = new DataResource( '/eventTypes', '/:_id' ),
      { _id } = $routeParams;

    // ===# View Model #=== //
    vm.eventType = {};
    vm.alert = {};
    vm.alertEmitter = uiAlert( vm.alert );
    vm.submitForm = submitForm;

    // ===# Bootstraping data #=== //
    if ( _id ) {
      eventTypeResource
        .get( _id )
        .$promise
        .then( _eventType => vm.eventType = _eventType )
        .catch( error => vm.alertEmitter.danger( error.data ) );
    }

    // ===# Setup #===//
    function submitForm( eventType ) {
      if ( $scope.eventTypeForm.$invalid ) return;

      $q
        .resolve( eventType )
        .then( saveForm )
        .then( redirectToEventTypeList )
        .catch( error => vm.alertEmitter.danger( error.data ) );
    }

    function redirectToEventTypeList() {
      $location.path( '/event/types' );
    }

    function saveForm( eventType ) {
      if ( !_id ) return eventTypeResource.save( eventType );
      return eventTypeResource.update( eventType );
    }

  }

  function eventTypeController( $log, DataResource ) {
    const
      vm = this,
      eventTypeResource = new DataResource( '/eventTypes', '/:_id' );

    // ===# View Model ===# //
    vm.eventType = {};
    vm.setCurrentEventType = setCurrentEventType;
    vm.deleteEventType = deleteEventType;

    // ===# Bootstraping data #=== //
    vm.eventTypeList = eventTypeResource.query();

    // ===# Setup #=== //
    function setCurrentEventType( eventType ) {
      vm.eventType = eventType;
    }

    function deleteEventType( { _id } ) {
      if ( !_id ) return;

      eventTypeResource
        .logicalRemove( _id )
        .then( spliceEventType( _id ) )
        .catch( $log.error );
    }

    function spliceEventType( _id ) {
      return () => {
        vm.eventTypeList = vm.eventTypeList.filter( eventType => eventType._id !== _id );
      };
    }

  }
})( angular );<|endoftext|>


<commit_before>Elm.Native.Scheduler = {};
Elm.Native.Scheduler.make = function(localRuntime)
{
	localRuntime.Native = localRuntime.Native || {};
	localRuntime.Native.Scheduler = localRuntime.Native.Scheduler || {};
	if (localRuntime.Native.Scheduler.values)
	{
		return localRuntime.Native.Scheduler.values;
	}

	var Utils = Elm.Native.Utils.make(localRuntime);

	var MAX_STEPS = 10000;

	// TASKS

	function succeed(value)
	{
		return {
			ctor: '_Task_succeed',
			value: value
		};
	}

	function fail(error)
	{
		return {
			ctor: '_Task_fail',
			value: error
		};
	}

	function nativeBinding(func, cancel)
	{
		return {
			ctor: '_Task_nativeBinding',
			func: func,
			cancel: cancel
		};
	}

	function andThen(task, callback)
	{
		return {
			ctor: '_Task_andThen',
			task: task,
			callback: callback
		};
	}

	function onError(task, callback)
	{
		return {
			ctor: '_Task_onError',
			task: task,
			callback: callback
		};
	}

	function receive(callback)
	{
		return {
			ctor: '_Task_receive',
			callback: callback
		};
	}

	// PROCESSES

	function spawn(task)
	{
		var process = {
			ctor: '_Process',
			_0: Utils.guid(),
			root: task,
			stack: null,
			mailbox: []
		}

		enqueue(process);

		return process;
	}

	function send(process, msg)
	{
		return nativeBinding(function(callback) {
			process.mailbox.push(msg);
			enqueue(process);
			callback(succeed(Utils.Tuple0));
		});
	}

	function kill(process)
	{
		var root = process.root;
		if (root.ctor === '_Task_nativeBinding' && root.cancel)
		{
			root.cancel();
		}

		process.root = null;

		return Utils.Tuple0;
	}

	function step(numSteps, process)
	{
		var root = process.root;
		var stack = process.stack;

		while (numSteps < MAX_STEPS)
		{
			var ctor = root.ctor;

			if (ctor === '_Task_succeed')
			{
				while (stack.ctor === '_Task_onError')
				{
					stack = stack.rest;
				}
				if (stack === null)
				{
					break;
				}
				root = stack.callback(root.value);
				stack = stack.rest;
				++numSteps;
				continue;
			}

			if (ctor === '_Task_fail')
			{
				while (stack.ctor === '_Task_andThen')
				{
					stack = stack.rest;
				}
				if (stack === null)
				{
					break;
				}
				root = stack.callback(root.value);
				stack = stack.rest;
				++numSteps;
				continue;
			}

			if (ctor === '_Task_andThen')
			{
				stack = {
					ctor: '_Task_andThen',
					callback: root.callback,
					rest: stack
				};
				root = root.task;
				++numSteps;
				continue;
			}

			if (ctor === '_Task_onError')
			{
				stack = {
					ctor: '_Task_onError',
					callback: root.callback,
					rest: stack
				};
				root = root.task;
				++numSteps;
				continue;
			}

			if (ctor === '_Task_nativeBinding')
			{
				root.func(function(newRoot) {
					process.root = newRoot;
					enqueue(process);
				});

				break;
			}

			if (ctor === '_Task_receive')
			{
				var mailbox = process.mailbox;
				if (mailbox.length === 0)
				{
					break;
				}

				var msg = mailbox.shift();
				root = root.callback(msg);
				++numSteps;
				continue;
			}
		}

		if (numSteps < MAX_STEPS)
		{
			return numSteps + 1;
		}

		process.root = root;
		process.stack = stack;
		enqueue(process);

		return numSteps;
	}

	// WORK QUEUE

	var workQueue = [];

	function enqueue(process)
	{
		workQueue.push(process);
	}

	function work()
	{
		var numSteps = 0;
		var process;
		while (numSteps < MAX_STEPS && (process = workQueue.shift()))
		{
			numSteps = step(numSteps, process);
		}
		if (!process)
		{
			return;
		}
		setTimeout(work, 0);
	}

	return localRuntime.Native.Scheduler.values = {
		succeed: succeed,
		fail: fail,
		nativeBinding: nativeBinding,
		andThen: F2(andThen),
		onError: F2(onError),

		spawn: spawn,
		kill: kill,
		send: F2(send),

		work: work
	};
};
<commit_msg>Get cancelation of native tasks working, make spawn/kill tasks<commit_after>Elm.Native.Scheduler = {};
Elm.Native.Scheduler.make = function(localRuntime)
{
	localRuntime.Native = localRuntime.Native || {};
	localRuntime.Native.Scheduler = localRuntime.Native.Scheduler || {};
	if (localRuntime.Native.Scheduler.values)
	{
		return localRuntime.Native.Scheduler.values;
	}

	var Utils = Elm.Native.Utils.make(localRuntime);

	var MAX_STEPS = 10000;

	// TASKS

	function succeed(value)
	{
		return {
			ctor: '_Task_succeed',
			value: value
		};
	}

	function fail(error)
	{
		return {
			ctor: '_Task_fail',
			value: error
		};
	}

	function nativeBinding(callback)
	{
		return {
			ctor: '_Task_nativeBinding',
			callback: callback,
			cancel: null
		};
	}

	function andThen(task, callback)
	{
		return {
			ctor: '_Task_andThen',
			task: task,
			callback: callback
		};
	}

	function onError(task, callback)
	{
		return {
			ctor: '_Task_onError',
			task: task,
			callback: callback
		};
	}

	function receive(callback)
	{
		return {
			ctor: '_Task_receive',
			callback: callback
		};
	}

	// PROCESSES

	function spawn(task)
	{
		return nativeBinding(function(callback) {
			var process = {
				ctor: '_Process',
				_0: Utils.guid(),
				root: task,
				stack: null,
				mailbox: []
			}

			enqueue(process);

			callback(succeed(process));
		};
	}

	function send(process, msg)
	{
		return nativeBinding(function(callback) {
			process.mailbox.push(msg);
			enqueue(process);
			callback(succeed(Utils.Tuple0));
		});
	}

	function kill(process)
	{
		return nativeBinding(function(callback) {
			var root = process.root;
			if (root.ctor === '_Task_nativeBinding' && root.cancel)
			{
				root.cancel();
			}

			process.root = null;

			callback(succeed(Utils.Tuple0));
		};
	}

	function step(numSteps, process)
	{
		var root = process.root;
		var stack = process.stack;

		while (numSteps < MAX_STEPS)
		{
			var ctor = root.ctor;

			if (ctor === '_Task_succeed')
			{
				while (stack.ctor === '_Task_onError')
				{
					stack = stack.rest;
				}
				if (stack === null)
				{
					break;
				}
				root = stack.callback(root.value);
				stack = stack.rest;
				++numSteps;
				continue;
			}

			if (ctor === '_Task_fail')
			{
				while (stack.ctor === '_Task_andThen')
				{
					stack = stack.rest;
				}
				if (stack === null)
				{
					break;
				}
				root = stack.callback(root.value);
				stack = stack.rest;
				++numSteps;
				continue;
			}

			if (ctor === '_Task_andThen')
			{
				stack = {
					ctor: '_Task_andThen',
					callback: root.callback,
					rest: stack
				};
				root = root.task;
				++numSteps;
				continue;
			}

			if (ctor === '_Task_onError')
			{
				stack = {
					ctor: '_Task_onError',
					callback: root.callback,
					rest: stack
				};
				root = root.task;
				++numSteps;
				continue;
			}

			if (ctor === '_Task_nativeBinding')
			{
				root.cancel = root.func(function(newRoot) {
					process.root = newRoot;
					enqueue(process);
				});

				break;
			}

			if (ctor === '_Task_receive')
			{
				var mailbox = process.mailbox;
				if (mailbox.length === 0)
				{
					break;
				}

				var msg = mailbox.shift();
				root = root.callback(msg);
				++numSteps;
				continue;
			}
		}

		if (numSteps < MAX_STEPS)
		{
			return numSteps + 1;
		}

		process.root = root;
		process.stack = stack;
		enqueue(process);

		return numSteps;
	}

	// WORK QUEUE

	var workQueue = [];

	function enqueue(process)
	{
		workQueue.push(process);
	}

	function work()
	{
		var numSteps = 0;
		var process;
		while (numSteps < MAX_STEPS && (process = workQueue.shift()))
		{
			numSteps = step(numSteps, process);
		}
		if (!process)
		{
			return;
		}
		setTimeout(work, 0);
	}

	return localRuntime.Native.Scheduler.values = {
		succeed: succeed,
		fail: fail,
		nativeBinding: nativeBinding,
		andThen: F2(andThen),
		onError: F2(onError),

		spawn: spawn,
		kill: kill,
		send: F2(send),

		work: work
	};
};
<|endoftext|>


<commit_before>/*
 * Magic Move based on https://github.com/ryanflorence/react-magic-move 0.1.0
 * Adapted for React 0.13 by Katsuyuki Ohmuro
 */
(function() {

    var Clones = React.createClass({
        displayName: 'MagicMoveClones',

        childrenWithPositions:function () {
            return React.Children.map(this.props.children, function(child)  {
                var style = this.props.positions[child.key];
                return React.cloneElement(child, { style:style });
            }.bind(this));
        },

        render:function () {
            return (
                React.createElement("div", {className: this.props.className + ' MagicMoveClones'},
                    this.childrenWithPositions()
                )
            );
        }
    });

    var MagicMove = React.createClass({

        displayName: 'MagicMove',

        getInitialState:function () {
            return {
                animating: false
            };
        },

        componentDidMount:function () {
            this.makePortal();
            this.renderClonesInitially();
        },

        componentWillUnmount:function () {
            this.portalNode.parent.removeChild(this.portalNode);
        },

        componentWillReceiveProps:function (nextProps) {
            this.startAnimation(nextProps);
        },

        componentDidUpdate:function (prevProps) {
            if (this.state.animating) {
                this.renderClonesToNewPositions(prevProps);
            }
        },

        makePortal:function () {
            this.portalNode = document.createElement('div');
            this.portalNode.style.left = '-9999px';
            this.portalNode.style.position = 'absolute';
            var baseNode;
            if (this.props.portalBaseId) {
                baseNode = document.getElementById(this.props.portalBaseId);
            } else {
                baseNode = document.body;
            }
            baseNode.appendChild(this.portalNode);
        },

        addTransitionEndEvent:function () {
            // if you click RIGHT before the transition is done, the animation jumps,
            // its because the transitionend event fires even though its not quite
            // done, not sure how to hack around it yet.
            this._transitionHandler = callOnNthCall(this.props.children.length, this.finishAnimation);
            this.portalNode.addEventListener('transitionend', this._transitionHandler);
        },

        removeTransitionEndEvent:function () {
            this.portalNode.removeEventListener('transitionend', this._transitionHandler);
        },

        startAnimation:function (nextProps) {
            if (this.state.animating) {
                return;
            }
            this.addTransitionEndEvent();
            var overrides = {
                animating: true,
                positions: this.getPositions()
            };
            this.renderClones(nextProps, overrides, function()  {
                this.setState({ animating: true });
            }.bind(this));
        },

        renderClonesToNewPositions:function (prevProps) {
            var overrides = {
                positions: this.getPositions()
            };
            this.renderClones(prevProps, overrides);
        },

        finishAnimation:function () {
            this.removeTransitionEndEvent();
            this.portalNode.style.position = 'absolute';
            this.setState({ animating: false });
        },

        getPositions:function () {
            var positions = {};
            React.Children.forEach(this.props.children, function(child)  {
                var ref = child.key;
                var node = this.refs[ref].getDOMNode();
                var rect = node.getBoundingClientRect();
                var computedStyle = getComputedStyle(node);
                var marginTop = parseInt(computedStyle.marginTop, 10);
                var marginLeft = parseInt(computedStyle.marginLeft, 10);
                var position = {
                    top: (rect.top - marginTop),
                    left: (rect.left - marginLeft),
                    width: rect.width,
                    height: rect.height,
                    position: 'absolute'
                };
                positions[ref] = position;
            }.bind(this));
            return positions;
        },

        renderClonesInitially:function () {
            var positions = this.getPositions();
            // this.props.positions = this.getPositions();
            React.render(React.createElement(Clones, React.__spread({},  this.props, {positions: positions})), this.portalNode);
        },

        renderClones:function (props, overrides, cb) {
            this.portalNode.style.position = '';
            React.render(React.createElement(Clones, React.__spread({},  props,  overrides)), this.portalNode, cb);
        },

        childrenWithRefs:function () {
            return React.Children.map(this.props.children, function(child)  {
                return React.cloneElement(child, { ref: child.key });
            });
        },

        render:function () {
            var style = { opacity: this.state.animating ? 0 : 1 };
            return (
                React.createElement("div", {className: this.props.className, style: style},
                    this.childrenWithRefs()
                )
            );
        }
    });

    function callOnNthCall(n, fn) {
        var calls = 0;
        return function () {
            calls++;
            if (calls === n) {
                calls = 0;
                return fn.apply(this, arguments);
            }
        };
    }

    window.MagicMove = MagicMove;
})();
<commit_msg>Some cleanup to Magic Move<commit_after>/*
 * Magic Move based on https://github.com/ryanflorence/react-magic-move 0.1.0
 * Adapted for React 0.13 by Katsuyuki Ohmuro
 */
(function() {

    var Clones = React.createClass({
        displayName: 'MagicMoveClones',

        childrenWithPositions:function () {
            return React.Children.map(this.props.children, function(child)  {
                var style = this.props.positions[child.key];
                return React.cloneElement(child, { style:style });
            }.bind(this));
        },

        render:function () {
            return (
                React.createElement("div", {className: this.props.className + ' MagicMoveClones'},
                    this.childrenWithPositions()
                )
            );
        }
    });

    var MagicMove = React.createClass({

        displayName: 'MagicMove',

        getInitialState:function () {
            return {
                animating: false
            };
        },

        componentDidMount:function () {
            this.makePortal();
            this.renderClones(this.props, false);
        },

        componentWillUnmount:function () {
            this.portalNode.parent.removeChild(this.portalNode);
        },

        componentWillReceiveProps:function (nextProps) {
            this.startAnimation(nextProps);
        },

        componentDidUpdate:function (prevProps) {
            if (this.state.animating) {
                this.renderClones(prevProps, false);
            }
        },

        makePortal:function () {
            this.portalNode = document.createElement('div');
            this.portalNode.style.left = '-9999px';
            this.portalNode.style.position = 'absolute';
            var baseNode;
            if (this.props.portalBaseId) {
                baseNode = document.getElementById(this.props.portalBaseId);
            } else {
                baseNode = document.body;
            }
            baseNode.appendChild(this.portalNode);
        },

        addTransitionEndEvent:function () {
            // if you click RIGHT before the transition is done, the animation jumps,
            // its because the transitionend event fires even though its not quite
            // done, not sure how to hack around it yet.
            this._transitionHandler = callOnNthCall(this.props.children.length, this.finishAnimation);
            this.portalNode.addEventListener('transitionend', this._transitionHandler);
        },

        removeTransitionEndEvent:function () {
            this.portalNode.removeEventListener('transitionend', this._transitionHandler);
        },

        startAnimation:function (nextProps) {
            if (this.state.animating) {
                return;
            }
            this.addTransitionEndEvent();
            this.portalNode.style.position = '';
            this.renderClones(nextProps, true);
        },

        finishAnimation:function () {
            this.removeTransitionEndEvent();
            this.portalNode.style.position = 'absolute';
            this.setState({ animating: false });
        },

        getPositions:function () {
            var positions = {};
            React.Children.forEach(this.props.children, function(child)  {
                var ref = child.key;
                var node = this.refs[ref].getDOMNode();
                var rect = node.getBoundingClientRect();
                var computedStyle = getComputedStyle(node);
                var marginTop = parseInt(computedStyle.marginTop, 10);
                var marginLeft = parseInt(computedStyle.marginLeft, 10);
                var position = {
                    top: (rect.top - marginTop),
                    left: (rect.left - marginLeft),
                    width: rect.width,
                    height: rect.height,
                    position: 'absolute'
                };
                positions[ref] = position;
            }.bind(this));
            return positions;
        },

        renderClones:function (props, animating) {
            var positions = this.getPositions();
            var cb = animating ? function()  { this.setState({ animating: true }); }.bind(this) : null;
            React.render(React.createElement(Clones, React.__spread({},  props, {positions: positions})), this.portalNode, cb);
        },

        childrenWithRefs:function () {
            return React.Children.map(this.props.children, function(child)  {
                return React.cloneElement(child, { ref: child.key });
            });
        },

        render:function () {
            var style = { opacity: this.state.animating ? 0 : 1 };
            return (
                React.createElement("div", {className: this.props.className, style: style},
                    this.childrenWithRefs()
                )
            );
        }
    });

    function callOnNthCall(n, fn) {
        var calls = 0;
        return function () {
            calls++;
            if (calls === n) {
                calls = 0;
                return fn.apply(this, arguments);
            }
        };
    }

    window.MagicMove = MagicMove;
})();
<|endoftext|>


<commit_before>$(document).ready(function () {
    // Hides all other dives except for the first. Also hides previous button on the first div.
    $(".add-extension .Div1").each(function (e) {
        if (e != 0)
            $(this).hide();
        else
            $("#previous").hide();
    });

    // Handles click events on the next button
    $("#next").click(function (e) {
        if ($('#extension-select').parsley().isValid() == false){
            $('#extension-select').parsley().validate();
            e.preventDefault();
            e.stopImmediatePropagation();
            return false
        }
        if ($('#dtpick').parsley().isValid() == false) {
            $('#dtpick').parsley().validate();
            e.preventDefault();
            e.stopImmediatePropagation();
            return false
        }
            if ($(".add-extension .Div1:visible").next().length != 0) {
                $('#dtpick').parsley().reset();
                $(".add-extension .Div1:visible").next().show().prev().hide();
                $("#previous").show();
            }
            else {
                $(".add-extension .Div1:visible").hide();
                $(".add-extension .Div1:first").show();
            }
            return false;
    });

    // Handles click events on the previous button
    $("#previous").click(function () {
        if ($(".add-extension .Div1:visible").prev().length != 0)
            $(".add-extension .Div1:visible").prev().show().next().hide();
        else {
            $(".add-extension .Div1:visible").hide();
            $(".add-extension .Div1:last").show();
        }
        return false;
    });

    // Shows custom due date datepicker when Custom Due Date is selected
    $("#extension-select").change(function () {
        selected = $(this).val();
        if (selected === "-1") {
            $("#custom_due_date").show();
        }
        else {
            $("#custom_due_date").hide();
        }
    });

    // Datepicker for extension date of a request
    $("#dtpick").datepicker({
        dateFormat: "yy-mm-dd"
    });

    // Apply data-parsley-required attribute to specified fields
    $('#dtpick').attr('data-parsley-required','');
    $('#extension-select').attr('data-parsley-required', '');

    // Custom validation messages
    $('#dtpick').attr('data-parsley-required-message', 'Extension date must be chosen');
    $('#extension-select').attr('data-parsley-required-message', 'Extension length must be selected');
});
<commit_msg>Fixed documentation and changed if to else if<commit_after>$(document).ready(function () {
    // Hides all other divs except for the first. Also hides previous button on the first div.
    $(".add-extension .Div1").each(function (e) {
        if (e != 0)
            $(this).hide();
        else
            $("#previous").hide();
    });

    // Handles click events on the next button
    $("#next").click(function (e) {
        // Validates extension select field on next button click
        if ($('#extension-select').parsley().isValid() == false) {
            $('#extension-select').parsley().validate();
            e.preventDefault();
            return false
        }
        // Validates custom datepicker on next button click
        else if ($('#dtpick').parsley().isValid() == false) {
            $('#dtpick').parsley().validate();
            e.preventDefault();
            return false
        }
        // Proceeds to next div on next button click
        else if ($(".add-extension .Div1:visible").next().length != 0) {
            $('#dtpick').parsley().reset();
            $(".add-extension .Div1:visible").next().show().prev().hide();
            $("#previous").show();
        }
        else {
            $(".add-extension .Div1:visible").hide();
            $(".add-extension .Div1:first").show();
        }
        return false;
    });

    // Handles click events on the previous button
    $("#previous").click(function () {
        // Proceeds to previous div on previous button click
        if ($(".add-extension .Div1:visible").prev().length != 0)
            $(".add-extension .Div1:visible").prev().show().next().hide();
        else {
            $(".add-extension .Div1:visible").hide();
            $(".add-extension .Div1:last").show();
        }
        return false;
    });

    // Shows custom due date datepicker when Custom Due Date is selected
    $("#extension-select").change(function () {
        selected = $(this).val();
        if (selected === "-1") {
            $("#custom_due_date").show();
        }
        else {
            $("#custom_due_date").hide();
        }
    });

    // Datepicker for extension date of a request
    $("#dtpick").datepicker({
        dateFormat: "yy-mm-dd"
    });

    // Apply data-parsley-required attribute to specified fields
    $('#dtpick').attr('data-parsley-required', '');
    $('#extension-select').attr('data-parsley-required', '');

    // Custom validation messages
    $('#dtpick').attr('data-parsley-required-message', 'Extension date must be chosen');
    $('#extension-select').attr('data-parsley-required-message', 'Extension length must be selected');
});
<|endoftext|>


<commit_before>sap.ui.define(['sap/ui/core/mvc/Controller'],
	function(Controller) {
	"use strict";

	var CController = Controller.extend("sap.m.sample.TitleWrapping.C", {

		onInit: function () {
			this.getView();
		},
		onSliderMoved: function (event) {
			var value = event.getParameter("value");
			this.byId("containerLayout").setWidth(value + "%");
		},
		onWrappingChange: function() {

			var title = sap.ui.getCore().byId("__xmlview0--WrappingTitle");
			title.setWrapping(!title.getWrapping());
		}
	});

	return CController;

});

<commit_msg>[INTERNAL] [FIX] sap.m.Title: Wrapping sample in Demokit fixed<commit_after>sap.ui.define(['sap/ui/core/mvc/Controller'],
	function(Controller) {
	"use strict";

	var CController = Controller.extend("sap.m.sample.TitleWrapping.C", {

		onInit: function () {
			this.getView();
		},
		onSliderMoved: function (event) {
			var value = event.getParameter("value");
			this.byId("containerLayout").setWidth(value + "%");
		},
		onWrappingChange: function() {

			var title = sap.ui.getCore().byId(this.getView().getId() + "--WrappingTitle");
			title.setWrapping(!title.getWrapping());
		}
	});

	return CController;

});

<|endoftext|>


<commit_before>import { Col, PageHeader, Row } from "antd";
import React from "react";
import { render } from "react-dom";
import { Provider, useSelector } from "react-redux";
import { setBaseUrl } from "../../../utilities/url-utilities";
import { ShareLayout } from "./ShareLayout";
import { ShareNoSamples } from "./ShareNoSamples";
import store from "./store";

/**
 * Base component for sharing samples between projects.
 *
 * @returns {JSX.Element}
 * @constructor
 */
function ShareApp() {
  /*
  Create redirect href to project samples page.
  */
  const [redirect] = React.useState(
    () => window.location.href.match(/(.*)\/share/)[1]
  );

  const { originalSamples, currentProject } = useSelector(
    (state) => state.shareReducer
  );

  /*
  1. No Samples - this would be if the user came to this page from anything
  other than the share samples link.
   */
  const NO_SAMPLES =
    typeof originalSamples === "undefined" || originalSamples.length === 0;

  if (NO_SAMPLES) {
    return <ShareNoSamples redirect={redirect} />;
  }

  /**
   * Return to previous page (project samples page)
   */
  const goToPrevious = () =>
    (window.location.href = setBaseUrl(`/projects/${currentProject}/samples`));

  return (
    <Row>
      <Col xl={{ span: 12, offset: 6 }} lg={{ span: 18, offset: 3 }} xs={24}>
        <PageHeader
          ghost={false}
          title={i18n("ShareSamples.title")}
          onBack={goToPrevious}
        >
          <ShareLayout />
        </PageHeader>
      </Col>
    </Row>
  );
}

render(
  <Provider store={store}>
    <ShareApp />
  </Provider>,
  document.querySelector("#root")
);
<commit_msg>Added border around content<commit_after>import { Card, Col, PageHeader, Row } from "antd";
import React from "react";
import { render } from "react-dom";
import { Provider, useSelector } from "react-redux";
import { setBaseUrl } from "../../../utilities/url-utilities";
import { ShareLayout } from "./ShareLayout";
import { ShareNoSamples } from "./ShareNoSamples";
import store from "./store";

/**
 * Base component for sharing samples between projects.
 *
 * @returns {JSX.Element}
 * @constructor
 */
function ShareApp() {
  /*
  Create redirect href to project samples page.
  */
  const [redirect] = React.useState(
    () => window.location.href.match(/(.*)\/share/)[1]
  );

  const { originalSamples, currentProject } = useSelector(
    (state) => state.shareReducer
  );

  /*
  1. No Samples - this would be if the user came to this page from anything
  other than the share samples link.
   */
  const NO_SAMPLES =
    typeof originalSamples === "undefined" || originalSamples.length === 0;

  if (NO_SAMPLES) {
    return <ShareNoSamples redirect={redirect} />;
  }

  /**
   * Return to previous page (project samples page)
   */
  const goToPrevious = () =>
    (window.location.href = setBaseUrl(`/projects/${currentProject}/samples`));

  return (
    <Row>
      <Col xl={{ span: 12, offset: 6 }} lg={{ span: 18, offset: 3 }} xs={24}>
        <PageHeader
          ghost={false}
          title={i18n("ShareSamples.title")}
          onBack={goToPrevious}
        >
          <Card>
            <ShareLayout />
          </Card>
        </PageHeader>
      </Col>
    </Row>
  );
}

render(
  <Provider store={store}>
    <ShareApp />
  </Provider>,
  document.querySelector("#root")
);
<|endoftext|>


<commit_before>var _ = require('./utils');

/**
 * A module of methods for object that you want to be able to listen to.
 * This module is consumed by `createStore` and `createAction`
 */
module.exports = {

    /**
     * Hook used by the publisher that is invoked before emitting
     * and before `shouldEmit`. The arguments are the ones that the action
     * is invoked with. If this function returns something other than
     * undefined, that will be passed on as arguments for shouldEmit and
     * emission.
     */
    preEmit: function() {},

    /**
     * Hook used by the publisher after `preEmit` to determine if the
     * event should be emitted with given arguments. This may be overridden
     * in your application, default implementation always returns true.
     *
     * @returns {Boolean} true if event should be emitted
     */
    shouldEmit: function() { return true; },

    /**
     * Subscribes the given callback for action triggered
     *
     * @param {Function} callback The callback to register as event handler
     * @param {Mixed} [optional] bindContext The context to bind the callback with
     * @returns {Function} Callback that unsubscribes the registered event handler
     */
    listen: function(callback, bindContext) {
        bindContext = bindContext || this;
        var eventHandler = function(args) {
            callback.apply(bindContext, args);
        }, me = this;
        this.emitter.addListener(this.eventLabel, eventHandler);
        return function() {
            me.emitter.removeListener(me.eventLabel, eventHandler);
        };
    },

    /**
     * Attach handlers to promise that trigger the completed and failed
     * child publishers, if available.
     *
     * @param {Object} The promise to attach to
     */
    promise: function(promise) {
        var me = this;

        var canHandlePromise =
            this.children.indexOf('completed') >= 0 &&
            this.children.indexOf('failed') >= 0;

        if (!canHandlePromise){
            throw new Error('Publisher must have "completed" and "failed" child publishers');
        }

        promise.then(function(response) {
            return me.completed(response);
        }).catch(function(error) {
            return me.failed(error);
        });
    },

    /**
     * Subscribes the given callback for action triggered, which should
     * return a promise that in turn is passed to `this.promise`
     *
     * @param {Function} callback The callback to register as event handler
     */
    listenAndPromise: function(callback, bindContext) {
        var me = this;
        bindContext = bindContext || this;

        return this.listen(function() {
            var args = arguments,
                promise = callback.apply(bindContext, args);
            return me.promise.call(me, promise);
        }, bindContext);
    },

    /**
     * Publishes an event using `this.emitter` (if `shouldEmit` agrees)
     */
    trigger: function() {
        var args = arguments,
            pre = this.preEmit.apply(this, args);
        args = pre === undefined ? args : _.isArguments(pre) ? pre : [].concat(pre);
        if (this.shouldEmit.apply(this, args)) {
            this.emitter.emit(this.eventLabel, args);
        }
    },

    /**
     * Tries to publish the event on the next tick
     */
    triggerAsync: function(){
        var args = arguments,me = this;
        _.nextTick(function() {
            me.trigger.apply(me, args);
        });
    }
};
<commit_msg>Throw error on undefined promise passed to PublisherMethods.listenAndPromise function.<commit_after>var _ = require('./utils');

/**
 * A module of methods for object that you want to be able to listen to.
 * This module is consumed by `createStore` and `createAction`
 */
module.exports = {

    /**
     * Hook used by the publisher that is invoked before emitting
     * and before `shouldEmit`. The arguments are the ones that the action
     * is invoked with. If this function returns something other than
     * undefined, that will be passed on as arguments for shouldEmit and
     * emission.
     */
    preEmit: function() {},

    /**
     * Hook used by the publisher after `preEmit` to determine if the
     * event should be emitted with given arguments. This may be overridden
     * in your application, default implementation always returns true.
     *
     * @returns {Boolean} true if event should be emitted
     */
    shouldEmit: function() { return true; },

    /**
     * Subscribes the given callback for action triggered
     *
     * @param {Function} callback The callback to register as event handler
     * @param {Mixed} [optional] bindContext The context to bind the callback with
     * @returns {Function} Callback that unsubscribes the registered event handler
     */
    listen: function(callback, bindContext) {
        bindContext = bindContext || this;
        var eventHandler = function(args) {
            callback.apply(bindContext, args);
        }, me = this;
        this.emitter.addListener(this.eventLabel, eventHandler);
        return function() {
            me.emitter.removeListener(me.eventLabel, eventHandler);
        };
    },

    /**
     * Attach handlers to promise that trigger the completed and failed
     * child publishers, if available.
     *
     * @param {Object} The promise to attach to
     */
    promise: function(promise) {
        var me = this;

        var canHandlePromise =
            this.children.indexOf('completed') >= 0 &&
            this.children.indexOf('failed') >= 0;

        if (!canHandlePromise){
            throw new Error('Publisher must have "completed" and "failed" child publishers');
        }

        promise.then(function(response) {
            return me.completed(response);
        }).catch(function(error) {
            return me.failed(error);
        });
    },

    /**
     * Subscribes the given callback for action triggered, which should
     * return a promise that in turn is passed to `this.promise`
     *
     * @param {Function} callback The callback to register as event handler
     */
    listenAndPromise: function(callback, bindContext) {
        var me = this;
        bindContext = bindContext || this;

        return this.listen(function() {

            if (!callback) {
                throw new Error('Expected a function returning a promise but got ' + callback);
            }

            var args = arguments,
                promise = callback.apply(bindContext, args);
            return me.promise.call(me, promise);
        }, bindContext);
    },

    /**
     * Publishes an event using `this.emitter` (if `shouldEmit` agrees)
     */
    trigger: function() {
        var args = arguments,
            pre = this.preEmit.apply(this, args);
        args = pre === undefined ? args : _.isArguments(pre) ? pre : [].concat(pre);
        if (this.shouldEmit.apply(this, args)) {
            this.emitter.emit(this.eventLabel, args);
        }
    },

    /**
     * Tries to publish the event on the next tick
     */
    triggerAsync: function(){
        var args = arguments,me = this;
        _.nextTick(function() {
            me.trigger.apply(me, args);
        });
    }
};
<|endoftext|>


<commit_before>// @flow
// TODO why only allow a single children element?
// what happens with <ReactHigherEvent><img /><caption /></ReactHigherEvent>?
import * as React from 'react'
import SubscribeContext from './SubscribeContext.js'
import type { EventProps } from './ReactHigherEventTypes.js'

const { Children, useContext, useEffect, useRef } = React

type Props = {
    ...EventProps,
    children: React.Node,
}

type Unsubscribers = { [eventName: string]: () => void }

const ReactHigherEvent = (props: Props) => {
    const subscribe = useContext(SubscribeContext)
    const unsubscribersRef = useRef<Unsubscribers | null>(null)
    const previousPropsRef = useRef<Props | null>(null)

    useEffect(() => {
        unsubscribersRef.current = {}
        // On unmount, call any remaining cleanup functions
        return () => {
            const unsubscribers = unsubscribersRef.current
            if (!unsubscribers) return
            Object.keys(unsubscribers).forEach((key) => {
                unsubscribers[key]()
            })
        }
    }, [])

    // On props changes, call cleanup for any changed handlers and subscribe any new
    useEffect(() => {
        if (!subscribe) return

        const unsubscribers = unsubscribersRef.current || {}
        const previousProps = previousPropsRef.current || {}
        previousPropsRef.current = props

        let previousKeys = Object.keys(previousProps)
        let currentKeys = Object.keys(props)
        let unhandledCurrentKeysCount = currentKeys.length

        previousKeys.forEach((key) => {
            if (key === 'children') return

            if (props[key]) {
                unhandledCurrentKeysCount--
            }

            if (props[key] === previousProps[key]) return

            // If this event handler has changed, call previous handler’s cleanup function
            if (unsubscribers[key]) {
                unsubscribers[key]()
                delete unsubscribers[key]
            }

            // If event handler doesn’t exist in current props, no need to do anything else
            if (!props[key]) return

            // Subscribe the new handler to the event and capture its cleanup function
            unsubscribers[key] = subscribe(key, props[key])
        })

        // If we already handled all new subscriptions, no need to do anything else
        if (!unhandledCurrentKeysCount) return

        currentKeys.forEach((key) => {
            if (key === 'children') return
            // If key exists in previousProps, we already handled it above
            if (previousProps[key]) return
            // If new value is falsey, we already cleaned up above, nothing else to do
            if (!props[key]) return

            unsubscribers[key] = subscribe(key, props[key])
        })
    }, [props, subscribe])

    return Children.only(props.children)
}

export default (ReactHigherEvent: React.ComponentType<Props>)
<commit_msg>Allow passing any number of children to ReactHigherEvent<commit_after>// @flow
import * as React from 'react'
import SubscribeContext from './SubscribeContext.js'
import type { EventProps } from './ReactHigherEventTypes.js'

const { useContext, useEffect, useRef } = React

type Props = {
    ...EventProps,
    children: React.Node,
}

type Unsubscribers = { [eventName: string]: () => void }

const ReactHigherEvent = (props: Props) => {
    const subscribe = useContext(SubscribeContext)
    const unsubscribersRef = useRef<Unsubscribers | null>(null)
    const previousPropsRef = useRef<Props | null>(null)

    useEffect(() => {
        unsubscribersRef.current = {}
        // On unmount, call any remaining cleanup functions
        return () => {
            const unsubscribers = unsubscribersRef.current
            if (!unsubscribers) return
            Object.keys(unsubscribers).forEach((key) => {
                unsubscribers[key]()
            })
        }
    }, [])

    // On props changes, call cleanup for any changed handlers and subscribe any new
    useEffect(() => {
        if (!subscribe) return

        const unsubscribers = unsubscribersRef.current || {}
        const previousProps = previousPropsRef.current || {}
        previousPropsRef.current = props

        let previousKeys = Object.keys(previousProps)
        let currentKeys = Object.keys(props)
        let unhandledCurrentKeysCount = currentKeys.length

        previousKeys.forEach((key) => {
            if (key === 'children') return

            if (props[key]) {
                unhandledCurrentKeysCount--
            }

            if (props[key] === previousProps[key]) return

            // If this event handler has changed, call previous handler’s cleanup function
            if (unsubscribers[key]) {
                unsubscribers[key]()
                delete unsubscribers[key]
            }

            // If event handler doesn’t exist in current props, no need to do anything else
            if (!props[key]) return

            // Subscribe the new handler to the event and capture its cleanup function
            unsubscribers[key] = subscribe(key, props[key])
        })

        // If we already handled all new subscriptions, no need to do anything else
        if (!unhandledCurrentKeysCount) return

        currentKeys.forEach((key) => {
            if (key === 'children') return
            // If key exists in previousProps, we already handled it above
            if (previousProps[key]) return
            // If new value is falsey, we already cleaned up above, nothing else to do
            if (!props[key]) return

            unsubscribers[key] = subscribe(key, props[key])
        })
    }, [props, subscribe])

    return props.children
}

export default (ReactHigherEvent: React.ComponentType<Props>)
<|endoftext|>


<commit_before>import {ElementResizeDetector} from 'widget/elementResizeDetector'
import {Graph} from 'widget/graph'
import {animationFrameScheduler, fromEvent, interval, merge} from 'rxjs'
import {compose} from 'compose'
import {distinctUntilChanged, filter, map, mapTo, scan, switchMap} from 'rxjs/operators'
import Hammer from 'hammerjs'
import Icon from 'widget/icon'
import Portal from 'widget/portal'
import React from 'react'
import _ from 'lodash'
import format from 'format'
import styles from './histogram.module.css'
import withSubscriptions from 'subscription'

const DEFAULT_STRETCH = 99.9
const MIN_STEPS = 40

export class Histogram extends React.Component {
    state = {
        width: null,
        dragging: false
    }

    constructor(params) {
        super(params)
        this.onDragging = this.onDragging.bind(this)
    }

    render() {
        const {loading, histogram} = this.props
        if (loading) {
            return this.renderLoading()
        } else if (histogram) {
            return this.renderHistogram()
        } else {
            return

        }
    }

    renderLoading() {
        return (

                <Icon name='spinner' className={styles.spinner}/>

        )
    }

    renderHistogram() {
        const {histogram: {data} = {}, min, max, onMinMaxChange} = this.props
        const {width} = this.state
        return (

                <ElementResizeDetector onResize={({width}) => this.setState({width})}>

                        {width
                            ? (
                                <Graph
                                    data={data}
                                    dimensions={width}
                                    drawGrid={false}
                                    axes={{
                                        x: {drawAxis: false},
                                        y: {drawAxis: false}
                                    }}
                                    legend='never'
                                    highlightCircleSize={0}
                                    fillGraph={true}
                                />
                            )
                            : null
                        }

                </ElementResizeDetector>
                <Handles
                    histogram={data}
                    min={min}
                    max={max}
                    width={width}
                    onMinMaxChange={onMinMaxChange}
                    onDragging={this.onDragging}
                />
                {this.renderOverlay()}

        )
    }

    onDragging(dragging) {
        this.setState({dragging})
    }

    renderOverlay() {
        const {dragging} = this.state
        return dragging
            ? (
                <Portal type='global'>

                </Portal>
            ) : null
    }

    componentDidUpdate(prevProps) {
        const {histogram: {data: prevData} = {}} = prevProps
        const {histogram: {data, stretch} = {}, onMinMaxChange} = this.props
        if (stretch && data && prevData !== data) {
            onMinMaxChange(histogramStretch(data, DEFAULT_STRETCH))
        }
    }
}

class Handles extends React.Component {
    state = {
        histogramMin: undefined,
        histogramMax: undefined
    }

    constructor(props) {
        super(props)
        this.onMinPosition = this.onMinPosition.bind(this)
        this.onMaxPosition = this.onMaxPosition.bind(this)
    }

    render() {
        return (

                {this.renderHandles()}

        )
    }

    renderHandles() {
        const {min, max, width, onDragging} = this.props
        const {histogramMin, histogramMax} = this.state
        const widthFactor = width / (histogramMax - histogramMin)
        const leftWidth = Math.max(0, min - histogramMin) * widthFactor
        const rightWidth = Math.max(0, histogramMax - max) * widthFactor
        const leftPosition = leftWidth
        const rightPosition = width - rightWidth
        // Handle width - adjust based on space between left and right
        if (width) {
            return <React.Fragment>

                    <div className={styles.spacer} style={{'--width': `${leftWidth}px`}}/>
                    <Handle
                        position={leftPosition}
                        width={width}
                        onDragging={onDragging}
                        onPosition={this.onMinPosition}
                    />

                    <Handle
                        position={rightPosition}
                        width={width}
                        onDragging={onDragging}
                        onPosition={this.onMaxPosition}
                    />
                    <div className={styles.spacer} style={{'--width': `${rightWidth}px`}}/>

            </React.Fragment>
        } else {
            return null
        }
    }

    componentDidUpdate() {
        const {histogram} = this.props
        const {histogramMin, histogramMax} = histogramMinMax(histogram)
        this.setState(({histogramMin: prevMin, histogramMax: prevMax}) => {
            return _.isFinite(histogramMin) && _.isFinite(histogramMax) && (prevMin !== histogramMin || prevMax !== histogramMax)
                ? {
                    histogramMin,
                    histogramMax,
                    magnitude: format.stepMagnitude({min: histogramMin, max: histogramMax, minSteps: MIN_STEPS})
                }
                : null
        })
    }

    onMinPosition(minPosition) {
        const {max, onMinMaxChange} = this.props
        const min = this.positionToValue(minPosition)
        onMinMaxChange({min, max: Math.max(min, max)})
    }

    onMaxPosition(maxPosition) {
        const {min, onMinMaxChange} = this.props
        const max = this.positionToValue(maxPosition)
        onMinMaxChange({min: Math.min(min, max), max})
    }

    positionToValue(position) {
        const {width} = this.props
        const {histogramMin, histogramMax, magnitude} = this.state
        const widthFactor = (histogramMax - histogramMin) / width
        const value = _.toNumber(histogramMin + position * widthFactor)
        return format.round({value, magnitude})
    }
}

const SMOOTHING_FACTOR = .2
const clamp = (value, {min, max}) => Math.max(min, Math.min(max, value))
const lerp = (value, target) => value + (target - value) * Math.min(SMOOTHING_FACTOR, 1)

class _Handle extends React.Component {
    ref = React.createRef()

    render() {
        return (

        )
    }

    componentDidMount() {
        this.initializeHandle()
    }

    initializeHandle() {
        const {onDragging, onPosition, addSubscription} = this.props
        const ref = this.ref.current
        if (!ref) {
            return
        }

        const handle = new Hammer(ref)

        handle.get('pan').set({
            direction: Hammer.DIRECTION_HORIZONTAL,
            threshold: 0
        })

        const dragLerp = (current, target) => {
            return lerp(current, target)
        }

        const hold$ = merge(
            fromEvent(ref, 'mousedown'),
            fromEvent(ref, 'touchstart')
        )
        const release$ = merge(
            fromEvent(ref, 'mouseup'),
            fromEvent(ref, 'touchend')
        )

        const pan$ = fromEvent(handle, 'panstart panmove panend')
        const panStart$ = pan$.pipe(filter(e => e.type === 'panstart'))
        const panMove$ = pan$.pipe(filter(e => e.type === 'panmove'))
        const panEnd$ = pan$.pipe(filter(e => e.type === 'panend'))
        const animationFrame$ = interval(0, animationFrameScheduler)

        const dragPosition$ =
            panStart$.pipe(
                switchMap(() => {
                    const {position} = this.props
                    return panMove$.pipe(
                        map(event => {
                            return this.clampPosition(position + event.deltaX)
                        }),
                        distinctUntilChanged(_.isEqual),
                    )
                })
            )

        const handlePosition$ = dragPosition$.pipe(
            switchMap(targetPosition => {
                const {position} = this.props
                return animationFrame$.pipe(
                    map(() => targetPosition),
                    scan(dragLerp, position),
                    map(position => Math.round(position)),
                    distinctUntilChanged(_.isEqual)
                )
            })
        )

        const dragging$ = merge(
            hold$.pipe(mapTo(true)),
            release$.pipe(mapTo(false)),
            panStart$.pipe(mapTo(true)),
            panEnd$.pipe(mapTo(false)),
        )

        addSubscription(
            handlePosition$.subscribe(position =>
                onPosition(position)
            ),
            dragging$.subscribe(dragging =>
                onDragging(dragging)
            )
        )
    }

    clampPosition(position) {
        const {width} = this.props
        const margin = 0
        return Math.round(
            clamp(position, {
                min: margin,
                max: width - margin
            })
        )
    }
}
const Handle = compose(
    _Handle,
    withSubscriptions()
)

const histogramMinMax = histogram => {
    const histogramMin = histogram[0][0]
    const histogramLastValue = histogram[histogram.length - 1][0]
    const bucketWidth = (histogramLastValue - histogramMin) / (histogram.length - 1)
    const histogramMax = histogramLastValue + bucketWidth
    return {histogramMin, histogramMax}
}

export const histogramStretch = (data, percent) => {
    const total = data.reduce((acc, [_value, count]) => acc + count, 0)
    const threshold = total * (1 - (percent / 100)) / 2
    const inMinStretch = _.last(
        data
            .reduce((acc, [value, count]) => [...acc, [value, (acc.length ? acc[acc.length - 1][1] : 0) + count]], [])
            .filter(([_value, total]) => total < threshold)
    )
    const min = inMinStretch ? inMinStretch[0] : data[0][0]
    const inMaxStretch = _.last(
        data
            .slice().reverse() // Immutably reverse
            .reduce((acc, [value, count]) => [...acc, [value, (acc.length ? acc[acc.length - 1][1] : 0) + count]], [])
            .filter(([_value, total]) => total < threshold)
    )
    const max = inMaxStretch ? inMaxStretch[0] : data[data.length - 1][0]
    return {min, max}
}
<commit_msg>Explicitly specified empty labels to get rid of warning.<commit_after>import {ElementResizeDetector} from 'widget/elementResizeDetector'
import {Graph} from 'widget/graph'
import {animationFrameScheduler, fromEvent, interval, merge} from 'rxjs'
import {compose} from 'compose'
import {distinctUntilChanged, filter, map, mapTo, scan, switchMap} from 'rxjs/operators'
import Hammer from 'hammerjs'
import Icon from 'widget/icon'
import Portal from 'widget/portal'
import React from 'react'
import _ from 'lodash'
import format from 'format'
import styles from './histogram.module.css'
import withSubscriptions from 'subscription'

const DEFAULT_STRETCH = 99.9
const MIN_STEPS = 40

export class Histogram extends React.Component {
    state = {
        width: null,
        dragging: false
    }

    constructor(params) {
        super(params)
        this.onDragging = this.onDragging.bind(this)
    }

    render() {
        const {loading, histogram} = this.props
        if (loading) {
            return this.renderLoading()
        } else if (histogram) {
            return this.renderHistogram()
        } else {
            return

        }
    }

    renderLoading() {
        return (

                <Icon name='spinner' className={styles.spinner}/>

        )
    }

    renderHistogram() {
        const {histogram: {data} = {}, min, max, onMinMaxChange} = this.props
        const {width} = this.state
        return (

                <ElementResizeDetector onResize={({width}) => this.setState({width})}>

                        {width
                            ? (
                                <Graph
                                    data={data}
                                    dimensions={width}
                                    drawGrid={false}
                                    axes={{
                                        x: {drawAxis: false},
                                        y: {drawAxis: false}
                                    }}
                                    labels={['', '']}
                                    legend='never'
                                    highlightCircleSize={0}
                                    fillGraph={true}
                                />
                            )
                            : null
                        }

                </ElementResizeDetector>
                <Handles
                    histogram={data}
                    min={min}
                    max={max}
                    width={width}
                    onMinMaxChange={onMinMaxChange}
                    onDragging={this.onDragging}
                />
                {this.renderOverlay()}

        )
    }

    onDragging(dragging) {
        this.setState({dragging})
    }

    renderOverlay() {
        const {dragging} = this.state
        return dragging
            ? (
                <Portal type='global'>

                </Portal>
            ) : null
    }

    componentDidUpdate(prevProps) {
        const {histogram: {data: prevData} = {}} = prevProps
        const {histogram: {data, stretch} = {}, onMinMaxChange} = this.props
        if (stretch && data && prevData !== data) {
            onMinMaxChange(histogramStretch(data, DEFAULT_STRETCH))
        }
    }
}

class Handles extends React.Component {
    state = {
        histogramMin: undefined,
        histogramMax: undefined
    }

    constructor(props) {
        super(props)
        this.onMinPosition = this.onMinPosition.bind(this)
        this.onMaxPosition = this.onMaxPosition.bind(this)
    }

    render() {
        return (

                {this.renderHandles()}

        )
    }

    renderHandles() {
        const {min, max, width, onDragging} = this.props
        const {histogramMin, histogramMax} = this.state
        const widthFactor = width / (histogramMax - histogramMin)
        const leftWidth = Math.max(0, min - histogramMin) * widthFactor
        const rightWidth = Math.max(0, histogramMax - max) * widthFactor
        const leftPosition = leftWidth
        const rightPosition = width - rightWidth
        // Handle width - adjust based on space between left and right
        if (width) {
            return <React.Fragment>

                    <div className={styles.spacer} style={{'--width': `${leftWidth}px`}}/>
                    <Handle
                        position={leftPosition}
                        width={width}
                        onDragging={onDragging}
                        onPosition={this.onMinPosition}
                    />

                    <Handle
                        position={rightPosition}
                        width={width}
                        onDragging={onDragging}
                        onPosition={this.onMaxPosition}
                    />
                    <div className={styles.spacer} style={{'--width': `${rightWidth}px`}}/>

            </React.Fragment>
        } else {
            return null
        }
    }

    componentDidUpdate() {
        const {histogram} = this.props
        const {histogramMin, histogramMax} = histogramMinMax(histogram)
        this.setState(({histogramMin: prevMin, histogramMax: prevMax}) => {
            return _.isFinite(histogramMin) && _.isFinite(histogramMax) && (prevMin !== histogramMin || prevMax !== histogramMax)
                ? {
                    histogramMin,
                    histogramMax,
                    magnitude: format.stepMagnitude({min: histogramMin, max: histogramMax, minSteps: MIN_STEPS})
                }
                : null
        })
    }

    onMinPosition(minPosition) {
        const {max, onMinMaxChange} = this.props
        const min = this.positionToValue(minPosition)
        onMinMaxChange({min, max: Math.max(min, max)})
    }

    onMaxPosition(maxPosition) {
        const {min, onMinMaxChange} = this.props
        const max = this.positionToValue(maxPosition)
        onMinMaxChange({min: Math.min(min, max), max})
    }

    positionToValue(position) {
        const {width} = this.props
        const {histogramMin, histogramMax, magnitude} = this.state
        const widthFactor = (histogramMax - histogramMin) / width
        const value = _.toNumber(histogramMin + position * widthFactor)
        return format.round({value, magnitude})
    }
}

const SMOOTHING_FACTOR = .2
const clamp = (value, {min, max}) => Math.max(min, Math.min(max, value))
const lerp = (value, target) => value + (target - value) * Math.min(SMOOTHING_FACTOR, 1)

class _Handle extends React.Component {
    ref = React.createRef()

    render() {
        return (

        )
    }

    componentDidMount() {
        this.initializeHandle()
    }

    initializeHandle() {
        const {onDragging, onPosition, addSubscription} = this.props
        const ref = this.ref.current
        if (!ref) {
            return
        }

        const handle = new Hammer(ref)

        handle.get('pan').set({
            direction: Hammer.DIRECTION_HORIZONTAL,
            threshold: 0
        })

        const dragLerp = (current, target) => {
            return lerp(current, target)
        }

        const hold$ = merge(
            fromEvent(ref, 'mousedown'),
            fromEvent(ref, 'touchstart')
        )
        const release$ = merge(
            fromEvent(ref, 'mouseup'),
            fromEvent(ref, 'touchend')
        )

        const pan$ = fromEvent(handle, 'panstart panmove panend')
        const panStart$ = pan$.pipe(filter(e => e.type === 'panstart'))
        const panMove$ = pan$.pipe(filter(e => e.type === 'panmove'))
        const panEnd$ = pan$.pipe(filter(e => e.type === 'panend'))
        const animationFrame$ = interval(0, animationFrameScheduler)

        const dragPosition$ =
            panStart$.pipe(
                switchMap(() => {
                    const {position} = this.props
                    return panMove$.pipe(
                        map(event => {
                            return this.clampPosition(position + event.deltaX)
                        }),
                        distinctUntilChanged(_.isEqual),
                    )
                })
            )

        const handlePosition$ = dragPosition$.pipe(
            switchMap(targetPosition => {
                const {position} = this.props
                return animationFrame$.pipe(
                    map(() => targetPosition),
                    scan(dragLerp, position),
                    map(position => Math.round(position)),
                    distinctUntilChanged(_.isEqual)
                )
            })
        )

        const dragging$ = merge(
            hold$.pipe(mapTo(true)),
            release$.pipe(mapTo(false)),
            panStart$.pipe(mapTo(true)),
            panEnd$.pipe(mapTo(false)),
        )

        addSubscription(
            handlePosition$.subscribe(position =>
                onPosition(position)
            ),
            dragging$.subscribe(dragging =>
                onDragging(dragging)
            )
        )
    }

    clampPosition(position) {
        const {width} = this.props
        const margin = 0
        return Math.round(
            clamp(position, {
                min: margin,
                max: width - margin
            })
        )
    }
}
const Handle = compose(
    _Handle,
    withSubscriptions()
)

const histogramMinMax = histogram => {
    const histogramMin = histogram[0][0]
    const histogramLastValue = histogram[histogram.length - 1][0]
    const bucketWidth = (histogramLastValue - histogramMin) / (histogram.length - 1)
    const histogramMax = histogramLastValue + bucketWidth
    return {histogramMin, histogramMax}
}

export const histogramStretch = (data, percent) => {
    const total = data.reduce((acc, [_value, count]) => acc + count, 0)
    const threshold = total * (1 - (percent / 100)) / 2
    const inMinStretch = _.last(
        data
            .reduce((acc, [value, count]) => [...acc, [value, (acc.length ? acc[acc.length - 1][1] : 0) + count]], [])
            .filter(([_value, total]) => total < threshold)
    )
    const min = inMinStretch ? inMinStretch[0] : data[0][0]
    const inMaxStretch = _.last(
        data
            .slice().reverse() // Immutably reverse
            .reduce((acc, [value, count]) => [...acc, [value, (acc.length ? acc[acc.length - 1][1] : 0) + count]], [])
            .filter(([_value, total]) => total < threshold)
    )
    const max = inMaxStretch ? inMaxStretch[0] : data[data.length - 1][0]
    return {min, max}
}
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2018 The FOAM Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.u2.dialog',
  name: 'InlineNotificationMessage',
  extends: 'foam.u2.View',

  documentation: `
    Inline notification message container.
  `,

  properties: [
    {
      class: 'String',
      name: 'type'
    },
    'message',
    'data'
  ],

  css: `
  ^ {
    display: flex;
    position: relative;
    justify-content: center;
    z-index: 15000;
  }
  ^inner {
    width: 90vw;
    max-width: 1024px;
    margin: auto;
    padding: 8px 24px;
    animation-name: fade;
    animation-duration: 10s;
    font-size: 14px;
    line-height: 1.33;
    letter-spacing: 0.2px;
    border-radius: 3px;
    box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.16);
    background: #f6fff2;
    border: 1px solid #03cf1f;
    display: flex;
    justify-content: space-between;
  }
  ^status-icon {
    margin-right: 10px;
    vertical-align: middle;
  }
  ^message {
    display: inline-block;
    vertical-align: middle;
  }
  ^error-background {
    background: #fff6f6;
    border: 1px solid #f91c1c;
  }
  ^warning-background {
    background: #f5f4ff;
    border: 1px solid #604aff;
  }
  `,

  methods: [
    function initE() {
      var img;
      if ( this.type === 'error' ) {
        img = 'images/inline-error-icon.svg';
      } else if ( this.type === 'warning' ) {
        img = 'images/information-small-purple.svg';
      } else {
        img = 'images/checkmark-small-green.svg';
      }
      this
        .hide(this.message$.map(function(msg) {
          return msg == '' || msg == undefined;
        }))
        .addClass(this.myClass())
        .start().addClass(this.myClass('inner'))
          .enableClass(this.myClass('error-background'), this.type === 'error')
          .enableClass(this.myClass('warning-background'), this.type === 'warning')
          .start()
            .start('img')
              .addClass(this.myClass('status-icon'))
              .attrs({ src: img })
            .end()
            .start()
              .addClass(this.myClass('message'))
              .add(this.message)
            .end()
          .end()
        .end();
    }
  ]
});
<commit_msg>copyright year update/indent fix<commit_after>/**
 * @license
 * Copyright 2019 The FOAM Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.u2.dialog',
  name: 'InlineNotificationMessage',
  extends: 'foam.u2.View',

  documentation: `
    Inline notification message container.
  `,

  properties: [
    {
      class: 'String',
      name: 'type'
    },
    'message',
    'data'
  ],

  css: `
    ^ {
      display: flex;
      position: relative;
      justify-content: center;
      z-index: 15000;
    }
    ^inner {
      width: 90vw;
      max-width: 1024px;
      margin: auto;
      padding: 8px 24px;
      animation-name: fade;
      animation-duration: 10s;
      font-size: 14px;
      line-height: 1.33;
      letter-spacing: 0.2px;
      border-radius: 3px;
      box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.16);
      background: #f6fff2;
      border: 1px solid #03cf1f;
      display: flex;
      justify-content: space-between;
    }
    ^status-icon {
      margin-right: 10px;
      vertical-align: middle;
    }
    ^message {
      display: inline-block;
      vertical-align: middle;
    }
    ^error-background {
      background: #fff6f6;
      border: 1px solid #f91c1c;
    }
    ^warning-background {
      background: #f5f4ff;
      border: 1px solid #604aff;
    }
  `,

  methods: [
    function initE() {
      var img;
      if ( this.type === 'error' ) {
        img = 'images/inline-error-icon.svg';
      } else if ( this.type === 'warning' ) {
        img = 'images/information-small-purple.svg';
      } else {
        img = 'images/checkmark-small-green.svg';
      }
      this
        .hide(this.message$.map(function(msg) {
          return msg == '' || msg == undefined;
        }))
        .addClass(this.myClass())
        .start().addClass(this.myClass('inner'))
          .enableClass(this.myClass('error-background'), this.type === 'error')
          .enableClass(this.myClass('warning-background'), this.type === 'warning')
          .start()
            .start('img')
              .addClass(this.myClass('status-icon'))
              .attrs({ src: img })
            .end()
            .start()
              .addClass(this.myClass('message'))
              .add(this.message)
            .end()
          .end()
        .end();
    }
  ]
});
<|endoftext|>