| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265 | 
							- /*! Select for DataTables 1.3.4-dev
 
-  * 2015-2021 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.4-dev
 
-  * @file        dataTables.select.js
 
-  * @author      SpryMedia Ltd (www.sprymedia.co.uk)
 
-  * @contact     datatables.net/forums
 
-  * @copyright   Copyright 2015-2021 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 debugger
 
- DataTable.select = {};
 
- DataTable.select.version = '1.3.4-dev';
 
- DataTable.select.init = function ( dt ) {
 
- 	var ctx = dt.settings()[0];
 
- 	if (ctx._select) {
 
- 		return;
 
- 	}
 
- 	var savedSelected = dt.state.loaded();
 
- 	var selectAndSave = function(e, settings, data) {
 
- 		if(data === null || data.select === undefined) {
 
- 			return;
 
- 		}
 
- 		dt.rows().deselect();
 
- 		dt.columns().deselect();
 
- 		dt.cells().deselect();
 
- 		if (data.select.rows !== undefined) {
 
- 			dt.rows(data.select.rows).select();
 
- 		}
 
- 		if (data.select.columns !== undefined) {
 
- 			dt.columns(data.select.columns).select();
 
- 		}
 
- 		if (data.select.cells !== undefined) {
 
- 			for(var i = 0; i < data.select.cells.length; i++) {
 
- 				dt.cell(data.select.cells[i].row, data.select.cells[i].column).select();
 
- 			}
 
- 		}
 
- 		dt.state.save();
 
- 	}
 
- 	
 
- 	dt.one('init', function() {
 
- 		dt.on('stateSaveParams', function(e, settings, data) {
 
- 			data.select = {};
 
- 			data.select.rows = dt.rows({selected:true}).ids(true).toArray();
 
- 			data.select.columns = dt.columns({selected:true})[0];
 
- 			data.select.cells = dt.cells({selected:true})[0].map(function(coords) {
 
- 				return {row: dt.row(coords.row).id(true), column: coords.column}
 
- 			});
 
- 		})
 
- 		
 
- 		selectAndSave(undefined, undefined, savedSelected)
 
- 		dt.on('stateLoaded stateLoadParams', selectAndSave)
 
- 	})
 
- 	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 and
 
- buttons (for the `Buttons` extension) for DataTables. It provides the following
 
- features, 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 not
 
- been created for rows / cells (DataTables' defer rendering feature).
 
- ## API methods
 
- A range of API methods are available for triggering selection and de-selection
 
- of rows. Methods are also available to configure the selection events that can
 
- be triggered by an end user (such as which items are to be selected). To a large
 
- extent, these of API methods *is* Select. It is basically a collection of helper
 
- functions that can be used to select items in a DataTable.
 
- Configuration of select is held in the object `_select` which is attached to the
 
- DataTables settings object on initialisation. Select being available on a table
 
- is not optional when Select is loaded, but its default is for selection only to
 
- be available via the API - so the end user wouldn't be able to select rows
 
- without 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 selector
 
- options for rows, columns and cells adding a `selected` option to the selector
 
- options object, allowing the developer to select only selected items or
 
- unselected items.
 
- ## Mouse selection of items
 
- Clicking on items can be used to select items. This is done by a simple event
 
- handler 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 = dt.settings()[0].oClasses.sWrapper.trim().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 );
 
- 	ctx._select_init = true;
 
- 	// 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 (e, settings) {
 
- 		if (settings !== api.settings()[0]) {
 
- 			// Not triggered by our DataTable!
 
- 			return;
 
- 		}
 
- 		// 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 );
 
- 		api.state.save();
 
- 	} );
 
- 	// Clean up and release
 
- 	api.on( 'destroy.dtSelect', function () {
 
- 		api.rows({selected: true}).deselect();
 
- 		disableMouseSelection( api );
 
- 		api.off( '.dtSelect' );
 
- 		$('body').off('.dtSelect' + _safeId(api.table().node()));
 
- 	} );
 
- }
 
- /**
 
-  * 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 compression
 
- var 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 ( flag === 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 that
 
- apiRegister( 'select.style()', function ( style ) {
 
- 	if ( style === undefined ) {
 
- 		return this.context[0]._select.style;
 
- 	}
 
- 	return this.iterator( 'table', function ( ctx ) {
 
- 		if ( ! ctx._select ) {
 
- 			DataTable.select.init( new DataTable.Api(ctx) );
 
- 		}
 
- 		if ( ! ctx._select_init ) {
 
- 			init(ctx);
 
- 		}
 
- 		ctx._select.style = style;
 
- 		// 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.cells(api[i]).indexes().toArray() ], 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._select_lastCell = null;
 
- 		$( 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 ];
 
- 		if(data._selected_cells !== undefined) {
 
- 			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 namespaces
 
- function 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;
 
- }));
 
 
  |