/*! Select for DataTables 3.0.0 * © SpryMedia Ltd - datatables.net/license/mit */ (function( factory ){ if ( typeof define === 'function' && define.amd ) { // AMD define( ['jquery', 'datatables.net'], function ( $ ) { return factory( $, window, document ); } ); } else if ( typeof exports === 'object' ) { // CommonJS var jq = require('jquery'); var cjsRequires = function (root, $) { if ( ! $.fn.dataTable ) { require('datatables.net')(root, $); } }; if (typeof window === 'undefined') { module.exports = function (root, $) { if ( ! root ) { // CommonJS environments without a window global must pass a // root. This will give an error otherwise root = window; } if ( ! $ ) { $ = jq( root ); } cjsRequires( root, $ ); return factory( $, root, root.document ); }; } else { cjsRequires( window, jq ); module.exports = factory( jq, window, window.document ); } } else { // Browser factory( jQuery, window, document ); } }(function( $, window, document ) { 'use strict'; var DataTable = $.fn.dataTable; // Version information for debugger DataTable.select = {}; DataTable.select.classes = { checkbox: 'dt-select-checkbox' }; DataTable.select.version = '3.0.0'; DataTable.select.init = function (dt) { var ctx = dt.settings()[0]; if (!DataTable.versionCheck('2')) { throw 'Warning: Select requires DataTables 2 or newer'; } if (ctx._select) { return; } var savedSelected = dt.state.loaded(); var selectAndSave = function (e, settings, data) { if (data === null || data.select === undefined) { return; } // Clear any currently selected rows, before restoring state // None will be selected on first initialisation if (dt.rows({ selected: true }).any()) { dt.rows().deselect(); } if (data.select.rows !== undefined) { dt.rows(data.select.rows).select(); } if (dt.columns({ selected: true }).any()) { dt.columns().deselect(); } if (data.select.columns !== undefined) { dt.columns(data.select.columns).select(); } if (dt.cells({ selected: true }).any()) { dt.cells().deselect(); } 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.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 }; }); }) .on('stateLoadParams', selectAndSave) .one('init', function () { selectAndSave(undefined, undefined, savedSelected); }); 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 selectable = null; var info = true; var selector = 'td, th'; var className = 'selected'; var headerCheckbox = true; var setStyle = false; var keys = false; ctx._select = { infoEls: [] }; // 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; } if (opts.headerCheckbox !== undefined) { headerCheckbox = opts.headerCheckbox; } if (opts.selectable !== undefined) { selectable = opts.selectable; } if (opts.keys !== undefined) { keys = opts.keys; } } dt.select.selector(selector); dt.select.items(items); dt.select.style(style); dt.select.blurable(blurable); dt.select.toggleable(toggleable); dt.select.info(info); dt.select.keys(keys); dt.select.selectable(selectable); ctx._select.className = className; // 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'); } // Insert a checkbox into the header if needed - might need to wait // for init complete if (headerCheckbox || headerCheckbox === 'select-page' || headerCheckbox === 'select-all') { dt.ready(function () { initCheckboxHeader(dt, headerCheckbox); }); } }; /* 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 infoEls:element[] - List of HTML elements with info elements for a table } ``` 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(); } } /** * Get the class * @returns */ function checkboxClass(selector) { var name = DataTable.select.classes.checkbox; return selector ? name.replace(/ /g, '.') : name; } /** * 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 container = dt.table().container(); // Ignore clicks inside a sub-table if ($(e.target).closest('div.dt-container')[0] != 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; } var event = $.Event('select-blur.dt'); eventTrigger(dt, event, [e.target, e]); if (event.isDefaultPrevented()) { 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); } /** * Determine if a column is a checkbox column * @param {*} col DataTables column object * @returns */ function isCheckboxColumn(col) { return col.mRender && col.mRender._name === 'selectCheckbox'; } /** * 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, node) { if (api.select.style() === 'api' || api.select.info() === false) { return; } var ctx = api.settings()[0]; var rowSetLength = ctx._select_set.length; var rows = rowSetLength ? rowSetLength : api.rows({ selected: true }).count(); var columns = api.columns({ selected: true }).count(); var cells = api.cells({ selected: true }).count(); // If subtractive selection, then we need to take the number of rows and // subtract those that have been deselected if (ctx._select_mode === 'subtractive') { rows = api.page.info().recordsDisplay - rowSetLength; } var add = function (el, name, num) { el.append( $('').append( api.i18n( 'select.' + name + 's', { _: '%d ' + name + 's selected', 0: '', 1: '1 ' + name + ' selected' }, num ) ) ); }; var el = $(node); var output = $(''); add(output, 'row', rows); add(output, 'column', columns); add(output, 'cell', cells); var existing = el.children('span.select-info'); if (existing.length) { existing.remove(); } if (output.text() !== '') { el.append(output); } } /** * Add a checkbox to the header for checkbox columns, allowing all rows to * be selected, deselected or just to show the state. * * @param {*} dt API * @param {*} headerCheckbox the header checkbox option */ function initCheckboxHeader( dt, headerCheckbox ) { var dtSettings = dt.settings()[0]; var dtInternalColumns = dtSettings.aoColumns; // Find any checkbox column(s) dt.columns().iterator('column', function (s, idx) { var col = dtInternalColumns[idx]; // Checkbox columns have a rendering function with a given name if (! isCheckboxColumn(col)) { return; } var header = dt.column(idx).header(); if (! $('input', header).length) { // If no checkbox yet, insert one var input = $('') .attr({ class: checkboxClass(true), type: 'checkbox', 'aria-label': dt.i18n('select.aria.headerCheckbox') || 'Select all rows' }) .appendTo(header) .on('change', function () { if (this.checked) { if (headerCheckbox == 'select-page') { dt.rows({page: 'current'}).select(); } else { dt.rows({search: 'applied'}).select(); } } else { if (headerCheckbox == 'select-page') { dt.rows({page: 'current', selected: true}).deselect(); } else { dt.rows({selected: true}).deselect(); } } }) .on('click', function (e) { e.stopPropagation(); }); // Update the header checkbox's state when the selection in the // table changes dt.on('draw select deselect', function (e, pass, type) { if (type === 'row' || ! type) { var nums = headerCheckboxState(dt, headerCheckbox); if (nums.search && nums.search <= nums.count && nums.search === nums.available) { input .prop('checked', true) .prop('indeterminate', false); } else if (nums.search === 0 && nums.count === 0) { input .prop('checked', false) .prop('indeterminate', false); } else { input .prop('checked', false) .prop('indeterminate', true); } } }); } }); } function keysSet(dt) { var ctx = dt.settings()[0]; var flag = ctx._select.keys; var namespace = 'dts-keys-' + ctx.sTableId; if (flag) { // Need a tabindex of the `tr` elements to make them focusable by the browser $(dt.rows({page: 'current'}).nodes()).attr('tabindex', 0); dt.on('draw.' + namespace, function () { $(dt.rows({page: 'current'}).nodes()).attr('tabindex', 0); }); // Listen on document for tab, up and down $(document).on('keydown.' + namespace, function (e) { var key = e.keyCode; var active = document.activeElement; // Can't use e.key as it wasn't widely supported until 2017 // 9 Tab // 13 Return // 32 Space // 38 ArrowUp // 40 ArrowDown if (! [9, 13, 32, 38, 40].includes(key)) { return; } var nodes = dt.rows({page: 'current'}).nodes().toArray(); var idx = nodes.indexOf(active); var preventDefault = true; // Only take an action if a row has focus if (idx === -1) { return; } if (key === 9) { // Tab focus change if (e.shift === false && idx === nodes.length - 1) { keysPageDown(dt); } else if (e.shift === true && idx === 0) { keysPageUp(dt); } else { // Browser will do it for us preventDefault = false; } } else if (key === 13 || key === 32) { // Row selection / deselection var row = dt.row(active); if (row.selected()) { row.deselect(); } else { row.select(); } } else if (key === 38) { // Move up if (idx > 0) { nodes[idx-1].focus(); } else { keysPageUp(dt); } } else { // Move down if (idx < nodes.length -1) { nodes[idx+1].focus(); } else { keysPageDown(dt); } } if (preventDefault) { e.stopPropagation(); e.preventDefault(); } }); } else { // Stop the rows from being able to gain focus $(dt.rows().nodes()).removeAttr('tabindex'); // Nuke events dt.off('draw.' + namespace); $(document).off('keydown.' + namespace); } } /** * Change to the next page and focus on the first row * * @param {DataTable.Api} dt DataTable instance */ function keysPageDown(dt) { // Is there another page to turn to? var info = dt.page.info(); if (info.page < info.pages - 1) { dt .one('draw', function () { dt.row(':first-child').node().focus(); }) .page('next') .draw(false); } } /** * Change to the previous page and focus on the last row * * @param {DataTable.Api} dt DataTable instance */ function keysPageUp(dt) { // Is there another page to turn to? var info = dt.page.info(); if (info.page > 0) { dt .one('draw', function () { dt.row(':last-child').node().focus(); }) .page('previous') .draw(false); } } /** * Determine the counts used to define the header checkbox's state * * @param {*} dt DT API * @param {*} headerCheckbox Configuration for what the header checkbox does * @returns Counts object */ function headerCheckboxState(dt, headerCheckbox) { var ctx = dt.settings()[0]; var selectable = ctx._select.selectable; var available = 0; var count = headerCheckbox == 'select-page' ? dt.rows({page: 'current', selected: true}).count() : dt.rows({selected: true}).count(); var search = headerCheckbox == 'select-page' ? dt.rows({page: 'current', selected: true}).count() : dt.rows({search: 'applied', selected: true}).count(); if (! selectable) { available = headerCheckbox == 'select-page' ? dt.rows({page: 'current'}).count() : dt.rows({search: 'applied'}).count(); } else { // Need to count how many rows are actually selectable to know if all selectable // rows are selected or not var indexes = headerCheckbox == 'select-page' ? dt.rows({page: 'current'}).indexes() : dt.rows({search: 'applied'}).indexes(); for (var i=0 ; i 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(indexes.indexOf(idx), 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, '-'); } /** * Set up event handlers for cumulative selection * * @param {*} api DT API instance */ function _cumulativeEvents(api) { // Add event listeners to add / remove from the _select_set api.on('select', function (e, dt, type, indexes) { // Only support for rows at the moment if (type !== 'row') { return; } var ctx = api.settings()[0]; if (ctx._select_mode === 'additive') { // Add row to the selection list if it isn't already there _add(api, ctx._select_set, indexes); } else { // Subtractive - if a row is selected it should not in the list // as in subtractive mode the list gives the rows which are not // selected _remove(api, ctx._select_set, indexes); } }); api.on('deselect', function (e, dt, type, indexes) { // Only support for rows at the moment if (type !== 'row') { return; } var ctx = api.settings()[0]; if (ctx._select_mode === 'additive') { // List is of those rows selected, so remove it _remove(api, ctx._select_set, indexes); } else { // List is of rows which are deselected, so add it! _add(api, ctx._select_set, indexes); } }); } function _add(api, arr, indexes) { for (var i=0 ; i 0); }); this.disable(); }, destroy: function (dt, node, config) { dt.off(config._eventNamespace); } }, showSelected: { text: i18n('showSelected', 'Show only selected'), className: 'buttons-show-selected', action: function (e, dt) { if (dt.search.fixed('dt-select')) { // Remove existing function dt.search.fixed('dt-select', null); this.active(false); } else { // Use a fixed filtering function to match on selected rows // This needs to reference the internal aoData since that is // where Select stores its reference for the selected state var dataSrc = dt.settings()[0].aoData; dt.search.fixed('dt-select', function (text, data, idx) { // _select_selected is set by Select on the data object for the row return dataSrc[idx]._select_selected; }); this.active(true); } dt.draw(); } } }); $.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; this.active(dt.select.items() === lc); dt.on('selectItems.dt.DT', function (e, ctx, items) { that.active(items === lc); }); } }; }); // Note that DataTables 2.1 has more robust type detection, but we retain // backwards compatibility with 2.0 for the moment. DataTable.type('select-checkbox', { className: 'dt-select', detect: DataTable.versionCheck('2.1') ? { oneOf: function () { return false; // no op }, allOf: function () { return false; // no op }, init: function (settings, col, idx) { return isCheckboxColumn(col); } } : function (data) { // Rendering function will tell us if it is a checkbox type return data === 'select-checkbox' ? data : false; }, order: { pre: function (d) { return d === 'X' ? -1 : 0; } } }); $.extend(true, DataTable.defaults.oLanguage, { select: { aria: { rowCheckbox: 'Select row' } } }); DataTable.render.select = function (valueProp, nameProp) { var valueFn = valueProp ? DataTable.util.get(valueProp) : null; var nameFn = nameProp ? DataTable.util.get(nameProp) : null; var fn = function (data, type, row, meta) { var dtRow = meta.settings.aoData[meta.row]; var selected = dtRow._select_selected; var ariaLabel = meta.settings.oLanguage.select.aria.rowCheckbox; var selectable = meta.settings._select.selectable; if (type === 'display') { // Check if the row is selectable before showing the checkbox if (selectable) { var result = selectable(row, dtRow.nTr, meta.row); if (result === false) { return ''; } } return $('') .attr({ 'aria-label': ariaLabel, class: checkboxClass(), name: nameFn ? nameFn(row) : null, type: 'checkbox', value: valueFn ? valueFn(row) : null, checked: selected }) .on('input', function (e) { // Let Select 100% control the state of the checkbox e.preventDefault(); // And make sure this checkbox matches it's row as it is possible // to check out of sync if this was clicked on to deselect a range // but remains selected itself this.checked = $(this).closest('tr').hasClass('selected'); })[0]; } else if (type === 'type') { return 'select-checkbox'; } else if (type === 'filter') { return ''; } return selected ? 'X' : ''; } // Workaround so uglify doesn't strip the function name. It is used // for the column type detection. fn._name = 'selectCheckbox'; return fn; } // Legacy checkbox ordering 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).toString(); } else if (settings._select.items === 'cell') { return $(td).hasClass(settings._select.className).toString(); } return false; }); }; $.fn.DataTable.select = DataTable.select; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Initialisation */ // DataTables creation - we need this to run _before_ data is read in, but // for backwards compat. we also run again on preInit. If it happens twice // it will simply do nothing the second time around. $(document).on('i18n.dt.dtSelect preInit.dt.dtSelect', function (e, ctx) { if (e.namespace !== 'dt') { return; } DataTable.select.init(new DataTable.Api(ctx)); }); return DataTable; }));