naf 1.1.4 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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);