From 0225bdb772d1334cc1aa7ab0fc3678df0864df6b Mon Sep 17 00:00:00 2001 From: AlisaLinUwU Date: Sun, 26 Jan 2025 10:42:28 +0500 Subject: Initialize --- .../datatables-select/js/dataTables.select.js | 1265 ++++++++++++++++++++ 1 file changed, 1265 insertions(+) create mode 100644 build/resources/main/static/plugins/datatables-select/js/dataTables.select.js (limited to 'build/resources/main/static/plugins/datatables-select/js/dataTables.select.js') diff --git a/build/resources/main/static/plugins/datatables-select/js/dataTables.select.js b/build/resources/main/static/plugins/datatables-select/js/dataTables.select.js new file mode 100644 index 0000000..737fbec --- /dev/null +++ b/build/resources/main/static/plugins/datatables-select/js/dataTables.select.js @@ -0,0 +1,1265 @@ +/*! Select for DataTables 1.3.4-dev + * 2015-2021 SpryMedia Ltd - datatables.net/license/mit + */ + +/** + * @summary Select for DataTables + * @description A collection of API methods, events and buttons for DataTables + * that provides selection options of the items in a DataTable + * @version 1.3.4-dev + * @file dataTables.select.js + * @author SpryMedia Ltd (www.sprymedia.co.uk) + * @contact datatables.net/forums + * @copyright Copyright 2015-2021 SpryMedia Ltd. + * + * This source file is free software, available under the following license: + * MIT license - http://datatables.net/license/mit + * + * This source file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. + * + * For details please refer to: http://www.datatables.net/extensions/select + */ +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + root = window; + } + + if ( ! $ || ! $.fn.dataTable ) { + $ = require('datatables.net')(root, $).$; + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + + +// Version information for debugger +DataTable.select = {}; + +DataTable.select.version = '1.3.4-dev'; + +DataTable.select.init = function ( dt ) { + var ctx = dt.settings()[0]; + + if (ctx._select) { + return; + } + + var savedSelected = dt.state.loaded(); + + var selectAndSave = function(e, settings, data) { + if(data === null || data.select === undefined) { + return; + } + dt.rows().deselect(); + dt.columns().deselect(); + dt.cells().deselect(); + if (data.select.rows !== undefined) { + dt.rows(data.select.rows).select(); + } + if (data.select.columns !== undefined) { + dt.columns(data.select.columns).select(); + } + if (data.select.cells !== undefined) { + for(var i = 0; i < data.select.cells.length; i++) { + dt.cell(data.select.cells[i].row, data.select.cells[i].column).select(); + } + } + dt.state.save(); + } + + dt.one('init', function() { + dt.on('stateSaveParams', function(e, settings, data) { + data.select = {}; + data.select.rows = dt.rows({selected:true}).ids(true).toArray(); + data.select.columns = dt.columns({selected:true})[0]; + data.select.cells = dt.cells({selected:true})[0].map(function(coords) { + return {row: dt.row(coords.row).id(true), column: coords.column} + }); + }) + + selectAndSave(undefined, undefined, savedSelected) + dt.on('stateLoaded stateLoadParams', selectAndSave) + }) + + var init = ctx.oInit.select; + var defaults = DataTable.defaults.select; + var opts = init === undefined ? + defaults : + init; + + // Set defaults + var items = 'row'; + var style = 'api'; + var blurable = false; + var toggleable = true; + var info = true; + var selector = 'td, th'; + var className = 'selected'; + var setStyle = false; + + ctx._select = {}; + + // Initialisation customisations + if ( opts === true ) { + style = 'os'; + setStyle = true; + } + else if ( typeof opts === 'string' ) { + style = opts; + setStyle = true; + } + else if ( $.isPlainObject( opts ) ) { + if ( opts.blurable !== undefined ) { + blurable = opts.blurable; + } + + if ( opts.toggleable !== undefined ) { + toggleable = opts.toggleable; + } + + if ( opts.info !== undefined ) { + info = opts.info; + } + + if ( opts.items !== undefined ) { + items = opts.items; + } + + if ( opts.style !== undefined ) { + style = opts.style; + setStyle = true; + } + else { + style = 'os'; + setStyle = true; + } + + if ( opts.selector !== undefined ) { + selector = opts.selector; + } + + if ( opts.className !== undefined ) { + className = opts.className; + } + } + + dt.select.selector( selector ); + dt.select.items( items ); + dt.select.style( style ); + dt.select.blurable( blurable ); + dt.select.toggleable( toggleable ); + dt.select.info( info ); + ctx._select.className = className; + + + // Sort table based on selected rows. Requires Select Datatables extension + $.fn.dataTable.ext.order['select-checkbox'] = function ( settings, col ) { + return this.api().column( col, {order: 'index'} ).nodes().map( function ( td ) { + if ( settings._select.items === 'row' ) { + return $( td ).parent().hasClass( settings._select.className ); + } else if ( settings._select.items === 'cell' ) { + return $( td ).hasClass( settings._select.className ); + } + return false; + }); + }; + + // If the init options haven't enabled select, but there is a selectable + // class name, then enable + if ( ! setStyle && $( dt.table().node() ).hasClass( 'selectable' ) ) { + dt.select.style( 'os' ); + } +}; + +/* + +Select is a collection of API methods, event handlers, event emitters and +buttons (for the `Buttons` extension) for DataTables. It provides the following +features, with an overview of how they are implemented: + +## Selection of rows, columns and cells. Whether an item is selected or not is + stored in: + +* rows: a `_select_selected` property which contains a boolean value of the + DataTables' `aoData` object for each row +* columns: a `_select_selected` property which contains a boolean value of the + DataTables' `aoColumns` object for each column +* cells: a `_selected_cells` property which contains an array of boolean values + of the `aoData` object for each row. The array is the same length as the + columns array, with each element of it representing a cell. + +This method of using boolean flags allows Select to operate when nodes have not +been created for rows / cells (DataTables' defer rendering feature). + +## API methods + +A range of API methods are available for triggering selection and de-selection +of rows. Methods are also available to configure the selection events that can +be triggered by an end user (such as which items are to be selected). To a large +extent, these of API methods *is* Select. It is basically a collection of helper +functions that can be used to select items in a DataTable. + +Configuration of select is held in the object `_select` which is attached to the +DataTables settings object on initialisation. Select being available on a table +is not optional when Select is loaded, but its default is for selection only to +be available via the API - so the end user wouldn't be able to select rows +without additional configuration. + +The `_select` object contains the following properties: + +``` +{ + items:string - Can be `rows`, `columns` or `cells`. Defines what item + will be selected if the user is allowed to activate row + selection using the mouse. + style:string - Can be `none`, `single`, `multi` or `os`. Defines the + interaction style when selecting items + blurable:boolean - If row selection can be cleared by clicking outside of + the table + toggleable:boolean - If row selection can be cancelled by repeated clicking + on the row + info:boolean - If the selection summary should be shown in the table + information elements +} +``` + +In addition to the API methods, Select also extends the DataTables selector +options for rows, columns and cells adding a `selected` option to the selector +options object, allowing the developer to select only selected items or +unselected items. + +## Mouse selection of items + +Clicking on items can be used to select items. This is done by a simple event +handler that will select the items using the API methods. + + */ + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Local functions + */ + +/** + * Add one or more cells to the selection when shift clicking in OS selection + * style cell selection. + * + * Cell range is more complicated than row and column as we want to select + * in the visible grid rather than by index in sequence. For example, if you + * click first in cell 1-1 and then shift click in 2-2 - cells 1-2 and 2-1 + * should also be selected (and not 1-3, 1-4. etc) + * + * @param {DataTable.Api} dt DataTable + * @param {object} idx Cell index to select to + * @param {object} last Cell index to select from + * @private + */ +function cellRange( dt, idx, last ) +{ + var indexes; + var columnIndexes; + var rowIndexes; + var selectColumns = function ( start, end ) { + if ( start > end ) { + var tmp = end; + end = start; + start = tmp; + } + + var record = false; + return dt.columns( ':visible' ).indexes().filter( function (i) { + if ( i === start ) { + record = true; + } + + if ( i === end ) { // not else if, as start might === end + record = false; + return true; + } + + return record; + } ); + }; + + var selectRows = function ( start, end ) { + var indexes = dt.rows( { search: 'applied' } ).indexes(); + + // Which comes first - might need to swap + if ( indexes.indexOf( start ) > indexes.indexOf( end ) ) { + var tmp = end; + end = start; + start = tmp; + } + + var record = false; + return indexes.filter( function (i) { + if ( i === start ) { + record = true; + } + + if ( i === end ) { + record = false; + return true; + } + + return record; + } ); + }; + + if ( ! dt.cells( { selected: true } ).any() && ! last ) { + // select from the top left cell to this one + columnIndexes = selectColumns( 0, idx.column ); + rowIndexes = selectRows( 0 , idx.row ); + } + else { + // Get column indexes between old and new + columnIndexes = selectColumns( last.column, idx.column ); + rowIndexes = selectRows( last.row , idx.row ); + } + + indexes = dt.cells( rowIndexes, columnIndexes ).flatten(); + + if ( ! dt.cells( idx, { selected: true } ).any() ) { + // Select range + dt.cells( indexes ).select(); + } + else { + // Deselect range + dt.cells( indexes ).deselect(); + } +} + +/** + * Disable mouse selection by removing the selectors + * + * @param {DataTable.Api} dt DataTable to remove events from + * @private + */ +function disableMouseSelection( dt ) +{ + var ctx = dt.settings()[0]; + var selector = ctx._select.selector; + + $( dt.table().container() ) + .off( 'mousedown.dtSelect', selector ) + .off( 'mouseup.dtSelect', selector ) + .off( 'click.dtSelect', selector ); + + $('body').off( 'click.dtSelect' + _safeId(dt.table().node()) ); +} + +/** + * Attach mouse listeners to the table to allow mouse selection of items + * + * @param {DataTable.Api} dt DataTable to remove events from + * @private + */ +function enableMouseSelection ( dt ) +{ + var container = $( dt.table().container() ); + var ctx = dt.settings()[0]; + var selector = ctx._select.selector; + var matchSelection; + + container + .on( 'mousedown.dtSelect', selector, function(e) { + // Disallow text selection for shift clicking on the table so multi + // element selection doesn't look terrible! + if ( e.shiftKey || e.metaKey || e.ctrlKey ) { + container + .css( '-moz-user-select', 'none' ) + .one('selectstart.dtSelect', selector, function () { + return false; + } ); + } + + if ( window.getSelection ) { + matchSelection = window.getSelection(); + } + } ) + .on( 'mouseup.dtSelect', selector, function() { + // Allow text selection to occur again, Mozilla style (tested in FF + // 35.0.1 - still required) + container.css( '-moz-user-select', '' ); + } ) + .on( 'click.dtSelect', selector, function ( e ) { + var items = dt.select.items(); + var idx; + + // If text was selected (click and drag), then we shouldn't change + // the row's selected state + if ( matchSelection ) { + var selection = window.getSelection(); + + // If the element that contains the selection is not in the table, we can ignore it + // This can happen if the developer selects text from the click event + if ( ! selection.anchorNode || $(selection.anchorNode).closest('table')[0] === dt.table().node() ) { + if ( selection !== matchSelection ) { + return; + } + } + } + + var ctx = dt.settings()[0]; + var wrapperClass = dt.settings()[0].oClasses.sWrapper.trim().replace(/ +/g, '.'); + + // Ignore clicks inside a sub-table + if ( $(e.target).closest('div.'+wrapperClass)[0] != dt.table().container() ) { + return; + } + + var cell = dt.cell( $(e.target).closest('td, th') ); + + // Check the cell actually belongs to the host DataTable (so child + // rows, etc, are ignored) + if ( ! cell.any() ) { + return; + } + + var event = $.Event('user-select.dt'); + eventTrigger( dt, event, [ items, cell, e ] ); + + if ( event.isDefaultPrevented() ) { + return; + } + + var cellIndex = cell.index(); + if ( items === 'row' ) { + idx = cellIndex.row; + typeSelect( e, dt, ctx, 'row', idx ); + } + else if ( items === 'column' ) { + idx = cell.index().column; + typeSelect( e, dt, ctx, 'column', idx ); + } + else if ( items === 'cell' ) { + idx = cell.index(); + typeSelect( e, dt, ctx, 'cell', idx ); + } + + ctx._select_lastCell = cellIndex; + } ); + + // Blurable + $('body').on( 'click.dtSelect' + _safeId(dt.table().node()), function ( e ) { + if ( ctx._select.blurable ) { + // If the click was inside the DataTables container, don't blur + if ( $(e.target).parents().filter( dt.table().container() ).length ) { + return; + } + + // Ignore elements which have been removed from the DOM (i.e. paging + // buttons) + if ( $(e.target).parents('html').length === 0 ) { + return; + } + + // Don't blur in Editor form + if ( $(e.target).parents('div.DTE').length ) { + return; + } + + clear( ctx, true ); + } + } ); +} + +/** + * Trigger an event on a DataTable + * + * @param {DataTable.Api} api DataTable to trigger events on + * @param {boolean} selected true if selected, false if deselected + * @param {string} type Item type acting on + * @param {boolean} any Require that there are values before + * triggering + * @private + */ +function eventTrigger ( api, type, args, any ) +{ + if ( any && ! api.flatten().length ) { + return; + } + + if ( typeof type === 'string' ) { + type = type +'.dt'; + } + + args.unshift( api ); + + $(api.table().node()).trigger( type, args ); +} + +/** + * Update the information element of the DataTable showing information about the + * items selected. This is done by adding tags to the existing text + * + * @param {DataTable.Api} api DataTable to update + * @private + */ +function info ( api ) +{ + var ctx = api.settings()[0]; + + if ( ! ctx._select.info || ! ctx.aanFeatures.i ) { + return; + } + + if ( api.select.style() === 'api' ) { + return; + } + + var rows = api.rows( { selected: true } ).flatten().length; + var columns = api.columns( { selected: true } ).flatten().length; + var cells = api.cells( { selected: true } ).flatten().length; + + var add = function ( el, name, num ) { + el.append( $('').append( api.i18n( + 'select.'+name+'s', + { _: '%d '+name+'s selected', 0: '', 1: '1 '+name+' selected' }, + num + ) ) ); + }; + + // Internal knowledge of DataTables to loop over all information elements + $.each( ctx.aanFeatures.i, function ( i, el ) { + el = $(el); + + var output = $(''); + add( output, 'row', rows ); + add( output, 'column', columns ); + add( output, 'cell', cells ); + + var exisiting = el.children('span.select-info'); + if ( exisiting.length ) { + exisiting.remove(); + } + + if ( output.text() !== '' ) { + el.append( output ); + } + } ); +} + +/** + * Initialisation of a new table. Attach event handlers and callbacks to allow + * Select to operate correctly. + * + * This will occur _after_ the initial DataTables initialisation, although + * before Ajax data is rendered, if there is ajax data + * + * @param {DataTable.settings} ctx Settings object to operate on + * @private + */ +function init ( ctx ) { + var api = new DataTable.Api( ctx ); + ctx._select_init = true; + + // Row callback so that classes can be added to rows and cells if the item + // was selected before the element was created. This will happen with the + // `deferRender` option enabled. + // + // This method of attaching to `aoRowCreatedCallback` is a hack until + // DataTables has proper events for row manipulation If you are reviewing + // this code to create your own plug-ins, please do not do this! + ctx.aoRowCreatedCallback.push( { + fn: function ( row, data, index ) { + var i, ien; + var d = ctx.aoData[ index ]; + + // Row + if ( d._select_selected ) { + $( row ).addClass( ctx._select.className ); + } + + // Cells and columns - if separated out, we would need to do two + // loops, so it makes sense to combine them into a single one + for ( i=0, ien=ctx.aoColumns.length ; i idx2 ) { + var tmp = idx2; + idx2 = idx1; + idx1 = tmp; + } + + indexes.splice( idx2+1, indexes.length ); + indexes.splice( 0, idx1 ); + } + + if ( ! dt[type]( idx, { selected: true } ).any() ) { + // Select range + dt[type+'s']( indexes ).select(); + } + else { + // Deselect range - need to keep the clicked on row selected + indexes.splice( $.inArray( idx, indexes ), 1 ); + dt[type+'s']( indexes ).deselect(); + } +} + +/** + * Clear all selected items + * + * @param {DataTable.settings} ctx Settings object of the host DataTable + * @param {boolean} [force=false] Force the de-selection to happen, regardless + * of selection style + * @private + */ +function clear( ctx, force ) +{ + if ( force || ctx._select.style === 'single' ) { + var api = new DataTable.Api( ctx ); + + api.rows( { selected: true } ).deselect(); + api.columns( { selected: true } ).deselect(); + api.cells( { selected: true } ).deselect(); + } +} + +/** + * Select items based on the current configuration for style and items. + * + * @param {object} e Mouse event object + * @param {DataTables.Api} dt DataTable + * @param {DataTable.settings} ctx Settings object of the host DataTable + * @param {string} type Items to select + * @param {int|object} idx Index of the item to select + * @private + */ +function typeSelect ( e, dt, ctx, type, idx ) +{ + var style = dt.select.style(); + var toggleable = dt.select.toggleable(); + var isSelected = dt[type]( idx, { selected: true } ).any(); + + if ( isSelected && ! toggleable ) { + return; + } + + if ( style === 'os' ) { + if ( e.ctrlKey || e.metaKey ) { + // Add or remove from the selection + dt[type]( idx ).select( ! isSelected ); + } + else if ( e.shiftKey ) { + if ( type === 'cell' ) { + cellRange( dt, idx, ctx._select_lastCell || null ); + } + else { + rowColumnRange( dt, type, idx, ctx._select_lastCell ? + ctx._select_lastCell[type] : + null + ); + } + } + else { + // No cmd or shift click - deselect if selected, or select + // this row only + var selected = dt[type+'s']( { selected: true } ); + + if ( isSelected && selected.flatten().length === 1 ) { + dt[type]( idx ).deselect(); + } + else { + selected.deselect(); + dt[type]( idx ).select(); + } + } + } else if ( style == 'multi+shift' ) { + if ( e.shiftKey ) { + if ( type === 'cell' ) { + cellRange( dt, idx, ctx._select_lastCell || null ); + } + else { + rowColumnRange( dt, type, idx, ctx._select_lastCell ? + ctx._select_lastCell[type] : + null + ); + } + } + else { + dt[ type ]( idx ).select( ! isSelected ); + } + } + else { + dt[ type ]( idx ).select( ! isSelected ); + } +} + +function _safeId( node ) { + return node.id.replace(/[^a-zA-Z0-9\-\_]/g, '-'); +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables selectors + */ + +// row and column are basically identical just assigned to different properties +// and checking a different array, so we can dynamically create the functions to +// reduce the code size +$.each( [ + { type: 'row', prop: 'aoData' }, + { type: 'column', prop: 'aoColumns' } +], function ( i, o ) { + DataTable.ext.selector[ o.type ].push( function ( settings, opts, indexes ) { + var selected = opts.selected; + var data; + var out = []; + + if ( selected !== true && selected !== false ) { + return indexes; + } + + for ( var i=0, ien=indexes.length ; i 0 ); + } ); + + this.disable(); + }, + destroy: function ( dt, node, config ) { + dt.off( config._eventNamespace ); + } + } +} ); + +$.each( [ 'Row', 'Column', 'Cell' ], function ( i, item ) { + var lc = item.toLowerCase(); + + DataTable.ext.buttons[ 'select'+item+'s' ] = { + text: i18n( 'select'+item+'s', 'Select '+lc+'s' ), + className: 'buttons-select-'+lc+'s', + action: function () { + this.select.items( lc ); + }, + init: function ( dt ) { + var that = this; + + dt.on( 'selectItems.dt.DT', function ( e, ctx, items ) { + that.active( items === lc ); + } ); + } + }; +} ); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Initialisation + */ + +// DataTables creation - check if select has been defined in the options. Note +// this required that the table be in the document! If it isn't then something +// needs to trigger this method unfortunately. The next major release of +// DataTables will rework the events and address this. +$(document).on( 'preInit.dt.dtSelect', function (e, ctx) { + if ( e.namespace !== 'dt' ) { + return; + } + + DataTable.select.init( new DataTable.Api( ctx ) ); +} ); + + +return DataTable.select; +})); -- cgit v1.2.3