diff --git a/css/playlist.css b/css/playlist.css index 70726f78..c5de9a0e 100644 --- a/css/playlist.css +++ b/css/playlist.css @@ -34,6 +34,10 @@ #playlist #tracks li { white-space: nowrap; color: lightgreen; + font-size: 8px; +} +#playlist #tracks li.selected { + background-color: red; } #playlist .top { @@ -135,3 +139,11 @@ width: 150px; background-position: -126px -72px; } + +#playlist #playlist-resize-handle { + position: absolute; + width: 20px; + height: 20px; + bottom: 0px; + right: 0px; +} diff --git a/index.html b/index.html index 91a7e612..f69f9e48 100755 --- a/index.html +++ b/index.html @@ -104,18 +104,7 @@
- +
@@ -132,8 +121,9 @@
-
-
+
+
+
diff --git a/js/main-window.js b/js/main-window.js index 4d2febe3..296a5f5f 100644 --- a/js/main-window.js +++ b/js/main-window.js @@ -206,6 +206,8 @@ MainWindow = { window.addEventListener('doubledModeToggled', function() { self.toggleDoubledMode(); }); window.addEventListener('repeatToggled', function() { self.toggleRepeat(); }); window.addEventListener('llamaToggled', function() { self.toggleLlama(); }); + window.addEventListener('openPlaylist', function() { self.nodes.playlistButton.classList.add('selected'); }); + window.addEventListener('closePlaylist', function() { self.nodes.playlistButton.classList.remove('selected'); }); this.nodes.window.addEventListener('dragenter', this.dragenter.bind(this)); this.nodes.window.addEventListener('dragover', this.dragover.bind(this)); @@ -373,11 +375,6 @@ MainWindow = { togglePlaylist: function() { this.winamp.togglePlaylist(); - if(this.winamp.playlistIsClosed()) { - this.nodes.playlistButton.classList.remove('selected'); - } else { - this.nodes.playlistButton.classList.add('selected'); - } }, dragenter: function(e) { diff --git a/js/playlist-window.js b/js/playlist-window.js index cae254f0..e0a0ea26 100644 --- a/js/playlist-window.js +++ b/js/playlist-window.js @@ -5,13 +5,17 @@ PlaylistWindow = { 'window': document.getElementById('playlist'), 'top': document.querySelector('#playlist .top'), 'shade': document.getElementById('playlist-shade'), - 'close': document.getElementById('playlist-close') + 'close': document.getElementById('playlist-close'), + 'tracks': document.getElementById('tracks'), + 'resizeHandle': document.getElementById('playlist-resize-handle') }; this.closed = this.nodes.window.classList.contains('closed'); this.handle = this.nodes.top; this.body = this.nodes.window; + this.resizeHandle = this.nodes.resizeHandle; + this._registerListeners(); return this; @@ -20,9 +24,18 @@ PlaylistWindow = { _registerListeners: function() { var self = this; + window.addEventListener('openPlaylist', function() { self.open(); }); + window.addEventListener('closePlaylist', function() { self.close(); }); + window.addEventListener('tracksUpdated', function() { self.updateTracks(); }); + window.addEventListener('currentTrackChanged', function() { self.updateCurrentTrack(); }); + this.nodes.close.onclick = function() { - self.close(); + self.winamp.closePlaylist(); } + + this.nodes.window.addEventListener('dragenter', this.dragenter.bind(this)); + this.nodes.window.addEventListener('dragover', this.dragover.bind(this)); + this.nodes.window.addEventListener('drop', this.drop.bind(this)); }, close: function() { @@ -45,6 +58,32 @@ PlaylistWindow = { } }, + updateTracks: function() { + var tracks = this.nodes.tracks; + while (tracks.firstChild) { + tracks.removeChild(tracks.firstChild); + } + + for(i = 0; i < this.winamp.playlist.length; i++) { + var li = document.createElement('li'); + li.innerHTML = "
  • " + (i+1) + ". " + this.winamp.playlist[i].name + "
  • "; + tracks.appendChild(li); + } + + this.updateCurrentTrack(); + }, + + updateCurrentTrack: function() { + var tracks = this.nodes.tracks.children; + for(i = 0; i < tracks.length; i++) { + if(i == this.winamp.currentTrack) { + tracks[i].classList.add('selected'); + } else { + tracks[i].classList.remove('selected'); + } + } + }, + dragenter: function(e) { e.stopPropagation(); e.preventDefault(); @@ -60,7 +99,7 @@ PlaylistWindow = { e.preventDefault(); var dt = e.dataTransfer; var file = dt.files[0]; - this.winamp.loadFromFileReference(file); + this.winamp.enqueueFromFileReference(file, 0); } } diff --git a/js/winamp.js b/js/winamp.js index abfc1bd7..f790c8b2 100755 --- a/js/winamp.js +++ b/js/winamp.js @@ -13,6 +13,9 @@ Winamp = { this.mainWindow = MainWindow.init(this); this.playlistWindow = PlaylistWindow.init(this); + this.playlist = []; + this.currentTrack = null; + this.events = { timeUpdated: new Event('timeUpdated'), startWaiting: new Event('startWaiting'), @@ -27,7 +30,11 @@ Winamp = { balanceChanged: new Event('balanceChanged'), doubledModeToggled: new Event('doubledModeToggled'), repeatToggled: new Event('repeatToggled'), - llamaToggled: new Event('llamaToggled') + llamaToggled: new Event('llamaToggled'), + openPlaylist: new Event('openPlaylist'), + closePlaylist: new Event('closePlaylist'), + tracksUpdated: new Event('tracksUpdated'), + currentTrackChanged: new Event('currentTrackChanged') }; this.setVolume(options.volume); @@ -117,8 +124,11 @@ Winamp = { }, previous: function(num) { - // Jump back num tracks - // Not yet supported + if(this.currentTrack > 0) { + this.currentTrack = this.currentTrack - 1; + window.dispatchEvent(this.events.currentTrackChanged); + this.playFromFileReference(this.playlist[this.currentTrack]); + } }, play: function() { @@ -139,14 +149,19 @@ Winamp = { this.setState('pause'); } }, + stop: function() { this.media.stop(); this.setState('stop'); }, next: function(num) { - // Jump back num tracks - // Not yet supported + this.currentTrack++; + if(this.currentTrack == this.playlist.length) { + this.currentTrack = 0; + } + window.dispatchEvent(this.events.currentTrackChanged); + this.playFromFileReference(this.playlist[this.currentTrack]); }, // From 0-100 @@ -203,12 +218,20 @@ Winamp = { this.setState('stop'); // Currently unneeded }, - togglePlaylist: function() { - this.playlistWindow.toggle(); + openPlaylist: function() { + window.dispatchEvent(this.events.openPlaylist); }, - playlistIsClosed: function() { - return this.playlistWindow.isClosed(); + closePlaylist: function() { + window.dispatchEvent(this.events.closePlaylist); + }, + + togglePlaylist: function() { + if(this.playlistWindow.isClosed()) { + this.openPlaylist(); + } else { + this.closePlaylist(); + } }, openFileDialog: function() { @@ -221,12 +244,24 @@ Winamp = { if(new RegExp("(wsz|zip)$", 'i').test(fileReference.name)) { this.skin.setSkinByFile(file); } else { - this.media.autoPlay = true; - this.fileName = fileReference.name; - file.processBuffer(this._loadBuffer.bind(this)); + this.playlist = []; + this.enqueueFromFileReference(fileReference); + this.currentTrack = 0; + this.playFromFileReference(this.playlist[0]); } }, + playFromFileReference: function(fileReference) { + this.media.autoPlay = true; + this.fileName = fileReference.name; + this.fileManager.bufferFromFileReference(fileReference, this._loadBuffer.bind(this)); + }, + + enqueueFromFileReference: function(fileReference, position) { + this.playlist.push(fileReference); + window.dispatchEvent(this.events.tracksUpdated); + }, + // Used only for the initial load, since it must have a CORS header loadFromUrl: function(url, fileName) { this.fileName = fileName; diff --git a/js/window-manager.js b/js/window-manager.js index 382534df..c2dc455e 100644 --- a/js/window-manager.js +++ b/js/window-manager.js @@ -2,6 +2,7 @@ WindowManager = { registerWindow: function(win) { var body = win.body; var handle = win.handle; + var resizeHandle = win.resizeHandle; // Make window dragable handle.addEventListener('mousedown',function(e){ @@ -54,5 +55,56 @@ WindowManager = { window.addEventListener('mousemove',handleMove); window.addEventListener('mouseup',handleUp); }); + + if (typeof resizeHandle == 'undefined') return; + + // Make window resizeable + resizeHandle.addEventListener('mousedown',function(e){ + var winStartHeight = body.offsetHeight, + winStartWidth = body.offsetWidth; + + // Get starting mouse position + var mouseStartLeft = e.clientX, + mouseStartTop = e.clientY; + + // Mouse move handler function while mouse is down + function handleResize(e) { + // Get current mouse position + var mouseLeft = e.clientX, + mouseTop = e.clientY; + + // Calculate difference offsets + var diffLeft = mouseLeft-mouseStartLeft, + diffTop = mouseTop-mouseStartTop; + + var newWidth = (winStartWidth+diffLeft), + newHeight = (winStartHeight+diffTop); + + // Enforce resizing by 25px + newWidth = Math.ceil(newWidth / 25.0) * 25; + newHeight = Math.ceil(newHeight / 29.0) * 29; + + // Enforce minimum size + newWidth = Math.max(newWidth, 275); + newHeight = Math.max(newHeight, 116); + + // Resize window + body.style.width = newWidth +"px"; + body.style.height = newHeight +"px"; + } + + // Mouse button up + function handleUp() { + removeListeners(); + } + + function removeListeners() { + window.removeEventListener('mousemove',handleResize); + window.removeEventListener('mouseup',handleUp); + } + + window.addEventListener('mousemove',handleResize); + window.addEventListener('mouseup',handleUp); + }); } };