Translation update done using Pootle.
[phpmyadmin/ammaryasirr.git] / js / jquery / jquery.sortableTable.js
blob1f4fc91db836029edacf1f243741714d9d716b3a
1 /* vim: set expandtab sw=4 ts=4 sts=4: */
2 /**
3 * @fileoverview A jquery plugin that allows drag&drop sorting in tables.
4 * Coded because JQuery UI sortable doesn't support tables. Also it has no animation
6 * @name Sortable Table JQuery plugin
8 * @requires jQuery
12 /* Options:
14 $('table').sortableTable({
15 ignoreRect: { top, left, width, height } - relative coordinates on each element. If the user clicks
16 in this area, it is not seen as a drag&drop request. Useful for toolbars etc.
17 events: {
18 start: callback function when the user starts dragging
19 drop: callback function after an element has been dropped
24 /* Commands:
26 $('table').sortableTable('init') - equivalent to $('table').sortableTable()
27 $('table').sortableTable('refresh') - if the table has been changed, refresh correctly assigns all events again
28 $('table').sortableTable('destroy') - removes all events from the table
30 */
32 /* Setup:
34 Can be applied on any table, there is just one convention.
35 Each cell (<td>) has to contain one and only one element (preferably div or span)
36 which is the actually draggable element.
38 (function($) {
39 jQuery.fn.sortableTable = function(method) {
41 var methods = {
42 init : function(options) {
43 var tb = new sortableTableInstance(this, options);
44 tb.init();
45 $(this).data('sortableTable',tb);
47 refresh : function( ) {
48 $(this).data('sortableTable').refresh();
50 destroy : function( ) {
51 $(this).data('sortableTable').destroy();
55 if ( methods[method] ) {
56 return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
57 } else if ( typeof method === 'object' || ! method ) {
58 return methods.init.apply( this, arguments );
59 } else {
60 $.error( 'Method ' + method + ' does not exist on jQuery.sortableTable' );
63 function sortableTableInstance(table, options) {
64 var down = false;
65 var $draggedEl, oldCell, previewMove, id;
67 if(!options) options = {};
69 /* Mouse handlers on the child elements */
70 var onMouseUp = function(e) {
71 dropAt(e.pageX, e.pageY);
74 var onMouseDown = function(e) {
75 $draggedEl = $(this).children();
76 if($draggedEl.length == 0) return;
77 if(options.ignoreRect && insideRect({x: e.pageX - $draggedEl.offset().left, y: e.pageY - $draggedEl.offset().top}, options.ignoreRect)) return;
79 down = true;
80 oldCell = this;
81 //move(e.pageX,e.pageY);
83 if(options.events && options.events.start)
84 options.events.start(this);
86 return false;
89 var globalMouseMove = function(e) {
90 if(down) {
91 move(e.pageX,e.pageY);
93 if(inside($(oldCell), e.pageX, e.pageY)) {
94 if(previewMove != null) {
95 moveTo(previewMove);
96 previewMove = null;
98 } else
99 $(table).find('td').each(function() {
100 if(inside($(this), e.pageX, e.pageY)) {
101 if($(previewMove).attr('class') != $(this).children().first().attr('class')) {
102 if(previewMove != null) moveTo(previewMove);
103 previewMove = $(this).children().first();
104 if(previewMove.length > 0)
105 moveTo($(previewMove), { pos: {
106 top: $(oldCell).offset().top - $(previewMove).parent().offset().top,
107 left: $(oldCell).offset().left - $(previewMove).parent().offset().left
108 } });
111 return false;
116 return false;
119 var globalMouseOut = function() {
120 if(down) {
121 down = false;
122 if(previewMove) moveTo(previewMove);
123 moveTo($draggedEl);
124 previewMove = null;
128 // Initialize sortable table
129 this.init = function() {
130 id = 1;
131 // Add some required css to each child element in the <td>s
132 $(table).find('td').children().each(function() {
133 // Remove any old occurences of our added draggable-num class
134 $(this).attr('class',$(this).attr('class').replace(/\s*draggable\-\d+/g,''));
135 $(this).addClass('draggable-' + (id++));
138 // Mouse events
139 $(table).find('td').bind('mouseup',onMouseUp);
140 $(table).find('td').bind('mousedown',onMouseDown);
142 $(document).mousemove(globalMouseMove);
143 $(document).bind('mouseleave', globalMouseOut);
146 // Call this when the table has been updated
147 this.refresh = function() {
148 this.destroy();
149 this.init();
152 this.destroy = function() {
153 // Add some required css to each child element in the <td>s
154 $(table).find('td').children().each(function() {
155 // Remove any old occurences of our added draggable-num class
156 $(this).attr('class',$(this).attr('class').replace(/\s*draggable\-\d+/g,''));
159 // Mouse events
160 $(table).find('td').unbind('mouseup',onMouseUp)
161 $(table).find('td').unbind('mousedown',onMouseDown);
163 $(document).unbind('mousemove',globalMouseMove);
164 $(document).unbind('mouseleave',globalMouseOut);
167 function switchElement(drag, dropTo) {
168 var dragPosDiff = {
169 left: $(drag).children().first().offset().left - $(dropTo).offset().left,
170 top: $(drag).children().first().offset().top - $(dropTo).offset().top
173 var dropPosDiff = null;
174 if($(dropTo).children().length > 0) {
175 dropPosDiff = {
176 left: $(dropTo).children().first().offset().left - $(drag).offset().left,
177 top: $(dropTo).children().first().offset().top - $(drag).offset().top
181 /* I love you append(). It moves the DOM Elements so gracefully <3 */
182 // Put the element in the way to old place
183 $(drag).append($(dropTo).children().first()).children()
184 .stop(true,true)
185 .bind('mouseup',onMouseUp);
187 if(dropPosDiff)
188 $(drag).append($(dropTo).children().first()).children()
189 .css('left',dropPosDiff.left + 'px')
190 .css('top',dropPosDiff.top + 'px');
192 // Put our dragged element into the space we just freed up
193 $(dropTo).append($(drag).children().first()).children()
194 .bind('mouseup',onMouseUp)
195 .css('left',dragPosDiff.left + 'px')
196 .css('top',dragPosDiff.top + 'px');
198 moveTo($(dropTo).children().first(), { duration: 100 });
199 moveTo($(drag).children().first(), { duration: 100 });
201 if(options.events && options.events.drop) {
202 // Drop event. The drag child element is moved into the drop element
203 // and vice versa. So the parameters are switched.
205 // Calculate row and column index
206 colIdx = $(dropTo).prevAll().length;
207 rowIdx = $(dropTo).parent().prevAll().length;
209 options.events.drop(drag,dropTo, { col: colIdx, row: rowIdx });
213 function move(x,y) {
214 $draggedEl.offset({
215 top: Math.min($(document).height(), Math.max(0, y - $draggedEl.height()/2)),
216 left: Math.min($(document).width(), Math.max(0, x - $draggedEl.width()/2))
220 function inside($el, x,y) {
221 var off = $el.offset();
222 return y >= off.top && x >= off.left && x < off.left + $el.width() && y < off.top + $el.height();
225 function insideRect(pos, r) {
226 return pos.y > r.top && pos.x > r.left && pos.y < r.top + r.height && pos.x < r.left + r.width;
229 function dropAt(x,y) {
230 if(!down) return;
231 down = false;
233 var switched = false;
235 $(table).find('td').each(function() {
236 if($(this).children().first().attr('class') != $(oldCell).children().first().attr('class') && inside($(this), x, y)) {
237 switchElement(oldCell, this);
238 switched = true;
239 return;
243 if(!switched) {
244 if(previewMove) moveTo(previewMove);
245 moveTo($draggedEl);
248 previewMove = null;
251 function moveTo(elem, opts) {
252 if(!opts) opts = {};
253 if(!opts.pos) opts.pos = { left: 0, top: 0 };
254 if(!opts.duration) opts.duration = 200;
256 $(elem).css('position','relative');
257 $(elem).animate({ top: opts.pos.top, left: opts.pos.left }, {
258 duration: opts.duration,
259 complete: function() {
260 if(opts.pos.left == 0 && opts.pos.top == 0) {
261 $(elem)
262 .css('position','')
263 .css('left','')
264 .css('top','');
272 })( jQuery );