Subversion Repositories DevTools

Rev

Rev 6578 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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