This commit is contained in:
nelsonlaquet 2013-08-15 18:49:20 -05:00
parent a80de5ea8f
commit d349fa1e6e
23 changed files with 274 additions and 88 deletions

View file

@ -51,6 +51,7 @@
public function getIndex() { public function getIndex() {
$page = 1; $page = 1;
$perPage = 60;
if (Input::has('page')) if (Input::has('page'))
$page = Input::get('page'); $page = Input::get('page');
@ -63,7 +64,7 @@
$this->applyFilters($query); $this->applyFilters($query);
$totalCount = $query->count(); $totalCount = $query->count();
$query->take(30)->skip(30 * ($page - 1)); $query->take($perPage)->skip(30 * ($page - 1));
$tracks = []; $tracks = [];
$ids = []; $ids = [];
@ -73,7 +74,7 @@
$ids[] = $track->id; $ids[] = $track->id;
} }
return Response::json(["tracks" => $tracks, "current_page" => $page, "total_pages" => ceil($totalCount / 30)], 200); return Response::json(["tracks" => $tracks, "current_page" => $page, "total_pages" => ceil($totalCount / $perPage)], 200);
} }
public function getOwned() { public function getOwned() {

View file

@ -47,6 +47,7 @@
new FileAsset('scripts/base/jquery-ui.js'), new FileAsset('scripts/base/jquery-ui.js'),
new FileAsset('scripts/base/jquery.cookie.js'), new FileAsset('scripts/base/jquery.cookie.js'),
new FileAsset('scripts/base/jquery.colorbox.js'), new FileAsset('scripts/base/jquery.colorbox.js'),
new FileAsset('scripts/base/jquery.viewport.js'),
new FileAsset('scripts/base/underscore.js'), new FileAsset('scripts/base/underscore.js'),
new FileAsset('scripts/base/moment.js'), new FileAsset('scripts/base/moment.js'),
new FileAsset('scripts/base/soundmanager2-nodebug.js'), new FileAsset('scripts/base/soundmanager2-nodebug.js'),

View file

@ -11,16 +11,16 @@
<div class="site-body"> <div class="site-body">
<ul class="sidebar" ng-controller="sidebar"> <ul class="sidebar" ng-controller="sidebar">
@if (Auth::check()) @if (Auth::check())
<li ng-class="{selected: $state.includes('home')}"><a href="/">Dashboard <i class="icon-home"></i></a></li> <li ng-class="{selected: stateIncludes('home')}"><a href="/">Dashboard <i class="icon-home"></i></a></li>
@else @else
<li ng-class="{selected: $state.includes('home')}"><a href="/">Home <i class="icon-home"></i></a></li> <li ng-class="{selected: stateIncludes('home')}"><a href="/">Home <i class="icon-home"></i></a></li>
@endif @endif
<li ng-class="{selected: $state.includes('content')}"> <li ng-class="{selected: stateIncludes('content')}">
<a href="/tracks">Discover <i class="icon-music"></i></a> <a href="/tracks">Discover <i class="icon-music"></i></a>
</li> </li>
@if (Auth::check()) @if (Auth::check())
<li ng-class="{selected: $state.includes('account-content') || isActive('/account')}"><a href="/account/tracks">Account <i class="icon-user"></i></a></li> <li ng-class="{selected: stateIncludes('account-content') || isActive('/account')}"><a href="/account/tracks">Account <i class="icon-user"></i></a></li>
@endif @endif
<li ng-class="{selected: isActive('/about')}"><a href="/about">Meta <i class="icon-info"></i></a></li> <li ng-class="{selected: isActive('/about')}"><a href="/about">Meta <i class="icon-info"></i></a></li>

View file

@ -5,6 +5,7 @@ angular.module('ponyfm').controller "application", [
$scope.$state = $state $scope.$state = $state
$scope.$stateParams = $stateParams $scope.$stateParams = $stateParams
$loadingElement = null $loadingElement = null
loadingStateName = null
$rootScope.safeApply = (fn) -> $rootScope.safeApply = (fn) ->
phase = $rootScope.$$phase phase = $rootScope.$$phase
@ -25,8 +26,20 @@ angular.module('ponyfm').controller "application", [
$loadingElement.removeClass 'loading' $loadingElement.removeClass 'loading'
$loadingElement = null $loadingElement = null
$scope.stateIncludes = (state) ->
if $loadingElement
newParts = state.split '.'
oldParts = loadingStateName.split '.'
for i in [0..newParts.length]
continue if !newParts[i]
return false if newParts[i] != oldParts[i]
return true
else
$state.includes(state)
statesPreloaded = {} statesPreloaded = {}
$scope.$on '$stateChangeStart', (e, newState, newParams, oldState) -> $scope.$on '$stateChangeStart', (e, newState, newParams, oldState, oldParams) ->
return if !oldState || !newState.controller return if !oldState || !newState.controller
preloader = window.pfm.preloaders[newState.controller] preloader = window.pfm.preloaders[newState.controller]
@ -37,6 +50,7 @@ angular.module('ponyfm').controller "application", [
return return
e.preventDefault() e.preventDefault()
loadingStateName = newState.name
selector = '' selector = ''
newParts = newState.name.split '.' newParts = newState.name.split '.'

View file

@ -9,7 +9,6 @@ angular.module('ponyfm').controller "track", [
($scope, tracks, $state, playlists, auth, favourites, $dialog) -> ($scope, tracks, $state, playlists, auth, favourites, $dialog) ->
tracks.fetch($state.params.id).done (trackResponse) -> tracks.fetch($state.params.id).done (trackResponse) ->
$scope.track = trackResponse.track $scope.track = trackResponse.track
$scope.trackArray = [$scope.track]
$scope.playlists = [] $scope.playlists = []

View file

@ -2,10 +2,8 @@ window.pfm.preloaders['tracks-list'] = [
'tracks', '$state' 'tracks', '$state'
(tracks, $state) -> (tracks, $state) ->
tracks.loadFilters().then(-> tracks.loadFilters().then(->
if !tracks.mainQuery.hasLoadedFilters
tracks.mainQuery.fromFilterString($state.params.filter) tracks.mainQuery.fromFilterString($state.params.filter)
if $state.params.page tracks.mainQuery.setPage $state.params.page || 1
tracks.mainQuery.setPage $state.params.page
tracks.mainQuery.fetch() tracks.mainQuery.fetch()
) )

View file

@ -23,6 +23,10 @@ angular.module('ponyfm').controller "tracks", [
$scope.query.setListFilter filter, id $scope.query.setListFilter filter, id
$state.transitionTo 'content.tracks.list', {filter: $scope.query.toFilterString()} $state.transitionTo 'content.tracks.list', {filter: $scope.query.toFilterString()}
$scope.clearFilter = (filter) ->
$scope.query.clearFilter filter
$state.transitionTo 'content.tracks.list', {filter: $scope.query.toFilterString()}
tracks.mainQuery.listen (searchResults) -> tracks.mainQuery.listen (searchResults) ->
$scope.tracks = searchResults.tracks $scope.tracks = searchResults.tracks
$scope.currentPage = parseInt(searchResults.current_page) $scope.currentPage = parseInt(searchResults.current_page)

View file

@ -4,6 +4,7 @@ angular.module('ponyfm').directive 'pfmPlayer', () ->
restrict: 'E' restrict: 'E'
templateUrl: '/templates/directives/player.html' templateUrl: '/templates/directives/player.html'
scope: {} scope: {}
replace: true
compile: (element) -> compile: (element) ->
$element = element $element = element

View file

@ -0,0 +1,28 @@
angular.module('ponyfm').directive 'pfmScrollRecorder', () ->
(scope, element, attrs) ->
timeout = null
onScroll = null
lastInView = null
element.scroll (e) ->
(window.clearTimeout timeout) if timeout
timeout = window.setTimeout (-> onScroll e), 500
onScroll = (e) -> scope.safeApply ->
items = element.find 'li:not(.empty)'
itemHeight = (items.eq 0).height()
itemsArray = items.get()
elementViewTop = element.offset().top
elementViewBottom = elementViewTop + element.height()
for i in [itemsArray.length - 1..0]
listItem = $ itemsArray[i]
listItemTop = listItem.offset().top + itemHeight
isInView = listItemTop > elementViewTop && listItemTop < elementViewBottom
if isInView
lastInView = listItem
break
scope.$emit 'element-in-view', angular.element(lastInView).scope()

View file

@ -0,0 +1,13 @@
angular.module('ponyfm').directive 'pfmTrackPlayer', () ->
restrict: 'E'
templateUrl: '/templates/directives/track-player.html'
scope:
track: '=track',
class: '@class'
controller: [
'$scope', 'player'
($scope, player) ->
$scope.play = () ->
player.playTracks [$scope.track], 0
]

View file

@ -12,7 +12,9 @@ angular.module('ponyfm').factory('tracks', [
constructor: (@availableFilters) -> constructor: (@availableFilters) ->
@filters = {} @filters = {}
@hasLoadedFilters = false @hasLoadedFilters = false
@resetFilters()
resetFilters: ->
_.each @availableFilters, (filter, name) => _.each @availableFilters, (filter, name) =>
if filter.type == 'single' if filter.type == 'single'
@filters[name] = _.find filter.values, (f) -> f.isDefault @filters[name] = _.find filter.values, (f) -> f.isDefault
@ -38,6 +40,19 @@ angular.module('ponyfm').factory('tracks', [
filter.selectedObject[id] = filterToAdd filter.selectedObject[id] = filterToAdd
filter.title = filterToAdd.title filter.title = filterToAdd.title
clearFilter: (type) ->
@cachedDef = null
@page = 1
filter = @availableFilters[type]
if filter.type == 'single'
@filters[type] = _.find filter.values, (f) -> f.isDefault
else
currentFilter = @filters[type]
currentFilter.selectedArray = []
currentFilter.selectedObject = {}
currentFilter.title = 'Any'
toggleListFilter: (type, id) -> toggleListFilter: (type, id) ->
@cachedDef = null @cachedDef = null
@page = 1 @page = 1
@ -82,8 +97,10 @@ angular.module('ponyfm').factory('tracks', [
fromFilterString: (str) -> fromFilterString: (str) ->
@hasLoadedFilters = true @hasLoadedFilters = true
return if !str @cachedDef = null
filters = str.split '!' @resetFilters()
filters = (str || "").split '!'
for filter in filters for filter in filters
parts = filter.split '-' parts = filter.split '-'
name = parts[0] name = parts[0]
@ -91,7 +108,8 @@ angular.module('ponyfm').factory('tracks', [
if @availableFilters[name].type == 'single' if @availableFilters[name].type == 'single'
filterToSet = _.find @availableFilters[name].values, (f) -> f.query == parts[1] filterToSet = _.find @availableFilters[name].values, (f) -> f.query == parts[1]
filterToSet = _.find @availableFilters[name].values, (f) -> f.isDefault if filterToSet == null filterToSet = (_.find @availableFilters[name].values, (f) -> f.isDefault) if filterToSet == null
@setFilter name, filterToSet
else else
@toggleListFilter name, id for id in _.rest parts, 1 @toggleListFilter name, id for id in _.rest parts, 1
@ -116,6 +134,7 @@ angular.module('ponyfm').factory('tracks', [
for listener in @listeners for listener in @listeners
listener tracks listener tracks
trackDef.resolve tracks trackDef.resolve tracks
trackDef.promise() trackDef.promise()
@ -150,7 +169,7 @@ angular.module('ponyfm').factory('tracks', [
type: 'single' type: 'single'
values: [ values: [
{title: 'Newest to Oldest', query: '', isDefault: true, filter: 'order=created_at,desc'}, {title: 'Newest to Oldest', query: '', isDefault: true, filter: 'order=created_at,desc'},
{title: 'Oldest to Newest', query: 'created_at,asc', isDefault: true, filter: 'order=created_at,asc'} {title: 'Oldest to Newest', query: 'created_at,asc', isDefault: false, filter: 'order=created_at,asc'}
] ]
self.filters.genres = self.filters.genres =

View file

@ -0,0 +1,58 @@
/*
* Viewport - jQuery selectors for finding elements in viewport
*
* Copyright (c) 2008-2009 Mika Tuupola
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/mit-license.php
*
* Project home:
* http://www.appelsiini.net/projects/viewport
*
*/
(function($) {
$.belowthefold = function(element, settings) {
var fold = $(window).height() + $(window).scrollTop();
return fold <= $(element).offset().top - settings.threshold;
};
$.abovethetop = function(element, settings) {
var top = $(window).scrollTop();
return top >= $(element).offset().top + $(element).height() - settings.threshold;
};
$.rightofscreen = function(element, settings) {
var fold = $(window).width() + $(window).scrollLeft();
return fold <= $(element).offset().left - settings.threshold;
};
$.leftofscreen = function(element, settings) {
var left = $(window).scrollLeft();
return left >= $(element).offset().left + $(element).width() - settings.threshold;
};
$.inviewport = function(element, settings) {
return !$.rightofscreen(element, settings) && !$.leftofscreen(element, settings) && !$.belowthefold(element, settings) && !$.abovethetop(element, settings);
};
$.extend($.expr[':'], {
"below-the-fold": function(a, i, m) {
return $.belowthefold(a, {threshold : 0});
},
"above-the-top": function(a, i, m) {
return $.abovethetop(a, {threshold : 0});
},
"left-of-screen": function(a, i, m) {
return $.leftofscreen(a, {threshold : 0});
},
"right-of-screen": function(a, i, m) {
return $.rightofscreen(a, {threshold : 0});
},
"in-viewport": function(a, i, m) {
return $.inviewport(a, {threshold : 0});
}
});
})(jQuery);

View file

@ -20,6 +20,34 @@
margin-right: 10px; margin-right: 10px;
line-height: normal; line-height: normal;
> .btn {
float: left;
display: block;
}
> .btn + .btn {
.transition(background 300ms ease-out);
display: none;
margin: 0px;
}
&.has-filter {
> .btn {
background: @pfm-purple;
color: #fff;
}
> .btn + .btn {
display: block;
background: darken(@pfm-purple, 20%);
&:hover {
background: darken(@pfm-purple, 40%);
}
}
}
&.open { &.open {
> .btn { > .btn {
background: @pfm-purple; background: @pfm-purple;
@ -320,7 +348,7 @@ html {
li.active a { li.active a {
background: @pfm-purple; background: @pfm-purple;
color: #ddd; color: #fff;
} }
} }

View file

@ -7,14 +7,12 @@ html, body {
html body { html body {
height: 100%; height: 100%;
background: @pfm-dark-grey; background: #444;
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
} }
header, .site-body { header, .site-body {
.box-shadow(0 0 7px rgba(0, 0, 0, .3)); .box-shadow(0 0 7px rgba(0, 0, 0, .6));
max-width: 1200px;
margin: auto;
} }
header { header {
@ -50,9 +48,9 @@ header {
} }
.sidebar { .sidebar {
background: @pfm-light-grey;
width: @pfm-sidebar-size; width: @pfm-sidebar-size;
height: 100%; height: 100%;
background: @pfm-light-grey;
float: left; float: left;
list-style: none; list-style: none;
padding: 0px; padding: 0px;
@ -68,6 +66,7 @@ header {
background: #fff; background: #fff;
> a { > a {
cursor: default;
color: #000; color: #000;
} }
} }

View file

@ -2,6 +2,8 @@
@import-once 'mixins'; @import-once 'mixins';
@import-once 'variables'; @import-once 'variables';
@icon-size: 42px;
.tracks-listing.four-columns { .tracks-listing.four-columns {
li { li {
float: left; float: left;
@ -23,23 +25,7 @@
} }
} }
.tracks-listing { .single-player, .tracks-listing li .image {
@icon-size: 42px;
margin: 0px;
padding: 0px;
list-style: none;
li {
.clearfix();
.box-sizing(border-box);
line-height: normal;
margin: 5px 0px;
padding: 0px;
padding-right: 10px;
.image {
float: left; float: left;
width: @icon-size; width: @icon-size;
height: @icon-size; height: @icon-size;
@ -70,7 +56,38 @@
display: block; display: block;
width: 100%; width: 100%;
} }
}
.tracks-listing {
margin: 0px;
padding: 0px;
list-style: none;
li {
.clearfix();
.box-sizing(border-box);
&.empty {
.border-radius(0px);
background: lighten(@pfm-purple, 30%);
border: 1px solid lighten(@pfm-purple, 10%);
color: lighten(@pfm-purple, 3%);
float: none !important;
width: auto !important;
display: block;
margin-top: 5px;
padding: 5px;
font-size: 9pt;
&:hover {
background-color: lighten(@pfm-purple, 30%);
} }
}
line-height: normal;
margin: 5px 0px;
padding: 0px;
padding-right: 10px;
.icons { .icons {
float: right; float: right;

View file

@ -1,7 +1,7 @@
<div> <div>
<ul class="tabs"> <ul class="tabs">
<li ng-class="{active: $state.includes('account-content.tracks')}"><a href="/account/tracks">Tracks</a></li> <li ng-class="{active: stateIncludes('account-content.tracks')}"><a href="/account/tracks">Tracks</a></li>
<li ng-class="{active: $state.includes('account-content.albums')}"><a href="/account/albums">Albums</a></li> <li ng-class="{active: stateIncludes('account-content.albums')}"><a href="/account/albums">Albums</a></li>
</ul> </ul>
<ui-view></ui-view> <ui-view></ui-view>

View file

@ -1,8 +1,8 @@
<div> <div>
<ul class="tabs"> <ul class="tabs">
<li ng-class="{active: $state.includes('account-favourites.tracks')}"><a href="/account/favourites">Tracks</a></li> <li ng-class="{active: stateIncludes('account-favourites.tracks')}"><a href="/account/favourites">Tracks</a></li>
<li ng-class="{active: $state.includes('account-favourites.albums')}"><a href="/account/favourites/albums">Albums</a></li> <li ng-class="{active: stateIncludes('account-favourites.albums')}"><a href="/account/favourites/albums">Albums</a></li>
<li ng-class="{active: $state.includes('account-favourites.playlists')}"><a href="/account/favourites/playlists">Playlists</a></li> <li ng-class="{active: stateIncludes('account-favourites.playlists')}"><a href="/account/favourites/playlists">Playlists</a></li>
</ul> </ul>
<ui-view></ui-view> <ui-view></ui-view>

View file

@ -22,9 +22,9 @@
</h1> </h1>
<ul class="tabs"> <ul class="tabs">
<li ng-class="{active: $state.includes('artist.profile')}"><a href="{{artist.slug}}">Profile</a></li> <li ng-class="{active: stateIncludes('artist.profile')}"><a href="{{artist.slug}}">Profile</a></li>
<li ng-class="{active: $state.includes('artist.content')}"><a href="{{artist.slug}}/content">Content</a></li> <li ng-class="{active: stateIncludes('artist.content')}"><a href="{{artist.slug}}/content">Content</a></li>
<li ng-class="{active: $state.includes('artist.favourites')}"><a href="{{artist.slug}}/favourites">Favourites</a></li> <li ng-class="{active: stateIncludes('artist.favourites')}"><a href="{{artist.slug}}/favourites">Favourites</a></li>
</ul> </ul>
</div> </div>

View file

@ -1,8 +1,8 @@
<ul class="tabs"> <ul class="tabs">
<li ng-class="{active: $state.includes('content.tracks') || $state.includes('content.track')}"><a href="/tracks">Tracks</a></li> <li ng-class="{active: stateIncludes('content.tracks') || stateIncludes('content.track')}"><a href="/tracks">Tracks</a></li>
<li ng-class="{active: $state.includes('content.artists') || $state.includes('content.artist')}"><a href="/artists">Artists</a></li> <li ng-class="{active: stateIncludes('content.artists') || stateIncludes('content.artist')}"><a href="/artists">Artists</a></li>
<li ng-class="{active: $state.includes('content.albums') || $state.includes('content.album')}"><a href="/albums">Albums</a></li> <li ng-class="{active: stateIncludes('content.albums') || stateIncludes('content.album')}"><a href="/albums">Albums</a></li>
<li ng-class="{active: $state.includes('content.playlists') || $state.includes('content.playlist')}"><a href="/playlists">Playlists</a></li> <li ng-class="{active: stateIncludes('content.playlists') || stateIncludes('content.playlist')}"><a href="/playlists">Playlists</a></li>
</ul> </ul>
<ui-view></ui-view> <ui-view></ui-view>

View file

@ -0,0 +1,7 @@
<div class="single-player">
<a href="#" class="play-button" pfm-eat-click ng-click="play()">
<i class="icon-play" ng-show="!track.isPlaying"></i>
<i class="icon-pause" ng-hide="!track.isPlaying"></i>
</a>
<img ng-src="{{track.covers.thumbnail}}" />
</div>

View file

@ -1,3 +1,3 @@
<div class="stretch-to-bottom"> <div class="stretch-to-bottom">
<pfm-tracks-list tracks="tracks" class="two-columns"></pfm-tracks-list> <pfm-tracks-list tracks="tracks" class="three-columns"></pfm-tracks-list>
</div> </div>

View file

@ -1,8 +1,9 @@
<ul class="dropdowns"> <ul class="dropdowns">
<li class="dropdown"> <li class="dropdown" ng-class="{'has-filter': query.filters.trackTypes.selectedArray.length}">
<a class="dropdown-toggle btn" ng-class="{'btn-info': query.filters.trackTypes.selectedArray.length}"> <a class="dropdown-toggle btn">
Type: <strong class="ng-cloak">{{query.filters.trackTypes.title}}</strong> Type: <strong>{{query.filters.trackTypes.title}}</strong>
</a> </a>
<a class="btn" pfm-eat-click ng-click="clearFilter('trackTypes')"><i class="icon-remove"></i></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li ng-repeat="type in filters.trackTypes.values" ng-class="{selected: query.isIdSelected('trackTypes', type.id)}"> <li ng-repeat="type in filters.trackTypes.values" ng-class="{selected: query.isIdSelected('trackTypes', type.id)}">
<a class="dont-close" pfm-eat-click href="#" ng-click="toggleListFilter('trackTypes', type.id); $event.stopPropagation();"><i class="icon-plus"></i></a> <a class="dont-close" pfm-eat-click href="#" ng-click="toggleListFilter('trackTypes', type.id); $event.stopPropagation();"><i class="icon-plus"></i></a>
@ -10,10 +11,11 @@
</li> </li>
</ul> </ul>
</li> </li>
<li class="dropdown"> <li class="dropdown" ng-class="{'has-filter': query.filters.showSongs.selectedArray.length}">
<a class="dropdown-toggle btn" ng-class="{'btn-info': query.filters.showSongs.selectedArray.length}"> <a class="dropdown-toggle btn">
Show Songs: <strong>{{query.filters.showSongs.title}}</strong> Show Songs: <strong>{{query.filters.showSongs.title}}</strong>
</a> </a>
<a class="btn" pfm-eat-click ng-click="clearFilter('showSongs')"><i class="icon-remove"></i></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li ng-repeat="song in filters.showSongs.values" ng-class="{selected: query.isIdSelected('showSongs', song.id)}"> <li ng-repeat="song in filters.showSongs.values" ng-class="{selected: query.isIdSelected('showSongs', song.id)}">
<a class="dont-close" pfm-eat-click href="#" ng-click="toggleListFilter('showSongs', song.id); $event.stopPropagation();"><i class="icon-plus"></i></a> <a class="dont-close" pfm-eat-click href="#" ng-click="toggleListFilter('showSongs', song.id); $event.stopPropagation();"><i class="icon-plus"></i></a>
@ -21,10 +23,11 @@
</li> </li>
</ul> </ul>
</li> </li>
<li class="dropdown"> <li class="dropdown" ng-class="{'has-filter': query.filters.genres.selectedArray.length}">
<a class="dropdown-toggle btn" ng-class="{'btn-info': query.filters.genres.selectedArray.length}"> <a class="dropdown-toggle btn">
Genre: <strong>{{query.filters.genres.title}}</strong> Genre: <strong>{{query.filters.genres.title}}</strong>
</a> </a>
<a class="btn" pfm-eat-click ng-click="clearFilter('genres')"><i class="icon-remove"></i></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li ng-repeat="genre in filters.genres.values" ng-class="{selected: query.isIdSelected('genres', genre.id)}"> <li ng-repeat="genre in filters.genres.values" ng-class="{selected: query.isIdSelected('genres', genre.id)}">
<a class="dont-close" pfm-eat-click href="#" ng-click="toggleListFilter('genres', genre.id); $event.stopPropagation();"><i class="icon-plus"></i></a> <a class="dont-close" pfm-eat-click href="#" ng-click="toggleListFilter('genres', genre.id); $event.stopPropagation();"><i class="icon-plus"></i></a>
@ -32,20 +35,22 @@
</li> </li>
</ul> </ul>
</li> </li>
<li class="dropdown"> <li class="dropdown" ng-class="{'has-filter': !query.filters.isVocal.isDefault}">
<a class="dropdown-toggle btn" ng-class="{'btn-info': !query.filters.isVocal.isDefault}"> <a class="dropdown-toggle btn">
Is Vocal: <strong>{{query.filters.isVocal.title}}</strong> Is Vocal: <strong>{{query.filters.isVocal.title}}</strong>
</a> </a>
<a class="btn" pfm-eat-click ng-click="clearFilter('isVocal')"><i class="icon-remove"></i></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li ng-repeat="item in filters.isVocal.values" ng-class="{selected: item == query.filters.isVocal}"> <li ng-repeat="item in filters.isVocal.values" ng-class="{selected: item == query.filters.isVocal}">
<a pfm-eat-click href="#" ng-click="setFilter('isVocal', item);">{{item.title}}</a> <a pfm-eat-click href="#" ng-click="setFilter('isVocal', item);">{{item.title}}</a>
</li> </li>
</ul> </ul>
</li> </li>
<li class="dropdown"> <li class="dropdown" ng-class="{'has-filter': !query.filters.sort.isDefault}">
<a class="dropdown-toggle btn" ng-class="{'btn-info': !query.filters.sort.isDefault}"> <a class="dropdown-toggle btn">
Order: <strong>{{query.filters.sort.title}}</strong> Order: <strong>{{query.filters.sort.title}}</strong>
</a> </a>
<a class="btn" pfm-eat-click ng-click="clearFilter('sort')"><i class="icon-remove"></i></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li ng-repeat="filter in filters.sort.values" ng-class="{selected: filter == query.filters.sort}"> <li ng-repeat="filter in filters.sort.values" ng-class="{selected: filter == query.filters.sort}">
<a pfm-eat-click href="#" ng-click="setFilter('sort', filter)">{{filter.title}}</a> <a pfm-eat-click href="#" ng-click="setFilter('sort', filter)">{{filter.title}}</a>

View file

@ -1,10 +1,4 @@
<div class="track-details" xmlns="http://www.w3.org/1999/html"> <div class="track-details" xmlns="http://www.w3.org/1999/html">
<ul class="breadcrumb">
<li><a href="/tracks">Tracks</a> <span class="divider">/</span></li>
<li><a href="/tracks?filter=genres-{{track.genre.id}}">{{track.genre.name}}</a> <span class="divider">/</span></li>
<li class="active">{{track.title}}</li>
</ul>
<div class="track-toolbar btn-group pull-right"> <div class="track-toolbar btn-group pull-right">
<pfm-favourite-button resource="track" type="track"></pfm-favourite-button> <pfm-favourite-button resource="track" type="track"></pfm-favourite-button>
<div class="dropdown"> <div class="dropdown">
@ -31,7 +25,7 @@
</div> </div>
</div> </div>
<pfm-tracks-list tracks="trackArray"></pfm-tracks-list> <pfm-track-player track="track"></pfm-track-player>
<h1> <h1>
{{track.title}} {{track.title}}
<span class="subtitle"> <span class="subtitle">