Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

[soc2009/admin-ui] Reordering selector inlines.

happy 4th!


git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/admin-ui@11179 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit da943bf6a86e6ec53ad7ad382b71af84285ff15b 1 parent e0e60ef
@zain zain authored
View
10 django/contrib/admin/media/css/base.css
@@ -350,6 +350,16 @@ table.orderable-initalized .order-cell, body>tr>td.order-cell {
background-color: #F6F6F6;
}
+.dragHandle {
+ height: 20px;
+ width: 20px;
+ float: right;
+ cursor: move;
+ background-color: #fff;
+ border: 1px solid #f00;
+ display: block;
+}
+
.empty_form {
display: none;
}
View
19 django/contrib/admin/media/css/forms.css
@@ -233,10 +233,6 @@ fieldset.monospace textarea {
width: 8em;
}
-.inline-related {
- position: relative;
-}
-
.inline-related h3 {
margin: 0;
color: #666;
@@ -247,10 +243,7 @@ fieldset.monospace textarea {
}
.inline-related h3 span.delete {
- padding-left: 20px;
- position: absolute;
- top: 2px;
- right: 10px;
+ float: right;
}
.inline-related h3 span.delete label {
@@ -329,24 +322,26 @@ fieldset.monospace textarea {
display: none;
}
-.inline-selector {
+ul.inline-selector {
float: left;
width: 19%;
+ padding: 0;
}
.inline-selector a, .inline-selector a:visited {
color: #000;
}
-.inline-selector-item {
+li.inline-selector-item {
background-color: #F6F6F6;
border: 1px solid #E7E7E7;
padding: 5px;
margin: 7px 0px 7px 5px;
font-size: 0.9em;
+ list-style-type: none;
}
-.inline-selector-item:hover {
+li.inline-selector-item:hover {
background-color: #C1DBFD;
}
@@ -360,7 +355,7 @@ fieldset.monospace textarea {
float: right;
}
-.inline-selected {
+li.inline-selected {
background-color: #9EB7D5;
}
View
19 django/contrib/admin/media/js/jquery-disable.text.select.pack.js
@@ -0,0 +1,19 @@
+/**
+ * .disableTextSelect - Disable Text Select Plugin
+ *
+ * Version: 1.1
+ * Updated: 2007-11-28
+ *
+ * Used to stop users from selecting text
+ *
+ * Copyright (c) 2007 James Dempster (letssurf@gmail.com, http://www.jdempster.com/category/jquery/disabletextselect/)
+ *
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ **/
+
+/**
+ * Requirements:
+ * - jQuery (John Resig, http://www.jquery.com/)
+ **/
+(function($){if($.browser.mozilla){$.fn.disableTextSelect=function(){return this.each(function(){$(this).css({"MozUserSelect":"none"})})};$.fn.enableTextSelect=function(){return this.each(function(){$(this).css({"MozUserSelect":""})})}}else{if($.browser.msie){$.fn.disableTextSelect=function(){return this.each(function(){$(this).bind("selectstart.disableTextSelect",function(){return false})})};$.fn.enableTextSelect=function(){return this.each(function(){$(this).unbind("selectstart.disableTextSelect")})}}else{$.fn.disableTextSelect=function(){return this.each(function(){$(this).bind("mousedown.disableTextSelect",function(){return false})})};$.fn.enableTextSelect=function(){return this.each(function(){$(this).unbind("mousedown.disableTextSelect")})}}}})(jQuery)
View
289 django/contrib/admin/media/js/jquery-listreorder.js
@@ -0,0 +1,289 @@
+/*
+Copyright (c) 2009 Jordan Bach, http://www.utdallas.edu/~jrb048000/
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/*
+List Reorder <http://www.utdallas.edu/~jrb048000/ListReorder/>
+
+Enables drag-and-drop reordering of list items for any simple ordered <ol> or unordered <li> list.
+
+Author: Jordan Bach
+Version: 0.1
+Created: January 1, 2009
+License: MIT License
+
+Constructor
+ $(expr).ListOrder(options)
+
+Methods:
+ makeDefaultOrder - sets the current list order to [0, 1, 2, ...]
+ restoreOrder - returns the list to its original order
+
+Events:
+ listorderchanged - Fired after a list item is dropped. The 2nd argument
+ is a jQuery object representing the list that fired the event.
+ The 3rd argument is an array where the values represent
+ the original index of each list item.
+
+Options:
+ itemHoverClass : 'itemHover',
+ dragTargetClass : 'dragTarget',
+ dropTargetClass : 'dropTarget',
+ dragHandleClass : 'dragHandle'
+
+*/
+
+(function($){
+
+$.fn.ListReorder = function (options) {
+
+ $.fn.ListReorder.defaults = {
+ itemHoverClass : 'itemHover',
+ dragTargetClass : 'dragTarget',
+ dropTargetClass : 'dropTarget',
+ dragHandleClass : 'dragHandle',
+ useDefaultDragHandle : false
+ };
+
+ var opts = $.extend({}, $.fn.ListReorder.defaults, options);
+
+ return this.each(function() {
+ var theList = $(this), // The list (<ul>|<ol>)
+ theItems = $('li', theList), // All <li> elements in the list
+ dragActive = false, // Are we currently dragging an item?
+ dropTarget = null, // The list placeholder
+ dragTarget = null, // The element currently being dragged
+ dropIndex = -1, // The list index of the dropTarget
+ offset = {}, // Positions the mouse in the dragTarget
+ listOrder = [], // Keeps track of order relative to original order
+ ref = this;
+
+ theList.mouseout(ul_mouseout);
+
+ // Create the drag target
+ dragTarget = $('<div></div>');
+ dragTarget.insertAfter(theList);
+ dragTarget.hide();
+ dragTarget.css('position', 'absolute');
+ dragTarget.addClass(opts.dragTargetClass);
+
+ for (var i = 0; i < theItems.length; i++)
+ listOrder.push(i);
+
+ resetList();
+
+ function resetList() {
+ theItems = $('li', theList),
+
+ // For each <li> in the list
+ theItems.each(function() {
+ var li = $(this);
+
+ var dragHandle = $('<span></span>');
+ dragHandle.addClass(opts.dragHandleClass)
+ .mouseover(li_mouseover)
+ .mousedown(dragHandle_mousedown);
+
+ if (opts.useDefaultDragHandle)
+ dragHandle.css({
+ 'display' : 'block',
+ 'float' : 'right',
+ 'width' : '10px',
+ 'height' : '10px',
+ 'border' : '2px solid #333',
+ 'background' : '#ccc',
+ 'cursor' : 'move'
+ });
+
+ $('.' + opts.dragHandleClass, li).remove();
+ li.prepend(dragHandle);
+ });
+
+ clearListItemStyles();
+ }
+
+ // Return all list items to their default state
+ function clearListItemStyles() {
+ theItems.each(function() {
+ var li = $(this);
+ li.removeClass(opts.itemHoverClass);
+ li.removeClass(opts.dropTargetClass);
+ });
+ }
+
+ // Handle any cleanup when the mouse leaves the list
+ function ul_mouseout() {
+ if (!dragActive)
+ clearListItemStyles();
+ }
+
+ // Add a hover class to a list item on mouseover
+ function li_mouseover() {
+ if (!dragActive) {
+ clearListItemStyles();
+ $(this).parent().addClass(opts.itemHoverClass);
+ }
+ }
+
+ // Prepare the list for dragging an item
+ function dragHandle_mousedown(e) {
+ var li = $(this).parent();
+
+ dragActive = true;
+ dropIndex = theItems.index(li);
+
+ // Show the drag target
+ dragTarget.html(li.html());
+ dragTarget.css('display', 'block');
+ offset.top = e.pageY - li.offset().top;
+ offset.left = e.pageX - li.offset().left;
+ updateDragTargetPos(e);
+
+ // Insert the placeholder
+ dropTarget = li;
+ dropTarget.html('');
+ dropTarget.css('height', dragTarget.css('height'));
+ dragTarget.css('width', dropTarget.width() + 'px');
+ dropTarget.addClass(opts.dropTargetClass);
+
+ // Disable Text and DOM selection
+ $(document).disableTextSelect();
+
+ $(document).mouseup(dragHandle_mouseup);
+ $(document).mousemove(document_mousemove);
+ }
+
+ // If this were on the element, we could lose the drag on the element
+ // if we move the mouse too fast
+ function document_mousemove(e) {
+ if (dragActive) {
+ // drag target follows mouse cursor
+ updateDragTargetPos(e);
+
+ // Don't do mess with drop index if we are above or below the list
+ if (y_mid(dragTarget) > y_bot(theList)
+ || y_mid(dragTarget) < y_top(theList)) {
+ return;
+ }
+
+ // detect position of drag target relative to list items
+ // and swap drop target and neighboring item if necessary
+ if (y_mid(dragTarget) + 5 < y_top(dropTarget)) {
+ swapListItems(dropIndex, --dropIndex);
+ } else if (y_mid(dragTarget) - 5 > y_bot(dropTarget)) {
+ swapListItems(dropIndex, ++dropIndex);
+ }
+ }
+ }
+
+ function dragHandle_mouseup() {
+ // Restore the drop target
+ dropTarget.html(dragTarget.html());
+ dropTarget.removeClass(opts.dragTargetClass);
+ dropTarget = null;
+
+ // Hide the drag target
+ dragTarget.css('display', 'none');
+
+ dragActive = false;
+ dragTarget.unbind('mouseup', dragHandle_mouseup);
+ $(document).unbind('mousemove', document_mousemove);
+ resetList();
+
+ theList.trigger('listorderchanged', [theList, listOrder]);
+
+ // Re-enable text selection
+ $(document).enableTextSelect();
+ $(document).unbind('mouseup', dragHandle_mouseup);
+ }
+
+ function updateDragTargetPos(e) {
+ dragTarget.css({
+ 'top' : e.pageY - offset.top + 'px',
+ 'left' : e.pageX - offset.left + 'px'
+ });
+ }
+
+ // Change the order of two list items
+ function swapListItems(oldDropIndex, newDropIndex) {
+ // keep indices in bounds
+ if (dropIndex < 0) {
+ dropIndex = 0;
+ return;
+ } else if (dropIndex >= theItems.length) {
+ dropIndex = theItems.length - 1;
+ return;
+ }
+
+ var t = listOrder[oldDropIndex];
+ listOrder[oldDropIndex] = listOrder[newDropIndex];
+ listOrder[newDropIndex] = t;
+
+ // swap list items
+ var oldDropTarget = theItems.get(oldDropIndex),
+ newDropTarget = theItems.get(newDropIndex),
+ temp1 = $(oldDropTarget).clone(true);
+ temp2 = $(newDropTarget).clone(true);
+
+ $(oldDropTarget).replaceWith(temp2)
+ .mouseover(li_mouseover)
+ .mousedown(dragHandle_mousedown);
+ $(newDropTarget).replaceWith(temp1)
+ .mouseover(li_mouseover)
+ .mousedown(dragHandle_mousedown);
+
+ // reset so it is valid on next use
+ theItems = $('li', theList);
+ dropTarget = $(theItems.get(newDropIndex));
+ }
+
+ function y_top(jq) {
+ return jq.offset().top;
+ }
+
+ function y_mid(jq) {
+ return (y_top(jq) + y_bot(jq)) / 2
+ }
+
+ function y_bot(jq) {
+ return jq.offset().top + jq.outerHeight();
+ }
+
+ this.makeDefaultOrder = function() {
+ for (var i = 0; i < listOrder.length; i++)
+ listOrder[i] = i;
+ }
+
+ this.restoreOrder = function() {
+ for (var i = 0; i < theItems.length; i++) {
+ if (i != listOrder[i]) {
+ var k = 0;
+ for (; k < listOrder.length; k++)
+ if (listOrder[k] == i)
+ break;
+ swapListItems(i, k);
+ }
+ }
+ theList.trigger('listorderchanged', [theList, listOrder]);
+ }
+ });
+}
+})(jQuery);
View
3  django/contrib/admin/options.py
@@ -1129,7 +1129,8 @@ def _media(self):
if self.filter_vertical or self.filter_horizontal:
js.extend(['js/SelectBox.js' , 'js/SelectFilter2.js'])
if self.order_field:
- js.append('js/jquery-tablednd.js')
+ js.extend(['js/jquery-tablednd.js', 'js/jquery-disable.text.select.pack.js',
+ 'js/jquery-listreorder.js'])
return forms.Media(js=['%s%s' % (settings.ADMIN_MEDIA_PREFIX, url) for url in js])
media = property(_media)
View
34 django/contrib/admin/templates/admin/edit_inline/selector.html
@@ -1,25 +1,26 @@
{% load i18n %}
-<div class="inline-group">
- <div class="tabular inline-related {% if forloop.last %}last-related{% endif %}">
+
+<div class="selector-inline inline-group" id="{{ inline_admin_formset.opts.verbose_name}}-group">
+ <div class="inline-related">
{{ inline_admin_formset.formset.management_form }}
<h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}</h2>
{{ inline_admin_formset.formset.non_form_errors }}
- <div class="inline-selector">
+ <ul class="inline-selector">
{% for inline_admin_form in inline_admin_formset %}
- <div class="inline-selector-item">
+ <li class="inline-selector-item">
<a href="#" class="inline-select" title="{{ inline_admin_formset.opts.verbose_name}}{{ forloop.counter }}">
{% if inline_admin_form.original or inline_admin_form.show_url %}
{% 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 %}
{% else %}
- [New Inline]
+ {{ inline_admin_formset.opts.verbose_name|title}}: #{{ forloop.counter }}
{% endif %}
</a>
- </div>
+ </li>
{% endfor %}
- </div>
+ </ul>
<div class="inline-detail">
{% for inline_admin_form in inline_admin_formset %}
@@ -29,7 +30,7 @@
{% 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 %}
{% else %}
- [New Inline]
+ {{ inline_admin_formset.opts.verbose_name|title}}: #{{ forloop.counter }}
{% endif %}
{% if inline_admin_formset.formset.can_delete %}
@@ -104,5 +105,22 @@
return false;
});
+
+ {% if inline_admin_formset.opts.order_field %}
+ /* Reordering Inlines */
+ var list = $('ul.inline-selector').ListReorder({ useDefaultDragHandle: true});
+ var id_prefix = '#{{ inline_admin_formset.opts.verbose_name}}';
+
+ list.bind('listorderchanged', function(evt, jq_list, list_order) {
+ counter = 1;
+ $(id_prefix + '-group a.inline-select').each(function (i) {
+ if (counter < list_order.length) {
+ $('.inline-detail #' + $(this).attr('title') +
+ ' input[id$="{{ inline_admin_formset.opts.order_field }}"]').val(counter++);
+ }
+ });
+ });
+
+ {% endif %}
});
</script>
View
2  django/contrib/admin/templates/admin/edit_inline/tabular.html
@@ -132,7 +132,7 @@
$("table.orderable tbody tr").unbind('mouseenter').unbind('mouseleave');
},
onDrop: function(table, row_obj) {
- var counter = 0;
+ var counter = 1;
$(row_obj).parent().find('input[id$="{{ inline_admin_formset.opts.order_field }}"]')
.each(function (i) {
Please sign in to comment.
Something went wrong with that request. Please try again.