##// END OF EJS Templates
datatables: updated to latest version 1.10.13
marcink -
r1514:5660c532 default
parent child Browse files
Show More
This diff has been collapsed as it changes many lines, (4232 lines changed) Show them Hide them
@@ -1,15 +1,15 b''
1 /*! DataTables 1.10.4
1 /*! DataTables 1.10.13
2 * ©2008-2014 SpryMedia Ltd - datatables.net/license
2 * ©2008-2016 SpryMedia Ltd - datatables.net/license
3 */
3 */
4
4
5 /**
5 /**
6 * @summary DataTables
6 * @summary DataTables
7 * @description Paginate, search and order HTML tables
7 * @description Paginate, search and order HTML tables
8 * @version 1.10.4
8 * @version 1.10.13
9 * @file jquery.dataTables.js
9 * @file jquery.dataTables.js
10 * @author SpryMedia Ltd (www.sprymedia.co.uk)
10 * @author SpryMedia Ltd
11 * @contact www.sprymedia.co.uk/contact
11 * @contact www.datatables.net
12 * @copyright Copyright 2008-2014 SpryMedia Ltd.
12 * @copyright Copyright 2008-2016 SpryMedia Ltd.
13 *
13 *
14 * This source file is free software, available under the following license:
14 * This source file is free software, available under the following license:
15 * MIT license - http://datatables.net/license
15 * MIT license - http://datatables.net/license
@@ -22,28 +22,41 b''
22 */
22 */
23
23
24 /*jslint evil: true, undef: true, browser: true */
24 /*jslint evil: true, undef: true, browser: true */
25 /*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnScrollBarWidth,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
25 /*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
26
27 (/** @lends <global> */function( window, document, undefined ) {
28
26
29 (function( factory ) {
27 (function( factory ) {
30 "use strict";
28 "use strict";
31
29
32 if ( typeof define === 'function' && define.amd ) {
30 if ( typeof define === 'function' && define.amd ) {
33 // Define as an AMD module if possible
31 // AMD
34 define( 'datatables', ['jquery'], factory );
32 define( ['jquery'], function ( $ ) {
33 return factory( $, window, document );
34 } );
35 }
35 }
36 else if ( typeof exports === 'object' ) {
36 else if ( typeof exports === 'object' ) {
37 // Node/CommonJS
37 // CommonJS
38 factory( require( 'jquery' ) );
38 module.exports = function (root, $) {
39 }
39 if ( ! root ) {
40 else if ( jQuery && !jQuery.fn.dataTable ) {
40 // CommonJS environments without a window global must pass a
41 // Define using browser globals otherwise
41 // root. This will give an error otherwise
42 // Prevent multiple instantiations if the script is loaded twice
42 root = window;
43 factory( jQuery );
43 }
44 }
44
45 }
45 if ( ! $ ) {
46 (/** @lends <global> */function( $ ) {
46 $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
47 require('jquery') :
48 require('jquery')( root );
49 }
50
51 return factory( $, root, root.document );
52 };
53 }
54 else {
55 // Browser
56 factory( jQuery, window, document );
57 }
58 }
59 (function( $, window, document, undefined ) {
47 "use strict";
60 "use strict";
48
61
49 /**
62 /**
@@ -78,7 +91,1251 b''
78 * } );
91 * } );
79 * } );
92 * } );
80 */
93 */
81 var DataTable;
94 var DataTable = function ( options )
95 {
96 /**
97 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
98 * return the resulting jQuery object.
99 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
100 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
101 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
102 * criterion ("applied") or all TR elements (i.e. no filter).
103 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
104 * Can be either 'current', whereby the current sorting of the table is used, or
105 * 'original' whereby the original order the data was read into the table is used.
106 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
107 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
108 * 'current' and filter is 'applied', regardless of what they might be given as.
109 * @returns {object} jQuery object, filtered by the given selector.
110 * @dtopt API
111 * @deprecated Since v1.10
112 *
113 * @example
114 * $(document).ready(function() {
115 * var oTable = $('#example').dataTable();
116 *
117 * // Highlight every second row
118 * oTable.$('tr:odd').css('backgroundColor', 'blue');
119 * } );
120 *
121 * @example
122 * $(document).ready(function() {
123 * var oTable = $('#example').dataTable();
124 *
125 * // Filter to rows with 'Webkit' in them, add a background colour and then
126 * // remove the filter, thus highlighting the 'Webkit' rows only.
127 * oTable.fnFilter('Webkit');
128 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
129 * oTable.fnFilter('');
130 * } );
131 */
132 this.$ = function ( sSelector, oOpts )
133 {
134 return this.api(true).$( sSelector, oOpts );
135 };
136
137
138 /**
139 * Almost identical to $ in operation, but in this case returns the data for the matched
140 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
141 * rather than any descendants, so the data can be obtained for the row/cell. If matching
142 * rows are found, the data returned is the original data array/object that was used to
143 * create the row (or a generated array if from a DOM source).
144 *
145 * This method is often useful in-combination with $ where both functions are given the
146 * same parameters and the array indexes will match identically.
147 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
148 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
149 * @param {string} [oOpts.filter=none] Select elements that meet the current filter
150 * criterion ("applied") or all elements (i.e. no filter).
151 * @param {string} [oOpts.order=current] Order of the data in the processed array.
152 * Can be either 'current', whereby the current sorting of the table is used, or
153 * 'original' whereby the original order the data was read into the table is used.
154 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
155 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
156 * 'current' and filter is 'applied', regardless of what they might be given as.
157 * @returns {array} Data for the matched elements. If any elements, as a result of the
158 * selector, were not TR, TD or TH elements in the DataTable, they will have a null
159 * entry in the array.
160 * @dtopt API
161 * @deprecated Since v1.10
162 *
163 * @example
164 * $(document).ready(function() {
165 * var oTable = $('#example').dataTable();
166 *
167 * // Get the data from the first row in the table
168 * var data = oTable._('tr:first');
169 *
170 * // Do something useful with the data
171 * alert( "First cell is: "+data[0] );
172 * } );
173 *
174 * @example
175 * $(document).ready(function() {
176 * var oTable = $('#example').dataTable();
177 *
178 * // Filter to 'Webkit' and get all data for
179 * oTable.fnFilter('Webkit');
180 * var data = oTable._('tr', {"search": "applied"});
181 *
182 * // Do something with the data
183 * alert( data.length+" rows matched the search" );
184 * } );
185 */
186 this._ = function ( sSelector, oOpts )
187 {
188 return this.api(true).rows( sSelector, oOpts ).data();
189 };
190
191
192 /**
193 * Create a DataTables Api instance, with the currently selected tables for
194 * the Api's context.
195 * @param {boolean} [traditional=false] Set the API instance's context to be
196 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
197 * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
198 * or if all tables captured in the jQuery object should be used.
199 * @return {DataTables.Api}
200 */
201 this.api = function ( traditional )
202 {
203 return traditional ?
204 new _Api(
205 _fnSettingsFromNode( this[ _ext.iApiIndex ] )
206 ) :
207 new _Api( this );
208 };
209
210
211 /**
212 * Add a single new row or multiple rows of data to the table. Please note
213 * that this is suitable for client-side processing only - if you are using
214 * server-side processing (i.e. "bServerSide": true), then to add data, you
215 * must add it to the data source, i.e. the server-side, through an Ajax call.
216 * @param {array|object} data The data to be added to the table. This can be:
217 * <ul>
218 * <li>1D array of data - add a single row with the data provided</li>
219 * <li>2D array of arrays - add multiple rows in a single call</li>
220 * <li>object - data object when using <i>mData</i></li>
221 * <li>array of objects - multiple data objects when using <i>mData</i></li>
222 * </ul>
223 * @param {bool} [redraw=true] redraw the table or not
224 * @returns {array} An array of integers, representing the list of indexes in
225 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
226 * the table.
227 * @dtopt API
228 * @deprecated Since v1.10
229 *
230 * @example
231 * // Global var for counter
232 * var giCount = 2;
233 *
234 * $(document).ready(function() {
235 * $('#example').dataTable();
236 * } );
237 *
238 * function fnClickAddRow() {
239 * $('#example').dataTable().fnAddData( [
240 * giCount+".1",
241 * giCount+".2",
242 * giCount+".3",
243 * giCount+".4" ]
244 * );
245 *
246 * giCount++;
247 * }
248 */
249 this.fnAddData = function( data, redraw )
250 {
251 var api = this.api( true );
252
253 /* Check if we want to add multiple rows or not */
254 var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
255 api.rows.add( data ) :
256 api.row.add( data );
257
258 if ( redraw === undefined || redraw ) {
259 api.draw();
260 }
261
262 return rows.flatten().toArray();
263 };
264
265
266 /**
267 * This function will make DataTables recalculate the column sizes, based on the data
268 * contained in the table and the sizes applied to the columns (in the DOM, CSS or
269 * through the sWidth parameter). This can be useful when the width of the table's
270 * parent element changes (for example a window resize).
271 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
272 * @dtopt API
273 * @deprecated Since v1.10
274 *
275 * @example
276 * $(document).ready(function() {
277 * var oTable = $('#example').dataTable( {
278 * "sScrollY": "200px",
279 * "bPaginate": false
280 * } );
281 *
282 * $(window).on('resize', function () {
283 * oTable.fnAdjustColumnSizing();
284 * } );
285 * } );
286 */
287 this.fnAdjustColumnSizing = function ( bRedraw )
288 {
289 var api = this.api( true ).columns.adjust();
290 var settings = api.settings()[0];
291 var scroll = settings.oScroll;
292
293 if ( bRedraw === undefined || bRedraw ) {
294 api.draw( false );
295 }
296 else if ( scroll.sX !== "" || scroll.sY !== "" ) {
297 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
298 _fnScrollDraw( settings );
299 }
300 };
301
302
303 /**
304 * Quickly and simply clear a table
305 * @param {bool} [bRedraw=true] redraw the table or not
306 * @dtopt API
307 * @deprecated Since v1.10
308 *
309 * @example
310 * $(document).ready(function() {
311 * var oTable = $('#example').dataTable();
312 *
313 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
314 * oTable.fnClearTable();
315 * } );
316 */
317 this.fnClearTable = function( bRedraw )
318 {
319 var api = this.api( true ).clear();
320
321 if ( bRedraw === undefined || bRedraw ) {
322 api.draw();
323 }
324 };
325
326
327 /**
328 * The exact opposite of 'opening' a row, this function will close any rows which
329 * are currently 'open'.
330 * @param {node} nTr the table row to 'close'
331 * @returns {int} 0 on success, or 1 if failed (can't find the row)
332 * @dtopt API
333 * @deprecated Since v1.10
334 *
335 * @example
336 * $(document).ready(function() {
337 * var oTable;
338 *
339 * // 'open' an information row when a row is clicked on
340 * $('#example tbody tr').click( function () {
341 * if ( oTable.fnIsOpen(this) ) {
342 * oTable.fnClose( this );
343 * } else {
344 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
345 * }
346 * } );
347 *
348 * oTable = $('#example').dataTable();
349 * } );
350 */
351 this.fnClose = function( nTr )
352 {
353 this.api( true ).row( nTr ).child.hide();
354 };
355
356
357 /**
358 * Remove a row for the table
359 * @param {mixed} target The index of the row from aoData to be deleted, or
360 * the TR element you want to delete
361 * @param {function|null} [callBack] Callback function
362 * @param {bool} [redraw=true] Redraw the table or not
363 * @returns {array} The row that was deleted
364 * @dtopt API
365 * @deprecated Since v1.10
366 *
367 * @example
368 * $(document).ready(function() {
369 * var oTable = $('#example').dataTable();
370 *
371 * // Immediately remove the first row
372 * oTable.fnDeleteRow( 0 );
373 * } );
374 */
375 this.fnDeleteRow = function( target, callback, redraw )
376 {
377 var api = this.api( true );
378 var rows = api.rows( target );
379 var settings = rows.settings()[0];
380 var data = settings.aoData[ rows[0][0] ];
381
382 rows.remove();
383
384 if ( callback ) {
385 callback.call( this, settings, data );
386 }
387
388 if ( redraw === undefined || redraw ) {
389 api.draw();
390 }
391
392 return data;
393 };
394
395
396 /**
397 * Restore the table to it's original state in the DOM by removing all of DataTables
398 * enhancements, alterations to the DOM structure of the table and event listeners.
399 * @param {boolean} [remove=false] Completely remove the table from the DOM
400 * @dtopt API
401 * @deprecated Since v1.10
402 *
403 * @example
404 * $(document).ready(function() {
405 * // This example is fairly pointless in reality, but shows how fnDestroy can be used
406 * var oTable = $('#example').dataTable();
407 * oTable.fnDestroy();
408 * } );
409 */
410 this.fnDestroy = function ( remove )
411 {
412 this.api( true ).destroy( remove );
413 };
414
415
416 /**
417 * Redraw the table
418 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
419 * @dtopt API
420 * @deprecated Since v1.10
421 *
422 * @example
423 * $(document).ready(function() {
424 * var oTable = $('#example').dataTable();
425 *
426 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
427 * oTable.fnDraw();
428 * } );
429 */
430 this.fnDraw = function( complete )
431 {
432 // Note that this isn't an exact match to the old call to _fnDraw - it takes
433 // into account the new data, but can hold position.
434 this.api( true ).draw( complete );
435 };
436
437
438 /**
439 * Filter the input based on data
440 * @param {string} sInput String to filter the table on
441 * @param {int|null} [iColumn] Column to limit filtering to
442 * @param {bool} [bRegex=false] Treat as regular expression or not
443 * @param {bool} [bSmart=true] Perform smart filtering or not
444 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
445 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
446 * @dtopt API
447 * @deprecated Since v1.10
448 *
449 * @example
450 * $(document).ready(function() {
451 * var oTable = $('#example').dataTable();
452 *
453 * // Sometime later - filter...
454 * oTable.fnFilter( 'test string' );
455 * } );
456 */
457 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
458 {
459 var api = this.api( true );
460
461 if ( iColumn === null || iColumn === undefined ) {
462 api.search( sInput, bRegex, bSmart, bCaseInsensitive );
463 }
464 else {
465 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
466 }
467
468 api.draw();
469 };
470
471
472 /**
473 * Get the data for the whole table, an individual row or an individual cell based on the
474 * provided parameters.
475 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
476 * a TR node then the data source for the whole row will be returned. If given as a
477 * TD/TH cell node then iCol will be automatically calculated and the data for the
478 * cell returned. If given as an integer, then this is treated as the aoData internal
479 * data index for the row (see fnGetPosition) and the data for that row used.
480 * @param {int} [col] Optional column index that you want the data of.
481 * @returns {array|object|string} If mRow is undefined, then the data for all rows is
482 * returned. If mRow is defined, just data for that row, and is iCol is
483 * defined, only data for the designated cell is returned.
484 * @dtopt API
485 * @deprecated Since v1.10
486 *
487 * @example
488 * // Row data
489 * $(document).ready(function() {
490 * oTable = $('#example').dataTable();
491 *
492 * oTable.$('tr').click( function () {
493 * var data = oTable.fnGetData( this );
494 * // ... do something with the array / object of data for the row
495 * } );
496 * } );
497 *
498 * @example
499 * // Individual cell data
500 * $(document).ready(function() {
501 * oTable = $('#example').dataTable();
502 *
503 * oTable.$('td').click( function () {
504 * var sData = oTable.fnGetData( this );
505 * alert( 'The cell clicked on had the value of '+sData );
506 * } );
507 * } );
508 */
509 this.fnGetData = function( src, col )
510 {
511 var api = this.api( true );
512
513 if ( src !== undefined ) {
514 var type = src.nodeName ? src.nodeName.toLowerCase() : '';
515
516 return col !== undefined || type == 'td' || type == 'th' ?
517 api.cell( src, col ).data() :
518 api.row( src ).data() || null;
519 }
520
521 return api.data().toArray();
522 };
523
524
525 /**
526 * Get an array of the TR nodes that are used in the table's body. Note that you will
527 * typically want to use the '$' API method in preference to this as it is more
528 * flexible.
529 * @param {int} [iRow] Optional row index for the TR element you want
530 * @returns {array|node} If iRow is undefined, returns an array of all TR elements
531 * in the table's body, or iRow is defined, just the TR element requested.
532 * @dtopt API
533 * @deprecated Since v1.10
534 *
535 * @example
536 * $(document).ready(function() {
537 * var oTable = $('#example').dataTable();
538 *
539 * // Get the nodes from the table
540 * var nNodes = oTable.fnGetNodes( );
541 * } );
542 */
543 this.fnGetNodes = function( iRow )
544 {
545 var api = this.api( true );
546
547 return iRow !== undefined ?
548 api.row( iRow ).node() :
549 api.rows().nodes().flatten().toArray();
550 };
551
552
553 /**
554 * Get the array indexes of a particular cell from it's DOM element
555 * and column index including hidden columns
556 * @param {node} node this can either be a TR, TD or TH in the table's body
557 * @returns {int} If nNode is given as a TR, then a single index is returned, or
558 * if given as a cell, an array of [row index, column index (visible),
559 * column index (all)] is given.
560 * @dtopt API
561 * @deprecated Since v1.10
562 *
563 * @example
564 * $(document).ready(function() {
565 * $('#example tbody td').click( function () {
566 * // Get the position of the current data from the node
567 * var aPos = oTable.fnGetPosition( this );
568 *
569 * // Get the data array for this row
570 * var aData = oTable.fnGetData( aPos[0] );
571 *
572 * // Update the data array and return the value
573 * aData[ aPos[1] ] = 'clicked';
574 * this.innerHTML = 'clicked';
575 * } );
576 *
577 * // Init DataTables
578 * oTable = $('#example').dataTable();
579 * } );
580 */
581 this.fnGetPosition = function( node )
582 {
583 var api = this.api( true );
584 var nodeName = node.nodeName.toUpperCase();
585
586 if ( nodeName == 'TR' ) {
587 return api.row( node ).index();
588 }
589 else if ( nodeName == 'TD' || nodeName == 'TH' ) {
590 var cell = api.cell( node ).index();
591
592 return [
593 cell.row,
594 cell.columnVisible,
595 cell.column
596 ];
597 }
598 return null;
599 };
600
601
602 /**
603 * Check to see if a row is 'open' or not.
604 * @param {node} nTr the table row to check
605 * @returns {boolean} true if the row is currently open, false otherwise
606 * @dtopt API
607 * @deprecated Since v1.10
608 *
609 * @example
610 * $(document).ready(function() {
611 * var oTable;
612 *
613 * // 'open' an information row when a row is clicked on
614 * $('#example tbody tr').click( function () {
615 * if ( oTable.fnIsOpen(this) ) {
616 * oTable.fnClose( this );
617 * } else {
618 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
619 * }
620 * } );
621 *
622 * oTable = $('#example').dataTable();
623 * } );
624 */
625 this.fnIsOpen = function( nTr )
626 {
627 return this.api( true ).row( nTr ).child.isShown();
628 };
629
630
631 /**
632 * This function will place a new row directly after a row which is currently
633 * on display on the page, with the HTML contents that is passed into the
634 * function. This can be used, for example, to ask for confirmation that a
635 * particular record should be deleted.
636 * @param {node} nTr The table row to 'open'
637 * @param {string|node|jQuery} mHtml The HTML to put into the row
638 * @param {string} sClass Class to give the new TD cell
639 * @returns {node} The row opened. Note that if the table row passed in as the
640 * first parameter, is not found in the table, this method will silently
641 * return.
642 * @dtopt API
643 * @deprecated Since v1.10
644 *
645 * @example
646 * $(document).ready(function() {
647 * var oTable;
648 *
649 * // 'open' an information row when a row is clicked on
650 * $('#example tbody tr').click( function () {
651 * if ( oTable.fnIsOpen(this) ) {
652 * oTable.fnClose( this );
653 * } else {
654 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
655 * }
656 * } );
657 *
658 * oTable = $('#example').dataTable();
659 * } );
660 */
661 this.fnOpen = function( nTr, mHtml, sClass )
662 {
663 return this.api( true )
664 .row( nTr )
665 .child( mHtml, sClass )
666 .show()
667 .child()[0];
668 };
669
670
671 /**
672 * Change the pagination - provides the internal logic for pagination in a simple API
673 * function. With this function you can have a DataTables table go to the next,
674 * previous, first or last pages.
675 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
676 * or page number to jump to (integer), note that page 0 is the first page.
677 * @param {bool} [bRedraw=true] Redraw the table or not
678 * @dtopt API
679 * @deprecated Since v1.10
680 *
681 * @example
682 * $(document).ready(function() {
683 * var oTable = $('#example').dataTable();
684 * oTable.fnPageChange( 'next' );
685 * } );
686 */
687 this.fnPageChange = function ( mAction, bRedraw )
688 {
689 var api = this.api( true ).page( mAction );
690
691 if ( bRedraw === undefined || bRedraw ) {
692 api.draw(false);
693 }
694 };
695
696
697 /**
698 * Show a particular column
699 * @param {int} iCol The column whose display should be changed
700 * @param {bool} bShow Show (true) or hide (false) the column
701 * @param {bool} [bRedraw=true] Redraw the table or not
702 * @dtopt API
703 * @deprecated Since v1.10
704 *
705 * @example
706 * $(document).ready(function() {
707 * var oTable = $('#example').dataTable();
708 *
709 * // Hide the second column after initialisation
710 * oTable.fnSetColumnVis( 1, false );
711 * } );
712 */
713 this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
714 {
715 var api = this.api( true ).column( iCol ).visible( bShow );
716
717 if ( bRedraw === undefined || bRedraw ) {
718 api.columns.adjust().draw();
719 }
720 };
721
722
723 /**
724 * Get the settings for a particular table for external manipulation
725 * @returns {object} DataTables settings object. See
726 * {@link DataTable.models.oSettings}
727 * @dtopt API
728 * @deprecated Since v1.10
729 *
730 * @example
731 * $(document).ready(function() {
732 * var oTable = $('#example').dataTable();
733 * var oSettings = oTable.fnSettings();
734 *
735 * // Show an example parameter from the settings
736 * alert( oSettings._iDisplayStart );
737 * } );
738 */
739 this.fnSettings = function()
740 {
741 return _fnSettingsFromNode( this[_ext.iApiIndex] );
742 };
743
744
745 /**
746 * Sort the table by a particular column
747 * @param {int} iCol the data index to sort on. Note that this will not match the
748 * 'display index' if you have hidden data entries
749 * @dtopt API
750 * @deprecated Since v1.10
751 *
752 * @example
753 * $(document).ready(function() {
754 * var oTable = $('#example').dataTable();
755 *
756 * // Sort immediately with columns 0 and 1
757 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
758 * } );
759 */
760 this.fnSort = function( aaSort )
761 {
762 this.api( true ).order( aaSort ).draw();
763 };
764
765
766 /**
767 * Attach a sort listener to an element for a given column
768 * @param {node} nNode the element to attach the sort listener to
769 * @param {int} iColumn the column that a click on this node will sort on
770 * @param {function} [fnCallback] callback function when sort is run
771 * @dtopt API
772 * @deprecated Since v1.10
773 *
774 * @example
775 * $(document).ready(function() {
776 * var oTable = $('#example').dataTable();
777 *
778 * // Sort on column 1, when 'sorter' is clicked on
779 * oTable.fnSortListener( document.getElementById('sorter'), 1 );
780 * } );
781 */
782 this.fnSortListener = function( nNode, iColumn, fnCallback )
783 {
784 this.api( true ).order.listener( nNode, iColumn, fnCallback );
785 };
786
787
788 /**
789 * Update a table cell or row - this method will accept either a single value to
790 * update the cell with, an array of values with one element for each column or
791 * an object in the same format as the original data source. The function is
792 * self-referencing in order to make the multi column updates easier.
793 * @param {object|array|string} mData Data to update the cell/row with
794 * @param {node|int} mRow TR element you want to update or the aoData index
795 * @param {int} [iColumn] The column to update, give as null or undefined to
796 * update a whole row.
797 * @param {bool} [bRedraw=true] Redraw the table or not
798 * @param {bool} [bAction=true] Perform pre-draw actions or not
799 * @returns {int} 0 on success, 1 on error
800 * @dtopt API
801 * @deprecated Since v1.10
802 *
803 * @example
804 * $(document).ready(function() {
805 * var oTable = $('#example').dataTable();
806 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
807 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
808 * } );
809 */
810 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
811 {
812 var api = this.api( true );
813
814 if ( iColumn === undefined || iColumn === null ) {
815 api.row( mRow ).data( mData );
816 }
817 else {
818 api.cell( mRow, iColumn ).data( mData );
819 }
820
821 if ( bAction === undefined || bAction ) {
822 api.columns.adjust();
823 }
824
825 if ( bRedraw === undefined || bRedraw ) {
826 api.draw();
827 }
828 return 0;
829 };
830
831
832 /**
833 * Provide a common method for plug-ins to check the version of DataTables being used, in order
834 * to ensure compatibility.
835 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
836 * formats "X" and "X.Y" are also acceptable.
837 * @returns {boolean} true if this version of DataTables is greater or equal to the required
838 * version, or false if this version of DataTales is not suitable
839 * @method
840 * @dtopt API
841 * @deprecated Since v1.10
842 *
843 * @example
844 * $(document).ready(function() {
845 * var oTable = $('#example').dataTable();
846 * alert( oTable.fnVersionCheck( '1.9.0' ) );
847 * } );
848 */
849 this.fnVersionCheck = _ext.fnVersionCheck;
850
851
852 var _that = this;
853 var emptyInit = options === undefined;
854 var len = this.length;
855
856 if ( emptyInit ) {
857 options = {};
858 }
859
860 this.oApi = this.internal = _ext.internal;
861
862 // Extend with old style plug-in API methods
863 for ( var fn in DataTable.ext.internal ) {
864 if ( fn ) {
865 this[fn] = _fnExternApiFunc(fn);
866 }
867 }
868
869 this.each(function() {
870 // For each initialisation we want to give it a clean initialisation
871 // object that can be bashed around
872 var o = {};
873 var oInit = len > 1 ? // optimisation for single table case
874 _fnExtend( o, options, true ) :
875 options;
876
877 /*global oInit,_that,emptyInit*/
878 var i=0, iLen, j, jLen, k, kLen;
879 var sId = this.getAttribute( 'id' );
880 var bInitHandedOff = false;
881 var defaults = DataTable.defaults;
882 var $this = $(this);
883
884
885 /* Sanity check */
886 if ( this.nodeName.toLowerCase() != 'table' )
887 {
888 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
889 return;
890 }
891
892 /* Backwards compatibility for the defaults */
893 _fnCompatOpts( defaults );
894 _fnCompatCols( defaults.column );
895
896 /* Convert the camel-case defaults to Hungarian */
897 _fnCamelToHungarian( defaults, defaults, true );
898 _fnCamelToHungarian( defaults.column, defaults.column, true );
899
900 /* Setting up the initialisation object */
901 _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
902
903
904
905 /* Check to see if we are re-initialising a table */
906 var allSettings = DataTable.settings;
907 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
908 {
909 var s = allSettings[i];
910
911 /* Base check on table node */
912 if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )
913 {
914 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
915 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
916
917 if ( emptyInit || bRetrieve )
918 {
919 return s.oInstance;
920 }
921 else if ( bDestroy )
922 {
923 s.oInstance.fnDestroy();
924 break;
925 }
926 else
927 {
928 _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
929 return;
930 }
931 }
932
933 /* If the element we are initialising has the same ID as a table which was previously
934 * initialised, but the table nodes don't match (from before) then we destroy the old
935 * instance by simply deleting it. This is under the assumption that the table has been
936 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
937 */
938 if ( s.sTableId == this.id )
939 {
940 allSettings.splice( i, 1 );
941 break;
942 }
943 }
944
945 /* Ensure the table has an ID - required for accessibility */
946 if ( sId === null || sId === "" )
947 {
948 sId = "DataTables_Table_"+(DataTable.ext._unique++);
949 this.id = sId;
950 }
951
952 /* Create the settings object for this table and set some of the default parameters */
953 var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
954 "sDestroyWidth": $this[0].style.width,
955 "sInstance": sId,
956 "sTableId": sId
957 } );
958 oSettings.nTable = this;
959 oSettings.oApi = _that.internal;
960 oSettings.oInit = oInit;
961
962 allSettings.push( oSettings );
963
964 // Need to add the instance after the instance after the settings object has been added
965 // to the settings array, so we can self reference the table instance if more than one
966 oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
967
968 // Backwards compatibility, before we apply all the defaults
969 _fnCompatOpts( oInit );
970
971 if ( oInit.oLanguage )
972 {
973 _fnLanguageCompat( oInit.oLanguage );
974 }
975
976 // If the length menu is given, but the init display length is not, use the length menu
977 if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
978 {
979 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
980 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
981 }
982
983 // Apply the defaults and init options to make a single init object will all
984 // options defined from defaults and instance options.
985 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
986
987
988 // Map the initialisation options onto the settings object
989 _fnMap( oSettings.oFeatures, oInit, [
990 "bPaginate",
991 "bLengthChange",
992 "bFilter",
993 "bSort",
994 "bSortMulti",
995 "bInfo",
996 "bProcessing",
997 "bAutoWidth",
998 "bSortClasses",
999 "bServerSide",
1000 "bDeferRender"
1001 ] );
1002 _fnMap( oSettings, oInit, [
1003 "asStripeClasses",
1004 "ajax",
1005 "fnServerData",
1006 "fnFormatNumber",
1007 "sServerMethod",
1008 "aaSorting",
1009 "aaSortingFixed",
1010 "aLengthMenu",
1011 "sPaginationType",
1012 "sAjaxSource",
1013 "sAjaxDataProp",
1014 "iStateDuration",
1015 "sDom",
1016 "bSortCellsTop",
1017 "iTabIndex",
1018 "fnStateLoadCallback",
1019 "fnStateSaveCallback",
1020 "renderer",
1021 "searchDelay",
1022 "rowId",
1023 [ "iCookieDuration", "iStateDuration" ], // backwards compat
1024 [ "oSearch", "oPreviousSearch" ],
1025 [ "aoSearchCols", "aoPreSearchCols" ],
1026 [ "iDisplayLength", "_iDisplayLength" ],
1027 [ "bJQueryUI", "bJUI" ]
1028 ] );
1029 _fnMap( oSettings.oScroll, oInit, [
1030 [ "sScrollX", "sX" ],
1031 [ "sScrollXInner", "sXInner" ],
1032 [ "sScrollY", "sY" ],
1033 [ "bScrollCollapse", "bCollapse" ]
1034 ] );
1035 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
1036
1037 /* Callback functions which are array driven */
1038 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
1039 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
1040 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
1041 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
1042 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
1043 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
1044 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
1045 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
1046 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
1047 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
1048 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
1049
1050 oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
1051
1052 /* Browser support detection */
1053 _fnBrowserDetect( oSettings );
1054
1055 var oClasses = oSettings.oClasses;
1056
1057 // @todo Remove in 1.11
1058 if ( oInit.bJQueryUI )
1059 {
1060 /* Use the JUI classes object for display. You could clone the oStdClasses object if
1061 * you want to have multiple tables with multiple independent classes
1062 */
1063 $.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );
1064
1065 if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" )
1066 {
1067 /* Set the DOM to use a layout suitable for jQuery UI's theming */
1068 oSettings.sDom = '<"H"lfr>t<"F"ip>';
1069 }
1070
1071 if ( ! oSettings.renderer ) {
1072 oSettings.renderer = 'jqueryui';
1073 }
1074 else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {
1075 oSettings.renderer.header = 'jqueryui';
1076 }
1077 }
1078 else
1079 {
1080 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
1081 }
1082 $this.addClass( oClasses.sTable );
1083
1084
1085 if ( oSettings.iInitDisplayStart === undefined )
1086 {
1087 /* Display start point, taking into account the save saving */
1088 oSettings.iInitDisplayStart = oInit.iDisplayStart;
1089 oSettings._iDisplayStart = oInit.iDisplayStart;
1090 }
1091
1092 if ( oInit.iDeferLoading !== null )
1093 {
1094 oSettings.bDeferLoading = true;
1095 var tmp = $.isArray( oInit.iDeferLoading );
1096 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
1097 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
1098 }
1099
1100 /* Language definitions */
1101 var oLanguage = oSettings.oLanguage;
1102 $.extend( true, oLanguage, oInit.oLanguage );
1103
1104 if ( oLanguage.sUrl )
1105 {
1106 /* Get the language definitions from a file - because this Ajax call makes the language
1107 * get async to the remainder of this function we use bInitHandedOff to indicate that
1108 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
1109 */
1110 $.ajax( {
1111 dataType: 'json',
1112 url: oLanguage.sUrl,
1113 success: function ( json ) {
1114 _fnLanguageCompat( json );
1115 _fnCamelToHungarian( defaults.oLanguage, json );
1116 $.extend( true, oLanguage, json );
1117 _fnInitialise( oSettings );
1118 },
1119 error: function () {
1120 // Error occurred loading language file, continue on as best we can
1121 _fnInitialise( oSettings );
1122 }
1123 } );
1124 bInitHandedOff = true;
1125 }
1126
1127 /*
1128 * Stripes
1129 */
1130 if ( oInit.asStripeClasses === null )
1131 {
1132 oSettings.asStripeClasses =[
1133 oClasses.sStripeOdd,
1134 oClasses.sStripeEven
1135 ];
1136 }
1137
1138 /* Remove row stripe classes if they are already on the table row */
1139 var stripeClasses = oSettings.asStripeClasses;
1140 var rowOne = $this.children('tbody').find('tr').eq(0);
1141 if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
1142 return rowOne.hasClass(el);
1143 } ) ) !== -1 ) {
1144 $('tbody tr', this).removeClass( stripeClasses.join(' ') );
1145 oSettings.asDestroyStripes = stripeClasses.slice();
1146 }
1147
1148 /*
1149 * Columns
1150 * See if we should load columns automatically or use defined ones
1151 */
1152 var anThs = [];
1153 var aoColumnsInit;
1154 var nThead = this.getElementsByTagName('thead');
1155 if ( nThead.length !== 0 )
1156 {
1157 _fnDetectHeader( oSettings.aoHeader, nThead[0] );
1158 anThs = _fnGetUniqueThs( oSettings );
1159 }
1160
1161 /* If not given a column array, generate one with nulls */
1162 if ( oInit.aoColumns === null )
1163 {
1164 aoColumnsInit = [];
1165 for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
1166 {
1167 aoColumnsInit.push( null );
1168 }
1169 }
1170 else
1171 {
1172 aoColumnsInit = oInit.aoColumns;
1173 }
1174
1175 /* Add the columns */
1176 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
1177 {
1178 _fnAddColumn( oSettings, anThs ? anThs[i] : null );
1179 }
1180
1181 /* Apply the column definitions */
1182 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
1183 _fnColumnOptions( oSettings, iCol, oDef );
1184 } );
1185
1186 /* HTML5 attribute detection - build an mData object automatically if the
1187 * attributes are found
1188 */
1189 if ( rowOne.length ) {
1190 var a = function ( cell, name ) {
1191 return cell.getAttribute( 'data-'+name ) !== null ? name : null;
1192 };
1193
1194 $( rowOne[0] ).children('th, td').each( function (i, cell) {
1195 var col = oSettings.aoColumns[i];
1196
1197 if ( col.mData === i ) {
1198 var sort = a( cell, 'sort' ) || a( cell, 'order' );
1199 var filter = a( cell, 'filter' ) || a( cell, 'search' );
1200
1201 if ( sort !== null || filter !== null ) {
1202 col.mData = {
1203 _: i+'.display',
1204 sort: sort !== null ? i+'.@data-'+sort : undefined,
1205 type: sort !== null ? i+'.@data-'+sort : undefined,
1206 filter: filter !== null ? i+'.@data-'+filter : undefined
1207 };
1208
1209 _fnColumnOptions( oSettings, i );
1210 }
1211 }
1212 } );
1213 }
1214
1215 var features = oSettings.oFeatures;
1216 var loadedInit = function () {
1217 /*
1218 * Sorting
1219 * @todo For modularisation (1.11) this needs to do into a sort start up handler
1220 */
1221
1222 // If aaSorting is not defined, then we use the first indicator in asSorting
1223 // in case that has been altered, so the default sort reflects that option
1224 if ( oInit.aaSorting === undefined ) {
1225 var sorting = oSettings.aaSorting;
1226 for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
1227 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
1228 }
1229 }
1230
1231 /* Do a first pass on the sorting classes (allows any size changes to be taken into
1232 * account, and also will apply sorting disabled classes if disabled
1233 */
1234 _fnSortingClasses( oSettings );
1235
1236 if ( features.bSort ) {
1237 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1238 if ( oSettings.bSorted ) {
1239 var aSort = _fnSortFlatten( oSettings );
1240 var sortedColumns = {};
1241
1242 $.each( aSort, function (i, val) {
1243 sortedColumns[ val.src ] = val.dir;
1244 } );
1245
1246 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
1247 _fnSortAria( oSettings );
1248 }
1249 } );
1250 }
1251
1252 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1253 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
1254 _fnSortingClasses( oSettings );
1255 }
1256 }, 'sc' );
1257
1258
1259 /*
1260 * Final init
1261 * Cache the header, body and footer as required, creating them if needed
1262 */
1263
1264 // Work around for Webkit bug 83867 - store the caption-side before removing from doc
1265 var captions = $this.children('caption').each( function () {
1266 this._captionSide = $(this).css('caption-side');
1267 } );
1268
1269 var thead = $this.children('thead');
1270 if ( thead.length === 0 ) {
1271 thead = $('<thead/>').appendTo($this);
1272 }
1273 oSettings.nTHead = thead[0];
1274
1275 var tbody = $this.children('tbody');
1276 if ( tbody.length === 0 ) {
1277 tbody = $('<tbody/>').appendTo($this);
1278 }
1279 oSettings.nTBody = tbody[0];
1280
1281 var tfoot = $this.children('tfoot');
1282 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) {
1283 // If we are a scrolling table, and no footer has been given, then we need to create
1284 // a tfoot element for the caption element to be appended to
1285 tfoot = $('<tfoot/>').appendTo($this);
1286 }
1287
1288 if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
1289 $this.addClass( oClasses.sNoFooter );
1290 }
1291 else if ( tfoot.length > 0 ) {
1292 oSettings.nTFoot = tfoot[0];
1293 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
1294 }
1295
1296 /* Check if there is data passing into the constructor */
1297 if ( oInit.aaData ) {
1298 for ( i=0 ; i<oInit.aaData.length ; i++ ) {
1299 _fnAddData( oSettings, oInit.aaData[ i ] );
1300 }
1301 }
1302 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {
1303 /* Grab the data from the page - only do this when deferred loading or no Ajax
1304 * source since there is no point in reading the DOM data if we are then going
1305 * to replace it with Ajax data
1306 */
1307 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
1308 }
1309
1310 /* Copy the data index array */
1311 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
1312
1313 /* Initialisation complete - table can be drawn */
1314 oSettings.bInitialised = true;
1315
1316 /* Check if we need to initialise the table (it might not have been handed off to the
1317 * language processor)
1318 */
1319 if ( bInitHandedOff === false ) {
1320 _fnInitialise( oSettings );
1321 }
1322 };
1323
1324 /* Must be done after everything which can be overridden by the state saving! */
1325 if ( oInit.bStateSave )
1326 {
1327 features.bStateSave = true;
1328 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
1329 _fnLoadState( oSettings, oInit, loadedInit );
1330 }
1331 else {
1332 loadedInit();
1333 }
1334
1335 } );
1336 _that = null;
1337 return this;
1338 };
82
1339
83
1340
84 /*
1341 /*
@@ -105,15 +1362,25 b''
105 var _re_dic = {};
1362 var _re_dic = {};
106 var _re_new_lines = /[\r\n]/g;
1363 var _re_new_lines = /[\r\n]/g;
107 var _re_html = /<.*?>/g;
1364 var _re_html = /<.*?>/g;
108 var _re_date_start = /^[\w\+\-]/;
1365
109 var _re_date_end = /[\w\+\-]$/;
1366 // This is not strict ISO8601 - Date.parse() is quite lax, although
1367 // implementations differ between browsers.
1368 var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/;
110
1369
111 // Escape regular expression special characters
1370 // Escape regular expression special characters
112 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
1371 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
113
1372
114 // U+2009 is thin space and U+202F is narrow no-break space, both used in many
1373 // http://en.wikipedia.org/wiki/Foreign_exchange_market
115 // standards as thousands separators
1374 // - \u20BD - Russian ruble.
116 var _re_formatted_numeric = /[',$£€¥%\u2009\u202F]/g;
1375 // - \u20a9 - South Korean Won
1376 // - \u20BA - Turkish Lira
1377 // - \u20B9 - Indian Rupee
1378 // - R - Brazil (R$) and South Africa
1379 // - fr - Swiss Franc
1380 // - kr - Swedish krona, Norwegian krone and Danish krone
1381 // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
1382 // standards as thousands separators.
1383 var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi;
117
1384
118
1385
119 var _empty = function ( d ) {
1386 var _empty = function ( d ) {
@@ -142,6 +1409,13 b''
142 var _isNumber = function ( d, decimalPoint, formatted ) {
1409 var _isNumber = function ( d, decimalPoint, formatted ) {
143 var strType = typeof d === 'string';
1410 var strType = typeof d === 'string';
144
1411
1412 // If empty return immediately so there must be a number if it is a
1413 // formatted string (this stops the string "k", or "kr", etc being detected
1414 // as a formatted number for currency
1415 if ( _empty( d ) ) {
1416 return true;
1417 }
1418
145 if ( decimalPoint && strType ) {
1419 if ( decimalPoint && strType ) {
146 d = _numToDecimal( d, decimalPoint );
1420 d = _numToDecimal( d, decimalPoint );
147 }
1421 }
@@ -150,7 +1424,7 b''
150 d = d.replace( _re_formatted_numeric, '' );
1424 d = d.replace( _re_formatted_numeric, '' );
151 }
1425 }
152
1426
153 return _empty( d ) || (!isNaN( parseFloat(d) ) && isFinite( d ));
1427 return !isNaN( parseFloat(d) ) && isFinite( d );
154 };
1428 };
155
1429
156
1430
@@ -302,6 +1576,65 b''
302 };
1576 };
303
1577
304
1578
1579 /**
1580 * DataTables utility methods
1581 *
1582 * This namespace provides helper methods that DataTables uses internally to
1583 * create a DataTable, but which are not exclusively used only for DataTables.
1584 * These methods can be used by extension authors to save the duplication of
1585 * code.
1586 *
1587 * @namespace
1588 */
1589 DataTable.util = {
1590 /**
1591 * Throttle the calls to a function. Arguments and context are maintained
1592 * for the throttled function.
1593 *
1594 * @param {function} fn Function to be called
1595 * @param {integer} freq Call frequency in mS
1596 * @return {function} Wrapped function
1597 */
1598 throttle: function ( fn, freq ) {
1599 var
1600 frequency = freq !== undefined ? freq : 200,
1601 last,
1602 timer;
1603
1604 return function () {
1605 var
1606 that = this,
1607 now = +new Date(),
1608 args = arguments;
1609
1610 if ( last && now < last + frequency ) {
1611 clearTimeout( timer );
1612
1613 timer = setTimeout( function () {
1614 last = undefined;
1615 fn.apply( that, args );
1616 }, frequency );
1617 }
1618 else {
1619 last = now;
1620 fn.apply( that, args );
1621 }
1622 };
1623 },
1624
1625
1626 /**
1627 * Escape a string such that it can be used in a regular expression
1628 *
1629 * @param {string} val string to escape
1630 * @returns {string} escaped string
1631 */
1632 escapeRegex: function ( val ) {
1633 return val.replace( _re_escape_regex, '\\$1' );
1634 }
1635 };
1636
1637
305
1638
306 /**
1639 /**
307 * Create a mapping object that allows camel case parameters to be looked up
1640 * Create a mapping object that allows camel case parameters to be looked up
@@ -452,6 +1785,14 b''
452 _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
1785 _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
453 _fnCompatMap( init, 'searching', 'bFilter' );
1786 _fnCompatMap( init, 'searching', 'bFilter' );
454
1787
1788 // Boolean initialisation of x-scrolling
1789 if ( typeof init.sScrollX === 'boolean' ) {
1790 init.sScrollX = init.sScrollX ? '100%' : '';
1791 }
1792 if ( typeof init.scrollX === 'boolean' ) {
1793 init.scrollX = init.scrollX ? '100%' : '';
1794 }
1795
455 // Column search objects are in an array, so it needs to be converted
1796 // Column search objects are in an array, so it needs to be converted
456 // element by element
1797 // element by element
457 var searchCols = init.aoSearchCols;
1798 var searchCols = init.aoSearchCols;
@@ -478,6 +1819,12 b''
478 _fnCompatMap( init, 'orderData', 'aDataSort' );
1819 _fnCompatMap( init, 'orderData', 'aDataSort' );
479 _fnCompatMap( init, 'orderSequence', 'asSorting' );
1820 _fnCompatMap( init, 'orderSequence', 'asSorting' );
480 _fnCompatMap( init, 'orderDataType', 'sortDataType' );
1821 _fnCompatMap( init, 'orderDataType', 'sortDataType' );
1822
1823 // orderData can be given as an integer
1824 var dataSort = init.aDataSort;
1825 if ( dataSort && ! $.isArray( dataSort ) ) {
1826 init.aDataSort = [ dataSort ];
1827 }
481 }
1828 }
482
1829
483
1830
@@ -488,14 +1835,19 b''
488 */
1835 */
489 function _fnBrowserDetect( settings )
1836 function _fnBrowserDetect( settings )
490 {
1837 {
491 var browser = settings.oBrowser;
1838 // We don't need to do this every time DataTables is constructed, the values
1839 // calculated are specific to the browser and OS configuration which we
1840 // don't expect to change between initialisations
1841 if ( ! DataTable.__browser ) {
1842 var browser = {};
1843 DataTable.__browser = browser;
492
1844
493 // Scrolling feature / quirks detection
1845 // Scrolling feature / quirks detection
494 var n = $('<div/>')
1846 var n = $('<div/>')
495 .css( {
1847 .css( {
496 position: 'absolute',
1848 position: 'fixed',
497 top: 0,
1849 top: 0,
498 left: 0,
1850 left: $(window).scrollLeft()*-1, // allow for scrolling
499 height: 1,
1851 height: 1,
500 width: 1,
1852 width: 1,
501 overflow: 'hidden'
1853 overflow: 'hidden'
@@ -510,7 +1862,7 b''
510 overflow: 'scroll'
1862 overflow: 'scroll'
511 } )
1863 } )
512 .append(
1864 .append(
513 $('<div class="test"/>')
1865 $('<div/>')
514 .css( {
1866 .css( {
515 width: '100%',
1867 width: '100%',
516 height: 10
1868 height: 10
@@ -519,20 +1871,41 b''
519 )
1871 )
520 .appendTo( 'body' );
1872 .appendTo( 'body' );
521
1873
522 var test = n.find('.test');
1874 var outer = n.children();
1875 var inner = outer.children();
1876
1877 // Numbers below, in order, are:
1878 // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
1879 //
1880 // IE6 XP: 100 100 100 83
1881 // IE7 Vista: 100 100 100 83
1882 // IE 8+ Windows: 83 83 100 83
1883 // Evergreen Windows: 83 83 100 83
1884 // Evergreen Mac with scrollbars: 85 85 100 85
1885 // Evergreen Mac without scrollbars: 100 100 100 100
1886
1887 // Get scrollbar width
1888 browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
523
1889
524 // IE6/7 will oversize a width 100% element inside a scrolling element, to
1890 // IE6/7 will oversize a width 100% element inside a scrolling element, to
525 // include the width of the scrollbar, while other browsers ensure the inner
1891 // include the width of the scrollbar, while other browsers ensure the inner
526 // element is contained without forcing scrolling
1892 // element is contained without forcing scrolling
527 browser.bScrollOversize = test[0].offsetWidth === 100;
1893 browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
528
1894
529 // In rtl text layout, some browsers (most, but not all) will place the
1895 // In rtl text layout, some browsers (most, but not all) will place the
530 // scrollbar on the left, rather than the right.
1896 // scrollbar on the left, rather than the right.
531 browser.bScrollbarLeft = test.offset().left !== 1;
1897 browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
1898
1899 // IE8- don't provide height and width for getBoundingClientRect
1900 browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
532
1901
533 n.remove();
1902 n.remove();
534 }
1903 }
535
1904
1905 $.extend( settings.oBrowser, DataTable.__browser );
1906 settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
1907 }
1908
536
1909
537 /**
1910 /**
538 * Array.prototype reduce[Right] method, used for browsers which don't support
1911 * Array.prototype reduce[Right] method, used for browsers which don't support
@@ -595,7 +1968,7 b''
595 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
1968 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
596
1969
597 // Use the default column options function to initialise classes etc
1970 // Use the default column options function to initialise classes etc
598 _fnColumnOptions( oSettings, iCol, null );
1971 _fnColumnOptions( oSettings, iCol, $(nTh).data() );
599 }
1972 }
600
1973
601
1974
@@ -658,7 +2031,7 b''
658 /* iDataSort to be applied (backwards compatibility), but aDataSort will take
2031 /* iDataSort to be applied (backwards compatibility), but aDataSort will take
659 * priority if defined
2032 * priority if defined
660 */
2033 */
661 if ( typeof oOptions.iDataSort === 'number' )
2034 if ( oOptions.iDataSort !== undefined )
662 {
2035 {
663 oCol.aDataSort = [ oOptions.iDataSort ];
2036 oCol.aDataSort = [ oOptions.iDataSort ];
664 }
2037 }
@@ -676,6 +2049,7 b''
676 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
2049 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
677 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
2050 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
678 );
2051 );
2052 oCol._setter = null;
679
2053
680 oCol.fnGetData = function (rowData, type, meta) {
2054 oCol.fnGetData = function (rowData, type, meta) {
681 var innerData = mData( rowData, type, undefined, meta );
2055 var innerData = mData( rowData, type, undefined, meta );
@@ -800,7 +2174,16 b''
800 */
2174 */
801 function _fnVisbleColumns( oSettings )
2175 function _fnVisbleColumns( oSettings )
802 {
2176 {
803 return _fnGetColumns( oSettings, 'bVisible' ).length;
2177 var vis = 0;
2178
2179 // No reduce in IE8, use a loop for now
2180 $.each( oSettings.aoColumns, function ( i, col ) {
2181 if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {
2182 vis++;
2183 }
2184 } );
2185
2186 return vis;
804 }
2187 }
805
2188
806
2189
@@ -987,7 +2370,8 b''
987 /* Create the object for storing information about this new row */
2370 /* Create the object for storing information about this new row */
988 var iRow = oSettings.aoData.length;
2371 var iRow = oSettings.aoData.length;
989 var oData = $.extend( true, {}, DataTable.models.oRow, {
2372 var oData = $.extend( true, {}, DataTable.models.oRow, {
990 src: nTr ? 'dom' : 'data'
2373 src: nTr ? 'dom' : 'data',
2374 idx: iRow
991 } );
2375 } );
992
2376
993 oData._aData = aDataIn;
2377 oData._aData = aDataIn;
@@ -996,20 +2380,21 b''
996 /* Create the cells */
2380 /* Create the cells */
997 var nTd, sThisType;
2381 var nTd, sThisType;
998 var columns = oSettings.aoColumns;
2382 var columns = oSettings.aoColumns;
2383
2384 // Invalidate the column types as the new data needs to be revalidated
999 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
2385 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
1000 {
2386 {
1001 // When working with a row, the data source object must be populated. In
1002 // all other cases, the data source object is already populated, so we
1003 // don't overwrite it, which might break bindings etc
1004 if ( nTr ) {
1005 _fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );
1006 }
1007 columns[i].sType = null;
2387 columns[i].sType = null;
1008 }
2388 }
1009
2389
1010 /* Add to the display array */
2390 /* Add to the display array */
1011 oSettings.aiDisplayMaster.push( iRow );
2391 oSettings.aiDisplayMaster.push( iRow );
1012
2392
2393 var id = oSettings.rowIdFn( aDataIn );
2394 if ( id !== undefined ) {
2395 oSettings.aIds[ id ] = oData;
2396 }
2397
1013 /* Create the DOM information, or register it if already present */
2398 /* Create the DOM information, or register it if already present */
1014 if ( nTr || ! oSettings.oFeatures.bDeferRender )
2399 if ( nTr || ! oSettings.oFeatures.bDeferRender )
1015 {
2400 {
@@ -1098,14 +2483,15 b''
1098 if ( settings.iDrawError != draw && defaultContent === null ) {
2483 if ( settings.iDrawError != draw && defaultContent === null ) {
1099 _fnLog( settings, 0, "Requested unknown parameter "+
2484 _fnLog( settings, 0, "Requested unknown parameter "+
1100 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
2485 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
1101 " for row "+rowIdx, 4 );
2486 " for row "+rowIdx+", column "+colIdx, 4 );
1102 settings.iDrawError = draw;
2487 settings.iDrawError = draw;
1103 }
2488 }
1104 return defaultContent;
2489 return defaultContent;
1105 }
2490 }
1106
2491
1107 /* When the data source is null, we can use default column data */
2492 // When the data source is null and a specific data type is requested (i.e.
1108 if ( (cellData === rowData || cellData === null) && defaultContent !== null ) {
2493 // not the original data), we can use default column data
2494 if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
1109 cellData = defaultContent;
2495 cellData = defaultContent;
1110 }
2496 }
1111 else if ( typeof cellData === 'function' ) {
2497 else if ( typeof cellData === 'function' ) {
@@ -1153,8 +2539,8 b''
1153 */
2539 */
1154 function _fnSplitObjNotation( str )
2540 function _fnSplitObjNotation( str )
1155 {
2541 {
1156 return $.map( str.match(/(\\.|[^\.])+/g), function ( s ) {
2542 return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
1157 return s.replace(/\\./g, '.');
2543 return s.replace(/\\\./g, '.');
1158 } );
2544 } );
1159 }
2545 }
1160
2546
@@ -1236,9 +2622,11 b''
1236 innerSrc = a.join('.');
2622 innerSrc = a.join('.');
1237
2623
1238 // Traverse each entry in the array getting the properties requested
2624 // Traverse each entry in the array getting the properties requested
2625 if ( $.isArray( data ) ) {
1239 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
2626 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1240 out.push( fetchData( data[j], type, innerSrc ) );
2627 out.push( fetchData( data[j], type, innerSrc ) );
1241 }
2628 }
2629 }
1242
2630
1243 // If a string is given in between the array notation indicators, that
2631 // If a string is given in between the array notation indicators, that
1244 // is used to join the strings together, otherwise an array is returned
2632 // is used to join the strings together, otherwise an array is returned
@@ -1337,12 +2725,22 b''
1337 innerSrc = b.join('.');
2725 innerSrc = b.join('.');
1338
2726
1339 // Traverse each entry in the array setting the properties requested
2727 // Traverse each entry in the array setting the properties requested
2728 if ( $.isArray( val ) )
2729 {
1340 for ( var j=0, jLen=val.length ; j<jLen ; j++ )
2730 for ( var j=0, jLen=val.length ; j<jLen ; j++ )
1341 {
2731 {
1342 o = {};
2732 o = {};
1343 setData( o, val[j], innerSrc );
2733 setData( o, val[j], innerSrc );
1344 data[ a[i] ].push( o );
2734 data[ a[i] ].push( o );
1345 }
2735 }
2736 }
2737 else
2738 {
2739 // We've been asked to save data to an array, but it
2740 // isn't array data to be saved. Best that can be done
2741 // is to just save the value.
2742 data[ a[i] ] = val;
2743 }
1346
2744
1347 // The inner call to setData has already traversed through the remainder
2745 // The inner call to setData has already traversed through the remainder
1348 // of the source and has set the data, thus we can exit here
2746 // of the source and has set the data, thus we can exit here
@@ -1414,6 +2812,7 b''
1414 settings.aoData.length = 0;
2812 settings.aoData.length = 0;
1415 settings.aiDisplayMaster.length = 0;
2813 settings.aiDisplayMaster.length = 0;
1416 settings.aiDisplay.length = 0;
2814 settings.aiDisplay.length = 0;
2815 settings.aIds = {};
1417 }
2816 }
1418
2817
1419
2818
@@ -1519,7 +2918,7 b''
1519 }
2918 }
1520
2919
1521 // Update DataTables special `DT_*` attributes for the row
2920 // Update DataTables special `DT_*` attributes for the row
1522 _fnRowAttributes( row );
2921 _fnRowAttributes( settings, row );
1523 }
2922 }
1524 }
2923 }
1525
2924
@@ -1551,7 +2950,11 b''
1551 objectRead = settings._rowReadObject;
2950 objectRead = settings._rowReadObject;
1552
2951
1553 // Allow the data object to be passed in, or construct
2952 // Allow the data object to be passed in, or construct
1554 d = d || objectRead ? {} : [];
2953 d = d !== undefined ?
2954 d :
2955 objectRead ?
2956 {} :
2957 [];
1555
2958
1556 var attr = function ( str, td ) {
2959 var attr = function ( str, td ) {
1557 if ( typeof str === 'string' ) {
2960 if ( typeof str === 'string' ) {
@@ -1620,6 +3023,17 b''
1620 }
3023 }
1621 }
3024 }
1622
3025
3026 // Read the ID from the DOM if present
3027 var rowNode = row.firstChild ? row : row.nTr;
3028
3029 if ( rowNode ) {
3030 var id = rowNode.getAttribute( 'id' );
3031
3032 if ( id ) {
3033 _fnSetObjectDataFn( settings.rowId )( d, id );
3034 }
3035 }
3036
1623 return {
3037 return {
1624 data: d,
3038 data: d,
1625 cells: tds
3039 cells: tds
@@ -1657,7 +3071,7 b''
1657 nTr._DT_RowIndex = iRow;
3071 nTr._DT_RowIndex = iRow;
1658
3072
1659 /* Special parameters can be given by the data source to be used on the row */
3073 /* Special parameters can be given by the data source to be used on the row */
1660 _fnRowAttributes( row );
3074 _fnRowAttributes( oSettings, row );
1661
3075
1662 /* Process each column */
3076 /* Process each column */
1663 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
3077 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
@@ -1665,11 +3079,17 b''
1665 oCol = oSettings.aoColumns[i];
3079 oCol = oSettings.aoColumns[i];
1666
3080
1667 nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
3081 nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
3082 nTd._DT_CellIndex = {
3083 row: iRow,
3084 column: i
3085 };
3086
1668 cells.push( nTd );
3087 cells.push( nTd );
1669
3088
1670 // Need to create the HTML if new, or if a rendering function is defined
3089 // Need to create the HTML if new, or if a rendering function is defined
1671 if ( !nTrIn || oCol.mRender || oCol.mData !== i )
3090 if ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&
1672 {
3091 (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
3092 ) {
1673 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
3093 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
1674 }
3094 }
1675
3095
@@ -1709,17 +3129,20 b''
1709 /**
3129 /**
1710 * Add attributes to a row based on the special `DT_*` parameters in a data
3130 * Add attributes to a row based on the special `DT_*` parameters in a data
1711 * source object.
3131 * source object.
3132 * @param {object} settings DataTables settings object
1712 * @param {object} DataTables row object for the row to be modified
3133 * @param {object} DataTables row object for the row to be modified
1713 * @memberof DataTable#oApi
3134 * @memberof DataTable#oApi
1714 */
3135 */
1715 function _fnRowAttributes( row )
3136 function _fnRowAttributes( settings, row )
1716 {
3137 {
1717 var tr = row.nTr;
3138 var tr = row.nTr;
1718 var data = row._aData;
3139 var data = row._aData;
1719
3140
1720 if ( tr ) {
3141 if ( tr ) {
1721 if ( data.DT_RowId ) {
3142 var id = settings.rowIdFn( data );
1722 tr.id = data.DT_RowId;
3143
3144 if ( id ) {
3145 tr.id = id;
1723 }
3146 }
1724
3147
1725 if ( data.DT_RowClass ) {
3148 if ( data.DT_RowClass ) {
@@ -1734,6 +3157,10 b''
1734 .addClass( data.DT_RowClass );
3157 .addClass( data.DT_RowClass );
1735 }
3158 }
1736
3159
3160 if ( data.DT_RowAttr ) {
3161 $(tr).attr( data.DT_RowAttr );
3162 }
3163
1737 if ( data.DT_RowData ) {
3164 if ( data.DT_RowData ) {
1738 $(tr).data( data.DT_RowData );
3165 $(tr).data( data.DT_RowData );
1739 }
3166 }
@@ -1780,7 +3207,7 b''
1780 }
3207 }
1781 }
3208 }
1782
3209
1783 if ( column.sTitle != cell.html() ) {
3210 if ( column.sTitle != cell[0].innerHTML ) {
1784 cell.html( column.sTitle );
3211 cell.html( column.sTitle );
1785 }
3212 }
1786
3213
@@ -2252,6 +3679,7 b''
2252
3679
2253 /* Built our DOM structure - replace the holding div with what we want */
3680 /* Built our DOM structure - replace the holding div with what we want */
2254 holding.replaceWith( insert );
3681 holding.replaceWith( insert );
3682 oSettings.nHolding = null;
2255 }
3683 }
2256
3684
2257
3685
@@ -2367,8 +3795,6 b''
2367 return aReturn;
3795 return aReturn;
2368 }
3796 }
2369
3797
2370
2371
2372 /**
3798 /**
2373 * Create an Ajax call based on the table's settings, taking into account that
3799 * Create an Ajax call based on the table's settings, taking into account that
2374 * parameters can have multiple forms, and backwards compatibility.
3800 * parameters can have multiple forms, and backwards compatibility.
@@ -2411,16 +3837,20 b''
2411 var ajaxData;
3837 var ajaxData;
2412 var ajax = oSettings.ajax;
3838 var ajax = oSettings.ajax;
2413 var instance = oSettings.oInstance;
3839 var instance = oSettings.oInstance;
3840 var callback = function ( json ) {
3841 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
3842 fn( json );
3843 };
2414
3844
2415 if ( $.isPlainObject( ajax ) && ajax.data )
3845 if ( $.isPlainObject( ajax ) && ajax.data )
2416 {
3846 {
2417 ajaxData = ajax.data;
3847 ajaxData = ajax.data;
2418
3848
2419 var newData = $.isFunction( ajaxData ) ?
3849 var newData = $.isFunction( ajaxData ) ?
2420 ajaxData( data ) : // fn can manipulate data or return an object
3850 ajaxData( data, oSettings ) : // fn can manipulate data or return
2421 ajaxData; // object or array to merge
3851 ajaxData; // an object object or array to merge
2422
3852
2423 // If the function returned an object, use that alone
3853 // If the function returned something, use that alone
2424 data = $.isFunction( ajaxData ) && newData ?
3854 data = $.isFunction( ajaxData ) && newData ?
2425 newData :
3855 newData :
2426 $.extend( true, data, newData );
3856 $.extend( true, data, newData );
@@ -2435,24 +3865,25 b''
2435 "success": function (json) {
3865 "success": function (json) {
2436 var error = json.error || json.sError;
3866 var error = json.error || json.sError;
2437 if ( error ) {
3867 if ( error ) {
2438 oSettings.oApi._fnLog( oSettings, 0, error );
3868 _fnLog( oSettings, 0, error );
2439 }
3869 }
2440
3870
2441 oSettings.json = json;
3871 oSettings.json = json;
2442 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json] );
3872 callback( json );
2443 fn( json );
2444 },
3873 },
2445 "dataType": "json",
3874 "dataType": "json",
2446 "cache": false,
3875 "cache": false,
2447 "type": oSettings.sServerMethod,
3876 "type": oSettings.sServerMethod,
2448 "error": function (xhr, error, thrown) {
3877 "error": function (xhr, error, thrown) {
2449 var log = oSettings.oApi._fnLog;
3878 var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
2450
3879
3880 if ( $.inArray( true, ret ) === -1 ) {
2451 if ( error == "parsererror" ) {
3881 if ( error == "parsererror" ) {
2452 log( oSettings, 0, 'Invalid JSON response', 1 );
3882 _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
2453 }
3883 }
2454 else if ( xhr.readyState === 4 ) {
3884 else if ( xhr.readyState === 4 ) {
2455 log( oSettings, 0, 'Ajax error', 7 );
3885 _fnLog( oSettings, 0, 'Ajax error', 7 );
3886 }
2456 }
3887 }
2457
3888
2458 _fnProcessingDisplay( oSettings, false );
3889 _fnProcessingDisplay( oSettings, false );
@@ -2473,7 +3904,7 b''
2473 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
3904 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
2474 return { name: key, value: val };
3905 return { name: key, value: val };
2475 } ),
3906 } ),
2476 fn,
3907 callback,
2477 oSettings
3908 oSettings
2478 );
3909 );
2479 }
3910 }
@@ -2487,7 +3918,7 b''
2487 else if ( $.isFunction( ajax ) )
3918 else if ( $.isFunction( ajax ) )
2488 {
3919 {
2489 // Is a function - let the caller define what needs to be done
3920 // Is a function - let the caller define what needs to be done
2490 oSettings.jqXHR = ajax.call( instance, data, fn, oSettings );
3921 oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
2491 }
3922 }
2492 else
3923 else
2493 {
3924 {
@@ -2653,6 +4084,7 b''
2653 return json[old] !== undefined ? json[old] : json[modern];
4084 return json[old] !== undefined ? json[old] : json[modern];
2654 };
4085 };
2655
4086
4087 var data = _fnAjaxDataSrc( settings, json );
2656 var draw = compat( 'sEcho', 'draw' );
4088 var draw = compat( 'sEcho', 'draw' );
2657 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
4089 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
2658 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
4090 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
@@ -2669,7 +4101,6 b''
2669 settings._iRecordsTotal = parseInt(recordsTotal, 10);
4101 settings._iRecordsTotal = parseInt(recordsTotal, 10);
2670 settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
4102 settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
2671
4103
2672 var data = _fnAjaxDataSrc( settings, json );
2673 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
4104 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
2674 _fnAddData( settings, data[i] );
4105 _fnAddData( settings, data[i] );
2675 }
4106 }
@@ -2712,7 +4143,6 b''
2712 json;
4143 json;
2713 }
4144 }
2714
4145
2715
2716 /**
4146 /**
2717 * Generate the node required for filtering text
4147 * Generate the node required for filtering text
2718 * @returns {node} Filter control element
4148 * @returns {node} Filter control element
@@ -2768,13 +4198,13 b''
2768 var jqFilter = $('input', filter)
4198 var jqFilter = $('input', filter)
2769 .val( previousSearch.sSearch )
4199 .val( previousSearch.sSearch )
2770 .attr( 'placeholder', language.sSearchPlaceholder )
4200 .attr( 'placeholder', language.sSearchPlaceholder )
2771 .bind(
4201 .on(
2772 'keyup.DT search.DT input.DT paste.DT cut.DT',
4202 'keyup.DT search.DT input.DT paste.DT cut.DT',
2773 searchDelay ?
4203 searchDelay ?
2774 _fnThrottle( searchFn, searchDelay ) :
4204 _fnThrottle( searchFn, searchDelay ) :
2775 searchFn
4205 searchFn
2776 )
4206 )
2777 .bind( 'keypress.DT', function(e) {
4207 .on( 'keypress.DT', function(e) {
2778 /* Prevent form submission */
4208 /* Prevent form submission */
2779 if ( e.keyCode == 13 ) {
4209 if ( e.keyCode == 13 ) {
2780 return false;
4210 return false;
@@ -2882,7 +4312,7 b''
2882 // So the array reference doesn't break set the results into the
4312 // So the array reference doesn't break set the results into the
2883 // existing array
4313 // existing array
2884 displayRows.length = 0;
4314 displayRows.length = 0;
2885 displayRows.push.apply( displayRows, rows );
4315 $.merge( displayRows, rows );
2886 }
4316 }
2887 }
4317 }
2888
4318
@@ -2904,16 +4334,19 b''
2904 }
4334 }
2905
4335
2906 var data;
4336 var data;
4337 var out = [];
2907 var display = settings.aiDisplay;
4338 var display = settings.aiDisplay;
2908 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
4339 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
2909
4340
2910 for ( var i=display.length-1 ; i>=0 ; i-- ) {
4341 for ( var i=0 ; i<display.length ; i++ ) {
2911 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
4342 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
2912
4343
2913 if ( ! rpSearch.test( data ) ) {
4344 if ( rpSearch.test( data ) ) {
2914 display.splice( i, 1 );
4345 out.push( display[i] );
2915 }
4346 }
2916 }
4347 }
4348
4349 settings.aiDisplay = out;
2917 }
4350 }
2918
4351
2919
4352
@@ -2933,6 +4366,7 b''
2933 var prevSearch = settings.oPreviousSearch.sSearch;
4366 var prevSearch = settings.oPreviousSearch.sSearch;
2934 var displayMaster = settings.aiDisplayMaster;
4367 var displayMaster = settings.aiDisplayMaster;
2935 var display, invalidated, i;
4368 var display, invalidated, i;
4369 var filtered = [];
2936
4370
2937 // Need to take account of custom filtering functions - always filter
4371 // Need to take account of custom filtering functions - always filter
2938 if ( DataTable.ext.search.length !== 0 ) {
4372 if ( DataTable.ext.search.length !== 0 ) {
@@ -2961,11 +4395,13 b''
2961 // Search the display array
4395 // Search the display array
2962 display = settings.aiDisplay;
4396 display = settings.aiDisplay;
2963
4397
2964 for ( i=display.length-1 ; i>=0 ; i-- ) {
4398 for ( i=0 ; i<display.length ; i++ ) {
2965 if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
4399 if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
2966 display.splice( i, 1 );
4400 filtered.push( display[i] );
2967 }
4401 }
2968 }
4402 }
4403
4404 settings.aiDisplay = filtered;
2969 }
4405 }
2970 }
4406 }
2971
4407
@@ -2993,7 +4429,7 b''
2993 *
4429 *
2994 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
4430 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
2995 */
4431 */
2996 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || '', function ( word ) {
4432 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
2997 if ( word.charAt(0) === '"' ) {
4433 if ( word.charAt(0) === '"' ) {
2998 var m = word.match( /^"(.*)"$/ );
4434 var m = word.match( /^"(.*)"$/ );
2999 word = m ? m[1] : word;
4435 word = m ? m[1] : word;
@@ -3015,12 +4451,7 b''
3015 * @returns {string} escaped string
4451 * @returns {string} escaped string
3016 * @memberof DataTable#oApi
4452 * @memberof DataTable#oApi
3017 */
4453 */
3018 function _fnEscapeRegex ( sVal )
4454 var _fnEscapeRegex = DataTable.util.escapeRegex;
3019 {
3020 return sVal.replace( _re_escape_regex, '\\$1' );
3021 }
3022
3023
3024
4455
3025 var __filter_div = $('<div>')[0];
4456 var __filter_div = $('<div>')[0];
3026 var __filter_div_textContent = __filter_div.textContent !== undefined;
4457 var __filter_div_textContent = __filter_div.textContent !== undefined;
@@ -3238,6 +4669,7 b''
3238 var i, iLen, iAjaxStart=settings.iInitDisplayStart;
4669 var i, iLen, iAjaxStart=settings.iInitDisplayStart;
3239 var columns = settings.aoColumns, column;
4670 var columns = settings.aoColumns, column;
3240 var features = settings.oFeatures;
4671 var features = settings.oFeatures;
4672 var deferLoading = settings.bDeferLoading; // value modified by the draw
3241
4673
3242 /* Ensure that the table data is fully initialised */
4674 /* Ensure that the table data is fully initialised */
3243 if ( ! settings.bInitialised ) {
4675 if ( ! settings.bInitialised ) {
@@ -3269,6 +4701,8 b''
3269 }
4701 }
3270 }
4702 }
3271
4703
4704 _fnCallbackFire( settings, null, 'preInit', [settings] );
4705
3272 // If there is default sorting required - let's do it. The sort function
4706 // If there is default sorting required - let's do it. The sort function
3273 // will do the drawing for us. Otherwise we draw the table regardless of the
4707 // will do the drawing for us. Otherwise we draw the table regardless of the
3274 // Ajax source - this allows the table to look initialised for Ajax sourcing
4708 // Ajax source - this allows the table to look initialised for Ajax sourcing
@@ -3277,7 +4711,7 b''
3277
4711
3278 // Server-side processing init complete is done by _fnAjaxUpdateDraw
4712 // Server-side processing init complete is done by _fnAjaxUpdateDraw
3279 var dataSrc = _fnDataSource( settings );
4713 var dataSrc = _fnDataSource( settings );
3280 if ( dataSrc != 'ssp' ) {
4714 if ( dataSrc != 'ssp' || deferLoading ) {
3281 // if there is an ajax source load the data
4715 // if there is an ajax source load the data
3282 if ( dataSrc == 'ajax' ) {
4716 if ( dataSrc == 'ajax' ) {
3283 _fnBuildAjax( settings, [], function(json) {
4717 _fnBuildAjax( settings, [], function(json) {
@@ -3318,12 +4752,13 b''
3318 {
4752 {
3319 settings._bInitComplete = true;
4753 settings._bInitComplete = true;
3320
4754
3321 // On an Ajax load we now have data and therefore want to apply the column
4755 // When data was added after the initialisation (data or Ajax) we need to
3322 // sizing
4756 // calculate the column sizing
3323 if ( json ) {
4757 if ( json || settings.oInit.aaData ) {
3324 _fnAdjustColumnSizing( settings );
4758 _fnAdjustColumnSizing( settings );
3325 }
4759 }
3326
4760
4761 _fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
3327 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
4762 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
3328 }
4763 }
3329
4764
@@ -3379,13 +4814,13 b''
3379 // reference is broken by the use of outerHTML
4814 // reference is broken by the use of outerHTML
3380 $('select', div)
4815 $('select', div)
3381 .val( settings._iDisplayLength )
4816 .val( settings._iDisplayLength )
3382 .bind( 'change.DT', function(e) {
4817 .on( 'change.DT', function(e) {
3383 _fnLengthChange( settings, $(this).val() );
4818 _fnLengthChange( settings, $(this).val() );
3384 _fnDraw( settings );
4819 _fnDraw( settings );
3385 } );
4820 } );
3386
4821
3387 // Update node value whenever anything changes the table's length
4822 // Update node value whenever anything changes the table's length
3388 $(settings.nTable).bind( 'length.dt.DT', function (e, s, len) {
4823 $(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
3389 if ( settings === s ) {
4824 if ( settings === s ) {
3390 $('select', div).val( len );
4825 $('select', div).val( len );
3391 }
4826 }
@@ -3600,17 +5035,6 b''
3600 return !s ? null : _fnStringToCss( s );
5035 return !s ? null : _fnStringToCss( s );
3601 };
5036 };
3602
5037
3603 // This is fairly messy, but with x scrolling enabled, if the table has a
3604 // width attribute, regardless of any width applied using the column width
3605 // options, the browser will shrink or grow the table as needed to fit into
3606 // that 100%. That would make the width options useless. So we remove it.
3607 // This is okay, under the assumption that width:100% is applied to the
3608 // table in CSS (it is in the default stylesheet) which will set the table
3609 // width as appropriate (the attribute and css behave differently...)
3610 if ( scroll.sX && table.attr('width') === '100%' ) {
3611 table.removeAttr('width');
3612 }
3613
3614 if ( ! footer.length ) {
5038 if ( ! footer.length ) {
3615 footer = null;
5039 footer = null;
3616 }
5040 }
@@ -3660,8 +5084,8 b''
3660 .append(
5084 .append(
3661 $(_div, { 'class': classes.sScrollBody } )
5085 $(_div, { 'class': classes.sScrollBody } )
3662 .css( {
5086 .css( {
5087 position: 'relative',
3663 overflow: 'auto',
5088 overflow: 'auto',
3664 height: size( scrollY ),
3665 width: size( scrollX )
5089 width: size( scrollX )
3666 } )
5090 } )
3667 .append( table )
5091 .append( table )
@@ -3697,7 +5121,7 b''
3697
5121
3698 // When the body is scrolled, then we also want to scroll the headers
5122 // When the body is scrolled, then we also want to scroll the headers
3699 if ( scrollX ) {
5123 if ( scrollX ) {
3700 $(scrollBody).scroll( function (e) {
5124 $(scrollBody).on( 'scroll.DT', function (e) {
3701 var scrollLeft = this.scrollLeft;
5125 var scrollLeft = this.scrollLeft;
3702
5126
3703 scrollHead.scrollLeft = scrollLeft;
5127 scrollHead.scrollLeft = scrollLeft;
@@ -3708,6 +5132,11 b''
3708 } );
5132 } );
3709 }
5133 }
3710
5134
5135 $(scrollBody).css(
5136 scrollY && scroll.bCollapse ? 'max-height' : 'height',
5137 scrollY
5138 );
5139
3711 settings.nScrollHead = scrollHead;
5140 settings.nScrollHead = scrollHead;
3712 settings.nScrollBody = scrollBody;
5141 settings.nScrollBody = scrollBody;
3713 settings.nScrollFoot = scrollFoot;
5142 settings.nScrollFoot = scrollFoot;
@@ -3765,11 +5194,12 b''
3765 footer = settings.nTFoot ? $(settings.nTFoot) : null,
5194 footer = settings.nTFoot ? $(settings.nTFoot) : null,
3766 browser = settings.oBrowser,
5195 browser = settings.oBrowser,
3767 ie67 = browser.bScrollOversize,
5196 ie67 = browser.bScrollOversize,
5197 dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ),
3768 headerTrgEls, footerTrgEls,
5198 headerTrgEls, footerTrgEls,
3769 headerSrcEls, footerSrcEls,
5199 headerSrcEls, footerSrcEls,
3770 headerCopy, footerCopy,
5200 headerCopy, footerCopy,
3771 headerWidths=[], footerWidths=[],
5201 headerWidths=[], footerWidths=[],
3772 headerContent=[],
5202 headerContent=[], footerContent=[],
3773 idx, correction, sanityWidth,
5203 idx, correction, sanityWidth,
3774 zeroOut = function(nSizer) {
5204 zeroOut = function(nSizer) {
3775 var style = nSizer.style;
5205 var style = nSizer.style;
@@ -3780,6 +5210,20 b''
3780 style.height = 0;
5210 style.height = 0;
3781 };
5211 };
3782
5212
5213 // If the scrollbar visibility has changed from the last draw, we need to
5214 // adjust the column sizes as the table width will have changed to account
5215 // for the scrollbar
5216 var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
5217
5218 if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
5219 settings.scrollBarVis = scrollBarVis;
5220 _fnAdjustColumnSizing( settings );
5221 return; // adjust column sizing will call this function again
5222 }
5223 else {
5224 settings.scrollBarVis = scrollBarVis;
5225 }
5226
3783 /*
5227 /*
3784 * 1. Re-create the table inside the scrolling div
5228 * 1. Re-create the table inside the scrolling div
3785 */
5229 */
@@ -3787,18 +5231,18 b''
3787 // Remove the old minimised thead and tfoot elements in the inner table
5231 // Remove the old minimised thead and tfoot elements in the inner table
3788 table.children('thead, tfoot').remove();
5232 table.children('thead, tfoot').remove();
3789
5233
5234 if ( footer ) {
5235 footerCopy = footer.clone().prependTo( table );
5236 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
5237 footerSrcEls = footerCopy.find('tr');
5238 }
5239
3790 // Clone the current header and footer elements and then place it into the inner table
5240 // Clone the current header and footer elements and then place it into the inner table
3791 headerCopy = header.clone().prependTo( table );
5241 headerCopy = header.clone().prependTo( table );
3792 headerTrgEls = header.find('tr'); // original header is in its own table
5242 headerTrgEls = header.find('tr'); // original header is in its own table
3793 headerSrcEls = headerCopy.find('tr');
5243 headerSrcEls = headerCopy.find('tr');
3794 headerCopy.find('th, td').removeAttr('tabindex');
5244 headerCopy.find('th, td').removeAttr('tabindex');
3795
5245
3796 if ( footer ) {
3797 footerCopy = footer.clone().prependTo( table );
3798 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
3799 footerSrcEls = footerCopy.find('tr');
3800 }
3801
3802
5246
3803 /*
5247 /*
3804 * 2. Take live measurements from the DOM - do not alter the DOM itself!
5248 * 2. Take live measurements from the DOM - do not alter the DOM itself!
@@ -3824,13 +5268,6 b''
3824 }, footerSrcEls );
5268 }, footerSrcEls );
3825 }
5269 }
3826
5270
3827 // If scroll collapse is enabled, when we put the headers back into the body for sizing, we
3828 // will end up forcing the scrollbar to appear, making our measurements wrong for when we
3829 // then hide it (end of this function), so add the header height to the body scroller.
3830 if ( scroll.bCollapse && scrollY !== "" ) {
3831 divBodyStyle.height = (divBody[0].offsetHeight + header[0].offsetHeight)+"px";
3832 }
3833
3834 // Size the table as a whole
5271 // Size the table as a whole
3835 sanityWidth = table.outerWidth();
5272 sanityWidth = table.outerWidth();
3836 if ( scrollX === "" ) {
5273 if ( scrollX === "" ) {
@@ -3845,32 +5282,17 b''
3845 ) {
5282 ) {
3846 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
5283 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
3847 }
5284 }
3848 }
5285
3849 else
5286 // Recalculate the sanity width
3850 {
5287 sanityWidth = table.outerWidth();
3851 // x scrolling
5288 }
3852 if ( scrollXInner !== "" ) {
5289 else if ( scrollXInner !== "" ) {
3853 // x scroll inner has been given - use it
5290 // legacy x scroll inner has been given - use it
3854 tableStyle.width = _fnStringToCss(scrollXInner);
5291 tableStyle.width = _fnStringToCss(scrollXInner);
3855 }
5292
3856 else if ( sanityWidth == divBody.width() && divBody.height() < table.height() ) {
5293 // Recalculate the sanity width
3857 // There is y-scrolling - try to take account of the y scroll bar
3858 tableStyle.width = _fnStringToCss( sanityWidth-barWidth );
3859 if ( table.outerWidth() > sanityWidth-barWidth ) {
3860 // Not possible to take account of it
3861 tableStyle.width = _fnStringToCss( sanityWidth );
3862 }
3863 }
3864 else {
3865 // When all else fails
3866 tableStyle.width = _fnStringToCss( sanityWidth );
3867 }
3868 }
3869
3870 // Recalculate the sanity width - now that we've applied the required width,
3871 // before it was a temporary variable. This is required because the column
3872 // width calculation is done before this table DOM is created.
3873 sanityWidth = table.outerWidth();
5294 sanityWidth = table.outerWidth();
5295 }
3874
5296
3875 // Hidden header should have zero height, so remove padding and borders. Then
5297 // Hidden header should have zero height, so remove padding and borders. Then
3876 // set the width based on the real headers
5298 // set the width based on the real headers
@@ -3886,7 +5308,11 b''
3886
5308
3887 // Apply all widths in final pass
5309 // Apply all widths in final pass
3888 _fnApplyToChildren( function(nToSize, i) {
5310 _fnApplyToChildren( function(nToSize, i) {
5311 // Only apply widths to the DataTables detected header cells - this
5312 // prevents complex headers from having contradictory sizes applied
5313 if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {
3889 nToSize.style.width = headerWidths[i];
5314 nToSize.style.width = headerWidths[i];
5315 }
3890 }, headerTrgEls );
5316 }, headerTrgEls );
3891
5317
3892 $(headerSrcEls).height(0);
5318 $(headerSrcEls).height(0);
@@ -3897,6 +5323,7 b''
3897 _fnApplyToChildren( zeroOut, footerSrcEls );
5323 _fnApplyToChildren( zeroOut, footerSrcEls );
3898
5324
3899 _fnApplyToChildren( function(nSizer) {
5325 _fnApplyToChildren( function(nSizer) {
5326 footerContent.push( nSizer.innerHTML );
3900 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
5327 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
3901 }, footerSrcEls );
5328 }, footerSrcEls );
3902
5329
@@ -3924,7 +5351,7 b''
3924 if ( footer )
5351 if ( footer )
3925 {
5352 {
3926 _fnApplyToChildren( function(nSizer, i) {
5353 _fnApplyToChildren( function(nSizer, i) {
3927 nSizer.innerHTML = "";
5354 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+footerContent[i]+'</div>';
3928 nSizer.style.width = footerWidths[i];
5355 nSizer.style.width = footerWidths[i];
3929 }, footerSrcEls );
5356 }, footerSrcEls );
3930 }
5357 }
@@ -3978,18 +5405,6 b''
3978 }
5405 }
3979 }
5406 }
3980
5407
3981 if ( scrollY && scroll.bCollapse ) {
3982 divBodyStyle.height = _fnStringToCss( scrollY );
3983
3984 var iExtra = (scrollX && tableEl.offsetWidth > divBodyEl.offsetWidth) ?
3985 barWidth :
3986 0;
3987
3988 if ( tableEl.offsetHeight < divBodyEl.offsetHeight ) {
3989 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+iExtra );
3990 }
3991 }
3992
3993 /* Finally set the width's of the header and footer tables */
5408 /* Finally set the width's of the header and footer tables */
3994 var iOuterWidth = table.outerWidth();
5409 var iOuterWidth = table.outerWidth();
3995 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
5410 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
@@ -4007,6 +5422,9 b''
4007 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
5422 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
4008 }
5423 }
4009
5424
5425 // Correct DOM ordering for colgroup - comes before the thead
5426 table.children('colgroup').insertBefore( table.children('thead') );
5427
4010 /* Adjust the position of the header in case we loose the y-scrollbar */
5428 /* Adjust the position of the header in case we loose the y-scrollbar */
4011 divBody.scroll();
5429 divBody.scroll();
4012
5430
@@ -4078,10 +5496,17 b''
4078 columnCount = columns.length,
5496 columnCount = columns.length,
4079 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
5497 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
4080 headerCells = $('th', oSettings.nTHead),
5498 headerCells = $('th', oSettings.nTHead),
4081 tableWidthAttr = table.getAttribute('width'),
5499 tableWidthAttr = table.getAttribute('width'), // from DOM element
4082 tableContainer = table.parentNode,
5500 tableContainer = table.parentNode,
4083 userInputs = false,
5501 userInputs = false,
4084 i, column, columnIdx, width, outerWidth;
5502 i, column, columnIdx, width, outerWidth,
5503 browser = oSettings.oBrowser,
5504 ie67 = browser.bScrollOversize;
5505
5506 var styleWidth = table.style.width;
5507 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
5508 tableWidthAttr = styleWidth;
5509 }
4085
5510
4086 /* Convert any user input sizes into pixel sizes */
5511 /* Convert any user input sizes into pixel sizes */
4087 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5512 for ( i=0 ; i<visibleColumns.length ; i++ ) {
@@ -4099,32 +5524,43 b''
4099 * the web- browser. No custom sizes can be set in order for this to happen,
5524 * the web- browser. No custom sizes can be set in order for this to happen,
4100 * nor scrolling used
5525 * nor scrolling used
4101 */
5526 */
4102 if ( ! userInputs && ! scrollX && ! scrollY &&
5527 if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
4103 columnCount == _fnVisbleColumns( oSettings ) &&
5528 columnCount == _fnVisbleColumns( oSettings ) &&
4104 columnCount == headerCells.length
5529 columnCount == headerCells.length
4105 ) {
5530 ) {
4106 for ( i=0 ; i<columnCount ; i++ ) {
5531 for ( i=0 ; i<columnCount ; i++ ) {
4107 columns[i].sWidth = _fnStringToCss( headerCells.eq(i).width() );
5532 var colIdx = _fnVisibleToColumnIndex( oSettings, i );
5533
5534 if ( colIdx !== null ) {
5535 columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
5536 }
4108 }
5537 }
4109 }
5538 }
4110 else
5539 else
4111 {
5540 {
4112 // Otherwise construct a single row table with the widest node in the
5541 // Otherwise construct a single row, worst case, table with the widest
4113 // data, assign any user defined widths, then insert it into the DOM and
5542 // node in the data, assign any user defined widths, then insert it into
4114 // allow the browser to do all the hard work of calculating table widths
5543 // the DOM and allow the browser to do all the hard work of calculating
5544 // table widths
4115 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
5545 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
4116 .empty()
4117 .css( 'visibility', 'hidden' )
5546 .css( 'visibility', 'hidden' )
4118 .removeAttr( 'id' )
5547 .removeAttr( 'id' );
4119 .append( $(oSettings.nTHead).clone( false ) )
5548
4120 .append( $(oSettings.nTFoot).clone( false ) )
5549 // Clean up the table body
4121 .append( $('<tbody><tr/></tbody>') );
5550 tmpTable.find('tbody tr').remove();
5551 var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
5552
5553 // Clone the table header and footer - we can't use the header / footer
5554 // from the cloned table, since if scrolling is active, the table's
5555 // real header and footer are contained in different table tags
5556 tmpTable.find('thead, tfoot').remove();
5557 tmpTable
5558 .append( $(oSettings.nTHead).clone() )
5559 .append( $(oSettings.nTFoot).clone() );
4122
5560
4123 // Remove any assigned widths from the footer (from scrolling)
5561 // Remove any assigned widths from the footer (from scrolling)
4124 tmpTable.find('tfoot th, tfoot td').css('width', '');
5562 tmpTable.find('tfoot th, tfoot td').css('width', '');
4125
5563
4126 var tr = tmpTable.find( 'tbody tr' );
4127
4128 // Apply custom sizing to the cloned header
5564 // Apply custom sizing to the cloned header
4129 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
5565 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
4130
5566
@@ -4134,6 +5570,19 b''
4134 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
5570 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
4135 _fnStringToCss( column.sWidthOrig ) :
5571 _fnStringToCss( column.sWidthOrig ) :
4136 '';
5572 '';
5573
5574 // For scrollX we need to force the column width otherwise the
5575 // browser will collapse it. If this width is smaller than the
5576 // width the column requires, then it will have no effect
5577 if ( column.sWidthOrig && scrollX ) {
5578 $( headerCells[i] ).append( $('<div/>').css( {
5579 width: column.sWidthOrig,
5580 margin: 0,
5581 padding: 0,
5582 border: 0,
5583 height: 1
5584 } ) );
5585 }
4137 }
5586 }
4138
5587
4139 // Find the widest cell for each column and put it into the table
5588 // Find the widest cell for each column and put it into the table
@@ -4149,8 +5598,28 b''
4149 }
5598 }
4150 }
5599 }
4151
5600
4152 // Table has been built, attach to the document so we can work with it
5601 // Tidy the temporary table - remove name attributes so there aren't
4153 tmpTable.appendTo( tableContainer );
5602 // duplicated in the dom (radio elements for example)
5603 $('[name]', tmpTable).removeAttr('name');
5604
5605 // Table has been built, attach to the document so we can work with it.
5606 // A holding element is used, positioned at the top of the container
5607 // with minimal height, so it has no effect on if the container scrolls
5608 // or not. Otherwise it might trigger scrolling when it actually isn't
5609 // needed
5610 var holder = $('<div/>').css( scrollX || scrollY ?
5611 {
5612 position: 'absolute',
5613 top: 0,
5614 left: 0,
5615 height: 1,
5616 right: 0,
5617 overflow: 'hidden'
5618 } :
5619 {}
5620 )
5621 .append( tmpTable )
5622 .appendTo( tableContainer );
4154
5623
4155 // When scrolling (X or Y) we want to set the width of the table as
5624 // When scrolling (X or Y) we want to set the width of the table as
4156 // appropriate. However, when not scrolling leave the table width as it
5625 // appropriate. However, when not scrolling leave the table width as it
@@ -4160,57 +5629,50 b''
4160 }
5629 }
4161 else if ( scrollX ) {
5630 else if ( scrollX ) {
4162 tmpTable.css( 'width', 'auto' );
5631 tmpTable.css( 'width', 'auto' );
4163
5632 tmpTable.removeAttr('width');
4164 if ( tmpTable.width() < tableContainer.offsetWidth ) {
5633
4165 tmpTable.width( tableContainer.offsetWidth );
5634 // If there is no width attribute or style, then allow the table to
5635 // collapse
5636 if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
5637 tmpTable.width( tableContainer.clientWidth );
4166 }
5638 }
4167 }
5639 }
4168 else if ( scrollY ) {
5640 else if ( scrollY ) {
4169 tmpTable.width( tableContainer.offsetWidth );
5641 tmpTable.width( tableContainer.clientWidth );
4170 }
5642 }
4171 else if ( tableWidthAttr ) {
5643 else if ( tableWidthAttr ) {
4172 tmpTable.width( tableWidthAttr );
5644 tmpTable.width( tableWidthAttr );
4173 }
5645 }
4174
5646
4175 // Take into account the y scrollbar
5647 // Get the width of each column in the constructed table - we need to
4176 _fnScrollingWidthAdjust( oSettings, tmpTable[0] );
5648 // know the inner width (so it can be assigned to the other table's
4177
5649 // cells) and the outer width so we can calculate the full width of the
4178 // Browsers need a bit of a hand when a width is assigned to any columns
5650 // table. This is safe since DataTables requires a unique cell for each
4179 // when x-scrolling as they tend to collapse the table to the min-width,
5651 // column, but if ever a header can span multiple columns, this will
4180 // even if we sent the column widths. So we need to keep track of what
5652 // need to be modified.
4181 // the table width should be by summing the user given values, and the
4182 // automatic values
4183 if ( scrollX )
4184 {
4185 var total = 0;
5653 var total = 0;
4186
4187 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5654 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4188 column = columns[ visibleColumns[i] ];
5655 var cell = $(headerCells[i]);
4189 outerWidth = $(headerCells[i]).outerWidth();
5656 var border = cell.outerWidth() - cell.width();
4190
5657
4191 total += column.sWidthOrig === null ?
5658 // Use getBounding... where possible (not IE8-) because it can give
4192 outerWidth :
5659 // sub-pixel accuracy, which we then want to round up!
4193 parseInt( column.sWidth, 10 ) + outerWidth - $(headerCells[i]).width();
5660 var bounding = browser.bBounding ?
4194 }
5661 Math.ceil( headerCells[i].getBoundingClientRect().width ) :
4195
5662 cell.outerWidth();
4196 tmpTable.width( _fnStringToCss( total ) );
5663
5664 // Total is tracked to remove any sub-pixel errors as the outerWidth
5665 // of the table might not equal the total given here (IE!).
5666 total += bounding;
5667
5668 // Width for each column to use
5669 columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
5670 }
5671
4197 table.style.width = _fnStringToCss( total );
5672 table.style.width = _fnStringToCss( total );
4198 }
4199
4200 // Get the width of each column in the constructed table
4201 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4202 column = columns[ visibleColumns[i] ];
4203 width = $(headerCells[i]).width();
4204
4205 if ( width ) {
4206 column.sWidth = _fnStringToCss( width );
4207 }
4208 }
4209
4210 table.style.width = _fnStringToCss( tmpTable.css('width') );
4211
5673
4212 // Finished with the table - ditch it
5674 // Finished with the table - ditch it
4213 tmpTable.remove();
5675 holder.remove();
4214 }
5676 }
4215
5677
4216 // If there is a width attr, we want to attach an event listener which
5678 // If there is a width attr, we want to attach an event listener which
@@ -4222,9 +5684,20 b''
4222 }
5684 }
4223
5685
4224 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
5686 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
4225 $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
5687 var bindResize = function () {
5688 $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
4226 _fnAdjustColumnSizing( oSettings );
5689 _fnAdjustColumnSizing( oSettings );
4227 } ) );
5690 } ) );
5691 };
5692
5693 // IE6/7 will crash if we bind a resize event handler on page load.
5694 // To be removed in 1.11 which drops IE6/7 support
5695 if ( ie67 ) {
5696 setTimeout( bindResize, 1000 );
5697 }
5698 else {
5699 bindResize();
5700 }
4228
5701
4229 oSettings._reszEvt = true;
5702 oSettings._reszEvt = true;
4230 }
5703 }
@@ -4239,35 +5712,7 b''
4239 * @returns {function} wrapped function
5712 * @returns {function} wrapped function
4240 * @memberof DataTable#oApi
5713 * @memberof DataTable#oApi
4241 */
5714 */
4242 function _fnThrottle( fn, freq ) {
5715 var _fnThrottle = DataTable.util.throttle;
4243 var
4244 frequency = freq !== undefined ? freq : 200,
4245 last,
4246 timer;
4247
4248 return function () {
4249 var
4250 that = this,
4251 now = +new Date(),
4252 args = arguments;
4253
4254 if ( last && now < last + frequency ) {
4255 clearTimeout( timer );
4256
4257 timer = setTimeout( function () {
4258 last = undefined;
4259 fn.apply( that, args );
4260 }, frequency );
4261 }
4262 else if ( last ) {
4263 last = now;
4264 fn.apply( that, args );
4265 }
4266 else {
4267 last = now;
4268 }
4269 };
4270 }
4271
5716
4272
5717
4273 /**
5718 /**
@@ -4295,27 +5740,6 b''
4295
5740
4296
5741
4297 /**
5742 /**
4298 * Adjust a table's width to take account of vertical scroll bar
4299 * @param {object} oSettings dataTables settings object
4300 * @param {node} n table node
4301 * @memberof DataTable#oApi
4302 */
4303
4304 function _fnScrollingWidthAdjust ( settings, n )
4305 {
4306 var scroll = settings.oScroll;
4307
4308 if ( scroll.sX || scroll.sY ) {
4309 // When y-scrolling only, we want to remove the width of the scroll bar
4310 // so the table + scroll bar will fit into the area available, otherwise
4311 // we fix the table at its current size with no adjustment
4312 var correction = ! scroll.sX ? scroll.iBarWidth : 0;
4313 n.style.width = _fnStringToCss( $(n).outerWidth() - correction );
4314 }
4315 }
4316
4317
4318 /**
4319 * Get the widest node
5743 * Get the widest node
4320 * @param {object} settings dataTables settings object
5744 * @param {object} settings dataTables settings object
4321 * @param {int} colIdx column of interest
5745 * @param {int} colIdx column of interest
@@ -4350,6 +5774,7 b''
4350 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
5774 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4351 s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
5775 s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
4352 s = s.replace( __re_html_remove, '' );
5776 s = s.replace( __re_html_remove, '' );
5777 s = s.replace( /&nbsp;/g, ' ' );
4353
5778
4354 if ( s.length > max ) {
5779 if ( s.length > max ) {
4355 max = s.length;
5780 max = s.length;
@@ -4386,53 +5811,6 b''
4386 }
5811 }
4387
5812
4388
5813
4389 /**
4390 * Get the width of a scroll bar in this browser being used
4391 * @returns {int} width in pixels
4392 * @memberof DataTable#oApi
4393 */
4394 function _fnScrollBarWidth ()
4395 {
4396 // On first run a static variable is set, since this is only needed once.
4397 // Subsequent runs will just use the previously calculated value
4398 if ( ! DataTable.__scrollbarWidth ) {
4399 var inner = $('<p/>').css( {
4400 width: '100%',
4401 height: 200,
4402 padding: 0
4403 } )[0];
4404
4405 var outer = $('<div/>')
4406 .css( {
4407 position: 'absolute',
4408 top: 0,
4409 left: 0,
4410 width: 200,
4411 height: 150,
4412 padding: 0,
4413 overflow: 'hidden',
4414 visibility: 'hidden'
4415 } )
4416 .append( inner )
4417 .appendTo( 'body' );
4418
4419 var w1 = inner.offsetWidth;
4420 outer.css( 'overflow', 'scroll' );
4421 var w2 = inner.offsetWidth;
4422
4423 if ( w1 === w2 ) {
4424 w2 = outer[0].clientWidth;
4425 }
4426
4427 outer.remove();
4428
4429 DataTable.__scrollbarWidth = w1 - w2;
4430 }
4431
4432 return DataTable.__scrollbarWidth;
4433 }
4434
4435
4436
5814
4437 function _fnSortFlatten ( settings )
5815 function _fnSortFlatten ( settings )
4438 {
5816 {
@@ -4452,7 +5830,7 b''
4452 }
5830 }
4453 else {
5831 else {
4454 // 2D array
5832 // 2D array
4455 nestedSort.push.apply( nestedSort, a );
5833 $.merge( nestedSort, a );
4456 }
5834 }
4457 };
5835 };
4458
5836
@@ -4720,6 +6098,10 b''
4720 // Yes, modify the sort
6098 // Yes, modify the sort
4721 nextSortIdx = next( sorting[sortIdx], true );
6099 nextSortIdx = next( sorting[sortIdx], true );
4722
6100
6101 if ( nextSortIdx === null && sorting.length === 1 ) {
6102 nextSortIdx = 0; // can't remove sorting completely
6103 }
6104
4723 if ( nextSortIdx === null ) {
6105 if ( nextSortIdx === null ) {
4724 sorting.splice( sortIdx, 1 );
6106 sorting.splice( sortIdx, 1 );
4725 }
6107 }
@@ -4914,38 +6296,37 b''
4914 * Attempt to load a saved table state
6296 * Attempt to load a saved table state
4915 * @param {object} oSettings dataTables settings object
6297 * @param {object} oSettings dataTables settings object
4916 * @param {object} oInit DataTables init object so we can override settings
6298 * @param {object} oInit DataTables init object so we can override settings
4917 * @memberof DataTable#oApi
6299 * @param {function} callback Callback to execute when the state has been loaded
4918 */
6300 * @memberof DataTable#oApi
4919 function _fnLoadState ( settings, oInit )
6301 */
6302 function _fnLoadState ( settings, oInit, callback )
4920 {
6303 {
4921 var i, ien;
6304 var i, ien;
4922 var columns = settings.aoColumns;
6305 var columns = settings.aoColumns;
4923
6306 var loaded = function ( s ) {
4924 if ( ! settings.oFeatures.bStateSave ) {
6307 if ( ! s || ! s.time ) {
6308 callback();
4925 return;
6309 return;
4926 }
6310 }
4927
6311
4928 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings );
6312 // Allow custom and plug-in manipulation functions to alter the saved data set and
4929 if ( ! state || ! state.time ) {
6313 // cancelling of loading by returning false
4930 return;
4931 }
4932
4933 /* Allow custom and plug-in manipulation functions to alter the saved data set and
4934 * cancelling of loading by returning false
4935 */
4936 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );
6314 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );
4937 if ( $.inArray( false, abStateLoad ) !== -1 ) {
6315 if ( $.inArray( false, abStateLoad ) !== -1 ) {
6316 callback();
4938 return;
6317 return;
4939 }
6318 }
4940
6319
4941 /* Reject old data */
6320 // Reject old data
4942 var duration = settings.iStateDuration;
6321 var duration = settings.iStateDuration;
4943 if ( duration > 0 && state.time < +new Date() - (duration*1000) ) {
6322 if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
6323 callback();
4944 return;
6324 return;
4945 }
6325 }
4946
6326
4947 // Number of columns have changed - all bets are off, no restore of settings
6327 // Number of columns have changed - all bets are off, no restore of settings
4948 if ( columns.length !== state.columns.length ) {
6328 if ( s.columns && columns.length !== s.columns.length ) {
6329 callback();
4949 return;
6330 return;
4950 }
6331 }
4951
6332
@@ -4954,34 +6335,63 b''
4954
6335
4955 // Restore key features - todo - for 1.11 this needs to be done by
6336 // Restore key features - todo - for 1.11 this needs to be done by
4956 // subscribed events
6337 // subscribed events
4957 settings._iDisplayStart = state.start;
6338 if ( s.start !== undefined ) {
4958 settings.iInitDisplayStart = state.start;
6339 settings._iDisplayStart = s.start;
4959 settings._iDisplayLength = state.length;
6340 settings.iInitDisplayStart = s.start;
4960 settings.aaSorting = [];
6341 }
6342 if ( s.length !== undefined ) {
6343 settings._iDisplayLength = s.length;
6344 }
4961
6345
4962 // Order
6346 // Order
4963 $.each( state.order, function ( i, col ) {
6347 if ( s.order !== undefined ) {
6348 settings.aaSorting = [];
6349 $.each( s.order, function ( i, col ) {
4964 settings.aaSorting.push( col[0] >= columns.length ?
6350 settings.aaSorting.push( col[0] >= columns.length ?
4965 [ 0, col[1] ] :
6351 [ 0, col[1] ] :
4966 col
6352 col
4967 );
6353 );
4968 } );
6354 } );
6355 }
4969
6356
4970 // Search
6357 // Search
4971 $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
6358 if ( s.search !== undefined ) {
6359 $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );
6360 }
4972
6361
4973 // Columns
6362 // Columns
4974 for ( i=0, ien=state.columns.length ; i<ien ; i++ ) {
6363 //
4975 var col = state.columns[i];
6364 if ( s.columns ) {
6365 for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
6366 var col = s.columns[i];
4976
6367
4977 // Visibility
6368 // Visibility
6369 if ( col.visible !== undefined ) {
4978 columns[i].bVisible = col.visible;
6370 columns[i].bVisible = col.visible;
6371 }
4979
6372
4980 // Search
6373 // Search
6374 if ( col.search !== undefined ) {
4981 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
6375 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
4982 }
6376 }
6377 }
6378 }
4983
6379
4984 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
6380 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
6381 callback();
6382 }
6383
6384 if ( ! settings.oFeatures.bStateSave ) {
6385 callback();
6386 return;
6387 }
6388
6389 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
6390
6391 if ( state !== undefined ) {
6392 loaded( state );
6393 }
6394 // otherwise, wait for the loaded callback to be executed
4985 }
6395 }
4986
6396
4987
6397
@@ -5013,7 +6423,7 b''
5013 function _fnLog( settings, level, msg, tn )
6423 function _fnLog( settings, level, msg, tn )
5014 {
6424 {
5015 msg = 'DataTables warning: '+
6425 msg = 'DataTables warning: '+
5016 (settings!==null ? 'table id='+settings.sTableId+' - ' : '')+msg;
6426 (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
5017
6427
5018 if ( tn ) {
6428 if ( tn ) {
5019 msg += '. For more information about this error, please see '+
6429 msg += '. For more information about this error, please see '+
@@ -5025,12 +6435,19 b''
5025 var ext = DataTable.ext;
6435 var ext = DataTable.ext;
5026 var type = ext.sErrMode || ext.errMode;
6436 var type = ext.sErrMode || ext.errMode;
5027
6437
6438 if ( settings ) {
6439 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
6440 }
6441
5028 if ( type == 'alert' ) {
6442 if ( type == 'alert' ) {
5029 alert( msg );
6443 alert( msg );
5030 }
6444 }
5031 else {
6445 else if ( type == 'throw' ) {
5032 throw new Error(msg);
6446 throw new Error(msg);
5033 }
6447 }
6448 else if ( typeof type == 'function' ) {
6449 type( settings, tn, msg );
6450 }
5034 }
6451 }
5035 else if ( window.console && console.log ) {
6452 else if ( window.console && console.log ) {
5036 console.log( msg );
6453 console.log( msg );
@@ -5127,17 +6544,17 b''
5127 function _fnBindAction( n, oData, fn )
6544 function _fnBindAction( n, oData, fn )
5128 {
6545 {
5129 $(n)
6546 $(n)
5130 .bind( 'click.DT', oData, function (e) {
6547 .on( 'click.DT', oData, function (e) {
5131 n.blur(); // Remove focus outline for mouse users
6548 n.blur(); // Remove focus outline for mouse users
5132 fn(e);
6549 fn(e);
5133 } )
6550 } )
5134 .bind( 'keypress.DT', oData, function (e){
6551 .on( 'keypress.DT', oData, function (e){
5135 if ( e.which === 13 ) {
6552 if ( e.which === 13 ) {
5136 e.preventDefault();
6553 e.preventDefault();
5137 fn(e);
6554 fn(e);
5138 }
6555 }
5139 } )
6556 } )
5140 .bind( 'selectstart.DT', function () {
6557 .on( 'selectstart.DT', function () {
5141 /* Take the brutal approach to cancelling text selection */
6558 /* Take the brutal approach to cancelling text selection */
5142 return false;
6559 return false;
5143 } );
6560 } );
@@ -5173,13 +6590,13 b''
5173 * @param {object} settings dataTables settings object
6590 * @param {object} settings dataTables settings object
5174 * @param {string} callbackArr Name of the array storage for the callbacks in
6591 * @param {string} callbackArr Name of the array storage for the callbacks in
5175 * oSettings
6592 * oSettings
5176 * @param {string} event Name of the jQuery custom event to trigger. If null no
6593 * @param {string} eventName Name of the jQuery custom event to trigger. If
5177 * trigger is fired
6594 * null no trigger is fired
5178 * @param {array} args Array of arguments to pass to the callback function /
6595 * @param {array} args Array of arguments to pass to the callback function /
5179 * trigger
6596 * trigger
5180 * @memberof DataTable#oApi
6597 * @memberof DataTable#oApi
5181 */
6598 */
5182 function _fnCallbackFire( settings, callbackArr, e, args )
6599 function _fnCallbackFire( settings, callbackArr, eventName, args )
5183 {
6600 {
5184 var ret = [];
6601 var ret = [];
5185
6602
@@ -5189,8 +6606,12 b''
5189 } );
6606 } );
5190 }
6607 }
5191
6608
5192 if ( e !== null ) {
6609 if ( eventName !== null ) {
5193 $(settings.nTable).trigger( e+'.dt', args );
6610 var e = $.Event( eventName+'.dt' );
6611
6612 $(settings.nTable).trigger( e, args );
6613
6614 ret.push( e.result );
5194 }
6615 }
5195
6616
5196 return ret;
6617 return ret;
@@ -5263,1257 +6684,6 b''
5263 }
6684 }
5264
6685
5265
6686
5266 DataTable = function( options )
5267 {
5268 /**
5269 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
5270 * return the resulting jQuery object.
5271 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5272 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
5273 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
5274 * criterion ("applied") or all TR elements (i.e. no filter).
5275 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
5276 * Can be either 'current', whereby the current sorting of the table is used, or
5277 * 'original' whereby the original order the data was read into the table is used.
5278 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5279 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
5280 * 'current' and filter is 'applied', regardless of what they might be given as.
5281 * @returns {object} jQuery object, filtered by the given selector.
5282 * @dtopt API
5283 * @deprecated Since v1.10
5284 *
5285 * @example
5286 * $(document).ready(function() {
5287 * var oTable = $('#example').dataTable();
5288 *
5289 * // Highlight every second row
5290 * oTable.$('tr:odd').css('backgroundColor', 'blue');
5291 * } );
5292 *
5293 * @example
5294 * $(document).ready(function() {
5295 * var oTable = $('#example').dataTable();
5296 *
5297 * // Filter to rows with 'Webkit' in them, add a background colour and then
5298 * // remove the filter, thus highlighting the 'Webkit' rows only.
5299 * oTable.fnFilter('Webkit');
5300 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
5301 * oTable.fnFilter('');
5302 * } );
5303 */
5304 this.$ = function ( sSelector, oOpts )
5305 {
5306 return this.api(true).$( sSelector, oOpts );
5307 };
5308
5309
5310 /**
5311 * Almost identical to $ in operation, but in this case returns the data for the matched
5312 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
5313 * rather than any descendants, so the data can be obtained for the row/cell. If matching
5314 * rows are found, the data returned is the original data array/object that was used to
5315 * create the row (or a generated array if from a DOM source).
5316 *
5317 * This method is often useful in-combination with $ where both functions are given the
5318 * same parameters and the array indexes will match identically.
5319 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5320 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
5321 * @param {string} [oOpts.filter=none] Select elements that meet the current filter
5322 * criterion ("applied") or all elements (i.e. no filter).
5323 * @param {string} [oOpts.order=current] Order of the data in the processed array.
5324 * Can be either 'current', whereby the current sorting of the table is used, or
5325 * 'original' whereby the original order the data was read into the table is used.
5326 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5327 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
5328 * 'current' and filter is 'applied', regardless of what they might be given as.
5329 * @returns {array} Data for the matched elements. If any elements, as a result of the
5330 * selector, were not TR, TD or TH elements in the DataTable, they will have a null
5331 * entry in the array.
5332 * @dtopt API
5333 * @deprecated Since v1.10
5334 *
5335 * @example
5336 * $(document).ready(function() {
5337 * var oTable = $('#example').dataTable();
5338 *
5339 * // Get the data from the first row in the table
5340 * var data = oTable._('tr:first');
5341 *
5342 * // Do something useful with the data
5343 * alert( "First cell is: "+data[0] );
5344 * } );
5345 *
5346 * @example
5347 * $(document).ready(function() {
5348 * var oTable = $('#example').dataTable();
5349 *
5350 * // Filter to 'Webkit' and get all data for
5351 * oTable.fnFilter('Webkit');
5352 * var data = oTable._('tr', {"search": "applied"});
5353 *
5354 * // Do something with the data
5355 * alert( data.length+" rows matched the search" );
5356 * } );
5357 */
5358 this._ = function ( sSelector, oOpts )
5359 {
5360 return this.api(true).rows( sSelector, oOpts ).data();
5361 };
5362
5363
5364 /**
5365 * Create a DataTables Api instance, with the currently selected tables for
5366 * the Api's context.
5367 * @param {boolean} [traditional=false] Set the API instance's context to be
5368 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
5369 * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
5370 * or if all tables captured in the jQuery object should be used.
5371 * @return {DataTables.Api}
5372 */
5373 this.api = function ( traditional )
5374 {
5375 return traditional ?
5376 new _Api(
5377 _fnSettingsFromNode( this[ _ext.iApiIndex ] )
5378 ) :
5379 new _Api( this );
5380 };
5381
5382
5383 /**
5384 * Add a single new row or multiple rows of data to the table. Please note
5385 * that this is suitable for client-side processing only - if you are using
5386 * server-side processing (i.e. "bServerSide": true), then to add data, you
5387 * must add it to the data source, i.e. the server-side, through an Ajax call.
5388 * @param {array|object} data The data to be added to the table. This can be:
5389 * <ul>
5390 * <li>1D array of data - add a single row with the data provided</li>
5391 * <li>2D array of arrays - add multiple rows in a single call</li>
5392 * <li>object - data object when using <i>mData</i></li>
5393 * <li>array of objects - multiple data objects when using <i>mData</i></li>
5394 * </ul>
5395 * @param {bool} [redraw=true] redraw the table or not
5396 * @returns {array} An array of integers, representing the list of indexes in
5397 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
5398 * the table.
5399 * @dtopt API
5400 * @deprecated Since v1.10
5401 *
5402 * @example
5403 * // Global var for counter
5404 * var giCount = 2;
5405 *
5406 * $(document).ready(function() {
5407 * $('#example').dataTable();
5408 * } );
5409 *
5410 * function fnClickAddRow() {
5411 * $('#example').dataTable().fnAddData( [
5412 * giCount+".1",
5413 * giCount+".2",
5414 * giCount+".3",
5415 * giCount+".4" ]
5416 * );
5417 *
5418 * giCount++;
5419 * }
5420 */
5421 this.fnAddData = function( data, redraw )
5422 {
5423 var api = this.api( true );
5424
5425 /* Check if we want to add multiple rows or not */
5426 var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
5427 api.rows.add( data ) :
5428 api.row.add( data );
5429
5430 if ( redraw === undefined || redraw ) {
5431 api.draw();
5432 }
5433
5434 return rows.flatten().toArray();
5435 };
5436
5437
5438 /**
5439 * This function will make DataTables recalculate the column sizes, based on the data
5440 * contained in the table and the sizes applied to the columns (in the DOM, CSS or
5441 * through the sWidth parameter). This can be useful when the width of the table's
5442 * parent element changes (for example a window resize).
5443 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
5444 * @dtopt API
5445 * @deprecated Since v1.10
5446 *
5447 * @example
5448 * $(document).ready(function() {
5449 * var oTable = $('#example').dataTable( {
5450 * "sScrollY": "200px",
5451 * "bPaginate": false
5452 * } );
5453 *
5454 * $(window).bind('resize', function () {
5455 * oTable.fnAdjustColumnSizing();
5456 * } );
5457 * } );
5458 */
5459 this.fnAdjustColumnSizing = function ( bRedraw )
5460 {
5461 var api = this.api( true ).columns.adjust();
5462 var settings = api.settings()[0];
5463 var scroll = settings.oScroll;
5464
5465 if ( bRedraw === undefined || bRedraw ) {
5466 api.draw( false );
5467 }
5468 else if ( scroll.sX !== "" || scroll.sY !== "" ) {
5469 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
5470 _fnScrollDraw( settings );
5471 }
5472 };
5473
5474
5475 /**
5476 * Quickly and simply clear a table
5477 * @param {bool} [bRedraw=true] redraw the table or not
5478 * @dtopt API
5479 * @deprecated Since v1.10
5480 *
5481 * @example
5482 * $(document).ready(function() {
5483 * var oTable = $('#example').dataTable();
5484 *
5485 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
5486 * oTable.fnClearTable();
5487 * } );
5488 */
5489 this.fnClearTable = function( bRedraw )
5490 {
5491 var api = this.api( true ).clear();
5492
5493 if ( bRedraw === undefined || bRedraw ) {
5494 api.draw();
5495 }
5496 };
5497
5498
5499 /**
5500 * The exact opposite of 'opening' a row, this function will close any rows which
5501 * are currently 'open'.
5502 * @param {node} nTr the table row to 'close'
5503 * @returns {int} 0 on success, or 1 if failed (can't find the row)
5504 * @dtopt API
5505 * @deprecated Since v1.10
5506 *
5507 * @example
5508 * $(document).ready(function() {
5509 * var oTable;
5510 *
5511 * // 'open' an information row when a row is clicked on
5512 * $('#example tbody tr').click( function () {
5513 * if ( oTable.fnIsOpen(this) ) {
5514 * oTable.fnClose( this );
5515 * } else {
5516 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5517 * }
5518 * } );
5519 *
5520 * oTable = $('#example').dataTable();
5521 * } );
5522 */
5523 this.fnClose = function( nTr )
5524 {
5525 this.api( true ).row( nTr ).child.hide();
5526 };
5527
5528
5529 /**
5530 * Remove a row for the table
5531 * @param {mixed} target The index of the row from aoData to be deleted, or
5532 * the TR element you want to delete
5533 * @param {function|null} [callBack] Callback function
5534 * @param {bool} [redraw=true] Redraw the table or not
5535 * @returns {array} The row that was deleted
5536 * @dtopt API
5537 * @deprecated Since v1.10
5538 *
5539 * @example
5540 * $(document).ready(function() {
5541 * var oTable = $('#example').dataTable();
5542 *
5543 * // Immediately remove the first row
5544 * oTable.fnDeleteRow( 0 );
5545 * } );
5546 */
5547 this.fnDeleteRow = function( target, callback, redraw )
5548 {
5549 var api = this.api( true );
5550 var rows = api.rows( target );
5551 var settings = rows.settings()[0];
5552 var data = settings.aoData[ rows[0][0] ];
5553
5554 rows.remove();
5555
5556 if ( callback ) {
5557 callback.call( this, settings, data );
5558 }
5559
5560 if ( redraw === undefined || redraw ) {
5561 api.draw();
5562 }
5563
5564 return data;
5565 };
5566
5567
5568 /**
5569 * Restore the table to it's original state in the DOM by removing all of DataTables
5570 * enhancements, alterations to the DOM structure of the table and event listeners.
5571 * @param {boolean} [remove=false] Completely remove the table from the DOM
5572 * @dtopt API
5573 * @deprecated Since v1.10
5574 *
5575 * @example
5576 * $(document).ready(function() {
5577 * // This example is fairly pointless in reality, but shows how fnDestroy can be used
5578 * var oTable = $('#example').dataTable();
5579 * oTable.fnDestroy();
5580 * } );
5581 */
5582 this.fnDestroy = function ( remove )
5583 {
5584 this.api( true ).destroy( remove );
5585 };
5586
5587
5588 /**
5589 * Redraw the table
5590 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
5591 * @dtopt API
5592 * @deprecated Since v1.10
5593 *
5594 * @example
5595 * $(document).ready(function() {
5596 * var oTable = $('#example').dataTable();
5597 *
5598 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
5599 * oTable.fnDraw();
5600 * } );
5601 */
5602 this.fnDraw = function( complete )
5603 {
5604 // Note that this isn't an exact match to the old call to _fnDraw - it takes
5605 // into account the new data, but can old position.
5606 this.api( true ).draw( ! complete );
5607 };
5608
5609
5610 /**
5611 * Filter the input based on data
5612 * @param {string} sInput String to filter the table on
5613 * @param {int|null} [iColumn] Column to limit filtering to
5614 * @param {bool} [bRegex=false] Treat as regular expression or not
5615 * @param {bool} [bSmart=true] Perform smart filtering or not
5616 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
5617 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
5618 * @dtopt API
5619 * @deprecated Since v1.10
5620 *
5621 * @example
5622 * $(document).ready(function() {
5623 * var oTable = $('#example').dataTable();
5624 *
5625 * // Sometime later - filter...
5626 * oTable.fnFilter( 'test string' );
5627 * } );
5628 */
5629 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
5630 {
5631 var api = this.api( true );
5632
5633 if ( iColumn === null || iColumn === undefined ) {
5634 api.search( sInput, bRegex, bSmart, bCaseInsensitive );
5635 }
5636 else {
5637 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
5638 }
5639
5640 api.draw();
5641 };
5642
5643
5644 /**
5645 * Get the data for the whole table, an individual row or an individual cell based on the
5646 * provided parameters.
5647 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
5648 * a TR node then the data source for the whole row will be returned. If given as a
5649 * TD/TH cell node then iCol will be automatically calculated and the data for the
5650 * cell returned. If given as an integer, then this is treated as the aoData internal
5651 * data index for the row (see fnGetPosition) and the data for that row used.
5652 * @param {int} [col] Optional column index that you want the data of.
5653 * @returns {array|object|string} If mRow is undefined, then the data for all rows is
5654 * returned. If mRow is defined, just data for that row, and is iCol is
5655 * defined, only data for the designated cell is returned.
5656 * @dtopt API
5657 * @deprecated Since v1.10
5658 *
5659 * @example
5660 * // Row data
5661 * $(document).ready(function() {
5662 * oTable = $('#example').dataTable();
5663 *
5664 * oTable.$('tr').click( function () {
5665 * var data = oTable.fnGetData( this );
5666 * // ... do something with the array / object of data for the row
5667 * } );
5668 * } );
5669 *
5670 * @example
5671 * // Individual cell data
5672 * $(document).ready(function() {
5673 * oTable = $('#example').dataTable();
5674 *
5675 * oTable.$('td').click( function () {
5676 * var sData = oTable.fnGetData( this );
5677 * alert( 'The cell clicked on had the value of '+sData );
5678 * } );
5679 * } );
5680 */
5681 this.fnGetData = function( src, col )
5682 {
5683 var api = this.api( true );
5684
5685 if ( src !== undefined ) {
5686 var type = src.nodeName ? src.nodeName.toLowerCase() : '';
5687
5688 return col !== undefined || type == 'td' || type == 'th' ?
5689 api.cell( src, col ).data() :
5690 api.row( src ).data() || null;
5691 }
5692
5693 return api.data().toArray();
5694 };
5695
5696
5697 /**
5698 * Get an array of the TR nodes that are used in the table's body. Note that you will
5699 * typically want to use the '$' API method in preference to this as it is more
5700 * flexible.
5701 * @param {int} [iRow] Optional row index for the TR element you want
5702 * @returns {array|node} If iRow is undefined, returns an array of all TR elements
5703 * in the table's body, or iRow is defined, just the TR element requested.
5704 * @dtopt API
5705 * @deprecated Since v1.10
5706 *
5707 * @example
5708 * $(document).ready(function() {
5709 * var oTable = $('#example').dataTable();
5710 *
5711 * // Get the nodes from the table
5712 * var nNodes = oTable.fnGetNodes( );
5713 * } );
5714 */
5715 this.fnGetNodes = function( iRow )
5716 {
5717 var api = this.api( true );
5718
5719 return iRow !== undefined ?
5720 api.row( iRow ).node() :
5721 api.rows().nodes().flatten().toArray();
5722 };
5723
5724
5725 /**
5726 * Get the array indexes of a particular cell from it's DOM element
5727 * and column index including hidden columns
5728 * @param {node} node this can either be a TR, TD or TH in the table's body
5729 * @returns {int} If nNode is given as a TR, then a single index is returned, or
5730 * if given as a cell, an array of [row index, column index (visible),
5731 * column index (all)] is given.
5732 * @dtopt API
5733 * @deprecated Since v1.10
5734 *
5735 * @example
5736 * $(document).ready(function() {
5737 * $('#example tbody td').click( function () {
5738 * // Get the position of the current data from the node
5739 * var aPos = oTable.fnGetPosition( this );
5740 *
5741 * // Get the data array for this row
5742 * var aData = oTable.fnGetData( aPos[0] );
5743 *
5744 * // Update the data array and return the value
5745 * aData[ aPos[1] ] = 'clicked';
5746 * this.innerHTML = 'clicked';
5747 * } );
5748 *
5749 * // Init DataTables
5750 * oTable = $('#example').dataTable();
5751 * } );
5752 */
5753 this.fnGetPosition = function( node )
5754 {
5755 var api = this.api( true );
5756 var nodeName = node.nodeName.toUpperCase();
5757
5758 if ( nodeName == 'TR' ) {
5759 return api.row( node ).index();
5760 }
5761 else if ( nodeName == 'TD' || nodeName == 'TH' ) {
5762 var cell = api.cell( node ).index();
5763
5764 return [
5765 cell.row,
5766 cell.columnVisible,
5767 cell.column
5768 ];
5769 }
5770 return null;
5771 };
5772
5773
5774 /**
5775 * Check to see if a row is 'open' or not.
5776 * @param {node} nTr the table row to check
5777 * @returns {boolean} true if the row is currently open, false otherwise
5778 * @dtopt API
5779 * @deprecated Since v1.10
5780 *
5781 * @example
5782 * $(document).ready(function() {
5783 * var oTable;
5784 *
5785 * // 'open' an information row when a row is clicked on
5786 * $('#example tbody tr').click( function () {
5787 * if ( oTable.fnIsOpen(this) ) {
5788 * oTable.fnClose( this );
5789 * } else {
5790 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5791 * }
5792 * } );
5793 *
5794 * oTable = $('#example').dataTable();
5795 * } );
5796 */
5797 this.fnIsOpen = function( nTr )
5798 {
5799 return this.api( true ).row( nTr ).child.isShown();
5800 };
5801
5802
5803 /**
5804 * This function will place a new row directly after a row which is currently
5805 * on display on the page, with the HTML contents that is passed into the
5806 * function. This can be used, for example, to ask for confirmation that a
5807 * particular record should be deleted.
5808 * @param {node} nTr The table row to 'open'
5809 * @param {string|node|jQuery} mHtml The HTML to put into the row
5810 * @param {string} sClass Class to give the new TD cell
5811 * @returns {node} The row opened. Note that if the table row passed in as the
5812 * first parameter, is not found in the table, this method will silently
5813 * return.
5814 * @dtopt API
5815 * @deprecated Since v1.10
5816 *
5817 * @example
5818 * $(document).ready(function() {
5819 * var oTable;
5820 *
5821 * // 'open' an information row when a row is clicked on
5822 * $('#example tbody tr').click( function () {
5823 * if ( oTable.fnIsOpen(this) ) {
5824 * oTable.fnClose( this );
5825 * } else {
5826 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5827 * }
5828 * } );
5829 *
5830 * oTable = $('#example').dataTable();
5831 * } );
5832 */
5833 this.fnOpen = function( nTr, mHtml, sClass )
5834 {
5835 return this.api( true )
5836 .row( nTr )
5837 .child( mHtml, sClass )
5838 .show()
5839 .child()[0];
5840 };
5841
5842
5843 /**
5844 * Change the pagination - provides the internal logic for pagination in a simple API
5845 * function. With this function you can have a DataTables table go to the next,
5846 * previous, first or last pages.
5847 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
5848 * or page number to jump to (integer), note that page 0 is the first page.
5849 * @param {bool} [bRedraw=true] Redraw the table or not
5850 * @dtopt API
5851 * @deprecated Since v1.10
5852 *
5853 * @example
5854 * $(document).ready(function() {
5855 * var oTable = $('#example').dataTable();
5856 * oTable.fnPageChange( 'next' );
5857 * } );
5858 */
5859 this.fnPageChange = function ( mAction, bRedraw )
5860 {
5861 var api = this.api( true ).page( mAction );
5862
5863 if ( bRedraw === undefined || bRedraw ) {
5864 api.draw(false);
5865 }
5866 };
5867
5868
5869 /**
5870 * Show a particular column
5871 * @param {int} iCol The column whose display should be changed
5872 * @param {bool} bShow Show (true) or hide (false) the column
5873 * @param {bool} [bRedraw=true] Redraw the table or not
5874 * @dtopt API
5875 * @deprecated Since v1.10
5876 *
5877 * @example
5878 * $(document).ready(function() {
5879 * var oTable = $('#example').dataTable();
5880 *
5881 * // Hide the second column after initialisation
5882 * oTable.fnSetColumnVis( 1, false );
5883 * } );
5884 */
5885 this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
5886 {
5887 var api = this.api( true ).column( iCol ).visible( bShow );
5888
5889 if ( bRedraw === undefined || bRedraw ) {
5890 api.columns.adjust().draw();
5891 }
5892 };
5893
5894
5895 /**
5896 * Get the settings for a particular table for external manipulation
5897 * @returns {object} DataTables settings object. See
5898 * {@link DataTable.models.oSettings}
5899 * @dtopt API
5900 * @deprecated Since v1.10
5901 *
5902 * @example
5903 * $(document).ready(function() {
5904 * var oTable = $('#example').dataTable();
5905 * var oSettings = oTable.fnSettings();
5906 *
5907 * // Show an example parameter from the settings
5908 * alert( oSettings._iDisplayStart );
5909 * } );
5910 */
5911 this.fnSettings = function()
5912 {
5913 return _fnSettingsFromNode( this[_ext.iApiIndex] );
5914 };
5915
5916
5917 /**
5918 * Sort the table by a particular column
5919 * @param {int} iCol the data index to sort on. Note that this will not match the
5920 * 'display index' if you have hidden data entries
5921 * @dtopt API
5922 * @deprecated Since v1.10
5923 *
5924 * @example
5925 * $(document).ready(function() {
5926 * var oTable = $('#example').dataTable();
5927 *
5928 * // Sort immediately with columns 0 and 1
5929 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
5930 * } );
5931 */
5932 this.fnSort = function( aaSort )
5933 {
5934 this.api( true ).order( aaSort ).draw();
5935 };
5936
5937
5938 /**
5939 * Attach a sort listener to an element for a given column
5940 * @param {node} nNode the element to attach the sort listener to
5941 * @param {int} iColumn the column that a click on this node will sort on
5942 * @param {function} [fnCallback] callback function when sort is run
5943 * @dtopt API
5944 * @deprecated Since v1.10
5945 *
5946 * @example
5947 * $(document).ready(function() {
5948 * var oTable = $('#example').dataTable();
5949 *
5950 * // Sort on column 1, when 'sorter' is clicked on
5951 * oTable.fnSortListener( document.getElementById('sorter'), 1 );
5952 * } );
5953 */
5954 this.fnSortListener = function( nNode, iColumn, fnCallback )
5955 {
5956 this.api( true ).order.listener( nNode, iColumn, fnCallback );
5957 };
5958
5959
5960 /**
5961 * Update a table cell or row - this method will accept either a single value to
5962 * update the cell with, an array of values with one element for each column or
5963 * an object in the same format as the original data source. The function is
5964 * self-referencing in order to make the multi column updates easier.
5965 * @param {object|array|string} mData Data to update the cell/row with
5966 * @param {node|int} mRow TR element you want to update or the aoData index
5967 * @param {int} [iColumn] The column to update, give as null or undefined to
5968 * update a whole row.
5969 * @param {bool} [bRedraw=true] Redraw the table or not
5970 * @param {bool} [bAction=true] Perform pre-draw actions or not
5971 * @returns {int} 0 on success, 1 on error
5972 * @dtopt API
5973 * @deprecated Since v1.10
5974 *
5975 * @example
5976 * $(document).ready(function() {
5977 * var oTable = $('#example').dataTable();
5978 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
5979 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
5980 * } );
5981 */
5982 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
5983 {
5984 var api = this.api( true );
5985
5986 if ( iColumn === undefined || iColumn === null ) {
5987 api.row( mRow ).data( mData );
5988 }
5989 else {
5990 api.cell( mRow, iColumn ).data( mData );
5991 }
5992
5993 if ( bAction === undefined || bAction ) {
5994 api.columns.adjust();
5995 }
5996
5997 if ( bRedraw === undefined || bRedraw ) {
5998 api.draw();
5999 }
6000 return 0;
6001 };
6002
6003
6004 /**
6005 * Provide a common method for plug-ins to check the version of DataTables being used, in order
6006 * to ensure compatibility.
6007 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
6008 * formats "X" and "X.Y" are also acceptable.
6009 * @returns {boolean} true if this version of DataTables is greater or equal to the required
6010 * version, or false if this version of DataTales is not suitable
6011 * @method
6012 * @dtopt API
6013 * @deprecated Since v1.10
6014 *
6015 * @example
6016 * $(document).ready(function() {
6017 * var oTable = $('#example').dataTable();
6018 * alert( oTable.fnVersionCheck( '1.9.0' ) );
6019 * } );
6020 */
6021 this.fnVersionCheck = _ext.fnVersionCheck;
6022
6023
6024 var _that = this;
6025 var emptyInit = options === undefined;
6026 var len = this.length;
6027
6028 if ( emptyInit ) {
6029 options = {};
6030 }
6031
6032 this.oApi = this.internal = _ext.internal;
6033
6034 // Extend with old style plug-in API methods
6035 for ( var fn in DataTable.ext.internal ) {
6036 if ( fn ) {
6037 this[fn] = _fnExternApiFunc(fn);
6038 }
6039 }
6040
6041 this.each(function() {
6042 // For each initialisation we want to give it a clean initialisation
6043 // object that can be bashed around
6044 var o = {};
6045 var oInit = len > 1 ? // optimisation for single table case
6046 _fnExtend( o, options, true ) :
6047 options;
6048
6049 /*global oInit,_that,emptyInit*/
6050 var i=0, iLen, j, jLen, k, kLen;
6051 var sId = this.getAttribute( 'id' );
6052 var bInitHandedOff = false;
6053 var defaults = DataTable.defaults;
6054
6055
6056 /* Sanity check */
6057 if ( this.nodeName.toLowerCase() != 'table' )
6058 {
6059 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
6060 return;
6061 }
6062
6063 /* Backwards compatibility for the defaults */
6064 _fnCompatOpts( defaults );
6065 _fnCompatCols( defaults.column );
6066
6067 /* Convert the camel-case defaults to Hungarian */
6068 _fnCamelToHungarian( defaults, defaults, true );
6069 _fnCamelToHungarian( defaults.column, defaults.column, true );
6070
6071 /* Setting up the initialisation object */
6072 _fnCamelToHungarian( defaults, oInit );
6073
6074 /* Check to see if we are re-initialising a table */
6075 var allSettings = DataTable.settings;
6076 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
6077 {
6078 /* Base check on table node */
6079 if ( allSettings[i].nTable == this )
6080 {
6081 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
6082 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
6083
6084 if ( emptyInit || bRetrieve )
6085 {
6086 return allSettings[i].oInstance;
6087 }
6088 else if ( bDestroy )
6089 {
6090 allSettings[i].oInstance.fnDestroy();
6091 break;
6092 }
6093 else
6094 {
6095 _fnLog( allSettings[i], 0, 'Cannot reinitialise DataTable', 3 );
6096 return;
6097 }
6098 }
6099
6100 /* If the element we are initialising has the same ID as a table which was previously
6101 * initialised, but the table nodes don't match (from before) then we destroy the old
6102 * instance by simply deleting it. This is under the assumption that the table has been
6103 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
6104 */
6105 if ( allSettings[i].sTableId == this.id )
6106 {
6107 allSettings.splice( i, 1 );
6108 break;
6109 }
6110 }
6111
6112 /* Ensure the table has an ID - required for accessibility */
6113 if ( sId === null || sId === "" )
6114 {
6115 sId = "DataTables_Table_"+(DataTable.ext._unique++);
6116 this.id = sId;
6117 }
6118
6119 /* Create the settings object for this table and set some of the default parameters */
6120 var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
6121 "nTable": this,
6122 "oApi": _that.internal,
6123 "oInit": oInit,
6124 "sDestroyWidth": $(this)[0].style.width,
6125 "sInstance": sId,
6126 "sTableId": sId
6127 } );
6128 allSettings.push( oSettings );
6129
6130 // Need to add the instance after the instance after the settings object has been added
6131 // to the settings array, so we can self reference the table instance if more than one
6132 oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable();
6133
6134 // Backwards compatibility, before we apply all the defaults
6135 _fnCompatOpts( oInit );
6136
6137 if ( oInit.oLanguage )
6138 {
6139 _fnLanguageCompat( oInit.oLanguage );
6140 }
6141
6142 // If the length menu is given, but the init display length is not, use the length menu
6143 if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
6144 {
6145 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
6146 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
6147 }
6148
6149 // Apply the defaults and init options to make a single init object will all
6150 // options defined from defaults and instance options.
6151 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
6152
6153
6154 // Map the initialisation options onto the settings object
6155 _fnMap( oSettings.oFeatures, oInit, [
6156 "bPaginate",
6157 "bLengthChange",
6158 "bFilter",
6159 "bSort",
6160 "bSortMulti",
6161 "bInfo",
6162 "bProcessing",
6163 "bAutoWidth",
6164 "bSortClasses",
6165 "bServerSide",
6166 "bDeferRender"
6167 ] );
6168 _fnMap( oSettings, oInit, [
6169 "asStripeClasses",
6170 "ajax",
6171 "fnServerData",
6172 "fnFormatNumber",
6173 "sServerMethod",
6174 "aaSorting",
6175 "aaSortingFixed",
6176 "aLengthMenu",
6177 "sPaginationType",
6178 "sAjaxSource",
6179 "sAjaxDataProp",
6180 "iStateDuration",
6181 "sDom",
6182 "bSortCellsTop",
6183 "iTabIndex",
6184 "fnStateLoadCallback",
6185 "fnStateSaveCallback",
6186 "renderer",
6187 "searchDelay",
6188 [ "iCookieDuration", "iStateDuration" ], // backwards compat
6189 [ "oSearch", "oPreviousSearch" ],
6190 [ "aoSearchCols", "aoPreSearchCols" ],
6191 [ "iDisplayLength", "_iDisplayLength" ],
6192 [ "bJQueryUI", "bJUI" ]
6193 ] );
6194 _fnMap( oSettings.oScroll, oInit, [
6195 [ "sScrollX", "sX" ],
6196 [ "sScrollXInner", "sXInner" ],
6197 [ "sScrollY", "sY" ],
6198 [ "bScrollCollapse", "bCollapse" ]
6199 ] );
6200 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
6201
6202 /* Callback functions which are array driven */
6203 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
6204 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
6205 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
6206 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
6207 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
6208 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
6209 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
6210 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
6211 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
6212 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
6213 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
6214
6215 var oClasses = oSettings.oClasses;
6216
6217 // @todo Remove in 1.11
6218 if ( oInit.bJQueryUI )
6219 {
6220 /* Use the JUI classes object for display. You could clone the oStdClasses object if
6221 * you want to have multiple tables with multiple independent classes
6222 */
6223 $.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );
6224
6225 if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" )
6226 {
6227 /* Set the DOM to use a layout suitable for jQuery UI's theming */
6228 oSettings.sDom = '<"H"lfr>t<"F"ip>';
6229 }
6230
6231 if ( ! oSettings.renderer ) {
6232 oSettings.renderer = 'jqueryui';
6233 }
6234 else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {
6235 oSettings.renderer.header = 'jqueryui';
6236 }
6237 }
6238 else
6239 {
6240 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
6241 }
6242 $(this).addClass( oClasses.sTable );
6243
6244 /* Calculate the scroll bar width and cache it for use later on */
6245 if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
6246 {
6247 oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
6248 }
6249 if ( oSettings.oScroll.sX === true ) { // Easy initialisation of x-scrolling
6250 oSettings.oScroll.sX = '100%';
6251 }
6252
6253 if ( oSettings.iInitDisplayStart === undefined )
6254 {
6255 /* Display start point, taking into account the save saving */
6256 oSettings.iInitDisplayStart = oInit.iDisplayStart;
6257 oSettings._iDisplayStart = oInit.iDisplayStart;
6258 }
6259
6260 if ( oInit.iDeferLoading !== null )
6261 {
6262 oSettings.bDeferLoading = true;
6263 var tmp = $.isArray( oInit.iDeferLoading );
6264 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
6265 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
6266 }
6267
6268 /* Language definitions */
6269 var oLanguage = oSettings.oLanguage;
6270 $.extend( true, oLanguage, oInit.oLanguage );
6271
6272 if ( oLanguage.sUrl !== "" )
6273 {
6274 /* Get the language definitions from a file - because this Ajax call makes the language
6275 * get async to the remainder of this function we use bInitHandedOff to indicate that
6276 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
6277 */
6278 $.ajax( {
6279 dataType: 'json',
6280 url: oLanguage.sUrl,
6281 success: function ( json ) {
6282 _fnLanguageCompat( json );
6283 _fnCamelToHungarian( defaults.oLanguage, json );
6284 $.extend( true, oLanguage, json );
6285 _fnInitialise( oSettings );
6286 },
6287 error: function () {
6288 // Error occurred loading language file, continue on as best we can
6289 _fnInitialise( oSettings );
6290 }
6291 } );
6292 bInitHandedOff = true;
6293 }
6294
6295 /*
6296 * Stripes
6297 */
6298 if ( oInit.asStripeClasses === null )
6299 {
6300 oSettings.asStripeClasses =[
6301 oClasses.sStripeOdd,
6302 oClasses.sStripeEven
6303 ];
6304 }
6305
6306 /* Remove row stripe classes if they are already on the table row */
6307 var stripeClasses = oSettings.asStripeClasses;
6308 var rowOne = $('tbody tr:eq(0)', this);
6309 if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
6310 return rowOne.hasClass(el);
6311 } ) ) !== -1 ) {
6312 $('tbody tr', this).removeClass( stripeClasses.join(' ') );
6313 oSettings.asDestroyStripes = stripeClasses.slice();
6314 }
6315
6316 /*
6317 * Columns
6318 * See if we should load columns automatically or use defined ones
6319 */
6320 var anThs = [];
6321 var aoColumnsInit;
6322 var nThead = this.getElementsByTagName('thead');
6323 if ( nThead.length !== 0 )
6324 {
6325 _fnDetectHeader( oSettings.aoHeader, nThead[0] );
6326 anThs = _fnGetUniqueThs( oSettings );
6327 }
6328
6329 /* If not given a column array, generate one with nulls */
6330 if ( oInit.aoColumns === null )
6331 {
6332 aoColumnsInit = [];
6333 for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
6334 {
6335 aoColumnsInit.push( null );
6336 }
6337 }
6338 else
6339 {
6340 aoColumnsInit = oInit.aoColumns;
6341 }
6342
6343 /* Add the columns */
6344 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
6345 {
6346 _fnAddColumn( oSettings, anThs ? anThs[i] : null );
6347 }
6348
6349 /* Apply the column definitions */
6350 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
6351 _fnColumnOptions( oSettings, iCol, oDef );
6352 } );
6353
6354 /* HTML5 attribute detection - build an mData object automatically if the
6355 * attributes are found
6356 */
6357 if ( rowOne.length ) {
6358 var a = function ( cell, name ) {
6359 return cell.getAttribute( 'data-'+name ) ? name : null;
6360 };
6361
6362 $.each( _fnGetRowElements( oSettings, rowOne[0] ).cells, function (i, cell) {
6363 var col = oSettings.aoColumns[i];
6364
6365 if ( col.mData === i ) {
6366 var sort = a( cell, 'sort' ) || a( cell, 'order' );
6367 var filter = a( cell, 'filter' ) || a( cell, 'search' );
6368
6369 if ( sort !== null || filter !== null ) {
6370 col.mData = {
6371 _: i+'.display',
6372 sort: sort !== null ? i+'.@data-'+sort : undefined,
6373 type: sort !== null ? i+'.@data-'+sort : undefined,
6374 filter: filter !== null ? i+'.@data-'+filter : undefined
6375 };
6376
6377 _fnColumnOptions( oSettings, i );
6378 }
6379 }
6380 } );
6381 }
6382
6383 var features = oSettings.oFeatures;
6384
6385 /* Must be done after everything which can be overridden by the state saving! */
6386 if ( oInit.bStateSave )
6387 {
6388 features.bStateSave = true;
6389 _fnLoadState( oSettings, oInit );
6390 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
6391 }
6392
6393
6394 /*
6395 * Sorting
6396 * @todo For modularisation (1.11) this needs to do into a sort start up handler
6397 */
6398
6399 // If aaSorting is not defined, then we use the first indicator in asSorting
6400 // in case that has been altered, so the default sort reflects that option
6401 if ( oInit.aaSorting === undefined )
6402 {
6403 var sorting = oSettings.aaSorting;
6404 for ( i=0, iLen=sorting.length ; i<iLen ; i++ )
6405 {
6406 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
6407 }
6408 }
6409
6410 /* Do a first pass on the sorting classes (allows any size changes to be taken into
6411 * account, and also will apply sorting disabled classes if disabled
6412 */
6413 _fnSortingClasses( oSettings );
6414
6415 if ( features.bSort )
6416 {
6417 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6418 if ( oSettings.bSorted ) {
6419 var aSort = _fnSortFlatten( oSettings );
6420 var sortedColumns = {};
6421
6422 $.each( aSort, function (i, val) {
6423 sortedColumns[ val.src ] = val.dir;
6424 } );
6425
6426 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
6427 _fnSortAria( oSettings );
6428 }
6429 } );
6430 }
6431
6432 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6433 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
6434 _fnSortingClasses( oSettings );
6435 }
6436 }, 'sc' );
6437
6438
6439 /*
6440 * Final init
6441 * Cache the header, body and footer as required, creating them if needed
6442 */
6443
6444 /* Browser support detection */
6445 _fnBrowserDetect( oSettings );
6446
6447 // Work around for Webkit bug 83867 - store the caption-side before removing from doc
6448 var captions = $(this).children('caption').each( function () {
6449 this._captionSide = $(this).css('caption-side');
6450 } );
6451
6452 var thead = $(this).children('thead');
6453 if ( thead.length === 0 )
6454 {
6455 thead = $('<thead/>').appendTo(this);
6456 }
6457 oSettings.nTHead = thead[0];
6458
6459 var tbody = $(this).children('tbody');
6460 if ( tbody.length === 0 )
6461 {
6462 tbody = $('<tbody/>').appendTo(this);
6463 }
6464 oSettings.nTBody = tbody[0];
6465
6466 var tfoot = $(this).children('tfoot');
6467 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
6468 {
6469 // If we are a scrolling table, and no footer has been given, then we need to create
6470 // a tfoot element for the caption element to be appended to
6471 tfoot = $('<tfoot/>').appendTo(this);
6472 }
6473
6474 if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
6475 $(this).addClass( oClasses.sNoFooter );
6476 }
6477 else if ( tfoot.length > 0 ) {
6478 oSettings.nTFoot = tfoot[0];
6479 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
6480 }
6481
6482 /* Check if there is data passing into the constructor */
6483 if ( oInit.aaData )
6484 {
6485 for ( i=0 ; i<oInit.aaData.length ; i++ )
6486 {
6487 _fnAddData( oSettings, oInit.aaData[ i ] );
6488 }
6489 }
6490 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' )
6491 {
6492 /* Grab the data from the page - only do this when deferred loading or no Ajax
6493 * source since there is no point in reading the DOM data if we are then going
6494 * to replace it with Ajax data
6495 */
6496 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
6497 }
6498
6499 /* Copy the data index array */
6500 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
6501
6502 /* Initialisation complete - table can be drawn */
6503 oSettings.bInitialised = true;
6504
6505 /* Check if we need to initialise the table (it might not have been handed off to the
6506 * language processor)
6507 */
6508 if ( bInitHandedOff === false )
6509 {
6510 _fnInitialise( oSettings );
6511 }
6512 } );
6513 _that = null;
6514 return this;
6515 };
6516
6517
6687
6518
6688
6519 /**
6689 /**
@@ -6681,17 +6851,15 b''
6681 */
6851 */
6682 _Api = function ( context, data )
6852 _Api = function ( context, data )
6683 {
6853 {
6684 if ( ! this instanceof _Api ) {
6854 if ( ! (this instanceof _Api) ) {
6685 throw 'DT API must be constructed as a new object';
6855 return new _Api( context, data );
6686 // or should it do the 'new' for the caller?
6687 // return new _Api.apply( this, arguments );
6688 }
6856 }
6689
6857
6690 var settings = [];
6858 var settings = [];
6691 var ctxSettings = function ( o ) {
6859 var ctxSettings = function ( o ) {
6692 var a = _toSettings( o );
6860 var a = _toSettings( o );
6693 if ( a ) {
6861 if ( a ) {
6694 settings.push.apply( settings, a );
6862 settings = settings.concat( a );
6695 }
6863 }
6696 };
6864 };
6697
6865
@@ -6709,7 +6877,7 b''
6709
6877
6710 // Initial data
6878 // Initial data
6711 if ( data ) {
6879 if ( data ) {
6712 this.push.apply( this, data.toArray ? data.toArray() : data );
6880 $.merge( this, data );
6713 }
6881 }
6714
6882
6715 // selector
6883 // selector
@@ -6724,25 +6892,27 b''
6724
6892
6725 DataTable.Api = _Api;
6893 DataTable.Api = _Api;
6726
6894
6727 _Api.prototype = /** @lends DataTables.Api */{
6895 // Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6728 /**
6896 // isPlainObject.
6729 * Return a new Api instance, comprised of the data held in the current
6897 $.extend( _Api.prototype, {
6730 * instance, join with the other array(s) and/or value(s).
6898 any: function ()
6731 *
6899 {
6732 * An alias for `Array.prototype.concat`.
6900 return this.count() !== 0;
6733 *
6901 },
6734 * @type method
6902
6735 * @param {*} value1 Arrays and/or values to concatenate.
6903
6736 * @param {*} [...] Additional arrays and/or values to concatenate.
6737 * @returns {DataTables.Api} New API instance, comprising of the combined
6738 * array.
6739 */
6740 concat: __arrayProto.concat,
6904 concat: __arrayProto.concat,
6741
6905
6742
6906
6743 context: [], // array of table settings objects
6907 context: [], // array of table settings objects
6744
6908
6745
6909
6910 count: function ()
6911 {
6912 return this.flatten().length;
6913 },
6914
6915
6746 each: function ( fn )
6916 each: function ( fn )
6747 {
6917 {
6748 for ( var i=0, ien=this.length ; i<ien; i++ ) {
6918 for ( var i=0, ien=this.length ; i<ien; i++ ) {
@@ -6803,7 +6973,6 b''
6803 return -1;
6973 return -1;
6804 },
6974 },
6805
6975
6806 // Note that `alwaysNew` is internal - use iteratorNew externally
6807 iterator: function ( flatten, type, fn, alwaysNew ) {
6976 iterator: function ( flatten, type, fn, alwaysNew ) {
6808 var
6977 var
6809 a = [], ret,
6978 a = [], ret,
@@ -6971,13 +7140,13 b''
6971
7140
6972
7141
6973 unshift: __arrayProto.unshift
7142 unshift: __arrayProto.unshift
6974 };
7143 } );
6975
7144
6976
7145
6977 _Api.extend = function ( scope, obj, ext )
7146 _Api.extend = function ( scope, obj, ext )
6978 {
7147 {
6979 // Only extend API instances and static properties of the API
7148 // Only extend API instances and static properties of the API
6980 if ( ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
7149 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
6981 return;
7150 return;
6982 }
7151 }
6983
7152
@@ -7226,15 +7395,21 b''
7226
7395
7227 /**
7396 /**
7228 * Redraw the tables in the current context.
7397 * Redraw the tables in the current context.
7229 *
7398 */
7230 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7399 _api_register( 'draw()', function ( paging ) {
7231 * position. A full re-sort and re-filter is performed when this method is
7232 * called, which is why the pagination reset is the default action.
7233 * @returns {DataTables.Api} this
7234 */
7235 _api_register( 'draw()', function ( resetPaging ) {
7236 return this.iterator( 'table', function ( settings ) {
7400 return this.iterator( 'table', function ( settings ) {
7237 _fnReDraw( settings, resetPaging===false );
7401 if ( paging === 'page' ) {
7402 _fnDraw( settings );
7403 }
7404 else {
7405 if ( typeof paging === 'string' ) {
7406 paging = paging === 'full-hold' ?
7407 false :
7408 true;
7409 }
7410
7411 _fnReDraw( settings, paging===false );
7412 }
7238 } );
7413 } );
7239 } );
7414 } );
7240
7415
@@ -7297,7 +7472,7 b''
7297 var
7472 var
7298 settings = this.context[0],
7473 settings = this.context[0],
7299 start = settings._iDisplayStart,
7474 start = settings._iDisplayStart,
7300 len = settings._iDisplayLength,
7475 len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7301 visRecords = settings.fnRecordsDisplay(),
7476 visRecords = settings.fnRecordsDisplay(),
7302 all = len === -1;
7477 all = len === -1;
7303
7478
@@ -7308,7 +7483,8 b''
7308 "end": settings.fnDisplayEnd(),
7483 "end": settings.fnDisplayEnd(),
7309 "length": len,
7484 "length": len,
7310 "recordsTotal": settings.fnRecordsTotal(),
7485 "recordsTotal": settings.fnRecordsTotal(),
7311 "recordsDisplay": visRecords
7486 "recordsDisplay": visRecords,
7487 "serverSide": _fnDataSource( settings ) === 'ssp'
7312 };
7488 };
7313 } );
7489 } );
7314
7490
@@ -7343,13 +7519,28 b''
7343
7519
7344
7520
7345 var __reload = function ( settings, holdPosition, callback ) {
7521 var __reload = function ( settings, holdPosition, callback ) {
7522 // Use the draw event to trigger a callback
7523 if ( callback ) {
7524 var api = new _Api( settings );
7525
7526 api.one( 'draw', function () {
7527 callback( api.ajax.json() );
7528 } );
7529 }
7530
7346 if ( _fnDataSource( settings ) == 'ssp' ) {
7531 if ( _fnDataSource( settings ) == 'ssp' ) {
7347 _fnReDraw( settings, holdPosition );
7532 _fnReDraw( settings, holdPosition );
7348 }
7533 }
7349 else {
7534 else {
7535 _fnProcessingDisplay( settings, true );
7536
7537 // Cancel an existing request
7538 var xhr = settings.jqXHR;
7539 if ( xhr && xhr.readyState !== 4 ) {
7540 xhr.abort();
7541 }
7542
7350 // Trigger xhr
7543 // Trigger xhr
7351 _fnProcessingDisplay( settings, true );
7352
7353 _fnBuildAjax( settings, [], function( json ) {
7544 _fnBuildAjax( settings, [], function( json ) {
7354 _fnClearTable( settings );
7545 _fnClearTable( settings );
7355
7546
@@ -7362,16 +7553,6 b''
7362 _fnProcessingDisplay( settings, false );
7553 _fnProcessingDisplay( settings, false );
7363 } );
7554 } );
7364 }
7555 }
7365
7366 // Use the draw event to trigger a callback, regardless of if it is an async
7367 // or sync draw
7368 if ( callback ) {
7369 var api = new _Api( settings );
7370
7371 api.one( 'draw', function () {
7372 callback( api.ajax.json() );
7373 } );
7374 }
7375 };
7556 };
7376
7557
7377
7558
@@ -7487,7 +7668,7 b''
7487
7668
7488
7669
7489
7670
7490 var _selector_run = function ( selector, select )
7671 var _selector_run = function ( type, selector, selectFn, settings, opts )
7491 {
7672 {
7492 var
7673 var
7493 out = [], res,
7674 out = [], res,
@@ -7501,20 +7682,29 b''
7501 }
7682 }
7502
7683
7503 for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7684 for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7504 a = selector[i] && selector[i].split ?
7685 // Only split on simple strings - complex expressions will be jQuery selectors
7686 a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ?
7505 selector[i].split(',') :
7687 selector[i].split(',') :
7506 [ selector[i] ];
7688 [ selector[i] ];
7507
7689
7508 for ( j=0, jen=a.length ; j<jen ; j++ ) {
7690 for ( j=0, jen=a.length ; j<jen ; j++ ) {
7509 res = select( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7691 res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7510
7692
7511 if ( res && res.length ) {
7693 if ( res && res.length ) {
7512 out.push.apply( out, res );
7694 out = out.concat( res );
7513 }
7695 }
7514 }
7696 }
7515 }
7697 }
7516
7698
7517 return out;
7699 // selector extensions
7700 var ext = _ext.selector[ type ];
7701 if ( ext.length ) {
7702 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7703 out = ext[i]( settings, opts, out );
7704 }
7705 }
7706
7707 return _unique( out );
7518 };
7708 };
7519
7709
7520
7710
@@ -7526,15 +7716,15 b''
7526
7716
7527 // Backwards compatibility for 1.9- which used the terminology filter rather
7717 // Backwards compatibility for 1.9- which used the terminology filter rather
7528 // than search
7718 // than search
7529 if ( opts.filter && ! opts.search ) {
7719 if ( opts.filter && opts.search === undefined ) {
7530 opts.search = opts.filter;
7720 opts.search = opts.filter;
7531 }
7721 }
7532
7722
7533 return {
7723 return $.extend( {
7534 search: opts.search || 'none',
7724 search: 'none',
7535 order: opts.order || 'current',
7725 order: 'current',
7536 page: opts.page || 'all'
7726 page: 'all'
7537 };
7727 }, opts );
7538 };
7728 };
7539
7729
7540
7730
@@ -7546,6 +7736,7 b''
7546 // Assign the first element to the first item in the instance
7736 // Assign the first element to the first item in the instance
7547 // and truncate the instance and context
7737 // and truncate the instance and context
7548 inst[0] = inst[i];
7738 inst[0] = inst[i];
7739 inst[0].length = 1;
7549 inst.length = 1;
7740 inst.length = 1;
7550 inst.context = [ inst.context[i] ];
7741 inst.context = [ inst.context[i] ];
7551
7742
@@ -7632,7 +7823,8 b''
7632
7823
7633 var __row_selector = function ( settings, selector, opts )
7824 var __row_selector = function ( settings, selector, opts )
7634 {
7825 {
7635 return _selector_run( selector, function ( sel ) {
7826 var rows;
7827 var run = function ( sel ) {
7636 var selInt = _intVal( sel );
7828 var selInt = _intVal( sel );
7637 var i, ien;
7829 var i, ien;
7638
7830
@@ -7643,13 +7835,15 b''
7643 return [ selInt ];
7835 return [ selInt ];
7644 }
7836 }
7645
7837
7646 var rows = _selector_row_indexes( settings, opts );
7838 if ( ! rows ) {
7839 rows = _selector_row_indexes( settings, opts );
7840 }
7647
7841
7648 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7842 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7649 // Selector - integer
7843 // Selector - integer
7650 return [ selInt ];
7844 return [ selInt ];
7651 }
7845 }
7652 else if ( ! sel ) {
7846 else if ( sel === null || sel === undefined || sel === '' ) {
7653 // Selector - none
7847 // Selector - none
7654 return rows;
7848 return rows;
7655 }
7849 }
@@ -7669,10 +7863,38 b''
7669
7863
7670 // Selector - node
7864 // Selector - node
7671 if ( sel.nodeName ) {
7865 if ( sel.nodeName ) {
7672 if ( $.inArray( sel, nodes ) !== -1 ) {
7866 if ( sel._DT_RowIndex !== undefined ) {
7673 return [ sel._DT_RowIndex ]; // sel is a TR node that is in the table
7867 return [ sel._DT_RowIndex ]; // Property added by DT for fast lookup
7674 // and DataTables adds a prop for fast lookup
7868 }
7675 }
7869 else if ( sel._DT_CellIndex ) {
7870 return [ sel._DT_CellIndex.row ];
7871 }
7872 else {
7873 var host = $(sel).closest('*[data-dt-row]');
7874 return host.length ?
7875 [ host.data('dt-row') ] :
7876 [];
7877 }
7878 }
7879
7880 // ID selector. Want to always be able to select rows by id, regardless
7881 // of if the tr element has been created or not, so can't rely upon
7882 // jQuery here - hence a custom implementation. This does not match
7883 // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7884 // but to select it using a CSS selector engine (like Sizzle or
7885 // querySelect) it would need to need to be escaped for some characters.
7886 // DataTables simplifies this for row selectors since you can select
7887 // only a row. A # indicates an id any anything that follows is the id -
7888 // unescaped.
7889 if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
7890 // get row index from id
7891 var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
7892 if ( rowObj !== undefined ) {
7893 return [ rowObj.idx ];
7894 }
7895
7896 // need to fall through to jQuery in case there is DOM id that
7897 // matches
7676 }
7898 }
7677
7899
7678 // Selector - jQuery selector string, array of nodes or jQuery object/
7900 // Selector - jQuery selector string, array of nodes or jQuery object/
@@ -7684,13 +7906,12 b''
7684 return this._DT_RowIndex;
7906 return this._DT_RowIndex;
7685 } )
7907 } )
7686 .toArray();
7908 .toArray();
7687 } );
7909 };
7688 };
7910
7689
7911 return _selector_run( 'row', selector, run, settings, opts );
7690
7912 };
7691 /**
7913
7692 *
7914
7693 */
7694 _api_register( 'rows()', function ( selector, opts ) {
7915 _api_register( 'rows()', function ( selector, opts ) {
7695 // argument shifting
7916 // argument shifting
7696 if ( selector === undefined ) {
7917 if ( selector === undefined ) {
@@ -7714,7 +7935,6 b''
7714 return inst;
7935 return inst;
7715 } );
7936 } );
7716
7937
7717
7718 _api_register( 'rows().nodes()', function () {
7938 _api_register( 'rows().nodes()', function () {
7719 return this.iterator( 'row', function ( settings, row ) {
7939 return this.iterator( 'row', function ( settings, row ) {
7720 return settings.aoData[ row ].nTr || undefined;
7940 return settings.aoData[ row ].nTr || undefined;
@@ -7746,23 +7966,49 b''
7746 }, 1 );
7966 }, 1 );
7747 } );
7967 } );
7748
7968
7969 _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
7970 var a = [];
7971 var context = this.context;
7972
7973 // `iterator` will drop undefined values, but in this case we want them
7974 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
7975 for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
7976 var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
7977 a.push( (hash === true ? '#' : '' )+ id );
7978 }
7979 }
7980
7981 return new _Api( context, a );
7982 } );
7983
7749 _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
7984 _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
7750 var that = this;
7985 var that = this;
7751
7986
7752 return this.iterator( 'row', function ( settings, row, thatIdx ) {
7987 this.iterator( 'row', function ( settings, row, thatIdx ) {
7753 var data = settings.aoData;
7988 var data = settings.aoData;
7989 var rowData = data[ row ];
7990 var i, ien, j, jen;
7991 var loopRow, loopCells;
7754
7992
7755 data.splice( row, 1 );
7993 data.splice( row, 1 );
7756
7994
7757 // Update the _DT_RowIndex parameter on all rows in the table
7995 // Update the cached indexes
7758 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7996 for ( i=0, ien=data.length ; i<ien ; i++ ) {
7759 if ( data[i].nTr !== null ) {
7997 loopRow = data[i];
7760 data[i].nTr._DT_RowIndex = i;
7998 loopCells = loopRow.anCells;
7761 }
7999
7762 }
8000 // Rows
7763
8001 if ( loopRow.nTr !== null ) {
7764 // Remove the target row from the search array
8002 loopRow.nTr._DT_RowIndex = i;
7765 var displayIndex = $.inArray( row, settings.aiDisplay );
8003 }
8004
8005 // Cells
8006 if ( loopCells !== null ) {
8007 for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
8008 loopCells[j]._DT_CellIndex.row = i;
8009 }
8010 }
8011 }
7766
8012
7767 // Delete from the display arrays
8013 // Delete from the display arrays
7768 _fnDeleteIndex( settings.aiDisplayMaster, row );
8014 _fnDeleteIndex( settings.aiDisplayMaster, row );
@@ -7771,7 +8017,21 b''
7771
8017
7772 // Check for an 'overflow' they case for displaying the table
8018 // Check for an 'overflow' they case for displaying the table
7773 _fnLengthOverflow( settings );
8019 _fnLengthOverflow( settings );
7774 } );
8020
8021 // Remove the row's ID reference if there is one
8022 var id = settings.rowIdFn( rowData._aData );
8023 if ( id !== undefined ) {
8024 delete settings.aIds[ id ];
8025 }
8026 } );
8027
8028 this.iterator( 'table', function ( settings ) {
8029 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
8030 settings.aoData[i].idx = i;
8031 }
8032 } );
8033
8034 return this;
7775 } );
8035 } );
7776
8036
7777
8037
@@ -7797,7 +8057,7 b''
7797 // Return an Api.rows() extended instance, so rows().nodes() etc can be used
8057 // Return an Api.rows() extended instance, so rows().nodes() etc can be used
7798 var modRows = this.rows( -1 );
8058 var modRows = this.rows( -1 );
7799 modRows.pop();
8059 modRows.pop();
7800 modRows.push.apply( modRows, newRows.toArray() );
8060 $.merge( modRows, newRows );
7801
8061
7802 return modRows;
8062 return modRows;
7803 } );
8063 } );
@@ -7868,6 +8128,14 b''
7868 // Convert to array of TR elements
8128 // Convert to array of TR elements
7869 var rows = [];
8129 var rows = [];
7870 var addRow = function ( r, k ) {
8130 var addRow = function ( r, k ) {
8131 // Recursion to allow for arrays of jQuery objects
8132 if ( $.isArray( r ) || r instanceof $ ) {
8133 for ( var i=0, ien=r.length ; i<ien ; i++ ) {
8134 addRow( r[i], k );
8135 }
8136 return;
8137 }
8138
7871 // If we get a TR element, then just add it directly - up to the dev
8139 // If we get a TR element, then just add it directly - up to the dev
7872 // to add the correct number of columns etc
8140 // to add the correct number of columns etc
7873 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
8141 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
@@ -7885,17 +8153,10 b''
7885 }
8153 }
7886 };
8154 };
7887
8155
7888 if ( $.isArray( data ) || data instanceof $ ) {
7889 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7890 addRow( data[i], klass );
7891 }
7892 }
7893 else {
7894 addRow( data, klass );
8156 addRow( data, klass );
7895 }
7896
8157
7897 if ( row._details ) {
8158 if ( row._details ) {
7898 row._details.remove();
8159 row._details.detach();
7899 }
8160 }
7900
8161
7901 row._details = $(rows);
8162 row._details = $(rows);
@@ -7914,7 +8175,7 b''
7914 if ( ctx.length ) {
8175 if ( ctx.length ) {
7915 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
8176 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
7916
8177
7917 if ( row._details ) {
8178 if ( row && row._details ) {
7918 row._details.remove();
8179 row._details.remove();
7919
8180
7920 row._detailsShow = undefined;
8181 row._detailsShow = undefined;
@@ -8096,7 +8357,7 b''
8096 // can be an array of these items, comma separated list, or an array of comma
8357 // can be an array of these items, comma separated list, or an array of comma
8097 // separated lists
8358 // separated lists
8098
8359
8099 var __re_column_selector = /^(.+):(name|visIdx|visible)$/;
8360 var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;
8100
8361
8101
8362
8102 // r1 and r2 are redundant - but it means that the parameters match for the
8363 // r1 and r2 are redundant - but it means that the parameters match for the
@@ -8117,7 +8378,7 b''
8117 names = _pluck( columns, 'sName' ),
8378 names = _pluck( columns, 'sName' ),
8118 nodes = _pluck( columns, 'nTh' );
8379 nodes = _pluck( columns, 'nTh' );
8119
8380
8120 return _selector_run( selector, function ( s ) {
8381 var run = function ( s ) {
8121 var selInt = _intVal( s );
8382 var selInt = _intVal( s );
8122
8383
8123 // Selector - all
8384 // Selector - all
@@ -8172,22 +8433,42 b''
8172 return $.map( names, function (name, i) {
8433 return $.map( names, function (name, i) {
8173 return name === match[1] ? i : null;
8434 return name === match[1] ? i : null;
8174 } );
8435 } );
8175 }
8436
8176 }
8437 default:
8177 else {
8438 return [];
8439 }
8440 }
8441
8442 // Cell in the table body
8443 if ( s.nodeName && s._DT_CellIndex ) {
8444 return [ s._DT_CellIndex.column ];
8445 }
8446
8178 // jQuery selector on the TH elements for the columns
8447 // jQuery selector on the TH elements for the columns
8179 return $( nodes )
8448 var jqResult = $( nodes )
8180 .filter( s )
8449 .filter( s )
8181 .map( function () {
8450 .map( function () {
8182 return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8451 return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8183 } )
8452 } )
8184 .toArray();
8453 .toArray();
8185 }
8454
8186 } );
8455 if ( jqResult.length || ! s.nodeName ) {
8187 };
8456 return jqResult;
8188
8457 }
8189
8458
8190 var __setColumnVis = function ( settings, column, vis, recalc ) {
8459 // Otherwise a node which might have a `dt-column` data attribute, or be
8460 // a child or such an element
8461 var host = $(s).closest('*[data-dt-column]');
8462 return host.length ?
8463 [ host.data('dt-column') ] :
8464 [];
8465 };
8466
8467 return _selector_run( 'column', selector, run, settings, opts );
8468 };
8469
8470
8471 var __setColumnVis = function ( settings, column, vis ) {
8191 var
8472 var
8192 cols = settings.aoColumns,
8473 cols = settings.aoColumns,
8193 col = cols[ column ],
8474 col = cols[ column ],
@@ -8230,25 +8511,10 b''
8230 _fnDrawHead( settings, settings.aoHeader );
8511 _fnDrawHead( settings, settings.aoHeader );
8231 _fnDrawHead( settings, settings.aoFooter );
8512 _fnDrawHead( settings, settings.aoFooter );
8232
8513
8233 if ( recalc === undefined || recalc ) {
8234 // Automatically adjust column sizing
8235 _fnAdjustColumnSizing( settings );
8236
8237 // Realign columns for scrolling
8238 if ( settings.oScroll.sX || settings.oScroll.sY ) {
8239 _fnScrollDraw( settings );
8240 }
8241 }
8242
8243 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis] );
8244
8245 _fnSaveState( settings );
8514 _fnSaveState( settings );
8246 };
8515 };
8247
8516
8248
8517
8249 /**
8250 *
8251 */
8252 _api_register( 'columns()', function ( selector, opts ) {
8518 _api_register( 'columns()', function ( selector, opts ) {
8253 // argument shifting
8519 // argument shifting
8254 if ( selector === undefined ) {
8520 if ( selector === undefined ) {
@@ -8272,42 +8538,28 b''
8272 return inst;
8538 return inst;
8273 } );
8539 } );
8274
8540
8275
8276 /**
8277 *
8278 */
8279 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8541 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8280 return this.iterator( 'column', function ( settings, column ) {
8542 return this.iterator( 'column', function ( settings, column ) {
8281 return settings.aoColumns[column].nTh;
8543 return settings.aoColumns[column].nTh;
8282 }, 1 );
8544 }, 1 );
8283 } );
8545 } );
8284
8546
8285
8286 /**
8287 *
8288 */
8289 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8547 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8290 return this.iterator( 'column', function ( settings, column ) {
8548 return this.iterator( 'column', function ( settings, column ) {
8291 return settings.aoColumns[column].nTf;
8549 return settings.aoColumns[column].nTf;
8292 }, 1 );
8550 }, 1 );
8293 } );
8551 } );
8294
8552
8295
8296 /**
8297 *
8298 */
8299 _api_registerPlural( 'columns().data()', 'column().data()', function () {
8553 _api_registerPlural( 'columns().data()', 'column().data()', function () {
8300 return this.iterator( 'column-rows', __columnData, 1 );
8554 return this.iterator( 'column-rows', __columnData, 1 );
8301 } );
8555 } );
8302
8556
8303
8304 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8557 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8305 return this.iterator( 'column', function ( settings, column ) {
8558 return this.iterator( 'column', function ( settings, column ) {
8306 return settings.aoColumns[column].mData;
8559 return settings.aoColumns[column].mData;
8307 }, 1 );
8560 }, 1 );
8308 } );
8561 } );
8309
8562
8310
8311 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8563 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8312 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8564 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8313 return _pluck_order( settings.aoData, rows,
8565 return _pluck_order( settings.aoData, rows,
@@ -8316,25 +8568,34 b''
8316 }, 1 );
8568 }, 1 );
8317 } );
8569 } );
8318
8570
8319
8320 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8571 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8321 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8572 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8322 return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8573 return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8323 }, 1 );
8574 }, 1 );
8324 } );
8575 } );
8325
8576
8326
8327
8328 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8577 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8329 return this.iterator( 'column', function ( settings, column ) {
8578 var ret = this.iterator( 'column', function ( settings, column ) {
8330 if ( vis === undefined ) {
8579 if ( vis === undefined ) {
8331 return settings.aoColumns[ column ].bVisible;
8580 return settings.aoColumns[ column ].bVisible;
8332 } // else
8581 } // else
8333 __setColumnVis( settings, column, vis, calc );
8582 __setColumnVis( settings, column, vis );
8334 } );
8583 } );
8335 } );
8584
8336
8585 // Group the column visibility changes
8337
8586 if ( vis !== undefined ) {
8587 // Second loop once the first is done for events
8588 this.iterator( 'column', function ( settings, column ) {
8589 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
8590 } );
8591
8592 if ( calc === undefined || calc ) {
8593 this.columns.adjust();
8594 }
8595 }
8596
8597 return ret;
8598 } );
8338
8599
8339 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8600 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8340 return this.iterator( 'column', function ( settings, column ) {
8601 return this.iterator( 'column', function ( settings, column ) {
@@ -8344,28 +8605,12 b''
8344 }, 1 );
8605 }, 1 );
8345 } );
8606 } );
8346
8607
8347
8348 // _api_register( 'columns().show()', function () {
8349 // var selector = this.selector;
8350 // return this.columns( selector.cols, selector.opts ).visible( true );
8351 // } );
8352
8353
8354 // _api_register( 'columns().hide()', function () {
8355 // var selector = this.selector;
8356 // return this.columns( selector.cols, selector.opts ).visible( false );
8357 // } );
8358
8359
8360
8361 _api_register( 'columns.adjust()', function () {
8608 _api_register( 'columns.adjust()', function () {
8362 return this.iterator( 'table', function ( settings ) {
8609 return this.iterator( 'table', function ( settings ) {
8363 _fnAdjustColumnSizing( settings );
8610 _fnAdjustColumnSizing( settings );
8364 }, 1 );
8611 }, 1 );
8365 } );
8612 } );
8366
8613
8367
8368 // Convert from one column index type, to another type
8369 _api_register( 'column.index()', function ( type, idx ) {
8614 _api_register( 'column.index()', function ( type, idx ) {
8370 if ( this.context.length !== 0 ) {
8615 if ( this.context.length !== 0 ) {
8371 var ctx = this.context[0];
8616 var ctx = this.context[0];
@@ -8379,14 +8624,12 b''
8379 }
8624 }
8380 } );
8625 } );
8381
8626
8382
8383 _api_register( 'column()', function ( selector, opts ) {
8627 _api_register( 'column()', function ( selector, opts ) {
8384 return _selector_first( this.columns( selector, opts ) );
8628 return _selector_first( this.columns( selector, opts ) );
8385 } );
8629 } );
8386
8630
8387
8631
8388
8632
8389
8390 var __cell_selector = function ( settings, selector, opts )
8633 var __cell_selector = function ( settings, selector, opts )
8391 {
8634 {
8392 var data = settings.aoData;
8635 var data = settings.aoData;
@@ -8397,7 +8640,7 b''
8397 var columns = settings.aoColumns.length;
8640 var columns = settings.aoColumns.length;
8398 var a, i, ien, j, o, host;
8641 var a, i, ien, j, o, host;
8399
8642
8400 return _selector_run( selector, function ( s ) {
8643 var run = function ( s ) {
8401 var fnSelector = typeof s === 'function';
8644 var fnSelector = typeof s === 'function';
8402
8645
8403 if ( s === null || s === undefined || fnSelector ) {
8646 if ( s === null || s === undefined || fnSelector ) {
@@ -8415,9 +8658,9 b''
8415
8658
8416 if ( fnSelector ) {
8659 if ( fnSelector ) {
8417 // Selector - function
8660 // Selector - function
8418 host = settings.aoData[ row ];
8661 host = data[ row ];
8419
8662
8420 if ( s( o, _fnGetCellData(settings, row, j), host.anCells[j] ) ) {
8663 if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8421 a.push( o );
8664 a.push( o );
8422 }
8665 }
8423 }
8666 }
@@ -8437,18 +8680,33 b''
8437 }
8680 }
8438
8681
8439 // Selector - jQuery filtered cells
8682 // Selector - jQuery filtered cells
8440 return allCells
8683 var jqResult = allCells
8441 .filter( s )
8684 .filter( s )
8442 .map( function (i, el) {
8685 .map( function (i, el) {
8443 row = el.parentNode._DT_RowIndex;
8686 return { // use a new object, in case someone changes the values
8444
8687 row: el._DT_CellIndex.row,
8445 return {
8688 column: el._DT_CellIndex.column
8446 row: row,
8447 column: $.inArray( el, data[ row ].anCells )
8448 };
8689 };
8449 } )
8690 } )
8450 .toArray();
8691 .toArray();
8451 } );
8692
8693 if ( jqResult.length || ! s.nodeName ) {
8694 return jqResult;
8695 }
8696
8697 // Otherwise the selector is a node, and there is one last option - the
8698 // element might be a child of an element which has dt-row and dt-column
8699 // data attributes
8700 host = $(s).closest('*[data-dt-row]');
8701 return host.length ?
8702 [ {
8703 row: host.data('dt-row'),
8704 column: host.data('dt-column')
8705 } ] :
8706 [];
8707 };
8708
8709 return _selector_run( 'cell', selector, run, settings, opts );
8452 };
8710 };
8453
8711
8454
8712
@@ -8458,14 +8716,16 b''
8458 // Argument shifting
8716 // Argument shifting
8459 if ( $.isPlainObject( rowSelector ) ) {
8717 if ( $.isPlainObject( rowSelector ) ) {
8460 // Indexes
8718 // Indexes
8461 if ( typeof rowSelector.row !== undefined ) {
8719 if ( rowSelector.row === undefined ) {
8720 // Selector options in first parameter
8721 opts = rowSelector;
8722 rowSelector = null;
8723 }
8724 else {
8725 // Cell index objects in first parameter
8462 opts = columnSelector;
8726 opts = columnSelector;
8463 columnSelector = null;
8727 columnSelector = null;
8464 }
8728 }
8465 else {
8466 opts = rowSelector;
8467 rowSelector = null;
8468 }
8469 }
8729 }
8470 if ( $.isPlainObject( columnSelector ) ) {
8730 if ( $.isPlainObject( columnSelector ) ) {
8471 opts = columnSelector;
8731 opts = columnSelector;
@@ -8511,9 +8771,10 b''
8511
8771
8512 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8772 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8513 return this.iterator( 'cell', function ( settings, row, column ) {
8773 return this.iterator( 'cell', function ( settings, row, column ) {
8514 var cells = settings.aoData[ row ].anCells;
8774 var data = settings.aoData[ row ];
8515 return cells ?
8775
8516 cells[ column ] :
8776 return data && data.anCells ?
8777 data.anCells[ column ] :
8517 undefined;
8778 undefined;
8518 }, 1 );
8779 }, 1 );
8519 } );
8780 } );
@@ -8629,7 +8890,7 b''
8629 // Simple column / direction passed in
8890 // Simple column / direction passed in
8630 order = [ [ order, dir ] ];
8891 order = [ [ order, dir ] ];
8631 }
8892 }
8632 else if ( ! $.isArray( order[0] ) ) {
8893 else if ( order.length && ! $.isArray( order[0] ) ) {
8633 // Arguments passed in (list of 1D arrays)
8894 // Arguments passed in (list of 1D arrays)
8634 order = Array.prototype.slice.call( arguments );
8895 order = Array.prototype.slice.call( arguments );
8635 }
8896 }
@@ -8658,6 +8919,24 b''
8658 } );
8919 } );
8659
8920
8660
8921
8922 _api_register( 'order.fixed()', function ( set ) {
8923 if ( ! set ) {
8924 var ctx = this.context;
8925 var fixed = ctx.length ?
8926 ctx[0].aaSortingFixed :
8927 undefined;
8928
8929 return $.isArray( fixed ) ?
8930 { pre: fixed } :
8931 fixed;
8932 }
8933
8934 return this.iterator( 'table', function ( settings ) {
8935 settings.aaSortingFixed = $.extend( true, {}, set );
8936 } );
8937 } );
8938
8939
8661 // Order by the selected column(s)
8940 // Order by the selected column(s)
8662 _api_register( [
8941 _api_register( [
8663 'columns().order()',
8942 'columns().order()',
@@ -8825,8 +9104,15 b''
8825 var t = $(table).get(0);
9104 var t = $(table).get(0);
8826 var is = false;
9105 var is = false;
8827
9106
9107 if ( table instanceof DataTable.Api ) {
9108 return true;
9109 }
9110
8828 $.each( DataTable.settings, function (i, o) {
9111 $.each( DataTable.settings, function (i, o) {
8829 if ( o.nTable === t || o.nScrollHead === t || o.nScrollFoot === t ) {
9112 var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
9113 var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
9114
9115 if ( o.nTable === t || head === t || foot === t ) {
8830 is = true;
9116 is = true;
8831 }
9117 }
8832 } );
9118 } );
@@ -8853,43 +9139,22 b''
8853 */
9139 */
8854 DataTable.tables = DataTable.fnTables = function ( visible )
9140 DataTable.tables = DataTable.fnTables = function ( visible )
8855 {
9141 {
8856 return $.map( DataTable.settings, function (o) {
9142 var api = false;
9143
9144 if ( $.isPlainObject( visible ) ) {
9145 api = visible.api;
9146 visible = visible.visible;
9147 }
9148
9149 var a = $.map( DataTable.settings, function (o) {
8857 if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
9150 if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
8858 return o.nTable;
9151 return o.nTable;
8859 }
9152 }
8860 } );
9153 } );
8861 };
9154
8862
9155 return api ?
8863
9156 new _Api( a ) :
8864 /**
9157 a;
8865 * DataTables utility methods
8866 *
8867 * This namespace provides helper methods that DataTables uses internally to
8868 * create a DataTable, but which are not exclusively used only for DataTables.
8869 * These methods can be used by extension authors to save the duplication of
8870 * code.
8871 *
8872 * @namespace
8873 */
8874 DataTable.util = {
8875 /**
8876 * Throttle the calls to a function. Arguments and context are maintained
8877 * for the throttled function.
8878 *
8879 * @param {function} fn Function to be called
8880 * @param {integer} freq Call frequency in mS
8881 * @return {function} Wrapped function
8882 */
8883 throttle: _fnThrottle,
8884
8885
8886 /**
8887 * Escape a string such that it can be used in a regular expression
8888 *
8889 * @param {string} sVal string to escape
8890 * @returns {string} escaped string
8891 */
8892 escapeRegex: _fnEscapeRegex
8893 };
9158 };
8894
9159
8895
9160
@@ -8931,9 +9196,11 b''
8931 var args = Array.prototype.slice.call(arguments);
9196 var args = Array.prototype.slice.call(arguments);
8932
9197
8933 // Add the `dt` namespace automatically if it isn't already present
9198 // Add the `dt` namespace automatically if it isn't already present
8934 if ( ! args[0].match(/\.dt\b/) ) {
9199 args[0] = $.map( args[0].split( /\s/ ), function ( e ) {
8935 args[0] += '.dt';
9200 return ! e.match(/\.dt\b/) ?
8936 }
9201 e+'.dt' :
9202 e;
9203 } ).join( ' ' );
8937
9204
8938 var inst = $( this.tables().nodes() );
9205 var inst = $( this.tables().nodes() );
8939 inst[key].apply( inst, args );
9206 inst[key].apply( inst, args );
@@ -8954,6 +9221,12 b''
8954 } );
9221 } );
8955
9222
8956
9223
9224 _api_register( 'init()', function () {
9225 var ctx = this.context;
9226 return ctx.length ? ctx[0].oInit : null;
9227 } );
9228
9229
8957 _api_register( 'data()', function () {
9230 _api_register( 'data()', function () {
8958 return this.iterator( 'table', function ( settings ) {
9231 return this.iterator( 'table', function ( settings ) {
8959 return _pluck( settings.aoData, '_aData' );
9232 return _pluck( settings.aoData, '_aData' );
@@ -8992,8 +9265,8 b''
8992 // Blitz all `DT` namespaced events (these are internal events, the
9265 // Blitz all `DT` namespaced events (these are internal events, the
8993 // lowercase, `dt` events are user subscribed and they are responsible
9266 // lowercase, `dt` events are user subscribed and they are responsible
8994 // for removing them
9267 // for removing them
8995 jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT');
9268 jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
8996 $(window).unbind('.DT-'+settings.sInstance);
9269 $(window).off('.DT-'+settings.sInstance);
8997
9270
8998 // When scrolling we had to break the table up - restore it
9271 // When scrolling we had to break the table up - restore it
8999 if ( table != thead.parentNode ) {
9272 if ( table != thead.parentNode ) {
@@ -9006,10 +9279,6 b''
9006 jqTable.append( tfoot );
9279 jqTable.append( tfoot );
9007 }
9280 }
9008
9281
9009 // Remove the DataTables generated nodes, events and classes
9010 jqTable.detach();
9011 jqWrapper.detach();
9012
9013 settings.aaSorting = [];
9282 settings.aaSorting = [];
9014 settings.aaSortingFixed = [];
9283 settings.aaSortingFixed = [];
9015 _fnSortingClasses( settings );
9284 _fnSortingClasses( settings );
@@ -9029,14 +9298,19 b''
9029 } );
9298 } );
9030 }
9299 }
9031
9300
9301 // Add the TR elements back into the table in their original order
9302 jqTbody.children().detach();
9303 jqTbody.append( rows );
9304
9305 // Remove the DataTables generated nodes, events and classes
9306 var removedMethod = remove ? 'remove' : 'detach';
9307 jqTable[ removedMethod ]();
9308 jqWrapper[ removedMethod ]();
9309
9310 // If we need to reattach the table to the document
9032 if ( ! remove && orig ) {
9311 if ( ! remove && orig ) {
9033 // insertBefore acts like appendChild if !arg[1]
9312 // insertBefore acts like appendChild if !arg[1]
9034 orig.insertBefore( table, settings.nTableReinsertBefore );
9313 orig.insertBefore( table, settings.nTableReinsertBefore );
9035 }
9036
9037 // Add the TR elements back into the table in their original order
9038 jqTbody.children().detach();
9039 jqTbody.append( rows );
9040
9314
9041 // Restore the width of the original table - was read from the style property,
9315 // Restore the width of the original table - was read from the style property,
9042 // so we can restore directly to that
9316 // so we can restore directly to that
@@ -9054,6 +9328,7 b''
9054 $(this).addClass( settings.asDestroyStripes[i % ien] );
9328 $(this).addClass( settings.asDestroyStripes[i % ien] );
9055 } );
9329 } );
9056 }
9330 }
9331 }
9057
9332
9058 /* Remove the settings object from the settings array */
9333 /* Remove the settings object from the settings array */
9059 var idx = $.inArray( settings, DataTable.settings );
9334 var idx = $.inArray( settings, DataTable.settings );
@@ -9064,6 +9339,55 b''
9064 } );
9339 } );
9065
9340
9066
9341
9342 // Add the `every()` method for rows, columns and cells in a compact form
9343 $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9344 _api_register( type+'s().every()', function ( fn ) {
9345 var opts = this.selector.opts;
9346 var api = this;
9347
9348 return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
9349 // Rows and columns:
9350 // arg1 - index
9351 // arg2 - table counter
9352 // arg3 - loop counter
9353 // arg4 - undefined
9354 // Cells:
9355 // arg1 - row index
9356 // arg2 - column index
9357 // arg3 - table counter
9358 // arg4 - loop counter
9359 fn.call(
9360 api[ type ](
9361 arg1,
9362 type==='cell' ? arg2 : opts,
9363 type==='cell' ? opts : undefined
9364 ),
9365 arg1, arg2, arg3, arg4
9366 );
9367 } );
9368 } );
9369 } );
9370
9371
9372 // i18n method for extensions to be able to use the language object from the
9373 // DataTable
9374 _api_register( 'i18n()', function ( token, def, plural ) {
9375 var ctx = this.context[0];
9376 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9377
9378 if ( resolved === undefined ) {
9379 resolved = def;
9380 }
9381
9382 if ( plural !== undefined && $.isPlainObject( resolved ) ) {
9383 resolved = resolved[ plural ] !== undefined ?
9384 resolved[ plural ] :
9385 resolved._;
9386 }
9387
9388 return resolved.replace( '%d', plural ); // nb: plural might be undefined,
9389 } );
9390
9067 /**
9391 /**
9068 * Version string for plug-ins to check compatibility. Allowed format is
9392 * Version string for plug-ins to check compatibility. Allowed format is
9069 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9393 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
@@ -9072,7 +9396,7 b''
9072 * @type string
9396 * @type string
9073 * @default Version number
9397 * @default Version number
9074 */
9398 */
9075 DataTable.version = "1.10.4";
9399 DataTable.version = "1.10.13";
9076
9400
9077 /**
9401 /**
9078 * Private data store, containing all of the settings objects that are
9402 * Private data store, containing all of the settings objects that are
@@ -9224,7 +9548,16 b''
9224 * @default null
9548 * @default null
9225 * @private
9549 * @private
9226 */
9550 */
9227 "src": null
9551 "src": null,
9552
9553 /**
9554 * Index in the aoData array. This saves an indexOf lookup when we have the
9555 * object, but want to know the index
9556 * @type integer
9557 * @default -1
9558 * @private
9559 */
9560 "idx": -1
9228 };
9561 };
9229
9562
9230
9563
@@ -10571,6 +10904,8 b''
10571 * @type function
10904 * @type function
10572 * @member
10905 * @member
10573 * @param {object} settings DataTables settings object
10906 * @param {object} settings DataTables settings object
10907 * @param {object} callback Callback that can be executed when done. It
10908 * should be passed the loaded state object.
10574 * @return {object} The DataTables state object to be loaded
10909 * @return {object} The DataTables state object to be loaded
10575 *
10910 *
10576 * @dtopt Callbacks
10911 * @dtopt Callbacks
@@ -10580,21 +10915,14 b''
10580 * $(document).ready( function() {
10915 * $(document).ready( function() {
10581 * $('#example').dataTable( {
10916 * $('#example').dataTable( {
10582 * "stateSave": true,
10917 * "stateSave": true,
10583 * "stateLoadCallback": function (settings) {
10918 * "stateLoadCallback": function (settings, callback) {
10584 * var o;
10585 *
10586 * // Send an Ajax request to the server to get the data. Note that
10587 * // this is a synchronous request.
10588 * $.ajax( {
10919 * $.ajax( {
10589 * "url": "/state_load",
10920 * "url": "/state_load",
10590 * "async": false,
10591 * "dataType": "json",
10921 * "dataType": "json",
10592 * "success": function (json) {
10922 * "success": function (json) {
10593 * o = json;
10923 * callback( json );
10594 * }
10924 * }
10595 * } );
10925 * } );
10596 *
10597 * return o;
10598 * }
10926 * }
10599 * } );
10927 * } );
10600 * } );
10928 * } );
@@ -11533,14 +11861,15 b''
11533
11861
11534
11862
11535 /**
11863 /**
11536 * DataTables features four different built-in options for the buttons to
11864 * DataTables features six different built-in options for the buttons to
11537 * display for pagination control:
11865 * display for pagination control:
11538 *
11866 *
11867 * * `numbers` - Page number buttons only
11539 * * `simple` - 'Previous' and 'Next' buttons only
11868 * * `simple` - 'Previous' and 'Next' buttons only
11540 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11869 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11541 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11870 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11542 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus
11871 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
11543 * page numbers
11872 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
11544 *
11873 *
11545 * Further methods can be added using {@link DataTable.ext.oPagination}.
11874 * Further methods can be added using {@link DataTable.ext.oPagination}.
11546 * @type string
11875 * @type string
@@ -11665,7 +11994,18 b''
11665 * @name DataTable.defaults.renderer
11994 * @name DataTable.defaults.renderer
11666 *
11995 *
11667 */
11996 */
11668 "renderer": null
11997 "renderer": null,
11998
11999
12000 /**
12001 * Set the data property name that DataTables should use to get a row's id
12002 * to set as the `id` property in the node.
12003 * @type string
12004 * @default DT_RowId
12005 *
12006 * @name DataTable.defaults.rowId
12007 */
12008 "rowId": "DT_RowId"
11669 };
12009 };
11670
12010
11671 _fnHungarianMap( DataTable.defaults );
12011 _fnHungarianMap( DataTable.defaults );
@@ -12764,7 +13104,21 b''
12764 * @type boolean
13104 * @type boolean
12765 * @default false
13105 * @default false
12766 */
13106 */
12767 "bScrollbarLeft": false
13107 "bScrollbarLeft": false,
13108
13109 /**
13110 * Flag for if `getBoundingClientRect` is fully supported or not
13111 * @type boolean
13112 * @default false
13113 */
13114 "bBounding": false,
13115
13116 /**
13117 * Browser scrollbar width
13118 * @type integer
13119 * @default 0
13120 */
13121 "barWidth": 0
12768 },
13122 },
12769
13123
12770
13124
@@ -12810,6 +13164,13 b''
12810 "aiDisplayMaster": [],
13164 "aiDisplayMaster": [],
12811
13165
12812 /**
13166 /**
13167 * Map of row ids to data indexes
13168 * @type object
13169 * @default {}
13170 */
13171 "aIds": {},
13172
13173 /**
12813 * Store information about each column that is in use
13174 * Store information about each column that is in use
12814 * @type array
13175 * @type array
12815 * @default []
13176 * @default []
@@ -13417,7 +13778,21 b''
13417 * @type object
13778 * @type object
13418 * @default {}
13779 * @default {}
13419 */
13780 */
13420 "oPlugins": {}
13781 "oPlugins": {},
13782
13783 /**
13784 * Function used to get a row's id from the row's data
13785 * @type function
13786 * @default null
13787 */
13788 "rowIdFn": null,
13789
13790 /**
13791 * Data location where to store a row's id
13792 * @type string
13793 * @default null
13794 */
13795 "rowId": null
13421 };
13796 };
13422
13797
13423 /**
13798 /**
@@ -13447,6 +13822,17 b''
13447 */
13822 */
13448 DataTable.ext = _ext = {
13823 DataTable.ext = _ext = {
13449 /**
13824 /**
13825 * Buttons. For use with the Buttons extension for DataTables. This is
13826 * defined here so other extensions can define buttons regardless of load
13827 * order. It is _not_ used by DataTables core.
13828 *
13829 * @type object
13830 * @default {}
13831 */
13832 buttons: {},
13833
13834
13835 /**
13450 * Element class names
13836 * Element class names
13451 *
13837 *
13452 * @type object
13838 * @type object
@@ -13456,12 +13842,20 b''
13456
13842
13457
13843
13458 /**
13844 /**
13845 * DataTables build type (expanded by the download builder)
13846 *
13847 * @type string
13848 */
13849 builder: "-source-",
13850
13851
13852 /**
13459 * Error reporting.
13853 * Error reporting.
13460 *
13854 *
13461 * How should DataTables report an error. Can take the value 'alert' or
13855 * How should DataTables report an error. Can take the value 'alert',
13462 * 'throw'
13856 * 'throw', 'none' or a function.
13463 *
13857 *
13464 * @type string
13858 * @type string|function
13465 * @default alert
13859 * @default alert
13466 */
13860 */
13467 errMode: "alert",
13861 errMode: "alert",
@@ -13569,6 +13963,37 b''
13569
13963
13570
13964
13571 /**
13965 /**
13966 * Selector extensions
13967 *
13968 * The `selector` option can be used to extend the options available for the
13969 * selector modifier options (`selector-modifier` object data type) that
13970 * each of the three built in selector types offer (row, column and cell +
13971 * their plural counterparts). For example the Select extension uses this
13972 * mechanism to provide an option to select only rows, columns and cells
13973 * that have been marked as selected by the end user (`{selected: true}`),
13974 * which can be used in conjunction with the existing built in selector
13975 * options.
13976 *
13977 * Each property is an array to which functions can be pushed. The functions
13978 * take three attributes:
13979 *
13980 * * Settings object for the host table
13981 * * Options object (`selector-modifier` object type)
13982 * * Array of selected item indexes
13983 *
13984 * The return is an array of the resulting item indexes after the custom
13985 * selector has been applied.
13986 *
13987 * @type object
13988 */
13989 selector: {
13990 cell: [],
13991 column: [],
13992 row: []
13993 },
13994
13995
13996 /**
13572 * Internal functions, exposed for used in plug-ins.
13997 * Internal functions, exposed for used in plug-ins.
13573 *
13998 *
13574 * Please note that you should not need to use the internal methods for
13999 * Please note that you should not need to use the internal methods for
@@ -14061,7 +14486,7 b''
14061 numbers.splice( 0, 0, 0 );
14486 numbers.splice( 0, 0, 0 );
14062 }
14487 }
14063 else {
14488 else {
14064 numbers = _range( page-1, page+2 );
14489 numbers = _range( page-half+2, page+half-1 );
14065 numbers.push( 'ellipsis' );
14490 numbers.push( 'ellipsis' );
14066 numbers.push( pages-1 );
14491 numbers.push( pages-1 );
14067 numbers.splice( 0, 0, 'ellipsis' );
14492 numbers.splice( 0, 0, 'ellipsis' );
@@ -14082,6 +14507,10 b''
14082 return [ 'first', 'previous', 'next', 'last' ];
14507 return [ 'first', 'previous', 'next', 'last' ];
14083 },
14508 },
14084
14509
14510 numbers: function ( page, pages ) {
14511 return [ _numbers(page, pages) ];
14512 },
14513
14085 simple_numbers: function ( page, pages ) {
14514 simple_numbers: function ( page, pages ) {
14086 return [ 'previous', _numbers(page, pages), 'next' ];
14515 return [ 'previous', _numbers(page, pages), 'next' ];
14087 },
14516 },
@@ -14090,8 +14519,14 b''
14090 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14519 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14091 },
14520 },
14092
14521
14522 first_last_numbers: function (page, pages) {
14523 return ['first', _numbers(page, pages), 'last'];
14524 },
14525
14093 // For testing and plug-ins to use
14526 // For testing and plug-ins to use
14094 _numbers: _numbers,
14527 _numbers: _numbers,
14528
14529 // Number of number buttons (including ellipsis) to show. _Must be odd!_
14095 numbers_length: 7
14530 numbers_length: 7
14096 } );
14531 } );
14097
14532
@@ -14101,6 +14536,7 b''
14101 _: function ( settings, host, idx, buttons, page, pages ) {
14536 _: function ( settings, host, idx, buttons, page, pages ) {
14102 var classes = settings.oClasses;
14537 var classes = settings.oClasses;
14103 var lang = settings.oLanguage.oPaginate;
14538 var lang = settings.oLanguage.oPaginate;
14539 var aria = settings.oLanguage.oAria.paginate || {};
14104 var btnDisplay, btnClass, counter=0;
14540 var btnDisplay, btnClass, counter=0;
14105
14541
14106 var attach = function( container, buttons ) {
14542 var attach = function( container, buttons ) {
@@ -14118,13 +14554,12 b''
14118 attach( inner, button );
14554 attach( inner, button );
14119 }
14555 }
14120 else {
14556 else {
14121 btnDisplay = '';
14557 btnDisplay = null;
14122 btnClass = '';
14558 btnClass = '';
14123
14559
14124 switch ( button ) {
14560 switch ( button ) {
14125 case 'ellipsis':
14561 case 'ellipsis':
14126 //RhodeCode fixed, added class paginate_button
14562 container.append('<span class="ellipsis">&#x2026;</span>');
14127 container.append('<span class=\"paginate_button\">&hellip;</span>');
14128 break;
14563 break;
14129
14564
14130 case 'first':
14565 case 'first':
@@ -14158,10 +14593,11 b''
14158 break;
14593 break;
14159 }
14594 }
14160
14595
14161 if ( btnDisplay ) {
14596 if ( btnDisplay !== null ) {
14162 node = $('<a>', {
14597 node = $('<a>', {
14163 'class': classes.sPageButton+' '+btnClass,
14598 'class': classes.sPageButton+' '+btnClass,
14164 'aria-controls': settings.sTableId,
14599 'aria-controls': settings.sTableId,
14600 'aria-label': aria[ button ],
14165 'data-dt-idx': counter,
14601 'data-dt-idx': counter,
14166 'tabindex': settings.iTabIndex,
14602 'tabindex': settings.iTabIndex,
14167 'id': idx === 0 && typeof button === 'string' ?
14603 'id': idx === 0 && typeof button === 'string' ?
@@ -14184,21 +14620,23 b''
14184 // IE9 throws an 'unknown error' if document.activeElement is used
14620 // IE9 throws an 'unknown error' if document.activeElement is used
14185 // inside an iframe or frame. Try / catch the error. Not good for
14621 // inside an iframe or frame. Try / catch the error. Not good for
14186 // accessibility, but neither are frames.
14622 // accessibility, but neither are frames.
14623 var activeEl;
14624
14187 try {
14625 try {
14188 // Because this approach is destroying and recreating the paging
14626 // Because this approach is destroying and recreating the paging
14189 // elements, focus is lost on the select button which is bad for
14627 // elements, focus is lost on the select button which is bad for
14190 // accessibility. So we want to restore focus once the draw has
14628 // accessibility. So we want to restore focus once the draw has
14191 // completed
14629 // completed
14192 var activeEl = $(document.activeElement).data('dt-idx');
14630 activeEl = $(host).find(document.activeElement).data('dt-idx');
14631 }
14632 catch (e) {}
14193
14633
14194 attach( $(host).empty(), buttons );
14634 attach( $(host).empty(), buttons );
14195
14635
14196 if ( activeEl !== null ) {
14636 if ( activeEl !== undefined ) {
14197 $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14637 $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14198 }
14638 }
14199 }
14639 }
14200 catch (e) {}
14201 }
14202 }
14640 }
14203 } );
14641 } );
14204
14642
@@ -14218,10 +14656,10 b''
14218 // Dates (only those recognised by the browser's Date.parse)
14656 // Dates (only those recognised by the browser's Date.parse)
14219 function ( d, settings )
14657 function ( d, settings )
14220 {
14658 {
14221 // V8 will remove any unknown characters at the start and end of the
14659 // V8 tries _very_ hard to make a string passed into `Date.parse()`
14222 // expression, leading to false matches such as `$245.12` or `10%` being
14660 // valid, so we need to use a regex to restrict date formats. Use a
14223 // a valid date. See forum thread 18941 for detail.
14661 // plug-in for anything other than ISO8601 style strings
14224 if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) {
14662 if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
14225 return null;
14663 return null;
14226 }
14664 }
14227 var parsed = Date.parse(d);
14665 var parsed = Date.parse(d);
@@ -14358,7 +14796,7 b''
14358 $.extend( _ext.type.order, {
14796 $.extend( _ext.type.order, {
14359 // Dates
14797 // Dates
14360 "date-pre": function ( d ) {
14798 "date-pre": function ( d ) {
14361 return Date.parse( d ) || 0;
14799 return Date.parse( d ) || -Infinity;
14362 },
14800 },
14363
14801
14364 // html
14802 // html
@@ -14479,6 +14917,12 b''
14479 * to make working with DataTables a little bit easier.
14917 * to make working with DataTables a little bit easier.
14480 */
14918 */
14481
14919
14920 var __htmlEscapeEntities = function ( d ) {
14921 return typeof d === 'string' ?
14922 d.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') :
14923 d;
14924 };
14925
14482 /**
14926 /**
14483 * Helpers for `columns.render`.
14927 * Helpers for `columns.render`.
14484 *
14928 *
@@ -14487,11 +14931,14 b''
14487 *
14931 *
14488 * * `number` - Will format numeric data (defined by `columns.data`) for
14932 * * `number` - Will format numeric data (defined by `columns.data`) for
14489 * display, retaining the original unformatted data for sorting and filtering.
14933 * display, retaining the original unformatted data for sorting and filtering.
14490 * It takes 4 parameters:
14934 * It takes 5 parameters:
14491 * * `string` - Thousands grouping separator
14935 * * `string` - Thousands grouping separator
14492 * * `string` - Decimal point indicator
14936 * * `string` - Decimal point indicator
14493 * * `integer` - Number of decimal points to show
14937 * * `integer` - Number of decimal points to show
14494 * * `string` (optional) - Prefix.
14938 * * `string` (optional) - Prefix.
14939 * * `string` (optional) - Postfix (/suffix).
14940 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
14941 * parameters.
14495 *
14942 *
14496 * @example
14943 * @example
14497 * // Column definition using the number renderer
14944 * // Column definition using the number renderer
@@ -14503,11 +14950,25 b''
14503 * @namespace
14950 * @namespace
14504 */
14951 */
14505 DataTable.render = {
14952 DataTable.render = {
14506 number: function ( thousands, decimal, precision, prefix ) {
14953 number: function ( thousands, decimal, precision, prefix, postfix ) {
14507 return {
14954 return {
14508 display: function ( d ) {
14955 display: function ( d ) {
14956 if ( typeof d !== 'number' && typeof d !== 'string' ) {
14957 return d;
14958 }
14959
14509 var negative = d < 0 ? '-' : '';
14960 var negative = d < 0 ? '-' : '';
14510 d = Math.abs( parseFloat( d ) );
14961 var flo = parseFloat( d );
14962
14963 // If NaN then there isn't much formatting that we can do - just
14964 // return immediately, escaping any HTML (this was supposed to
14965 // be a number after all)
14966 if ( isNaN( flo ) ) {
14967 return __htmlEscapeEntities( d );
14968 }
14969
14970 flo = flo.toFixed( precision );
14971 d = Math.abs( flo );
14511
14972
14512 var intPart = parseInt( d, 10 );
14973 var intPart = parseInt( d, 10 );
14513 var floatPart = precision ?
14974 var floatPart = precision ?
@@ -14518,8 +14979,15 b''
14518 intPart.toString().replace(
14979 intPart.toString().replace(
14519 /\B(?=(\d{3})+(?!\d))/g, thousands
14980 /\B(?=(\d{3})+(?!\d))/g, thousands
14520 ) +
14981 ) +
14521 floatPart;
14982 floatPart +
14522 }
14983 (postfix||'');
14984 }
14985 };
14986 },
14987
14988 text: function () {
14989 return {
14990 display: __htmlEscapeEntities
14523 };
14991 };
14524 }
14992 }
14525 };
14993 };
@@ -14622,11 +15090,9 b''
14622 _fnCalculateColumnWidths: _fnCalculateColumnWidths,
15090 _fnCalculateColumnWidths: _fnCalculateColumnWidths,
14623 _fnThrottle: _fnThrottle,
15091 _fnThrottle: _fnThrottle,
14624 _fnConvertToWidth: _fnConvertToWidth,
15092 _fnConvertToWidth: _fnConvertToWidth,
14625 _fnScrollingWidthAdjust: _fnScrollingWidthAdjust,
14626 _fnGetWidestNode: _fnGetWidestNode,
15093 _fnGetWidestNode: _fnGetWidestNode,
14627 _fnGetMaxLenString: _fnGetMaxLenString,
15094 _fnGetMaxLenString: _fnGetMaxLenString,
14628 _fnStringToCss: _fnStringToCss,
15095 _fnStringToCss: _fnStringToCss,
14629 _fnScrollBarWidth: _fnScrollBarWidth,
14630 _fnSortFlatten: _fnSortFlatten,
15096 _fnSortFlatten: _fnSortFlatten,
14631 _fnSort: _fnSort,
15097 _fnSort: _fnSort,
14632 _fnSortAria: _fnSortAria,
15098 _fnSortAria: _fnSortAria,
@@ -14655,6 +15121,9 b''
14655 // jQuery access
15121 // jQuery access
14656 $.fn.dataTable = DataTable;
15122 $.fn.dataTable = DataTable;
14657
15123
15124 // Provide access to the host jQuery object (circular reference)
15125 DataTable.$ = $;
15126
14658 // Legacy aliases
15127 // Legacy aliases
14659 $.fn.dataTableSettings = DataTable.settings;
15128 $.fn.dataTableSettings = DataTable.settings;
14660 $.fn.dataTableExt = DataTable.ext;
15129 $.fn.dataTableExt = DataTable.ext;
@@ -14835,7 +15304,4 b''
14835 */
15304 */
14836
15305
14837 return $.fn.dataTable;
15306 return $.fn.dataTable;
14838 }));
15307 })); No newline at end of file
14839
14840 }(window, document));
14841
General Comments 0
You need to be logged in to leave comments. Login now