React: fix warnings
This commit is contained in:
@@ -83,7 +83,7 @@
|
||||
"clean": "node ./bin/clean.js",
|
||||
"open-config": "node ./bin/open-config.js",
|
||||
"package": "node ./bin/package.js",
|
||||
"start": "electron .",
|
||||
"start": "jsx --es6module src/ build/ && electron .",
|
||||
"test": "standard && node ./bin/check-deps.js",
|
||||
"update-authors": "./bin/update-authors.sh"
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ function getDefaultPlayState () {
|
||||
lastTimeUpdate: 0, /* Unix time in ms */
|
||||
mouseStationarySince: 0, /* Unix time in ms */
|
||||
playbackRate: 1,
|
||||
volume: 1,
|
||||
subtitles: {
|
||||
tracks: [], /* subtitle tracks, each {label, language, ...} */
|
||||
selectedIndex: -1, /* current subtitle track */
|
||||
|
||||
@@ -82,7 +82,7 @@ function onState (err, _state) {
|
||||
// a progress bar and to keep the cursor in sync when playing a video
|
||||
setInterval(update, 1000)
|
||||
window.requestAnimationFrame(renderIfNecessary)
|
||||
app = ReactDOM.render(<App state={state} />, document.querySelector('body'))
|
||||
app = ReactDOM.render(<App state={state} />, document.querySelector('#body'))
|
||||
|
||||
// OS integrations:
|
||||
// ...drag and drop a torrent or video file to play or seed
|
||||
@@ -240,8 +240,8 @@ const dispatchHandlers = {
|
||||
|
||||
// Events from the UI never modify state directly. Instead they call dispatch()
|
||||
function dispatch (action, ...args) {
|
||||
// Log dispatch calls, for debugging
|
||||
if (!['mediaMouseMoved', 'mediaTimeUpdate'].includes(action)) {
|
||||
// Log dispatch calls, for debugging, but don't spam
|
||||
if (!['mediaMouseMoved', 'mediaTimeUpdate', 'update'].includes(action)) {
|
||||
console.log('dispatch: %s %o', action, args)
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ module.exports = class App extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
console.time('render app')
|
||||
var state = this.state
|
||||
|
||||
// Hide player controls while playing video, if the mouse stays still for a while
|
||||
@@ -55,7 +54,7 @@ module.exports = class App extends React.Component {
|
||||
{getModal(state)}
|
||||
</div>
|
||||
)
|
||||
console.timeEnd('render app')
|
||||
|
||||
return vdom
|
||||
}
|
||||
}
|
||||
|
||||
26
src/renderer/views/create-torrent-error-page.js
Normal file
26
src/renderer/views/create-torrent-error-page.js
Normal file
@@ -0,0 +1,26 @@
|
||||
const React = require('react')
|
||||
|
||||
const {dispatcher} = require('../lib/dispatcher')
|
||||
|
||||
module.exports = class CreateTorrentErrorPage extends React.Component {
|
||||
render () {
|
||||
return (
|
||||
<div className='create-torrent'>
|
||||
<h2>Create torrent</h2>
|
||||
<p className='torrent-info'>
|
||||
<p>
|
||||
Sorry, you must select at least one file that is not a hidden file.
|
||||
</p>
|
||||
<p>
|
||||
Hidden files, starting with a . character, are not included.
|
||||
</p>
|
||||
</p>
|
||||
<p className='float-right'>
|
||||
<button className='button-flat light' onClick={dispatcher('back')}>
|
||||
Cancel
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -46,12 +46,12 @@ module.exports = class CreateTorrentPage extends React.Component {
|
||||
basePath = path.dirname(pathPrefix)
|
||||
}
|
||||
var maxFileElems = 100
|
||||
var fileElems = files.slice(0, maxFileElems).map(function (file) {
|
||||
var fileElems = files.slice(0, maxFileElems).map(function (file, i) {
|
||||
var relativePath = files.length === 0 ? file.name : path.relative(pathPrefix, file.path)
|
||||
return (<div>{relativePath}</div>)
|
||||
return (<div key={i}>{relativePath}</div>)
|
||||
})
|
||||
if (files.length > maxFileElems) {
|
||||
fileElems.push(<div>+ {maxFileElems - files.length} more</div>)
|
||||
fileElems.push(<div key='more'>+ {maxFileElems - files.length} more</div>)
|
||||
}
|
||||
var trackers = createTorrent.announceList.join('\n')
|
||||
var collapsedClass = info.showAdvanced ? 'expanded' : 'collapsed'
|
||||
@@ -59,39 +59,39 @@ module.exports = class CreateTorrentPage extends React.Component {
|
||||
return (
|
||||
<div className='create-torrent'>
|
||||
<h2>Create torrent {defaultName}</h2>
|
||||
<p className='torrent-info'>
|
||||
<div key='info' className='torrent-info'>
|
||||
{torrentInfo}
|
||||
</p>
|
||||
<p className='torrent-attribute'>
|
||||
</div>
|
||||
<div key='path-prefix' className='torrent-attribute'>
|
||||
<label>Path:</label>
|
||||
<div className='torrent-attribute'>{pathPrefix}</div>
|
||||
</p>
|
||||
<div className={'expand-collapse ' + collapsedClass}
|
||||
</div>
|
||||
<div key='toggle' className={'expand-collapse ' + collapsedClass}
|
||||
onClick={dispatcher('toggleCreateTorrentAdvanced')}>
|
||||
{info.showAdvanced ? 'Basic' : 'Advanced'}
|
||||
</div>
|
||||
<div className={'create-torrent-advanced ' + collapsedClass}>
|
||||
<p className='torrent-attribute'>
|
||||
<div key='advanced' className={'create-torrent-advanced ' + collapsedClass}>
|
||||
<div key='comment' className='torrent-attribute'>
|
||||
<label>Comment:</label>
|
||||
<textarea className='torrent-attribute torrent-comment'></textarea>
|
||||
</p>
|
||||
<p className='torrent-attribute'>
|
||||
</div>
|
||||
<div key='trackers' className='torrent-attribute'>
|
||||
<label>Trackers:</label>
|
||||
<textarea className='torrent-attribute torrent-trackers'>{trackers}</textarea>
|
||||
</p>
|
||||
<p className='torrent-attribute'>
|
||||
<textarea className='torrent-attribute torrent-trackers' value={trackers}></textarea>
|
||||
</div>
|
||||
<div key='private' className='torrent-attribute'>
|
||||
<label>Private:</label>
|
||||
<input type='checkbox' className='torrent-is-private' value='torrent-is-private' />
|
||||
</p>
|
||||
<p className='torrent-attribute'>
|
||||
</div>
|
||||
<div key='files' className='torrent-attribute'>
|
||||
<label>Files:</label>
|
||||
<div>{fileElems}</div>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div key='buttons' className='float-right'>
|
||||
<button key='cancel' className='button-flat light' onClick={dispatcher('back')}>Cancel</button>
|
||||
<button key='create' className='button-raised' onClick={handleOK}>Create Torrent</button>
|
||||
</div>
|
||||
<p className='float-right'>
|
||||
<button className='button-flat light' onClick={dispatcher('back')}>Cancel</button>
|
||||
<button className='button-raised' onClick={handleOK}>Create Torrent</button>
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@ function renderMedia (state) {
|
||||
var isSelected = state.playing.subtitles.selectedIndex === i
|
||||
trackTags.push(
|
||||
<track
|
||||
key={i}
|
||||
default={isSelected ? 'default' : ''}
|
||||
label={track.label}
|
||||
type='subtitles'
|
||||
@@ -110,7 +111,7 @@ function renderMedia (state) {
|
||||
onDoubleClick={dispatcher('toggleFullScreen')}
|
||||
onLoadedMetadata={onLoadedMetadata}
|
||||
onEnded={onEnded}
|
||||
onStalling={dispatcher('mediaStalled')}
|
||||
onStalled={dispatcher('mediaStalled')}
|
||||
onError={dispatcher('mediaError')}
|
||||
onTimeUpdate={dispatcher('mediaTimeUpdate')}
|
||||
onEncrypted={dispatcher('mediaEncrypted')}
|
||||
@@ -122,6 +123,7 @@ function renderMedia (state) {
|
||||
// Show the media.
|
||||
return (
|
||||
<div
|
||||
key='letterbox'
|
||||
className='letterbox'
|
||||
onMouseMove={dispatcher('mediaMouseMoved')}>
|
||||
{mediaTag}
|
||||
@@ -179,7 +181,7 @@ function renderOverlay (state) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='media-overlay-background' style={style}>
|
||||
<div key='overlay' className='media-overlay-background' style={style}>
|
||||
<div className='media-overlay'>{elems}</div>
|
||||
</div>
|
||||
)
|
||||
@@ -209,21 +211,21 @@ function renderAudioMetadata (state) {
|
||||
var elems = []
|
||||
if (artist) {
|
||||
elems.push((
|
||||
<div className='audio-artist'>
|
||||
<div key='artist' className='audio-artist'>
|
||||
<label>Artist</label>{artist}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
if (album) {
|
||||
elems.push((
|
||||
<div className='audio-album'>
|
||||
<div key='album' className='audio-album'>
|
||||
<label>Album</label>{album}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
if (track) {
|
||||
elems.push((
|
||||
<div className='audio-track'>
|
||||
<div key='track' className='audio-track'>
|
||||
<label>Track</label>{track}
|
||||
</div>
|
||||
))
|
||||
@@ -232,12 +234,12 @@ function renderAudioMetadata (state) {
|
||||
// Align the title with the other info, if available. Otherwise, center title
|
||||
var emptyLabel = (<label></label>)
|
||||
elems.unshift((
|
||||
<div className='audio-title'>
|
||||
<div key='title' className='audio-title'>
|
||||
{elems.length ? emptyLabel : undefined}{title}
|
||||
</div>
|
||||
))
|
||||
|
||||
return (<div className='audio-metadata'>{elems}</div>)
|
||||
return (<div key='audio-metadata' className='audio-metadata'>{elems}</div>)
|
||||
}
|
||||
|
||||
function renderLoadingSpinner (state) {
|
||||
@@ -254,9 +256,9 @@ function renderLoadingSpinner (state) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='media-stalled'>
|
||||
<div className='loading-spinner'> </div>
|
||||
<div className='loading-status ellipsis'>
|
||||
<div key='loading' className='media-stalled'>
|
||||
<div key='loading-spinner' className='loading-spinner'> </div>
|
||||
<div key='loading-progress' className='loading-status ellipsis'>
|
||||
<span className='progress'>{fileProgress}%</span> downloaded,
|
||||
<span>↓ {prettyBytes(prog.downloadSpeed || 0)}/s</span>
|
||||
<span>↑ {prettyBytes(prog.uploadSpeed || 0)}/s</span>
|
||||
@@ -302,11 +304,11 @@ function renderCastScreen (state) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='letterbox' style={style}>
|
||||
<div key='cast' className='letterbox' style={style}>
|
||||
<div className='cast-screen'>
|
||||
<i className='icon'>{castIcon}</i>
|
||||
<div className='cast-type'>{castType}</div>
|
||||
<div className='cast-status'>{castStatus}</div>
|
||||
<div key='type' className='cast-type'>{castType}</div>
|
||||
<div key='status' className='cast-status'>{castStatus}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -322,7 +324,7 @@ function renderCastOptions (state) {
|
||||
var isSelected = player.device === device
|
||||
var name = device.name
|
||||
return (
|
||||
<li onClick={dispatcher('selectCastDevice', ix)}>
|
||||
<li key={ix} onClick={dispatcher('selectCastDevice', ix)}>
|
||||
<i className='icon'>{isSelected ? 'radio_button_checked' : 'radio_button_unchecked'}</i>
|
||||
{name}
|
||||
</li>
|
||||
@@ -330,20 +332,20 @@ function renderCastOptions (state) {
|
||||
})
|
||||
|
||||
return (
|
||||
<ul className='options-list'>
|
||||
<ul key='cast-options' className='options-list'>
|
||||
{items}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
function renderSubtitlesOptions (state) {
|
||||
function renderSubtitleOptions (state) {
|
||||
var subtitles = state.playing.subtitles
|
||||
if (!subtitles.tracks.length || !subtitles.showMenu) return
|
||||
|
||||
var items = subtitles.tracks.map(function (track, ix) {
|
||||
var isSelected = state.playing.subtitles.selectedIndex === ix
|
||||
return (
|
||||
<li onClick={dispatcher('selectSubtitle', ix)}>
|
||||
<li key={ix} onClick={dispatcher('selectSubtitle', ix)}>
|
||||
<i className='icon'>{'radio_button_' + (isSelected ? 'checked' : 'unchecked')}</i>
|
||||
{track.label}
|
||||
</li>
|
||||
@@ -353,7 +355,7 @@ function renderSubtitlesOptions (state) {
|
||||
var noneSelected = state.playing.subtitles.selectedIndex === -1
|
||||
var noneClass = 'radio_button_' + (noneSelected ? 'checked' : 'unchecked')
|
||||
return (
|
||||
<ul className='options-list'>
|
||||
<ul key='subtitle-options' className='options-list'>
|
||||
{items}
|
||||
<li onClick={dispatcher('selectSubtitle', -1)}>
|
||||
<i className='icon'>{noneClass}</i>
|
||||
@@ -373,13 +375,15 @@ function renderPlayerControls (state) {
|
||||
: ''
|
||||
|
||||
var elements = [
|
||||
<div className='playback-bar'>
|
||||
<div key='playback-bar' className='playback-bar'>
|
||||
{renderLoadingBar(state)}
|
||||
<div
|
||||
key='cursor'
|
||||
className='playback-cursor'
|
||||
style={playbackCursorStyle}>
|
||||
</div>
|
||||
<div
|
||||
key='scrub-bar'
|
||||
className='scrub-bar'
|
||||
draggable='true'
|
||||
onDragStart={handleDragStart}
|
||||
@@ -388,11 +392,15 @@ function renderPlayerControls (state) {
|
||||
</div>
|
||||
</div>,
|
||||
|
||||
<i className='icon play-pause float-left' onClick={dispatcher('playPause')}>
|
||||
<i
|
||||
key='play'
|
||||
className='icon play-pause float-left'
|
||||
onClick={dispatcher('playPause')}>
|
||||
{state.playing.isPaused ? 'play_arrow' : 'pause'}
|
||||
</i>,
|
||||
|
||||
<i
|
||||
key='fullscreen'
|
||||
className='icon fullscreen float-right'
|
||||
onClick={dispatcher('toggleFullScreen')}>
|
||||
{state.window.isFullScreen ? 'fullscreen_exit' : 'fullscreen'}
|
||||
@@ -403,6 +411,7 @@ function renderPlayerControls (state) {
|
||||
// show closed captions icon
|
||||
elements.push((
|
||||
<i
|
||||
key='subtitles'
|
||||
className={'icon closed-caption float-right ' + captionsClass}
|
||||
onClick={handleSubtitles}>
|
||||
closed_caption
|
||||
@@ -446,6 +455,7 @@ function renderPlayerControls (state) {
|
||||
|
||||
elements.push((
|
||||
<i
|
||||
key={castType}
|
||||
className={'icon device float-right ' + buttonClass}
|
||||
onClick={buttonHandler}>
|
||||
{buttonIcon}
|
||||
@@ -466,8 +476,10 @@ function renderPlayerControls (state) {
|
||||
'color-stop(' + (volume * 100) + '%, #727272))'
|
||||
}
|
||||
|
||||
//TODO: dcposch change the range input to use value / onChanged instead of
|
||||
// "readonly" / onMouse[Down,Move,Up]
|
||||
elements.push((
|
||||
<div className='volume float-left'>
|
||||
<div key='volume' className='volume float-left'>
|
||||
<i
|
||||
className='icon volume-icon float-left'
|
||||
onMouseDown={handleVolumeMute}>
|
||||
@@ -476,10 +488,8 @@ function renderPlayerControls (state) {
|
||||
<input
|
||||
className='volume-slider float-right'
|
||||
type='range' min='0' max='1' step='0.05'
|
||||
value={volumeChanging !== false ? volumeChanging : volume}
|
||||
onMouseDown={handleVolumeScrub}
|
||||
onMouseUp={handleVolumeScrub}
|
||||
onMouseMove={handleVolumeScrub}
|
||||
value={volume}
|
||||
onChange={handleVolumeScrub}
|
||||
style={volumeStyle}
|
||||
/>
|
||||
</div>
|
||||
@@ -489,7 +499,7 @@ function renderPlayerControls (state) {
|
||||
var currentTimeStr = formatTime(state.playing.currentTime)
|
||||
var durationStr = formatTime(state.playing.duration)
|
||||
elements.push((
|
||||
<span className='time float-left'>
|
||||
<span key='time' className='time float-left'>
|
||||
{currentTimeStr} / {durationStr}
|
||||
</span>
|
||||
))
|
||||
@@ -497,17 +507,17 @@ function renderPlayerControls (state) {
|
||||
// render playback rate
|
||||
if (state.playing.playbackRate !== 1) {
|
||||
elements.push((
|
||||
<span className='rate float-left'>
|
||||
<span key='rate' className='rate float-left'>
|
||||
{state.playing.playbackRate}x
|
||||
</span>
|
||||
))
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='controls'>
|
||||
<div key='controls' className='controls'>
|
||||
{elements}
|
||||
{renderCastOptions(state)}
|
||||
{renderSubtitlesOptions(state)}
|
||||
{renderSubtitleOptions(state)}
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -540,21 +550,7 @@ function renderPlayerControls (state) {
|
||||
|
||||
// Handles volume slider scrub
|
||||
function handleVolumeScrub (e) {
|
||||
switch (e.type) {
|
||||
case 'mouseup':
|
||||
volumeChanging = false
|
||||
dispatch('setVolume', e.nativeEvent.offsetX / 50)
|
||||
break
|
||||
case 'mousedown':
|
||||
volumeChanging = this.value
|
||||
break
|
||||
case 'mousemove':
|
||||
// only change if move was started by click
|
||||
if (volumeChanging !== false) {
|
||||
volumeChanging = this.value
|
||||
}
|
||||
break
|
||||
}
|
||||
dispatch('setVolume', e.target.value)
|
||||
}
|
||||
|
||||
function handleSubtitles (e) {
|
||||
@@ -567,9 +563,6 @@ function renderPlayerControls (state) {
|
||||
}
|
||||
}
|
||||
|
||||
// lets scrub without sending to volume backend
|
||||
var volumeChanging = false
|
||||
|
||||
// Renders the loading bar. Shows which parts of the torrent are loaded, which
|
||||
// can be 'spongey' / non-contiguous
|
||||
function renderLoadingBar (state) {
|
||||
@@ -594,15 +587,15 @@ function renderLoadingBar (state) {
|
||||
}
|
||||
|
||||
// Output some bars to show which parts of the file are loaded
|
||||
var loadingBarElems = parts.map(function (part) {
|
||||
var loadingBarElems = parts.map(function (part, i) {
|
||||
var style = {
|
||||
left: (100 * part.start / fileProg.numPieces) + '%',
|
||||
width: (100 * part.count / fileProg.numPieces) + '%'
|
||||
}
|
||||
|
||||
return (<div className='loading-bar-part' style={style}></div>)
|
||||
return (<div key={i} className='loading-bar-part' style={style}></div>)
|
||||
})
|
||||
return (<div className='loading-bar'>{loadingBarElems}</div>)
|
||||
return (<div key='loading-bar' className='loading-bar'>{loadingBarElems}</div>)
|
||||
}
|
||||
|
||||
// Returns the CSS background-image string for a poster image + dark vignette
|
||||
|
||||
@@ -17,6 +17,7 @@ module.exports = class Preferences extends React.Component {
|
||||
|
||||
function renderGeneralSection (state) {
|
||||
return renderSection({
|
||||
key: 'general',
|
||||
title: 'General',
|
||||
description: '',
|
||||
icon: 'settings'
|
||||
@@ -27,6 +28,7 @@ function renderGeneralSection (state) {
|
||||
|
||||
function renderDownloadDirSelector (state) {
|
||||
return renderFileSelector({
|
||||
key: 'download-path',
|
||||
label: 'Download Path',
|
||||
description: 'Data from torrents will be saved here',
|
||||
property: 'downloadPath',
|
||||
@@ -46,18 +48,18 @@ function renderDownloadDirSelector (state) {
|
||||
// - controls should be an array of vdom elements
|
||||
function renderSection (definition, controls) {
|
||||
var helpElem = !definition.description ? null : (
|
||||
<div className='help text'>
|
||||
<div key='help' className='help text'>
|
||||
<i className='icon'>help_outline</i>{definition.description}
|
||||
</div>
|
||||
)
|
||||
return (
|
||||
<section className='section preferences-panel'>
|
||||
<section key={definition.key} className='section preferences-panel'>
|
||||
<div className='section-container'>
|
||||
<div className='section-heading'>
|
||||
<div key='heading' className='section-heading'>
|
||||
<i className='icon'>{definition.icon}</i>{definition.title}
|
||||
</div>
|
||||
{helpElem}
|
||||
<div className='section-body'>
|
||||
<div key='body' className='section-body'>
|
||||
{controls}
|
||||
</div>
|
||||
</div>
|
||||
@@ -72,7 +74,7 @@ function renderSection (definition, controls) {
|
||||
// - callback takes a new file or folder path
|
||||
function renderFileSelector (definition, value, callback) {
|
||||
return (
|
||||
<div className='control-group'>
|
||||
<div key={definition.key} className='control-group'>
|
||||
<div className='controls'>
|
||||
<label className='control-label'>
|
||||
<div className='preference-title'>{definition.label}</div>
|
||||
|
||||
@@ -13,9 +13,9 @@ module.exports = class TorrentList extends React.Component {
|
||||
)
|
||||
|
||||
return (
|
||||
<div className='torrent-list'>
|
||||
<div key='torrent-list' className='torrent-list'>
|
||||
{torrentRows}
|
||||
<div className='torrent-placeholder'>
|
||||
<div key='torrent-placeholder' className='torrent-placeholder'>
|
||||
<span className='ellipsis'>Drop a torrent file here or paste a magnet link</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -45,7 +45,10 @@ module.exports = class TorrentList extends React.Component {
|
||||
if (isSelected) classes.push('selected')
|
||||
if (!infoHash) classes.push('disabled')
|
||||
return (
|
||||
<div style={style} className={classes.join(' ')}
|
||||
<div
|
||||
key={torrentSummary.torrentKey}
|
||||
style={style}
|
||||
className={classes.join(' ')}
|
||||
onContextMenu={infoHash && dispatcher('openTorrentContextMenu', infoHash)}
|
||||
onClick={infoHash && dispatcher('toggleSelectTorrent', infoHash)}>
|
||||
{this.renderTorrentMetadata(torrentSummary)}
|
||||
@@ -59,14 +62,14 @@ module.exports = class TorrentList extends React.Component {
|
||||
renderTorrentMetadata (torrentSummary) {
|
||||
var name = torrentSummary.name || 'Loading torrent...'
|
||||
var elements = [(
|
||||
<div className='name ellipsis'>{name}</div>
|
||||
<div key='name' className='name ellipsis'>{name}</div>
|
||||
)]
|
||||
|
||||
// If it's downloading/seeding then show progress info
|
||||
var prog = torrentSummary.progress
|
||||
if (torrentSummary.status !== 'paused' && prog) {
|
||||
elements.push((
|
||||
<div className='ellipsis'>
|
||||
<div key='progress-info' className='ellipsis'>
|
||||
{renderPercentProgress()}
|
||||
{renderTotalProgress()}
|
||||
{renderPeers()}
|
||||
@@ -77,37 +80,37 @@ module.exports = class TorrentList extends React.Component {
|
||||
))
|
||||
}
|
||||
|
||||
return (<div className='metadata'>{elements}</div>)
|
||||
return (<div key='metadata' className='metadata'>{elements}</div>)
|
||||
|
||||
function renderPercentProgress () {
|
||||
var progress = Math.floor(100 * prog.progress)
|
||||
return (<span>{progress}%</span>)
|
||||
return (<span key='percent-progress'>{progress}%</span>)
|
||||
}
|
||||
|
||||
function renderTotalProgress () {
|
||||
var downloaded = prettyBytes(prog.downloaded)
|
||||
var total = prettyBytes(prog.length || 0)
|
||||
if (downloaded === total) {
|
||||
return (<span>{downloaded}</span>)
|
||||
return (<span key='total-progress'>{downloaded}</span>)
|
||||
} else {
|
||||
return (<span>{downloaded} / {total}</span>)
|
||||
return (<span key='total-progress'>{downloaded} / {total}</span>)
|
||||
}
|
||||
}
|
||||
|
||||
function renderPeers () {
|
||||
if (prog.numPeers === 0) return
|
||||
var count = prog.numPeers === 1 ? 'peer' : 'peers'
|
||||
return (<span>{prog.numPeers} {count}</span>)
|
||||
return (<span key='peers'>{prog.numPeers} {count}</span>)
|
||||
}
|
||||
|
||||
function renderDownloadSpeed () {
|
||||
if (prog.downloadSpeed === 0) return
|
||||
return (<span>↓ {prettyBytes(prog.downloadSpeed)}/s</span>)
|
||||
return (<span key='download'>↓ {prettyBytes(prog.downloadSpeed)}/s</span>)
|
||||
}
|
||||
|
||||
function renderUploadSpeed () {
|
||||
if (prog.uploadSpeed === 0) return
|
||||
return (<span>↑ {prettyBytes(prog.uploadSpeed)}/s</span>)
|
||||
return (<span key='upload'>↑ {prettyBytes(prog.uploadSpeed)}/s</span>)
|
||||
}
|
||||
|
||||
function renderEta () {
|
||||
@@ -175,6 +178,7 @@ module.exports = class TorrentList extends React.Component {
|
||||
if (TorrentPlayer.isPlayableTorrentSummary(torrentSummary)) {
|
||||
playButton = (
|
||||
<i
|
||||
key='play-button'
|
||||
title={playTooltip}
|
||||
className={'button-round icon play ' + playClass}
|
||||
onClick={dispatcher('playFile', infoHash)}>
|
||||
@@ -184,16 +188,18 @@ module.exports = class TorrentList extends React.Component {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='buttons'>
|
||||
<div key='buttons' className='buttons'>
|
||||
{positionElem}
|
||||
{playButton}
|
||||
<i
|
||||
key='download-button'
|
||||
className={'button-round icon download ' + torrentSummary.status}
|
||||
title={downloadTooltip}
|
||||
onClick={dispatcher('toggleTorrent', infoHash)}>
|
||||
{downloadIcon}
|
||||
</i>
|
||||
<i
|
||||
key='delete-button'
|
||||
className='icon delete'
|
||||
title='Remove torrent'
|
||||
onClick={dispatcher('confirmDeleteTorrent', infoHash, false)}>
|
||||
@@ -211,7 +217,7 @@ module.exports = class TorrentList extends React.Component {
|
||||
var message = torrentSummary.status === 'paused'
|
||||
? 'Failed to load torrent info. Click the download button to try again...'
|
||||
: 'Downloading torrent info...'
|
||||
filesElement = (<div className='files warning'>{message}</div>)
|
||||
filesElement = (<div key='files' className='files warning'>{message}</div>)
|
||||
} else {
|
||||
// We do know the files. List them and show download stats for each one
|
||||
var fileRows = torrentSummary.files
|
||||
@@ -224,16 +230,18 @@ module.exports = class TorrentList extends React.Component {
|
||||
.map((object) => this.renderFileRow(torrentSummary, object.file, object.index))
|
||||
|
||||
filesElement = (
|
||||
<div className='files'>
|
||||
<div key='files' className='files'>
|
||||
<table>
|
||||
{fileRows}
|
||||
<tbody>
|
||||
{fileRows}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='torrent-details'>
|
||||
<div key='details' className='torrent-details'>
|
||||
{filesElement}
|
||||
</div>
|
||||
)
|
||||
@@ -275,7 +283,7 @@ module.exports = class TorrentList extends React.Component {
|
||||
if (!isSelected) rowClass = 'disabled' // File deselected, not being torrented
|
||||
if (!isDone && !isPlayable) rowClass = 'disabled' // Can't open yet, can't stream
|
||||
return (
|
||||
<tr onClick={handleClick}>
|
||||
<tr key={index} onClick={handleClick}>
|
||||
<td className={'col-icon ' + rowClass}>
|
||||
{positionElem}
|
||||
<i className='icon'>{icon}</i>
|
||||
@@ -303,17 +311,17 @@ module.exports = class TorrentList extends React.Component {
|
||||
var transformFix = {transform: 'rotate(' + rotation + 'deg)'}
|
||||
|
||||
return (
|
||||
<div className={'radial-progress ' + cssClass}>
|
||||
<div className='circle'>
|
||||
<div className='mask full' style={transformFill}>
|
||||
<div className='fill' style={transformFill}></div>
|
||||
<div key='radial-progress' className={'radial-progress ' + cssClass}>
|
||||
<div key='circle' className='circle'>
|
||||
<div key='mask-full' className='mask full' style={transformFill}>
|
||||
<div key='fill' className='fill' style={transformFill}></div>
|
||||
</div>
|
||||
<div className='mask half'>
|
||||
<div className='fill' style={transformFill}></div>
|
||||
<div className='fill fix' style={transformFix}></div>
|
||||
<div key='mask-half' className='mask half'>
|
||||
<div key='fill' className='fill' style={transformFill}></div>
|
||||
<div key='fill-fix' className='fill fix' style={transformFix}></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='inset'></div>
|
||||
<div key='inset' className='inset'></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -26,6 +26,13 @@ body {
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
#body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
table {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
@@ -9,5 +9,7 @@
|
||||
require('../build/renderer/main.js')
|
||||
</script>
|
||||
</head>
|
||||
<body></body>
|
||||
<body>
|
||||
<div id='body'></div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user