Skip to content

Commit

Permalink
Redo list css, make nested sortables work properly.
Browse files Browse the repository at this point in the history
  • Loading branch information
parndt committed Jun 18, 2010
1 parent 2bbb45d commit 754647d
Show file tree
Hide file tree
Showing 7 changed files with 264 additions and 39 deletions.
186 changes: 186 additions & 0 deletions public/javascripts/jquery/jquery.nestedsortables.js
@@ -0,0 +1,186 @@
$.fn.nestedSortable = function(options) {

var settings = $.extend({
nestable: 'li'
, container: 'ul'
, indent: 30
, handle: null
, opacity: 1
, placeholderClass: 'placeholder'
, placeholderElement: 'div'
, helperClass: 'helper'
, appendTo: 'parent'
, start: function() {}
, stop: function() {}
, drag: function() {}
, maxDepth: null
}, options);
settings.snapTolerance = settings.indent * 0.4;
cursor = {x: 0, y: 0};

this.each(function() {

// The top level nestable list container
var $root = $(this);

// An element placed to preview the location of the dragged element in its new position
var $placeholder = $('<' + settings.placeholderElement + '></' + settings.placeholderElement + '>', {
"class": settings.placeholderClass
});


$root.find(settings.nestable).each(function() {

var $this = $(this);

// Check if the element has already been set up as a nestable
if (!$this.data("nestable")) {

// Make the element draggable
$this.draggable({

// Transfer over some settings to jQuery's draggable implementation
opacity: settings.opacity,
handle: settings.handle,
appendTo: settings.appendTo,

// Creates a helper element
helper: function() {
// Create a helper that is a clone of the original (with a few little tweaks)
return $this.clone().width($this.width()).addClass(settings.helperClass);
},

// When dragging starts
start: function() {

// Hide the original and initialize the placeholder ontop of the starting position
$this.addClass('ui-dragging').hide().after($placeholder);

// Find the deepest nested child
var maxChildDepth = 0;
$this.find(settings.nestable).each(function(index, child) {
var $child = $(child);
var childDepth = $child.parentsUntil($this).filter(settings.nestable).length;
if (childDepth > maxChildDepth) {
maxChildDepth = childDepth;
}
});
$this.data("maxChildDepth", maxChildDepth);

// Run a custom start function specitifed in the settings
settings.start.apply(this);

},

// When dragging ends
stop: function(event, ui) {
// Replace the placeholder with the original while protecting it from disappearing.
if ($.inArray($root.get(0), $placeholder.parents()) > -1) {
$placeholder.after($this.show()).remove();
} else {
$this.show();
$placeholder.remove();
}
// Run a custom stop function specitifed in the settings
settings.stop.apply(this);
$('.ui-dragging').removeClass('ui-dragging');
$('.below-placeholder').removeClass('below-placeholder').animate({'marginTop':'0px'}, 0);
},

// Each "step" during the drag
drag: function (event, ui) {
// reduce sensitivity
if (cursor.y == 0 || typeof(event.clientY) == 'undefined' || ((cursor.y - event.clientY) >= 15) || ((cursor.y - event.clientY) <= -15) ) {
// Cycle through all nestables to find the item directly underneath the helper
var largestY = 0;
var depth;
var maxChildDepth = $this.data("maxChildDepth");
var underItems = $.grep($root.find(settings.nestable), function(item) {

$item = $(item);

// Is the item being checked underneath the one being dragged?
if (!(($item.offset().top < ui.position.top) && ($item.offset().top > largestY))) {
return false;
}

// Is the item being checked on the same nesting level as the dragged item?
if ($item.offset().left - settings.snapTolerance >= ui.position.left) {
return false;
}

// Make sure the item being checked is not part of the helper
if (ui.helper.find($item).length) {
return false;
}

// Make sure the item complies with max depth rules
if (settings.maxDepth !== null) {
depth = $item.parentsUntil($root).filter(settings.container).length + maxChildDepth;
if (depth - 1 > settings.maxDepth) {
return false;
}
}

// If we've got this far, its a match
largestY = $item.offset().top;
return true;

});

var underItem = underItems.length ? $(underItems.pop()) : null;
var nestedBeneath = null;

// If there is no item directly underneath the helper, check if the helper is over the first list item
if (underItem === null) {
var firstItem = $root.find(settings.nestable + ":first");

if ((firstItem.offset().top < ui.position.top + $(this).height()) && (firstItem.offset().top > ui.position.top)) {
underContainer = firstItem.closest(settings.container);
nestedBeneath = underContainer;
underContainer.prepend($placeholder);
}

// Place the placeholder inside or after the item underneath, depending on their relative x coordinates
} else {
// Should the dragged item be nested?
if ((underItem.offset().left + settings.indent - settings.snapTolerance < ui.position.left) && (settings.maxDepth === null || depth <= settings.maxDepth)) {
underContainer = underItem.children(settings.container);
nestedBeneath = underContainer;
underContainer.prepend($placeholder);
}
// ... or should it just be placed after
else {
nestedBeneath = underItem;
underItem.after($placeholder);
}
}
try{
$placeholder.css({'width': (w = nestedBeneath.width()) > 0 ? w : $placeholder.parent().width()});
} catch(e) {}

old_placeholder = $('.below-placeholder').removeClass('below-placeholder');
new_below_placeholder = $placeholder.nextAll('li.record:not(.ui-dragging):not(.ui-draggable-dragging):first').addClass('below-placeholder');
if (old_placeholder.attr('id') != new_below_placeholder.attr('id')) {
old_placeholder.animate({'marginTop':'0px'}, 125);
new_below_placeholder.addClass('below-placeholder').animate({'marginTop' : '20px'}, 125);
}
// Run a custom drag callback specifed in the settings
settings.drag.apply(this);

// save mouse co-ordinates.
if (typeof(event.clientX) != 'undefined') {
cursor.x = event.clientX;
}
if (typeof(event.clientY) != 'undefined') {
cursor.y = event.clientY;
}
}
}

}).data("nestable", true);
}
});
});
return this;
};
53 changes: 37 additions & 16 deletions public/javascripts/refinery/admin.js
Expand Up @@ -52,7 +52,7 @@ init_interface = function() {

// focus first field in an admin form.
$('form input[type=text]:first').focus();

// ensure that the menu isn't wider than the page_container or else it looks silly to round that corner.
if (((last_item = $('#menu a:visible:last'))
.offset().left + last_item.outerWidth() - $('#menu').offset().left + 5) < $('#page_container').outerWidth()) {
Expand Down Expand Up @@ -677,20 +677,32 @@ var list_reorder = {
, enable_reordering: function(e) {
if(e) { e.preventDefault(); }

list_reorder.sortable_list.find('li').each(function(index, li) {
if ($('ul', li).length) { return; }
$("<ul></ul>").appendTo(li);
});

list_reorder.sortable_list.add(list_reorder.sortable_list.find('ul')).sortable({
'connectWith': $(list_reorder.sortable_list.find('ul'))
, 'tolerance': 'pointer'
sortable_options = {
'tolerance': 'pointer'
, 'placeholder': 'placeholder'
, 'cursor': 'drag'
, 'items': 'li'
, 'axis': 'y'
};

$(list_reorder.sortable_list).find('li').each(function(index, li) {
if ($('ul', li).length) { return; }
$("<ul></ul>").appendTo(li);
});

if (list_reorder.tree) {
$(list_reorder.sortable_list).parent().nestedSortable($.extend(sortable_options, {
'maxDepth': 1
, 'placeholderElement': 'li'
}));
$(list_reorder.sortable_list).addClass('ui-sortable');
} else {
$(list_reorder.sortable_list).sortable(sortable_options);
}

$('#site_bar, #header > *:not(script)').fadeTo(500, 0.3);
$('#actions *:not("#reorder_action_done, #reorder_action")').not($('#reorder_action_done').parents('li, ul')).fadeTo(500, 0.55);

$('#reorder_action').hide();
$('#reorder_action_done').show();
}
Expand Down Expand Up @@ -729,19 +741,28 @@ var list_reorder = {
serialized += "&continue_reordering=false";

$.post(list_reorder.update_url, serialized, function(data) {
$(list_reorder.sortable_list.get(0)).html(data);

$(list_reorder.sortable_list).removeClass('reordering').sortable('destroy');
$(list_reorder.sortable_list).html(data);

$('#reorder_action_done').hide();
$('#reorder_action').show();
list_reorder.restore_controls(e);
});
} else {
$(list_reorder.sortable_list).removeClass('reordering').sortable('destroy');
list_reorder.restore_controls(e);
}
}

, restore_controls: function(e) {
if (list_reorder.tree) {
list_reorder.sortable_list.add(list_reorder.sortable_list.find('ul, li')).draggable('destroy');
} else {
$(list_reorder.sortable_list).sortable('destroy');
}
$(list_reorder.sortable_list).removeClass('reordering, ui-sortable');

$('#site_bar, #header > *:not(script)').fadeTo(250, 1);
$('#actions *:not("#reorder_action_done, #reorder_action")').not($('#reorder_action_done').parents('li, ul')).fadeTo(250, 1, function() {
$('#reorder_action_done').hide();
$('#reorder_action').show();
}
});
}
}

Expand Down
53 changes: 35 additions & 18 deletions public/stylesheets/refinery/refinery.css
Expand Up @@ -442,33 +442,35 @@ pre {
#records ul.empty {
display: none;
}
/* order of specificity: class rules need to be ruled important otherwise id based rules override them */
.tree ul li ul {
#records.tree ul li ul, .tree ul li ul {
padding: 0;
}
.tree ul li {
margin: 0 !important;
padding: 4px 0 0 40px !important;
#records.tree ul li, .tree ul li {
margin: 0px;
padding: 4px 0 0 40px;
background: url('/images/refinery/branch.gif') no-repeat 15px 0px;
}
.tree .on-hover, #pagination ul.tree a:hover, #pagination .tree .on {
#records.tree .on-hover, #pagination ul.tree a:hover, #pagination .tree .on {
background: url('/images/refinery/branch.gif') no-repeat 15px 0px;
}
.tree ul li.branch_start {
#records.tree ul li.branch_start, .tree ul li.branch_start {
background-image: url('/images/refinery/branch-start.gif');
}
.tree ul li.branch_end {
#records.tree ul li.branch_end, .tree ul li.branch_end {
background-image: url('/images/refinery/branch-end.gif');
}
#records.tree li {
line-height: 19px;
}
.tree li span.spacing {
#records.tree li span.spacing, .tree li span.spacing {
display: none;
}
.tree ul li > div:hover {
#records.tree ul li > div:hover, .tree ul li > div:hover {
background-color: #EAEAEA;
}
#records.tree ul.ui-sortable li div:hover, .tree ul.ui-sortable li div:hover {
background-color: inherit;
}
#records ul#sortable_list {
margin-top: 6px;
}
Expand All @@ -486,15 +488,19 @@ pre {
#content #records > .ui-sortable {
padding-top: 10px;
}
#content .ui-sortable li ul{
padding: 6px 10px 12px 40px !important;
#content #records ul.ui-sortable li ul, #content .ui-sortable li ul {
padding: 6px 10px 12px 40px;
}
#content ul.ui-sortable li {
background: #E6E5DC !important;
#content #records ul.ui-sortable li, #content ul.ui-sortable li {
background-image: none;
background-color: #EAEAEA;
cursor: move;
border: 1px solid #b7b7a8;
margin-bottom: 2px !important;
padding: 3px 0px 0px 3px !important;
border: 1px solid #ccc;
margin-bottom: 6px;
padding: 3px 0px 0px 3px;
}
#content #records ul.ui-sortable li ul li, #content ul.ui-sortable li {
background-color: #F2F2F2;
}
#content ul.ui-sortable li ul.empty {
display: block;
Expand All @@ -513,11 +519,22 @@ pre {
min-height: 12px;
}
#content .ui-sortable li.placeholder {
opacity: 0.4;
opacity: 0.7;
border-width: 2px;
border-style: dashed;
height: 38px;
}
#content .tree .ui-sortable li.placeholder {
height: 6px;
border-width: 2px;
position: absolute;
background: #22A7F2 !important;
}
#content #records .tree .ui-sortable li.helper, #content .tree .ui-sortable li.helper {
opacity: 0.5 !important;
}
#content .tree .ui-sortable li.below-placeholder {
}
#content ul.ui-sortable li.ui-sortable-helper {
height: 38px !important;
}
Expand Down
2 changes: 1 addition & 1 deletion public/stylesheets/wymeditor/skins/refinery/skin.css
Expand Up @@ -25,7 +25,7 @@

/*WYM_HTML*/
.wym_skin_refinery .wym_html { width: 100%;}
.wym_skin_refinery .wym_html textarea { width: 100% !important; height:200px; border: 1px solid gray; background: white; }
.wym_skin_refinery .wym_html textarea { width: 100% !important; height:400px; border: 1px solid gray; background: white; }

/*WYM_IFRAME*/
.wym_skin_refinery .wym_iframe { width: 100%; }
Expand Down
4 changes: 2 additions & 2 deletions vendor/plugins/refinery/app/views/admin/_head.html.erb
Expand Up @@ -29,15 +29,15 @@
'jquery/jquery.textTruncate.js',
'jquery/jquery.html5-placeholder-shim.js',
:cache => (js_caching ? "cache/jquery-plugins" : false) %>
<%= yield :head_after_javascript_libraries %>
<%= javascript_include_tag 'wymeditor/jquery.refinery.wymeditor.js',
'admin',
'refinery/boot_wym',
'refinery/admin',
:cache => (js_caching ? "cache/admin" : false) %>
<%= yield :head_after_javascript_libraries %>
<%= "<!--[if lt IE 8]>#{stylesheet_link_tag 'refinery/ie'}<![endif]-->" if request.env['HTTP_USER_AGENT'] =~ /MSIE/ %>
<%= yield :head %>
</head>

0 comments on commit 754647d

Please sign in to comment.