From e02e710cffacd73bf11926e153984042fb8debb4 Mon Sep 17 00:00:00 2001 From: dtbuild Date: Tue, 12 Nov 2024 09:25:14 +0000 Subject: [PATCH] 4e81940e4ca7dcc42f9d5e7438a5011aa0016763 Dev: Update docs for key control being in v3 4308024722b5d1be81ba5194e988a6ff98949ef0 New: Improved support for server-side processing through new additive / subtractive modes Sync to source repo @4308024722b5d1be81ba5194e988a6ff98949ef0 --- datatables.json | 2 +- js/dataTables.select.js | 103 ++++++++++++++++++++++++++++------- js/dataTables.select.min.js | 2 +- js/dataTables.select.min.mjs | 2 +- js/dataTables.select.mjs | 103 ++++++++++++++++++++++++++++------- 5 files changed, 171 insertions(+), 41 deletions(-) diff --git a/datatables.json b/datatables.json index 4575862..e299c2e 100644 --- a/datatables.json +++ b/datatables.json @@ -11,5 +11,5 @@ ], "src-repo": "http://github.com/DataTables/Select", "last-tag": "2.1.0", - "last-sync": "4ec3a6891012f01409e740c68221473f80c78266" + "last-sync": "4308024722b5d1be81ba5194e988a6ff98949ef0" } \ No newline at end of file diff --git a/js/dataTables.select.js b/js/dataTables.select.js index 929243a..36b5f28 100644 --- a/js/dataTables.select.js +++ b/js/dataTables.select.js @@ -580,14 +580,18 @@ function info(api, node) { return; } - // If _select_set has any length, then ids are available and should be used - // as the counter. Otherwise use the API to workout how many rows are - // selected. - var rowSetLength = api.settings()[0]._select_set.length; + var ctx = api.settings()[0]; + var rowSetLength = ctx._select_set.length; var rows = rowSetLength ? rowSetLength : api.rows({ selected: true }).count(); var columns = api.columns({ selected: true }).count(); var cells = api.cells({ selected: true }).count(); + // If subtractive selection, then we need to take the number of rows and + // subtract those that have been deselected + if (ctx._select_mode === 'subtractive') { + rows = api.page.info().recordsDisplay - rowSetLength; + } + var add = function (el, name, num) { el.append( $('').append( @@ -652,7 +656,8 @@ function initCheckboxHeader( dt, headerCheckbox ) { if (this.checked) { if (headerCheckbox == 'select-page') { dt.rows({page: 'current'}).select(); - } else { + } + else { dt.rows({search: 'applied'}).select(); } } @@ -699,26 +704,28 @@ function initCheckboxHeader( dt, headerCheckbox ) { function keysSet(dt) { var ctx = dt.settings()[0]; var flag = ctx._select.keys; + var namespace = 'dts-keys-' + ctx.sTableId; if (flag) { // Need a tabindex of the `tr` elements to make them focusable by the browser $(dt.rows({page: 'current'}).nodes()).attr('tabindex', 0); - dt.on('draw.dts-keys', function () { + dt.on('draw.' + namespace, function () { $(dt.rows({page: 'current'}).nodes()).attr('tabindex', 0); }); // Listen on document for tab, up and down - $(document).on('keydown.dts-keys', function (e) { + $(document).on('keydown.' + namespace, function (e) { var key = e.keyCode; var active = document.activeElement; // Can't use e.key as it wasn't widely supported until 2017 // 9 Tab + // 13 Return // 32 Space // 38 ArrowUp // 40 ArrowDown - if (! [9, 32, 38, 40].includes(key)) { + if (! [9, 13, 32, 38, 40].includes(key)) { return; } @@ -744,7 +751,7 @@ function keysSet(dt) { preventDefault = false; } } - else if (key === 32) { + else if (key === 13 || key === 32) { // Row selection / deselection var row = dt.row(active); @@ -775,6 +782,7 @@ function keysSet(dt) { } if (preventDefault) { + e.stopPropagation(); e.preventDefault(); } }); @@ -784,8 +792,8 @@ function keysSet(dt) { $(dt.rows().nodes()).removeAttr('tabindex'); // Nuke events - dt.off('draw.dts-keys'); - $(document).off('keydown.dts-keys'); + dt.off('draw.' + namespace); + $(document).off('keydown.' + namespace); } } @@ -889,7 +897,10 @@ function init(ctx) { var api = new DataTable.Api(ctx); ctx._select_init = true; - // _select_set contains a list of the ids of all rows that are selected + // When `additive` then `_select_set` contains a list of the row ids that + // are selected. If `subtractive` then all rows are selected, except those + // in `_select_set`, which is a list of ids. + ctx._select_mode = 'additive'; ctx._select_set = []; // Row callback so that classes can be added to rows and cells if the item @@ -907,7 +918,8 @@ function init(ctx) { // Row if ( d._select_selected || - (id !== 'undefined' && ctx._select_set.includes(id)) + (ctx._select_mode === 'additive' && ctx._select_set.includes(id)) || + (ctx._select_mode === 'subtractive' && ! ctx._select_set.includes(id)) ) { d._select_selected = true; @@ -1117,7 +1129,16 @@ function _cumulativeEvents(api) { var ctx = api.settings()[0]; - _add(api, ctx._select_set, indexes); + if (ctx._select_mode === 'additive') { + // Add row to the selection list if it isn't already there + _add(api, ctx._select_set, indexes); + } + else { + // Subtractive - if a row is selected it should not in the list + // as in subtractive mode the list gives the rows which are not + // selected + _remove(api, ctx._select_set, indexes); + } }); api.on('deselect', function (e, dt, type, indexes) { @@ -1128,7 +1149,14 @@ function _cumulativeEvents(api) { var ctx = api.settings()[0]; - _remove(api, ctx._select_set, indexes); + if (ctx._select_mode === 'additive') { + // List is of those rows selected, so remove it + _remove(api, ctx._select_set, indexes); + } + else { + // List is of rows which are deselected, so add it! + _add(api, ctx._select_set, indexes); + } }); } @@ -1286,6 +1314,10 @@ apiRegister('select.keys()', function (flag) { } return this.iterator('table', function (ctx) { + if (!ctx._select) { + DataTable.select.init(new DataTable.Api(ctx)); + } + ctx._select.keys = flag; keysSet(new DataTable.Api(ctx)); @@ -1375,12 +1407,45 @@ apiRegister('select.last()', function (set) { return ctx._select_lastCell; }); -apiRegister('select.cumulative()', function () { +apiRegister('select.cumulative()', function (mode) { + if (mode) { + return this.iterator('table', function (ctx) { + if (ctx._select_mode === mode) { + return; + } + + var dt = new DataTable.Api(ctx); + + // Convert from the current mode, to the new + if (mode === 'subtractive') { + // For subtractive mode we track the row ids which are not selected + var unselected = dt.rows({selected: false}).ids().toArray(); + + ctx._select_mode = mode; + ctx._select_set.length = 0; + ctx._select_set.push.apply(ctx._select_set, unselected); + } + else { + // Switching to additive, so selected rows are to be used + var selected = dt.rows({selected: true}).ids().toArray(); + + ctx._select_mode = mode; + ctx._select_set.length = 0; + ctx._select_set.push.apply(ctx._select_set, selected); + } + }).draw(false); + } + let ctx = this.context[0]; - return ctx && ctx._select_set - ? ctx._select_set - : []; + if (ctx && ctx._select_set) { + return { + mode: ctx._select_mode, + rows: ctx._select_set + }; + } + + return null; }); apiRegisterPlural('rows().select()', 'row().select()', function (select) { diff --git a/js/dataTables.select.min.js b/js/dataTables.select.min.js index 3014bb7..3973eef 100644 --- a/js/dataTables.select.min.js +++ b/js/dataTables.select.min.js @@ -1,4 +1,4 @@ /*! Select for DataTables 2.1.0 * © SpryMedia Ltd - datatables.net/license/mit */ -!function(s){var l,c;"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(e){return s(e,window,document)}):"object"==typeof exports?(l=require("jquery"),c=function(e,t){t.fn.dataTable||require("datatables.net")(e,t)},"undefined"==typeof window?module.exports=function(e,t){return e=e||window,t=t||l(e),c(e,t),s(t,e,e.document)}:(c(window,l),module.exports=s(l,window,window.document))):s(jQuery,window,document)}(function(m,i,a){"use strict";var v=m.fn.dataTable;function r(n,e,t){function s(t,s){sl.indexOf(s)&&(e=s,s=t,t=e),!1);return l.filter(function(e){return e===t&&(c=!0),e===s?!(c=!1):c})}var c,t=n.cells({selected:!0}).any()||t?(c=s(t.column,e.column),l(t.row,e.row)):(c=s(0,e.column),l(0,e.row)),t=n.cells(t,c).flatten();n.cells(e,{selected:!0}).any()?n.cells(t).deselect():n.cells(t).select()}function w(e){var t=v.select.classes.checkbox;return e?t.replace(/ /g,"."):t}function c(e){var t=e.settings()[0]._select.selector;m(e.table().container()).off("mousedown.dtSelect",t).off("mouseup.dtSelect",t).off("click.dtSelect",t),m("body").off("click.dtSelect"+b(e.table().node()))}function n(o){var a,t=m(o.table().container()),s=o.settings()[0],l=s._select.selector;t.on("mousedown.dtSelect",l,function(e){(e.shiftKey||e.metaKey||e.ctrlKey)&&t.css("-moz-user-select","none").one("selectstart.dtSelect",l,function(){return!1}),i.getSelection&&(a=i.getSelection())}).on("mouseup.dtSelect",l,function(){t.css("-moz-user-select","")}).on("click.dtSelect",l,function(e){var t,s=o.select.items();if(a){var l=i.getSelection();if((!l.anchorNode||m(l.anchorNode).closest("table")[0]===o.table().node())&&l!==a)return}var c,l=o.settings()[0],n=o.table().container();m(e.target).closest("div.dt-container")[0]==n&&(n=o.cell(m(e.target).closest("td, th"))).any()&&(c=m.Event("user-select.dt"),u(o,c,[s,n,e]),c.isDefaultPrevented()||(c=n.index(),"row"===s?(t=c.row,p(e,o,l,"row",t)):"column"===s?(t=n.index().column,p(e,o,l,"column",t)):"cell"===s&&(t=n.index(),p(e,o,l,"cell",t)),l._select_lastCell=c))}),m("body").on("click.dtSelect"+b(o.table().node()),function(e){var t;!s._select.blurable||m(e.target).parents().filter(o.table().container()).length||0===m(e.target).parents("html").length||m(e.target).parents("div.DTE").length||(t=m.Event("select-blur.dt"),u(o,t,[e.target,e]),t.isDefaultPrevented())||_(s,!0)})}function u(e,t,s,l){l&&!e.flatten().length||("string"==typeof t&&(t+=".dt"),s.unshift(e),m(e.table().node()).trigger(t,s))}function g(e){return e.mRender&&"selectCheckbox"===e.mRender._name}function l(l,e){var t,s,c,n,o;"api"!==l.select.style()&&!1!==l.select.info()&&(o=l.settings()[0]._select_set.length||l.rows({selected:!0}).count(),t=l.columns({selected:!0}).count(),s=l.cells({selected:!0}).count(),c=function(e,t,s){e.append(m('').append(l.i18n("select."+t+"s",{_:"%d "+t+"s selected",0:"",1:"1 "+t+" selected"},s)))},e=m(e),c(n=m(''),"row",o),c(n,"column",t),c(n,"cell",s),(o=e.children("span.select-info")).length&&o.remove(),""!==n.text())&&e.append(n)}function d(e){var t=e.page.info();t.page").attr({class:w(!0),type:"checkbox","aria-label":c.i18n("select.aria.headerCheckbox")||"Select all rows"}).appendTo(t).on("change",function(){this.checked?("select-page"==n?c.rows({page:"current"}):c.rows({search:"applied"})).select():("select-page"==n?c.rows({page:"current",selected:!0}):c.rows({selected:!0})).deselect()}).on("click",function(e){e.stopPropagation()}),c.on("draw select deselect",function(e,t,s){"row"!==s&&s||((s=function(e,t){var s=e.settings()[0],l=s._select.selectable,c=0,n=("select-page"==t?e.rows({page:"current",selected:!0}):e.rows({selected:!0})).count(),o=("select-page"==t?e.rows({page:"current",selected:!0}):e.rows({search:"applied",selected:!0})).count();if(l)for(var a=("select-page"==t?e.rows({page:"current"}):e.rows({search:"applied"})).indexes(),i=0;i").attr({"aria-label":o,class:w(),name:r?r(s):null,type:"checkbox",value:i?i(s):null,checked:n}).on("input",function(e){e.preventDefault(),this.checked=m(this).closest("tr").hasClass("selected")})[0]}var i=e?v.util.get(e):null,r=t?v.util.get(t):null;return s._name="selectCheckbox",s},v.ext.order["select-checkbox"]=function(t,e){return this.api().column(e,{order:"index"}).nodes().map(function(e){return"row"===t._select.items?m(e).parent().hasClass(t._select.className).toString():"cell"===t._select.items&&m(e).hasClass(t._select.className).toString()})},m.fn.DataTable.select=v.select,m(a).on("i18n.dt.dtSelect preInit.dt.dtSelect",function(e,t){"dt"===e.namespace&&v.select.init(new v.Api(t))}),v}); \ No newline at end of file +!function(s){var l,c;"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(e){return s(e,window,document)}):"object"==typeof exports?(l=require("jquery"),c=function(e,t){t.fn.dataTable||require("datatables.net")(e,t)},"undefined"==typeof window?module.exports=function(e,t){return e=e||window,t=t||l(e),c(e,t),s(t,e,e.document)}:(c(window,l),module.exports=s(l,window,window.document))):s(jQuery,window,document)}(function(m,i,a){"use strict";var v=m.fn.dataTable;function r(n,e,t){function s(t,s){sl.indexOf(s)&&(e=s,s=t,t=e),!1);return l.filter(function(e){return e===t&&(c=!0),e===s?!(c=!1):c})}var c,t=n.cells({selected:!0}).any()||t?(c=s(t.column,e.column),l(t.row,e.row)):(c=s(0,e.column),l(0,e.row)),t=n.cells(t,c).flatten();n.cells(e,{selected:!0}).any()?n.cells(t).deselect():n.cells(t).select()}function w(e){var t=v.select.classes.checkbox;return e?t.replace(/ /g,"."):t}function n(e){var t=e.settings()[0]._select.selector;m(e.table().container()).off("mousedown.dtSelect",t).off("mouseup.dtSelect",t).off("click.dtSelect",t),m("body").off("click.dtSelect"+b(e.table().node()))}function c(o){var a,t=m(o.table().container()),s=o.settings()[0],l=s._select.selector;t.on("mousedown.dtSelect",l,function(e){(e.shiftKey||e.metaKey||e.ctrlKey)&&t.css("-moz-user-select","none").one("selectstart.dtSelect",l,function(){return!1}),i.getSelection&&(a=i.getSelection())}).on("mouseup.dtSelect",l,function(){t.css("-moz-user-select","")}).on("click.dtSelect",l,function(e){var t,s=o.select.items();if(a){var l=i.getSelection();if((!l.anchorNode||m(l.anchorNode).closest("table")[0]===o.table().node())&&l!==a)return}var c,l=o.settings()[0],n=o.table().container();m(e.target).closest("div.dt-container")[0]==n&&(n=o.cell(m(e.target).closest("td, th"))).any()&&(c=m.Event("user-select.dt"),u(o,c,[s,n,e]),c.isDefaultPrevented()||(c=n.index(),"row"===s?(t=c.row,p(e,o,l,"row",t)):"column"===s?(t=n.index().column,p(e,o,l,"column",t)):"cell"===s&&(t=n.index(),p(e,o,l,"cell",t)),l._select_lastCell=c))}),m("body").on("click.dtSelect"+b(o.table().node()),function(e){var t;!s._select.blurable||m(e.target).parents().filter(o.table().container()).length||0===m(e.target).parents("html").length||m(e.target).parents("div.DTE").length||(t=m.Event("select-blur.dt"),u(o,t,[e.target,e]),t.isDefaultPrevented())||_(s,!0)})}function u(e,t,s,l){l&&!e.flatten().length||("string"==typeof t&&(t+=".dt"),s.unshift(e),m(e.table().node()).trigger(t,s))}function g(e){return e.mRender&&"selectCheckbox"===e.mRender._name}function l(l,e){var t,s,c,n,o;"api"!==l.select.style()&&!1!==l.select.info()&&(o=(n=(c=l.settings()[0])._select_set.length)||l.rows({selected:!0}).count(),t=l.columns({selected:!0}).count(),s=l.cells({selected:!0}).count(),"subtractive"===c._select_mode&&(o=l.page.info().recordsDisplay-n),c=function(e,t,s){e.append(m('').append(l.i18n("select."+t+"s",{_:"%d "+t+"s selected",0:"",1:"1 "+t+" selected"},s)))},n=m(e),c(e=m(''),"row",o),c(e,"column",t),c(e,"cell",s),(o=n.children("span.select-info")).length&&o.remove(),""!==e.text())&&n.append(e)}function d(e){var t=e.page.info();t.page").attr({class:w(!0),type:"checkbox","aria-label":c.i18n("select.aria.headerCheckbox")||"Select all rows"}).appendTo(t).on("change",function(){this.checked?("select-page"==n?c.rows({page:"current"}):c.rows({search:"applied"})).select():("select-page"==n?c.rows({page:"current",selected:!0}):c.rows({selected:!0})).deselect()}).on("click",function(e){e.stopPropagation()}),c.on("draw select deselect",function(e,t,s){"row"!==s&&s||((s=function(e,t){var s=e.settings()[0],l=s._select.selectable,c=0,n=("select-page"==t?e.rows({page:"current",selected:!0}):e.rows({selected:!0})).count(),o=("select-page"==t?e.rows({page:"current",selected:!0}):e.rows({search:"applied",selected:!0})).count();if(l)for(var a=("select-page"==t?e.rows({page:"current"}):e.rows({search:"applied"})).indexes(),i=0;i").attr({"aria-label":o,class:w(),name:r?r(s):null,type:"checkbox",value:i?i(s):null,checked:n}).on("input",function(e){e.preventDefault(),this.checked=m(this).closest("tr").hasClass("selected")})[0]}var i=e?v.util.get(e):null,r=t?v.util.get(t):null;return s._name="selectCheckbox",s},v.ext.order["select-checkbox"]=function(t,e){return this.api().column(e,{order:"index"}).nodes().map(function(e){return"row"===t._select.items?m(e).parent().hasClass(t._select.className).toString():"cell"===t._select.items&&m(e).hasClass(t._select.className).toString()})},m.fn.DataTable.select=v.select,m(a).on("i18n.dt.dtSelect preInit.dt.dtSelect",function(e,t){"dt"===e.namespace&&v.select.init(new v.Api(t))}),v}); \ No newline at end of file diff --git a/js/dataTables.select.min.mjs b/js/dataTables.select.min.mjs index 08f5a33..a179379 100644 --- a/js/dataTables.select.min.mjs +++ b/js/dataTables.select.min.mjs @@ -1,4 +1,4 @@ /*! Select for DataTables 2.1.0 * © SpryMedia Ltd - datatables.net/license/mit */ -import jQuery from"jquery";import DataTable from"datatables.net";let $=jQuery;function cellRange(n,e,t){function l(t,l){ls.indexOf(l)&&(e=l,l=t,t=e),!1);return s.filter(function(e){return e===t&&(c=!0),e===l?!(c=!1):c})}var c,t=n.cells({selected:!0}).any()||t?(c=l(t.column,e.column),s(t.row,e.row)):(c=l(0,e.column),s(0,e.row)),t=n.cells(t,c).flatten();n.cells(e,{selected:!0}).any()?n.cells(t).deselect():n.cells(t).select()}function checkboxClass(e){var t=DataTable.select.classes.checkbox;return e?t.replace(/ /g,"."):t}function disableMouseSelection(e){var t=e.settings()[0]._select.selector;$(e.table().container()).off("mousedown.dtSelect",t).off("mouseup.dtSelect",t).off("click.dtSelect",t),$("body").off("click.dtSelect"+_safeId(e.table().node()))}function enableMouseSelection(a){var o,t=$(a.table().container()),l=a.settings()[0],s=l._select.selector;t.on("mousedown.dtSelect",s,function(e){(e.shiftKey||e.metaKey||e.ctrlKey)&&t.css("-moz-user-select","none").one("selectstart.dtSelect",s,function(){return!1}),window.getSelection&&(o=window.getSelection())}).on("mouseup.dtSelect",s,function(){t.css("-moz-user-select","")}).on("click.dtSelect",s,function(e){var t,l=a.select.items();if(o){var s=window.getSelection();if((!s.anchorNode||$(s.anchorNode).closest("table")[0]===a.table().node())&&s!==o)return}var c,s=a.settings()[0],n=a.table().container();$(e.target).closest("div.dt-container")[0]==n&&(n=a.cell($(e.target).closest("td, th"))).any()&&(c=$.Event("user-select.dt"),eventTrigger(a,c,[l,n,e]),c.isDefaultPrevented()||(c=n.index(),"row"===l?(t=c.row,typeSelect(e,a,s,"row",t)):"column"===l?(t=n.index().column,typeSelect(e,a,s,"column",t)):"cell"===l&&(t=n.index(),typeSelect(e,a,s,"cell",t)),s._select_lastCell=c))}),$("body").on("click.dtSelect"+_safeId(a.table().node()),function(e){var t;!l._select.blurable||$(e.target).parents().filter(a.table().container()).length||0===$(e.target).parents("html").length||$(e.target).parents("div.DTE").length||(t=$.Event("select-blur.dt"),eventTrigger(a,t,[e.target,e]),t.isDefaultPrevented())||clear(l,!0)})}function eventTrigger(e,t,l,s){s&&!e.flatten().length||("string"==typeof t&&(t+=".dt"),l.unshift(e),$(e.table().node()).trigger(t,l))}function isCheckboxColumn(e){return e.mRender&&"selectCheckbox"===e.mRender._name}function info(s,e){var t,l,c,n,a;"api"!==s.select.style()&&!1!==s.select.info()&&(a=s.settings()[0]._select_set.length||s.rows({selected:!0}).count(),t=s.columns({selected:!0}).count(),l=s.cells({selected:!0}).count(),c=function(e,t,l){e.append($('').append(s.i18n("select."+t+"s",{_:"%d "+t+"s selected",0:"",1:"1 "+t+" selected"},l)))},e=$(e),c(n=$(''),"row",a),c(n,"column",t),c(n,"cell",l),(a=e.children("span.select-info")).length&&a.remove(),""!==n.text())&&e.append(n)}function initCheckboxHeader(c,n){var l=c.settings()[0].aoColumns;c.columns().iterator("column",function(e,t){var s;isCheckboxColumn(l[t])&&(t=c.column(t).header(),$("input",t).length||(s=$("").attr({class:checkboxClass(!0),type:"checkbox","aria-label":c.i18n("select.aria.headerCheckbox")||"Select all rows"}).appendTo(t).on("change",function(){this.checked?("select-page"==n?c.rows({page:"current"}):c.rows({search:"applied"})).select():("select-page"==n?c.rows({page:"current",selected:!0}):c.rows({selected:!0})).deselect()}).on("click",function(e){e.stopPropagation()}),c.on("draw select deselect",function(e,t,l){"row"!==l&&l||((l=headerCheckboxState(c,n)).search&&l.search<=l.count&&l.search===l.available?s.prop("checked",!0).prop("indeterminate",!1):0===l.search&&0===l.count?s.prop("checked",!1).prop("indeterminate",!1):s.prop("checked",!1).prop("indeterminate",!0))})))})}function keysSet(a){a.settings()[0]._select.keys?($(a.rows({page:"current"}).nodes()).attr("tabindex",0),a.on("draw.dts-keys",function(){$(a.rows({page:"current"}).nodes()).attr("tabindex",0)}),$(document).on("keydown.dts-keys",function(e){var t,l,s,c=e.keyCode,n=document.activeElement;[9,32,38,40].includes(c)&&(s=!0,-1!==(l=(t=a.rows({page:"current"}).nodes().toArray()).indexOf(n)))&&(9===c?!1===e.shift&&l===t.length-1?keysPageDown(a):!0===e.shift&&0===l?keysPageUp(a):s=!1:32===c?(n=a.row(n)).selected()?n.deselect():n.select():38===c?0").attr({"aria-label":a,class:checkboxClass(),name:r?r(l):null,type:"checkbox",value:i?i(l):null,checked:n}).on("input",function(e){e.preventDefault(),this.checked=$(this).closest("tr").hasClass("selected")})[0]}var i=e?DataTable.util.get(e):null,r=t?DataTable.util.get(t):null;return l._name="selectCheckbox",l},DataTable.ext.order["select-checkbox"]=function(t,e){return this.api().column(e,{order:"index"}).nodes().map(function(e){return"row"===t._select.items?$(e).parent().hasClass(t._select.className).toString():"cell"===t._select.items&&$(e).hasClass(t._select.className).toString()})},$.fn.DataTable.select=DataTable.select,$(document).on("i18n.dt.dtSelect preInit.dt.dtSelect",function(e,t){"dt"===e.namespace&&DataTable.select.init(new DataTable.Api(t))});export default DataTable; \ No newline at end of file +import jQuery from"jquery";import DataTable from"datatables.net";let $=jQuery;function cellRange(n,e,t){function l(t,l){ls.indexOf(l)&&(e=l,l=t,t=e),!1);return s.filter(function(e){return e===t&&(c=!0),e===l?!(c=!1):c})}var c,t=n.cells({selected:!0}).any()||t?(c=l(t.column,e.column),s(t.row,e.row)):(c=l(0,e.column),s(0,e.row)),t=n.cells(t,c).flatten();n.cells(e,{selected:!0}).any()?n.cells(t).deselect():n.cells(t).select()}function checkboxClass(e){var t=DataTable.select.classes.checkbox;return e?t.replace(/ /g,"."):t}function disableMouseSelection(e){var t=e.settings()[0]._select.selector;$(e.table().container()).off("mousedown.dtSelect",t).off("mouseup.dtSelect",t).off("click.dtSelect",t),$("body").off("click.dtSelect"+_safeId(e.table().node()))}function enableMouseSelection(a){var o,t=$(a.table().container()),l=a.settings()[0],s=l._select.selector;t.on("mousedown.dtSelect",s,function(e){(e.shiftKey||e.metaKey||e.ctrlKey)&&t.css("-moz-user-select","none").one("selectstart.dtSelect",s,function(){return!1}),window.getSelection&&(o=window.getSelection())}).on("mouseup.dtSelect",s,function(){t.css("-moz-user-select","")}).on("click.dtSelect",s,function(e){var t,l=a.select.items();if(o){var s=window.getSelection();if((!s.anchorNode||$(s.anchorNode).closest("table")[0]===a.table().node())&&s!==o)return}var c,s=a.settings()[0],n=a.table().container();$(e.target).closest("div.dt-container")[0]==n&&(n=a.cell($(e.target).closest("td, th"))).any()&&(c=$.Event("user-select.dt"),eventTrigger(a,c,[l,n,e]),c.isDefaultPrevented()||(c=n.index(),"row"===l?(t=c.row,typeSelect(e,a,s,"row",t)):"column"===l?(t=n.index().column,typeSelect(e,a,s,"column",t)):"cell"===l&&(t=n.index(),typeSelect(e,a,s,"cell",t)),s._select_lastCell=c))}),$("body").on("click.dtSelect"+_safeId(a.table().node()),function(e){var t;!l._select.blurable||$(e.target).parents().filter(a.table().container()).length||0===$(e.target).parents("html").length||$(e.target).parents("div.DTE").length||(t=$.Event("select-blur.dt"),eventTrigger(a,t,[e.target,e]),t.isDefaultPrevented())||clear(l,!0)})}function eventTrigger(e,t,l,s){s&&!e.flatten().length||("string"==typeof t&&(t+=".dt"),l.unshift(e),$(e.table().node()).trigger(t,l))}function isCheckboxColumn(e){return e.mRender&&"selectCheckbox"===e.mRender._name}function info(s,e){var t,l,c,n,a;"api"!==s.select.style()&&!1!==s.select.info()&&(a=(n=(c=s.settings()[0])._select_set.length)||s.rows({selected:!0}).count(),t=s.columns({selected:!0}).count(),l=s.cells({selected:!0}).count(),"subtractive"===c._select_mode&&(a=s.page.info().recordsDisplay-n),c=function(e,t,l){e.append($('').append(s.i18n("select."+t+"s",{_:"%d "+t+"s selected",0:"",1:"1 "+t+" selected"},l)))},n=$(e),c(e=$(''),"row",a),c(e,"column",t),c(e,"cell",l),(a=n.children("span.select-info")).length&&a.remove(),""!==e.text())&&n.append(e)}function initCheckboxHeader(c,n){var l=c.settings()[0].aoColumns;c.columns().iterator("column",function(e,t){var s;isCheckboxColumn(l[t])&&(t=c.column(t).header(),$("input",t).length||(s=$("").attr({class:checkboxClass(!0),type:"checkbox","aria-label":c.i18n("select.aria.headerCheckbox")||"Select all rows"}).appendTo(t).on("change",function(){this.checked?("select-page"==n?c.rows({page:"current"}):c.rows({search:"applied"})).select():("select-page"==n?c.rows({page:"current",selected:!0}):c.rows({selected:!0})).deselect()}).on("click",function(e){e.stopPropagation()}),c.on("draw select deselect",function(e,t,l){"row"!==l&&l||((l=headerCheckboxState(c,n)).search&&l.search<=l.count&&l.search===l.available?s.prop("checked",!0).prop("indeterminate",!1):0===l.search&&0===l.count?s.prop("checked",!1).prop("indeterminate",!1):s.prop("checked",!1).prop("indeterminate",!0))})))})}function keysSet(a){var e=a.settings()[0],t=e._select.keys,e="dts-keys-"+e.sTableId;t?($(a.rows({page:"current"}).nodes()).attr("tabindex",0),a.on("draw."+e,function(){$(a.rows({page:"current"}).nodes()).attr("tabindex",0)}),$(document).on("keydown."+e,function(e){var t,l,s,c=e.keyCode,n=document.activeElement;[9,13,32,38,40].includes(c)&&(s=!0,-1!==(l=(t=a.rows({page:"current"}).nodes().toArray()).indexOf(n)))&&(9===c?!1===e.shift&&l===t.length-1?keysPageDown(a):!0===e.shift&&0===l?keysPageUp(a):s=!1:13===c||32===c?(n=a.row(n)).selected()?n.deselect():n.select():38===c?0").attr({"aria-label":a,class:checkboxClass(),name:r?r(l):null,type:"checkbox",value:i?i(l):null,checked:n}).on("input",function(e){e.preventDefault(),this.checked=$(this).closest("tr").hasClass("selected")})[0]}var i=e?DataTable.util.get(e):null,r=t?DataTable.util.get(t):null;return l._name="selectCheckbox",l},DataTable.ext.order["select-checkbox"]=function(t,e){return this.api().column(e,{order:"index"}).nodes().map(function(e){return"row"===t._select.items?$(e).parent().hasClass(t._select.className).toString():"cell"===t._select.items&&$(e).hasClass(t._select.className).toString()})},$.fn.DataTable.select=DataTable.select,$(document).on("i18n.dt.dtSelect preInit.dt.dtSelect",function(e,t){"dt"===e.namespace&&DataTable.select.init(new DataTable.Api(t))});export default DataTable; \ No newline at end of file diff --git a/js/dataTables.select.mjs b/js/dataTables.select.mjs index 7c0c898..2627475 100644 --- a/js/dataTables.select.mjs +++ b/js/dataTables.select.mjs @@ -540,14 +540,18 @@ function info(api, node) { return; } - // If _select_set has any length, then ids are available and should be used - // as the counter. Otherwise use the API to workout how many rows are - // selected. - var rowSetLength = api.settings()[0]._select_set.length; + var ctx = api.settings()[0]; + var rowSetLength = ctx._select_set.length; var rows = rowSetLength ? rowSetLength : api.rows({ selected: true }).count(); var columns = api.columns({ selected: true }).count(); var cells = api.cells({ selected: true }).count(); + // If subtractive selection, then we need to take the number of rows and + // subtract those that have been deselected + if (ctx._select_mode === 'subtractive') { + rows = api.page.info().recordsDisplay - rowSetLength; + } + var add = function (el, name, num) { el.append( $('').append( @@ -612,7 +616,8 @@ function initCheckboxHeader( dt, headerCheckbox ) { if (this.checked) { if (headerCheckbox == 'select-page') { dt.rows({page: 'current'}).select(); - } else { + } + else { dt.rows({search: 'applied'}).select(); } } @@ -659,26 +664,28 @@ function initCheckboxHeader( dt, headerCheckbox ) { function keysSet(dt) { var ctx = dt.settings()[0]; var flag = ctx._select.keys; + var namespace = 'dts-keys-' + ctx.sTableId; if (flag) { // Need a tabindex of the `tr` elements to make them focusable by the browser $(dt.rows({page: 'current'}).nodes()).attr('tabindex', 0); - dt.on('draw.dts-keys', function () { + dt.on('draw.' + namespace, function () { $(dt.rows({page: 'current'}).nodes()).attr('tabindex', 0); }); // Listen on document for tab, up and down - $(document).on('keydown.dts-keys', function (e) { + $(document).on('keydown.' + namespace, function (e) { var key = e.keyCode; var active = document.activeElement; // Can't use e.key as it wasn't widely supported until 2017 // 9 Tab + // 13 Return // 32 Space // 38 ArrowUp // 40 ArrowDown - if (! [9, 32, 38, 40].includes(key)) { + if (! [9, 13, 32, 38, 40].includes(key)) { return; } @@ -704,7 +711,7 @@ function keysSet(dt) { preventDefault = false; } } - else if (key === 32) { + else if (key === 13 || key === 32) { // Row selection / deselection var row = dt.row(active); @@ -735,6 +742,7 @@ function keysSet(dt) { } if (preventDefault) { + e.stopPropagation(); e.preventDefault(); } }); @@ -744,8 +752,8 @@ function keysSet(dt) { $(dt.rows().nodes()).removeAttr('tabindex'); // Nuke events - dt.off('draw.dts-keys'); - $(document).off('keydown.dts-keys'); + dt.off('draw.' + namespace); + $(document).off('keydown.' + namespace); } } @@ -849,7 +857,10 @@ function init(ctx) { var api = new DataTable.Api(ctx); ctx._select_init = true; - // _select_set contains a list of the ids of all rows that are selected + // When `additive` then `_select_set` contains a list of the row ids that + // are selected. If `subtractive` then all rows are selected, except those + // in `_select_set`, which is a list of ids. + ctx._select_mode = 'additive'; ctx._select_set = []; // Row callback so that classes can be added to rows and cells if the item @@ -867,7 +878,8 @@ function init(ctx) { // Row if ( d._select_selected || - (id !== 'undefined' && ctx._select_set.includes(id)) + (ctx._select_mode === 'additive' && ctx._select_set.includes(id)) || + (ctx._select_mode === 'subtractive' && ! ctx._select_set.includes(id)) ) { d._select_selected = true; @@ -1077,7 +1089,16 @@ function _cumulativeEvents(api) { var ctx = api.settings()[0]; - _add(api, ctx._select_set, indexes); + if (ctx._select_mode === 'additive') { + // Add row to the selection list if it isn't already there + _add(api, ctx._select_set, indexes); + } + else { + // Subtractive - if a row is selected it should not in the list + // as in subtractive mode the list gives the rows which are not + // selected + _remove(api, ctx._select_set, indexes); + } }); api.on('deselect', function (e, dt, type, indexes) { @@ -1088,7 +1109,14 @@ function _cumulativeEvents(api) { var ctx = api.settings()[0]; - _remove(api, ctx._select_set, indexes); + if (ctx._select_mode === 'additive') { + // List is of those rows selected, so remove it + _remove(api, ctx._select_set, indexes); + } + else { + // List is of rows which are deselected, so add it! + _add(api, ctx._select_set, indexes); + } }); } @@ -1246,6 +1274,10 @@ apiRegister('select.keys()', function (flag) { } return this.iterator('table', function (ctx) { + if (!ctx._select) { + DataTable.select.init(new DataTable.Api(ctx)); + } + ctx._select.keys = flag; keysSet(new DataTable.Api(ctx)); @@ -1335,12 +1367,45 @@ apiRegister('select.last()', function (set) { return ctx._select_lastCell; }); -apiRegister('select.cumulative()', function () { +apiRegister('select.cumulative()', function (mode) { + if (mode) { + return this.iterator('table', function (ctx) { + if (ctx._select_mode === mode) { + return; + } + + var dt = new DataTable.Api(ctx); + + // Convert from the current mode, to the new + if (mode === 'subtractive') { + // For subtractive mode we track the row ids which are not selected + var unselected = dt.rows({selected: false}).ids().toArray(); + + ctx._select_mode = mode; + ctx._select_set.length = 0; + ctx._select_set.push.apply(ctx._select_set, unselected); + } + else { + // Switching to additive, so selected rows are to be used + var selected = dt.rows({selected: true}).ids().toArray(); + + ctx._select_mode = mode; + ctx._select_set.length = 0; + ctx._select_set.push.apply(ctx._select_set, selected); + } + }).draw(false); + } + let ctx = this.context[0]; - return ctx && ctx._select_set - ? ctx._select_set - : []; + if (ctx && ctx._select_set) { + return { + mode: ctx._select_mode, + rows: ctx._select_set + }; + } + + return null; }); apiRegisterPlural('rows().select()', 'row().select()', function (select) {