/*jshint browser:true */ /*globals React, App */ (function () { 'use strict'; /** * Displays a noteboard from given notes * * @prop {notes: array} Array of notes to show * @prop {channels: array} Array of configured channels * @prop {time: int} Playback time * @prop {length: int} Playback length * @prop {speed: int} Playback speed * @prop {opened: bool} Whether a file is opened * @prop {startWheel: function} Called when wheeling starts * @prop {setTime: function} Called to change time * @prop {open: function} Called to load a file * @child Note */ App.components.create('Note', { displayName: 'Board', mixins: [React.addons.PureRenderMixin], statics: { /** * List of black keys */ black: [22, 25, 27, 30, 32, 34, 37, 39, 42, 44, 46, 49, 51, 54, 56, 58, 61, 63, 66, 68, 70, 73, 75, 78, 80, 82, 85, 87, 90, 92, 94, 97, 99, 102, 104, 106] }, /** * State and props config */ propTypes: { notes: React.PropTypes.array, channels: React.PropTypes.array, time: React.PropTypes.number, length: React.PropTypes.number, speed: React.PropTypes.number, opened: React.PropTypes.bool, startWheel: React.PropTypes.func, setTime: React.PropTypes.func, open: React.PropTypes.func, create: React.PropTypes.func }, getDefaultProps: function () { return { notes: [], channels: [], playing: false, time: 0, length: 0, speed: 1, opened: false, startWheel: function () {}, setTime: function () {}, open: function () {}, create: function () {} }; }, /** * Events */ componentDidMount: function () { window.addEventListener('keyup', this.keyUp); window.addEventListener('keydown', this.keyDown); }, componentWillUnmount: function () { window.removeEventListener('keyup', this.keyUp); window.removeEventListener('keydown', this.keyDown); }, /* keyboard shortcuts */ keyDown: function (e) { var code = e.keyCode; // top arrow: scroll top if (code === 38) { this.scroll(-0.5); e.preventDefault(); } // bottom arrow: scroll bottom if (code === 40) { this.scroll(0.5); e.preventDefault(); } }, keyUp: function (e) { var code = e.keyCode; // home: go to start if (code === 36) { this.props.setTime(0); e.preventDefault(); } // end: go to end if (code === 35) { this.props.setTime(this.props.length - 1); e.preventDefault(); } }, /* scroll noteboard */ scroll: function (delta) { var nextValue = this.props.time - delta; if (nextValue < 0) { nextValue = 0; } if (nextValue > this.props.length) { nextValue = this.props.length; } this.props.setTime(nextValue); }, /* reduce wheel amplitude */ wheel: function (e) { this.props.startWheel(); this.scroll(e.deltaY * 0.01); }, /* trigger opening window */ open: function () { this.props.open('', true); }, /** * Render noteboard */ render: function () { var children, notes, controls = [], id = -1, className = 'noteboard'; if (this.props.opened) { className += ' opened'; children = App.components.Note.Score({ key: 'score', className: 'score', notes: this.props.notes, channels: this.props.channels, time: this.props.time }); } else { className += ' closed'; // add opening controls controls.push(React.DOM.button({ key: 'create', className: 'bt primary', onClick: this.props.create }, 'Composer')); controls.push(React.DOM.button({ key: 'open', className: 'bt primary', onClick: this.open }, 'Ouvrir un fichier')); children = React.DOM.p({ key: 'controls', className: 'controls' }, [ React.DOM.img({ key: 'image', src: 'images/logos/logo_u128.png', alt: 'Aucun fichier ouvert' }) ].concat(controls)); } return React.DOM.div({ className: className, onWheel: this.wheel, onClick: this.click }, children); } }); }());