Merge branch 'master' into develop

This commit is contained in:
Brandon Taylor
2018-03-19 21:40:06 -04:00
36 changed files with 773 additions and 615 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
VERSION = (2, 0, 21)
VERSION = (2, 1, 4)
DEV_N = None
+36 -68
View File
@@ -3,24 +3,11 @@ import json
from django import VERSION
from django.conf import settings
try:
from django.conf.urls import url
except ImportError:
# Django < 1.4
from django.conf.urls.defaults import url
from django.conf.urls import url
from django.contrib.admin import ModelAdmin, TabularInline, StackedInline
from django.contrib.admin.options import InlineModelAdmin
try:
from django.contrib.contenttypes.admin import (GenericStackedInline,
GenericTabularInline)
except:
# Django < 1.7
from django.contrib.contenttypes.generic import (GenericStackedInline,
GenericTabularInline)
from django.contrib.contenttypes.admin import (GenericStackedInline,
GenericTabularInline)
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied
from django.http import HttpResponse, Http404
@@ -51,13 +38,7 @@ class SortableAdminBase(object):
its sort order can be changed. This view adds a link to the
object_tools block to take people to the view to change the sorting.
"""
try:
qs_method = getattr(self, 'get_queryset', self.queryset)
except AttributeError:
qs_method = self.get_queryset
if get_is_sortable(qs_method(request)):
if get_is_sortable(self.get_queryset(request)):
self.change_list_template = \
self.sortable_change_list_with_sort_link_template
self.is_sortable = True
@@ -101,12 +82,7 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
def get_urls(self):
urls = super(SortableAdmin, self).get_urls()
opts = self.model._meta
try:
info = opts.app_label, opts.model_name
except AttributeError:
# Django < 1.7
info = opts.app_label, opts.model_name
info = self.model._meta.app_label, self.model._meta.model_name
# this ajax view changes the order of instances of the model type
admin_do_sorting_url = url(
@@ -126,6 +102,24 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
] + urls
return urls
def get_sort_view_queryset(self, request, sortable_by_expression):
"""
Return a queryset, optionally filtered based on request and
`sortable_by_expression` to be used in the sort view.
"""
# get sort group index from querystring if present
sort_filter_index = request.GET.get('sort_filter')
filters = {}
if sort_filter_index:
try:
filters = self.model.sorting_filters[int(sort_filter_index)][1]
except (IndexError, ValueError):
pass
# Apply any sort filters to create a subset of sortable objects
return self.get_queryset(request).filter(**filters)
def sort_view(self, request):
"""
Custom admin view that displays the objects as a list whose sort
@@ -139,23 +133,6 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
jquery_lib_path = 'admin/js/jquery.js' if VERSION < (1, 9) \
else 'admin/js/vendor/jquery/jquery.js'
# get sort group index from querystring if present
sort_filter_index = request.GET.get('sort_filter')
filters = {}
if sort_filter_index:
try:
filters = self.model.sorting_filters[int(sort_filter_index)][1]
except (IndexError, ValueError):
pass
# Apply any sort filters to create a subset of sortable objects
try:
qs_method = getattr(self, 'get_queryset', self.queryset)
except AttributeError:
qs_method = self.get_queryset
objects = qs_method(request).filter(**filters)
# Determine if we need to regroup objects relative to a
# foreign key specified on the model class that is extending Sortable.
# Legacy support for 'sortable_by' defined as a model property
@@ -169,7 +146,11 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
for field in self.model._meta.fields:
if isinstance(field, SortableForeignKey):
sortable_by_fk = field.rel.to
try:
sortable_by_fk = field.remote_field.model
except AttributeError:
# Django < 1.9
sortable_by_fk = field.rel.to
sortable_by_field_name = field.name.lower()
sortable_by_class_is_sortable = sortable_by_fk.objects.count() >= 2
@@ -199,6 +180,8 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
sortable_by_class_display_name = \
sortable_by_class_is_sortable = None
objects = self.get_sort_view_queryset(request, sortable_by_expression)
if sortable_by_property or sortable_by_fk:
# Order the objects by the property they are sortable by,
# then by the order, otherwise the regroup
@@ -206,9 +189,6 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
try:
order_field_name = opts.model._meta.ordering[0]
except (AttributeError, IndexError):
# for Django 1.5.x
order_field_name = opts.ordering[0]
except (AttributeError, IndexError):
order_field_name = 'order'
@@ -301,8 +281,11 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
for index in indexes:
obj = objects_dict.get(index)
setattr(obj, order_field_name, start_index)
obj.save()
# perform the update only if the order field has changed
if getattr(obj, order_field_name) != start_index:
setattr(obj, order_field_name, start_index)
# only update the object's order field
obj.save(update_fields=(order_field_name,))
start_index += step
response = {'objects_sorted': True}
except (KeyError, IndexError, klass.DoesNotExist,
@@ -329,27 +312,18 @@ class SortableInlineBase(SortableAdminBase, InlineModelAdmin):
' (or Sortable for legacy implementations)')
def get_queryset(self, request):
if VERSION < (1, 6):
qs = super(SortableInlineBase, self).queryset(request)
else:
qs = super(SortableInlineBase, self).get_queryset(request)
qs = super(SortableInlineBase, self).get_queryset(request)
if get_is_sortable(qs):
self.model.is_sortable = True
else:
self.model.is_sortable = False
return qs
if VERSION < (1, 6):
queryset = get_queryset
class SortableTabularInline(TabularInline, SortableInlineBase):
"""Custom template that enables sorting for tabular inlines"""
if VERSION >= (1, 10):
template = 'adminsortable/edit_inline/tabular-1.10.x.html'
elif VERSION < (1, 6):
template = 'adminsortable/edit_inline/tabular-1.5.x.html'
else:
template = 'adminsortable/edit_inline/tabular.html'
@@ -358,8 +332,6 @@ class SortableStackedInline(StackedInline, SortableInlineBase):
"""Custom template that enables sorting for stacked inlines"""
if VERSION >= (1, 10):
template = 'adminsortable/edit_inline/stacked-1.10.x.html'
elif VERSION < (1, 6):
template = 'adminsortable/edit_inline/stacked-1.5.x.html'
else:
template = 'adminsortable/edit_inline/stacked.html'
@@ -368,8 +340,6 @@ class SortableGenericTabularInline(GenericTabularInline, SortableInlineBase):
"""Custom template that enables sorting for tabular inlines"""
if VERSION >= (1, 10):
template = 'adminsortable/edit_inline/tabular-1.10.x.html'
elif VERSION < (1, 6):
template = 'adminsortable/edit_inline/tabular-1.5.x.html'
else:
template = 'adminsortable/edit_inline/tabular.html'
@@ -378,7 +348,5 @@ class SortableGenericStackedInline(GenericStackedInline, SortableInlineBase):
"""Custom template that enables sorting for stacked inlines"""
if VERSION >= (1, 10):
template = 'adminsortable/edit_inline/stacked-1.10.x.html'
elif VERSION < (1, 6):
template = 'adminsortable/edit_inline/stacked-1.5.x.html'
else:
template = 'adminsortable/edit_inline/stacked.html'
+1 -11
View File
@@ -7,14 +7,4 @@ class SortableForeignKey(ForeignKey):
This field replaces previous functionality where `sortable_by` was
defined as a model property that specified another model class.
"""
def south_field_triple(self):
try:
from south.modelsinspector import introspector
cls_name = '{0}.{1}'.format(
self.__class__.__module__,
self.__class__.__name__)
args, kwargs = introspector(self)
return cls_name, args, kwargs
except ImportError:
pass
pass
@@ -0,0 +1,51 @@
msgid ""
msgstr ""
"Project-Id-Version: adminsortable\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-09-22 15:42+0200\n"
"PO-Revision-Date: 2018-02-08 22:47+0200\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Last-Translator: Pēteris <pb@sungis.lv>\n"
"Language-Team: \n"
"Language: lv\n"
"X-Generator: Poedit 1.8.7.1\n"
#: templates/adminsortable/change_list.html:15
#, python-format
msgid "Drag and drop %(model)s to change display order"
msgstr "Velc un novieto %(model)s, lai mainītu attēlošanas secību"
#: templates/adminsortable/change_list.html:25
#, python-format
msgid "Reorder"
msgstr "Pārkārtot"
#: templates/adminsortable/change_list.html:32
#, python-format
msgid "Drag and drop %(sort_type)s %(model)s to change their order."
msgstr "Velc un novieto %(sort_type)s %(model)s, lai mainītu to secību."
#: templates/adminsortable/change_list.html:34
#, python-format
msgid "Drag and drop %(model)s to change their order."
msgstr "Velc un novieto %(model)s, lai mainītu attēlošanas secību."
#: templates/adminsortable/change_list.html:39
#, python-format
msgid ""
"You may also drag and drop %(sortable_by_class_display_name)s to change "
"their order."
msgstr ""
"Tu vari arī vilt un pārvieetot %(sortable_by_class_display_name)s, lai "
"mainītu secību."
#: templates/adminsortable/change_list.html:50
#, python-format
msgid "Return to %(model)s"
msgstr "Atgriezties pie %(model)s"
#: templates/adminsortable/change_list_with_sort_link.html:6
msgid "Change Order"
msgstr "Mainīt secību"
Binary file not shown.
@@ -0,0 +1,51 @@
msgid ""
msgstr ""
"Project-Id-Version: adminsortable\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-09-22 15:42+0200\n"
"PO-Revision-Date: 2018-02-05 17:24+0100\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Last-Translator: Simen Heggestøyl <simenheg@gmail.com>\n"
"Language-Team: \n"
"Language: nb\n"
"X-Generator: Poedit 2.0.5\n"
#: templates/adminsortable/change_list.html:15
#, python-format
msgid "Drag and drop %(model)s to change display order"
msgstr "Dra og slipp %(model)s for å endre visningsrekkefølgen"
#: templates/adminsortable/change_list.html:25
#, python-format
msgid "Reorder"
msgstr "Endre rekkefølge"
#: templates/adminsortable/change_list.html:32
#, python-format
msgid "Drag and drop %(sort_type)s %(model)s to change their order."
msgstr "Dra og slipp %(sort_type)s %(model)s for å endre rekkefølgen deres."
#: templates/adminsortable/change_list.html:34
#, python-format
msgid "Drag and drop %(model)s to change their order."
msgstr "Dra og slipp %(model)s for å endre rekkefølgen deres."
#: templates/adminsortable/change_list.html:39
#, python-format
msgid ""
"You may also drag and drop %(sortable_by_class_display_name)s to change "
"their order."
msgstr ""
"Du kan også dra og slippe %(sortable_by_class_display_name)s for å endre "
"rekkefølgen deres."
#: templates/adminsortable/change_list.html:50
#, python-format
msgid "Return to %(model)s"
msgstr "Tilbake til %(model)s"
#: templates/adminsortable/change_list_with_sort_link.html:6
msgid "Change Order"
msgstr "Endre rekkefølge"
@@ -19,10 +19,15 @@
#sortable ul li
{
overflow: auto;
margin-bottom: 8px;
margin-left: 0;
display: block;
}
#sortable ul li:last-child {
margin-bottom: 0;
}
#sortable .sortable
{
list-style: none;
@@ -0,0 +1,11 @@
/*!
* jQuery UI Touch Punch 0.2.3
*
* Copyright 20112014, Dave Furfero
* Dual licensed under the MIT or GPL Version 2 licenses.
*
* Depends:
* jquery.ui.widget.js
* jquery.ui.mouse.js
*/
!function(a){function f(a,b){if(!(a.originalEvent.touches.length>1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery);
@@ -8,6 +8,7 @@
{% if has_sortable_tabular_inlines or has_sortable_stacked_inlines %}
<script type="text/javascript" src="{% static 'adminsortable/js/jquery-ui-django-admin.min.js' %}"></script>
<script src="{% static 'adminsortable/js/jquery.ui.touch-punch.min.js' %}"></script>
{% include 'adminsortable/csrf/jquery.django-csrf.html' with csrf_cookie_name=csrf_cookie_name %}
{% endif %}
@@ -1,5 +1,5 @@
{% extends "admin/base_site.html" %}
{% load i18n admin_urls static admin_list adminsortable_tags %}
{% load i18n admin_urls static admin_list %}
{% block extrastyle %}
{{ block.super }}
@@ -26,6 +26,7 @@
<script src="{% static jquery_lib_path %}"></script>
<script src="{% static 'admin/js/jquery.init.js' %}"></script>
<script src="{% static 'adminsortable/js/jquery-ui-django-admin.min.js' %}"></script>
<script src="{% static 'adminsortable/js/jquery.ui.touch-punch.min.js' %}"></script>
{% include 'adminsortable/csrf/jquery.django-csrf.html' with csrf_cookie_name=csrf_cookie_name %}
<script src="{% static 'adminsortable/js/admin.sortable.js' %}"></script>
{% endblock %}
@@ -74,20 +75,20 @@
{% block content %}
<div id="content-main">
{% block object-tools %}
<ul class="object-tools">
<li>
<a href="{% url opts|admin_urlname:'changelist' %}">
{% blocktrans with opts.verbose_name_plural|capfirst as model %}Return to {{ model }}{% endblocktrans %}
</a>
</li>
</ul>
{% endblock %}
<ul class="object-tools">
<li>
<a href="{% url opts|admin_urlname:'changelist' %}">
{% blocktrans with opts.verbose_name_plural|capfirst as model %}Return to {{ model }}{% endblocktrans %}
</a>
</li>
</ul>
{% endblock %}
{% if objects %}
<div id="sortable">
{% if group_expression %}
{% render_nested_sortable_objects objects group_expression %}
{% include "adminsortable/shared/nested_objects.html" %}
{% else %}
{% render_sortable_objects objects %}
{% include "adminsortable/shared/objects.html" %}
{% endif %}
{% csrf_token %}
</div>
@@ -16,7 +16,7 @@
return cookieValue;
}
var csrftoken = getCookie('{{ csrf_cookie_name }}');
var csrftoken = '{{ csrf_token }}' || getCookie('{{ csrf_cookie_name }}');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
@@ -1,92 +0,0 @@
{% load i18n admin_modify adminsortable_tags admin_urls %}
{% load static from staticfiles %}
<div class="inline-group" id="{{ inline_admin_formset.formset.prefix }}-group">
<h2>{{ inline_admin_formset.opts.verbose_name_plural|title }} {% if inline_admin_formset.formset.initial_form_count > 1 %} - {% trans "drag and drop to change order" %}{% endif %}</h2>
{{ inline_admin_formset.formset.management_form }}
{{ inline_admin_formset.formset.non_form_errors }}
{% for inline_admin_form in inline_admin_formset %}<div class="inline-related{% if inline_admin_form.original %} has_original{% endif %}{% if forloop.last %} empty-form last-related{% endif %}" id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
<h3>
{% if inline_admin_form.original %}
{% with initial_forms_count=inline_admin_formset.formset.management_form.INITIAL_FORMS.value %}
<i class="fa fa-{% if forloop.first %}sort-desc{% elif forloop.counter == initial_forms_count %}sort-asc{% else %}sort{% endif %}"></i>
{% endwith %}
{% endif %}
<b>{{ inline_admin_formset.opts.verbose_name|title }}:</b>&nbsp;<span class="inline_label">{% if inline_admin_form.original %}{{ inline_admin_form.original }}{% else %}#{{ forloop.counter }}{% endif %}</span>
{% if inline_admin_form.show_url %}<a href="../../../r/{{ inline_admin_form.original_content_type_id }}/{{ inline_admin_form.original.id }}/">{% trans "View on site" %}</a>{% endif %}
{% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}<span class="delete">{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}</span>{% endif %}
</h3>
{% if inline_admin_form.form.non_field_errors %}{{ inline_admin_form.form.non_field_errors }}{% endif %}
{% for fieldset in inline_admin_form %}
{% include "admin/includes/fieldset.html" %}
{% endfor %}
{% if inline_admin_form.has_auto_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
{{ inline_admin_form.fk_field.field }}
{% if inline_admin_form.original %}
<input type="hidden" name="admin_sorting_url" value="{% url opts|admin_urlname:'do_sorting' inline_admin_form.original.model_type_id %}" />
{% endif %}
</div>{% endfor %}
</div>
<script type="text/javascript">
(function($) {
$(document).ready(function() {
var rows = "#{{ inline_admin_formset.formset.prefix }}-group .inline-related";
var updateInlineLabel = function(row) {
$(rows).find(".inline_label").each(function(i) {
var count = i + 1;
$(this).html($(this).html().replace(/(#\d+)/g, "#" + count));
});
}
var reinitDateTimeShortCuts = function() {
// Reinitialize the calendar and clock widgets by force, yuck.
if (typeof DateTimeShortcuts != "undefined") {
$(".datetimeshortcuts").remove();
DateTimeShortcuts.init();
}
}
var updateSelectFilter = function() {
// If any SelectFilter widgets were added, instantiate a new instance.
if (typeof SelectFilter != "undefined"){
$(".selectfilter").each(function(index, value){
var namearr = value.name.split('-');
SelectFilter.init(value.id, namearr[namearr.length-1], false, "{% static 'admin/' %}");
});
$(".selectfilterstacked").each(function(index, value){
var namearr = value.name.split('-');
SelectFilter.init(value.id, namearr[namearr.length-1], true, "{% static 'admin/' %}");
});
}
}
var initPrepopulatedFields = function(row) {
row.find('.prepopulated_field').each(function() {
var field = $(this);
var input = field.find('input, select, textarea');
var dependency_list = input.data('dependency_list') || [];
var dependencies = [];
$.each(dependency_list, function(i, field_name) {
dependencies.push('#' + row.find(field_name).find('input, select, textarea').attr('id'));
});
if (dependencies.length) {
input.prepopulate(dependencies, input.attr('maxlength'));
}
});
}
$(rows).formset({
prefix: "{{ inline_admin_formset.formset.prefix }}",
addText: "{% blocktrans with inline_admin_formset.opts.verbose_name|title as verbose_name %}Add another {{ verbose_name }}{% endblocktrans %}",
formCssClass: "dynamic-{{ inline_admin_formset.formset.prefix }}",
deleteCssClass: "inline-deletelink",
deleteText: "{% trans "Remove" %}",
emptyCssClass: "empty-form",
removed: updateInlineLabel,
added: (function(row) {
initPrepopulatedFields(row);
reinitDateTimeShortCuts();
updateSelectFilter();
updateInlineLabel(row);
})
});
});
})(django.jQuery);
</script>
@@ -1,136 +0,0 @@
{% load i18n admin_modify adminsortable_tags admin_urls %}
{% load static from staticfiles %}
<div class="inline-group" id="{{ inline_admin_formset.formset.prefix }}-group">
<div class="tabular inline-related {% if forloop.last %}last-related{% endif %}">
{{ inline_admin_formset.formset.management_form }}
<fieldset class="module">
<h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }} {% if inline_admin_formset.formset.initial_form_count > 1 %} - {% trans "drag and drop to change order" %}{% endif %}</h2>
{{ inline_admin_formset.formset.non_form_errors }}
<table>
<thead><tr>
{% for field in inline_admin_formset.fields %}
{% if not field.widget.is_hidden %}
<th{% if forloop.first %} colspan="2"{% endif %}{% if field.required %} class="required"{% endif %}>{{ field.label|capfirst }}</th>
{% endif %}
{% endfor %}
{% if inline_admin_formset.formset.can_delete %}<th>{% trans "Delete?" %}</th>{% endif %}
</tr></thead>
<tbody>
{% for inline_admin_form in inline_admin_formset %}
{% if inline_admin_form.form.non_field_errors %}
<tr><td colspan="{{ inline_admin_form|cell_count }}">{{ inline_admin_form.form.non_field_errors }}</td></tr>
{% endif %}
<tr class="{% cycle "row1" "row2" %} {% if inline_admin_form.original or inline_admin_form.show_url %}has_original{% endif %}{% if forloop.last %} empty-form{% endif %}"
id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
<td class="original">
{% if inline_admin_form.original or inline_admin_form.show_url %}<p>
{% with initial_forms_count=inline_admin_form.formset.management_form.INITIAL_FORMS.value %}
<i class="fa fa-{% if forloop.first %}sort-desc{% elif forloop.counter == initial_forms_count %}sort-asc{% else %}sort{% endif %}"></i>
{% endwith %}
{% if inline_admin_form.original %} {{ inline_admin_form.original }}{% endif %}
{% if inline_admin_form.show_url %}<a href="../../../r/{{ inline_admin_form.original_content_type_id }}/{{ inline_admin_form.original.id }}/">{% trans "View on site" %}</a>{% endif %}
</p>{% endif %}
{% if inline_admin_form.has_auto_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
{{ inline_admin_form.fk_field.field }}
{% spaceless %}
{% for fieldset in inline_admin_form %}
{% for line in fieldset %}
{% for field in line %}
{% if field.is_hidden %} {{ field.field }} {% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endspaceless %}
{% if inline_admin_form.original %}
<input type="hidden" name="admin_sorting_url" value="{% url opts|admin_urlname:'do_sorting' inline_admin_form.original.model_type_id %}" />
{% endif %}
</td>
{% for fieldset in inline_admin_form %}
{% for line in fieldset %}
{% for field in line %}
<td class="{{ field.field.name }}">
{% if field.is_readonly %}
<p>{{ field.contents }}</p>
{% else %}
{{ field.field.errors.as_ul }}
{{ field.field }}
{% endif %}
</td>
{% endfor %}
{% endfor %}
{% endfor %}
{% if inline_admin_formset.formset.can_delete %}
<td class="delete">{% if inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }}{% endif %}</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</fieldset>
</div>
</div>
<script type="text/javascript">
(function($) {
$(document).ready(function($) {
var rows = "#{{ inline_admin_formset.formset.prefix }}-group .tabular.inline-related tbody tr";
var alternatingRows = function(row) {
$(rows).not(".add-row").removeClass("row1 row2")
.filter(":even").addClass("row1").end()
.filter(rows + ":odd").addClass("row2");
}
var reinitDateTimeShortCuts = function() {
// Reinitialize the calendar and clock widgets by force
if (typeof DateTimeShortcuts != "undefined") {
$(".datetimeshortcuts").remove();
DateTimeShortcuts.init();
}
}
var updateSelectFilter = function() {
// If any SelectFilter widgets are a part of the new form,
// instantiate a new SelectFilter instance for it.
if (typeof SelectFilter != "undefined"){
$(".selectfilter").each(function(index, value){
var namearr = value.name.split('-');
SelectFilter.init(value.id, namearr[namearr.length-1], false, "{% static 'admin/' %}");
});
$(".selectfilterstacked").each(function(index, value){
var namearr = value.name.split('-');
SelectFilter.init(value.id, namearr[namearr.length-1], true, "{% static 'admin/' %}");
});
}
}
var initPrepopulatedFields = function(row) {
row.find('.prepopulated_field').each(function() {
var field = $(this);
var input = field.find('input, select, textarea');
var dependency_list = input.data('dependency_list') || [];
var dependencies = [];
$.each(dependency_list, function(i, field_name) {
dependencies.push('#' + row.find(field_name).find('input, select, textarea').attr('id'));
});
if (dependencies.length) {
input.prepopulate(dependencies, input.attr('maxlength'));
}
});
}
$(rows).formset({
prefix: "{{ inline_admin_formset.formset.prefix }}",
addText: "{% blocktrans with inline_admin_formset.opts.verbose_name|title as verbose_name %}Add another {{ verbose_name }}{% endblocktrans %}",
formCssClass: "dynamic-{{ inline_admin_formset.formset.prefix }}",
deleteCssClass: "inline-deletelink",
deleteText: "{% trans "Remove" %}",
emptyCssClass: "empty-form",
removed: alternatingRows,
added: (function(row) {
initPrepopulatedFields(row);
reinitDateTimeShortCuts();
updateSelectFilter();
alternatingRows(row);
})
});
});
})(django.jQuery);
</script>
@@ -1,9 +1,8 @@
{% load adminsortable_tags %}
{% with list_objects_length=list_objects|length %}
{% for object in list_objects %}
<li>
{% if list_objects_length > 1 %}
{% render_object_rep object forloop %}
{% include "adminsortable/shared/object_rep.html" %}
{% else %}
{{ object }}
{% endif %}
@@ -1,4 +1,4 @@
{% load django_template_additions adminsortable_tags %}
{% load django_template_additions %}
{% dynamic_regroup objects by group_expression as regrouped_objects %}
{% if regrouped_objects %}
<ul {% if sortable_by_class_is_sortable %}class="sortable"{% endif %}>
@@ -6,7 +6,7 @@
{% with object=regrouped_object.grouper %}
{% if object %}
<li class="parent">{% if sortable_by_class_is_sortable %}
{% render_object_rep object forloop %}
{% include "adminsortable/shared/object_rep.html" %}
{% else %}
{{ object }}
{% endif %}
@@ -14,7 +14,7 @@
{% if regrouped_object.list %}
{% with regrouped_object_list_length=regrouped_object.list|length %}
<ul {% if regrouped_object_list_length > 1 %}class="sortable"{% endif %}>
{% render_list_items regrouped_object.list %}
{% include "adminsortable/shared/list_items.html" with list_objects=regrouped_object.list %}
</ul>
{% endwith %}
{% endif %}
@@ -1,4 +1,4 @@
{% load adminsortable_tags admin_urls %}
{% load admin_urls %}
<form>
<input name="pk" type="hidden" value="{{ object.pk }}" />
@@ -1,7 +1,5 @@
{% load adminsortable_tags %}
{% if objects %}
<ul class="sortable single">
{% render_list_items objects %}
{% include "adminsortable/shared/list_items.html" with list_objects=objects %}
</ul>
{% endif %}
@@ -1,35 +0,0 @@
from django import template
register = template.Library()
@register.simple_tag(takes_context=True)
def render_sortable_objects(context, objects,
sortable_objects_template='adminsortable/shared/objects.html'):
context.update({'objects': objects})
tmpl = template.loader.get_template(sortable_objects_template)
return tmpl.render(context)
@register.simple_tag(takes_context=True)
def render_nested_sortable_objects(context, objects, group_expression,
sortable_nested_objects_template='adminsortable/shared/nested_objects.html'):
context.update({'objects': objects, 'group_expression': group_expression})
tmpl = template.loader.get_template(sortable_nested_objects_template)
return tmpl.render(context)
@register.simple_tag(takes_context=True)
def render_list_items(context, list_objects,
sortable_list_items_template='adminsortable/shared/list_items.html'):
context.update({'list_objects': list_objects})
tmpl = template.loader.get_template(sortable_list_items_template)
return tmpl.render(context)
@register.simple_tag(takes_context=True)
def render_object_rep(context, obj, forloop,
sortable_object_rep_template='adminsortable/shared/object_rep.html'):
context.update({'object': obj, 'forloop': forloop})
tmpl = template.loader.get_template(sortable_object_rep_template)
return tmpl.render(context)
@@ -2,11 +2,6 @@ from itertools import groupby
import django
from django import template
try:
from django import TemplateSyntaxError
except ImportError:
#support for django 1.3
from django.template.base import TemplateSyntaxError
register = template.Library()
@@ -64,14 +59,15 @@ def dynamic_regroup(parser, token):
"""
firstbits = token.contents.split(None, 3)
if len(firstbits) != 4:
raise TemplateSyntaxError("'regroup' tag takes five arguments")
raise template.TemplateSyntaxError("'regroup' tag takes five arguments")
target = parser.compile_filter(firstbits[1])
if firstbits[2] != 'by':
raise TemplateSyntaxError("second argument to 'regroup' tag must be 'by'")
raise template.TemplateSyntaxError(
"second argument to 'regroup' tag must be 'by'")
lastbits_reversed = firstbits[3][::-1].split(None, 2)
if lastbits_reversed[1][::-1] != 'as':
raise TemplateSyntaxError("next-to-last argument to 'regroup' tag must"
" be 'as'")
raise template.TemplateSyntaxError(
"next-to-last argument to 'regroup' tag must be 'as'")
expression = lastbits_reversed[2][::-1]
var_name = lastbits_reversed[0][::-1]
@@ -80,7 +76,7 @@ def dynamic_regroup(parser, token):
return DynamicRegroupNode(target, parser, expression, var_name)
@register.assignment_tag
@register.simple_tag
def get_django_version():
version = django.VERSION
return {'major': version[0], 'minor': version[1]}