jam-cloud/web/app/assets/javascripts/react-components/PopupJamTrackPlayer.js.jsx....

761 lines
28 KiB
CoffeeScript

context = window
logger = context.JK.logger
ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
rest = context.JK.Rest()
mixins = []
# make sure this is actually us opening the window, not someone else (by checking for MixerStore)
# this check ensures we attempt to listen if this component is created in a popup
reactContext = if window.opener? then window.opener else window
# make sure this is actually us opening the window, not someone else (by checking for MixerStore)
if window.opener?
try
m = window.opener.MixerStore
catch e
reactContext = window
# temporarily..
# reactContext = window
AppActions = reactContext.AppActions
JamTrackPlayerActions = reactContext.JamTrackPlayerActions
JamTrackPlayerStore = reactContext.JamTrackPlayerStore
mixins.push(Reflux.listenTo(JamTrackPlayerStore, 'onJamTrackPlayerStoreChanged'))
@PopupJamTrackPlayer = React.createClass({
mixins: mixins
onJamTrackPlayerStoreChanged: (changes) ->
#logger.debug("PopupMediaControls: jamtrack changed", changes)
@setState({jamTrackState: changes})
showMetronome: (e) ->
e.preventDefault()
SessionActions.showNativeMetronomeGui()
getInitialState: () ->
state = {}
state.jamTrackState = JamTrackPlayerStore.getState()
state.showCustomMixes = true
return state
close: () ->
window.close()
help: (e) ->
e.preventDefault()
AppActions.openExternalUrl($(e.target).attr('href'))
render: () ->
closeLinkText = null
header = null
extraControls = null
jamTrack = @state.jamTrackState?.jamTrack
mediaType = "JamTrack"
mediaName = jamTrack?.name
closeLinkText = 'CLOSE JAMTRACK'
helpLink = 'https://jamkazam.desk.com/customer/portal/articles/2138903-using-custom-mixes-to-slow-tempo-change-pitch'
selectedMixdown = jamTrack?.activeMixdown
selectedStem = jamTrack?.activeStem
if selectedMixdown?
jamTrackTypeHeader = 'Custom Mix'
disabled = true
if selectedMixdown.client_state?
switch selectedMixdown.client_state
when 'cant_open'
customMixName = `<h5>{selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
when 'keying_timeout'
customMixName = `<h5>{selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
when 'download_fail'
customMixName = `<h5>{selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
when 'keying'
customMixName = `<h5>Loading selected mix... <img src="/assets/shared/spinner.gif" /></h5>`
when 'downloading'
customMixName = `<h5>Loading selected mix... <img src="/assets/shared/spinner.gif" /></h5>`
when 'ready'
customMixName = `<h5>{selectedMixdown.name}</h5>`
disabled = false
else
if selectedMixdown.myPackage
customMixName = `<h5>Creating mixdown... <img src="/assets/shared/spinner.gif" /></h5>`
else
customMixName = `<h5>{selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
else if selectedStem?
if selectedStem.instrument
instrumentId = selectedStem.instrument.id
instrumentDescription = selectedStem.instrument.description
part = "(#{selectedStem.part})" if selectedStem.part? && selectedStem.part != instrumentDescription
part = '' unless part
jamTrackTypeHeader = 'Track'
trackName = "#{instrumentDescription} #{part}"
disabled = true
if selectedStem.client_state?
switch selectedStem.client_state
when 'downloading'
customMixName = `<h5>Loading {trackName}... <img src="/assets/shared/spinner.gif" /></h5>`
when 'ready'
customMixName = `<h5>{trackName}</h5>`
disabled = false
else
customMixName = `<h5>{trackName}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
else
if jamTrack?.client_state == 'downloading'
downloader = `<img src="/assets/shared/spinner.gif" />`
jamTrackTypeHeader = `<span>Full JamTrack {downloader}</span>`
header = `
<div className="header">
<h3>{mediaType}: {mediaName}</h3>
<h4>{jamTrackTypeHeader}</h4>
{customMixName}
</div>`
myMixes = null
if @state.showMyMixes
myMixdowns = []
boundPlayClick = this.jamTrackPlay.bind(this, jamTrack);
boundDownloadClick = this.jamTrackDownload.bind(this, jamTrack);
active = jamTrack.last_mixdown_id == null && jamTrack.last_stem_id == null
myMixdowns.push `
<div key="full-track" className={classNames({'full-track': true, 'mixdown-display': true, 'active' : active})}>
<div className="mixdown-name">
Full JamTrack
</div>
<div className="mixdown-actions">
<img src="/assets/content/icon_download@2X.png" className="mixdown-download" onClick={boundDownloadClick}/>
<img src="/assets/content/icon_open@2X.png" className="mixdown-play" onClick={boundPlayClick}/>
<img src ="/assets/content/icon-delete@2X.png" style={{visibility:'hidden'}} className="mixdown-edit" onClick={false} />
<img src ="/assets/content/icon-delete@2X.png" style={{visibility:'hidden'}} className="mixdown-delete" onClick={false} />
</div>
</div>`
for mixdown in jamTrack.mixdowns
boundPlayClick = this.mixdownPlay.bind(this, mixdown);
boundEditClick = this.mixdownEdit.bind(this, mixdown);
boundSaveClick = this.mixdownSave.bind(this, mixdown);
boundDeleteClick = this.mixdownDelete.bind(this, mixdown);
boundErrorClick = this.mixdownError.bind(this, mixdown);
boundEditKeydown = this.onEditKeydown.bind(this, mixdown);
boundDownloadNotReadyClick = this.downloadNotReady.bind(this, mixdown)
boundDownloadReadyClick = this.downloadMixdownReady.bind(this, mixdown)
mixdown_package = mixdown.myPackage
active = mixdown.id == jamTrack.last_mixdown_id
editing = mixdown.id == @state.editingMixdownId
# if there is a package, check it's state; otherwise let the user enqueue it
if mixdown_package
switch mixdown_package.signing_state
when 'QUIET_TIMEOUT'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
when 'QUIET'
action = `<img src="/assets/shared/spinner.gif" className="mixdown-play"/>`
when 'QUEUED'
action = `<img src="/assets/shared/spinner.gif" className="mixdown-play"/>`
when 'QUEUED_TIMEOUT'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
when 'SIGNING'
action = `<img src="/assets/shared/spinner.gif" className="mixdown-play"/>`
when 'SIGNING_TIMEOUT'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
when 'SIGNED'
action = `<img src="/assets/content/icon_open@2X.png" className="mixdown-play" onClick={boundPlayClick}/>`
when 'ERROR'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
else
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
if editing
mixdownName = `<input className="edit-name" type="text" defaultValue={mixdown.name} onKeyDown={boundEditKeydown} />`
editIcon = `<img src="/assets/content/icon-save@2X.png" className="mixdown-edit" onClick={boundSaveClick}/>`
else
mixdownName = mixdown.name
editIcon = `<img src="/assets/content/icon-edit@2X.png" className="mixdown-edit" onClick={boundEditClick}/>`
# create hidden objects to deal with alginment issues using a table
if !editIcon
editIcon = `<img src ="/assets/content/icon-delete@2X.png" style={{visibility:'hidden'}} className="mixdown-edit" onClick={false} />`
download = `<img src="/assets/content/icon_download@2X.png" className="mixdown-download" onClick={boundDownloadReadyClick} />`
myMixdowns.push `
<div key={mixdown.id} className={classNames({'mixdown-display': true, 'active' : active})}>
<div className="mixdown-name">
{mixdownName}
</div>
<div className="mixdown-actions">
{download}
{action}
{editIcon}
<img src ="/assets/content/icon-delete@2X.png" className="mixdown-delete" onClick={boundDeleteClick} />
</div>
</div>`
active = jamTrack.last_stem_id?
trackOptions = []
for track in jamTrack.tracks
if track.track_type == 'Track'
if track.instrument
instrumentId = track.instrument.id
instrumentDescription = track.instrument.description
if track.part? && track.part != instrumentDescription
part = "(#{track.part})"
else
part = ''
trackOptions.push(`<option key={track.id} value={track.id}>{instrumentDescription} {part}</option>`)
boundStemActivateClick = this.activateStem.bind(this)
boundStemPlayClick = this.downloadStem.bind(this)
boundStemChange = this.stemChanged.bind(this)
action = `<img src="/assets/content/icon_open@2X.png" className="mixdown-play" onClick={boundStemActivateClick}/>`
download = `<img src="/assets/content/icon_download@2X.png" className="mixdown-download" onClick={boundStemPlayClick} />`
myMixdowns.push `
<div key={track.id} className={classNames({'stem-track' : true, 'mixdown-display': true, 'active' : active})}>
<div className="mixdown-name">
<select className="active-stem-select" name="active-stem-select" onChange={boundStemChange} defaultValue={jamTrack.last_stem_id}>
<option key="null" value="">or select a track</option>
{trackOptions}
</select>
</div>
<div className="mixdown-actions">
{download}
{action}
<img src ="/assets/content/icon-delete@2X.png" style={{visibility:'hidden'}} className="mixdown-edit" onClick={false} />
<img src ="/assets/content/icon-delete@2X.png" style={{visibility:'hidden'}} className="mixdown-delete" onClick={false} />
</div>
</div>`
myMixes = `<div key="my-mixes" className="my-mixes">{myMixdowns}</div>`
mixControls = null
if @state.showCustomMixes
tracks = []
if jamTrack?
for track in jamTrack.tracks
if track.track_type == 'Track'
if track.instrument
instrumentId = track.instrument.id
instrumentDescription = track.instrument.description
if track.part? && track.part != instrumentDescription
part = "(#{track.part})"
else
part = ''
tracks.push(`
<tr className="stem">
<td><img src={context.JK.getInstrumentIcon24(instrumentId)} className="instrument-icon" /> {instrumentDescription} {part}</td>
<td className="mute"><input type="checkbox" className="stem-mute" data-stem-id={track.id} /></td>
</tr>`)
stems = `<div key="stems" className="stems">
<table>
<thead>
<col align="left" /><col align="right"/>
<tr><th>TRACKS</th><th className="mute">mute</th></tr>
</thead>
<tbody>
{tracks}
</tbody>
</table>
</div>`
nameClassData = {field: true}
if @state.createMixdownErrors?
errorHtml = context.JK.reactErrors(@state.createMixdownErrors, {name: 'Mix Name', settings: 'Settings', jam_track: 'JamTrack'})
createMixClasses = classNames({'button-orange' : true, 'create-mix-btn' : true, 'disabled' : @state.creatingMixdown})
if !selectedMixdown?
mixControls = `
<div key="create-mix" className="create-mix">
<p>Mute or unmute any tracks you like. You can also use the controls below to adjust the tempo or pitch of the JamTrack. Then give your custom mix a name, and click the Create Mix button.</p>
{stems}
<div className="field">
<label>TEMPO</label>
<select name="mix-speed">
<option value="">No change</option>
<option value="separator-1">------------</option>
<option value="-5">Slower by 5%</option>
<option value="-10">Slower by 10%</option>
<option value="-15">Slower by 15%</option>
<option value="-20">Slower by 20%</option>
<option value="-25">Slower by 25%</option>
<option value="-30">Slower by 30%</option>
<option value="-35">Slower by 35%</option>
<option value="-40">Slower by 40%</option>
<option value="-45">Slower by 45%</option>
<option value="-50">Slower by 50%</option>
<option value="-60">Slower by 60%</option>
<option value="-70">Slower by 70%</option>
<option value="-80">Slower by 80%</option>
<option value="separator-2">------------</option>
<option value="5">Faster by 5%</option>
<option value="10">Faster by 10%</option>
<option value="15">Faster by 15%</option>
<option value="20">Faster by 20%</option>
<option value="30">Faster by 30%</option>
<option value="40">Faster by 40%</option>
<option value="50">Faster by 50%</option>
</select>
</div>
<div className="field">
<label>PITCH</label>
<select name="mix-pitch">
<option value="">No change</option>
<option value="separator-1">---------------</option>
<option value="-1">Down 1 Semitone</option>
<option value="-2">Down 2 Semitones</option>
<option value="-3">Down 3 Semitones</option>
<option value="-4">Down 4 Semitones</option>
<option value="-5">Down 5 Semitones</option>
<option value="-6">Down 6 Semitones</option>
<option value="-7">Down 7 Semitones</option>
<option value="-8">Down 8 Semitones</option>
<option value="-9">Down 9 Semitones</option>
<option value="-10">Down 10 Semitones</option>
<option value="-11">Down 11 Semitones</option>
<option value="-12">Down 12 Semitones</option>
<option value="separator-2">---------------</option>
<option value="1">Up 1 Semitone</option>
<option value="2">Up 2 Semitones</option>
<option value="3">Up 3 Semitones</option>
<option value="4">Up 4 Semitones</option>
<option value="5">Up 5 Semitones</option>
<option value="6">Up 6 Semitones</option>
<option value="7">Up 7 Semitones</option>
<option value="8">Up 8 Semitones</option>
<option value="9">Up 9 Semitones</option>
<option value="10">Up 10 Semitones</option>
<option value="11">Up 11 Semitones</option>
<option value="12">Up 12 Semitones</option>
</select>
</div>
<div className={classNames(nameClassData)}>
<label>MIX NAME</label>
<input type="text" name="mix-name"/>
</div>
<div className="field">
<a className={createMixClasses} onClick={this.createMix}>CREATE MIX</a>
{errorHtml}
</div>
<div className="clearall"/>
</div>`
else
mixControls =
`<div key="no-full-mix-open" className="create-mix not-active">
<p>To create a custom mix, you must open the Full JamTrack in the My Mixes section above.</p>
</div>`
if @state.showMyMixes
showMyMixesText = `<a onClick={this.toggleMyMixes}>hide my mixes <div className="details-arrow arrow-up" /></a>`
else
showMyMixesText = `<a onClick={this.toggleMyMixes}>show my mixes <div className="details-arrow arrow-down" /></a>`
if @state.showCustomMixes
showMixControlsText = `<a onClick={this.toggleCustomMixes}>hide mix controls <div className="details-arrow arrow-up" /></a>`
else
showMixControlsText = `<a onClick={this.toggleCustomMixes}>show mix controls <div className="details-arrow arrow-down" /></a>`
extraControls = `
<div className="extra-controls">
<h4>My Mixes {showMyMixesText}</h4>
<ReactCSSTransitionGroup transitionName="session-track-list" transitionAppear={true}>
{myMixes}
</ReactCSSTransitionGroup>
<h4 className="custom-mix-header">Create Custom Mix {showMixControlsText}</h4>
<ReactCSSTransitionGroup transitionName="session-track-list" transitionAppear={false}>
{mixControls}
</ReactCSSTransitionGroup>
</div>`
if helpLink?
helpButton = `<a className="help-link button-grey" href={helpLink} onClick={this.help}>HELP</a>`
`<div className="media-controls-popup">
{header}
<BrowserMediaControls disabled={this.disableLoading}/>
{extraControls}
<div className="actions">
{helpButton}
<a className="close-link button-orange" onClick={this.close}>{closeLinkText}</a>
</div>
</div>`
windowUnloaded: () ->
JamTrackPlayerActions.windowUnloaded() unless window.DontAutoCloseMedia
toggleMyMixes: (e) ->
e.preventDefault()
@setState({showMyMixes: !@state.showMyMixes})
toggleCustomMixes: (e) ->
e.preventDefault()
@setState({showCustomMixes: !@state.showCustomMixes})
downloadNotReady: (mixdown, e) ->
alert("This mix is not yet ready to download.")
e.preventDefault()
downloadMixdownReady: (mixdown, e) ->
e.preventDefault()
if mixdown.myPackage?.signing_state == 'SIGNED'
iframe = document.createElement("iframe")
iframe.src = window.location.protocol + '//' + window.location.host + "/api/mixdowns/#{mixdown.id}/download.mp3?file_type=mp3&sample_rate=48&download=1"
iframe.style.display = "none"
document.body.appendChild(iframe);
else
alert("The mix is not yet ready to download")
activateStem: (e) ->
e.preventDefault()
$select = $(this.getDOMNode()).find('.active-stem-select')
selectedTrackId = $select.val()
if !selectedTrackId? || selectedTrackId == ''
alert("You must pick a track from the dropdown in order to play it.")
else
@setState({editingMixdownId: null})
e.preventDefault()
if @disableLoading
alert('Certain actions are disabled while a track is being loaded.')
return
# make this package the active one
JamTrackPlayerActions.openStem(selectedTrackId)
downloadStem: (e) ->
e.preventDefault()
$select = $(this.getDOMNode()).find('.active-stem-select')
selectedTrackId = $select.val()
if !selectedTrackId? || selectedTrackId == ''
alert("You must select a track in order to download.")
else
e.preventDefault()
iframe = document.createElement("iframe")
iframe.src = window.location.protocol + '//' + window.location.host + "/api/jamtracks/#{@state.jamTrackState.jamTrack.id}/stems/#{selectedTrackId}/download.mp3?file_type=mp3&download=1"
iframe.style.display = "none"
document.body.appendChild(iframe);
stemChanged: () ->
mixdownPlay: (mixdown, e) ->
@setState({editingMixdownId: null})
e.preventDefault()
if @disableLoading
alert('Certain actions are disabled while a track is being loaded.')
return
# make this package the active one
JamTrackPlayerActions.openMixdown(mixdown)
jamTrackPlay: (jamtrack, e) ->
e.preventDefault()
# user wants to select the full track
if @disableLoading
alert('Certain actions are disabled while a track is being loaded.')
return
JamTrackPlayerActions.activateNoMixdown(jamtrack)
jamTrackDownload: (jamTrack, e) ->
e.preventDefault()
iframe = document.createElement("iframe")
iframe.src = window.location.protocol + '//' + window.location.host + "/api/jamtracks/#{jamTrack.id}/stems/master/download.mp3?file_type=mp3&download=1"
iframe.style.display = "none"
document.body.appendChild(iframe);
onEditKeydown: (mixdown, e) ->
logger.debug("on edit keydown", e)
if e.keyCode == 13 # enter
@mixdownSave(mixdown, e)
else if e.keyCode == 27 # esc
@setState({editingMixdownId: null})
mixdownEdit: (mixdown) ->
@setState({editingMixdownId: mixdown.id})
mixdownSave: (mixdown, e) ->
e.preventDefault()
$input = $(this.getDOMNode()).find('input.edit-name')
newValue = $input.val()
logger.debug("editing mixdown name to be: " + newValue)
JamTrackPlayerActions.editMixdown({id: mixdown.id, name: newValue})
@setState({editingMixdownId: null})
mixdownDelete: (mixdown) ->
if @state.editingMixdownId?
@setState({editingMixdownId:null})
return
if confirm("Delete this custom mix?")
JamTrackPlayerActions.deleteMixdown(mixdown)
mixdownError: (mixdown) ->
myPackage = mixdown.myPackage
if myPackage?
switch myPackage.signing_state
when 'QUIET_TIMEOUT'
action = 'Custom mix never got created. Retry?'
when 'QUEUED_TIMEOUT'
action = 'Custom mix was never built. Retry?'
when 'SIGNING_TIMEOUT'
action = 'Custom mix took took long to build. Retry?'
when 'ERROR'
action = 'Custom mix failed to build. Retry?'
else
action = 'Custom mix never got created. Retry?'
return unless action?
if confirm(action)
JamTrackPlayerActions.enqueueMixdown(mixdown, @enqueueDone)
enqueueDone: (enqueued) ->
@promptEstimate(enqueued)
promptEstimate: (enqueued) ->
time = enqueued.queue_time
if time == 0
alert("Your custom mix will take about 1 minute to be created.")
else
guess = Math.ceil(time / 60.0)
if guess == 1
msg = '1 minute'
else
msg = "#{guess} minutes"
alert("Your custom mix will take about #{msg} to be created.")
createMix: (e) ->
e.preventDefault()
return if @state.creatingMix
$root = $(@getDOMNode())
name = $root.find('input[name="mix-name"]').val()
speed = $root.find('select[name="mix-speed"]').val()
pitch = $root.find('select[name="mix-pitch"]').val()
if @state.jamTrackState?.jamTrack?.activeMixdown?
@setState({createMixdownErrors: {errors: {'Full JamTrack': ['must be selected']}}})
return
if name == null || name == ''
@setState({createMixdownErrors: {errors: {'Mix Name': ["can't be blank"]}}})
return
# sanitize junk out of speed/pitch
if speed == '' || speed.indexOf('separator') > -1
speed = undefined
else
speed = parseInt(speed)
if pitch == '' || pitch.indexOf('separator') > -1
pitch = undefined
else
pitch = parseInt(pitch)
# get mute state of all tracks
$mutes = $(@getDOMNode()).find('.stems .stem .stem-mute')
tracks = []
$mutes.each((i, mute) =>
$mute = $(mute)
stemId = $mute.attr('data-stem-id')
muted = $mute.is(':checked')
tracks.push({id: stemId, mute: muted})
)
mixdown = {jamTrackID: @state.jamTrackState.jamTrack.id, name: name, settings: {speed:speed, pitch: pitch, tracks:tracks}}
JamTrackPlayerActions.createMixdown(mixdown, @createMixdownDone, @createMixdownFail)
@setState({creatingMixdown: true, createMixdownErrors: null})
createMixdownDone: (created) ->
logger.debug("created (within PopupMediaControls)", created)
@setState({creatingMixdown: false, showCustomMixes: true, showMyMixes: true})
@promptEstimate(created)
createMixdownFail: (jqXHR) ->
logger.debug("create mixdown fail (within PopupMediaControls)", jqXHR.status)
@setState({creatingMixdown: false})
if jqXHR.status == 422
response = JSON.parse(jqXHR.responseText)
logger.warn("failed to create mixdown", response, jqXHR.responseText)
@setState({createMixdownErrors: response})
fetchJamTrackInfo: () ->
rest.getJamTrack({plan_code: gon.jamtrack_id})
.done((response) =>
JamTrackPlayerActions.open(response, false);
@fetchUserInfo()
)
.fail((jqXHR) =>
alert("Unable to fetch JamTrack information. Try logging in.")
)
fetchUserInfo: () ->
rest.getUserDetail()
.done((response) =>
rest.postUserEvent({name: 'jamtrack_web_player_open'})
context.stats.write('web.jamtrack_web_player.open', {
value: 1,
user_id: context.JK.currentUserId,
user_name: context.JK.currentUserName
})
if !response.first_opened_jamtrack_web_player
setTimeout((() =>
logger.debug("first time user")
rest.userOpenedJamTrackWebPlayer()
$root = $(@getDOMNode())
#context.JK.prodBubble($root.find('.create-mix-btn'), 'first-time-jamtrack-web-player', {}, {positions:['left'], offsetParent: $root})
), 1500)
)
componentDidMount: () ->
$(window).unload(@windowUnloaded)
@root = jQuery(this.getDOMNode())
$loop = @root.find('input[name="loop"]')
context.JK.checkbox($loop)
$loop.on('ifChecked', () =>
# it doesn't matter if you do personal or master, because backend just syncs both
MixerActions.loopChanged(@state.media.backingTracks[0].mixers.personal.mixer, true)
)
$loop.on('ifUnchecked', () =>
# it doesn't matter if you do personal or master, because backend just syncs both
MixerActions.loopChanged(@state.media.backingTracks[0].mixers.personal.mixer, false)
)
@resizeWindow()
# this is necessary due to whatever the client's rendering behavior is.
setTimeout(@resizeWindow, 300)
@fetchJamTrackInfo()
componentDidUpdate: () ->
@resizeWindow()
setTimeout(@resizeWindow, 1000)
resizeWindow: () =>
$container = $('#minimal-container')
width = $container.width()
height = $container.height()
# there is 20px or so of unused space at the top of the page. can't figure out why it's there. (above #minimal-container)
#mysteryTopMargin = 20
mysteryTopMargin = 0
# deal with chrome in real browsers
offset = (window.outerHeight - window.innerHeight) + mysteryTopMargin
# handle native client chrome that the above outer-inner doesn't catch
#if navigator.userAgent.indexOf('JamKazam') > -1
#offset += 25
window.resizeTo(width, height + offset)
computeDisableLoading: (state) ->
@disableLoading = false
return unless nextState?
selectedMixdown = state?.jamTrackState?.jamTrack?.activeMixdown
mixdownDownloading = false
if selectedMixdown?
switch selectedMixdown.client_state
when 'downloading'
mixdownDownloading = true
selectedStem = state?.jamTrackState?.jamTrack?.activeStem
stemDownloading = false
if selectedStem?
switch selectedStem.client_state
when 'downloading'
stemDownloading = true
@disableLoading = state?.jamTrackState?.jamTrack?.client_state == 'downloading' || mixdownDownloading || stemDownloading
componentWillMount: () ->
@computeDisableLoading(@state)
componentWillUpdate: (nextProps, nextState) ->
@computeDisableLoading(nextState)
})