453 lines
16 KiB
CoffeeScript
453 lines
16 KiB
CoffeeScript
context = window
|
|
rest = context.JK.Rest()
|
|
logger = context.JK.logger
|
|
JamBlasterActions = @JamBlasterActions
|
|
|
|
@JamBlasterScreen = React.createClass({
|
|
|
|
mixins: [
|
|
@ICheckMixin,
|
|
@PostProcessorMixin,
|
|
@BonjourMixin,
|
|
Reflux.listenTo(AppStore, "onAppInit"),
|
|
Reflux.listenTo(UserStore, "onUserChanged"),
|
|
Reflux.listenTo(JamBlasterStore, "onJamBlasterChanged")
|
|
]
|
|
|
|
TILE_AUDIO: 'audio'
|
|
TILE_INTERNET: 'internet'
|
|
TILE_MANAGEMENT: 'management'
|
|
TILE_USB: 'usb'
|
|
|
|
TILES: ['management', 'audio', 'internet']
|
|
|
|
networkStale: false
|
|
ipRegex: /^0([0-9])+/
|
|
|
|
onAppInit: (@app) ->
|
|
@app.bindScreen('jamblaster',
|
|
{beforeShow: @beforeShow, afterShow: @afterShow, beforeHide: @beforeHide})
|
|
|
|
onUserChanged: (userState) ->
|
|
@setState({user: userState?.user})
|
|
|
|
onJamBlasterChanged: (jamblasterState) ->
|
|
@setState(jamblasterState)
|
|
|
|
componentDidMount: () ->
|
|
@checkboxes = [{selector: 'input.dhcp', stateKey: 'userdhcp'}]
|
|
@root = $(@getDOMNode())
|
|
@iCheckify()
|
|
|
|
|
|
|
|
componentDidUpdate: () ->
|
|
@iCheckify()
|
|
|
|
items = @root.find('.jamtable .optionsColumn .jamblaster-options-btn')
|
|
|
|
$.each(items, (i, node) => (
|
|
$node = $(node)
|
|
|
|
jamblaster = @findJamBlaster({
|
|
server_id: $node.attr('data-jamblaster-id'),
|
|
ipv6_addr: $node.attr('data-jamblaster-addr')
|
|
})
|
|
|
|
$node.jamblasterOptions(jamblaster).off(context.JK.EVENTS.JAMBLASTER_ACTION).on(context.JK.EVENTS.JAMBLASTER_ACTION,
|
|
@jamblasterOptionSelected)
|
|
))
|
|
|
|
@root.find('input.networksettings').inputmask({
|
|
alias: "ip",
|
|
"placeholder": "_"
|
|
});
|
|
|
|
checkboxChanged: (e) ->
|
|
checked = $(e.target).is(':checked')
|
|
|
|
value = $(e.target).val()
|
|
console.log("checkbox changed: ", value)
|
|
|
|
|
|
@setState({userdhcp: "true" == value})
|
|
|
|
componentWillUpdate: (nextProps, nextState) ->
|
|
if @networkStale && @state.pairedJamBlaster?
|
|
console.log("stale network update", @state)
|
|
nextState.userdhcp = @state.pairedJamBlaster.network?.dhcp
|
|
nextState.useraddr = @state.pairedJamBlaster.network?.addr
|
|
nextState.usersubnet = @state.pairedJamBlaster.network?.subnet
|
|
nextState.usergateway = @state.pairedJamBlaster.network?.gateway
|
|
nextState.userdns1 = @state.pairedJamBlaster.network?.dns1
|
|
nextState.userdns2 = @state.pairedJamBlaster.network?.dns2
|
|
nextState.userdhcperror = false
|
|
nextState.useraddrerror = false
|
|
nextState.usersubneterror = false
|
|
nextState.usergatewayerror = false
|
|
nextState.userdns1error = false
|
|
nextState.userdns2error = false
|
|
@networkStale = false
|
|
|
|
#context.JK.popExternalLinks(@root)
|
|
|
|
jamblasterOptionSelected: (e, data) ->
|
|
jamblaster = data.options
|
|
jamblaster = @findJamBlaster(jamblaster)
|
|
|
|
if data.option == 'auto-connect'
|
|
JamBlasterActions.setAutoPair(!jamblaster.autoconnect)
|
|
else if data.option == 'restart'
|
|
context.JK.Banner.showYesNo({
|
|
title: "reboot JamBlaster",
|
|
html: "Are you sure?"
|
|
yes: =>
|
|
result = context.jamClient.rebootJamBlaster()
|
|
if result
|
|
setTimeout((() => context.JK.Banner.showNotice("JamBlaster is rebooting",
|
|
"It should be back online within a minute.")), 1)
|
|
setTimeout((() => JamBlasterActions.resyncBonjour()), 1000)
|
|
|
|
else
|
|
setTimeout((() => context.JK.Banner.showAlert("could not reboot",
|
|
"The JamBlaster could not be rebooted remotely. Please cycle the power manually.")), 1)
|
|
|
|
})
|
|
|
|
else if data.option == 'name'
|
|
@app.layout.showDialog('jamblaster-name-dialog', {d1: jamblaster.name}).one(context.JK.EVENTS.DIALOG_CLOSED,
|
|
(e, data) =>
|
|
setTimeout((() => JamBlasterActions.resyncBonjour()), 1000)
|
|
)
|
|
|
|
else if data.option == 'check-for-updates'
|
|
context.JK.Banner.showNotice('Check for Update',
|
|
'The JamBlaster only checks for updates when booting up. Please reboot the JamBlaster to initiate an update check.')
|
|
else if data.option == 'set-static-ports'
|
|
if jamblaster.isDynamicPorts
|
|
context.JK.Banner.showYesNo({
|
|
title: "revert to dynamic ports",
|
|
html: "Your JamBlaster is currently configured to use ports #{jamblaster.portState.static_port} - #{jamblaster.portState.static_port + 10}). Would you like to revert to the use of dynamic ports for UDP communication?"
|
|
yes: =>
|
|
context.jamClient.setJbPortBindState({use_static_port: false, static_port: 12000})
|
|
JamBlasterActions.clearPortBindState()
|
|
#setTimeout((() => JamBlasterActions.resyncBonjour()), 1000)
|
|
JamBlasterActions.resyncBonjour()
|
|
setTimeout((() => context.JK.Banner.showNotice("reboot JamBlaster",
|
|
"For these settings to take effect, you must restart the JamBlaster.")), 1)
|
|
|
|
})
|
|
|
|
else
|
|
@app.layout.showDialog('jamblaster-port-dialog').one(context.JK.EVENTS.DIALOG_CLOSED, (e, data) =>
|
|
JamBlasterActions.clearPortBindState()
|
|
JamBlasterActions.resyncBonjour()
|
|
context.JK.Banner.showNotice("reboot JamBlaster",
|
|
"For these settings to take effect, you must restart the JamBlaster.")
|
|
)
|
|
else if data.option == 'factory-reset'
|
|
context.JK.Banner.showNotice('Factory Reset',
|
|
'The JamBlaster only checks for updates when it boots up, and if there is an update available, it will automatically begin updating.<br/><br/>Please reboot the JamBlaster to initiate an update check.')
|
|
else
|
|
logger.debug("unknown action")
|
|
getInitialState: () ->
|
|
{
|
|
selected: 'management',
|
|
user: null,
|
|
userJamBlasters: [],
|
|
localJamBlasters: [],
|
|
allJamBlasters: []
|
|
}
|
|
|
|
beforeHide: (e) ->
|
|
@clearTimer()
|
|
|
|
beforeShow: (e) ->
|
|
@setTimer()
|
|
|
|
afterShow: (e) ->
|
|
JamBlasterActions.resyncBonjour()
|
|
|
|
openMenu: (client, e) ->
|
|
logger.debug("open jamblaster options menu")
|
|
$this = $(e.target)
|
|
if !$this.is('.jamblaster-options-btn')
|
|
$this = $this.closest('.jamblaster-options-btn')
|
|
$this.btOn()
|
|
|
|
clearTimer: () ->
|
|
if @interval?
|
|
clearInterval(@interval)
|
|
@interval = null
|
|
|
|
# Refresh bonjour status every 30 second, so that we catch major changes
|
|
setTimer: () ->
|
|
@clearTimer()
|
|
time = 30000 # every 30 seconds
|
|
|
|
@interval = setInterval((() => JamBlasterActions.resyncBonjour()), time)
|
|
|
|
connect: (client, e) ->
|
|
logger.debug("beginning pairing to #{client.connect_url}")
|
|
|
|
@clearTimer()
|
|
@app.layout.showDialog('jamblaster-pairing-dialog', {d1: client}).one(context.JK.EVENTS.DIALOG_CLOSED, (e, data) =>
|
|
JamBlasterActions.resyncBonjour()
|
|
@setTimer()
|
|
)
|
|
disconnect: (client, e) ->
|
|
logger.debug("disconnecting from currently paired client #{client.connect_url}")
|
|
context.jamClient.endPairing()
|
|
setTimeout((() => JamBlasterActions.resyncBonjour()), 1000)
|
|
|
|
mergeClients: () ->
|
|
clientsJsx = []
|
|
for client in @state.allJamBlasters
|
|
if client.display_name?
|
|
displayName = client.display_name
|
|
else
|
|
displayName = client.name
|
|
|
|
if client.serial_no? && displayName? && displayName.indexOf(client.serial_no) == -1
|
|
displayName = "#{displayName} (#{client.serial_no})"
|
|
name = `<span className="displayNameColumn">{displayName}</span>`
|
|
|
|
if client.isPaired
|
|
connect = `<span className="connectColumn"><a
|
|
onClick={this.disconnect.bind(this, client)}>disconnect</a></span>`
|
|
else if client.has_local
|
|
connect = `<span className="connectColumn"><a onClick={this.connect.bind(this, client)}>connect</a></span>`
|
|
else
|
|
connect = `<span className="connectColumn">offline</span>`
|
|
|
|
options = `<span className="optionsColumn"><a data-jamblaster-id={client.server_id}
|
|
data-jamblaster-addr={client.ipv6_addr}
|
|
className="jamblaster-options-btn"
|
|
onClick={this.openMenu.bind(this, client)}>more options
|
|
<div className="details-arrow arrow-down"/>
|
|
</a></span>`
|
|
|
|
clientsJsx.push(`<tr>
|
|
<td>{name}{options}{connect}</td>
|
|
</tr>`)
|
|
|
|
clientsJsx
|
|
|
|
mainContent: () ->
|
|
if !@state.user?.id || !@state.userJamBlasters? || !@state.localJamBlasters?
|
|
return `<div>Loading ...</div>`
|
|
|
|
|
|
if @state.selected == @TILE_AUDIO
|
|
@audio()
|
|
else if @state.selected == @TILE_INTERNET
|
|
@internet()
|
|
else if @state.selected == @TILE_MANAGEMENT
|
|
@management()
|
|
else if @state.selected == @TILE_USB
|
|
@usb()
|
|
|
|
audio: () ->
|
|
`<div className="audio-content">
|
|
To edit the JamBlaster audio settings, get into a session, and click the Settings link under My Tracks.
|
|
</div>`
|
|
|
|
ipSettingsChanged: (key, e) ->
|
|
userKey = 'user' + key
|
|
state = {}
|
|
ip = $(e.target).val()
|
|
state[userKey] = ip
|
|
if ip?
|
|
bits = ip.split('.')
|
|
|
|
console.log("bits", bits)
|
|
for bit in bits
|
|
result = @ipRegex.test(bit.replace(/_/g, ''))
|
|
console.log("STILL GOT THAT _?", result)
|
|
error = false
|
|
if result == true || bit == "___"
|
|
error = true
|
|
break
|
|
|
|
if error
|
|
console.log("SETTING ERROR for " + userKey + 'error')
|
|
state[userKey + 'error'] = true
|
|
else
|
|
state[userKey + 'error'] = false
|
|
this.setState(state)
|
|
|
|
onSaveNetworkSettings: (e) ->
|
|
e.preventDefault()
|
|
|
|
settings = {
|
|
dhcp: this.state.userdhcp,
|
|
addr: this.state.useraddr,
|
|
gateway: this.state.usergateway,
|
|
subnet: this.state.usersubnet,
|
|
dns1: this.state.userdns1,
|
|
dns2: this.state.userdns2
|
|
}
|
|
|
|
logger.debug("saving network settings", settings)
|
|
JamBlasterActions.saveNetworkSettings(settings)
|
|
@networkStale = true
|
|
|
|
usb: () ->
|
|
`<div className="networking-content">
|
|
<h3>USB Settings</h3>
|
|
</div>`
|
|
|
|
internet: () ->
|
|
pairedJamBlaster = this.state.pairedJamBlaster
|
|
hasPairedJamBlaster = pairedJamBlaster?
|
|
isJamBlasterDhcp = !!this.state.userdhcp
|
|
|
|
if hasPairedJamBlaster
|
|
status =
|
|
`<div className="jamblaster-network-status">
|
|
<div className="status-field"><span className="status-label">Ethernet:</span><span>Connected</span></div>
|
|
<div className="status-field"><span className="status-label">Internet:</span><span>Connected</span></div>
|
|
<div className="status-field"><span className="status-label">Streaming:</span><span>Supported</span></div>
|
|
</div>`
|
|
else
|
|
status =
|
|
`<div className="jamblaster-network-status">
|
|
<div className="status-field"><span className="status-label">Ethernet:</span><span>Unknown</span></div>
|
|
<div className="status-field"><span className="status-label">Internet:</span><span>Unknown</span></div>
|
|
<div className="status-field"><span className="status-label">Streaming:</span><span>Unknown</span></div>
|
|
</div>`
|
|
|
|
addrClasses = {field: true, error: this.state.useraddrerror}
|
|
subnetClasses = {field: true, error: this.state.usersubneterror}
|
|
gatewayClasses = {field: true, error: this.state.usergatewayerror}
|
|
dns1Classes = {field: true, error: this.state.userdns1error}
|
|
dns2Classes = {field: true, error: this.state.userdns2error}
|
|
|
|
saveBtnClasses = {}
|
|
saveBtnClasses["save-settings-btn"] = true
|
|
saveBtnClasses["button-orange"] = true
|
|
saveBtnClasses["disabled"] = !hasPairedJamBlaster
|
|
|
|
ipdisabled = !hasPairedJamBlaster || isJamBlasterDhcp
|
|
|
|
`<div className="networking-content">
|
|
<h3>Internet Settings</h3>
|
|
|
|
<div className="column-left column">
|
|
<div className="assign-ip-address">
|
|
<h4>Assign IP Address</h4>
|
|
|
|
<div className="dhcpfield">
|
|
<input className="dhcp" type="radio" name="dhcp" readOnly={true} value="true" defaultChecked={isJamBlasterDhcp}
|
|
disabled={!hasPairedJamBlaster}/><label>Using DHCP</label>
|
|
</div>
|
|
<div className="dhcpfield">
|
|
<input className="dhcp" type="radio" name="dhcp" readOnly={true} value="false" defaultChecked={!isJamBlasterDhcp}
|
|
disabled={!hasPairedJamBlaster}/><label>Manually</label>
|
|
</div>
|
|
</div>
|
|
<div className="manual-settings">
|
|
<h4>Manual Settings</h4>
|
|
<div className={classNames(addrClasses)}>
|
|
<label>IP Address:</label><input className="addr networksettings" type="text" value={this.state.useraddr} name="addr" onBlur={this.ipSettingsChanged.bind(this, 'addr')} disabled={ipdisabled}></input>
|
|
</div>
|
|
<div className={classNames(subnetClasses)}>
|
|
<label>Subnet Mask:</label><input className="subnet networksettings" type="text" value={this.state.usersubnet} name="subnet" onBlur={this.ipSettingsChanged.bind(this, 'subnet')} disabled={ipdisabled}></input>
|
|
</div>
|
|
<div className={classNames(gatewayClasses)}>
|
|
<label>Router:</label><input className="gateway networksettings" type="text" value={this.state.usergateway} name="gateway" onBlur={this.ipSettingsChanged.bind(this, 'gateway')} disabled={ipdisabled}></input>
|
|
</div>
|
|
<div className={classNames(dns1Classes)}>
|
|
<label>DNS Server 1:</label><input className="dns1 networksettings" type="text" value={this.state.userdns1} name="dns1" onBlur={this.ipSettingsChanged.bind(this, 'dns1')} disabled={ipdisabled}></input>
|
|
</div>
|
|
<div className={classNames(dns1Classes)}>
|
|
<label>DNS Server 2:</label><input className="dns2 networksettings" type="text" value={this.state.userdns2} name="dns1" onBlur={this.ipSettingsChanged.bind(this, 'dns2')} disabled={ipdisabled}></input>
|
|
</div>
|
|
|
|
</div>
|
|
<div className="save-settings">
|
|
<a onClick={this.onSaveNetworkSettings} className={classNames(saveBtnClasses)}>SAVE SETTINGS</a>
|
|
</div>
|
|
</div>
|
|
<div className="column-right column">
|
|
<h4>Network Status</h4>
|
|
{status}
|
|
</div>
|
|
</div>`
|
|
|
|
management: () ->
|
|
clients = @mergeClients()
|
|
if @state.refreshingBonjour
|
|
refreshingText = 'SCANNING'
|
|
else
|
|
refreshingText = 'SCAN NETWORK'
|
|
|
|
refreshClasses = {"resync-bonjour": true, "button-orange": true, disabled: @state.refreshingBonjour}
|
|
`<div className="management-content">
|
|
|
|
<table className="jamtable">
|
|
<thead>
|
|
<tr>
|
|
<th className="jamblasterColumn">JAMBLASTERS ON YOUR NETWORK</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{clients}
|
|
</tbody>
|
|
</table>
|
|
<a onClick={JamBlasterActions.resyncBonjour} className={classNames(refreshClasses)}>{refreshingText}</a>
|
|
|
|
<p className="help-text">If you don't see your JamBlaster listed above, please check to make sure you have power
|
|
connected to your JamBlaster,
|
|
and make sure your JamBlaster is connected via an Ethernet cable to the same router/network as the device on
|
|
which you are viewing this application.
|
|
</p>
|
|
</div>`
|
|
|
|
tiles: () ->
|
|
@TILES
|
|
|
|
selectionMade: (selection, e) ->
|
|
e.preventDefault()
|
|
|
|
if selection == @TILE_INTERNET
|
|
@networkStale = true
|
|
|
|
@setState({selected: selection})
|
|
|
|
createTileLink: (i, tile) ->
|
|
if this.state.selected?
|
|
active = this.state.selected == tile
|
|
else
|
|
active = tile == @TILE_MANAGEMENT
|
|
|
|
tileClasses = {activeTile: active, 'jamblaster-tile': true}
|
|
tileClasses = classNames(tileClasses)
|
|
|
|
classes = classNames({last: i == @tiles().length - 1})
|
|
|
|
return `<div key={i} className={tileClasses}><a className={classes}
|
|
onClick={this.selectionMade.bind(this, tile)}>{tile}</a></div>`
|
|
|
|
render: () ->
|
|
disabled = @state.updating
|
|
|
|
tiles = []
|
|
for tile, i in @tiles()
|
|
tiles.push(@createTileLink(i, tile))
|
|
|
|
`<div className="content-body-scroller">
|
|
<div className="">
|
|
<h2>jamblaster settings</h2>
|
|
|
|
<div className="tiles">
|
|
{tiles}
|
|
</div>
|
|
|
|
<div className="jamclass-section">
|
|
{this.mainContent()}
|
|
</div>
|
|
</div>
|
|
<br className="clearall"/>
|
|
</div>`
|
|
}) |