django-reorder-items-widget 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. django_reorder_items_widget-1.0.0/LICENCE +27 -0
  2. django_reorder_items_widget-1.0.0/PKG-INFO +131 -0
  3. django_reorder_items_widget-1.0.0/README.md +97 -0
  4. django_reorder_items_widget-1.0.0/django_reorder_items_widget.egg-info/PKG-INFO +131 -0
  5. django_reorder_items_widget-1.0.0/django_reorder_items_widget.egg-info/SOURCES.txt +18 -0
  6. django_reorder_items_widget-1.0.0/django_reorder_items_widget.egg-info/dependency_links.txt +1 -0
  7. django_reorder_items_widget-1.0.0/django_reorder_items_widget.egg-info/requires.txt +1 -0
  8. django_reorder_items_widget-1.0.0/django_reorder_items_widget.egg-info/top_level.txt +1 -0
  9. django_reorder_items_widget-1.0.0/pyproject.toml +51 -0
  10. django_reorder_items_widget-1.0.0/reorder_items_widget/__init__.py +0 -0
  11. django_reorder_items_widget-1.0.0/reorder_items_widget/__version__.py +16 -0
  12. django_reorder_items_widget-1.0.0/reorder_items_widget/apps.py +6 -0
  13. django_reorder_items_widget-1.0.0/reorder_items_widget/static/css/reorder-items-widget.css +9 -0
  14. django_reorder_items_widget-1.0.0/reorder_items_widget/static/js/reorder-items-widget.js +136 -0
  15. django_reorder_items_widget-1.0.0/reorder_items_widget/templates/forms/widgets/reorder-items-widget.html +14 -0
  16. django_reorder_items_widget-1.0.0/reorder_items_widget/templatetags/__init__.py +0 -0
  17. django_reorder_items_widget-1.0.0/reorder_items_widget/templatetags/reorder_items_widget.py +9 -0
  18. django_reorder_items_widget-1.0.0/reorder_items_widget/tests.py +28 -0
  19. django_reorder_items_widget-1.0.0/reorder_items_widget/widgets.py +20 -0
  20. django_reorder_items_widget-1.0.0/setup.cfg +4 -0
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2024, Thomas Leichtfuß.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+
10
+ 2. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+
14
+ 3. Neither the name of the author nor the names of contributors
15
+ may be used to endorse or promote products derived from this software
16
+ without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,131 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-reorder-items-widget
3
+ Version: 1.0.0
4
+ Summary: Easily reorder the order of items within the django admin backend.
5
+ Author-email: Thomas Leichtfuß <thomas.leichtfuss@posteo.de>
6
+ License: BSD-3-Clause
7
+ Project-URL: Homepage, https://github.com/thomst/django-reorder-items-widget
8
+ Project-URL: Repository, https://github.com/thomst/django-reorder-items-widget
9
+ Project-URL: Documentation, https://github.com/thomst/django-reorder-items-widget#readme
10
+ Keywords: django,django-admin,widgets
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Framework :: Django
13
+ Classifier: Framework :: Django :: 3.2
14
+ Classifier: Framework :: Django :: 4.0
15
+ Classifier: Framework :: Django :: 4.1
16
+ Classifier: Framework :: Django :: 4.2
17
+ Classifier: Framework :: Django :: 5.0
18
+ Classifier: Framework :: Django :: 5.1
19
+ Classifier: Framework :: Django :: 5.2
20
+ Classifier: Framework :: Django :: 6.0
21
+ Classifier: Environment :: Web Environment
22
+ Classifier: Intended Audience :: Developers
23
+ Classifier: Operating System :: OS Independent
24
+ Classifier: Programming Language :: Python
25
+ Classifier: Programming Language :: Python :: 3
26
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
27
+ Classifier: Topic :: Software Development
28
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
29
+ Requires-Python: >=3.8
30
+ Description-Content-Type: text/markdown
31
+ License-File: LICENCE
32
+ Requires-Dist: Django>=3.2
33
+ Dynamic: license-file
34
+
35
+ # Welcome to django-reorder-items-widget
36
+
37
+ [![Tests](https://github.com/thomst/django-reorder-items-widget/actions/workflows/tests.yml/badge.svg)](https://github.com/thomst/django-reorder-items-widget/actions/workflows/tests.yml)
38
+ [<img src="https://coveralls.io/repos/github/thomst/django-reorder-items-widget/badge.svg?branch=main">](https://coveralls.io/github/thomst/django-reorder-items-widget?branch=main)
39
+ [<img src="https://img.shields.io/badge/python-3-blue">](https://img.shields.io/badge/python-3-blue)
40
+ [<img src="https://img.shields.io/badge/django-3.2%20%7C%204.0%20%7C%204.1%20%7C%204.2%20%7C%205.0%20%7C%205.1%20%7C%205.2%20%7C%206.0-orange">](https://img.shields.io/badge/django-3.2%20%7C%204.0%20%7C%204.1%20%7C%204.2%20%7C%205.0%20%7C%205.1%20%7C%205.2%20%7C%206.0-orange)
41
+
42
+
43
+ ## Description
44
+
45
+ Reorder your items by simply dragging them to their new position. This works
46
+ fine within django admin's changelists or inline model forms.
47
+
48
+ All you need to do is to use an editable index field with the famous
49
+ `ReorderItemsWidget` of this app.
50
+
51
+
52
+ ## Installation
53
+
54
+ Install via pip:
55
+ ```
56
+ pip install django-reorder-items-widget
57
+ ```
58
+
59
+ ## Setup
60
+
61
+ Add `reorder_items_widget` to your `INSTALLED_APPS`:
62
+ ```
63
+ INSTALLED_APPS = [
64
+ 'reorder_items_widget',
65
+ ...
66
+ ]
67
+ ```
68
+
69
+ Add a index field to your model:
70
+ ```
71
+ class Item(models.Model):
72
+ index = models.PositiveSmallIntegerField()
73
+ ...
74
+ class Meta:
75
+ ordering = ('index',)
76
+ ```
77
+
78
+ Using the ReorderItemsWidget with your index field only makes sense in result
79
+ lists or inline modeladmin forms. A simple way to put the widget in place is a
80
+ custom model form:
81
+ ```
82
+ class ReorderItemForm(forms.ModelForm):
83
+ class Meta:
84
+ widgets={'index': ReorderItemsWidget()}
85
+ ```
86
+
87
+ Now you can use this form with your changelist by overwriting the
88
+ `get_changelist_form` method of your model admin:
89
+ ```
90
+ class BaseItemAdmin(admin.ModelAdmin):
91
+ list_editable = ("index",)
92
+ list_display = ("index", ...)
93
+
94
+ def get_changelist_form(self, request, **kwargs):
95
+ kwargs.setdefault('form', ReorderItemForm)
96
+ return super().get_changelist_form(request, **kwargs)
97
+ ```
98
+
99
+ **_NOTE:_** Mind that your index field must be editable.
100
+
101
+ To use the widget with your inline modeladmin simple at your form to the
102
+ `TabularInline` class:
103
+ ```
104
+ class ItemInline(admin.TabularInline):
105
+ form = ReorderItemForm
106
+ fields = ("index", ...)
107
+ ...
108
+ ```
109
+
110
+ That's it.
111
+
112
+ ## Caveats
113
+
114
+ The widget will always number your items sequentially. Reordering items in a
115
+ filtered list might be have unexpected results. Paging however should not be a
116
+ problem since indexes are updated using the lowest one as base.
117
+
118
+ ## General considerations on switching index values
119
+
120
+ There is a general problem with switching values on a unique index field: In
121
+ mysql like databases you will run into a constraint violation - even if you
122
+ update all items in a single update transaction.
123
+
124
+ To work around this you can either obmit the unique constraint. Or implement a
125
+ complex saving logic like saving changed indexes as negative values first and
126
+ update them to their positiv counterpart afterwards.
127
+
128
+ ## Contribute
129
+
130
+ Feedback, feature requests, bug reports or pull requests are most welcome. Just
131
+ use the common github infrastructure.
@@ -0,0 +1,97 @@
1
+ # Welcome to django-reorder-items-widget
2
+
3
+ [![Tests](https://github.com/thomst/django-reorder-items-widget/actions/workflows/tests.yml/badge.svg)](https://github.com/thomst/django-reorder-items-widget/actions/workflows/tests.yml)
4
+ [<img src="https://coveralls.io/repos/github/thomst/django-reorder-items-widget/badge.svg?branch=main">](https://coveralls.io/github/thomst/django-reorder-items-widget?branch=main)
5
+ [<img src="https://img.shields.io/badge/python-3-blue">](https://img.shields.io/badge/python-3-blue)
6
+ [<img src="https://img.shields.io/badge/django-3.2%20%7C%204.0%20%7C%204.1%20%7C%204.2%20%7C%205.0%20%7C%205.1%20%7C%205.2%20%7C%206.0-orange">](https://img.shields.io/badge/django-3.2%20%7C%204.0%20%7C%204.1%20%7C%204.2%20%7C%205.0%20%7C%205.1%20%7C%205.2%20%7C%206.0-orange)
7
+
8
+
9
+ ## Description
10
+
11
+ Reorder your items by simply dragging them to their new position. This works
12
+ fine within django admin's changelists or inline model forms.
13
+
14
+ All you need to do is to use an editable index field with the famous
15
+ `ReorderItemsWidget` of this app.
16
+
17
+
18
+ ## Installation
19
+
20
+ Install via pip:
21
+ ```
22
+ pip install django-reorder-items-widget
23
+ ```
24
+
25
+ ## Setup
26
+
27
+ Add `reorder_items_widget` to your `INSTALLED_APPS`:
28
+ ```
29
+ INSTALLED_APPS = [
30
+ 'reorder_items_widget',
31
+ ...
32
+ ]
33
+ ```
34
+
35
+ Add a index field to your model:
36
+ ```
37
+ class Item(models.Model):
38
+ index = models.PositiveSmallIntegerField()
39
+ ...
40
+ class Meta:
41
+ ordering = ('index',)
42
+ ```
43
+
44
+ Using the ReorderItemsWidget with your index field only makes sense in result
45
+ lists or inline modeladmin forms. A simple way to put the widget in place is a
46
+ custom model form:
47
+ ```
48
+ class ReorderItemForm(forms.ModelForm):
49
+ class Meta:
50
+ widgets={'index': ReorderItemsWidget()}
51
+ ```
52
+
53
+ Now you can use this form with your changelist by overwriting the
54
+ `get_changelist_form` method of your model admin:
55
+ ```
56
+ class BaseItemAdmin(admin.ModelAdmin):
57
+ list_editable = ("index",)
58
+ list_display = ("index", ...)
59
+
60
+ def get_changelist_form(self, request, **kwargs):
61
+ kwargs.setdefault('form', ReorderItemForm)
62
+ return super().get_changelist_form(request, **kwargs)
63
+ ```
64
+
65
+ **_NOTE:_** Mind that your index field must be editable.
66
+
67
+ To use the widget with your inline modeladmin simple at your form to the
68
+ `TabularInline` class:
69
+ ```
70
+ class ItemInline(admin.TabularInline):
71
+ form = ReorderItemForm
72
+ fields = ("index", ...)
73
+ ...
74
+ ```
75
+
76
+ That's it.
77
+
78
+ ## Caveats
79
+
80
+ The widget will always number your items sequentially. Reordering items in a
81
+ filtered list might be have unexpected results. Paging however should not be a
82
+ problem since indexes are updated using the lowest one as base.
83
+
84
+ ## General considerations on switching index values
85
+
86
+ There is a general problem with switching values on a unique index field: In
87
+ mysql like databases you will run into a constraint violation - even if you
88
+ update all items in a single update transaction.
89
+
90
+ To work around this you can either obmit the unique constraint. Or implement a
91
+ complex saving logic like saving changed indexes as negative values first and
92
+ update them to their positiv counterpart afterwards.
93
+
94
+ ## Contribute
95
+
96
+ Feedback, feature requests, bug reports or pull requests are most welcome. Just
97
+ use the common github infrastructure.
@@ -0,0 +1,131 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-reorder-items-widget
3
+ Version: 1.0.0
4
+ Summary: Easily reorder the order of items within the django admin backend.
5
+ Author-email: Thomas Leichtfuß <thomas.leichtfuss@posteo.de>
6
+ License: BSD-3-Clause
7
+ Project-URL: Homepage, https://github.com/thomst/django-reorder-items-widget
8
+ Project-URL: Repository, https://github.com/thomst/django-reorder-items-widget
9
+ Project-URL: Documentation, https://github.com/thomst/django-reorder-items-widget#readme
10
+ Keywords: django,django-admin,widgets
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Framework :: Django
13
+ Classifier: Framework :: Django :: 3.2
14
+ Classifier: Framework :: Django :: 4.0
15
+ Classifier: Framework :: Django :: 4.1
16
+ Classifier: Framework :: Django :: 4.2
17
+ Classifier: Framework :: Django :: 5.0
18
+ Classifier: Framework :: Django :: 5.1
19
+ Classifier: Framework :: Django :: 5.2
20
+ Classifier: Framework :: Django :: 6.0
21
+ Classifier: Environment :: Web Environment
22
+ Classifier: Intended Audience :: Developers
23
+ Classifier: Operating System :: OS Independent
24
+ Classifier: Programming Language :: Python
25
+ Classifier: Programming Language :: Python :: 3
26
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
27
+ Classifier: Topic :: Software Development
28
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
29
+ Requires-Python: >=3.8
30
+ Description-Content-Type: text/markdown
31
+ License-File: LICENCE
32
+ Requires-Dist: Django>=3.2
33
+ Dynamic: license-file
34
+
35
+ # Welcome to django-reorder-items-widget
36
+
37
+ [![Tests](https://github.com/thomst/django-reorder-items-widget/actions/workflows/tests.yml/badge.svg)](https://github.com/thomst/django-reorder-items-widget/actions/workflows/tests.yml)
38
+ [<img src="https://coveralls.io/repos/github/thomst/django-reorder-items-widget/badge.svg?branch=main">](https://coveralls.io/github/thomst/django-reorder-items-widget?branch=main)
39
+ [<img src="https://img.shields.io/badge/python-3-blue">](https://img.shields.io/badge/python-3-blue)
40
+ [<img src="https://img.shields.io/badge/django-3.2%20%7C%204.0%20%7C%204.1%20%7C%204.2%20%7C%205.0%20%7C%205.1%20%7C%205.2%20%7C%206.0-orange">](https://img.shields.io/badge/django-3.2%20%7C%204.0%20%7C%204.1%20%7C%204.2%20%7C%205.0%20%7C%205.1%20%7C%205.2%20%7C%206.0-orange)
41
+
42
+
43
+ ## Description
44
+
45
+ Reorder your items by simply dragging them to their new position. This works
46
+ fine within django admin's changelists or inline model forms.
47
+
48
+ All you need to do is to use an editable index field with the famous
49
+ `ReorderItemsWidget` of this app.
50
+
51
+
52
+ ## Installation
53
+
54
+ Install via pip:
55
+ ```
56
+ pip install django-reorder-items-widget
57
+ ```
58
+
59
+ ## Setup
60
+
61
+ Add `reorder_items_widget` to your `INSTALLED_APPS`:
62
+ ```
63
+ INSTALLED_APPS = [
64
+ 'reorder_items_widget',
65
+ ...
66
+ ]
67
+ ```
68
+
69
+ Add a index field to your model:
70
+ ```
71
+ class Item(models.Model):
72
+ index = models.PositiveSmallIntegerField()
73
+ ...
74
+ class Meta:
75
+ ordering = ('index',)
76
+ ```
77
+
78
+ Using the ReorderItemsWidget with your index field only makes sense in result
79
+ lists or inline modeladmin forms. A simple way to put the widget in place is a
80
+ custom model form:
81
+ ```
82
+ class ReorderItemForm(forms.ModelForm):
83
+ class Meta:
84
+ widgets={'index': ReorderItemsWidget()}
85
+ ```
86
+
87
+ Now you can use this form with your changelist by overwriting the
88
+ `get_changelist_form` method of your model admin:
89
+ ```
90
+ class BaseItemAdmin(admin.ModelAdmin):
91
+ list_editable = ("index",)
92
+ list_display = ("index", ...)
93
+
94
+ def get_changelist_form(self, request, **kwargs):
95
+ kwargs.setdefault('form', ReorderItemForm)
96
+ return super().get_changelist_form(request, **kwargs)
97
+ ```
98
+
99
+ **_NOTE:_** Mind that your index field must be editable.
100
+
101
+ To use the widget with your inline modeladmin simple at your form to the
102
+ `TabularInline` class:
103
+ ```
104
+ class ItemInline(admin.TabularInline):
105
+ form = ReorderItemForm
106
+ fields = ("index", ...)
107
+ ...
108
+ ```
109
+
110
+ That's it.
111
+
112
+ ## Caveats
113
+
114
+ The widget will always number your items sequentially. Reordering items in a
115
+ filtered list might be have unexpected results. Paging however should not be a
116
+ problem since indexes are updated using the lowest one as base.
117
+
118
+ ## General considerations on switching index values
119
+
120
+ There is a general problem with switching values on a unique index field: In
121
+ mysql like databases you will run into a constraint violation - even if you
122
+ update all items in a single update transaction.
123
+
124
+ To work around this you can either obmit the unique constraint. Or implement a
125
+ complex saving logic like saving changed indexes as negative values first and
126
+ update them to their positiv counterpart afterwards.
127
+
128
+ ## Contribute
129
+
130
+ Feedback, feature requests, bug reports or pull requests are most welcome. Just
131
+ use the common github infrastructure.
@@ -0,0 +1,18 @@
1
+ LICENCE
2
+ README.md
3
+ pyproject.toml
4
+ django_reorder_items_widget.egg-info/PKG-INFO
5
+ django_reorder_items_widget.egg-info/SOURCES.txt
6
+ django_reorder_items_widget.egg-info/dependency_links.txt
7
+ django_reorder_items_widget.egg-info/requires.txt
8
+ django_reorder_items_widget.egg-info/top_level.txt
9
+ reorder_items_widget/__init__.py
10
+ reorder_items_widget/__version__.py
11
+ reorder_items_widget/apps.py
12
+ reorder_items_widget/tests.py
13
+ reorder_items_widget/widgets.py
14
+ reorder_items_widget/static/css/reorder-items-widget.css
15
+ reorder_items_widget/static/js/reorder-items-widget.js
16
+ reorder_items_widget/templates/forms/widgets/reorder-items-widget.html
17
+ reorder_items_widget/templatetags/__init__.py
18
+ reorder_items_widget/templatetags/reorder_items_widget.py
@@ -0,0 +1,51 @@
1
+ [build-system]
2
+ requires = ["setuptools"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "django-reorder-items-widget"
7
+ authors = [{name = "Thomas Leichtfuß", email = "thomas.leichtfuss@posteo.de"}]
8
+ description = "Easily reorder the order of items within the django admin backend."
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ keywords = ["django", "django-admin", "widgets"]
12
+ license = { text = "BSD-3-Clause"}
13
+ classifiers = [
14
+ "Development Status :: 5 - Production/Stable",
15
+ "Framework :: Django",
16
+ "Framework :: Django :: 3.2",
17
+ "Framework :: Django :: 4.0",
18
+ "Framework :: Django :: 4.1",
19
+ "Framework :: Django :: 4.2",
20
+ "Framework :: Django :: 5.0",
21
+ "Framework :: Django :: 5.1",
22
+ "Framework :: Django :: 5.2",
23
+ "Framework :: Django :: 6.0",
24
+ "Environment :: Web Environment",
25
+ "Intended Audience :: Developers",
26
+ "Operating System :: OS Independent",
27
+ "Programming Language :: Python",
28
+ "Programming Language :: Python :: 3",
29
+ "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
30
+ "Topic :: Software Development",
31
+ "Topic :: Software Development :: Libraries :: Application Frameworks",
32
+ ]
33
+ dependencies = [
34
+ "Django>=3.2",
35
+ ]
36
+ dynamic = ["version"]
37
+
38
+ [project.urls]
39
+ Homepage = "https://github.com/thomst/django-reorder-items-widget"
40
+ Repository = "https://github.com/thomst/django-reorder-items-widget"
41
+ Documentation = "https://github.com/thomst/django-reorder-items-widget#readme"
42
+
43
+ [tool.setuptools]
44
+ packages = ["reorder_items_widget", "reorder_items_widget.templatetags"]
45
+ include-package-data = false
46
+
47
+ [tool.setuptools.package-data]
48
+ reorder_items_widget = ["templates/**", "static/**"]
49
+
50
+ [tool.setuptools.dynamic]
51
+ version = {attr = "reorder_items_widget.__version__.__version__"}
@@ -0,0 +1,16 @@
1
+ """
2
+ This project uses the Semantic Versioning scheme in conjunction with PEP 0440:
3
+ <http://semver.org/>
4
+ <https://www.python.org/dev/peps/pep-0440>
5
+
6
+ Major versions introduce significant changes to the API, and backwards
7
+ compatibility is not guaranteed. Minor versions are for new features and other
8
+ backwards-compatible changes to the API. Patch versions are for bug fixes and
9
+ internal code changes that do not affect the API. Development versions are
10
+ incomplete states of a release .
11
+
12
+ Version 0.x should be considered a development version with an unstable API,
13
+ and backwards compatibility is not guaranteed for minor versions.
14
+ """
15
+
16
+ __version__ = "1.0.0"
@@ -0,0 +1,6 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class ReorderItemsWidgetConfig(AppConfig):
5
+ default_auto_field = 'django.db.models.BigAutoField'
6
+ name = 'reorder_items_widget'
@@ -0,0 +1,9 @@
1
+ .drag-handle {
2
+ display: inline;
3
+ cursor: grab;
4
+ font-size: 180%;
5
+ }
6
+
7
+ .on-drag {
8
+ opacity: 50%;
9
+ }
@@ -0,0 +1,136 @@
1
+ (function() {
2
+ "use strict";
3
+
4
+ class ReorderItemsTable {
5
+
6
+ constructor (table) {
7
+ this.table = table;
8
+ this.form = table.closest('form');
9
+ this.baseIndex = Number(table.querySelector('.reorder-items-widget-index').value);
10
+ const style = window.getComputedStyle(table.querySelector('tbody > tr'))
11
+ this.rowHeight = style.getPropertyValue('height');
12
+ this.initRows();
13
+ this.initHeaderAsDragOverAndDropZone();
14
+ this.initFormSubmission();
15
+ }
16
+
17
+ getRows() {
18
+ var selector;
19
+ if (this.table.id == 'result_list') {
20
+ selector = 'tbody > tr';
21
+ } else {
22
+ selector = 'tbody > tr.has_original'
23
+ }
24
+ return this.table.querySelectorAll(selector);
25
+ }
26
+
27
+ initRows() {
28
+ [].forEach.call(this.getRows(), (row) => {
29
+ this.initRowAsDragOver(row);
30
+ this.initRowAsDropZone(row);
31
+ this.initRowAsDraggable(row);
32
+ });
33
+ }
34
+
35
+ initRowAsDragOver(row) {
36
+ var counter = 0
37
+ const that = this;
38
+ row.addEventListener("dragenter", function (e) {
39
+ counter++;
40
+ // The hovering row is not itself or the one above - which also
41
+ // could be the header.
42
+ const firstRow = that.table.querySelector('tbody > tr');
43
+ if (
44
+ !row.draggable &&
45
+ !(row.nextElementSibling && row.nextElementSibling.draggable) &&
46
+ !(row.parentElement.nodeName == 'THEAD' && firstRow.draggable)
47
+ ) that.addDragOverStyle(row);
48
+ });
49
+ row.addEventListener("dragleave", function (e) {
50
+ counter--;
51
+ if (counter == 0)
52
+ that.removeDragOverStyle(row);
53
+ });
54
+ row.addEventListener("drop", function (e) {
55
+ counter = 0;
56
+ that.removeDragOverStyle(row);
57
+ });
58
+ }
59
+
60
+ addDragOverStyle(row) {
61
+ row.style.borderBottom = `${this.rowHeight} solid var(--selected-bg)`;
62
+ }
63
+
64
+ removeDragOverStyle(row) {
65
+ row.style.borderBottom = 0;
66
+ }
67
+
68
+ initRowAsDropZone(row) {
69
+ row.addEventListener("dragover", function (e) {
70
+ e.preventDefault();
71
+ });
72
+ row.addEventListener("drop", function (e) {
73
+ e.preventDefault();
74
+ const inputID = e.dataTransfer.getData("text");
75
+ const draggedRow = document.getElementById(inputID).closest('tr');
76
+ row.after(draggedRow);
77
+ });
78
+ }
79
+
80
+ initRowAsDraggable(row) {
81
+ const handle = row.querySelector('.drag-handle');
82
+ handle.addEventListener("mousedown", function (e) {
83
+ row.setAttribute('draggable', 'true');
84
+ });
85
+ handle.addEventListener("mouseup", function(e) {
86
+ row.setAttribute('draggable', 'false');
87
+ });
88
+ row.addEventListener("dragstart", function (e) {
89
+ row.classList.add("on-drag");
90
+ const inputID = row.querySelector('input.reorder-items-widget-index').id;
91
+ e.dataTransfer.setData("text", inputID);
92
+ });
93
+ row.addEventListener("dragend", function (e) {
94
+ row.classList.remove("on-drag");
95
+ row.setAttribute('draggable', 'false');
96
+ });
97
+ }
98
+
99
+ initHeaderAsDragOverAndDropZone() {
100
+ const row = this.table.querySelector('thead > tr');
101
+ this.initRowAsDragOver(row);
102
+ row.addEventListener("dragover", function (e) {
103
+ e.preventDefault();
104
+ });
105
+ const querySelector = this.table.querySelector.bind(this.table);
106
+ row.addEventListener("drop", function (e) {
107
+ e.preventDefault();
108
+ const inputID = e.dataTransfer.getData("text");
109
+ const draggedRow = document.getElementById(inputID).closest('tr');
110
+ const firstRow = querySelector('tbody > tr');
111
+ firstRow.before(draggedRow);
112
+ });
113
+ }
114
+
115
+ initFormSubmission() {
116
+ const that = this;
117
+ this.form.addEventListener("submit", function (e) {
118
+ [].forEach.call(that.getRows(), (row, counter) => {
119
+ const index = that.baseIndex + counter;
120
+ row.querySelector('.reorder-items-widget-index').value = index;
121
+ });
122
+ });
123
+ }
124
+ }
125
+
126
+
127
+ document.addEventListener("DOMContentLoaded", function () {
128
+ // Init each table which uses the reorder-items-widget.
129
+ document.querySelectorAll('table').forEach((el) => {
130
+ if (el.querySelector('.drag-handle')) {
131
+ new ReorderItemsTable(el);
132
+ }
133
+ });
134
+ });
135
+
136
+ })();
@@ -0,0 +1,14 @@
1
+ {% load reorder_items_widget %}
2
+
3
+ {% comment %}
4
+ We only render the widget for existing items. Doing something smart with the
5
+ index input for extra rows in inline model forms - like using a hidden input and
6
+ set the index within a pre-save signal handler - is not our buisness.
7
+ {% endcomment %}
8
+
9
+ {% if widget.value %}
10
+ {% hide_widget %}
11
+ <div title="Drag me!" class="drag-handle">⇳</div>
12
+ {% endif %}
13
+
14
+ {% include "django/forms/widgets/input.html" %}
@@ -0,0 +1,9 @@
1
+ from django import template
2
+
3
+ register = template.Library()
4
+
5
+
6
+ @register.simple_tag(takes_context=True)
7
+ def hide_widget(context):
8
+ context['widget']['attrs']['class'] += ' hidden'
9
+ return ''
@@ -0,0 +1,28 @@
1
+ from django.test import TestCase
2
+ from .widgets import ReorderItemsWidget
3
+
4
+ # Just for coverage score.
5
+ from . import __version__
6
+
7
+
8
+ class WidgetTestCase(TestCase):
9
+ def test_widget(self):
10
+ widget = ReorderItemsWidget()
11
+ css_classes = widget.build_attrs(dict(), dict())['class']
12
+ self.assertIn('reorder-items-widget-index', css_classes)
13
+
14
+ def test_rendering_with_value(self):
15
+ widget = ReorderItemsWidget()
16
+ html = widget.render('index', 1)
17
+ input = '<input type="number" name="index" value="1" class="reorder-items-widget-index hidden">'
18
+ drag_handle = '<div title="Drag me!" class="drag-handle">⇳</div>'
19
+ self.assertInHTML(input, html)
20
+ self.assertInHTML(drag_handle, html)
21
+
22
+ def test_rendering_without_value(self):
23
+ widget = ReorderItemsWidget()
24
+ html = widget.render('index', None)
25
+ input = '<input type="number" name="index" class="reorder-items-widget-index">'
26
+ drag_handle = '<div title="Drag me!" class="drag-handle">⇳</div>'
27
+ self.assertInHTML(input, html)
28
+ self.assertNotIn(drag_handle, html)
@@ -0,0 +1,20 @@
1
+ from django.forms import NumberInput
2
+
3
+
4
+ class ReorderItemsWidget(NumberInput):
5
+ """
6
+ A widget that allows to move items up and down within a listing with an
7
+ editable index field.
8
+ """
9
+ template_name = 'forms/widgets/reorder-items-widget.html'
10
+
11
+ class Media:
12
+ css = {'all': ('css/reorder-items-widget.css',)}
13
+ js = ('js/reorder-items-widget.js',)
14
+
15
+ def build_attrs(self, base_attrs, extra_attrs):
16
+ attrs = super().build_attrs(base_attrs, extra_attrs)
17
+ css_classes = attrs['class'].split(' ') if attrs.get('class') else []
18
+ css_classes += ['reorder-items-widget-index']
19
+ attrs['class'] = ' '.join(css_classes)
20
+ return attrs
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+