naf 1.1.4 → 2.0.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.
Files changed (118) hide show
  1. data/Gemfile +4 -2
  2. data/app/assets/images/{papertrail_job.png → job.png} +0 -0
  3. data/app/assets/images/{papertrail_machine.png → machine.png} +0 -0
  4. data/app/assets/images/{papertrail_machine_runner.png → machine_runner.png} +0 -0
  5. data/app/assets/javascripts/col_reorder_with_resize.js +1228 -0
  6. data/app/assets/javascripts/dataTablesTemplates/applications.js +2 -1
  7. data/app/assets/javascripts/dataTablesTemplates/jobs.js +2 -1
  8. data/app/assets/javascripts/dataTablesTemplates/machine_runner_invocations.js +2 -1
  9. data/app/assets/javascripts/dataTablesTemplates/machine_runners.js +2 -1
  10. data/app/assets/javascripts/dataTablesTemplates/machines.js +2 -1
  11. data/app/assets/javascripts/jquery.dataTables.js +10339 -5103
  12. data/app/assets/javascripts/naf.js +1 -0
  13. data/app/assets/stylesheets/jquery_ui/jquery-ui-1.8.5.custom.css.erb +6 -6
  14. data/app/assets/stylesheets/min_naf/layout.css.scss +94 -43
  15. data/app/assets/stylesheets/naf/layout.css.scss +94 -43
  16. data/app/controllers/naf/affinities_controller.rb +1 -1
  17. data/app/controllers/naf/applications_controller.rb +3 -0
  18. data/app/controllers/naf/historical_job_affinity_tabs_controller.rb +1 -1
  19. data/app/controllers/naf/historical_jobs_controller.rb +2 -5
  20. data/app/controllers/naf/log_parsers_controller.rb +16 -0
  21. data/app/controllers/naf/log_viewer_controller.rb +19 -0
  22. data/app/controllers/naf/machine_affinity_slots_controller.rb +1 -1
  23. data/app/controllers/naf/machine_runners_controller.rb +12 -0
  24. data/app/controllers/naf/machines_controller.rb +8 -10
  25. data/app/controllers/naf/status_controller.rb +12 -0
  26. data/app/helpers/naf/application_helper.rb +19 -38
  27. data/app/helpers/naf/time_helper.rb +37 -0
  28. data/app/models/logical/naf/application.rb +13 -19
  29. data/app/models/logical/naf/construction_zone/boss.rb +1 -1
  30. data/app/models/logical/naf/construction_zone/foreman.rb +1 -1
  31. data/app/models/logical/naf/job.rb +39 -34
  32. data/app/models/logical/naf/job_creator.rb +19 -23
  33. data/app/models/logical/naf/job_fetcher.rb +36 -6
  34. data/app/models/logical/naf/log_file.rb +70 -0
  35. data/app/models/logical/naf/log_parser/base.rb +272 -0
  36. data/app/models/logical/naf/log_parser/job.rb +65 -0
  37. data/app/models/logical/naf/log_parser/machine.rb +64 -0
  38. data/app/models/logical/naf/log_parser/runner.rb +72 -0
  39. data/app/models/logical/naf/log_reader.rb +85 -0
  40. data/app/models/logical/naf/machine.rb +39 -1
  41. data/app/models/naf/affinity.rb +18 -0
  42. data/app/models/naf/application_schedule_affinity_tab.rb +1 -0
  43. data/app/models/naf/application_type.rb +2 -1
  44. data/app/models/naf/historical_job.rb +9 -29
  45. data/app/models/naf/machine.rb +8 -0
  46. data/app/models/naf/machine_runner.rb +11 -2
  47. data/app/models/naf/machine_runner_invocation.rb +9 -1
  48. data/app/models/naf/running_job.rb +40 -1
  49. data/app/models/process/naf/application.rb +3 -3
  50. data/app/models/process/naf/log_archiver.rb +78 -0
  51. data/app/models/process/naf/machine_manager.rb +3 -1
  52. data/app/models/process/naf/runner.rb +286 -162
  53. data/app/models/process/naf/runner_log.rb +26 -0
  54. data/app/views/naf/application_schedule_affinity_tabs/_form.html.erb +1 -5
  55. data/app/views/naf/applications/show.html.erb +1 -1
  56. data/app/views/naf/historical_job_affinity_tabs/_form.html.erb +1 -5
  57. data/app/views/naf/historical_jobs/_form.html.erb +1 -1
  58. data/app/views/naf/historical_jobs/_runners.html.erb +21 -12
  59. data/app/views/naf/historical_jobs/_search_container.html.erb +1 -2
  60. data/app/views/naf/historical_jobs/index.html.erb +0 -1
  61. data/app/views/naf/historical_jobs/index.json.erb +4 -4
  62. data/app/views/naf/historical_jobs/show.html.erb +57 -51
  63. data/app/views/naf/log_viewer/_job_logs.html.erb +65 -0
  64. data/app/views/naf/log_viewer/_log_display.html.erb +259 -0
  65. data/app/views/naf/log_viewer/_log_layout.html.erb +59 -0
  66. data/app/views/naf/log_viewer/_machine_logs.html.erb +62 -0
  67. data/app/views/naf/log_viewer/_runner_logs.html.erb +62 -0
  68. data/app/views/naf/log_viewer/_search_options.html.erb +36 -0
  69. data/app/views/naf/log_viewer/_update_page_title.html.erb +9 -0
  70. data/app/views/naf/log_viewer/index.html.erb +1 -0
  71. data/app/views/naf/logger_names/_form.html.erb +1 -2
  72. data/app/views/naf/machine_affinity_slots/_form.html.erb +1 -5
  73. data/app/views/naf/machine_runner_invocations/show.html.erb +4 -0
  74. data/app/views/naf/machine_runners/show.html.erb +44 -34
  75. data/app/views/naf/machines/index.json.erb +14 -6
  76. data/app/views/naf/machines/show.html.erb +44 -40
  77. data/app/views/naf/shared/_auto_resize_width.html.erb +7 -0
  78. data/app/views/naf/shared/_date_select.html.erb +65 -0
  79. data/app/views/naf/shared/_select_per_page.html.erb +48 -13
  80. data/app/views/naf/status/index.html.erb +27 -0
  81. data/bin/naf +26 -0
  82. data/config/initializers/naf.rb +13 -1
  83. data/config/routes.rb +16 -2
  84. data/db/migrate/20131106162436_add_uuid_column_to_machine_runner_invocations.rb +15 -0
  85. data/db/migrate/20131121185222_move_tabs_column_from_historical_jobs_to_running_jobs.rb +15 -0
  86. data/lib/generators/templates/config/logging/naf.yml +0 -8
  87. data/lib/generators/templates/config/logging/nafjob.yml +0 -8
  88. data/lib/generators/templates/config/logging/nafrunner.yml +0 -8
  89. data/lib/generators/templates/naf.rb +0 -8
  90. data/lib/naf.rb +0 -8
  91. data/lib/naf/configuration.rb +0 -4
  92. data/lib/naf/version.rb +1 -1
  93. data/lib/tasks/naf_tasks.rake +18 -0
  94. data/naf.gemspec +3 -1
  95. data/spec/controllers/naf/affinities_controller_spec.rb +0 -1
  96. data/spec/controllers/naf/applications_controller_spec.rb +3 -2
  97. data/spec/controllers/naf/machine_affinity_slots_controller_spec.rb +0 -1
  98. data/spec/controllers/naf/machines_controller_spec.rb +1 -1
  99. data/spec/dummy/config/logging/naf.yml +0 -8
  100. data/spec/dummy/config/logging/nafjob.yml +0 -9
  101. data/spec/dummy/config/logging/nafrunner.yml +0 -10
  102. data/spec/factories/naf.rb +4 -0
  103. data/spec/models/logical/naf/application_spec.rb +3 -4
  104. data/spec/models/logical/naf/job_creator_spec.rb +91 -21
  105. data/spec/models/logical/naf/job_spec.rb +19 -6
  106. data/spec/models/logical/naf/log_file_spec.rb +105 -0
  107. data/spec/models/logical/naf/machine_runner_invocation_spec.rb +41 -0
  108. data/spec/models/logical/naf/machine_runner_spec.rb +42 -0
  109. data/spec/models/logical/naf/machine_spec.rb +98 -28
  110. data/spec/models/naf/affinity_classification_spec.rb +20 -0
  111. data/spec/models/naf/affinity_spec.rb +21 -0
  112. data/spec/models/naf/historical_job_spec.rb +2 -44
  113. data/spec/models/naf/machine_runner_invocation_spec.rb +17 -1
  114. data/spec/models/naf/running_job_spec.rb +64 -1
  115. metadata +40 -9
  116. data/app/models/log4r/papertrail_outputter.rb +0 -19
  117. data/app/views/naf/historical_jobs/edit.html.erb +0 -11
  118. data/app/views/naf/machines/_show.html.erb +0 -169
data/Gemfile CHANGED
@@ -12,6 +12,8 @@ gem 'awesome_print'
12
12
  gem 'will_paginate'
13
13
  gem 'facter'
14
14
  gem 'shoulda-matchers', '2.0.0'
15
- gem "timecop", '0.4.5'
16
-
15
+ gem 'timecop', '0.4.5'
16
+ gem 'open4'
17
+ gem 'yajl-ruby'
18
+ gem 'aws-sdk'
17
19
  gem 'fiksu-af'
@@ -0,0 +1,1228 @@
1
+ /*
2
+ * File: ColReorderWithResize.js
3
+ * Version: 1.0.7
4
+ * CVS: $Id$
5
+ * Description: Allow columns to be reordered in a DataTable
6
+ * Author: Allan Jardine (www.sprymedia.co.uk)
7
+ * Author: Christophe Battarel (www.altairis.fr)
8
+ * Created: Wed Sep 15 18:23:29 BST 2010
9
+ * Modified: July 2011 by Christophe Battarel - christophe.battarel@altairis.fr (columns resizable)
10
+ * Modified: February 2012 by Martin Marchetta - martin.marchetta@gmail.com
11
+ * 1. Made the "hot area" for resizing a little wider (it was a little difficult to hit the exact border of a column for resizing)
12
+ * 2. Resizing didn't work at all when using scroller (that plugin splits the table into 2 different tables: one for the header and another one for the body, so when you resized the header, the data columns didn't follow)
13
+ * 3. Fixed collateral effects of sorting feature
14
+ * 4. If sScrollX is enabled (i.e. horizontal scrolling), when resizing a column the width of the other columns is not changed, but the whole
15
+ * table is resized to give an Excel-like behavior (good suggestion by Allan)
16
+ * Modified: February 2012 by Christophe Battarel - christophe.battarel@altairis.fr (ColReorder v1.0.5 adaptation)
17
+ * Modified: September 16th 2012 by Hassan Kamara - h@phrmc.com
18
+ * Language: Javascript
19
+ * License: GPL v2 or BSD 3 point style
20
+ * Project: DataTables
21
+ * Contact: www.sprymedia.co.uk/contact
22
+ *
23
+ * Copyright 2010-2011 Allan Jardine, all rights reserved.
24
+ *
25
+ * This source file is free software, under either the GPL v2 license or a
26
+ * BSD style license, available at:
27
+ * http://datatables.net/license_gpl2
28
+ * http://datatables.net/license_bsd
29
+ *
30
+ */
31
+
32
+
33
+ (function($, window, document) {
34
+
35
+
36
+ /**
37
+ * Switch the key value pairing of an index array to be value key (i.e. the old value is now the
38
+ * key). For example consider [ 2, 0, 1 ] this would be returned as [ 1, 2, 0 ].
39
+ * @method fnInvertKeyValues
40
+ * @param array aIn Array to switch around
41
+ * @returns array
42
+ */
43
+ function fnInvertKeyValues( aIn )
44
+ {
45
+ var aRet=[];
46
+ for ( var i=0, iLen=aIn.length ; i<iLen ; i++ )
47
+ {
48
+ aRet[ aIn[i] ] = i;
49
+ }
50
+ return aRet;
51
+ }
52
+
53
+
54
+ /**
55
+ * Modify an array by switching the position of two elements
56
+ * @method fnArraySwitch
57
+ * @param array aArray Array to consider, will be modified by reference (i.e. no return)
58
+ * @param int iFrom From point
59
+ * @param int iTo Insert point
60
+ * @returns void
61
+ */
62
+ function fnArraySwitch( aArray, iFrom, iTo )
63
+ {
64
+ var mStore = aArray.splice( iFrom, 1 )[0];
65
+ aArray.splice( iTo, 0, mStore );
66
+ }
67
+
68
+
69
+ /**
70
+ * Switch the positions of nodes in a parent node (note this is specifically designed for
71
+ * table rows). Note this function considers all element nodes under the parent!
72
+ * @method fnDomSwitch
73
+ * @param string sTag Tag to consider
74
+ * @param int iFrom Element to move
75
+ * @param int Point to element the element to (before this point), can be null for append
76
+ * @returns void
77
+ */
78
+ function fnDomSwitch( nParent, iFrom, iTo )
79
+ {
80
+ var anTags = [];
81
+ for ( var i=0, iLen=nParent.childNodes.length ; i<iLen ; i++ )
82
+ {
83
+ if ( nParent.childNodes[i].nodeType == 1 )
84
+ {
85
+ anTags.push( nParent.childNodes[i] );
86
+ }
87
+ }
88
+ var nStore = anTags[ iFrom ];
89
+
90
+ if ( iTo !== null )
91
+ {
92
+ nParent.insertBefore( nStore, anTags[iTo] );
93
+ }
94
+ else
95
+ {
96
+ nParent.appendChild( nStore );
97
+ }
98
+ }
99
+
100
+
101
+
102
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
103
+ * DataTables plug-in API functions
104
+ *
105
+ * This are required by ColReorder in order to perform the tasks required, and also keep this
106
+ * code portable, to be used for other column reordering projects with DataTables, if needed.
107
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
108
+
109
+
110
+ /**
111
+ * Plug-in for DataTables which will reorder the internal column structure by taking the column
112
+ * from one position (iFrom) and insert it into a given point (iTo).
113
+ * @method $.fn.dataTableExt.oApi.fnColReorder
114
+ * @param object oSettings DataTables settings object - automatically added by DataTables!
115
+ * @param int iFrom Take the column to be repositioned from this point
116
+ * @param int iTo and insert it into this point
117
+ * @returns void
118
+ */
119
+ $.fn.dataTableExt.oApi.fnColReorder = function ( oSettings, iFrom, iTo )
120
+ {
121
+ var i, iLen, j, jLen, iCols=oSettings.aoColumns.length, nTrs, oCol;
122
+
123
+ /* Sanity check in the input */
124
+ if ( iFrom == iTo )
125
+ {
126
+ /* Pointless reorder */
127
+ return;
128
+ }
129
+
130
+ if ( iFrom < 0 || iFrom >= iCols )
131
+ {
132
+ this.oApi._fnLog( oSettings, 1, "ColReorder 'from' index is out of bounds: "+iFrom );
133
+ return;
134
+ }
135
+
136
+ if ( iTo < 0 || iTo >= iCols )
137
+ {
138
+ this.oApi._fnLog( oSettings, 1, "ColReorder 'to' index is out of bounds: "+iTo );
139
+ return;
140
+ }
141
+
142
+ /*
143
+ * Calculate the new column array index, so we have a mapping between the old and new
144
+ */
145
+ var aiMapping = [];
146
+ for ( i=0, iLen=iCols ; i<iLen ; i++ )
147
+ {
148
+ aiMapping[i] = i;
149
+ }
150
+ fnArraySwitch( aiMapping, iFrom, iTo );
151
+ var aiInvertMapping = fnInvertKeyValues( aiMapping );
152
+
153
+
154
+ /*
155
+ * Convert all internal indexing to the new column order indexes
156
+ */
157
+ /* Sorting */
158
+ for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
159
+ {
160
+ oSettings.aaSorting[i][0] = aiInvertMapping[ oSettings.aaSorting[i][0] ];
161
+ }
162
+
163
+ /* Fixed sorting */
164
+ if ( oSettings.aaSortingFixed !== null )
165
+ {
166
+ for ( i=0, iLen=oSettings.aaSortingFixed.length ; i<iLen ; i++ )
167
+ {
168
+ oSettings.aaSortingFixed[i][0] = aiInvertMapping[ oSettings.aaSortingFixed[i][0] ];
169
+ }
170
+ }
171
+
172
+ /* Data column sorting (the column which the sort for a given column should take place on) */
173
+ for ( i=0, iLen=iCols ; i<iLen ; i++ )
174
+ {
175
+ oCol = oSettings.aoColumns[i];
176
+ for ( j=0, jLen=oCol.aDataSort.length ; j<jLen ; j++ )
177
+ {
178
+ oCol.aDataSort[j] = aiInvertMapping[ oCol.aDataSort[j] ];
179
+ }
180
+ }
181
+
182
+ /* Update the Get and Set functions for each column */
183
+ for ( i=0, iLen=iCols ; i<iLen ; i++ )
184
+ {
185
+ oCol = oSettings.aoColumns[i];
186
+ if ( typeof oCol.mData == 'number' ) {
187
+ oCol.mData = aiInvertMapping[ oCol.mData ];
188
+ oCol.fnGetData = oSettings.oApi._fnGetObjectDataFn( oCol.mData );
189
+ oCol.fnSetData = oSettings.oApi._fnSetObjectDataFn( oCol.mData );
190
+ }
191
+ }
192
+
193
+
194
+ /*
195
+ * Move the DOM elements
196
+ */
197
+ if ( oSettings.aoColumns[iFrom].bVisible )
198
+ {
199
+ /* Calculate the current visible index and the point to insert the node before. The insert
200
+ * before needs to take into account that there might not be an element to insert before,
201
+ * in which case it will be null, and an appendChild should be used
202
+ */
203
+ var iVisibleIndex = this.oApi._fnColumnIndexToVisible( oSettings, iFrom );
204
+ var iInsertBeforeIndex = null;
205
+
206
+ i = iTo < iFrom ? iTo : iTo + 1;
207
+ while ( iInsertBeforeIndex === null && i < iCols )
208
+ {
209
+ iInsertBeforeIndex = this.oApi._fnColumnIndexToVisible( oSettings, i );
210
+ i++;
211
+ }
212
+
213
+ /* Header */
214
+ nTrs = oSettings.nTHead.getElementsByTagName('tr');
215
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
216
+ {
217
+ fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );
218
+ }
219
+
220
+ /* Footer */
221
+ if ( oSettings.nTFoot !== null )
222
+ {
223
+ nTrs = oSettings.nTFoot.getElementsByTagName('tr');
224
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
225
+ {
226
+ fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );
227
+ }
228
+ }
229
+
230
+ /* Body */
231
+ for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
232
+ {
233
+ if ( oSettings.aoData[i].nTr !== null )
234
+ {
235
+ fnDomSwitch( oSettings.aoData[i].nTr, iVisibleIndex, iInsertBeforeIndex );
236
+ }
237
+ }
238
+ }
239
+
240
+
241
+ /*
242
+ * Move the internal array elements
243
+ */
244
+ /* Columns */
245
+ fnArraySwitch( oSettings.aoColumns, iFrom, iTo );
246
+
247
+ /* Search columns */
248
+ fnArraySwitch( oSettings.aoPreSearchCols, iFrom, iTo );
249
+
250
+ /* Array array - internal data anodes cache */
251
+ for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
252
+ {
253
+ if ( $.isArray( oSettings.aoData[i]._aData ) ) {
254
+ fnArraySwitch( oSettings.aoData[i]._aData, iFrom, iTo );
255
+ }
256
+ fnArraySwitch( oSettings.aoData[i]._anHidden, iFrom, iTo );
257
+ }
258
+
259
+ /* Reposition the header elements in the header layout array */
260
+ for ( i=0, iLen=oSettings.aoHeader.length ; i<iLen ; i++ )
261
+ {
262
+ fnArraySwitch( oSettings.aoHeader[i], iFrom, iTo );
263
+ }
264
+
265
+ if ( oSettings.aoFooter !== null )
266
+ {
267
+ for ( i=0, iLen=oSettings.aoFooter.length ; i<iLen ; i++ )
268
+ {
269
+ fnArraySwitch( oSettings.aoFooter[i], iFrom, iTo );
270
+ }
271
+ }
272
+
273
+
274
+ /*
275
+ * Update DataTables' event handlers
276
+ */
277
+
278
+ /* Sort listener */
279
+ for ( i=0, iLen=iCols ; i<iLen ; i++ )
280
+ {
281
+ //Martin Marchetta:
282
+ //Update this field which is the one used by DataTables for getting the column's data for sorting.
283
+ oSettings.aoColumns[i].aDataSort = [i];
284
+ //Update the internal column index, since columns are actually being re-ordered in the internal structure
285
+ oSettings.aoColumns[i]._ColReorder_iOrigCol = i;
286
+ ///////////////////////////////////
287
+ $(oSettings.aoColumns[i].nTh).unbind('click');
288
+ this.oApi._fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
289
+ }
290
+
291
+
292
+ /*
293
+ * Any extra operations for the other plug-ins
294
+ */
295
+ if ( typeof ColVis != 'undefined' )
296
+ {
297
+ ColVis.fnRebuild( oSettings.oInstance );
298
+ }
299
+
300
+ /* Fire an event so other plug-ins can update */
301
+ $(oSettings.oInstance).trigger( 'column-reorder', [ oSettings, {
302
+ "iFrom": iFrom,
303
+ "iTo": iTo,
304
+ "aiInvertMapping": aiInvertMapping
305
+ } ] );
306
+
307
+ if ( typeof oSettings.oInstance._oPluginFixedHeader != 'undefined' )
308
+ {
309
+ oSettings.oInstance._oPluginFixedHeader.fnUpdate();
310
+ }
311
+ };
312
+
313
+
314
+
315
+
316
+ /**
317
+ * ColReorder provides column visiblity control for DataTables
318
+ * @class ColReorder
319
+ * @constructor
320
+ * @param {object} DataTables settings object
321
+ * @param {object} ColReorder options
322
+ */
323
+ ColReorder = function( oDTSettings, oOpts )
324
+ {
325
+ /* Santiy check that we are a new instance */
326
+ if ( !this.CLASS || this.CLASS != "ColReorder" )
327
+ {
328
+ alert( "Warning: ColReorder must be initialised with the keyword 'new'" );
329
+ }
330
+
331
+ if ( typeof oOpts == 'undefined' )
332
+ {
333
+ oOpts = {};
334
+ }
335
+
336
+
337
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
338
+ * Public class variables
339
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
340
+
341
+ /**
342
+ * @namespace Settings object which contains customisable information for ColReorder instance
343
+ */
344
+ this.s = {
345
+ /**
346
+ * DataTables settings object
347
+ * @property dt
348
+ * @type Object
349
+ * @default null
350
+ */
351
+ "dt": null,
352
+
353
+ /**
354
+ * Initialisation object used for this instance
355
+ * @property init
356
+ * @type object
357
+ * @default {}
358
+ */
359
+ "init": oOpts,
360
+
361
+ /**
362
+ * Allow Reorder functionnality
363
+ * @property allowReorder
364
+ * @type boolean
365
+ * @default true
366
+ */
367
+ "allowReorder": true,
368
+
369
+ /**
370
+ * Allow Resize functionnality
371
+ * @property allowResize
372
+ * @type boolean
373
+ * @default true
374
+ */
375
+ "allowResize": true,
376
+
377
+ /**
378
+ * Number of columns to fix (not allow to be reordered)
379
+ * @property fixed
380
+ * @type int
381
+ * @default 0
382
+ */
383
+ "fixed": 0,
384
+
385
+ /**
386
+ * Callback function for once the reorder has been done
387
+ * @property dropcallback
388
+ * @type function
389
+ * @default null
390
+ */
391
+ "dropCallback": null,
392
+
393
+ /**
394
+ * @namespace Information used for the mouse drag
395
+ */
396
+ "mouse": {
397
+ "startX": -1,
398
+ "startY": -1,
399
+ "offsetX": -1,
400
+ "offsetY": -1,
401
+ "target": -1,
402
+ "targetIndex": -1,
403
+ "fromIndex": -1
404
+ },
405
+
406
+ /**
407
+ * Information which is used for positioning the insert cusor and knowing where to do the
408
+ * insert. Array of objects with the properties:
409
+ * x: x-axis position
410
+ * to: insert point
411
+ * @property aoTargets
412
+ * @type array
413
+ * @default []
414
+ */
415
+ "aoTargets": []
416
+ };
417
+
418
+
419
+ /**
420
+ * @namespace Common and useful DOM elements for the class instance
421
+ */
422
+ this.dom = {
423
+ /**
424
+ * Dragging element (the one the mouse is moving)
425
+ * @property drag
426
+ * @type element
427
+ * @default null
428
+ */
429
+ "drag": null,
430
+
431
+ /**
432
+ * Resizing a column
433
+ * @property drag
434
+ * @type element
435
+ * @default null
436
+ */
437
+ "resize": null,
438
+
439
+ /**
440
+ * The insert cursor
441
+ * @property pointer
442
+ * @type element
443
+ * @default null
444
+ */
445
+ "pointer": null
446
+ };
447
+
448
+ /////////////////
449
+ //Martin Marchetta: keep the current table's size in order to resize it if columns are resized and scrollX is enabled
450
+ this.table_size = -1;
451
+ /////////////////
452
+
453
+ /* Constructor logic */
454
+ this.s.dt = oDTSettings.oInstance.fnSettings();
455
+ this._fnConstruct();
456
+
457
+ /* Add destroy callback */
458
+ oDTSettings.oApi._fnCallbackReg(oDTSettings, 'aoDestroyCallback', jQuery.proxy(this._fnDestroy, this), 'ColReorder');
459
+
460
+ /* Store the instance for later use */
461
+ ColReorder.aoInstances.push( this );
462
+ return this;
463
+ };
464
+
465
+
466
+
467
+ ColReorder.prototype = {
468
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
469
+ * Public methods
470
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
471
+
472
+ "fnReset": function ()
473
+ {
474
+ var a = [];
475
+ for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
476
+ {
477
+ a.push( this.s.dt.aoColumns[i]._ColReorder_iOrigCol );
478
+ }
479
+
480
+ this._fnOrderColumns( a );
481
+ },
482
+
483
+
484
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
485
+ * Private methods (they are of course public in JS, but recommended as private)
486
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
487
+
488
+ /**
489
+ * Constructor logic
490
+ * @method _fnConstruct
491
+ * @returns void
492
+ * @private
493
+ */
494
+ "_fnConstruct": function ()
495
+ {
496
+ var that = this;
497
+ var i, iLen;
498
+
499
+ /* allow reorder */
500
+ if ( typeof this.s.init.allowReorder != 'undefined' )
501
+ {
502
+ this.s.allowReorder = this.s.init.allowReorder;
503
+ }
504
+
505
+ /* allow resize */
506
+ if ( typeof this.s.init.allowResize != 'undefined' )
507
+ {
508
+ this.s.allowResize = this.s.init.allowResize;
509
+ }
510
+
511
+ /* Columns discounted from reordering - counting left to right */
512
+ if ( typeof this.s.init.iFixedColumns != 'undefined' )
513
+ {
514
+ this.s.fixed = this.s.init.iFixedColumns;
515
+ }
516
+
517
+ /* Drop callback initialisation option */
518
+ if ( typeof this.s.init.fnReorderCallback != 'undefined' )
519
+ {
520
+ this.s.dropCallback = this.s.init.fnReorderCallback;
521
+ }
522
+
523
+ /* Add event handlers for the drag and drop, and also mark the original column order */
524
+ for ( i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
525
+ {
526
+ if ( i > this.s.fixed-1 )
527
+ {
528
+ this._fnMouseListener( i, this.s.dt.aoColumns[i].nTh );
529
+ }
530
+
531
+ /* Mark the original column order for later reference */
532
+ this.s.dt.aoColumns[i]._ColReorder_iOrigCol = i;
533
+ }
534
+
535
+ /* State saving */
536
+ this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) {
537
+ that._fnStateSave.call( that, oData );
538
+ }, "ColReorder_State" );
539
+
540
+ /* An initial column order has been specified */
541
+ var aiOrder = null;
542
+ if ( typeof this.s.init.aiOrder != 'undefined' )
543
+ {
544
+ aiOrder = this.s.init.aiOrder.slice();
545
+ }
546
+
547
+ /* State loading, overrides the column order given */
548
+ if ( this.s.dt.oLoadedState && typeof this.s.dt.oLoadedState.ColReorder != 'undefined' &&
549
+ this.s.dt.oLoadedState.ColReorder.length == this.s.dt.aoColumns.length )
550
+ {
551
+ aiOrder = this.s.dt.oLoadedState.ColReorder;
552
+ }
553
+
554
+ /* If we have an order to apply - do so */
555
+ if ( aiOrder )
556
+ {
557
+ /* We might be called during or after the DataTables initialisation. If before, then we need
558
+ * to wait until the draw is done, if after, then do what we need to do right away
559
+ */
560
+ if ( !that.s.dt._bInitComplete )
561
+ {
562
+ var bDone = false;
563
+ this.s.dt.aoDrawCallback.push( {
564
+ "fn": function () {
565
+ if ( !that.s.dt._bInitComplete && !bDone )
566
+ {
567
+ bDone = true;
568
+ var resort = fnInvertKeyValues( aiOrder );
569
+ that._fnOrderColumns.call( that, resort );
570
+ }
571
+ },
572
+ "sName": "ColReorder_Pre"
573
+ } );
574
+ }
575
+ else
576
+ {
577
+ var resort = fnInvertKeyValues( aiOrder );
578
+ that._fnOrderColumns.call( that, resort );
579
+ }
580
+ }
581
+ },
582
+
583
+
584
+ /**
585
+ * Set the column order from an array
586
+ * @method _fnOrderColumns
587
+ * @param array a An array of integers which dictate the column order that should be applied
588
+ * @returns void
589
+ * @private
590
+ */
591
+ "_fnOrderColumns": function ( a )
592
+ {
593
+ if ( a.length != this.s.dt.aoColumns.length )
594
+ {
595
+ this.s.dt.oInstance.oApi._fnLog( oDTSettings, 1, "ColReorder - array reorder does not "+
596
+ "match known number of columns. Skipping." );
597
+ return;
598
+ }
599
+
600
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ )
601
+ {
602
+ var currIndex = $.inArray( i, a );
603
+ if ( i != currIndex )
604
+ {
605
+ /* Reorder our switching array */
606
+ fnArraySwitch( a, currIndex, i );
607
+
608
+ /* Do the column reorder in the table */
609
+ this.s.dt.oInstance.fnColReorder( currIndex, i );
610
+ }
611
+ }
612
+
613
+ /* When scrolling we need to recalculate the column sizes to allow for the shift */
614
+ if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
615
+ {
616
+ this.s.dt.oInstance.fnAdjustColumnSizing();
617
+ }
618
+
619
+ /* Save the state */
620
+ this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
621
+ },
622
+
623
+
624
+ /**
625
+ * Because we change the indexes of columns in the table, relative to their starting point
626
+ * we need to reorder the state columns to what they are at the starting point so we can
627
+ * then rearrange them again on state load!
628
+ * @method _fnStateSave
629
+ * @param object oState DataTables state
630
+ * @returns string JSON encoded cookie string for DataTables
631
+ * @private
632
+ */
633
+ "_fnStateSave": function ( oState )
634
+ {
635
+ var i, iLen, aCopy, iOrigColumn;
636
+ var oSettings = this.s.dt;
637
+
638
+ /* Sorting */
639
+ for ( i=0 ; i<oState.aaSorting.length ; i++ )
640
+ {
641
+ oState.aaSorting[i][0] = oSettings.aoColumns[ oState.aaSorting[i][0] ]._ColReorder_iOrigCol;
642
+ }
643
+
644
+ aSearchCopy = $.extend( true, [], oState.aoSearchCols );
645
+ oState.ColReorder = [];
646
+
647
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
648
+ {
649
+ iOrigColumn = oSettings.aoColumns[i]._ColReorder_iOrigCol;
650
+
651
+ /* Column filter */
652
+ oState.aoSearchCols[ iOrigColumn ] = aSearchCopy[i];
653
+
654
+ /* Visibility */
655
+ oState.abVisCols[ iOrigColumn ] = oSettings.aoColumns[i].bVisible;
656
+
657
+ /* Column reordering */
658
+ oState.ColReorder.push( iOrigColumn );
659
+ }
660
+ },
661
+
662
+
663
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
664
+ * Mouse drop and drag
665
+ */
666
+
667
+ /**
668
+ * Add a mouse down listener to a particluar TH element
669
+ * @method _fnMouseListener
670
+ * @param int i Column index
671
+ * @param element nTh TH element clicked on
672
+ * @returns void
673
+ * @private
674
+ */
675
+ "_fnMouseListener": function ( i, nTh )
676
+ {
677
+ var that = this;
678
+
679
+ //Martin Marchetta (rebind events since after column re-order they use wrong column indices)
680
+ $(nTh).unbind('mousemove.ColReorder');
681
+ $(nTh).unbind('mousedown.ColReorder');
682
+ ////////////////
683
+
684
+ // listen to mousemove event for resize
685
+ if (this.s.allowResize) {
686
+ $(nTh).bind( 'mousemove.ColReorder', function (e) {
687
+ if ( that.dom.drag === null && that.dom.resize === null)
688
+ {
689
+ /* Store information about the mouse position */
690
+ var nThTarget = e.target.nodeName == "TH" ? e.target : $(e.target).parents('TH')[0];
691
+ var offset = $(nThTarget).offset();
692
+ var nLength = $(nThTarget).innerWidth();
693
+
694
+ /* are we on the col border (if so, resize col) */
695
+ if (Math.abs(e.pageX - Math.round(offset.left + nLength)) <= 5)
696
+ {
697
+ $(nThTarget).css({'cursor': 'col-resize'});
698
+ }
699
+ else
700
+ $(nThTarget).css({'cursor': 'pointer'});
701
+ }
702
+ } );
703
+ }
704
+
705
+ // listen to mousedown event
706
+ $(nTh).bind( 'mousedown.ColReorder', function (e) {
707
+ that._fnMouseDown.call( that, e, nTh, i ); //Martin Marchetta: added the index of the column dragged or resized
708
+ return false;
709
+ } );
710
+ },
711
+
712
+
713
+ /**
714
+ * Mouse down on a TH element in the table header
715
+ * @method _fnMouseDown
716
+ * @param event e Mouse event
717
+ * @param element nTh TH element to be dragged
718
+ * @param i The column that's resized/dragged
719
+ * @returns void
720
+ * @private
721
+ */
722
+ "_fnMouseDown": function ( e, nTh, i )
723
+ {
724
+ var
725
+ that = this,
726
+ aoColumns = this.s.dt.aoColumns;
727
+
728
+ /* are we resizing a column ? */
729
+ if ($(nTh).css('cursor') == 'col-resize') {
730
+ this.s.mouse.startX = e.pageX;
731
+ this.s.mouse.startWidth = $(nTh).width();
732
+ this.s.mouse.resizeElem = $(nTh);
733
+ var nThNext = $(nTh).next();
734
+ this.s.mouse.nextStartWidth = $(nThNext).width();
735
+ that.dom.resize = true;
736
+ ////////////////////
737
+ //Martin Marchetta
738
+ //a. Disable column sorting so as to avoid issues when finishing column resizing
739
+ this.s.dt.aoColumns[i].bSortable = false;
740
+ //b. Disable Autowidth feature (now the user is in charge of setting column width so keeping this enabled looses changes after operations)
741
+ this.s.dt.oFeatures.bAutoWidth = false;
742
+ ////////////////////
743
+ }
744
+ else if (this.s.allowReorder) {
745
+ that.dom.resize = null;
746
+ /* Store information about the mouse position */
747
+ var nThTarget = e.target.nodeName == "TH" ? e.target : $(e.target).parents('TH')[0];
748
+ var offset = $(nThTarget).offset();
749
+ this.s.mouse.startX = e.pageX;
750
+ this.s.mouse.startY = e.pageY;
751
+ this.s.mouse.offsetX = e.pageX - offset.left;
752
+ this.s.mouse.offsetY = e.pageY - offset.top;
753
+ this.s.mouse.target = nTh;
754
+ this.s.mouse.targetIndex = $('th', nTh.parentNode).index( nTh );
755
+ this.s.mouse.fromIndex = this.s.dt.oInstance.oApi._fnVisibleToColumnIndex( this.s.dt,
756
+ this.s.mouse.targetIndex );
757
+
758
+ /* Calculate a cached array with the points of the column inserts, and the 'to' points */
759
+ this.s.aoTargets.splice( 0, this.s.aoTargets.length );
760
+
761
+ this.s.aoTargets.push( {
762
+ "x": $(this.s.dt.nTable).offset().left,
763
+ "to": 0
764
+ } );
765
+
766
+ var iToPoint = 0;
767
+ for ( var i=0, iLen=aoColumns.length ; i<iLen ; i++ )
768
+ {
769
+ /* For the column / header in question, we want it's position to remain the same if the
770
+ * position is just to it's immediate left or right, so we only incremement the counter for
771
+ * other columns
772
+ */
773
+ if ( i != this.s.mouse.fromIndex )
774
+ {
775
+ iToPoint++;
776
+ }
777
+
778
+ if ( aoColumns[i].bVisible )
779
+ {
780
+ this.s.aoTargets.push( {
781
+ "x": $(aoColumns[i].nTh).offset().left + $(aoColumns[i].nTh).outerWidth(),
782
+ "to": iToPoint
783
+ } );
784
+ }
785
+ }
786
+
787
+ /* Disallow columns for being reordered by drag and drop, counting left to right */
788
+ if ( this.s.fixed !== 0 )
789
+ {
790
+ this.s.aoTargets.splice( 0, this.s.fixed );
791
+ }
792
+ }
793
+
794
+ /* Add event handlers to the document */
795
+ $(document).bind( 'mousemove.ColReorder', function (e) {
796
+ that._fnMouseMove.call( that, e, i); //Martin Marchetta: Added index of the call being dragged or resized
797
+ } );
798
+
799
+ $(document).bind( 'mouseup.ColReorder', function (e) {
800
+ //Martin Marcheta: Added this small delay in order to prevent collision with column sort feature (there must be a better
801
+ //way of doing this, but I don't have more time to digg into it)
802
+ setTimeout(function(){
803
+ that._fnMouseUp.call( that, e, i ); //Martin Marchetta: Added index of the call being dragged or resized
804
+ }, 10);
805
+ } );
806
+ },
807
+
808
+
809
+ /**
810
+ * Deal with a mouse move event while dragging a node
811
+ * @method _fnMouseMove
812
+ * @param event e Mouse event
813
+ * @param colResized Index of the column that's being dragged or resized (index within the internal model, not the visible order)
814
+ * @returns void
815
+ * @private
816
+ */
817
+ "_fnMouseMove": function ( e, colResized )
818
+ {
819
+ var that = this;
820
+
821
+ ////////////////////
822
+ //Martin Marchetta: Determine if ScrollX is enabled
823
+ var scrollXEnabled;
824
+
825
+ scrollXEnabled = this.s.dt.oInit.sScrollX === "" ? false:true;
826
+
827
+ //Keep the current table's width (used in case sScrollX is enabled to resize the whole table, giving an Excel-like behavior)
828
+ if(this.table_size < 0 && scrollXEnabled && $('div.dataTables_scrollHead', this.s.dt.nTableWrapper) != undefined){
829
+ if($('div.dataTables_scrollHead', this.s.dt.nTableWrapper).length > 0)
830
+ this.table_size = $($('div.dataTables_scrollHead', this.s.dt.nTableWrapper)[0].childNodes[0].childNodes[0]).width();
831
+ }
832
+ ////////////////////
833
+
834
+ /* are we resizing a column ? */
835
+ if (this.dom.resize) {
836
+ var nTh = this.s.mouse.resizeElem;
837
+ var nThNext = $(nTh).next();
838
+ var moveLength = e.pageX-this.s.mouse.startX;
839
+ if (moveLength != 0 && !scrollXEnabled)
840
+ $(nThNext).width(this.s.mouse.nextStartWidth - moveLength);
841
+ $(nTh).width(this.s.mouse.startWidth + moveLength);
842
+
843
+ //Martin Marchetta: Resize the header too (if sScrollX is enabled)
844
+ if(scrollXEnabled && $('div.dataTables_scrollHead', this.s.dt.nTableWrapper) != undefined){
845
+ if($('div.dataTables_scrollHead', this.s.dt.nTableWrapper).length > 0)
846
+ $($('div.dataTables_scrollHead', this.s.dt.nTableWrapper)[0].childNodes[0].childNodes[0]).width(this.table_size + moveLength);
847
+ }
848
+
849
+ ////////////////////////
850
+ //Martin Marchetta: Fixed col resizing when the scroller is enabled.
851
+ var visibleColumnIndex;
852
+ //First determine if this plugin is being used along with the smart scroller...
853
+ if($('div.dataTables_scrollBody') != null){
854
+ //...if so, when resizing the header, also resize the table's body (when enabling the Scroller, the table's header and
855
+ //body are split into different tables, so the column resizing doesn't work anymore)
856
+ if($('div.dataTables_scrollBody').length > 0){
857
+ //Since some columns might have been hidden, find the correct one to resize in the table's body
858
+ var currentColumnIndex;
859
+ visibleColumnIndex = -1;
860
+ for(currentColumnIndex=-1; currentColumnIndex < this.s.dt.aoColumns.length-1 && currentColumnIndex != colResized; currentColumnIndex++){
861
+ if(this.s.dt.aoColumns[currentColumnIndex+1].bVisible)
862
+ visibleColumnIndex++;
863
+ }
864
+
865
+ //Get the scroller's div
866
+ tableScroller = $('div.dataTables_scrollBody', this.s.dt.nTableWrapper)[0];
867
+
868
+ //Get the table
869
+ scrollingTableHead = $(tableScroller)[0].childNodes[0].childNodes[0].childNodes[0];
870
+
871
+ //Resize the columns
872
+ if (moveLength != 0 && !scrollXEnabled){
873
+ $($(scrollingTableHead)[0].childNodes[visibleColumnIndex+1]).width(this.s.mouse.nextStartWidth - moveLength);
874
+ }
875
+ $($(scrollingTableHead)[0].childNodes[visibleColumnIndex]).width(this.s.mouse.startWidth + moveLength);
876
+
877
+ //Resize the table too
878
+ if(scrollXEnabled)
879
+ $($(tableScroller)[0].childNodes[0]).width(this.table_size + moveLength);
880
+ }
881
+ }
882
+ ////////////////////////
883
+
884
+ return;
885
+ }
886
+ else if (this.s.allowReorder) {
887
+ if ( this.dom.drag === null )
888
+ {
889
+ /* Only create the drag element if the mouse has moved a specific distance from the start
890
+ * point - this allows the user to make small mouse movements when sorting and not have a
891
+ * possibly confusing drag element showing up
892
+ */
893
+ if ( Math.pow(
894
+ Math.pow(e.pageX - this.s.mouse.startX, 2) +
895
+ Math.pow(e.pageY - this.s.mouse.startY, 2), 0.5 ) < 5 )
896
+ {
897
+ return;
898
+ }
899
+ this._fnCreateDragNode();
900
+ }
901
+
902
+ /* Position the element - we respect where in the element the click occured */
903
+ this.dom.drag.style.left = (e.pageX - this.s.mouse.offsetX) + "px";
904
+ this.dom.drag.style.top = (e.pageY - this.s.mouse.offsetY) + "px";
905
+
906
+ /* Based on the current mouse position, calculate where the insert should go */
907
+ var bSet = false;
908
+ for ( var i=1, iLen=this.s.aoTargets.length ; i<iLen ; i++ )
909
+ {
910
+ if ( e.pageX < this.s.aoTargets[i-1].x + ((this.s.aoTargets[i].x-this.s.aoTargets[i-1].x)/2) )
911
+ {
912
+ this.dom.pointer.style.left = this.s.aoTargets[i-1].x +"px";
913
+ this.s.mouse.toIndex = this.s.aoTargets[i-1].to;
914
+ bSet = true;
915
+ break;
916
+ }
917
+ }
918
+
919
+ /* The insert element wasn't positioned in the array (less than operator), so we put it at
920
+ * the end
921
+ */
922
+ if ( !bSet )
923
+ {
924
+ this.dom.pointer.style.left = this.s.aoTargets[this.s.aoTargets.length-1].x +"px";
925
+ this.s.mouse.toIndex = this.s.aoTargets[this.s.aoTargets.length-1].to;
926
+ }
927
+ }
928
+ },
929
+
930
+
931
+ /**
932
+ * Finish off the mouse drag and insert the column where needed
933
+ * @method _fnMouseUp
934
+ * @param event e Mouse event
935
+ * @param colResized The index of the column that was just dragged or resized (index within the internal model, not the visible order).
936
+ * @returns void
937
+ * @private
938
+ */
939
+ "_fnMouseUp": function ( e, colResized)
940
+ {
941
+ var that = this;
942
+
943
+ $(document).unbind( 'mousemove.ColReorder' );
944
+ $(document).unbind( 'mouseup.ColReorder' );
945
+
946
+ if ( this.dom.drag !== null )
947
+ {
948
+ /* Remove the guide elements */
949
+ document.body.removeChild( this.dom.drag );
950
+ document.body.removeChild( this.dom.pointer );
951
+ this.dom.drag = null;
952
+ this.dom.pointer = null;
953
+
954
+ /* Actually do the reorder */
955
+ this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex );
956
+
957
+ /* When scrolling we need to recalculate the column sizes to allow for the shift */
958
+ if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
959
+ {
960
+ this.s.dt.oInstance.fnAdjustColumnSizing();
961
+ }
962
+
963
+ if ( this.s.dropCallback !== null )
964
+ {
965
+ this.s.dropCallback.call( this );
966
+ }
967
+
968
+ ////////////
969
+ //Martin Marchetta: Re-initialize so as to register the new column order
970
+ //(otherwise the events remain bound to the original column indices)
971
+ this._fnConstruct();
972
+ ///////////
973
+
974
+ /* Save the state */
975
+ this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
976
+ }
977
+ ///////////////////////////////////////////////////////
978
+ //Martin Marchetta
979
+ else if(this.dom.resize !== null) {
980
+ var i;
981
+ var j;
982
+ var currentColumn;
983
+ var nextVisibleColumnIndex;
984
+ var previousVisibleColumnIndex;
985
+ var scrollXEnabled;
986
+
987
+ //Re-enable column sorting
988
+ this.s.dt.aoColumns[colResized].bSortable = true;
989
+
990
+ //Save the new resized column's width
991
+ this.s.dt.aoColumns[colResized].sWidth = $(this.s.mouse.resizeElem).innerWidth() + "px";
992
+
993
+ //If other columns might have changed their size, save their size too
994
+ scrollXEnabled = this.s.dt.oInit.sScrollX === "" ? false:true;
995
+ if(!scrollXEnabled){
996
+ //The colResized index (internal model) here might not match the visible index since some columns might have been hidden
997
+ for(nextVisibleColumnIndex=colResized+1; nextVisibleColumnIndex < this.s.dt.aoColumns.length; nextVisibleColumnIndex++){
998
+ if(this.s.dt.aoColumns[nextVisibleColumnIndex].bVisible)
999
+ break;
1000
+ }
1001
+
1002
+ for(previousVisibleColumnIndex=colResized-1; previousVisibleColumnIndex >= 0; previousVisibleColumnIndex--){
1003
+ if(this.s.dt.aoColumns[previousVisibleColumnIndex].bVisible)
1004
+ break;
1005
+ }
1006
+
1007
+ if(this.s.dt.aoColumns.length > nextVisibleColumnIndex)
1008
+ this.s.dt.aoColumns[nextVisibleColumnIndex].sWidth = $(this.s.mouse.resizeElem).next().innerWidth() + "px";
1009
+ else{ //The column resized is the right-most, so save the sizes of all the columns at the left
1010
+ currentColumn = this.s.mouse.resizeElem;
1011
+ for(i = previousVisibleColumnIndex; i > 0; i--){
1012
+ if(this.s.dt.aoColumns[i].bVisible){
1013
+ currentColumn = $(currentColumn).prev();
1014
+ this.s.dt.aoColumns[i].sWidth = $(currentColumn).innerWidth() + "px";
1015
+ }
1016
+ }
1017
+ }
1018
+ }
1019
+
1020
+ //Update the internal storage of the table's width (in case we changed it because the user resized some column and scrollX was enabled
1021
+ if(scrollXEnabled && $('div.dataTables_scrollHead', this.s.dt.nTableWrapper) != undefined){
1022
+ if($('div.dataTables_scrollHead', this.s.dt.nTableWrapper).length > 0)
1023
+ this.table_size = $($('div.dataTables_scrollHead', this.s.dt.nTableWrapper)[0].childNodes[0].childNodes[0]).width();
1024
+ }
1025
+
1026
+ //Save the state
1027
+ this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
1028
+ }
1029
+ ///////////////////////////////////////////////////////
1030
+
1031
+ this.dom.resize = null;
1032
+ },
1033
+
1034
+
1035
+ /**
1036
+ * Copy the TH element that is being drags so the user has the idea that they are actually
1037
+ * moving it around the page.
1038
+ * @method _fnCreateDragNode
1039
+ * @returns void
1040
+ * @private
1041
+ */
1042
+ "_fnCreateDragNode": function ()
1043
+ {
1044
+ var that = this;
1045
+
1046
+ this.dom.drag = $(this.s.dt.nTHead.parentNode).clone(true)[0];
1047
+ this.dom.drag.className += " DTCR_clonedTable";
1048
+ while ( this.dom.drag.getElementsByTagName('caption').length > 0 )
1049
+ {
1050
+ this.dom.drag.removeChild( this.dom.drag.getElementsByTagName('caption')[0] );
1051
+ }
1052
+ while ( this.dom.drag.getElementsByTagName('tbody').length > 0 )
1053
+ {
1054
+ this.dom.drag.removeChild( this.dom.drag.getElementsByTagName('tbody')[0] );
1055
+ }
1056
+ while ( this.dom.drag.getElementsByTagName('tfoot').length > 0 )
1057
+ {
1058
+ this.dom.drag.removeChild( this.dom.drag.getElementsByTagName('tfoot')[0] );
1059
+ }
1060
+
1061
+ $('thead tr:eq(0)', this.dom.drag).each( function () {
1062
+ $('th:not(:eq('+that.s.mouse.targetIndex+'))', this).remove();
1063
+ } );
1064
+ $('tr', this.dom.drag).height( $('tr:eq(0)', that.s.dt.nTHead).height() );
1065
+
1066
+ $('thead tr:gt(0)', this.dom.drag).remove();
1067
+
1068
+ $('thead th:eq(0)', this.dom.drag).each( function (i) {
1069
+ this.style.width = $('th:eq('+that.s.mouse.targetIndex+')', that.s.dt.nTHead).width()+"px";
1070
+ } );
1071
+
1072
+ this.dom.drag.style.position = "absolute";
1073
+ this.dom.drag.style.zIndex = 1200;
1074
+ this.dom.drag.style.top = "0px";
1075
+ this.dom.drag.style.left = "0px";
1076
+ this.dom.drag.style.width = $('th:eq('+that.s.mouse.targetIndex+')', that.s.dt.nTHead).outerWidth()+"px";
1077
+
1078
+
1079
+ this.dom.pointer = document.createElement( 'div' );
1080
+ this.dom.pointer.className = "DTCR_pointer";
1081
+ this.dom.pointer.style.position = "absolute";
1082
+
1083
+ if ( this.s.dt.oScroll.sX === "" && this.s.dt.oScroll.sY === "" )
1084
+ {
1085
+ this.dom.pointer.style.top = $(this.s.dt.nTable).offset().top+"px";
1086
+ this.dom.pointer.style.height = $(this.s.dt.nTable).height()+"px";
1087
+ }
1088
+ else
1089
+ {
1090
+ this.dom.pointer.style.top = $('div.dataTables_scroll', this.s.dt.nTableWrapper).offset().top+"px";
1091
+ this.dom.pointer.style.height = $('div.dataTables_scroll', this.s.dt.nTableWrapper).height()+"px";
1092
+ }
1093
+
1094
+ document.body.appendChild( this.dom.pointer );
1095
+ document.body.appendChild( this.dom.drag );
1096
+ },
1097
+
1098
+ /**
1099
+ * Clean up ColReorder memory references and event handlers
1100
+ * @method _fnDestroy
1101
+ * @returns void
1102
+ * @private
1103
+ */
1104
+ "_fnDestroy": function ()
1105
+ {
1106
+ for ( var i=0, iLen=ColReorder.aoInstances.length ; i<iLen ; i++ )
1107
+ {
1108
+ if ( ColReorder.aoInstances[i] === this )
1109
+ {
1110
+ ColReorder.aoInstances.splice( i, 1 );
1111
+ break;
1112
+ }
1113
+ }
1114
+
1115
+ $(this.s.dt.nTHead).find( '*' ).unbind( '.ColReorder' );
1116
+
1117
+ this.s.dt.oInstance._oPluginColReorder = null;
1118
+ this.s = null;
1119
+ }
1120
+ };
1121
+
1122
+
1123
+
1124
+
1125
+
1126
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1127
+ * Static parameters
1128
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1129
+
1130
+ /**
1131
+ * Array of all ColReorder instances for later reference
1132
+ * @property ColReorder.aoInstances
1133
+ * @type array
1134
+ * @default []
1135
+ * @static
1136
+ */
1137
+ ColReorder.aoInstances = [];
1138
+
1139
+
1140
+
1141
+
1142
+
1143
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1144
+ * Static functions
1145
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1146
+
1147
+ /**
1148
+ * Reset the column ordering for a DataTables instance
1149
+ * @method ColReorder.fnReset
1150
+ * @param object oTable DataTables instance to consider
1151
+ * @returns void
1152
+ * @static
1153
+ */
1154
+ ColReorder.fnReset = function ( oTable )
1155
+ {
1156
+ for ( var i=0, iLen=ColReorder.aoInstances.length ; i<iLen ; i++ )
1157
+ {
1158
+ if ( ColReorder.aoInstances[i].s.dt.oInstance == oTable )
1159
+ {
1160
+ ColReorder.aoInstances[i].fnReset();
1161
+ }
1162
+ }
1163
+ };
1164
+
1165
+
1166
+
1167
+
1168
+
1169
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1170
+ * Constants
1171
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1172
+
1173
+ /**
1174
+ * Name of this class
1175
+ * @constant CLASS
1176
+ * @type String
1177
+ * @default ColReorder
1178
+ */
1179
+ ColReorder.prototype.CLASS = "ColReorder";
1180
+
1181
+
1182
+ /**
1183
+ * ColReorder version
1184
+ * @constant VERSION
1185
+ * @type String
1186
+ * @default As code
1187
+ */
1188
+ ColReorder.VERSION = "1.0.7";
1189
+ ColReorder.prototype.VERSION = ColReorder.VERSION;
1190
+
1191
+
1192
+
1193
+
1194
+
1195
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1196
+ * Initialisation
1197
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1198
+
1199
+ /*
1200
+ * Register a new feature with DataTables
1201
+ */
1202
+ if ( typeof $.fn.dataTable == "function" &&
1203
+ typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
1204
+ $.fn.dataTableExt.fnVersionCheck('1.9.3') )
1205
+ {
1206
+ $.fn.dataTableExt.aoFeatures.push( {
1207
+ "fnInit": function( oDTSettings ) {
1208
+ var oTable = oDTSettings.oInstance;
1209
+ if ( typeof oTable._oPluginColReorder == 'undefined' ) {
1210
+ var opts = typeof oDTSettings.oInit.oColReorder != 'undefined' ?
1211
+ oDTSettings.oInit.oColReorder : {};
1212
+ oTable._oPluginColReorder = new ColReorder( oDTSettings, opts );
1213
+ } else {
1214
+ oTable.oApi._fnLog( oDTSettings, 1, "ColReorder attempted to initialise twice. Ignoring second" );
1215
+ }
1216
+
1217
+ return null; /* No node to insert */
1218
+ },
1219
+ "cFeature": "R",
1220
+ "sFeature": "ColReorder"
1221
+ } );
1222
+ }
1223
+ else
1224
+ {
1225
+ alert( "Warning: ColReorder requires DataTables 1.9.3 or greater - www.datatables.net/download");
1226
+ }
1227
+
1228
+ })(jQuery, window, document);