work on player ui
This commit is contained in:
parent
d80322dd15
commit
e05cdb343d
|
@ -543,9 +543,15 @@ class SectionPlaylist(Section):
|
||||||
"""
|
"""
|
||||||
fields = {
|
fields = {
|
||||||
'name': 'name',
|
'name': 'name',
|
||||||
'duration': lambda e, o: (
|
'embed': 'embed',
|
||||||
o.duration.hour, o.duration.minute, o.duration.second
|
'duration': lambda e, o:
|
||||||
),
|
o.duration.hour * 3600 + o.duration.minute * 60 +
|
||||||
|
o.duration.second
|
||||||
|
,
|
||||||
|
'duration_str': lambda e, o:
|
||||||
|
(str(o.duration.hour) + '"' if o.duration.hour else '') +
|
||||||
|
str(o.duration.minute) + "'" + str(o.duration.second)
|
||||||
|
,
|
||||||
'sources': lambda e, o: [ o.url() ],
|
'sources': lambda e, o: [ o.url() ],
|
||||||
'detail_url':
|
'detail_url':
|
||||||
lambda e, o: o.diffusion and hasattr(o.diffusion, 'page') \
|
lambda e, o: o.diffusion and hasattr(o.diffusion, 'page') \
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
.nav-submenu h2 {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-submenu .menu-item .info {
|
|
||||||
margin-right: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-submenu .menu-item a {
|
|
||||||
white-space: normal;
|
|
||||||
padding: 0.9em 1em 0.9em 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-submenu .menu-item a:hover {
|
|
||||||
background-color: rgba(100, 100, 100, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-submenu li {
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -486,153 +486,111 @@ ul.list, .list > ul {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** content: player **/
|
/** component: sound **/
|
||||||
.player {
|
.component.sound {
|
||||||
}
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
.player:not([seekable]) > .controls > .progress {
|
margin: 0.2em;
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.player .controls {
|
|
||||||
margin-top: 1em;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
.player .controls > * {
|
|
||||||
margin: 0em 0.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.player .controls .single {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.player .controls .single + label {
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 1em;
|
|
||||||
padding: 0.1em;
|
|
||||||
width: 1.5em;
|
|
||||||
height: 1.0em;
|
|
||||||
text-align: center;
|
|
||||||
box-shadow: inset 0em 0em 0.1em #818181;
|
|
||||||
}
|
|
||||||
|
|
||||||
.player .controls .single:not(:checked) + label {
|
|
||||||
border-left: 2px #818181 solid;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.player .controls .single:checked + label {
|
|
||||||
border-right: 2px #818181 solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.player .playlist .item {
|
|
||||||
position: relative;
|
|
||||||
margin: 0em;
|
|
||||||
padding: 0.2em 0.4em;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.player .playlist .item:hover {
|
|
||||||
color: #007EDF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.player .item > * {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.player .playlist .item .actions {
|
|
||||||
display: none;
|
|
||||||
height: 100%;
|
|
||||||
max-width: 2.9em;
|
|
||||||
position: absolute;
|
|
||||||
right: 0px;
|
|
||||||
font-size: 1.2em;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.player .playlist .item:hover .actions {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.player .playlist .item .action {
|
|
||||||
display: inline-block;
|
|
||||||
width: 1.2em;
|
|
||||||
height: 1.2em;
|
|
||||||
border-radius: 0.2em;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 1.2em;
|
|
||||||
background-color: #F2F2F2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.player .playlist .item .action:hover {
|
|
||||||
background-color: rgba(0, 126, 223, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.player .playlist .duration {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.player .playlist progress {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.component.sound[state="play"] button {
|
||||||
.player .item[selected] {
|
animation-name: sound-blink;
|
||||||
border-left: 1px #007EDF solid;
|
animation-duration: 4s;
|
||||||
font-size: 1.0em;
|
animation-iteration-count: infinite;
|
||||||
|
animation-direction: alternate;
|
||||||
}
|
}
|
||||||
|
|
||||||
.player .item:not([selected]) {
|
@keyframes sound-blink {
|
||||||
|
from { background-color: rgba(255, 255, 255, 0); }
|
||||||
|
to { background-color: rgba(255, 255, 255, 0.6); }
|
||||||
}
|
}
|
||||||
|
|
||||||
.player .button {
|
|
||||||
display: inline-block;
|
.component.sound .button {
|
||||||
|
width: 4em;
|
||||||
|
height: 4em;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
height: 2.0em;
|
position: relative;
|
||||||
background: none;
|
margin-right: 0.4em;
|
||||||
border: none;
|
|
||||||
font-size: 1.4em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.player .button > img {
|
.component.sound .button > img {
|
||||||
max-height: 2.0em;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.player:not([state]) .item[selected] .button > img:not(.play),
|
.component.sound button {
|
||||||
.player[state="paused"] .item[selected] .button > img:not(.play),
|
transition: background-color 0.5s;
|
||||||
.player[state="playing"] .item[selected] .button > img:not(.pause),
|
background-color: rgba(255,255,255,0.1);
|
||||||
.player[state="loading"] .item[selected] .button > img:not(.loading)
|
|
||||||
{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.player .item:not([selected]) .button > img.play {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.player .item:not([selected]) .button > img:not(.play):not(.cover) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.player .item .button > img.cover {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
transition: opacity 0.2s;
|
cursor: pointer;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.player .item:hover .button > img.cover {
|
.component.sound button:hover {
|
||||||
opacity: 0.2;
|
background-color: rgba(255,255,255,0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.component.sound button > img {
|
||||||
|
background-color: rgba(255,255,255,0.9);
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.component.sound .content {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.component.sound .info {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.component.sound progress {
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
height: 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.component.sound progress:hover {
|
||||||
|
height: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** component: playlist **/
|
||||||
|
.component.playlist footer {
|
||||||
|
text-align: right;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
main .player .actions .action:not(.add),
|
.component.playlist .read_all {
|
||||||
.section_player .actions .action.add,
|
|
||||||
.player .list_item.live:hover .actions {
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.component.playlist .read_all + label {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.1em;
|
||||||
|
margin-left: 0.2em;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1em;
|
||||||
|
box-shadow: inset 0em 0em 0.1em #818181;
|
||||||
|
}
|
||||||
|
|
||||||
|
.component.playlist .read_all:not(:checked) + label {
|
||||||
|
border-left: 0.1em #818181 solid;
|
||||||
|
margin-right: 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.component.playlist .read_all:checked + label {
|
||||||
|
border-right: 0.1em #007EDF solid;
|
||||||
|
box-shadow: inset 0em 0em 0.1em #007EDF;
|
||||||
|
margin-right: 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** content: page **/
|
/** content: page **/
|
||||||
main .body ~ section:not(.comments) {
|
main .body ~ section:not(.comments) {
|
||||||
|
|
|
@ -19,36 +19,8 @@
|
||||||
|
|
||||||
/** detail view **/
|
/** detail view **/
|
||||||
|
|
||||||
/** player **/
|
|
||||||
.player[state='playing'] .item[selected] .button > img {
|
|
||||||
animation-duration: 4s;
|
|
||||||
animation-iteration-count: infinite;
|
|
||||||
animation-name: blink;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@keyframes blink {
|
|
||||||
from {
|
|
||||||
opacity: 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
50% {
|
|
||||||
opacity: 0.3;
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.player[state="loading"] .item[selected] .button > img.loading {
|
|
||||||
animation-duration: 2s;
|
|
||||||
animation-iteration-count: infinite;
|
|
||||||
animation-name: rotate;
|
|
||||||
animation-timing-function: linear;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes rotate {
|
@keyframes rotate {
|
||||||
from {
|
from {
|
||||||
transform: rotate(0deg);
|
transform: rotate(0deg);
|
||||||
|
|
|
@ -1,21 +1,13 @@
|
||||||
/* Implementation status: -- TODO
|
/* Implementation status: -- TODO
|
||||||
* - actions:
|
|
||||||
* - add to user playlist
|
|
||||||
* - go to detail
|
|
||||||
* - remove from playlist: for user playlist
|
|
||||||
* - save sound infos:
|
|
||||||
* - while playing: save current position
|
|
||||||
* - otherwise: remove from localstorage
|
|
||||||
* - save playlist in localstorage
|
|
||||||
* - proper design
|
* - proper design
|
||||||
* - mini-button integration in lists (list of diffusion articles)
|
* - mini-button integration in lists (list of diffusion articles)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
var State = Object.freeze({
|
var State = Object.freeze({
|
||||||
Stop: Symbol('Stop'),
|
Stop: 'stop',
|
||||||
Loading: Symbol('Loading'),
|
Loading: 'loading',
|
||||||
Play: Symbol('Play'),
|
Play: 'play',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -110,28 +102,29 @@ var Sound = Vue.extend({
|
||||||
state: State.Stop,
|
state: State.Stop,
|
||||||
// current position in playing sound
|
// current position in playing sound
|
||||||
position: 0,
|
position: 0,
|
||||||
// estimated position when user mouse over progress bar
|
|
||||||
seek_position: null,
|
|
||||||
// url to the page related to the sound
|
// url to the page related to the sound
|
||||||
detail_url: '',
|
detail_url: '',
|
||||||
|
// estimated position when user mouse over progress bar
|
||||||
|
user_seek: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
// sound can be seeked
|
// sound can be seeked
|
||||||
seekable: function() {
|
seekable() {
|
||||||
// seekable: for the moment only when we have a podcast file
|
// seekable: for the moment only when we have a podcast file
|
||||||
// note: need mounted because $refs is not reactive
|
// note: need mounted because $refs is not reactive
|
||||||
return this.mounted && this.duration && this.$refs.audio.seekable;
|
return this.mounted && this.duration && this.$refs.audio.seekable;
|
||||||
},
|
},
|
||||||
|
|
||||||
// sound duration in seconds
|
// sound duration in seconds
|
||||||
duration: function() {
|
duration() {
|
||||||
if(this.track.duration)
|
return this.track.duration;
|
||||||
return this.track.duration[0] * 3600 +
|
},
|
||||||
this.track.duration[1] * 60 +
|
|
||||||
this.track.duration[2];
|
seek_position() {
|
||||||
return null;
|
return (this.user_seek === null && this.position) ||
|
||||||
|
this.user_seek;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -196,6 +189,29 @@ var Sound = Vue.extend({
|
||||||
tracks.splice(i, 1);
|
tracks.splice(i, 1);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
//
|
||||||
|
// Utils functions
|
||||||
|
//
|
||||||
|
_as_progress_time(event) {
|
||||||
|
bounding = this.$refs.progress.getBoundingClientRect()
|
||||||
|
offset = (event.clientX - bounding.left);
|
||||||
|
return offset * this.$refs.audio.duration / bounding.width;
|
||||||
|
},
|
||||||
|
|
||||||
|
// format seconds into time string such as: [h"m]m'ss
|
||||||
|
format_time(seconds) {
|
||||||
|
seconds = Math.floor(seconds);
|
||||||
|
var hours = Math.floor(seconds / 3600);
|
||||||
|
seconds -= hours * 3600;
|
||||||
|
var minutes = Math.floor(seconds / 60);
|
||||||
|
seconds -= minutes * 60;
|
||||||
|
|
||||||
|
return (hours ? ((hours < 10 ? '0' + hours : hours) + '"') : '') +
|
||||||
|
minutes + "'" + seconds
|
||||||
|
;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Events
|
// Events
|
||||||
//
|
//
|
||||||
|
@ -214,21 +230,15 @@ var Sound = Vue.extend({
|
||||||
this.$emit('ended', this);
|
this.$emit('ended', this);
|
||||||
},
|
},
|
||||||
|
|
||||||
_as_progress_time(event) {
|
|
||||||
bounding = this.$refs.progress.getBoundingClientRect()
|
|
||||||
offset = (event.clientX - bounding.left);
|
|
||||||
return offset * this.$refs.audio.duration / bounding.width;
|
|
||||||
},
|
|
||||||
|
|
||||||
progress_mouse_out(event) {
|
progress_mouse_out(event) {
|
||||||
this.seek_position = null;
|
this.user_seek = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
progress_mouse_move(event) {
|
progress_mouse_move(event) {
|
||||||
if(this.$refs.audio.duration == Infinity ||
|
if(this.$refs.audio.duration == Infinity ||
|
||||||
isNaN(this.$refs.audio.duration))
|
isNaN(this.$refs.audio.duration))
|
||||||
return;
|
return;
|
||||||
this.seek_position = this._as_progress_time(event);
|
this.user_seek = this._as_progress_time(event);
|
||||||
},
|
},
|
||||||
|
|
||||||
progress_clicked(event) {
|
progress_clicked(event) {
|
||||||
|
@ -250,8 +260,8 @@ var Playlist = Vue.extend({
|
||||||
return {
|
return {
|
||||||
// if true, use this playlist as user's default playlist
|
// if true, use this playlist as user's default playlist
|
||||||
default: false,
|
default: false,
|
||||||
// single mode enabled
|
// read all mode enabled
|
||||||
single_mode: false,
|
read_all: false,
|
||||||
// playlist can be modified by user
|
// playlist can be modified by user
|
||||||
modifiable: false,
|
modifiable: false,
|
||||||
// if set, save items into localstorage using this root key
|
// if set, save items into localstorage using this root key
|
||||||
|
@ -261,6 +271,13 @@ var Playlist = Vue.extend({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
// id of the read all mode checkbox switch
|
||||||
|
read_all_id() {
|
||||||
|
return this.id + "_read_all";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
// set default
|
// set default
|
||||||
if(this.default) {
|
if(this.default) {
|
||||||
|
@ -283,8 +300,8 @@ var Playlist = Vue.extend({
|
||||||
// ensure sound is stopped (beforeDestroy())
|
// ensure sound is stopped (beforeDestroy())
|
||||||
sound.stop();
|
sound.stop();
|
||||||
|
|
||||||
// next only when single mode
|
// next only when read all mode
|
||||||
if(this.single_mode)
|
if(!this.read_all)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var sounds = this.$refs.sounds;
|
var sounds = this.$refs.sounds;
|
||||||
|
|
|
@ -9,16 +9,21 @@
|
||||||
<a-playlist class="playlist" id="{{ playlist_id }}">
|
<a-playlist class="playlist" id="{{ playlist_id }}">
|
||||||
<noscript>
|
<noscript>
|
||||||
{% for track in tracks %}
|
{% for track in tracks %}
|
||||||
<li class="item">
|
<div class="item">
|
||||||
<span class="name">{{ track.name }} ({{ track.duration|date:"H\"i's" }}): </span>
|
<span class="name">
|
||||||
|
{{ track.data.name }}
|
||||||
|
{% if track.data.duration %}
|
||||||
|
({{ track.data.duration_str }})
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
<span class="podcast">
|
<span class="podcast">
|
||||||
{% if not track.embed %}
|
{% if not track.data.embed %}
|
||||||
<audio src="{{ track.url|escape }}" controls>
|
<audio src="{{ track.url|escape }}" controls>
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ track.embed|safe }}
|
{{ track.embed|safe }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</noscript>
|
</noscript>
|
||||||
<script>
|
<script>
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
<script type="text/x-template" id="template-sound">
|
<script type="text/x-template" id="template-sound">
|
||||||
<div class="sound">
|
<div class="component sound flex_row"
|
||||||
|
:state="state"
|
||||||
|
>
|
||||||
<audio preload="metadata" ref="audio"
|
<audio preload="metadata" ref="audio"
|
||||||
@pause="state = State.Stop"
|
@pause="state = State.Stop"
|
||||||
@playing="state = State.Play"
|
@playing="state = State.Play"
|
||||||
|
@ -11,8 +13,9 @@
|
||||||
>
|
>
|
||||||
<source v-for="source in track.sources" :src="source">
|
<source v-for="source in track.sources" :src="source">
|
||||||
</audio>
|
</audio>
|
||||||
<img :src="track.cover" v-if="track.cover" class="icon cover">
|
<div class="cover button">
|
||||||
<button class="button" @click="play_stop">
|
<img :src="track.cover" v-if="track.cover">
|
||||||
|
<button @click="play_stop">
|
||||||
<img class="icon pause"
|
<img class="icon pause"
|
||||||
src="{% static "aircox/images/pause.png" %}"
|
src="{% static "aircox/images/pause.png" %}"
|
||||||
title="{% trans "Click to pause" %}"
|
title="{% trans "Click to pause" %}"
|
||||||
|
@ -26,14 +29,25 @@
|
||||||
title="{% trans "Click to play" %}"
|
title="{% trans "Click to play" %}"
|
||||||
v-else >
|
v-else >
|
||||||
</button>
|
</button>
|
||||||
<div>
|
</div>
|
||||||
<h3>
|
<div class="content flex_item">
|
||||||
|
<h3 class="flex_item">
|
||||||
<a :href="detail_url">[[ track.name ]]</a>
|
<a :href="detail_url">[[ track.name ]]</a>
|
||||||
</h3>
|
</h3>
|
||||||
<span v-if="track.duration" class="info">
|
<div v-if="track.duration" class="info">
|
||||||
[[ (track.duration[0] && track.duration[0] + '"') || '' ]]
|
<span v-if="seek_position !== null">
|
||||||
[[ track.duration[1] + "'" + track.duration[2] ]]
|
[[ format_time(seek_position) ]] /
|
||||||
</span>
|
</span>
|
||||||
|
<span v-else-if="state == State.Play">[[ format_time(position) ]] /</span>
|
||||||
|
[[ format_time(track.duration) ]]
|
||||||
|
</div>
|
||||||
|
<progress ref="progress"
|
||||||
|
v-show="state == State.Play && track.duration"
|
||||||
|
v-on:click.prevent="progress_clicked"
|
||||||
|
v-on:mousemove = "progress_mouse_move"
|
||||||
|
v-on:mouseout = "progress_mouse_out"
|
||||||
|
:value="seek_position" :max="duration"
|
||||||
|
></progress>
|
||||||
</div>
|
</div>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<a class="action remove"
|
<a class="action remove"
|
||||||
|
@ -47,35 +61,28 @@
|
||||||
v-else
|
v-else
|
||||||
>+</a>
|
>+</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="content flex_row" v-show="track.duration != null">
|
|
||||||
<span v-if="seek_position !== null">[[ seek_position ]]</span>
|
|
||||||
<span v-else>[[ position ]]</span>
|
|
||||||
<progress class="flex_item progress" ref="progress"
|
|
||||||
v-show="track.duration"
|
|
||||||
v-on:click.prevent="progress_clicked"
|
|
||||||
v-on:mousemove = "progress_mouse_move"
|
|
||||||
v-on:mouseout = "progress_mouse_out"
|
|
||||||
:value="position" :max="duration"
|
|
||||||
></progress>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<script type="text/x-template" id="template-playlist">
|
<script type="text/x-template" id="template-playlist">
|
||||||
<div class="playlist">
|
<div class="component playlist">
|
||||||
<a-sound v-for="track in tracks" ref="sounds"
|
<a-sound v-for="track in tracks" ref="sounds"
|
||||||
:id="track.id" :track="track"
|
:id="track.id" :track="track"
|
||||||
@ended="sound_ended"
|
@ended="sound_ended"
|
||||||
@beforeDestroy="sound_ended"
|
@beforeDestroy="sound_ended"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div v-show="tracks.length > 1" class="playlist_footer">
|
<footer v-show="tracks.length > 1" class="info">
|
||||||
<input type="checkbox" class="single" id="[[ playlist ]]_single_mode"
|
<span v-show="read_all">{% trans "read all" %}</span>
|
||||||
value="true" v-model="single_mode">
|
<input type="checkbox" class="read_all"
|
||||||
<label for="[[ playlist ]]_single_mode" class="info"
|
:id="read_all_id"
|
||||||
title="{% trans "Enable and disable single mode" %}">↻</label>
|
value="true" v-model="read_all">
|
||||||
</div>
|
<label :for="read_all_id"
|
||||||
|
title="{% trans "Read all the playlist" %}">
|
||||||
|
<img src="{% static "aircox/images/list.png" %}" class="small icon">
|
||||||
|
</label>
|
||||||
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user