jquery-datatables-rails 1.10.0 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,956 @@
1
+ /*
2
+ * File: ColReorder.js
3
+ * Version: 1.0.6
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, oCol;
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
+ oCol = oSettings.aoColumns[i];
167
+ for ( j=0, jLen=oCol.aDataSort.length ; j<jLen ; j++ )
168
+ {
169
+ oCol.aDataSort[j] = aiInvertMapping[ oCol.aDataSort[j] ];
170
+ }
171
+ }
172
+
173
+ /* Update the Get and Set functions for each column */
174
+ for ( i=0, iLen=iCols ; i<iLen ; i++ )
175
+ {
176
+ oCol = oSettings.aoColumns[i];
177
+ if ( typeof oCol.mDataProp == 'number' ) {
178
+ oCol.mDataProp = aiInvertMapping[ oCol.mDataProp ];
179
+ oCol.fnGetData = oSettings.oApi._fnGetObjectDataFn( oCol.mDataProp );
180
+ oCol.fnSetData = oSettings.oApi._fnSetObjectDataFn( oCol.mDataProp );
181
+ }
182
+ }
183
+
184
+
185
+ /*
186
+ * Move the DOM elements
187
+ */
188
+ if ( oSettings.aoColumns[iFrom].bVisible )
189
+ {
190
+ /* Calculate the current visible index and the point to insert the node before. The insert
191
+ * before needs to take into account that there might not be an element to insert before,
192
+ * in which case it will be null, and an appendChild should be used
193
+ */
194
+ var iVisibleIndex = this.oApi._fnColumnIndexToVisible( oSettings, iFrom );
195
+ var iInsertBeforeIndex = null;
196
+
197
+ i = iTo < iFrom ? iTo : iTo + 1;
198
+ while ( iInsertBeforeIndex === null && i < iCols )
199
+ {
200
+ iInsertBeforeIndex = this.oApi._fnColumnIndexToVisible( oSettings, i );
201
+ i++;
202
+ }
203
+
204
+ /* Header */
205
+ nTrs = oSettings.nTHead.getElementsByTagName('tr');
206
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
207
+ {
208
+ fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );
209
+ }
210
+
211
+ /* Footer */
212
+ if ( oSettings.nTFoot !== null )
213
+ {
214
+ nTrs = oSettings.nTFoot.getElementsByTagName('tr');
215
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
216
+ {
217
+ fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );
218
+ }
219
+ }
220
+
221
+ /* Body */
222
+ for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
223
+ {
224
+ if ( oSettings.aoData[i].nTr !== null )
225
+ {
226
+ fnDomSwitch( oSettings.aoData[i].nTr, iVisibleIndex, iInsertBeforeIndex );
227
+ }
228
+ }
229
+ }
230
+
231
+
232
+ /*
233
+ * Move the internal array elements
234
+ */
235
+ /* Columns */
236
+ fnArraySwitch( oSettings.aoColumns, iFrom, iTo );
237
+
238
+ /* Search columns */
239
+ fnArraySwitch( oSettings.aoPreSearchCols, iFrom, iTo );
240
+
241
+ /* Array array - internal data anodes cache */
242
+ for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
243
+ {
244
+ if ( $.isArray( oSettings.aoData[i]._aData ) ) {
245
+ fnArraySwitch( oSettings.aoData[i]._aData, iFrom, iTo );
246
+ }
247
+ fnArraySwitch( oSettings.aoData[i]._anHidden, iFrom, iTo );
248
+ }
249
+
250
+ /* Reposition the header elements in the header layout array */
251
+ for ( i=0, iLen=oSettings.aoHeader.length ; i<iLen ; i++ )
252
+ {
253
+ fnArraySwitch( oSettings.aoHeader[i], iFrom, iTo );
254
+ }
255
+
256
+ if ( oSettings.aoFooter !== null )
257
+ {
258
+ for ( i=0, iLen=oSettings.aoFooter.length ; i<iLen ; i++ )
259
+ {
260
+ fnArraySwitch( oSettings.aoFooter[i], iFrom, iTo );
261
+ }
262
+ }
263
+
264
+
265
+ /*
266
+ * Update DataTables' event handlers
267
+ */
268
+
269
+ /* Sort listener */
270
+ for ( i=0, iLen=iCols ; i<iLen ; i++ )
271
+ {
272
+ $(oSettings.aoColumns[i].nTh).unbind('click');
273
+ this.oApi._fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
274
+ }
275
+
276
+
277
+ /* Fire an event so other plug-ins can update */
278
+ $(oSettings.oInstance).trigger( 'column-reorder', [ oSettings, {
279
+ "iFrom": iFrom,
280
+ "iTo": iTo,
281
+ "aiInvertMapping": aiInvertMapping
282
+ } ] );
283
+
284
+ if ( typeof oSettings.oInstance._oPluginFixedHeader != 'undefined' )
285
+ {
286
+ oSettings.oInstance._oPluginFixedHeader.fnUpdate();
287
+ }
288
+ };
289
+
290
+
291
+
292
+
293
+ /**
294
+ * ColReorder provides column visiblity control for DataTables
295
+ * @class ColReorder
296
+ * @constructor
297
+ * @param {object} DataTables object
298
+ * @param {object} ColReorder options
299
+ */
300
+ ColReorder = function( oTable, oOpts )
301
+ {
302
+ /* Santiy check that we are a new instance */
303
+ if ( !this.CLASS || this.CLASS != "ColReorder" )
304
+ {
305
+ alert( "Warning: ColReorder must be initialised with the keyword 'new'" );
306
+ }
307
+
308
+ if ( typeof oOpts == 'undefined' )
309
+ {
310
+ oOpts = {};
311
+ }
312
+
313
+
314
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
315
+ * Public class variables
316
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
317
+
318
+ /**
319
+ * @namespace Settings object which contains customisable information for ColReorder instance
320
+ */
321
+ this.s = {
322
+ /**
323
+ * DataTables settings object
324
+ * @property dt
325
+ * @type Object
326
+ * @default null
327
+ */
328
+ "dt": null,
329
+
330
+ /**
331
+ * Initialisation object used for this instance
332
+ * @property init
333
+ * @type object
334
+ * @default {}
335
+ */
336
+ "init": oOpts,
337
+
338
+ /**
339
+ * Number of columns to fix (not allow to be reordered)
340
+ * @property fixed
341
+ * @type int
342
+ * @default 0
343
+ */
344
+ "fixed": 0,
345
+
346
+ /**
347
+ * Callback function for once the reorder has been done
348
+ * @property dropcallback
349
+ * @type function
350
+ * @default null
351
+ */
352
+ "dropCallback": null,
353
+
354
+ /**
355
+ * @namespace Information used for the mouse drag
356
+ */
357
+ "mouse": {
358
+ "startX": -1,
359
+ "startY": -1,
360
+ "offsetX": -1,
361
+ "offsetY": -1,
362
+ "target": -1,
363
+ "targetIndex": -1,
364
+ "fromIndex": -1
365
+ },
366
+
367
+ /**
368
+ * Information which is used for positioning the insert cusor and knowing where to do the
369
+ * insert. Array of objects with the properties:
370
+ * x: x-axis position
371
+ * to: insert point
372
+ * @property aoTargets
373
+ * @type array
374
+ * @default []
375
+ */
376
+ "aoTargets": []
377
+ };
378
+
379
+
380
+ /**
381
+ * @namespace Common and useful DOM elements for the class instance
382
+ */
383
+ this.dom = {
384
+ /**
385
+ * Dragging element (the one the mouse is moving)
386
+ * @property drag
387
+ * @type element
388
+ * @default null
389
+ */
390
+ "drag": null,
391
+
392
+ /**
393
+ * The insert cursor
394
+ * @property pointer
395
+ * @type element
396
+ * @default null
397
+ */
398
+ "pointer": null
399
+ };
400
+
401
+
402
+ /* Constructor logic */
403
+ this.s.dt = oTable.fnSettings();
404
+ this._fnConstruct();
405
+
406
+ /* Store the instance for later use */
407
+ ColReorder.aoInstances.push( this );
408
+ return this;
409
+ };
410
+
411
+
412
+
413
+ ColReorder.prototype = {
414
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
415
+ * Public methods
416
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
417
+
418
+ "fnReset": function ()
419
+ {
420
+ var a = [];
421
+ for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
422
+ {
423
+ a.push( this.s.dt.aoColumns[i]._ColReorder_iOrigCol );
424
+ }
425
+
426
+ this._fnOrderColumns( a );
427
+ },
428
+
429
+
430
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
431
+ * Private methods (they are of course public in JS, but recommended as private)
432
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
433
+
434
+ /**
435
+ * Constructor logic
436
+ * @method _fnConstruct
437
+ * @returns void
438
+ * @private
439
+ */
440
+ "_fnConstruct": function ()
441
+ {
442
+ var that = this;
443
+ var i, iLen;
444
+
445
+ /* Columns discounted from reordering - counting left to right */
446
+ if ( typeof this.s.init.iFixedColumns != 'undefined' )
447
+ {
448
+ this.s.fixed = this.s.init.iFixedColumns;
449
+ }
450
+
451
+ /* Drop callback initialisation option */
452
+ if ( typeof this.s.init.fnReorderCallback != 'undefined' )
453
+ {
454
+ this.s.dropCallback = this.s.init.fnReorderCallback;
455
+ }
456
+
457
+ /* Add event handlers for the drag and drop, and also mark the original column order */
458
+ for ( i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
459
+ {
460
+ if ( i > this.s.fixed-1 )
461
+ {
462
+ this._fnMouseListener( i, this.s.dt.aoColumns[i].nTh );
463
+ }
464
+
465
+ /* Mark the original column order for later reference */
466
+ this.s.dt.aoColumns[i]._ColReorder_iOrigCol = i;
467
+ }
468
+
469
+ /* State saving */
470
+ this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) {
471
+ that._fnStateSave.call( that, oData );
472
+ }, "ColReorder_State" );
473
+
474
+ /* An initial column order has been specified */
475
+ var aiOrder = null;
476
+ if ( typeof this.s.init.aiOrder != 'undefined' )
477
+ {
478
+ aiOrder = this.s.init.aiOrder.slice();
479
+ }
480
+
481
+ /* State loading, overrides the column order given */
482
+ if ( this.s.dt.oLoadedState && typeof this.s.dt.oLoadedState.ColReorder != 'undefined' &&
483
+ this.s.dt.oLoadedState.ColReorder.length == this.s.dt.aoColumns.length )
484
+ {
485
+ aiOrder = this.s.dt.oLoadedState.ColReorder;
486
+ }
487
+
488
+ /* If we have an order to apply - do so */
489
+ if ( aiOrder )
490
+ {
491
+ /* We might be called during or after the DataTables initialisation. If before, then we need
492
+ * to wait until the draw is done, if after, then do what we need to do right away
493
+ */
494
+ if ( !that.s.dt._bInitComplete )
495
+ {
496
+ var bDone = false;
497
+ this.s.dt.aoDrawCallback.push( {
498
+ "fn": function () {
499
+ if ( !that.s.dt._bInitComplete && !bDone )
500
+ {
501
+ bDone = true;
502
+ var resort = fnInvertKeyValues( aiOrder );
503
+ that._fnOrderColumns.call( that, resort );
504
+ }
505
+ },
506
+ "sName": "ColReorder_Pre"
507
+ } );
508
+ }
509
+ else
510
+ {
511
+ var resort = fnInvertKeyValues( aiOrder );
512
+ that._fnOrderColumns.call( that, resort );
513
+ }
514
+ }
515
+ },
516
+
517
+
518
+ /**
519
+ * Set the column order from an array
520
+ * @method _fnOrderColumns
521
+ * @param array a An array of integers which dictate the column order that should be applied
522
+ * @returns void
523
+ * @private
524
+ */
525
+ "_fnOrderColumns": function ( a )
526
+ {
527
+ if ( a.length != this.s.dt.aoColumns.length )
528
+ {
529
+ this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "ColReorder - array reorder does not "+
530
+ "match known number of columns. Skipping." );
531
+ return;
532
+ }
533
+
534
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ )
535
+ {
536
+ var currIndex = $.inArray( i, a );
537
+ if ( i != currIndex )
538
+ {
539
+ /* Reorder our switching array */
540
+ fnArraySwitch( a, currIndex, i );
541
+
542
+ /* Do the column reorder in the table */
543
+ this.s.dt.oInstance.fnColReorder( currIndex, i );
544
+ }
545
+ }
546
+
547
+ /* When scrolling we need to recalculate the column sizes to allow for the shift */
548
+ if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
549
+ {
550
+ this.s.dt.oInstance.fnAdjustColumnSizing();
551
+ }
552
+
553
+ /* Save the state */
554
+ this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
555
+ },
556
+
557
+
558
+ /**
559
+ * Because we change the indexes of columns in the table, relative to their starting point
560
+ * we need to reorder the state columns to what they are at the starting point so we can
561
+ * then rearrange them again on state load!
562
+ * @method _fnStateSave
563
+ * @param object oState DataTables state
564
+ * @returns string JSON encoded cookie string for DataTables
565
+ * @private
566
+ */
567
+ "_fnStateSave": function ( oState )
568
+ {
569
+ var i, iLen, aCopy, iOrigColumn;
570
+ var oSettings = this.s.dt;
571
+
572
+ /* Sorting */
573
+ for ( i=0 ; i<oState.aaSorting.length ; i++ )
574
+ {
575
+ oState.aaSorting[i][0] = oSettings.aoColumns[ oState.aaSorting[i][0] ]._ColReorder_iOrigCol;
576
+ }
577
+
578
+ aSearchCopy = $.extend( true, [], oState.aoSearchCols );
579
+ oState.ColReorder = [];
580
+
581
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
582
+ {
583
+ iOrigColumn = oSettings.aoColumns[i]._ColReorder_iOrigCol;
584
+
585
+ /* Column filter */
586
+ oState.aoSearchCols[ iOrigColumn ] = aSearchCopy[i];
587
+
588
+ /* Visibility */
589
+ oState.abVisCols[ iOrigColumn ] = oSettings.aoColumns[i].bVisible;
590
+
591
+ /* Column reordering */
592
+ oState.ColReorder.push( iOrigColumn );
593
+ }
594
+ },
595
+
596
+
597
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
598
+ * Mouse drop and drag
599
+ */
600
+
601
+ /**
602
+ * Add a mouse down listener to a particluar TH element
603
+ * @method _fnMouseListener
604
+ * @param int i Column index
605
+ * @param element nTh TH element clicked on
606
+ * @returns void
607
+ * @private
608
+ */
609
+ "_fnMouseListener": function ( i, nTh )
610
+ {
611
+ var that = this;
612
+ $(nTh).bind( 'mousedown.ColReorder', function (e) {
613
+ e.preventDefault();
614
+ that._fnMouseDown.call( that, e, nTh );
615
+ } );
616
+ },
617
+
618
+
619
+ /**
620
+ * Mouse down on a TH element in the table header
621
+ * @method _fnMouseDown
622
+ * @param event e Mouse event
623
+ * @param element nTh TH element to be dragged
624
+ * @returns void
625
+ * @private
626
+ */
627
+ "_fnMouseDown": function ( e, nTh )
628
+ {
629
+ var
630
+ that = this,
631
+ aoColumns = this.s.dt.aoColumns;
632
+
633
+ /* Store information about the mouse position */
634
+ var nThTarget = e.target.nodeName == "TH" ? e.target : $(e.target).parents('TH')[0];
635
+ var offset = $(nThTarget).offset();
636
+ this.s.mouse.startX = e.pageX;
637
+ this.s.mouse.startY = e.pageY;
638
+ this.s.mouse.offsetX = e.pageX - offset.left;
639
+ this.s.mouse.offsetY = e.pageY - offset.top;
640
+ this.s.mouse.target = nTh;
641
+ this.s.mouse.targetIndex = $('th', nTh.parentNode).index( nTh );
642
+ this.s.mouse.fromIndex = this.s.dt.oInstance.oApi._fnVisibleToColumnIndex( this.s.dt,
643
+ this.s.mouse.targetIndex );
644
+
645
+ /* Calculate a cached array with the points of the column inserts, and the 'to' points */
646
+ this.s.aoTargets.splice( 0, this.s.aoTargets.length );
647
+
648
+ this.s.aoTargets.push( {
649
+ "x": $(this.s.dt.nTable).offset().left,
650
+ "to": 0
651
+ } );
652
+
653
+ var iToPoint = 0;
654
+ for ( var i=0, iLen=aoColumns.length ; i<iLen ; i++ )
655
+ {
656
+ /* For the column / header in question, we want it's position to remain the same if the
657
+ * position is just to it's immediate left or right, so we only incremement the counter for
658
+ * other columns
659
+ */
660
+ if ( i != this.s.mouse.fromIndex )
661
+ {
662
+ iToPoint++;
663
+ }
664
+
665
+ if ( aoColumns[i].bVisible )
666
+ {
667
+ this.s.aoTargets.push( {
668
+ "x": $(aoColumns[i].nTh).offset().left + $(aoColumns[i].nTh).outerWidth(),
669
+ "to": iToPoint
670
+ } );
671
+ }
672
+ }
673
+
674
+ /* Disallow columns for being reordered by drag and drop, counting left to right */
675
+ if ( this.s.fixed !== 0 )
676
+ {
677
+ this.s.aoTargets.splice( 0, this.s.fixed );
678
+ }
679
+
680
+ /* Add event handlers to the document */
681
+ $(document).bind( 'mousemove.ColReorder', function (e) {
682
+ that._fnMouseMove.call( that, e );
683
+ } );
684
+
685
+ $(document).bind( 'mouseup.ColReorder', function (e) {
686
+ that._fnMouseUp.call( that, e );
687
+ } );
688
+ },
689
+
690
+
691
+ /**
692
+ * Deal with a mouse move event while dragging a node
693
+ * @method _fnMouseMove
694
+ * @param event e Mouse event
695
+ * @returns void
696
+ * @private
697
+ */
698
+ "_fnMouseMove": function ( e )
699
+ {
700
+ var that = this;
701
+
702
+ if ( this.dom.drag === null )
703
+ {
704
+ /* Only create the drag element if the mouse has moved a specific distance from the start
705
+ * point - this allows the user to make small mouse movements when sorting and not have a
706
+ * possibly confusing drag element showing up
707
+ */
708
+ if ( Math.pow(
709
+ Math.pow(e.pageX - this.s.mouse.startX, 2) +
710
+ Math.pow(e.pageY - this.s.mouse.startY, 2), 0.5 ) < 5 )
711
+ {
712
+ return;
713
+ }
714
+ this._fnCreateDragNode();
715
+ }
716
+
717
+ /* Position the element - we respect where in the element the click occured */
718
+ this.dom.drag.style.left = (e.pageX - this.s.mouse.offsetX) + "px";
719
+ this.dom.drag.style.top = (e.pageY - this.s.mouse.offsetY) + "px";
720
+
721
+ /* Based on the current mouse position, calculate where the insert should go */
722
+ var bSet = false;
723
+ for ( var i=1, iLen=this.s.aoTargets.length ; i<iLen ; i++ )
724
+ {
725
+ if ( e.pageX < this.s.aoTargets[i-1].x + ((this.s.aoTargets[i].x-this.s.aoTargets[i-1].x)/2) )
726
+ {
727
+ this.dom.pointer.style.left = this.s.aoTargets[i-1].x +"px";
728
+ this.s.mouse.toIndex = this.s.aoTargets[i-1].to;
729
+ bSet = true;
730
+ break;
731
+ }
732
+ }
733
+
734
+ /* The insert element wasn't positioned in the array (less than operator), so we put it at
735
+ * the end
736
+ */
737
+ if ( !bSet )
738
+ {
739
+ this.dom.pointer.style.left = this.s.aoTargets[this.s.aoTargets.length-1].x +"px";
740
+ this.s.mouse.toIndex = this.s.aoTargets[this.s.aoTargets.length-1].to;
741
+ }
742
+ },
743
+
744
+
745
+ /**
746
+ * Finish off the mouse drag and insert the column where needed
747
+ * @method _fnMouseUp
748
+ * @param event e Mouse event
749
+ * @returns void
750
+ * @private
751
+ */
752
+ "_fnMouseUp": function ( e )
753
+ {
754
+ var that = this;
755
+
756
+ $(document).unbind( 'mousemove.ColReorder' );
757
+ $(document).unbind( 'mouseup.ColReorder' );
758
+
759
+ if ( this.dom.drag !== null )
760
+ {
761
+ /* Remove the guide elements */
762
+ document.body.removeChild( this.dom.drag );
763
+ document.body.removeChild( this.dom.pointer );
764
+ this.dom.drag = null;
765
+ this.dom.pointer = null;
766
+
767
+ /* Actually do the reorder */
768
+ this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex );
769
+
770
+ /* When scrolling we need to recalculate the column sizes to allow for the shift */
771
+ if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
772
+ {
773
+ this.s.dt.oInstance.fnAdjustColumnSizing();
774
+ }
775
+
776
+ if ( this.s.dropCallback !== null )
777
+ {
778
+ this.s.dropCallback.call( this );
779
+ }
780
+
781
+ /* Save the state */
782
+ this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
783
+ }
784
+ },
785
+
786
+
787
+ /**
788
+ * Copy the TH element that is being drags so the user has the idea that they are actually
789
+ * moving it around the page.
790
+ * @method _fnCreateDragNode
791
+ * @returns void
792
+ * @private
793
+ */
794
+ "_fnCreateDragNode": function ()
795
+ {
796
+ var that = this;
797
+
798
+ this.dom.drag = $(this.s.dt.nTHead.parentNode).clone(true)[0];
799
+ this.dom.drag.className += " DTCR_clonedTable";
800
+ while ( this.dom.drag.getElementsByTagName('caption').length > 0 )
801
+ {
802
+ this.dom.drag.removeChild( this.dom.drag.getElementsByTagName('caption')[0] );
803
+ }
804
+ while ( this.dom.drag.getElementsByTagName('tbody').length > 0 )
805
+ {
806
+ this.dom.drag.removeChild( this.dom.drag.getElementsByTagName('tbody')[0] );
807
+ }
808
+ while ( this.dom.drag.getElementsByTagName('tfoot').length > 0 )
809
+ {
810
+ this.dom.drag.removeChild( this.dom.drag.getElementsByTagName('tfoot')[0] );
811
+ }
812
+
813
+ $('thead tr:eq(0)', this.dom.drag).each( function () {
814
+ $('th:not(:eq('+that.s.mouse.targetIndex+'))', this).remove();
815
+ } );
816
+ $('tr', this.dom.drag).height( $('tr:eq(0)', that.s.dt.nTHead).height() );
817
+
818
+ $('thead tr:gt(0)', this.dom.drag).remove();
819
+
820
+ $('thead th:eq(0)', this.dom.drag).each( function (i) {
821
+ this.style.width = $('th:eq('+that.s.mouse.targetIndex+')', that.s.dt.nTHead).width()+"px";
822
+ } );
823
+
824
+ this.dom.drag.style.position = "absolute";
825
+ this.dom.drag.style.top = "0px";
826
+ this.dom.drag.style.left = "0px";
827
+ this.dom.drag.style.width = $('th:eq('+that.s.mouse.targetIndex+')', that.s.dt.nTHead).outerWidth()+"px";
828
+
829
+
830
+ this.dom.pointer = document.createElement( 'div' );
831
+ this.dom.pointer.className = "DTCR_pointer";
832
+ this.dom.pointer.style.position = "absolute";
833
+
834
+ if ( this.s.dt.oScroll.sX === "" && this.s.dt.oScroll.sY === "" )
835
+ {
836
+ this.dom.pointer.style.top = $(this.s.dt.nTable).offset().top+"px";
837
+ this.dom.pointer.style.height = $(this.s.dt.nTable).height()+"px";
838
+ }
839
+ else
840
+ {
841
+ this.dom.pointer.style.top = $('div.dataTables_scroll', this.s.dt.nTableWrapper).offset().top+"px";
842
+ this.dom.pointer.style.height = $('div.dataTables_scroll', this.s.dt.nTableWrapper).height()+"px";
843
+ }
844
+
845
+ document.body.appendChild( this.dom.pointer );
846
+ document.body.appendChild( this.dom.drag );
847
+ }
848
+ };
849
+
850
+
851
+
852
+
853
+
854
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
855
+ * Static parameters
856
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
857
+
858
+ /**
859
+ * Array of all ColReorder instances for later reference
860
+ * @property ColReorder.aoInstances
861
+ * @type array
862
+ * @default []
863
+ * @static
864
+ */
865
+ ColReorder.aoInstances = [];
866
+
867
+
868
+
869
+
870
+
871
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
872
+ * Static functions
873
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
874
+
875
+ /**
876
+ * Reset the column ordering for a DataTables instance
877
+ * @method ColReorder.fnReset
878
+ * @param object oTable DataTables instance to consider
879
+ * @returns void
880
+ * @static
881
+ */
882
+ ColReorder.fnReset = function ( oTable )
883
+ {
884
+ for ( var i=0, iLen=ColReorder.aoInstances.length ; i<iLen ; i++ )
885
+ {
886
+ if ( ColReorder.aoInstances[i].s.dt.oInstance == oTable )
887
+ {
888
+ ColReorder.aoInstances[i].fnReset();
889
+ }
890
+ }
891
+ };
892
+
893
+
894
+
895
+
896
+
897
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
898
+ * Constants
899
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
900
+
901
+ /**
902
+ * Name of this class
903
+ * @constant CLASS
904
+ * @type String
905
+ * @default ColReorder
906
+ */
907
+ ColReorder.prototype.CLASS = "ColReorder";
908
+
909
+
910
+ /**
911
+ * ColReorder version
912
+ * @constant VERSION
913
+ * @type String
914
+ * @default As code
915
+ */
916
+ ColReorder.VERSION = "1.0.6";
917
+ ColReorder.prototype.VERSION = ColReorder.VERSION;
918
+
919
+
920
+
921
+
922
+
923
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
924
+ * Initialisation
925
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
926
+
927
+ /*
928
+ * Register a new feature with DataTables
929
+ */
930
+ if ( typeof $.fn.dataTable == "function" &&
931
+ typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
932
+ $.fn.dataTableExt.fnVersionCheck('1.9.0') )
933
+ {
934
+ $.fn.dataTableExt.aoFeatures.push( {
935
+ "fnInit": function( oDTSettings ) {
936
+ var oTable = oDTSettings.oInstance;
937
+ if ( typeof oTable._oPluginColReorder == 'undefined' ) {
938
+ var opts = typeof oDTSettings.oInit.oColReorder != 'undefined' ?
939
+ oDTSettings.oInit.oColReorder : {};
940
+ oTable._oPluginColReorder = new ColReorder( oDTSettings.oInstance, opts );
941
+ } else {
942
+ oTable.oApi._fnLog( oDTSettings, 1, "ColReorder attempted to initialise twice. Ignoring second" );
943
+ }
944
+
945
+ return null; /* No node to insert */
946
+ },
947
+ "cFeature": "R",
948
+ "sFeature": "ColReorder"
949
+ } );
950
+ }
951
+ else
952
+ {
953
+ alert( "Warning: ColReorder requires DataTables 1.9.0 or greater - www.datatables.net/download");
954
+ }
955
+
956
+ })(jQuery, window, document);