- save & load

- key navigation
- ui improvements
This commit is contained in:
bkfox
2022-12-11 00:29:53 +01:00
parent cfc0e45439
commit 61af53eecb
10 changed files with 250 additions and 95 deletions

View File

@ -9,7 +9,7 @@ from adminsortable2.admin import SortableAdminBase, SortableInlineAdminMixin
from ..models import Sound, Track
class TrackInline(SortableInlineAdminMixin, admin.TabularInline):
class TrackInline(admin.TabularInline):
template = 'admin/aircox/playlist_inline.html'
model = Track
extra = 0

File diff suppressed because one or more lines are too long

View File

@ -4,21 +4,18 @@
{# include "adminsortable2/edit_inline/tabular-django-4.1.html" #}
{% with inline_admin_formset as admin_formset %}
{% with admin_formset.formset as formset %}
<script id="{{ formset.prefix }}-init-data">
{{ formset|inline_data|json }}
</script>
<div id="inline-tracks" class="box mb-5">
<h5 class="title is-4">{% trans "Playlist" %}</h5>
<script id="{{ formset.prefix }}-init-data">{
"items": [
{% for form in formset.forms %}
{{ form.initial|json }}
{% if not forloop.last %},{% endif %}
{% endfor %}
]
}
</script>
{{ admin_formset.non_form_errors }}
<a-playlist-editor>
<a-playlist-editor data-el="{{ formset.prefix }}-init-data"
data-prefix="{{ formset.prefix }}-">
<template #title>
<h5 class="title is-4">{% trans "Playlist" %}</h5>
</template>
<template v-slot:top="{items}">
<input type="hidden" name="{{ formset.prefix }}-TOTAL_FORMS"
:value="items.length || 0"/>
@ -43,7 +40,7 @@
<input type="hidden"
:name="'{{ formset.prefix }}-' + row + '-position'"
:value="row"/>
<input t-if="item.data.id" type="hidden"
<input t-if="item.id" type="hidden"
:name="'{{ formset.prefix }}-' + row + '-id'"
:value="item.data.id"/>
@ -59,11 +56,17 @@
{% for field in admin_formset.fields %}
{% if not field.widget.is_hidden and not field.is_readonly %}
<template v-slot:row-{{ field.name }}="{item,col,row,value,attr,emit}">
<div class="control">
<input type="{{ widget.type }}" class="input half-field"
:name="'{{ formset.prefix }}-' + row + '-{{ field.name }}'"
v-model="item.data[attr]"
@change="emit('change', col)"/>
<div class="field">
<div class="control">
<input type="{{ widget.type }}"
:class="['input', item.error(attr) ? 'is-danger' : 'half-field']"
:name="'{{ formset.prefix }}-' + row + '-{{ field.name }}'"
v-model="item.data[attr]"
@change="emit('change', col)"/>
</div>
<p v-for="error in item.error(attr)" class="help is-danger">
[[ error ]] !
</p>
</div>
</template>
{% endif %}

View File

@ -18,7 +18,7 @@ The audio player
</noscript>
<a-player ref="player"
:live-args="{url: '{% url "api:live" %}', timeout:10, src: {{ audio_streams|json }} || []}"
:live-args="{url: '{% url "api:live" %}', timeout:10, src: {{ audio_streams|json|force_escape }} || []}"
button-title="{% translate "Play or pause audio" %}">
<template v-slot:content="{ loaded, live, current }">
<h4 v-if="loaded" class="title is-4">

View File

@ -6,7 +6,7 @@ from django.contrib.admin.templatetags.admin_urls import admin_urlname
from django.urls import reverse
from django.utils.safestring import mark_safe
from aircox.models import Page, Diffusion, Log
from aircox.models import Diffusion, Log
random.seed()
register = template.Library()
@ -17,7 +17,8 @@ def do_admin_url(obj, arg, pass_id=True):
""" Reverse admin url for object """
name = admin_urlname(obj._meta, arg)
return reverse(name, args=(obj.id,)) if pass_id else reverse(name)
@register.filter(name='get_tracks')
def do_get_tracks(obj):
""" Get a list of track for the provided log, diffusion, or episode """
@ -28,6 +29,7 @@ def do_get_tracks(obj):
obj = obj.episode
return obj.track_set.all()
@register.simple_tag(name='has_perm', takes_context=True)
def do_has_perm(context, obj, perm, user=None):
""" Return True if ``user.has_perm('[APP].[perm]_[MODEL]')`` """
@ -36,17 +38,21 @@ def do_has_perm(context, obj, perm, user=None):
return user.has_perm('{}.{}_{}'.format(
obj._meta.app_label, perm, obj._meta.model_name))
@register.filter(name='is_diffusion')
def do_is_diffusion(obj):
""" Return True if object is a Diffusion. """
return isinstance(obj, Diffusion)
@register.filter(name='json')
def do_json(obj,fields=""):
def do_json(obj, fields=""):
""" Return object as json """
if fields:
obj = { k: getattr(obj,k,None) for k in ','.split(fields) }
return json.dumps(obj)
obj = {k: getattr(obj, k, None)
for k in ','.split(fields)}
return mark_safe(json.dumps(obj))
@register.simple_tag(name='nav_items', takes_context=True)
def do_nav_items(context, menu, **kwargs):
@ -55,6 +61,7 @@ def do_nav_items(context, menu, **kwargs):
return [(item, item.render(request, **kwargs))
for item in station.navitem_set.filter(menu=menu)]
@register.simple_tag(name='update_query')
def do_update_query(obj, **kwargs):
""" Replace provided querydict's values with **kwargs. """
@ -65,6 +72,7 @@ def do_update_query(obj, **kwargs):
obj.pop(k)
return obj
@register.filter(name='verbose_name')
def do_verbose_name(obj, plural=False):
"""
@ -72,6 +80,5 @@ def do_verbose_name(obj, plural=False):
string (can act for default values).
"""
return obj if isinstance(obj, str) else \
obj._meta.verbose_name_plural if plural else \
obj._meta.verbose_name
obj._meta.verbose_name_plural if plural else \
obj._meta.verbose_name

View File

@ -1,16 +1,27 @@
from django import template
from django.contrib import admin
from ..serializers import AdminTrackSerializer
register = template.Library()
@register.simple_tag(name='get_admin_tools')
def do_get_admin_tools():
return admin.site.get_tools()
@register.filter(name='serialize_track')
def do_serialize_track(instance):
ser = AdminTrackSerializer(instance=instance)
return ser.data
@register.filter(name='inline_data')
def do_inline_data(formset):
items = []
for form in formset.forms:
item = {name: form[name].value()
for name in form.fields.keys()}
item['__errors__'] = form.errors
# hack for playlist editor
tags = item.get('tags')
if tags and not isinstance(tags, str):
item['tags'] = ', '.join(tag.name for tag in tags)
items.append(item)
return {"items": items}