- save & load
- key navigation - ui improvements
This commit is contained in:
		@ -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
											
										
									
								
							@ -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 %}
 | 
			
		||||
 | 
			
		||||
@ -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">
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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}
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user