source: public/vendors/dataTable/Select-1.3.1/js/dataTables.select.js@ bbcbb57

develop
Last change on this file since bbcbb57 was 7304c7f, checked in by beratkjufliju <kufliju@…>, 3 years ago

added user authentication, create & forgot password methods and blades

  • Property mode set to 100644
File size: 31.8 KB
Line 
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';
51var DataTable = $.fn.dataTable;
52
53
54// Version information for debugger
55DataTable.select = {};
56
57DataTable.select.version = '1.3.1';
58
59DataTable.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
153Select is a collection of API methods, event handlers, event emitters and
154buttons (for the `Buttons` extension) for DataTables. It provides the following
155features, 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
168This method of using boolean flags allows Select to operate when nodes have not
169been created for rows / cells (DataTables' defer rendering feature).
170
171## API methods
172
173A range of API methods are available for triggering selection and de-selection
174of rows. Methods are also available to configure the selection events that can
175be triggered by an end user (such as which items are to be selected). To a large
176extent, these of API methods *is* Select. It is basically a collection of helper
177functions that can be used to select items in a DataTable.
178
179Configuration of select is held in the object `_select` which is attached to the
180DataTables settings object on initialisation. Select being available on a table
181is not optional when Select is loaded, but its default is for selection only to
182be available via the API - so the end user wouldn't be able to select rows
183without additional configuration.
184
185The `_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
203In addition to the API methods, Select also extends the DataTables selector
204options for rows, columns and cells adding a `selected` option to the selector
205options object, allowing the developer to select only selected items or
206unselected items.
207
208## Mouse selection of items
209
210Clicking on items can be used to select items. This is done by a simple event
211handler 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 */
234function 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 */
315function 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 */
334function 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 */
454function 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 */
476function 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 */
530function 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 */
614function 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 */
657function 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 */
678function 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
738function _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
778DataTable.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
810var apiRegister = DataTable.Api.register;
811var apiRegisterPlural = DataTable.Api.registerPlural;
812
813apiRegister( 'select()', function () {
814 return this.iterator( 'table', function ( ctx ) {
815 DataTable.select.init( new DataTable.Api( ctx ) );
816 } );
817} );
818
819apiRegister( '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
829apiRegister( '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
839apiRegister( '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
849apiRegister( '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
863apiRegister( '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
888apiRegister( '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
906apiRegisterPlural( '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
927apiRegisterPlural( '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
954apiRegisterPlural( '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
985apiRegisterPlural( '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
1000apiRegisterPlural( '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
1032apiRegisterPlural( '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 */
1060function i18n( label, def ) {
1061 return function (dt) {
1062 return dt.i18n( 'buttons.'+label, def );
1063 };
1064}
1065
1066// Common events with suitable namespaces
1067function namespacedEvents ( config ) {
1068 var unique = config._eventNamespace;
1069
1070 return 'draw.dt.DT'+unique+' select.dt.DT'+unique+' deselect.dt.DT'+unique;
1071}
1072
1073function 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
1089var _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
1205return DataTable.select;
1206}));
Note: See TracBrowser for help on using the repository browser.