Browse Source

Improve admin-sortable-2 appearance

Denis K 9 years ago
parent
commit
2e66d8da55

+ 44 - 0
jet/static/adminsortable2/js/inline-sortable.js

@@ -0,0 +1,44 @@
+// make tabular- and stacked inlines sortable
+jQuery(function($) {
+	$('div.inline-group.sortable').each(function() {
+		var default_order_field = $(this).find('.default_order_field').attr('default_order_field');
+		var order_input_field = 'input[name$="-' + default_order_field + '"]';
+		// first, try with tabluar inlines
+		var tabular_inlines = $(this).find('div.tabular table');
+		tabular_inlines.sortable({
+			handle: $(this).find('tbody .drag'),
+			items: 'tr.form-row.has_original',
+			axis: 'y',
+			scroll: true,
+			cursor: 'ns-resize',
+			containment: $(this).find('tbody'),
+			stop: function(event, dragged_rows) {
+				var $result_list = $(this);
+				$result_list.find('tbody tr').each(function(index) {
+					$(this).removeClass('row1 row2').addClass(index % 2 ? 'row2' : 'row1');
+				});
+				$result_list.find('tbody tr.has_original').each(function(index) {
+					$(this).find(order_input_field).val(index + 1);
+				});
+			}
+		});
+		if (tabular_inlines.length)
+			return true;
+		// else, try with stacked inlines
+		$(this).find('.stacked-inline-list').each(function() {
+			$(this).sortable({
+				items: '.stacked-inline-list-item.has_original',
+				axis: 'y',
+				scroll: true,
+				cursor: 'move',
+				stop: function(event, dragged_rows) {
+					var $result_list = $(this);
+					$result_list.find('.stacked-inline-list-item.has_original .stacked-inline-list-item-link').each(function(index) {
+						var id = $(this).data('inline-related-id');
+						$('#' + id).find(order_input_field).val(index + 1);
+					});
+				}
+			});
+		});
+	});
+});

+ 94 - 0
jet/static/adminsortable2/js/list-sortable.js

@@ -0,0 +1,94 @@
+"use strict";
+
+jQuery.extend({
+	getQueryParams: function() {
+		var vars = [], hash, i;
+		var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
+		for (i = 0; i < hashes.length; i++) {
+			hash = hashes[i].split('=');
+			vars.push(hash[0]);
+			vars[hash[0]] = hash[1];
+		}
+		return vars;
+	},
+	getQueryParam: function(name) {
+		return jQuery.getQueryParams()[name];
+	}
+});
+
+// make list view sortable
+jQuery(function($) {
+	var startindex, startorder, endindex, endorder;
+	var csrfvalue = $('form').find('input[name="csrfmiddlewaretoken"]').val();
+	var ordering = $.getQueryParam('o');
+
+	if (window.admin_sortable2 === undefined)
+		return;  // global variables not initialized by change_list.html
+	if (ordering === undefined) {
+		ordering = '1';
+	}
+
+	var $helper;
+
+	$('#result_list').sortable({
+        tolerance: 'pointer',
+		items: 'tr',
+        cursor: 'move',
+        axis: 'y',
+		containment: $('#result_list tbody'),
+        forcePlaceholderSize: true,
+		helper: function(e, tr){
+            var $originals = tr.children();
+            $helper = tr.clone().addClass('dragging');
+            $helper.children().each(function(index) {
+                $(this).width($originals.eq(index).width())
+            });
+
+            return $helper;
+        },
+		start: function(event, dragged_rows) {
+			$('#result_list tr.ui-sortable-placeholder').attr('height', $helper.height() + 1);
+			startindex = dragged_rows.item.index();
+		},
+		stop: function(event, dragged_rows) {
+			var $result_list = $(this);
+			$result_list.find('tbody tr').each(function(index) {
+				$(this).removeClass('row1 row2').addClass(index % 2 ? 'row2' : 'row1');
+			});
+			endindex = dragged_rows.item.index()
+
+			if (startindex == endindex) return;
+			else if (endindex == 0) {
+				if (ordering.split('.')[0] === '-1')
+					endorder = parseInt($(dragged_rows.item.context.nextElementSibling).find('div.drag').attr('order')) + 1;
+				else
+					endorder = parseInt($(dragged_rows.item.context.nextElementSibling).find('div.drag').attr('order')) - 1;
+			} else {
+				endorder = $(dragged_rows.item.context.previousElementSibling).find('div.drag').attr('order');
+			}
+			startorder = $(dragged_rows.item.context).find('div.drag').attr('order');
+
+			$.ajax({
+				url: window.admin_sortable2.update_url,
+				type: 'POST',
+				data: {
+					o: ordering,
+					startorder: startorder,
+					endorder: endorder,
+					csrfmiddlewaretoken: csrfvalue
+				},
+				success: function(moved_items) {
+					$.each(moved_items, function(index, item) {
+						$result_list.find('tbody tr input.action-select[value=' + item.pk + ']').parents('tr').each(function() {
+							$(this).find('div.drag').attr('order', item.order);
+						});
+					});
+				},
+				error: function(response) {
+					console.error('The server responded: ' + response.responseText);
+				}
+			});
+		}
+	});
+	$('#result_list, tbody, tr, td, th').disableSelection();
+});

+ 2 - 1
jet/static/jet/css/_base.scss

@@ -70,4 +70,5 @@ a:hover {
 @import "login";
 @import "content";
 @import "dashboard";
-@import "relatedpopup";
+@import "relatedpopup";
+@import "sortable";

+ 34 - 0
jet/static/jet/css/_sortable.scss

@@ -0,0 +1,34 @@
+@import "globals";
+
+#result_list, table.helper {
+  thead .column-_reorder {
+    width: 16px !important;
+
+    & * {
+      display: none !important;
+    }
+  }
+
+  tbody tr {
+    .field-_reorder {
+      text-align: center;
+
+      div.drag {
+        visibility: hidden;
+        background: none !important;
+
+        &:after {
+          @include font-icon;
+          vertical-align: middle;
+          font-size: 16px;
+          font-weight: bold;
+          content: $icon-order;
+        }
+      }
+    }
+
+    &:hover .field-_reorder div.drag, &.dragging .field-_reorder div.drag {
+      visibility: visible;
+    }
+  }
+}

+ 2 - 1
jet/static/jet/css/_table.scss

@@ -110,6 +110,7 @@
 
   tbody {
     tr {
+      background: $content-background-color;
       border-bottom: 1px solid $content-border-color;
 
       &:last-child {
@@ -130,7 +131,7 @@
       }
     }
 
-    tr.selected {
+    tr.selected, tr.dragging {
       border-color: $content-selected-border-color;
 
       &:last-child {

+ 1 - 0
jet/static/jet/css/icons/_variables.scss

@@ -1,3 +1,4 @@
+$icon-order: "\e901";
 $icon-reset: "\e61e";
 $icon-search: "\e61d";
 $icon-user: "\e61c";

BIN
jet/static/jet/css/icons/fonts/jet-icons.eot


+ 1 - 0
jet/static/jet/css/icons/fonts/jet-icons.svg

@@ -38,4 +38,5 @@
 <glyph unicode="&#xe61c;" glyph-name="user" d="M851.481 250.954c-39.072 50.987-86.335 84.097-154.057 102.883l-63.453-222.157c0-20.464-16.755-37.216-37.216-37.216-20.455 0-37.21 16.753-37.21 37.216v176.765c0 25.674-20.845 46.519-46.519 46.519s-46.516-20.847-46.516-46.519v-176.765c0-20.464-16.755-37.216-37.212-37.216-20.464 0-37.218 16.753-37.218 37.216l-63.453 222.157c-67.723-18.969-114.985-51.895-154.053-102.883-15.446-20.095-23.839-60.471-24.388-82.063 0.185-5.581 0-12.095 0-18.601v-74.435c0-41.12 33.309-74.425 74.43-74.425h576.815c41.12 0 74.435 33.305 74.435 74.425v74.435c0 6.505-0.182 13.019 0 18.601-0.563 21.591-8.946 61.97-24.383 82.063zM317.649 697.706c0-108.665 67.744-268.315 195.375-268.315 125.413 0 195.371 159.65 195.371 268.315 0 108.661-87.454 196.862-195.371 196.862s-195.375-88.201-195.375-196.862z" />
 <glyph unicode="&#xe61d;" glyph-name="search" d="M120.942 128.031l203.291 203.291c-38.651 53.090-61.716 118.249-61.716 188.955 0 177.713 144.047 321.759 321.759 321.759s321.759-144.047 321.759-321.759-144.047-321.759-321.759-321.759c-70.706 0-135.862 23.068-188.955 61.716l-203.291-203.291-71.089 71.089zM584.274 299.065c121.965 0 221.209 99.243 221.209 221.209s-99.243 221.209-221.209 221.209-221.209-99.243-221.209-221.209 99.243-221.209 221.209-221.209z" />
 <glyph unicode="&#xe61e;" glyph-name="reset" horiz-adv-x="1013" d="M1011.457 476.745c-56.408-0.485-112.778-0.784-169.149-1.269 9.482-97.062-22.511-197.371-96.838-271.586-131.966-131.929-345.801-131.929-477.692 0-131.929 131.817-131.929 345.689 0 477.618 112.554 112.591 284.652 128.607 414.714 49.016-44.088-43.566-95.942-95.158-95.942-95.158-37.331-39.646 0.635-65.927 25.759-66.077h329.562c12.618 0 22.772 10.191 22.809 22.809v326.874c1.531 30.798-32.292 59.432-65.554 26.132 0 0-55.81-55.213-94.56-93.664-198.080 144.771-477.244 128.345-656.174-50.547-197.856-197.856-197.856-518.645 0-716.464 197.819-197.782 518.608-197.782 716.427 0 107.664 107.589 156.195 251.614 146.638 392.316z" />
+<glyph unicode="&#xe901;" glyph-name="order" horiz-adv-x="384" d="M192 256l64 64v-192h128l-192-192-192 192h128v192zM192 638.016l-64-62.016v192h-128l192 192 192-192h-128v-192z" />
 </font></defs></svg>

BIN
jet/static/jet/css/icons/fonts/jet-icons.ttf


BIN
jet/static/jet/css/icons/fonts/jet-icons.woff


+ 83 - 1
jet/templates/adminsortable2/stacked-1.5.html

@@ -1 +1,83 @@
-{% extends "admin/edit_inline/stacked.html" %}
+{% load i18n admin_urls admin_static jet_tags %}
+
+<div class="module" id="inline_module_{{ index }}">
+<div class="inline-group sortable" id="{{ inline_admin_formset.formset.prefix }}-group">
+    {{ inline_admin_formset.formset.management_form }}
+    {% if errors %}
+        <p class="errornote">
+            {% trans "Please correct the errors below." %}
+        </p>
+    {% endif %}
+    {{ inline_admin_formset.formset.non_form_errors }}
+    <div class="stacked-inline{% if not inline_admin_formset.formset|if_onetoone %} side{% endif %} cf">
+        {% if not inline_admin_formset.formset|if_onetoone %}
+            <div class="stacked-inline-side">
+                <div class="stacked-inline-side-top"></div>
+                <ul class="stacked-inline-list">
+                    {% for inline_admin_form in inline_admin_formset %}
+                        <li class="stacked-inline-list-item {% if inline_admin_form.original %} has_original{% endif %}{% if forloop.first and not forloop.last %} selected{% endif %}{% if forloop.last %} empty{% endif %}{% if inline_admin_form.form.errors %} errors{% endif %}">
+                            <a href="#" class="stacked-inline-list-item-link" data-inline-related-id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
+                                {% if not inline_admin_form.original %}
+                                    <span class="stacked-inline-list-item-link-remove">{% trans "Remove" %}</span>
+                                    <span class="icon-new"></span>
+                                {% endif %}
+                                <b>{{ inline_admin_formset.opts.verbose_name|capfirst }}:</b>&nbsp;
+                                <span class="inline_label">
+                                    {% if inline_admin_form.original %}
+                                        {{ inline_admin_form.original }}
+                                    {% else %}
+                                        #{{ forloop.counter }}
+                                    {% endif %}
+                                </span>
+                            </a>
+                        </li>
+                    {% endfor %}
+                </ul>
+                <div class="stacked-inline-side-bottom"></div>
+            </div>
+        {% endif %}
+        <div class="stacked-inline-content">
+            {% for inline_admin_form in inline_admin_formset %}
+                <div class="stacked {% if forloop.first and not forloop.last %}selected {% endif %}inline-related {% if inline_admin_form.original or inline_admin_form.show_url %} 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 %}">
+                    <div class="actions">
+                    {% if inline_admin_form.original and inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %}
+                        <a href="{% url inline_admin_form.model_admin.opts|admin_urlname:'change' inline_admin_form.original.pk|admin_urlquote %}" class="inlinechangelink" title="{% trans "Change" %} {{ inline_admin_form.original }}">
+                            <span class="icon-edit"></span>
+                        </a>
+                    {% endif %}
+                    {% if inline_admin_form.show_url %}
+                        <a href="{{ inline_admin_form.absolute_url }}" title="{% trans "View on site" %}">
+                            <span class="icon-open-external"></span>
+                        </a>
+                    {% endif %}
+                    </div>
+                    {% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}
+                        <div class="delete">{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }} {{ inline_admin_formset.opts.verbose_name|capfirst }}</div>
+                    {% endif %}
+                    {% 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" with errors=False %}
+                    {% endfor %}
+                    {% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
+                    {{ inline_admin_form.fk_field.field }}
+                </div>
+            {% endfor %}
+        </div>
+    </div>
+<div class="default_order_field" default_order_field="{{ inline_admin_formset.formset.default_order_field }}"></div>
+</div>
+</div>
+
+<script type="text/javascript">
+(function($) {
+  $("#{{ inline_admin_formset.formset.prefix }}-group .inline-related").stackedFormset({
+    prefix: '{{ inline_admin_formset.formset.prefix }}',
+    adminStaticPrefix: '{% static "admin/" %}',
+    deleteText: "{% trans "Remove" %}",
+    addText: "<span class=\"icon-add\"></span> {% blocktrans with verbose_name=inline_admin_formset.opts.verbose_name|capfirst %}Add another {{ verbose_name }}{% endblocktrans %}"
+  });
+})(django.jQuery);
+</script>
+
+
+

+ 83 - 1
jet/templates/adminsortable2/stacked-1.6.html

@@ -1 +1,83 @@
-{% extends "admin/edit_inline/stacked.html" %}
+{% load i18n admin_urls admin_static jet_tags %}
+
+<div class="module" id="inline_module_{{ index }}">
+<div class="inline-group sortable" id="{{ inline_admin_formset.formset.prefix }}-group">
+    {{ inline_admin_formset.formset.management_form }}
+    {% if errors %}
+        <p class="errornote">
+            {% trans "Please correct the errors below." %}
+        </p>
+    {% endif %}
+    {{ inline_admin_formset.formset.non_form_errors }}
+    <div class="stacked-inline{% if not inline_admin_formset.formset|if_onetoone %} side{% endif %} cf">
+        {% if not inline_admin_formset.formset|if_onetoone %}
+            <div class="stacked-inline-side">
+                <div class="stacked-inline-side-top"></div>
+                <ul class="stacked-inline-list">
+                    {% for inline_admin_form in inline_admin_formset %}
+                        <li class="stacked-inline-list-item {% if inline_admin_form.original %} has_original{% endif %}{% if forloop.first and not forloop.last %} selected{% endif %}{% if forloop.last %} empty{% endif %}{% if inline_admin_form.form.errors %} errors{% endif %}">
+                            <a href="#" class="stacked-inline-list-item-link" data-inline-related-id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
+                                {% if not inline_admin_form.original %}
+                                    <span class="stacked-inline-list-item-link-remove">{% trans "Remove" %}</span>
+                                    <span class="icon-new"></span>
+                                {% endif %}
+                                <b>{{ inline_admin_formset.opts.verbose_name|capfirst }}:</b>&nbsp;
+                                <span class="inline_label">
+                                    {% if inline_admin_form.original %}
+                                        {{ inline_admin_form.original }}
+                                    {% else %}
+                                        #{{ forloop.counter }}
+                                    {% endif %}
+                                </span>
+                            </a>
+                        </li>
+                    {% endfor %}
+                </ul>
+                <div class="stacked-inline-side-bottom"></div>
+            </div>
+        {% endif %}
+        <div class="stacked-inline-content">
+            {% for inline_admin_form in inline_admin_formset %}
+                <div class="stacked {% if forloop.first and not forloop.last %}selected {% endif %}inline-related {% if inline_admin_form.original or inline_admin_form.show_url %} 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 %}">
+                    <div class="actions">
+                    {% if inline_admin_form.original and inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %}
+                        <a href="{% url inline_admin_form.model_admin.opts|admin_urlname:'change' inline_admin_form.original.pk|admin_urlquote %}" class="inlinechangelink" title="{% trans "Change" %} {{ inline_admin_form.original }}">
+                            <span class="icon-edit"></span>
+                        </a>
+                    {% endif %}
+                    {% if inline_admin_form.show_url %}
+                        <a href="{{ inline_admin_form.absolute_url }}" title="{% trans "View on site" %}">
+                            <span class="icon-open-external"></span>
+                        </a>
+                    {% endif %}
+                    </div>
+                    {% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}
+                        <div class="delete">{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }} {{ inline_admin_formset.opts.verbose_name|capfirst }}</div>
+                    {% endif %}
+                    {% 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" with errors=False %}
+                    {% endfor %}
+                    {% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
+                    {{ inline_admin_form.fk_field.field }}
+                </div>
+            {% endfor %}
+        </div>
+    </div>
+<div class="default_order_field" default_order_field="{{ inline_admin_formset.formset.default_order_field }}"></div>
+</div>
+</div>
+
+<script type="text/javascript">
+(function($) {
+  $("#{{ inline_admin_formset.formset.prefix }}-group .inline-related").stackedFormset({
+    prefix: '{{ inline_admin_formset.formset.prefix }}',
+    adminStaticPrefix: '{% static "admin/" %}',
+    deleteText: "{% trans "Remove" %}",
+    addText: "<span class=\"icon-add\"></span> {% blocktrans with verbose_name=inline_admin_formset.opts.verbose_name|capfirst %}Add another {{ verbose_name }}{% endblocktrans %}"
+  });
+})(django.jQuery);
+</script>
+
+
+