datatables-rails 1.10.3.0 → 1.10.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 448695f83eb0baab891618a62105aa0ae68ea726
4
- data.tar.gz: b3f5672e45fe6480a63a03030d36950d8b5e6ada
3
+ metadata.gz: bb2262628aa14bde5ae36449b004cb85767b3c74
4
+ data.tar.gz: f666eae22ab348a0a687f5afffcb22bf05d1c376
5
5
  SHA512:
6
- metadata.gz: b4453f2c7a8b0b8fc703d386b97092ad4f744e2c2afcda2e136ff06e347f0182210d1a81e324b3d21e9a0ed3cd01ee5ecd93be8c166ea6f0a825ebbb472bc431
7
- data.tar.gz: abeb44b9b03a24cc9083a4a8eeab9137a67ba336b929653b085ab87113735c4fd9b92005896f14cd7f753ef949f8026fe09cff3280f6adb1fe1680cff85ab15a
6
+ metadata.gz: 02ee35669617af600877215ae68f0aab9cf253d556eac7278554c26036076a972d179a58ffc506aa99e8caf9f1fa3e06d3da2296f6ce0c1f176ff1296c554278
7
+ data.tar.gz: 093cb2cf508c9d31d8689b2730f0e32907a7b8a9f0d12d85068e7b98c48c4ad6899211a54ad5cea5b1a00f0ac55865fe0952d0e8fdea61741115c2bf3a765c6f
data/README.md CHANGED
@@ -1,9 +1,11 @@
1
- # datatables-rails
1
+ # datatables-rails [![Gem Version](https://badge.fury.io/rb/datatables-rails.svg)](http://badge.fury.io/rb/datatables-rails)
2
2
 
3
3
  The `datatables-rails` gem packages the [jQuery DataTables](http://www.datatables.net/) assets for easy inclusion in an Rails >= 3.1 application using the asset pipeline.
4
4
 
5
5
  The MAJOR, MINOR and PATCH version numbers of this gem will follow the version numbers of jQuery DataTables. The fourth version number will be increased for changes unrelated to the assets themselves.
6
6
 
7
+ For an alternative solution, feel free to take a look at the [jquery-datatables-rails gem](https://github.com/rweng/jquery-datatables-rails).
8
+
7
9
  ## Installation
8
10
 
9
11
  To use this gem you need to include [jQuery](http://jquery.com/) in your applications's javascript.
@@ -13,7 +15,7 @@ To do so you may use the [jquery-rails gem](https://github.com/rails/jquery-rail
13
15
  Add this line to your application's `Gemfile`:
14
16
 
15
17
  ```
16
- gem 'datatables-rails', '~> 1.10.3.0'
18
+ gem 'datatables-rails', '~> 1.10.7.0'
17
19
  ```
18
20
 
19
21
  And then execute:
@@ -1,11 +1,11 @@
1
- /*! DataTables 1.10.3
1
+ /*! DataTables 1.10.7
2
2
  * ©2008-2014 SpryMedia Ltd - datatables.net/license
3
3
  */
4
4
 
5
5
  /**
6
6
  * @summary DataTables
7
7
  * @description Paginate, search and order HTML tables
8
- * @version 1.10.3
8
+ * @version 1.10.7
9
9
  * @file jquery.dataTables.js
10
10
  * @author SpryMedia Ltd (www.sprymedia.co.uk)
11
11
  * @contact www.sprymedia.co.uk/contact
@@ -22,7 +22,7 @@
22
22
  */
23
23
 
24
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,_fnInvalidateRow,_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,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnScrollBarWidth,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
26
26
 
27
27
  (/** @lends <global> */function( window, document, undefined ) {
28
28
 
@@ -35,7 +35,7 @@
35
35
  }
36
36
  else if ( typeof exports === 'object' ) {
37
37
  // Node/CommonJS
38
- factory( require( 'jquery' ) );
38
+ module.exports = factory( require( 'jquery' ) );
39
39
  }
40
40
  else if ( jQuery && !jQuery.fn.dataTable ) {
41
41
  // Define using browser globals otherwise
@@ -111,9 +111,17 @@
111
111
  // Escape regular expression special characters
112
112
  var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
113
113
 
114
- // U+2009 is thin space and U+202F is narrow no-break space, both used in many
115
- // standards as thousands separators
116
- var _re_formatted_numeric = /[',$£€¥%\u2009\u202F]/g;
114
+ // http://en.wikipedia.org/wiki/Foreign_exchange_market
115
+ // - \u20BD - Russian ruble.
116
+ // - \u20a9 - South Korean Won
117
+ // - \u20BA - Turkish Lira
118
+ // - \u20B9 - Indian Rupee
119
+ // - R - Brazil (R$) and South Africa
120
+ // - fr - Swiss Franc
121
+ // - kr - Swedish krona, Norwegian krone and Danish krone
122
+ // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
123
+ // standards as thousands separators.
124
+ var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi;
117
125
 
118
126
 
119
127
  var _empty = function ( d ) {
@@ -142,6 +150,13 @@
142
150
  var _isNumber = function ( d, decimalPoint, formatted ) {
143
151
  var strType = typeof d === 'string';
144
152
 
153
+ // If empty return immediately so there must be a number if it is a
154
+ // formatted string (this stops the string "k", or "kr", etc being detected
155
+ // as a formatted number for currency
156
+ if ( _empty( d ) ) {
157
+ return true;
158
+ }
159
+
145
160
  if ( decimalPoint && strType ) {
146
161
  d = _numToDecimal( d, decimalPoint );
147
162
  }
@@ -150,7 +165,7 @@
150
165
  d = d.replace( _re_formatted_numeric, '' );
151
166
  }
152
167
 
153
- return _empty( d ) || (!isNaN( parseFloat(d) ) && isFinite( d ));
168
+ return !isNaN( parseFloat(d) ) && isFinite( d );
154
169
  };
155
170
 
156
171
 
@@ -210,7 +225,9 @@
210
225
  // is essential here
211
226
  if ( prop2 !== undefined ) {
212
227
  for ( ; i<ien ; i++ ) {
213
- out.push( a[ order[i] ][ prop ][ prop2 ] );
228
+ if ( a[ order[i] ][ prop ] ) {
229
+ out.push( a[ order[i] ][ prop ][ prop2 ] );
230
+ }
214
231
  }
215
232
  }
216
233
  else {
@@ -245,6 +262,20 @@
245
262
  };
246
263
 
247
264
 
265
+ var _removeEmpty = function ( a )
266
+ {
267
+ var out = [];
268
+
269
+ for ( var i=0, ien=a.length ; i<ien ; i++ ) {
270
+ if ( a[i] ) { // careful - will remove all falsy values!
271
+ out.push( a[i] );
272
+ }
273
+ }
274
+
275
+ return out;
276
+ };
277
+
278
+
248
279
  var _stripHtml = function ( d ) {
249
280
  return d.replace( _re_html, '' );
250
281
  };
@@ -462,6 +493,12 @@
462
493
  _fnCompatMap( init, 'orderData', 'aDataSort' );
463
494
  _fnCompatMap( init, 'orderSequence', 'asSorting' );
464
495
  _fnCompatMap( init, 'orderDataType', 'sortDataType' );
496
+
497
+ // orderData can be given as an integer
498
+ var dataSort = init.aDataSort;
499
+ if ( dataSort && ! $.isArray( dataSort ) ) {
500
+ init.aDataSort = [ dataSort ];
501
+ }
465
502
  }
466
503
 
467
504
 
@@ -512,7 +549,7 @@
512
549
 
513
550
  // In rtl text layout, some browsers (most, but not all) will place the
514
551
  // scrollbar on the left, rather than the right.
515
- browser.bScrollbarLeft = test.offset().left !== 1;
552
+ browser.bScrollbarLeft = Math.round( test.offset().left ) !== 1;
516
553
 
517
554
  n.remove();
518
555
  }
@@ -579,7 +616,7 @@
579
616
  searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
580
617
 
581
618
  // Use the default column options function to initialise classes etc
582
- _fnColumnOptions( oSettings, iCol, null );
619
+ _fnColumnOptions( oSettings, iCol, $(nTh).data() );
583
620
  }
584
621
 
585
622
 
@@ -642,7 +679,7 @@
642
679
  /* iDataSort to be applied (backwards compatibility), but aDataSort will take
643
680
  * priority if defined
644
681
  */
645
- if ( typeof oOptions.iDataSort === 'number' )
682
+ if ( oOptions.iDataSort !== undefined )
646
683
  {
647
684
  oCol.aDataSort = [ oOptions.iDataSort ];
648
685
  }
@@ -842,11 +879,18 @@
842
879
 
843
880
  detectedType = types[j]( cache[k], settings );
844
881
 
845
- // Doesn't match, so break early, since this type can't
846
- // apply to this column. Also, HTML is a special case since
847
- // it is so similar to `string`. Just a single match is
848
- // needed for a column to be html type
849
- if ( ! detectedType || detectedType === 'html' ) {
882
+ // If null, then this type can't apply to this column, so
883
+ // rather than testing all cells, break out. There is an
884
+ // exception for the last type which is `html`. We need to
885
+ // scan all rows since it is possible to mix string and HTML
886
+ // types
887
+ if ( ! detectedType && j !== types.length-1 ) {
888
+ break;
889
+ }
890
+
891
+ // Only a single match is needed for html type since it is
892
+ // bottom of the pile and very similar to string
893
+ if ( detectedType === 'html' ) {
850
894
  break;
851
895
  }
852
896
  }
@@ -1429,61 +1473,75 @@
1429
1473
  * the cached data is next requested. Also update from the data source object.
1430
1474
  *
1431
1475
  * @param {object} settings DataTables settings object
1432
- * @param {int} rowIdx Row index to invalidate
1476
+ * @param {int} rowIdx Row index to invalidate
1477
+ * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
1478
+ * or 'data'
1479
+ * @param {int} [colIdx] Column index to invalidate. If undefined the whole
1480
+ * row will be invalidated
1433
1481
  * @memberof DataTable#oApi
1434
1482
  *
1435
1483
  * @todo For the modularisation of v1.11 this will need to become a callback, so
1436
1484
  * the sort and filter methods can subscribe to it. That will required
1437
1485
  * initialisation options for sorting, which is why it is not already baked in
1438
1486
  */
1439
- function _fnInvalidateRow( settings, rowIdx, src, column )
1487
+ function _fnInvalidate( settings, rowIdx, src, colIdx )
1440
1488
  {
1441
1489
  var row = settings.aoData[ rowIdx ];
1442
1490
  var i, ien;
1491
+ var cellWrite = function ( cell, col ) {
1492
+ // This is very frustrating, but in IE if you just write directly
1493
+ // to innerHTML, and elements that are overwritten are GC'ed,
1494
+ // even if there is a reference to them elsewhere
1495
+ while ( cell.childNodes.length ) {
1496
+ cell.removeChild( cell.firstChild );
1497
+ }
1498
+
1499
+ cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
1500
+ };
1443
1501
 
1444
1502
  // Are we reading last data from DOM or the data object?
1445
1503
  if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
1446
1504
  // Read the data from the DOM
1447
- row._aData = _fnGetRowElements( settings, row ).data;
1505
+ row._aData = _fnGetRowElements(
1506
+ settings, row, colIdx, colIdx === undefined ? undefined : row._aData
1507
+ )
1508
+ .data;
1448
1509
  }
1449
1510
  else {
1450
1511
  // Reading from data object, update the DOM
1451
1512
  var cells = row.anCells;
1452
- var cell;
1453
1513
 
1454
1514
  if ( cells ) {
1455
- for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1456
- cell = cells[i];
1457
-
1458
- // This is very frustrating, but in IE if you just write directly
1459
- // to innerHTML, and elements that are overwritten are GC'ed,
1460
- // even if there is a reference to them elsewhere
1461
- while ( cell.childNodes.length ) {
1462
- cell.removeChild( cell.firstChild );
1515
+ if ( colIdx !== undefined ) {
1516
+ cellWrite( cells[colIdx], colIdx );
1517
+ }
1518
+ else {
1519
+ for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1520
+ cellWrite( cells[i], i );
1463
1521
  }
1464
-
1465
- cells[i].innerHTML = _fnGetCellData( settings, rowIdx, i, 'display' );
1466
1522
  }
1467
1523
  }
1468
1524
  }
1469
1525
 
1526
+ // For both row and cell invalidation, the cached data for sorting and
1527
+ // filtering is nulled out
1470
1528
  row._aSortData = null;
1471
1529
  row._aFilterData = null;
1472
1530
 
1473
1531
  // Invalidate the type for a specific column (if given) or all columns since
1474
1532
  // the data might have changed
1475
1533
  var cols = settings.aoColumns;
1476
- if ( column !== undefined ) {
1477
- cols[ column ].sType = null;
1534
+ if ( colIdx !== undefined ) {
1535
+ cols[ colIdx ].sType = null;
1478
1536
  }
1479
1537
  else {
1480
1538
  for ( i=0, ien=cols.length ; i<ien ; i++ ) {
1481
1539
  cols[i].sType = null;
1482
1540
  }
1483
- }
1484
1541
 
1485
- // Update DataTables special `DT_*` attributes for the row
1486
- _fnRowAttributes( row );
1542
+ // Update DataTables special `DT_*` attributes for the row
1543
+ _fnRowAttributes( row );
1544
+ }
1487
1545
  }
1488
1546
 
1489
1547
 
@@ -1494,13 +1552,17 @@
1494
1552
  * @param {object} settings DataTables settings object
1495
1553
  * @param {node|object} TR element from which to read data or existing row
1496
1554
  * object from which to re-read the data from the cells
1555
+ * @param {int} [colIdx] Optional column index
1556
+ * @param {array|object} [d] Data source object. If `colIdx` is given then this
1557
+ * parameter should also be given and will be used to write the data into.
1558
+ * Only the column in question will be written
1497
1559
  * @returns {object} Object with two parameters: `data` the data read, in
1498
1560
  * document order, and `cells` and array of nodes (they can be useful to the
1499
1561
  * caller, so rather than needing a second traversal to get them, just return
1500
1562
  * them from here).
1501
1563
  * @memberof DataTable#oApi
1502
1564
  */
1503
- function _fnGetRowElements( settings, row )
1565
+ function _fnGetRowElements( settings, row, colIdx, d )
1504
1566
  {
1505
1567
  var
1506
1568
  tds = [],
@@ -1509,7 +1571,8 @@
1509
1571
  columns = settings.aoColumns,
1510
1572
  objectRead = settings._rowReadObject;
1511
1573
 
1512
- var d = objectRead ? {} : [];
1574
+ // Allow the data object to be passed in, or construct
1575
+ d = d || objectRead ? {} : [];
1513
1576
 
1514
1577
  var attr = function ( str, td ) {
1515
1578
  if ( typeof str === 'string' ) {
@@ -1523,30 +1586,33 @@
1523
1586
  }
1524
1587
  };
1525
1588
 
1589
+ // Read data from a cell and store into the data object
1526
1590
  var cellProcess = function ( cell ) {
1527
- col = columns[i];
1528
- contents = $.trim(cell.innerHTML);
1591
+ if ( colIdx === undefined || colIdx === i ) {
1592
+ col = columns[i];
1593
+ contents = $.trim(cell.innerHTML);
1529
1594
 
1530
- if ( col && col._bAttrSrc ) {
1531
- var setter = _fnSetObjectDataFn( col.mData._ );
1532
- setter( d, contents );
1595
+ if ( col && col._bAttrSrc ) {
1596
+ var setter = _fnSetObjectDataFn( col.mData._ );
1597
+ setter( d, contents );
1533
1598
 
1534
- attr( col.mData.sort, cell );
1535
- attr( col.mData.type, cell );
1536
- attr( col.mData.filter, cell );
1537
- }
1538
- else {
1539
- // Depending on the `data` option for the columns the data can be
1540
- // read to either an object or an array.
1541
- if ( objectRead ) {
1542
- if ( ! col._setter ) {
1543
- // Cache the setter function
1544
- col._setter = _fnSetObjectDataFn( col.mData );
1545
- }
1546
- col._setter( d, contents );
1599
+ attr( col.mData.sort, cell );
1600
+ attr( col.mData.type, cell );
1601
+ attr( col.mData.filter, cell );
1547
1602
  }
1548
1603
  else {
1549
- d.push( contents );
1604
+ // Depending on the `data` option for the columns the data can
1605
+ // be read to either an object or an array.
1606
+ if ( objectRead ) {
1607
+ if ( ! col._setter ) {
1608
+ // Cache the setter function
1609
+ col._setter = _fnSetObjectDataFn( col.mData );
1610
+ }
1611
+ col._setter( d, contents );
1612
+ }
1613
+ else {
1614
+ d[i] = contents;
1615
+ }
1550
1616
  }
1551
1617
  }
1552
1618
 
@@ -1554,7 +1620,7 @@
1554
1620
  };
1555
1621
 
1556
1622
  if ( td ) {
1557
- // `tr` element passed in
1623
+ // `tr` element was passed in
1558
1624
  while ( td ) {
1559
1625
  name = td.nodeName.toUpperCase();
1560
1626
 
@@ -1689,6 +1755,10 @@
1689
1755
  .addClass( data.DT_RowClass );
1690
1756
  }
1691
1757
 
1758
+ if ( data.DT_RowAttr ) {
1759
+ $(tr).attr( data.DT_RowAttr );
1760
+ }
1761
+
1692
1762
  if ( data.DT_RowData ) {
1693
1763
  $(tr).data( data.DT_RowData );
1694
1764
  }
@@ -2322,8 +2392,6 @@
2322
2392
  return aReturn;
2323
2393
  }
2324
2394
 
2325
-
2326
-
2327
2395
  /**
2328
2396
  * Create an Ajax call based on the table's settings, taking into account that
2329
2397
  * parameters can have multiple forms, and backwards compatibility.
@@ -2366,16 +2434,20 @@
2366
2434
  var ajaxData;
2367
2435
  var ajax = oSettings.ajax;
2368
2436
  var instance = oSettings.oInstance;
2437
+ var callback = function ( json ) {
2438
+ _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
2439
+ fn( json );
2440
+ };
2369
2441
 
2370
2442
  if ( $.isPlainObject( ajax ) && ajax.data )
2371
2443
  {
2372
2444
  ajaxData = ajax.data;
2373
2445
 
2374
2446
  var newData = $.isFunction( ajaxData ) ?
2375
- ajaxData( data ) : // fn can manipulate data or return an object
2376
- ajaxData; // object or array to merge
2447
+ ajaxData( data, oSettings ) : // fn can manipulate data or return
2448
+ ajaxData; // an object object or array to merge
2377
2449
 
2378
- // If the function returned an object, use that alone
2450
+ // If the function returned something, use that alone
2379
2451
  data = $.isFunction( ajaxData ) && newData ?
2380
2452
  newData :
2381
2453
  $.extend( true, data, newData );
@@ -2390,24 +2462,25 @@
2390
2462
  "success": function (json) {
2391
2463
  var error = json.error || json.sError;
2392
2464
  if ( error ) {
2393
- oSettings.oApi._fnLog( oSettings, 0, error );
2465
+ _fnLog( oSettings, 0, error );
2394
2466
  }
2395
2467
 
2396
2468
  oSettings.json = json;
2397
- _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json] );
2398
- fn( json );
2469
+ callback( json );
2399
2470
  },
2400
2471
  "dataType": "json",
2401
2472
  "cache": false,
2402
2473
  "type": oSettings.sServerMethod,
2403
2474
  "error": function (xhr, error, thrown) {
2404
- var log = oSettings.oApi._fnLog;
2475
+ var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
2405
2476
 
2406
- if ( error == "parsererror" ) {
2407
- log( oSettings, 0, 'Invalid JSON response', 1 );
2408
- }
2409
- else if ( xhr.readyState === 4 ) {
2410
- log( oSettings, 0, 'Ajax error', 7 );
2477
+ if ( $.inArray( true, ret ) === -1 ) {
2478
+ if ( error == "parsererror" ) {
2479
+ _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
2480
+ }
2481
+ else if ( xhr.readyState === 4 ) {
2482
+ _fnLog( oSettings, 0, 'Ajax error', 7 );
2483
+ }
2411
2484
  }
2412
2485
 
2413
2486
  _fnProcessingDisplay( oSettings, false );
@@ -2428,7 +2501,7 @@
2428
2501
  $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
2429
2502
  return { name: key, value: val };
2430
2503
  } ),
2431
- fn,
2504
+ callback,
2432
2505
  oSettings
2433
2506
  );
2434
2507
  }
@@ -2442,7 +2515,7 @@
2442
2515
  else if ( $.isFunction( ajax ) )
2443
2516
  {
2444
2517
  // Is a function - let the caller define what needs to be done
2445
- oSettings.jqXHR = ajax.call( instance, data, fn, oSettings );
2518
+ oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
2446
2519
  }
2447
2520
  else
2448
2521
  {
@@ -2608,9 +2681,10 @@
2608
2681
  return json[old] !== undefined ? json[old] : json[modern];
2609
2682
  };
2610
2683
 
2684
+ var data = _fnAjaxDataSrc( settings, json );
2611
2685
  var draw = compat( 'sEcho', 'draw' );
2612
2686
  var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
2613
- var rocordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
2687
+ var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
2614
2688
 
2615
2689
  if ( draw ) {
2616
2690
  // Protect against out of sequence returns
@@ -2622,9 +2696,8 @@
2622
2696
 
2623
2697
  _fnClearTable( settings );
2624
2698
  settings._iRecordsTotal = parseInt(recordsTotal, 10);
2625
- settings._iRecordsDisplay = parseInt(rocordsFiltered, 10);
2699
+ settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
2626
2700
 
2627
- var data = _fnAjaxDataSrc( settings, json );
2628
2701
  for ( var i=0, ien=data.length ; i<ien ; i++ ) {
2629
2702
  _fnAddData( settings, data[i] );
2630
2703
  }
@@ -2667,7 +2740,6 @@
2667
2740
  json;
2668
2741
  }
2669
2742
 
2670
-
2671
2743
  /**
2672
2744
  * Generate the node required for filtering text
2673
2745
  * @returns {node} Filter control element
@@ -2948,7 +3020,7 @@
2948
3020
  *
2949
3021
  * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
2950
3022
  */
2951
- var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || '', function ( word ) {
3023
+ var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
2952
3024
  if ( word.charAt(0) === '"' ) {
2953
3025
  var m = word.match( /^"(.*)"$/ );
2954
3026
  word = m ? m[1] : word;
@@ -2965,7 +3037,7 @@
2965
3037
 
2966
3038
 
2967
3039
  /**
2968
- * scape a string such that it can be used in a regular expression
3040
+ * Escape a string such that it can be used in a regular expression
2969
3041
  * @param {string} sVal string to escape
2970
3042
  * @returns {string} escaped string
2971
3043
  * @memberof DataTable#oApi
@@ -3605,12 +3677,12 @@
3605
3677
  headerClone
3606
3678
  .removeAttr('id')
3607
3679
  .css( 'margin-left', 0 )
3680
+ .append( captionSide === 'top' ? caption : null )
3608
3681
  .append(
3609
3682
  table.children('thead')
3610
3683
  )
3611
3684
  )
3612
3685
  )
3613
- .append( captionSide === 'top' ? caption : null )
3614
3686
  )
3615
3687
  .append(
3616
3688
  $(_div, { 'class': classes.sScrollBody } )
@@ -3636,12 +3708,12 @@
3636
3708
  footerClone
3637
3709
  .removeAttr('id')
3638
3710
  .css( 'margin-left', 0 )
3711
+ .append( captionSide === 'bottom' ? caption : null )
3639
3712
  .append(
3640
3713
  table.children('tfoot')
3641
3714
  )
3642
3715
  )
3643
3716
  )
3644
- .append( captionSide === 'bottom' ? caption : null )
3645
3717
  );
3646
3718
  }
3647
3719
 
@@ -3652,7 +3724,7 @@
3652
3724
 
3653
3725
  // When the body is scrolled, then we also want to scroll the headers
3654
3726
  if ( scrollX ) {
3655
- $(scrollBody).scroll( function (e) {
3727
+ $(scrollBody).on( 'scroll.DT', function (e) {
3656
3728
  var scrollLeft = this.scrollLeft;
3657
3729
 
3658
3730
  scrollHead.scrollLeft = scrollLeft;
@@ -4033,11 +4105,16 @@
4033
4105
  columnCount = columns.length,
4034
4106
  visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
4035
4107
  headerCells = $('th', oSettings.nTHead),
4036
- tableWidthAttr = table.getAttribute('width'),
4108
+ tableWidthAttr = table.getAttribute('width'), // from DOM element
4037
4109
  tableContainer = table.parentNode,
4038
4110
  userInputs = false,
4039
4111
  i, column, columnIdx, width, outerWidth;
4040
4112
 
4113
+ var styleWidth = table.style.width;
4114
+ if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
4115
+ tableWidthAttr = styleWidth;
4116
+ }
4117
+
4041
4118
  /* Convert any user input sizes into pixel sizes */
4042
4119
  for ( i=0 ; i<visibleColumns.length ; i++ ) {
4043
4120
  column = columns[ visibleColumns[i] ];
@@ -4064,22 +4141,21 @@
4064
4141
  }
4065
4142
  else
4066
4143
  {
4067
- // Otherwise construct a single row table with the widest node in the
4068
- // data, assign any user defined widths, then insert it into the DOM and
4069
- // allow the browser to do all the hard work of calculating table widths
4144
+ // Otherwise construct a single row, worst case, table with the widest
4145
+ // node in the data, assign any user defined widths, then insert it into
4146
+ // the DOM and allow the browser to do all the hard work of calculating
4147
+ // table widths
4070
4148
  var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
4071
- .empty()
4072
4149
  .css( 'visibility', 'hidden' )
4073
- .removeAttr( 'id' )
4074
- .append( $(oSettings.nTHead).clone( false ) )
4075
- .append( $(oSettings.nTFoot).clone( false ) )
4076
- .append( $('<tbody><tr/></tbody>') );
4150
+ .removeAttr( 'id' );
4151
+
4152
+ // Clean up the table body
4153
+ tmpTable.find('tbody tr').remove();
4154
+ var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
4077
4155
 
4078
4156
  // Remove any assigned widths from the footer (from scrolling)
4079
4157
  tmpTable.find('tfoot th, tfoot td').css('width', '');
4080
4158
 
4081
- var tr = tmpTable.find( 'tbody tr' );
4082
-
4083
4159
  // Apply custom sizing to the cloned header
4084
4160
  headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
4085
4161
 
@@ -4177,9 +4253,20 @@
4177
4253
  }
4178
4254
 
4179
4255
  if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
4180
- $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
4181
- _fnAdjustColumnSizing( oSettings );
4182
- } ) );
4256
+ var bindResize = function () {
4257
+ $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
4258
+ _fnAdjustColumnSizing( oSettings );
4259
+ } ) );
4260
+ };
4261
+
4262
+ // IE6/7 will crash if we bind a resize event handler on page load.
4263
+ // To be removed in 1.11 which drops IE6/7 support
4264
+ if ( oSettings.oBrowser.bScrollOversize ) {
4265
+ setTimeout( bindResize, 1000 );
4266
+ }
4267
+ else {
4268
+ bindResize();
4269
+ }
4183
4270
 
4184
4271
  oSettings._reszEvt = true;
4185
4272
  }
@@ -4214,12 +4301,9 @@
4214
4301
  fn.apply( that, args );
4215
4302
  }, frequency );
4216
4303
  }
4217
- else if ( last ) {
4218
- last = now;
4219
- fn.apply( that, args );
4220
- }
4221
4304
  else {
4222
4305
  last = now;
4306
+ fn.apply( that, args );
4223
4307
  }
4224
4308
  };
4225
4309
  }
@@ -4350,41 +4434,28 @@
4350
4434
  {
4351
4435
  // On first run a static variable is set, since this is only needed once.
4352
4436
  // Subsequent runs will just use the previously calculated value
4353
- if ( ! DataTable.__scrollbarWidth ) {
4354
- var inner = $('<p/>').css( {
4355
- width: '100%',
4356
- height: 200,
4357
- padding: 0
4358
- } )[0];
4359
-
4360
- var outer = $('<div/>')
4361
- .css( {
4437
+ var width = DataTable.__scrollbarWidth;
4438
+
4439
+ if ( width === undefined ) {
4440
+ var sizer = $('<p/>').css( {
4362
4441
  position: 'absolute',
4363
4442
  top: 0,
4364
4443
  left: 0,
4365
- width: 200,
4444
+ width: '100%',
4366
4445
  height: 150,
4367
4446
  padding: 0,
4368
- overflow: 'hidden',
4447
+ overflow: 'scroll',
4369
4448
  visibility: 'hidden'
4370
4449
  } )
4371
- .append( inner )
4372
- .appendTo( 'body' );
4373
-
4374
- var w1 = inner.offsetWidth;
4375
- outer.css( 'overflow', 'scroll' );
4376
- var w2 = inner.offsetWidth;
4377
-
4378
- if ( w1 === w2 ) {
4379
- w2 = outer[0].clientWidth;
4380
- }
4450
+ .appendTo('body');
4381
4451
 
4382
- outer.remove();
4452
+ width = sizer[0].offsetWidth - sizer[0].clientWidth;
4453
+ DataTable.__scrollbarWidth = width;
4383
4454
 
4384
- DataTable.__scrollbarWidth = w1 - w2;
4455
+ sizer.remove();
4385
4456
  }
4386
4457
 
4387
- return DataTable.__scrollbarWidth;
4458
+ return width;
4388
4459
  }
4389
4460
 
4390
4461
 
@@ -4675,6 +4746,10 @@
4675
4746
  // Yes, modify the sort
4676
4747
  nextSortIdx = next( sorting[sortIdx], true );
4677
4748
 
4749
+ if ( nextSortIdx === null && sorting.length === 1 ) {
4750
+ nextSortIdx = 0; // can't remove sorting completely
4751
+ }
4752
+
4678
4753
  if ( nextSortIdx === null ) {
4679
4754
  sorting.splice( sortIdx, 1 );
4680
4755
  }
@@ -4909,31 +4984,43 @@
4909
4984
 
4910
4985
  // Restore key features - todo - for 1.11 this needs to be done by
4911
4986
  // subscribed events
4912
- settings._iDisplayStart = state.start;
4913
- settings.iInitDisplayStart = state.start;
4914
- settings._iDisplayLength = state.length;
4915
- settings.aaSorting = [];
4987
+ if ( state.start !== undefined ) {
4988
+ settings._iDisplayStart = state.start;
4989
+ settings.iInitDisplayStart = state.start;
4990
+ }
4991
+ if ( state.length !== undefined ) {
4992
+ settings._iDisplayLength = state.length;
4993
+ }
4916
4994
 
4917
4995
  // Order
4918
- $.each( state.order, function ( i, col ) {
4919
- settings.aaSorting.push( col[0] >= columns.length ?
4920
- [ 0, col[1] ] :
4921
- col
4922
- );
4923
- } );
4996
+ if ( state.order !== undefined ) {
4997
+ settings.aaSorting = [];
4998
+ $.each( state.order, function ( i, col ) {
4999
+ settings.aaSorting.push( col[0] >= columns.length ?
5000
+ [ 0, col[1] ] :
5001
+ col
5002
+ );
5003
+ } );
5004
+ }
4924
5005
 
4925
5006
  // Search
4926
- $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
5007
+ if ( state.search !== undefined ) {
5008
+ $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
5009
+ }
4927
5010
 
4928
5011
  // Columns
4929
5012
  for ( i=0, ien=state.columns.length ; i<ien ; i++ ) {
4930
5013
  var col = state.columns[i];
4931
5014
 
4932
5015
  // Visibility
4933
- columns[i].bVisible = col.visible;
5016
+ if ( col.visible !== undefined ) {
5017
+ columns[i].bVisible = col.visible;
5018
+ }
4934
5019
 
4935
5020
  // Search
4936
- $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
5021
+ if ( col.search !== undefined ) {
5022
+ $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
5023
+ }
4937
5024
  }
4938
5025
 
4939
5026
  _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
@@ -4980,12 +5067,17 @@
4980
5067
  var ext = DataTable.ext;
4981
5068
  var type = ext.sErrMode || ext.errMode;
4982
5069
 
5070
+ _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
5071
+
4983
5072
  if ( type == 'alert' ) {
4984
5073
  alert( msg );
4985
5074
  }
4986
- else {
5075
+ else if ( type == 'throw' ) {
4987
5076
  throw new Error(msg);
4988
5077
  }
5078
+ else if ( typeof type == 'function' ) {
5079
+ type( settings, tn, msg );
5080
+ }
4989
5081
  }
4990
5082
  else if ( window.console && console.log ) {
4991
5083
  console.log( msg );
@@ -5128,13 +5220,13 @@
5128
5220
  * @param {object} settings dataTables settings object
5129
5221
  * @param {string} callbackArr Name of the array storage for the callbacks in
5130
5222
  * oSettings
5131
- * @param {string} event Name of the jQuery custom event to trigger. If null no
5132
- * trigger is fired
5223
+ * @param {string} eventName Name of the jQuery custom event to trigger. If
5224
+ * null no trigger is fired
5133
5225
  * @param {array} args Array of arguments to pass to the callback function /
5134
5226
  * trigger
5135
5227
  * @memberof DataTable#oApi
5136
5228
  */
5137
- function _fnCallbackFire( settings, callbackArr, e, args )
5229
+ function _fnCallbackFire( settings, callbackArr, eventName, args )
5138
5230
  {
5139
5231
  var ret = [];
5140
5232
 
@@ -5144,8 +5236,12 @@
5144
5236
  } );
5145
5237
  }
5146
5238
 
5147
- if ( e !== null ) {
5148
- $(settings.nTable).trigger( e+'.dt', args );
5239
+ if ( eventName !== null ) {
5240
+ var e = $.Event( eventName+'.dt' );
5241
+
5242
+ $(settings.nTable).trigger( e, args );
5243
+
5244
+ ret.push( e.result );
5149
5245
  }
5150
5246
 
5151
5247
  return ret;
@@ -5160,11 +5256,14 @@
5160
5256
  len = settings._iDisplayLength;
5161
5257
 
5162
5258
  /* If we have space to show extra rows (backing up from the end point - then do so */
5163
- if (start >= end)
5259
+ if ( start >= end )
5164
5260
  {
5165
5261
  start = end - len;
5166
5262
  }
5167
5263
 
5264
+ // Keep the start record on the current page
5265
+ start -= (start % len);
5266
+
5168
5267
  if ( len === -1 || start < 0 )
5169
5268
  {
5170
5269
  start = 0;
@@ -5554,8 +5653,8 @@
5554
5653
  this.fnDraw = function( complete )
5555
5654
  {
5556
5655
  // Note that this isn't an exact match to the old call to _fnDraw - it takes
5557
- // into account the new data, but can old position.
5558
- this.api( true ).draw( ! complete );
5656
+ // into account the new data, but can hold position.
5657
+ this.api( true ).draw( complete );
5559
5658
  };
5560
5659
 
5561
5660
 
@@ -6003,6 +6102,7 @@
6003
6102
  var sId = this.getAttribute( 'id' );
6004
6103
  var bInitHandedOff = false;
6005
6104
  var defaults = DataTable.defaults;
6105
+ var $this = $(this);
6006
6106
 
6007
6107
 
6008
6108
  /* Sanity check */
@@ -6021,30 +6121,34 @@
6021
6121
  _fnCamelToHungarian( defaults.column, defaults.column, true );
6022
6122
 
6023
6123
  /* Setting up the initialisation object */
6024
- _fnCamelToHungarian( defaults, oInit );
6124
+ _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
6125
+
6126
+
6025
6127
 
6026
6128
  /* Check to see if we are re-initialising a table */
6027
6129
  var allSettings = DataTable.settings;
6028
6130
  for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
6029
6131
  {
6132
+ var s = allSettings[i];
6133
+
6030
6134
  /* Base check on table node */
6031
- if ( allSettings[i].nTable == this )
6135
+ if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )
6032
6136
  {
6033
6137
  var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
6034
6138
  var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
6035
6139
 
6036
6140
  if ( emptyInit || bRetrieve )
6037
6141
  {
6038
- return allSettings[i].oInstance;
6142
+ return s.oInstance;
6039
6143
  }
6040
6144
  else if ( bDestroy )
6041
6145
  {
6042
- allSettings[i].oInstance.fnDestroy();
6146
+ s.oInstance.fnDestroy();
6043
6147
  break;
6044
6148
  }
6045
6149
  else
6046
6150
  {
6047
- _fnLog( allSettings[i], 0, 'Cannot reinitialise DataTable', 3 );
6151
+ _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
6048
6152
  return;
6049
6153
  }
6050
6154
  }
@@ -6054,7 +6158,7 @@
6054
6158
  * instance by simply deleting it. This is under the assumption that the table has been
6055
6159
  * destroyed by other methods. Anyone using non-id selectors will need to do this manually
6056
6160
  */
6057
- if ( allSettings[i].sTableId == this.id )
6161
+ if ( s.sTableId == this.id )
6058
6162
  {
6059
6163
  allSettings.splice( i, 1 );
6060
6164
  break;
@@ -6070,18 +6174,19 @@
6070
6174
 
6071
6175
  /* Create the settings object for this table and set some of the default parameters */
6072
6176
  var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
6073
- "nTable": this,
6074
- "oApi": _that.internal,
6075
- "oInit": oInit,
6076
- "sDestroyWidth": $(this)[0].style.width,
6177
+ "sDestroyWidth": $this[0].style.width,
6077
6178
  "sInstance": sId,
6078
6179
  "sTableId": sId
6079
6180
  } );
6181
+ oSettings.nTable = this;
6182
+ oSettings.oApi = _that.internal;
6183
+ oSettings.oInit = oInit;
6184
+
6080
6185
  allSettings.push( oSettings );
6081
6186
 
6082
6187
  // Need to add the instance after the instance after the settings object has been added
6083
6188
  // to the settings array, so we can self reference the table instance if more than one
6084
- oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable();
6189
+ oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
6085
6190
 
6086
6191
  // Backwards compatibility, before we apply all the defaults
6087
6192
  _fnCompatOpts( oInit );
@@ -6191,7 +6296,7 @@
6191
6296
  {
6192
6297
  $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
6193
6298
  }
6194
- $(this).addClass( oClasses.sTable );
6299
+ $this.addClass( oClasses.sTable );
6195
6300
 
6196
6301
  /* Calculate the scroll bar width and cache it for use later on */
6197
6302
  if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
@@ -6218,26 +6323,31 @@
6218
6323
  }
6219
6324
 
6220
6325
  /* Language definitions */
6221
- if ( oInit.oLanguage.sUrl !== "" )
6326
+ var oLanguage = oSettings.oLanguage;
6327
+ $.extend( true, oLanguage, oInit.oLanguage );
6328
+
6329
+ if ( oLanguage.sUrl !== "" )
6222
6330
  {
6223
6331
  /* Get the language definitions from a file - because this Ajax call makes the language
6224
6332
  * get async to the remainder of this function we use bInitHandedOff to indicate that
6225
6333
  * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
6226
6334
  */
6227
- oSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;
6228
- $.getJSON( oSettings.oLanguage.sUrl, null, function( json ) {
6229
- _fnLanguageCompat( json );
6230
- _fnCamelToHungarian( defaults.oLanguage, json );
6231
- $.extend( true, oSettings.oLanguage, oInit.oLanguage, json );
6232
- _fnInitialise( oSettings );
6335
+ $.ajax( {
6336
+ dataType: 'json',
6337
+ url: oLanguage.sUrl,
6338
+ success: function ( json ) {
6339
+ _fnLanguageCompat( json );
6340
+ _fnCamelToHungarian( defaults.oLanguage, json );
6341
+ $.extend( true, oLanguage, json );
6342
+ _fnInitialise( oSettings );
6343
+ },
6344
+ error: function () {
6345
+ // Error occurred loading language file, continue on as best we can
6346
+ _fnInitialise( oSettings );
6347
+ }
6233
6348
  } );
6234
6349
  bInitHandedOff = true;
6235
6350
  }
6236
- else
6237
- {
6238
- $.extend( true, oSettings.oLanguage, oInit.oLanguage );
6239
- }
6240
-
6241
6351
 
6242
6352
  /*
6243
6353
  * Stripes
@@ -6252,7 +6362,7 @@
6252
6362
 
6253
6363
  /* Remove row stripe classes if they are already on the table row */
6254
6364
  var stripeClasses = oSettings.asStripeClasses;
6255
- var rowOne = $('tbody tr:eq(0)', this);
6365
+ var rowOne = $this.children('tbody').find('tr').eq(0);
6256
6366
  if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
6257
6367
  return rowOne.hasClass(el);
6258
6368
  } ) ) !== -1 ) {
@@ -6303,7 +6413,7 @@
6303
6413
  */
6304
6414
  if ( rowOne.length ) {
6305
6415
  var a = function ( cell, name ) {
6306
- return cell.getAttribute( 'data-'+name ) ? name : null;
6416
+ return cell.getAttribute( 'data-'+name ) !== null ? name : null;
6307
6417
  };
6308
6418
 
6309
6419
  $.each( _fnGetRowElements( oSettings, rowOne[0] ).cells, function (i, cell) {
@@ -6392,25 +6502,25 @@
6392
6502
  _fnBrowserDetect( oSettings );
6393
6503
 
6394
6504
  // Work around for Webkit bug 83867 - store the caption-side before removing from doc
6395
- var captions = $(this).children('caption').each( function () {
6396
- this._captionSide = $(this).css('caption-side');
6505
+ var captions = $this.children('caption').each( function () {
6506
+ this._captionSide = $this.css('caption-side');
6397
6507
  } );
6398
6508
 
6399
- var thead = $(this).children('thead');
6509
+ var thead = $this.children('thead');
6400
6510
  if ( thead.length === 0 )
6401
6511
  {
6402
6512
  thead = $('<thead/>').appendTo(this);
6403
6513
  }
6404
6514
  oSettings.nTHead = thead[0];
6405
6515
 
6406
- var tbody = $(this).children('tbody');
6516
+ var tbody = $this.children('tbody');
6407
6517
  if ( tbody.length === 0 )
6408
6518
  {
6409
6519
  tbody = $('<tbody/>').appendTo(this);
6410
6520
  }
6411
6521
  oSettings.nTBody = tbody[0];
6412
6522
 
6413
- var tfoot = $(this).children('tfoot');
6523
+ var tfoot = $this.children('tfoot');
6414
6524
  if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
6415
6525
  {
6416
6526
  // If we are a scrolling table, and no footer has been given, then we need to create
@@ -6419,7 +6529,7 @@
6419
6529
  }
6420
6530
 
6421
6531
  if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
6422
- $(this).addClass( oClasses.sNoFooter );
6532
+ $this.addClass( oClasses.sNoFooter );
6423
6533
  }
6424
6534
  else if ( tfoot.length > 0 ) {
6425
6535
  oSettings.nTFoot = tfoot[0];
@@ -6628,10 +6738,8 @@
6628
6738
  */
6629
6739
  _Api = function ( context, data )
6630
6740
  {
6631
- if ( ! this instanceof _Api ) {
6632
- throw 'DT API must be constructed as a new object';
6633
- // or should it do the 'new' for the caller?
6634
- // return new _Api.apply( this, arguments );
6741
+ if ( ! (this instanceof _Api) ) {
6742
+ return new _Api( context, data );
6635
6743
  }
6636
6744
 
6637
6745
  var settings = [];
@@ -6672,18 +6780,12 @@
6672
6780
  DataTable.Api = _Api;
6673
6781
 
6674
6782
  _Api.prototype = /** @lends DataTables.Api */{
6675
- /**
6676
- * Return a new Api instance, comprised of the data held in the current
6677
- * instance, join with the other array(s) and/or value(s).
6678
- *
6679
- * An alias for `Array.prototype.concat`.
6680
- *
6681
- * @type method
6682
- * @param {*} value1 Arrays and/or values to concatenate.
6683
- * @param {*} [...] Additional arrays and/or values to concatenate.
6684
- * @returns {DataTables.Api} New API instance, comprising of the combined
6685
- * array.
6686
- */
6783
+ any: function ()
6784
+ {
6785
+ return this.flatten().length !== 0;
6786
+ },
6787
+
6788
+
6687
6789
  concat: __arrayProto.concat,
6688
6790
 
6689
6791
 
@@ -6750,8 +6852,7 @@
6750
6852
  return -1;
6751
6853
  },
6752
6854
 
6753
- // Internal only at the moment - relax?
6754
- iterator: function ( flatten, type, fn ) {
6855
+ iterator: function ( flatten, type, fn, alwaysNew ) {
6755
6856
  var
6756
6857
  a = [], ret,
6757
6858
  i, ien, j, jen,
@@ -6761,6 +6862,7 @@
6761
6862
 
6762
6863
  // Argument shifting
6763
6864
  if ( typeof flatten === 'string' ) {
6865
+ alwaysNew = fn;
6764
6866
  fn = type;
6765
6867
  type = flatten;
6766
6868
  flatten = false;
@@ -6810,7 +6912,7 @@
6810
6912
  }
6811
6913
  }
6812
6914
 
6813
- if ( a.length ) {
6915
+ if ( a.length || alwaysNew ) {
6814
6916
  var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
6815
6917
  var apiSelector = api.selector;
6816
6918
  apiSelector.rows = selector.rows;
@@ -6923,7 +7025,7 @@
6923
7025
  _Api.extend = function ( scope, obj, ext )
6924
7026
  {
6925
7027
  // Only extend API instances and static properties of the API
6926
- if ( ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
7028
+ if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
6927
7029
  return;
6928
7030
  }
6929
7031
 
@@ -7137,35 +7239,35 @@
7137
7239
  _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
7138
7240
  return this.iterator( 'table', function ( ctx ) {
7139
7241
  return ctx.nTable;
7140
- } );
7242
+ }, 1 );
7141
7243
  } );
7142
7244
 
7143
7245
 
7144
7246
  _api_registerPlural( 'tables().body()', 'table().body()' , function () {
7145
7247
  return this.iterator( 'table', function ( ctx ) {
7146
7248
  return ctx.nTBody;
7147
- } );
7249
+ }, 1 );
7148
7250
  } );
7149
7251
 
7150
7252
 
7151
7253
  _api_registerPlural( 'tables().header()', 'table().header()' , function () {
7152
7254
  return this.iterator( 'table', function ( ctx ) {
7153
7255
  return ctx.nTHead;
7154
- } );
7256
+ }, 1 );
7155
7257
  } );
7156
7258
 
7157
7259
 
7158
7260
  _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7159
7261
  return this.iterator( 'table', function ( ctx ) {
7160
7262
  return ctx.nTFoot;
7161
- } );
7263
+ }, 1 );
7162
7264
  } );
7163
7265
 
7164
7266
 
7165
7267
  _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7166
7268
  return this.iterator( 'table', function ( ctx ) {
7167
7269
  return ctx.nTableWrapper;
7168
- } );
7270
+ }, 1 );
7169
7271
  } );
7170
7272
 
7171
7273
 
@@ -7289,6 +7391,15 @@
7289
7391
 
7290
7392
 
7291
7393
  var __reload = function ( settings, holdPosition, callback ) {
7394
+ // Use the draw event to trigger a callback
7395
+ if ( callback ) {
7396
+ var api = new _Api( settings );
7397
+
7398
+ api.one( 'draw', function () {
7399
+ callback( api.ajax.json() );
7400
+ } );
7401
+ }
7402
+
7292
7403
  if ( _fnDataSource( settings ) == 'ssp' ) {
7293
7404
  _fnReDraw( settings, holdPosition );
7294
7405
  }
@@ -7308,16 +7419,6 @@
7308
7419
  _fnProcessingDisplay( settings, false );
7309
7420
  } );
7310
7421
  }
7311
-
7312
- // Use the draw event to trigger a callback, regardless of if it is an async
7313
- // or sync draw
7314
- if ( callback ) {
7315
- var api = new _Api( settings );
7316
-
7317
- api.one( 'draw', function () {
7318
- callback( api.ajax.json() );
7319
- } );
7320
- }
7321
7422
  };
7322
7423
 
7323
7424
 
@@ -7433,7 +7534,7 @@
7433
7534
 
7434
7535
 
7435
7536
 
7436
- var _selector_run = function ( selector, select )
7537
+ var _selector_run = function ( type, selector, selectFn, settings, opts )
7437
7538
  {
7438
7539
  var
7439
7540
  out = [], res,
@@ -7452,7 +7553,7 @@
7452
7553
  [ selector[i] ];
7453
7554
 
7454
7555
  for ( j=0, jen=a.length ; j<jen ; j++ ) {
7455
- res = select( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7556
+ res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7456
7557
 
7457
7558
  if ( res && res.length ) {
7458
7559
  out.push.apply( out, res );
@@ -7460,6 +7561,14 @@
7460
7561
  }
7461
7562
  }
7462
7563
 
7564
+ // selector extensions
7565
+ var ext = _ext.selector[ type ];
7566
+ if ( ext.length ) {
7567
+ for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7568
+ out = ext[i]( settings, opts, out );
7569
+ }
7570
+ }
7571
+
7463
7572
  return out;
7464
7573
  };
7465
7574
 
@@ -7472,15 +7581,15 @@
7472
7581
 
7473
7582
  // Backwards compatibility for 1.9- which used the terminology filter rather
7474
7583
  // than search
7475
- if ( opts.filter && ! opts.search ) {
7584
+ if ( opts.filter && opts.search === undefined ) {
7476
7585
  opts.search = opts.filter;
7477
7586
  }
7478
7587
 
7479
- return {
7480
- search: opts.search || 'none',
7481
- order: opts.order || 'current',
7482
- page: opts.page || 'all'
7483
- };
7588
+ return $.extend( {
7589
+ search: 'none',
7590
+ order: 'current',
7591
+ page: 'all'
7592
+ }, opts );
7484
7593
  };
7485
7594
 
7486
7595
 
@@ -7492,6 +7601,7 @@
7492
7601
  // Assign the first element to the first item in the instance
7493
7602
  // and truncate the instance and context
7494
7603
  inst[0] = inst[i];
7604
+ inst[0].length = 1;
7495
7605
  inst.length = 1;
7496
7606
  inst.context = [ inst.context[i] ];
7497
7607
 
@@ -7578,7 +7688,7 @@
7578
7688
 
7579
7689
  var __row_selector = function ( settings, selector, opts )
7580
7690
  {
7581
- return _selector_run( selector, function ( sel ) {
7691
+ var run = function ( sel ) {
7582
7692
  var selInt = _intVal( sel );
7583
7693
  var i, ien;
7584
7694
 
@@ -7600,9 +7710,6 @@
7600
7710
  return rows;
7601
7711
  }
7602
7712
 
7603
- // Get nodes in the order from the `rows` array
7604
- var nodes = _pluck_order( settings.aoData, rows, 'nTr' );
7605
-
7606
7713
  // Selector - function
7607
7714
  if ( typeof sel === 'function' ) {
7608
7715
  return $.map( rows, function (idx) {
@@ -7611,11 +7718,16 @@
7611
7718
  } );
7612
7719
  }
7613
7720
 
7721
+ // Get nodes in the order from the `rows` array with null values removed
7722
+ var nodes = _removeEmpty(
7723
+ _pluck_order( settings.aoData, rows, 'nTr' )
7724
+ );
7725
+
7614
7726
  // Selector - node
7615
7727
  if ( sel.nodeName ) {
7616
7728
  if ( $.inArray( sel, nodes ) !== -1 ) {
7617
- return [ sel._DT_RowIndex ];// sel is a TR node that is in the table
7618
- // and DataTables adds a prop for fast lookup
7729
+ return [ sel._DT_RowIndex ]; // sel is a TR node that is in the table
7730
+ // and DataTables adds a prop for fast lookup
7619
7731
  }
7620
7732
  }
7621
7733
 
@@ -7628,13 +7740,12 @@
7628
7740
  return this._DT_RowIndex;
7629
7741
  } )
7630
7742
  .toArray();
7631
- } );
7743
+ };
7744
+
7745
+ return _selector_run( 'row', selector, run, settings, opts );
7632
7746
  };
7633
7747
 
7634
7748
 
7635
- /**
7636
- *
7637
- */
7638
7749
  _api_register( 'rows()', function ( selector, opts ) {
7639
7750
  // argument shifting
7640
7751
  if ( selector === undefined ) {
@@ -7649,7 +7760,7 @@
7649
7760
 
7650
7761
  var inst = this.iterator( 'table', function ( settings ) {
7651
7762
  return __row_selector( settings, selector, opts );
7652
- } );
7763
+ }, 1 );
7653
7764
 
7654
7765
  // Want argument shifting here and in __row_selector?
7655
7766
  inst.selector.rows = selector;
@@ -7658,36 +7769,35 @@
7658
7769
  return inst;
7659
7770
  } );
7660
7771
 
7661
-
7662
7772
  _api_register( 'rows().nodes()', function () {
7663
7773
  return this.iterator( 'row', function ( settings, row ) {
7664
7774
  return settings.aoData[ row ].nTr || undefined;
7665
- } );
7775
+ }, 1 );
7666
7776
  } );
7667
7777
 
7668
7778
  _api_register( 'rows().data()', function () {
7669
7779
  return this.iterator( true, 'rows', function ( settings, rows ) {
7670
7780
  return _pluck_order( settings.aoData, rows, '_aData' );
7671
- } );
7781
+ }, 1 );
7672
7782
  } );
7673
7783
 
7674
7784
  _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7675
7785
  return this.iterator( 'row', function ( settings, row ) {
7676
7786
  var r = settings.aoData[ row ];
7677
7787
  return type === 'search' ? r._aFilterData : r._aSortData;
7678
- } );
7788
+ }, 1 );
7679
7789
  } );
7680
7790
 
7681
7791
  _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7682
7792
  return this.iterator( 'row', function ( settings, row ) {
7683
- _fnInvalidateRow( settings, row, src );
7793
+ _fnInvalidate( settings, row, src );
7684
7794
  } );
7685
7795
  } );
7686
7796
 
7687
7797
  _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
7688
7798
  return this.iterator( 'row', function ( settings, row ) {
7689
7799
  return row;
7690
- } );
7800
+ }, 1 );
7691
7801
  } );
7692
7802
 
7693
7803
  _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
@@ -7736,7 +7846,7 @@
7736
7846
  }
7737
7847
 
7738
7848
  return out;
7739
- } );
7849
+ }, 1 );
7740
7850
 
7741
7851
  // Return an Api.rows() extended instance, so rows().nodes() etc can be used
7742
7852
  var modRows = this.rows( -1 );
@@ -7772,7 +7882,7 @@
7772
7882
  ctx[0].aoData[ this[0] ]._aData = data;
7773
7883
 
7774
7884
  // Automatically invalidate
7775
- _fnInvalidateRow( ctx[0], this[0], 'data' );
7885
+ _fnInvalidate( ctx[0], this[0], 'data' );
7776
7886
 
7777
7887
  return this;
7778
7888
  } );
@@ -7812,6 +7922,14 @@
7812
7922
  // Convert to array of TR elements
7813
7923
  var rows = [];
7814
7924
  var addRow = function ( r, k ) {
7925
+ // Recursion to allow for arrays of jQuery objects
7926
+ if ( $.isArray( r ) || r instanceof $ ) {
7927
+ for ( var i=0, ien=r.length ; i<ien ; i++ ) {
7928
+ addRow( r[i], k );
7929
+ }
7930
+ return;
7931
+ }
7932
+
7815
7933
  // If we get a TR element, then just add it directly - up to the dev
7816
7934
  // to add the correct number of columns etc
7817
7935
  if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
@@ -7829,14 +7947,7 @@
7829
7947
  }
7830
7948
  };
7831
7949
 
7832
- if ( $.isArray( data ) || data instanceof $ ) {
7833
- for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7834
- addRow( data[i], klass );
7835
- }
7836
- }
7837
- else {
7838
- addRow( data, klass );
7839
- }
7950
+ addRow( data, klass );
7840
7951
 
7841
7952
  if ( row._details ) {
7842
7953
  row._details.remove();
@@ -8061,7 +8172,7 @@
8061
8172
  names = _pluck( columns, 'sName' ),
8062
8173
  nodes = _pluck( columns, 'nTh' );
8063
8174
 
8064
- return _selector_run( selector, function ( s ) {
8175
+ var run = function ( s ) {
8065
8176
  var selInt = _intVal( s );
8066
8177
 
8067
8178
  // Selector - all
@@ -8127,7 +8238,9 @@
8127
8238
  } )
8128
8239
  .toArray();
8129
8240
  }
8130
- } );
8241
+ };
8242
+
8243
+ return _selector_run( 'column', selector, run, settings, opts );
8131
8244
  };
8132
8245
 
8133
8246
 
@@ -8190,9 +8303,6 @@
8190
8303
  };
8191
8304
 
8192
8305
 
8193
- /**
8194
- *
8195
- */
8196
8306
  _api_register( 'columns()', function ( selector, opts ) {
8197
8307
  // argument shifting
8198
8308
  if ( selector === undefined ) {
@@ -8207,7 +8317,7 @@
8207
8317
 
8208
8318
  var inst = this.iterator( 'table', function ( settings ) {
8209
8319
  return __column_selector( settings, selector, opts );
8210
- } );
8320
+ }, 1 );
8211
8321
 
8212
8322
  // Want argument shifting here and in _row_selector?
8213
8323
  inst.selector.cols = selector;
@@ -8216,99 +8326,65 @@
8216
8326
  return inst;
8217
8327
  } );
8218
8328
 
8219
-
8220
- /**
8221
- *
8222
- */
8223
8329
  _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8224
8330
  return this.iterator( 'column', function ( settings, column ) {
8225
8331
  return settings.aoColumns[column].nTh;
8226
- } );
8332
+ }, 1 );
8227
8333
  } );
8228
8334
 
8229
-
8230
- /**
8231
- *
8232
- */
8233
8335
  _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8234
8336
  return this.iterator( 'column', function ( settings, column ) {
8235
8337
  return settings.aoColumns[column].nTf;
8236
- } );
8338
+ }, 1 );
8237
8339
  } );
8238
8340
 
8239
-
8240
- /**
8241
- *
8242
- */
8243
8341
  _api_registerPlural( 'columns().data()', 'column().data()', function () {
8244
- return this.iterator( 'column-rows', __columnData );
8342
+ return this.iterator( 'column-rows', __columnData, 1 );
8245
8343
  } );
8246
8344
 
8247
-
8248
8345
  _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8249
8346
  return this.iterator( 'column', function ( settings, column ) {
8250
8347
  return settings.aoColumns[column].mData;
8251
- } );
8348
+ }, 1 );
8252
8349
  } );
8253
8350
 
8254
-
8255
8351
  _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8256
8352
  return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8257
8353
  return _pluck_order( settings.aoData, rows,
8258
8354
  type === 'search' ? '_aFilterData' : '_aSortData', column
8259
8355
  );
8260
- } );
8356
+ }, 1 );
8261
8357
  } );
8262
8358
 
8263
-
8264
8359
  _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8265
8360
  return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8266
8361
  return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8267
- } );
8362
+ }, 1 );
8268
8363
  } );
8269
8364
 
8270
-
8271
-
8272
8365
  _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8273
8366
  return this.iterator( 'column', function ( settings, column ) {
8274
- return vis === undefined ?
8275
- settings.aoColumns[ column ].bVisible :
8276
- __setColumnVis( settings, column, vis, calc );
8367
+ if ( vis === undefined ) {
8368
+ return settings.aoColumns[ column ].bVisible;
8369
+ } // else
8370
+ __setColumnVis( settings, column, vis, calc );
8277
8371
  } );
8278
8372
  } );
8279
8373
 
8280
-
8281
-
8282
8374
  _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8283
8375
  return this.iterator( 'column', function ( settings, column ) {
8284
8376
  return type === 'visible' ?
8285
8377
  _fnColumnIndexToVisible( settings, column ) :
8286
8378
  column;
8287
- } );
8379
+ }, 1 );
8288
8380
  } );
8289
8381
 
8290
-
8291
- // _api_register( 'columns().show()', function () {
8292
- // var selector = this.selector;
8293
- // return this.columns( selector.cols, selector.opts ).visible( true );
8294
- // } );
8295
-
8296
-
8297
- // _api_register( 'columns().hide()', function () {
8298
- // var selector = this.selector;
8299
- // return this.columns( selector.cols, selector.opts ).visible( false );
8300
- // } );
8301
-
8302
-
8303
-
8304
8382
  _api_register( 'columns.adjust()', function () {
8305
8383
  return this.iterator( 'table', function ( settings ) {
8306
8384
  _fnAdjustColumnSizing( settings );
8307
- } );
8385
+ }, 1 );
8308
8386
  } );
8309
8387
 
8310
-
8311
- // Convert from one column index type, to another type
8312
8388
  _api_register( 'column.index()', function ( type, idx ) {
8313
8389
  if ( this.context.length !== 0 ) {
8314
8390
  var ctx = this.context[0];
@@ -8322,7 +8398,6 @@
8322
8398
  }
8323
8399
  } );
8324
8400
 
8325
-
8326
8401
  _api_register( 'column()', function ( selector, opts ) {
8327
8402
  return _selector_first( this.columns( selector, opts ) );
8328
8403
  } );
@@ -8334,13 +8409,13 @@
8334
8409
  {
8335
8410
  var data = settings.aoData;
8336
8411
  var rows = _selector_row_indexes( settings, opts );
8337
- var cells = _pluck_order( data, rows, 'anCells' );
8412
+ var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8338
8413
  var allCells = $( [].concat.apply([], cells) );
8339
8414
  var row;
8340
8415
  var columns = settings.aoColumns.length;
8341
8416
  var a, i, ien, j, o, host;
8342
8417
 
8343
- return _selector_run( selector, function ( s ) {
8418
+ var run = function ( s ) {
8344
8419
  var fnSelector = typeof s === 'function';
8345
8420
 
8346
8421
  if ( s === null || s === undefined || fnSelector ) {
@@ -8360,7 +8435,7 @@
8360
8435
  // Selector - function
8361
8436
  host = settings.aoData[ row ];
8362
8437
 
8363
- if ( s( o, _fnGetCellData(settings, row, j), host.anCells[j] ) ) {
8438
+ if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8364
8439
  a.push( o );
8365
8440
  }
8366
8441
  }
@@ -8391,7 +8466,9 @@
8391
8466
  };
8392
8467
  } )
8393
8468
  .toArray();
8394
- } );
8469
+ };
8470
+
8471
+ return _selector_run( 'cell', selector, run, settings, opts );
8395
8472
  };
8396
8473
 
8397
8474
 
@@ -8401,14 +8478,16 @@
8401
8478
  // Argument shifting
8402
8479
  if ( $.isPlainObject( rowSelector ) ) {
8403
8480
  // Indexes
8404
- if ( typeof rowSelector.row !== undefined ) {
8405
- opts = columnSelector;
8406
- columnSelector = null;
8407
- }
8408
- else {
8481
+ if ( rowSelector.row === undefined ) {
8482
+ // Selector options in first parameter
8409
8483
  opts = rowSelector;
8410
8484
  rowSelector = null;
8411
8485
  }
8486
+ else {
8487
+ // Cell index objects in first parameter
8488
+ opts = columnSelector;
8489
+ columnSelector = null;
8490
+ }
8412
8491
  }
8413
8492
  if ( $.isPlainObject( columnSelector ) ) {
8414
8493
  opts = columnSelector;
@@ -8440,7 +8519,7 @@
8440
8519
  }
8441
8520
 
8442
8521
  return a;
8443
- } );
8522
+ }, 1 );
8444
8523
 
8445
8524
  $.extend( cells.selector, {
8446
8525
  cols: columnSelector,
@@ -8454,15 +8533,18 @@
8454
8533
 
8455
8534
  _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8456
8535
  return this.iterator( 'cell', function ( settings, row, column ) {
8457
- return settings.aoData[ row ].anCells[ column ];
8458
- } );
8536
+ var cells = settings.aoData[ row ].anCells;
8537
+ return cells ?
8538
+ cells[ column ] :
8539
+ undefined;
8540
+ }, 1 );
8459
8541
  } );
8460
8542
 
8461
8543
 
8462
8544
  _api_register( 'cells().data()', function () {
8463
8545
  return this.iterator( 'cell', function ( settings, row, column ) {
8464
8546
  return _fnGetCellData( settings, row, column );
8465
- } );
8547
+ }, 1 );
8466
8548
  } );
8467
8549
 
8468
8550
 
@@ -8471,14 +8553,14 @@
8471
8553
 
8472
8554
  return this.iterator( 'cell', function ( settings, row, column ) {
8473
8555
  return settings.aoData[ row ][ type ][ column ];
8474
- } );
8556
+ }, 1 );
8475
8557
  } );
8476
8558
 
8477
8559
 
8478
8560
  _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8479
8561
  return this.iterator( 'cell', function ( settings, row, column ) {
8480
8562
  return _fnGetCellData( settings, row, column, type );
8481
- } );
8563
+ }, 1 );
8482
8564
  } );
8483
8565
 
8484
8566
 
@@ -8489,33 +8571,23 @@
8489
8571
  column: column,
8490
8572
  columnVisible: _fnColumnIndexToVisible( settings, column )
8491
8573
  };
8492
- } );
8574
+ }, 1 );
8493
8575
  } );
8494
8576
 
8495
8577
 
8496
- _api_register( [
8497
- 'cells().invalidate()',
8498
- 'cell().invalidate()'
8499
- ], function ( src ) {
8500
- var selector = this.selector;
8501
-
8502
- // Use the rows method of the instance to perform the invalidation, rather
8503
- // than doing it here. This avoids needing to handle duplicate rows from
8504
- // the cells.
8505
- this.rows( selector.rows, selector.opts ).invalidate( src );
8506
-
8507
- return this;
8578
+ _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8579
+ return this.iterator( 'cell', function ( settings, row, column ) {
8580
+ _fnInvalidate( settings, row, src, column );
8581
+ } );
8508
8582
  } );
8509
8583
 
8510
8584
 
8511
8585
 
8512
-
8513
8586
  _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8514
8587
  return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8515
8588
  } );
8516
8589
 
8517
8590
 
8518
-
8519
8591
  _api_register( 'cell().data()', function ( data ) {
8520
8592
  var ctx = this.context;
8521
8593
  var cell = this[0];
@@ -8529,7 +8601,7 @@
8529
8601
 
8530
8602
  // Set
8531
8603
  _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8532
- _fnInvalidateRow( ctx[0], cell[0].row, 'data', cell[0].column );
8604
+ _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8533
8605
 
8534
8606
  return this;
8535
8607
  } );
@@ -8776,7 +8848,10 @@
8776
8848
  var is = false;
8777
8849
 
8778
8850
  $.each( DataTable.settings, function (i, o) {
8779
- if ( o.nTable === t || o.nScrollHead === t || o.nScrollFoot === t ) {
8851
+ var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
8852
+ var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
8853
+
8854
+ if ( o.nTable === t || head === t || foot === t ) {
8780
8855
  is = true;
8781
8856
  }
8782
8857
  } );
@@ -8803,7 +8878,7 @@
8803
8878
  */
8804
8879
  DataTable.tables = DataTable.fnTables = function ( visible )
8805
8880
  {
8806
- return jQuery.map( DataTable.settings, function (o) {
8881
+ return $.map( DataTable.settings, function (o) {
8807
8882
  if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
8808
8883
  return o.nTable;
8809
8884
  }
@@ -8830,7 +8905,16 @@
8830
8905
  * @param {integer} freq Call frequency in mS
8831
8906
  * @return {function} Wrapped function
8832
8907
  */
8833
- throttle: _fnThrottle
8908
+ throttle: _fnThrottle,
8909
+
8910
+
8911
+ /**
8912
+ * Escape a string such that it can be used in a regular expression
8913
+ *
8914
+ * @param {string} sVal string to escape
8915
+ * @returns {string} escaped string
8916
+ */
8917
+ escapeRegex: _fnEscapeRegex
8834
8918
  };
8835
8919
 
8836
8920
 
@@ -8895,6 +8979,12 @@
8895
8979
  } );
8896
8980
 
8897
8981
 
8982
+ _api_register( 'init()', function () {
8983
+ var ctx = this.context;
8984
+ return ctx.length ? ctx[0].oInit : null;
8985
+ } );
8986
+
8987
+
8898
8988
  _api_register( 'data()', function () {
8899
8989
  return this.iterator( 'table', function ( settings ) {
8900
8990
  return _pluck( settings.aoData, '_aData' );
@@ -9004,6 +9094,36 @@
9004
9094
  } );
9005
9095
  } );
9006
9096
 
9097
+
9098
+ // Add the `every()` method for rows, columns and cells in a compact form
9099
+ $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9100
+ _api_register( type+'s().every()', function ( fn ) {
9101
+ return this.iterator( type, function ( settings, idx, idx2 ) {
9102
+ // idx2 is undefined for rows and columns.
9103
+ fn.call( new _Api( settings )[ type ]( idx, idx2 ) );
9104
+ } );
9105
+ } );
9106
+ } );
9107
+
9108
+
9109
+ // i18n method for extensions to be able to use the language object from the
9110
+ // DataTable
9111
+ _api_register( 'i18n()', function ( token, def, plural ) {
9112
+ var ctx = this.context[0];
9113
+ var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9114
+
9115
+ if ( resolved === undefined ) {
9116
+ resolved = def;
9117
+ }
9118
+
9119
+ if ( plural !== undefined && $.isPlainObject( resolved ) ) {
9120
+ resolved = resolved[ plural ] !== undefined ?
9121
+ resolved[ plural ] :
9122
+ resolved._;
9123
+ }
9124
+
9125
+ return resolved.replace( '%d', plural ); // nb: plural might be undefined,
9126
+ } );
9007
9127
 
9008
9128
  /**
9009
9129
  * Version string for plug-ins to check compatibility. Allowed format is
@@ -9013,7 +9133,7 @@
9013
9133
  * @type string
9014
9134
  * @default Version number
9015
9135
  */
9016
- DataTable.version = "1.10.3";
9136
+ DataTable.version = "1.10.7";
9017
9137
 
9018
9138
  /**
9019
9139
  * Private data store, containing all of the settings objects that are
@@ -13387,6 +13507,17 @@
13387
13507
  * @namespace
13388
13508
  */
13389
13509
  DataTable.ext = _ext = {
13510
+ /**
13511
+ * Buttons. For use with the Buttons extension for DataTables. This is
13512
+ * defined here so other extensions can define buttons regardless of load
13513
+ * order. It is _not_ used by DataTables core.
13514
+ *
13515
+ * @type object
13516
+ * @default {}
13517
+ */
13518
+ buttons: {},
13519
+
13520
+
13390
13521
  /**
13391
13522
  * Element class names
13392
13523
  *
@@ -13399,10 +13530,10 @@
13399
13530
  /**
13400
13531
  * Error reporting.
13401
13532
  *
13402
- * How should DataTables report an error. Can take the value 'alert' or
13403
- * 'throw'
13533
+ * How should DataTables report an error. Can take the value 'alert',
13534
+ * 'throw', 'none' or a function.
13404
13535
  *
13405
- * @type string
13536
+ * @type string|function
13406
13537
  * @default alert
13407
13538
  */
13408
13539
  errMode: "alert",
@@ -13509,6 +13640,37 @@
13509
13640
  search: [],
13510
13641
 
13511
13642
 
13643
+ /**
13644
+ * Selector extensions
13645
+ *
13646
+ * The `selector` option can be used to extend the options available for the
13647
+ * selector modifier options (`selector-modifier` object data type) that
13648
+ * each of the three built in selector types offer (row, column and cell +
13649
+ * their plural counterparts). For example the Select extension uses this
13650
+ * mechanism to provide an option to select only rows, columns and cells
13651
+ * that have been marked as selected by the end user (`{selected: true}`),
13652
+ * which can be used in conjunction with the existing built in selector
13653
+ * options.
13654
+ *
13655
+ * Each property is an array to which functions can be pushed. The functions
13656
+ * take three attributes:
13657
+ *
13658
+ * * Settings object for the host table
13659
+ * * Options object (`selector-modifier` object type)
13660
+ * * Array of selected item indexes
13661
+ *
13662
+ * The return is an array of the resulting item indexes after the custom
13663
+ * selector has been applied.
13664
+ *
13665
+ * @type object
13666
+ */
13667
+ selector: {
13668
+ cell: [],
13669
+ column: [],
13670
+ row: []
13671
+ },
13672
+
13673
+
13512
13674
  /**
13513
13675
  * Internal functions, exposed for used in plug-ins.
13514
13676
  *
@@ -14002,7 +14164,7 @@
14002
14164
  numbers.splice( 0, 0, 0 );
14003
14165
  }
14004
14166
  else {
14005
- numbers = _range( page-1, page+2 );
14167
+ numbers = _range( page-half+2, page+half-1 );
14006
14168
  numbers.push( 'ellipsis' );
14007
14169
  numbers.push( pages-1 );
14008
14170
  numbers.splice( 0, 0, 'ellipsis' );
@@ -14033,6 +14195,8 @@
14033
14195
 
14034
14196
  // For testing and plug-ins to use
14035
14197
  _numbers: _numbers,
14198
+
14199
+ // Number of number buttons (including ellipsis) to show. _Must be odd!_
14036
14200
  numbers_length: 7
14037
14201
  } );
14038
14202
 
@@ -14064,7 +14228,7 @@
14064
14228
 
14065
14229
  switch ( button ) {
14066
14230
  case 'ellipsis':
14067
- container.append('<span>&hellip;</span>');
14231
+ container.append('<span class="ellipsis">&#x2026;</span>');
14068
14232
  break;
14069
14233
 
14070
14234
  case 'first':
@@ -14124,26 +14288,113 @@
14124
14288
  // IE9 throws an 'unknown error' if document.activeElement is used
14125
14289
  // inside an iframe or frame. Try / catch the error. Not good for
14126
14290
  // accessibility, but neither are frames.
14291
+ var activeEl;
14292
+
14127
14293
  try {
14128
14294
  // Because this approach is destroying and recreating the paging
14129
14295
  // elements, focus is lost on the select button which is bad for
14130
14296
  // accessibility. So we want to restore focus once the draw has
14131
14297
  // completed
14132
- var activeEl = $(document.activeElement).data('dt-idx');
14298
+ activeEl = $(document.activeElement).data('dt-idx');
14299
+ }
14300
+ catch (e) {}
14133
14301
 
14134
- attach( $(host).empty(), buttons );
14302
+ attach( $(host).empty(), buttons );
14135
14303
 
14136
- if ( activeEl !== null ) {
14137
- $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14138
- }
14304
+ if ( activeEl ) {
14305
+ $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14139
14306
  }
14140
- catch (e) {}
14141
14307
  }
14142
14308
  }
14143
14309
  } );
14144
14310
 
14145
14311
 
14146
14312
 
14313
+ // Built in type detection. See model.ext.aTypes for information about
14314
+ // what is required from this methods.
14315
+ $.extend( DataTable.ext.type.detect, [
14316
+ // Plain numbers - first since V8 detects some plain numbers as dates
14317
+ // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14318
+ function ( d, settings )
14319
+ {
14320
+ var decimal = settings.oLanguage.sDecimal;
14321
+ return _isNumber( d, decimal ) ? 'num'+decimal : null;
14322
+ },
14323
+
14324
+ // Dates (only those recognised by the browser's Date.parse)
14325
+ function ( d, settings )
14326
+ {
14327
+ // V8 will remove any unknown characters at the start and end of the
14328
+ // expression, leading to false matches such as `$245.12` or `10%` being
14329
+ // a valid date. See forum thread 18941 for detail.
14330
+ if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) {
14331
+ return null;
14332
+ }
14333
+ var parsed = Date.parse(d);
14334
+ return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14335
+ },
14336
+
14337
+ // Formatted numbers
14338
+ function ( d, settings )
14339
+ {
14340
+ var decimal = settings.oLanguage.sDecimal;
14341
+ return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14342
+ },
14343
+
14344
+ // HTML numeric
14345
+ function ( d, settings )
14346
+ {
14347
+ var decimal = settings.oLanguage.sDecimal;
14348
+ return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14349
+ },
14350
+
14351
+ // HTML numeric, formatted
14352
+ function ( d, settings )
14353
+ {
14354
+ var decimal = settings.oLanguage.sDecimal;
14355
+ return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14356
+ },
14357
+
14358
+ // HTML (this is strict checking - there must be html)
14359
+ function ( d, settings )
14360
+ {
14361
+ return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14362
+ 'html' : null;
14363
+ }
14364
+ ] );
14365
+
14366
+
14367
+
14368
+ // Filter formatting functions. See model.ext.ofnSearch for information about
14369
+ // what is required from these methods.
14370
+ //
14371
+ // Note that additional search methods are added for the html numbers and
14372
+ // html formatted numbers by `_addNumericSort()` when we know what the decimal
14373
+ // place is
14374
+
14375
+
14376
+ $.extend( DataTable.ext.type.search, {
14377
+ html: function ( data ) {
14378
+ return _empty(data) ?
14379
+ data :
14380
+ typeof data === 'string' ?
14381
+ data
14382
+ .replace( _re_new_lines, " " )
14383
+ .replace( _re_html, "" ) :
14384
+ '';
14385
+ },
14386
+
14387
+ string: function ( data ) {
14388
+ return _empty(data) ?
14389
+ data :
14390
+ typeof data === 'string' ?
14391
+ data.replace( _re_new_lines, " " ) :
14392
+ data;
14393
+ }
14394
+ } );
14395
+
14396
+
14397
+
14147
14398
  var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
14148
14399
  if ( d !== 0 && (!d || d === '-') ) {
14149
14400
  return -Infinity;
@@ -14170,8 +14421,8 @@
14170
14421
  };
14171
14422
 
14172
14423
 
14173
- // Add the numeric 'deformatting' functions for sorting. This is done in a
14174
- // function to provide an easy ability for the language options to add
14424
+ // Add the numeric 'deformatting' functions for sorting and search. This is done
14425
+ // in a function to provide an easy ability for the language options to add
14175
14426
  // additional methods if a non-period decimal place is used.
14176
14427
  function _addNumericSort ( decimalPlace ) {
14177
14428
  $.each(
@@ -14197,7 +14448,13 @@
14197
14448
  }
14198
14449
  },
14199
14450
  function ( key, fn ) {
14451
+ // Add the ordering method
14200
14452
  _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14453
+
14454
+ // For HTML types add a search formatter that will strip the HTML
14455
+ if ( key.match(/^html\-/) ) {
14456
+ _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
14457
+ }
14201
14458
  }
14202
14459
  );
14203
14460
  }
@@ -14248,87 +14505,6 @@
14248
14505
  _addNumericSort( '' );
14249
14506
 
14250
14507
 
14251
- // Built in type detection. See model.ext.aTypes for information about
14252
- // what is required from this methods.
14253
- $.extend( DataTable.ext.type.detect, [
14254
- // Plain numbers - first since V8 detects some plain numbers as dates
14255
- // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14256
- function ( d, settings )
14257
- {
14258
- var decimal = settings.oLanguage.sDecimal;
14259
- return _isNumber( d, decimal ) ? 'num'+decimal : null;
14260
- },
14261
-
14262
- // Dates (only those recognised by the browser's Date.parse)
14263
- function ( d, settings )
14264
- {
14265
- // V8 will remove any unknown characters at the start and end of the
14266
- // expression, leading to false matches such as `$245.12` or `10%` being
14267
- // a valid date. See forum thread 18941 for detail.
14268
- if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) {
14269
- return null;
14270
- }
14271
- var parsed = Date.parse(d);
14272
- return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14273
- },
14274
-
14275
- // Formatted numbers
14276
- function ( d, settings )
14277
- {
14278
- var decimal = settings.oLanguage.sDecimal;
14279
- return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14280
- },
14281
-
14282
- // HTML numeric
14283
- function ( d, settings )
14284
- {
14285
- var decimal = settings.oLanguage.sDecimal;
14286
- return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14287
- },
14288
-
14289
- // HTML numeric, formatted
14290
- function ( d, settings )
14291
- {
14292
- var decimal = settings.oLanguage.sDecimal;
14293
- return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14294
- },
14295
-
14296
- // HTML (this is strict checking - there must be html)
14297
- function ( d, settings )
14298
- {
14299
- return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14300
- 'html' : null;
14301
- }
14302
- ] );
14303
-
14304
-
14305
-
14306
- // Filter formatting functions. See model.ext.ofnSearch for information about
14307
- // what is required from these methods.
14308
-
14309
-
14310
- $.extend( DataTable.ext.type.search, {
14311
- html: function ( data ) {
14312
- return _empty(data) ?
14313
- data :
14314
- typeof data === 'string' ?
14315
- data
14316
- .replace( _re_new_lines, " " )
14317
- .replace( _re_html, "" ) :
14318
- '';
14319
- },
14320
-
14321
- string: function ( data ) {
14322
- return _empty(data) ?
14323
- data :
14324
- typeof data === 'string' ?
14325
- data.replace( _re_new_lines, " " ) :
14326
- data;
14327
- }
14328
- } );
14329
-
14330
-
14331
-
14332
14508
  $.extend( true, DataTable.ext.renderer, {
14333
14509
  header: {
14334
14510
  _: function ( settings, cell, column, classes ) {
@@ -14436,6 +14612,10 @@
14436
14612
  number: function ( thousands, decimal, precision, prefix ) {
14437
14613
  return {
14438
14614
  display: function ( d ) {
14615
+ if ( typeof d !== 'number' && typeof d !== 'string' ) {
14616
+ return d;
14617
+ }
14618
+
14439
14619
  var negative = d < 0 ? '-' : '';
14440
14620
  d = Math.abs( parseFloat( d ) );
14441
14621
 
@@ -14517,7 +14697,7 @@
14517
14697
  _fnGetDataMaster: _fnGetDataMaster,
14518
14698
  _fnClearTable: _fnClearTable,
14519
14699
  _fnDeleteIndex: _fnDeleteIndex,
14520
- _fnInvalidateRow: _fnInvalidateRow,
14700
+ _fnInvalidate: _fnInvalidate,
14521
14701
  _fnGetRowElements: _fnGetRowElements,
14522
14702
  _fnCreateTr: _fnCreateTr,
14523
14703
  _fnBuildHead: _fnBuildHead,