Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2629 vikas 1
/*
2
 * File:        ColReorder.js
3
 * Version:     1.0.2
4
 * CVS:         $Id$
5
 * Description: Controls for column visiblity in DataTables
6
 * Author:      Allan Jardine (www.sprymedia.co.uk)
7
 * Created:     Wed Sep 15 18:23:29 BST 2010
8
 * Modified:    $Date$ by $Author$
9
 * Language:    Javascript
10
 * License:     GPL v2 or BSD 3 point style
11
 * Project:     DataTables
12
 * Contact:     www.sprymedia.co.uk/contact
13
 * 
14
 * Copyright 2010-2011 Allan Jardine, all rights reserved.
15
 *
16
 * This source file is free software, under either the GPL v2 license or a
17
 * BSD style license, available at:
18
 *   http://datatables.net/license_gpl2
19
 *   http://datatables.net/license_bsd
20
 *
21
 */
22
 
23
 
24
(function($, window, document) {
25
 
26
 
27
/**
28
 * Switch the key value pairing of an index array to be value key (i.e. the old value is now the
29
 * key). For example consider [ 2, 0, 1 ] this would be returned as [ 1, 2, 0 ].
30
 *  @method  fnInvertKeyValues
31
 *  @param   array aIn Array to switch around
32
 *  @returns array
33
 */
34
function fnInvertKeyValues( aIn )
35
{
36
	var aRet=[];
37
	for ( var i=0, iLen=aIn.length ; i<iLen ; i++ )
38
	{
39
		aRet[ aIn[i] ] = i;
40
	}
41
	return aRet;
42
}
43
 
44
 
45
/**
46
 * Modify an array by switching the position of two elements
47
 *  @method  fnArraySwitch
48
 *  @param   array aArray Array to consider, will be modified by reference (i.e. no return)
49
 *  @param   int iFrom From point
50
 *  @param   int iTo Insert point
51
 *  @returns void
52
 */
53
function fnArraySwitch( aArray, iFrom, iTo )
54
{
55
	var mStore = aArray.splice( iFrom, 1 )[0];
56
	aArray.splice( iTo, 0, mStore );
57
}
58
 
59
 
60
/**
61
 * Switch the positions of nodes in a parent node (note this is specifically designed for 
62
 * table rows). Note this function considers all element nodes under the parent!
63
 *  @method  fnDomSwitch
64
 *  @param   string sTag Tag to consider
65
 *  @param   int iFrom Element to move
66
 *  @param   int Point to element the element to (before this point), can be null for append
67
 *  @returns void
68
 */
69
function fnDomSwitch( nParent, iFrom, iTo )
70
{
71
	var anTags = [];
72
	for ( var i=0, iLen=nParent.childNodes.length ; i<iLen ; i++ )
73
	{
74
		if ( nParent.childNodes[i].nodeType == 1 )
75
		{
76
			anTags.push( nParent.childNodes[i] );
77
		}
78
	}
79
	var nStore = anTags[ iFrom ];
80
 
81
	if ( iTo !== null )
82
	{
83
		nParent.insertBefore( nStore, anTags[iTo] );
84
	}
85
	else
86
	{
87
		nParent.appendChild( nStore );
88
	}
89
}
90
 
91
 
92
 
93
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
94
 * DataTables plug-in API functions
95
 *
96
 * This are required by ColReorder in order to perform the tasks required, and also keep this
97
 * code portable, to be used for other column reordering projects with DataTables, if needed.
98
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
99
 
100
 
101
/**
102
 * Plug-in for DataTables which will reorder the internal column structure by taking the column
103
 * from one position (iFrom) and insert it into a given point (iTo).
104
 *  @method  $.fn.dataTableExt.oApi.fnColReorder
105
 *  @param   object oSettings DataTables settings object - automatically added by DataTables! 
106
 *  @param   int iFrom Take the column to be repositioned from this point
107
 *  @param   int iTo and insert it into this point
108
 *  @returns void
109
 */
110
$.fn.dataTableExt.oApi.fnColReorder = function ( oSettings, iFrom, iTo )
111
{
112
	var i, iLen, j, jLen, iCols=oSettings.aoColumns.length, nTrs;
113
 
114
	/* Sanity check in the input */
115
	if ( iFrom == iTo )
116
	{
117
		/* Pointless reorder */
118
		return;
119
	}
120
 
121
	if ( iFrom < 0 || iFrom >= iCols )
122
	{
123
		this.oApi._fnLog( oSettings, 1, "ColReorder 'from' index is out of bounds: "+iFrom );
124
		return;
125
	}
126
 
127
	if ( iTo < 0 || iTo >= iCols )
128
	{
129
		this.oApi._fnLog( oSettings, 1, "ColReorder 'to' index is out of bounds: "+iTo );
130
		return;
131
	}
132
 
133
	/*
134
	 * Calculate the new column array index, so we have a mapping between the old and new
135
	 */
136
	var aiMapping = [];
137
	for ( i=0, iLen=iCols ; i<iLen ; i++ )
138
	{
139
		aiMapping[i] = i;
140
	}
141
	fnArraySwitch( aiMapping, iFrom, iTo );
142
	var aiInvertMapping = fnInvertKeyValues( aiMapping );
143
 
144
 
145
	/*
146
	 * Convert all internal indexing to the new column order indexes
147
	 */
148
	/* Sorting */
149
	for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
150
	{
151
		oSettings.aaSorting[i][0] = aiInvertMapping[ oSettings.aaSorting[i][0] ];
152
	}
153
 
154
	/* Fixed sorting */
155
	if ( oSettings.aaSortingFixed !== null )
156
	{
157
		for ( i=0, iLen=oSettings.aaSortingFixed.length ; i<iLen ; i++ )
158
		{
159
			oSettings.aaSortingFixed[i][0] = aiInvertMapping[ oSettings.aaSortingFixed[i][0] ];
160
		}
161
	}
162
 
163
	/* Data column sorting (the column which the sort for a given column should take place on) */
164
	for ( i=0, iLen=iCols ; i<iLen ; i++ )
165
	{
166
		oSettings.aoColumns[i].iDataSort = aiInvertMapping[ oSettings.aoColumns[i].iDataSort ];
167
	}
168
 
169
 
170
	/*
171
	 * Move the DOM elements
172
	 */
173
	if ( oSettings.aoColumns[iFrom].bVisible )
174
	{
175
		/* Calculate the current visible index and the point to insert the node before. The insert
176
		 * before needs to take into account that there might not be an element to insert before,
177
		 * in which case it will be null, and an appendChild should be used
178
		 */
179
		var iVisibleIndex = this.oApi._fnColumnIndexToVisible( oSettings, iFrom );
180
		var iInsertBeforeIndex = null;
181
 
182
		i = iTo < iFrom ? iTo : iTo + 1;
183
		while ( iInsertBeforeIndex === null && i < iCols )
184
		{
185
			iInsertBeforeIndex = this.oApi._fnColumnIndexToVisible( oSettings, i );
186
			i++;
187
		}
188
 
189
		/* Header */
190
		nTrs = oSettings.nTHead.getElementsByTagName('tr');
191
		for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
192
		{
193
			fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );
194
		}
195
 
196
		/* Footer */
197
		if ( oSettings.nTFoot !== null )
198
		{
199
			nTrs = oSettings.nTFoot.getElementsByTagName('tr');
200
			for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
201
			{
202
				fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );
203
			}
204
		}
205
 
206
		/* Body */
207
		for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
208
		{
209
			fnDomSwitch( oSettings.aoData[i].nTr, iVisibleIndex, iInsertBeforeIndex );
210
		}
211
	}
212
 
213
 
214
	/* 
215
	 * Move the internal array elements
216
	 */
217
	/* Columns */
218
	fnArraySwitch( oSettings.aoColumns, iFrom, iTo );
219
 
220
	/* Search columns */
221
	fnArraySwitch( oSettings.aoPreSearchCols, iFrom, iTo );
222
 
223
	/* Array array - internal data anodes cache */
224
	for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
225
	{
226
		if ( $.isArray( oSettings.aoData[i]._aData ) ) {
227
		  fnArraySwitch( oSettings.aoData[i]._aData, iFrom, iTo );
228
		}
229
		fnArraySwitch( oSettings.aoData[i]._anHidden, iFrom, iTo );
230
	}
231
 
232
	/* Reposition the header elements in the header layout array */
233
	for ( i=0, iLen=oSettings.aoHeader.length ; i<iLen ; i++ )
234
	{
235
		fnArraySwitch( oSettings.aoHeader[i], iFrom, iTo );
236
	}
237
 
238
	if ( oSettings.aoFooter !== null )
239
	{
240
		for ( i=0, iLen=oSettings.aoFooter.length ; i<iLen ; i++ )
241
		{
242
			fnArraySwitch( oSettings.aoFooter[i], iFrom, iTo );
243
		}
244
	}
245
 
246
 
247
	/*
248
	 * Update DataTables' event handlers
249
	 */
250
 
251
	/* Sort listener */
252
	for ( i=0, iLen=iCols ; i<iLen ; i++ )
253
	{
254
		$(oSettings.aoColumns[i].nTh).unbind('click');
255
		this.oApi._fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
256
	}
257
 
258
 
259
	/*
260
	 * Any extra operations for the other plug-ins
261
	 */
262
	if ( typeof ColVis != 'undefined' )
263
	{
264
		ColVis.fnRebuild( oSettings.oInstance );
265
	}
266
 
267
	if ( typeof oSettings.oInstance._oPluginFixedHeader != 'undefined' )
268
	{
269
		oSettings.oInstance._oPluginFixedHeader.fnUpdate();
270
	}
271
};
272
 
273
 
274
 
275
 
276
/** 
277
 * ColReorder provides column visiblity control for DataTables
278
 * @class ColReorder
279
 * @constructor
280
 * @param {object} DataTables object
281
 * @param {object} ColReorder options
282
 */
283
ColReorder = function( oTable, oOpts )
284
{
285
	/* Santiy check that we are a new instance */
286
	if ( !this.CLASS || this.CLASS != "ColReorder" )
287
	{
288
		alert( "Warning: ColReorder must be initialised with the keyword 'new'" );
289
	}
290
 
291
	if ( typeof oOpts == 'undefined' )
292
	{
293
		oOpts = {};
294
	}
295
 
296
 
297
	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
298
	 * Public class variables
299
	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
300
 
301
	/**
302
	 * @namespace Settings object which contains customisable information for ColReorder instance
303
	 */
304
	this.s = {
305
		/**
306
		 * DataTables settings object
307
		 *  @property dt
308
		 *  @type     Object
309
		 *  @default  null
310
		 */
311
		"dt": null,
312
 
313
		/**
314
		 * Initialisation object used for this instance
315
		 *  @property init
316
		 *  @type     object
317
		 *  @default  {}
318
		 */
319
		"init": oOpts,
320
 
321
		/**
322
		 * Number of columns to fix (not allow to be reordered)
323
		 *  @property fixed
324
		 *  @type     int
325
		 *  @default  0
326
		 */
327
		"fixed": 0,
328
 
329
		/**
330
		 * @namespace Information used for the mouse drag
331
		 */
332
		"mouse": {
333
			"startX": -1,
334
			"startY": -1,
335
			"offsetX": -1,
336
			"offsetY": -1,
337
			"target": -1,
338
			"targetIndex": -1,
339
			"fromIndex": -1
340
		},
341
 
342
		/**
343
		 * Information which is used for positioning the insert cusor and knowing where to do the
344
		 * insert. Array of objects with the properties:
345
		 *   x: x-axis position
346
		 *   to: insert point
347
		 *  @property aoTargets
348
		 *  @type     array
349
		 *  @default  []
350
		 */
351
		"aoTargets": []
352
	};
353
 
354
 
355
	/**
356
	 * @namespace Common and useful DOM elements for the class instance
357
	 */
358
	this.dom = {
359
		/**
360
		 * Dragging element (the one the mouse is moving)
361
		 *  @property drag
362
		 *  @type     element
363
		 *  @default  null
364
		 */
365
		"drag": null,
366
 
367
		/**
368
		 * The insert cursor
369
		 *  @property pointer
370
		 *  @type     element
371
		 *  @default  null
372
		 */
373
		"pointer": null
374
	};
375
 
376
 
377
	/* Constructor logic */
378
	this.s.dt = oTable.fnSettings();
379
	this._fnConstruct();
380
 
381
	/* Store the instance for later use */
382
	ColReorder.aoInstances.push( this );
383
	return this;
384
};
385
 
386
 
387
 
388
ColReorder.prototype = {
389
	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
390
	 * Public methods
391
	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
392
 
393
	"fnReset": function ()
394
	{
395
		var a = [];
396
		for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
397
		{
398
			a.push( this.s.dt.aoColumns[i]._ColReorder_iOrigCol );
399
		}
400
 
401
		this._fnOrderColumns( a );
402
	},
403
 
404
 
405
	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
406
	 * Private methods (they are of course public in JS, but recommended as private)
407
	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
408
 
409
	/**
410
	 * Constructor logic
411
	 *  @method  _fnConstruct
412
	 *  @returns void
413
	 *  @private 
414
	 */
415
	"_fnConstruct": function ()
416
	{
417
		var that = this;
418
		var i, iLen;
419
 
420
		/* Columns discounted from reordering - counting left to right */
421
		if ( typeof this.s.init.iFixedColumns != 'undefined' )
422
		{
423
			this.s.fixed = this.s.init.iFixedColumns;
424
		}
425
 
426
		/* Add event handlers for the drag and drop, and also mark the original column order */
427
		for ( i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
428
		{
429
			if ( i > this.s.fixed-1 )
430
			{
431
				this._fnMouseListener( i, this.s.dt.aoColumns[i].nTh );
432
			}
433
 
434
			/* Mark the original column order for later reference */
435
			this.s.dt.aoColumns[i]._ColReorder_iOrigCol = i;
436
		}
437
 
438
		/* State saving */
439
		this.s.dt.aoStateSave.push( {
440
			"fn": function (oS, sVal) {
441
				return that._fnStateSave.call( that, sVal );
442
			},
443
			"sName": "ColReorder_State"
444
		} );
445
 
446
		/* An initial column order has been specified */
447
		var aiOrder = null;
448
		if ( typeof this.s.init.aiOrder != 'undefined' )
449
		{
450
			aiOrder = this.s.init.aiOrder.slice();
451
		}
452
 
453
		/* State loading, overrides the column order given */
454
		if ( this.s.dt.oLoadedState && typeof this.s.dt.oLoadedState.ColReorder != 'undefined' &&
455
		  this.s.dt.oLoadedState.ColReorder.length == this.s.dt.aoColumns.length )
456
		{
457
			aiOrder = this.s.dt.oLoadedState.ColReorder;
458
		}
459
 
460
		/* If we have an order to apply - do so */
461
		if ( aiOrder )
462
		{
463
			/* We might be called during or after the DataTables initialisation. If before, then we need
464
			 * to wait until the draw is done, if after, then do what we need to do right away
465
			 */
466
			if ( !that.s.dt._bInitComplete )
467
			{
468
				var bDone = false;
469
				this.s.dt.aoDrawCallback.push( {
470
					"fn": function () {
471
						if ( !that.s.dt._bInitComplete && !bDone )
472
						{
473
							bDone = true;
474
							var resort = fnInvertKeyValues( aiOrder );
475
							that._fnOrderColumns.call( that, resort );
476
						}
477
					},
478
					"sName": "ColReorder_Pre"
479
				} );
480
			}
481
			else
482
			{
483
				var resort = fnInvertKeyValues( aiOrder );
484
				that._fnOrderColumns.call( that, resort );
485
			}
486
		}
487
	},
488
 
489
 
490
	/**
491
	 * Set the column order from an array
492
	 *  @method  _fnOrderColumns
493
	 *  @param   array a An array of integers which dictate the column order that should be applied
494
	 *  @returns void
495
	 *  @private 
496
	 */
497
	"_fnOrderColumns": function ( a )
498
	{
499
		if ( a.length != this.s.dt.aoColumns.length )
500
		{
501
			this.s.dt.oInstance.oApi._fnLog( oDTSettings, 1, "ColReorder - array reorder does not "+
502
			 	"match known number of columns. Skipping." );
503
			return;
504
		}
505
 
506
		for ( var i=0, iLen=a.length ; i<iLen ; i++ )
507
		{
508
			var currIndex = $.inArray( i, a );
509
			if ( i != currIndex )
510
			{
511
				/* Reorder our switching array */
512
				fnArraySwitch( a, currIndex, i );
513
 
514
				/* Do the column reorder in the table */
515
				this.s.dt.oInstance.fnColReorder( currIndex, i );
516
			}
517
		}
518
 
519
		/* When scrolling we need to recalculate the column sizes to allow for the shift */
520
		if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
521
		{
522
			this.s.dt.oInstance.fnAdjustColumnSizing();
523
		}
524
 
525
		/* Save the state */
526
		this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
527
	},
528
 
529
 
530
	/**
531
	 * This function effectively replaces the state saving function in DataTables (this is needed
532
	 * because otherwise DataTables would state save the columns in their reordered state, not the
533
	 * original which is needed on first draw). This is sensitive to any changes in the DataTables
534
	 * state saving method!
535
	 *  @method  _fnStateSave
536
	 *  @param   string sCurrentVal 
537
	 *  @returns string JSON encoded cookie string for DataTables
538
	 *  @private 
539
	 */
540
	"_fnStateSave": function ( sCurrentVal )
541
	{
542
		var i, iLen, sTmp;
543
		var sValue = sCurrentVal.split('"aaSorting"')[0];
544
		var a = [];
545
		var oSettings = this.s.dt;
546
 
547
		/* Sorting */
548
		sValue += '"aaSorting":[ ';
549
		for ( i=0 ; i<oSettings.aaSorting.length ; i++ )
550
		{
551
			sValue += '['+oSettings.aoColumns[ oSettings.aaSorting[i][0] ]._ColReorder_iOrigCol+
552
				',"'+oSettings.aaSorting[i][1]+'"],';
553
		}
554
		sValue = sValue.substring(0, sValue.length-1);
555
		sValue += "],";
556
 
557
		/* Column filter */
558
		for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
559
		{
560
			a[ oSettings.aoColumns[i]._ColReorder_iOrigCol ] = {
561
				"sSearch": encodeURIComponent(oSettings.aoPreSearchCols[i].sSearch),
562
				"bRegex": !oSettings.aoPreSearchCols[i].bRegex
563
			};
564
		}
565
 
566
		sValue += '"aaSearchCols":[ ';
567
		for ( i=0 ; i<a.length ; i++ )
568
		{
569
			sValue += '["'+a[i].sSearch+'",'+a[i].bRegex+'],';
570
		}
571
		sValue = sValue.substring(0, sValue.length-1);
572
		sValue += "],";
573
 
574
		/* Visibility */
575
		a = [];
576
		for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
577
		{
578
			a[ oSettings.aoColumns[i]._ColReorder_iOrigCol ] = oSettings.aoColumns[i].bVisible;
579
		}
580
 
581
		sValue += '"abVisCols":[ ';
582
		for ( i=0 ; i<a.length ; i++ )
583
		{
584
			sValue += a[i]+",";
585
		}
586
		sValue = sValue.substring(0, sValue.length-1);
587
		sValue += "],";
588
 
589
		/* Column reordering */
590
		a = [];
591
		for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) {
592
			a.push( oSettings.aoColumns[i]._ColReorder_iOrigCol );
593
		}
594
		sValue += '"ColReorder":['+a.join(',')+']';
595
 
596
		return sValue;
597
	},
598
 
599
 
600
	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
601
	 * Mouse drop and drag
602
	 */
603
 
604
	/**
605
	 * Add a mouse down listener to a particluar TH element
606
	 *  @method  _fnMouseListener
607
	 *  @param   int i Column index
608
	 *  @param   element nTh TH element clicked on
609
	 *  @returns void
610
	 *  @private 
611
	 */
612
	"_fnMouseListener": function ( i, nTh )
613
	{
614
		var that = this;
615
		$(nTh).bind( 'mousedown.ColReorder', function (e) {
616
			that._fnMouseDown.call( that, e, nTh );
617
			return false;
618
		} );
619
	},
620
 
621
 
622
	/**
623
	 * Mouse down on a TH element in the table header
624
	 *  @method  _fnMouseDown
625
	 *  @param   event e Mouse event
626
	 *  @param   element nTh TH element to be dragged
627
	 *  @returns void
628
	 *  @private 
629
	 */
630
	"_fnMouseDown": function ( e, nTh )
631
	{
632
		var
633
			that = this,
634
			aoColumns = this.s.dt.aoColumns;
635
 
636
		/* Store information about the mouse position */
637
		var nThTarget = e.target.nodeName == "TH" ? e.target : $(e.target).parents('TH')[0];
638
		var offset = $(nThTarget).offset();
639
		this.s.mouse.startX = e.pageX;
640
		this.s.mouse.startY = e.pageY;
641
		this.s.mouse.offsetX = e.pageX - offset.left;
642
		this.s.mouse.offsetY = e.pageY - offset.top;
643
		this.s.mouse.target = nTh;
644
		this.s.mouse.targetIndex = $('th', nTh.parentNode).index( nTh );
645
		this.s.mouse.fromIndex = this.s.dt.oInstance.oApi._fnVisibleToColumnIndex( this.s.dt, 
646
			this.s.mouse.targetIndex );
647
 
648
		/* Calculate a cached array with the points of the column inserts, and the 'to' points */
649
		this.s.aoTargets.splice( 0, this.s.aoTargets.length );
650
 
651
		this.s.aoTargets.push( {
652
			"x":  $(this.s.dt.nTable).offset().left,
653
			"to": 0
654
		} );
655
 
656
		var iToPoint = 0;
657
		for ( var i=0, iLen=aoColumns.length ; i<iLen ; i++ )
658
		{
659
			/* For the column / header in question, we want it's position to remain the same if the 
660
			 * position is just to it's immediate left or right, so we only incremement the counter for
661
			 * other columns
662
			 */
663
			if ( i != this.s.mouse.fromIndex )
664
			{
665
				iToPoint++;
666
			}
667
 
668
			if ( aoColumns[i].bVisible )
669
			{
670
				this.s.aoTargets.push( {
671
					"x":  $(aoColumns[i].nTh).offset().left + $(aoColumns[i].nTh).outerWidth(),
672
					"to": iToPoint
673
				} );
674
			}
675
		}
676
 
677
		/* Disallow columns for being reordered by drag and drop, counting left to right */
678
		if ( this.s.fixed !== 0 )
679
		{
680
			this.s.aoTargets.splice( 0, this.s.fixed );
681
		}
682
 
683
		/* Add event handlers to the document */
684
		$(document).bind( 'mousemove.ColReorder', function (e) {
685
			that._fnMouseMove.call( that, e );
686
		} );
687
 
688
		$(document).bind( 'mouseup.ColReorder', function (e) {
689
			that._fnMouseUp.call( that, e );
690
		} );
691
	},
692
 
693
 
694
	/**
695
	 * Deal with a mouse move event while dragging a node
696
	 *  @method  _fnMouseMove
697
	 *  @param   event e Mouse event
698
	 *  @returns void
699
	 *  @private 
700
	 */
701
	"_fnMouseMove": function ( e )
702
	{
703
		var that = this;
704
 
705
		if ( this.dom.drag === null )
706
		{
707
			/* Only create the drag element if the mouse has moved a specific distance from the start
708
			 * point - this allows the user to make small mouse movements when sorting and not have a
709
			 * possibly confusing drag element showing up
710
			 */
711
			if ( Math.pow(
712
				Math.pow(e.pageX - this.s.mouse.startX, 2) + 
713
				Math.pow(e.pageY - this.s.mouse.startY, 2), 0.5 ) < 5 )
714
			{
715
				return;
716
			}
717
			this._fnCreateDragNode();
718
		}
719
 
720
		/* Position the element - we respect where in the element the click occured */
721
		this.dom.drag.style.left = (e.pageX - this.s.mouse.offsetX) + "px";
722
		this.dom.drag.style.top = (e.pageY - this.s.mouse.offsetY) + "px";
723
 
724
		/* Based on the current mouse position, calculate where the insert should go */
725
		var bSet = false;
726
		for ( var i=1, iLen=this.s.aoTargets.length ; i<iLen ; i++ )
727
		{
728
			if ( e.pageX < this.s.aoTargets[i-1].x + ((this.s.aoTargets[i].x-this.s.aoTargets[i-1].x)/2) )
729
			{
730
				this.dom.pointer.style.left = this.s.aoTargets[i-1].x +"px";
731
				this.s.mouse.toIndex = this.s.aoTargets[i-1].to;
732
				bSet = true;
733
				break;
734
			}
735
		}
736
 
737
		/* The insert element wasn't positioned in the array (less than operator), so we put it at 
738
		 * the end
739
		 */
740
		if ( !bSet )
741
		{
742
			this.dom.pointer.style.left = this.s.aoTargets[this.s.aoTargets.length-1].x +"px";
743
			this.s.mouse.toIndex = this.s.aoTargets[this.s.aoTargets.length-1].to;
744
		}
745
	},
746
 
747
 
748
	/**
749
	 * Finish off the mouse drag and insert the column where needed
750
	 *  @method  _fnMouseUp
751
	 *  @param   event e Mouse event
752
	 *  @returns void
753
	 *  @private 
754
	 */
755
	"_fnMouseUp": function ( e )
756
	{
757
		var that = this;
758
 
759
		$(document).unbind( 'mousemove.ColReorder' );
760
		$(document).unbind( 'mouseup.ColReorder' );
761
 
762
		if ( this.dom.drag !== null )
763
		{
764
			/* Remove the guide elements */
765
			document.body.removeChild( this.dom.drag );
766
			document.body.removeChild( this.dom.pointer );
767
			this.dom.drag = null;
768
			this.dom.pointer = null;
769
 
770
			/* Actually do the reorder */
771
			this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex );
772
 
773
			/* When scrolling we need to recalculate the column sizes to allow for the shift */
774
			if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
775
			{
776
				this.s.dt.oInstance.fnAdjustColumnSizing();
777
			}
778
 
779
			/* Save the state */
780
			this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
781
		}
782
	},
783
 
784
 
785
	/**
786
	 * Copy the TH element that is being drags so the user has the idea that they are actually 
787
	 * moving it around the page.
788
	 *  @method  _fnCreateDragNode
789
	 *  @returns void
790
	 *  @private 
791
	 */
792
	"_fnCreateDragNode": function ()
793
	{
794
		var that = this;
795
 
796
		this.dom.drag = $(this.s.dt.nTHead.parentNode).clone(true)[0];
797
		this.dom.drag.className += " DTCR_clonedTable";
798
		while ( this.dom.drag.getElementsByTagName('tbody').length > 0 )
799
		{
800
			this.dom.drag.removeChild( this.dom.drag.getElementsByTagName('tbody')[0] );
801
		}
802
		while ( this.dom.drag.getElementsByTagName('tfoot').length > 0 )
803
		{
804
			this.dom.drag.removeChild( this.dom.drag.getElementsByTagName('tfoot')[0] );
805
		}
806
 
807
		$('thead tr:eq(0)', this.dom.drag).each( function () {
808
			$('th:not(:eq('+that.s.mouse.targetIndex+'))', this).remove();
809
		} );
810
		$('tr', this.dom.drag).height( $('tr:eq(0)', that.s.dt.nTHead).height() );
811
 
812
		$('thead tr:gt(0)', this.dom.drag).remove();
813
 
814
		$('thead th:eq(0)', this.dom.drag).each( function (i) {
815
			this.style.width = $('th:eq('+that.s.mouse.targetIndex+')', that.s.dt.nTHead).width()+"px";
816
		} );
817
 
818
		this.dom.drag.style.position = "absolute";
819
		this.dom.drag.style.top = "0px";
820
		this.dom.drag.style.left = "0px";
821
		this.dom.drag.style.width = $('th:eq('+that.s.mouse.targetIndex+')', that.s.dt.nTHead).outerWidth()+"px";
822
 
823
 
824
		this.dom.pointer = document.createElement( 'div' );
825
		this.dom.pointer.className = "DTCR_pointer";
826
		this.dom.pointer.style.position = "absolute";
827
 
828
		if ( this.s.dt.oScroll.sX === "" && this.s.dt.oScroll.sY === "" )
829
		{
830
			this.dom.pointer.style.top = $(this.s.dt.nTable).offset().top+"px";
831
			this.dom.pointer.style.height = $(this.s.dt.nTable).height()+"px";
832
		}
833
		else
834
		{
835
			this.dom.pointer.style.top = $('div.dataTables_scroll', this.s.dt.nTableWrapper).offset().top+"px";
836
			this.dom.pointer.style.height = $('div.dataTables_scroll', this.s.dt.nTableWrapper).height()+"px";
837
		}
838
 
839
		document.body.appendChild( this.dom.pointer );
840
		document.body.appendChild( this.dom.drag );
841
	}
842
};
843
 
844
 
845
 
846
 
847
 
848
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
849
 * Static parameters
850
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
851
 
852
/**
853
 * Array of all ColReorder instances for later reference
854
 *  @property ColReorder.aoInstances
855
 *  @type     array
856
 *  @default  []
857
 *  @static
858
 */
859
ColReorder.aoInstances = [];
860
 
861
 
862
 
863
 
864
 
865
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
866
 * Static functions
867
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
868
 
869
/**
870
 * Reset the column ordering for a DataTables instance
871
 *  @method  ColReorder.fnReset
872
 *  @param   object oTable DataTables instance to consider
873
 *  @returns void
874
 *  @static
875
 */
876
ColReorder.fnReset = function ( oTable )
877
{
878
	for ( var i=0, iLen=ColReorder.aoInstances.length ; i<iLen ; i++ )
879
	{
880
		if ( ColReorder.aoInstances[i].s.dt.oInstance == oTable )
881
		{
882
			ColReorder.aoInstances[i].fnReset();
883
		}
884
	}
885
};
886
 
887
 
888
 
889
 
890
 
891
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
892
 * Constants
893
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
894
 
895
/**
896
 * Name of this class
897
 *  @constant CLASS
898
 *  @type     String
899
 *  @default  ColReorder
900
 */
901
ColReorder.prototype.CLASS = "ColReorder";
902
 
903
 
904
/**
905
 * ColReorder version
906
 *  @constant  VERSION
907
 *  @type      String
908
 *  @default   1.0.2
909
 */
910
ColReorder.VERSION = "1.0.2";
911
ColReorder.prototype.VERSION = ColReorder.VERSION;
912
 
913
 
914
 
915
 
916
 
917
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
918
 * Initialisation
919
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
920
 
921
/*
922
 * Register a new feature with DataTables
923
 */
924
if ( typeof $.fn.dataTable == "function" &&
925
     typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
926
     $.fn.dataTableExt.fnVersionCheck('1.8.0') )
927
{
928
	$.fn.dataTableExt.aoFeatures.push( {
929
		"fnInit": function( oDTSettings ) {
930
			var oTable = oDTSettings.oInstance;
931
			if ( typeof oTable._oPluginColReorder == 'undefined' ) {
932
				var opts = typeof oDTSettings.oInit.oColReorder != 'undefined' ? 
933
					oDTSettings.oInit.oColReorder : {};
934
				oTable._oPluginColReorder = new ColReorder( oDTSettings.oInstance, opts );
935
			} else {
936
				oTable.oApi._fnLog( oDTSettings, 1, "ColReorder attempted to initialise twice. Ignoring second" );
937
			}
938
 
939
			return null; /* No node to insert */
940
		},
941
		"cFeature": "R",
942
		"sFeature": "ColReorder"
943
	} );
944
}
945
else
946
{
947
	alert( "Warning: ColReorder requires DataTables 1.8.0 or greater - www.datatables.net/download");
948
}
949
 
950
})(jQuery, window, document);