Index: misc/tabledrag.js =================================================================== RCS file: /cvs/drupal/drupal/misc/tabledrag.js,v retrieving revision 1.9 diff -u -r1.9 tabledrag.js --- misc/tabledrag.js 6 Dec 2007 09:53:53 -0000 1.9 +++ misc/tabledrag.js 13 Dec 2007 22:16:52 -0000 @@ -267,8 +267,22 @@ self.safeBlur = false; // Do not allow the onBlur cleanup. self.rowObject.direction = 'up'; keyChange = true; - if (self.rowObject.isValidSwap(previousRow, 0)) { + + if ($(item).is('.no-parent')) { + // Switch with the first top-level row we find up the table. + var groupHeight = 0; + while (previousRow && $('.indentation', previousRow).size()) { + previousRow = $(previousRow).prev('tr').get(0); + groupHeight += previousRow.offsetHeight; + } + if (previousRow) { + self.rowObject.swap('before', previousRow); + window.scrollBy(0, -groupHeight); + } + } + else if (self.rowObject.isValidSwap(previousRow, 0)) { self.rowObject.swap('before', previousRow); + self.rowObject.indent(0); window.scrollBy(0, -parseInt(item.offsetHeight)); } else if (self.table.tBodies[0].rows[0] != previousRow || $(previousRow).is('.draggable')) { @@ -294,15 +308,29 @@ self.safeBlur = false; // Do not allow the onBlur cleanup. self.rowObject.direction = 'down'; keyChange = true; - if (self.rowObject.isValidSwap(nextRow, 0)) { + + if ($(item).is('.no-parent')) { + // Switch with last row of the next group + var groupHeight = 0; + nextGroup = new self.row(nextRow, 'keyboard', self.indentEnabled, self.maxDepth, false); + if (nextGroup) { + $(nextGroup.group).each(function () {groupHeight += this.offsetHeight}); + nextGroupRow = $(nextGroup.group).filter(':last').get(0); + self.rowObject.swap('after', nextGroupRow); + window.scrollBy(0, parseInt(groupHeight)); + } + } + else if (self.rowObject.isValidSwap(nextRow, 0)) { self.rowObject.swap('after', nextRow); + self.rowObject.indent(0); + window.scrollBy(0, parseInt(item.offsetHeight)); } else { self.rowObject.swap('after', nextRow); self.rowObject.indent(-1); + window.scrollBy(0, parseInt(item.offsetHeight)); } handle.get(0).focus(); // Regain focus after the DOM manipulation. - window.scrollBy(0, parseInt(item.offsetHeight)); } break; } @@ -375,7 +403,7 @@ } // Similar to row swapping, handle indentations. - if (self.indentEnabled && x != self.oldX) { + if (self.indentEnabled) { self.oldX = x; var xDiff = self.currentMouseCoords.x - self.dragObject.indentMousePos.x; // Set the number of indentations the mouse has been moved left or right. @@ -383,17 +411,14 @@ // Limit the indentation to no less than the left edge of the table and no // more than the total amount of indentation in the table. indentDiff = indentDiff > 0 ? Math.min(indentDiff, self.indentCount - self.rowObject.indents + 1) : Math.max(indentDiff, -self.rowObject.indents); - if (indentDiff != 0) { - // Indent the row with our estimated diff, which may be further - // restricted according to the rows around this row. - var indentChange = self.rowObject.indent(indentDiff); - - // Update table and mouse indentations. - self.dragObject.indentMousePos.x += self.indentAmount * indentChange; - self.indentCount = Math.max(self.indentCount, self.rowObject.indents); - } + // Indent the row with our estimated diff, which may be further + // restricted according to the rows around this row. + var indentChange = self.rowObject.indent(indentDiff); + + // Update table and mouse indentations. + self.dragObject.indentMousePos.x += self.indentAmount * indentChange; + self.indentCount = Math.max(self.indentCount, self.rowObject.indents); } - return false; } }; @@ -547,7 +572,7 @@ return null; } - // We've may have found the row the mouse just passed over, but it doesn't + // We may have found the row the mouse just passed over, but it doesn't // take into account hidden rows. Skip backwards until we find a draggable // row. while ($(row).is(':hidden') && $(row).prev('tr').is(':hidden')) { @@ -861,19 +886,25 @@ var rowIndents = $('.indentation', row).size(); var prevIndents = $('.indentation', $(row).prev('tr')).size(); var nextIndents = $('.indentation', $(row).next('tr')).size(); + var indentForbidden = $(this.element).is('.no-parent'); if ( (this.direction == 'down') && ( // Prevent being able to drag a row downward with 2 indentations from a parent. this.indents > rowIndents + 1 || // Prevent orphaning children when dragging into a parent. - this.indents < nextIndents - indentDiff + this.indents < nextIndents - indentDiff || + // Prevent breaking hierarchy when dragging into a parent if the + // current row can't be nested. + (indentForbidden && nextIndents) ) || (this.direction == 'up') && ( // Prevent being able to drag a row upward with 2 indentations from a parent. this.indents < rowIndents || // Prevent orphaning children when dragging between a child and parent. this.indents > prevIndents + 1 - indentDiff + // The first test also catches the "Prevent breaking hierarchy when + // dragging into a parent if the current row can't be nested" case. ) ) { return false; @@ -915,13 +946,13 @@ */ Drupal.tableDrag.prototype.row.prototype.indent = function(indentDiff) { if (indentDiff > 0) { - var prevRow = $(this.group).filter(':first').prev('tr').get(0); + var prevRow = $(this.element).prev('tr').get(0); if (prevRow) { - var prevIndent = $('.indentation', $(this.group).filter(':first').prev('tr')).size(); - indentDiff = Math.min(prevIndent - this.indents + 1, indentDiff); + var parentIndent = $('.indentation', prevRow).size(); + indentDiff = Math.min(parentIndent - this.indents + (!$(prevRow).is('.no-child')), indentDiff); } else { - indentDiff = 0; // First row may not contain indents. + indentDiff = -this.indents; // First row may not contain indents. } } else { @@ -929,7 +960,7 @@ indentDiff = Math.max(nextIndent - this.indents, indentDiff); } - // Never allow indentation greater the set limit. + // Never allow indentation greater than the set limit. if (this.maxDepth && indentDiff + this.groupDepth > this.maxDepth) { indentDiff = 0; } Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.734 diff -u -r1.734 common.inc --- includes/common.inc 12 Dec 2007 14:54:27 -0000 1.734 +++ includes/common.inc 13 Dec 2007 22:42:21 -0000 @@ -2076,6 +2076,12 @@ * ); * @endcode * + * Additionnally, when tree relationships are present, the two additional + * 'no-child' and 'no-parent' classes can be used to refine the behavior: + * - Rows with the 'no-child' class are leaves that cannot have child rows. + * - Rows with the 'no-parent' class are roots that cannot be nested under + * a parent row. + * * Calling drupal_add_tabledrag() would then be written as such: * @code * drupal_add_tabledrag('my-module-table', 'order', 'sibling', 'my-elements-weight');