1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
var currenttable = null;
document.onmousemove = function(ev){
if (currenttable && currenttable.dragObject) {
ev = ev || window.event;
var mousePos = currenttable.mouseCoords(ev);
var y = mousePos.y - currenttable.mouseOffset.y;
if (y != currenttable.oldY) {
// work out if we're going up or down...
var movingDown = y > currenttable.oldY;
// update the old value
currenttable.oldY = y;
// update the style to show we're dragging
currenttable.dragObject.style.backgroundColor = "#eee";
// If we're over a cell then move the dragged cell to there so that the user sees the
// effect dynamically
var currentCell = currenttable.findDropTargetCell(y);
if (currentCell) {
if (movingDown && currenttable.dragObject != currentCell) {
currenttable.dragObject.parentNode.insertBefore(currenttable.dragObject, currentCell.nextSibling);
} else if (! movingDown && currenttable.dragObject != currentCell) {
currenttable.dragObject.parentNode.insertBefore(currenttable.dragObject, currentCell);
}
}
}
return false;
}
}
// Similarly for the mouseup
document.onmouseup = function(ev){
if (currenttable && currenttable.dragObject) {
var droppedCell = currenttable.dragObject;
// If we have a dragObject, then we need to release it,
// The cell will already have been moved to the right place so we just reset stuff
droppedCell.style.backgroundColor = 'transparent';
currenttable.dragObject = null;
// And then call the onDrop method in case anyone wants to do any post processing
currenttable.onDrop(currenttable.table, droppedCell);
currenttable = null; // let go of the table too
}
}
/** get the source element from an event in a way that works for IE and Firefox and Safari
* @param evt the source event for Firefox (but not IE--IE uses window.event) */
function getEventSource(evt) {
if (window.event) {
evt = window.event; // For IE
return evt.srcElement;
} else {
return evt.target; // For Firefox
}
}
/**
* Encapsulate table Drag and Drop in a class. We'll have this as a Singleton
* so we don't get scoping problems.
*/
function TableDnD() {
/** Keep hold of the current drag object if any */
this.dragObject = null;
/** The current mouse offset */
this.mouseOffset = null;
/** The current table */
this.table = null;
/** Remember the old value of Y so that we don't do too much processing */
this.oldY = 0;
/** Initialise the drag and drop by capturing mouse move events */
this.init = function(table) {
this.table = table;
var rows = table.tBodies[0].rows; //getElementsByTagName("td")
for (var j=0; j<rows.length;j++) {
var cells = table.tBodies[0].rows[j].cells;
for (var i=0; i<cells.length; i++) {
// John Tarr: added to ignore cells that I've added the NoDnD attribute to (Category and Header cells)
var nodrag = cells[i].getAttribute("NoDrag")
if (nodrag == null || nodrag == "undefined") { //There is no NoDnD attribute on cells I want to drag
this.makeDraggable(cells[i]);
}
}
}
}
/** This function is called when you drop a cell, so redefine it in your code
to do whatever you want, for example use Ajax to update the server */
this.onDrop = function(table, droppedCell) {
// Do nothing for now
}
/** Get the position of an element by going up the DOM tree and adding up all the offsets */
this.getPosition = function(e){
var left = 0;
var top = 0;
/** Safari fix -- thanks to Luis Chato for this! */
if (e.offsetHeight == 0) {
/** Safari 2 doesn't correctly grab the offsetTop of a table cell
this is detailed here:
http://jacob.peargrove.com/blog/2006/technical/table-cell-offsettop-bug-in-safari/
the solution is likewise noted there, grab the offset of a table cell in the cell - the firstChild.
note that firefox will return a text node as a first child, so designing a more thorough
solution may need to take that into account, for now this seems to work in firefox, safari, ie */
e = e.firstChild; // a table cell
}
while (e.offsetParent){
left += e.offsetLeft;
top += e.offsetTop;
e = e.offsetParent;
}
left += e.offsetLeft;
top += e.offsetTop;
return {x:left, y:top};
}
/** Get the mouse coordinates from the event (allowing for browser differences) */
this.mouseCoords = function(ev){
if(ev.pageX || ev.pageY){
return {x:ev.pageX, y:ev.pageY};
}
return {
x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
y:ev.clientY + document.body.scrollTop - document.body.clientTop
};
}
/** 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 */
this.getMouseOffset = function(target, ev){
ev = ev || window.event;
var docPos = this.getPosition(target);
var mousePos = this.mouseCoords(ev);
return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
}
/** Take an item and add an onmousedown method so that we can make it draggable */
this.makeDraggable = function(item) {
if(!item) return;
var self = this; // Keep the context of the TableDnd inside the function
item.onmousedown = function(ev) {
// Need to check to see if we are an input or not, if we are an input, then
// return true to allow normal processing
var target = getEventSource(ev);
if (target.tagName == 'INPUT' || target.tagName == 'SELECT') return true;
currenttable = self;
self.dragObject = this;
self.mouseOffset = self.getMouseOffset(this, ev);
return false;
}
item.style.cursor = "move";
}
/** We're only worried about the y position really, because we can only move cells up and down */
this.findDropTargetCell = function(y) {
var rows = this.table.tBodies[0].rows;
for (var j=0; j<rows.length;j++) {
var cells = this.table.tBodies[0].rows[j].cells;
for (var i=0; i<cells.length; i++) {
var cell = cells[i];
// John Tarr added to ignore cells that I've added the NoDnD attribute to (Header cells)
var nodrop = cell.getAttribute("NoDrop");
if (nodrop == null || nodrop == "undefined") { //There is no NoDnD attribute on cells I want to drag
var cellY = this.getPosition(cell).y;
var cellHeight = parseInt(cell.offsetHeight)/2;
// Because we always have to insert before, we need to offset the height a bit
if ((y > cellY - cellHeight) && (y < (cellY + cellHeight))) {
// that's the cell we're over
return cell;
}
}
}
}
return null;
}
} |
Partager