2009-04-27 20:19:38 +00:00
( function ( $ ) {
2007-11-14 09:50:00 +00:00
/ * *
* Drag and drop table rows with field manipulation .
*
* Using the drupal _add _tabledrag ( ) function , any table with weights or parent
* relationships may be made into draggable tables . Columns containing a field
* may optionally be hidden , providing a better user experience .
*
* Created tableDrag instances may be modified with custom behaviors by
* overriding the . onDrag , . onDrop , . row . onSwap , and . row . onIndent methods .
* See blocks . js for an example of adding additional functionality to tableDrag .
* /
2008-10-29 10:01:28 +00:00
Drupal . behaviors . tableDrag = {
2009-04-27 20:19:38 +00:00
attach : function ( context , settings ) {
2009-03-13 23:15:09 +00:00
for ( var base in settings . tableDrag ) {
2012-04-07 07:19:30 +00:00
$ ( context ) . find ( '#' + base ) . once ( 'tabledrag' , function ( ) {
2009-08-31 05:51:08 +00:00
// Create the new tableDrag instance. Save in the Drupal variable
// to allow other scripts access to the object.
Drupal . tableDrag [ base ] = new Drupal . tableDrag ( this , settings . tableDrag [ base ] ) ;
} ) ;
2007-11-14 09:50:00 +00:00
}
}
} ;
/ * *
* Constructor for the tableDrag object . Provides table and field manipulation .
*
* @ param table
* DOM object for the table to be made draggable .
* @ param tableSettings
* Settings for the table added via drupal _add _dragtable ( ) .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag = function ( table , tableSettings ) {
2007-11-14 09:50:00 +00:00
var self = this ;
2012-04-07 07:19:30 +00:00
var $table = $ ( table ) ;
2007-11-14 09:50:00 +00:00
// Required object variables.
this . table = table ;
this . tableSettings = tableSettings ;
this . dragObject = null ; // Used to hold information about a current drag operation.
this . rowObject = null ; // Provides operations for row manipulation.
this . oldRowElement = null ; // Remember the previous element.
this . oldY = 0 ; // Used to determine up or down direction from last mouse move.
this . changed = false ; // Whether anything in the entire table has changed.
2007-12-06 09:53:53 +00:00
this . maxDepth = 0 ; // Maximum amount of allowed parenting.
2007-12-16 10:36:53 +00:00
this . rtl = $ ( this . table ) . css ( 'direction' ) == 'rtl' ? - 1 : 1 ; // Direction of the table.
2007-11-14 09:50:00 +00:00
// Configure the scroll settings.
this . scrollSettings = { amount : 4 , interval : 50 , trigger : 70 } ;
this . scrollInterval = null ;
this . scrollY = 0 ;
this . windowHeight = 0 ;
2007-11-20 10:18:43 +00:00
// Check this table's settings to see if there are parent relationships in
// this table. For efficiency, large sections of code can be skipped if we
// don't need to track horizontal movement and indentations.
this . indentEnabled = false ;
2009-12-08 03:10:51 +00:00
for ( var group in tableSettings ) {
for ( var n in tableSettings [ group ] ) {
2009-04-26 19:18:46 +00:00
if ( tableSettings [ group ] [ n ] . relationship == 'parent' ) {
2007-11-20 10:18:43 +00:00
this . indentEnabled = true ;
}
2009-04-26 19:18:46 +00:00
if ( tableSettings [ group ] [ n ] . limit > 0 ) {
this . maxDepth = tableSettings [ group ] [ n ] . limit ;
2007-11-26 16:19:37 +00:00
}
2007-11-20 10:18:43 +00:00
}
}
2007-11-14 09:50:00 +00:00
if ( this . indentEnabled ) {
this . indentCount = 1 ; // Total width of indents, set in makeDraggable.
2007-11-20 10:18:43 +00:00
// Find the width of indentations to measure mouse movements against.
// Because the table doesn't need to start with any indentations, we
2008-09-18 18:37:29 +00:00
// manually append 2 indentations in the first draggable row, measure
// the offset, then remove.
var indent = Drupal . theme ( 'tableDragIndentation' ) ;
2010-03-10 20:31:59 +00:00
var testRow = $ ( '<tr/>' ) . addClass ( 'draggable' ) . appendTo ( table ) ;
var testCell = $ ( '<td/>' ) . appendTo ( testRow ) . prepend ( indent ) . prepend ( indent ) ;
2012-04-07 07:19:30 +00:00
var $indentation = testCell . find ( '.indentation' ) ;
this . indentAmount = $indentation . get ( 1 ) . offsetLeft - $indentation . get ( 0 ) . offsetLeft ;
2010-03-10 20:31:59 +00:00
testRow . remove ( ) ;
2007-11-14 09:50:00 +00:00
}
// Make each applicable row draggable.
2009-06-10 05:06:57 +00:00
// Match immediate children of the parent element to allow nesting.
2012-04-07 07:19:30 +00:00
$table . find ( '> tr.draggable, > tbody > tr.draggable' ) . each ( function ( ) { self . makeDraggable ( this ) ; } ) ;
2007-11-14 09:50:00 +00:00
2010-06-20 17:34:51 +00:00
// Add a link before the table for users to show or hide weight columns.
2012-04-07 07:19:30 +00:00
$table . before ( $ ( '<a href="#" class="tabledrag-toggle-weight"></a>' )
2010-06-20 17:34:51 +00:00
. attr ( 'title' , Drupal . t ( 'Re-order rows by numerical weight instead of dragging.' ) )
. click ( function ( ) {
if ( $ . cookie ( 'Drupal.tableDrag.showWeight' ) == 1 ) {
self . hideColumns ( ) ;
}
else {
self . showColumns ( ) ;
}
return false ;
} )
. wrap ( '<div class="tabledrag-toggle-weight-wrapper"></div>' )
. parent ( )
) ;
// Initialize the specified columns (for example, weight or parent columns)
// to show or hide according to user preference. This aids accessibility
// so that, e.g., screen reader users can choose to enter weight values and
// manipulate form elements directly, rather than using drag-and-drop..
self . initColumns ( ) ;
2007-11-14 09:50:00 +00:00
// Add mouse bindings to the document. The self variable is passed along
// as event handlers do not have direct access to the tableDrag object.
2009-04-27 20:19:38 +00:00
$ ( document ) . bind ( 'mousemove' , function ( event ) { return self . dragRow ( event , self ) ; } ) ;
$ ( document ) . bind ( 'mouseup' , function ( event ) { return self . dropRow ( event , self ) ; } ) ;
2007-11-14 09:50:00 +00:00
} ;
/ * *
2010-06-20 17:34:51 +00:00
* Initialize columns containing form elements to be hidden by default ,
* according to the settings for this tableDrag instance .
*
* Identify and mark each cell with a CSS class so we can easily toggle
* show / hide it . Finally , hide columns if user does not have a
* 'Drupal.tableDrag.showWeight' cookie .
2007-11-14 09:50:00 +00:00
* /
2010-06-20 17:34:51 +00:00
Drupal . tableDrag . prototype . initColumns = function ( ) {
2012-04-07 07:19:30 +00:00
var $table = $ ( this . table ) ;
2007-11-14 09:50:00 +00:00
for ( var group in this . tableSettings ) {
// Find the first field in this group.
for ( var d in this . tableSettings [ group ] ) {
2012-04-07 07:19:30 +00:00
var field = $table . find ( '.' + this . tableSettings [ group ] [ d ] . target + ':first' ) ;
2012-01-29 13:54:40 +00:00
if ( field . length && this . tableSettings [ group ] [ d ] . hidden ) {
2009-04-26 19:18:46 +00:00
var hidden = this . tableSettings [ group ] [ d ] . hidden ;
2012-01-24 18:54:39 +00:00
var cell = field . closest ( 'td' ) ;
2007-11-14 09:50:00 +00:00
break ;
}
}
2008-05-02 15:20:39 +00:00
2010-06-20 17:34:51 +00:00
// Mark the column containing this field so it can be hidden.
2011-07-28 22:15:41 +00:00
if ( hidden && cell [ 0 ] ) {
2007-11-14 09:50:00 +00:00
// Add 1 to our indexes. The nth-child selector is 1 based, not 0 based.
2009-06-10 05:06:57 +00:00
// Match immediate children of the parent element to allow nesting.
2012-04-07 07:19:30 +00:00
var columnIndex = cell . parent ( ) . find ( '> td' ) . index ( cell . get ( 0 ) ) + 1 ;
$table . find ( '> thead > tr, > tbody > tr, > tr' ) . each ( function ( ) {
2011-07-28 22:15:41 +00:00
// Get the columnIndex and adjust for any colspans in this row.
var index = columnIndex ;
var cells = $ ( this ) . children ( ) ;
cells . each ( function ( n ) {
if ( n < index && this . colSpan && this . colSpan > 1 ) {
index -= this . colSpan - 1 ;
2008-05-02 15:20:39 +00:00
}
} ) ;
if ( index > 0 ) {
2011-07-28 22:15:41 +00:00
cell = cells . filter ( ':nth-child(' + index + ')' ) ;
if ( cell [ 0 ] . colSpan && cell [ 0 ] . colSpan > 1 ) {
2010-06-20 17:34:51 +00:00
// If this cell has a colspan, mark it so we can reduce the colspan.
2011-07-28 22:15:41 +00:00
cell . addClass ( 'tabledrag-has-colspan' ) ;
2008-05-02 15:20:39 +00:00
}
else {
2010-06-20 17:34:51 +00:00
// Mark this cell so we can hide it.
2011-07-28 22:15:41 +00:00
cell . addClass ( 'tabledrag-hide' ) ;
2008-05-02 15:20:39 +00:00
}
2007-11-14 09:50:00 +00:00
}
} ) ;
}
}
2010-06-20 17:34:51 +00:00
// Now hide cells and reduce colspans unless cookie indicates previous choice.
// Set a cookie if it is not already present.
if ( $ . cookie ( 'Drupal.tableDrag.showWeight' ) === null ) {
$ . cookie ( 'Drupal.tableDrag.showWeight' , 0 , {
path : Drupal . settings . basePath ,
// The cookie expires in one year.
expires : 365
} ) ;
this . hideColumns ( ) ;
}
// Check cookie value and show/hide weight columns accordingly.
else {
if ( $ . cookie ( 'Drupal.tableDrag.showWeight' ) == 1 ) {
this . showColumns ( ) ;
}
else {
this . hideColumns ( ) ;
}
}
} ;
/ * *
* Hide the columns containing weight / parent form elements .
* Undo showColumns ( ) .
* /
Drupal . tableDrag . prototype . hideColumns = function ( ) {
2012-04-07 07:19:30 +00:00
var $tables = $ ( 'table.tabledrag-processed' ) ;
2010-06-20 17:34:51 +00:00
// Hide weight/parent cells and headers.
2012-04-07 07:19:30 +00:00
$tables . find ( '.tabledrag-hide' ) . css ( 'display' , 'none' ) ;
2010-06-20 17:34:51 +00:00
// Show TableDrag handles.
2012-04-07 07:19:30 +00:00
$tables . find ( '.tabledrag-handle' ) . css ( 'display' , '' ) ;
2010-06-20 17:34:51 +00:00
// Reduce the colspan of any effected multi-span columns.
2012-04-07 07:19:30 +00:00
$tables . find ( '.tabledrag-has-colspan' ) . each ( function ( ) {
2010-06-20 17:34:51 +00:00
this . colSpan = this . colSpan - 1 ;
} ) ;
// Change link text.
$ ( '.tabledrag-toggle-weight' ) . text ( Drupal . t ( 'Show row weights' ) ) ;
// Change cookie.
$ . cookie ( 'Drupal.tableDrag.showWeight' , 0 , {
path : Drupal . settings . basePath ,
// The cookie expires in one year.
expires : 365
} ) ;
2012-02-29 07:27:01 +00:00
// Trigger an event to allow other scripts to react to this display change.
$ ( 'table.tabledrag-processed' ) . trigger ( 'columnschange' , 'hide' ) ;
2010-06-20 17:34:51 +00:00
} ;
/ * *
* Show the columns containing weight / parent form elements
* Undo hideColumns ( ) .
* /
Drupal . tableDrag . prototype . showColumns = function ( ) {
2012-04-07 07:19:30 +00:00
var $tables = $ ( 'table.tabledrag-processed' ) ;
2010-06-20 17:34:51 +00:00
// Show weight/parent cells and headers.
2012-04-07 07:19:30 +00:00
$tables . find ( '.tabledrag-hide' ) . css ( 'display' , '' ) ;
2010-06-20 17:34:51 +00:00
// Hide TableDrag handles.
2012-04-07 07:19:30 +00:00
$tables . find ( '.tabledrag-handle' ) . css ( 'display' , 'none' ) ;
2010-06-20 17:34:51 +00:00
// Increase the colspan for any columns where it was previously reduced.
2012-04-07 07:19:30 +00:00
$tables . find ( '.tabledrag-has-colspan' ) . each ( function ( ) {
2010-06-20 17:34:51 +00:00
this . colSpan = this . colSpan + 1 ;
} ) ;
// Change link text.
$ ( '.tabledrag-toggle-weight' ) . text ( Drupal . t ( 'Hide row weights' ) ) ;
// Change cookie.
$ . cookie ( 'Drupal.tableDrag.showWeight' , 1 , {
path : Drupal . settings . basePath ,
// The cookie expires in one year.
expires : 365
} ) ;
2012-02-29 07:27:01 +00:00
// Trigger an event to allow other scripts to react to this display change.
$ ( 'table.tabledrag-processed' ) . trigger ( 'columnschange' , 'show' ) ;
2007-11-14 09:50:00 +00:00
} ;
/ * *
* Find the target used within a particular row and group .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . rowSettings = function ( group , row ) {
2012-04-07 07:19:30 +00:00
var field = $ ( row ) . find ( '.' + group ) ;
2009-12-08 03:10:51 +00:00
for ( var delta in this . tableSettings [ group ] ) {
2009-04-26 19:18:46 +00:00
var targetClass = this . tableSettings [ group ] [ delta ] . target ;
2007-11-14 09:50:00 +00:00
if ( field . is ( '.' + targetClass ) ) {
// Return a copy of the row settings.
2009-04-26 19:18:46 +00:00
var rowSettings = { } ;
2007-11-14 09:50:00 +00:00
for ( var n in this . tableSettings [ group ] [ delta ] ) {
rowSettings [ n ] = this . tableSettings [ group ] [ delta ] [ n ] ;
}
return rowSettings ;
}
}
} ;
/ * *
* Take an item and add event handlers to make it become draggable .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . makeDraggable = function ( item ) {
2007-11-14 09:50:00 +00:00
var self = this ;
2012-04-07 07:19:30 +00:00
var $item = $ ( item ) ;
2007-11-14 09:50:00 +00:00
// Create the handle.
2007-12-16 10:36:53 +00:00
var handle = $ ( '<a href="#" class="tabledrag-handle"><div class="handle"> </div></a>' ) . attr ( 'title' , Drupal . t ( 'Drag to re-order' ) ) ;
2007-11-14 09:50:00 +00:00
// Insert the handle after indentations (if any).
2012-04-07 07:19:30 +00:00
var $indentationLast = $item . find ( 'td:first .indentation:last' ) ;
if ( $indentationLast . length ) {
$indentationLast . after ( handle ) ;
2007-11-14 09:50:00 +00:00
// Update the total width of indentation in this entire table.
2012-04-07 07:19:30 +00:00
self . indentCount = Math . max ( $item . find ( '.indentation' ) . length , self . indentCount ) ;
2007-11-14 09:50:00 +00:00
}
else {
2012-04-07 07:19:30 +00:00
$item . find ( 'td:first' ) . prepend ( handle ) ;
2007-11-14 09:50:00 +00:00
}
// Add hover action for the handle.
2009-04-27 20:19:38 +00:00
handle . hover ( function ( ) {
2007-11-14 09:50:00 +00:00
self . dragObject == null ? $ ( this ) . addClass ( 'tabledrag-handle-hover' ) : null ;
2009-04-27 20:19:38 +00:00
} , function ( ) {
2007-11-14 09:50:00 +00:00
self . dragObject == null ? $ ( this ) . removeClass ( 'tabledrag-handle-hover' ) : null ;
} ) ;
// Add the mousedown action for the handle.
2009-04-27 20:19:38 +00:00
handle . mousedown ( function ( event ) {
2007-11-14 09:50:00 +00:00
// Create a new dragObject recording the event information.
2009-04-26 19:18:46 +00:00
self . dragObject = { } ;
2007-11-14 09:50:00 +00:00
self . dragObject . initMouseOffset = self . getMouseOffset ( item , event ) ;
self . dragObject . initMouseCoords = self . mouseCoords ( event ) ;
if ( self . indentEnabled ) {
self . dragObject . indentMousePos = self . dragObject . initMouseCoords ;
}
2007-11-26 16:36:44 +00:00
// If there's a lingering row object from the keyboard, remove its focus.
2007-11-14 09:50:00 +00:00
if ( self . rowObject ) {
2012-04-07 07:19:30 +00:00
$ ( self . rowObject . element ) . find ( 'a.tabledrag-handle' ) . blur ( ) ;
2007-11-14 09:50:00 +00:00
}
// Create a new rowObject for manipulation of this row.
2007-11-26 16:19:37 +00:00
self . rowObject = new self . row ( item , 'mouse' , self . indentEnabled , self . maxDepth , true ) ;
2007-11-14 09:50:00 +00:00
// Save the position of the table.
2009-03-08 03:16:26 +00:00
self . table . topY = $ ( self . table ) . offset ( ) . top ;
2007-11-14 09:50:00 +00:00
self . table . bottomY = self . table . topY + self . table . offsetHeight ;
// Add classes to the handle and row.
$ ( this ) . addClass ( 'tabledrag-handle-hover' ) ;
$ ( item ) . addClass ( 'drag' ) ;
// Set the document to use the move cursor during drag.
$ ( 'body' ) . addClass ( 'drag' ) ;
if ( self . oldRowElement ) {
$ ( self . oldRowElement ) . removeClass ( 'drag-previous' ) ;
}
// Hack for Konqueror, prevent the blur handler from firing.
// Konqueror always gives links focus, even after returning false on mousedown.
self . safeBlur = false ;
// Call optional placeholder function.
self . onDrag ( ) ;
return false ;
} ) ;
// Prevent the anchor tag from jumping us to the top of the page.
2009-04-27 20:19:38 +00:00
handle . click ( function ( ) {
2007-11-14 09:50:00 +00:00
return false ;
} ) ;
// Similar to the hover event, add a class when the handle is focused.
2009-04-27 20:19:38 +00:00
handle . focus ( function ( ) {
2007-11-14 09:50:00 +00:00
$ ( this ) . addClass ( 'tabledrag-handle-hover' ) ;
self . safeBlur = true ;
} ) ;
// Remove the handle class on blur and fire the same function as a mouseup.
2009-04-27 20:19:38 +00:00
handle . blur ( function ( event ) {
2007-11-14 09:50:00 +00:00
$ ( this ) . removeClass ( 'tabledrag-handle-hover' ) ;
if ( self . rowObject && self . safeBlur ) {
2007-11-27 13:10:24 +00:00
self . dropRow ( event , self ) ;
2007-11-14 09:50:00 +00:00
}
} ) ;
// Add arrow-key support to the handle.
2009-04-27 20:19:38 +00:00
handle . keydown ( function ( event ) {
2007-11-14 09:50:00 +00:00
// If a rowObject doesn't yet exist and this isn't the tab key.
if ( event . keyCode != 9 && ! self . rowObject ) {
2007-11-26 16:19:37 +00:00
self . rowObject = new self . row ( item , 'keyboard' , self . indentEnabled , self . maxDepth , true ) ;
2007-11-14 09:50:00 +00:00
}
var keyChange = false ;
switch ( event . keyCode ) {
case 37 : // Left arrow.
case 63234 : // Safari left arrow.
keyChange = true ;
2007-12-13 10:14:18 +00:00
self . rowObject . indent ( - 1 * self . rtl ) ;
2007-11-14 09:50:00 +00:00
break ;
case 38 : // Up arrow.
case 63232 : // Safari up arrow.
2012-04-07 07:19:30 +00:00
var $previousRow = $ ( self . rowObject . element ) . prev ( 'tr' ) . eq ( 0 ) ;
var previousRow = $previousRow . get ( 0 ) ;
while ( previousRow && $previousRow . is ( ':hidden' ) ) {
$previousRow = $ ( previousRow ) . prev ( 'tr' ) . eq ( 0 ) ;
previousRow = $previousRow . get ( 0 ) ;
2007-11-14 09:50:00 +00:00
}
if ( previousRow ) {
self . safeBlur = false ; // Do not allow the onBlur cleanup.
self . rowObject . direction = 'up' ;
keyChange = true ;
2007-12-19 10:58:35 +00:00
if ( $ ( item ) . is ( '.tabledrag-root' ) ) {
2008-10-12 00:29:09 +00:00
// Swap with the previous top-level row.
2007-12-19 10:58:35 +00:00
var groupHeight = 0 ;
2012-04-07 07:19:30 +00:00
while ( previousRow && $previousRow . find ( '.indentation' ) . length ) {
$previousRow = $ ( previousRow ) . prev ( 'tr' ) . eq ( 0 ) ;
previousRow = $previousRow . get ( 0 ) ;
groupHeight += $previousRow . is ( ':hidden' ) ? 0 : previousRow . offsetHeight ;
2007-12-19 10:58:35 +00:00
}
if ( previousRow ) {
self . rowObject . swap ( 'before' , previousRow ) ;
// No need to check for indentation, 0 is the only valid one.
window . scrollBy ( 0 , - groupHeight ) ;
}
2007-11-14 09:50:00 +00:00
}
2012-04-07 07:19:30 +00:00
else if ( self . table . tBodies [ 0 ] . rows [ 0 ] != previousRow || $previousRow . is ( '.draggable' ) ) {
2007-12-19 10:58:35 +00:00
// Swap with the previous row (unless previous row is the first one
// and undraggable).
2007-11-14 09:50:00 +00:00
self . rowObject . swap ( 'before' , previousRow ) ;
2007-12-19 10:58:35 +00:00
self . rowObject . interval = null ;
self . rowObject . indent ( 0 ) ;
2009-09-20 19:14:40 +00:00
window . scrollBy ( 0 , - parseInt ( item . offsetHeight , 10 ) ) ;
2007-11-14 09:50:00 +00:00
}
handle . get ( 0 ) . focus ( ) ; // Regain focus after the DOM manipulation.
}
break ;
case 39 : // Right arrow.
case 63235 : // Safari right arrow.
keyChange = true ;
2012-03-23 20:02:29 +00:00
self . rowObject . indent ( self . rtl ) ;
2007-11-14 09:50:00 +00:00
break ;
case 40 : // Down arrow.
case 63233 : // Safari down arrow.
2012-04-07 07:19:30 +00:00
var $nextRow = $ ( self . rowObject . group ) . filter ( ':last' ) . next ( 'tr' ) . eq ( 0 ) ;
var nextRow = $nextRow . get ( 0 ) ;
while ( nextRow && $nextRow . is ( ':hidden' ) ) {
$nextRow = $ ( nextRow ) . next ( 'tr' ) . eq ( 0 ) ;
nextRow = $nextRow . get ( 0 ) ;
2007-11-14 09:50:00 +00:00
}
if ( nextRow ) {
self . safeBlur = false ; // Do not allow the onBlur cleanup.
self . rowObject . direction = 'down' ;
keyChange = true ;
2007-12-19 10:58:35 +00:00
if ( $ ( item ) . is ( '.tabledrag-root' ) ) {
// Swap with the next group (necessarily a top-level one).
var groupHeight = 0 ;
2012-02-03 21:18:21 +00:00
var nextGroup = new self . row ( nextRow , 'keyboard' , self . indentEnabled , self . maxDepth , false ) ;
2007-12-19 10:58:35 +00:00
if ( nextGroup ) {
2009-04-27 20:19:38 +00:00
$ ( nextGroup . group ) . each ( function ( ) {
2009-02-18 13:46:55 +00:00
groupHeight += $ ( this ) . is ( ':hidden' ) ? 0 : this . offsetHeight ;
} ) ;
2012-02-03 21:18:21 +00:00
var nextGroupRow = $ ( nextGroup . group ) . filter ( ':last' ) . get ( 0 ) ;
2007-12-19 10:58:35 +00:00
self . rowObject . swap ( 'after' , nextGroupRow ) ;
// No need to check for indentation, 0 is the only valid one.
2009-09-20 19:14:40 +00:00
window . scrollBy ( 0 , parseInt ( groupHeight , 10 ) ) ;
2007-12-19 10:58:35 +00:00
}
2007-11-14 09:50:00 +00:00
}
else {
2007-12-19 10:58:35 +00:00
// Swap with the next row.
2007-11-14 09:50:00 +00:00
self . rowObject . swap ( 'after' , nextRow ) ;
2007-12-19 10:58:35 +00:00
self . rowObject . interval = null ;
self . rowObject . indent ( 0 ) ;
2009-09-20 19:14:40 +00:00
window . scrollBy ( 0 , parseInt ( item . offsetHeight , 10 ) ) ;
2007-11-14 09:50:00 +00:00
}
handle . get ( 0 ) . focus ( ) ; // Regain focus after the DOM manipulation.
}
break ;
}
if ( self . rowObject && self . rowObject . changed == true ) {
$ ( item ) . addClass ( 'drag' ) ;
if ( self . oldRowElement ) {
$ ( self . oldRowElement ) . removeClass ( 'drag-previous' ) ;
}
self . oldRowElement = item ;
self . restripeTable ( ) ;
self . onDrag ( ) ;
}
// Returning false if we have an arrow key to prevent scrolling.
if ( keyChange ) {
return false ;
}
} ) ;
// Compatibility addition, return false on keypress to prevent unwanted scrolling.
2008-12-30 16:43:20 +00:00
// IE and Safari will suppress scrolling on keydown, but all other browsers
2007-11-14 09:50:00 +00:00
// need to return false on keypress. http://www.quirksmode.org/js/keys.html
2009-04-27 20:19:38 +00:00
handle . keypress ( function ( event ) {
2007-11-14 09:50:00 +00:00
switch ( event . keyCode ) {
case 37 : // Left arrow.
case 38 : // Up arrow.
case 39 : // Right arrow.
case 40 : // Down arrow.
return false ;
}
} ) ;
} ;
/ * *
* Mousemove event handler , bound to document .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . dragRow = function ( event , self ) {
2007-11-14 09:50:00 +00:00
if ( self . dragObject ) {
self . currentMouseCoords = self . mouseCoords ( event ) ;
var y = self . currentMouseCoords . y - self . dragObject . initMouseOffset . y ;
var x = self . currentMouseCoords . x - self . dragObject . initMouseOffset . x ;
// Check for row swapping and vertical scrolling.
if ( y != self . oldY ) {
self . rowObject . direction = y > self . oldY ? 'down' : 'up' ;
self . oldY = y ; // Update the old value.
// Check if the window should be scrolled (and how fast).
var scrollAmount = self . checkScroll ( self . currentMouseCoords . y ) ;
// Stop any current scrolling.
clearInterval ( self . scrollInterval ) ;
// Continue scrolling if the mouse has moved in the scroll direction.
if ( scrollAmount > 0 && self . rowObject . direction == 'down' || scrollAmount < 0 && self . rowObject . direction == 'up' ) {
self . setScroll ( scrollAmount ) ;
}
// If we have a valid target, perform the swap and restripe the table.
var currentRow = self . findDropTargetRow ( x , y ) ;
if ( currentRow ) {
if ( self . rowObject . direction == 'down' ) {
self . rowObject . swap ( 'after' , currentRow , self ) ;
}
else {
self . rowObject . swap ( 'before' , currentRow , self ) ;
}
self . restripeTable ( ) ;
}
}
// Similar to row swapping, handle indentations.
2007-12-19 10:58:35 +00:00
if ( self . indentEnabled ) {
2007-11-14 09:50:00 +00:00
var xDiff = self . currentMouseCoords . x - self . dragObject . indentMousePos . x ;
// Set the number of indentations the mouse has been moved left or right.
2008-09-18 18:37:29 +00:00
var indentDiff = Math . round ( xDiff / self . indentAmount * self . rtl ) ;
2007-12-19 10:58:35 +00:00
// 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 . rtl ;
self . indentCount = Math . max ( self . indentCount , self . rowObject . indents ) ;
2007-11-14 09:50:00 +00:00
}
2008-06-12 19:13:17 +00:00
return false ;
2007-11-14 09:50:00 +00:00
}
} ;
/ * *
* Mouseup event handler , bound to document .
* Blur event handler , bound to drag handle for keyboard support .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . dropRow = function ( event , self ) {
2007-11-14 09:50:00 +00:00
// Drop row functionality shared between mouseup and blur events.
if ( self . rowObject != null ) {
var droppedRow = self . rowObject . element ;
2012-04-07 07:19:30 +00:00
var $droppedRow = $ ( droppedRow ) ;
2007-11-14 09:50:00 +00:00
// The row is already in the right place so we just release it.
if ( self . rowObject . changed == true ) {
2007-11-26 19:46:52 +00:00
// Update the fields in the dropped row.
2007-11-14 09:50:00 +00:00
self . updateFields ( droppedRow ) ;
2007-11-26 19:46:52 +00:00
// If a setting exists for affecting the entire group, update all the
// fields in the entire dragged group.
for ( var group in self . tableSettings ) {
var rowSettings = self . rowSettings ( group , droppedRow ) ;
if ( rowSettings . relationship == 'group' ) {
2009-12-08 03:10:51 +00:00
for ( var n in self . rowObject . children ) {
2007-11-26 19:46:52 +00:00
self . updateField ( self . rowObject . children [ n ] , group ) ;
}
}
}
2007-11-14 09:50:00 +00:00
self . rowObject . markChanged ( ) ;
if ( self . changed == false ) {
2008-06-24 16:52:18 +00:00
$ ( Drupal . theme ( 'tableDragChangedWarning' ) ) . insertBefore ( self . table ) . hide ( ) . fadeIn ( 'slow' ) ;
2007-11-14 09:50:00 +00:00
self . changed = true ;
}
}
if ( self . indentEnabled ) {
self . rowObject . removeIndentClasses ( ) ;
}
if ( self . oldRowElement ) {
$ ( self . oldRowElement ) . removeClass ( 'drag-previous' ) ;
}
2012-04-07 07:19:30 +00:00
$droppedRow . removeClass ( 'drag' ) . addClass ( 'drag-previous' ) ;
2007-11-14 09:50:00 +00:00
self . oldRowElement = droppedRow ;
self . onDrop ( ) ;
self . rowObject = null ;
}
// Functionality specific only to mouseup event.
if ( self . dragObject != null ) {
2012-04-07 07:19:30 +00:00
$droppedRow . find ( '.tabledrag-handle' ) . removeClass ( 'tabledrag-handle-hover' ) ;
2007-11-14 09:50:00 +00:00
self . dragObject = null ;
$ ( 'body' ) . removeClass ( 'drag' ) ;
clearInterval ( self . scrollInterval ) ;
}
} ;
/ * *
* Get the mouse coordinates from the event ( allowing for browser differences ) .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . mouseCoords = function ( event ) {
2007-11-14 09:50:00 +00:00
if ( event . pageX || event . pageY ) {
2009-04-26 19:18:46 +00:00
return { x : event . pageX , y : event . pageY } ;
2007-11-14 09:50:00 +00:00
}
return {
2009-04-26 19:18:46 +00:00
x : event . clientX + document . body . scrollLeft - document . body . clientLeft ,
y : event . clientY + document . body . scrollTop - document . body . clientTop
2007-11-14 09:50:00 +00:00
} ;
} ;
/ * *
* Given a target element and a mouse event , get the mouse offset from that
* element . To do this we need the element ' s position and the mouse position .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . getMouseOffset = function ( target , event ) {
2009-03-08 03:16:26 +00:00
var docPos = $ ( target ) . offset ( ) ;
2007-11-14 09:50:00 +00:00
var mousePos = this . mouseCoords ( event ) ;
2009-03-08 03:16:26 +00:00
return { x : mousePos . x - docPos . left , y : mousePos . y - docPos . top } ;
2007-11-14 09:50:00 +00:00
} ;
/ * *
* Find the row the mouse is currently over . This row is then taken and swapped
* with the one being dragged .
*
* @ param x
* The x coordinate of the mouse on the page ( not the screen ) .
* @ param y
* The y coordinate of the mouse on the page ( not the screen ) .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . findDropTargetRow = function ( x , y ) {
2010-04-27 13:19:31 +00:00
var rows = $ ( this . table . tBodies [ 0 ] . rows ) . not ( ':hidden' ) ;
2009-04-26 19:18:46 +00:00
for ( var n = 0 ; n < rows . length ; n ++ ) {
2007-11-14 09:50:00 +00:00
var row = rows [ n ] ;
2012-04-07 07:19:30 +00:00
var $row = $ ( row ) ;
2007-11-14 09:50:00 +00:00
var indentDiff = 0 ;
2012-04-07 07:19:30 +00:00
var rowY = $row . offset ( ) . top ;
2009-03-17 02:59:27 +00:00
// Because Safari does not report offsetHeight on table rows, but does on
// table cells, grab the firstChild of the row and use that instead.
// http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari.
if ( row . offsetHeight == 0 ) {
2009-09-20 19:14:40 +00:00
var rowHeight = parseInt ( row . firstChild . offsetHeight , 10 ) / 2 ;
2009-03-17 02:59:27 +00:00
}
// Other browsers.
else {
2009-09-20 19:14:40 +00:00
var rowHeight = parseInt ( row . offsetHeight , 10 ) / 2 ;
2009-03-17 02:59:27 +00:00
}
2007-11-14 09:50:00 +00:00
// Because we always insert before, we need to offset the height a bit.
if ( ( y > ( rowY - rowHeight ) ) && ( y < ( rowY + rowHeight ) ) ) {
if ( this . indentEnabled ) {
// Check that this row is not a child of the row being dragged.
2009-12-08 03:10:51 +00:00
for ( var n in this . rowObject . group ) {
2007-11-14 09:50:00 +00:00
if ( this . rowObject . group [ n ] == row ) {
return null ;
}
}
}
2009-03-08 03:16:26 +00:00
else {
// Do not allow a row to be swapped with itself.
if ( row == this . rowObject . element ) {
return null ;
}
}
2007-12-19 10:58:35 +00:00
// Check that swapping with this row is allowed.
if ( ! this . rowObject . isValidSwap ( row ) ) {
2007-11-14 09:50:00 +00:00
return null ;
}
2007-12-19 10:58:35 +00:00
// We may have found the row the mouse just passed over, but it doesn't
2007-11-14 09:50:00 +00:00
// take into account hidden rows. Skip backwards until we find a draggable
// row.
2012-04-07 07:19:30 +00:00
while ( $row . is ( ':hidden' ) && $row . prev ( 'tr' ) . is ( ':hidden' ) ) {
$row = $row . prev ( 'tr' ) . eq ( 0 ) ;
row = $row . get ( 0 ) ;
2007-11-14 09:50:00 +00:00
}
return row ;
}
}
return null ;
} ;
/ * *
* After the row is dropped , update the table fields according to the settings
* set for this table .
*
* @ param changedRow
* DOM object for the row that was just dropped .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . updateFields = function ( changedRow ) {
2007-11-14 09:50:00 +00:00
for ( var group in this . tableSettings ) {
// Each group may have a different setting for relationship, so we find
2008-12-30 16:43:20 +00:00
// the source rows for each separately.
2007-11-26 19:46:52 +00:00
this . updateField ( changedRow , group ) ;
}
2007-12-06 09:53:53 +00:00
} ;
2007-11-14 09:50:00 +00:00
2007-11-26 19:46:52 +00:00
/ * *
* After the row is dropped , update a single table field according to specific
* settings .
*
* @ param changedRow
* DOM object for the row that was just dropped .
* @ param group
* The settings group on which field updates will occur .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . updateField = function ( changedRow , group ) {
2007-11-26 19:46:52 +00:00
var rowSettings = this . rowSettings ( group , changedRow ) ;
2012-04-07 07:19:30 +00:00
var $changedRow = $ ( changedRow ) ;
2007-11-26 19:46:52 +00:00
2010-07-21 00:26:21 +00:00
// Set the row as its own target.
2007-11-26 19:46:52 +00:00
if ( rowSettings . relationship == 'self' || rowSettings . relationship == 'group' ) {
var sourceRow = changedRow ;
}
// Siblings are easy, check previous and next rows.
else if ( rowSettings . relationship == 'sibling' ) {
2012-04-07 07:19:30 +00:00
var $previousRow = $changedRow . prev ( 'tr' ) . eq ( 0 ) ;
var previousRow = $previousRow . get ( 0 ) ;
var $nextRow = $changedRow . next ( 'tr' ) . eq ( 0 ) ;
var nextRow = $nextRow . get ( 0 ) ;
2007-11-26 19:46:52 +00:00
var sourceRow = changedRow ;
2012-04-07 07:19:30 +00:00
if ( $previousRow . is ( '.draggable' ) && $previousRow . find ( '.' + group ) . length ) {
2007-11-26 19:46:52 +00:00
if ( this . indentEnabled ) {
2012-04-07 07:19:30 +00:00
if ( $previousRow . find ( '.indentations' ) . length == $changedRow . find ( '.indentations' ) ) {
2007-11-14 09:50:00 +00:00
sourceRow = previousRow ;
}
}
2007-11-26 19:46:52 +00:00
else {
sourceRow = previousRow ;
2007-11-14 09:50:00 +00:00
}
}
2012-04-07 07:19:30 +00:00
else if ( $nextRow . is ( '.draggable' ) && $nextRow . find ( '.' + group ) . length ) {
2007-11-26 19:46:52 +00:00
if ( this . indentEnabled ) {
2012-04-07 07:19:30 +00:00
if ( $nextRow . find ( '.indentations' ) . length == $changedRow . find ( '.indentations' ) ) {
2007-11-26 19:46:52 +00:00
sourceRow = nextRow ;
}
2007-11-14 09:50:00 +00:00
}
else {
2007-11-26 19:46:52 +00:00
sourceRow = nextRow ;
}
}
}
// Parents, look up the tree until we find a field not in this group.
// Go up as many parents as indentations in the changed row.
else if ( rowSettings . relationship == 'parent' ) {
2012-04-07 07:19:30 +00:00
var $previousRow = $changedRow . prev ( 'tr' ) ;
var previousRow = $previousRow ;
while ( $previousRow . length && $previousRow . find ( '.indentation' ) . length >= this . rowObject . indents ) {
$previousRow = $previousRow . prev ( 'tr' ) ;
previousRow = $previousRow ;
2007-11-26 19:46:52 +00:00
}
// If we found a row.
2012-04-07 07:19:30 +00:00
if ( $previousRow . length ) {
sourceRow = $previousRow . get ( 0 ) ;
2007-11-26 19:46:52 +00:00
}
// Otherwise we went all the way to the left of the table without finding
// a parent, meaning this item has been placed at the root level.
else {
2008-12-30 16:43:20 +00:00
// Use the first row in the table as source, because it's guaranteed to
2007-11-26 19:46:52 +00:00
// be at the root level. Find the first item, then compare this row
// against it as a sibling.
2010-03-31 19:22:00 +00:00
sourceRow = $ ( this . table ) . find ( 'tr.draggable:first' ) . get ( 0 ) ;
2007-11-26 19:46:52 +00:00
if ( sourceRow == this . rowObject . element ) {
sourceRow = $ ( this . rowObject . group [ this . rowObject . group . length - 1 ] ) . next ( 'tr.draggable' ) . get ( 0 ) ;
2007-11-14 09:50:00 +00:00
}
2007-11-26 19:46:52 +00:00
var useSibling = true ;
2007-11-14 09:50:00 +00:00
}
2007-11-26 19:46:52 +00:00
}
2007-11-14 09:50:00 +00:00
2007-11-26 19:46:52 +00:00
// Because we may have moved the row from one category to another,
// take a look at our sibling and borrow its sources and targets.
this . copyDragClasses ( sourceRow , changedRow , group ) ;
rowSettings = this . rowSettings ( group , changedRow ) ;
2007-11-14 09:50:00 +00:00
2007-11-26 19:46:52 +00:00
// In the case that we're looking for a parent, but the row is at the top
// of the tree, copy our sibling's values.
if ( useSibling ) {
rowSettings . relationship = 'sibling' ;
rowSettings . source = rowSettings . target ;
}
2007-11-14 09:50:00 +00:00
2007-11-26 19:46:52 +00:00
var targetClass = '.' + rowSettings . target ;
2012-04-07 07:19:30 +00:00
var targetElement = $changedRow . find ( targetClass ) . get ( 0 ) ;
2007-11-26 19:46:52 +00:00
// Check if a target element exists in this row.
if ( targetElement ) {
var sourceClass = '.' + rowSettings . source ;
var sourceElement = $ ( sourceClass , sourceRow ) . get ( 0 ) ;
switch ( rowSettings . action ) {
case 'depth' :
// Get the depth of the target row.
2012-04-07 07:19:30 +00:00
targetElement . value = $ ( sourceElement ) . closest ( 'tr' ) . find ( '.indentation' ) . length ;
2007-11-26 19:46:52 +00:00
break ;
case 'match' :
// Update the value.
targetElement . value = sourceElement . value ;
break ;
case 'order' :
var siblings = this . rowObject . findSiblings ( rowSettings ) ;
if ( $ ( targetElement ) . is ( 'select' ) ) {
// Get a list of acceptable values.
2009-04-26 19:18:46 +00:00
var values = [ ] ;
2012-04-07 07:19:30 +00:00
$ ( targetElement ) . find ( 'option' ) . each ( function ( ) {
2007-11-26 19:46:52 +00:00
values . push ( this . value ) ;
} ) ;
2008-02-10 19:14:08 +00:00
var maxVal = values [ values . length - 1 ] ;
2007-11-26 19:46:52 +00:00
// Populate the values in the siblings.
2012-04-07 07:19:30 +00:00
$ ( siblings ) . find ( targetClass ) . each ( function ( ) {
2008-02-10 19:14:08 +00:00
// If there are more items than possible values, assign the maximum value to the row.
if ( values . length > 0 ) {
this . value = values . shift ( ) ;
}
else {
this . value = maxVal ;
}
2007-11-26 19:46:52 +00:00
} ) ;
}
else {
// Assume a numeric input field.
2012-04-07 07:19:30 +00:00
var weight = parseInt ( $ ( siblings [ 0 ] ) . find ( targetClass ) . val ( ) , 10 ) || 0 ;
$ ( siblings ) . find ( targetClass ) . each ( function ( ) {
2007-11-26 19:46:52 +00:00
this . value = weight ;
weight ++ ;
} ) ;
}
break ;
2007-11-14 09:50:00 +00:00
}
}
} ;
/ * *
* Copy all special tableDrag classes from one row ' s form elements to a
* different one , removing any special classes that the destination row
* may have had .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . copyDragClasses = function ( sourceRow , targetRow , group ) {
2012-04-07 07:19:30 +00:00
var sourceElement = $ ( sourceRow ) . find ( '.' + group ) ;
var targetElement = $ ( targetRow ) . find ( '.' + group ) ;
2007-11-14 09:50:00 +00:00
if ( sourceElement . length && targetElement . length ) {
targetElement [ 0 ] . className = sourceElement [ 0 ] . className ;
}
} ;
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . checkScroll = function ( cursorY ) {
2007-11-14 09:50:00 +00:00
var de = document . documentElement ;
var b = document . body ;
var windowHeight = this . windowHeight = window . innerHeight || ( de . clientHeight && de . clientWidth != 0 ? de . clientHeight : b . offsetHeight ) ;
var scrollY = this . scrollY = ( document . all ? ( ! de . scrollTop ? b . scrollTop : de . scrollTop ) : ( window . pageYOffset ? window . pageYOffset : window . scrollY ) ) ;
var trigger = this . scrollSettings . trigger ;
var delta = 0 ;
// Return a scroll speed relative to the edge of the screen.
if ( cursorY - scrollY > windowHeight - trigger ) {
delta = trigger / ( windowHeight + scrollY - cursorY ) ;
delta = ( delta > 0 && delta < trigger ) ? delta : trigger ;
return delta * this . scrollSettings . amount ;
}
else if ( cursorY - scrollY < trigger ) {
delta = trigger / ( cursorY - scrollY ) ;
delta = ( delta > 0 && delta < trigger ) ? delta : trigger ;
return - delta * this . scrollSettings . amount ;
}
} ;
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . setScroll = function ( scrollAmount ) {
2007-11-14 09:50:00 +00:00
var self = this ;
2009-04-27 20:19:38 +00:00
this . scrollInterval = setInterval ( function ( ) {
2007-11-14 09:50:00 +00:00
// Update the scroll values stored in the object.
self . checkScroll ( self . currentMouseCoords . y ) ;
var aboveTable = self . scrollY > self . table . topY ;
var belowTable = self . scrollY + self . windowHeight < self . table . bottomY ;
if ( scrollAmount > 0 && belowTable || scrollAmount < 0 && aboveTable ) {
window . scrollBy ( 0 , scrollAmount ) ;
}
} , this . scrollSettings . interval ) ;
} ;
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . restripeTable = function ( ) {
2008-12-30 16:43:20 +00:00
// :even and :odd are reversed because jQuery counts from 0 and
2007-11-14 09:50:00 +00:00
// we count from 1, so we're out of sync.
2009-06-10 05:06:57 +00:00
// Match immediate children of the parent element to allow nesting.
2012-04-07 07:19:30 +00:00
$ ( this . table ) . find ( '> tbody > tr.draggable:visible, > tr.draggable:visible' )
2009-12-08 03:10:51 +00:00
. removeClass ( 'odd even' )
. filter ( ':odd' ) . addClass ( 'even' ) . end ( )
. filter ( ':even' ) . addClass ( 'odd' ) ;
2007-11-14 09:50:00 +00:00
} ;
/ * *
* Stub function . Allows a custom handler when a row begins dragging .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . onDrag = function ( ) {
2007-11-14 09:50:00 +00:00
return null ;
} ;
/ * *
* Stub function . Allows a custom handler when a row is dropped .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . onDrop = function ( ) {
2007-11-14 09:50:00 +00:00
return null ;
} ;
/ * *
* Constructor to make a new object to manipulate a table row .
*
* @ param tableRow
* The DOM element for the table row we will be manipulating .
* @ param method
* The method in which this row is being moved . Either 'keyboard' or 'mouse' .
* @ param indentEnabled
* Whether the containing table uses indentations . Used for optimizations .
2007-11-26 16:19:37 +00:00
* @ param maxDepth
* The maximum amount of indentations this row may contain .
2007-11-14 09:50:00 +00:00
* @ param addClasses
* Whether we want to add classes to this row to indicate child relationships .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . row = function ( tableRow , method , indentEnabled , maxDepth , addClasses ) {
2012-04-07 07:19:30 +00:00
var $tableRow = $ ( tableRow ) ;
2007-11-14 09:50:00 +00:00
this . element = tableRow ;
this . method = method ;
2009-04-26 19:18:46 +00:00
this . group = [ tableRow ] ;
2012-04-07 07:19:30 +00:00
this . groupDepth = $tableRow . find ( '.indentation' ) . length ;
2007-11-14 09:50:00 +00:00
this . changed = false ;
2012-04-07 07:19:30 +00:00
this . table = $tableRow . closest ( 'table' ) . get ( 0 ) ;
2007-11-14 09:50:00 +00:00
this . indentEnabled = indentEnabled ;
2007-11-26 16:19:37 +00:00
this . maxDepth = maxDepth ;
2007-11-14 09:50:00 +00:00
this . direction = '' ; // Direction the row is being moved.
if ( this . indentEnabled ) {
2012-04-07 07:19:30 +00:00
this . indents = $tableRow . find ( '.indentation' ) . length ;
2007-11-14 09:50:00 +00:00
this . children = this . findChildren ( addClasses ) ;
this . group = $ . merge ( this . group , this . children ) ;
// Find the depth of this entire group.
for ( var n = 0 ; n < this . group . length ; n ++ ) {
2012-04-07 07:19:30 +00:00
this . groupDepth = Math . max ( $ ( this . group [ n ] ) . find ( '.indentation' ) . length , this . groupDepth ) ;
2007-11-14 09:50:00 +00:00
}
}
} ;
/ * *
* Find all children of rowObject by indentation .
*
* @ param addClasses
* Whether we want to add classes to this row to indicate child relationships .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . row . prototype . findChildren = function ( addClasses ) {
2007-11-14 09:50:00 +00:00
var parentIndentation = this . indents ;
var currentRow = $ ( this . element , this . table ) . next ( 'tr.draggable' ) ;
2009-04-26 19:18:46 +00:00
var rows = [ ] ;
2007-11-14 09:50:00 +00:00
var child = 0 ;
while ( currentRow . length ) {
2012-04-07 07:19:30 +00:00
var rowIndentation = currentRow . find ( '.indentation' ) . length ;
2007-11-14 09:50:00 +00:00
// A greater indentation indicates this is a child.
if ( rowIndentation > parentIndentation ) {
child ++ ;
rows . push ( currentRow [ 0 ] ) ;
if ( addClasses ) {
2012-04-07 07:19:30 +00:00
currentRow . find ( '.indentation' ) . each ( function ( indentNum ) {
2007-11-14 09:50:00 +00:00
if ( child == 1 && ( indentNum == parentIndentation ) ) {
$ ( this ) . addClass ( 'tree-child-first' ) ;
}
if ( indentNum == parentIndentation ) {
$ ( this ) . addClass ( 'tree-child' ) ;
}
else if ( indentNum > parentIndentation ) {
$ ( this ) . addClass ( 'tree-child-horizontal' ) ;
}
} ) ;
}
}
else {
break ;
}
currentRow = currentRow . next ( 'tr.draggable' ) ;
}
if ( addClasses && rows . length ) {
2012-04-07 07:19:30 +00:00
$ ( rows [ rows . length - 1 ] ) . find ( '.indentation:nth-child(' + ( parentIndentation + 1 ) + ')' ) . addClass ( 'tree-child-last' ) ;
2007-11-14 09:50:00 +00:00
}
return rows ;
} ;
/ * *
2007-12-19 10:58:35 +00:00
* Ensure that two rows are allowed to be swapped .
2007-11-14 09:50:00 +00:00
*
* @ param row
2007-12-19 10:58:35 +00:00
* DOM object for the row being considered for swapping .
2007-11-14 09:50:00 +00:00
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . row . prototype . isValidSwap = function ( row ) {
2012-04-07 07:19:30 +00:00
var $row = $ ( row ) ;
2007-11-14 09:50:00 +00:00
if ( this . indentEnabled ) {
2007-12-19 10:58:35 +00:00
var prevRow , nextRow ;
if ( this . direction == 'down' ) {
prevRow = row ;
2012-04-07 07:19:30 +00:00
nextRow = $row . next ( 'tr' ) . get ( 0 ) ;
2007-11-14 09:50:00 +00:00
}
2007-12-19 10:58:35 +00:00
else {
2012-04-07 07:19:30 +00:00
prevRow = $row . prev ( 'tr' ) . get ( 0 ) ;
2007-12-19 10:58:35 +00:00
nextRow = row ;
}
this . interval = this . validIndentInterval ( prevRow , nextRow ) ;
2007-11-14 09:50:00 +00:00
2007-12-19 10:58:35 +00:00
// We have an invalid swap if the valid indentations interval is empty.
if ( this . interval . min > this . interval . max ) {
2007-11-14 09:50:00 +00:00
return false ;
}
}
2007-12-19 10:58:35 +00:00
// Do not let an un-draggable first row have anything put before it.
2012-04-07 07:19:30 +00:00
if ( this . table . tBodies [ 0 ] . rows [ 0 ] == row && $row . is ( ':not(.draggable)' ) ) {
2007-12-19 10:58:35 +00:00
return false ;
}
2007-11-14 09:50:00 +00:00
return true ;
} ;
/ * *
* Perform the swap between two rows .
*
* @ param position
* Whether the swap will occur 'before' or 'after' the given row .
* @ param row
* DOM element what will be swapped with the row group .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . row . prototype . swap = function ( position , row ) {
2009-11-03 05:34:37 +00:00
Drupal . detachBehaviors ( this . group , Drupal . settings , 'move' ) ;
2007-11-14 09:50:00 +00:00
$ ( row ) [ position ] ( this . group ) ;
2009-11-03 05:34:37 +00:00
Drupal . attachBehaviors ( this . group , Drupal . settings ) ;
2007-11-14 09:50:00 +00:00
this . changed = true ;
this . onSwap ( row ) ;
} ;
/ * *
2007-12-19 10:58:35 +00:00
* Determine the valid indentations interval for the row at a given position
* in the table .
2007-11-14 09:50:00 +00:00
*
2007-12-19 10:58:35 +00:00
* @ param prevRow
* DOM object for the row before the tested position
* ( or null for first position in the table ) .
* @ param nextRow
* DOM object for the row after the tested position
* ( or null for last position in the table ) .
2007-11-14 09:50:00 +00:00
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . row . prototype . validIndentInterval = function ( prevRow , nextRow ) {
2012-04-07 07:19:30 +00:00
var $prevRow = $ ( prevRow ) ;
2007-12-19 10:58:35 +00:00
var minIndent , maxIndent ;
// Minimum indentation:
// Do not orphan the next row.
2012-04-07 07:19:30 +00:00
minIndent = nextRow ? $ ( nextRow ) . find ( '.indentation' ) . length : 0 ;
2007-12-19 10:58:35 +00:00
// Maximum indentation:
2012-04-07 07:19:30 +00:00
if ( ! prevRow || $prevRow . is ( ':not(.draggable)' ) || $ ( this . element ) . is ( '.tabledrag-root' ) ) {
2010-09-11 00:03:42 +00:00
// Do not indent:
// - the first row in the table,
// - rows dragged below a non-draggable row,
// - 'root' rows.
2007-12-19 10:58:35 +00:00
maxIndent = 0 ;
2007-11-14 09:50:00 +00:00
}
else {
2007-12-19 10:58:35 +00:00
// Do not go deeper than as a child of the previous row.
2012-04-07 07:19:30 +00:00
maxIndent = $prevRow . find ( '.indentation' ) . length + ( $prevRow . is ( '.tabledrag-leaf' ) ? 0 : 1 ) ;
2007-12-19 10:58:35 +00:00
// Limit by the maximum allowed depth for the table.
if ( this . maxDepth ) {
maxIndent = Math . min ( maxIndent , this . maxDepth - ( this . groupDepth - this . indents ) ) ;
}
2007-11-14 09:50:00 +00:00
}
2009-04-26 19:18:46 +00:00
return { 'min' : minIndent , 'max' : maxIndent } ;
2009-02-18 13:46:55 +00:00
} ;
2007-12-19 10:58:35 +00:00
/ * *
* Indent a row within the legal bounds of the table .
*
* @ param indentDiff
* The number of additional indentations proposed for the row ( can be
* positive or negative ) . This number will be adjusted to nearest valid
* indentation level for the row .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . row . prototype . indent = function ( indentDiff ) {
2012-04-07 07:19:30 +00:00
var $group = $ ( this . group ) ;
2007-12-19 10:58:35 +00:00
// Determine the valid indentations interval if not available yet.
if ( ! this . interval ) {
2012-01-29 13:31:36 +00:00
var prevRow = $ ( this . element ) . prev ( 'tr' ) . get ( 0 ) ;
2012-04-07 07:19:30 +00:00
var nextRow = $group . filter ( ':last' ) . next ( 'tr' ) . get ( 0 ) ;
2007-12-19 10:58:35 +00:00
this . interval = this . validIndentInterval ( prevRow , nextRow ) ;
2007-11-14 09:50:00 +00:00
}
2007-12-19 10:58:35 +00:00
// Adjust to the nearest valid indentation.
var indent = this . indents + indentDiff ;
indent = Math . max ( indent , this . interval . min ) ;
indent = Math . min ( indent , this . interval . max ) ;
indentDiff = indent - this . indents ;
2007-11-14 09:50:00 +00:00
for ( var n = 1 ; n <= Math . abs ( indentDiff ) ; n ++ ) {
// Add or remove indentations.
if ( indentDiff < 0 ) {
2012-04-07 07:19:30 +00:00
$group . find ( '.indentation:first' ) . remove ( ) ;
2007-11-14 09:50:00 +00:00
this . indents -- ;
}
else {
2012-04-07 07:19:30 +00:00
$group . find ( 'td:first' ) . prepend ( Drupal . theme ( 'tableDragIndentation' ) ) ;
2007-11-14 09:50:00 +00:00
this . indents ++ ;
}
}
if ( indentDiff ) {
2007-12-19 10:58:35 +00:00
// Update indentation for this row.
2007-11-14 09:50:00 +00:00
this . changed = true ;
2007-12-19 10:58:35 +00:00
this . groupDepth += indentDiff ;
this . onIndent ( ) ;
2007-11-14 09:50:00 +00:00
}
return indentDiff ;
} ;
/ * *
* Find all siblings for a row , either according to its subgroup or indentation .
2011-04-12 20:54:16 +00:00
* Note that the passed - in row is included in the list of siblings .
2007-11-14 09:50:00 +00:00
*
* @ param settings
* The field settings we ' re using to identify what constitutes a sibling .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . row . prototype . findSiblings = function ( rowSettings ) {
2009-04-26 19:18:46 +00:00
var siblings = [ ] ;
var directions = [ 'prev' , 'next' ] ;
2007-11-14 09:50:00 +00:00
var rowIndentation = this . indents ;
2010-05-18 06:46:45 +00:00
for ( var d = 0 ; d < directions . length ; d ++ ) {
2007-11-14 09:50:00 +00:00
var checkRow = $ ( this . element ) [ directions [ d ] ] ( ) ;
while ( checkRow . length ) {
// Check that the sibling contains a similar target field.
2012-04-07 07:19:30 +00:00
if ( checkRow . find ( '.' + rowSettings . target ) ) {
2007-11-14 09:50:00 +00:00
// Either add immediately if this is a flat table, or check to ensure
2008-12-30 16:43:20 +00:00
// that this row has the same level of indentation.
2007-11-14 09:50:00 +00:00
if ( this . indentEnabled ) {
2012-04-07 07:19:30 +00:00
var checkRowIndentation = checkRow . find ( '.indentation' ) . length ;
2007-11-14 09:50:00 +00:00
}
if ( ! ( this . indentEnabled ) || ( checkRowIndentation == rowIndentation ) ) {
siblings . push ( checkRow [ 0 ] ) ;
}
else if ( checkRowIndentation < rowIndentation ) {
// No need to keep looking for siblings when we get to a parent.
break ;
}
}
else {
break ;
}
2012-04-07 07:19:30 +00:00
checkRow = checkRow [ directions [ d ] ] ( ) ;
2007-11-14 09:50:00 +00:00
}
// Since siblings are added in reverse order for previous, reverse the
// completed list of previous siblings. Add the current row and continue.
if ( directions [ d ] == 'prev' ) {
siblings . reverse ( ) ;
siblings . push ( this . element ) ;
}
}
return siblings ;
} ;
/ * *
* Remove indentation helper classes from the current row group .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . row . prototype . removeIndentClasses = function ( ) {
2009-12-08 03:10:51 +00:00
for ( var n in this . children ) {
2012-04-07 07:19:30 +00:00
$ ( this . children [ n ] ) . find ( '.indentation' )
2007-11-14 09:50:00 +00:00
. removeClass ( 'tree-child' )
. removeClass ( 'tree-child-first' )
. removeClass ( 'tree-child-last' )
. removeClass ( 'tree-child-horizontal' ) ;
}
} ;
/ * *
* Add an asterisk or other marker to the changed row .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . row . prototype . markChanged = function ( ) {
2007-11-14 09:50:00 +00:00
var marker = Drupal . theme ( 'tableDragChangedMarker' ) ;
2012-04-07 07:19:30 +00:00
var cell = $ ( this . element ) . find ( 'td:first' ) ;
if ( cell . find ( 'abbr.tabledrag-changed' ) . length == 0 ) {
2007-11-14 09:50:00 +00:00
cell . append ( marker ) ;
}
} ;
/ * *
* Stub function . Allows a custom handler when a row is indented .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . row . prototype . onIndent = function ( ) {
2007-11-14 09:50:00 +00:00
return null ;
} ;
/ * *
* Stub function . Allows a custom handler when a row is swapped .
* /
2009-04-27 20:19:38 +00:00
Drupal . tableDrag . prototype . row . prototype . onSwap = function ( swappedRow ) {
2007-11-14 09:50:00 +00:00
return null ;
} ;
2009-04-27 20:19:38 +00:00
Drupal . theme . prototype . tableDragChangedMarker = function ( ) {
2011-07-05 13:44:58 +00:00
return '<abbr class="warning tabledrag-changed" title="' + Drupal . t ( 'Changed' ) + '">*</abbr>' ;
2007-11-14 09:50:00 +00:00
} ;
2009-04-27 20:19:38 +00:00
Drupal . theme . prototype . tableDragIndentation = function ( ) {
2007-11-14 09:50:00 +00:00
return '<div class="indentation"> </div>' ;
} ;
2009-04-27 20:19:38 +00:00
Drupal . theme . prototype . tableDragChangedWarning = function ( ) {
2010-08-09 16:58:15 +00:00
return '<div class="tabledrag-changed-warning messages warning">' + Drupal . theme ( 'tableDragChangedMarker' ) + ' ' + Drupal . t ( 'Changes made in this table will not be saved until the form is submitted.' ) + '</div>' ;
2007-11-14 09:50:00 +00:00
} ;
2009-02-18 13:46:55 +00:00
2009-03-17 02:59:27 +00:00
} ) ( jQuery ) ;