@@ -144,18 +144,67 @@ if (delete_all) {
144144 } ) ;
145145}
146146
147- const check_all = document . querySelector ( '.check-all' ) ;
148- if ( check_all ) {
149- check_all . addEventListener ( 'change' , ( ) => {
150- if ( delete_selected ) {
151- delete_selected . disabled = check_all . checked !== true ;
152- }
147+ // Check all keys in a table or treeview
148+ document . addEventListener ( 'change' , ( e ) => {
149+ if ( ! e . target . matches ( 'input[type="checkbox"].check-all' ) ) {
150+ return ;
151+ }
153152
154- keys . forEach ( key => {
155- key . querySelector ( '[type="checkbox"]' ) . checked = check_all . checked ;
156- } ) ;
153+ let scope ;
154+
155+ if ( e . target . closest ( '.tree-group' ) ) {
156+ const tree_group = e . target . closest ( '.tree-group' ) ;
157+ const children = tree_group . querySelector ( ':scope > .tree-children' ) ;
158+ scope = children || tree_group ;
159+ } else {
160+ scope = e . target . closest ( 'table' ) || e . target . closest ( '.treeview' ) ;
161+ }
162+
163+ if ( ! scope ) {
164+ return ;
165+ }
166+
167+ const checkboxes = scope . querySelectorAll ( 'input[type="checkbox"]:not(.check-all)' ) ;
168+
169+ checkboxes . forEach ( cb => {
170+ cb . checked = e . target . checked ;
171+ cb . dispatchEvent ( new Event ( 'change' , { bubbles : true } ) ) ;
157172 } ) ;
158- }
173+ } ) ;
174+
175+ // Shift-click multi-select
176+ let last_checked = null ;
177+ document . addEventListener ( 'click' , ( e ) => {
178+ if ( ! e . target . matches ( 'input[type="checkbox"]' ) || e . target . classList . contains ( 'check-all' ) ) {
179+ return ;
180+ }
181+
182+ const tree = e . target . closest ( '.treeview' ) ;
183+ const table = e . target . closest ( 'table' ) ;
184+ let checkboxes ;
185+
186+ if ( tree ) {
187+ checkboxes = Array . from ( tree . querySelectorAll ( '.keywrapper input[type="checkbox"]:not(.check-all)' ) ) ;
188+ } else if ( table ) {
189+ checkboxes = Array . from ( table . querySelectorAll ( 'input[type="checkbox"]:not(.check-all)' ) ) ;
190+ } else {
191+ return ;
192+ }
193+
194+ if ( e . shiftKey && last_checked ) {
195+ const start = checkboxes . indexOf ( last_checked ) ;
196+ const end = checkboxes . indexOf ( e . target ) ;
197+
198+ if ( start !== - 1 && end !== - 1 ) {
199+ for ( let i = Math . min ( start , end ) ; i <= Math . max ( start , end ) ; i ++ ) {
200+ checkboxes [ i ] . checked = e . target . checked ;
201+ checkboxes [ i ] . dispatchEvent ( new Event ( 'change' , { bubbles : true } ) ) ;
202+ }
203+ }
204+ }
205+
206+ last_checked = e . target ;
207+ } ) ;
159208
160209/**
161210 * Ajax panels
0 commit comments