mirror of
https://github.com/captbaritone/webamp.git
synced 2026-08-03 07:23:55 +00:00
Add eslint
This commit is contained in:
parent
dea6e43f96
commit
8b986ec3cb
18 changed files with 1537 additions and 1431 deletions
90
.eslintrc
Normal file
90
.eslintrc
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"amd": true
|
||||
},
|
||||
|
||||
"rules": {
|
||||
"block-scoped-var": 1,
|
||||
"brace-style": [1, "1tbs"],
|
||||
"camelcase": 2,
|
||||
"comma-dangle": [2, "never"],
|
||||
"comma-spacing": 2,
|
||||
"consistent-return": 1,
|
||||
"dot-notation": [2, { "allowKeywords": false }],
|
||||
"eol-last": 2,
|
||||
"eqeqeq": [2, "smart"],
|
||||
"indent": [2, 2, {"SwitchCase": 1}],
|
||||
"key-spacing": 1,
|
||||
"linebreak-style": 2,
|
||||
"max-depth": [1, 4],
|
||||
"max-params": [1, 5],
|
||||
"new-cap": 2,
|
||||
"no-alert": 2,
|
||||
"no-caller": 2,
|
||||
"no-catch-shadow": 2,
|
||||
"no-debugger": 2,
|
||||
"no-delete-var": 2,
|
||||
"no-div-regex": 1,
|
||||
"no-dupe-args": 2,
|
||||
"no-dupe-keys": 2,
|
||||
"no-duplicate-case": 2,
|
||||
"no-else-return": 1,
|
||||
"no-empty-character-class": 2,
|
||||
"no-empty-label": 2,
|
||||
"no-eval": 2,
|
||||
"no-ex-assign": 2,
|
||||
"no-extend-native": 1,
|
||||
"no-extra-boolean-cast": 2,
|
||||
"no-extra-semi": 2,
|
||||
"no-fallthrough": 2,
|
||||
"no-floating-decimal": 2,
|
||||
"no-func-assign": 2,
|
||||
"no-implied-eval": 2,
|
||||
"no-inner-declarations": 2,
|
||||
"no-irregular-whitespace": 2,
|
||||
"no-label-var": 2,
|
||||
"no-lone-blocks": 2,
|
||||
"no-lonely-if": 2,
|
||||
"no-multi-spaces": 1,
|
||||
"no-multi-str": 2,
|
||||
"no-native-reassign": 2,
|
||||
"no-negated-in-lhs": 1,
|
||||
"no-nested-ternary": 2,
|
||||
"no-new-object": 2,
|
||||
"no-new-wrappers": 2,
|
||||
"no-obj-calls": 2,
|
||||
"no-octal": 2,
|
||||
"no-octal-escape": 2,
|
||||
"no-proto": 2,
|
||||
"no-redeclare": 2,
|
||||
"no-shadow": 2,
|
||||
"no-spaced-func": 2,
|
||||
"no-throw-literal": 2,
|
||||
"no-trailing-spaces": 2,
|
||||
"no-undef": 2,
|
||||
"no-undef-init": 2,
|
||||
"no-undefined": 2,
|
||||
"no-unneeded-ternary": 2,
|
||||
"no-unreachable": 2,
|
||||
"no-unused-expressions": 2,
|
||||
"no-unused-vars": 2,
|
||||
"no-use-before-define": [2, "nofunc"],
|
||||
"no-with": 2,
|
||||
"quote-props": [1, "consistent-as-needed"],
|
||||
"quotes": [2, "single", "avoid-escape"],
|
||||
"radix": 2,
|
||||
"semi": 2,
|
||||
"space-after-keywords": [2, "always"],
|
||||
"space-before-keywords": [2, "always"],
|
||||
"space-before-function-paren": [2, {"anonymous": "never", "named": "never"}],
|
||||
"object-curly-spacing": [2, "never"],
|
||||
"space-infix-ops": 2,
|
||||
"space-return-throw-case": 2,
|
||||
"space-unary-ops": [2, { "words": true, "nonwords": false }],
|
||||
"use-isnan": 2,
|
||||
"valid-typeof": 2,
|
||||
"wrap-iife": 2
|
||||
}
|
||||
}
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -2,3 +2,5 @@ preview.png
|
|||
|
||||
# Files I use for local dev sometimes
|
||||
llama-2.91.mp3
|
||||
|
||||
node_modules
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
define({
|
||||
isCompatible: function() {
|
||||
return this._supportsAudioApi() && this._supportsCanvas();
|
||||
},
|
||||
isCompatible: function() {
|
||||
return this._supportsAudioApi() && this._supportsCanvas();
|
||||
},
|
||||
|
||||
_supportsAudioApi: function() {
|
||||
return !!(window.AudioContext || window.webkitAudioContext);
|
||||
},
|
||||
_supportsCanvas: function() {
|
||||
return !!document.createElement('canvas').getContext;
|
||||
}
|
||||
_supportsAudioApi: function() {
|
||||
return !!(window.AudioContext || window.webkitAudioContext);
|
||||
},
|
||||
_supportsCanvas: function() {
|
||||
return !!document.createElement('canvas').getContext;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,45 +1,45 @@
|
|||
define([
|
||||
'my-file'
|
||||
'my-file'
|
||||
], function(
|
||||
MyFile
|
||||
MyFile
|
||||
) {
|
||||
return {
|
||||
return {
|
||||
init: function(winamp) {
|
||||
this.winamp = winamp;
|
||||
this.winamp = winamp;
|
||||
|
||||
// The Option button
|
||||
this.option = document.getElementById('option');
|
||||
var self = this;
|
||||
// The Option button
|
||||
this.option = document.getElementById('option');
|
||||
var self = this;
|
||||
|
||||
document.onclick = function() {
|
||||
self.option.classList.remove('selected');
|
||||
};
|
||||
document.onclick = function() {
|
||||
self.option.classList.remove('selected');
|
||||
};
|
||||
|
||||
this.option.onclick = function(event) {
|
||||
self.option.classList.toggle('selected');
|
||||
event.stopPropagation();
|
||||
};
|
||||
this.option.onclick = function(event) {
|
||||
self.option.classList.toggle('selected');
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
var skinSelectNodes = document.getElementsByClassName('skin-select');
|
||||
for(var i = 0; i < skinSelectNodes.length; i++) {
|
||||
skinSelectNodes[i].onclick = this._loadSkin.bind(this);
|
||||
}
|
||||
var skinSelectNodes = document.getElementsByClassName('skin-select');
|
||||
for (var i = 0; i < skinSelectNodes.length; i++) {
|
||||
skinSelectNodes[i].onclick = this._loadSkin.bind(this);
|
||||
}
|
||||
|
||||
document.getElementById('context-play-file').onclick = function() {
|
||||
self.winamp.openFileDialog();
|
||||
};
|
||||
document.getElementById('context-load-skin').onclick = function() {
|
||||
self.winamp.openFileDialog();
|
||||
};
|
||||
document.getElementById('context-exit').onclick = function() {
|
||||
self.winamp.close();
|
||||
};
|
||||
document.getElementById('context-play-file').onclick = function() {
|
||||
self.winamp.openFileDialog();
|
||||
};
|
||||
document.getElementById('context-load-skin').onclick = function() {
|
||||
self.winamp.openFileDialog();
|
||||
};
|
||||
document.getElementById('context-exit').onclick = function() {
|
||||
self.winamp.close();
|
||||
};
|
||||
},
|
||||
|
||||
_loadSkin: function(event) {
|
||||
var skinFile = new MyFile();
|
||||
skinFile.setUrl(event.target.dataset.skinUrl);
|
||||
this.winamp.setSkin(skinFile);
|
||||
var skinFile = new MyFile();
|
||||
skinFile.setUrl(event.target.dataset.skinUrl);
|
||||
this.winamp.setSkin(skinFile);
|
||||
}
|
||||
};
|
||||
};
|
||||
});
|
||||
|
|
|
|||
80
js/embed.js
80
js/embed.js
|
|
@ -2,52 +2,52 @@
|
|||
var scriptTag = document.currentScript;
|
||||
|
||||
require([
|
||||
'browser',
|
||||
'../rjs/text!../html/main-window.html',
|
||||
'../rjs/css!../css/cleanslate.css',
|
||||
'../rjs/css!../css/winamp.css',
|
||||
'winamp',
|
||||
'context',
|
||||
'hotkeys'
|
||||
'browser',
|
||||
'../rjs/text!../html/main-window.html',
|
||||
'../rjs/css!../css/cleanslate.css',
|
||||
'../rjs/css!../css/winamp.css',
|
||||
'winamp',
|
||||
'context',
|
||||
'hotkeys'
|
||||
], function(
|
||||
Browser,
|
||||
mainWindowHtml,
|
||||
cleanslateCss,
|
||||
winampCss,
|
||||
Winamp,
|
||||
Context,
|
||||
Hotkeys
|
||||
Browser,
|
||||
mainWindowHtml,
|
||||
cleanslateCss,
|
||||
winampCss,
|
||||
Winamp,
|
||||
Context,
|
||||
Hotkeys
|
||||
) {
|
||||
var node = document.createElement('div');
|
||||
var node = document.createElement('div');
|
||||
|
||||
scriptTag.parentNode.insertBefore(node, scriptTag);
|
||||
var options = scriptTag.dataset;
|
||||
scriptTag.parentNode.insertBefore(node, scriptTag);
|
||||
var options = scriptTag.dataset;
|
||||
|
||||
var media = options.media ? options.media : 'https://cdn.rawgit.com/captbaritone/llama/master/llama-2.91.mp3';
|
||||
var skin = options.skin ? options.skin : 'https://cdn.rawgit.com/captbaritone/winamp-skins/master/v2/base-2.91.wsz';
|
||||
var hotKeys = typeof options.hotkeys !== "undefined" ? true : false;
|
||||
var media = options.media ? options.media : 'https://cdn.rawgit.com/captbaritone/llama/master/llama-2.91.mp3';
|
||||
var skin = options.skin ? options.skin : 'https://cdn.rawgit.com/captbaritone/winamp-skins/master/v2/base-2.91.wsz';
|
||||
var hotKeys = typeof options.hotkeys !== 'undefined';
|
||||
|
||||
if(Browser.isCompatible()) {
|
||||
node.innerHTML = mainWindowHtml;
|
||||
node.setAttribute("id", "winamp2-js");
|
||||
if (Browser.isCompatible()) {
|
||||
node.innerHTML = mainWindowHtml;
|
||||
node.setAttribute('id', 'winamp2-js');
|
||||
|
||||
var winamp = Winamp.init({
|
||||
'volume': 50,
|
||||
'balance': 0,
|
||||
'mediaFile': {
|
||||
'url': media
|
||||
},
|
||||
'skinUrl': skin
|
||||
});
|
||||
var winamp = Winamp.init({
|
||||
volume: 50,
|
||||
balance: 0,
|
||||
mediaFile: {
|
||||
url: media
|
||||
},
|
||||
skinUrl: skin
|
||||
});
|
||||
|
||||
if(hotKeys) {
|
||||
Hotkeys.init(winamp);
|
||||
}
|
||||
Context.init(winamp);
|
||||
} else {
|
||||
var audio = document.createElement('audio');
|
||||
audio.src = media;
|
||||
audio.setAttribute('controls', true);
|
||||
node.appendChild(audio);
|
||||
if (hotKeys) {
|
||||
Hotkeys.init(winamp);
|
||||
}
|
||||
Context.init(winamp);
|
||||
} else {
|
||||
var audio = document.createElement('audio');
|
||||
audio.src = media;
|
||||
audio.setAttribute('controls', true);
|
||||
node.appendChild(audio);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
132
js/font.js
132
js/font.js
|
|
@ -1,78 +1,78 @@
|
|||
// Manage rendering text from this skin's text.bmp file
|
||||
define({
|
||||
|
||||
// Fill a node with a <div> containing character <div>s
|
||||
setNodeToString: function(node, string) {
|
||||
stringElement = this._stringNode(string);
|
||||
node.innerHTML = '';
|
||||
node.appendChild(stringElement);
|
||||
},
|
||||
// Fill a node with a <div> containing character <div>s
|
||||
setNodeToString: function(node, string) {
|
||||
var stringElement = this._stringNode(string);
|
||||
node.innerHTML = '';
|
||||
node.appendChild(stringElement);
|
||||
},
|
||||
|
||||
// Get a <div> containing char
|
||||
characterNode: function(char) {
|
||||
return this.displayCharacterInNode(char, document.createElement('div'));
|
||||
},
|
||||
// Get a <div> containing char
|
||||
characterNode: function(char) {
|
||||
return this.displayCharacterInNode(char, document.createElement('div'));
|
||||
},
|
||||
|
||||
// Style/populate a <div> to display a character
|
||||
displayCharacterInNode: function(character, node) {
|
||||
position = this._getCharPosition(character);
|
||||
row = position[0];
|
||||
column = position[1];
|
||||
verticalOffset = row * 6;
|
||||
horizontalOffset = column * 5;
|
||||
// Style/populate a <div> to display a character
|
||||
displayCharacterInNode: function(character, node) {
|
||||
var position = this._getCharPosition(character);
|
||||
var row = position[0];
|
||||
var column = position[1];
|
||||
var verticalOffset = row * 6;
|
||||
var horizontalOffset = column * 5;
|
||||
|
||||
x = '-' + horizontalOffset + 'px';
|
||||
y = '-' + verticalOffset + 'px';
|
||||
node.style.backgroundPosition = x + ' ' + y;
|
||||
node.classList.add('character');
|
||||
var x = '-' + horizontalOffset + 'px';
|
||||
var y = '-' + verticalOffset + 'px';
|
||||
node.style.backgroundPosition = x + ' ' + y;
|
||||
node.classList.add('character');
|
||||
|
||||
node.innerHTML = character;
|
||||
return node;
|
||||
},
|
||||
node.innerHTML = character;
|
||||
return node;
|
||||
},
|
||||
|
||||
// Get a <div> containing a digit
|
||||
digitNode: function(digit) {
|
||||
var div = document.createElement('div');
|
||||
div.classList.add('digit');
|
||||
div.classList.add('digit-' + digit);
|
||||
return div;
|
||||
},
|
||||
// Get a <div> containing a digit
|
||||
digitNode: function(digit) {
|
||||
var div = document.createElement('div');
|
||||
div.classList.add('digit');
|
||||
div.classList.add('digit-' + digit);
|
||||
return div;
|
||||
},
|
||||
|
||||
|
||||
// Get a <div> containing character <div>s
|
||||
_stringNode: function(string) {
|
||||
parentDiv = document.createElement('div');
|
||||
for (var i = 0, len = string.length; i < len; i++) {
|
||||
char = string[i].toLowerCase();
|
||||
parentDiv.appendChild(this.characterNode(char));
|
||||
}
|
||||
return parentDiv;
|
||||
},
|
||||
|
||||
// Find the background offsets for a given character
|
||||
_getCharPosition: function(char) {
|
||||
position = this._fontLookup[char];
|
||||
if(!position) {
|
||||
return this._fontLookup[' '];
|
||||
}
|
||||
return position;
|
||||
},
|
||||
|
||||
/* TODO: There are too many " " and "_" characters */
|
||||
_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,29], "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,10], "_": [1,11], ":": [1,12],
|
||||
"(": [1,13], ")": [1,14], "-": [1,15], "'": [1,16], "!": [1,17],
|
||||
"_": [1,18], "+": [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]
|
||||
// Get a <div> containing character <div>s
|
||||
_stringNode: function(string) {
|
||||
var parentDiv = document.createElement('div');
|
||||
for (var i = 0, len = string.length; i < len; i++) {
|
||||
var char = string[i].toLowerCase();
|
||||
parentDiv.appendChild(this.characterNode(char));
|
||||
}
|
||||
return parentDiv;
|
||||
},
|
||||
|
||||
// Find the background offsets for a given character
|
||||
_getCharPosition: function(char) {
|
||||
var position = this._fontLookup[char];
|
||||
if (!position) {
|
||||
return this._fontLookup[' '];
|
||||
}
|
||||
return position;
|
||||
},
|
||||
|
||||
/* TODO: There are too many " " and "_" characters */
|
||||
_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]
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,48 +1,48 @@
|
|||
define({
|
||||
init: function(winamp) {
|
||||
keylog = [];
|
||||
trigger = [78,85,76,27,76,27,83,79,70,84];
|
||||
document.onkeyup = 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
|
||||
}
|
||||
}
|
||||
init: function(winamp) {
|
||||
var keylog = [];
|
||||
var trigger = [78, 85, 76, 27, 76, 27, 83, 79, 70, 84];
|
||||
document.onkeyup = 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();
|
||||
}
|
||||
};
|
||||
}
|
||||
// Easter Egg
|
||||
keylog.push(e.keyCode);
|
||||
keylog = keylog.slice(-10);
|
||||
if (keylog.toString() === trigger.toString()) {
|
||||
winamp.toggleLlama();
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,398 +1,428 @@
|
|||
define([
|
||||
'multi-display',
|
||||
'font'
|
||||
'multi-display',
|
||||
'font'
|
||||
], function(
|
||||
MultiDisplay,
|
||||
Font
|
||||
MultiDisplay,
|
||||
Font
|
||||
) {
|
||||
return {
|
||||
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'),
|
||||
};
|
||||
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.handle = document.getElementById('title-bar');
|
||||
this.body = this.nodes.window;
|
||||
this.handle = document.getElementById('title-bar');
|
||||
this.body = this.nodes.window;
|
||||
|
||||
this.textDisplay = MultiDisplay.init(Font, 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 = MultiDisplay.init(Font, 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.showRegister('songTitle');
|
||||
this.textDisplay.showRegister('songTitle');
|
||||
|
||||
this.textDisplay.startRegisterMarquee('songTitle');
|
||||
this.textDisplay.startRegisterMarquee('songTitle');
|
||||
|
||||
this._registerListeners();
|
||||
return this;
|
||||
this._registerListeners();
|
||||
return this;
|
||||
},
|
||||
|
||||
_registerListeners: function() {
|
||||
var self = this;
|
||||
var self = this;
|
||||
|
||||
this.nodes.close.onclick = function() {
|
||||
self.winamp.close();
|
||||
};
|
||||
this.nodes.close.onclick = function() {
|
||||
self.winamp.close();
|
||||
};
|
||||
|
||||
this.nodes.shade.onclick = function() {
|
||||
self.nodes.window.classList.toggle('shade');
|
||||
};
|
||||
this.nodes.shade.onclick = function() {
|
||||
self.nodes.window.classList.toggle('shade');
|
||||
};
|
||||
|
||||
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.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.buttonD.onmouseup = function() {
|
||||
self.textDisplay.showRegister('songTitle');
|
||||
};
|
||||
this.nodes.buttonD.onmouseup = function() {
|
||||
self.textDisplay.showRegister('songTitle');
|
||||
};
|
||||
|
||||
this.nodes.buttonD.onclick = function() {
|
||||
self.winamp.toggleDoubledMode();
|
||||
};
|
||||
this.nodes.buttonD.onclick = function() {
|
||||
self.winamp.toggleDoubledMode();
|
||||
};
|
||||
|
||||
this.nodes.play.onclick = function() {
|
||||
self.winamp.play();
|
||||
};
|
||||
this.nodes.play.onclick = function() {
|
||||
self.winamp.play();
|
||||
};
|
||||
|
||||
this.nodes.songTitle.onmousedown = function() {
|
||||
self.textDisplay.pauseRegisterMarquee('songTitle');
|
||||
};
|
||||
this.nodes.songTitle.onmousedown = function() {
|
||||
self.textDisplay.pauseRegisterMarquee('songTitle');
|
||||
};
|
||||
|
||||
this.nodes.songTitle.onmouseup = function() {
|
||||
setTimeout(function () {
|
||||
self.textDisplay.startRegisterMarquee('songTitle');
|
||||
}, 1000);
|
||||
};
|
||||
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.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.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.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.position.onchange = function() {
|
||||
if (self.winamp.getState() !== 'stop'){
|
||||
self.winamp.seekToPercentComplete(this.value);
|
||||
}
|
||||
};
|
||||
|
||||
this.nodes.previous.onclick = function() {
|
||||
self.winamp.previous();
|
||||
};
|
||||
this.nodes.previous.onclick = function() {
|
||||
self.winamp.previous();
|
||||
};
|
||||
|
||||
this.nodes.next.onclick = function() {
|
||||
self.winamp.next();
|
||||
};
|
||||
this.nodes.next.onclick = function() {
|
||||
self.winamp.next();
|
||||
};
|
||||
|
||||
this.nodes.pause.onclick = function() {
|
||||
self.winamp.pause();
|
||||
};
|
||||
this.nodes.pause.onclick = function() {
|
||||
self.winamp.pause();
|
||||
};
|
||||
|
||||
this.nodes.stop.onclick = function() {
|
||||
self.winamp.stop();
|
||||
};
|
||||
this.nodes.stop.onclick = function() {
|
||||
self.winamp.stop();
|
||||
};
|
||||
|
||||
this.nodes.eject.onclick = function() {
|
||||
self.winamp.openFileDialog();
|
||||
};
|
||||
this.nodes.eject.onclick = function() {
|
||||
self.winamp.openFileDialog();
|
||||
};
|
||||
|
||||
this.nodes.repeat.onclick = function() {
|
||||
self.winamp.toggleRepeat();
|
||||
};
|
||||
this.nodes.repeat.onclick = function() {
|
||||
self.winamp.toggleRepeat();
|
||||
};
|
||||
|
||||
this.nodes.shuffle.onclick = function() {
|
||||
self.winamp.toggleShuffle();
|
||||
};
|
||||
this.nodes.shuffle.onclick = function() {
|
||||
self.winamp.toggleShuffle();
|
||||
};
|
||||
|
||||
this.nodes.shadeTime.onclick = function() {
|
||||
self.winamp.toggleTimeMode();
|
||||
};
|
||||
this.nodes.shadeTime.onclick = function() {
|
||||
self.winamp.toggleTimeMode();
|
||||
};
|
||||
|
||||
this.nodes.volume.onmousedown = function() {
|
||||
self.textDisplay.showRegister('volume');
|
||||
};
|
||||
this.nodes.volume.onmousedown = function() {
|
||||
self.textDisplay.showRegister('volume');
|
||||
};
|
||||
|
||||
this.nodes.volume.onmouseup = function() {
|
||||
self.textDisplay.showRegister('songTitle');
|
||||
};
|
||||
this.nodes.volume.onmouseup = function() {
|
||||
self.textDisplay.showRegister('songTitle');
|
||||
};
|
||||
|
||||
this.nodes.volume.oninput = function() {
|
||||
self.winamp.setVolume(this.value);
|
||||
};
|
||||
this.nodes.volume.oninput = function() {
|
||||
self.winamp.setVolume(this.value);
|
||||
};
|
||||
|
||||
this.nodes.time.onclick = function() {
|
||||
self.winamp.toggleTimeMode();
|
||||
};
|
||||
this.nodes.time.onclick = function() {
|
||||
self.winamp.toggleTimeMode();
|
||||
};
|
||||
|
||||
this.nodes.balance.onmousedown = function() {
|
||||
self.textDisplay.showRegister('balance');
|
||||
};
|
||||
this.nodes.balance.onmousedown = function() {
|
||||
self.textDisplay.showRegister('balance');
|
||||
};
|
||||
|
||||
this.nodes.balance.onmouseup = function() {
|
||||
self.textDisplay.showRegister('songTitle');
|
||||
};
|
||||
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.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();
|
||||
};
|
||||
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(); });
|
||||
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));
|
||||
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');
|
||||
this.nodes.buttonD.classList.toggle('selected');
|
||||
this.nodes.window.classList.toggle('doubled');
|
||||
},
|
||||
|
||||
close: function() {
|
||||
this.nodes.window.classList.add('closed');
|
||||
this.nodes.window.classList.add('closed');
|
||||
},
|
||||
|
||||
updatePosition: function() {
|
||||
if(!this.nodes.window.classList.contains('setting-position')) {
|
||||
this.nodes.position.value = this.winamp.getPercentComplete();
|
||||
}
|
||||
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;
|
||||
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');
|
||||
}
|
||||
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();
|
||||
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 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')
|
||||
];
|
||||
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);
|
||||
}
|
||||
// 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');
|
||||
this.nodes.workIndicator.classList.add('selected');
|
||||
},
|
||||
|
||||
unsetWorkingIndicator: function() {
|
||||
this.nodes.workIndicator.classList.remove('selected');
|
||||
this.nodes.workIndicator.classList.remove('selected');
|
||||
},
|
||||
|
||||
setLoadingState: function() {
|
||||
this.nodes.window.classList.add('loading');
|
||||
this.nodes.window.classList.add('loading');
|
||||
},
|
||||
|
||||
unsetLoadingState: function() {
|
||||
this.nodes.window.classList.remove('loading');
|
||||
this.nodes.window.classList.remove('loading');
|
||||
},
|
||||
|
||||
toggleTimeMode: function() {
|
||||
this.nodes.time.classList.toggle('countdown');
|
||||
this.updateTime();
|
||||
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 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);
|
||||
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;
|
||||
// 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';
|
||||
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);
|
||||
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');
|
||||
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);
|
||||
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');
|
||||
}
|
||||
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');
|
||||
this.nodes.repeat.classList.toggle('selected');
|
||||
},
|
||||
|
||||
toggleShuffle: function() {
|
||||
this.nodes.shuffle.classList.toggle('selected');
|
||||
this.nodes.shuffle.classList.toggle('selected');
|
||||
},
|
||||
|
||||
dragenter: function(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
},
|
||||
|
||||
dragover: function(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
},
|
||||
|
||||
drop: function(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
var dt = e.dataTransfer;
|
||||
var file = dt.files[0];
|
||||
this.winamp.loadFromFileReference(file);
|
||||
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];
|
||||
var timeObject = this.winamp._timeObject(time);
|
||||
return timeObject[0] + timeObject[1] + ':' + timeObject[2] + timeObject[3];
|
||||
}
|
||||
};
|
||||
};
|
||||
});
|
||||
|
|
|
|||
73
js/main.js
73
js/main.js
|
|
@ -1,43 +1,42 @@
|
|||
require([
|
||||
'browser',
|
||||
'../rjs/text!../html/main-window.html',
|
||||
'../rjs/css!../css/winamp.css',
|
||||
'winamp',
|
||||
'context',
|
||||
'hotkeys'
|
||||
'browser',
|
||||
'../rjs/text!../html/main-window.html',
|
||||
'../rjs/css!../css/winamp.css',
|
||||
'winamp',
|
||||
'context',
|
||||
'hotkeys'
|
||||
], function(
|
||||
Browser,
|
||||
mainWindowHtml,
|
||||
pageCss,
|
||||
Winamp,
|
||||
Context,
|
||||
Hotkeys
|
||||
Browser,
|
||||
mainWindowHtml,
|
||||
pageCss,
|
||||
Winamp,
|
||||
Context,
|
||||
Hotkeys
|
||||
) {
|
||||
document.getElementById('embed-link').onclick = function() {
|
||||
document.getElementById('embed').classList.toggle('selected');
|
||||
document.getElementById('embed-input').select();
|
||||
return false;
|
||||
};
|
||||
if(Browser.isCompatible()) {
|
||||
var mainWindowElement = document.createElement('div');
|
||||
mainWindowElement.innerHTML = mainWindowHtml;
|
||||
document.getElementById('winamp2-js').appendChild(mainWindowElement);
|
||||
document.getElementById('embed-link').onclick = function() {
|
||||
document.getElementById('embed').classList.toggle('selected');
|
||||
document.getElementById('embed-input').select();
|
||||
return false;
|
||||
};
|
||||
if (Browser.isCompatible()) {
|
||||
var mainWindowElement = document.createElement('div');
|
||||
mainWindowElement.innerHTML = mainWindowHtml;
|
||||
document.getElementById('winamp2-js').appendChild(mainWindowElement);
|
||||
|
||||
var winamp = Winamp.init({
|
||||
'volume': 50,
|
||||
'balance': 0,
|
||||
'mediaFile': {
|
||||
'url': "https://cdn.rawgit.com/captbaritone/llama/master/llama-2.91.mp3",
|
||||
'name': "1. DJ Mike Llama - Llama Whippin' Intro"
|
||||
},
|
||||
'skinUrl':
|
||||
'https://cdn.rawgit.com/captbaritone/winamp-skins/master/v2/base-2.91.wsz'
|
||||
});
|
||||
var winamp = Winamp.init({
|
||||
volume: 50,
|
||||
balance: 0,
|
||||
mediaFile: {
|
||||
url: 'https://cdn.rawgit.com/captbaritone/llama/master/llama-2.91.mp3',
|
||||
name: "1. DJ Mike Llama - Llama Whippin' Intro"
|
||||
},
|
||||
skinUrl: 'https://cdn.rawgit.com/captbaritone/winamp-skins/master/v2/base-2.91.wsz'
|
||||
});
|
||||
|
||||
Hotkeys.init(winamp);
|
||||
Context.init(winamp);
|
||||
} else {
|
||||
document.getElementById('winamp').style.display = 'none';
|
||||
document.getElementById('browser-compatibility').style.display = 'block';
|
||||
}
|
||||
Hotkeys.init(winamp);
|
||||
Context.init(winamp);
|
||||
} else {
|
||||
document.getElementById('winamp').style.display = 'none';
|
||||
document.getElementById('browser-compatibility').style.display = 'block';
|
||||
}
|
||||
});
|
||||
|
|
|
|||
476
js/media.js
476
js/media.js
|
|
@ -1,260 +1,256 @@
|
|||
/* Emulate the native <audio> element with Web Audio API */
|
||||
define({
|
||||
_context: new(window.AudioContext || window.webkitAudioContext)(),
|
||||
_source: null,
|
||||
_buffer: null,
|
||||
_callbacks: {
|
||||
waiting: function(){},
|
||||
stopWaiting: function(){},
|
||||
playing: function(){},
|
||||
timeupdate: function(){},
|
||||
visualizerupdate: function(){},
|
||||
ended: function(){}
|
||||
},
|
||||
_startTime: 0,
|
||||
_position: 0,
|
||||
_balance: 0,
|
||||
_playing: false,
|
||||
_loop: false,
|
||||
autoPlay: false,
|
||||
_context: new (window.AudioContext || window.webkitAudioContext)(),
|
||||
_source: null,
|
||||
_buffer: null,
|
||||
_callbacks: {
|
||||
waiting: function(){},
|
||||
stopWaiting: function(){},
|
||||
playing: function(){},
|
||||
timeupdate: function(){},
|
||||
visualizerupdate: function(){},
|
||||
ended: function(){}
|
||||
},
|
||||
_startTime: 0,
|
||||
_position: 0,
|
||||
_balance: 0,
|
||||
_playing: false,
|
||||
_loop: false,
|
||||
autoPlay: false,
|
||||
|
||||
init: function() {
|
||||
// The _source node has to be recreated each time it's stopped or
|
||||
// paused, so we don't create it here.
|
||||
init: function() {
|
||||
// The _source node has to be recreated each time it's stopped or
|
||||
// paused, so we don't create it here.
|
||||
|
||||
// Create the spliter node
|
||||
this._chanSplit = this._context.createChannelSplitter(2);
|
||||
// Create the spliter node
|
||||
this._chanSplit = this._context.createChannelSplitter(2);
|
||||
|
||||
// Create the gains for left and right
|
||||
this._leftGain = this._context.createGain();
|
||||
this._rightGain = this._context.createGain();
|
||||
// Create the gains for left and right
|
||||
this._leftGain = this._context.createGain();
|
||||
this._rightGain = this._context.createGain();
|
||||
|
||||
// Create channel merge
|
||||
this._chanMerge = this._context.createChannelMerger(2);
|
||||
// Create channel merge
|
||||
this._chanMerge = this._context.createChannelMerger(2);
|
||||
|
||||
// Create the gain node for the volume control
|
||||
this._gainNode = this._context.createGain();
|
||||
// Create the gain node for the volume control
|
||||
this._gainNode = this._context.createGain();
|
||||
|
||||
// Create the analyser node for the visualizer
|
||||
this._analyser = this._context.createAnalyser();
|
||||
this._analyser.fftSize = 2048;
|
||||
// Create the analyser node for the visualizer
|
||||
this._analyser = this._context.createAnalyser();
|
||||
this._analyser.fftSize = 2048;
|
||||
|
||||
// Connect all the nodes in the correct way
|
||||
// (Note, source is created and connected later)
|
||||
//
|
||||
// <source>
|
||||
// |\
|
||||
// | <analyser>
|
||||
// |
|
||||
// (split using createChannelSplitter)
|
||||
// |
|
||||
// / \
|
||||
// / \
|
||||
// leftGain rightGain
|
||||
// \ /
|
||||
// \ /
|
||||
// |
|
||||
// (merge using createChannelMerger)
|
||||
// |
|
||||
// chanMerge
|
||||
// |
|
||||
// gain
|
||||
// |
|
||||
// destination
|
||||
// Connect all the nodes in the correct way
|
||||
// (Note, source is created and connected later)
|
||||
//
|
||||
// <source>
|
||||
// |\
|
||||
// | <analyser>
|
||||
// |
|
||||
// (split using createChannelSplitter)
|
||||
// |
|
||||
// / \
|
||||
// / \
|
||||
// leftGain rightGain
|
||||
// \ /
|
||||
// \ /
|
||||
// |
|
||||
// (merge using createChannelMerger)
|
||||
// |
|
||||
// chanMerge
|
||||
// |
|
||||
// gain
|
||||
// |
|
||||
// destination
|
||||
|
||||
// Connect split channels to left / right gains
|
||||
this._chanSplit.connect(this._leftGain,0);
|
||||
this._chanSplit.connect(this._rightGain,1);
|
||||
// Connect split channels to left / right gains
|
||||
this._chanSplit.connect(this._leftGain, 0);
|
||||
this._chanSplit.connect(this._rightGain, 1);
|
||||
|
||||
// Reconnect the left / right gains to the merge node
|
||||
this._leftGain.connect(this._chanMerge, 0, 0);
|
||||
this._rightGain.connect(this._chanMerge, 0, 1);
|
||||
// Reconnect the left / right gains to the merge node
|
||||
this._leftGain.connect(this._chanMerge, 0, 0);
|
||||
this._rightGain.connect(this._chanMerge, 0, 1);
|
||||
|
||||
this._chanMerge.connect(this._gainNode);
|
||||
this._chanMerge.connect(this._gainNode);
|
||||
|
||||
this._gainNode.connect(this._context.destination);
|
||||
this._gainNode.connect(this._context.destination);
|
||||
|
||||
// Kick off the animation loop
|
||||
this._draw(0);
|
||||
return this;
|
||||
},
|
||||
// Kick off the animation loop
|
||||
this._draw(0);
|
||||
return this;
|
||||
},
|
||||
|
||||
// Load from bufferArray
|
||||
loadBuffer: function(buffer, loadedCallback) {
|
||||
this.stop();
|
||||
this._callbacks.waiting();
|
||||
// Load from bufferArray
|
||||
loadBuffer: function(buffer, loadedCallback) {
|
||||
this.stop();
|
||||
this._callbacks.waiting();
|
||||
|
||||
var loadAudioBuffer = function(buffer) {
|
||||
this._buffer = buffer;
|
||||
loadedCallback();
|
||||
this._callbacks.stopWaiting();
|
||||
if(this.autoPlay) {
|
||||
this.play(0);
|
||||
}
|
||||
};
|
||||
var loadAudioBuffer = function(audioBuffer) {
|
||||
this._buffer = audioBuffer;
|
||||
loadedCallback();
|
||||
this._callbacks.stopWaiting();
|
||||
if (this.autoPlay) {
|
||||
this.play(0);
|
||||
}
|
||||
};
|
||||
|
||||
var error = function (error) {
|
||||
//console.error("failed to decode:", error);
|
||||
};
|
||||
// Decode the target file into an arrayBuffer and pass it to loadBuffer
|
||||
this._context.decodeAudioData(buffer, loadAudioBuffer.bind(this), error);
|
||||
},
|
||||
var error = function(errorMessage) {
|
||||
console.error('failed to decode:', errorMessage);
|
||||
};
|
||||
// Decode the target file into an arrayBuffer and pass it to loadBuffer
|
||||
this._context.decodeAudioData(buffer, loadAudioBuffer.bind(this), error);
|
||||
},
|
||||
|
||||
/* Properties */
|
||||
duration: function() {
|
||||
return this._buffer.duration;
|
||||
},
|
||||
timeElapsed: function() {
|
||||
return this._position;
|
||||
},
|
||||
timeRemaining: function() {
|
||||
return this.duration() - this.timeElapsed();
|
||||
},
|
||||
percentComplete: function() {
|
||||
return (this.timeElapsed() / this.duration()) * 100;
|
||||
},
|
||||
channels: function() {
|
||||
if(!this._buffer) {
|
||||
return 0;
|
||||
}
|
||||
return this._buffer.numberOfChannels;
|
||||
},
|
||||
sampleRate: function() {
|
||||
return this._buffer.sampleRate;
|
||||
},
|
||||
|
||||
/* Actions */
|
||||
previous: function() {
|
||||
// Implement this when we support playlists
|
||||
},
|
||||
play: function(position) {
|
||||
if(this._playing) {
|
||||
// So we don't get a race condition with _position getting overwritten
|
||||
this.pause();
|
||||
}
|
||||
if(this._buffer) {
|
||||
this._source = this._context.createBufferSource();
|
||||
this._source.buffer = this._buffer;
|
||||
this._source.connect(this._analyser);
|
||||
this._source.connect(this._chanSplit);
|
||||
|
||||
this._position = typeof position !== 'undefined' ? position : this._position;
|
||||
this._startTime = this._context.currentTime - this._position;
|
||||
this._source.start(0, this._position);
|
||||
this._playing = true;
|
||||
this._callbacks.playing();
|
||||
}
|
||||
},
|
||||
pause: function() {
|
||||
if(!this._playing) {
|
||||
return;
|
||||
}
|
||||
this._silence();
|
||||
this._updatePosition();
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
this._silence();
|
||||
this._position = 0;
|
||||
},
|
||||
|
||||
_silence: function() {
|
||||
if(this._source) {
|
||||
this._source.stop(0);
|
||||
this._source = null;
|
||||
}
|
||||
this._playing = false;
|
||||
},
|
||||
|
||||
/* Actions with arguments */
|
||||
seekToPercentComplete: function(percent) {
|
||||
var seekTime = this.duration() * (percent / 100);
|
||||
this.seekToTime(seekTime);
|
||||
},
|
||||
|
||||
// From 0-1
|
||||
setVolume: function(volume) {
|
||||
this._gainNode.gain.value = volume;
|
||||
},
|
||||
|
||||
getVolume: function() {
|
||||
return this._gainNode.gain.value;
|
||||
},
|
||||
|
||||
// From -100 to 100
|
||||
setBalance: function(balance) {
|
||||
var changeVal = Math.abs(balance) / 100;
|
||||
|
||||
// Hack for Firefox. Having either channel set to 0 seems to revert us
|
||||
// to equal balance.
|
||||
changeVal = changeVal - 0.00000001;
|
||||
|
||||
if(balance > 0) { // Right
|
||||
this._leftGain.gain.value = 1 - changeVal;
|
||||
this._rightGain.gain.value = 1;
|
||||
}
|
||||
else if(balance < 0) // Left
|
||||
{
|
||||
this._leftGain.gain.value = 1;
|
||||
this._rightGain.gain.value = 1 - changeVal;
|
||||
}
|
||||
else // Center
|
||||
{
|
||||
this._leftGain.gain.value = 1;
|
||||
this._rightGain.gain.value = 1;
|
||||
}
|
||||
this._balance = balance;
|
||||
},
|
||||
|
||||
getBalance: function() {
|
||||
return this._balance;
|
||||
},
|
||||
|
||||
toggleRepeat: function() {
|
||||
this._loop = !this._loop;
|
||||
},
|
||||
|
||||
toggleShuffle: function() {
|
||||
// Implement this when we support playlists
|
||||
},
|
||||
|
||||
/* Listeners */
|
||||
addEventListener: function(event, callback) {
|
||||
this._callbacks[event] = callback;
|
||||
},
|
||||
|
||||
seekToTime: function(time) {
|
||||
// Make sure we are within range
|
||||
time = Math.min(time, this.duration());
|
||||
time = Math.max(time, 0);
|
||||
this.play(time);
|
||||
},
|
||||
|
||||
// There is probably a more reasonable way to do this, rather than having
|
||||
// it always running.
|
||||
_draw: function() {
|
||||
if(this._playing) {
|
||||
this._updatePosition();
|
||||
this._callbacks.timeupdate();
|
||||
|
||||
// _updatePosition might have stopped the playing
|
||||
if(this._playing) {
|
||||
this._callbacks.visualizerupdate(this._analyser);
|
||||
}
|
||||
}
|
||||
window.requestAnimationFrame(this._draw.bind(this));
|
||||
},
|
||||
|
||||
_updatePosition: function() {
|
||||
this._position = this._context.currentTime - this._startTime;
|
||||
if(this._position >= this._buffer.duration && this._playing) {
|
||||
// Idealy we could use _source.loop, but it makes updating the position tricky
|
||||
if(this._loop) {
|
||||
this.play(0);
|
||||
} else {
|
||||
this.stop();
|
||||
this._callbacks.ended();
|
||||
}
|
||||
}
|
||||
/* Properties */
|
||||
duration: function() {
|
||||
return this._buffer.duration;
|
||||
},
|
||||
timeElapsed: function() {
|
||||
return this._position;
|
||||
},
|
||||
timeRemaining: function() {
|
||||
return this.duration() - this.timeElapsed();
|
||||
},
|
||||
percentComplete: function() {
|
||||
return (this.timeElapsed() / this.duration()) * 100;
|
||||
},
|
||||
channels: function() {
|
||||
if (!this._buffer) {
|
||||
return 0;
|
||||
}
|
||||
return this._buffer.numberOfChannels;
|
||||
},
|
||||
sampleRate: function() {
|
||||
return this._buffer.sampleRate;
|
||||
},
|
||||
|
||||
/* Actions */
|
||||
previous: function() {
|
||||
// Implement this when we support playlists
|
||||
},
|
||||
play: function(position) {
|
||||
if (this._playing) {
|
||||
// So we don't get a race condition with _position getting overwritten
|
||||
this.pause();
|
||||
}
|
||||
if (this._buffer) {
|
||||
this._source = this._context.createBufferSource();
|
||||
this._source.buffer = this._buffer;
|
||||
this._source.connect(this._analyser);
|
||||
this._source.connect(this._chanSplit);
|
||||
|
||||
this._position = typeof position !== 'undefined' ? position : this._position;
|
||||
this._startTime = this._context.currentTime - this._position;
|
||||
this._source.start(0, this._position);
|
||||
this._playing = true;
|
||||
this._callbacks.playing();
|
||||
}
|
||||
},
|
||||
pause: function() {
|
||||
if (!this._playing) {
|
||||
return;
|
||||
}
|
||||
this._silence();
|
||||
this._updatePosition();
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
this._silence();
|
||||
this._position = 0;
|
||||
},
|
||||
|
||||
_silence: function() {
|
||||
if (this._source) {
|
||||
this._source.stop(0);
|
||||
this._source = null;
|
||||
}
|
||||
this._playing = false;
|
||||
},
|
||||
|
||||
/* Actions with arguments */
|
||||
seekToPercentComplete: function(percent) {
|
||||
var seekTime = this.duration() * (percent / 100);
|
||||
this.seekToTime(seekTime);
|
||||
},
|
||||
|
||||
// From 0-1
|
||||
setVolume: function(volume) {
|
||||
this._gainNode.gain.value = volume;
|
||||
},
|
||||
|
||||
getVolume: function() {
|
||||
return this._gainNode.gain.value;
|
||||
},
|
||||
|
||||
// From -100 to 100
|
||||
setBalance: function(balance) {
|
||||
var changeVal = Math.abs(balance) / 100;
|
||||
|
||||
// Hack for Firefox. Having either channel set to 0 seems to revert us
|
||||
// to equal balance.
|
||||
changeVal = changeVal - 0.00000001;
|
||||
|
||||
if (balance > 0) { // Right
|
||||
this._leftGain.gain.value = 1 - changeVal;
|
||||
this._rightGain.gain.value = 1;
|
||||
} else if (balance < 0) { // Left
|
||||
this._leftGain.gain.value = 1;
|
||||
this._rightGain.gain.value = 1 - changeVal;
|
||||
} else { // Center
|
||||
this._leftGain.gain.value = 1;
|
||||
this._rightGain.gain.value = 1;
|
||||
}
|
||||
this._balance = balance;
|
||||
},
|
||||
|
||||
getBalance: function() {
|
||||
return this._balance;
|
||||
},
|
||||
|
||||
toggleRepeat: function() {
|
||||
this._loop = !this._loop;
|
||||
},
|
||||
|
||||
toggleShuffle: function() {
|
||||
// Implement this when we support playlists
|
||||
},
|
||||
|
||||
/* Listeners */
|
||||
addEventListener: function(event, callback) {
|
||||
this._callbacks[event] = callback;
|
||||
},
|
||||
|
||||
seekToTime: function(time) {
|
||||
// Make sure we are within range
|
||||
time = Math.min(time, this.duration());
|
||||
time = Math.max(time, 0);
|
||||
this.play(time);
|
||||
},
|
||||
|
||||
// There is probably a more reasonable way to do this, rather than having
|
||||
// it always running.
|
||||
_draw: function() {
|
||||
if (this._playing) {
|
||||
this._updatePosition();
|
||||
this._callbacks.timeupdate();
|
||||
|
||||
// _updatePosition might have stopped the playing
|
||||
if (this._playing) {
|
||||
this._callbacks.visualizerupdate(this._analyser);
|
||||
}
|
||||
}
|
||||
window.requestAnimationFrame(this._draw.bind(this));
|
||||
},
|
||||
|
||||
_updatePosition: function() {
|
||||
this._position = this._context.currentTime - this._startTime;
|
||||
if (this._position >= this._buffer.duration && this._playing) {
|
||||
// Idealy we could use _source.loop, but it makes updating the position tricky
|
||||
if (this._loop) {
|
||||
this.play(0);
|
||||
} else {
|
||||
this.stop();
|
||||
this._callbacks.ended();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,61 +1,61 @@
|
|||
// Single line text display that can animate and hold multiple registers
|
||||
define({
|
||||
node: null, // The DOM node of the display
|
||||
registers: {},
|
||||
init: function(font, node) {
|
||||
this.font = font;
|
||||
this.node = node;
|
||||
this._marqueeLoop();
|
||||
return this;
|
||||
},
|
||||
addRegister: function(key) {
|
||||
// Create element node
|
||||
var register = document.createElement("div");
|
||||
register.style.display = 'none';
|
||||
node: null, // The DOM node of the display
|
||||
registers: {},
|
||||
init: function(font, node) {
|
||||
this.font = font;
|
||||
this.node = node;
|
||||
this._marqueeLoop();
|
||||
return this;
|
||||
},
|
||||
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
|
||||
};
|
||||
},
|
||||
setRegisterText: function(register, text) {
|
||||
// Set text of register
|
||||
this.font.setNodeToString(this.registers[register].node, text);
|
||||
},
|
||||
hideAllRegisters: function() {
|
||||
for(var key in this.registers) {
|
||||
this.registers[key].node.style.display = 'none';
|
||||
}
|
||||
},
|
||||
showRegister: function(key) {
|
||||
this.hideAllRegisters();
|
||||
// Show the one register
|
||||
this.registers[key].node.style.display = 'block';
|
||||
},
|
||||
startRegisterMarquee: function(key) {
|
||||
this.registers[key].marquee = true;
|
||||
},
|
||||
pauseRegisterMarquee: function(key) {
|
||||
this.registers[key].marquee = false;
|
||||
},
|
||||
_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);
|
||||
this.node.appendChild(register);
|
||||
this.registers[key] = {
|
||||
node: register,
|
||||
text: '',
|
||||
marquee: false
|
||||
};
|
||||
},
|
||||
setRegisterText: function(register, text) {
|
||||
// Set text of register
|
||||
this.font.setNodeToString(this.registers[register].node, text);
|
||||
},
|
||||
hideAllRegisters: function() {
|
||||
for (var key in this.registers) {
|
||||
this.registers[key].node.style.display = 'none';
|
||||
}
|
||||
},
|
||||
showRegister: function(key) {
|
||||
this.hideAllRegisters();
|
||||
// Show the one register
|
||||
this.registers[key].node.style.display = 'block';
|
||||
},
|
||||
startRegisterMarquee: function(key) {
|
||||
this.registers[key].marquee = true;
|
||||
},
|
||||
pauseRegisterMarquee: function(key) {
|
||||
this.registers[key].marquee = false;
|
||||
},
|
||||
_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);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,45 +1,45 @@
|
|||
// Custom object representing a file
|
||||
// `File` is already a builtin, so we use `MyFile`
|
||||
define([], function(){
|
||||
return function() {
|
||||
return function() {
|
||||
this.reader = new FileReader();
|
||||
this.url = null;
|
||||
this.fileReference = null;
|
||||
this.setUrl = function(url){
|
||||
this.url = url;
|
||||
this.url = url;
|
||||
};
|
||||
this.setFileReference = function(fileReference){
|
||||
this.fileReference = fileReference;
|
||||
this.fileReference = fileReference;
|
||||
};
|
||||
this.processBuffer = function(bufferHandler) {
|
||||
if(this.url) {
|
||||
var oReq = new XMLHttpRequest();
|
||||
oReq.open("GET", this.url, true);
|
||||
oReq.responseType = "arraybuffer";
|
||||
if (this.url) {
|
||||
var oReq = new XMLHttpRequest();
|
||||
oReq.open('GET', this.url, true);
|
||||
oReq.responseType = 'arraybuffer';
|
||||
|
||||
oReq.onload = function (oEvent) {
|
||||
var arrayBuffer = oReq.response; // Note: not oReq.responseText
|
||||
bufferHandler(arrayBuffer);
|
||||
};
|
||||
oReq.onload = function() {
|
||||
var arrayBuffer = oReq.response; // Note: not oReq.responseText
|
||||
bufferHandler(arrayBuffer);
|
||||
};
|
||||
|
||||
oReq.send(null);
|
||||
return;
|
||||
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);
|
||||
};
|
||||
} 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;
|
||||
}
|
||||
this.reader.readAsArrayBuffer(this.fileReference);
|
||||
return true;
|
||||
}
|
||||
|
||||
console.error('Tried to process an unpopulated file object');
|
||||
return false;
|
||||
console.error('Tried to process an unpopulated file object');
|
||||
return false;
|
||||
};
|
||||
};
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,171 +1,171 @@
|
|||
define([], function() {
|
||||
return [
|
||||
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: '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: '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: '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: '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: '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: '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: '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: '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: '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: '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: '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: [".lllama #title-bar"], x: 27, y: 61, width: 275, height: 14},
|
||||
{ selectors: [".lllama #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: '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: ['.lllama #title-bar'], x: 27, y: 61, width: 275, height: 14},
|
||||
{selectors: ['.lllama #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},
|
||||
]
|
||||
},
|
||||
];
|
||||
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}
|
||||
]
|
||||
}
|
||||
];
|
||||
});
|
||||
|
|
|
|||
158
js/skin.js
158
js/skin.js
|
|
@ -1,21 +1,21 @@
|
|||
// Dynamically set the css background images for all the sprites
|
||||
define([
|
||||
'skin-sprites',
|
||||
'font',
|
||||
'visualizer',
|
||||
'jszip.2.4.0.min'
|
||||
'skin-sprites',
|
||||
'font',
|
||||
'visualizer',
|
||||
'vendor/jszip.2.4.0.min'
|
||||
], function(
|
||||
SKIN_SPRITES,
|
||||
Font,
|
||||
Visualizer,
|
||||
JSZip
|
||||
SKIN_SPRITES,
|
||||
Font,
|
||||
Visualizer,
|
||||
JSZip
|
||||
) {
|
||||
return {
|
||||
return {
|
||||
font: Font,
|
||||
init: function(visualizerNode, analyser) {
|
||||
this._createNewStyleNode();
|
||||
this.visualizer = Visualizer.init(visualizerNode, analyser);
|
||||
return this;
|
||||
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
|
||||
|
|
@ -23,97 +23,97 @@ return {
|
|||
|
||||
// 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));
|
||||
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 zip = new JSZip(buffer);
|
||||
document.getElementById('time').classList.remove('ex');
|
||||
|
||||
var promisedCssRules = this._skinSprites.map(function(spriteObj) {
|
||||
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);
|
||||
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 !== undefined) {
|
||||
this.completedCallback();
|
||||
}
|
||||
}.bind(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 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.visualizer.setColors(colors);
|
||||
}
|
||||
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];
|
||||
// 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);
|
||||
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, reject) {
|
||||
var imageObj = new Image();
|
||||
imageObj.src = src;
|
||||
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;
|
||||
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);
|
||||
};
|
||||
});
|
||||
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);
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
});
|
||||
|
|
|
|||
308
js/visualizer.js
308
js/visualizer.js
|
|
@ -1,163 +1,163 @@
|
|||
/* Use Canvas to recreate the simple Winamp visualizer */
|
||||
define({
|
||||
init: function(canvasNode, analyser) {
|
||||
this.canvas = canvasNode;
|
||||
this.analyser = analyser;
|
||||
this.canvasCtx = this.canvas.getContext("2d");
|
||||
this.canvasCtx.imageSmoothingEnabled= false;
|
||||
this.width = this.canvas.width * 1; // Cast to int
|
||||
this.height = this.canvas.height * 1; // Cast to int
|
||||
this.colors = []; // skin.js fills this from viscolors.txt
|
||||
this.NONE = 0;
|
||||
this.OSCILLOSCOPE = 1;
|
||||
this.BAR = 2;
|
||||
this.bufferLength = null;
|
||||
this.dataArray = null;
|
||||
this.setStyle(this.BAR);
|
||||
init: function(canvasNode, analyser) {
|
||||
this.canvas = canvasNode;
|
||||
this.analyser = analyser;
|
||||
this.canvasCtx = this.canvas.getContext('2d');
|
||||
this.canvasCtx.imageSmoothingEnabled = false;
|
||||
this.width = this.canvas.width * 1; // Cast to int
|
||||
this.height = this.canvas.height * 1; // Cast to int
|
||||
this.colors = []; // skin.js fills this from viscolors.txt
|
||||
this.NONE = 0;
|
||||
this.OSCILLOSCOPE = 1;
|
||||
this.BAR = 2;
|
||||
this.bufferLength = null;
|
||||
this.dataArray = null;
|
||||
this.setStyle(this.BAR);
|
||||
|
||||
// Off-screen canvas for pre-rendering the background
|
||||
this.bgCanvas = document.createElement('canvas');
|
||||
this.bgCanvas.width = this.width;
|
||||
this.bgCanvas.height = this.height;
|
||||
this.bgCanvasCtx = this.bgCanvas.getContext("2d");
|
||||
// Off-screen canvas for pre-rendering the background
|
||||
this.bgCanvas = document.createElement('canvas');
|
||||
this.bgCanvas.width = this.width;
|
||||
this.bgCanvas.height = this.height;
|
||||
this.bgCanvasCtx = this.bgCanvas.getContext('2d');
|
||||
|
||||
// Off-screen canvas for pre-rendering a single bar gradient
|
||||
this.barCanvas = document.createElement('canvas');
|
||||
this.barCanvas.width = 6;
|
||||
this.barCanvas.height = 32;
|
||||
this.barCanvasCtx = this.barCanvas.getContext("2d");
|
||||
return this;
|
||||
},
|
||||
// Off-screen canvas for pre-rendering a single bar gradient
|
||||
this.barCanvas = document.createElement('canvas');
|
||||
this.barCanvas.width = 6;
|
||||
this.barCanvas.height = 32;
|
||||
this.barCanvasCtx = this.barCanvas.getContext('2d');
|
||||
return this;
|
||||
},
|
||||
|
||||
clear: function() {
|
||||
this.canvasCtx.drawImage(this.bgCanvas, 0, 0);
|
||||
},
|
||||
clear: function() {
|
||||
this.canvasCtx.drawImage(this.bgCanvas, 0, 0);
|
||||
},
|
||||
|
||||
setColors: function(colors) {
|
||||
this.colors = colors;
|
||||
this.preRenderBg();
|
||||
this.preRenderBar();
|
||||
},
|
||||
setColors: function(colors) {
|
||||
this.colors = colors;
|
||||
this.preRenderBg();
|
||||
this.preRenderBar();
|
||||
},
|
||||
|
||||
// Pre-render the background grid
|
||||
preRenderBg: function() {
|
||||
this.bgCanvasCtx.fillStyle = this.colors[0];
|
||||
this.bgCanvasCtx.fillRect(0,0,this.width, this.height);
|
||||
this.bgCanvasCtx.fillStyle = this.colors[1];
|
||||
for(x = 0; x < this.width; x += 4) {
|
||||
for(y = 2; y < this.height; y += 4) {
|
||||
this.bgCanvasCtx.fillRect(x,y,2,2);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Pre-render the bar gradient
|
||||
preRenderBar: function() {
|
||||
this.barCanvasCtx.fillStyle = this.colors[23];
|
||||
this.barCanvasCtx.fillRect(0,0,6,2);
|
||||
for(var i = 0; i <= 15; i++) {
|
||||
var colorNumber = 17 - i;
|
||||
this.barCanvasCtx.fillStyle = this.colors[colorNumber];
|
||||
var y = 32 - (i*2);
|
||||
this.barCanvasCtx.fillRect(0,y,6,2);
|
||||
}
|
||||
// If we are paused when the skin changes, we will keep the vis colors
|
||||
// until we paint again. For now we can just clear the current frame so
|
||||
// we don't end up with a clashing visual.
|
||||
this.clear();
|
||||
},
|
||||
|
||||
setStyle: function(style) {
|
||||
this.style = style;
|
||||
if(this.style == this.OSCILLOSCOPE) {
|
||||
this.analyser.fftSize = 2048;
|
||||
this.bufferLength = this.analyser.fftSize;
|
||||
this.dataArray = new Uint8Array(this.bufferLength);
|
||||
} else if(this.style == this.BAR) {
|
||||
this.analyser.fftSize = 64; // Must be a power of two
|
||||
// Number of bins/bars we get
|
||||
this.bufferLength = this.analyser.frequencyBinCount;
|
||||
this.dataArray = new Uint8Array(this.bufferLength);
|
||||
}
|
||||
},
|
||||
|
||||
paintFrame: function() {
|
||||
this.clear();
|
||||
if(this.style == this.OSCILLOSCOPE) {
|
||||
return this._paintOscilloscopeFrame();
|
||||
} else if(this.style == this.BAR) {
|
||||
return this._paintBarFrame();
|
||||
}
|
||||
},
|
||||
|
||||
_paintOscilloscopeFrame: function() {
|
||||
// Return the average value in a slice of dataArray
|
||||
function sliceAverage(dataArray, sliceWidth, sliceNumber) {
|
||||
var start = sliceWidth * sliceNumber;
|
||||
var end = start + sliceWidth;
|
||||
var sum = 0;
|
||||
for(var i = start; i < end; i++) {
|
||||
sum += dataArray[i];
|
||||
}
|
||||
return sum / sliceWidth;
|
||||
}
|
||||
|
||||
this.analyser.getByteTimeDomainData(this.dataArray);
|
||||
|
||||
// 2 because we're shrinking the canvas by 2
|
||||
this.canvasCtx.lineWidth = 2;
|
||||
|
||||
// Just use one of the viscolors for now
|
||||
this.canvasCtx.strokeStyle = this.colors[18];
|
||||
|
||||
// Since dataArray has more values than we have pixels to display, we
|
||||
// have to average several dataArray values per pixel. We call these
|
||||
// groups slices.
|
||||
//
|
||||
// We use the 2x scale here since we only want to plot values for
|
||||
// "real" pixels.
|
||||
var sliceWidth = Math.floor(this.bufferLength / this.width) * 2;
|
||||
|
||||
// The max amplitude is half the height
|
||||
var h = this.height / 2;
|
||||
|
||||
this.canvasCtx.beginPath();
|
||||
|
||||
// Iterate over the width of the canvas in "real" pixels.
|
||||
for (var j = 0; j <= this.width/2; j++) {
|
||||
amplitude = sliceAverage(this.dataArray, sliceWidth, j);
|
||||
percentAmplitude = amplitude / 128; // dataArray gives us bytes
|
||||
y = percentAmplitude * h;
|
||||
x = j * 2;
|
||||
|
||||
// Canvas coordinates are in the middle of the pixel by default.
|
||||
// When we want to draw pixel perfect lines, we will need to
|
||||
// account for that here
|
||||
if(x === 0) {
|
||||
this.canvasCtx.moveTo(x, y);
|
||||
} else {
|
||||
this.canvasCtx.lineTo(x, y);
|
||||
}
|
||||
}
|
||||
this.canvasCtx.stroke();
|
||||
},
|
||||
|
||||
_paintBarFrame: function() {
|
||||
var printBar = function(x, height) {
|
||||
height = Math.round(height) * 2;
|
||||
if(height > 0) {
|
||||
y = 32 - height;
|
||||
// Draw the gray peak line
|
||||
this.canvasCtx.drawImage(this.barCanvas, 0, 0, 6, 2, x, y - 2, 6, 2);
|
||||
// Draw the gradient
|
||||
this.canvasCtx.drawImage(this.barCanvas, 0, y, 6, height, x, y, 6, height);
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
this.analyser.getByteFrequencyData(this.dataArray);
|
||||
for(j = 0; j < this.bufferLength; j++) {
|
||||
height = this.dataArray[j] * (14/256);
|
||||
printBar(j*8, height);
|
||||
}
|
||||
// Pre-render the background grid
|
||||
preRenderBg: function() {
|
||||
this.bgCanvasCtx.fillStyle = this.colors[0];
|
||||
this.bgCanvasCtx.fillRect(0, 0, this.width, this.height);
|
||||
this.bgCanvasCtx.fillStyle = this.colors[1];
|
||||
for (var x = 0; x < this.width; x += 4) {
|
||||
for (var y = 2; y < this.height; y += 4) {
|
||||
this.bgCanvasCtx.fillRect(x, y, 2, 2);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Pre-render the bar gradient
|
||||
preRenderBar: function() {
|
||||
this.barCanvasCtx.fillStyle = this.colors[23];
|
||||
this.barCanvasCtx.fillRect(0, 0, 6, 2);
|
||||
for (var i = 0; i <= 15; i++) {
|
||||
var colorNumber = 17 - i;
|
||||
this.barCanvasCtx.fillStyle = this.colors[colorNumber];
|
||||
var y = 32 - (i * 2);
|
||||
this.barCanvasCtx.fillRect(0, y, 6, 2);
|
||||
}
|
||||
// If we are paused when the skin changes, we will keep the vis colors
|
||||
// until we paint again. For now we can just clear the current frame so
|
||||
// we don't end up with a clashing visual.
|
||||
this.clear();
|
||||
},
|
||||
|
||||
setStyle: function(style) {
|
||||
this.style = style;
|
||||
if (this.style === this.OSCILLOSCOPE) {
|
||||
this.analyser.fftSize = 2048;
|
||||
this.bufferLength = this.analyser.fftSize;
|
||||
this.dataArray = new Uint8Array(this.bufferLength);
|
||||
} else if (this.style === this.BAR) {
|
||||
this.analyser.fftSize = 64; // Must be a power of two
|
||||
// Number of bins/bars we get
|
||||
this.bufferLength = this.analyser.frequencyBinCount;
|
||||
this.dataArray = new Uint8Array(this.bufferLength);
|
||||
}
|
||||
},
|
||||
|
||||
paintFrame: function() {
|
||||
this.clear();
|
||||
if (this.style === this.OSCILLOSCOPE) {
|
||||
return this._paintOscilloscopeFrame();
|
||||
} else if (this.style === this.BAR) {
|
||||
return this._paintBarFrame();
|
||||
}
|
||||
},
|
||||
|
||||
_paintOscilloscopeFrame: function() {
|
||||
// Return the average value in a slice of dataArray
|
||||
function sliceAverage(dataArray, sliceWidth, sliceNumber) {
|
||||
var start = sliceWidth * sliceNumber;
|
||||
var end = start + sliceWidth;
|
||||
var sum = 0;
|
||||
for (var i = start; i < end; i++) {
|
||||
sum += dataArray[i];
|
||||
}
|
||||
return sum / sliceWidth;
|
||||
}
|
||||
|
||||
this.analyser.getByteTimeDomainData(this.dataArray);
|
||||
|
||||
// 2 because we're shrinking the canvas by 2
|
||||
this.canvasCtx.lineWidth = 2;
|
||||
|
||||
// Just use one of the viscolors for now
|
||||
this.canvasCtx.strokeStyle = this.colors[18];
|
||||
|
||||
// Since dataArray has more values than we have pixels to display, we
|
||||
// have to average several dataArray values per pixel. We call these
|
||||
// groups slices.
|
||||
//
|
||||
// We use the 2x scale here since we only want to plot values for
|
||||
// "real" pixels.
|
||||
var sliceWidth = Math.floor(this.bufferLength / this.width) * 2;
|
||||
|
||||
// The max amplitude is half the height
|
||||
var h = this.height / 2;
|
||||
|
||||
this.canvasCtx.beginPath();
|
||||
|
||||
// Iterate over the width of the canvas in "real" pixels.
|
||||
for (var j = 0; j <= this.width / 2; j++) {
|
||||
var amplitude = sliceAverage(this.dataArray, sliceWidth, j);
|
||||
var percentAmplitude = amplitude / 128; // dataArray gives us bytes
|
||||
var y = percentAmplitude * h;
|
||||
var x = j * 2;
|
||||
|
||||
// Canvas coordinates are in the middle of the pixel by default.
|
||||
// When we want to draw pixel perfect lines, we will need to
|
||||
// account for that here
|
||||
if (x === 0) {
|
||||
this.canvasCtx.moveTo(x, y);
|
||||
} else {
|
||||
this.canvasCtx.lineTo(x, y);
|
||||
}
|
||||
}
|
||||
this.canvasCtx.stroke();
|
||||
},
|
||||
|
||||
_paintBarFrame: function() {
|
||||
var printBar = function(x, height) {
|
||||
height = Math.round(height) * 2;
|
||||
if (height > 0) {
|
||||
var y = 32 - height;
|
||||
// Draw the gray peak line
|
||||
this.canvasCtx.drawImage(this.barCanvas, 0, 0, 6, 2, x, y - 2, 6, 2);
|
||||
// Draw the gradient
|
||||
this.canvasCtx.drawImage(this.barCanvas, 0, y, 6, height, x, y, 6, height);
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
this.analyser.getByteFrequencyData(this.dataArray);
|
||||
for (var j = 0; j < this.bufferLength; j++) {
|
||||
var height = this.dataArray[j] * (14 / 256);
|
||||
printBar(j * 8, height);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
340
js/winamp.js
340
js/winamp.js
|
|
@ -1,303 +1,291 @@
|
|||
// UI and App logic
|
||||
define([
|
||||
'main-window',
|
||||
'window-manager',
|
||||
'skin',
|
||||
'media',
|
||||
'my-file'
|
||||
'main-window',
|
||||
'window-manager',
|
||||
'skin',
|
||||
'media',
|
||||
'my-file'
|
||||
], function(
|
||||
MainWindow,
|
||||
WindowManager,
|
||||
Skin,
|
||||
Media,
|
||||
MyFile
|
||||
MainWindow,
|
||||
WindowManager,
|
||||
Skin,
|
||||
Media,
|
||||
MyFile
|
||||
) {
|
||||
return {
|
||||
return {
|
||||
init: function(options) {
|
||||
this.fileInput = document.createElement('input');
|
||||
this.fileInput.type = 'file';
|
||||
this.fileInput.style.display = 'none';
|
||||
this.fileInput = document.createElement('input');
|
||||
this.fileInput.type = 'file';
|
||||
this.fileInput.style.display = 'none';
|
||||
|
||||
this.windowManager = WindowManager;
|
||||
this.media = Media.init();
|
||||
this.skin = Skin.init(document.getElementById('visualizer'), this.media._analyser);
|
||||
this.state = '';
|
||||
this.windowManager = WindowManager;
|
||||
this.media = Media.init();
|
||||
this.skin = Skin.init(document.getElementById('visualizer'), this.media._analyser);
|
||||
this.state = '';
|
||||
|
||||
this.mainWindow = MainWindow.init(this);
|
||||
this.mainWindow = MainWindow.init(this);
|
||||
|
||||
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.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.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.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._registerListeners();
|
||||
return this;
|
||||
this._registerListeners();
|
||||
return this;
|
||||
},
|
||||
|
||||
_registerListeners: function() {
|
||||
var self = this;
|
||||
var self = this;
|
||||
|
||||
this.windowManager.registerWindow(this.mainWindow);
|
||||
this.windowManager.registerWindow(this.mainWindow);
|
||||
|
||||
this.media.addEventListener('timeupdate', function() {
|
||||
window.dispatchEvent(self.events.timeUpdated);
|
||||
});
|
||||
this.media.addEventListener('timeupdate', function() {
|
||||
window.dispatchEvent(self.events.timeUpdated);
|
||||
});
|
||||
|
||||
this.media.addEventListener('visualizerupdate', function(analyser) {
|
||||
self.skin.visualizer.paintFrame(self.visualizerStyle, analyser);
|
||||
});
|
||||
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('ended', function() {
|
||||
self.skin.visualizer.clear();
|
||||
self.setState('stop');
|
||||
});
|
||||
|
||||
this.media.addEventListener('waiting', function() {
|
||||
window.dispatchEvent(self.events.startWaiting);
|
||||
});
|
||||
this.media.addEventListener('waiting', function() {
|
||||
window.dispatchEvent(self.events.startWaiting);
|
||||
});
|
||||
|
||||
this.media.addEventListener('stopWaiting', function() {
|
||||
window.dispatchEvent(self.events.stopWaiting);
|
||||
});
|
||||
this.media.addEventListener('stopWaiting', function() {
|
||||
window.dispatchEvent(self.events.stopWaiting);
|
||||
});
|
||||
|
||||
this.media.addEventListener('playing', function() {
|
||||
self.setState('play');
|
||||
});
|
||||
this.media.addEventListener('playing', function() {
|
||||
self.setState('play');
|
||||
});
|
||||
|
||||
this.fileInput.onchange = function(e){
|
||||
self.loadFromFileReference(e.target.files[0]);
|
||||
};
|
||||
this.fileInput.onchange = function(e){
|
||||
self.loadFromFileReference(e.target.files[0]);
|
||||
};
|
||||
},
|
||||
|
||||
/* Functions */
|
||||
setState: function(state) {
|
||||
this.state = state;
|
||||
window.dispatchEvent(this.events.changeState);
|
||||
this.state = state;
|
||||
window.dispatchEvent(this.events.changeState);
|
||||
},
|
||||
|
||||
getState: function() {
|
||||
return this.state;
|
||||
return this.state;
|
||||
},
|
||||
|
||||
getDuration: function() {
|
||||
return this.media.duration();
|
||||
return this.media.duration();
|
||||
},
|
||||
|
||||
getTimeRemaining: function() {
|
||||
return this.media.timeRemaining();
|
||||
return this.media.timeRemaining();
|
||||
},
|
||||
|
||||
getTimeElapsed: function() {
|
||||
return this.media.timeElapsed();
|
||||
return this.media.timeElapsed();
|
||||
},
|
||||
|
||||
getPercentComplete: function() {
|
||||
return this.media.percentComplete();
|
||||
return this.media.percentComplete();
|
||||
},
|
||||
|
||||
getChannelCount: function() {
|
||||
return this.media.channels();
|
||||
return this.media.channels();
|
||||
},
|
||||
|
||||
getVolume: function() {
|
||||
return Math.round(this.media.getVolume() * 100);
|
||||
return Math.round(this.media.getVolume() * 100);
|
||||
},
|
||||
|
||||
seekToPercentComplete: function(percent) {
|
||||
this.media.seekToPercentComplete(percent);
|
||||
this.media.seekToPercentComplete(percent);
|
||||
},
|
||||
|
||||
toggleTimeMode: function() {
|
||||
window.dispatchEvent(this.events.toggleTimeMode);
|
||||
},
|
||||
|
||||
previous: function(num) {
|
||||
// Jump back num tracks
|
||||
// Not yet supported
|
||||
window.dispatchEvent(this.events.toggleTimeMode);
|
||||
},
|
||||
|
||||
play: function() {
|
||||
if(this.getState() === 'play'){
|
||||
this.media.stop();
|
||||
}
|
||||
this.media.play();
|
||||
this.setState('play');
|
||||
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');
|
||||
}
|
||||
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');
|
||||
},
|
||||
|
||||
next: function(num) {
|
||||
// Jump back num tracks
|
||||
// Not yet supported
|
||||
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);
|
||||
// Ensure volume does not go out of bounds
|
||||
volume = Math.max(volume, 0);
|
||||
volume = Math.min(volume, 100);
|
||||
|
||||
var percent = volume / 100;
|
||||
var percent = volume / 100;
|
||||
|
||||
this.media.setVolume(percent);
|
||||
window.dispatchEvent(this.events.volumeChanged);
|
||||
this.media.setVolume(percent);
|
||||
window.dispatchEvent(this.events.volumeChanged);
|
||||
},
|
||||
|
||||
incrementVolumeBy: function(ammount) {
|
||||
this.setVolume((this.media.getVolume() * 100) + ammount);
|
||||
this.setVolume((this.media.getVolume() * 100) + ammount);
|
||||
},
|
||||
|
||||
toggleDoubledMode: function() {
|
||||
window.dispatchEvent(this.events.doubledModeToggled);
|
||||
window.dispatchEvent(this.events.doubledModeToggled);
|
||||
},
|
||||
|
||||
// From -100 to 100
|
||||
setBalance: function(balance) {
|
||||
this.media.setBalance(balance);
|
||||
window.dispatchEvent(this.events.balanceChanged);
|
||||
this.media.setBalance(balance);
|
||||
window.dispatchEvent(this.events.balanceChanged);
|
||||
},
|
||||
|
||||
getBalance: function() {
|
||||
return this.media.getBalance();
|
||||
return this.media.getBalance();
|
||||
},
|
||||
|
||||
seekForwardBy: function(seconds) {
|
||||
this.media.seekToTime(this.media.timeElapsed() + seconds);
|
||||
window.dispatchEvent(self.events.timeUpdated);
|
||||
this.media.seekToTime(this.media.timeElapsed() + seconds);
|
||||
window.dispatchEvent(self.events.timeUpdated);
|
||||
},
|
||||
|
||||
toggleRepeat: function() {
|
||||
this.media.toggleRepeat();
|
||||
window.dispatchEvent(this.events.repeatToggled);
|
||||
this.media.toggleRepeat();
|
||||
window.dispatchEvent(this.events.repeatToggled);
|
||||
},
|
||||
|
||||
toggleShuffle: function() {
|
||||
this.media.toggleShuffle();
|
||||
this.mainWindow.toggleShuffle();
|
||||
this.media.toggleShuffle();
|
||||
this.mainWindow.toggleShuffle();
|
||||
},
|
||||
|
||||
toggleLlama: function() {
|
||||
window.dispatchEvent(this.events.llamaToggled);
|
||||
window.dispatchEvent(this.events.llamaToggled);
|
||||
},
|
||||
|
||||
close: function() {
|
||||
window.dispatchEvent(this.events.close);
|
||||
this.media.stop();
|
||||
this.setState('stop'); // Currently unneeded
|
||||
window.dispatchEvent(this.events.close);
|
||||
this.media.stop();
|
||||
this.setState('stop'); // Currently unneeded
|
||||
},
|
||||
|
||||
openFileDialog: function() {
|
||||
this.fileInput.click();
|
||||
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));
|
||||
}
|
||||
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));
|
||||
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));
|
||||
this.setLoadingState();
|
||||
this.skin.setSkinByFile(file, this.unsetLoadingState.bind(this));
|
||||
},
|
||||
|
||||
setLoadingState: function() {
|
||||
window.dispatchEvent(this.events.startLoading);
|
||||
window.dispatchEvent(this.events.startLoading);
|
||||
},
|
||||
|
||||
unsetLoadingState: function() {
|
||||
window.dispatchEvent(this.events.stopLoading);
|
||||
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();
|
||||
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);
|
||||
}
|
||||
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));
|
||||
// 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);
|
||||
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)
|
||||
];
|
||||
},
|
||||
};
|
||||
return [
|
||||
Math.floor(minutes / 10),
|
||||
Math.floor(minutes % 10),
|
||||
Math.floor(seconds / 10),
|
||||
Math.floor(seconds % 10)
|
||||
];
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,58 +1,59 @@
|
|||
define({
|
||||
registerWindow: function(win) {
|
||||
body = win.body;
|
||||
handle = win.handle;
|
||||
registerWindow: function(win) {
|
||||
var body = win.body;
|
||||
var handle = win.handle;
|
||||
|
||||
// Make window dragable
|
||||
handle.addEventListener('mousedown',function(e){
|
||||
if(e.target !== this) {
|
||||
// Prevent going into drag mode when clicking any of the title
|
||||
// bar's icons by making sure the click was made directly on the
|
||||
// titlebar
|
||||
return true; }
|
||||
// Make window dragable
|
||||
handle.addEventListener('mousedown', function(e){
|
||||
if (e.target !== this) {
|
||||
// Prevent going into drag mode when clicking any of the title
|
||||
// bar's icons by making sure the click was made directly on the
|
||||
// titlebar
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the element was 'absolutely' positioned we could simply use
|
||||
// offsetLeft / offsetTop however the element is 'relatively'
|
||||
// positioned so we're using style.left. parseInt is used to remove the
|
||||
// 'px' postfix from the value
|
||||
var winStartLeft = parseInt(body.offsetLeft || 0,10),
|
||||
winStartTop = parseInt(body.offsetTop || 0,10);
|
||||
// If the element was 'absolutely' positioned we could simply use
|
||||
// offsetLeft / offsetTop however the element is 'relatively'
|
||||
// positioned so we're using style.left. parseInt is used to remove the
|
||||
// 'px' postfix from the value
|
||||
var winStartLeft = parseInt(body.offsetLeft || 0, 10),
|
||||
winStartTop = parseInt(body.offsetTop || 0, 10);
|
||||
|
||||
// Get starting mouse position
|
||||
var mouseStartLeft = e.clientX,
|
||||
mouseStartTop = e.clientY;
|
||||
// Get starting mouse position
|
||||
var mouseStartLeft = e.clientX,
|
||||
mouseStartTop = e.clientY;
|
||||
|
||||
// Mouse move handler function while mouse is down
|
||||
function handleMove(e) {
|
||||
// Get current mouse position
|
||||
var mouseLeft = e.clientX,
|
||||
mouseTop = e.clientY;
|
||||
// Mouse move handler function while mouse is down
|
||||
function handleMove(moveEvent) {
|
||||
// Get current mouse position
|
||||
var mouseLeft = moveEvent.clientX,
|
||||
mouseTop = moveEvent.clientY;
|
||||
|
||||
// Calculate difference offsets
|
||||
var diffLeft = mouseLeft-mouseStartLeft,
|
||||
diffTop = mouseTop-mouseStartTop;
|
||||
// Calculate difference offsets
|
||||
var diffLeft = mouseLeft - mouseStartLeft,
|
||||
diffTop = mouseTop - mouseStartTop;
|
||||
|
||||
// These margins were only useful for centering the div, now we
|
||||
// don't need them
|
||||
body.style.marginLeft = "0px";
|
||||
body.style.marginTop = "0px";
|
||||
// Move window to new position
|
||||
body.style.left = (winStartLeft+diffLeft)+"px";
|
||||
body.style.top = (winStartTop+diffTop)+"px";
|
||||
}
|
||||
// These margins were only useful for centering the div, now we
|
||||
// don't need them
|
||||
body.style.marginLeft = '0px';
|
||||
body.style.marginTop = '0px';
|
||||
// Move window to new position
|
||||
body.style.left = (winStartLeft + diffLeft) + 'px';
|
||||
body.style.top = (winStartTop + diffTop) + 'px';
|
||||
}
|
||||
|
||||
// Mouse button up
|
||||
function handleUp() {
|
||||
removeListeners();
|
||||
}
|
||||
// Mouse button up
|
||||
function handleUp() {
|
||||
removeListeners();
|
||||
}
|
||||
|
||||
function removeListeners() {
|
||||
window.removeEventListener('mousemove',handleMove);
|
||||
window.removeEventListener('mouseup',handleUp);
|
||||
}
|
||||
function removeListeners() {
|
||||
window.removeEventListener('mousemove', handleMove);
|
||||
window.removeEventListener('mouseup', handleUp);
|
||||
}
|
||||
|
||||
window.addEventListener('mousemove',handleMove);
|
||||
window.addEventListener('mouseup',handleUp);
|
||||
});
|
||||
}
|
||||
window.addEventListener('mousemove', handleMove);
|
||||
window.addEventListener('mouseup', handleUp);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue