-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add everything
0 parents
commit e1f8c0a
Showing
14 changed files
with
955 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
*,cover | ||
*.egg | ||
*.egg-info/ | ||
*.log | ||
*.manifest | ||
*.pot | ||
*.py[cod] | ||
*.so | ||
*.spec | ||
.cache | ||
.coverage | ||
.coverage.* | ||
.eggs/ | ||
.idea | ||
.installed.cfg | ||
.Python | ||
.tox/ | ||
__pycache__/ | ||
build/ | ||
coverage.xml | ||
develop-eggs/ | ||
dist/ | ||
docs/_build/ | ||
downloads/ | ||
eggs/ | ||
env/ | ||
htmlcov/ | ||
lib/ | ||
lib64/ | ||
nosetests.xml | ||
parts/ | ||
pip-delete-this-directory.txt | ||
pip-log.txt | ||
sdist/ | ||
target/ | ||
var/ |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
include README.rst | ||
include LICENSE | ||
|
||
recursive-include django_sorting_field *.css *.html *.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
Django Sorting Field | ||
==================== | ||
|
||
* This package implements a Django form field + widget for drag & drog sorting of items | ||
* Sorting any item with a field called ``id`` is supported | ||
* The drag and drop feature has been implemented with `html5sortable <https://lukasoppermann.github.io/html5sortable/index.html>`_. | ||
|
||
Example of the widget | ||
--------------------- | ||
|
||
.. image:: readme-media/example.gif | ||
|
||
Usage | ||
----- | ||
|
||
The sort order field should be implemented on the model containing the sorted objects. | ||
This allows ordering of different instances of the same item set differently. | ||
|
||
Let's say you have image CarouselPlugin, Carousel, and Picture models, and you wish to be able to | ||
sort the same Carousel instance differently on each CarouselPlugin. | ||
|
||
You also have a CMSPlugin object for the carousel. | ||
|
||
.. code-block:: python | ||
class Carousel(models.Model): | ||
pass | ||
class Picture(models.Model): | ||
carousel = models.ForeignKey(Carousel, related_name="pictures") | ||
image = SomeImageField() | ||
name = models.CharField() | ||
class CarouselPlugin(CMSPlugin): | ||
carousel = models.ForeignKey(Carousel, related_name="x") | ||
class CMSCarouselPlugin(CMSPluginBase): | ||
model = CarouselPlugin | ||
def render(self, context, instance, placeholder): | ||
context.update({ | ||
"pictures": self.instance.carousel.pictures.all(), | ||
}) | ||
return context | ||
Achieving the wanted behavior can be done in the following steps: | ||
|
||
Add a (nullable) TextField to the model containing the order information | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
.. code-block:: python | ||
class CarouselPlugin(CMSPlugin): | ||
carousel = models.ForeignKey(Carousel, related_name="x") | ||
carousel_order = models.TextField(null=True) | ||
Add the SortingFormField to the CMS Plugin and populate it | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
.. code-block:: python | ||
from django_sorting_field.fields import SortingFormField | ||
class CarouselPluginForm(forms.ModelForm): | ||
carousel_order = SortingFormField() | ||
def __init__(self, *args, **kwargs): | ||
super(CarouselPluginForm, self).__init__(*args, **kwargs) | ||
self.fields["carousel_order"].populate( | ||
items=self.instance.carousel.pictures.all(), | ||
) | ||
class CMSCarouselPlugin(CMSPluginBase): | ||
model = CarouselPlugin | ||
form = CarouselPluginForm | ||
def render(self, context, instance, placeholder): | ||
context.update({ | ||
"pictures": self.instance.carousel.pictures.all(), | ||
}) | ||
return context | ||
Finally, sort the items passed to the context data | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
.. code-block:: python | ||
from django_sorting_field.utils import iterate_in_order | ||
class CMSCarouselPlugin(CMSPluginBase): | ||
model = CarouselPlugin | ||
form = CarouselPluginForm | ||
def render(self, context, instance, placeholder): | ||
context.update({ | ||
"pictures": iterate_in_order( | ||
self.instance.carousel.pictures.all(), | ||
self.instance.carousel_order | ||
), | ||
}) | ||
return context |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from django import forms | ||
import json | ||
|
||
from widgets import SortingWidget | ||
from utils import iterate_in_order, clean_order_json | ||
|
||
|
||
class SortedItem(object): | ||
|
||
def __init__(self, identifier, label): | ||
self.id = identifier | ||
self.label = label | ||
|
||
|
||
class SortingFormField(forms.CharField): | ||
|
||
def __init__(self, *args, **kwargs): | ||
kwargs.update({ | ||
"widget": SortingWidget(), | ||
"required": False, | ||
}) | ||
self.items = () | ||
super(SortingFormField, self).__init__(*args, **kwargs) | ||
|
||
def populate(self, items): | ||
self.items = (SortedItem(item.pk, unicode(item)) for item in items) | ||
|
||
def prepare_value(self, value): | ||
value = clean_order_json(value) | ||
return iterate_in_order(self.items, value) | ||
|
||
def to_python(self, value): | ||
value = clean_order_json(value) | ||
return json.dumps(value) |
19 changes: 19 additions & 0 deletions
19
django_sorting_field/static/sorting/css/sorting_widget.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
.sortable-widget-list { | ||
} | ||
|
||
.sortable-widget-list .sortable-widget-placeholder, | ||
.sortable-widget-list .sortable-widget-item { | ||
padding: 10px; | ||
margin-bottom: 5px; | ||
margin-top: 5px; | ||
color: rgb(255, 255, 255); | ||
background-color: #0bf; | ||
border: 1px solid #0bf; | ||
border-radius: 3px; | ||
cursor: pointer; | ||
} | ||
|
||
.sortable-widget-list .sortable-widget-placeholder { | ||
border: 1px dashed #0bf; | ||
background-color: inherit; | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
const CreateSortableWidget = function(sortable_id) { | ||
var sortable_list_id = "#" + sortable_id + "_list"; | ||
|
||
var refreshInputValue = function() { | ||
result = []; | ||
$(sortable_list_id).children(".sortable-widget-item").each(function(index, element) { | ||
result.push($(element).data("id")); | ||
}); | ||
$("input#" + sortable_id).val(JSON.stringify(result)); | ||
} | ||
|
||
sortable(sortable_list_id, { | ||
placeholder: '<div class="sortable-widget-placeholder"> </div>' | ||
})[0].addEventListener("sortstop", function() { | ||
refreshInputValue(); | ||
}); | ||
|
||
refreshInputValue(); | ||
}; |
11 changes: 11 additions & 0 deletions
11
django_sorting_field/templates/sorting/widgets/sorting_widget.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<div class="sortable-widget-list" id="{{ id }}_list"> | ||
{% for item in items %} | ||
<div class="sortable-widget-item" data-id="{{ item.id }}">{{ item.label }}</div> | ||
{% endfor %} | ||
</div> | ||
<input type="hidden" id="{{ id }}" name="{{ name }}" value=""> | ||
<script type="text/javascript"> | ||
$(document).ready(function() { | ||
CreateSortableWidget("{{ id }}"); | ||
}); | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import json | ||
|
||
|
||
def clean_order_json(value): | ||
value = "[]" if value is None else value | ||
|
||
try: | ||
return json.loads(value) | ||
except ValueError: | ||
return [] | ||
|
||
|
||
def iterate_in_order(items, order): | ||
# In case our order is still in json format | ||
if isinstance(order, basestring): | ||
order = clean_order_json(order) | ||
|
||
items_by_id = {item.id: item for item in items} | ||
|
||
# Return items that are ordered first | ||
for entry in order: | ||
if entry not in items_by_id: | ||
continue | ||
yield items_by_id.pop(entry) | ||
|
||
# Return the rest | ||
for identifier, item in items_by_id.iteritems(): | ||
yield item |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from django.forms.widgets import Widget | ||
from django.utils.safestring import mark_safe | ||
from django.template.loader import render_to_string | ||
|
||
|
||
class SortingWidget(Widget): | ||
template_name = 'sorting/widgets/sorting_widget.html' | ||
|
||
class Media: | ||
css = { | ||
"all": ("sorting/css/sorting_widget.css",) | ||
} | ||
js = ( | ||
"sorting/js/html.sortable.min.js", | ||
"sorting/js/sorting_widget.js", | ||
) | ||
|
||
def render(self, name, value, attrs=None): | ||
context = attrs | ||
context.update({ | ||
"items": value, | ||
"name": name, | ||
}) | ||
html = render_to_string(self.template_name, context) | ||
return mark_safe(html) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import setuptools | ||
|
||
if __name__ == '__main__': | ||
setuptools.setup( | ||
name="django-sorting-field", | ||
version="1.0.0", | ||
description="Django Sorting Field", | ||
packages=setuptools.find_packages(), | ||
include_package_data=True, | ||
) |