Skip to content

Commit

Permalink
Feature: Sortable for Stacked and Generic inlines added. #137
Browse files Browse the repository at this point in the history
  • Loading branch information
darklow committed Mar 21, 2014
1 parent af5663a commit 84eccfb
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 18 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ Changelog
Only important changes are mentioned below. See `commit log <https://github.com/darklow/django-suit/commits/develop>`_ and `closed issues <https://github.com/darklow/django-suit/issues?direction=desc&sort=updated&state=closed>`_ for full changes.


v0.2.7 (2014-03-21)
-------------------

* [Feature] `Sortables <http://django-suit.readthedocs.org/en/develop/sortables.html>`_ for `StackedInline <http://djangosuit.com/admin/examples/kitchensink/3/>`_ and Generic inlines added. Closes `#137 <https://github.com/darklow/django-suit/issues/137>`_
* [Fix] Fixes `#209 <https://github.com/darklow/django-suit/issues/209>`_ Wrap jQuery autosize in Suit jQuery scope
* [Fix] Fixes `#206 <https://github.com/darklow/django-suit/pull/206>`_ Fixed exception when menu config is Unicode [Thanks to @kane-c]
* [Fix] Fixes `#90 <https://github.com/darklow/django-suit/issues/90>`_ Django test sometimes crashes, because of Django Suit
* [Fix] Fixes login template for custom user model `#200 <https://github.com/darklow/django-suit/pull/200>`_ [Thanks to @theskumar]


v0.2.6 (2014-02-14)
-------------------------------------------------------------

Expand Down
Binary file added docs/_static/img/stacked_inline_sortable.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 29 additions & 4 deletions docs/sortables.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
Sortables
=========

Currently Django Suit supports three types of sortables:
Currently Django Suit supports these types of sortables:

1. Sortable for change list
2. Sortable for ``django-mptt`` tree list
3. Sortable for tabular inlines
3. Sortable for Tabular, Stacked, GenericTabular, GenericStacked inlines

Limitations
-----------
Expand Down Expand Up @@ -127,8 +127,6 @@ Resources
Tabular inlines sortable
------------------------

Currently inline sortable supports only TabularInline. Feel free to make a feature request `on Github <https://github.com/darklow/django-suit>`_, if you think also StackedInline should be supported.

1. In ``models.py`` your model for inlines, should have integer property for sortable, same way as described in all previous sortable examples::

from django.db import models
Expand Down Expand Up @@ -165,3 +163,30 @@ Resources
* `Live example #2 <http://djangosuit.com/admin/examples/kitchensink/2/>`_
* `Github source <https://github.com/darklow/django-suit-examples>`_


Stacked and Generic inlines sortable
------------------------------------

Implementation of sortables for Stacked and Generic inlines is the same as mentioned above for Tabular inlines. You just have to use appropriate base class instead of ``SortableTabularInline``:

::

# For Stacked inlines
from suit.admin import SortableStackedInline

# For Generic inlines
from suit.admin import SortableTabularStackedInline
from suit.admin import SortableGenericStackedInline


Example
^^^^^^^

.. image:: _static/img/stacked_inline_sortable.png
:target: http://djangosuit.com/admin/examples/kitchensink/3/

Resources
^^^^^^^^^

* `Live example <http://djangosuit.com/admin/examples/kitchensink/3/>`_
* `Github source <https://github.com/darklow/django-suit-examples>`_
71 changes: 66 additions & 5 deletions suit/admin.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import copy
from django.conf import settings
import suit.config
from django.contrib.admin import ModelAdmin
from django.contrib.admin.views.main import ChangeList
from django.contrib.contenttypes import generic
from django.forms import ModelForm
from django.contrib import admin
from django.db import models
from suit.widgets import NumberInput, SuitSplitDateTimeWidget, AutosizedTextarea
from suit.widgets import NumberInput, SuitSplitDateTimeWidget


class SortableModelAdminBase(object):
Expand Down Expand Up @@ -39,13 +40,13 @@ def get_ordering(self, request, queryset):
return [self.model_admin.sortable, '-' + self.model._meta.pk.name]


class SortableTabularInline(SortableModelAdminBase, admin.TabularInline):
class SortableTabularInlineBase(SortableModelAdminBase):
"""
Sortable tabular inline
"""

def __init__(self, *args, **kwargs):
super(SortableTabularInline, self).__init__(*args, **kwargs)
super(SortableTabularInlineBase, self).__init__(*args, **kwargs)

self.ordering = (self.sortable,)
self.fields = self.fields or []
Expand All @@ -55,10 +56,70 @@ def __init__(self, *args, **kwargs):
def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name == self.sortable:
kwargs['widget'] = SortableListForm.Meta.widgets['order']
return super(SortableTabularInline, self).formfield_for_dbfield(
return super(SortableTabularInlineBase, self).formfield_for_dbfield(
db_field, **kwargs)


class SortableTabularInline(SortableTabularInlineBase, admin.TabularInline):
pass


class SortableGenericTabularInline(SortableTabularInlineBase,
generic.GenericTabularInline):
pass


class SortableStackedInlineBase(SortableModelAdminBase):
"""
Sortable stacked inline
"""

def get_fieldsets(self, *args, **kwargs):
"""
Iterate all fieldsets and make sure sortable is in the first fieldset
Remove sortable from every other fieldset, if by some reason someone
has added it
"""
fieldsets = super(SortableStackedInlineBase, self).get_fieldsets(
*args, **kwargs)

sortable_added = False
for fieldset in fieldsets:
for line in fieldset:
if not line or not isinstance(line, dict):
continue

fields = line.get('fields')
if self.sortable in fields:
fields.remove(self.sortable)

# Add sortable field always as first
if not sortable_added:
fields.insert(0, self.sortable)
sortable_added = True
break

return fieldsets

def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name == self.sortable:
kwargs['widget'] = copy.deepcopy(
SortableListForm.Meta.widgets['order'])
kwargs['widget'].attrs['class'] += ' suit-sortable-stacked'
kwargs['widget'].attrs['rowclass'] = ' suit-sortable-stacked-row'
return super(SortableStackedInlineBase, self).formfield_for_dbfield(
db_field, **kwargs)


class SortableStackedInline(SortableStackedInlineBase, admin.StackedInline):
pass


class SortableGenericStackedInline(SortableStackedInlineBase,
generic.GenericStackedInline):
pass


class SortableModelAdmin(SortableModelAdminBase, ModelAdmin):
"""
Sortable tabular inline
Expand Down
3 changes: 3 additions & 0 deletions suit/static/suit/css/suit.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 33 additions & 9 deletions suit/static/suit/js/sortables.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,23 +60,47 @@
}

function on_arrow_click(e) {
perform_move($(this), $(this).closest('tr'));
var $sortable = $(this);
var $row = $sortable.closest(
$sortable.hasClass('sortable-stacked') ? 'div.inline-related' : 'tr'
);
perform_move($sortable, $row);
e.preventDefault();
}

function create_link(text, direction) {
function create_link(text, direction, on_click_func, is_stacked) {
return $('<a/>').attr('href', '#')
.addClass('sortable sortable-' + direction)
.addClass('sortable sortable-' + direction +
(is_stacked ? ' sortable-stacked' : ''))
.attr('data-dir', direction).html(text)
.click(on_arrow_click);
.click(on_click_func);
}

$inputs.each(function () {
var $inline_sortable = $('<div class="inline-sortable"/>');
var icon = '<i class="icon-arrow-up icon-alpha5"></i>';
$(this).parent().append($inline_sortable);
$inline_sortable.append(create_link(icon, 'up'));
$inline_sortable.append(create_link(icon.replace('-up', '-down'), 'down'));
var $inline_sortable = $('<div class="inline-sortable"/>'),
icon = '<i class="icon-arrow-up icon-alpha5"></i>',
$sortable = $(this),
is_stacked = $sortable.hasClass('suit-sortable-stacked');

var $up_link = create_link(icon, 'up', on_arrow_click, is_stacked),
$down_link = create_link(icon.replace('-up', '-down'), 'down', on_arrow_click, is_stacked);

if (is_stacked) {
var $sortable_row = $sortable.closest('div.form-row'),
$stacked_block = $sortable.closest('div.inline-related'),
$links_span = $('<span/>').attr('class', 'stacked-inline-sortable');

// Add arrows to header h3, move order input and remove order field row
$links_span.append($up_link).append($down_link);
$stacked_block.find('h3').append($links_span);
$stacked_block.append($sortable);
$sortable_row.remove();
} else {
$sortable.parent().append($inline_sortable);
$inline_sortable.append($up_link);
$inline_sortable.append($down_link);
}

});

// Filters out unchanged selects and sortable field itself
Expand Down
17 changes: 17 additions & 0 deletions suit/static/suit/less/ui/form.less
Original file line number Diff line number Diff line change
Expand Up @@ -619,3 +619,20 @@ h3 {
font-size: 11px;
margin-right: 5px;
}

/* StackedInline sortables */
.stacked-inline-sortable {
float: right;
:first-child {
padding-right: 1px;
}
&:nth-last-child(2) {
margin-right: 10px;
}
}
.inline-group > div:first-of-type .stacked-inline-sortable .sortable-up,
.inline-group > div:nth-last-child(3) .stacked-inline-sortable .sortable-down
{
opacity: .15 !important;
cursor: default;
}

0 comments on commit 84eccfb

Please sign in to comment.