Forked from
funkwhale / funkwhale
6460 commits behind the upstream repository.
-
R En authorede3c56767
Editor.vue 6.07 KiB
<template>
<div class="ui text container">
<playlist-form @updated="$emit('playlist-updated', $event)" :title="false" :playlist="playlist"></playlist-form>
<h3 class="ui top attached header">
<translate>Playlist editor</translate>
</h3>
<div class="ui attached segment">
<template v-if="status === 'loading'">
<div class="ui active tiny inline loader"></div>
<translate>Syncing changes to server...</translate>
</template>
<template v-else-if="status === 'errored'">
<i class="red close icon"></i>
<translate>An error occured while saving your changes</translate>
<div v-if="errors.length > 0" class="ui negative message">
<ul class="list">
<li v-for="error in errors">{{ error }}</li>
</ul>
</div>
</template>
<template v-else-if="status === 'saved'">
<i class="green check icon"></i> <translate>Changes synced with server</translate>
</template>
</div>
<div class="ui bottom attached segment">
<div
@click="insertMany(queueTracks)"
:disabled="queueTracks.length === 0"
:class="['ui', {disabled: queueTracks.length === 0}, 'labeled', 'icon', 'button']"
:title="labels.copyTitle">
<i class="plus icon"></i>
<translate
translate-plural="Insert from queue (%{ count } tracks)"
:translate-n="queueTracks.length"
:translate-params="{count: queueTracks.length}">
Insert from queue (%{ count } track)
</translate>
</div>
<dangerous-button :disabled="plts.length === 0" class="labeled right floated icon" color='yellow' :action="clearPlaylist">
<i class="eraser icon"></i> <translate>Clear playlist</translate>
<p slot="modal-header">
<translate :translate-params="{playlist: playlist.name}">Do you want to clear the playlist "%{ playlist }"?</translate>
</p>
<p slot="modal-content"><translate>This will remove all tracks from this playlist and cannot be undone.</translate></p>
<p slot="modal-confirm"><translate>Clear playlist</translate></p>
</dangerous-button>
<div class="ui hidden divider"></div>
<template v-if="plts.length > 0">
<p><translate>Drag and drop rows to reorder tracks in the playlist</translate></p>
<table class="ui compact very basic fixed single line unstackable table">
<draggable v-model="plts" element="tbody" @update="reorder">
<tr v-for="(plt, index) in plts" :key="plt.id">
<td class="left aligned">{{ plt.index + 1}}</td>
<td class="center aligned">
<img class="ui mini image" v-if="plt.track.album.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](plt.track.album.cover.small_square_crop)">
<img class="ui mini image" v-else src="../../assets/audio/default-cover.png">
</td>
<td colspan="4">
<strong>{{ plt.track.title }}</strong><br />
{{ plt.track.artist.name }}
</td>
<td class="right aligned">
<i @click.stop="removePlt(index)" class="circular red trash icon"></i>
</td>
</tr>
</draggable>
</table>
</template>
</div>
</div>
</template>
<script>
import {mapState} from 'vuex'
import axios from 'axios'
import PlaylistForm from '@/components/playlists/Form'
import draggable from 'vuedraggable'
export default {
components: {
draggable,
PlaylistForm
},
props: ['playlist', 'playlistTracks'],
data () {
return {
plts: this.playlistTracks,
isLoading: false,
errors: []
}
},
methods: {
success () {
this.isLoading = false
this.errors = []
},
errored (errors) {
this.isLoading = false
this.errors = errors
},
reorder ({oldIndex, newIndex}) {
let self = this
self.isLoading = true
let plt = this.plts[newIndex]
let url = 'playlist-tracks/' + plt.id + '/'
axios.patch(url, {index: newIndex}).then((response) => {
self.success()
}, error => {
self.errored(error.backendErrors)
})
},
removePlt (index) {
let plt = this.plts[index]
this.plts.splice(index, 1)
let self = this
self.isLoading = true
let url = 'playlist-tracks/' + plt.id + '/'
axios.delete(url).then((response) => {
self.success()
self.$store.dispatch('playlists/fetchOwn')
}, error => {
self.errored(error.backendErrors)
})
},
clearPlaylist () {
this.plts = []
let self = this
self.isLoading = true
let url = 'playlists/' + this.playlist.id + '/clear'
axios.delete(url).then((response) => {
self.success()
self.$store.dispatch('playlists/fetchOwn')
}, error => {
self.errored(error.backendErrors)
})
},
insertMany (tracks) {
let self = this
let ids = tracks.map(t => {
return t.id
})
self.isLoading = true
let url = 'playlists/' + this.playlist.id + '/add/'
axios.post(url, {tracks: ids}).then((response) => {
response.data.results.forEach(r => {
self.plts.push(r)
})
self.success()
self.$store.dispatch('playlists/fetchOwn')
}, error => {
self.errored(error.backendErrors)
})
}
},
computed: {
...mapState({
queueTracks: state => state.queue.tracks
}),
labels () {
return {
copyTitle: this.$gettext('Copy tracks from current queue to playlist')
}
},
status () {
if (this.isLoading) {
return 'loading'
}
if (this.errors.length > 0) {
return 'errored'
}
return 'saved'
}
},
watch: {
plts: {
handler (newValue) {
newValue.forEach((e, i) => {
e.index = i
})
this.$emit('tracks-updated', newValue)
},
deep: true
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>