[7304c7f] | 1 | /*! Select for DataTables 1.3.1
|
---|
| 2 | * 2015-2019 SpryMedia Ltd - datatables.net/license/mit
|
---|
| 3 | */
|
---|
| 4 |
|
---|
| 5 | /**
|
---|
| 6 | * @summary Select for DataTables
|
---|
| 7 | * @description A collection of API methods, events and buttons for DataTables
|
---|
| 8 | * that provides selection options of the items in a DataTable
|
---|
| 9 | * @version 1.3.1
|
---|
| 10 | * @file dataTables.select.js
|
---|
| 11 | * @author SpryMedia Ltd (www.sprymedia.co.uk)
|
---|
| 12 | * @contact datatables.net/forums
|
---|
| 13 | * @copyright Copyright 2015-2019 SpryMedia Ltd.
|
---|
| 14 | *
|
---|
| 15 | * This source file is free software, available under the following license:
|
---|
| 16 | * MIT license - http://datatables.net/license/mit
|
---|
| 17 | *
|
---|
| 18 | * This source file is distributed in the hope that it will be useful, but
|
---|
| 19 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
---|
| 20 | * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
|
---|
| 21 | *
|
---|
| 22 | * For details please refer to: http://www.datatables.net/extensions/select
|
---|
| 23 | */
|
---|
| 24 | (function( factory ){
|
---|
| 25 | if ( typeof define === 'function' && define.amd ) {
|
---|
| 26 | // AMD
|
---|
| 27 | define( ['jquery', 'datatables.net'], function ( $ ) {
|
---|
| 28 | return factory( $, window, document );
|
---|
| 29 | } );
|
---|
| 30 | }
|
---|
| 31 | else if ( typeof exports === 'object' ) {
|
---|
| 32 | // CommonJS
|
---|
| 33 | module.exports = function (root, $) {
|
---|
| 34 | if ( ! root ) {
|
---|
| 35 | root = window;
|
---|
| 36 | }
|
---|
| 37 |
|
---|
| 38 | if ( ! $ || ! $.fn.dataTable ) {
|
---|
| 39 | $ = require('datatables.net')(root, $).$;
|
---|
| 40 | }
|
---|
| 41 |
|
---|
| 42 | return factory( $, root, root.document );
|
---|
| 43 | };
|
---|
| 44 | }
|
---|
| 45 | else {
|
---|
| 46 | // Browser
|
---|
| 47 | factory( jQuery, window, document );
|
---|
| 48 | }
|
---|
| 49 | }(function( $, window, document, undefined ) {
|
---|
| 50 | 'use strict';
|
---|
| 51 | var DataTable = $.fn.dataTable;
|
---|
| 52 |
|
---|
| 53 |
|
---|
| 54 | // Version information for debugger
|
---|
| 55 | DataTable.select = {};
|
---|
| 56 |
|
---|
| 57 | DataTable.select.version = '1.3.1';
|
---|
| 58 |
|
---|
| 59 | DataTable.select.init = function ( dt ) {
|
---|
| 60 | var ctx = dt.settings()[0];
|
---|
| 61 | var init = ctx.oInit.select;
|
---|
| 62 | var defaults = DataTable.defaults.select;
|
---|
| 63 | var opts = init === undefined ?
|
---|
| 64 | defaults :
|
---|
| 65 | init;
|
---|
| 66 |
|
---|
| 67 | // Set defaults
|
---|
| 68 | var items = 'row';
|
---|
| 69 | var style = 'api';
|
---|
| 70 | var blurable = false;
|
---|
| 71 | var toggleable = true;
|
---|
| 72 | var info = true;
|
---|
| 73 | var selector = 'td, th';
|
---|
| 74 | var className = 'selected';
|
---|
| 75 | var setStyle = false;
|
---|
| 76 |
|
---|
| 77 | ctx._select = {};
|
---|
| 78 |
|
---|
| 79 | // Initialisation customisations
|
---|
| 80 | if ( opts === true ) {
|
---|
| 81 | style = 'os';
|
---|
| 82 | setStyle = true;
|
---|
| 83 | }
|
---|
| 84 | else if ( typeof opts === 'string' ) {
|
---|
| 85 | style = opts;
|
---|
| 86 | setStyle = true;
|
---|
| 87 | }
|
---|
| 88 | else if ( $.isPlainObject( opts ) ) {
|
---|
| 89 | if ( opts.blurable !== undefined ) {
|
---|
| 90 | blurable = opts.blurable;
|
---|
| 91 | }
|
---|
| 92 |
|
---|
| 93 | if ( opts.toggleable !== undefined ) {
|
---|
| 94 | toggleable = opts.toggleable;
|
---|
| 95 | }
|
---|
| 96 |
|
---|
| 97 | if ( opts.info !== undefined ) {
|
---|
| 98 | info = opts.info;
|
---|
| 99 | }
|
---|
| 100 |
|
---|
| 101 | if ( opts.items !== undefined ) {
|
---|
| 102 | items = opts.items;
|
---|
| 103 | }
|
---|
| 104 |
|
---|
| 105 | if ( opts.style !== undefined ) {
|
---|
| 106 | style = opts.style;
|
---|
| 107 | setStyle = true;
|
---|
| 108 | }
|
---|
| 109 | else {
|
---|
| 110 | style = 'os';
|
---|
| 111 | setStyle = true;
|
---|
| 112 | }
|
---|
| 113 |
|
---|
| 114 | if ( opts.selector !== undefined ) {
|
---|
| 115 | selector = opts.selector;
|
---|
| 116 | }
|
---|
| 117 |
|
---|
| 118 | if ( opts.className !== undefined ) {
|
---|
| 119 | className = opts.className;
|
---|
| 120 | }
|
---|
| 121 | }
|
---|
| 122 |
|
---|
| 123 | dt.select.selector( selector );
|
---|
| 124 | dt.select.items( items );
|
---|
| 125 | dt.select.style( style );
|
---|
| 126 | dt.select.blurable( blurable );
|
---|
| 127 | dt.select.toggleable( toggleable );
|
---|
| 128 | dt.select.info( info );
|
---|
| 129 | ctx._select.className = className;
|
---|
| 130 |
|
---|
| 131 |
|
---|
| 132 | // Sort table based on selected rows. Requires Select Datatables extension
|
---|
| 133 | $.fn.dataTable.ext.order['select-checkbox'] = function ( settings, col ) {
|
---|
| 134 | return this.api().column( col, {order: 'index'} ).nodes().map( function ( td ) {
|
---|
| 135 | if ( settings._select.items === 'row' ) {
|
---|
| 136 | return $( td ).parent().hasClass( settings._select.className );
|
---|
| 137 | } else if ( settings._select.items === 'cell' ) {
|
---|
| 138 | return $( td ).hasClass( settings._select.className );
|
---|
| 139 | }
|
---|
| 140 | return false;
|
---|
| 141 | });
|
---|
| 142 | };
|
---|
| 143 |
|
---|
| 144 | // If the init options haven't enabled select, but there is a selectable
|
---|
| 145 | // class name, then enable
|
---|
| 146 | if ( ! setStyle && $( dt.table().node() ).hasClass( 'selectable' ) ) {
|
---|
| 147 | dt.select.style( 'os' );
|
---|
| 148 | }
|
---|
| 149 | };
|
---|
| 150 |
|
---|
| 151 | /*
|
---|
| 152 |
|
---|
| 153 | Select is a collection of API methods, event handlers, event emitters and
|
---|
| 154 | buttons (for the `Buttons` extension) for DataTables. It provides the following
|
---|
| 155 | features, with an overview of how they are implemented:
|
---|
| 156 |
|
---|
| 157 | ## Selection of rows, columns and cells. Whether an item is selected or not is
|
---|
| 158 | stored in:
|
---|
| 159 |
|
---|
| 160 | * rows: a `_select_selected` property which contains a boolean value of the
|
---|
| 161 | DataTables' `aoData` object for each row
|
---|
| 162 | * columns: a `_select_selected` property which contains a boolean value of the
|
---|
| 163 | DataTables' `aoColumns` object for each column
|
---|
| 164 | * cells: a `_selected_cells` property which contains an array of boolean values
|
---|
| 165 | of the `aoData` object for each row. The array is the same length as the
|
---|
| 166 | columns array, with each element of it representing a cell.
|
---|
| 167 |
|
---|
| 168 | This method of using boolean flags allows Select to operate when nodes have not
|
---|
| 169 | been created for rows / cells (DataTables' defer rendering feature).
|
---|
| 170 |
|
---|
| 171 | ## API methods
|
---|
| 172 |
|
---|
| 173 | A range of API methods are available for triggering selection and de-selection
|
---|
| 174 | of rows. Methods are also available to configure the selection events that can
|
---|
| 175 | be triggered by an end user (such as which items are to be selected). To a large
|
---|
| 176 | extent, these of API methods *is* Select. It is basically a collection of helper
|
---|
| 177 | functions that can be used to select items in a DataTable.
|
---|
| 178 |
|
---|
| 179 | Configuration of select is held in the object `_select` which is attached to the
|
---|
| 180 | DataTables settings object on initialisation. Select being available on a table
|
---|
| 181 | is not optional when Select is loaded, but its default is for selection only to
|
---|
| 182 | be available via the API - so the end user wouldn't be able to select rows
|
---|
| 183 | without additional configuration.
|
---|
| 184 |
|
---|
| 185 | The `_select` object contains the following properties:
|
---|
| 186 |
|
---|
| 187 | ```
|
---|
| 188 | {
|
---|
| 189 | items:string - Can be `rows`, `columns` or `cells`. Defines what item
|
---|
| 190 | will be selected if the user is allowed to activate row
|
---|
| 191 | selection using the mouse.
|
---|
| 192 | style:string - Can be `none`, `single`, `multi` or `os`. Defines the
|
---|
| 193 | interaction style when selecting items
|
---|
| 194 | blurable:boolean - If row selection can be cleared by clicking outside of
|
---|
| 195 | the table
|
---|
| 196 | toggleable:boolean - If row selection can be cancelled by repeated clicking
|
---|
| 197 | on the row
|
---|
| 198 | info:boolean - If the selection summary should be shown in the table
|
---|
| 199 | information elements
|
---|
| 200 | }
|
---|
| 201 | ```
|
---|
| 202 |
|
---|
| 203 | In addition to the API methods, Select also extends the DataTables selector
|
---|
| 204 | options for rows, columns and cells adding a `selected` option to the selector
|
---|
| 205 | options object, allowing the developer to select only selected items or
|
---|
| 206 | unselected items.
|
---|
| 207 |
|
---|
| 208 | ## Mouse selection of items
|
---|
| 209 |
|
---|
| 210 | Clicking on items can be used to select items. This is done by a simple event
|
---|
| 211 | handler that will select the items using the API methods.
|
---|
| 212 |
|
---|
| 213 | */
|
---|
| 214 |
|
---|
| 215 |
|
---|
| 216 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
---|
| 217 | * Local functions
|
---|
| 218 | */
|
---|
| 219 |
|
---|
| 220 | /**
|
---|
| 221 | * Add one or more cells to the selection when shift clicking in OS selection
|
---|
| 222 | * style cell selection.
|
---|
| 223 | *
|
---|
| 224 | * Cell range is more complicated than row and column as we want to select
|
---|
| 225 | * in the visible grid rather than by index in sequence. For example, if you
|
---|
| 226 | * click first in cell 1-1 and then shift click in 2-2 - cells 1-2 and 2-1
|
---|
| 227 | * should also be selected (and not 1-3, 1-4. etc)
|
---|
| 228 | *
|
---|
| 229 | * @param {DataTable.Api} dt DataTable
|
---|
| 230 | * @param {object} idx Cell index to select to
|
---|
| 231 | * @param {object} last Cell index to select from
|
---|
| 232 | * @private
|
---|
| 233 | */
|
---|
| 234 | function cellRange( dt, idx, last )
|
---|
| 235 | {
|
---|
| 236 | var indexes;
|
---|
| 237 | var columnIndexes;
|
---|
| 238 | var rowIndexes;
|
---|
| 239 | var selectColumns = function ( start, end ) {
|
---|
| 240 | if ( start > end ) {
|
---|
| 241 | var tmp = end;
|
---|
| 242 | end = start;
|
---|
| 243 | start = tmp;
|
---|
| 244 | }
|
---|
| 245 |
|
---|
| 246 | var record = false;
|
---|
| 247 | return dt.columns( ':visible' ).indexes().filter( function (i) {
|
---|
| 248 | if ( i === start ) {
|
---|
| 249 | record = true;
|
---|
| 250 | }
|
---|
| 251 |
|
---|
| 252 | if ( i === end ) { // not else if, as start might === end
|
---|
| 253 | record = false;
|
---|
| 254 | return true;
|
---|
| 255 | }
|
---|
| 256 |
|
---|
| 257 | return record;
|
---|
| 258 | } );
|
---|
| 259 | };
|
---|
| 260 |
|
---|
| 261 | var selectRows = function ( start, end ) {
|
---|
| 262 | var indexes = dt.rows( { search: 'applied' } ).indexes();
|
---|
| 263 |
|
---|
| 264 | // Which comes first - might need to swap
|
---|
| 265 | if ( indexes.indexOf( start ) > indexes.indexOf( end ) ) {
|
---|
| 266 | var tmp = end;
|
---|
| 267 | end = start;
|
---|
| 268 | start = tmp;
|
---|
| 269 | }
|
---|
| 270 |
|
---|
| 271 | var record = false;
|
---|
| 272 | return indexes.filter( function (i) {
|
---|
| 273 | if ( i === start ) {
|
---|
| 274 | record = true;
|
---|
| 275 | }
|
---|
| 276 |
|
---|
| 277 | if ( i === end ) {
|
---|
| 278 | record = false;
|
---|
| 279 | return true;
|
---|
| 280 | }
|
---|
| 281 |
|
---|
| 282 | return record;
|
---|
| 283 | } );
|
---|
| 284 | };
|
---|
| 285 |
|
---|
| 286 | if ( ! dt.cells( { selected: true } ).any() && ! last ) {
|
---|
| 287 | // select from the top left cell to this one
|
---|
| 288 | columnIndexes = selectColumns( 0, idx.column );
|
---|
| 289 | rowIndexes = selectRows( 0 , idx.row );
|
---|
| 290 | }
|
---|
| 291 | else {
|
---|
| 292 | // Get column indexes between old and new
|
---|
| 293 | columnIndexes = selectColumns( last.column, idx.column );
|
---|
| 294 | rowIndexes = selectRows( last.row , idx.row );
|
---|
| 295 | }
|
---|
| 296 |
|
---|
| 297 | indexes = dt.cells( rowIndexes, columnIndexes ).flatten();
|
---|
| 298 |
|
---|
| 299 | if ( ! dt.cells( idx, { selected: true } ).any() ) {
|
---|
| 300 | // Select range
|
---|
| 301 | dt.cells( indexes ).select();
|
---|
| 302 | }
|
---|
| 303 | else {
|
---|
| 304 | // Deselect range
|
---|
| 305 | dt.cells( indexes ).deselect();
|
---|
| 306 | }
|
---|
| 307 | }
|
---|
| 308 |
|
---|
| 309 | /**
|
---|
| 310 | * Disable mouse selection by removing the selectors
|
---|
| 311 | *
|
---|
| 312 | * @param {DataTable.Api} dt DataTable to remove events from
|
---|
| 313 | * @private
|
---|
| 314 | */
|
---|
| 315 | function disableMouseSelection( dt )
|
---|
| 316 | {
|
---|
| 317 | var ctx = dt.settings()[0];
|
---|
| 318 | var selector = ctx._select.selector;
|
---|
| 319 |
|
---|
| 320 | $( dt.table().container() )
|
---|
| 321 | .off( 'mousedown.dtSelect', selector )
|
---|
| 322 | .off( 'mouseup.dtSelect', selector )
|
---|
| 323 | .off( 'click.dtSelect', selector );
|
---|
| 324 |
|
---|
| 325 | $('body').off( 'click.dtSelect' + _safeId(dt.table().node()) );
|
---|
| 326 | }
|
---|
| 327 |
|
---|
| 328 | /**
|
---|
| 329 | * Attach mouse listeners to the table to allow mouse selection of items
|
---|
| 330 | *
|
---|
| 331 | * @param {DataTable.Api} dt DataTable to remove events from
|
---|
| 332 | * @private
|
---|
| 333 | */
|
---|
| 334 | function enableMouseSelection ( dt )
|
---|
| 335 | {
|
---|
| 336 | var container = $( dt.table().container() );
|
---|
| 337 | var ctx = dt.settings()[0];
|
---|
| 338 | var selector = ctx._select.selector;
|
---|
| 339 | var matchSelection;
|
---|
| 340 |
|
---|
| 341 | container
|
---|
| 342 | .on( 'mousedown.dtSelect', selector, function(e) {
|
---|
| 343 | // Disallow text selection for shift clicking on the table so multi
|
---|
| 344 | // element selection doesn't look terrible!
|
---|
| 345 | if ( e.shiftKey || e.metaKey || e.ctrlKey ) {
|
---|
| 346 | container
|
---|
| 347 | .css( '-moz-user-select', 'none' )
|
---|
| 348 | .one('selectstart.dtSelect', selector, function () {
|
---|
| 349 | return false;
|
---|
| 350 | } );
|
---|
| 351 | }
|
---|
| 352 |
|
---|
| 353 | if ( window.getSelection ) {
|
---|
| 354 | matchSelection = window.getSelection();
|
---|
| 355 | }
|
---|
| 356 | } )
|
---|
| 357 | .on( 'mouseup.dtSelect', selector, function() {
|
---|
| 358 | // Allow text selection to occur again, Mozilla style (tested in FF
|
---|
| 359 | // 35.0.1 - still required)
|
---|
| 360 | container.css( '-moz-user-select', '' );
|
---|
| 361 | } )
|
---|
| 362 | .on( 'click.dtSelect', selector, function ( e ) {
|
---|
| 363 | var items = dt.select.items();
|
---|
| 364 | var idx;
|
---|
| 365 |
|
---|
| 366 | // If text was selected (click and drag), then we shouldn't change
|
---|
| 367 | // the row's selected state
|
---|
| 368 | if ( matchSelection ) {
|
---|
| 369 | var selection = window.getSelection();
|
---|
| 370 |
|
---|
| 371 | // If the element that contains the selection is not in the table, we can ignore it
|
---|
| 372 | // This can happen if the developer selects text from the click event
|
---|
| 373 | if ( ! selection.anchorNode || $(selection.anchorNode).closest('table')[0] === dt.table().node() ) {
|
---|
| 374 | if ( selection !== matchSelection ) {
|
---|
| 375 | return;
|
---|
| 376 | }
|
---|
| 377 | }
|
---|
| 378 | }
|
---|
| 379 |
|
---|
| 380 | var ctx = dt.settings()[0];
|
---|
| 381 | var wrapperClass = $.trim(dt.settings()[0].oClasses.sWrapper).replace(/ +/g, '.');
|
---|
| 382 |
|
---|
| 383 | // Ignore clicks inside a sub-table
|
---|
| 384 | if ( $(e.target).closest('div.'+wrapperClass)[0] != dt.table().container() ) {
|
---|
| 385 | return;
|
---|
| 386 | }
|
---|
| 387 |
|
---|
| 388 | var cell = dt.cell( $(e.target).closest('td, th') );
|
---|
| 389 |
|
---|
| 390 | // Check the cell actually belongs to the host DataTable (so child
|
---|
| 391 | // rows, etc, are ignored)
|
---|
| 392 | if ( ! cell.any() ) {
|
---|
| 393 | return;
|
---|
| 394 | }
|
---|
| 395 |
|
---|
| 396 | var event = $.Event('user-select.dt');
|
---|
| 397 | eventTrigger( dt, event, [ items, cell, e ] );
|
---|
| 398 |
|
---|
| 399 | if ( event.isDefaultPrevented() ) {
|
---|
| 400 | return;
|
---|
| 401 | }
|
---|
| 402 |
|
---|
| 403 | var cellIndex = cell.index();
|
---|
| 404 | if ( items === 'row' ) {
|
---|
| 405 | idx = cellIndex.row;
|
---|
| 406 | typeSelect( e, dt, ctx, 'row', idx );
|
---|
| 407 | }
|
---|
| 408 | else if ( items === 'column' ) {
|
---|
| 409 | idx = cell.index().column;
|
---|
| 410 | typeSelect( e, dt, ctx, 'column', idx );
|
---|
| 411 | }
|
---|
| 412 | else if ( items === 'cell' ) {
|
---|
| 413 | idx = cell.index();
|
---|
| 414 | typeSelect( e, dt, ctx, 'cell', idx );
|
---|
| 415 | }
|
---|
| 416 |
|
---|
| 417 | ctx._select_lastCell = cellIndex;
|
---|
| 418 | } );
|
---|
| 419 |
|
---|
| 420 | // Blurable
|
---|
| 421 | $('body').on( 'click.dtSelect' + _safeId(dt.table().node()), function ( e ) {
|
---|
| 422 | if ( ctx._select.blurable ) {
|
---|
| 423 | // If the click was inside the DataTables container, don't blur
|
---|
| 424 | if ( $(e.target).parents().filter( dt.table().container() ).length ) {
|
---|
| 425 | return;
|
---|
| 426 | }
|
---|
| 427 |
|
---|
| 428 | // Ignore elements which have been removed from the DOM (i.e. paging
|
---|
| 429 | // buttons)
|
---|
| 430 | if ( $(e.target).parents('html').length === 0 ) {
|
---|
| 431 | return;
|
---|
| 432 | }
|
---|
| 433 |
|
---|
| 434 | // Don't blur in Editor form
|
---|
| 435 | if ( $(e.target).parents('div.DTE').length ) {
|
---|
| 436 | return;
|
---|
| 437 | }
|
---|
| 438 |
|
---|
| 439 | clear( ctx, true );
|
---|
| 440 | }
|
---|
| 441 | } );
|
---|
| 442 | }
|
---|
| 443 |
|
---|
| 444 | /**
|
---|
| 445 | * Trigger an event on a DataTable
|
---|
| 446 | *
|
---|
| 447 | * @param {DataTable.Api} api DataTable to trigger events on
|
---|
| 448 | * @param {boolean} selected true if selected, false if deselected
|
---|
| 449 | * @param {string} type Item type acting on
|
---|
| 450 | * @param {boolean} any Require that there are values before
|
---|
| 451 | * triggering
|
---|
| 452 | * @private
|
---|
| 453 | */
|
---|
| 454 | function eventTrigger ( api, type, args, any )
|
---|
| 455 | {
|
---|
| 456 | if ( any && ! api.flatten().length ) {
|
---|
| 457 | return;
|
---|
| 458 | }
|
---|
| 459 |
|
---|
| 460 | if ( typeof type === 'string' ) {
|
---|
| 461 | type = type +'.dt';
|
---|
| 462 | }
|
---|
| 463 |
|
---|
| 464 | args.unshift( api );
|
---|
| 465 |
|
---|
| 466 | $(api.table().node()).trigger( type, args );
|
---|
| 467 | }
|
---|
| 468 |
|
---|
| 469 | /**
|
---|
| 470 | * Update the information element of the DataTable showing information about the
|
---|
| 471 | * items selected. This is done by adding tags to the existing text
|
---|
| 472 | *
|
---|
| 473 | * @param {DataTable.Api} api DataTable to update
|
---|
| 474 | * @private
|
---|
| 475 | */
|
---|
| 476 | function info ( api )
|
---|
| 477 | {
|
---|
| 478 | var ctx = api.settings()[0];
|
---|
| 479 |
|
---|
| 480 | if ( ! ctx._select.info || ! ctx.aanFeatures.i ) {
|
---|
| 481 | return;
|
---|
| 482 | }
|
---|
| 483 |
|
---|
| 484 | if ( api.select.style() === 'api' ) {
|
---|
| 485 | return;
|
---|
| 486 | }
|
---|
| 487 |
|
---|
| 488 | var rows = api.rows( { selected: true } ).flatten().length;
|
---|
| 489 | var columns = api.columns( { selected: true } ).flatten().length;
|
---|
| 490 | var cells = api.cells( { selected: true } ).flatten().length;
|
---|
| 491 |
|
---|
| 492 | var add = function ( el, name, num ) {
|
---|
| 493 | el.append( $('<span class="select-item"/>').append( api.i18n(
|
---|
| 494 | 'select.'+name+'s',
|
---|
| 495 | { _: '%d '+name+'s selected', 0: '', 1: '1 '+name+' selected' },
|
---|
| 496 | num
|
---|
| 497 | ) ) );
|
---|
| 498 | };
|
---|
| 499 |
|
---|
| 500 | // Internal knowledge of DataTables to loop over all information elements
|
---|
| 501 | $.each( ctx.aanFeatures.i, function ( i, el ) {
|
---|
| 502 | el = $(el);
|
---|
| 503 |
|
---|
| 504 | var output = $('<span class="select-info"/>');
|
---|
| 505 | add( output, 'row', rows );
|
---|
| 506 | add( output, 'column', columns );
|
---|
| 507 | add( output, 'cell', cells );
|
---|
| 508 |
|
---|
| 509 | var exisiting = el.children('span.select-info');
|
---|
| 510 | if ( exisiting.length ) {
|
---|
| 511 | exisiting.remove();
|
---|
| 512 | }
|
---|
| 513 |
|
---|
| 514 | if ( output.text() !== '' ) {
|
---|
| 515 | el.append( output );
|
---|
| 516 | }
|
---|
| 517 | } );
|
---|
| 518 | }
|
---|
| 519 |
|
---|
| 520 | /**
|
---|
| 521 | * Initialisation of a new table. Attach event handlers and callbacks to allow
|
---|
| 522 | * Select to operate correctly.
|
---|
| 523 | *
|
---|
| 524 | * This will occur _after_ the initial DataTables initialisation, although
|
---|
| 525 | * before Ajax data is rendered, if there is ajax data
|
---|
| 526 | *
|
---|
| 527 | * @param {DataTable.settings} ctx Settings object to operate on
|
---|
| 528 | * @private
|
---|
| 529 | */
|
---|
| 530 | function init ( ctx ) {
|
---|
| 531 | var api = new DataTable.Api( ctx );
|
---|
| 532 |
|
---|
| 533 | // Row callback so that classes can be added to rows and cells if the item
|
---|
| 534 | // was selected before the element was created. This will happen with the
|
---|
| 535 | // `deferRender` option enabled.
|
---|
| 536 | //
|
---|
| 537 | // This method of attaching to `aoRowCreatedCallback` is a hack until
|
---|
| 538 | // DataTables has proper events for row manipulation If you are reviewing
|
---|
| 539 | // this code to create your own plug-ins, please do not do this!
|
---|
| 540 | ctx.aoRowCreatedCallback.push( {
|
---|
| 541 | fn: function ( row, data, index ) {
|
---|
| 542 | var i, ien;
|
---|
| 543 | var d = ctx.aoData[ index ];
|
---|
| 544 |
|
---|
| 545 | // Row
|
---|
| 546 | if ( d._select_selected ) {
|
---|
| 547 | $( row ).addClass( ctx._select.className );
|
---|
| 548 | }
|
---|
| 549 |
|
---|
| 550 | // Cells and columns - if separated out, we would need to do two
|
---|
| 551 | // loops, so it makes sense to combine them into a single one
|
---|
| 552 | for ( i=0, ien=ctx.aoColumns.length ; i<ien ; i++ ) {
|
---|
| 553 | if ( ctx.aoColumns[i]._select_selected || (d._selected_cells && d._selected_cells[i]) ) {
|
---|
| 554 | $(d.anCells[i]).addClass( ctx._select.className );
|
---|
| 555 | }
|
---|
| 556 | }
|
---|
| 557 | },
|
---|
| 558 | sName: 'select-deferRender'
|
---|
| 559 | } );
|
---|
| 560 |
|
---|
| 561 | // On Ajax reload we want to reselect all rows which are currently selected,
|
---|
| 562 | // if there is an rowId (i.e. a unique value to identify each row with)
|
---|
| 563 | api.on( 'preXhr.dt.dtSelect', function () {
|
---|
| 564 | // note that column selection doesn't need to be cached and then
|
---|
| 565 | // reselected, as they are already selected
|
---|
| 566 | var rows = api.rows( { selected: true } ).ids( true ).filter( function ( d ) {
|
---|
| 567 | return d !== undefined;
|
---|
| 568 | } );
|
---|
| 569 |
|
---|
| 570 | var cells = api.cells( { selected: true } ).eq(0).map( function ( cellIdx ) {
|
---|
| 571 | var id = api.row( cellIdx.row ).id( true );
|
---|
| 572 | return id ?
|
---|
| 573 | { row: id, column: cellIdx.column } :
|
---|
| 574 | undefined;
|
---|
| 575 | } ).filter( function ( d ) {
|
---|
| 576 | return d !== undefined;
|
---|
| 577 | } );
|
---|
| 578 |
|
---|
| 579 | // On the next draw, reselect the currently selected items
|
---|
| 580 | api.one( 'draw.dt.dtSelect', function () {
|
---|
| 581 | api.rows( rows ).select();
|
---|
| 582 |
|
---|
| 583 | // `cells` is not a cell index selector, so it needs a loop
|
---|
| 584 | if ( cells.any() ) {
|
---|
| 585 | cells.each( function ( id ) {
|
---|
| 586 | api.cells( id.row, id.column ).select();
|
---|
| 587 | } );
|
---|
| 588 | }
|
---|
| 589 | } );
|
---|
| 590 | } );
|
---|
| 591 |
|
---|
| 592 | // Update the table information element with selected item summary
|
---|
| 593 | api.on( 'draw.dtSelect.dt select.dtSelect.dt deselect.dtSelect.dt info.dt', function () {
|
---|
| 594 | info( api );
|
---|
| 595 | } );
|
---|
| 596 |
|
---|
| 597 | // Clean up and release
|
---|
| 598 | api.on( 'destroy.dtSelect', function () {
|
---|
| 599 | disableMouseSelection( api );
|
---|
| 600 | api.off( '.dtSelect' );
|
---|
| 601 | } );
|
---|
| 602 | }
|
---|
| 603 |
|
---|
| 604 | /**
|
---|
| 605 | * Add one or more items (rows or columns) to the selection when shift clicking
|
---|
| 606 | * in OS selection style
|
---|
| 607 | *
|
---|
| 608 | * @param {DataTable.Api} dt DataTable
|
---|
| 609 | * @param {string} type Row or column range selector
|
---|
| 610 | * @param {object} idx Item index to select to
|
---|
| 611 | * @param {object} last Item index to select from
|
---|
| 612 | * @private
|
---|
| 613 | */
|
---|
| 614 | function rowColumnRange( dt, type, idx, last )
|
---|
| 615 | {
|
---|
| 616 | // Add a range of rows from the last selected row to this one
|
---|
| 617 | var indexes = dt[type+'s']( { search: 'applied' } ).indexes();
|
---|
| 618 | var idx1 = $.inArray( last, indexes );
|
---|
| 619 | var idx2 = $.inArray( idx, indexes );
|
---|
| 620 |
|
---|
| 621 | if ( ! dt[type+'s']( { selected: true } ).any() && idx1 === -1 ) {
|
---|
| 622 | // select from top to here - slightly odd, but both Windows and Mac OS
|
---|
| 623 | // do this
|
---|
| 624 | indexes.splice( $.inArray( idx, indexes )+1, indexes.length );
|
---|
| 625 | }
|
---|
| 626 | else {
|
---|
| 627 | // reverse so we can shift click 'up' as well as down
|
---|
| 628 | if ( idx1 > idx2 ) {
|
---|
| 629 | var tmp = idx2;
|
---|
| 630 | idx2 = idx1;
|
---|
| 631 | idx1 = tmp;
|
---|
| 632 | }
|
---|
| 633 |
|
---|
| 634 | indexes.splice( idx2+1, indexes.length );
|
---|
| 635 | indexes.splice( 0, idx1 );
|
---|
| 636 | }
|
---|
| 637 |
|
---|
| 638 | if ( ! dt[type]( idx, { selected: true } ).any() ) {
|
---|
| 639 | // Select range
|
---|
| 640 | dt[type+'s']( indexes ).select();
|
---|
| 641 | }
|
---|
| 642 | else {
|
---|
| 643 | // Deselect range - need to keep the clicked on row selected
|
---|
| 644 | indexes.splice( $.inArray( idx, indexes ), 1 );
|
---|
| 645 | dt[type+'s']( indexes ).deselect();
|
---|
| 646 | }
|
---|
| 647 | }
|
---|
| 648 |
|
---|
| 649 | /**
|
---|
| 650 | * Clear all selected items
|
---|
| 651 | *
|
---|
| 652 | * @param {DataTable.settings} ctx Settings object of the host DataTable
|
---|
| 653 | * @param {boolean} [force=false] Force the de-selection to happen, regardless
|
---|
| 654 | * of selection style
|
---|
| 655 | * @private
|
---|
| 656 | */
|
---|
| 657 | function clear( ctx, force )
|
---|
| 658 | {
|
---|
| 659 | if ( force || ctx._select.style === 'single' ) {
|
---|
| 660 | var api = new DataTable.Api( ctx );
|
---|
| 661 |
|
---|
| 662 | api.rows( { selected: true } ).deselect();
|
---|
| 663 | api.columns( { selected: true } ).deselect();
|
---|
| 664 | api.cells( { selected: true } ).deselect();
|
---|
| 665 | }
|
---|
| 666 | }
|
---|
| 667 |
|
---|
| 668 | /**
|
---|
| 669 | * Select items based on the current configuration for style and items.
|
---|
| 670 | *
|
---|
| 671 | * @param {object} e Mouse event object
|
---|
| 672 | * @param {DataTables.Api} dt DataTable
|
---|
| 673 | * @param {DataTable.settings} ctx Settings object of the host DataTable
|
---|
| 674 | * @param {string} type Items to select
|
---|
| 675 | * @param {int|object} idx Index of the item to select
|
---|
| 676 | * @private
|
---|
| 677 | */
|
---|
| 678 | function typeSelect ( e, dt, ctx, type, idx )
|
---|
| 679 | {
|
---|
| 680 | var style = dt.select.style();
|
---|
| 681 | var toggleable = dt.select.toggleable();
|
---|
| 682 | var isSelected = dt[type]( idx, { selected: true } ).any();
|
---|
| 683 |
|
---|
| 684 | if ( isSelected && ! toggleable ) {
|
---|
| 685 | return;
|
---|
| 686 | }
|
---|
| 687 |
|
---|
| 688 | if ( style === 'os' ) {
|
---|
| 689 | if ( e.ctrlKey || e.metaKey ) {
|
---|
| 690 | // Add or remove from the selection
|
---|
| 691 | dt[type]( idx ).select( ! isSelected );
|
---|
| 692 | }
|
---|
| 693 | else if ( e.shiftKey ) {
|
---|
| 694 | if ( type === 'cell' ) {
|
---|
| 695 | cellRange( dt, idx, ctx._select_lastCell || null );
|
---|
| 696 | }
|
---|
| 697 | else {
|
---|
| 698 | rowColumnRange( dt, type, idx, ctx._select_lastCell ?
|
---|
| 699 | ctx._select_lastCell[type] :
|
---|
| 700 | null
|
---|
| 701 | );
|
---|
| 702 | }
|
---|
| 703 | }
|
---|
| 704 | else {
|
---|
| 705 | // No cmd or shift click - deselect if selected, or select
|
---|
| 706 | // this row only
|
---|
| 707 | var selected = dt[type+'s']( { selected: true } );
|
---|
| 708 |
|
---|
| 709 | if ( isSelected && selected.flatten().length === 1 ) {
|
---|
| 710 | dt[type]( idx ).deselect();
|
---|
| 711 | }
|
---|
| 712 | else {
|
---|
| 713 | selected.deselect();
|
---|
| 714 | dt[type]( idx ).select();
|
---|
| 715 | }
|
---|
| 716 | }
|
---|
| 717 | } else if ( style == 'multi+shift' ) {
|
---|
| 718 | if ( e.shiftKey ) {
|
---|
| 719 | if ( type === 'cell' ) {
|
---|
| 720 | cellRange( dt, idx, ctx._select_lastCell || null );
|
---|
| 721 | }
|
---|
| 722 | else {
|
---|
| 723 | rowColumnRange( dt, type, idx, ctx._select_lastCell ?
|
---|
| 724 | ctx._select_lastCell[type] :
|
---|
| 725 | null
|
---|
| 726 | );
|
---|
| 727 | }
|
---|
| 728 | }
|
---|
| 729 | else {
|
---|
| 730 | dt[ type ]( idx ).select( ! isSelected );
|
---|
| 731 | }
|
---|
| 732 | }
|
---|
| 733 | else {
|
---|
| 734 | dt[ type ]( idx ).select( ! isSelected );
|
---|
| 735 | }
|
---|
| 736 | }
|
---|
| 737 |
|
---|
| 738 | function _safeId( node ) {
|
---|
| 739 | return node.id.replace(/[^a-zA-Z0-9\-\_]/g, '-');
|
---|
| 740 | }
|
---|
| 741 |
|
---|
| 742 |
|
---|
| 743 |
|
---|
| 744 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
---|
| 745 | * DataTables selectors
|
---|
| 746 | */
|
---|
| 747 |
|
---|
| 748 | // row and column are basically identical just assigned to different properties
|
---|
| 749 | // and checking a different array, so we can dynamically create the functions to
|
---|
| 750 | // reduce the code size
|
---|
| 751 | $.each( [
|
---|
| 752 | { type: 'row', prop: 'aoData' },
|
---|
| 753 | { type: 'column', prop: 'aoColumns' }
|
---|
| 754 | ], function ( i, o ) {
|
---|
| 755 | DataTable.ext.selector[ o.type ].push( function ( settings, opts, indexes ) {
|
---|
| 756 | var selected = opts.selected;
|
---|
| 757 | var data;
|
---|
| 758 | var out = [];
|
---|
| 759 |
|
---|
| 760 | if ( selected !== true && selected !== false ) {
|
---|
| 761 | return indexes;
|
---|
| 762 | }
|
---|
| 763 |
|
---|
| 764 | for ( var i=0, ien=indexes.length ; i<ien ; i++ ) {
|
---|
| 765 | data = settings[ o.prop ][ indexes[i] ];
|
---|
| 766 |
|
---|
| 767 | if ( (selected === true && data._select_selected === true) ||
|
---|
| 768 | (selected === false && ! data._select_selected )
|
---|
| 769 | ) {
|
---|
| 770 | out.push( indexes[i] );
|
---|
| 771 | }
|
---|
| 772 | }
|
---|
| 773 |
|
---|
| 774 | return out;
|
---|
| 775 | } );
|
---|
| 776 | } );
|
---|
| 777 |
|
---|
| 778 | DataTable.ext.selector.cell.push( function ( settings, opts, cells ) {
|
---|
| 779 | var selected = opts.selected;
|
---|
| 780 | var rowData;
|
---|
| 781 | var out = [];
|
---|
| 782 |
|
---|
| 783 | if ( selected === undefined ) {
|
---|
| 784 | return cells;
|
---|
| 785 | }
|
---|
| 786 |
|
---|
| 787 | for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
|
---|
| 788 | rowData = settings.aoData[ cells[i].row ];
|
---|
| 789 |
|
---|
| 790 | if ( (selected === true && rowData._selected_cells && rowData._selected_cells[ cells[i].column ] === true) ||
|
---|
| 791 | (selected === false && ( ! rowData._selected_cells || ! rowData._selected_cells[ cells[i].column ] ) )
|
---|
| 792 | ) {
|
---|
| 793 | out.push( cells[i] );
|
---|
| 794 | }
|
---|
| 795 | }
|
---|
| 796 |
|
---|
| 797 | return out;
|
---|
| 798 | } );
|
---|
| 799 |
|
---|
| 800 |
|
---|
| 801 |
|
---|
| 802 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
---|
| 803 | * DataTables API
|
---|
| 804 | *
|
---|
| 805 | * For complete documentation, please refer to the docs/api directory or the
|
---|
| 806 | * DataTables site
|
---|
| 807 | */
|
---|
| 808 |
|
---|
| 809 | // Local variables to improve compression
|
---|
| 810 | var apiRegister = DataTable.Api.register;
|
---|
| 811 | var apiRegisterPlural = DataTable.Api.registerPlural;
|
---|
| 812 |
|
---|
| 813 | apiRegister( 'select()', function () {
|
---|
| 814 | return this.iterator( 'table', function ( ctx ) {
|
---|
| 815 | DataTable.select.init( new DataTable.Api( ctx ) );
|
---|
| 816 | } );
|
---|
| 817 | } );
|
---|
| 818 |
|
---|
| 819 | apiRegister( 'select.blurable()', function ( flag ) {
|
---|
| 820 | if ( flag === undefined ) {
|
---|
| 821 | return this.context[0]._select.blurable;
|
---|
| 822 | }
|
---|
| 823 |
|
---|
| 824 | return this.iterator( 'table', function ( ctx ) {
|
---|
| 825 | ctx._select.blurable = flag;
|
---|
| 826 | } );
|
---|
| 827 | } );
|
---|
| 828 |
|
---|
| 829 | apiRegister( 'select.toggleable()', function ( flag ) {
|
---|
| 830 | if ( flag === undefined ) {
|
---|
| 831 | return this.context[0]._select.toggleable;
|
---|
| 832 | }
|
---|
| 833 |
|
---|
| 834 | return this.iterator( 'table', function ( ctx ) {
|
---|
| 835 | ctx._select.toggleable = flag;
|
---|
| 836 | } );
|
---|
| 837 | } );
|
---|
| 838 |
|
---|
| 839 | apiRegister( 'select.info()', function ( flag ) {
|
---|
| 840 | if ( info === undefined ) {
|
---|
| 841 | return this.context[0]._select.info;
|
---|
| 842 | }
|
---|
| 843 |
|
---|
| 844 | return this.iterator( 'table', function ( ctx ) {
|
---|
| 845 | ctx._select.info = flag;
|
---|
| 846 | } );
|
---|
| 847 | } );
|
---|
| 848 |
|
---|
| 849 | apiRegister( 'select.items()', function ( items ) {
|
---|
| 850 | if ( items === undefined ) {
|
---|
| 851 | return this.context[0]._select.items;
|
---|
| 852 | }
|
---|
| 853 |
|
---|
| 854 | return this.iterator( 'table', function ( ctx ) {
|
---|
| 855 | ctx._select.items = items;
|
---|
| 856 |
|
---|
| 857 | eventTrigger( new DataTable.Api( ctx ), 'selectItems', [ items ] );
|
---|
| 858 | } );
|
---|
| 859 | } );
|
---|
| 860 |
|
---|
| 861 | // Takes effect from the _next_ selection. None disables future selection, but
|
---|
| 862 | // does not clear the current selection. Use the `deselect` methods for that
|
---|
| 863 | apiRegister( 'select.style()', function ( style ) {
|
---|
| 864 | if ( style === undefined ) {
|
---|
| 865 | return this.context[0]._select.style;
|
---|
| 866 | }
|
---|
| 867 |
|
---|
| 868 | return this.iterator( 'table', function ( ctx ) {
|
---|
| 869 | ctx._select.style = style;
|
---|
| 870 |
|
---|
| 871 | if ( ! ctx._select_init ) {
|
---|
| 872 | init( ctx );
|
---|
| 873 | }
|
---|
| 874 |
|
---|
| 875 | // Add / remove mouse event handlers. They aren't required when only
|
---|
| 876 | // API selection is available
|
---|
| 877 | var dt = new DataTable.Api( ctx );
|
---|
| 878 | disableMouseSelection( dt );
|
---|
| 879 |
|
---|
| 880 | if ( style !== 'api' ) {
|
---|
| 881 | enableMouseSelection( dt );
|
---|
| 882 | }
|
---|
| 883 |
|
---|
| 884 | eventTrigger( new DataTable.Api( ctx ), 'selectStyle', [ style ] );
|
---|
| 885 | } );
|
---|
| 886 | } );
|
---|
| 887 |
|
---|
| 888 | apiRegister( 'select.selector()', function ( selector ) {
|
---|
| 889 | if ( selector === undefined ) {
|
---|
| 890 | return this.context[0]._select.selector;
|
---|
| 891 | }
|
---|
| 892 |
|
---|
| 893 | return this.iterator( 'table', function ( ctx ) {
|
---|
| 894 | disableMouseSelection( new DataTable.Api( ctx ) );
|
---|
| 895 |
|
---|
| 896 | ctx._select.selector = selector;
|
---|
| 897 |
|
---|
| 898 | if ( ctx._select.style !== 'api' ) {
|
---|
| 899 | enableMouseSelection( new DataTable.Api( ctx ) );
|
---|
| 900 | }
|
---|
| 901 | } );
|
---|
| 902 | } );
|
---|
| 903 |
|
---|
| 904 |
|
---|
| 905 |
|
---|
| 906 | apiRegisterPlural( 'rows().select()', 'row().select()', function ( select ) {
|
---|
| 907 | var api = this;
|
---|
| 908 |
|
---|
| 909 | if ( select === false ) {
|
---|
| 910 | return this.deselect();
|
---|
| 911 | }
|
---|
| 912 |
|
---|
| 913 | this.iterator( 'row', function ( ctx, idx ) {
|
---|
| 914 | clear( ctx );
|
---|
| 915 |
|
---|
| 916 | ctx.aoData[ idx ]._select_selected = true;
|
---|
| 917 | $( ctx.aoData[ idx ].nTr ).addClass( ctx._select.className );
|
---|
| 918 | } );
|
---|
| 919 |
|
---|
| 920 | this.iterator( 'table', function ( ctx, i ) {
|
---|
| 921 | eventTrigger( api, 'select', [ 'row', api[i] ], true );
|
---|
| 922 | } );
|
---|
| 923 |
|
---|
| 924 | return this;
|
---|
| 925 | } );
|
---|
| 926 |
|
---|
| 927 | apiRegisterPlural( 'columns().select()', 'column().select()', function ( select ) {
|
---|
| 928 | var api = this;
|
---|
| 929 |
|
---|
| 930 | if ( select === false ) {
|
---|
| 931 | return this.deselect();
|
---|
| 932 | }
|
---|
| 933 |
|
---|
| 934 | this.iterator( 'column', function ( ctx, idx ) {
|
---|
| 935 | clear( ctx );
|
---|
| 936 |
|
---|
| 937 | ctx.aoColumns[ idx ]._select_selected = true;
|
---|
| 938 |
|
---|
| 939 | var column = new DataTable.Api( ctx ).column( idx );
|
---|
| 940 |
|
---|
| 941 | $( column.header() ).addClass( ctx._select.className );
|
---|
| 942 | $( column.footer() ).addClass( ctx._select.className );
|
---|
| 943 |
|
---|
| 944 | column.nodes().to$().addClass( ctx._select.className );
|
---|
| 945 | } );
|
---|
| 946 |
|
---|
| 947 | this.iterator( 'table', function ( ctx, i ) {
|
---|
| 948 | eventTrigger( api, 'select', [ 'column', api[i] ], true );
|
---|
| 949 | } );
|
---|
| 950 |
|
---|
| 951 | return this;
|
---|
| 952 | } );
|
---|
| 953 |
|
---|
| 954 | apiRegisterPlural( 'cells().select()', 'cell().select()', function ( select ) {
|
---|
| 955 | var api = this;
|
---|
| 956 |
|
---|
| 957 | if ( select === false ) {
|
---|
| 958 | return this.deselect();
|
---|
| 959 | }
|
---|
| 960 |
|
---|
| 961 | this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {
|
---|
| 962 | clear( ctx );
|
---|
| 963 |
|
---|
| 964 | var data = ctx.aoData[ rowIdx ];
|
---|
| 965 |
|
---|
| 966 | if ( data._selected_cells === undefined ) {
|
---|
| 967 | data._selected_cells = [];
|
---|
| 968 | }
|
---|
| 969 |
|
---|
| 970 | data._selected_cells[ colIdx ] = true;
|
---|
| 971 |
|
---|
| 972 | if ( data.anCells ) {
|
---|
| 973 | $( data.anCells[ colIdx ] ).addClass( ctx._select.className );
|
---|
| 974 | }
|
---|
| 975 | } );
|
---|
| 976 |
|
---|
| 977 | this.iterator( 'table', function ( ctx, i ) {
|
---|
| 978 | eventTrigger( api, 'select', [ 'cell', api[i] ], true );
|
---|
| 979 | } );
|
---|
| 980 |
|
---|
| 981 | return this;
|
---|
| 982 | } );
|
---|
| 983 |
|
---|
| 984 |
|
---|
| 985 | apiRegisterPlural( 'rows().deselect()', 'row().deselect()', function () {
|
---|
| 986 | var api = this;
|
---|
| 987 |
|
---|
| 988 | this.iterator( 'row', function ( ctx, idx ) {
|
---|
| 989 | ctx.aoData[ idx ]._select_selected = false;
|
---|
| 990 | $( ctx.aoData[ idx ].nTr ).removeClass( ctx._select.className );
|
---|
| 991 | } );
|
---|
| 992 |
|
---|
| 993 | this.iterator( 'table', function ( ctx, i ) {
|
---|
| 994 | eventTrigger( api, 'deselect', [ 'row', api[i] ], true );
|
---|
| 995 | } );
|
---|
| 996 |
|
---|
| 997 | return this;
|
---|
| 998 | } );
|
---|
| 999 |
|
---|
| 1000 | apiRegisterPlural( 'columns().deselect()', 'column().deselect()', function () {
|
---|
| 1001 | var api = this;
|
---|
| 1002 |
|
---|
| 1003 | this.iterator( 'column', function ( ctx, idx ) {
|
---|
| 1004 | ctx.aoColumns[ idx ]._select_selected = false;
|
---|
| 1005 |
|
---|
| 1006 | var api = new DataTable.Api( ctx );
|
---|
| 1007 | var column = api.column( idx );
|
---|
| 1008 |
|
---|
| 1009 | $( column.header() ).removeClass( ctx._select.className );
|
---|
| 1010 | $( column.footer() ).removeClass( ctx._select.className );
|
---|
| 1011 |
|
---|
| 1012 | // Need to loop over each cell, rather than just using
|
---|
| 1013 | // `column().nodes()` as cells which are individually selected should
|
---|
| 1014 | // not have the `selected` class removed from them
|
---|
| 1015 | api.cells( null, idx ).indexes().each( function (cellIdx) {
|
---|
| 1016 | var data = ctx.aoData[ cellIdx.row ];
|
---|
| 1017 | var cellSelected = data._selected_cells;
|
---|
| 1018 |
|
---|
| 1019 | if ( data.anCells && (! cellSelected || ! cellSelected[ cellIdx.column ]) ) {
|
---|
| 1020 | $( data.anCells[ cellIdx.column ] ).removeClass( ctx._select.className );
|
---|
| 1021 | }
|
---|
| 1022 | } );
|
---|
| 1023 | } );
|
---|
| 1024 |
|
---|
| 1025 | this.iterator( 'table', function ( ctx, i ) {
|
---|
| 1026 | eventTrigger( api, 'deselect', [ 'column', api[i] ], true );
|
---|
| 1027 | } );
|
---|
| 1028 |
|
---|
| 1029 | return this;
|
---|
| 1030 | } );
|
---|
| 1031 |
|
---|
| 1032 | apiRegisterPlural( 'cells().deselect()', 'cell().deselect()', function () {
|
---|
| 1033 | var api = this;
|
---|
| 1034 |
|
---|
| 1035 | this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {
|
---|
| 1036 | var data = ctx.aoData[ rowIdx ];
|
---|
| 1037 |
|
---|
| 1038 | data._selected_cells[ colIdx ] = false;
|
---|
| 1039 |
|
---|
| 1040 | // Remove class only if the cells exist, and the cell is not column
|
---|
| 1041 | // selected, in which case the class should remain (since it is selected
|
---|
| 1042 | // in the column)
|
---|
| 1043 | if ( data.anCells && ! ctx.aoColumns[ colIdx ]._select_selected ) {
|
---|
| 1044 | $( data.anCells[ colIdx ] ).removeClass( ctx._select.className );
|
---|
| 1045 | }
|
---|
| 1046 | } );
|
---|
| 1047 |
|
---|
| 1048 | this.iterator( 'table', function ( ctx, i ) {
|
---|
| 1049 | eventTrigger( api, 'deselect', [ 'cell', api[i] ], true );
|
---|
| 1050 | } );
|
---|
| 1051 |
|
---|
| 1052 | return this;
|
---|
| 1053 | } );
|
---|
| 1054 |
|
---|
| 1055 |
|
---|
| 1056 |
|
---|
| 1057 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
---|
| 1058 | * Buttons
|
---|
| 1059 | */
|
---|
| 1060 | function i18n( label, def ) {
|
---|
| 1061 | return function (dt) {
|
---|
| 1062 | return dt.i18n( 'buttons.'+label, def );
|
---|
| 1063 | };
|
---|
| 1064 | }
|
---|
| 1065 |
|
---|
| 1066 | // Common events with suitable namespaces
|
---|
| 1067 | function namespacedEvents ( config ) {
|
---|
| 1068 | var unique = config._eventNamespace;
|
---|
| 1069 |
|
---|
| 1070 | return 'draw.dt.DT'+unique+' select.dt.DT'+unique+' deselect.dt.DT'+unique;
|
---|
| 1071 | }
|
---|
| 1072 |
|
---|
| 1073 | function enabled ( dt, config ) {
|
---|
| 1074 | if ( $.inArray( 'rows', config.limitTo ) !== -1 && dt.rows( { selected: true } ).any() ) {
|
---|
| 1075 | return true;
|
---|
| 1076 | }
|
---|
| 1077 |
|
---|
| 1078 | if ( $.inArray( 'columns', config.limitTo ) !== -1 && dt.columns( { selected: true } ).any() ) {
|
---|
| 1079 | return true;
|
---|
| 1080 | }
|
---|
| 1081 |
|
---|
| 1082 | if ( $.inArray( 'cells', config.limitTo ) !== -1 && dt.cells( { selected: true } ).any() ) {
|
---|
| 1083 | return true;
|
---|
| 1084 | }
|
---|
| 1085 |
|
---|
| 1086 | return false;
|
---|
| 1087 | }
|
---|
| 1088 |
|
---|
| 1089 | var _buttonNamespace = 0;
|
---|
| 1090 |
|
---|
| 1091 | $.extend( DataTable.ext.buttons, {
|
---|
| 1092 | selected: {
|
---|
| 1093 | text: i18n( 'selected', 'Selected' ),
|
---|
| 1094 | className: 'buttons-selected',
|
---|
| 1095 | limitTo: [ 'rows', 'columns', 'cells' ],
|
---|
| 1096 | init: function ( dt, node, config ) {
|
---|
| 1097 | var that = this;
|
---|
| 1098 | config._eventNamespace = '.select'+(_buttonNamespace++);
|
---|
| 1099 |
|
---|
| 1100 | // .DT namespace listeners are removed by DataTables automatically
|
---|
| 1101 | // on table destroy
|
---|
| 1102 | dt.on( namespacedEvents(config), function () {
|
---|
| 1103 | that.enable( enabled(dt, config) );
|
---|
| 1104 | } );
|
---|
| 1105 |
|
---|
| 1106 | this.disable();
|
---|
| 1107 | },
|
---|
| 1108 | destroy: function ( dt, node, config ) {
|
---|
| 1109 | dt.off( config._eventNamespace );
|
---|
| 1110 | }
|
---|
| 1111 | },
|
---|
| 1112 | selectedSingle: {
|
---|
| 1113 | text: i18n( 'selectedSingle', 'Selected single' ),
|
---|
| 1114 | className: 'buttons-selected-single',
|
---|
| 1115 | init: function ( dt, node, config ) {
|
---|
| 1116 | var that = this;
|
---|
| 1117 | config._eventNamespace = '.select'+(_buttonNamespace++);
|
---|
| 1118 |
|
---|
| 1119 | dt.on( namespacedEvents(config), function () {
|
---|
| 1120 | var count = dt.rows( { selected: true } ).flatten().length +
|
---|
| 1121 | dt.columns( { selected: true } ).flatten().length +
|
---|
| 1122 | dt.cells( { selected: true } ).flatten().length;
|
---|
| 1123 |
|
---|
| 1124 | that.enable( count === 1 );
|
---|
| 1125 | } );
|
---|
| 1126 |
|
---|
| 1127 | this.disable();
|
---|
| 1128 | },
|
---|
| 1129 | destroy: function ( dt, node, config ) {
|
---|
| 1130 | dt.off( config._eventNamespace );
|
---|
| 1131 | }
|
---|
| 1132 | },
|
---|
| 1133 | selectAll: {
|
---|
| 1134 | text: i18n( 'selectAll', 'Select all' ),
|
---|
| 1135 | className: 'buttons-select-all',
|
---|
| 1136 | action: function () {
|
---|
| 1137 | var items = this.select.items();
|
---|
| 1138 | this[ items+'s' ]().select();
|
---|
| 1139 | }
|
---|
| 1140 | },
|
---|
| 1141 | selectNone: {
|
---|
| 1142 | text: i18n( 'selectNone', 'Deselect all' ),
|
---|
| 1143 | className: 'buttons-select-none',
|
---|
| 1144 | action: function () {
|
---|
| 1145 | clear( this.settings()[0], true );
|
---|
| 1146 | },
|
---|
| 1147 | init: function ( dt, node, config ) {
|
---|
| 1148 | var that = this;
|
---|
| 1149 | config._eventNamespace = '.select'+(_buttonNamespace++);
|
---|
| 1150 |
|
---|
| 1151 | dt.on( namespacedEvents(config), function () {
|
---|
| 1152 | var count = dt.rows( { selected: true } ).flatten().length +
|
---|
| 1153 | dt.columns( { selected: true } ).flatten().length +
|
---|
| 1154 | dt.cells( { selected: true } ).flatten().length;
|
---|
| 1155 |
|
---|
| 1156 | that.enable( count > 0 );
|
---|
| 1157 | } );
|
---|
| 1158 |
|
---|
| 1159 | this.disable();
|
---|
| 1160 | },
|
---|
| 1161 | destroy: function ( dt, node, config ) {
|
---|
| 1162 | dt.off( config._eventNamespace );
|
---|
| 1163 | }
|
---|
| 1164 | }
|
---|
| 1165 | } );
|
---|
| 1166 |
|
---|
| 1167 | $.each( [ 'Row', 'Column', 'Cell' ], function ( i, item ) {
|
---|
| 1168 | var lc = item.toLowerCase();
|
---|
| 1169 |
|
---|
| 1170 | DataTable.ext.buttons[ 'select'+item+'s' ] = {
|
---|
| 1171 | text: i18n( 'select'+item+'s', 'Select '+lc+'s' ),
|
---|
| 1172 | className: 'buttons-select-'+lc+'s',
|
---|
| 1173 | action: function () {
|
---|
| 1174 | this.select.items( lc );
|
---|
| 1175 | },
|
---|
| 1176 | init: function ( dt ) {
|
---|
| 1177 | var that = this;
|
---|
| 1178 |
|
---|
| 1179 | dt.on( 'selectItems.dt.DT', function ( e, ctx, items ) {
|
---|
| 1180 | that.active( items === lc );
|
---|
| 1181 | } );
|
---|
| 1182 | }
|
---|
| 1183 | };
|
---|
| 1184 | } );
|
---|
| 1185 |
|
---|
| 1186 |
|
---|
| 1187 |
|
---|
| 1188 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
---|
| 1189 | * Initialisation
|
---|
| 1190 | */
|
---|
| 1191 |
|
---|
| 1192 | // DataTables creation - check if select has been defined in the options. Note
|
---|
| 1193 | // this required that the table be in the document! If it isn't then something
|
---|
| 1194 | // needs to trigger this method unfortunately. The next major release of
|
---|
| 1195 | // DataTables will rework the events and address this.
|
---|
| 1196 | $(document).on( 'preInit.dt.dtSelect', function (e, ctx) {
|
---|
| 1197 | if ( e.namespace !== 'dt' ) {
|
---|
| 1198 | return;
|
---|
| 1199 | }
|
---|
| 1200 |
|
---|
| 1201 | DataTable.select.init( new DataTable.Api( ctx ) );
|
---|
| 1202 | } );
|
---|
| 1203 |
|
---|
| 1204 |
|
---|
| 1205 | return DataTable.select;
|
---|
| 1206 | }));
|
---|