Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /** | |
|
borenet
2014/05/07 18:18:05
Not modified.
| |
| 2 * TableDnD plug-in for JQuery, allows you to drag and drop table rows | |
| 3 * You can set up various options to control how the system will work | |
| 4 * Copyright © Denis Howlett <denish@isocra.com> | |
| 5 * Licensed like jQuery, see http://docs.jquery.com/License. | |
| 6 * | |
| 7 * Configuration options: | |
| 8 * | |
| 9 * onDragStyle | |
| 10 * This is the style that is assigned to the row during drag. There are limi tations to the styles that can be | |
| 11 * associated with a row (such as you can't assign a borderâwell you can, but it won't be | |
| 12 * displayed). (So instead consider using onDragClass.) The CSS style to app ly is specified as | |
| 13 * a map (as used in the jQuery css(...) function). | |
| 14 * onDropStyle | |
| 15 * This is the style that is assigned to the row when it is dropped. As for onDragStyle, there are limitations | |
| 16 * to what you can do. Also this replaces the original style, so again consi der using onDragClass which | |
| 17 * is simply added and then removed on drop. | |
| 18 * onDragClass | |
| 19 * This class is added for the duration of the drag and then removed when th e row is dropped. It is more | |
| 20 * flexible than using onDragStyle since it can be inherited by the row cell s and other content. The default | |
| 21 * is class is tDnD_whileDrag. So to use the default, simply customise this CSS class in your | |
| 22 * stylesheet. | |
| 23 * onDrop | |
| 24 * Pass a function that will be called when the row is dropped. The function takes 2 parameters: the table | |
| 25 * and the row that was dropped. You can work out the new order of the rows by using | |
| 26 * table.rows. | |
| 27 * onDragStart | |
| 28 * Pass a function that will be called when the user starts dragging. The fu nction takes 2 parameters: the | |
| 29 * table and the row which the user has started to drag. | |
| 30 * onAllowDrop | |
| 31 * Pass a function that will be called as a row is over another row. If the function returns true, allow | |
| 32 * dropping on that row, otherwise not. The function takes 2 parameters: the dragged row and the row under | |
| 33 * the cursor. It returns a boolean: true allows the drop, false doesn't all ow it. | |
| 34 * scrollAmount | |
| 35 * This is the number of pixels to scroll if the user moves the mouse cursor to the top or bottom of the | |
| 36 * window. The page should automatically scroll up or down as appropriate (t ested in IE6, IE7, Safari, FF2, | |
| 37 * FF3 beta) | |
| 38 * | |
| 39 * Other ways to control behaviour: | |
| 40 * | |
| 41 * Add class="nodrop" to any rows for which you don't want to allow dropping, an d class="nodrag" to any rows | |
| 42 * that you don't want to be draggable. | |
| 43 * | |
| 44 * Inside the onDrop method you can also call $.tableDnD.serialize() this return s a string of the form | |
| 45 * <tableID>[]=<rowID1>&<tableID>[]=<rowID2> so that you can send this back to t he server. The table must have | |
| 46 * an ID as must all the rows. | |
| 47 * | |
| 48 * Known problems: | |
| 49 * - Auto-scoll has some problems with IE7 (it scrolls even when it shouldn't), work-around: set scrollAmount to 0 | |
| 50 * | |
| 51 * Version 0.2: 2008-02-20 First public version | |
| 52 * Version 0.3: 2008-02-07 Added onDragStart option | |
| 53 * Made the scroll amount configurable (default is 5 as before) | |
| 54 * Version 0.4: 2008-03-15 Changed the noDrag/noDrop attributes to nodrag/nodrop classes | |
| 55 * Added onAllowDrop to control dropping | |
| 56 * Fixed a bug which meant that you couldn't set the scr oll amount in both directions | |
| 57 * Added serialise method | |
| 58 */ | |
| 59 jQuery.tableDnD = { | |
| 60 /** Keep hold of the current table being dragged */ | |
| 61 currentTable : null, | |
| 62 /** Keep hold of the current drag object if any */ | |
| 63 dragObject: null, | |
| 64 /** The current mouse offset */ | |
| 65 mouseOffset: null, | |
| 66 /** Remember the old value of Y so that we don't do too much processing */ | |
| 67 oldY: 0, | |
| 68 | |
| 69 /** Actually build the structure */ | |
| 70 build: function(options) { | |
| 71 // Make sure options exists | |
| 72 options = options || {}; | |
| 73 // Set up the defaults if any | |
| 74 | |
| 75 this.each(function() { | |
| 76 // Remember the options | |
| 77 this.tableDnDConfig = { | |
| 78 onDragStyle: options.onDragStyle, | |
| 79 onDropStyle: options.onDropStyle, | |
| 80 // Add in the default class for whileDragging | |
| 81 onDragClass: options.onDragClass ? options.onDra gClass : "tDnD_whileDrag", | |
| 82 onDrop: options.onDrop, | |
| 83 onDragStart: options.onDragStart, | |
| 84 scrollAmount: options.scrollAmount ? options.scrollAmount : 5 | |
| 85 }; | |
| 86 // Now make the rows draggable | |
| 87 jQuery.tableDnD.makeDraggable(this); | |
| 88 }); | |
| 89 | |
| 90 // Now we need to capture the mouse up and mouse move event | |
| 91 // We can use bind so that we don't interfere with other event handlers | |
| 92 jQuery(document) | |
| 93 .bind('mousemove', jQuery.tableDnD.mousemove) | |
| 94 .bind('mouseup', jQuery.tableDnD.mouseup); | |
| 95 | |
| 96 // Don't break the chain | |
| 97 return this; | |
| 98 }, | |
| 99 | |
| 100 /** This function makes all the rows on the table draggable apart from those marked as "NoDrag" */ | |
| 101 makeDraggable: function(table) { | |
| 102 // Now initialise the rows | |
| 103 var rows = table.rows; //getElementsByTagName("tr") | |
| 104 var config = table.tableDnDConfig; | |
| 105 for (var i=0; i<rows.length; i++) { | |
| 106 // To make non-draggable rows, add the nodrag class (eg for Category and Header rows) | |
| 107 // inspired by John Tarr and Famic | |
| 108 var nodrag = $(rows[i]).hasClass("nodrag"); | |
| 109 if (! nodrag) { //There is no NoDnD attribute on rows I want to drag | |
| 110 jQuery(rows[i]).mousedown(function(ev) { | |
| 111 if (ev.target.tagName == "TD") { | |
| 112 jQuery.tableDnD.dragObject = this; | |
| 113 jQuery.tableDnD.currentTable = table; | |
| 114 jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOf fset(this, ev); | |
| 115 if (config.onDragStart) { | |
| 116 // Call the onDrop method if there is one | |
| 117 config.onDragStart(table, this); | |
| 118 } | |
| 119 return false; | |
| 120 } | |
| 121 }).css("cursor", "move"); // Store the tableDnD object | |
| 122 } | |
| 123 } | |
| 124 }, | |
| 125 | |
| 126 /** Get the mouse coordinates from the event (allowing for browser differenc es) */ | |
| 127 mouseCoords: function(ev){ | |
| 128 if(ev.pageX || ev.pageY){ | |
| 129 return {x:ev.pageX, y:ev.pageY}; | |
| 130 } | |
| 131 return { | |
| 132 x:ev.clientX + document.body.scrollLeft - document.body.clientLeft, | |
| 133 y:ev.clientY + document.body.scrollTop - document.body.clientTop | |
| 134 }; | |
| 135 }, | |
| 136 | |
| 137 /** Given a target element and a mouse event, get the mouse offset from that element. | |
| 138 To do this we need the element's position and the mouse position */ | |
| 139 getMouseOffset: function(target, ev) { | |
| 140 ev = ev || window.event; | |
| 141 | |
| 142 var docPos = this.getPosition(target); | |
| 143 var mousePos = this.mouseCoords(ev); | |
| 144 return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y}; | |
| 145 }, | |
| 146 | |
| 147 /** Get the position of an element by going up the DOM tree and adding up al l the offsets */ | |
| 148 getPosition: function(e){ | |
| 149 var left = 0; | |
| 150 var top = 0; | |
| 151 /** Safari fix -- thanks to Luis Chato for this! */ | |
| 152 if (e.offsetHeight == 0) { | |
| 153 /** Safari 2 doesn't correctly grab the offsetTop of a table row | |
| 154 this is detailed here: | |
| 155 http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-b ug-in-safari/ | |
| 156 the solution is likewise noted there, grab the offset of a table cel l in the row - the firstChild. | |
| 157 note that firefox will return a text node as a first child, so desig ning a more thorough | |
| 158 solution may need to take that into account, for now this seems to w ork in firefox, safari, ie */ | |
| 159 e = e.firstChild; // a table cell | |
| 160 } | |
| 161 | |
| 162 while (e.offsetParent){ | |
| 163 left += e.offsetLeft; | |
| 164 top += e.offsetTop; | |
| 165 e = e.offsetParent; | |
| 166 } | |
| 167 | |
| 168 left += e.offsetLeft; | |
| 169 top += e.offsetTop; | |
| 170 | |
| 171 return {x:left, y:top}; | |
| 172 }, | |
| 173 | |
| 174 mousemove: function(ev) { | |
| 175 if (jQuery.tableDnD.dragObject == null) { | |
| 176 return; | |
| 177 } | |
| 178 | |
| 179 var dragObj = jQuery(jQuery.tableDnD.dragObject); | |
| 180 var config = jQuery.tableDnD.currentTable.tableDnDConfig; | |
| 181 var mousePos = jQuery.tableDnD.mouseCoords(ev); | |
| 182 var y = mousePos.y - jQuery.tableDnD.mouseOffset.y; | |
| 183 //auto scroll the window | |
| 184 var yOffset = window.pageYOffset; | |
| 185 if (document.all) { | |
| 186 // Windows version | |
| 187 //yOffset=document.body.scrollTop; | |
| 188 if (typeof document.compatMode != 'undefined' && | |
| 189 document.compatMode != 'BackCompat') { | |
| 190 yOffset = document.documentElement.scrollTop; | |
| 191 } | |
| 192 else if (typeof document.body != 'undefined') { | |
| 193 yOffset=document.body.scrollTop; | |
| 194 } | |
| 195 | |
| 196 } | |
| 197 | |
| 198 if (mousePos.y-yOffset < config.scrollAmount) { | |
| 199 window.scrollBy(0, -config.scrollAmount); | |
| 200 } else { | |
| 201 var windowHeight = window.innerHeight ? window.innerHeight | |
| 202 : document.documentElement.clientHeight ? document.documentE lement.clientHeight : document.body.clientHeight; | |
| 203 if (windowHeight-(mousePos.y-yOffset) < config.scrollAmount) { | |
| 204 window.scrollBy(0, config.scrollAmount); | |
| 205 } | |
| 206 } | |
| 207 | |
| 208 | |
| 209 if (y != jQuery.tableDnD.oldY) { | |
| 210 // work out if we're going up or down... | |
| 211 var movingDown = y > jQuery.tableDnD.oldY; | |
| 212 // update the old value | |
| 213 jQuery.tableDnD.oldY = y; | |
| 214 // update the style to show we're dragging | |
| 215 if (config.onDragClass) { | |
| 216 dragObj.addClass(config.onDragClass); | |
| 217 } else { | |
| 218 dragObj.css(config.onDragStyle); | |
| 219 } | |
| 220 // If we're over a row then move the dragged row to there so that th e user sees the | |
| 221 // effect dynamically | |
| 222 var currentRow = jQuery.tableDnD.findDropTargetRow(dragObj, y); | |
| 223 if (currentRow) { | |
| 224 // TODO worry about what happens when there are multiple TBODIES | |
| 225 if (movingDown && jQuery.tableDnD.dragObject != currentRow) { | |
| 226 jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.ta bleDnD.dragObject, currentRow.nextSibling); | |
| 227 } else if (! movingDown && jQuery.tableDnD.dragObject != current Row) { | |
| 228 jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.ta bleDnD.dragObject, currentRow); | |
| 229 } | |
| 230 } | |
| 231 } | |
| 232 | |
| 233 return false; | |
| 234 }, | |
| 235 | |
| 236 /** We're only worried about the y position really, because we can only move rows up and down */ | |
| 237 findDropTargetRow: function(draggedRow, y) { | |
| 238 var rows = jQuery.tableDnD.currentTable.rows; | |
| 239 for (var i=0; i<rows.length; i++) { | |
| 240 var row = rows[i]; | |
| 241 var rowY = this.getPosition(row).y; | |
| 242 var rowHeight = parseInt(row.offsetHeight)/2; | |
| 243 if (row.offsetHeight == 0) { | |
| 244 rowY = this.getPosition(row.firstChild).y; | |
| 245 rowHeight = parseInt(row.firstChild.offsetHeight)/2; | |
| 246 } | |
| 247 // Because we always have to insert before, we need to offset the he ight a bit | |
| 248 if ((y > rowY - rowHeight) && (y < (rowY + rowHeight))) { | |
| 249 // that's the row we're over | |
| 250 // If it's the same as the current row, ignore i t | |
| 251 if (row == draggedRow) {return null;} | |
| 252 var config = jQuery.tableDnD.currentTable.tableDnDConfig; | |
| 253 if (config.onAllowDrop) { | |
| 254 if (config.onAllowDrop(draggedRow, row)) { | |
| 255 return row; | |
| 256 } else { | |
| 257 return null; | |
| 258 } | |
| 259 } else { | |
| 260 // If a row has nodrop class, then don't allow dropping (inspired by John Tarr and Famic) | |
| 261 var nodrop = $(row).hasClass("nodrop"); | |
| 262 if (! nodrop) { | |
| 263 return row; | |
| 264 } else { | |
| 265 return null; | |
| 266 } | |
| 267 } | |
| 268 return row; | |
| 269 } | |
| 270 } | |
| 271 return null; | |
| 272 }, | |
| 273 | |
| 274 mouseup: function(e) { | |
| 275 if (jQuery.tableDnD.currentTable && jQuery.tableDnD.dragObject) { | |
| 276 var droppedRow = jQuery.tableDnD.dragObject; | |
| 277 var config = jQuery.tableDnD.currentTable.tableDnDConfig; | |
| 278 // If we have a dragObject, then we need to release it, | |
| 279 // The row will already have been moved to the right place so we jus t reset stuff | |
| 280 if (config.onDragClass) { | |
| 281 jQuery(droppedRow).removeClass(config.onDragClass); | |
| 282 } else { | |
| 283 jQuery(droppedRow).css(config.onDropStyle); | |
| 284 } | |
| 285 jQuery.tableDnD.dragObject = null; | |
| 286 if (config.onDrop) { | |
| 287 // Call the onDrop method if there is one | |
| 288 config.onDrop(jQuery.tableDnD.currentTable, droppedRow); | |
| 289 } | |
| 290 jQuery.tableDnD.currentTable = null; // let go of the table too | |
| 291 } | |
| 292 }, | |
| 293 | |
| 294 serialize: function() { | |
| 295 if (jQuery.tableDnD.currentTable) { | |
| 296 var result = ""; | |
| 297 var tableId = jQuery.tableDnD.currentTable.id; | |
| 298 var rows = jQuery.tableDnD.currentTable.rows; | |
| 299 for (var i=0; i<rows.length; i++) { | |
| 300 if (result.length > 0) result += "&"; | |
| 301 result += tableId + '[]=' + rows[i].id; | |
| 302 } | |
| 303 return result; | |
| 304 } else { | |
| 305 return "Error: No Table id set, you need to set an id on your table and every row"; | |
| 306 } | |
| 307 } | |
| 308 } | |
| 309 | |
| 310 jQuery.fn.extend( | |
| 311 { | |
| 312 tableDnD : jQuery.tableDnD.build | |
| 313 } | |
| 314 ); | |
| OLD | NEW |