jquery-datatables 1.10.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +27 -0
  5. data/README.md +118 -0
  6. data/Rakefile +166 -0
  7. data/app/assets/images/datatables/sort_asc.png +0 -0
  8. data/app/assets/images/datatables/sort_asc_disabled.png +0 -0
  9. data/app/assets/images/datatables/sort_both.png +0 -0
  10. data/app/assets/images/datatables/sort_desc.png +0 -0
  11. data/app/assets/images/datatables/sort_desc_disabled.png +0 -0
  12. data/app/assets/javascripts/datatables/dataTables.bootstrap.js +182 -0
  13. data/app/assets/javascripts/datatables/dataTables.bootstrap4.js +184 -0
  14. data/app/assets/javascripts/datatables/dataTables.foundation.js +174 -0
  15. data/app/assets/javascripts/datatables/dataTables.jqueryui.js +164 -0
  16. data/app/assets/javascripts/datatables/dataTables.material.js +191 -0
  17. data/app/assets/javascripts/datatables/dataTables.semanticui.js +208 -0
  18. data/app/assets/javascripts/datatables/dataTables.uikit.js +176 -0
  19. data/app/assets/javascripts/datatables/extensions/AutoFill/autoFill.bootstrap.js +43 -0
  20. data/app/assets/javascripts/datatables/extensions/AutoFill/autoFill.bootstrap4.js +43 -0
  21. data/app/assets/javascripts/datatables/extensions/AutoFill/autoFill.foundation.js +43 -0
  22. data/app/assets/javascripts/datatables/extensions/AutoFill/autoFill.jqueryui.js +43 -0
  23. data/app/assets/javascripts/datatables/extensions/AutoFill/autoFill.semanticui.js +43 -0
  24. data/app/assets/javascripts/datatables/extensions/AutoFill/dataTables.autoFill.js +1036 -0
  25. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.bootstrap.js +68 -0
  26. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.bootstrap4.js +60 -0
  27. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.colVis.js +199 -0
  28. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.flash.js +1325 -0
  29. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.foundation.js +85 -0
  30. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.html5.js +1322 -0
  31. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.jqueryui.js +62 -0
  32. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.print.js +172 -0
  33. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.semanticui.js +57 -0
  34. data/app/assets/javascripts/datatables/extensions/Buttons/dataTables.buttons.js +1634 -0
  35. data/app/assets/javascripts/datatables/extensions/ColReorder/dataTables.colReorder.js +1335 -0
  36. data/app/assets/javascripts/datatables/extensions/FixedColumns/dataTables.fixedColumns.js +1623 -0
  37. data/app/assets/javascripts/datatables/extensions/FixedHeader/dataTables.fixedHeader.js +672 -0
  38. data/app/assets/javascripts/datatables/extensions/KeyTable/dataTables.keyTable.js +883 -0
  39. data/app/assets/javascripts/datatables/extensions/Responsive/dataTables.responsive.js +1232 -0
  40. data/app/assets/javascripts/datatables/extensions/Responsive/responsive.bootstrap.js +81 -0
  41. data/app/assets/javascripts/datatables/extensions/Responsive/responsive.bootstrap4.js +81 -0
  42. data/app/assets/javascripts/datatables/extensions/Responsive/responsive.foundation.js +62 -0
  43. data/app/assets/javascripts/datatables/extensions/Responsive/responsive.jqueryui.js +63 -0
  44. data/app/assets/javascripts/datatables/extensions/Responsive/responsive.semanticui.js +77 -0
  45. data/app/assets/javascripts/datatables/extensions/RowReorder/dataTables.rowReorder.js +709 -0
  46. data/app/assets/javascripts/datatables/extensions/Scroller/dataTables.scroller.js +1349 -0
  47. data/app/assets/javascripts/datatables/extensions/Select/dataTables.select.js +1109 -0
  48. data/app/assets/javascripts/datatables/jquery.dataTables.js +15278 -0
  49. data/app/assets/media/swf/flashExport.swf +0 -0
  50. data/app/assets/stylesheets/datatables/dataTables.bootstrap.css +185 -0
  51. data/app/assets/stylesheets/datatables/dataTables.bootstrap4.css +193 -0
  52. data/app/assets/stylesheets/datatables/dataTables.foundation.css +116 -0
  53. data/app/assets/stylesheets/datatables/dataTables.jqueryui.css +481 -0
  54. data/app/assets/stylesheets/datatables/dataTables.material.css +87 -0
  55. data/app/assets/stylesheets/datatables/dataTables.semanticui.css +103 -0
  56. data/app/assets/stylesheets/datatables/dataTables.uikit.css +146 -0
  57. data/app/assets/stylesheets/datatables/extensions/AutoFill/autoFill.bootstrap.css +81 -0
  58. data/app/assets/stylesheets/datatables/extensions/AutoFill/autoFill.bootstrap4.css +81 -0
  59. data/app/assets/stylesheets/datatables/extensions/AutoFill/autoFill.dataTables.css +92 -0
  60. data/app/assets/stylesheets/datatables/extensions/AutoFill/autoFill.foundation.css +85 -0
  61. data/app/assets/stylesheets/datatables/extensions/AutoFill/autoFill.jqueryui.css +85 -0
  62. data/app/assets/stylesheets/datatables/extensions/AutoFill/autoFill.semanticui.css +81 -0
  63. data/app/assets/stylesheets/datatables/extensions/Buttons/buttons.bootstrap.css +102 -0
  64. data/app/assets/stylesheets/datatables/extensions/Buttons/buttons.bootstrap4.css +163 -0
  65. data/app/assets/stylesheets/datatables/extensions/Buttons/buttons.dataTables.css +298 -0
  66. data/app/assets/stylesheets/datatables/extensions/Buttons/buttons.foundation.css +129 -0
  67. data/app/assets/stylesheets/datatables/extensions/Buttons/buttons.jqueryui.css +162 -0
  68. data/app/assets/stylesheets/datatables/extensions/Buttons/buttons.semanticui.css +114 -0
  69. data/app/assets/stylesheets/datatables/extensions/Buttons/common.scss +27 -0
  70. data/app/assets/stylesheets/datatables/extensions/Buttons/mixins.scss +89 -0
  71. data/app/assets/stylesheets/datatables/extensions/ColReorder/colReorder.bootstrap.css +11 -0
  72. data/app/assets/stylesheets/datatables/extensions/ColReorder/colReorder.bootstrap4.css +11 -0
  73. data/app/assets/stylesheets/datatables/extensions/ColReorder/colReorder.dataTables.css +11 -0
  74. data/app/assets/stylesheets/datatables/extensions/ColReorder/colReorder.foundation.css +11 -0
  75. data/app/assets/stylesheets/datatables/extensions/ColReorder/colReorder.jqueryui.css +11 -0
  76. data/app/assets/stylesheets/datatables/extensions/ColReorder/colReorder.semanticui.css +11 -0
  77. data/app/assets/stylesheets/datatables/extensions/FixedColumns/fixedColumns.bootstrap.css +44 -0
  78. data/app/assets/stylesheets/datatables/extensions/FixedColumns/fixedColumns.bootstrap4.css +44 -0
  79. data/app/assets/stylesheets/datatables/extensions/FixedColumns/fixedColumns.dataTables.css +18 -0
  80. data/app/assets/stylesheets/datatables/extensions/FixedColumns/fixedColumns.foundation.css +27 -0
  81. data/app/assets/stylesheets/datatables/extensions/FixedColumns/fixedColumns.jqueryui.css +8 -0
  82. data/app/assets/stylesheets/datatables/extensions/FixedColumns/fixedColumns.semanticui.css +16 -0
  83. data/app/assets/stylesheets/datatables/extensions/FixedHeader/fixedHeader.bootstrap.css +20 -0
  84. data/app/assets/stylesheets/datatables/extensions/FixedHeader/fixedHeader.bootstrap4.css +20 -0
  85. data/app/assets/stylesheets/datatables/extensions/FixedHeader/fixedHeader.dataTables.css +19 -0
  86. data/app/assets/stylesheets/datatables/extensions/FixedHeader/fixedHeader.foundation.css +20 -0
  87. data/app/assets/stylesheets/datatables/extensions/FixedHeader/fixedHeader.jqueryui.css +15 -0
  88. data/app/assets/stylesheets/datatables/extensions/FixedHeader/fixedHeader.semanticui.css +14 -0
  89. data/app/assets/stylesheets/datatables/extensions/KeyTable/keyTable.bootstrap.css +5 -0
  90. data/app/assets/stylesheets/datatables/extensions/KeyTable/keyTable.bootstrap4.css +5 -0
  91. data/app/assets/stylesheets/datatables/extensions/KeyTable/keyTable.dataTables.css +5 -0
  92. data/app/assets/stylesheets/datatables/extensions/KeyTable/keyTable.foundation.css +5 -0
  93. data/app/assets/stylesheets/datatables/extensions/KeyTable/keyTable.jqueryui.css +5 -0
  94. data/app/assets/stylesheets/datatables/extensions/KeyTable/keyTable.semanticui.css +5 -0
  95. data/app/assets/stylesheets/datatables/extensions/Responsive/responsive.bootstrap.css +181 -0
  96. data/app/assets/stylesheets/datatables/extensions/Responsive/responsive.bootstrap4.css +181 -0
  97. data/app/assets/stylesheets/datatables/extensions/Responsive/responsive.dataTables.css +178 -0
  98. data/app/assets/stylesheets/datatables/extensions/Responsive/responsive.foundation.css +181 -0
  99. data/app/assets/stylesheets/datatables/extensions/Responsive/responsive.jqueryui.css +178 -0
  100. data/app/assets/stylesheets/datatables/extensions/Responsive/responsive.semanticui.css +181 -0
  101. data/app/assets/stylesheets/datatables/extensions/RowReorder/rowReorder.bootstrap.css +22 -0
  102. data/app/assets/stylesheets/datatables/extensions/RowReorder/rowReorder.bootstrap4.css +22 -0
  103. data/app/assets/stylesheets/datatables/extensions/RowReorder/rowReorder.dataTables.css +22 -0
  104. data/app/assets/stylesheets/datatables/extensions/RowReorder/rowReorder.foundation.css +22 -0
  105. data/app/assets/stylesheets/datatables/extensions/RowReorder/rowReorder.jqueryui.css +22 -0
  106. data/app/assets/stylesheets/datatables/extensions/RowReorder/rowReorder.semanticui.css +22 -0
  107. data/app/assets/stylesheets/datatables/extensions/RowReorder/semanticui.scss +5 -0
  108. data/app/assets/stylesheets/datatables/extensions/Scroller/scroller.bootstrap.css +24 -0
  109. data/app/assets/stylesheets/datatables/extensions/Scroller/scroller.bootstrap4.css +24 -0
  110. data/app/assets/stylesheets/datatables/extensions/Scroller/scroller.dataTables.css +20 -0
  111. data/app/assets/stylesheets/datatables/extensions/Scroller/scroller.foundation.css +17 -0
  112. data/app/assets/stylesheets/datatables/extensions/Scroller/scroller.jqueryui.css +20 -0
  113. data/app/assets/stylesheets/datatables/extensions/Scroller/scroller.semanticui.css +20 -0
  114. data/app/assets/stylesheets/datatables/extensions/Select/select.bootstrap.css +110 -0
  115. data/app/assets/stylesheets/datatables/extensions/Select/select.bootstrap4.css +110 -0
  116. data/app/assets/stylesheets/datatables/extensions/Select/select.dataTables.css +100 -0
  117. data/app/assets/stylesheets/datatables/extensions/Select/select.foundation.css +112 -0
  118. data/app/assets/stylesheets/datatables/extensions/Select/select.jqueryui.css +100 -0
  119. data/app/assets/stylesheets/datatables/extensions/Select/select.semanticui.css +105 -0
  120. data/app/assets/stylesheets/datatables/jquery.dataTables.css +452 -0
  121. data/app/assets/stylesheets/datatables/jquery.dataTables_themeroller.css +416 -0
  122. data/jquery-datatables.gemspec +27 -0
  123. data/lib/generators/jquery/datatables/install_generator.rb +63 -0
  124. data/lib/generators/jquery/datatables/templates/bootstrap.css.tt +15 -0
  125. data/lib/generators/jquery/datatables/templates/bootstrap.js.tt +22 -0
  126. data/lib/generators/jquery/datatables/templates/bootstrap4.css.tt +15 -0
  127. data/lib/generators/jquery/datatables/templates/bootstrap4.js.tt +22 -0
  128. data/lib/generators/jquery/datatables/templates/foundation.css.tt +15 -0
  129. data/lib/generators/jquery/datatables/templates/foundation.js.tt +24 -0
  130. data/lib/generators/jquery/datatables/templates/jqueryui.css.tt +15 -0
  131. data/lib/generators/jquery/datatables/templates/jqueryui.js.tt +18 -0
  132. data/lib/generators/jquery/datatables/templates/material.css.tt +15 -0
  133. data/lib/generators/jquery/datatables/templates/material.js.tt +19 -0
  134. data/lib/generators/jquery/datatables/templates/regular.css.tt +15 -0
  135. data/lib/generators/jquery/datatables/templates/regular.js.tt +18 -0
  136. data/lib/generators/jquery/datatables/templates/semanticui.css.tt +16 -0
  137. data/lib/generators/jquery/datatables/templates/semanticui.js.tt +22 -0
  138. data/lib/generators/jquery/datatables/templates/uikit.css.tt +15 -0
  139. data/lib/generators/jquery/datatables/templates/uikit.js.tt +19 -0
  140. data/lib/jquery-datatables.rb +26 -0
  141. data/lib/jquery-datatables/engine.rb +11 -0
  142. data/lib/jquery-datatables/version.rb +6 -0
  143. metadata +269 -0
@@ -0,0 +1,1349 @@
1
+ /*! Scroller 1.4.2
2
+ * ©2011-2016 SpryMedia Ltd - datatables.net/license
3
+ */
4
+
5
+ /**
6
+ * @summary Scroller
7
+ * @description Virtual rendering for DataTables
8
+ * @version 1.4.2
9
+ * @file dataTables.scroller.js
10
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
11
+ * @contact www.sprymedia.co.uk/contact
12
+ * @copyright Copyright 2011-2016 SpryMedia Ltd.
13
+ *
14
+ * This source file is free software, available under the following license:
15
+ * MIT license - http://datatables.net/license/mit
16
+ *
17
+ * This source file is distributed in the hope that it will be useful, but
18
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
20
+ *
21
+ * For details please refer to: http://www.datatables.net
22
+ */
23
+
24
+ (function( factory ){
25
+ if ( typeof define === 'function' && define.amd ) {
26
+ // AMD
27
+ define( ['jquery', 'datatables.net'], function ( $ ) {
28
+ return factory( $, window, document );
29
+ } );
30
+ }
31
+ else if ( typeof exports === 'object' ) {
32
+ // CommonJS
33
+ module.exports = function (root, $) {
34
+ if ( ! root ) {
35
+ root = window;
36
+ }
37
+
38
+ if ( ! $ || ! $.fn.dataTable ) {
39
+ $ = require('datatables.net')(root, $).$;
40
+ }
41
+
42
+ return factory( $, root, root.document );
43
+ };
44
+ }
45
+ else {
46
+ // Browser
47
+ factory( jQuery, window, document );
48
+ }
49
+ }(function( $, window, document, undefined ) {
50
+ 'use strict';
51
+ var DataTable = $.fn.dataTable;
52
+
53
+
54
+ /**
55
+ * Scroller is a virtual rendering plug-in for DataTables which allows large
56
+ * datasets to be drawn on screen every quickly. What the virtual rendering means
57
+ * is that only the visible portion of the table (and a bit to either side to make
58
+ * the scrolling smooth) is drawn, while the scrolling container gives the
59
+ * visual impression that the whole table is visible. This is done by making use
60
+ * of the pagination abilities of DataTables and moving the table around in the
61
+ * scrolling container DataTables adds to the page. The scrolling container is
62
+ * forced to the height it would be for the full table display using an extra
63
+ * element.
64
+ *
65
+ * Note that rows in the table MUST all be the same height. Information in a cell
66
+ * which expands on to multiple lines will cause some odd behaviour in the scrolling.
67
+ *
68
+ * Scroller is initialised by simply including the letter 'S' in the sDom for the
69
+ * table you want to have this feature enabled on. Note that the 'S' must come
70
+ * AFTER the 't' parameter in `dom`.
71
+ *
72
+ * Key features include:
73
+ * <ul class="limit_length">
74
+ * <li>Speed! The aim of Scroller for DataTables is to make rendering large data sets fast</li>
75
+ * <li>Full compatibility with deferred rendering in DataTables for maximum speed</li>
76
+ * <li>Display millions of rows</li>
77
+ * <li>Integration with state saving in DataTables (scrolling position is saved)</li>
78
+ * <li>Easy to use</li>
79
+ * </ul>
80
+ *
81
+ * @class
82
+ * @constructor
83
+ * @global
84
+ * @param {object} dt DataTables settings object or API instance
85
+ * @param {object} [opts={}] Configuration object for FixedColumns. Options
86
+ * are defined by {@link Scroller.defaults}
87
+ *
88
+ * @requires jQuery 1.7+
89
+ * @requires DataTables 1.10.0+
90
+ *
91
+ * @example
92
+ * $(document).ready(function() {
93
+ * $('#example').DataTable( {
94
+ * "scrollY": "200px",
95
+ * "ajax": "media/dataset/large.txt",
96
+ * "dom": "frtiS",
97
+ * "deferRender": true
98
+ * } );
99
+ * } );
100
+ */
101
+ var Scroller = function ( dt, opts ) {
102
+ /* Sanity check - you just know it will happen */
103
+ if ( ! (this instanceof Scroller) ) {
104
+ alert( "Scroller warning: Scroller must be initialised with the 'new' keyword." );
105
+ return;
106
+ }
107
+
108
+ if ( opts === undefined ) {
109
+ opts = {};
110
+ }
111
+
112
+ /**
113
+ * Settings object which contains customisable information for the Scroller instance
114
+ * @namespace
115
+ * @private
116
+ * @extends Scroller.defaults
117
+ */
118
+ this.s = {
119
+ /**
120
+ * DataTables settings object
121
+ * @type object
122
+ * @default Passed in as first parameter to constructor
123
+ */
124
+ "dt": $.fn.dataTable.Api( dt ).settings()[0],
125
+
126
+ /**
127
+ * Pixel location of the top of the drawn table in the viewport
128
+ * @type int
129
+ * @default 0
130
+ */
131
+ "tableTop": 0,
132
+
133
+ /**
134
+ * Pixel location of the bottom of the drawn table in the viewport
135
+ * @type int
136
+ * @default 0
137
+ */
138
+ "tableBottom": 0,
139
+
140
+ /**
141
+ * Pixel location of the boundary for when the next data set should be loaded and drawn
142
+ * when scrolling up the way.
143
+ * @type int
144
+ * @default 0
145
+ * @private
146
+ */
147
+ "redrawTop": 0,
148
+
149
+ /**
150
+ * Pixel location of the boundary for when the next data set should be loaded and drawn
151
+ * when scrolling down the way. Note that this is actually calculated as the offset from
152
+ * the top.
153
+ * @type int
154
+ * @default 0
155
+ * @private
156
+ */
157
+ "redrawBottom": 0,
158
+
159
+ /**
160
+ * Auto row height or not indicator
161
+ * @type bool
162
+ * @default 0
163
+ */
164
+ "autoHeight": true,
165
+
166
+ /**
167
+ * Number of rows calculated as visible in the visible viewport
168
+ * @type int
169
+ * @default 0
170
+ */
171
+ "viewportRows": 0,
172
+
173
+ /**
174
+ * setTimeout reference for state saving, used when state saving is enabled in the DataTable
175
+ * and when the user scrolls the viewport in order to stop the cookie set taking too much
176
+ * CPU!
177
+ * @type int
178
+ * @default 0
179
+ */
180
+ "stateTO": null,
181
+
182
+ /**
183
+ * setTimeout reference for the redraw, used when server-side processing is enabled in the
184
+ * DataTables in order to prevent DoSing the server
185
+ * @type int
186
+ * @default null
187
+ */
188
+ "drawTO": null,
189
+
190
+ heights: {
191
+ jump: null,
192
+ page: null,
193
+ virtual: null,
194
+ scroll: null,
195
+
196
+ /**
197
+ * Height of rows in the table
198
+ * @type int
199
+ * @default 0
200
+ */
201
+ row: null,
202
+
203
+ /**
204
+ * Pixel height of the viewport
205
+ * @type int
206
+ * @default 0
207
+ */
208
+ viewport: null
209
+ },
210
+
211
+ topRowFloat: 0,
212
+ scrollDrawDiff: null,
213
+ loaderVisible: false
214
+ };
215
+
216
+ // @todo The defaults should extend a `c` property and the internal settings
217
+ // only held in the `s` property. At the moment they are mixed
218
+ this.s = $.extend( this.s, Scroller.oDefaults, opts );
219
+
220
+ // Workaround for row height being read from height object (see above comment)
221
+ this.s.heights.row = this.s.rowHeight;
222
+
223
+ /**
224
+ * DOM elements used by the class instance
225
+ * @private
226
+ * @namespace
227
+ *
228
+ */
229
+ this.dom = {
230
+ "force": document.createElement('div'),
231
+ "scroller": null,
232
+ "table": null,
233
+ "loader": null
234
+ };
235
+
236
+ // Attach the instance to the DataTables instance so it can be accessed in
237
+ // future. Don't initialise Scroller twice on the same table
238
+ if ( this.s.dt.oScroller ) {
239
+ return;
240
+ }
241
+
242
+ this.s.dt.oScroller = this;
243
+
244
+ /* Let's do it */
245
+ this._fnConstruct();
246
+ };
247
+
248
+
249
+
250
+ $.extend( Scroller.prototype, {
251
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
252
+ * Public methods
253
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
254
+
255
+ /**
256
+ * Calculate the pixel position from the top of the scrolling container for
257
+ * a given row
258
+ * @param {int} iRow Row number to calculate the position of
259
+ * @returns {int} Pixels
260
+ * @example
261
+ * $(document).ready(function() {
262
+ * $('#example').dataTable( {
263
+ * "sScrollY": "200px",
264
+ * "sAjaxSource": "media/dataset/large.txt",
265
+ * "sDom": "frtiS",
266
+ * "bDeferRender": true,
267
+ * "fnInitComplete": function (o) {
268
+ * // Find where row 25 is
269
+ * alert( o.oScroller.fnRowToPixels( 25 ) );
270
+ * }
271
+ * } );
272
+ * } );
273
+ */
274
+ "fnRowToPixels": function ( rowIdx, intParse, virtual )
275
+ {
276
+ var pixels;
277
+
278
+ if ( virtual ) {
279
+ pixels = this._domain( 'virtualToPhysical', rowIdx * this.s.heights.row );
280
+ }
281
+ else {
282
+ var diff = rowIdx - this.s.baseRowTop;
283
+ pixels = this.s.baseScrollTop + (diff * this.s.heights.row);
284
+ }
285
+
286
+ return intParse || intParse === undefined ?
287
+ parseInt( pixels, 10 ) :
288
+ pixels;
289
+ },
290
+
291
+
292
+ /**
293
+ * Calculate the row number that will be found at the given pixel position
294
+ * (y-scroll).
295
+ *
296
+ * Please note that when the height of the full table exceeds 1 million
297
+ * pixels, Scroller switches into a non-linear mode for the scrollbar to fit
298
+ * all of the records into a finite area, but this function returns a linear
299
+ * value (relative to the last non-linear positioning).
300
+ * @param {int} iPixels Offset from top to calculate the row number of
301
+ * @param {int} [intParse=true] If an integer value should be returned
302
+ * @param {int} [virtual=false] Perform the calculations in the virtual domain
303
+ * @returns {int} Row index
304
+ * @example
305
+ * $(document).ready(function() {
306
+ * $('#example').dataTable( {
307
+ * "sScrollY": "200px",
308
+ * "sAjaxSource": "media/dataset/large.txt",
309
+ * "sDom": "frtiS",
310
+ * "bDeferRender": true,
311
+ * "fnInitComplete": function (o) {
312
+ * // Find what row number is at 500px
313
+ * alert( o.oScroller.fnPixelsToRow( 500 ) );
314
+ * }
315
+ * } );
316
+ * } );
317
+ */
318
+ "fnPixelsToRow": function ( pixels, intParse, virtual )
319
+ {
320
+ var diff = pixels - this.s.baseScrollTop;
321
+ var row = virtual ?
322
+ this._domain( 'physicalToVirtual', pixels ) / this.s.heights.row :
323
+ ( diff / this.s.heights.row ) + this.s.baseRowTop;
324
+
325
+ return intParse || intParse === undefined ?
326
+ parseInt( row, 10 ) :
327
+ row;
328
+ },
329
+
330
+
331
+ /**
332
+ * Calculate the row number that will be found at the given pixel position (y-scroll)
333
+ * @param {int} iRow Row index to scroll to
334
+ * @param {bool} [bAnimate=true] Animate the transition or not
335
+ * @returns {void}
336
+ * @example
337
+ * $(document).ready(function() {
338
+ * $('#example').dataTable( {
339
+ * "sScrollY": "200px",
340
+ * "sAjaxSource": "media/dataset/large.txt",
341
+ * "sDom": "frtiS",
342
+ * "bDeferRender": true,
343
+ * "fnInitComplete": function (o) {
344
+ * // Immediately scroll to row 1000
345
+ * o.oScroller.fnScrollToRow( 1000 );
346
+ * }
347
+ * } );
348
+ *
349
+ * // Sometime later on use the following to scroll to row 500...
350
+ * var oSettings = $('#example').dataTable().fnSettings();
351
+ * oSettings.oScroller.fnScrollToRow( 500 );
352
+ * } );
353
+ */
354
+ "fnScrollToRow": function ( iRow, bAnimate )
355
+ {
356
+ var that = this;
357
+ var ani = false;
358
+ var px = this.fnRowToPixels( iRow );
359
+
360
+ // We need to know if the table will redraw or not before doing the
361
+ // scroll. If it will not redraw, then we need to use the currently
362
+ // displayed table, and scroll with the physical pixels. Otherwise, we
363
+ // need to calculate the table's new position from the virtual
364
+ // transform.
365
+ var preRows = ((this.s.displayBuffer-1)/2) * this.s.viewportRows;
366
+ var drawRow = iRow - preRows;
367
+ if ( drawRow < 0 ) {
368
+ drawRow = 0;
369
+ }
370
+
371
+ if ( (px > this.s.redrawBottom || px < this.s.redrawTop) && this.s.dt._iDisplayStart !== drawRow ) {
372
+ ani = true;
373
+ px = this.fnRowToPixels( iRow, false, true );
374
+ }
375
+
376
+ if ( typeof bAnimate == 'undefined' || bAnimate )
377
+ {
378
+ this.s.ani = ani;
379
+ $(this.dom.scroller).animate( {
380
+ "scrollTop": px
381
+ }, function () {
382
+ // This needs to happen after the animation has completed and
383
+ // the final scroll event fired
384
+ setTimeout( function () {
385
+ that.s.ani = false;
386
+ }, 25 );
387
+ } );
388
+ }
389
+ else
390
+ {
391
+ $(this.dom.scroller).scrollTop( px );
392
+ }
393
+ },
394
+
395
+
396
+ /**
397
+ * Calculate and store information about how many rows are to be displayed
398
+ * in the scrolling viewport, based on current dimensions in the browser's
399
+ * rendering. This can be particularly useful if the table is initially
400
+ * drawn in a hidden element - for example in a tab.
401
+ * @param {bool} [bRedraw=true] Redraw the table automatically after the recalculation, with
402
+ * the new dimensions forming the basis for the draw.
403
+ * @returns {void}
404
+ * @example
405
+ * $(document).ready(function() {
406
+ * // Make the example container hidden to throw off the browser's sizing
407
+ * document.getElementById('container').style.display = "none";
408
+ * var oTable = $('#example').dataTable( {
409
+ * "sScrollY": "200px",
410
+ * "sAjaxSource": "media/dataset/large.txt",
411
+ * "sDom": "frtiS",
412
+ * "bDeferRender": true,
413
+ * "fnInitComplete": function (o) {
414
+ * // Immediately scroll to row 1000
415
+ * o.oScroller.fnScrollToRow( 1000 );
416
+ * }
417
+ * } );
418
+ *
419
+ * setTimeout( function () {
420
+ * // Make the example container visible and recalculate the scroller sizes
421
+ * document.getElementById('container').style.display = "block";
422
+ * oTable.fnSettings().oScroller.fnMeasure();
423
+ * }, 3000 );
424
+ */
425
+ "fnMeasure": function ( bRedraw )
426
+ {
427
+ if ( this.s.autoHeight )
428
+ {
429
+ this._fnCalcRowHeight();
430
+ }
431
+
432
+ var heights = this.s.heights;
433
+
434
+ if ( heights.row ) {
435
+ heights.viewport = $(this.dom.scroller).height();
436
+ this.s.viewportRows = parseInt( heights.viewport / heights.row, 10 )+1;
437
+ this.s.dt._iDisplayLength = this.s.viewportRows * this.s.displayBuffer;
438
+ }
439
+
440
+ if ( bRedraw === undefined || bRedraw )
441
+ {
442
+ this.s.dt.oInstance.fnDraw( false );
443
+ }
444
+ },
445
+
446
+
447
+ /**
448
+ * Get information about current displayed record range. This corresponds to
449
+ * the information usually displayed in the "Info" block of the table.
450
+ *
451
+ * @returns {object} info as an object:
452
+ * {
453
+ * start: {int}, // the 0-indexed record at the top of the viewport
454
+ * end: {int}, // the 0-indexed record at the bottom of the viewport
455
+ * }
456
+ */
457
+ "fnPageInfo": function()
458
+ {
459
+ var
460
+ dt = this.s.dt,
461
+ iScrollTop = this.dom.scroller.scrollTop,
462
+ iTotal = dt.fnRecordsDisplay(),
463
+ iPossibleEnd = Math.ceil(this.fnPixelsToRow(iScrollTop + this.s.heights.viewport, false, this.s.ani));
464
+
465
+ return {
466
+ start: Math.floor(this.fnPixelsToRow(iScrollTop, false, this.s.ani)),
467
+ end: iTotal < iPossibleEnd ? iTotal-1 : iPossibleEnd-1
468
+ };
469
+ },
470
+
471
+
472
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
473
+ * Private methods (they are of course public in JS, but recommended as private)
474
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
475
+
476
+ /**
477
+ * Initialisation for Scroller
478
+ * @returns {void}
479
+ * @private
480
+ */
481
+ "_fnConstruct": function ()
482
+ {
483
+ var that = this;
484
+
485
+ /* Sanity check */
486
+ if ( !this.s.dt.oFeatures.bPaginate ) {
487
+ this.s.dt.oApi._fnLog( this.s.dt, 0, 'Pagination must be enabled for Scroller' );
488
+ return;
489
+ }
490
+
491
+ /* Insert a div element that we can use to force the DT scrolling container to
492
+ * the height that would be required if the whole table was being displayed
493
+ */
494
+ this.dom.force.style.position = "relative";
495
+ this.dom.force.style.top = "0px";
496
+ this.dom.force.style.left = "0px";
497
+ this.dom.force.style.width = "1px";
498
+
499
+ this.dom.scroller = $('div.'+this.s.dt.oClasses.sScrollBody, this.s.dt.nTableWrapper)[0];
500
+ this.dom.scroller.appendChild( this.dom.force );
501
+ this.dom.scroller.style.position = "relative";
502
+
503
+ this.dom.table = $('>table', this.dom.scroller)[0];
504
+ this.dom.table.style.position = "absolute";
505
+ this.dom.table.style.top = "0px";
506
+ this.dom.table.style.left = "0px";
507
+
508
+ // Add class to 'announce' that we are a Scroller table
509
+ $(this.s.dt.nTableWrapper).addClass('DTS');
510
+
511
+ // Add a 'loading' indicator
512
+ if ( this.s.loadingIndicator )
513
+ {
514
+ this.dom.loader = $('<div class="dataTables_processing DTS_Loading">'+this.s.dt.oLanguage.sLoadingRecords+'</div>')
515
+ .css('display', 'none');
516
+
517
+ $(this.dom.scroller.parentNode)
518
+ .css('position', 'relative')
519
+ .append( this.dom.loader );
520
+ }
521
+
522
+ /* Initial size calculations */
523
+ if ( this.s.heights.row && this.s.heights.row != 'auto' )
524
+ {
525
+ this.s.autoHeight = false;
526
+ }
527
+ this.fnMeasure( false );
528
+
529
+ /* Scrolling callback to see if a page change is needed - use a throttled
530
+ * function for the save save callback so we aren't hitting it on every
531
+ * scroll
532
+ */
533
+ this.s.ingnoreScroll = true;
534
+ this.s.stateSaveThrottle = this.s.dt.oApi._fnThrottle( function () {
535
+ that.s.dt.oApi._fnSaveState( that.s.dt );
536
+ }, 500 );
537
+ $(this.dom.scroller).on( 'scroll.DTS', function (e) {
538
+ that._fnScroll.call( that );
539
+ } );
540
+
541
+ /* In iOS we catch the touchstart event in case the user tries to scroll
542
+ * while the display is already scrolling
543
+ */
544
+ $(this.dom.scroller).on('touchstart.DTS', function () {
545
+ that._fnScroll.call( that );
546
+ } );
547
+
548
+ /* Update the scroller when the DataTable is redrawn */
549
+ this.s.dt.aoDrawCallback.push( {
550
+ "fn": function () {
551
+ if ( that.s.dt.bInitialised ) {
552
+ that._fnDrawCallback.call( that );
553
+ }
554
+ },
555
+ "sName": "Scroller"
556
+ } );
557
+
558
+ /* On resize, update the information element, since the number of rows shown might change */
559
+ $(window).on( 'resize.DTS', function () {
560
+ that.fnMeasure( false );
561
+ that._fnInfo();
562
+ } );
563
+
564
+ /* Add a state saving parameter to the DT state saving so we can restore the exact
565
+ * position of the scrolling
566
+ */
567
+ var initialStateSave = true;
568
+ this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) {
569
+ /* Set iScroller to saved scroll position on initialization.
570
+ */
571
+ if(initialStateSave && that.s.dt.oLoadedState){
572
+ oData.iScroller = that.s.dt.oLoadedState.iScroller;
573
+ oData.iScrollerTopRow = that.s.dt.oLoadedState.iScrollerTopRow;
574
+ initialStateSave = false;
575
+ } else {
576
+ oData.iScroller = that.dom.scroller.scrollTop;
577
+ oData.iScrollerTopRow = that.s.topRowFloat;
578
+ }
579
+ }, "Scroller_State" );
580
+
581
+ if ( this.s.dt.oLoadedState ) {
582
+ this.s.topRowFloat = this.s.dt.oLoadedState.iScrollerTopRow || 0;
583
+ }
584
+
585
+ // Measure immediately. Scroller will have been added using preInit, so
586
+ // we can reliably do this here. We could potentially also measure on
587
+ // init complete, which would be useful for cases where the data is Ajax
588
+ // loaded and longer than a single line.
589
+ $(this.s.dt.nTable).one( 'init.dt', function () {
590
+ that.fnMeasure();
591
+ } );
592
+
593
+ /* Destructor */
594
+ this.s.dt.aoDestroyCallback.push( {
595
+ "sName": "Scroller",
596
+ "fn": function () {
597
+ $(window).off( 'resize.DTS' );
598
+ $(that.dom.scroller).off('touchstart.DTS scroll.DTS');
599
+ $(that.s.dt.nTableWrapper).removeClass('DTS');
600
+ $('div.DTS_Loading', that.dom.scroller.parentNode).remove();
601
+ $(that.s.dt.nTable).off( 'init.dt' );
602
+
603
+ that.dom.table.style.position = "";
604
+ that.dom.table.style.top = "";
605
+ that.dom.table.style.left = "";
606
+ }
607
+ } );
608
+ },
609
+
610
+
611
+ /**
612
+ * Scrolling function - fired whenever the scrolling position is changed.
613
+ * This method needs to use the stored values to see if the table should be
614
+ * redrawn as we are moving towards the end of the information that is
615
+ * currently drawn or not. If needed, then it will redraw the table based on
616
+ * the new position.
617
+ * @returns {void}
618
+ * @private
619
+ */
620
+ "_fnScroll": function ()
621
+ {
622
+ var
623
+ that = this,
624
+ heights = this.s.heights,
625
+ iScrollTop = this.dom.scroller.scrollTop,
626
+ iTopRow;
627
+
628
+ if ( this.s.skip ) {
629
+ return;
630
+ }
631
+
632
+ if ( this.s.ingnoreScroll ) {
633
+ return;
634
+ }
635
+
636
+ /* If the table has been sorted or filtered, then we use the redraw that
637
+ * DataTables as done, rather than performing our own
638
+ */
639
+ if ( this.s.dt.bFiltered || this.s.dt.bSorted ) {
640
+ this.s.lastScrollTop = 0;
641
+ return;
642
+ }
643
+
644
+ /* Update the table's information display for what is now in the viewport */
645
+ this._fnInfo();
646
+
647
+ /* We don't want to state save on every scroll event - that's heavy
648
+ * handed, so use a timeout to update the state saving only when the
649
+ * scrolling has finished
650
+ */
651
+ clearTimeout( this.s.stateTO );
652
+ this.s.stateTO = setTimeout( function () {
653
+ that.s.dt.oApi._fnSaveState( that.s.dt );
654
+ }, 250 );
655
+
656
+ /* Check if the scroll point is outside the trigger boundary which would required
657
+ * a DataTables redraw
658
+ */
659
+ if ( iScrollTop < this.s.redrawTop || iScrollTop > this.s.redrawBottom ) {
660
+ var preRows = Math.ceil( ((this.s.displayBuffer-1)/2) * this.s.viewportRows );
661
+
662
+ if ( Math.abs( iScrollTop - this.s.lastScrollTop ) > heights.viewport || this.s.ani ) {
663
+ iTopRow = parseInt(this._domain( 'physicalToVirtual', iScrollTop ) / heights.row, 10) - preRows;
664
+ this.s.topRowFloat = this._domain( 'physicalToVirtual', iScrollTop ) / heights.row;
665
+ }
666
+ else {
667
+ iTopRow = this.fnPixelsToRow( iScrollTop ) - preRows;
668
+ this.s.topRowFloat = this.fnPixelsToRow( iScrollTop, false );
669
+ }
670
+
671
+ if ( iTopRow <= 0 ) {
672
+ /* At the start of the table */
673
+ iTopRow = 0;
674
+ }
675
+ else if ( iTopRow + this.s.dt._iDisplayLength > this.s.dt.fnRecordsDisplay() ) {
676
+ /* At the end of the table */
677
+ iTopRow = this.s.dt.fnRecordsDisplay() - this.s.dt._iDisplayLength;
678
+ if ( iTopRow < 0 ) {
679
+ iTopRow = 0;
680
+ }
681
+ }
682
+ else if ( iTopRow % 2 !== 0 ) {
683
+ // For the row-striping classes (odd/even) we want only to start
684
+ // on evens otherwise the stripes will change between draws and
685
+ // look rubbish
686
+ iTopRow++;
687
+ }
688
+
689
+ if ( iTopRow != this.s.dt._iDisplayStart ) {
690
+ /* Cache the new table position for quick lookups */
691
+ this.s.tableTop = $(this.s.dt.nTable).offset().top;
692
+ this.s.tableBottom = $(this.s.dt.nTable).height() + this.s.tableTop;
693
+
694
+ var draw = function () {
695
+ if ( that.s.scrollDrawReq === null ) {
696
+ that.s.scrollDrawReq = iScrollTop;
697
+ }
698
+
699
+ that.s.dt._iDisplayStart = iTopRow;
700
+ that.s.dt.oApi._fnDraw( that.s.dt );
701
+ };
702
+
703
+ /* Do the DataTables redraw based on the calculated start point - note that when
704
+ * using server-side processing we introduce a small delay to not DoS the server...
705
+ */
706
+ if ( this.s.dt.oFeatures.bServerSide ) {
707
+ clearTimeout( this.s.drawTO );
708
+ this.s.drawTO = setTimeout( draw, this.s.serverWait );
709
+ }
710
+ else {
711
+ draw();
712
+ }
713
+
714
+ if ( this.dom.loader && ! this.s.loaderVisible ) {
715
+ this.dom.loader.css( 'display', 'block' );
716
+ this.s.loaderVisible = true;
717
+ }
718
+ }
719
+ }
720
+ else {
721
+ this.s.topRowFloat = this._domain( 'physicalToVirtual', iScrollTop ) / heights.row;
722
+ }
723
+
724
+ this.s.lastScrollTop = iScrollTop;
725
+ this.s.stateSaveThrottle();
726
+ },
727
+
728
+
729
+ /**
730
+ * Convert from one domain to another. The physical domain is the actual
731
+ * pixel count on the screen, while the virtual is if we had browsers which
732
+ * had scrolling containers of infinite height (i.e. the absolute value)
733
+ *
734
+ * @param {string} dir Domain transform direction, `virtualToPhysical` or
735
+ * `physicalToVirtual`
736
+ * @returns {number} Calculated transform
737
+ * @private
738
+ */
739
+ _domain: function ( dir, val )
740
+ {
741
+ var heights = this.s.heights;
742
+ var coeff;
743
+
744
+ // If the virtual and physical height match, then we use a linear
745
+ // transform between the two, allowing the scrollbar to be linear
746
+ if ( heights.virtual === heights.scroll ) {
747
+ return val;
748
+ }
749
+
750
+ // Otherwise, we want a non-linear scrollbar to take account of the
751
+ // redrawing regions at the start and end of the table, otherwise these
752
+ // can stutter badly - on large tables 30px (for example) scroll might
753
+ // be hundreds of rows, so the table would be redrawing every few px at
754
+ // the start and end. Use a simple quadratic to stop this. It does mean
755
+ // the scrollbar is non-linear, but with such massive data sets, the
756
+ // scrollbar is going to be a best guess anyway
757
+ var xMax = (heights.scroll - heights.viewport) / 2;
758
+ var yMax = (heights.virtual - heights.viewport) / 2;
759
+
760
+ coeff = yMax / ( xMax * xMax );
761
+
762
+ if ( dir === 'virtualToPhysical' ) {
763
+ if ( val < yMax ) {
764
+ return Math.pow(val / coeff, 0.5);
765
+ }
766
+ else {
767
+ val = (yMax*2) - val;
768
+ return val < 0 ?
769
+ heights.scroll :
770
+ (xMax*2) - Math.pow(val / coeff, 0.5);
771
+ }
772
+ }
773
+ else if ( dir === 'physicalToVirtual' ) {
774
+ if ( val < xMax ) {
775
+ return val * val * coeff;
776
+ }
777
+ else {
778
+ val = (xMax*2) - val;
779
+ return val < 0 ?
780
+ heights.virtual :
781
+ (yMax*2) - (val * val * coeff);
782
+ }
783
+ }
784
+ },
785
+
786
+
787
+ /**
788
+ * Draw callback function which is fired when the DataTable is redrawn. The main function of
789
+ * this method is to position the drawn table correctly the scrolling container for the rows
790
+ * that is displays as a result of the scrolling position.
791
+ * @returns {void}
792
+ * @private
793
+ */
794
+ "_fnDrawCallback": function ()
795
+ {
796
+ var
797
+ that = this,
798
+ heights = this.s.heights,
799
+ iScrollTop = this.dom.scroller.scrollTop,
800
+ iActualScrollTop = iScrollTop,
801
+ iScrollBottom = iScrollTop + heights.viewport,
802
+ iTableHeight = $(this.s.dt.nTable).height(),
803
+ displayStart = this.s.dt._iDisplayStart,
804
+ displayLen = this.s.dt._iDisplayLength,
805
+ displayEnd = this.s.dt.fnRecordsDisplay();
806
+
807
+ // Disable the scroll event listener while we are updating the DOM
808
+ this.s.skip = true;
809
+
810
+ // Resize the scroll forcing element
811
+ this._fnScrollForce();
812
+
813
+ // Reposition the scrolling for the updated virtual position if needed
814
+ if ( displayStart === 0 ) {
815
+ // Linear calculation at the top of the table
816
+ iScrollTop = this.s.topRowFloat * heights.row;
817
+ }
818
+ else if ( displayStart + displayLen >= displayEnd ) {
819
+ // Linear calculation that the bottom as well
820
+ iScrollTop = heights.scroll - ((displayEnd - this.s.topRowFloat) * heights.row);
821
+ }
822
+ else {
823
+ // Domain scaled in the middle
824
+ iScrollTop = this._domain( 'virtualToPhysical', this.s.topRowFloat * heights.row );
825
+ }
826
+
827
+ this.dom.scroller.scrollTop = iScrollTop;
828
+
829
+ // Store positional information so positional calculations can be based
830
+ // upon the current table draw position
831
+ this.s.baseScrollTop = iScrollTop;
832
+ this.s.baseRowTop = this.s.topRowFloat;
833
+
834
+ // Position the table in the virtual scroller
835
+ var tableTop = iScrollTop - ((this.s.topRowFloat - displayStart) * heights.row);
836
+ if ( displayStart === 0 ) {
837
+ tableTop = 0;
838
+ }
839
+ else if ( displayStart + displayLen >= displayEnd ) {
840
+ tableTop = heights.scroll - iTableHeight;
841
+ }
842
+
843
+ this.dom.table.style.top = tableTop+'px';
844
+
845
+ /* Cache some information for the scroller */
846
+ this.s.tableTop = tableTop;
847
+ this.s.tableBottom = iTableHeight + this.s.tableTop;
848
+
849
+ // Calculate the boundaries for where a redraw will be triggered by the
850
+ // scroll event listener
851
+ var boundaryPx = (iScrollTop - this.s.tableTop) * this.s.boundaryScale;
852
+ this.s.redrawTop = iScrollTop - boundaryPx;
853
+ this.s.redrawBottom = iScrollTop + boundaryPx;
854
+
855
+ this.s.skip = false;
856
+
857
+ // Restore the scrolling position that was saved by DataTable's state
858
+ // saving Note that this is done on the second draw when data is Ajax
859
+ // sourced, and the first draw when DOM soured
860
+ if ( this.s.dt.oFeatures.bStateSave && this.s.dt.oLoadedState !== null &&
861
+ typeof this.s.dt.oLoadedState.iScroller != 'undefined' )
862
+ {
863
+ // A quirk of DataTables is that the draw callback will occur on an
864
+ // empty set if Ajax sourced, but not if server-side processing.
865
+ var ajaxSourced = (this.s.dt.sAjaxSource || that.s.dt.ajax) && ! this.s.dt.oFeatures.bServerSide ?
866
+ true :
867
+ false;
868
+
869
+ if ( ( ajaxSourced && this.s.dt.iDraw == 2) ||
870
+ (!ajaxSourced && this.s.dt.iDraw == 1) )
871
+ {
872
+ setTimeout( function () {
873
+ $(that.dom.scroller).scrollTop( that.s.dt.oLoadedState.iScroller );
874
+ that.s.redrawTop = that.s.dt.oLoadedState.iScroller - (heights.viewport/2);
875
+
876
+ // In order to prevent layout thrashing we need another
877
+ // small delay
878
+ setTimeout( function () {
879
+ that.s.ingnoreScroll = false;
880
+ }, 0 );
881
+ }, 0 );
882
+ }
883
+ }
884
+ else {
885
+ that.s.ingnoreScroll = false;
886
+ }
887
+
888
+ // Because of the order of the DT callbacks, the info update will
889
+ // take precedence over the one we want here. So a 'thread' break is
890
+ // needed. Only add the thread break if bInfo is set
891
+ if ( this.s.dt.oFeatures.bInfo ) {
892
+ setTimeout( function () {
893
+ that._fnInfo.call( that );
894
+ }, 0 );
895
+ }
896
+
897
+ // Hide the loading indicator
898
+ if ( this.dom.loader && this.s.loaderVisible ) {
899
+ this.dom.loader.css( 'display', 'none' );
900
+ this.s.loaderVisible = false;
901
+ }
902
+ },
903
+
904
+
905
+ /**
906
+ * Force the scrolling container to have height beyond that of just the
907
+ * table that has been drawn so the user can scroll the whole data set.
908
+ *
909
+ * Note that if the calculated required scrolling height exceeds a maximum
910
+ * value (1 million pixels - hard-coded) the forcing element will be set
911
+ * only to that maximum value and virtual / physical domain transforms will
912
+ * be used to allow Scroller to display tables of any number of records.
913
+ * @returns {void}
914
+ * @private
915
+ */
916
+ _fnScrollForce: function ()
917
+ {
918
+ var heights = this.s.heights;
919
+ var max = 1000000;
920
+
921
+ heights.virtual = heights.row * this.s.dt.fnRecordsDisplay();
922
+ heights.scroll = heights.virtual;
923
+
924
+ if ( heights.scroll > max ) {
925
+ heights.scroll = max;
926
+ }
927
+
928
+ // Minimum height so there is always a row visible (the 'no rows found'
929
+ // if reduced to zero filtering)
930
+ this.dom.force.style.height = heights.scroll > this.s.heights.row ?
931
+ heights.scroll+'px' :
932
+ this.s.heights.row+'px';
933
+ },
934
+
935
+
936
+ /**
937
+ * Automatic calculation of table row height. This is just a little tricky here as using
938
+ * initialisation DataTables has tale the table out of the document, so we need to create
939
+ * a new table and insert it into the document, calculate the row height and then whip the
940
+ * table out.
941
+ * @returns {void}
942
+ * @private
943
+ */
944
+ "_fnCalcRowHeight": function ()
945
+ {
946
+ var dt = this.s.dt;
947
+ var origTable = dt.nTable;
948
+ var nTable = origTable.cloneNode( false );
949
+ var tbody = $('<tbody/>').appendTo( nTable );
950
+ var container = $(
951
+ '<div class="'+dt.oClasses.sWrapper+' DTS">'+
952
+ '<div class="'+dt.oClasses.sScrollWrapper+'">'+
953
+ '<div class="'+dt.oClasses.sScrollBody+'"></div>'+
954
+ '</div>'+
955
+ '</div>'
956
+ );
957
+
958
+ // Want 3 rows in the sizing table so :first-child and :last-child
959
+ // CSS styles don't come into play - take the size of the middle row
960
+ $('tbody tr:lt(4)', origTable).clone().appendTo( tbody );
961
+ while( $('tr', tbody).length < 3 ) {
962
+ tbody.append( '<tr><td>&nbsp;</td></tr>' );
963
+ }
964
+
965
+ $('div.'+dt.oClasses.sScrollBody, container).append( nTable );
966
+
967
+ // If initialised using `dom`, use the holding element as the insert point
968
+ var insertEl = this.s.dt.nHolding || origTable.parentNode;
969
+
970
+ if ( ! $(insertEl).is(':visible') ) {
971
+ insertEl = 'body';
972
+ }
973
+
974
+ container.appendTo( insertEl );
975
+ this.s.heights.row = $('tr', tbody).eq(1).outerHeight();
976
+
977
+ container.remove();
978
+ },
979
+
980
+
981
+ /**
982
+ * Update any information elements that are controlled by the DataTable based on the scrolling
983
+ * viewport and what rows are visible in it. This function basically acts in the same way as
984
+ * _fnUpdateInfo in DataTables, and effectively replaces that function.
985
+ * @returns {void}
986
+ * @private
987
+ */
988
+ "_fnInfo": function ()
989
+ {
990
+ if ( !this.s.dt.oFeatures.bInfo )
991
+ {
992
+ return;
993
+ }
994
+
995
+ var
996
+ dt = this.s.dt,
997
+ language = dt.oLanguage,
998
+ iScrollTop = this.dom.scroller.scrollTop,
999
+ iStart = Math.floor( this.fnPixelsToRow(iScrollTop, false, this.s.ani)+1 ),
1000
+ iMax = dt.fnRecordsTotal(),
1001
+ iTotal = dt.fnRecordsDisplay(),
1002
+ iPossibleEnd = Math.ceil( this.fnPixelsToRow(iScrollTop+this.s.heights.viewport, false, this.s.ani) ),
1003
+ iEnd = iTotal < iPossibleEnd ? iTotal : iPossibleEnd,
1004
+ sStart = dt.fnFormatNumber( iStart ),
1005
+ sEnd = dt.fnFormatNumber( iEnd ),
1006
+ sMax = dt.fnFormatNumber( iMax ),
1007
+ sTotal = dt.fnFormatNumber( iTotal ),
1008
+ sOut;
1009
+
1010
+ if ( dt.fnRecordsDisplay() === 0 &&
1011
+ dt.fnRecordsDisplay() == dt.fnRecordsTotal() )
1012
+ {
1013
+ /* Empty record set */
1014
+ sOut = language.sInfoEmpty+ language.sInfoPostFix;
1015
+ }
1016
+ else if ( dt.fnRecordsDisplay() === 0 )
1017
+ {
1018
+ /* Empty record set after filtering */
1019
+ sOut = language.sInfoEmpty +' '+
1020
+ language.sInfoFiltered.replace('_MAX_', sMax)+
1021
+ language.sInfoPostFix;
1022
+ }
1023
+ else if ( dt.fnRecordsDisplay() == dt.fnRecordsTotal() )
1024
+ {
1025
+ /* Normal record set */
1026
+ sOut = language.sInfo.
1027
+ replace('_START_', sStart).
1028
+ replace('_END_', sEnd).
1029
+ replace('_MAX_', sMax).
1030
+ replace('_TOTAL_', sTotal)+
1031
+ language.sInfoPostFix;
1032
+ }
1033
+ else
1034
+ {
1035
+ /* Record set after filtering */
1036
+ sOut = language.sInfo.
1037
+ replace('_START_', sStart).
1038
+ replace('_END_', sEnd).
1039
+ replace('_MAX_', sMax).
1040
+ replace('_TOTAL_', sTotal) +' '+
1041
+ language.sInfoFiltered.replace(
1042
+ '_MAX_',
1043
+ dt.fnFormatNumber(dt.fnRecordsTotal())
1044
+ )+
1045
+ language.sInfoPostFix;
1046
+ }
1047
+
1048
+ var callback = language.fnInfoCallback;
1049
+ if ( callback ) {
1050
+ sOut = callback.call( dt.oInstance,
1051
+ dt, iStart, iEnd, iMax, iTotal, sOut
1052
+ );
1053
+ }
1054
+
1055
+ var n = dt.aanFeatures.i;
1056
+ if ( typeof n != 'undefined' )
1057
+ {
1058
+ for ( var i=0, iLen=n.length ; i<iLen ; i++ )
1059
+ {
1060
+ $(n[i]).html( sOut );
1061
+ }
1062
+ }
1063
+
1064
+ // DT doesn't actually (yet) trigger this event, but it will in future
1065
+ $(dt.nTable).triggerHandler( 'info.dt' );
1066
+ }
1067
+ } );
1068
+
1069
+
1070
+
1071
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1072
+ * Statics
1073
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1074
+
1075
+
1076
+ /**
1077
+ * Scroller default settings for initialisation
1078
+ * @namespace
1079
+ * @name Scroller.defaults
1080
+ * @static
1081
+ */
1082
+ Scroller.defaults = /** @lends Scroller.defaults */{
1083
+ /**
1084
+ * Indicate if Scroller show show trace information on the console or not. This can be
1085
+ * useful when debugging Scroller or if just curious as to what it is doing, but should
1086
+ * be turned off for production.
1087
+ * @type bool
1088
+ * @default false
1089
+ * @static
1090
+ * @example
1091
+ * var oTable = $('#example').dataTable( {
1092
+ * "sScrollY": "200px",
1093
+ * "sDom": "frtiS",
1094
+ * "bDeferRender": true,
1095
+ * "oScroller": {
1096
+ * "trace": true
1097
+ * }
1098
+ * } );
1099
+ */
1100
+ "trace": false,
1101
+
1102
+ /**
1103
+ * Scroller will attempt to automatically calculate the height of rows for it's internal
1104
+ * calculations. However the height that is used can be overridden using this parameter.
1105
+ * @type int|string
1106
+ * @default auto
1107
+ * @static
1108
+ * @example
1109
+ * var oTable = $('#example').dataTable( {
1110
+ * "sScrollY": "200px",
1111
+ * "sDom": "frtiS",
1112
+ * "bDeferRender": true,
1113
+ * "oScroller": {
1114
+ * "rowHeight": 30
1115
+ * }
1116
+ * } );
1117
+ */
1118
+ "rowHeight": "auto",
1119
+
1120
+ /**
1121
+ * When using server-side processing, Scroller will wait a small amount of time to allow
1122
+ * the scrolling to finish before requesting more data from the server. This prevents
1123
+ * you from DoSing your own server! The wait time can be configured by this parameter.
1124
+ * @type int
1125
+ * @default 200
1126
+ * @static
1127
+ * @example
1128
+ * var oTable = $('#example').dataTable( {
1129
+ * "sScrollY": "200px",
1130
+ * "sDom": "frtiS",
1131
+ * "bDeferRender": true,
1132
+ * "oScroller": {
1133
+ * "serverWait": 100
1134
+ * }
1135
+ * } );
1136
+ */
1137
+ "serverWait": 200,
1138
+
1139
+ /**
1140
+ * The display buffer is what Scroller uses to calculate how many rows it should pre-fetch
1141
+ * for scrolling. Scroller automatically adjusts DataTables' display length to pre-fetch
1142
+ * rows that will be shown in "near scrolling" (i.e. just beyond the current display area).
1143
+ * The value is based upon the number of rows that can be displayed in the viewport (i.e.
1144
+ * a value of 1), and will apply the display range to records before before and after the
1145
+ * current viewport - i.e. a factor of 3 will allow Scroller to pre-fetch 1 viewport's worth
1146
+ * of rows before the current viewport, the current viewport's rows and 1 viewport's worth
1147
+ * of rows after the current viewport. Adjusting this value can be useful for ensuring
1148
+ * smooth scrolling based on your data set.
1149
+ * @type int
1150
+ * @default 7
1151
+ * @static
1152
+ * @example
1153
+ * var oTable = $('#example').dataTable( {
1154
+ * "sScrollY": "200px",
1155
+ * "sDom": "frtiS",
1156
+ * "bDeferRender": true,
1157
+ * "oScroller": {
1158
+ * "displayBuffer": 10
1159
+ * }
1160
+ * } );
1161
+ */
1162
+ "displayBuffer": 9,
1163
+
1164
+ /**
1165
+ * Scroller uses the boundary scaling factor to decide when to redraw the table - which it
1166
+ * typically does before you reach the end of the currently loaded data set (in order to
1167
+ * allow the data to look continuous to a user scrolling through the data). If given as 0
1168
+ * then the table will be redrawn whenever the viewport is scrolled, while 1 would not
1169
+ * redraw the table until the currently loaded data has all been shown. You will want
1170
+ * something in the middle - the default factor of 0.5 is usually suitable.
1171
+ * @type float
1172
+ * @default 0.5
1173
+ * @static
1174
+ * @example
1175
+ * var oTable = $('#example').dataTable( {
1176
+ * "sScrollY": "200px",
1177
+ * "sDom": "frtiS",
1178
+ * "bDeferRender": true,
1179
+ * "oScroller": {
1180
+ * "boundaryScale": 0.75
1181
+ * }
1182
+ * } );
1183
+ */
1184
+ "boundaryScale": 0.5,
1185
+
1186
+ /**
1187
+ * Show (or not) the loading element in the background of the table. Note that you should
1188
+ * include the dataTables.scroller.css file for this to be displayed correctly.
1189
+ * @type boolean
1190
+ * @default false
1191
+ * @static
1192
+ * @example
1193
+ * var oTable = $('#example').dataTable( {
1194
+ * "sScrollY": "200px",
1195
+ * "sDom": "frtiS",
1196
+ * "bDeferRender": true,
1197
+ * "oScroller": {
1198
+ * "loadingIndicator": true
1199
+ * }
1200
+ * } );
1201
+ */
1202
+ "loadingIndicator": false
1203
+ };
1204
+
1205
+ Scroller.oDefaults = Scroller.defaults;
1206
+
1207
+
1208
+
1209
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1210
+ * Constants
1211
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1212
+
1213
+ /**
1214
+ * Scroller version
1215
+ * @type String
1216
+ * @default See code
1217
+ * @name Scroller.version
1218
+ * @static
1219
+ */
1220
+ Scroller.version = "1.4.2";
1221
+
1222
+
1223
+
1224
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1225
+ * Initialisation
1226
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1227
+
1228
+ // Legacy `dom` parameter initialisation support
1229
+ if ( typeof $.fn.dataTable == "function" &&
1230
+ typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
1231
+ $.fn.dataTableExt.fnVersionCheck('1.10.0') )
1232
+ {
1233
+ $.fn.dataTableExt.aoFeatures.push( {
1234
+ "fnInit": function( oDTSettings ) {
1235
+ var init = oDTSettings.oInit;
1236
+ var opts = init.scroller || init.oScroller || {};
1237
+
1238
+ new Scroller( oDTSettings, opts );
1239
+ },
1240
+ "cFeature": "S",
1241
+ "sFeature": "Scroller"
1242
+ } );
1243
+ }
1244
+ else
1245
+ {
1246
+ alert( "Warning: Scroller requires DataTables 1.10.0 or greater - www.datatables.net/download");
1247
+ }
1248
+
1249
+ // Attach a listener to the document which listens for DataTables initialisation
1250
+ // events so we can automatically initialise
1251
+ $(document).on( 'preInit.dt.dtscroller', function (e, settings) {
1252
+ if ( e.namespace !== 'dt' ) {
1253
+ return;
1254
+ }
1255
+
1256
+ var init = settings.oInit.scroller;
1257
+ var defaults = DataTable.defaults.scroller;
1258
+
1259
+ if ( init || defaults ) {
1260
+ var opts = $.extend( {}, init, defaults );
1261
+
1262
+ if ( init !== false ) {
1263
+ new Scroller( settings, opts );
1264
+ }
1265
+ }
1266
+ } );
1267
+
1268
+
1269
+ // Attach Scroller to DataTables so it can be accessed as an 'extra'
1270
+ $.fn.dataTable.Scroller = Scroller;
1271
+ $.fn.DataTable.Scroller = Scroller;
1272
+
1273
+
1274
+ // DataTables 1.10 API method aliases
1275
+ var Api = $.fn.dataTable.Api;
1276
+
1277
+ Api.register( 'scroller()', function () {
1278
+ return this;
1279
+ } );
1280
+
1281
+ // Undocumented and deprecated - is it actually useful at all?
1282
+ Api.register( 'scroller().rowToPixels()', function ( rowIdx, intParse, virtual ) {
1283
+ var ctx = this.context;
1284
+
1285
+ if ( ctx.length && ctx[0].oScroller ) {
1286
+ return ctx[0].oScroller.fnRowToPixels( rowIdx, intParse, virtual );
1287
+ }
1288
+ // undefined
1289
+ } );
1290
+
1291
+ // Undocumented and deprecated - is it actually useful at all?
1292
+ Api.register( 'scroller().pixelsToRow()', function ( pixels, intParse, virtual ) {
1293
+ var ctx = this.context;
1294
+
1295
+ if ( ctx.length && ctx[0].oScroller ) {
1296
+ return ctx[0].oScroller.fnPixelsToRow( pixels, intParse, virtual );
1297
+ }
1298
+ // undefined
1299
+ } );
1300
+
1301
+ // Undocumented and deprecated - use `row().scrollTo()` instead
1302
+ Api.register( 'scroller().scrollToRow()', function ( row, ani ) {
1303
+ this.iterator( 'table', function ( ctx ) {
1304
+ if ( ctx.oScroller ) {
1305
+ ctx.oScroller.fnScrollToRow( row, ani );
1306
+ }
1307
+ } );
1308
+
1309
+ return this;
1310
+ } );
1311
+
1312
+ Api.register( 'row().scrollTo()', function ( ani ) {
1313
+ var that = this;
1314
+
1315
+ this.iterator( 'row', function ( ctx, rowIdx ) {
1316
+ if ( ctx.oScroller ) {
1317
+ var displayIdx = that
1318
+ .rows( { order: 'applied', search: 'applied' } )
1319
+ .indexes()
1320
+ .indexOf( rowIdx );
1321
+
1322
+ ctx.oScroller.fnScrollToRow( displayIdx, ani );
1323
+ }
1324
+ } );
1325
+
1326
+ return this;
1327
+ } );
1328
+
1329
+ Api.register( 'scroller.measure()', function ( redraw ) {
1330
+ this.iterator( 'table', function ( ctx ) {
1331
+ if ( ctx.oScroller ) {
1332
+ ctx.oScroller.fnMeasure( redraw );
1333
+ }
1334
+ } );
1335
+
1336
+ return this;
1337
+ } );
1338
+
1339
+ Api.register( 'scroller.page()', function() {
1340
+ var ctx = this.context;
1341
+
1342
+ if ( ctx.length && ctx[0].oScroller ) {
1343
+ return ctx[0].oScroller.fnPageInfo();
1344
+ }
1345
+ // undefined
1346
+ } );
1347
+
1348
+ return Scroller;
1349
+ }));