Switch to ES6-style imports

This commit is contained in:
Jordan Eldredge 2016-07-03 21:56:37 -07:00
parent b5c7824f86
commit f37ceb24f1
15 changed files with 1282 additions and 1337 deletions

View file

@ -1,9 +1,6 @@
define([], function() {
return function(base) {
var supportsAudioApi = !!(base.AudioContext || base.webkitAudioContext);
var supportsCanvas = !!(base.document.createElement('canvas').getContext);
this.isCompatible = supportsAudioApi && supportsCanvas;
};
});
module.exports = function(base) {
var supportsAudioApi = !!(base.AudioContext || base.webkitAudioContext);
var supportsCanvas = !!(base.document.createElement('canvas').getContext);
this.isCompatible = supportsAudioApi && supportsCanvas;
};

View file

@ -1,50 +1,45 @@
define([
'my-file'
], function(
MyFile
) {
var Context = function(winamp) {
this.winamp = winamp;
import MyFile from './my-file';
var Context = function(winamp) {
this.winamp = winamp;
var el = {
option: document.getElementById('option'),
playFile: document.getElementById('context-play-file'),
loadSkin: document.getElementById('context-load-skin'),
exit: document.getElementById('context-exit'),
skinOptions: document.getElementsByClassName('skin-select')
};
// Click anywhere to close the context menu
document.addEventListener('click', function() {
el.option.classList.remove('selected');
});
// Click the context menu to close it
el.option.addEventListener('click', function(e) {
el.option.classList.toggle('selected');
e.stopPropagation();
});
// Bind to each of the various skin options
for (var i = 0; i < el.skinOptions.length; i++) {
el.skinOptions[i].addEventListener('click', function(e) {
this.loadSkin(e.target.dataset.skinUrl);
}.bind(this));
}
// Play file and load skin both just spawn the file opener
el.playFile.addEventListener('click', winamp.openFileDialog);
el.loadSkin.addEventListener('click', winamp.openFileDialog);
// Close all of Winamp
el.exit.addEventListener('click', winamp.close);
var el = {
option: document.getElementById('option'),
playFile: document.getElementById('context-play-file'),
loadSkin: document.getElementById('context-load-skin'),
exit: document.getElementById('context-exit'),
skinOptions: document.getElementsByClassName('skin-select')
};
Context.prototype.loadSkin = function(url) {
var skinFile = new MyFile();
skinFile.setUrl(url);
this.winamp.setSkin(skinFile);
};
// Click anywhere to close the context menu
document.addEventListener('click', function() {
el.option.classList.remove('selected');
});
return Context;
});
// Click the context menu to close it
el.option.addEventListener('click', function(e) {
el.option.classList.toggle('selected');
e.stopPropagation();
});
// Bind to each of the various skin options
for (var i = 0; i < el.skinOptions.length; i++) {
el.skinOptions[i].addEventListener('click', function(e) {
this.loadSkin(e.target.dataset.skinUrl);
}.bind(this));
}
// Play file and load skin both just spawn the file opener
el.playFile.addEventListener('click', winamp.openFileDialog);
el.loadSkin.addEventListener('click', winamp.openFileDialog);
// Close all of Winamp
el.exit.addEventListener('click', winamp.close);
};
Context.prototype.loadSkin = function(url) {
var skinFile = new MyFile();
skinFile.setUrl(url);
this.winamp.setSkin(skinFile);
};
module.exports = Context;

View file

@ -1,63 +1,60 @@
// Manage rendering text from this skin's text.bmp file
define([], function(){
var Font = function() {
module.exports = function() {
// Fill a node with a <div> containing character <div>s
this.setNodeToString = function(node, string) {
var stringElement = document.createElement('div');
for (var i = 0, len = string.length; i < len; i++) {
var char = string[i].toLowerCase();
stringElement.appendChild(this.characterNode(char));
}
node.innerHTML = '';
node.appendChild(stringElement);
};
// Get a <div> containing char
this.characterNode = function(char) {
return this.displayCharacterInNode(char, document.createElement('div'));
};
// Style/populate a <div> to display a character
this.displayCharacterInNode = function(character, node) {
var position = this._fontLookup[character] || this._fontLookup[' '];
var verticalOffset = position[0] * 6;
var horizontalOffset = position[1] * 5;
var x = '-' + horizontalOffset + 'px';
var y = '-' + verticalOffset + 'px';
node.style.backgroundPosition = x + ' ' + y;
node.classList.add('character');
node.innerHTML = character;
return node;
};
// Get a <div> containing a digit
this.digitNode = function(digit) {
var div = document.createElement('div');
div.classList.add('digit');
div.classList.add('digit-' + digit);
return div;
};
/* TODO: There are too many " " and "_" characters */
this._fontLookup = {
'a': [0, 0], 'b': [0, 1], 'c': [0, 2], 'd': [0, 3], 'e': [0, 4], 'f': [0, 5],
'g': [0, 6], 'h': [0, 7], 'i': [0, 8], 'j': [0, 9], 'k': [0, 10],
'l': [0, 11], 'm': [0, 12], 'n': [0, 13], 'o': [0, 14], 'p': [0, 15],
'q': [0, 16], 'r': [0, 17], 's': [0, 18], 't': [0, 19], 'u': [0, 20],
'v': [0, 21], 'w': [0, 22], 'x': [0, 23], 'y': [0, 24], 'z': [0, 25],
'"': [0, 26], '@': [0, 27], '0': [1, 0], '1': [1, 1],
'2': [1, 2], '3': [1, 3], '4': [1, 4], '5': [1, 5], '6': [1, 6], '7': [1, 7],
'8': [1, 8], '9': [1, 9], '_': [1, 11], ':': [1, 12],
'(': [1, 13], ')': [1, 14], '-': [1, 15], "'": [1, 16], '!': [1, 17],
'+': [1, 19], '\\': [1, 20], '/': [1, 21], '[': [1, 22],
']': [1, 23], '^': [1, 24], '&': [1, 25], '%': [1, 26], '.': [1, 27],
'=': [1, 28], '$': [1, 29], '#': [1, 30], 'Å': [2, 0], 'Ö': [2, 1],
'Ä': [2, 2], '?': [2, 3], '*': [2, 4], ' ': [2, 5], '<': [1, 22],
'>': [1, 23], '{': [1, 22], '}': [1, 23]
};
// Fill a node with a <div> containing character <div>s
this.setNodeToString = function(node, string) {
var stringElement = document.createElement('div');
for (var i = 0, len = string.length; i < len; i++) {
var char = string[i].toLowerCase();
stringElement.appendChild(this.characterNode(char));
}
node.innerHTML = '';
node.appendChild(stringElement);
};
return Font;
});
// Get a <div> containing char
this.characterNode = function(char) {
return this.displayCharacterInNode(char, document.createElement('div'));
};
// Style/populate a <div> to display a character
this.displayCharacterInNode = function(character, node) {
var position = this._fontLookup[character] || this._fontLookup[' '];
var verticalOffset = position[0] * 6;
var horizontalOffset = position[1] * 5;
var x = '-' + horizontalOffset + 'px';
var y = '-' + verticalOffset + 'px';
node.style.backgroundPosition = x + ' ' + y;
node.classList.add('character');
node.innerHTML = character;
return node;
};
// Get a <div> containing a digit
this.digitNode = function(digit) {
var div = document.createElement('div');
div.classList.add('digit');
div.classList.add('digit-' + digit);
return div;
};
/* TODO: There are too many " " and "_" characters */
this._fontLookup = {
'a': [0, 0], 'b': [0, 1], 'c': [0, 2], 'd': [0, 3], 'e': [0, 4], 'f': [0, 5],
'g': [0, 6], 'h': [0, 7], 'i': [0, 8], 'j': [0, 9], 'k': [0, 10],
'l': [0, 11], 'm': [0, 12], 'n': [0, 13], 'o': [0, 14], 'p': [0, 15],
'q': [0, 16], 'r': [0, 17], 's': [0, 18], 't': [0, 19], 'u': [0, 20],
'v': [0, 21], 'w': [0, 22], 'x': [0, 23], 'y': [0, 24], 'z': [0, 25],
'"': [0, 26], '@': [0, 27], '0': [1, 0], '1': [1, 1],
'2': [1, 2], '3': [1, 3], '4': [1, 4], '5': [1, 5], '6': [1, 6], '7': [1, 7],
'8': [1, 8], '9': [1, 9], '_': [1, 11], ':': [1, 12],
'(': [1, 13], ')': [1, 14], '-': [1, 15], "'": [1, 16], '!': [1, 17],
'+': [1, 19], '\\': [1, 20], '/': [1, 21], '[': [1, 22],
']': [1, 23], '^': [1, 24], '&': [1, 25], '%': [1, 26], '.': [1, 27],
'=': [1, 28], '$': [1, 29], '#': [1, 30], 'Å': [2, 0], 'Ö': [2, 1],
'Ä': [2, 2], '?': [2, 3], '*': [2, 4], ' ': [2, 5], '<': [1, 22],
'>': [1, 23], '{': [1, 22], '}': [1, 23]
};
};

View file

@ -1,49 +1,46 @@
define([], function() {
var Hotkeys = function(winamp) {
var keylog = [];
var trigger = [78, 85, 76, 27, 76, 27, 83, 79, 70, 84];
document.addEventListener('keyup', function(e){
if (e.ctrlKey) { // Is CTRL depressed?
switch (e.keyCode) {
case 68: winamp.toggleDoubledMode(); break; // CTRL+D
// XXX FIXME
case 76: winamp.openOptionMenu(); break; // CTRL+L
case 84: winamp.toggleTimeMode(); break; // CTRL+T
}
} else {
switch (e.keyCode) {
case 37: winamp.seekForwardBy(-5); break; // left arrow
case 38: winamp.incrementVolumeBy(1); break; // up arrow
case 39: winamp.seekForwardBy(5); break; // right arrow
case 40: winamp.incrementVolumeBy(-1); break; // down arrow
case 66: winamp.next(); break; // B
case 67: winamp.pause(); break; // C
case 76: winamp.openFileDialog(); break; // L
case 82: winamp.toggleRepeat(); break; // R
case 83: winamp.toggleShuffle(); break; // S
case 86: winamp.stop(); break; // V
case 88: winamp.play(); break; // X
case 90: winamp.previous(); break; // Z
case 96: winamp.openFileDialog(); break; // numpad 0
case 97: winamp.previous(10); break; // numpad 1
case 98: winamp.incrementVolumeBy(-1); break; // numpad 2
case 99: winamp.next(10); break; // numpad 3
case 100: winamp.previous(); break; // numpad 4
case 101: winamp.play(); break; // numpad 5
case 102: winamp.next(); break; // numpad 6
case 103: winamp.seekForwardBy(-5); break; // numpad 7
case 104: winamp.incrementVolumeBy(1); break; // numpad 8
case 105: winamp.seekForwardBy(5); break; // numpad 9
}
module.exports = function(winamp) {
var keylog = [];
var trigger = [78, 85, 76, 27, 76, 27, 83, 79, 70, 84];
document.addEventListener('keyup', function(e){
if (e.ctrlKey) { // Is CTRL depressed?
switch (e.keyCode) {
case 68: winamp.toggleDoubledMode(); break; // CTRL+D
// XXX FIXME
case 76: winamp.openOptionMenu(); break; // CTRL+L
case 84: winamp.toggleTimeMode(); break; // CTRL+T
}
} else {
switch (e.keyCode) {
case 37: winamp.seekForwardBy(-5); break; // left arrow
case 38: winamp.incrementVolumeBy(1); break; // up arrow
case 39: winamp.seekForwardBy(5); break; // right arrow
case 40: winamp.incrementVolumeBy(-1); break; // down arrow
case 66: winamp.next(); break; // B
case 67: winamp.pause(); break; // C
case 76: winamp.openFileDialog(); break; // L
case 82: winamp.toggleRepeat(); break; // R
case 83: winamp.toggleShuffle(); break; // S
case 86: winamp.stop(); break; // V
case 88: winamp.play(); break; // X
case 90: winamp.previous(); break; // Z
case 96: winamp.openFileDialog(); break; // numpad 0
case 97: winamp.previous(10); break; // numpad 1
case 98: winamp.incrementVolumeBy(-1); break; // numpad 2
case 99: winamp.next(10); break; // numpad 3
case 100: winamp.previous(); break; // numpad 4
case 101: winamp.play(); break; // numpad 5
case 102: winamp.next(); break; // numpad 6
case 103: winamp.seekForwardBy(-5); break; // numpad 7
case 104: winamp.incrementVolumeBy(1); break; // numpad 8
case 105: winamp.seekForwardBy(5); break; // numpad 9
}
}
// Easter Egg
keylog.push(e.keyCode);
keylog = keylog.slice(-10);
if (keylog.toString() === trigger.toString()) {
winamp.toggleLlama();
}
});
};
return Hotkeys;
});
// Easter Egg
keylog.push(e.keyCode);
keylog = keylog.slice(-10);
if (keylog.toString() === trigger.toString()) {
winamp.toggleLlama();
}
});
};

View file

@ -1,111 +1,109 @@
define([], function() {
function el(tagName, attributes, content) {
tagName = tagName || 'div';
attributes = attributes || {};
content = content || [];
var tag = document.createElement(tagName);
if (typeof content === 'string') {
content = [content];
}
for (var attr in attributes) {
tag.setAttribute(attr, attributes[attr]);
}
for (var i = 0; i < content.length; i++) {
if (typeof content[i] === 'string') {
tag.appendChild(document.createTextNode(content[i]));
} else {
tag.appendChild(content[i]);
}
}
return tag;
function el(tagName, attributes, content) {
tagName = tagName || 'div';
attributes = attributes || {};
content = content || [];
var tag = document.createElement(tagName);
if (typeof content === 'string') {
content = [content];
}
for (var attr in attributes) {
tag.setAttribute(attr, attributes[attr]);
}
for (var i = 0; i < content.length; i++) {
if (typeof content[i] === 'string') {
tag.appendChild(document.createTextNode(content[i]));
} else {
tag.appendChild(content[i]);
}
}
return tag;
}
return el('div', {id: 'main-window', class: 'loading stop'}, [
el('div', {id: 'loading'}, 'Loading...'),
el('div', {id: 'title-bar', class: 'selected'}, [
el('div', {id: 'option'}, [
el('ul', {id: 'context-menu'}, [
el('li', {}, [
el('a', {href: 'https://github.com/captbaritone/winamp2-js', target: '_blank'}, 'Winamp2-js...')
module.exports = el('div', {id: 'main-window', class: 'loading stop'}, [
el('div', {id: 'loading'}, 'Loading...'),
el('div', {id: 'title-bar', class: 'selected'}, [
el('div', {id: 'option'}, [
el('ul', {id: 'context-menu'}, [
el('li', {}, [
el('a', {href: 'https://github.com/captbaritone/winamp2-js', target: '_blank'}, 'Winamp2-js...')
]),
el('li', {class: 'hr'}, [ el('hr') ]),
el('li', {id: 'context-play-file'}, 'Play File...'),
el('li', {class: 'parent'}, [
el('ul', {}, [
el('li', {id: 'context-load-skin'}, 'Load Skin...'),
el('li', {class: 'hr'}, [ el('hr') ]),
el('li', {'class': 'skin-select', 'data-skin-url': 'https://cdn.rawgit.com/captbaritone/winamp-skins/master/v2/base-2.91.wsz'}, '<Base Skin>'),
el('li', {'class': 'skin-select', 'data-skin-url': 'https://cdn.rawgit.com/captbaritone/winamp-skins/master/v2/MacOSXAqua1-5.wsz'}, 'Mac OSX v1.5 (Aqua)'),
el('li', {'class': 'skin-select', 'data-skin-url': 'https://cdn.rawgit.com/captbaritone/winamp-skins/master/v2/TopazAmp1-2.wsz'}, 'TopazAmp'),
el('li', {'class': 'skin-select', 'data-skin-url': 'https://cdn.rawgit.com/captbaritone/winamp-skins/master/v2/Vizor1-01.wsz'}, 'Vizor'),
el('li', {'class': 'skin-select', 'data-skin-url': 'https://cdn.rawgit.com/captbaritone/winamp-skins/master/v2/XMMS-Turquoise.wsz'}, 'XMMS Turquoise '),
el('li', {'class': 'skin-select', 'data-skin-url': 'https://cdn.rawgit.com/captbaritone/winamp-skins/master/v2/ZaxonRemake1-0.wsz'}, 'Zaxon Remake')
// More here
]),
el('li', {class: 'hr'}, [ el('hr') ]),
el('li', {id: 'context-play-file'}, 'Play File...'),
el('li', {class: 'parent'}, [
el('ul', {}, [
el('li', {id: 'context-load-skin'}, 'Load Skin...'),
el('li', {class: 'hr'}, [ el('hr') ]),
el('li', {'class': 'skin-select', 'data-skin-url': 'https://cdn.rawgit.com/captbaritone/winamp-skins/master/v2/base-2.91.wsz'}, '<Base Skin>'),
el('li', {'class': 'skin-select', 'data-skin-url': 'https://cdn.rawgit.com/captbaritone/winamp-skins/master/v2/MacOSXAqua1-5.wsz'}, 'Mac OSX v1.5 (Aqua)'),
el('li', {'class': 'skin-select', 'data-skin-url': 'https://cdn.rawgit.com/captbaritone/winamp-skins/master/v2/TopazAmp1-2.wsz'}, 'TopazAmp'),
el('li', {'class': 'skin-select', 'data-skin-url': 'https://cdn.rawgit.com/captbaritone/winamp-skins/master/v2/Vizor1-01.wsz'}, 'Vizor'),
el('li', {'class': 'skin-select', 'data-skin-url': 'https://cdn.rawgit.com/captbaritone/winamp-skins/master/v2/XMMS-Turquoise.wsz'}, 'XMMS Turquoise '),
el('li', {'class': 'skin-select', 'data-skin-url': 'https://cdn.rawgit.com/captbaritone/winamp-skins/master/v2/ZaxonRemake1-0.wsz'}, 'Zaxon Remake')
// More here
]),
'Skins'
]),
el('li', {class: 'hr'}, [ el('hr') ]),
el('li', {id: 'context-exit'}, 'Exit')
])
]),
el('div', {id: 'shade-time'}, [
el('div', {id: 'shade-minus-sign'}),
el('div', {id: 'shade-minute-first-digit', class: 'character'}),
el('div', {id: 'shade-minute-second-digit', class: 'character'}),
el('div', {id: 'shade-second-first-digit', class: 'character'}),
el('div', {id: 'shade-second-second-digit', class: 'character'})
]),
el('div', {id: 'minimize'}),
el('div', {id: 'shade'}),
el('div', {id: 'close'})
]),
el('div', {class: 'status'}, [
el('div', {id: 'clutter-bar'}, [
el('div', {id: 'button-o'}),
el('div', {id: 'button-a'}),
el('div', {id: 'button-i'}),
el('div', {id: 'button-d'}),
el('div', {id: 'button-v'})
]),
el('div', {id: 'play-pause'}),
el('div', {id: 'work-indicator'}),
el('div', {id: 'time'}, [
el('div', {id: 'minus-sign'}),
el('div', {id: 'minute-first-digit'}),
el('div', {id: 'minute-second-digit'}),
el('div', {id: 'second-first-digit'}),
el('div', {id: 'second-second-digit'})
]),
el('canvas', {id: 'visualizer', width: '152', height: '32'})
]),
el('div', {class: 'media-info'}, [
el('div', {id: 'song-title', class: 'text'}),
el('div', {id: 'kbps'}),
el('div', {id: 'khz'}),
el('div', {class: 'mono-stereo'}, [
el('div', {id: 'mono'}),
el('div', {id: 'stereo'})
'Skins'
]),
el('li', {class: 'hr'}, [ el('hr') ]),
el('li', {id: 'context-exit'}, 'Exit')
])
]),
el('input', {id: 'volume', type: 'range', min: '0', max: '100', step: '1', value: '50'}),
el('input', {id: 'balance', type: 'range', min: '-100', max: '100', step: '2', value: '0'}),
el('div', {class: 'windows'}, [
el('div', {id: 'equalizer-button'}),
el('div', {id: 'playlist-button'})
el('div', {id: 'shade-time'}, [
el('div', {id: 'shade-minus-sign'}),
el('div', {id: 'shade-minute-first-digit', class: 'character'}),
el('div', {id: 'shade-minute-second-digit', class: 'character'}),
el('div', {id: 'shade-second-first-digit', class: 'character'}),
el('div', {id: 'shade-second-second-digit', class: 'character'})
]),
el('input', {id: 'position', type: 'range', min: '0', max: '100', step: '1', value: '0'}),
el('div', {class: 'actions'}, [
el('div', {id: 'previous'}),
el('div', {id: 'play'}),
el('div', {id: 'pause'}),
el('div', {id: 'stop'}),
el('div', {id: 'next'})
el('div', {id: 'minimize'}),
el('div', {id: 'shade'}),
el('div', {id: 'close'})
]),
el('div', {class: 'status'}, [
el('div', {id: 'clutter-bar'}, [
el('div', {id: 'button-o'}),
el('div', {id: 'button-a'}),
el('div', {id: 'button-i'}),
el('div', {id: 'button-d'}),
el('div', {id: 'button-v'})
]),
el('div', {id: 'eject'}),
el('div', {class: 'shuffle-repeat'}, [
el('div', {id: 'shuffle'}),
el('div', {id: 'repeat'})
el('div', {id: 'play-pause'}),
el('div', {id: 'work-indicator'}),
el('div', {id: 'time'}, [
el('div', {id: 'minus-sign'}),
el('div', {id: 'minute-first-digit'}),
el('div', {id: 'minute-second-digit'}),
el('div', {id: 'second-first-digit'}),
el('div', {id: 'second-second-digit'})
]),
el('a', {id: 'about', target: 'blank', href: 'https://github.com/captbaritone/winamp2-js'})
]);
});
el('canvas', {id: 'visualizer', width: '152', height: '32'})
]),
el('div', {class: 'media-info'}, [
el('div', {id: 'song-title', class: 'text'}),
el('div', {id: 'kbps'}),
el('div', {id: 'khz'}),
el('div', {class: 'mono-stereo'}, [
el('div', {id: 'mono'}),
el('div', {id: 'stereo'})
])
]),
el('input', {id: 'volume', type: 'range', min: '0', max: '100', step: '1', value: '50'}),
el('input', {id: 'balance', type: 'range', min: '-100', max: '100', step: '2', value: '0'}),
el('div', {class: 'windows'}, [
el('div', {id: 'equalizer-button'}),
el('div', {id: 'playlist-button'})
]),
el('input', {id: 'position', type: 'range', min: '0', max: '100', step: '1', value: '0'}),
el('div', {class: 'actions'}, [
el('div', {id: 'previous'}),
el('div', {id: 'play'}),
el('div', {id: 'pause'}),
el('div', {id: 'stop'}),
el('div', {id: 'next'})
]),
el('div', {id: 'eject'}),
el('div', {class: 'shuffle-repeat'}, [
el('div', {id: 'shuffle'}),
el('div', {id: 'repeat'})
]),
el('a', {id: 'about', target: 'blank', href: 'https://github.com/captbaritone/winamp2-js'})
]);

View file

@ -1,428 +1,423 @@
define([
'multi-display',
'font'
], function(
MultiDisplay,
Font
) {
return {
init: function(winamp) {
this.winamp = winamp;
this.nodes = {
close: document.getElementById('close'),
shade: document.getElementById('shade'),
buttonD: document.getElementById('button-d'),
position: document.getElementById('position'),
volumeMessage: document.getElementById('volume-message'),
balanceMessage: document.getElementById('balance-message'),
positionMessage: document.getElementById('position-message'),
songTitle: document.getElementById('song-title'),
time: document.getElementById('time'),
shadeTime: document.getElementById('shade-time'),
shadeMinusSign: document.getElementById('shade-minus-sign'),
visualizer: document.getElementById('visualizer'),
previous: document.getElementById('previous'),
play: document.getElementById('play'),
pause: document.getElementById('pause'),
stop: document.getElementById('stop'),
next: document.getElementById('next'),
eject: document.getElementById('eject'),
repeat: document.getElementById('repeat'),
shuffle: document.getElementById('shuffle'),
volume: document.getElementById('volume'),
kbps: document.getElementById('kbps'),
khz: document.getElementById('khz'),
mono: document.getElementById('mono'),
stereo: document.getElementById('stereo'),
balance: document.getElementById('balance'),
workIndicator: document.getElementById('work-indicator'),
titleBar: document.getElementById('title-bar'),
window: document.getElementById('main-window')
};
import MultiDisplay from './multi-display';
import Font from './font';
this.handle = document.getElementById('title-bar');
this.body = this.nodes.window;
module.exports = {
init: function(winamp) {
this.winamp = winamp;
this.nodes = {
close: document.getElementById('close'),
shade: document.getElementById('shade'),
buttonD: document.getElementById('button-d'),
position: document.getElementById('position'),
volumeMessage: document.getElementById('volume-message'),
balanceMessage: document.getElementById('balance-message'),
positionMessage: document.getElementById('position-message'),
songTitle: document.getElementById('song-title'),
time: document.getElementById('time'),
shadeTime: document.getElementById('shade-time'),
shadeMinusSign: document.getElementById('shade-minus-sign'),
visualizer: document.getElementById('visualizer'),
previous: document.getElementById('previous'),
play: document.getElementById('play'),
pause: document.getElementById('pause'),
stop: document.getElementById('stop'),
next: document.getElementById('next'),
eject: document.getElementById('eject'),
repeat: document.getElementById('repeat'),
shuffle: document.getElementById('shuffle'),
volume: document.getElementById('volume'),
kbps: document.getElementById('kbps'),
khz: document.getElementById('khz'),
mono: document.getElementById('mono'),
stereo: document.getElementById('stereo'),
balance: document.getElementById('balance'),
workIndicator: document.getElementById('work-indicator'),
titleBar: document.getElementById('title-bar'),
window: document.getElementById('main-window')
};
this.textDisplay = new MultiDisplay(this.nodes.songTitle);
this.textDisplay.addRegister('songTitle');
this.textDisplay.addRegister('position');
this.textDisplay.addRegister('volume');
this.textDisplay.addRegister('balance');
this.textDisplay.addRegister('message'); // General purpose
this.handle = document.getElementById('title-bar');
this.body = this.nodes.window;
this.textDisplay.showRegister('songTitle');
this.textDisplay = new MultiDisplay(this.nodes.songTitle);
this.textDisplay.addRegister('songTitle');
this.textDisplay.addRegister('position');
this.textDisplay.addRegister('volume');
this.textDisplay.addRegister('balance');
this.textDisplay.addRegister('message'); // General purpose
this.textDisplay.startRegisterMarquee('songTitle');
this.textDisplay.showRegister('songTitle');
this._registerListeners();
return this;
},
this.textDisplay.startRegisterMarquee('songTitle');
_registerListeners: function() {
var self = this;
this._registerListeners();
return this;
},
this.nodes.close.onclick = function() {
self.winamp.close();
};
_registerListeners: function() {
var self = this;
this.nodes.shade.onclick = function() {
self.nodes.window.classList.toggle('shade');
};
this.nodes.close.onclick = function() {
self.winamp.close();
};
this.nodes.buttonD.onmousedown = function() {
if (self.nodes.window.classList.contains('doubled')) {
self.textDisplay.setRegisterText('message', 'Disable doublesize mode');
} else {
self.textDisplay.setRegisterText('message', 'Enable doublesize mode');
}
self.textDisplay.showRegister('message');
};
this.nodes.shade.onclick = function() {
self.nodes.window.classList.toggle('shade');
};
this.nodes.buttonD.onmouseup = function() {
self.textDisplay.showRegister('songTitle');
};
this.nodes.buttonD.onclick = function() {
self.winamp.toggleDoubledMode();
};
this.nodes.play.onclick = function() {
self.winamp.play();
};
this.nodes.songTitle.onmousedown = function() {
self.textDisplay.pauseRegisterMarquee('songTitle');
};
this.nodes.songTitle.onmouseup = function() {
setTimeout(function() {
self.textDisplay.startRegisterMarquee('songTitle');
}, 1000);
};
this.nodes.position.onmousedown = function() {
if (!self.nodes.window.classList.contains('stop')){
self.textDisplay.showRegister('position');
self.nodes.window.classList.add('setting-position');
}
};
this.nodes.position.onmouseup = function() {
self.textDisplay.showRegister('songTitle');
self.nodes.window.classList.remove('setting-position');
};
this.nodes.position.oninput = function() {
var newPercentComplete = self.nodes.position.value;
var newFractionComplete = newPercentComplete / 100;
var newElapsed = self._timeString(self.winamp.getDuration() * newFractionComplete);
var duration = self._timeString(self.winamp.getDuration());
var message = 'Seek to: ' + newElapsed + '/' + duration + ' (' + newPercentComplete + '%)';
self.textDisplay.setRegisterText('position', message);
};
this.nodes.position.onchange = function() {
if (self.winamp.getState() !== 'stop'){
self.winamp.seekToPercentComplete(this.value);
}
};
this.nodes.previous.onclick = function() {
self.winamp.previous();
};
this.nodes.next.onclick = function() {
self.winamp.next();
};
this.nodes.pause.onclick = function() {
self.winamp.pause();
};
this.nodes.stop.onclick = function() {
self.winamp.stop();
};
this.nodes.eject.onclick = function() {
self.winamp.openFileDialog();
};
this.nodes.repeat.onclick = function() {
self.winamp.toggleRepeat();
};
this.nodes.shuffle.onclick = function() {
self.winamp.toggleShuffle();
};
this.nodes.shadeTime.onclick = function() {
self.winamp.toggleTimeMode();
};
this.nodes.volume.onmousedown = function() {
self.textDisplay.showRegister('volume');
};
this.nodes.volume.onmouseup = function() {
self.textDisplay.showRegister('songTitle');
};
this.nodes.volume.oninput = function() {
self.winamp.setVolume(this.value);
};
this.nodes.time.onclick = function() {
self.winamp.toggleTimeMode();
};
this.nodes.balance.onmousedown = function() {
self.textDisplay.showRegister('balance');
};
this.nodes.balance.onmouseup = function() {
self.textDisplay.showRegister('songTitle');
};
this.nodes.balance.oninput = function() {
if (Math.abs(this.value) < 25) {
this.value = 0;
}
self.winamp.setBalance(this.value);
};
this.nodes.visualizer.onclick = function() {
self.winamp.toggleVisualizer();
};
window.addEventListener('timeUpdated', function() {
self.updateTime();
});
window.addEventListener('startWaiting', function() {
self.setWorkingIndicator();
});
window.addEventListener('stopWaiting', function() {
self.unsetWorkingIndicator();
});
window.addEventListener('startLoading', function() {
self.setLoadingState();
});
window.addEventListener('stopLoading', function() {
self.unsetLoadingState();
});
window.addEventListener('toggleTimeMode', function() {
self.toggleTimeMode();
});
window.addEventListener('changeState', function() {
self.changeState();
});
window.addEventListener('titleUpdated', function() {
self.updateTitle();
});
window.addEventListener('channelCountUpdated', function() {
self.updateChannelCount();
});
window.addEventListener('volumeChanged', function() {
self.updateVolume();
});
window.addEventListener('balanceChanged', function() {
self.setBalance();
});
window.addEventListener('doubledModeToggled', function() {
self.toggleDoubledMode();
});
window.addEventListener('repeatToggled', function() {
self.toggleRepeat();
});
window.addEventListener('llamaToggled', function() {
self.toggleLlama();
});
window.addEventListener('close', function() {
self.close();
});
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));
},
toggleDoubledMode: function() {
this.nodes.buttonD.classList.toggle('selected');
this.nodes.window.classList.toggle('doubled');
},
close: function() {
this.nodes.window.classList.add('closed');
},
updatePosition: function() {
if (!this.nodes.window.classList.contains('setting-position')) {
this.nodes.position.value = this.winamp.getPercentComplete();
}
},
// In shade mode, the position slider shows up differently depending on if
// it's near the start, middle or end of its progress
updateShadePositionClass: function() {
var position = this.nodes.position;
position.removeAttribute('class');
if (position.value <= 33) {
position.classList.add('left');
} else if (position.value >= 66) {
position.classList.add('right');
}
},
updateTime: function() {
this.updateShadePositionClass();
this.updatePosition();
var shadeMinusCharacter = ' ';
var digits = null;
if (this.nodes.time.classList.contains('countdown')) {
digits = this.winamp._timeObject(this.winamp.getTimeRemaining());
shadeMinusCharacter = '-';
this.nodes.buttonD.onmousedown = function() {
if (self.nodes.window.classList.contains('doubled')) {
self.textDisplay.setRegisterText('message', 'Disable doublesize mode');
} else {
digits = this.winamp._timeObject(this.winamp.getTimeElapsed());
self.textDisplay.setRegisterText('message', 'Enable doublesize mode');
}
this.winamp.skin.font.displayCharacterInNode(shadeMinusCharacter, this.nodes.shadeMinusSign);
self.textDisplay.showRegister('message');
};
var digitNodes = [
document.getElementById('minute-first-digit'),
document.getElementById('minute-second-digit'),
document.getElementById('second-first-digit'),
document.getElementById('second-second-digit')
];
var shadeDigitNodes = [
document.getElementById('shade-minute-first-digit'),
document.getElementById('shade-minute-second-digit'),
document.getElementById('shade-second-first-digit'),
document.getElementById('shade-second-second-digit')
];
this.nodes.buttonD.onmouseup = function() {
self.textDisplay.showRegister('songTitle');
};
// For each digit/node
for (var i = 0; i < 4; i++) {
var digit = digits[i];
var digitNode = digitNodes[i];
var shadeNode = shadeDigitNodes[i];
digitNode.innerHTML = '';
digitNode.appendChild(this.winamp.skin.font.digitNode(digit));
this.winamp.skin.font.displayCharacterInNode(digit, shadeNode);
this.nodes.buttonD.onclick = function() {
self.winamp.toggleDoubledMode();
};
this.nodes.play.onclick = function() {
self.winamp.play();
};
this.nodes.songTitle.onmousedown = function() {
self.textDisplay.pauseRegisterMarquee('songTitle');
};
this.nodes.songTitle.onmouseup = function() {
setTimeout(function() {
self.textDisplay.startRegisterMarquee('songTitle');
}, 1000);
};
this.nodes.position.onmousedown = function() {
if (!self.nodes.window.classList.contains('stop')){
self.textDisplay.showRegister('position');
self.nodes.window.classList.add('setting-position');
}
},
};
setWorkingIndicator: function() {
this.nodes.workIndicator.classList.add('selected');
},
this.nodes.position.onmouseup = function() {
self.textDisplay.showRegister('songTitle');
self.nodes.window.classList.remove('setting-position');
};
unsetWorkingIndicator: function() {
this.nodes.workIndicator.classList.remove('selected');
},
this.nodes.position.oninput = function() {
var newPercentComplete = self.nodes.position.value;
var newFractionComplete = newPercentComplete / 100;
var newElapsed = self._timeString(self.winamp.getDuration() * newFractionComplete);
var duration = self._timeString(self.winamp.getDuration());
var message = 'Seek to: ' + newElapsed + '/' + duration + ' (' + newPercentComplete + '%)';
self.textDisplay.setRegisterText('position', message);
};
setLoadingState: function() {
this.nodes.window.classList.add('loading');
},
unsetLoadingState: function() {
this.nodes.window.classList.remove('loading');
},
toggleTimeMode: function() {
this.nodes.time.classList.toggle('countdown');
this.updateTime();
},
updateVolume: function() {
var volume = this.winamp.getVolume();
var percent = volume / 100;
var sprite = Math.round(percent * 28);
var offset = (sprite - 1) * 15;
this.nodes.volume.style.backgroundPosition = '0 -' + offset + 'px';
var message = 'Volume: ' + volume + '%';
this.textDisplay.setRegisterText('volume', message);
// This shouldn't trigger an infinite loop with volume.onchange(),
// since the value will be the same
this.nodes.volume.value = volume;
},
setBalance: function() {
var balance = this.winamp.getBalance();
var string = '';
if (balance === 0) {
string = 'Balance: Center';
} else if (balance > 0) {
string = 'Balance: ' + balance + '% Right';
} else {
string = 'Balance: ' + Math.abs(balance) + '% Left';
this.nodes.position.onchange = function() {
if (self.winamp.getState() !== 'stop'){
self.winamp.seekToPercentComplete(this.value);
}
this.textDisplay.setRegisterText('balance', string);
balance = Math.abs(balance) / 100;
var sprite = Math.round(balance * 28);
var offset = (sprite - 1) * 15;
this.nodes.balance.style.backgroundPosition = '0px -' + offset + 'px';
},
};
changeState: function() {
var state = this.winamp.getState();
var stateOptions = ['play', 'stop', 'pause'];
for (var i = 0; i < stateOptions.length; i++) {
this.nodes.window.classList.remove(stateOptions[i]);
this.nodes.previous.onclick = function() {
self.winamp.previous();
};
this.nodes.next.onclick = function() {
self.winamp.next();
};
this.nodes.pause.onclick = function() {
self.winamp.pause();
};
this.nodes.stop.onclick = function() {
self.winamp.stop();
};
this.nodes.eject.onclick = function() {
self.winamp.openFileDialog();
};
this.nodes.repeat.onclick = function() {
self.winamp.toggleRepeat();
};
this.nodes.shuffle.onclick = function() {
self.winamp.toggleShuffle();
};
this.nodes.shadeTime.onclick = function() {
self.winamp.toggleTimeMode();
};
this.nodes.volume.onmousedown = function() {
self.textDisplay.showRegister('volume');
};
this.nodes.volume.onmouseup = function() {
self.textDisplay.showRegister('songTitle');
};
this.nodes.volume.oninput = function() {
self.winamp.setVolume(this.value);
};
this.nodes.time.onclick = function() {
self.winamp.toggleTimeMode();
};
this.nodes.balance.onmousedown = function() {
self.textDisplay.showRegister('balance');
};
this.nodes.balance.onmouseup = function() {
self.textDisplay.showRegister('songTitle');
};
this.nodes.balance.oninput = function() {
if (Math.abs(this.value) < 25) {
this.value = 0;
}
this.nodes.window.classList.add(state);
},
self.winamp.setBalance(this.value);
};
toggleLlama: function() {
this.nodes.window.classList.toggle('llama');
},
this.nodes.visualizer.onclick = function() {
self.winamp.toggleVisualizer();
};
updateTitle: function() {
var duration = this._timeString(this.winamp.getDuration());
var name = this.winamp.fileName + ' (' + duration + ') *** ';
this.textDisplay.setRegisterText('songTitle', name);
},
window.addEventListener('timeUpdated', function() {
self.updateTime();
});
window.addEventListener('startWaiting', function() {
self.setWorkingIndicator();
});
window.addEventListener('stopWaiting', function() {
self.unsetWorkingIndicator();
});
window.addEventListener('startLoading', function() {
self.setLoadingState();
});
window.addEventListener('stopLoading', function() {
self.unsetLoadingState();
});
window.addEventListener('toggleTimeMode', function() {
self.toggleTimeMode();
});
window.addEventListener('changeState', function() {
self.changeState();
});
window.addEventListener('titleUpdated', function() {
self.updateTitle();
});
window.addEventListener('channelCountUpdated', function() {
self.updateChannelCount();
});
window.addEventListener('volumeChanged', function() {
self.updateVolume();
});
window.addEventListener('balanceChanged', function() {
self.setBalance();
});
window.addEventListener('doubledModeToggled', function() {
self.toggleDoubledMode();
});
window.addEventListener('repeatToggled', function() {
self.toggleRepeat();
});
window.addEventListener('llamaToggled', function() {
self.toggleLlama();
});
window.addEventListener('close', function() {
self.close();
});
updateChannelCount: function() {
var channels = this.winamp.getChannelCount();
this.nodes.mono.classList.remove('selected');
this.nodes.stereo.classList.remove('selected');
if (channels === 1) {
this.nodes.mono.classList.add('selected');
} else if (channels === 2) {
this.nodes.stereo.classList.add('selected');
}
},
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));
},
toggleRepeat: function() {
this.nodes.repeat.classList.toggle('selected');
},
toggleDoubledMode: function() {
this.nodes.buttonD.classList.toggle('selected');
this.nodes.window.classList.toggle('doubled');
},
toggleShuffle: function() {
this.nodes.shuffle.classList.toggle('selected');
},
close: function() {
this.nodes.window.classList.add('closed');
},
dragenter: function(e) {
e.stopPropagation();
e.preventDefault();
},
dragover: function(e) {
e.stopPropagation();
e.preventDefault();
},
drop: function(e) {
e.stopPropagation();
e.preventDefault();
var dt = e.dataTransfer;
var file = dt.files[0];
this.winamp.loadFromFileReference(file);
},
_timeString: function(time) {
var timeObject = this.winamp._timeObject(time);
return timeObject[0] + timeObject[1] + ':' + timeObject[2] + timeObject[3];
updatePosition: function() {
if (!this.nodes.window.classList.contains('setting-position')) {
this.nodes.position.value = this.winamp.getPercentComplete();
}
};
});
},
// In shade mode, the position slider shows up differently depending on if
// it's near the start, middle or end of its progress
updateShadePositionClass: function() {
var position = this.nodes.position;
position.removeAttribute('class');
if (position.value <= 33) {
position.classList.add('left');
} else if (position.value >= 66) {
position.classList.add('right');
}
},
updateTime: function() {
this.updateShadePositionClass();
this.updatePosition();
var shadeMinusCharacter = ' ';
var digits = null;
if (this.nodes.time.classList.contains('countdown')) {
digits = this.winamp._timeObject(this.winamp.getTimeRemaining());
shadeMinusCharacter = '-';
} else {
digits = this.winamp._timeObject(this.winamp.getTimeElapsed());
}
this.winamp.skin.font.displayCharacterInNode(shadeMinusCharacter, this.nodes.shadeMinusSign);
var digitNodes = [
document.getElementById('minute-first-digit'),
document.getElementById('minute-second-digit'),
document.getElementById('second-first-digit'),
document.getElementById('second-second-digit')
];
var shadeDigitNodes = [
document.getElementById('shade-minute-first-digit'),
document.getElementById('shade-minute-second-digit'),
document.getElementById('shade-second-first-digit'),
document.getElementById('shade-second-second-digit')
];
// For each digit/node
for (var i = 0; i < 4; i++) {
var digit = digits[i];
var digitNode = digitNodes[i];
var shadeNode = shadeDigitNodes[i];
digitNode.innerHTML = '';
digitNode.appendChild(this.winamp.skin.font.digitNode(digit));
this.winamp.skin.font.displayCharacterInNode(digit, shadeNode);
}
},
setWorkingIndicator: function() {
this.nodes.workIndicator.classList.add('selected');
},
unsetWorkingIndicator: function() {
this.nodes.workIndicator.classList.remove('selected');
},
setLoadingState: function() {
this.nodes.window.classList.add('loading');
},
unsetLoadingState: function() {
this.nodes.window.classList.remove('loading');
},
toggleTimeMode: function() {
this.nodes.time.classList.toggle('countdown');
this.updateTime();
},
updateVolume: function() {
var volume = this.winamp.getVolume();
var percent = volume / 100;
var sprite = Math.round(percent * 28);
var offset = (sprite - 1) * 15;
this.nodes.volume.style.backgroundPosition = '0 -' + offset + 'px';
var message = 'Volume: ' + volume + '%';
this.textDisplay.setRegisterText('volume', message);
// This shouldn't trigger an infinite loop with volume.onchange(),
// since the value will be the same
this.nodes.volume.value = volume;
},
setBalance: function() {
var balance = this.winamp.getBalance();
var string = '';
if (balance === 0) {
string = 'Balance: Center';
} else if (balance > 0) {
string = 'Balance: ' + balance + '% Right';
} else {
string = 'Balance: ' + Math.abs(balance) + '% Left';
}
this.textDisplay.setRegisterText('balance', string);
balance = Math.abs(balance) / 100;
var sprite = Math.round(balance * 28);
var offset = (sprite - 1) * 15;
this.nodes.balance.style.backgroundPosition = '0px -' + offset + 'px';
},
changeState: function() {
var state = this.winamp.getState();
var stateOptions = ['play', 'stop', 'pause'];
for (var i = 0; i < stateOptions.length; i++) {
this.nodes.window.classList.remove(stateOptions[i]);
}
this.nodes.window.classList.add(state);
},
toggleLlama: function() {
this.nodes.window.classList.toggle('llama');
},
updateTitle: function() {
var duration = this._timeString(this.winamp.getDuration());
var name = this.winamp.fileName + ' (' + duration + ') *** ';
this.textDisplay.setRegisterText('songTitle', name);
},
updateChannelCount: function() {
var channels = this.winamp.getChannelCount();
this.nodes.mono.classList.remove('selected');
this.nodes.stereo.classList.remove('selected');
if (channels === 1) {
this.nodes.mono.classList.add('selected');
} else if (channels === 2) {
this.nodes.stereo.classList.add('selected');
}
},
toggleRepeat: function() {
this.nodes.repeat.classList.toggle('selected');
},
toggleShuffle: function() {
this.nodes.shuffle.classList.toggle('selected');
},
dragenter: function(e) {
e.stopPropagation();
e.preventDefault();
},
dragover: function(e) {
e.stopPropagation();
e.preventDefault();
},
drop: function(e) {
e.stopPropagation();
e.preventDefault();
var dt = e.dataTransfer;
var file = dt.files[0];
this.winamp.loadFromFileReference(file);
},
_timeString: function(time) {
var timeObject = this.winamp._timeObject(time);
return timeObject[0] + timeObject[1] + ':' + timeObject[2] + timeObject[3];
}
};

View file

@ -1,5 +1,5 @@
/* Emulate the native <audio> element with Web Audio API */
define({
module.exports = {
_context: new (window.AudioContext || window.webkitAudioContext)(),
_source: null,
_buffer: null,
@ -253,4 +253,4 @@ define({
}
}
}
});
};

View file

@ -1,63 +1,62 @@
// Single line text display that can animate and hold multiple registers
define(['font'], function(Font) {
var MultiDisplay = function(node) {
this.font = new Font();
this.node = node;
this.registers = {};
this._marqueeLoop();
import Font from './font';
var MultiDisplay = function(node) {
this.font = new Font();
this.node = node;
this.registers = {};
this._marqueeLoop();
};
MultiDisplay.prototype.addRegister = function(key) {
// Create element node
var register = document.createElement('div');
register.style.display = 'none';
this.node.appendChild(register);
this.registers[key] = {
node: register,
text: '',
marquee: false
};
};
MultiDisplay.prototype.addRegister = function(key) {
// Create element node
var register = document.createElement('div');
register.style.display = 'none';
// Set text of register
MultiDisplay.prototype.setRegisterText = function(register, text) {
this.font.setNodeToString(this.registers[register].node, text);
};
this.node.appendChild(register);
this.registers[key] = {
node: register,
text: '',
marquee: false
};
};
MultiDisplay.prototype.showRegister = function(showKey) {
for (var key in this.registers) {
var display = (key === showKey) ? 'block' : 'none';
this.registers[key].node.style.display = display;
}
};
// Set text of register
MultiDisplay.prototype.setRegisterText = function(register, text) {
this.font.setNodeToString(this.registers[register].node, text);
};
MultiDisplay.prototype.startRegisterMarquee = function(key) {
this.registers[key].marquee = true;
};
MultiDisplay.prototype.showRegister = function(showKey) {
for (var key in this.registers) {
var display = (key === showKey) ? 'block' : 'none';
this.registers[key].node.style.display = display;
}
};
MultiDisplay.prototype.pauseRegisterMarquee = function(key) {
this.registers[key].marquee = false;
};
MultiDisplay.prototype.startRegisterMarquee = function(key) {
this.registers[key].marquee = true;
};
MultiDisplay.prototype.pauseRegisterMarquee = function(key) {
this.registers[key].marquee = false;
};
MultiDisplay.prototype._marqueeLoop = function() {
var self = this;
setTimeout(function() {
for (var key in self.registers) {
// Check every register to see if it needs to be marqueed
if (self.registers[key].marquee) {
var text = self.registers[key].node.firstChild;
// Only scroll if the text is too long
if (text && text.childNodes.length > 30) {
var characterNode = text.firstChild;
text.removeChild(characterNode);
text.appendChild(characterNode);
}
MultiDisplay.prototype._marqueeLoop = function() {
var self = this;
setTimeout(function() {
for (var key in self.registers) {
// Check every register to see if it needs to be marqueed
if (self.registers[key].marquee) {
var text = self.registers[key].node.firstChild;
// Only scroll if the text is too long
if (text && text.childNodes.length > 30) {
var characterNode = text.firstChild;
text.removeChild(characterNode);
text.appendChild(characterNode);
}
}
self._marqueeLoop();
}, 220);
};
}
self._marqueeLoop();
}, 220);
};
return MultiDisplay;
});
module.exports = MultiDisplay;

View file

@ -1,45 +1,43 @@
// Custom object representing a file
// `File` is already a builtin, so we use `MyFile`
define([], function(){
return function() {
this.reader = new FileReader();
this.url = null;
this.fileReference = null;
this.setUrl = function(url){
this.url = url;
};
this.setFileReference = function(fileReference){
this.fileReference = fileReference;
};
this.processBuffer = function(bufferHandler) {
if (this.url) {
var oReq = new XMLHttpRequest();
oReq.open('GET', this.url, true);
oReq.responseType = 'arraybuffer';
oReq.onload = function() {
var arrayBuffer = oReq.response; // Note: not oReq.responseText
bufferHandler(arrayBuffer);
};
oReq.send(null);
return true;
} else if (this.fileReference) {
this.reader.onload = function(e) {
var arrayBuffer = e.target.result;
bufferHandler(arrayBuffer);
};
this.reader.onerror = function(e) {
console.error(e);
};
this.reader.readAsArrayBuffer(this.fileReference);
return true;
}
console.error('Tried to process an unpopulated file object');
return false;
};
module.exports = function() {
this.reader = new FileReader();
this.url = null;
this.fileReference = null;
this.setUrl = function(url){
this.url = url;
};
});
this.setFileReference = function(fileReference){
this.fileReference = fileReference;
};
this.processBuffer = function(bufferHandler) {
if (this.url) {
var oReq = new XMLHttpRequest();
oReq.open('GET', this.url, true);
oReq.responseType = 'arraybuffer';
oReq.onload = function() {
var arrayBuffer = oReq.response; // Note: not oReq.responseText
bufferHandler(arrayBuffer);
};
oReq.send(null);
return true;
} else if (this.fileReference) {
this.reader.onload = function(e) {
var arrayBuffer = e.target.result;
bufferHandler(arrayBuffer);
};
this.reader.onerror = function(e) {
console.error(e);
};
this.reader.readAsArrayBuffer(this.fileReference);
return true;
}
console.error('Tried to process an unpopulated file object');
return false;
};
};

View file

@ -1,171 +1,169 @@
define([], function() {
return [
{
img: 'BALANCE',
sprites: [
{selectors: ['#balance'], x: 9, y: 0, width: 38, height: 420},
{selectors: ['#balance::-webkit-slider-thumb', '#balance::-moz-range-thumb'], x: 15, y: 422, width: 14, height: 11},
{selectors: ['#balance::-webkit-slider-thumb:active', '#balance::-moz-range-thumb:active'], x: 0, y: 422, width: 14, height: 11}
]
},
{
img: 'CBUTTONS',
sprites: [
{selectors: ['.actions #previous'], x: 0, y: 0, width: 23, height: 18},
{selectors: ['.actions #previous:active'], x: 0, y: 18, width: 23, height: 18},
{selectors: ['.actions #play'], x: 23, y: 0, width: 23, height: 18},
{selectors: ['.actions #play:active'], x: 23, y: 18, width: 23, height: 18},
{selectors: ['.actions #pause'], x: 46, y: 0, width: 23, height: 18},
{selectors: ['.actions #pause:active'], x: 46, y: 18, width: 23, height: 18},
{selectors: ['.actions #stop'], x: 69, y: 0, width: 23, height: 18},
{selectors: ['.actions #stop:active'], x: 69, y: 18, width: 23, height: 18},
{selectors: ['.actions #next'], x: 92, y: 0, width: 23, height: 18},
{selectors: ['.actions #next:active'], x: 92, y: 18, width: 22, height: 18},
{selectors: ['#eject'], x: 114, y: 0, width: 22, height: 16},
{selectors: ['#eject:active'], x: 114, y: 16, width: 22, height: 16}
]
},
{
img: 'MAIN',
sprites: [
{selectors: ['#main-window'], x: 0, y: 0, width: 275, height: 116}
]
},
{
img: 'MONOSTER',
sprites: [
{selectors: ['.media-info #stereo', '.stop .media-info #stereo.selected'], x: 0, y: 12, width: 29, height: 12},
{selectors: ['.media-info #stereo.selected'], x: 0, y: 0, width: 29, height: 12},
{selectors: ['.media-info #mono', '.stop .media-info #mono.selected'], x: 29, y: 12, width: 29, height: 12},
{selectors: ['.media-info #mono.selected'], x: 29, y: 0, width: 29, height: 12}
]
},
{
img: 'NUMBERS',
sprites: [
{selectors: ['#time #minus-sign'], x: 9, y: 6, width: 5, height: 1},
{selectors: ['#time.countdown #minus-sign'], x: 20, y: 6, width: 5, height: 1},
{selectors: ['.digit-0'], x: 0, y: 0, width: 9, height: 13},
{selectors: ['.digit-1'], x: 9, y: 0, width: 9, height: 13},
{selectors: ['.digit-2'], x: 18, y: 0, width: 9, height: 13},
{selectors: ['.digit-3'], x: 27, y: 0, width: 9, height: 13},
{selectors: ['.digit-4'], x: 36, y: 0, width: 9, height: 13},
{selectors: ['.digit-5'], x: 45, y: 0, width: 9, height: 13},
{selectors: ['.digit-6'], x: 54, y: 0, width: 9, height: 13},
{selectors: ['.digit-7'], x: 63, y: 0, width: 9, height: 13},
{selectors: ['.digit-8'], x: 72, y: 0, width: 9, height: 13},
{selectors: ['.digit-9'], x: 81, y: 0, width: 9, height: 13}
]
},
{
img: 'NUMS_EX',
sprites: [
{selectors: ['#time.ex #minus-sign'], x: 90, y: 0, width: 9, height: 13},
{selectors: ['#time.ex.countdown #minus-sign'], x: 99, y: 0, width: 9, height: 13},
{selectors: ['.digit-0'], x: 0, y: 0, width: 9, height: 13},
{selectors: ['.digit-1'], x: 9, y: 0, width: 9, height: 13},
{selectors: ['.digit-2'], x: 18, y: 0, width: 9, height: 13},
{selectors: ['.digit-3'], x: 27, y: 0, width: 9, height: 13},
{selectors: ['.digit-4'], x: 36, y: 0, width: 9, height: 13},
{selectors: ['.digit-5'], x: 45, y: 0, width: 9, height: 13},
{selectors: ['.digit-6'], x: 54, y: 0, width: 9, height: 13},
{selectors: ['.digit-7'], x: 63, y: 0, width: 9, height: 13},
{selectors: ['.digit-8'], x: 72, y: 0, width: 9, height: 13},
{selectors: ['.digit-9'], x: 81, y: 0, width: 9, height: 13}
]
},
{
img: 'PLAYPAUS',
sprites: [
{selectors: ['.play #play-pause'], x: 0, y: 0, width: 9, height: 9},
{selectors: ['.pause #play-pause'], x: 9, y: 0, width: 9, height: 9},
{selectors: ['.stop #play-pause'], x: 18, y: 0, width: 9, height: 9},
{selectors: ['.play #work-indicator'], x: 36, y: 0, width: 9, height: 9},
{selectors: ['.play #work-indicator.selected'], x: 39, y: 0, width: 9, height: 9}
]
},
/* {
img: 'PLEDIT',
sprites: [
{selectors: ['.playlist-top-tile'], x: 127, y: 21, width: 25, height: 20},
{selectors: ['.selected .playlist-top-tile'], x: 127, y: 0, width: 25, height: 20},
{selectors: ['.playlist-left-tile'], x: 0, y: 42, width: 25, height: 29},
{selectors: ['.playlist-right-tile'], x: 27, y: 42, width: 25, height: 29},
{selectors: ['.playlist-bottom-tile'], x: 179, y: 0, width: 25, height: 38},
{selectors: ['#playlist.shade'], x: 72, y: 57, width: 25, height: 14}
]
}, */
{
img: 'POSBAR',
sprites: [
{selectors: ['#position'], x: 0, y: 0, width: 248, height: 10},
{selectors: ['#position::-webkit-slider-thumb', '#position::-moz-range-thumb'], x: 248, y: 0, width: 29, height: 10},
{selectors: ['#position:active::-webkit-slider-thumb', '#position:active::-moz-range-thumb'], x: 278, y: 0, width: 29, height: 10}
]
},
{
img: 'SHUFREP',
sprites: [
{selectors: ['#shuffle'], x: 28, y: 0, width: 47, height: 15},
{selectors: ['#shuffle:active'], x: 28, y: 15, width: 47, height: 15},
{selectors: ['#shuffle.selected'], x: 28, y: 30, width: 47, height: 15},
{selectors: ['#shuffle.selected:active'], x: 28, y: 45, width: 47, height: 15},
{selectors: ['#repeat'], x: 0, y: 0, width: 28, height: 15},
{selectors: ['#repeat:active'], x: 0, y: 15, width: 28, height: 15},
{selectors: ['#repeat.selected'], x: 0, y: 30, width: 28, height: 15},
{selectors: ['#repeat.selected:active'], x: 0, y: 45, width: 28, height: 15},
{selectors: ['#equalizer-button'], x: 0, y: 61, width: 23, height: 12},
{selectors: ['#equalizer-button:active'], x: 46, y: 61, width: 23, height: 12},
{selectors: ['#playlist-button'], x: 23, y: 61, width: 23, height: 12},
{selectors: ['#playlist-button:active'], x: 69, y: 61, width: 23, height: 12}
]
},
{
img: 'TEXT',
sprites: [
{selectors: ['.character'], x: 0, y: 0, width: 155, height: 74}
]
},
{
img: 'TITLEBAR',
sprites: [
{selectors: ['#title-bar'], x: 27, y: 15, width: 275, height: 14},
{selectors: ['#title-bar.selected'], x: 27, y: 0, width: 275, height: 14},
{selectors: ['.llama #title-bar'], x: 27, y: 61, width: 275, height: 14},
{selectors: ['.llama #title-bar.selected'], x: 27, y: 57, width: 275, height: 14},
{selectors: ['#title-bar #option'], x: 0, y: 0, width: 9, height: 9},
{selectors: ['#title-bar #option'], x: 0, y: 0, width: 9, height: 9},
{selectors: ['#title-bar #option:active', '#title-bar #option:selected'], x: 0, y: 9, width: 9, height: 9},
{selectors: ['#title-bar #minimize'], x: 9, y: 0, width: 9, height: 9},
{selectors: ['#title-bar #minimize:active'], x: 9, y: 9, width: 9, height: 9},
{selectors: ['#title-bar #shade'], x: 0, y: 18, width: 9, height: 9},
{selectors: ['#title-bar #shade:active'], x: 9, y: 18, width: 9, height: 9},
{selectors: ['#title-bar #close'], x: 18, y: 0, width: 9, height: 9},
{selectors: ['#title-bar #close:active'], x: 18, y: 9, width: 9, height: 9},
{selectors: ['#clutter-bar'], x: 304, y: 0, width: 8, height: 43},
{selectors: ['#clutter-bar.disabled'], x: 312, y: 0, width: 8, height: 43},
{selectors: ['#button-o:active', '#button-0:selected'], x: 304, y: 47, width: 8, height: 8},
{selectors: ['#button-a:active', '#button-a.selected'], x: 312, y: 55, width: 8, height: 7},
{selectors: ['#button-i:active', '#button-i.selected'], x: 320, y: 62, width: 8, height: 7},
{selectors: ['#button-d:active', '#button-d.selected'], x: 328, y: 69, width: 8, height: 8},
{selectors: ['#button-v:active', '#button-v.selected'], x: 336, y: 77, width: 8, height: 7},
{selectors: ['.shade #title-bar'], x: 27, y: 42, width: 275, height: 14},
{selectors: ['.shade #title-bar.selected'], x: 27, y: 29, width: 275, height: 14},
{selectors: ['.shade #title-bar #shade'], x: 0, y: 27, width: 9, height: 9},
{selectors: ['.shade #title-bar #shade:active'], x: 9, y: 27, width: 9, height: 9},
{selectors: ['.shade #position'], x: 0, y: 36, width: 17, height: 7},
{selectors: ['.shade #position::-moz-range-thumb', '.shade #position::-webkit-slider-thumb'], x: 20, y: 36, width: 3, height: 7},
{selectors: ['.shade #position.left::-moz-range-thumb', '.shade #position.left::-webkit-slider-thumb'], x: 17, y: 36, width: 3, height: 7},
{selectors: ['.shade #position.right::-moz-range-thumb', '.shade #position.right::-webkit-slider-thumb'], x: 23, y: 36, width: 3, height: 7}
]
},
{
img: 'VOLUME',
sprites: [
{selectors: ['#volume'], x: 0, y: 0, width: 68, height: 420},
{selectors: ['#volume::-webkit-slider-thumb', '#volume::-moz-range-thumb'], x: 15, y: 422, width: 14, height: 11},
{selectors: ['#volume::-webkit-slider-thumb:active', '#volume::-moz-range-thumb:active'], x: 0, y: 422, width: 14, height: 11}
]
}
];
});
module.exports = [
{
img: 'BALANCE',
sprites: [
{selectors: ['#balance'], x: 9, y: 0, width: 38, height: 420},
{selectors: ['#balance::-webkit-slider-thumb', '#balance::-moz-range-thumb'], x: 15, y: 422, width: 14, height: 11},
{selectors: ['#balance::-webkit-slider-thumb:active', '#balance::-moz-range-thumb:active'], x: 0, y: 422, width: 14, height: 11}
]
},
{
img: 'CBUTTONS',
sprites: [
{selectors: ['.actions #previous'], x: 0, y: 0, width: 23, height: 18},
{selectors: ['.actions #previous:active'], x: 0, y: 18, width: 23, height: 18},
{selectors: ['.actions #play'], x: 23, y: 0, width: 23, height: 18},
{selectors: ['.actions #play:active'], x: 23, y: 18, width: 23, height: 18},
{selectors: ['.actions #pause'], x: 46, y: 0, width: 23, height: 18},
{selectors: ['.actions #pause:active'], x: 46, y: 18, width: 23, height: 18},
{selectors: ['.actions #stop'], x: 69, y: 0, width: 23, height: 18},
{selectors: ['.actions #stop:active'], x: 69, y: 18, width: 23, height: 18},
{selectors: ['.actions #next'], x: 92, y: 0, width: 23, height: 18},
{selectors: ['.actions #next:active'], x: 92, y: 18, width: 22, height: 18},
{selectors: ['#eject'], x: 114, y: 0, width: 22, height: 16},
{selectors: ['#eject:active'], x: 114, y: 16, width: 22, height: 16}
]
},
{
img: 'MAIN',
sprites: [
{selectors: ['#main-window'], x: 0, y: 0, width: 275, height: 116}
]
},
{
img: 'MONOSTER',
sprites: [
{selectors: ['.media-info #stereo', '.stop .media-info #stereo.selected'], x: 0, y: 12, width: 29, height: 12},
{selectors: ['.media-info #stereo.selected'], x: 0, y: 0, width: 29, height: 12},
{selectors: ['.media-info #mono', '.stop .media-info #mono.selected'], x: 29, y: 12, width: 29, height: 12},
{selectors: ['.media-info #mono.selected'], x: 29, y: 0, width: 29, height: 12}
]
},
{
img: 'NUMBERS',
sprites: [
{selectors: ['#time #minus-sign'], x: 9, y: 6, width: 5, height: 1},
{selectors: ['#time.countdown #minus-sign'], x: 20, y: 6, width: 5, height: 1},
{selectors: ['.digit-0'], x: 0, y: 0, width: 9, height: 13},
{selectors: ['.digit-1'], x: 9, y: 0, width: 9, height: 13},
{selectors: ['.digit-2'], x: 18, y: 0, width: 9, height: 13},
{selectors: ['.digit-3'], x: 27, y: 0, width: 9, height: 13},
{selectors: ['.digit-4'], x: 36, y: 0, width: 9, height: 13},
{selectors: ['.digit-5'], x: 45, y: 0, width: 9, height: 13},
{selectors: ['.digit-6'], x: 54, y: 0, width: 9, height: 13},
{selectors: ['.digit-7'], x: 63, y: 0, width: 9, height: 13},
{selectors: ['.digit-8'], x: 72, y: 0, width: 9, height: 13},
{selectors: ['.digit-9'], x: 81, y: 0, width: 9, height: 13}
]
},
{
img: 'NUMS_EX',
sprites: [
{selectors: ['#time.ex #minus-sign'], x: 90, y: 0, width: 9, height: 13},
{selectors: ['#time.ex.countdown #minus-sign'], x: 99, y: 0, width: 9, height: 13},
{selectors: ['.digit-0'], x: 0, y: 0, width: 9, height: 13},
{selectors: ['.digit-1'], x: 9, y: 0, width: 9, height: 13},
{selectors: ['.digit-2'], x: 18, y: 0, width: 9, height: 13},
{selectors: ['.digit-3'], x: 27, y: 0, width: 9, height: 13},
{selectors: ['.digit-4'], x: 36, y: 0, width: 9, height: 13},
{selectors: ['.digit-5'], x: 45, y: 0, width: 9, height: 13},
{selectors: ['.digit-6'], x: 54, y: 0, width: 9, height: 13},
{selectors: ['.digit-7'], x: 63, y: 0, width: 9, height: 13},
{selectors: ['.digit-8'], x: 72, y: 0, width: 9, height: 13},
{selectors: ['.digit-9'], x: 81, y: 0, width: 9, height: 13}
]
},
{
img: 'PLAYPAUS',
sprites: [
{selectors: ['.play #play-pause'], x: 0, y: 0, width: 9, height: 9},
{selectors: ['.pause #play-pause'], x: 9, y: 0, width: 9, height: 9},
{selectors: ['.stop #play-pause'], x: 18, y: 0, width: 9, height: 9},
{selectors: ['.play #work-indicator'], x: 36, y: 0, width: 9, height: 9},
{selectors: ['.play #work-indicator.selected'], x: 39, y: 0, width: 9, height: 9}
]
},
/* {
img: 'PLEDIT',
sprites: [
{selectors: ['.playlist-top-tile'], x: 127, y: 21, width: 25, height: 20},
{selectors: ['.selected .playlist-top-tile'], x: 127, y: 0, width: 25, height: 20},
{selectors: ['.playlist-left-tile'], x: 0, y: 42, width: 25, height: 29},
{selectors: ['.playlist-right-tile'], x: 27, y: 42, width: 25, height: 29},
{selectors: ['.playlist-bottom-tile'], x: 179, y: 0, width: 25, height: 38},
{selectors: ['#playlist.shade'], x: 72, y: 57, width: 25, height: 14}
]
}, */
{
img: 'POSBAR',
sprites: [
{selectors: ['#position'], x: 0, y: 0, width: 248, height: 10},
{selectors: ['#position::-webkit-slider-thumb', '#position::-moz-range-thumb'], x: 248, y: 0, width: 29, height: 10},
{selectors: ['#position:active::-webkit-slider-thumb', '#position:active::-moz-range-thumb'], x: 278, y: 0, width: 29, height: 10}
]
},
{
img: 'SHUFREP',
sprites: [
{selectors: ['#shuffle'], x: 28, y: 0, width: 47, height: 15},
{selectors: ['#shuffle:active'], x: 28, y: 15, width: 47, height: 15},
{selectors: ['#shuffle.selected'], x: 28, y: 30, width: 47, height: 15},
{selectors: ['#shuffle.selected:active'], x: 28, y: 45, width: 47, height: 15},
{selectors: ['#repeat'], x: 0, y: 0, width: 28, height: 15},
{selectors: ['#repeat:active'], x: 0, y: 15, width: 28, height: 15},
{selectors: ['#repeat.selected'], x: 0, y: 30, width: 28, height: 15},
{selectors: ['#repeat.selected:active'], x: 0, y: 45, width: 28, height: 15},
{selectors: ['#equalizer-button'], x: 0, y: 61, width: 23, height: 12},
{selectors: ['#equalizer-button:active'], x: 46, y: 61, width: 23, height: 12},
{selectors: ['#playlist-button'], x: 23, y: 61, width: 23, height: 12},
{selectors: ['#playlist-button:active'], x: 69, y: 61, width: 23, height: 12}
]
},
{
img: 'TEXT',
sprites: [
{selectors: ['.character'], x: 0, y: 0, width: 155, height: 74}
]
},
{
img: 'TITLEBAR',
sprites: [
{selectors: ['#title-bar'], x: 27, y: 15, width: 275, height: 14},
{selectors: ['#title-bar.selected'], x: 27, y: 0, width: 275, height: 14},
{selectors: ['.llama #title-bar'], x: 27, y: 61, width: 275, height: 14},
{selectors: ['.llama #title-bar.selected'], x: 27, y: 57, width: 275, height: 14},
{selectors: ['#title-bar #option'], x: 0, y: 0, width: 9, height: 9},
{selectors: ['#title-bar #option'], x: 0, y: 0, width: 9, height: 9},
{selectors: ['#title-bar #option:active', '#title-bar #option:selected'], x: 0, y: 9, width: 9, height: 9},
{selectors: ['#title-bar #minimize'], x: 9, y: 0, width: 9, height: 9},
{selectors: ['#title-bar #minimize:active'], x: 9, y: 9, width: 9, height: 9},
{selectors: ['#title-bar #shade'], x: 0, y: 18, width: 9, height: 9},
{selectors: ['#title-bar #shade:active'], x: 9, y: 18, width: 9, height: 9},
{selectors: ['#title-bar #close'], x: 18, y: 0, width: 9, height: 9},
{selectors: ['#title-bar #close:active'], x: 18, y: 9, width: 9, height: 9},
{selectors: ['#clutter-bar'], x: 304, y: 0, width: 8, height: 43},
{selectors: ['#clutter-bar.disabled'], x: 312, y: 0, width: 8, height: 43},
{selectors: ['#button-o:active', '#button-0:selected'], x: 304, y: 47, width: 8, height: 8},
{selectors: ['#button-a:active', '#button-a.selected'], x: 312, y: 55, width: 8, height: 7},
{selectors: ['#button-i:active', '#button-i.selected'], x: 320, y: 62, width: 8, height: 7},
{selectors: ['#button-d:active', '#button-d.selected'], x: 328, y: 69, width: 8, height: 8},
{selectors: ['#button-v:active', '#button-v.selected'], x: 336, y: 77, width: 8, height: 7},
{selectors: ['.shade #title-bar'], x: 27, y: 42, width: 275, height: 14},
{selectors: ['.shade #title-bar.selected'], x: 27, y: 29, width: 275, height: 14},
{selectors: ['.shade #title-bar #shade'], x: 0, y: 27, width: 9, height: 9},
{selectors: ['.shade #title-bar #shade:active'], x: 9, y: 27, width: 9, height: 9},
{selectors: ['.shade #position'], x: 0, y: 36, width: 17, height: 7},
{selectors: ['.shade #position::-moz-range-thumb', '.shade #position::-webkit-slider-thumb'], x: 20, y: 36, width: 3, height: 7},
{selectors: ['.shade #position.left::-moz-range-thumb', '.shade #position.left::-webkit-slider-thumb'], x: 17, y: 36, width: 3, height: 7},
{selectors: ['.shade #position.right::-moz-range-thumb', '.shade #position.right::-webkit-slider-thumb'], x: 23, y: 36, width: 3, height: 7}
]
},
{
img: 'VOLUME',
sprites: [
{selectors: ['#volume'], x: 0, y: 0, width: 68, height: 420},
{selectors: ['#volume::-webkit-slider-thumb', '#volume::-moz-range-thumb'], x: 15, y: 422, width: 14, height: 11},
{selectors: ['#volume::-webkit-slider-thumb:active', '#volume::-moz-range-thumb:active'], x: 0, y: 422, width: 14, height: 11}
]
}
];

View file

@ -1,119 +1,112 @@
// Dynamically set the css background images for all the sprites
define([
'skin-sprites',
'font',
'visualizer',
'../node_modules/jszip/dist/jszip' // Hack
], function(
SKIN_SPRITES,
Font,
Visualizer,
JSZip
) {
return {
font: new Font(),
init: function(visualizerNode, analyser) {
import SKIN_SPRITES from './skin-sprites';
import Font from './font';
import Visualizer from './visualizer';
import JSZip from '../node_modules/jszip/dist/jszip'; // Hack
module.exports = {
font: new Font(),
init: function(visualizerNode, analyser) {
this._createNewStyleNode();
this.visualizer = Visualizer.init(visualizerNode, analyser);
return this;
},
// For sprites that tile, we need to use just the sprite, not the whole image
_skinSprites: SKIN_SPRITES,
// Given a file of an original Winamp WSZ file, set the current skin
setSkinByFile: function(file, completedCallback) {
this.completedCallback = completedCallback;
file.processBuffer(this._setSkinByBuffer.bind(this));
},
// Given a bufferArray containing a Winamp WSZ file, set the current skin
// Gets passed as a callback, so don't have access to `this`
_setSkinByBuffer: function(buffer) {
var zip = new JSZip(buffer);
document.getElementById('time').classList.remove('ex');
var promisedCssRules = this._skinSprites.map(function(spriteObj) {
var file = this._findFileInZip(spriteObj.img, zip);
if (file) {
// CSS has to change if this file is present
if (spriteObj.img === 'NUMS_EX') {
document.getElementById('time').classList.add('ex');
}
var src = 'data:image/bmp;base64,' + btoa(file.asBinary());
return this._spriteCssRule(src, spriteObj);
}
}, this);
// Extract sprite images
Promise.all(promisedCssRules).then(function(newCssRules) {
this._createNewStyleNode();
this.visualizer = Visualizer.init(visualizerNode, analyser);
return this;
},
// For sprites that tile, we need to use just the sprite, not the whole image
_skinSprites: SKIN_SPRITES,
// Given a file of an original Winamp WSZ file, set the current skin
setSkinByFile: function(file, completedCallback) {
this.completedCallback = completedCallback;
file.processBuffer(this._setSkinByBuffer.bind(this));
},
// Given a bufferArray containing a Winamp WSZ file, set the current skin
// Gets passed as a callback, so don't have access to `this`
_setSkinByBuffer: function(buffer) {
var zip = new JSZip(buffer);
document.getElementById('time').classList.remove('ex');
var promisedCssRules = this._skinSprites.map(function(spriteObj) {
var file = this._findFileInZip(spriteObj.img, zip);
if (file) {
// CSS has to change if this file is present
if (spriteObj.img === 'NUMS_EX') {
document.getElementById('time').classList.add('ex');
}
var src = 'data:image/bmp;base64,' + btoa(file.asBinary());
return this._spriteCssRule(src, spriteObj);
}
}, this);
// Extract sprite images
Promise.all(promisedCssRules).then(function(newCssRules) {
this._createNewStyleNode();
var cssRules = newCssRules.join('\n');
this.styleNode.appendChild(document.createTextNode(cssRules));
this._parseVisColors(zip);
if (this.completedCallback !== void 0) {
this.completedCallback();
}
}.bind(this));
},
_parseVisColors: function(zip) {
var entries = this._findFileInZip('VISCOLOR.TXT', zip).asText().split('\n');
var regex = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/;
var colors = [];
// changed to a hard number to deal with empty lines at the end...
// plus its only meant to be an exact amount of numbers anywayz
// - @PAEz
for (var i = 0; i < 24; i++) {
var matches = regex.exec(entries[i]);
if (matches) {
colors[i] = 'rgb(' + matches.slice(1, 4).join(',') + ')';
} else {
console.error('Error in VISCOLOR.TXT on line', i);
}
var cssRules = newCssRules.join('\n');
this.styleNode.appendChild(document.createTextNode(cssRules));
this._parseVisColors(zip);
if (this.completedCallback !== void 0) {
this.completedCallback();
}
this.visualizer.setColors(colors);
},
}.bind(this));
},
_findFileInZip: function(name, zip) {
// Note: "."s in file names are actually treated as wildcards
return zip.file(new RegExp('(/|^)' + name, 'i'))[0];
},
_createNewStyleNode: function() {
if (this.styleNode) {
document.head.removeChild(this.styleNode);
_parseVisColors: function(zip) {
var entries = this._findFileInZip('VISCOLOR.TXT', zip).asText().split('\n');
var regex = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/;
var colors = [];
// changed to a hard number to deal with empty lines at the end...
// plus its only meant to be an exact amount of numbers anywayz
// - @PAEz
for (var i = 0; i < 24; i++) {
var matches = regex.exec(entries[i]);
if (matches) {
colors[i] = 'rgb(' + matches.slice(1, 4).join(',') + ')';
} else {
console.error('Error in VISCOLOR.TXT on line', i);
}
this.styleNode = document.createElement('style');
document.head.appendChild(this.styleNode);
},
// Given an image URL and coordinates, returns a data url for a sub-section
// of that image
_spriteCssRule: function(src, spriteObj) {
return new Promise(function(resolve) {
var imageObj = new Image();
imageObj.src = src;
imageObj.onload = function() {
var skinImage = this;
var cssRules = '';
var canvas = document.createElement('canvas');
spriteObj.sprites.forEach(function(sprite) {
canvas.height = sprite.height;
canvas.width = sprite.width;
var context = canvas.getContext('2d');
context.drawImage(skinImage, -sprite.x, -sprite.y);
var value = 'background-image: url(' + canvas.toDataURL() + ')';
sprite.selectors.forEach(function(selector) {
cssRules += '#winamp2-js ' + selector + '{' + value + '}\n';
});
});
resolve(cssRules);
};
});
}
};
});
this.visualizer.setColors(colors);
},
_findFileInZip: function(name, zip) {
// Note: "."s in file names are actually treated as wildcards
return zip.file(new RegExp('(/|^)' + name, 'i'))[0];
},
_createNewStyleNode: function() {
if (this.styleNode) {
document.head.removeChild(this.styleNode);
}
this.styleNode = document.createElement('style');
document.head.appendChild(this.styleNode);
},
// Given an image URL and coordinates, returns a data url for a sub-section
// of that image
_spriteCssRule: function(src, spriteObj) {
return new Promise(function(resolve) {
var imageObj = new Image();
imageObj.src = src;
imageObj.onload = function() {
var skinImage = this;
var cssRules = '';
var canvas = document.createElement('canvas');
spriteObj.sprites.forEach(function(sprite) {
canvas.height = sprite.height;
canvas.width = sprite.width;
var context = canvas.getContext('2d');
context.drawImage(skinImage, -sprite.x, -sprite.y);
var value = 'background-image: url(' + canvas.toDataURL() + ')';
sprite.selectors.forEach(function(selector) {
cssRules += '#winamp2-js ' + selector + '{' + value + '}\n';
});
});
resolve(cssRules);
};
});
}
};

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,5 @@
/* Use Canvas to recreate the simple Winamp visualizer */
define({
module.exports = {
init: function(canvasNode, analyser) {
this.canvas = canvasNode;
this.analyser = analyser;
@ -160,4 +160,4 @@ define({
printBar(j * 8, height);
}
}
});
};

View file

@ -1,291 +1,283 @@
// UI and App logic
define([
'main-window',
'window-manager',
'skin',
'media',
'my-file'
], function(
MainWindow,
WindowManager,
Skin,
Media,
MyFile
) {
return {
init: function(options) {
this.fileInput = document.createElement('input');
this.fileInput.type = 'file';
this.fileInput.style.display = 'none';
import MainWindow from './main-window';
import WindowManager from './window-manager';
import Skin from './skin';
import Media from './media';
import MyFile from './my-file';
this.windowManager = WindowManager;
this.media = Media.init();
this.skin = Skin.init(document.getElementById('visualizer'), this.media._analyser);
this.state = '';
module.exports = {
init: function(options) {
this.fileInput = document.createElement('input');
this.fileInput.type = 'file';
this.fileInput.style.display = 'none';
this.mainWindow = MainWindow.init(this);
this.windowManager = WindowManager;
this.media = Media.init();
this.skin = Skin.init(document.getElementById('visualizer'), this.media._analyser);
this.state = '';
this.events = {
timeUpdated: new Event('timeUpdated'),
startWaiting: new Event('startWaiting'),
stopWaiting: new Event('stopWaiting'),
startLoading: new Event('startLoading'),
stopLoading: new Event('stopLoading'),
toggleTimeMode: new Event('toggleTimeMode'),
changeState: new Event('changeState'),
titleUpdated: new Event('titleUpdated'),
channelCountUpdated: new Event('channelCountUpdated'),
volumeChanged: new Event('volumeChanged'),
balanceChanged: new Event('balanceChanged'),
doubledModeToggled: new Event('doubledModeToggled'),
repeatToggled: new Event('repeatToggled'),
llamaToggled: new Event('llamaToggled'),
close: new Event('close')
};
this.mainWindow = MainWindow.init(this);
this.setVolume(options.volume);
this.setBalance(options.balance);
this.loadFromUrl(options.mediaFile.url, options.mediaFile.name);
var skinFile = new MyFile();
skinFile.setUrl(options.skinUrl);
this.setSkin(skinFile);
this.events = {
timeUpdated: new Event('timeUpdated'),
startWaiting: new Event('startWaiting'),
stopWaiting: new Event('stopWaiting'),
startLoading: new Event('startLoading'),
stopLoading: new Event('stopLoading'),
toggleTimeMode: new Event('toggleTimeMode'),
changeState: new Event('changeState'),
titleUpdated: new Event('titleUpdated'),
channelCountUpdated: new Event('channelCountUpdated'),
volumeChanged: new Event('volumeChanged'),
balanceChanged: new Event('balanceChanged'),
doubledModeToggled: new Event('doubledModeToggled'),
repeatToggled: new Event('repeatToggled'),
llamaToggled: new Event('llamaToggled'),
close: new Event('close')
};
this._registerListeners();
return this;
},
this.setVolume(options.volume);
this.setBalance(options.balance);
this.loadFromUrl(options.mediaFile.url, options.mediaFile.name);
var skinFile = new MyFile();
skinFile.setUrl(options.skinUrl);
this.setSkin(skinFile);
_registerListeners: function() {
var self = this;
this._registerListeners();
return this;
},
this.windowManager.registerWindow(this.mainWindow);
_registerListeners: function() {
var self = this;
this.media.addEventListener('timeupdate', function() {
window.dispatchEvent(self.events.timeUpdated);
});
this.windowManager.registerWindow(this.mainWindow);
this.media.addEventListener('visualizerupdate', function(analyser) {
self.skin.visualizer.paintFrame(self.visualizerStyle, analyser);
});
this.media.addEventListener('ended', function() {
self.skin.visualizer.clear();
self.setState('stop');
});
this.media.addEventListener('waiting', function() {
window.dispatchEvent(self.events.startWaiting);
});
this.media.addEventListener('stopWaiting', function() {
window.dispatchEvent(self.events.stopWaiting);
});
this.media.addEventListener('playing', function() {
self.setState('play');
});
this.fileInput.onchange = function(e){
self.loadFromFileReference(e.target.files[0]);
};
},
/* Functions */
setState: function(state) {
this.state = state;
window.dispatchEvent(this.events.changeState);
},
getState: function() {
return this.state;
},
getDuration: function() {
return this.media.duration();
},
getTimeRemaining: function() {
return this.media.timeRemaining();
},
getTimeElapsed: function() {
return this.media.timeElapsed();
},
getPercentComplete: function() {
return this.media.percentComplete();
},
getChannelCount: function() {
return this.media.channels();
},
getVolume: function() {
return Math.round(this.media.getVolume() * 100);
},
seekToPercentComplete: function(percent) {
this.media.seekToPercentComplete(percent);
},
toggleTimeMode: function() {
window.dispatchEvent(this.events.toggleTimeMode);
},
play: function() {
if (this.getState() === 'play'){
this.media.stop();
}
this.media.play();
this.setState('play');
},
pause: function() {
if (this.getState() === 'pause'){
this.media.play();
} else if (this.getState() === 'play') {
this.media.pause();
this.setState('pause');
}
},
stop: function() {
this.media.stop();
this.setState('stop');
},
// From 0-100
setVolume: function(volume) {
// Ensure volume does not go out of bounds
volume = Math.max(volume, 0);
volume = Math.min(volume, 100);
var percent = volume / 100;
this.media.setVolume(percent);
window.dispatchEvent(this.events.volumeChanged);
},
incrementVolumeBy: function(ammount) {
this.setVolume((this.media.getVolume() * 100) + ammount);
},
toggleDoubledMode: function() {
window.dispatchEvent(this.events.doubledModeToggled);
},
// From -100 to 100
setBalance: function(balance) {
this.media.setBalance(balance);
window.dispatchEvent(this.events.balanceChanged);
},
getBalance: function() {
return this.media.getBalance();
},
seekForwardBy: function(seconds) {
this.media.seekToTime(this.media.timeElapsed() + seconds);
this.media.addEventListener('timeupdate', function() {
window.dispatchEvent(self.events.timeUpdated);
},
});
toggleRepeat: function() {
this.media.toggleRepeat();
window.dispatchEvent(this.events.repeatToggled);
},
this.media.addEventListener('visualizerupdate', function(analyser) {
self.skin.visualizer.paintFrame(self.visualizerStyle, analyser);
});
toggleShuffle: function() {
this.media.toggleShuffle();
this.mainWindow.toggleShuffle();
},
this.media.addEventListener('ended', function() {
self.skin.visualizer.clear();
self.setState('stop');
});
toggleLlama: function() {
window.dispatchEvent(this.events.llamaToggled);
},
this.media.addEventListener('waiting', function() {
window.dispatchEvent(self.events.startWaiting);
});
close: function() {
window.dispatchEvent(this.events.close);
this.media.addEventListener('stopWaiting', function() {
window.dispatchEvent(self.events.stopWaiting);
});
this.media.addEventListener('playing', function() {
self.setState('play');
});
this.fileInput.onchange = function(e){
self.loadFromFileReference(e.target.files[0]);
};
},
/* Functions */
setState: function(state) {
this.state = state;
window.dispatchEvent(this.events.changeState);
},
getState: function() {
return this.state;
},
getDuration: function() {
return this.media.duration();
},
getTimeRemaining: function() {
return this.media.timeRemaining();
},
getTimeElapsed: function() {
return this.media.timeElapsed();
},
getPercentComplete: function() {
return this.media.percentComplete();
},
getChannelCount: function() {
return this.media.channels();
},
getVolume: function() {
return Math.round(this.media.getVolume() * 100);
},
seekToPercentComplete: function(percent) {
this.media.seekToPercentComplete(percent);
},
toggleTimeMode: function() {
window.dispatchEvent(this.events.toggleTimeMode);
},
play: function() {
if (this.getState() === 'play'){
this.media.stop();
this.setState('stop'); // Currently unneeded
},
openFileDialog: function() {
this.fileInput.click();
},
loadFromFileReference: function(fileReference) {
var file = new MyFile();
file.setFileReference(fileReference);
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));
}
},
// Used only for the initial load, since it must have a CORS header
loadFromUrl: function(url, fileName) {
if (!fileName) {
this.fileName = url.split('/').pop();
} else {
this.fileName = fileName;
}
var file = new MyFile();
file.setUrl(url);
file.processBuffer(this._loadBuffer.bind(this));
},
setSkin: function(file) {
this.setLoadingState();
this.skin.setSkinByFile(file, this.unsetLoadingState.bind(this));
},
setLoadingState: function() {
window.dispatchEvent(this.events.startLoading);
},
unsetLoadingState: function() {
window.dispatchEvent(this.events.stopLoading);
},
toggleVisualizer: function() {
if (this.skin.visualizer.style === this.skin.visualizer.NONE) {
this.skin.visualizer.setStyle(this.skin.visualizer.BAR);
} else if (this.skin.visualizer.style === this.skin.visualizer.BAR) {
this.skin.visualizer.setStyle(this.skin.visualizer.OSCILLOSCOPE);
} else if (this.skin.visualizer.style === this.skin.visualizer.OSCILLOSCOPE) {
this.skin.visualizer.setStyle(this.skin.visualizer.NONE);
}
this.skin.visualizer.clear();
},
/* Listeners */
_loadBuffer: function(buffer) {
function setMetaData() {
var kbps = '128';
var khz = Math.round(this.media.sampleRate() / 1000).toString();
this.skin.font.setNodeToString(document.getElementById('kbps'), kbps);
this.skin.font.setNodeToString(document.getElementById('khz'), khz);
window.dispatchEvent(this.events.channelCountUpdated);
window.dispatchEvent(this.events.titleUpdated);
window.dispatchEvent(this.events.timeUpdated);
}
// Note, this will not happen right away
this.media.loadBuffer(buffer, setMetaData.bind(this));
},
/* Helpers */
_timeObject: function(time) {
var minutes = Math.floor(time / 60);
var seconds = time - (minutes * 60);
return [
Math.floor(minutes / 10),
Math.floor(minutes % 10),
Math.floor(seconds / 10),
Math.floor(seconds % 10)
];
}
};
});
this.media.play();
this.setState('play');
},
pause: function() {
if (this.getState() === 'pause'){
this.media.play();
} else if (this.getState() === 'play') {
this.media.pause();
this.setState('pause');
}
},
stop: function() {
this.media.stop();
this.setState('stop');
},
// From 0-100
setVolume: function(volume) {
// Ensure volume does not go out of bounds
volume = Math.max(volume, 0);
volume = Math.min(volume, 100);
var percent = volume / 100;
this.media.setVolume(percent);
window.dispatchEvent(this.events.volumeChanged);
},
incrementVolumeBy: function(ammount) {
this.setVolume((this.media.getVolume() * 100) + ammount);
},
toggleDoubledMode: function() {
window.dispatchEvent(this.events.doubledModeToggled);
},
// From -100 to 100
setBalance: function(balance) {
this.media.setBalance(balance);
window.dispatchEvent(this.events.balanceChanged);
},
getBalance: function() {
return this.media.getBalance();
},
seekForwardBy: function(seconds) {
this.media.seekToTime(this.media.timeElapsed() + seconds);
window.dispatchEvent(self.events.timeUpdated);
},
toggleRepeat: function() {
this.media.toggleRepeat();
window.dispatchEvent(this.events.repeatToggled);
},
toggleShuffle: function() {
this.media.toggleShuffle();
this.mainWindow.toggleShuffle();
},
toggleLlama: function() {
window.dispatchEvent(this.events.llamaToggled);
},
close: function() {
window.dispatchEvent(this.events.close);
this.media.stop();
this.setState('stop'); // Currently unneeded
},
openFileDialog: function() {
this.fileInput.click();
},
loadFromFileReference: function(fileReference) {
var file = new MyFile();
file.setFileReference(fileReference);
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));
}
},
// Used only for the initial load, since it must have a CORS header
loadFromUrl: function(url, fileName) {
if (!fileName) {
this.fileName = url.split('/').pop();
} else {
this.fileName = fileName;
}
var file = new MyFile();
file.setUrl(url);
file.processBuffer(this._loadBuffer.bind(this));
},
setSkin: function(file) {
this.setLoadingState();
this.skin.setSkinByFile(file, this.unsetLoadingState.bind(this));
},
setLoadingState: function() {
window.dispatchEvent(this.events.startLoading);
},
unsetLoadingState: function() {
window.dispatchEvent(this.events.stopLoading);
},
toggleVisualizer: function() {
if (this.skin.visualizer.style === this.skin.visualizer.NONE) {
this.skin.visualizer.setStyle(this.skin.visualizer.BAR);
} else if (this.skin.visualizer.style === this.skin.visualizer.BAR) {
this.skin.visualizer.setStyle(this.skin.visualizer.OSCILLOSCOPE);
} else if (this.skin.visualizer.style === this.skin.visualizer.OSCILLOSCOPE) {
this.skin.visualizer.setStyle(this.skin.visualizer.NONE);
}
this.skin.visualizer.clear();
},
/* Listeners */
_loadBuffer: function(buffer) {
function setMetaData() {
var kbps = '128';
var khz = Math.round(this.media.sampleRate() / 1000).toString();
this.skin.font.setNodeToString(document.getElementById('kbps'), kbps);
this.skin.font.setNodeToString(document.getElementById('khz'), khz);
window.dispatchEvent(this.events.channelCountUpdated);
window.dispatchEvent(this.events.titleUpdated);
window.dispatchEvent(this.events.timeUpdated);
}
// Note, this will not happen right away
this.media.loadBuffer(buffer, setMetaData.bind(this));
},
/* Helpers */
_timeObject: function(time) {
var minutes = Math.floor(time / 60);
var seconds = time - (minutes * 60);
return [
Math.floor(minutes / 10),
Math.floor(minutes % 10),
Math.floor(seconds / 10),
Math.floor(seconds % 10)
];
}
};

View file

@ -1,4 +1,4 @@
define({
module.exports = {
registerWindow: function(win) {
var body = win.body;
var handle = win.handle;
@ -56,4 +56,4 @@ define({
window.addEventListener('mouseup', handleUp);
});
}
});
};