Adds a repeat directive to manage a 3-state repeat button

It will cycle through "repeat the playing queue", "repeat the playing song" and "don't repeat anything".

- Adds a custom "loop-single" icon based on iconic's loop icon.
- Removes the LoopQueue setting which is now the "queue" value of Repeat
- Moves the Repeat setting to player-service.js. That way, it does not depend on saving the settings in any way. It also allows us to remove a dependency from player-service.js.
- Adds a player css which will hold all the player-related styles
- Removes the former png icons (we can always find them back thanks to Git)
This commit is contained in:
Hyzual 2015-05-14 21:41:20 +02:00
parent acd2ae67f8
commit efa604265d
19 changed files with 263 additions and 112 deletions

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="8" width="8" version="1.1" viewBox="0 0 8 8">
<path d="m6.002 0v1.0015c-1.7031 0.00345-3.4067-0.006907-5.1095 0.0052-0.54821 0.0425-0.96298 0.5856-0.8995 1.1241v0.87368h1.0015v-1.0015h5.0075v1.0015l2.0031-1.5021c-0.6677-0.5008-1.3356-1.0015-2.0031-1.5024zm0.086036 3.1845c-1.0618-0.075578-1.8347 0.96819-1.9789 1.823h-2.1132v-1.0015l-2.003 1.5023 2.003 1.5023v-1.0015h2.404c0.54902 1.1213 2.228 1.3563 3.0632 0.42782 0.45961-0.43735 0.56857-1.0803 0.54177-1.6849v-0.74587c-0.2578 0.0273-0.4787-0.0007-0.5932-0.2906-0.3515-0.3384-0.836-0.5324-1.3237-0.531zm0.066497 0.47534c0.29389-0.085418 0.27048 0.17533 0.25848 0.36687v2.0667c0.16688 0.00839 0.34015-0.017266 0.5028 0.01371 0.12894 0.19311 0.050198 0.52465-0.2269 0.43624h-1.3868c-0.1886-0.1444-0.0957-0.5528 0.1898-0.4499 0.1002-0.0281 0.3133 0.0567 0.3423-0.0426v-1.8196c-0.1923 0.0909-0.367 0.2378-0.5739 0.2842-0.1524-0.206-0.0164-0.4607 0.2048-0.5449 0.1713-0.097 0.3231-0.2382 0.5077-0.3049 0.0603-0.0053 0.1223-0.006 0.1817-0.0058z"/>
</svg>

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 B

View file

@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><symbol viewBox="0 0 8 8" id="loop-single"><path d="M6.002 0v1.002C4.3 1.004 2.595.995.892 1.006c-.548.042-.962.585-.9 1.124v.874H.996v-1h5.007v1l2.003-1.502c-.668-.5-1.336-1-2.003-1.502zm.086 3.184c-1.062-.075-1.835.97-1.98 1.823H1.997v-1l-2.003 1.5 2.003 1.504v-1H4.4c.55 1.12 2.228 1.355 3.063.427.46-.437.57-1.08.542-1.685v-.746c-.258.027-.48 0-.593-.29-.352-.34-.836-.533-1.324-.53zm.067.476c.293-.086.27.175.258.367v2.066c.167.01.34-.017.503.014.13.193.05.525-.227.436H5.3c-.188-.144-.096-.552.19-.45.1-.028.313.057.342-.042V4.23c-.192.092-.367.24-.574.285-.152-.206-.016-.46.205-.544.17-.096.323-.238.508-.304.06-.006.122-.006.182-.006z"/></symbol></svg>

After

Width:  |  Height:  |  Size: 782 B

View file

@ -18,6 +18,10 @@
<link href="styles/Style.css" rel="stylesheet" type="text/css" data-name="main" /> <link href="styles/Style.css" rel="stylesheet" type="text/css" data-name="main" />
<link href="styles/Mobile.css" rel="stylesheet" type="text/css" data-name="main" /> <link href="styles/Mobile.css" rel="stylesheet" type="text/css" data-name="main" />
<link href="" rel="stylesheet" type="text/css" data-name="theme" /> <link href="" rel="stylesheet" type="text/css" data-name="theme" />
<!-- build:css(app) styles/concat.min.css -->
<link rel="stylesheet" href="player/player.css" />
<link rel="stylesheet" href="player/repeat-directive/repeat-directive.css" />
<!-- endbuild -->
</head> </head>
<body ui-keypress="{'32 179': 'togglePause($event)', '43 61 187': 'turnVolumeUp($event)', '45 95 189': 'turnVolumeDown($event)'}" ui-keydown="{'right 176': 'nextTrack($event)', 'left 177': 'previousTrack($event)'}"> <body ui-keypress="{'32 179': 'togglePause($event)', '43 61 187': 'turnVolumeUp($event)', '45 95 189': 'turnVolumeDown($event)'}" ui-keydown="{'right 176': 'nextTrack($event)', 'left 177': 'previousTrack($event)'}">
<div id="container"> <div id="container">
@ -112,6 +116,7 @@
<script src="player/player.js"></script> <script src="player/player.js"></script>
<script src="player/player-directive.js"></script> <script src="player/player-directive.js"></script>
<script src="player/player-service.js"></script> <script src="player/player-service.js"></script>
<script src="player/repeat-directive/repeat-directive.js"></script>
<script src="queue/queue.js"></script> <script src="queue/queue.js"></script>
<script src="common/filters.js"></script> <script src="common/filters.js"></script>
<script src="common/directives.js"></script> <script src="common/directives.js"></script>

View file

@ -32,7 +32,6 @@ describe("jplayer directive", function() {
return $delegate; return $delegate;
}); });
$provide.value('globals', mockGlobals); $provide.value('globals', mockGlobals);
$provide.constant('jamstashVersion', '1.0.0');
}); });
spyOn($.fn, "jPlayer").and.callThrough(); spyOn($.fn, "jPlayer").and.callThrough();

View file

@ -3,9 +3,9 @@
* *
* Manages the player and playing queue. Use it to play a song, go to next track or add songs to the queue. * Manages the player and playing queue. Use it to play a song, go to next track or add songs to the queue.
*/ */
angular.module('jamstash.player.service', ['jamstash.settings.service', 'angular-underscore/utils']) angular.module('jamstash.player.service', ['angular-underscore/utils'])
.factory('player', ['globals', function (globals) { .factory('player', [function () {
'use strict'; 'use strict';
var playerVolume = 1.0; var playerVolume = 1.0;
@ -18,6 +18,10 @@ angular.module('jamstash.player.service', ['jamstash.settings.service', 'angular
pauseSong: false, pauseSong: false,
restartSong: false, restartSong: false,
loadSong: false, loadSong: false,
settings: {
repeat: "none",
repeatValues: ["queue", "song", "none"]
},
play: function (song) { play: function (song) {
// Find the song's index in the queue, if it's in there // Find the song's index in the queue, if it's in there
@ -56,11 +60,11 @@ angular.module('jamstash.player.service', ['jamstash.settings.service', 'angular
// Called from the player directive at the end of the current song // Called from the player directive at the end of the current song
songEnded: function () { songEnded: function () {
if (globals.settings.Repeat) { if (player.settings.repeat === "song") {
// repeat current track // repeat current track
player.restart(); player.restart();
} else if (player.isLastSongPlaying() === true) { } else if (player.isLastSongPlaying() === true) {
if (globals.settings.LoopQueue) { if (player.settings.repeat === "queue") {
// Loop to first track in queue // Loop to first track in queue
player.playFirstSong(); player.playFirstSong();
} }

View file

@ -1,21 +1,13 @@
describe("Player service -", function() { describe("Player service -", function() {
'use strict'; 'use strict';
var player, mockGlobals, firstSong, secondSong, thirdSong, newSong; var player, firstSong, secondSong, thirdSong, newSong;
beforeEach(function() { beforeEach(function() {
// We redefine globals because in some tests we need to alter the settings module('jamstash.player.service');
mockGlobals = {
settings: {
Repeat: false,
LoopQueue: false
}
};
module('jamstash.player.service', function ($provide) {
$provide.value('globals', mockGlobals);
});
inject(function (_player_) { inject(function (_player_) {
player = _player_; player = _player_;
}); });
player.settings.repeat = "none";
}); });
describe("Given that I have 3 songs in my playing queue,", function() { describe("Given that I have 3 songs in my playing queue,", function() {
@ -206,9 +198,9 @@ describe("Player service -", function() {
expect(player.nextTrack).toHaveBeenCalled(); expect(player.nextTrack).toHaveBeenCalled();
}); });
it("and that the 'Repeat song' setting is true, when the current song ends, it restarts it", function() { it("and that the 'Repeat' setting is set to 'song', when the current song ends, it restarts it", function() {
spyOn(player, "restart"); spyOn(player, "restart");
mockGlobals.settings.Repeat = true; player.settings.repeat = "song";
player.songEnded(); player.songEnded();
@ -220,9 +212,9 @@ describe("Player service -", function() {
player._playingIndex = 2; player._playingIndex = 2;
}); });
it("if the 'Repeat queue' setting is true, it plays the first song of the queue", function() { it("if the 'Repeat' setting is set to 'queue', it plays the first song of the queue", function() {
spyOn(player, "playFirstSong"); spyOn(player, "playFirstSong");
mockGlobals.settings.LoopQueue = true; player.settings.repeat = "queue";
player.songEnded(); player.songEnded();

9
app/player/player.css Normal file
View file

@ -0,0 +1,9 @@
.icon {
height: 12px;
width: 12px;
display: block;
}
.icon-wrap {
margin: 4px 2px;
float: left;
}

View file

@ -17,7 +17,7 @@
</div> </div>
<div id="songdetails"> <div id="songdetails">
<div id="coverart"> <div id="coverart">
<a ng-click="fancyboxOpenImage(getPlayingSong().coverartfull)"> <a ng-click="fancyboxOpenImage(getPlayingSong().coverartfull)">
<img ng-src="{{getPlayingSong().coverartthumb}}" src="images/albumdefault_60.jpg" height="30" width="30" /> <img ng-src="{{getPlayingSong().coverartthumb}}" src="images/albumdefault_60.jpg" height="30" width="30" />
</a> </a>
</div> </div>
@ -27,7 +27,7 @@
</ul> </ul>
<div id="songdetails_controls"> <div id="songdetails_controls">
<a href="" class="jukebox" title="Jukebox Mode [Beta]" ng-click="toggleSetting('Jukebox')" ng-class="{'hoverSelected': !settings.Jukebox }"></a> <a href="" class="jukebox" title="Jukebox Mode [Beta]" ng-click="toggleSetting('Jukebox')" ng-class="{'hoverSelected': !settings.Jukebox }"></a>
<a href="" class="loop" title="Repeat" ng-click="toggleSetting('Repeat')" ng-class="{'hoverSelected': !settings.Repeat }"></a> <jamstash-repeat selected-value="playerSettings.repeat" values="playerSettings.repeatValues"></jamstash-repeat>
<a href="" id="action_SaveProgress" class="lock" title="Save Track Position: On" ng-show="settings.SaveTrackPosition"></a> <a href="" id="action_SaveProgress" class="lock" title="Save Track Position: On" ng-show="settings.SaveTrackPosition"></a>
<a title="Favorite" href="" ng-class="{'favorite': getPlayingSong().starred, 'rate': !getPlayingSong().starred}" ng-click="toggleStar(getPlayingSong())" stop-event="click"></a> <a title="Favorite" href="" ng-class="{'favorite': getPlayingSong().starred, 'rate': !getPlayingSong().starred}" ng-click="toggleStar(getPlayingSong())" stop-event="click"></a>
<a href="" id="action_Mute" class="mute" title="Mute"></a> <a href="" id="action_Mute" class="mute" title="Mute"></a>

View file

@ -5,13 +5,15 @@
* Also provides the currently playing song's info through the scope so it can be displayed next to * Also provides the currently playing song's info through the scope so it can be displayed next to
* the player controls. * the player controls.
*/ */
angular.module('jamstash.player.controller', ['jamstash.player.service', 'jamstash.player.directive']) angular.module('jamstash.player.controller', ['jamstash.player.service', 'jamstash.player.directive', 'jamstash.repeat.directive'])
.controller('PlayerController', ['$scope', 'player', 'globals', .controller('PlayerController', ['$scope', 'player', 'globals',
function ($scope, player, globals) { function ($scope, player, globals) {
'use strict'; 'use strict';
$scope.getPlayingSong = player.getPlayingSong; $scope.getPlayingSong = player.getPlayingSong;
$scope.settings = globals.settings;
$scope.playerSettings = player.settings;
$scope.play = function () { $scope.play = function () {
if (globals.settings.Jukebox) { if (globals.settings.Jukebox) {

View file

@ -1,36 +1,62 @@
describe("Player controller", function() { describe("Player controller", function() {
'use strict'; 'use strict';
var player, scope; var player, scope, mockGlobals;
beforeEach(function() { beforeEach(function() {
// We redefine globals because in some tests we need to alter the settings
mockGlobals = {
settings: {
Jukebox: false
}
};
module('jamstash.player.controller'); module('jamstash.player.controller');
inject(function ($controller, $rootScope) { inject(function ($controller, $rootScope) {
scope = $rootScope.$new(); scope = $rootScope.$new();
player = jasmine.createSpyObj("player", ["getPlayingSong", "previousTrack", "nextTrack"]); player = jasmine.createSpyObj("player", [
"getPlayingSong",
"previousTrack",
"nextTrack",
"getRepeatValues",
"togglePause"
]);
$controller('PlayerController', { $controller('PlayerController', {
$scope: scope, $scope: scope,
player: player player: player,
globals: mockGlobals
}); });
}); });
}); });
it("When I get the currently playing song, it asks the player service", function() { it("When I play a song, the player service will be called", function() {
scope.play();
expect(player.togglePause).toHaveBeenCalled();
});
it("when I pause a song, the player service will be called", function() {
scope.pause();
expect(player.togglePause).toHaveBeenCalled();
});
it("When I get the currently playing song, the player service will be called", function() {
scope.getPlayingSong(); scope.getPlayingSong();
expect(player.getPlayingSong).toHaveBeenCalled(); expect(player.getPlayingSong).toHaveBeenCalled();
}); });
it("When I get the previous track, it uses the player service", function() { it("When I get the previous track, the player service will be called", function() {
scope.previousTrack(); scope.previousTrack();
expect(player.previousTrack).toHaveBeenCalled(); expect(player.previousTrack).toHaveBeenCalled();
}); });
it("When I get the next track, it uses the player service", function() { it("When I get the next track, the player service will be called", function() {
scope.nextTrack(); scope.nextTrack();
expect(player.nextTrack).toHaveBeenCalled(); expect(player.nextTrack).toHaveBeenCalled();

View file

@ -0,0 +1,6 @@
.icon-loop-queue, .icon-loop-single {
fill: #fff;
}
.icon-loop-none {
fill: #adadad;
}

View file

@ -0,0 +1,20 @@
<a href="javascript:void(0)" class="icon-wrap" ng-click="cycleRepeat()">
<span title="Repeat the playing queue" ng-show="selectedValue === 'queue'">
<svg class="icon">
<title>Repeat the playing queue</title>
<use xlink:href="images/sprite/iconic.svg#loop" class="icon-loop-queue"></use>
</svg>
</span>
<span title="Repeat the current song" ng-show="selectedValue === 'song'">
<svg class="icon">
<title>Repeat the current song</title>
<use xlink:href="images/sprite/jamstash-sprite.svg#loop-single" class="icon-loop-single"></use>
</svg>
</span>
<span title="Disable repeat" ng-show="selectedValue === 'none'">
<svg class="icon">
<title>Disable repeat</title>
<use xlink:href="images/sprite/iconic.svg#loop" class="icon-loop-none"></use>
</svg>
</span>
</a>

View file

@ -0,0 +1,29 @@
/**
* jamstash.repeat.directive Module
*
* Triple-state button to toggle between repeating the entire playing queue, the current playing song and disabling repeat
*/
angular.module('jamstash.repeat.directive', ['jamstash.notifications'])
.directive('jamstashRepeat', ['notifications', function (notifications) {
'use strict';
return {
restrict: 'E',
templateUrl: 'player/repeat-directive/repeat-directive.html',
replace: true,
scope: {
selectedValue: '=',
values: '='
},
link: function ($scope) {
$scope.$watch('selectedValue', function (newVal) {
$scope.selectedIndex = $scope.values.indexOf(newVal);
});
$scope.cycleRepeat = function () {
$scope.selectedIndex = ($scope.selectedIndex + 1) % $scope.values.length;
$scope.selectedValue = $scope.values[$scope.selectedIndex];
notifications.updateMessage('Repeat ' + $scope.selectedValue, true);
};
}
};
}]);

View file

@ -0,0 +1,69 @@
describe("repeat directive", function() {
'use strict';
var element, scope, isolateScope, notifications, mockGlobals;
beforeEach(module ('templates'));
beforeEach(function() {
// We redefine globals because in some tests we need to alter the settings
mockGlobals = {
settings: {
RepeatValues: ["queue", "song", "none"],
Repeat: "none"
}
};
module('jamstash.repeat.directive', function($provide) {
$provide.value('globals', mockGlobals);
// Mock the notifications service
$provide.decorator('notifications', function () {
return jasmine.createSpyObj("notifications", ["updateMessage"]);
});
});
inject(function ($rootScope, $compile, _notifications_) {
notifications = _notifications_;
// Compile the directive
scope = $rootScope.$new();
scope.settings = mockGlobals.settings;
element = '<jamstash-repeat selected-value="settings.Repeat" values="settings.RepeatValues"></jamstash-repeat>';
element = $compile(element)(scope);
scope.$digest();
isolateScope = element.isolateScope();
});
});
it("Given that the Repeat setting was set to 'none', when I cycle through the values, then the Repeat setting will be set to 'queue'", function() {
isolateScope.cycleRepeat();
isolateScope.$apply();
expect(mockGlobals.settings.Repeat).toBe('queue');
});
it("Given that the Repeat setting was set to 'queue', when I cycle through the values, then the Repeat setting will be set to 'song'", function() {
mockGlobals.settings.Repeat = 'queue';
isolateScope.$apply();
isolateScope.cycleRepeat();
isolateScope.$apply();
expect(mockGlobals.settings.Repeat).toBe('song');
});
it("Given that the Repeat setting was set to 'song', when I cycle through the values, then the Repeat setting will be set to 'none", function() {
mockGlobals.settings.Repeat = 'song';
isolateScope.$apply();
isolateScope.cycleRepeat();
isolateScope.$apply();
expect(mockGlobals.settings.Repeat).toBe('none');
});
it("When I cycle through the values, then the user will be notified with the new value", function() {
isolateScope.cycleRepeat();
isolateScope.$apply();
expect(notifications.updateMessage).toHaveBeenCalledWith('Repeat queue', true);
});
});

View file

@ -4,7 +4,7 @@
* Manages the playing queue. Gives access to the player service's queue-related functions, * Manages the playing queue. Gives access to the player service's queue-related functions,
* like adding, removing and shuffling the queue. * like adding, removing and shuffling the queue.
*/ */
angular.module('jamstash.queue.controller', ['jamstash.player.service']) angular.module('jamstash.queue.controller', ['jamstash.player.service', 'jamstash.settings.service'])
.controller('QueueController', ['$scope', 'globals', 'player', .controller('QueueController', ['$scope', 'globals', 'player',
function ($scope, globals, player) { function ($scope, globals, player) {

View file

@ -33,9 +33,6 @@
<div class="inputwrap"><input type="checkbox" id="AutoPlay" name="AutoPlay" value="1" title="When the Queue has ended, load random songs" ng-model="settings.AutoPlay" /></div> <div class="inputwrap"><input type="checkbox" id="AutoPlay" name="AutoPlay" value="1" title="When the Queue has ended, load random songs" ng-model="settings.AutoPlay" /></div>
<label for="AutoPlay">Auto Play</label> <label for="AutoPlay">Auto Play</label>
<div class="clear"></div> <div class="clear"></div>
<div class="inputwrap"><input type="checkbox" id="LoopQueue" name="LoopQueue" value="1" title="When the Queue has ended, start from beginning" ng-model="settings.LoopQueue" /></div>
<label for="LoopQueue">Loop Queue</label>
<div class="clear"></div>
<div class="inputwrap"><input type="checkbox" id="HideAZ" name="HideAZ" value="1" title="Hide A-Z Artist Picker (Tablet/Touch friendly feature)" ng-model="settings.HideAZ" /></div> <div class="inputwrap"><input type="checkbox" id="HideAZ" name="HideAZ" value="1" title="Hide A-Z Artist Picker (Tablet/Touch friendly feature)" ng-model="settings.HideAZ" /></div>
<label for="HideAZ">Hide A-Z</label> <label for="HideAZ">Hide A-Z</label>
<div class="clear"></div> <div class="clear"></div>

View file

@ -1,14 +1,14 @@
html, body { height: 100%; width: 100%; } html, body { height: 100%; width: 100%; }
body body
{ {
font: 100% Trebuchet MS, Arial, Helvetica, sans-serif; font: 100% Trebuchet MS, Arial, Helvetica, sans-serif;
background: #fafafa; background: #fafafa;
margin: 0; margin: 0;
padding: 0; padding: 0;
text-align: center; text-align: center;
color: #5b5b4e; color: #5b5b4e;
} }
img img
{ {
border: none; border: none;
background: none; background: none;
@ -87,7 +87,7 @@ span.apiversion
font-size: 10px; font-size: 10px;
opacity: .8; opacity: .8;
} }
#nav #nav
{ {
height: 54px; height: 54px;
/*width: 270px;*/ /*width: 270px;*/
@ -96,18 +96,18 @@ span.apiversion
left: 50px; left: 50px;
z-index: 99; z-index: 99;
} }
#nav ul #nav ul
{ {
list-style-type: none; list-style-type: none;
padding: 0; padding: 0;
margin: 0 0 0 4px; margin: 0 0 0 4px;
} }
#nav li #nav li
{ {
float: left; float: left;
margin: 0 1px 0 0; margin: 0 1px 0 0;
} }
#nav a #nav a
{ {
display: block; display: block;
padding: 8px 12px; padding: 8px 12px;
@ -122,34 +122,34 @@ span.apiversion
border-left: 1px solid #D5D5D5; border-left: 1px solid #D5D5D5;
border-bottom: none; border-bottom: none;
} }
#nav a:hover #nav a:hover
{ {
color: #545454; color: #545454;
border: 1px solid #D5D5D5; border: 1px solid #D5D5D5;
border-bottom: none; border-bottom: none;
} }
#nav a.active #nav a.active
{ {
color: #545454; color: #545454;
background: #ffffff; background: #ffffff;
border: 1px solid #CBCBCB; border: 1px solid #CBCBCB;
border-bottom: none; border-bottom: none;
padding: 8px 12px 9px 12px; padding: 8px 12px 9px 12px;
box-shadow: -2px 1px 2px -2px rgba(0, 0, 0, 0.25); box-shadow: -2px 1px 2px -2px rgba(0, 0, 0, 0.25);
} }
#nav a.active:hover #nav a.active:hover
{ {
color: #545454; color: #545454;
border: 1px solid #CBCBCB; border: 1px solid #CBCBCB;
border-bottom: none; border-bottom: none;
} }
#nav a img #nav a img
{ {
display: block; display: block;
margin: 3px 0 4px 1px; margin: 3px 0 4px 1px;
} }
#nav a.active img #nav a.active img
{ {
display: block; display: block;
margin: 3px 0 4px 1px; margin: 3px 0 4px 1px;
@ -161,12 +161,12 @@ span.apiversion
left: 12px; left: 12px;
width: 32px; width: 32px;
height: 32px; height: 32px;
background: url('../images/favicon_32x32.png') no-repeat 0 0; background: url('../images/favicon_32x32.png') no-repeat 0 0;
cursor: pointer; cursor: pointer;
} }
#jslogo:hover #jslogo:hover
{ {
background: url('../images/favicon_32x32.png') no-repeat 0 1px; background: url('../images/favicon_32x32.png') no-repeat 0 1px;
} }
.pagetabcenter .pagetabcenter
{ {
@ -196,14 +196,14 @@ span.apiversion
right: 7px; right: 7px;
width: 54px; width: 54px;
height: 36px; height: 36px;
background: url('../images/subsonic_36.png') no-repeat 5px 3px; background: url('../images/subsonic_36.png') no-repeat 5px 3px;
cursor: pointer; cursor: pointer;
} }
#sslogo:hover #sslogo:hover
{ {
background: url('../images/subsonic_dn_36.png') no-repeat 5px 2px; background: url('../images/subsonic_dn_36.png') no-repeat 5px 2px;
} }
#content #content
{ {
background: #EDEDED; background: #EDEDED;
width: 100%; width: 100%;
@ -219,7 +219,7 @@ span.apiversion
{ {
margin: 0; margin: 0;
} }
.smcolumn .smcolumn
{ {
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
@ -242,7 +242,7 @@ span.apiversion
position: fixed; position: fixed;
left: 264px; left: 264px;
} }
.lgcolumn .lgcolumn
{ {
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
@ -271,7 +271,7 @@ span.apiversion
background: #fff; background: #fff;
border-top: 1px solid #cbcbcb; border-top: 1px solid #cbcbcb;
border-bottom: 1px solid #cbcbcb; border-bottom: 1px solid #cbcbcb;
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
position: fixed; position: fixed;
top: 40px; top: 40px;
@ -280,7 +280,7 @@ span.apiversion
*/ */
margin-bottom: -42px; margin-bottom: -42px;
} }
#SideBar #SideBar
{ {
display: none; display: none;
min-height: 100%; min-height: 100%;
@ -407,7 +407,7 @@ span.apiversion
border-radius: 4px 4px 4px 4px; border-radius: 4px 4px 4px 4px;
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1); box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
opacity: 0.95; opacity: 0.95;
cursor: pointer; cursor: pointer;
} }
.pager .pager
{ {
@ -420,7 +420,7 @@ span.apiversion
{ {
margin: 0 5px 0 0; margin: 0 5px 0 0;
} }
.pager a.next .pager a.next
{ {
margin: 0 0 0 5px; margin: 0 0 0 5px;
} }
@ -455,7 +455,7 @@ span.apiversion
} }
#welcome { #welcome {
display: none; display: none;
background: rgba(0, 0, 0, 0.25); background: rgba(0, 0, 0, 0.25);
border: solid 1px #a5a5a5; border: solid 1px #a5a5a5;
border-radius: 2px; border-radius: 2px;
-webkit-border-radius: 2px; -webkit-border-radius: 2px;
@ -638,13 +638,13 @@ ul.tablist li a:hover
{ {
color: #bbb; color: #bbb;
} }
#BreadCrumb #BreadCrumb
{ {
float: left; float: left;
margin: 16px 0 0 0; margin: 16px 0 0 0;
padding: 2px 0; padding: 2px 0;
color: #AEAEA7; color: #AEAEA7;
border-radius: .4em; border-radius: .4em;
} }
#BreadCrumb img #BreadCrumb img
{ {
@ -666,7 +666,7 @@ ul.tablist li a:hover
{ {
text-decoration: underline; text-decoration: underline;
} }
#BreadCrumbs .crumb #BreadCrumbs .crumb
{ {
float: left; float: left;
} }
@ -695,14 +695,14 @@ ul.songlist .album
ul.songlist .album a ul.songlist .album a
{ {
color: #7EA8D5; color: #7EA8D5;
text-decoration: none; text-decoration: none;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
font-size: 11px; font-size: 11px;
} }
ul.songlist .album a:hover ul.songlist .album a:hover
{ {
text-decoration: underline; text-decoration: underline;
} }
ul.songlist .album .description ul.songlist .album .description
{ {
@ -772,11 +772,11 @@ ul.songlist .album a.remove
} }
ul.songlist .album a.rate ul.songlist .album a.rate
{ {
background: url('../images/star_lgo_12x12.png') 4px center no-repeat; background: url('../images/star_lgo_12x12.png') 4px center no-repeat;
} }
ul.songlist .album a.favorite ul.songlist .album a.favorite
{ {
background: url('../images/star_yo_12x12.png') 4px center no-repeat; background: url('../images/star_yo_12x12.png') 4px center no-repeat;
} }
ul.songlist .album a.info ul.songlist .album a.info
{ {
@ -822,7 +822,7 @@ ul.songlist li:hover .albumgrid .albumart img {
top: -4px; top: -4px;
left: -4px; left: -4px;
} }
ul.songlist .albumgrid .albuminfo ul.songlist .albumgrid .albuminfo
{ {
float: left; float: left;
margin: 0 10px; margin: 0 10px;
@ -845,7 +845,7 @@ ul.songlist .albumgrid .itemactions a
} }
ul.songlist .albumgrid .itemactions a:hover { ul.songlist .albumgrid .itemactions a:hover {
box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2); box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
} }
ul.songlist .row ul.songlist .row
{ {
cursor: pointer; cursor: pointer;
@ -855,11 +855,11 @@ ul.songlist .row
ul.songlist .row a ul.songlist .row a
{ {
color: #7EA8D5; color: #7EA8D5;
text-decoration: none; text-decoration: none;
} }
ul.songlist .row a:hover ul.songlist .row a:hover
{ {
text-decoration: underline; text-decoration: underline;
} }
ul.songlist .row span.albumblock ul.songlist .row span.albumblock
{ {
@ -912,7 +912,7 @@ ul.songlist .row .albumblock img
height: 25px; height: 25px;
overflow: hidden; overflow: hidden;
} }
ul.songlist .row .artist ul.songlist .row .artist
{ {
width: 15%; width: 15%;
padding: 0 10px 0 0; padding: 0 10px 0 0;
@ -952,7 +952,7 @@ ul.songlist .row a.add:hover
} }
ul.songlist .row a.rate ul.songlist .row a.rate
{ {
background: url('../images/star_lgo_12x12.png') center 3px no-repeat; background: url('../images/star_lgo_12x12.png') center 3px no-repeat;
} }
ul.songlist .row a.rate:hover ul.songlist .row a.rate:hover
{ {
@ -960,7 +960,7 @@ ul.songlist .row a.rate:hover
} }
ul.songlist .row a.favorite ul.songlist .row a.favorite
{ {
background: url('../images/star_yo_12x12.png') center 3px no-repeat; background: url('../images/star_yo_12x12.png') center 3px no-repeat;
} }
ul.songlist .row a.remove ul.songlist .row a.remove
{ {
@ -1011,9 +1011,9 @@ ul.songlist li:hover
position: absolute; position: absolute;
/*top: 41px;*/ /*top: 41px;*/
top: 0; top: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
margin: 0; margin: 0;
overflow-y: scroll; overflow-y: scroll;
overflow-x: hidden; overflow-x: hidden;
} }
@ -1034,7 +1034,7 @@ ul.songlist li:hover
display: block; display: block;
} }
#AZIndex a:hover { text-decoration: underline; } #AZIndex a:hover { text-decoration: underline; }
#submenu_AZIndex #submenu_AZIndex
{ {
display: none; display: none;
width: 200px; width: 200px;
@ -1043,8 +1043,8 @@ ul.songlist li:hover
background: #f9f9f9; background: #f9f9f9;
border: 1px solid #C3C3C3; border: 1px solid #C3C3C3;
z-index: 999; z-index: 999;
} }
#submenu_AZIndex ul #submenu_AZIndex ul
{ {
list-style-type: none; list-style-type: none;
margin: 0; margin: 0;
@ -1062,7 +1062,7 @@ ul.songlist li:hover
text-decoration: none; text-decoration: none;
font-size: 24px; font-size: 24px;
padding: 0 5px 0 0; padding: 0 5px 0 0;
cursor: pointer; cursor: pointer;
} }
#submenu_AZIndex li a:hover #submenu_AZIndex li a:hover
{ {
@ -1097,7 +1097,7 @@ ul.songlist li:hover
padding: 0; padding: 0;
float: right; float: right;
} }
#globalactions #globalactions
{ {
position: absolute; position: absolute;
top: 0px; top: 0px;
@ -1110,7 +1110,7 @@ ul.songlist li:hover
margin: 5px; margin: 5px;
float: left; float: left;
} }
.submenu .submenu
{ {
position: fixed; position: fixed;
background: #fff; background: #fff;
@ -1140,7 +1140,7 @@ ul.songlist li:hover
width: 220px; width: 220px;
text-align: right; text-align: right;
} }
#submenu_CurrentPlaylist #submenu_CurrentPlaylist
{ {
width: 400px; width: 400px;
height: 200px; height: 200px;
@ -1264,7 +1264,7 @@ ul.songlist li:hover
#audiocontainer #audiocontainer
{ {
} }
.audiojs .audiojs
{ {
width: auto; width: auto;
height: 45px; height: 45px;
@ -1293,7 +1293,7 @@ ul.songlist li:hover
overflow: hidden; overflow: hidden;
cursor: pointer; cursor: pointer;
} }
.audiojs .progress .audiojs .progress
{ {
position: absolute; position: absolute;
top: 0px; top: 0px;
@ -1305,7 +1305,7 @@ ul.songlist li:hover
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #CCC), color-stop(0.5, #DDD), color-stop(0.51, #CCC), color-stop(1, #CCC)); background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #CCC), color-stop(0.5, #DDD), color-stop(0.51, #CCC), color-stop(1, #CCC));
background-image: -moz-linear-gradient(center top, #CCC 0%, #DDD 50%, #CCC 51%, #CCC 100%); background-image: -moz-linear-gradient(center top, #CCC 0%, #DDD 50%, #CCC 51%, #CCC 100%);
} }
.audiojs .loaded .audiojs .loaded
{ {
position: absolute; position: absolute;
top: 0px; top: 0px;
@ -1357,15 +1357,15 @@ ul.songlist li:hover
width: 322px; width: 322px;
margin: 6px; margin: 6px;
float: left; float: left;
cursor: pointer; cursor: pointer;
padding: 0; padding: 0;
visibility: hidden; visibility: hidden;
text-align: left; text-align: left;
color: #fff; color: #fff;
} }
#songdetails.hover #songdetails.hover
{ {
background: -webkit-gradient(linear, center top, center bottom, from(rgba(255, 255, 255, 0)), to(rgba(244, 244, 244, .2))); background: -webkit-gradient(linear, center top, center bottom, from(rgba(255, 255, 255, 0)), to(rgba(244, 244, 244, .2)));
} }
#songdetails .jp-volume-bar { #songdetails .jp-volume-bar {
overflow: hidden; overflow: hidden;
@ -1423,7 +1423,7 @@ ul.songlist li:hover
width: 12px; width: 12px;
margin: 2px; margin: 2px;
display: block; display: block;
background: url('../images/star_w_12x12.png') 0 center no-repeat; background: url('../images/star_w_12x12.png') 0 center no-repeat;
} }
#songdetails a.rate:hover #songdetails a.rate:hover
{ {
@ -1436,7 +1436,7 @@ ul.songlist li:hover
width: 12px; width: 12px;
margin: 2px; margin: 2px;
display: block; display: block;
background: url('../images/star_yo_12x12.png') 0 center no-repeat; background: url('../images/star_yo_12x12.png') 0 center no-repeat;
} }
#songdetails a.mute #songdetails a.mute
{ {
@ -1445,7 +1445,7 @@ ul.songlist li:hover
height: 12px; height: 12px;
width: 16px; width: 16px;
display: block; display: block;
background: url('../images/volume_mute_gl_12x9.png') 0 center no-repeat; background: url('../images/volume_mute_gl_12x9.png') 0 center no-repeat;
} }
#songdetails a.unmute #songdetails a.unmute
{ {
@ -1472,16 +1472,7 @@ ul.songlist li:hover
height: 12px; height: 12px;
width: 9px; width: 9px;
display: block; display: block;
background: url('../images/lock_stroke_gl_9x12.png') 0 center no-repeat; background: url('../images/lock_stroke_gl_9x12.png') 0 center no-repeat;
}
#songdetails a.loop
{
float: left;
margin: 4px 2px;
height: 9px;
width: 12px;
display: block;
background: url('../images/loop_alt3_w_12x9.png') 0 center no-repeat;
} }
#songdetails a.jukebox #songdetails a.jukebox
{ {
@ -1490,7 +1481,7 @@ ul.songlist li:hover
height: 9px; height: 9px;
width: 12px; width: 12px;
display: block; display: block;
background: url('../images/cloud_w_12x8.png') 0 center no-repeat; background: url('../images/cloud_w_12x8.png') 0 center no-repeat;
} }
#songdetails a.shuffle #songdetails a.shuffle
{ {
@ -1499,11 +1490,11 @@ ul.songlist li:hover
height: 11px; height: 11px;
width: 12px; width: 12px;
display: block; display: block;
background: url('../images/fork_gd_11x12.png') 0 center no-repeat; background: url('../images/fork_gd_11x12.png') 0 center no-repeat;
} }
#songdetails a.first #songdetails a.first
{ {
margin: 2px 2px 2px 0; margin: 2px 2px 2px 0;
} }
.vertshade { .vertshade {
position: relative; position: relative;
@ -1537,7 +1528,7 @@ ul.songlist li:hover
filter: alpha(opacity=80); filter: alpha(opacity=80);
} }
/* Settings */ /* Settings */
ul.preferences ul.preferences
{ {
list-style-type: none; list-style-type: none;
padding: 0; padding: 0;
@ -1555,7 +1546,7 @@ ul.preferences li.title
font-variant: small-caps; font-variant: small-caps;
padding: 0; padding: 0;
} }
ul.preferences li em ul.preferences li em
{ {
background: none repeat scroll 0 0 #D3D3D3; background: none repeat scroll 0 0 #D3D3D3;
border-radius: 4px 4px 4px 4px; border-radius: 4px 4px 4px 4px;
@ -1636,7 +1627,7 @@ a.buttonimg {
display: inline-block; display: inline-block;
} }
a.buttonimg:hover { a.buttonimg:hover {
opacity: .6; opacity: .6;
} }
a.buttonvertical { a.buttonvertical {
margin: 2px 0; margin: 2px 0;
@ -1681,7 +1672,7 @@ a.hoverSelected { opacity: .6; }
height: 8px; height: 8px;
} }
::-webkit-scrollbar-track { ::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 2px rgba(0,0,0,0.2); -webkit-box-shadow: inset 0 0 2px rgba(0,0,0,0.2);
/*-webkit-border-radius: 5px;*/ /*-webkit-border-radius: 5px;*/
background: #f2f2f2; background: #f2f2f2;
} }
@ -1833,5 +1824,3 @@ legend
font-variant: small-caps; font-variant: small-caps;
font-weight: bold; font-weight: bold;
} }