d28c1fcec0aca9505cc4de7bc07e08ae976ba1ff tdreszer Tue May 31 18:51:29 2011 -0700 Drag and drop of tracks in image will now drag contiguous set of subtracks if dragging side button. Occasional wierdness when dragging too fast. diff --git src/hg/js/jquery.tablednd.js src/hg/js/jquery.tablednd.js index 73e54fa..5fdb9ce 100644 --- src/hg/js/jquery.tablednd.js +++ src/hg/js/jquery.tablednd.js @@ -95,30 +95,33 @@ // Set up the defaults if any this.each(function() { // This is bound to each matching table, set up the defaults and override with user options this.tableDnDConfig = jQuery.extend({ onDragStyle: null, onDropStyle: null, // Add in the default class for whileDragging onDragClass: "tDnD_whileDrag", onDrop: null, onDragStart: null, scrollAmount: 5, serializeRegexp: /[^\-]*$/, // The regular expression to use to trim row IDs serializeParamName: null, // If you want to specify another parameter name instead of the table ID dragHandle: null, // If you give the name of a class here, then only Cells with this class will be draggable + dragObjects: [], // UCSC: Allows setting multiple rows to be dragged at one time + downOffset: 0, // UCSC: Dragging set, then offset Y to bottom of set + upOffset: 0, // UCSC: Dragging set, then offset Y to bottom of set dragStartIndex : 0 }, options || {}); // Now make the rows draggable jQuery.tableDnD.makeDraggable(this); }); // Now we need to capture the mouse up and mouse move event // We can use bind so that we don't interfere with other event handlers jQuery(document) .bind('mousemove', jQuery.tableDnD.mousemove) .bind('mouseup', jQuery.tableDnD.mouseup); // Don't break the chain return this; }, @@ -130,31 +133,46 @@ // We only need to add the event to the specified cells var cells = jQuery("td."+table.tableDnDConfig.dragHandle, table); cells.each(function() { // The cell is bound to "this" jQuery(this).mousedown(function(ev) { if(ev.button > 1) return true; if(jQuery.tableDnD == undefined) return false; jQuery.tableDnD.dragObject = this.parentNode; jQuery.tableDnD.currentTable = table; jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOffset(this, ev); config.dragStartIndex = $(jQuery.tableDnD.dragObject).attr('rowIndex'); if (config.onDragStart) { // Call the onDrop method if there is one - config.onDragStart(ev, table, this); + config.onDragStart(ev, table, this.parentNode); + + /////// UCSC + config.downOffset = 0; + config.upOffset = 0; + if (config.dragObjects.length > 1) { + for(var ix = 0; ix < config.dragObjects.length; ix++) { + var row = config.dragObjects[ix]; + var rowIx = $(row).attr('rowIndex'); + if (rowIx < config.dragStartIndex) + config.upOffset -= $(row).height(); + else if (rowIx > config.dragStartIndex) + config.downOffset += $(row).height(); + } + } + /////// UCSC } return false; }); }) } else { // For backwards compatibility, we add the event to the whole row var rows = jQuery("tr", table); // get all the rows as a wrapped set rows.each(function() { // Iterate through each row, the row is bound to "this" var row = jQuery(this); if (! row.hasClass("nodrag")) { row.mousedown(function(ev) { if (ev.target.tagName == "TD") { jQuery.tableDnD.dragObject = this; jQuery.tableDnD.currentTable = table; @@ -265,67 +283,105 @@ if (mousePos.y-yOffset < config.scrollAmount) { window.scrollBy(0, -config.scrollAmount); } else { var windowHeight = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight; if (windowHeight-(mousePos.y-yOffset) < config.scrollAmount) { window.scrollBy(0, config.scrollAmount); } } if (y != jQuery.tableDnD.oldY) { // work out if we're going up or down... var movingDown = y > jQuery.tableDnD.oldY; // update the old value - jQuery.tableDnD.oldY = y; + ////// UCSC jQuery.tableDnD.oldY = y; // Do this below, only when rows have moved. // update the style to show we're dragging if (config.onDragClass) { + ////// UCSC + if (config.dragObjects.length > 1) + config.dragObjects.addClass(config.onDragClass); + else ////// UCSC dragObj.addClass(config.onDragClass); } else { + ////// UCSC + if (config.dragObjects.length > 1) + config.css(config.onDragStyle); + else ////// UCSC dragObj.css(config.onDragStyle); } // If we're over a row then move the dragged row to there so that the user sees the // effect dynamically var currentRow = jQuery.tableDnD.findDropTargetRow(dragObj, y); + ////// UCSC + if (config.dragObjects.length > 1) { + if (movingDown) + currentRow = jQuery.tableDnD.findDropTargetRow(config.dragObjects[config.dragObjects.length - 1], y + config.downOffset); + else + currentRow = jQuery.tableDnD.findDropTargetRow(config.dragObjects[0], y + config.upOffset); + } ////// UCSC + if (currentRow) { + ////// UCSC + if (config.dragObjects.length > 1) { + if (movingDown && config.dragObjects[config.dragObjects.length - 1] != currentRow) { + try { // use try/catch because sometimes rows go missing when moving down + $( currentRow ).insertBefore( $( config.dragObjects[0] ) ); + jQuery.tableDnD.oldY = y; + } + catch (err) { // just put them all back + for(var ix=0;ix < config.dragObjects.length; ix++) { + $(config.dragObjects[ix]).insertBefore( currentRow ); + } + } + } else if (!movingDown && config.dragObjects[0] != currentRow) { + $(config.dragObjects).insertBefore( currentRow ); + jQuery.tableDnD.oldY = y; + } + } else { ////// UCSC + // TODO worry about what happens when there are multiple TBODIES if (movingDown && jQuery.tableDnD.dragObject != currentRow) { jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow.nextSibling); + jQuery.tableDnD.oldY = y; } else if (! movingDown && jQuery.tableDnD.dragObject != currentRow) { jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow); + jQuery.tableDnD.oldY = y; } + + } ////// UCSC } } return false; }, /** We're only worried about the y position really, because we can only move rows up and down */ findDropTargetRow: function(draggedRow, y) { var rows = jQuery.tableDnD.currentTable.rows; for (var i=0; i<rows.length; i++) { var row = rows[i]; var rowY = this.getPosition(row).y; var rowHeight = parseInt(row.offsetHeight)/2; if (row.offsetHeight == 0) { rowY = this.getPosition(row.firstChild).y; rowHeight = parseInt(row.firstChild.offsetHeight)/2; } // Because we always have to insert before, we need to offset the height a bit //////////if ((y > rowY - rowHeight) && (y < (rowY + rowHeight))) { - if ((y > rowY) && (y < (rowY + rowHeight))) { ////////// This was modified by tim because of tall tracks + if ((y > rowY) && (y < (rowY + rowHeight))) { ////////// UCSC This was modified by tim because of tall tracks // that's the row we're over // If it's the same as the current row, ignore it if (row == draggedRow) {return null;} var config = jQuery.tableDnD.currentTable.tableDnDConfig; if (config.onAllowDrop) { if (config.onAllowDrop(draggedRow, row)) { return row; } else { return null; } } else { // If a row has nodrop class, then don't allow dropping (inspired by John Tarr and Famic) var nodrop = jQuery(row).hasClass("nodrop"); if (! nodrop) { return row; @@ -340,40 +396,49 @@ }, mouseup: function(e) { if(jQuery.tableDnD == undefined) { jQuery(document) .unbind('mousemove')//, jQuery.tableDnD.mousemove); .unbind('mouseup');//, jQuery.tableDnD.mouseup); return; } if (jQuery.tableDnD.currentTable && jQuery.tableDnD.dragObject) { var droppedRow = jQuery.tableDnD.dragObject; var config = jQuery.tableDnD.currentTable.tableDnDConfig; // If we have a dragObject, then we need to release it, // The row will already have been moved to the right place so we just reset stuff if (config.onDragClass) { + ////// UCSC + if (config.dragObjects.length > 1) + config.dragObjects.removeClass(config.onDragClass); + else ////// UCSC jQuery(droppedRow).removeClass(config.onDragClass); } else { + ////// UCSC + if (config.dragObjects.length > 1) + config.dragObjects.css(config.onDropStyle); + else ////// UCSC jQuery(droppedRow).css(config.onDropStyle); } jQuery.tableDnD.dragObject = null; if (config.onDrop) { // Call the onDrop method if there is one config.onDrop(jQuery.tableDnD.currentTable, droppedRow, config.dragStartIndex); } jQuery.tableDnD.currentTable = null; // let go of the table too + config.dragObjects = []; ////// UCSC } }, serialize: function() { if (jQuery.tableDnD.currentTable) { return jQuery.tableDnD.serializeTable(jQuery.tableDnD.currentTable); } else { return "Error: No Table id set, you need to set an id on your table and every row"; } }, serializeTable: function(table) { var result = ""; var tableId = table.id; var rows = table.rows;