diff --git a/app/models/Commands/EditAlbumCommand.php b/app/models/Commands/EditAlbumCommand.php index 63ecf79f..40d30170 100644 --- a/app/models/Commands/EditAlbumCommand.php +++ b/app/models/Commands/EditAlbumCommand.php @@ -61,6 +61,6 @@ $this->_album->syncTrackIds($trackIds); $this->_album->save(); - return CommandResponse::succeed(); + return CommandResponse::succeed(['real_cover_url' => $this->_album->getCoverUrl(Image::NORMAL)]); } } \ No newline at end of file diff --git a/app/models/Commands/EditTrackCommand.php b/app/models/Commands/EditTrackCommand.php index b73edf9b..3e9700d8 100644 --- a/app/models/Commands/EditTrackCommand.php +++ b/app/models/Commands/EditTrackCommand.php @@ -107,7 +107,7 @@ $track->updateTags(); $track->save(); - return CommandResponse::succeed(); + return CommandResponse::succeed(['real_cover_url' => $track->getCoverUrl(Image::NORMAL)]); } private function removeTrackFromAlbum($track) { diff --git a/app/views/shared/_app_layout.blade.php b/app/views/shared/_app_layout.blade.php index ae3f76bc..045f2594 100644 --- a/app/views/shared/_app_layout.blade.php +++ b/app/views/shared/_app_layout.blade.php @@ -88,9 +88,9 @@ -
+ @yield('app_content') -
+ diff --git a/public/scripts/app/app.coffee b/public/scripts/app/app.coffee index 444dff6d..138c9e8f 100644 --- a/public/scripts/app/app.coffee +++ b/public/scripts/app/app.coffee @@ -1,6 +1,10 @@ +window.pfm.preloaders = {} + angular.module 'ponyfm', ['ui.bootstrap', 'ui.state', 'ui.date', 'ui.sortable'], [ - '$routeProvider', '$locationProvider', '$stateProvider', '$dialogProvider' - (route, location, state, $dialogProvider) -> + '$routeProvider', '$locationProvider', '$stateProvider', '$dialogProvider', '$injector' + (route, location, state, $dialogProvider, $injector) -> + + service = (name) -> angular.element(document.body).injector().get name # Account @@ -8,88 +12,58 @@ angular.module 'ponyfm', ['ui.bootstrap', 'ui.state', 'ui.date', 'ui.sortable'], url: '/account' templateUrl: '/templates/account/settings.html' controller: 'account-settings' - navigation: - index: 9 state.state 'account-content', url: '/account' abstract: true templateUrl: '/templates/account/content/_layout.html' - navigation: - index: 8 state.state 'account-content.tracks', url: '/tracks' templateUrl: '/templates/account/content/tracks.html' controller: 'account-tracks' - navigation: - index: 8 - subIndex: 1 state.state 'account-content.tracks.edit', url: '/edit/:track_id' - navigation: - index: 8 - subIndex: 1 + templateUrl: '/templates/account/content/track.html' + controller: 'account-tracks-edit' state.state 'account-content.albums', url: '/albums' templateUrl: '/templates/account/content/albums.html' controller: 'account-albums' - navigation: - index: 8 - subIndex: 2 state.state 'account-content.albums.create', url: '/create' templateUrl: '/templates/account/content/album.html' controller: 'account-albums-edit' - navigation: - index: 8 - subIndex: 2 state.state 'account-content.albums.edit', url: '/edit/:album_id' templateUrl: '/templates/account/content/album.html' controller: 'account-albums-edit' - navigation: - index: 8 - subIndex: 2 state.state 'account-content-playlists', url: '/account/playlists' templateUrl: '/templates/account/content/playlists.html' controller: 'account-playlists' - navigation: - index: 6 state.state 'account-favourites', url: '/account/favourites' abstract: true templateUrl: '/templates/account/favourites/_layout.html' - navigation: - index: 7 state.state 'account-favourites.tracks', url: '' templateUrl: '/templates/account/favourites/tracks.html' - navigation: - index: 7 - subIndex: 1 state.state 'account-favourites.playlists', url: '/playlists' templateUrl: '/templates/account/favourites/playlists.html' - navigation: - index: 7 - subIndex: 3 state.state 'account-favourites.albums', url: '/albums' templateUrl: '/templates/account/favourites/albums.html' - navigation: - index: 7 - subIndex: 2 # Tracks @@ -97,53 +71,39 @@ angular.module 'ponyfm', ['ui.bootstrap', 'ui.state', 'ui.date', 'ui.sortable'], url: '/tracks' templateUrl: '/templates/tracks/index.html' controller: 'tracks' - navigation: - index: 2 # Albums state.state 'albums', url: '/albums' templateUrl: '/templates/albums/index.html' - navigation: - index: 3 # Playlists state.state 'playlists', url: '/playlists' templateUrl: '/templates/playlists/index.html' - navigation: - index: 4 state.state 'playlist', url: '/playlist/:id/:slug' templateUrl: '/templates/playlists/show.html' controller: 'playlist' - navigation: - index: 4 # Artists state.state 'artists', url: '/artists' templateUrl: '/templates/artists/index.html' - navigation: - index: 5 # Pages state.state 'faq', url: '/faq' templateUrl: '/templates/pages/faq.html' - navigation: - index: 11 state.state 'about', url: '/about' templateUrl: '/templates/pages/about.html' - navigation: - index: 10 # Auth @@ -151,14 +111,10 @@ angular.module 'ponyfm', ['ui.bootstrap', 'ui.state', 'ui.date', 'ui.sortable'], url: '/login' templateUrl: '/templates/auth/login.html' controller: 'login' - navigation: - index: 12 state.state 'register', url: '/register' templateUrl: '/templates/auth/register.html' - navigation: - index: 13 # Hompage @@ -167,14 +123,10 @@ angular.module 'ponyfm', ['ui.bootstrap', 'ui.state', 'ui.date', 'ui.sortable'], url: '/' templateUrl: '/templates/dashboard.html' controller: 'dashboard' - navigation: - index: 0 else state.state 'home', url: '/' templateUrl: '/templates/home/index.html' - navigation: - index: 0 route.otherwise '/' diff --git a/public/scripts/app/controllers/account-albums-edit.coffee b/public/scripts/app/controllers/account-albums-edit.coffee index 506b1e86..3b671fd4 100644 --- a/public/scripts/app/controllers/account-albums-edit.coffee +++ b/public/scripts/app/controllers/account-albums-edit.coffee @@ -1,6 +1,16 @@ +window.pfm.preloaders['account-albums-edit'] = [ + 'account-tracks', 'account-albums', '$state' + (tracks, albums, $state) -> + defs = [tracks.refresh()] + if $state.params.album_id + defs.push albums.getEdit($state.params.album_id, true) + + $.when.all defs +] + angular.module('ponyfm').controller "account-albums-edit", [ - '$scope', '$state', 'taxonomies', '$dialog', 'lightbox' - ($scope, $state, taxonomies, $dialog, lightbox) -> + '$scope', '$state', '$dialog', 'account-albums' + ($scope, $state, $dialog, albums) -> $scope.isNew = $state.params.album_id == undefined $scope.data.isEditorOpen = true $scope.errors = {} @@ -38,33 +48,6 @@ angular.module('ponyfm').controller "account-albums-edit", [ $scope.isDirty = true - $scope.refresh = () -> - return if $scope.isNew - $.getJSON('/api/web/albums/edit/' + $state.params.album_id) - .done (album) -> $scope.$apply -> - $scope.isDirty = false - $scope.errors = {} - $scope.album = - id: album.id - title: album.title - description: album.description - remove_cover: false - cover: album.cover_url - - $scope.tracks = [] - $scope.tracks.push track for track in album.tracks - $scope.trackIds[track.id] = track for track in album.tracks - $scope.data.selectedAlbum.title = album.title - $scope.data.selectedAlbum.description = album.description - $scope.data.selectedAlbum.covers.normal = album.real_cover_url - - if $scope.isNew - $scope.album = - title: '' - description: '' - else - $scope.refresh(); - $scope.$on '$destroy', -> $scope.data.isEditorOpen = false $scope.saveAlbum = -> @@ -92,7 +75,9 @@ angular.module('ponyfm').controller "account-albums-edit", [ $scope.$emit 'album-created' $state.transitionTo 'account-content.albums.edit', {album_id: response.id} else - $scope.refresh() + $scope.isDirty = false + $scope.data.selectedAlbum.title = $scope.album.title + $scope.data.selectedAlbum.covers.normal = response.real_cover_url formData = new FormData() @@ -134,7 +119,29 @@ angular.module('ponyfm').controller "account-albums-edit", [ $scope.isDirty = true - $scope.$on '$stateChangeStart', (e) -> - return if $scope.selectedTrack == null || !$scope.isDirty + if !$scope.isNew + albums.getEdit($state.params.album_id).done (album) -> + $scope.album = + id: album.id + title: album.title + description: album.description + remove_cover: false + cover: album.cover_url + + $scope.tracks = [] + $scope.tracks.push track for track in album.tracks + $scope.trackIds[track.id] = track for track in album.tracks + + else + $scope.album = + title: '' + description: '' + + window.onbeforeunload = -> + return if !$scope.isDirty + "Are you sure you want to leave this page without saving your changes?" + + $scope.$on '$locationChangeStart', (e) -> + return if !$scope.isDirty e.preventDefault() if !confirm('Are you sure you want to leave this page without saving your changes?') ] \ No newline at end of file diff --git a/public/scripts/app/controllers/account-albums.coffee b/public/scripts/app/controllers/account-albums.coffee index 7b0ac670..c0af7899 100644 --- a/public/scripts/app/controllers/account-albums.coffee +++ b/public/scripts/app/controllers/account-albums.coffee @@ -1,41 +1,36 @@ -angular.module('ponyfm').controller "account-albums", [ - '$scope', '$state', 'taxonomies', '$dialog', 'lightbox' - ($scope, $state, taxonomies, $dialog, lightbox) -> - albumsDb = {} - lastIndex = null +window.pfm.preloaders['account-albums'] = [ + 'account-tracks', 'account-albums' + (tracks, albums) -> + $.when.all [tracks.refresh('published=true&in_album=false', true), albums.refresh(true)] +] +angular.module('ponyfm').controller "account-albums", [ + '$scope', '$state', 'account-albums', 'account-tracks' + ($scope, $state, albums, tracks) -> $scope.albums = [] $scope.data = isEditorOpen: false selectedAlbum: null - tracksDb: {} + tracksDb: [] - refreshTrackDatabase = () -> - $.getJSON('/api/web/tracks/owned?published=true&in_album=false') - .done (tracks) -> $scope.$apply -> - $scope.data.tracksDb[track.id] = track for track in tracks + updateTracks = (tracks) -> + $scope.data.tracksDb.push track for track in tracks - refreshList = () -> - $.getJSON('/api/web/albums/owned') - .done (albums) -> $scope.$apply -> - index = 0 - album.index = index++ for album in albums - albumsDb[album.id] = album for album in albums - $scope.albums = albums + tracks.refresh('published=true&in_album=false').done updateTracks - if $state.params.album_id != undefined - selectAlbum albumsDb[$state.params.album_id] - else if lastIndex != null - if $scope.albums.length - album = null - if $scope.albums.length > lastIndex + 1 - album = $scope.albums[lastIndex] - else if lastIndex > 0 - album = $scope.albums[lastIndex - 1] - else - album = $scope.albums[0] + albumsDb = {} - $state.transitionTo 'account-content.albums.edit', {album_id: album.id} + updateAlbums = (albums) -> + $scope.albums.length = 0 + + for album in albums + $scope.albums.push album + albumsDb[album.id] = album + + if $state.params.album_id + selectAlbum albumsDb[$state.params.album_id] + + albums.refresh().done updateAlbums selectAlbum = (album) -> $scope.data.selectedAlbum = album @@ -45,15 +40,7 @@ angular.module('ponyfm').controller "account-albums", [ else selectAlbum null - $scope.$on 'album-created', () -> refreshList() - - $scope.$on 'album-deleted', () -> - lastIndex = $scope.data.selectedAlbum.index - refreshList() - - $scope.$on 'album-updated', () -> - refreshTrackDatabase() - - refreshList() - refreshTrackDatabase() + $scope.$on 'album-created', () -> albums.refresh(true).done(updateAlbums) + $scope.$on 'album-deleted', () -> albums.refresh(true).done(updateAlbums) + $scope.$on 'album-updated', () -> tracks.refresh('published=true&in_album=false', true).done updateTracks ] \ No newline at end of file diff --git a/public/scripts/app/controllers/account-playlists.coffee b/public/scripts/app/controllers/account-playlists.coffee index a8d1c2c2..ae7865d7 100644 --- a/public/scripts/app/controllers/account-playlists.coffee +++ b/public/scripts/app/controllers/account-playlists.coffee @@ -1,12 +1,17 @@ +window.pfm.preloaders['account-playlists'] = [ + 'playlists' + (playlists) -> playlists.refreshOwned true +] + angular.module('ponyfm').controller "account-playlists", [ '$scope', 'auth', '$dialog', 'playlists' ($scope, auth, $dialog, playlists) -> $scope.playlists = [] - $scope.refresh = -> - $.get('/api/web/playlists/owned') - .done (playlists) -> $scope.$apply -> - $scope.playlists.push playlist for playlist in playlists + loadPlaylists = (playlists) -> + $scope.playlists.push playlist for playlist in playlists + + playlists.refreshOwned().done loadPlaylists $scope.editPlaylist = (playlist) -> dialog = $dialog.dialog @@ -36,6 +41,4 @@ angular.module('ponyfm').controller "account-playlists", [ content = $scope.playlists[index] _.each playlist, (value, name) -> content[name] = value $scope.playlists.sort (left, right) -> left.title.localeCompare right.title - - $scope.refresh(); ] \ No newline at end of file diff --git a/public/scripts/app/controllers/account-tracks-edit.coffee b/public/scripts/app/controllers/account-tracks-edit.coffee new file mode 100644 index 00000000..ba6a5a44 --- /dev/null +++ b/public/scripts/app/controllers/account-tracks-edit.coffee @@ -0,0 +1,148 @@ +window.pfm.preloaders['account-tracks-edit'] = [ + 'account-tracks', 'account-albums', 'taxonomies', '$state' + (tracks, albums, taxonomies, state) -> + $.when.all [albums.refresh(), taxonomies.refresh(), tracks.getEdit(state.params.track_id, true)] +] + +angular.module('ponyfm').controller "account-tracks-edit", [ + '$scope', '$state', 'taxonomies', '$dialog', 'account-albums', 'account-tracks' + ($scope, $state, taxonomies, $dialog, albums, tracks) -> + $scope.isDirty = false + $scope.isSaving = false + $scope.taxonomies = taxonomies + $scope.selectedSongsTitle = 'None' + $scope.selectedSongs = {} + $scope.albums = [] + $scope.selectedAlbum = null + + albumsDb = {} + albums.refresh().done (albums) -> + $scope.albums.legnth = 0 + albumsDb = {} + for album in albums + albumsDb[album.id] = album + $scope.albums.push album + + $scope.selectAlbum = (album) -> + $scope.selectedAlbum = album + $scope.edit.album_id = if album then album.id else null + $scope.isDirty = true + + $scope.setCover = (image, type) -> + delete $scope.edit.cover_id + delete $scope.edit.cover + + if image == null + $scope.edit.remove_cover = true + else if type == 'file' + $scope.edit.cover = image + else if type == 'gallery' + $scope.edit.cover_id = image.id + + $scope.isDirty = true + + updateSongDisplay = () -> + if _.size $scope.selectedSongs + $scope.selectedSongsTitle = (_.map _.values($scope.selectedSongs), (s) -> s.title).join(', ') + else + $scope.selectedSongsTitle = 'None' + + $scope.toggleSong = (song) -> + $scope.isDirty = true + if $scope.selectedSongs[song.id] + delete $scope.selectedSongs[song.id] + else + $scope.selectedSongs[song.id] = song + + updateSongDisplay() + + $scope.updateIsVocal = () -> + delete $scope.errors.lyrics if !$scope.edit.is_vocal + + $scope.updateTrack = () -> + xhr = new XMLHttpRequest() + xhr.onload = -> $scope.$apply -> + $scope.isSaving = false + if xhr.status != 200 + errors = + if xhr.getResponseHeader('content-type') == 'application/json' + $.parseJSON(xhr.responseText).errors + else + ['There was an unknown error!'] + + $scope.errors = {} + _.each errors, (value, key) -> $scope.errors[key] = value.join ', ' + return + + track = $.parseJSON(xhr.responseText) + + trackDbItem = $scope.data.selectedTrack + trackDbItem.title = $scope.edit.title + trackDbItem.is_explicit = $scope.edit.is_explicit + trackDbItem.is_vocal = $scope.edit.is_vocal + trackDbItem.genre_id = $scope.edit.genre_id + trackDbItem.is_published = true + trackDbItem.cover_url = track.real_cover_url + $scope.isDirty = false + $scope.errors = {} + + formData = new FormData(); + _.each $scope.edit, (value, name) -> + if name == 'cover' + return if value == null + if typeof(value) == 'object' + formData.append name, value, value.name + else + formData.append name, value + + if $scope.edit.track_type_id == 2 + formData.append 'show_song_ids', _.map(_.values($scope.selectedSongs), (s) -> s.id).join() + + xhr.open 'POST', '/api/web/tracks/edit/' + $scope.edit.id, true + xhr.setRequestHeader 'X-Token', pfm.token + $scope.isSaving = true + xhr.send formData + + tracks.getEdit($state.params.track_id).done (track) -> + $scope.edit = + id: track.id + title: track.title + description: track.description + lyrics: track.lyrics + is_explicit: track.is_explicit + is_downloadable: track.is_downloadable + is_vocal: track.is_vocal + license_id: track.license_id + genre_id: track.genre_id + track_type_id: track.track_type_id + released_at: if track.released_at then track.released_at.date else '' + remove_cover: false + cover: track.cover_url + album_id: track.album_id + is_published: track.is_published + + $scope.selectedAlbum = if track.album_id then albumsDb[track.album_id] else null + $scope.selectedSongs = {} + $scope.selectedSongs[song.id] = song for song in track.show_songs + updateSongDisplay() + + $scope.touchModel = -> $scope.isDirty = true + + $scope.deleteTrack = (track) -> + $dialog.messageBox('Delete ' + track.title, 'Are you sure you want to delete "' + track.title + '"? This cannot be undone.', [ + {result: 'ok', label: 'Yes', cssClass: 'btn-danger'}, {result: 'cancel', label: 'No', cssClass: 'btn-primary'} + ]).open().then (res) -> + return if res == 'cancel' + $.post('/api/web/tracks/delete/' + track.id, {_token: window.pfm.token}) + .then -> $scope.$apply -> + $scope.$emit 'track-deleted' + $state.transitionTo 'account-content.tracks' + + window.onbeforeunload = -> + return if !$scope.isDirty + "Are you sure you want to leave this page without saving your changes?" + + $scope.$on '$locationChangeStart', (e) -> + return if !$scope.isDirty + e.preventDefault() if !confirm('Are you sure you want to leave this page without saving your changes?') +] \ No newline at end of file diff --git a/public/scripts/app/controllers/account-tracks.coffee b/public/scripts/app/controllers/account-tracks.coffee index da9c43d7..369b00cd 100644 --- a/public/scripts/app/controllers/account-tracks.coffee +++ b/public/scripts/app/controllers/account-tracks.coffee @@ -1,95 +1,30 @@ +window.pfm.preloaders['account-tracks'] = [ + 'account-tracks', 'account-albums', 'taxonomies' + (tracks, albums, taxonomies) -> + $.when.all [tracks.refresh(null, true), albums.refresh(true), taxonomies.refresh()] +] + angular.module('ponyfm').controller "account-tracks", [ - '$scope', '$state', 'taxonomies', '$dialog', 'lightbox' - ($scope, $state, taxonomies, $dialog, lightbox) -> - $scope.selectedTrack = null - $scope.isDirty = false - $scope.isSaving = false - $scope.taxonomies = taxonomies - $scope.selectedSongsTitle = 'None' - $scope.selectedSongs = {} - $scope.albums = [] - $scope.selectedAlbum = null + '$scope', '$state', 'taxonomies', '$dialog', 'lightbox', 'account-albums', 'account-tracks' + ($scope, $state, taxonomies, $dialog, lightbox, albums, tracks) -> + $scope.data = + selectedTrack: null + + $scope.tracks = [] tracksDb = {} - albumsDb = {} - $scope.selectAlbum = (album) -> - $scope.selectedAlbum = album - $scope.edit.album_id = if album then album.id else null - $scope.isDirty = true + setTracks = (tracks) -> + $scope.tracks.length = 0 + tracksDb = {} + for track in tracks + tracksDb[track.id] = track + $scope.tracks.push track - $scope.setCover = (image, type) -> - delete $scope.edit.cover_id - delete $scope.edit.cover + if $state.params.track_id + $scope.data.selectedTrack = tracksDb[$state.params.track_id] - if image == null - $scope.edit.remove_cover = true - else if type == 'file' - $scope.edit.cover = image - else if type == 'gallery' - $scope.edit.cover_id = image.id - - $scope.isDirty = true - - refreshAlbums = () -> - $.getJSON('/api/web/albums/owned') - .done (albums) -> $scope.$apply -> - albumsDb[album.id] = album for album in albums - $scope.albums = albums - $scope.selectedAlbum = if $scope.edit && $scope.edit.album_id then albumsDb[$scope.edit.album_id] else null - - updateSongDisplay = () -> - if _.size $scope.selectedSongs - $scope.selectedSongsTitle = (_.map _.values($scope.selectedSongs), (s) -> s.title).join(', ') - else - $scope.selectedSongsTitle = 'None' - - $scope.toggleSong = (song) -> - $scope.isDirty = true - if $scope.selectedSongs[song.id] - delete $scope.selectedSongs[song.id] - else - $scope.selectedSongs[song.id] = song - - updateSongDisplay() - - $scope.updateIsVocal = () -> - delete $scope.errors.lyrics if !$scope.edit.is_vocal - - $scope.updateTrack = (track) -> - xhr = new XMLHttpRequest() - xhr.onload = -> $scope.$apply -> - $scope.isSaving = false - if xhr.status != 200 - errors = - if xhr.getResponseHeader('content-type') == 'application/json' - $.parseJSON(xhr.responseText).errors - else - ['There was an unknown error!'] - - $scope.errors = {} - _.each errors, (value, key) -> $scope.errors[key] = value.join ', ' - return - - $scope.selectedTrack.is_published = true - selectTrack $scope.selectedTrack - - formData = new FormData(); - _.each $scope.edit, (value, name) -> - if name == 'cover' - return if value == null - if typeof(value) == 'object' - formData.append name, value, value.name - else - formData.append name, value - - if $scope.edit.track_type_id == 2 - formData.append 'show_song_ids', _.map(_.values($scope.selectedSongs), (s) -> s.id).join() - - xhr.open 'POST', '/api/web/tracks/edit/' + $scope.edit.id, true - xhr.setRequestHeader 'X-Token', pfm.token - $scope.isSaving = true - xhr.send formData + tracks.refresh().done setTracks $scope.filters = published: [ @@ -114,17 +49,17 @@ angular.module('ponyfm').controller "account-tracks", [ genres: 'All' trackTypes: 'All' - taxonomies.refresh().done () -> - for genre in taxonomies.genres - $scope.filters.genres[genre.id] = - id: genre.id - title: genre.name - query: 'genres[]=' + genre.id - for type in taxonomies.trackTypes - $scope.filters.trackTypes[type.id] = - id: type.id - title: type.title - query: 'types[]=' + type.id + for genre in taxonomies.genres + $scope.filters.genres[genre.id] = + id: genre.id + title: genre.name + query: 'genres[]=' + genre.id + + for type in taxonomies.trackTypes + $scope.filters.trackTypes[type.id] = + id: type.id + title: type.title + query: 'types[]=' + type.id $scope.updateFilter = (type, filter) -> $scope.filter[type] = filter @@ -151,76 +86,18 @@ angular.module('ponyfm').controller "account-tracks", [ _.each $scope.filter.genres, (g) -> parts.push g.query _.each $scope.filter.trackTypes, (g) -> parts.push g.query query = parts.join '&' - $.getJSON('/api/web/tracks/owned?' + query).done (tracks) -> $scope.$apply -> showTracks tracks + tracks.refresh(query).done setTracks - showTracks = (tracks) -> - tracksDb = {} - $scope.tracks = tracks - tracksDb[track.id] = track for track in tracks - - selectTrack = (t) -> - $scope.selectedTrack = t - return if !t - $.getJSON('/api/web/tracks/edit/' + t.id) - .done (track) -> $scope.$apply -> - $scope.isDirty = false - $scope.errors = {} - $scope.edit = - id: track.id - title: track.title - description: track.description - lyrics: track.lyrics - is_explicit: track.is_explicit - is_downloadable: track.is_downloadable - is_vocal: track.is_vocal - license_id: track.license_id - genre_id: track.genre_id - track_type_id: track.track_type_id - released_at: if track.released_at then track.released_at.date else '' - remove_cover: false - cover: track.cover_url - album_id: track.album_id - - trackDbItem = tracksDb[t.id] - trackDbItem.title = track.title - trackDbItem.is_explicit = track.is_explicit - trackDbItem.is_vocal = track.is_vocal - trackDbItem.genre_id = track.genre_id - trackDbItem.is_published = track.is_published - trackDbItem.cover_url = track.real_cover_url - - $scope.selectedAlbum = if track.album_id then albumsDb[track.album_id] else null - $scope.selectedSongs = {} - $scope.selectedSongs[song.id] = song for song in track.show_songs - updateSongDisplay() - - $scope.touchModel = -> $scope.isDirty = true - - $.getJSON('/api/web/tracks/owned?order=created_at,desc').done (tracks) -> $scope.$apply -> - showTracks tracks - if $state.params.track_id - selectTrack tracksDb[$state.params.track_id] - - $scope.selectTrack = (track) -> $scope.selectedTrack = track - $scope.deleteTrack = (track) -> - $dialog.messageBox('Delete ' + track.title, 'Are you sure you want to delete "' + track.title + '"? This cannot be undone.', [ - {result: 'ok', label: 'Yes', cssClass: 'btn-danger'}, {result: 'cancel', label: 'No', cssClass: 'btn-primary'} - ]).open().then (res) -> - return if res == 'cancel' - selectTrack null if track == $scope.selectedTrack - $.post('/api/web/tracks/delete/' + track.id, {_token: window.pfm.token}) - .then -> - $scope.refreshList() + $scope.selectTrack = (track) -> + $scope.data.selectedTrack = track $scope.$on '$stateChangeSuccess', () -> if $state.params.track_id - selectTrack tracksDb[$state.params.track_id] + $scope.selectTrack tracksDb[$state.params.track_id] else - selectTrack null + $scope.selectTrack null - $scope.$on '$stateChangeStart', (e) -> - return if $scope.selectedTrack == null || !$scope.isDirty - e.preventDefault() if !confirm('Are you sure you want to leave this page without saving your changes?') - - refreshAlbums() + $scope.$on 'track-deleted', () -> + tracks.clearCache() + $scope.refreshList() ] \ No newline at end of file diff --git a/public/scripts/app/controllers/application.coffee b/public/scripts/app/controllers/application.coffee index 4d01a80d..e3f5a43f 100644 --- a/public/scripts/app/controllers/application.coffee +++ b/public/scripts/app/controllers/application.coffee @@ -1,52 +1,51 @@ angular.module('ponyfm').controller "application", [ - '$scope', 'auth', '$location', 'upload', '$state', '$stateParams', 'taxonomies' - ($scope, auth, $location, upload, $state, $stateParams, taxonomies) -> + '$scope', 'auth', '$location', 'upload', '$state', '$stateParams', '$injector' + ($scope, auth, $location, upload, $state, $stateParams, $injector) -> $scope.auth = auth.data $scope.$state = $state $scope.$stateParams = $stateParams + $loadingElement = null $scope.logout = () -> auth.logout().done -> location.reload() $scope.isActive = (loc) -> $location.path() == loc $scope.$on '$viewContentLoaded', () -> - window.setTimeout window.handleResize, 500 + window.handleResize() - # Show loading screen here? - taxonomies.refresh() - - $scope.mainViewAnimation = 'slide-down'; + if $loadingElement + $loadingElement.removeClass 'loading' + $loadingElement = null + statesPreloaded = {} $scope.$on '$stateChangeStart', (e, newState, newParams, oldState) -> - oldIndex = - if (oldState && oldState.navigation && oldState.navigation.index) - oldState.navigation.index - else - 0 + return if !oldState || !newState.controller - newIndex = - if (newState && newState.navigation && newState.navigation.index) - newState.navigation.index - else - 0 + preloader = window.pfm.preloaders[newState.controller] + return if !preloader - oldSubIndex = - if (oldState && oldState.navigation && oldState.navigation.subIndex) - oldState.navigation.subIndex - else - 0 + if statesPreloaded[newState] + delete statesPreloaded[newState] + return - newSubIndex = - if (newState && newState.navigation && newState.navigation.subIndex) - newState.navigation.subIndex - else - 0 + e.preventDefault() - $scope.mainViewAnimation = 'slide-down' if oldIndex > newIndex - $scope.mainViewAnimation = 'slide-up' if oldIndex < newIndex - $scope.mainViewAnimation = 'slide-right' if oldIndex == newIndex + selector = '' + newParts = newState.name.split '.' + oldParts = oldState.name.split '.' + zipped = _.zip(newParts, oldParts) + for i in [0..zipped.length] + break if !zipped[i] || zipped[i][0] != zipped[i][1] + selector += ' ui-view ' - $scope.subViewAnimation = 'slide-right' if oldSubIndex > newSubIndex - $scope.subViewAnimation = 'slide-left' if oldSubIndex < newSubIndex - $scope.subViewAnimation = 'slide-up' if oldSubIndex == newSubIndex + selector += ' ui-view ' if newState.name != oldState.name + + $loadingElement = $ selector + $loadingElement.addClass 'loading' + + stateToInject = angular.copy newState + stateToInject.params = newParams + $injector.invoke(preloader, null, {$state: stateToInject}).then -> + statesPreloaded[newState] = true + $state.transitionTo newState, newParams ] \ No newline at end of file diff --git a/public/scripts/app/directives/popup.coffee b/public/scripts/app/directives/popup.coffee index f8ba3251..3a59cb6c 100644 --- a/public/scripts/app/directives/popup.coffee +++ b/public/scripts/app/directives/popup.coffee @@ -12,9 +12,6 @@ angular.module('ponyfm').directive 'pfmPopup', () -> $positionParent = null open = false - $popup.parents().each () -> - $this = $ this - $positionParent = $this if $positionParent == null && ($this.css('position') == 'relative' || $this.is 'body') documentClickHandler = () -> return if !open @@ -22,6 +19,10 @@ angular.module('ponyfm').directive 'pfmPopup', () -> open = false calculatePosition = -> + $popup.parents().each () -> + $this = $ this + $positionParent = $this if $positionParent == null && ($this.css('position') == 'relative' || $this.is 'body') + position = $element.offset() parentPosition = $positionParent.offset() @@ -42,7 +43,7 @@ angular.module('ponyfm').directive 'pfmPopup', () -> height = windowHeight - top; return { - left: left - parentPosition.left - 2 + left: left - parentPosition.left - 5 top: top - parentPosition.top, height: height - 15} @@ -70,13 +71,15 @@ angular.module('ponyfm').directive 'pfmPopup', () -> $popup.addClass 'open' $popup.css 'height', 'auto' - position = calculatePosition() - $popup.css - left: position.left - top: position.top - height: position.height + window.setTimeout (-> + position = calculatePosition() + $popup.css + left: position.left + top: position.top + height: position.height - open = true + open = true + ), 0 scope.$on '$destroy', () -> $(document.body).unbind 'click', documentClickHandler diff --git a/public/scripts/app/services/account-albums.coffee b/public/scripts/app/services/account-albums.coffee new file mode 100644 index 00000000..6a381458 --- /dev/null +++ b/public/scripts/app/services/account-albums.coffee @@ -0,0 +1,27 @@ +angular.module('ponyfm').factory('account-albums', [ + '$rootScope', '$http' + ($rootScope, $http) -> + def = null + albums = [] + + self = + getEdit: (id, force) -> + url = '/api/web/albums/edit/' + id + force = force || false + return albums[id] if !force && albums[id] + + editDef = new $.Deferred() + albums[id] = editDef + $http.get(url).success (album) -> editDef.resolve album + editDef.promise() + + refresh: (force) -> + force = force || false + return def if !force && def + def = new $.Deferred() + $http.get('/api/web/albums/owned').success (ownedAlbums) -> + def.resolve(ownedAlbums) + def.promise() + + self +]) \ No newline at end of file diff --git a/public/scripts/app/services/account-tracks.coffee b/public/scripts/app/services/account-tracks.coffee new file mode 100644 index 00000000..7f4dc51f --- /dev/null +++ b/public/scripts/app/services/account-tracks.coffee @@ -0,0 +1,31 @@ +angular.module('ponyfm').factory('account-tracks', [ + '$rootScope', '$http' + ($rootScope, $http) -> + cache = {} + + self = + clearCache: () -> cache = {} + + getEdit: (id, force) -> + url = '/api/web/tracks/edit/' + id + force = force || false + return cache[url] if !force && cache[url] + + def = new $.Deferred() + cache[url] = def + $http.get(url).success (track) -> def.resolve track + def.promise() + + refresh: (query, force) -> + query = query || 'created_at,desc' + url = '/api/web/tracks/owned?' + query + force = force || false + return cache[url] if !force && cache[url] + + def = new $.Deferred() + cache[url] = def + $http.get(url).success (tracks) -> def.resolve tracks + def.promise() + + self +]) \ No newline at end of file diff --git a/public/scripts/app/services/playlists.coffee b/public/scripts/app/services/playlists.coffee index 13ed0dc2..bf1b1529 100644 --- a/public/scripts/app/services/playlists.coffee +++ b/public/scripts/app/services/playlists.coffee @@ -1,8 +1,20 @@ angular.module('ponyfm').factory('playlists', [ - '$rootScope', '$state' - ($rootScope, $state) -> + '$rootScope', '$state', '$http' + ($rootScope, $state, $http) -> + playlistDef = null + self = pinnedPlaylists: [] + refreshOwned: (force) -> + force = force || false + return playlistDef if !force && playlistDef + + playlistDef = new $.Deferred() + $http.get('/api/web/playlists/owned').success (playlists) -> + playlistDef.resolve playlists + + playlistDef + refresh: () -> $.getJSON('/api/web/playlists/pinned') .done (playlists) -> $rootScope.$apply -> diff --git a/public/scripts/app/services/taxonomies.coffee b/public/scripts/app/services/taxonomies.coffee index a1b152b2..d7b0f861 100644 --- a/public/scripts/app/services/taxonomies.coffee +++ b/public/scripts/app/services/taxonomies.coffee @@ -1,6 +1,6 @@ angular.module('ponyfm').factory('taxonomies', [ - '$rootScope' - ($rootScope) -> + '$rootScope', '$http' + ($rootScope, $http) -> def = null self = @@ -9,17 +9,18 @@ angular.module('ponyfm').factory('taxonomies', [ genres: [] showSongs: [] refresh: () -> - return def if def != null + return def.promise() if def != null def = new $.Deferred() - $.getJSON('/api/web/taxonomies/all') - .done (taxonomies) -> $rootScope.$apply -> + $http.get('/api/web/taxonomies/all') + .success (taxonomies) -> self.trackTypes.push t for t in taxonomies.track_types self.licenses.push t for t in taxonomies.licenses self.genres.push t for t in taxonomies.genres self.showSongs.push t for t in taxonomies.show_songs def.resolve self - def + + def.promise() self ]) \ No newline at end of file diff --git a/public/scripts/shared/jquery-extensions.js b/public/scripts/shared/jquery-extensions.js new file mode 100644 index 00000000..2c9d91b3 --- /dev/null +++ b/public/scripts/shared/jquery-extensions.js @@ -0,0 +1,14 @@ +if (jQuery.when.all===undefined) { + jQuery.when.all = function(deferreds) { + var deferred = new jQuery.Deferred(); + $.when.apply(jQuery, deferreds).then( + function() { + deferred.resolve(Array.prototype.slice.call(arguments)); + }, + function() { + deferred.fail(Array.prototype.slice.call(arguments)); + }); + + return deferred; + } +} \ No newline at end of file diff --git a/public/scripts/shared/layout.coffee b/public/scripts/shared/layout.coffee index 9a3893c0..9f58acc4 100644 --- a/public/scripts/shared/layout.coffee +++ b/public/scripts/shared/layout.coffee @@ -2,18 +2,13 @@ window.handleResize = () -> windowHeight = $(window).height() $siteBody = $ '.site-body' $siteBody.height windowHeight - $('header').height() - 1 - redo = false $('.stretch-to-bottom').each () -> $this = $ this newHeight = windowHeight - $this.offset().top + 1 - if newHeight <= 0 - redo = true - else + if newHeight > 0 $this.height newHeight - window.setTimeout(window.handleResize, 0) if redo - window.alignVertically = (element) -> $element = $(element) $parent = $element.parent() diff --git a/public/styles/layout.less b/public/styles/layout.less index e70592fd..84455451 100644 --- a/public/styles/layout.less +++ b/public/styles/layout.less @@ -21,6 +21,36 @@ html body { z-index: -5; } +ui-view { + display: block; + + &:before { + .transition(opacity 250ms); + + opacity: 0; + background: #fff; + content: ' '; + top: 0px; + left: 0px; + z-index: 1000; + width: 0px; + height: 0px; + position: absolute; + display: block; + overflow: hidden; + } + + &.loading { + position: relative; + + &:before { + opacity: .8; + width: 100%; + height: 100%; + } + } +} + header { .clearfix(); background: #222; diff --git a/public/templates/account/content/_layout.html b/public/templates/account/content/_layout.html index a17c8514..e8ee9ddc 100644 --- a/public/templates/account/content/_layout.html +++ b/public/templates/account/content/_layout.html @@ -4,5 +4,5 @@
  • Albums
  • -
    + \ No newline at end of file diff --git a/public/templates/account/content/albums.html b/public/templates/account/content/albums.html index d6e3480a..67f36c21 100644 --- a/public/templates/account/content/albums.html +++ b/public/templates/account/content/albums.html @@ -23,7 +23,6 @@ -
    -
    + \ No newline at end of file diff --git a/public/templates/account/content/track.html b/public/templates/account/content/track.html new file mode 100644 index 00000000..0ecdde92 --- /dev/null +++ b/public/templates/account/content/track.html @@ -0,0 +1,116 @@ +
    + +
    +
    + + +
    {{errors.title}}
    +
    +
    +
    + + +
    {{errors.description}}
    +
    +
    + + +
    {{errors.lyrics}}
    +
    +
    +
    +
    + + +
    {{errors.genre_id}}
    +
    +
    + + +
    {{errors.track_type_id}}
    +
    +
    +
    +
    + + Album: + {{selectedAlbum.title}} + None + +
    + +
    +
    {{errors.album_id}}
    +
    +
    + Show Songs: {{selectedSongsTitle}} +
    + +
    +
    {{errors.show_song_ids}}
    +
    +
    +
    +
    + + +
    +
    + + +
    {{errors.released_at}}
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    + + +
    +
    +
    \ No newline at end of file diff --git a/public/templates/account/content/tracks.html b/public/templates/account/content/tracks.html index 708e1fe5..73f11e1b 100644 --- a/public/templates/account/content/tracks.html +++ b/public/templates/account/content/tracks.html @@ -25,7 +25,7 @@ Type: {{titles.trackTypes}} @@ -35,18 +35,18 @@ Genera: {{titles.genres}} -
    +
    -
    -
    - -
    -
    - - -
    {{errors.title}}
    -
    -
    -
    - - -
    {{errors.description}}
    -
    -
    - - -
    {{errors.lyrics}}
    -
    -
    -
    -
    - - -
    {{errors.genre_id}}
    -
    -
    - - -
    {{errors.track_type_id}}
    -
    -
    -
    -
    - - Album: - {{selectedAlbum.title}} - None - -
    - -
    -
    {{errors.album_id}}
    -
    -
    - Show Songs: {{selectedSongsTitle}} -
    - -
    -
    {{errors.show_song_ids}}
    -
    -
    -
    -
    - - -
    -
    - - -
    {{errors.released_at}}
    -
    -
    -
    -
    - -
    -
    - -
    -
    -
    - - -
    -
    -
    -
    +
    \ No newline at end of file