| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206 | /*! Select for DataTables 1.3.1 * 2015-2019 SpryMedia Ltd - datatables.net/license/mit *//** * @summary     Select for DataTables * @description A collection of API methods, events and buttons for DataTables *   that provides selection options of the items in a DataTable * @version     1.3.1 * @file        dataTables.select.js * @author      SpryMedia Ltd (www.sprymedia.co.uk) * @contact     datatables.net/forums * @copyright   Copyright 2015-2019 SpryMedia Ltd. * * This source file is free software, available under the following license: *   MIT license - http://datatables.net/license/mit * * This source file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. * * For details please refer to: http://www.datatables.net/extensions/select */(function( factory ){	if ( typeof define === 'function' && define.amd ) {		// AMD		define( ['jquery', 'datatables.net'], function ( $ ) {			return factory( $, window, document );		} );	}	else if ( typeof exports === 'object' ) {		// CommonJS		module.exports = function (root, $) {			if ( ! root ) {				root = window;			}			if ( ! $ || ! $.fn.dataTable ) {				$ = require('datatables.net')(root, $).$;			}			return factory( $, root, root.document );		};	}	else {		// Browser		factory( jQuery, window, document );	}}(function( $, window, document, undefined ) {'use strict';var DataTable = $.fn.dataTable;// Version information for debuggerDataTable.select = {};DataTable.select.version = '1.3.1';DataTable.select.init = function ( dt ) {	var ctx = dt.settings()[0];	var init = ctx.oInit.select;	var defaults = DataTable.defaults.select;	var opts = init === undefined ?		defaults :		init;	// Set defaults	var items = 'row';	var style = 'api';	var blurable = false;	var toggleable = true;	var info = true;	var selector = 'td, th';	var className = 'selected';	var setStyle = false;	ctx._select = {};	// Initialisation customisations	if ( opts === true ) {		style = 'os';		setStyle = true;	}	else if ( typeof opts === 'string' ) {		style = opts;		setStyle = true;	}	else if ( $.isPlainObject( opts ) ) {		if ( opts.blurable !== undefined ) {			blurable = opts.blurable;		}				if ( opts.toggleable !== undefined ) {			toggleable = opts.toggleable;		}		if ( opts.info !== undefined ) {			info = opts.info;		}		if ( opts.items !== undefined ) {			items = opts.items;		}		if ( opts.style !== undefined ) {			style = opts.style;			setStyle = true;		}		else {			style = 'os';			setStyle = true;		}		if ( opts.selector !== undefined ) {			selector = opts.selector;		}		if ( opts.className !== undefined ) {			className = opts.className;		}	}	dt.select.selector( selector );	dt.select.items( items );	dt.select.style( style );	dt.select.blurable( blurable );	dt.select.toggleable( toggleable );	dt.select.info( info );	ctx._select.className = className;	// Sort table based on selected rows. Requires Select Datatables extension	$.fn.dataTable.ext.order['select-checkbox'] = function ( settings, col ) {		return this.api().column( col, {order: 'index'} ).nodes().map( function ( td ) {			if ( settings._select.items === 'row' ) {				return $( td ).parent().hasClass( settings._select.className );			} else if ( settings._select.items === 'cell' ) {				return $( td ).hasClass( settings._select.className );			}			return false;		});	};	// If the init options haven't enabled select, but there is a selectable	// class name, then enable	if ( ! setStyle && $( dt.table().node() ).hasClass( 'selectable' ) ) {		dt.select.style( 'os' );	}};/*Select is a collection of API methods, event handlers, event emitters andbuttons (for the `Buttons` extension) for DataTables. It provides the followingfeatures, with an overview of how they are implemented:## Selection of rows, columns and cells. Whether an item is selected or not is   stored in:* rows: a `_select_selected` property which contains a boolean value of the  DataTables' `aoData` object for each row* columns: a `_select_selected` property which contains a boolean value of the  DataTables' `aoColumns` object for each column* cells: a `_selected_cells` property which contains an array of boolean values  of the `aoData` object for each row. The array is the same length as the  columns array, with each element of it representing a cell.This method of using boolean flags allows Select to operate when nodes have notbeen created for rows / cells (DataTables' defer rendering feature).## API methodsA range of API methods are available for triggering selection and de-selectionof rows. Methods are also available to configure the selection events that canbe triggered by an end user (such as which items are to be selected). To a largeextent, these of API methods *is* Select. It is basically a collection of helperfunctions that can be used to select items in a DataTable.Configuration of select is held in the object `_select` which is attached to theDataTables settings object on initialisation. Select being available on a tableis not optional when Select is loaded, but its default is for selection only tobe available via the API - so the end user wouldn't be able to select rowswithout additional configuration.The `_select` object contains the following properties:```{	items:string       - Can be `rows`, `columns` or `cells`. Defines what item 	                     will be selected if the user is allowed to activate row	                     selection using the mouse.	style:string       - Can be `none`, `single`, `multi` or `os`. Defines the	                     interaction style when selecting items	blurable:boolean   - If row selection can be cleared by clicking outside of	                     the table	toggleable:boolean - If row selection can be cancelled by repeated clicking	                     on the row	info:boolean       - If the selection summary should be shown in the table	                     information elements}```In addition to the API methods, Select also extends the DataTables selectoroptions for rows, columns and cells adding a `selected` option to the selectoroptions object, allowing the developer to select only selected items orunselected items.## Mouse selection of itemsClicking on items can be used to select items. This is done by a simple eventhandler that will select the items using the API methods. *//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Local functions *//** * Add one or more cells to the selection when shift clicking in OS selection * style cell selection. * * Cell range is more complicated than row and column as we want to select * in the visible grid rather than by index in sequence. For example, if you * click first in cell 1-1 and then shift click in 2-2 - cells 1-2 and 2-1 * should also be selected (and not 1-3, 1-4. etc) *  * @param  {DataTable.Api} dt   DataTable * @param  {object}        idx  Cell index to select to * @param  {object}        last Cell index to select from * @private */function cellRange( dt, idx, last ){	var indexes;	var columnIndexes;	var rowIndexes;	var selectColumns = function ( start, end ) {		if ( start > end ) {			var tmp = end;			end = start;			start = tmp;		}				var record = false;		return dt.columns( ':visible' ).indexes().filter( function (i) {			if ( i === start ) {				record = true;			}						if ( i === end ) { // not else if, as start might === end				record = false;				return true;			}			return record;		} );	};	var selectRows = function ( start, end ) {		var indexes = dt.rows( { search: 'applied' } ).indexes();		// Which comes first - might need to swap		if ( indexes.indexOf( start ) > indexes.indexOf( end ) ) {			var tmp = end;			end = start;			start = tmp;		}		var record = false;		return indexes.filter( function (i) {			if ( i === start ) {				record = true;			}						if ( i === end ) {				record = false;				return true;			}			return record;		} );	};	if ( ! dt.cells( { selected: true } ).any() && ! last ) {		// select from the top left cell to this one		columnIndexes = selectColumns( 0, idx.column );		rowIndexes = selectRows( 0 , idx.row );	}	else {		// Get column indexes between old and new		columnIndexes = selectColumns( last.column, idx.column );		rowIndexes = selectRows( last.row , idx.row );	}	indexes = dt.cells( rowIndexes, columnIndexes ).flatten();	if ( ! dt.cells( idx, { selected: true } ).any() ) {		// Select range		dt.cells( indexes ).select();	}	else {		// Deselect range		dt.cells( indexes ).deselect();	}}/** * Disable mouse selection by removing the selectors * * @param {DataTable.Api} dt DataTable to remove events from * @private */function disableMouseSelection( dt ){	var ctx = dt.settings()[0];	var selector = ctx._select.selector;	$( dt.table().container() )		.off( 'mousedown.dtSelect', selector )		.off( 'mouseup.dtSelect', selector )		.off( 'click.dtSelect', selector );	$('body').off( 'click.dtSelect' + _safeId(dt.table().node()) );}/** * Attach mouse listeners to the table to allow mouse selection of items * * @param {DataTable.Api} dt DataTable to remove events from * @private */function enableMouseSelection ( dt ){	var container = $( dt.table().container() );	var ctx = dt.settings()[0];	var selector = ctx._select.selector;	var matchSelection;	container		.on( 'mousedown.dtSelect', selector, function(e) {			// Disallow text selection for shift clicking on the table so multi			// element selection doesn't look terrible!			if ( e.shiftKey || e.metaKey || e.ctrlKey ) {				container					.css( '-moz-user-select', 'none' )					.one('selectstart.dtSelect', selector, function () {						return false;					} );			}			if ( window.getSelection ) {				matchSelection = window.getSelection();			}		} )		.on( 'mouseup.dtSelect', selector, function() {			// Allow text selection to occur again, Mozilla style (tested in FF			// 35.0.1 - still required)			container.css( '-moz-user-select', '' );		} )		.on( 'click.dtSelect', selector, function ( e ) {			var items = dt.select.items();			var idx;			// If text was selected (click and drag), then we shouldn't change			// the row's selected state			if ( matchSelection ) {				var selection = window.getSelection();				// If the element that contains the selection is not in the table, we can ignore it				// This can happen if the developer selects text from the click event				if ( ! selection.anchorNode || $(selection.anchorNode).closest('table')[0] === dt.table().node() ) {					if ( selection !== matchSelection ) {						return;					}				}			}			var ctx = dt.settings()[0];			var wrapperClass = $.trim(dt.settings()[0].oClasses.sWrapper).replace(/ +/g, '.');			// Ignore clicks inside a sub-table			if ( $(e.target).closest('div.'+wrapperClass)[0] != dt.table().container() ) {				return;			}			var cell = dt.cell( $(e.target).closest('td, th') );			// Check the cell actually belongs to the host DataTable (so child			// rows, etc, are ignored)			if ( ! cell.any() ) {				return;			}			var event = $.Event('user-select.dt');			eventTrigger( dt, event, [ items, cell, e ] );			if ( event.isDefaultPrevented() ) {				return;			}			var cellIndex = cell.index();			if ( items === 'row' ) {				idx = cellIndex.row;				typeSelect( e, dt, ctx, 'row', idx );			}			else if ( items === 'column' ) {				idx = cell.index().column;				typeSelect( e, dt, ctx, 'column', idx );			}			else if ( items === 'cell' ) {				idx = cell.index();				typeSelect( e, dt, ctx, 'cell', idx );			}			ctx._select_lastCell = cellIndex;		} );	// Blurable	$('body').on( 'click.dtSelect' + _safeId(dt.table().node()), function ( e ) {		if ( ctx._select.blurable ) {			// If the click was inside the DataTables container, don't blur			if ( $(e.target).parents().filter( dt.table().container() ).length ) {				return;			}			// Ignore elements which have been removed from the DOM (i.e. paging			// buttons)			if ( $(e.target).parents('html').length === 0 ) {			 	return;			}			// Don't blur in Editor form			if ( $(e.target).parents('div.DTE').length ) {				return;			}			clear( ctx, true );		}	} );}/** * Trigger an event on a DataTable * * @param {DataTable.Api} api      DataTable to trigger events on * @param  {boolean}      selected true if selected, false if deselected * @param  {string}       type     Item type acting on * @param  {boolean}      any      Require that there are values before *     triggering * @private */function eventTrigger ( api, type, args, any ){	if ( any && ! api.flatten().length ) {		return;	}	if ( typeof type === 'string' ) {		type = type +'.dt';	}	args.unshift( api );	$(api.table().node()).trigger( type, args );}/** * Update the information element of the DataTable showing information about the * items selected. This is done by adding tags to the existing text *  * @param {DataTable.Api} api DataTable to update * @private */function info ( api ){	var ctx = api.settings()[0];	if ( ! ctx._select.info || ! ctx.aanFeatures.i ) {		return;	}	if ( api.select.style() === 'api' ) {		return;	}	var rows    = api.rows( { selected: true } ).flatten().length;	var columns = api.columns( { selected: true } ).flatten().length;	var cells   = api.cells( { selected: true } ).flatten().length;	var add = function ( el, name, num ) {		el.append( $('<span class="select-item"/>').append( api.i18n(			'select.'+name+'s',			{ _: '%d '+name+'s selected', 0: '', 1: '1 '+name+' selected' },			num		) ) );	};	// Internal knowledge of DataTables to loop over all information elements	$.each( ctx.aanFeatures.i, function ( i, el ) {		el = $(el);		var output  = $('<span class="select-info"/>');		add( output, 'row', rows );		add( output, 'column', columns );		add( output, 'cell', cells  );		var exisiting = el.children('span.select-info');		if ( exisiting.length ) {			exisiting.remove();		}		if ( output.text() !== '' ) {			el.append( output );		}	} );}/** * Initialisation of a new table. Attach event handlers and callbacks to allow * Select to operate correctly. * * This will occur _after_ the initial DataTables initialisation, although * before Ajax data is rendered, if there is ajax data * * @param  {DataTable.settings} ctx Settings object to operate on * @private */function init ( ctx ) {	var api = new DataTable.Api( ctx );	// Row callback so that classes can be added to rows and cells if the item	// was selected before the element was created. This will happen with the	// `deferRender` option enabled.	// 	// This method of attaching to `aoRowCreatedCallback` is a hack until	// DataTables has proper events for row manipulation If you are reviewing	// this code to create your own plug-ins, please do not do this!	ctx.aoRowCreatedCallback.push( {		fn: function ( row, data, index ) {			var i, ien;			var d = ctx.aoData[ index ];			// Row			if ( d._select_selected ) {				$( row ).addClass( ctx._select.className );			}			// Cells and columns - if separated out, we would need to do two			// loops, so it makes sense to combine them into a single one			for ( i=0, ien=ctx.aoColumns.length ; i<ien ; i++ ) {				if ( ctx.aoColumns[i]._select_selected || (d._selected_cells && d._selected_cells[i]) ) {					$(d.anCells[i]).addClass( ctx._select.className );				}			}		},		sName: 'select-deferRender'	} );	// On Ajax reload we want to reselect all rows which are currently selected,	// if there is an rowId (i.e. a unique value to identify each row with)	api.on( 'preXhr.dt.dtSelect', function () {		// note that column selection doesn't need to be cached and then		// reselected, as they are already selected		var rows = api.rows( { selected: true } ).ids( true ).filter( function ( d ) {			return d !== undefined;		} );		var cells = api.cells( { selected: true } ).eq(0).map( function ( cellIdx ) {			var id = api.row( cellIdx.row ).id( true );			return id ?				{ row: id, column: cellIdx.column } :				undefined;		} ).filter( function ( d ) {			return d !== undefined;		} );		// On the next draw, reselect the currently selected items		api.one( 'draw.dt.dtSelect', function () {			api.rows( rows ).select();			// `cells` is not a cell index selector, so it needs a loop			if ( cells.any() ) {				cells.each( function ( id ) {					api.cells( id.row, id.column ).select();				} );			}		} );	} );	// Update the table information element with selected item summary	api.on( 'draw.dtSelect.dt select.dtSelect.dt deselect.dtSelect.dt info.dt', function () {		info( api );	} );	// Clean up and release	api.on( 'destroy.dtSelect', function () {		disableMouseSelection( api );		api.off( '.dtSelect' );	} );}/** * Add one or more items (rows or columns) to the selection when shift clicking * in OS selection style * * @param  {DataTable.Api} dt   DataTable * @param  {string}        type Row or column range selector * @param  {object}        idx  Item index to select to * @param  {object}        last Item index to select from * @private */function rowColumnRange( dt, type, idx, last ){	// Add a range of rows from the last selected row to this one	var indexes = dt[type+'s']( { search: 'applied' } ).indexes();	var idx1 = $.inArray( last, indexes );	var idx2 = $.inArray( idx, indexes );	if ( ! dt[type+'s']( { selected: true } ).any() && idx1 === -1 ) {		// select from top to here - slightly odd, but both Windows and Mac OS		// do this		indexes.splice( $.inArray( idx, indexes )+1, indexes.length );	}	else {		// reverse so we can shift click 'up' as well as down		if ( idx1 > idx2 ) {			var tmp = idx2;			idx2 = idx1;			idx1 = tmp;		}		indexes.splice( idx2+1, indexes.length );		indexes.splice( 0, idx1 );	}	if ( ! dt[type]( idx, { selected: true } ).any() ) {		// Select range		dt[type+'s']( indexes ).select();	}	else {		// Deselect range - need to keep the clicked on row selected		indexes.splice( $.inArray( idx, indexes ), 1 );		dt[type+'s']( indexes ).deselect();	}}/** * Clear all selected items * * @param  {DataTable.settings} ctx Settings object of the host DataTable * @param  {boolean} [force=false] Force the de-selection to happen, regardless *     of selection style * @private */function clear( ctx, force ){	if ( force || ctx._select.style === 'single' ) {		var api = new DataTable.Api( ctx );				api.rows( { selected: true } ).deselect();		api.columns( { selected: true } ).deselect();		api.cells( { selected: true } ).deselect();	}}/** * Select items based on the current configuration for style and items. * * @param  {object}             e    Mouse event object * @param  {DataTables.Api}     dt   DataTable * @param  {DataTable.settings} ctx  Settings object of the host DataTable * @param  {string}             type Items to select * @param  {int|object}         idx  Index of the item to select * @private */function typeSelect ( e, dt, ctx, type, idx ){	var style = dt.select.style();	var toggleable = dt.select.toggleable();	var isSelected = dt[type]( idx, { selected: true } ).any();		if ( isSelected && ! toggleable ) {		return;	}	if ( style === 'os' ) {		if ( e.ctrlKey || e.metaKey ) {			// Add or remove from the selection			dt[type]( idx ).select( ! isSelected );		}		else if ( e.shiftKey ) {			if ( type === 'cell' ) {				cellRange( dt, idx, ctx._select_lastCell || null );			}			else {				rowColumnRange( dt, type, idx, ctx._select_lastCell ?					ctx._select_lastCell[type] :					null				);			}		}		else {			// No cmd or shift click - deselect if selected, or select			// this row only			var selected = dt[type+'s']( { selected: true } );			if ( isSelected && selected.flatten().length === 1 ) {				dt[type]( idx ).deselect();			}			else {				selected.deselect();				dt[type]( idx ).select();			}		}	} else if ( style == 'multi+shift' ) {		if ( e.shiftKey ) {			if ( type === 'cell' ) {				cellRange( dt, idx, ctx._select_lastCell || null );			}			else {				rowColumnRange( dt, type, idx, ctx._select_lastCell ?					ctx._select_lastCell[type] :					null				);			}		}		else {			dt[ type ]( idx ).select( ! isSelected );		}	}	else {		dt[ type ]( idx ).select( ! isSelected );	}}function _safeId( node ) {	return node.id.replace(/[^a-zA-Z0-9\-\_]/g, '-');}/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * DataTables selectors */// row and column are basically identical just assigned to different properties// and checking a different array, so we can dynamically create the functions to// reduce the code size$.each( [	{ type: 'row', prop: 'aoData' },	{ type: 'column', prop: 'aoColumns' }], function ( i, o ) {	DataTable.ext.selector[ o.type ].push( function ( settings, opts, indexes ) {		var selected = opts.selected;		var data;		var out = [];		if ( selected !== true && selected !== false ) {			return indexes;		}		for ( var i=0, ien=indexes.length ; i<ien ; i++ ) {			data = settings[ o.prop ][ indexes[i] ];			if ( (selected === true && data._select_selected === true) ||			     (selected === false && ! data._select_selected )			) {				out.push( indexes[i] );			}		}		return out;	} );} );DataTable.ext.selector.cell.push( function ( settings, opts, cells ) {	var selected = opts.selected;	var rowData;	var out = [];	if ( selected === undefined ) {		return cells;	}	for ( var i=0, ien=cells.length ; i<ien ; i++ ) {		rowData = settings.aoData[ cells[i].row ];		if ( (selected === true && rowData._selected_cells && rowData._selected_cells[ cells[i].column ] === true) ||		     (selected === false && ( ! rowData._selected_cells || ! rowData._selected_cells[ cells[i].column ] ) )		) {			out.push( cells[i] );		}	}	return out;} );/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * DataTables API * * For complete documentation, please refer to the docs/api directory or the * DataTables site */// Local variables to improve compressionvar apiRegister = DataTable.Api.register;var apiRegisterPlural = DataTable.Api.registerPlural;apiRegister( 'select()', function () {	return this.iterator( 'table', function ( ctx ) {		DataTable.select.init( new DataTable.Api( ctx ) );	} );} );apiRegister( 'select.blurable()', function ( flag ) {	if ( flag === undefined ) {		return this.context[0]._select.blurable;	}	return this.iterator( 'table', function ( ctx ) {		ctx._select.blurable = flag;	} );} );apiRegister( 'select.toggleable()', function ( flag ) {	if ( flag === undefined ) {		return this.context[0]._select.toggleable;	}	return this.iterator( 'table', function ( ctx ) {		ctx._select.toggleable = flag;	} );} );apiRegister( 'select.info()', function ( flag ) {	if ( info === undefined ) {		return this.context[0]._select.info;	}	return this.iterator( 'table', function ( ctx ) {		ctx._select.info = flag;	} );} );apiRegister( 'select.items()', function ( items ) {	if ( items === undefined ) {		return this.context[0]._select.items;	}	return this.iterator( 'table', function ( ctx ) {		ctx._select.items = items;		eventTrigger( new DataTable.Api( ctx ), 'selectItems', [ items ] );	} );} );// Takes effect from the _next_ selection. None disables future selection, but// does not clear the current selection. Use the `deselect` methods for thatapiRegister( 'select.style()', function ( style ) {	if ( style === undefined ) {		return this.context[0]._select.style;	}	return this.iterator( 'table', function ( ctx ) {		ctx._select.style = style;		if ( ! ctx._select_init ) {			init( ctx );		}		// Add / remove mouse event handlers. They aren't required when only		// API selection is available		var dt = new DataTable.Api( ctx );		disableMouseSelection( dt );				if ( style !== 'api' ) {			enableMouseSelection( dt );		}		eventTrigger( new DataTable.Api( ctx ), 'selectStyle', [ style ] );	} );} );apiRegister( 'select.selector()', function ( selector ) {	if ( selector === undefined ) {		return this.context[0]._select.selector;	}	return this.iterator( 'table', function ( ctx ) {		disableMouseSelection( new DataTable.Api( ctx ) );		ctx._select.selector = selector;		if ( ctx._select.style !== 'api' ) {			enableMouseSelection( new DataTable.Api( ctx ) );		}	} );} );apiRegisterPlural( 'rows().select()', 'row().select()', function ( select ) {	var api = this;	if ( select === false ) {		return this.deselect();	}	this.iterator( 'row', function ( ctx, idx ) {		clear( ctx );		ctx.aoData[ idx ]._select_selected = true;		$( ctx.aoData[ idx ].nTr ).addClass( ctx._select.className );	} );	this.iterator( 'table', function ( ctx, i ) {		eventTrigger( api, 'select', [ 'row', api[i] ], true );	} );	return this;} );apiRegisterPlural( 'columns().select()', 'column().select()', function ( select ) {	var api = this;	if ( select === false ) {		return this.deselect();	}	this.iterator( 'column', function ( ctx, idx ) {		clear( ctx );		ctx.aoColumns[ idx ]._select_selected = true;		var column = new DataTable.Api( ctx ).column( idx );		$( column.header() ).addClass( ctx._select.className );		$( column.footer() ).addClass( ctx._select.className );		column.nodes().to$().addClass( ctx._select.className );	} );	this.iterator( 'table', function ( ctx, i ) {		eventTrigger( api, 'select', [ 'column', api[i] ], true );	} );	return this;} );apiRegisterPlural( 'cells().select()', 'cell().select()', function ( select ) {	var api = this;	if ( select === false ) {		return this.deselect();	}	this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {		clear( ctx );		var data = ctx.aoData[ rowIdx ];		if ( data._selected_cells === undefined ) {			data._selected_cells = [];		}		data._selected_cells[ colIdx ] = true;		if ( data.anCells ) {			$( data.anCells[ colIdx ] ).addClass( ctx._select.className );		}	} );	this.iterator( 'table', function ( ctx, i ) {		eventTrigger( api, 'select', [ 'cell', api[i] ], true );	} );	return this;} );apiRegisterPlural( 'rows().deselect()', 'row().deselect()', function () {	var api = this;	this.iterator( 'row', function ( ctx, idx ) {		ctx.aoData[ idx ]._select_selected = false;		$( ctx.aoData[ idx ].nTr ).removeClass( ctx._select.className );	} );	this.iterator( 'table', function ( ctx, i ) {		eventTrigger( api, 'deselect', [ 'row', api[i] ], true );	} );	return this;} );apiRegisterPlural( 'columns().deselect()', 'column().deselect()', function () {	var api = this;	this.iterator( 'column', function ( ctx, idx ) {		ctx.aoColumns[ idx ]._select_selected = false;		var api = new DataTable.Api( ctx );		var column = api.column( idx );		$( column.header() ).removeClass( ctx._select.className );		$( column.footer() ).removeClass( ctx._select.className );		// Need to loop over each cell, rather than just using		// `column().nodes()` as cells which are individually selected should		// not have the `selected` class removed from them		api.cells( null, idx ).indexes().each( function (cellIdx) {			var data = ctx.aoData[ cellIdx.row ];			var cellSelected = data._selected_cells;			if ( data.anCells && (! cellSelected || ! cellSelected[ cellIdx.column ]) ) {				$( data.anCells[ cellIdx.column  ] ).removeClass( ctx._select.className );			}		} );	} );	this.iterator( 'table', function ( ctx, i ) {		eventTrigger( api, 'deselect', [ 'column', api[i] ], true );	} );	return this;} );apiRegisterPlural( 'cells().deselect()', 'cell().deselect()', function () {	var api = this;	this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {		var data = ctx.aoData[ rowIdx ];		data._selected_cells[ colIdx ] = false;		// Remove class only if the cells exist, and the cell is not column		// selected, in which case the class should remain (since it is selected		// in the column)		if ( data.anCells && ! ctx.aoColumns[ colIdx ]._select_selected ) {			$( data.anCells[ colIdx ] ).removeClass( ctx._select.className );		}	} );	this.iterator( 'table', function ( ctx, i ) {		eventTrigger( api, 'deselect', [ 'cell', api[i] ], true );	} );	return this;} );/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Buttons */function i18n( label, def ) {	return function (dt) {		return dt.i18n( 'buttons.'+label, def );	};}// Common events with suitable namespacesfunction namespacedEvents ( config ) {	var unique = config._eventNamespace;	return 'draw.dt.DT'+unique+' select.dt.DT'+unique+' deselect.dt.DT'+unique;}function enabled ( dt, config ) {	if ( $.inArray( 'rows', config.limitTo ) !== -1 && dt.rows( { selected: true } ).any() ) {		return true;	}	if ( $.inArray( 'columns', config.limitTo ) !== -1 && dt.columns( { selected: true } ).any() ) {		return true;	}	if ( $.inArray( 'cells', config.limitTo ) !== -1 && dt.cells( { selected: true } ).any() ) {		return true;	}	return false;}var _buttonNamespace = 0;$.extend( DataTable.ext.buttons, {	selected: {		text: i18n( 'selected', 'Selected' ),		className: 'buttons-selected',		limitTo: [ 'rows', 'columns', 'cells' ],		init: function ( dt, node, config ) {			var that = this;			config._eventNamespace = '.select'+(_buttonNamespace++);			// .DT namespace listeners are removed by DataTables automatically			// on table destroy			dt.on( namespacedEvents(config), function () {				that.enable( enabled(dt, config) );			} );			this.disable();		},		destroy: function ( dt, node, config ) {			dt.off( config._eventNamespace );		}	},	selectedSingle: {		text: i18n( 'selectedSingle', 'Selected single' ),		className: 'buttons-selected-single',		init: function ( dt, node, config ) {			var that = this;			config._eventNamespace = '.select'+(_buttonNamespace++);			dt.on( namespacedEvents(config), function () {				var count = dt.rows( { selected: true } ).flatten().length +				            dt.columns( { selected: true } ).flatten().length +				            dt.cells( { selected: true } ).flatten().length;				that.enable( count === 1 );			} );			this.disable();		},		destroy: function ( dt, node, config ) {			dt.off( config._eventNamespace );		}	},	selectAll: {		text: i18n( 'selectAll', 'Select all' ),		className: 'buttons-select-all',		action: function () {			var items = this.select.items();			this[ items+'s' ]().select();		}	},	selectNone: {		text: i18n( 'selectNone', 'Deselect all' ),		className: 'buttons-select-none',		action: function () {			clear( this.settings()[0], true );		},		init: function ( dt, node, config ) {			var that = this;			config._eventNamespace = '.select'+(_buttonNamespace++);			dt.on( namespacedEvents(config), function () {				var count = dt.rows( { selected: true } ).flatten().length +				            dt.columns( { selected: true } ).flatten().length +				            dt.cells( { selected: true } ).flatten().length;				that.enable( count > 0 );			} );			this.disable();		},		destroy: function ( dt, node, config ) {			dt.off( config._eventNamespace );		}	}} );$.each( [ 'Row', 'Column', 'Cell' ], function ( i, item ) {	var lc = item.toLowerCase();	DataTable.ext.buttons[ 'select'+item+'s' ] = {		text: i18n( 'select'+item+'s', 'Select '+lc+'s' ),		className: 'buttons-select-'+lc+'s',		action: function () {			this.select.items( lc );		},		init: function ( dt ) {			var that = this;			dt.on( 'selectItems.dt.DT', function ( e, ctx, items ) {				that.active( items === lc );			} );		}	};} );/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Initialisation */// DataTables creation - check if select has been defined in the options. Note// this required that the table be in the document! If it isn't then something// needs to trigger this method unfortunately. The next major release of// DataTables will rework the events and address this.$(document).on( 'preInit.dt.dtSelect', function (e, ctx) {	if ( e.namespace !== 'dt' ) {		return;	}	DataTable.select.init( new DataTable.Api( ctx ) );} );return DataTable.select;}));
 |