1
0
mirror of https://github.com/DataTables/DataTables.git synced 2024-12-01 13:24:10 +01:00

New - rows().cells(), columns.cells() API methods.

- row options for column selector

- Selectors (table, rows and columns) now held in a single file, sharing
  structure. A more unified API is used, with row options also being
  allow for columns, through the use of the second parameter for the
  columns() method, which will effect how a column function can act upon
  rows (for example, the order of the rows when getting data or nodes).

- Dev: tables() is no longer an iterator - using an `iterator()` method
  with options which are suitable for the different types of iteration
  the API needs.
This commit is contained in:
Allan Jardine 2013-04-28 08:53:05 +01:00
parent 638a1f6225
commit 68ea9af828
10 changed files with 213 additions and 95 deletions

View File

@ -1,16 +1,50 @@
var _pluck = function ( a, prop ) {
var _pluck = function ( a, prop, prop2 ) {
var out = [];
var i=0, ien=a.length;
for ( var i=0, ien=a.length ; i<ien ; i++ ) {
out.push( a[i][ prop ] );
// Could have the test in the loop for slightly smaller code, but speed
// is essential here
if ( prop2 !== undefined ) {
for ( ; i<ien ; i++ ) {
out.push( a[i][ prop ][ prop2 ] );
}
}
else {
for ( ; i<ien ; i++ ) {
out.push( a[i][ prop ] );
}
}
return out;
};
// Basically the same as _pluck, but rather than looping over `a` we use `order`
// as the indexes to pick from `a`
var _pluck_order = function ( a, order, prop, prop2 )
{
var out = [];
var i=0, ien=order.length;
// Could have the test in the loop for slightly smaller code, but speed
// is essential here
if ( prop2 !== undefined ) {
for ( ; i<ien ; i++ ) {
out.push( a[ order[i] ][ prop ][ prop2 ] );
}
}
else {
for ( ; i<ien ; i++ ) {
out.push( a[ order[i] ][ prop ] );
}
}
return out;
};
var _intVal = function ( s ) {
var integer = parseInt( s, 10 );
return !isNaN(integer) && isFinite(s) ? integer : null;
@ -21,7 +55,7 @@ var _selector_run = function ( selector, select )
var
out = [], res,
a, i, ien, j, jen;
if ( ! $.isArray( selector ) ) {
selector = [ selector ];
}
@ -43,6 +77,30 @@ var _selector_run = function ( selector, select )
return out;
};
var _selector_opts = function ( opts )
{
if ( ! opts ) {
opts = {};
}
return {
filter: opts.filter || 'none',
order: opts.order || 'current',
page: opts.page || 'all'
};
};
var _range = function ( len )
{
var out = [];
for ( var i=0 ; i<len ; i++ ) {
out.push( i );
}
return out;
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tables
@ -100,14 +158,10 @@ var _row_selector_indexes = function ( settings, opts )
displayFiltered = settings.aiDisplay,
displayMaster = settings.aiDisplayMaster;
if ( ! opts ) {
opts = {};
}
var
filter = opts.filter || 'none', // none, applied, removed
order = opts.order || 'current', // current, original
page = opts.page || 'all'; // all, page
filter = opts.filter, // none, applied, removed
order = opts.order, // current, index (original - compatibility with 1.9)
page = opts.page; // all, page
// Current page implies that order=current and fitler=applied, since it is
// fairly senseless otherwise, regardless of what order and filter actually
@ -127,7 +181,7 @@ var _row_selector_indexes = function ( settings, opts )
return $.inArray( el, displayFiltered ) === -1 ? el : null;
} );
}
else if ( order == 'original' ) {
else if ( order == 'index' || order == 'original' ) {
for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
if ( filter == 'none' ) {
a.push( i );
@ -150,15 +204,6 @@ var _row_selector_indexes = function ( settings, opts )
var _row_selector = function ( settings, selector, opts )
{
// argument shifting
if ( selector === undefined ) {
selector = '';
}
else if ( $.isPlainObject( selector ) ) {
opts = selector;
selector = '';
}
return _selector_run( selector, function ( sel ) {
var selInt = _intVal( sel );
@ -180,7 +225,7 @@ var _row_selector = function ( settings, selector, opts )
return [ selInt ];
}
// Get nodes in the order from the `rows` array (can't use `pluck`)
// Get nodes in the order from the `rows` array (can't use `pluck`) @todo - use pluck_order
var nodes = [];
for ( var i=0, ien=rows.length ; i<ien ; i++ ) {
nodes.push( settings.aoData[ rows[i] ].nTr );
@ -224,7 +269,7 @@ var _row_selector = function ( settings, selector, opts )
var _re_column_selector = /^(.*):(jq|visIdx)$/;
var _column_selector = function ( settings, selector )
var _column_selector = function ( settings, selector, opts )
{
var
columns = settings.aoColumns,
@ -234,7 +279,12 @@ var _column_selector = function ( settings, selector )
return _selector_run( selector, function ( s ) {
var selInt = _intVal( s );
if ( selInt !== null ) {
if ( s === '' ) {
// All columns
return _range( settings.aoColumns.length );
}
else if ( selInt !== null ) {
// Integer selector
return [ selInt ];
}
else {

View File

@ -57,7 +57,7 @@ _Api.register( 'ajax.json()', function () {
* @returns {DataTables.Api} this
*/
_Api.register( 'ajax.reload()', function ( resetPaging ) {
return this.tables( function (settings) {
return this.iterator( 'table', function (settings) {
_reload( settings, resetPaging===false );
} );
} );
@ -93,7 +93,7 @@ _Api.register( 'ajax.url()', function ( url ) {
}
// set
return this.tables( function ( settings ) {
return this.iterator( 'table', function ( settings ) {
if ( $.isPlainObject( settings.ajax ) ) {
settings.ajax.url = url;
}
@ -119,7 +119,7 @@ _Api.register( 'ajax.url()', function ( url ) {
_Api.register( 'ajax.url().load()', function () {
// Same as a reload, but makes sense to present it for easy access after a
// url change
return this.tables( _reload );
return this.iterator( 'table', _reload );
} );

View File

@ -6,21 +6,48 @@ var _api = DataTable.Api;
/**
*
*
*/
_api.register( 'columns()', function ( selector ) {
return this.tables( function ( settings ) {
return _column_selector( settings, selector );
_api.register( 'columns()', function ( selector, opts ) {
// argument shifting
if ( selector === undefined ) {
selector = '';
}
else if ( $.isPlainObject( selector ) ) {
opts = selector;
selector = '';
}
opts = _selector_opts( opts );
var inst = this.iterator( 'table', function ( settings ) {
return _column_selector( settings, selector, opts );
} );
// Want argument shifting here and in _row_selector?
inst.selector.cols = selector;
inst.selector.opts = opts;
return inst;
} );
/**
*
*/
_api.register( 'columns().header()', function ( selector, opts ) {
return this.iterator( 'column', function ( settings, column ) {
return settings.aoColumns[column].nTh;
} );
} );
/**
*
*
*/
_api.register( 'columns().header()', function ( selector, opts ) {
return this.iterator( function ( settings, el ) {
return settings.aoColumns[ el ].nTh;
_api.register( 'columns().cells()', function () {
return this.iterator( true, 'column-rows', function ( settings, column, i, j, rows ) {
return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
} );
} );

View File

@ -240,6 +240,13 @@ DataTable.Api = _Api = function ( context, data )
this.push.apply( this, data );
}
// selector
this.selector = {
rows: null,
cols: null,
opts: null
};
_Api.extend( this, this, _apiStruct );
};
@ -312,19 +319,48 @@ _Api.prototype = /** @lends DataTables.Api */{
},
// Internal only at the moment - relax?
iterator: function ( fn ) {
iterator: function ( flatten, type, fn ) {
var
a = [], ret,
i, ien, j, jen, k, ken,
i, ien, j, jen,
context = this.context,
items;
rows, items,
selector = this.selector;
// Argument shifting
if ( typeof flatten === 'string' ) {
fn = type;
type = flatten;
flatten = false;
}
for ( i=0, ien=context.length ; i<ien ; i++ ) {
for( j=0, jen=this.length ; j<jen ; j++ ) {
if ( type === 'table' ) {
ret = fn( context[i] );
if ( ret !== undefined ) {
a.push( ret );
}
}
else if ( type === 'columns' || type === 'rows' ) {
// this has same length as context - one entry for each table
ret = fn( context[i], this[i] );
if ( ret !== undefined ) {
a.push( ret );
}
}
else if ( type === 'column' || type === 'column-rows' || type === 'row' ) {
// columns and rows share the same structure.
// 'this' is an array of column indexes for each context
items = this[i];
for ( k=0, ken=items.length ; k<ken ; k++ ) {
ret = fn( context[i], items[k], i, j, k );
if ( type === 'column-rows' ) {
rows = _row_selector_indexes( context[i], selector.opts );
}
for ( j=0, jen=items.length ; j<jen ; j++ ) {
ret = fn( context[i], items[j], i, j, rows );
if ( ret !== undefined ) {
a.push( ret );
@ -333,9 +369,15 @@ _Api.prototype = /** @lends DataTables.Api */{
}
}
return a.length ?
new _Api( context, a ) :
this;
if ( a.length ) {
var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
var apiSelector = api.selector;
apiSelector.rows = selector.rows;
apiSelector.cols = selector.cols;
apiSelector.opts = selector.opts;
return api;
}
return this;
},
@ -436,6 +478,10 @@ _Api.prototype = /** @lends DataTables.Api */{
reverse: _arrayProto.reverse,
// Object with rows, columns and opts
selector: null,
shift: _arrayProto.shift,

View File

@ -14,7 +14,7 @@ var _api = DataTable.Api;
* @returns {DataTables.Api} this
*/
_api.register( 'draw()', function ( resetPaging ) {
return this.tables( function ( settings ) {
return this.iterator( 'table', function ( settings ) {
_fnReDraw( settings, resetPaging===false );
} );
} );

View File

@ -54,8 +54,8 @@ _Api.register( 'order()', function ( order, dir ) {
}
// otherwise a 2D array was passed in
return this.tables( function ( settings ) {
settings.aaSorting = order;
return this.iterator( 'table', function ( settings ) {
settings.aaSorting = order.slice();
} );
} );
@ -71,7 +71,7 @@ _Api.register( 'order()', function ( order, dir ) {
* @returns {DataTables.Api} this
*/
_Api.register( 'order.listener()', function ( node, column, callback ) {
return this.tables( function ( settings ) {
return this.iterator( 'table', function ( settings ) {
_fnSortAttachListener( settings, node, column, callback );
} );
} );

View File

@ -30,7 +30,7 @@ _Api.register( 'page()', function ( action ) {
}
// else, have an action to take on all tables
return this.tables( function ( settings ) {
return this.iterator( 'table', function ( settings ) {
_fnPageChange( settings, action );
} );
} );
@ -100,7 +100,7 @@ _Api.register( 'page.len()', function ( len ) {
}
// else, set the page length
return this.tables( function ( settings ) {
return this.iterator( 'table', function ( settings ) {
_fnLengthChange( settings, len );
} );
} );

View File

@ -9,25 +9,50 @@ var _api = DataTable.Api;
/**
*
*
*/
_api.register( 'rows()', function ( selector, opts ) {
return this.tables( function ( settings ) {
// argument shifting
if ( selector === undefined ) {
selector = '';
}
else if ( $.isPlainObject( selector ) ) {
opts = selector;
selector = '';
}
opts = _selector_opts( opts );
var inst = this.iterator( 'table', function ( settings ) {
return _row_selector( settings, selector, opts );
} );
// Want argument shifting here and in _row_selector?
inst.selector.rows = selector;
inst.selector.opts = opts;
return inst;
} );
_api.register( 'rows().nodes()', function () {
return this.iterator( function ( settings, el ) {
return settings.aoData[ el ].nTr || undefined;
return this.iterator( 'row', function ( settings, row ) {
// use pluck order on an array rather - rows gives an array, row gives it individually
return settings.aoData[ row ].nTr || undefined;
} );
} );
_api.register( 'rows().cells()', function () {
return this.iterator( true, 'row', function ( settings, row ) {
return settings.aoData[ row ].anCells || undefined;
} );
} );
_api.register( 'rows().data()', function ( data ) {
return this.iterator( function ( settings, el ) {
return settings.aoData[ el ]._aData;
return this.iterator( true, 'rows', function ( settings, rows ) {
return _pluck_order( settings.aoData, rows, '_aData' );
} );
} );

View File

@ -6,52 +6,21 @@ var _Api = DataTable.Api;
/**
* Context selector and iterator for the API's context (i.e. the tables the
* API instance refers to.
* Context selector for the API's context (i.e. the tables the API instance
* refers to.
*
* @name DataTable.Api#tables
* @param {string|integer} [selector] Selector to pick which tables the iterator
* should operate on. If not given, all tables in the current context are
* used. This can be given as a jQuery selector (for example `':gt(0)'`) to
* select multiple tables or as an integer to select a single table.
* @param {function} [fn] Iterator function. Will be called for every table in
* the current context (once the selector has been applied, if one is given).
* The function is passed two parameters: 1. the DataTables settings object
* for the table in question and 2. the index of that table in the current
* context. The execution scope of the function is the API instance.
* @returns {DataTable.Api} Returns a new API instance if a selector is given,
* or the callback function returns information from each loop. The
* information, if returned, is assigned to the API instance. Otherwise the
* original API instance is returned for chaining.
* @returns {DataTable.Api} Returns a new API instance if a selector is given.
*/
_Api.register( 'tables()', function ( selector, fn ) {
// Argument shifting
if ( typeof selector === 'function' ) {
fn = selector;
selector = undefined;
}
var a = [];
var context = selector ?
_table_selector( selector, this.context ) :
this.context;
if ( fn ) {
for ( var i=0, ien=context.length ; i<ien ; i++ ) {
var ret = fn.call( this, context[i], i );
if ( ret !== undefined ) {
a.push( ret );
}
}
}
// A new instance is created if there was a selector specified, or if
// data was returned from the callback
var api = selector || a.length ?
new _Api( context, a ) :
_Api.register( 'tables()', function ( selector ) {
// A new instance is created if there was a selector specified
return selector ?
new _Api( _table_selector( selector, this.context ) ) :
this;
return api;
} );
@ -61,7 +30,7 @@ _Api.register( 'tables()', function ( selector, fn ) {
* tables.
*/
_Api.register( 'tables().nodes()', function () {
return this.tables( function ( settings, i ) {
return this.iterator( 'table', function ( settings, i ) {
return settings.nTable;
} );
} );

View File

@ -578,6 +578,7 @@ function _fnAddOptionsHtml ( oSettings )
/* End container div */
nInsertNode = nInsertNode.parentNode;
}
// @todo Move options into their own plugins?
else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange )
{
/* Length */