<commit_before>import store from '../store';
import { mapState } from 'vuex';
import { Scroller, Example } from 'components';

export default {
	name: 'Main',
	store,
	computed: mapState({
		name: state => state.name
	}),
	render() {
		const { name } = this;
		const style = {
			overflowY: 'scroll',
			maxHeight: '100%',
			textAlign: 'center',
			fontSize: '46px'
		};

		return (
			<Scroller>
				<Example name={ name } />
			</Scroller>
		);
	}
};
<commit_msg>remove some useless code<commit_after>import store from '../store';
import { mapState } from 'vuex';
import { Scroller, Example } from 'components';

export default {
	name: 'Main',
	store,
	computed: mapState({
		name: state => state.name
	}),
	render() {
		const { name } = this;

		return (
			<Scroller>
				<Example name={ name } />
			</Scroller>
		);
	}
};
<|endoftext|>


<commit_before>var ResourceService = require("services/ResourceService");
var ItemListService = require("services/ItemListService");

Vue.component("item-search", {

    template: "#vue-item-search",

    data: function()
    {
        return {
            searchString: "",
            itemSearch: {}
        };
    },

    ready: function()
    {
        ResourceService.bind("itemSearch", this);

        var countries = [
            {value: "Andorra", data: "AD"},
            {value: "tets", data: "t1"},
            {value: "Test", data: "tt"},
            {value: "Test", data: "tt"},
            {value: "Test", data: "tt"},
            {value: "Test", data: "tt"},
            {value: "Test", data: "tt"},
            {value: "Test", data: "tt"},
            {value: "Zimbabwe", data: "ZZ"}
        ];
        var self = this;

        $(".search-input").autocomplete({
            lookup: countries,
            width: $(".search-box-shadow-frame").width(),
            onSelect: function(suggestion)
            {
                self.itemSearch.searchString = suggestion.value;
            }
        });

        $(window).resize(function()
        {
            $(".autocomplete-suggestions").width($(".search-box-shadow-frame").width());
        });
    },

    methods:
    {
        search: function()
        {
            if (document.location.pathname === "/search")
            {
                ItemListService.setSearchString(this.itemSearch.searchString);
            }
            else
            {
                window.open("/search?searchString=" + this.itemSearch.searchString, "_self", false);
            }
        }
    }
});
<commit_msg>UPDATE autocomplete "responsive"<commit_after>var ResourceService = require("services/ResourceService");
var ItemListService = require("services/ItemListService");

Vue.component("item-search", {

    template: "#vue-item-search",

    data: function()
    {
        return {
            searchString: "",
            itemSearch: {}
        };
    },

    ready: function()
    {
        ResourceService.bind("itemSearch", this);

        var countries = [
            {value: "Andorra", data: "AD"},
            {value: "tets", data: "t1"},
            {value: "Test", data: "tt"},
            {value: "Test", data: "tt"},
            {value: "Test", data: "tt"},
            {value: "Test", data: "tt"},
            {value: "Test", data: "tt"},
            {value: "Test", data: "tt"},
            {value: "Zimbabwe", data: "ZZ"}
        ];
        var self = this;

        $(".search-input").autocomplete({
            lookup: countries,
            width: $(".search-box-shadow-frame").width(),
            onSelect: function(suggestion)
            {
                self.itemSearch.searchString = suggestion.value;
            },
            beforeRender: function()
            {
                $(".autocomplete-suggestions").width($(".search-box-shadow-frame").width());
            }
        });

        $(window).resize(function()
        {
            $(".autocomplete-suggestions").width($(".search-box-shadow-frame").width());
        });
    },

    methods:
    {
        search: function()
        {
            if (document.location.pathname === "/search")
            {
                ItemListService.setSearchString(this.itemSearch.searchString);
            }
            else
            {
                window.open("/search?searchString=" + this.itemSearch.searchString, "_self", false);
            }
        }
    }
});
<|endoftext|>


<commit_before>var assert = require('assert');
var fs = require('fs');
var treeify = require('treeify');
var _ = require('lodash');
var bower_license = require('../../lib/index.js');

var options = {
    customLicensePath: process.cwd() + '/licenses.json',
    ignoredDependencyPath: process.cwd() + '/ignore.json'
};

function formatTree(data){
    return treeify.asTree(data, true);
}

function formatJson(data){
    return JSON.stringify(data, null, 4);
}

describe('basic intergration test', function() {
    describe('test row output', function () {
        it('should return the correct value', function (done) {
            var json_result = '';
            try {
                json_result = fs.readFileSync('json_result', 'utf8');
            } catch (err) {
                assert(false, 'cannot read file');
                done();
            }

        	var type = 'json';
            bower_license.init(options, function(result, err){
                if (!!err) {
                    assert(false, 'cannot process');
                } else  {
                    var output = type === 'tree' ? formatTree(result) : formatJson(result);
                    assert.equal(output, json_result);
                }
                done();
            });
        });

        it('shoule test file existed and correct', function (done) {
            var json_result = '';
            try {
                json_result = fs.readFileSync('json_result', 'utf8');
            } catch (err) {
                assert(false, 'cannot read file');
                done();
            }

            var type = 'json';
            bower_license.init(options, function(result, err){
                if (!!err) {
                    assert(false, 'cannot process');
                } else  {
                    var temp_file = 'temp_file.ignorefile';
                    var output = type === 'tree' ? formatTree(result) : formatJson(result);
                    fs.writeFileSync(temp_file, output);
                    var result_file = JSON.parse(fs.readFileSync(temp_file, 'utf8'));
                    // deeply compare two object
                    assert.equal(_.isEqual(result, result_file), true);
                }
                done();
            });
        });
    });
});<commit_msg>review suggestion; use deepEqual instead of lodash<commit_after>var assert = require('assert');
var fs = require('fs');

var bower_license = require('../../lib/index.js');

var options = {
    customLicensePath: process.cwd() + '/licenses.json',
    ignoredDependencyPath: process.cwd() + '/ignore.json'
};

function formatJson(data){
    return JSON.stringify(data, null, 4);
}

describe('basic intergration test', function() {
    describe('test row output', function () {
        it('should return the correct value', function (done) {
            var json_result = '';
            try {
                json_result = JSON.parse(fs.readFileSync('json_result', 'utf8'));
            } catch (err) {
                assert(false, 'cannot read file');
                done();
            }

        	var type = 'json';
            bower_license.init(options, function(result, err){
                if (!!err) {
                    assert(false, 'cannot process');
                } else  {
                    assert.deepEqual(result, json_result);
                }
                done();
            });
        });

        it('shoule test file existed and correct', function (done) {
            var json_result = '';
            try {
                json_result = fs.readFileSync('json_result', 'utf8');
            } catch (err) {
                assert(false, 'cannot read file');
                done();
            }

            var type = 'json';
            bower_license.init(options, function(result, err){
                if (!!err) {
                    assert(false, 'cannot process');
                } else  {
                    var temp_file = 'temp_file.ignorefile';
                    var output = type === 'tree' ? formatTree(result) : formatJson(result);
                    fs.writeFileSync(temp_file, output);
                    var result_file = JSON.parse(fs.readFileSync(temp_file, 'utf8'));
                    assert.deepEqual(result, result_file);
                }
                done();
            });
        });
    });
});<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as Actions from '../actions/track';
import { playCurrentNote, getReplaySpeedForNote } from '../util/audio';

import Soundfont from 'soundfont-player';

import TabRows from '../components/TabRows';
import EditorArea from '../components/editor/EditorArea';
import TimeSignatureModal from '../components/editor/TimeSignatureModal';
import TuningModal from '../components/editor/TuningModal';

class App extends Component {
  constructor(props) {
    super(props);

    if (typeof window !== 'undefined') {
      window.addEventListener('keydown', this.handleKeyPress);
      window.addEventListener('resize', this.handleResize);
    }

    let audioContext;
    try {
      audioContext = new AudioContext();
    } catch(e) {
      audioContext = new webkitAudioContext();
    }

    this.state = {
      currentPlayingNote: {
        measure: 0,
        noteIndex: 0
      },
      currentEditingIndex: {
        measureIndex: 0,
        noteIndex: 0,
        stringIndex: 0
      },
      audioContext,
      isPlaying: false,
      bpm: 120,
      layout: 'page'
    };
  }

  componentWillMount = () => {
    const ctx = this.state.audioContext;

    Soundfont.loadBuffers(ctx, 'acoustic_guitar_steel').then((buffers) => {
      this.setState({ buffers });
    });
  }

  handleResize = () => {
    this.forceUpdate();
  }

  getXOfCurrentNote = () => {
    const { measure, noteIndex } = this.state.currentPlayingNote;
    const xOfMeasures = this.props.track.measures.reduce((acc, curr, i) => {
      if(i >= measure) {
        return acc;
      }
      return acc + curr.width;
    }, 0);

    return xOfMeasures + 55 * noteIndex;
  }

  updateScrollPosition = () => {
    const x = this.getXOfCurrentNote();
    const scrollX = window.scrollX;

    if(x > window.innerWidth + scrollX - 50 && this.state.layout === 'linear') {
      window.scroll(x, 0);
    }
  }

  startPlayback = () => {
    let startTimestamp = Date.now();
    this.updateScrollPosition();
    playCurrentNote(this.state.audioContext, this.props.track, this.state.bpm, this.state.currentPlayingNote, this.state.buffers);

    this.setState({
      timer: requestAnimationFrame(() => {
        this.loopThroughSong(startTimestamp);
      })
    });
  }

  loopThroughSong = (startTimestamp) => {
    let { currentPlayingNote, bpm, audioContext } = this.state;
    let { measure, noteIndex } = currentPlayingNote;
    let { measures } = this.props.track;

    let currentTimestamp = Date.now();
    let replayDiff = currentTimestamp - startTimestamp;

    let measureToPlay = measures[currentPlayingNote.measure];

    let replaySpeed;
    if(measureToPlay.notes.length > 0) {
      replaySpeed = getReplaySpeedForNote(measureToPlay.notes[noteIndex], bpm);
    } else {
      replaySpeed = bpm * 4;
    }

    if(replayDiff >= replaySpeed) {
      if(measure === measures.length - 1 && noteIndex >= measures[measure].notes.length - 1) {
        this.handleStop();
      } else if(measure !== measures.length - 1 && noteIndex >= measures[measure].notes.length - 1) {
        this.setState({
          currentPlayingNote: {
            measure: measure + 1,
            noteIndex: 0
          },
          currentEditingIndex: {
            stringIndex: this.state.currentEditingIndex.stringIndex,
            measureIndex: measure + 1,
            noteIndex: 0
          },
          timer: requestAnimationFrame(() => {
            this.loopThroughSong(currentTimestamp);
          })
        }, () => {
          this.updateScrollPosition();
          playCurrentNote(audioContext, this.props.track, this.state.bpm, this.state.currentPlayingNote, this.state.buffers);
        });
      } else {
        this.setState({
          currentPlayingNote: {
            measure: measure,
            noteIndex: noteIndex + 1
          },
          currentEditingIndex: {
            stringIndex: this.state.currentEditingIndex.stringIndex,
            measureIndex: measure,
            noteIndex: noteIndex + 1
          },
          timer: requestAnimationFrame(() => {
            this.loopThroughSong(currentTimestamp);
          })
        }, () => {
          this.updateScrollPosition();
          playCurrentNote(audioContext, this.props.track, this.state.bpm, this.state.currentPlayingNote, this.state.buffers);
        });
      }
    } else {
      this.setState({
        timer: requestAnimationFrame(() => {
          this.loopThroughSong(startTimestamp);
        })
      });
    }
  }

  handleStop = () => {
    cancelAnimationFrame(this.state.timer);

    this.setState({
      isPlaying: false
    });
  }

  handlePlay = () => {
    if(this.state.isPlaying || !this.state.buffers) {
      return;
    }

    this.setState({
      isPlaying: true,
    }, () => {
      this.startPlayback();
    });
  }

  onNoteClick = (index) => {
    this.setState({
      currentEditingIndex: index,
      currentPlayingNote: {
        measure: index.measureIndex,
        noteIndex: index.noteIndex
      }
    });
  }

  getCurrentNote = () => {
    const { measures } = this.props.track;
    const { measureIndex, noteIndex } = this.state.currentEditingIndex;

    return measures[measureIndex].notes[noteIndex];
  }

  getNextNote = (measureIndex, noteIndex) => {
    const { measures } = this.props.track;

    if(measureIndex === measures.length - 1 && noteIndex >= measures[measureIndex].notes.length - 1) {
      return 'NEW';
    } else if(noteIndex >= measures[measureIndex].notes.length - 1) {
      return {
        measureIndex: measureIndex + 1,
        noteIndex: 0
      };
    } else {
      return {
        measureIndex,
        noteIndex: noteIndex + 1
      };
    }
  }

  getPrevNote = (measureIndex, noteIndex) => {
    const { measures } = this.props.track;

    if(measureIndex === 0 && noteIndex === 0) {
      return { measureIndex, noteIndex };
    } else if(noteIndex === 0) {
      let prevMeasure = measures[measureIndex - 1];
      if(prevMeasure.notes.length > 0) {
        return {
          measureIndex: measureIndex - 1,
          noteIndex: measures[measureIndex - 1].notes.length - 1
        };
      } else {
        return {
          measureIndex: measureIndex - 1,
          noteIndex: 0
        };
      }
    } else {
      return {
        measureIndex,
        noteIndex: noteIndex - 1
      };
    }
  }

  getUpperString = (stringIndex) => {
    return stringIndex === 5 ? 0 : stringIndex + 1;
  }

  getLowerString = (stringIndex) => {
    return stringIndex === 0 ? 5 : stringIndex - 1;
  }

  navigateCursor = (event) => {
    let { measureIndex, noteIndex, stringIndex } = this.state.currentEditingIndex;

    if(event.keyCode === 39) { // right arrow
      let newEditingIndex = this.getNextNote(measureIndex, noteIndex);
      if(newEditingIndex === 'NEW') {
        this.props.actions.insertMeasure(0);
        newEditingIndex = {
          stringIndex,
          measureIndex: measureIndex + 1,
          noteIndex: 0
        };
        this.setState({
          currentEditingIndex: newEditingIndex,
          currentPlayingNote: {
            measure: newEditingIndex.measureIndex,
            noteIndex: newEditingIndex.noteIndex
          }
        });
      } else {
        newEditingIndex.stringIndex = stringIndex;
        this.setState({
          currentEditingIndex: newEditingIndex,
          currentPlayingNote: {
            measure: newEditingIndex.measureIndex,
            noteIndex: newEditingIndex.noteIndex
          }
        });
      }
    } else if(event.keyCode === 37) { // left arrow
      let newEditingIndex = this.getPrevNote(measureIndex, noteIndex);
      newEditingIndex.stringIndex = stringIndex;
      this.setState({
        currentEditingIndex: newEditingIndex,
        currentPlayingNote: {
          measure: newEditingIndex.measureIndex,
          noteIndex: newEditingIndex.noteIndex
        }
      });
    } else if(event.keyCode === 38) { // up arrow
      event.preventDefault();
      let newEditingIndex = {
        stringIndex: this.getUpperString(stringIndex),
        noteIndex,
        measureIndex
      };
      this.setState({
        currentEditingIndex: newEditingIndex
      });
    } else if(event.keyCode === 40) { // down arrow
      event.preventDefault();
      let newEditingIndex = {
        stringIndex: this.getLowerString(stringIndex),
        noteIndex,
        measureIndex
      };
      this.setState({
        currentEditingIndex: newEditingIndex
      });
    }
  }

  editNote = (fret) => {
    this.props.actions.changeNote(this.state.currentEditingIndex, fret);
  }

  changeNoteLength = (duration) => {
    this.props.actions.changeNoteLength(this.state.currentEditingIndex, duration);
  }

  deleteNote = () => {
    const { noteIndex, measureIndex, stringIndex } = this.state.currentEditingIndex;
    let notes = this.props.track.measures[measureIndex].notes;

    if(notes.length > 1 && noteIndex === notes.length - 1 && notes[notes.length - 1].fret[0] === 'rest') {
      this.setState({
        currentEditingIndex: {
          stringIndex,
          measureIndex,
          noteIndex: noteIndex - 1
        }
      }, () => {
        this.props.actions.deleteNote({ stringIndex, measureIndex, noteIndex });
      });
    } else if(notes.length === 0) {
      this.props.actions.deleteMeasure(measureIndex);

      if(measureIndex === this.props.track.measures.length) {
        this.setState({
          currentEditingIndex: {
            stringIndex,
            measureIndex: measureIndex - 1,
            noteIndex: 0
          }
        });
      }
    } else {
      this.props.actions.deleteNote(this.state.currentEditingIndex);
    }
  }

  insertNote = () => {
    const { noteIndex, measureIndex, stringIndex } = this.state.currentEditingIndex;

    this.props.actions.insertNote(this.state.currentEditingIndex);

    if(this.props.track.measures[measureIndex].notes.length === 1) {
      this.setState({
        currentEditingIndex: {
          measureIndex,
          stringIndex,
          noteIndex: 0
        }
      });
    } else {
      this.setState({
        currentEditingIndex: {
          measureIndex,
          stringIndex,
          noteIndex: noteIndex + 1
        }
      });
    }
  }

  pasteNote = () => {
    const { measureIndex, noteIndex, stringIndex } = this.state.currentEditingIndex;

    this.props.actions.pasteNote(this.state.currentEditingIndex, this.props.clipboard);
    this.setState({
      currentEditingIndex: {
        measureIndex,
        noteIndex: this.props.track.measures[measureIndex].notes.length === 1 && noteIndex === 0 ? 0 : noteIndex + 1,
        stringIndex
      }
    });
  }

  handleKeyPress = (event) => {
    if((event.metaKey || event.ctrlKey) && event.keyCode === 67) { // cmd/ctrl+c
      event.preventDefault();
      return this.props.actions.copyNote(this.getCurrentNote());
    }
    if((event.metaKey || event.ctrlKey) && event.keyCode === 86) { // cmd/ctrl+v
      event.preventDefault();
      return this.pasteNote();
    }
    if((event.metaKey || event.ctrlKey) && event.keyCode === 88) { // cmd/ctrl+c
      event.preventDefault();
      const { noteIndex, measureIndex, stringIndex } = this.state.currentEditingIndex;
      let notes = this.props.track.measures[measureIndex].notes;
      if(notes.length > 1 && noteIndex === notes.length - 1) {
        const currentNote = this.getCurrentNote();

        this.setState({
          currentEditingIndex: {
            stringIndex,
            measureIndex,
            noteIndex: noteIndex - 1
          }
        }, () => {
          this.props.actions.cutNote({ noteIndex: noteIndex, measureIndex, stringIndex }, currentNote);
        });
      } else {
        return this.props.actions.cutNote({ noteIndex, measureIndex, stringIndex }, this.getCurrentNote());
      }
    }

    if(event.metaKey) {
      return;
    } else if(this.state.isPlaying && event.keyCode !== 32) {
      return;
    } else if(this.state.tuningModal || this.state.timeSignatureModal) {
      return;
    }

    if(event.keyCode <= 57 && event.keyCode >= 48) {
      return this.editNote(event.keyCode - 48);
    } else if(event.keyCode === 82 && !event.metaKey && !event.ctrlKey) {
      this.props.actions.changeNote(this.state.currentEditingIndex, 'rest');
    } else if(event.keyCode === 8) { // delete
      event.preventDefault();
      this.deleteNote();
    } else if(event.keyCode === 69) { // e
      return this.changeNoteLength('e');
    } else if(event.keyCode === 83) { // s
      return this.changeNoteLength('s');
    } else if(event.keyCode === 81) { // q
      return this.changeNoteLength('q');
    } else if(event.keyCode === 87) { // w
      return this.changeNoteLength('w');
    } else if(event.keyCode === 72 && !event.ctrlKey) { // h
      return this.changeNoteLength('h');
    } else if(event.keyCode === 73) { // i
      return this.insertNote();
    } else if(event.keyCode === 32) { // spacebar
      event.preventDefault();
      return this.state.isPlaying ? this.handleStop() : this.handlePlay();
    } else if(event.keyCode === 190) { // period
      this.props.actions.toggleNoteDotted(this.state.currentEditingIndex);
    } else {
      return this.navigateCursor(event);
    }
  }

  bpmChanged = (event) => {
    this.setState({
      bpm: event.target.value
    });
  }

  openTimeSignatureModal = () => {
    this.setState({
      timeSignatureModal: true
    });
  }

  closeModal = () => {
    this.setState({
      timeSignatureModal: false,
      tuningModal: false
    });
  }

  toggleLayout = () => {
    let layout = this.state.layout === 'page' ? 'linear' : 'page';
    this.setState({ layout });
  }

  openTuningModal = () => {
    this.setState({
      tuningModal: true
    });
  }

  render() {
    const { measures } = this.props.track;
    const { measureIndex } = this.state.currentEditingIndex;
    const timeSignature = measures[measureIndex] ? measures[measureIndex].timeSignature : '4/4';

    return (
      <div style={{ display: 'flex', flexDirection: 'column' }}>
        <EditorArea bpmChanged={this.bpmChanged}
          handlePlay={this.handlePlay}
          handleStop={this.handleStop}
          openModal={this.openTimeSignatureModal}
          openTuning={this.openTuningModal}
          toggleLayout={this.toggleLayout}
          bpm={this.state.bpm}
          timeSignature={timeSignature}
          layout={this.state.layout}
        />
        <TabRows track={measures} layout={this.state.layout}
          currentEditingIndex={this.state.currentEditingIndex}
          currentPlayingNote={this.state.currentPlayingNote}
          isPlaying={this.state.isPlaying}
          onClick={this.onNoteClick}
        />
        <TimeSignatureModal isOpen={this.state.timeSignatureModal} closeModal={this.closeModal}
          measureIndex={measureIndex} timeSignature={timeSignature}
        />
        <TuningModal isOpen={this.state.tuningModal} closeModal={this.closeModal} />
      </div>
    );
  }
}

function mapStateToProps(state) {
  return {
    track: state.tracks[state.currentTrackIndex],
    clipboard: state.clipboard
  };
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(Actions, dispatch)
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(App);
<commit_msg>make scrolling a bit less dramatic<commit_after>import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as Actions from '../actions/track';
import { playCurrentNote, getReplaySpeedForNote } from '../util/audio';

import Soundfont from 'soundfont-player';

import TabRows from '../components/TabRows';
import EditorArea from '../components/editor/EditorArea';
import TimeSignatureModal from '../components/editor/TimeSignatureModal';
import TuningModal from '../components/editor/TuningModal';

class App extends Component {
  constructor(props) {
    super(props);

    if (typeof window !== 'undefined') {
      window.addEventListener('keydown', this.handleKeyPress);
      window.addEventListener('resize', this.handleResize);
    }

    let audioContext;
    try {
      audioContext = new AudioContext();
    } catch(e) {
      audioContext = new webkitAudioContext();
    }

    this.state = {
      currentPlayingNote: {
        measure: 0,
        noteIndex: 0
      },
      currentEditingIndex: {
        measureIndex: 0,
        noteIndex: 0,
        stringIndex: 0
      },
      audioContext,
      isPlaying: false,
      bpm: 120,
      layout: 'page'
    };
  }

  componentWillMount = () => {
    const ctx = this.state.audioContext;

    Soundfont.loadBuffers(ctx, 'acoustic_guitar_steel').then((buffers) => {
      this.setState({ buffers });
    });
  }

  handleResize = () => {
    this.forceUpdate();
  }

  getXOfCurrentNote = () => {
    const { measure, noteIndex } = this.state.currentPlayingNote;
    const xOfMeasures = this.props.track.measures.reduce((acc, curr, i) => {
      if(i >= measure) {
        return acc;
      }
      return acc + curr.width;
    }, 0);

    return xOfMeasures + 55 * noteIndex;
  }

  updateScrollPosition = () => {
    const x = this.getXOfCurrentNote();
    const scrollX = window.scrollX;

    if(x > window.innerWidth + scrollX - 200 && this.state.layout === 'linear') {
      window.scroll(x - 200, 0);
    }
  }

  startPlayback = () => {
    let startTimestamp = Date.now();
    this.updateScrollPosition();
    playCurrentNote(this.state.audioContext, this.props.track, this.state.bpm, this.state.currentPlayingNote, this.state.buffers);

    this.setState({
      timer: requestAnimationFrame(() => {
        this.loopThroughSong(startTimestamp);
      })
    });
  }

  loopThroughSong = (startTimestamp) => {
    let { currentPlayingNote, bpm, audioContext } = this.state;
    let { measure, noteIndex } = currentPlayingNote;
    let { measures } = this.props.track;

    let currentTimestamp = Date.now();
    let replayDiff = currentTimestamp - startTimestamp;

    let measureToPlay = measures[currentPlayingNote.measure];

    let replaySpeed;
    if(measureToPlay.notes.length > 0) {
      replaySpeed = getReplaySpeedForNote(measureToPlay.notes[noteIndex], bpm);
    } else {
      replaySpeed = bpm * 4;
    }

    if(replayDiff >= replaySpeed) {
      if(measure === measures.length - 1 && noteIndex >= measures[measure].notes.length - 1) {
        this.handleStop();
      } else if(measure !== measures.length - 1 && noteIndex >= measures[measure].notes.length - 1) {
        this.setState({
          currentPlayingNote: {
            measure: measure + 1,
            noteIndex: 0
          },
          currentEditingIndex: {
            stringIndex: this.state.currentEditingIndex.stringIndex,
            measureIndex: measure + 1,
            noteIndex: 0
          },
          timer: requestAnimationFrame(() => {
            this.loopThroughSong(currentTimestamp);
          })
        }, () => {
          this.updateScrollPosition();
          playCurrentNote(audioContext, this.props.track, this.state.bpm, this.state.currentPlayingNote, this.state.buffers);
        });
      } else {
        this.setState({
          currentPlayingNote: {
            measure: measure,
            noteIndex: noteIndex + 1
          },
          currentEditingIndex: {
            stringIndex: this.state.currentEditingIndex.stringIndex,
            measureIndex: measure,
            noteIndex: noteIndex + 1
          },
          timer: requestAnimationFrame(() => {
            this.loopThroughSong(currentTimestamp);
          })
        }, () => {
          this.updateScrollPosition();
          playCurrentNote(audioContext, this.props.track, this.state.bpm, this.state.currentPlayingNote, this.state.buffers);
        });
      }
    } else {
      this.setState({
        timer: requestAnimationFrame(() => {
          this.loopThroughSong(startTimestamp);
        })
      });
    }
  }

  handleStop = () => {
    cancelAnimationFrame(this.state.timer);

    this.setState({
      isPlaying: false
    });
  }

  handlePlay = () => {
    if(this.state.isPlaying || !this.state.buffers) {
      return;
    }

    this.setState({
      isPlaying: true,
    }, () => {
      this.startPlayback();
    });
  }

  onNoteClick = (index) => {
    this.setState({
      currentEditingIndex: index,
      currentPlayingNote: {
        measure: index.measureIndex,
        noteIndex: index.noteIndex
      }
    });
  }

  getCurrentNote = () => {
    const { measures } = this.props.track;
    const { measureIndex, noteIndex } = this.state.currentEditingIndex;

    return measures[measureIndex].notes[noteIndex];
  }

  getNextNote = (measureIndex, noteIndex) => {
    const { measures } = this.props.track;

    if(measureIndex === measures.length - 1 && noteIndex >= measures[measureIndex].notes.length - 1) {
      return 'NEW';
    } else if(noteIndex >= measures[measureIndex].notes.length - 1) {
      return {
        measureIndex: measureIndex + 1,
        noteIndex: 0
      };
    } else {
      return {
        measureIndex,
        noteIndex: noteIndex + 1
      };
    }
  }

  getPrevNote = (measureIndex, noteIndex) => {
    const { measures } = this.props.track;

    if(measureIndex === 0 && noteIndex === 0) {
      return { measureIndex, noteIndex };
    } else if(noteIndex === 0) {
      let prevMeasure = measures[measureIndex - 1];
      if(prevMeasure.notes.length > 0) {
        return {
          measureIndex: measureIndex - 1,
          noteIndex: measures[measureIndex - 1].notes.length - 1
        };
      } else {
        return {
          measureIndex: measureIndex - 1,
          noteIndex: 0
        };
      }
    } else {
      return {
        measureIndex,
        noteIndex: noteIndex - 1
      };
    }
  }

  getUpperString = (stringIndex) => {
    return stringIndex === 5 ? 0 : stringIndex + 1;
  }

  getLowerString = (stringIndex) => {
    return stringIndex === 0 ? 5 : stringIndex - 1;
  }

  navigateCursor = (event) => {
    let { measureIndex, noteIndex, stringIndex } = this.state.currentEditingIndex;

    if(event.keyCode === 39) { // right arrow
      let newEditingIndex = this.getNextNote(measureIndex, noteIndex);
      if(newEditingIndex === 'NEW') {
        this.props.actions.insertMeasure(0);
        newEditingIndex = {
          stringIndex,
          measureIndex: measureIndex + 1,
          noteIndex: 0
        };
        this.setState({
          currentEditingIndex: newEditingIndex,
          currentPlayingNote: {
            measure: newEditingIndex.measureIndex,
            noteIndex: newEditingIndex.noteIndex
          }
        });
      } else {
        newEditingIndex.stringIndex = stringIndex;
        this.setState({
          currentEditingIndex: newEditingIndex,
          currentPlayingNote: {
            measure: newEditingIndex.measureIndex,
            noteIndex: newEditingIndex.noteIndex
          }
        });
      }
    } else if(event.keyCode === 37) { // left arrow
      let newEditingIndex = this.getPrevNote(measureIndex, noteIndex);
      newEditingIndex.stringIndex = stringIndex;
      this.setState({
        currentEditingIndex: newEditingIndex,
        currentPlayingNote: {
          measure: newEditingIndex.measureIndex,
          noteIndex: newEditingIndex.noteIndex
        }
      });
    } else if(event.keyCode === 38) { // up arrow
      event.preventDefault();
      let newEditingIndex = {
        stringIndex: this.getUpperString(stringIndex),
        noteIndex,
        measureIndex
      };
      this.setState({
        currentEditingIndex: newEditingIndex
      });
    } else if(event.keyCode === 40) { // down arrow
      event.preventDefault();
      let newEditingIndex = {
        stringIndex: this.getLowerString(stringIndex),
        noteIndex,
        measureIndex
      };
      this.setState({
        currentEditingIndex: newEditingIndex
      });
    }
  }

  editNote = (fret) => {
    this.props.actions.changeNote(this.state.currentEditingIndex, fret);
  }

  changeNoteLength = (duration) => {
    this.props.actions.changeNoteLength(this.state.currentEditingIndex, duration);
  }

  deleteNote = () => {
    const { noteIndex, measureIndex, stringIndex } = this.state.currentEditingIndex;
    let notes = this.props.track.measures[measureIndex].notes;

    if(notes.length > 1 && noteIndex === notes.length - 1 && notes[notes.length - 1].fret[0] === 'rest') {
      this.setState({
        currentEditingIndex: {
          stringIndex,
          measureIndex,
          noteIndex: noteIndex - 1
        }
      }, () => {
        this.props.actions.deleteNote({ stringIndex, measureIndex, noteIndex });
      });
    } else if(notes.length === 0) {
      this.props.actions.deleteMeasure(measureIndex);

      if(measureIndex === this.props.track.measures.length) {
        this.setState({
          currentEditingIndex: {
            stringIndex,
            measureIndex: measureIndex - 1,
            noteIndex: 0
          }
        });
      }
    } else {
      this.props.actions.deleteNote(this.state.currentEditingIndex);
    }
  }

  insertNote = () => {
    const { noteIndex, measureIndex, stringIndex } = this.state.currentEditingIndex;

    this.props.actions.insertNote(this.state.currentEditingIndex);

    if(this.props.track.measures[measureIndex].notes.length === 1) {
      this.setState({
        currentEditingIndex: {
          measureIndex,
          stringIndex,
          noteIndex: 0
        }
      });
    } else {
      this.setState({
        currentEditingIndex: {
          measureIndex,
          stringIndex,
          noteIndex: noteIndex + 1
        }
      });
    }
  }

  pasteNote = () => {
    const { measureIndex, noteIndex, stringIndex } = this.state.currentEditingIndex;

    this.props.actions.pasteNote(this.state.currentEditingIndex, this.props.clipboard);
    this.setState({
      currentEditingIndex: {
        measureIndex,
        noteIndex: this.props.track.measures[measureIndex].notes.length === 1 && noteIndex === 0 ? 0 : noteIndex + 1,
        stringIndex
      }
    });
  }

  handleKeyPress = (event) => {
    if((event.metaKey || event.ctrlKey) && event.keyCode === 67) { // cmd/ctrl+c
      event.preventDefault();
      return this.props.actions.copyNote(this.getCurrentNote());
    }
    if((event.metaKey || event.ctrlKey) && event.keyCode === 86) { // cmd/ctrl+v
      event.preventDefault();
      return this.pasteNote();
    }
    if((event.metaKey || event.ctrlKey) && event.keyCode === 88) { // cmd/ctrl+c
      event.preventDefault();
      const { noteIndex, measureIndex, stringIndex } = this.state.currentEditingIndex;
      let notes = this.props.track.measures[measureIndex].notes;
      if(notes.length > 1 && noteIndex === notes.length - 1) {
        const currentNote = this.getCurrentNote();

        this.setState({
          currentEditingIndex: {
            stringIndex,
            measureIndex,
            noteIndex: noteIndex - 1
          }
        }, () => {
          this.props.actions.cutNote({ noteIndex: noteIndex, measureIndex, stringIndex }, currentNote);
        });
      } else {
        return this.props.actions.cutNote({ noteIndex, measureIndex, stringIndex }, this.getCurrentNote());
      }
    }

    if(event.metaKey) {
      return;
    } else if(this.state.isPlaying && event.keyCode !== 32) {
      return;
    } else if(this.state.tuningModal || this.state.timeSignatureModal) {
      return;
    }

    if(event.keyCode <= 57 && event.keyCode >= 48) {
      return this.editNote(event.keyCode - 48);
    } else if(event.keyCode === 82 && !event.metaKey && !event.ctrlKey) {
      this.props.actions.changeNote(this.state.currentEditingIndex, 'rest');
    } else if(event.keyCode === 8) { // delete
      event.preventDefault();
      this.deleteNote();
    } else if(event.keyCode === 69) { // e
      return this.changeNoteLength('e');
    } else if(event.keyCode === 83) { // s
      return this.changeNoteLength('s');
    } else if(event.keyCode === 81) { // q
      return this.changeNoteLength('q');
    } else if(event.keyCode === 87) { // w
      return this.changeNoteLength('w');
    } else if(event.keyCode === 72 && !event.ctrlKey) { // h
      return this.changeNoteLength('h');
    } else if(event.keyCode === 73) { // i
      return this.insertNote();
    } else if(event.keyCode === 32) { // spacebar
      event.preventDefault();
      return this.state.isPlaying ? this.handleStop() : this.handlePlay();
    } else if(event.keyCode === 190) { // period
      this.props.actions.toggleNoteDotted(this.state.currentEditingIndex);
    } else {
      return this.navigateCursor(event);
    }
  }

  bpmChanged = (event) => {
    this.setState({
      bpm: event.target.value
    });
  }

  openTimeSignatureModal = () => {
    this.setState({
      timeSignatureModal: true
    });
  }

  closeModal = () => {
    this.setState({
      timeSignatureModal: false,
      tuningModal: false
    });
  }

  toggleLayout = () => {
    let layout = this.state.layout === 'page' ? 'linear' : 'page';
    this.setState({ layout });
  }

  openTuningModal = () => {
    this.setState({
      tuningModal: true
    });
  }

  render() {
    const { measures } = this.props.track;
    const { measureIndex } = this.state.currentEditingIndex;
    const timeSignature = measures[measureIndex] ? measures[measureIndex].timeSignature : '4/4';

    return (
      <div style={{ display: 'flex', flexDirection: 'column' }}>
        <EditorArea bpmChanged={this.bpmChanged}
          handlePlay={this.handlePlay}
          handleStop={this.handleStop}
          openModal={this.openTimeSignatureModal}
          openTuning={this.openTuningModal}
          toggleLayout={this.toggleLayout}
          bpm={this.state.bpm}
          timeSignature={timeSignature}
          layout={this.state.layout}
        />
        <TabRows track={measures} layout={this.state.layout}
          currentEditingIndex={this.state.currentEditingIndex}
          currentPlayingNote={this.state.currentPlayingNote}
          isPlaying={this.state.isPlaying}
          onClick={this.onNoteClick}
        />
        <TimeSignatureModal isOpen={this.state.timeSignatureModal} closeModal={this.closeModal}
          measureIndex={measureIndex} timeSignature={timeSignature}
        />
        <TuningModal isOpen={this.state.tuningModal} closeModal={this.closeModal} />
      </div>
    );
  }
}

function mapStateToProps(state) {
  return {
    track: state.tracks[state.currentTrackIndex],
    clipboard: state.clipboard
  };
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(Actions, dispatch)
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(App);
<|endoftext|>


<commit_before>'use strict';

var Client = require('node-rest-client').Client;
var querystring = require('querystring');
var urljoin = require('url-join');
var request = require('request');
var _initialised = false;
var _serviceUrlTemplate;
var _clientId;
var _clientSecret;
var _programCache;
var _tokenSafetyIntervalInSeconds = 30;

module.exports = {
    initialise: initialise,
    getClientToken: getClientToken,
    clearTokenCache: clearTokenCache,
    clearTokenCacheForProgram: clearTokenCacheForProgram,
    errorMessage: {
        noOptions: "initialise must be called with options",
        optionsNotAnObject: "options must be an object",
        neuronBaseUrlMustBeSpecified: "neuronBaseUrl must be set",
        neuronBaseUrlMustBeAString: "Neuron base url must be a string",
        neuronBaseUrlCannotBeBlank: "Neuron base url cannot be blank",
        noClientId: "clientId must be set",
        clientIdMustBeAString: "clientId must be a string",
        clientIdCannotBeBlank: "clientId cannot be blank",
        noClientSecret: "clientSecret must be specified",
        clientSecretMustBeAString: "clientSecret must be a string",
        clientSecretCannotBeBlank: "clientSecret cannot be blank",
        noInputs: "Input must be specified when getToken is called",
        inputsNotAnObject: "The first argument (inputs) on getToken must be an object",
        noCallback: "Callback must be specified when getToken is called",
        callbackNotAFunction: "callback must be a function",
        programNameRequired: "inputs.program name is required",
        programNameMustBeAString: "Program name must be a string",
        programNameCannotBeBlank: "Program name cannot be blank",
        notInitialised: "neuron-synapse has not yet been initialised",
        noAccessToken: "token object did not contain the property access_token",
        requestTimeout: 'request has expired',
        responseTimeout: 'response has expired'
    },
    _getServiceUrlTemplate: _getServiceUrlTemplate,
    _getCacheKey: _getCacheKey
};

function initialise(options) {
    if (!options) {
        throw new Error(module.exports.errorMessage.noOptions);
    }
    if (typeof (options) !== "object") {
        throw new Error(module.exports.errorMessage.optionsNotAnObject);
    }
    if (!options.neuronBaseUrl) {
        throw new Error(module.exports.errorMessage.neuronBaseUrlMustBeSpecified);
    }
    if (typeof (options.neuronBaseUrl) !== "string") {
        throw new Error(module.exports.errorMessage.neuronBaseUrlMustBeAString);
    }
    options.neuronBaseUrl = options.neuronBaseUrl.trim();
    if (options.neuronBaseUrl === "") {
        throw new Error(module.exports.errorMessage.neuronBaseUrlCannotBeBlank);
    }
    if (!options.clientId) {
        throw new Error(module.exports.errorMessage.noClientId);
    }
    if (typeof (options.clientId) !== "string") {
        throw new Error(module.exports.errorMessage.clientIdMustBeAString);
    }
    options.clientId = options.clientId.trim();
    if (options.clientId === "") {
        throw new Error(module.exports.errorMessage.clientIdCannotBeBlank);
    }

    if (!options.clientSecret) {
        throw new Error(module.exports.errorMessage.noClientSecret);
    }
    if (typeof (options.clientSecret) !== "string") {
        throw new Error(module.exports.errorMessage.clientSecretMustBeAString);
    }
    options.clientSecret = options.clientSecret.trim();
    if (options.clientSecret === "") {
        throw new Error(module.exports.errorMessage.clientSecretCannotBeBlank);
    }
    _initialised = true;
    clearTokenCache();
    _clientId = options.clientId;
    _clientSecret = options.clientSecret;
    _serviceUrlTemplate = urljoin(options.neuronBaseUrl, ':programName/oauth/token');
}

function getClientToken(inputs, callback) {
    if (!inputs) {
        return callback(new Error(module.exports.errorMessage.noInputs));
    }
    if (typeof (inputs) !== "object") {
        return callback(new Error(module.exports.errorMessage.inputsNotAnObject));
    }
    if (!callback) {
        throw new Error(module.exports.errorMessage.noCallback);
    }
    if (typeof (callback) !== "function") {
        throw new Error(module.exports.errorMessage.callbackNotAFunction);
    }
    if (!inputs.programName) {
        return callback(new Error(module.exports.errorMessage.programNameRequired));
    }
    if (typeof (inputs.programName) !== "string") {
        return callback(new Error(module.exports.errorMessage.programNameMustBeAString));
    }
    inputs.programName = inputs.programName.trim();
    if (inputs.programName === "") {
        return callback(new Error(module.exports.errorMessage.programNameCannotBeBlank));
    }
    if (_initialised === false) {
        return callback(new Error(module.exports.errorMessage.notInitialised));
    }
    if (!inputs.scope) {
        inputs.scope = "";
    }
    var cacheKey = _getCacheKey(inputs.scope);
    var token = _getValidTokenFromCache(inputs.programName, cacheKey);
    if (token) {
        return callback(null, token.access_token, "cacheHit");
    }

    var url = _serviceUrlTemplate.replace(':programName', inputs.programName);
    var options = {
        method: 'POST',
        uri: url,
        form: {
            "client_id": _clientId,
            "client_secret": _clientSecret,
            "grant_type": "client_credentials",
            "scope": inputs.scope
        },
        headers: {
            "Content-Type": "application/x-www-form-urlencoded"
        },
        timeout: 30000
    };

    request(options, function (error, response, body) {
        if (error) {
            if (error.code === 'ETIMEDOUT' && error.connect === true) {
                return callback(new Error(module.exports.errorMessage.requestTimeout));
            } else if (error.code === 'ETIMEDOUT') {
                return callback(new Error(module.exports.errorMessage.responseTimeout));
            }
            return callback(error);
        }
        if (response.statusCode !== 200) {
            return callback(new Error(body));
        }
        var token;
        try {
            token = JSON.parse(body);
        } catch (exception) {
            return callback(new Error("Error converting token string to JSON object, token string was : " + body));
        }
        if(!token){
            return callback(new Error("Token string resulted in a blank object, token string was : " + body));
        }
        if (!token.access_token) {
            return callback(new Error(module.exports.errorMessage.noAccessToken));
        }
        if (token.expires_in && token.expires_in > _tokenSafetyIntervalInSeconds) {
            _cacheToken(token, inputs.programName, cacheKey);
        }
        return callback(null, token.access_token, "cacheMiss");
    });
}

function clearTokenCache() {
    _programCache = {};
}

function clearTokenCacheForProgram(programName) {
    var lowerCaseProgramName = programName.toLowerCase();
    _programCache[lowerCaseProgramName] = {};
}

function _getServiceUrlTemplate() {
    return _serviceUrlTemplate;
}

function _getValidTokenFromCache(programName, cacheKey) {
    var thisProgramCache = _getEnsureProgramCacheExists(programName);
    var token = thisProgramCache[cacheKey];
    if (!token) {
        return null;
    }
    var now = new Date();
    if (now >= token.expiryDate) {
        return null;
    }
    return token;
}

function _cacheToken(token, programName, cacheKey) {
    _setExpiryDateOnToken(token);
    var thisProgramCache = _getEnsureProgramCacheExists(programName);
    thisProgramCache[cacheKey] = token;
}

function _getCacheKey(scope) {
    var inputScopeArray = scope.toLowerCase().split(' ');
    var validScopes = [];
    inputScopeArray.forEach(function (scope) {
        if (scope !== '') {
            validScopes.push(scope);
        }
    });
    if (validScopes.length === 0) {
        validScopes.push("none");
    }
    validScopes = validScopes.sort();
    var cacheKey = validScopes.join('');
    return cacheKey;
}

function _getEnsureProgramCacheExists(programName) {
    var lowerCaseProgramName = programName.toLowerCase();
    if (!_programCache[lowerCaseProgramName]) {
        _programCache[lowerCaseProgramName] = {};
    }
    return _programCache[lowerCaseProgramName];
}

function _setExpiryDateOnToken(token) {
    var secondsuntilTokenExpires = token.expires_in - _tokenSafetyIntervalInSeconds; //remove the tokenSafetyIntervalInSeconds to ensure that the token does not expire mid request
    var expiryDate = new Date();
    expiryDate.setSeconds(expiryDate.getSeconds() + secondsuntilTokenExpires);
    token.expiryDate = expiryDate;
}
<commit_msg>Removed the last remnants on node-rest-client<commit_after>'use strict';

var querystring = require('querystring');
var urljoin = require('url-join');
var request = require('request');
var _initialised = false;
var _serviceUrlTemplate;
var _clientId;
var _clientSecret;
var _programCache;
var _tokenSafetyIntervalInSeconds = 30;

module.exports = {
    initialise: initialise,
    getClientToken: getClientToken,
    clearTokenCache: clearTokenCache,
    clearTokenCacheForProgram: clearTokenCacheForProgram,
    errorMessage: {
        noOptions: "initialise must be called with options",
        optionsNotAnObject: "options must be an object",
        neuronBaseUrlMustBeSpecified: "neuronBaseUrl must be set",
        neuronBaseUrlMustBeAString: "Neuron base url must be a string",
        neuronBaseUrlCannotBeBlank: "Neuron base url cannot be blank",
        noClientId: "clientId must be set",
        clientIdMustBeAString: "clientId must be a string",
        clientIdCannotBeBlank: "clientId cannot be blank",
        noClientSecret: "clientSecret must be specified",
        clientSecretMustBeAString: "clientSecret must be a string",
        clientSecretCannotBeBlank: "clientSecret cannot be blank",
        noInputs: "Input must be specified when getToken is called",
        inputsNotAnObject: "The first argument (inputs) on getToken must be an object",
        noCallback: "Callback must be specified when getToken is called",
        callbackNotAFunction: "callback must be a function",
        programNameRequired: "inputs.program name is required",
        programNameMustBeAString: "Program name must be a string",
        programNameCannotBeBlank: "Program name cannot be blank",
        notInitialised: "neuron-synapse has not yet been initialised",
        noAccessToken: "token object did not contain the property access_token",
        requestTimeout: 'request has expired',
        responseTimeout: 'response has expired'
    },
    _getServiceUrlTemplate: _getServiceUrlTemplate,
    _getCacheKey: _getCacheKey
};

function initialise(options) {
    if (!options) {
        throw new Error(module.exports.errorMessage.noOptions);
    }
    if (typeof (options) !== "object") {
        throw new Error(module.exports.errorMessage.optionsNotAnObject);
    }
    if (!options.neuronBaseUrl) {
        throw new Error(module.exports.errorMessage.neuronBaseUrlMustBeSpecified);
    }
    if (typeof (options.neuronBaseUrl) !== "string") {
        throw new Error(module.exports.errorMessage.neuronBaseUrlMustBeAString);
    }
    options.neuronBaseUrl = options.neuronBaseUrl.trim();
    if (options.neuronBaseUrl === "") {
        throw new Error(module.exports.errorMessage.neuronBaseUrlCannotBeBlank);
    }
    if (!options.clientId) {
        throw new Error(module.exports.errorMessage.noClientId);
    }
    if (typeof (options.clientId) !== "string") {
        throw new Error(module.exports.errorMessage.clientIdMustBeAString);
    }
    options.clientId = options.clientId.trim();
    if (options.clientId === "") {
        throw new Error(module.exports.errorMessage.clientIdCannotBeBlank);
    }

    if (!options.clientSecret) {
        throw new Error(module.exports.errorMessage.noClientSecret);
    }
    if (typeof (options.clientSecret) !== "string") {
        throw new Error(module.exports.errorMessage.clientSecretMustBeAString);
    }
    options.clientSecret = options.clientSecret.trim();
    if (options.clientSecret === "") {
        throw new Error(module.exports.errorMessage.clientSecretCannotBeBlank);
    }
    _initialised = true;
    clearTokenCache();
    _clientId = options.clientId;
    _clientSecret = options.clientSecret;
    _serviceUrlTemplate = urljoin(options.neuronBaseUrl, ':programName/oauth/token');
}

function getClientToken(inputs, callback) {
    if (!inputs) {
        return callback(new Error(module.exports.errorMessage.noInputs));
    }
    if (typeof (inputs) !== "object") {
        return callback(new Error(module.exports.errorMessage.inputsNotAnObject));
    }
    if (!callback) {
        throw new Error(module.exports.errorMessage.noCallback);
    }
    if (typeof (callback) !== "function") {
        throw new Error(module.exports.errorMessage.callbackNotAFunction);
    }
    if (!inputs.programName) {
        return callback(new Error(module.exports.errorMessage.programNameRequired));
    }
    if (typeof (inputs.programName) !== "string") {
        return callback(new Error(module.exports.errorMessage.programNameMustBeAString));
    }
    inputs.programName = inputs.programName.trim();
    if (inputs.programName === "") {
        return callback(new Error(module.exports.errorMessage.programNameCannotBeBlank));
    }
    if (_initialised === false) {
        return callback(new Error(module.exports.errorMessage.notInitialised));
    }
    if (!inputs.scope) {
        inputs.scope = "";
    }
    var cacheKey = _getCacheKey(inputs.scope);
    var token = _getValidTokenFromCache(inputs.programName, cacheKey);
    if (token) {
        return callback(null, token.access_token, "cacheHit");
    }

    var url = _serviceUrlTemplate.replace(':programName', inputs.programName);
    var options = {
        method: 'POST',
        uri: url,
        form: {
            "client_id": _clientId,
            "client_secret": _clientSecret,
            "grant_type": "client_credentials",
            "scope": inputs.scope
        },
        headers: {
            "Content-Type": "application/x-www-form-urlencoded"
        },
        timeout: 30000
    };

    request(options, function (error, response, body) {
        if (error) {
            if (error.code === 'ETIMEDOUT' && error.connect === true) {
                return callback(new Error(module.exports.errorMessage.requestTimeout));
            } else if (error.code === 'ETIMEDOUT') {
                return callback(new Error(module.exports.errorMessage.responseTimeout));
            }
            return callback(error);
        }
        if (response.statusCode !== 200) {
            return callback(new Error(body));
        }
        var token;
        try {
            token = JSON.parse(body);
        } catch (exception) {
            return callback(new Error("Error converting token string to JSON object, token string was : " + body));
        }
        if(!token){
            return callback(new Error("Token string resulted in a blank object, token string was : " + body));
        }
        if (!token.access_token) {
            return callback(new Error(module.exports.errorMessage.noAccessToken));
        }
        if (token.expires_in && token.expires_in > _tokenSafetyIntervalInSeconds) {
            _cacheToken(token, inputs.programName, cacheKey);
        }
        return callback(null, token.access_token, "cacheMiss");
    });
}

function clearTokenCache() {
    _programCache = {};
}

function clearTokenCacheForProgram(programName) {
    var lowerCaseProgramName = programName.toLowerCase();
    _programCache[lowerCaseProgramName] = {};
}

function _getServiceUrlTemplate() {
    return _serviceUrlTemplate;
}

function _getValidTokenFromCache(programName, cacheKey) {
    var thisProgramCache = _getEnsureProgramCacheExists(programName);
    var token = thisProgramCache[cacheKey];
    if (!token) {
        return null;
    }
    var now = new Date();
    if (now >= token.expiryDate) {
        return null;
    }
    return token;
}

function _cacheToken(token, programName, cacheKey) {
    _setExpiryDateOnToken(token);
    var thisProgramCache = _getEnsureProgramCacheExists(programName);
    thisProgramCache[cacheKey] = token;
}

function _getCacheKey(scope) {
    var inputScopeArray = scope.toLowerCase().split(' ');
    var validScopes = [];
    inputScopeArray.forEach(function (scope) {
        if (scope !== '') {
            validScopes.push(scope);
        }
    });
    if (validScopes.length === 0) {
        validScopes.push("none");
    }
    validScopes = validScopes.sort();
    var cacheKey = validScopes.join('');
    return cacheKey;
}

function _getEnsureProgramCacheExists(programName) {
    var lowerCaseProgramName = programName.toLowerCase();
    if (!_programCache[lowerCaseProgramName]) {
        _programCache[lowerCaseProgramName] = {};
    }
    return _programCache[lowerCaseProgramName];
}

function _setExpiryDateOnToken(token) {
    var secondsuntilTokenExpires = token.expires_in - _tokenSafetyIntervalInSeconds; //remove the tokenSafetyIntervalInSeconds to ensure that the token does not expire mid request
    var expiryDate = new Date();
    expiryDate.setSeconds(expiryDate.getSeconds() + secondsuntilTokenExpires);
    token.expiryDate = expiryDate;
}
<|endoftext|>


<commit_before>/* ***** BEGIN LICENSE BLOCK *****
 *   Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is WebTabs.
 *
 * The Initial Developer of the Original Code is
 * David Ascher.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Dave Townsend <dtownsend@oxymoronical.com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://webapptabs/modules/LogManager.jsm");
LogManager.createLogger(this, "webtab");

const Cc = Components.classes;
const Ci = Components.interfaces;
const Ce = Components.Exception;

var EXTPREFNAME = "extension.webapptabs.data";

const WEBAPP_SCHEMA = 1;
const DEFAULT_WEBAPPS = [{
  'name': 'Google Calendar',
  'href': 'https://calendar.google.com/',
  'icon': 'https://calendar.google.com/googlecalendar/images/favicon.ico',
}, {
  'name': 'Facebook',
  'href': 'https://www.facebook.com/',
  'icon': 'https://www.facebook.com/favicon.ico',
}, {
  'name': 'Google+',
  'href': 'https://plus.google.com/',
  'icon': 'https://ssl.gstatic.com/s2/oz/images/favicon.ico',
}, {
  'name': 'Twitter',
  'href': 'https://www.twitter.com',
  'icon': 'https://www.twitter.com/favicon.ico',
}];

var webtabs = {
  // A map from webapp ID to webapp descriptor
  tabDescsMap: null,
  // A list of webapp descriptors
  tabDescsList: null,

  // A reference to the default window content area click handler
  _origContentAreaClick: null,

  onLoad: function() {
    this.tabDescsMap = {};
    this.loadPrefs();
    this.tabDescsList.forEach(function(aDesc) {
      this.createWebAppButton(aDesc);
    }, this);

    this._origContentAreaClick = contentAreaClick;
    window.contentAreaClick = this.newContentAreaClick;
  },

  onUnload: function() {
    window.contentAreaClick = this._origContentAreaClick;

    this.tabDescsList.forEach(function(aDesc) {
      this.removeWebAppButton(aDesc);
    }, this);
  },

  newContentAreaClick: function(aEvent) {
    // If you click in a link to a website we have a shortcut for, we load it in a tab
    let href = hRefForClickEvent(aEvent);
    for (let [, tabDesc] in Iterator(webtabs.tabDescsList)) {
      if (href.indexOf(tabDesc['options']['contentPage']) == 0) {
        tabDesc.options.contentPage = href;
        let tabmail = document.getElementById('tabmail');
        let info = tabmail.openTab("contentTab", tabDesc.options);
        info.tabNode.image=tabDesc.icon;
        aEvent.preventDefault()
        return;
      }
    }
    this._origContentAreaClick(aEvent);
  },

  createWebAppButton: function(aDesc) {
    if (!aDesc.id) {
      aDesc.id = aDesc.name.replace(' ', '_', 'g');
    }

    if (!webtabs.tabDescsMap[aDesc.id]) {
      this.tabDescsMap[aDesc.id] = aDesc;
    }

    let tabmailButtons = document.getElementById("tabmail-buttons");
    let button = document.createElement("toolbarbutton");
    button.setAttribute("id", aDesc.id);
    button.setAttribute("class", "webtab");
    button.setAttribute("style", "list-style-image: url('" + aDesc.icon + "')");
    button.setAttribute("tooltiptext", aDesc.name);
    tabmailButtons.appendChild(button);

    button.addEventListener("command", function() {
      webtabs.openTab(aDesc);
    }, false);
  },

  removeWebAppButton: function(aDesc) {
    let button = document.getElementById(aDesc.id);
    if (button)
      button.parentNode.removeChild(button);
    else
      ERROR("Missing webapp button for " + aDesc.name);
  },

  openTab: function(aDesc) {
    let url = NetUtil.newURI(aDesc.href);
    let regex = new RegExp("^http[s]?://" + url.hostname + "/");

    let tabmail = document.getElementById('tabmail');
    let info = tabmail.openTab("contentTab", {
      contentPage: aDesc.href,
      clickHandler: "return true;"
    });

    info.tabNode.image = aDesc.icon;

    info.browser.addEventListener("click", function(aEvent) {
      specialTabs.siteClickHandler(aEvent, regex);
    }, false);
  },

  siteClickHandler: function(aEvent) {
  },

  persistPrefs: function() {
    let jsondata = JSON.stringify({
      schema: WEBAPP_SCHEMA,
      webapps: this.tabDescsList,
    })
    Application.prefs.setValue(EXTPREFNAME, jsondata);
  },

  loadPrefs: function() {
    try {
      if (Application.prefs.has(EXTPREFNAME)) {
        let data = JSON.parse(Application.prefs.get(EXTPREFNAME).value);
        let schema = 0;
        if ("schema" in data)
          schema = data.schema;

        switch (schema) {
        case WEBAPP_SCHEMA:
          this.tabDescsList = data.webapps;
          break;
        default:
          throw new Ce("Unknown webapps data schema " + schema);
        }

        return;
      }
    }
    catch (e) {
      ERROR("Failed to read webapps from config", e);
    }

    this.tabDescsList = DEFAULT_WEBAPPS;
    this.persistPrefs();
  }
};

var OverlayListener = {
  load: function() {
    webtabs.onLoad();
  },

  unload: function() {
    webtabs.onUnload();
  }
};
<commit_msg>Keep a map of webapp tabs and switch to the tab if it is already open. Closes #2<commit_after>/* ***** BEGIN LICENSE BLOCK *****
 *   Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is WebTabs.
 *
 * The Initial Developer of the Original Code is
 * David Ascher.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Dave Townsend <dtownsend@oxymoronical.com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://webapptabs/modules/LogManager.jsm");
LogManager.createLogger(this, "webtab");

const Cc = Components.classes;
const Ci = Components.interfaces;
const Ce = Components.Exception;

var EXTPREFNAME = "extension.webapptabs.data";

const WEBAPP_SCHEMA = 1;
const DEFAULT_WEBAPPS = [{
  'name': 'Google Calendar',
  'href': 'https://calendar.google.com/',
  'icon': 'https://calendar.google.com/googlecalendar/images/favicon.ico',
}, {
  'name': 'Facebook',
  'href': 'https://www.facebook.com/',
  'icon': 'https://www.facebook.com/favicon.ico',
}, {
  'name': 'Google+',
  'href': 'https://plus.google.com/',
  'icon': 'https://ssl.gstatic.com/s2/oz/images/favicon.ico',
}, {
  'name': 'Twitter',
  'href': 'https://www.twitter.com',
  'icon': 'https://www.twitter.com/favicon.ico',
}];

var webtabs = {
  // A list of webapp descriptors
  webappList: null,
  // A WeakMap from webapp to tab
  webappTabMap: null,

  // A reference to the default window content area click handler
  _origContentAreaClick: null,

  onLoad: function() {
    this.webappTabMap = new WeakMap();
    this.loadPrefs();
    this.webappList.forEach(function(aDesc) {
      this.createWebAppButton(aDesc);
    }, this);

    this._origContentAreaClick = contentAreaClick;
    window.contentAreaClick = this.newContentAreaClick;
  },

  onUnload: function() {
    window.contentAreaClick = this._origContentAreaClick;

    this.webappList.forEach(function(aDesc) {
      this.removeWebAppButton(aDesc);
    }, this);
  },

  newContentAreaClick: function(aEvent) {
    // If you click in a link to a website we have a shortcut for, we load it in a tab
    let href = hRefForClickEvent(aEvent);
    for (let [, tabDesc] in Iterator(webtabs.webappList)) {
      if (href.indexOf(tabDesc['options']['contentPage']) == 0) {
        tabDesc.options.contentPage = href;
        let tabmail = document.getElementById('tabmail');
        let info = tabmail.openTab("contentTab", tabDesc.options);
        info.tabNode.image=tabDesc.icon;
        aEvent.preventDefault()
        return;
      }
    }
    this._origContentAreaClick(aEvent);
  },

  createWebAppButton: function(aDesc) {
    if (!aDesc.id) {
      aDesc.id = aDesc.name.replace(' ', '_', 'g');
    }

    let tabmailButtons = document.getElementById("tabmail-buttons");
    let button = document.createElement("toolbarbutton");
    button.setAttribute("id", aDesc.id);
    button.setAttribute("class", "webtab");
    button.setAttribute("style", "list-style-image: url('" + aDesc.icon + "')");
    button.setAttribute("tooltiptext", aDesc.name);
    tabmailButtons.appendChild(button);

    button.addEventListener("command", function() {
      try {
        webtabs.openTab(aDesc);
      }
      catch (e) {
        ERROR("Failed to open webapp", e);
      }
    }, false);
  },

  removeWebAppButton: function(aDesc) {
    let button = document.getElementById(aDesc.id);
    if (button)
      button.parentNode.removeChild(button);
    else
      ERROR("Missing webapp button for " + aDesc.name);
  },

  getTabInfoForWebApp: function(aDesc) {
    if (!this.webappTabMap.has(aDesc))
      return null;

    let info = this.webappTabMap.get(aDesc);
    if (!info)
      return null;

    // Check that this tabinfo is still in the UI
    let node = info.browser;
    while (node && node != node.ownerDocument.documentElement)
      node = node.parentNode;

    if (node)
      return info;
    return null;
  },

  openTab: function(aDesc) {
    let tabmail = document.getElementById('tabmail');

    let info = this.getTabInfoForWebApp(aDesc);
    if (info) {
      tabmail.switchToTab(info);
      return;
    }

    let url = NetUtil.newURI(aDesc.href);
    let regex = new RegExp("^http[s]?://" + url.hostname + "/");

    info = tabmail.openTab("contentTab", {
      contentPage: aDesc.href,
      clickHandler: "return true;"
    });
    LOG(info);

    this.webappTabMap.set(aDesc, info);

    info.browser.addEventListener("click", function(aEvent) {
      specialTabs.siteClickHandler(aEvent, regex);
    }, false);
  },

  siteClickHandler: function(aEvent) {
  },

  persistPrefs: function() {
    let jsondata = JSON.stringify({
      schema: WEBAPP_SCHEMA,
      webapps: this.webappList,
    })
    Application.prefs.setValue(EXTPREFNAME, jsondata);
  },

  loadPrefs: function() {
    try {
      if (Application.prefs.has(EXTPREFNAME)) {
        let data = JSON.parse(Application.prefs.get(EXTPREFNAME).value);
        let schema = 0;
        if ("schema" in data)
          schema = data.schema;

        switch (schema) {
        case WEBAPP_SCHEMA:
          this.webappList = data.webapps;
          break;
        default:
          throw new Ce("Unknown webapps data schema " + schema);
        }

        return;
      }
    }
    catch (e) {
      ERROR("Failed to read webapps from config", e);
    }

    this.webappList = DEFAULT_WEBAPPS;
    this.persistPrefs();
  }
};

var OverlayListener = {
  load: function() {
    webtabs.onLoad();
  },

  unload: function() {
    webtabs.onUnload();
  }
};
<|endoftext|>


<commit_before>define(function () {

    function OnDataChange (bezl) {
        if (bezl.data.ReportListing) {
            bezl.vars.reportListingLoading = false;
        }

        if (bezl.data.Report) {
            var sliceSize = 1024;
            var byteCharacters = atob(bezl.data.Report);
            var bytesLength = byteCharacters.length;
            var slicesCount = Math.ceil(bytesLength / sliceSize);
            var byteArrays = new Array(slicesCount);
            for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
            var begin = sliceIndex * sliceSize;
            var end = Math.min(begin + sliceSize, bytesLength);
            var bytes = new Array(end - begin);
            for (var offset = begin, i = 0 ; offset < end; ++i, ++offset) {
                bytes[i] = byteCharacters[offset].charCodeAt(0);
            }
            byteArrays[sliceIndex] = new Uint8Array(bytes);
            }

            var file = new Blob(byteArrays, {type: 'application/pdf'});
            var fileURL = URL.createObjectURL(file);
            var viewer = $(bezl.container.nativeElement).find('#viewer')[0];
            viewer.src = fileURL;
            bezl.vars.reportLoading = false;
        }
    }

    return {
        onDataChange: OnDataChange
    }
});<commit_msg>Updated logic for small screens to do a save as instead of iframe for report viewer window<commit_after>define(["./report.js"], function (report) {

    function OnDataChange (bezl) {
        if (bezl.data.ReportListing) {
            bezl.vars.reportListingLoading = false;
        }

        if (bezl.data.Report) {
            var sliceSize = 1024;
            var byteCharacters = atob(bezl.data.Report);
            var bytesLength = byteCharacters.length;
            var slicesCount = Math.ceil(bytesLength / sliceSize);
            var byteArrays = new Array(slicesCount);
            for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
            var begin = sliceIndex * sliceSize;
            var end = Math.min(begin + sliceSize, bytesLength);
            var bytes = new Array(end - begin);
            for (var offset = begin, i = 0 ; offset < end; ++i, ++offset) {
                bytes[i] = byteCharacters[offset].charCodeAt(0);
            }
            byteArrays[sliceIndex] = new Uint8Array(bytes);
            }

            var file = new Blob(byteArrays, {type: 'application/pdf'});

            if (screen.width <= 480) {
                saveAs(file);
                report.back(bezl);
            } else {
                var fileURL = URL.createObjectURL(file);
                var viewer = $(bezl.container.nativeElement).find('#viewer')[0];
                viewer.src = fileURL;
            }

            bezl.vars.reportLoading = false;
        }
    }

    return {
        onDataChange: OnDataChange
    }
});<|endoftext|>


<commit_before>#!/usr/bin/env node

var program = require("commander");
var _ = require("lodash");
var utils = require("./utils");<commit_msg>Add directive generator<commit_after>#!/usr/bin/env node

const program = require("commander");
const _ = require("lodash");
const path = require("path");
const utils = require("./utils");
var dest = "";

program
    .usage("<directive-name> [options]")
    .arguments("<directive-name>")
    .action(function (directiveName) {
        cmdDirectiveName = directiveName;
    })
    .option("-r, --restrict <restriction>", "Restrict the directive as attribute, element, class or comment. [A, E, C, M]. Could be multiple values like AE.")
    .option("-a, --ctrl-alias <alias>", "Alias for the controller inside the directive. Defaults to $ctrl.")
    .option("-t, --template", "Generate a template along with the directive.")
    .option("-s, --stylesheet", "Generate a stylesheet along with the directive.")
    .parse(process.argv);

if (typeof cmdDirectiveName === "undefined") {
    console.log("You must specify a name for the directive.");
    process.exit(1);
}

program.ctrlAlias = program.ctrlAlias || "$ctrl";

cmdDirectiveName = (utils.isHyphenated(cmdDirectiveName)) ? cmdDirectiveName.toLowerCase() : cmdDirectiveName;

//dest = path.join(process.cwd(), utils.hyphenate(cmdDirectiveName));

var vals = {
    restrict: !!program.restrict,
    restriction: program.restrict,
    pName: utils.pascalCase(_.camelCase(cmdDirectiveName)),
    name: _.camelCase(cmdDirectiveName),
    ctrlAlias: program.ctrlAlias,
    hName: utils.hyphenate(cmdDirectiveName),
    decoratorPath: utils.getDecoratorPath()
};

var tpls = utils.compileTemplates(utils.readTemplates("directive"), vals, cmdDirectiveName);
var ctrlTpl = utils.compileTemplates(utils.readTemplate("module", "_name.controller.ts"), vals, cmdDirectiveName);

tpls = _.extend(tpls, ctrlTpl);

if (program.template || (!!program.restrict && program.restrict.indexOf('E') > -1)) {
    var htmlTpl = utils.compileTemplates(utils.readTemplate("module", "_name.tpl.html"), vals, cmdDirectiveName);

    tpls = _.extend(tpls, htmlTpl);
}

if (program.stylesheet) {
    var scssTpl = utils.compileTemplates(utils.readTemplate("module", "_name.scss"), vals, cmdDirectiveName);

    tpls = _.extend(tpls, scssTpl);
}

utils.writeFiles(tpls, dest);<|endoftext|>


<commit_before>function TBError(){
  navigator.notification.alert("Error!");
};
function TBNothing(){
  console.log("TB NOTHING IS CALLED!");
};

/**
* Function Helpers
* @param {String} divName   Id of the div
* @return {top:y, left:x}   Returns an object with position coordinates
*/
function getPosition(divName){
  pubDiv = document.getElementById(divName);

  // Get the position of element
  var curtop = curleft = 0;
  if(pubDiv.offsetParent){
    do{
      curleft += pubDiv.offsetLeft;
      curtop += pubDiv.offsetTop;
    }while(pubDiv = pubDiv.offsetParent);
  }
  return {top:curtop, left:curleft};
}

/**
* replaceWithObject  Replace input divName with object element
* @param {String}, {String} divName, connectionId   Id of the div
* @return {top:y, left:x}   Returns an object with position coordinates
*/
function replaceWithObject(divName, connectionId, properties){
  // Replace and add to streamsConnected
  var newId = "TBStreamConnection"+connectionId;
  var oldDiv = document.getElementById(divName);
  var objDiv = document.createElement("object");
  oldDiv.parentNode.replaceChild(objDiv, oldDiv);

  // Setting object Attributes
  objDiv.id = newId;
  objDiv.style.width = properties.width+"px";
  objDiv.style.height = properties.height+"px";
  objDiv.setAttribute('cid',connectionId);
  objDiv.textContext = connectionId;
  objDiv.className = 'TBstreamObject';
  return getPosition(objDiv.id);
}

/**
 * TBSession Object
 *
 */
function TBSession(){
    var self = this;

    this.connect = function(apiKey, token, properties){
        console.log("JS: Connect Called");
        self.apiKey = apiKey;
        self.token = token;
        Cordova.exec(self.sessionConnectedHandler, TBError, "Tokbox", "connect", [self.apiKey, self.token] );

        // Housekeeping Listeners
        Cordova.exec(self.streamDisconnectedHandler, TBError, "Tokbox", "streamDisconnectedHandler", [] );
        return;
    };
    this.disconnect = function(){
      Cordova.exec(self.streamDisconnectedHandler, TBError, "Tokbox", "disconnect", [] );
    };

    this.publish = function(divName, properties){
      console.log("JS: Publish Called");
      var width = 320, height = 240;
      if(properties){
        if(properties.width){
          width = properties.width;
        }
        if(properties.height){
          height = properties.height;
        }
      }
      pubProperties = {width:width, height:height};
      var position = replaceWithObject(divName, self.connection.connectionId, pubProperties);
      // Would like to pass into exec as {top:35, left:3535, width:35, height:458}
      return Cordova.exec(TBNothing, TBError, "Tokbox", "publish", [position.top, position.left, pubProperties.width, pubProperties.height] );
    };

    this.unpublish = function(){
      return Cordova.exec(TBNothing, TBError, "Tokbox", "unpublish", [] );
    };

    this.subscribe = function(stream, divName, properties){
      console.log("JS: Subscribe Called");
      var connectionId = stream.connection.connectionId;
      var width = 320, height = 240;
      if(properties){
        if(properties.width){
          width = properties.width;
        }
        if(properties.height){
          height = properties.height;
        }
      }
      var property = {width:width, height:height};
      var position = replaceWithObject(divName, connectionId, property);
      return Cordova.exec(TBNothing, TBError, "Tokbox", "subscribe", [connectionId, position.top, position.left, property.width, property.height] );
    };

    this.addEventListener = function(event, handler){
        console.log("JS: Add Event Listener Called");

        // Set Handlers based on Events
        if(event == 'sessionConnected'){
          // Parse information returned from iOS before calling handler
          self.sessionConnectedHandler = function(response){
            self.connection = {connectionId:response};
            return handler({streams:[]});
          }
        }else if(event == 'streamCreated'){
          // Parse information returned from iOS before calling handler
          self.streamCreatedHandler = function(response){
            var arr = response.split(' ');
            var stream = {connection:{connectionId:arr[0]}, streamId:arr[1]};
            return handler({streams:[stream]});
          };

          // Set up Stream Created Handler: Could receive many callbacks
          Cordova.exec(self.streamCreatedHandler, TBNothing, "Tokbox", "addStreamCreatedEvent", [] );
        }
    };

    // Housekeeping:
    this.streamDisconnectedHandler = function(connectionId){
      console.log("JS: Diconnected Handler Executed");
      var elementId = "TBStreamConnection"+connectionId;
      var element = document.getElementById(elementId);
      element.parentNode.removeChild(element);
      self.updateObjects();
      return;
    }

    // When stream disconnects, this function repositions all objects
    this.updateObjects = function(){
      console.log("JS: Objects being updated");
      var objects = document.getElementsByClassName('TBstreamObject')
      for(var i=0; i<objects.length; i++ ){
        console.log("JS: Object updated");
        var cid = objects[i].getAttribute('cid');
        var id = objects[i].id;
        var position = getPosition(id);
        Cordova.exec(TBNothing, TBError, "Tokbox", "updateView", [cid, position.top, position.left] );
      }
      return
    };
};

var TB = {
    initSession: function(sid){
        var result = new TBSession();
        result.sessionId = sid;
        Cordova.exec(TBNothing, TBNothing, "Tokbox", "initSession", [result.sessionId] );
        return result;
    }
};
<commit_msg>phonegap js<commit_after>function TBError(error){
  navigator.notification.alert(error);
};
function TBNothing(){
  console.log("TB NOTHING IS CALLED!");
};

function getPosition(divName){
  pubDiv = document.getElementById(divName);

  // Get the position of element
  var curtop = curleft = 0;
  if(pubDiv.offsetParent){
    do{
      curleft += pubDiv.offsetLeft;
      curtop += pubDiv.offsetTop;
    }while(pubDiv = pubDiv.offsetParent);
  }
  return {top:curtop, left:curleft};
};

function replaceWithObject(divName, streamId, properties){
  // Replace and add to streamsConnected
  var newId = "TBStreamConnection"+streamId;
  var oldDiv = document.getElementById(divName);
  var objDiv = document.createElement("object");
  oldDiv.parentNode.replaceChild(objDiv, oldDiv);

  // Setting object Attributes
  objDiv.id = newId;
  objDiv.style.width = properties.width+"px";
  objDiv.style.height = properties.height+"px";
  objDiv.setAttribute('streamId',streamId);
  objDiv.textContext = streamId;
  objDiv.className = 'TBstreamObject';
  return getPosition(objDiv.id);
};

/**
 * TBSubscriber Object
 *
 */
function TBSubscriber(stream, divName, properties, env){
  console.log("JS: Subscribing");
  var width = 320, height = 240, subscribeToVideo="true";
  if(properties){
    if(properties.width){
      width = properties.width;
    }
    if(properties.height){
      height = properties.height;
    }
    if(properties.subscribeToVideo === false){
      subscribeToVideo="false";
    }
  }
  var property = {width:width, height:height};
  var position = replaceWithObject(divName, stream.streamId, property);
  Cordova.exec(TBNothing, TBError, "Tokbox", "subscribe", [stream.streamId, position.top, position.left, property.width, property.height, subscribeToVideo] );
}

/**
 * TBPublisher Object
 *
 */
function TBPublisher(divName, properties, env){
      console.log("JS: Publish Called");
      var width = 160, height = 120, name="", publishAudio="true", publishVideo="true";
      if(properties){
        if(properties.width){
          width = properties.width;
        }
        if(properties.height){
          height = properties.height;
        }
        if(properties.name){
          name = properties.name;
        }
        if(properties.publishAudio===false){
          publishAudio="false"
        }
        if(properties.publishVideo===false){
          publishVideo="false"
        }
      }
      var pubProperties = {width:width, height:height};
      var position = replaceWithObject(divName, env.connection.connectionId, pubProperties);
      //Cordova.exec(TBNothing, TBError, "Tokbox", "publish", [position.top, position.left, pubProperties.width, pubProperties.height, name] );
      Cordova.exec(TBNothing, TBError, "Tokbox", "publish", [position.top, position.left, pubProperties.width, pubProperties.height, name, publishAudio, publishVideo] );
}

/**
 * TBSession Object
 *
 */
function TBSession(sid, production){
    var self = this;
    self.sessionId = sid;

    // production is set as strings because NSStrings are most reliable for Phonegap Plugins
    if(production){
      self.production = "true";
    }else{
      self.production="false";
    }
    // ios: InitSession creates an OTSession Object with given sessionId
    Cordova.exec(TBNothing, TBNothing, "Tokbox", "initSession", [self.sessionId, self.production] );

    this.cleanUpDom = function(){
      // Remove all dom objects:
      var objects = document.getElementsByClassName('TBstreamObject');
      for(var i = 0; i < objects.length; i++) {
        var element = objects[i];
        element.parentNode.removeChild(element);
      }
    };
    this.sessionDisconnectedHandler = function(event){
      console.log("JS: Session Disconnected Handler Called");
      self.cleanUpDom();
    };

    this.addEventListener = function(event, handler){
        console.log("JS: Add Event Listener Called");

        // Set Handlers based on Events
        // Events: sessionConnected, sessionDisconnected, streamCreated, streamDestroyed
        if(event == 'sessionConnected'){
          // Parse information returned from iOS before calling handler
          self.sessionConnectedHandler = function(event){
            self.connection = event.connection;
            // When user first connect, there are no streams in the session
            return handler(event);
          }
        }else if(event == 'streamCreated'){
          // Parse information returned from iOS before calling handler
          self.streamCreatedHandler = function(response){
            var arr = response.split(' ');
            var stream = {connection:{connectionId:arr[0]}, streamId:arr[1]};
            return handler({streams:[stream]});
          };
          // ios: After setting up function, set up listener in ios
          Cordova.exec(self.streamCreatedHandler, TBNothing, "Tokbox", "streamCreatedHandler", [] );
        }else if(event=='sessionDisconnected'){
          self.sessionDisconnectedHandler = function(event){
            self.cleanUpDom();
            return handler(event)
          }
        }
    };

    this.connect = function(apiKey, token, properties){
        console.log("JS: Connect Called");
        self.apiKey = apiKey;
        self.token = token;
        // ios: Set up key/token, and call _session connectWithApiKey
        Cordova.exec(self.sessionConnectedHandler, TBError, "Tokbox", "connect", [self.apiKey, self.token] );

        // Housekeeping Listeners: Session needs to be removed from DOM after being created
        Cordova.exec(self.streamDisconnectedHandler, TBError, "Tokbox", "streamDisconnectedHandler", [] );
        Cordova.exec(self.sessionDisconnectedHandler, TBError, "Tokbox", "sessionDisconnectedHandler", [] );
        return;
    };

    this.disconnect = function(){
      Cordova.exec(self.sessionDisconnectedHandler, TBError, "Tokbox", "disconnect", [] );
    };

    this.publish = function(divName, properties){
      self.publisher = new TBPublisher(divName, properties, self);
      return self.publisher
    };

    this.unpublish = function(){
      var elementId = "TBStreamConnection"+self.connection.connectionId;
      var element = document.getElementById(elementId);
      if(element){
        element.parentNode.removeChild(element);
        self.updateObjects();
      }
      return Cordova.exec(TBNothing, TBError, "Tokbox", "unpublish", [] );
    };

    this.subscribe = function(stream, divName, properties){
      return new TBSubscriber(stream, divName, properties, self);
    };

    // Housekeeping:
    this.streamDisconnectedHandler = function(streamId){
      console.log("JS: Stream Disconnected Handler Executed");
      var elementId = "TBStreamConnection"+streamId;
      var element = document.getElementById(elementId);
      if(element){
        element.parentNode.removeChild(element);
        self.updateObjects();
      }
      return;
    };

    // When stream disconnects, this function repositions all objects
    this.updateObjects = function(){
      console.log("JS: Objects being updated");
      var objects = document.getElementsByClassName('TBstreamObject')
      for(var i=0; i<objects.length; i++ ){
        console.log("JS: Object updated");
        var streamId = objects[i].getAttribute('streamId');
        var id = objects[i].id;
        var position = getPosition(id);
        Cordova.exec(TBNothing, TBError, "Tokbox", "updateView", [streamId, position.top, position.left] );
      }
      return
    };
};

var TB = {
    initSession: function(sid, production){
      return new TBSession(sid, production);
    },
    setLogLevel: function(a){
     console.log("Log Level Set");
    },
    addEventListener: function(event, handler){
      if(event=="exception"){
        console.log("JS: TB Exception Handler added");
        Cordova.exec(handler, TBError, "Tokbox", "exceptionHandler", [] );
      }
    }
};
<|endoftext|>


<commit_before>/*jslint indent: 2, nomen: true, maxlen: 120 */
/*global require */

(function () {
  'use strict';
  var Foxx = require('org/arangodb/foxx'),
    _ = require('underscore'),
    Graph = require('./foxx_generator/graph').Graph,
    Generator,
    TransitionContext,
    defaultsForStateOptions,
    mediaTypes;

  mediaTypes = {
    'application/vnd.api+json': require('./foxx_generator/json_api').mediaType,
    'application/vnd.siren+json': require('./foxx_generator/siren').mediaType
  };

  TransitionContext = function (Transition, transitions, graph, controller) {
    this.Transition = Transition;
    this.transitions = transitions;
    this.graph = graph;
    this.controller = controller;
  };

  _.extend(TransitionContext.prototype, {
    inverseTransition: function (name, options) {
      var ReverseTransition = this.Transition.reverse(name, options.to);
      this.transitions[name] = new ReverseTransition(this.graph, this.controller);
    }
  });

  Generator = function (name, options) {
    this.graph = new Graph(name, options.applicationContext);
    this.mediaType = mediaTypes[options.mediaType];
    this.controller = new Foxx.Controller(options.applicationContext, options);
    this.states = {};
    this.transitions = _.reduce(this.mediaType.transitions, function (transitions, tuple) {
      transitions[tuple.name] = new tuple.Transition(this.graph, this.controller);
      return transitions;
    }, {}, this);
  };

  defaultsForStateOptions = {
    parameterized: false,
    verb: 'post',
    maxFailures: 1,
    queue: 'defaultQueue'
  };

  _.extend(Generator.prototype, {
    addStartState: function (options) {
      var name = '',
        state = new this.mediaType.State(name, this.graph, false);
      state.addTransitions(options.transitions, this.transitions);
      state.setAsStart(this.controller);
      this.states[name] = state;
    },

    addState: function (name, opts) {
      var options = _.defaults(opts, defaultsForStateOptions),
        state = new this.mediaType.State(name, this.graph, options.parameterized);

      state.configure(options, this.mediaType, this.states);
      state.addTransitions(options.transitions, this.transitions);

      this.states[name] = state;
    },

    defineTransition: function (name, options) {
      var Transition,
        semantics = options.semantics || 'follow',
        condition = options.condition || function () { return true; },
        precondition = options.precondition || condition,
        context;

      Transition = this.mediaType.Transition.extend({
        collectionBaseName: name,
        relationType: options.to,
        relationName: name,
        parameters: options.parameters,
        description: options.description,
        semantics: semantics,
        condition: condition,
        precondition: precondition
      });

      context = new TransitionContext(Transition, this.transitions, this.graph, this.controller);

      this.transitions[name] = new Transition(this.graph, this.controller);
      return context;
    },

    generate: function () {
      _.each(this.states, function (state) {
        state.applyTransitions(this.states);
      }, this);
    }
  });

  exports.Generator = Generator;
}());
<commit_msg>Refactor defineTransition<commit_after>/*jslint indent: 2, nomen: true, maxlen: 120 */
/*global require */

(function () {
  'use strict';
  var Foxx = require('org/arangodb/foxx'),
    _ = require('underscore'),
    Graph = require('./foxx_generator/graph').Graph,
    Generator,
    TransitionContext,
    defaultsForStateOptions,
    defaultsForTransitionOptions,
    mediaTypes;

  mediaTypes = {
    'application/vnd.api+json': require('./foxx_generator/json_api').mediaType,
    'application/vnd.siren+json': require('./foxx_generator/siren').mediaType
  };

  TransitionContext = function (Transition, transitions, graph, controller) {
    this.Transition = Transition;
    this.transitions = transitions;
    this.graph = graph;
    this.controller = controller;
  };

  _.extend(TransitionContext.prototype, {
    inverseTransition: function (name, options) {
      var ReverseTransition = this.Transition.reverse(name, options.to);
      this.transitions[name] = new ReverseTransition(this.graph, this.controller);
    }
  });

  Generator = function (name, options) {
    this.graph = new Graph(name, options.applicationContext);
    this.mediaType = mediaTypes[options.mediaType];
    this.controller = new Foxx.Controller(options.applicationContext, options);
    this.states = {};
    this.transitions = _.reduce(this.mediaType.transitions, function (transitions, tuple) {
      transitions[tuple.name] = new tuple.Transition(this.graph, this.controller);
      return transitions;
    }, {}, this);
  };

  defaultsForStateOptions = {
    parameterized: false,
    verb: 'post',
    maxFailures: 1,
    queue: 'defaultQueue'
  };

  defaultsForTransitionOptions = {
    semantics: 'follow',
    condition: function () { return true; }
  };

  _.extend(Generator.prototype, {
    addStartState: function (options) {
      var name = '',
        state = new this.mediaType.State(name, this.graph, false);
      state.addTransitions(options.transitions, this.transitions);
      state.setAsStart(this.controller);
      this.states[name] = state;
    },

    addState: function (name, opts) {
      var options = _.defaults(opts, defaultsForStateOptions),
        state = new this.mediaType.State(name, this.graph, options.parameterized);

      state.configure(options, this.mediaType, this.states);
      state.addTransitions(options.transitions, this.transitions);

      this.states[name] = state;
    },

    defineTransition: function (name, opts) {
      var Transition,
        options = _.defaults(opts, defaultsForTransitionOptions),
        context;

      options.precondition = options.precondition || options.condition;

      Transition = this.mediaType.Transition.extend(_.extend(options, {
        collectionBaseName: name,
        relationName: name,
        relationType: options.to
      }));

      context = new TransitionContext(Transition, this.transitions, this.graph, this.controller);

      this.transitions[name] = new Transition(this.graph, this.controller);
      return context;
    },

    generate: function () {
      _.each(this.states, function (state) {
        state.applyTransitions(this.states);
      }, this);
    }
  });

  exports.Generator = Generator;
}());
<|endoftext|>