Merge pull request #597 from feross/refactor

[WIP] Major code cleanup
This commit is contained in:
Feross Aboukhadijeh
2016-05-29 04:06:51 -07:00
36 changed files with 984 additions and 771 deletions

View File

@@ -1,36 +1,39 @@
module.exports = {
setDispatch,
dispatch,
dispatcher
dispatcher,
setDispatch
}
// Memoize most of our event handlers, which are functions in the form
// () => dispatch(<args>)
// ... this prevents virtual-dom from updating every listener on every update()
var _dispatchers = {}
var _dispatch = () => {}
var dispatchers = {}
var _dispatch = function () {}
function setDispatch (dispatch) {
_dispatch = dispatch
}
// Get a _memoized event handler that calls dispatch()
// All args must be JSON-able
function dispatch (...args) {
_dispatch(...args)
}
// Most DOM event handlers are trivial functions like `() => dispatch(<args>)`.
// For these, `dispatcher(<args>)` is preferred because it memoizes the handler
// function. This prevents virtual-dom from updating the listener functions on
// each update().
function dispatcher (...args) {
var json = JSON.stringify(args)
var handler = _dispatchers[json]
var str = JSON.stringify(args)
var handler = dispatchers[str]
if (!handler) {
handler = _dispatchers[json] = (e) => {
// Don't click on whatever is below the button
handler = dispatchers[str] = function (e) {
// Do not propagate click to elements below the button
e.stopPropagation()
// Don't regisiter clicks on disabled buttons
if (e.currentTarget.classList.contains('disabled')) return
_dispatch.apply(null, args)
if (e.currentTarget.classList.contains('disabled')) {
// Ignore clicks on disabled elements
return
}
dispatch(...args)
}
}
return handler
}
function dispatch (...args) {
_dispatch.apply(null, args)
}

5
renderer/lib/hx.js Normal file
View File

@@ -0,0 +1,5 @@
var h = require('virtual-dom/h')
var hyperx = require('hyperx')
var hx = hyperx(h)
module.exports = hx

View File

@@ -3,8 +3,8 @@ var path = require('path')
var remote = electron.remote
var config = require('../config')
var LocationHistory = require('./lib/location-history')
var config = require('../../config')
var LocationHistory = require('./location-history')
module.exports = {
getInitialState,

View File

@@ -280,36 +280,36 @@ table {
width: 100%;
}
.create-torrent-page {
.create-torrent {
padding: 10px 25px;
overflow: hidden;
}
.create-torrent-page .torrent-attribute {
.create-torrent .torrent-attribute {
white-space: nowrap;
}
.create-torrent-page .torrent-attribute>* {
.create-torrent .torrent-attribute>* {
display: inline-block;
}
.create-torrent-page .torrent-attribute label {
.create-torrent .torrent-attribute label {
width: 60px;
margin-right: 10px;
vertical-align: top;
}
.create-torrent-page .torrent-attribute>div {
.create-torrent .torrent-attribute>div {
width: calc(100% - 90px);
}
.create-torrent-page .torrent-attribute div {
.create-torrent .torrent-attribute div {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.create-torrent-page .torrent-attribute textarea {
.create-torrent .torrent-attribute textarea {
width: calc(100% - 80px);
height: 80px;
color: #eee;
@@ -321,11 +321,11 @@ table {
padding: 4px 6px;
}
.create-torrent-page textarea.torrent-trackers {
.create-torrent textarea.torrent-trackers {
height: 200px;
}
.create-torrent-page input.torrent-is-private {
.create-torrent input.torrent-is-private {
width: initial;
margin: 0;
}

View File

@@ -3,9 +3,9 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="index.css" charset="utf-8">
<link rel="stylesheet" href="main.css" charset="utf-8">
</head>
<body>
<script async src="index.js"></script>
<script async src="main.js"></script>
</body>
</html>

View File

@@ -28,7 +28,7 @@ var App = require('./views/app')
var config = require('../config')
var errors = require('./lib/errors')
var sound = require('./lib/sound')
var State = require('./state')
var State = require('./lib/state')
var TorrentPlayer = require('./lib/torrent-player')
var TorrentSummary = require('./lib/torrent-summary')
@@ -224,12 +224,16 @@ function dispatch (action, ...args) {
if (action === 'addTorrent') {
addTorrent(args[0] /* torrent */)
}
if (action === 'showOpenTorrentFile') {
ipcRenderer.send('showOpenTorrentFile') /* open torrent file */
if (action === 'openTorrentFile') {
ipcRenderer.send('openTorrentFile') /* open torrent file */
}
if (action === 'showCreateTorrent') {
showCreateTorrent(args[0] /* paths */)
}
if (action === 'openTorrentAddress') {
state.modal = { id: 'open-torrent-address-modal' }
update()
}
if (action === 'createTorrent') {
createTorrent(args[0] /* options */)
}
@@ -377,6 +381,9 @@ function dispatch (action, ...args) {
if (action === 'saveState') {
saveState()
}
if (action === 'setTitle') {
state.window.title = args[0] /* title */
}
// Update the virtual-dom, unless it's just a mouse move event
if (action !== 'mediaMouseMoved' || showOrHidePlayerControls()) {
@@ -508,11 +515,6 @@ function setupIpc () {
ipcRenderer.on('dispatch', (e, ...args) => dispatch(...args))
ipcRenderer.on('showOpenTorrentAddress', function (e) {
state.modal = { id: 'open-torrent-address-modal' }
update()
})
ipcRenderer.on('fullscreenChanged', function (e, isFullScreen) {
state.window.isFullScreen = isFullScreen
if (!isFullScreen) {
@@ -606,7 +608,8 @@ function saveState () {
update()
}
// Called when the user drag-drops files onto the app
// Called when the user adds files (.torrent, files to seed, subtitles) to the app
// via any method (drag-drop, drag to app icon, command line)
function onOpen (files) {
if (!Array.isArray(files)) files = [ files ]
@@ -674,12 +677,13 @@ function addTorrent (torrentId) {
}
function addSubtitles (files, autoSelect) {
// Subtitles are only supported while playing video
// Subtitles are only supported when playing video files
if (state.playing.type !== 'video') return
if (files.length === 0) return
// Read the files concurrently, then add all resulting subtitle tracks
var jobs = files.map((file) => (cb) => loadSubtitle(file, cb))
parallel(jobs, function (err, tracks) {
var tasks = files.map((file) => (cb) => loadSubtitle(file, cb))
parallel(tasks, function (err, tracks) {
if (err) return onError(err)
for (var i = 0; i < tracks.length; i++) {
@@ -974,7 +978,10 @@ function torrentProgress (progressInfo) {
torrentSummary.progress = p
})
checkForSubtitles()
// TODO: Find an efficient way to re-enable this line, which allows subtitle
// files which are completed after a video starts to play to be added
// dynamically to the list of subtitles.
// checkForSubtitles()
update()
}
@@ -1312,7 +1319,7 @@ function showDoneNotification (torrent) {
})
notif.onclick = function () {
ipcRenderer.send('focusWindow', 'main')
ipcRenderer.send('show')
}
sound.play('DONE')

View File

@@ -1,16 +1,15 @@
module.exports = App
var h = require('virtual-dom/h')
var hyperx = require('hyperx')
var hx = hyperx(h)
var hx = require('../lib/hx')
var Header = require('./header')
var Views = {
'home': require('./torrent-list'),
'home': require('./home'),
'player': require('./player'),
'create-torrent': require('./create-torrent-page'),
'create-torrent': require('./create-torrent'),
'preferences': require('./preferences')
}
var Modals = {
'open-torrent-address-modal': require('./open-torrent-address-modal'),
'update-available-modal': require('./update-available-modal'),

View File

@@ -1,14 +1,11 @@
module.exports = CreateTorrentPage
var h = require('virtual-dom/h')
var hyperx = require('hyperx')
var hx = hyperx(h)
var createTorrent = require('create-torrent')
var path = require('path')
var prettyBytes = require('prettier-bytes')
var {dispatch, dispatcher} = require('../lib/dispatcher')
var hx = require('../lib/hx')
function CreateTorrentPage (state) {
var info = state.location.current()
@@ -59,7 +56,7 @@ function CreateTorrentPage (state) {
var collapsedClass = info.showAdvanced ? 'expanded' : 'collapsed'
return hx`
<div class='create-torrent-page'>
<div class='create-torrent'>
<h2>Create torrent ${defaultName}</h2>
<p class="torrent-info">
${torrentInfo}
@@ -132,7 +129,7 @@ function CreateTorrentPage (state) {
function CreateTorrentErrorPage () {
return hx`
<div class='create-torrent-page'>
<div class='create-torrent'>
<h2>Create torrent</h2>
<p class="torrent-info">
<p>

View File

@@ -1,10 +1,7 @@
module.exports = Header
var h = require('virtual-dom/h')
var hyperx = require('hyperx')
var hx = hyperx(h)
var {dispatcher} = require('../lib/dispatcher')
var hx = require('../lib/hx')
function Header (state) {
return hx`
@@ -42,7 +39,7 @@ function Header (state) {
<i
class='icon add'
title='Add torrent'
onclick=${dispatcher('showOpenTorrentFile')}>
onclick=${dispatcher('openTorrentFile')}>
add
</i>
`

View File

@@ -1,17 +1,17 @@
module.exports = TorrentList
var h = require('virtual-dom/h')
var hyperx = require('hyperx')
var hx = hyperx(h)
var prettyBytes = require('prettier-bytes')
var hx = require('../lib/hx')
var TorrentSummary = require('../lib/torrent-summary')
var TorrentPlayer = require('../lib/torrent-player')
var {dispatcher} = require('../lib/dispatcher')
function TorrentList (state) {
var torrentRows = state.saved.torrents.map(
(torrentSummary) => renderTorrent(torrentSummary))
(torrentSummary) => renderTorrent(torrentSummary)
)
return hx`
<div class='torrent-list'>
${torrentRows}
@@ -20,11 +20,7 @@ function TorrentList (state) {
</div>
</div>`
// Renders a torrent in the torrent list
// Includes name, download status, play button, background image
// May be expanded for additional info, including the list of files inside
function renderTorrent (torrentSummary) {
// Get ephemeral data (like progress %) directly from the WebTorrent handle
var infoHash = torrentSummary.infoHash
var isSelected = infoHash && state.selectedInfoHash === infoHash

View File

@@ -1,10 +1,7 @@
module.exports = OpenTorrentAddressModal
var h = require('virtual-dom/h')
var hyperx = require('hyperx')
var hx = hyperx(h)
var {dispatch} = require('../lib/dispatcher')
var hx = require('../lib/hx')
function OpenTorrentAddressModal (state) {
return hx`

View File

@@ -1,13 +1,10 @@
module.exports = Player
var h = require('virtual-dom/h')
var hyperx = require('hyperx')
var hx = hyperx(h)
var Bitfield = require('bitfield')
var prettyBytes = require('prettier-bytes')
var zeroFill = require('zero-fill')
var hx = require('../lib/hx')
var TorrentSummary = require('../lib/torrent-summary')
var {dispatch, dispatcher} = require('../lib/dispatcher')

View File

@@ -1,8 +1,6 @@
module.exports = Preferences
var h = require('virtual-dom/h')
var hyperx = require('hyperx')
var hx = hyperx(h)
var hx = require('../lib/hx')
var {dispatch} = require('../lib/dispatcher')
var remote = require('electron').remote

View File

@@ -1,12 +1,9 @@
module.exports = UnsupportedMediaModal
var h = require('virtual-dom/h')
var hyperx = require('hyperx')
var hx = hyperx(h)
var electron = require('electron')
var {dispatch, dispatcher} = require('../lib/dispatcher')
var hx = require('../lib/hx')
function UnsupportedMediaModal (state) {
var err = state.modal.error

View File

@@ -1,12 +1,9 @@
module.exports = UpdateAvailableModal
var h = require('virtual-dom/h')
var hyperx = require('hyperx')
var hx = hyperx(h)
var electron = require('electron')
var {dispatch} = require('../lib/dispatcher')
var hx = require('../lib/hx')
function UpdateAvailableModal (state) {
return hx`