@@ -30,6 +30,7 @@ export class ConstraintMenu extends AbstractUIExtension implements Switchable {
3030 private tree : AutoCompleteTree ;
3131 private forceReadOnly : boolean ;
3232 private optionsMenu ?: HTMLDivElement ;
33+ private ignoreCheckboxChange = false ;
3334
3435 constructor (
3536 @inject ( ConstraintRegistry ) private readonly constraintRegistry : ConstraintRegistry ,
@@ -233,7 +234,7 @@ export class ConstraintMenu extends AbstractUIExtension implements Switchable {
233234 const btn = document . createElement ( "button" ) ;
234235 btn . id = "constraint-options-button" ;
235236 btn . title = "Filter…" ;
236- btn . innerHTML = "⋮" ; // or insert a font-awesome icon
237+ btn . innerHTML = '<span class="codicon codicon-kebab-vertical"></span>' ;
237238 btn . onclick = ( ) => this . toggleOptionsMenu ( ) ;
238239 return btn ;
239240 }
@@ -257,28 +258,39 @@ export class ConstraintMenu extends AbstractUIExtension implements Switchable {
257258 const allCb = document . createElement ( "input" ) ;
258259 allCb . type = "checkbox" ;
259260 allCb . value = "ALL" ;
260- // initially checked if no specific constraint is selected
261- allCb . checked = this . constraintRegistry . getSelectedConstraints ( ) . includes ( "ALL" ) ;
261+ allCb . checked = this . constraintRegistry
262+ . getConstraintList ( )
263+ . map ( ( c ) => c . name )
264+ . every ( ( c ) => this . constraintRegistry . getSelectedConstraints ( ) . includes ( c ) ) ;
262265
263266 allCb . onchange = ( ) => {
264267 if ( ! this . optionsMenu ) return ;
265- if ( allCb . checked ) {
266- // uncheck every other constraint-checkbox
267- this . optionsMenu . querySelectorAll < HTMLInputElement > ( "input[type=checkbox]" ) . forEach ( ( cb ) => {
268- if ( cb !== allCb ) cb . checked = false ;
269- } ) ;
270- // dispatch with empty array to mean “all”
271- this . dispatcher . dispatch ( ChooseConstraintAction . create ( [ "ALL" ] ) ) ;
272- } else {
273- this . dispatcher . dispatch ( ChooseConstraintAction . create ( [ ] ) ) ;
268+
269+ this . ignoreCheckboxChange = true ;
270+ try {
271+ if ( allCb . checked ) {
272+ this . optionsMenu . querySelectorAll < HTMLInputElement > ( "input[type=checkbox]" ) . forEach ( ( cb ) => {
273+ if ( cb !== allCb ) cb . checked = true ;
274+ } ) ;
275+ this . dispatcher . dispatch (
276+ ChooseConstraintAction . create ( this . constraintRegistry . getConstraintList ( ) . map ( ( c ) => c . name ) ) ,
277+ ) ;
278+ } else {
279+ this . optionsMenu . querySelectorAll < HTMLInputElement > ( "input[type=checkbox]" ) . forEach ( ( cb ) => {
280+ if ( cb !== allCb ) cb . checked = false ;
281+ } ) ;
282+ this . dispatcher . dispatch ( ChooseConstraintAction . create ( [ ] ) ) ;
283+ }
284+ } finally {
285+ this . ignoreCheckboxChange = false ;
274286 }
275287 } ;
276288
277289 allConstraints . appendChild ( allCb ) ;
278290 allConstraints . appendChild ( document . createTextNode ( "All constraints" ) ) ;
279291 this . optionsMenu . appendChild ( allConstraints ) ;
280292
281- // 2) pull your dynamic items (replace with your real API)
293+ // 2) pull your dynamic items
282294 const items = this . constraintRegistry . getConstraintList ( ) ;
283295
284296 // 3) for each item build a checkbox
@@ -292,14 +304,14 @@ export class ConstraintMenu extends AbstractUIExtension implements Switchable {
292304 cb . checked = this . constraintRegistry . getSelectedConstraints ( ) . includes ( cb . value ) ;
293305
294306 cb . onchange = ( ) => {
295- if ( cb . checked ) allCb . checked = false ;
307+ if ( this . ignoreCheckboxChange ) return ;
296308
297- const selected = Array . from (
298- this . optionsMenu ! . querySelectorAll < HTMLInputElement > ( "input[type=checkbox]:checked" ) ,
299- ) . map ( ( cb ) => cb . value ) ;
309+ const checkboxes = this . optionsMenu ! . querySelectorAll < HTMLInputElement > ( "input[type=checkbox]" ) ;
310+ const individualCheckboxes = Array . from ( checkboxes ) . filter ( ( cb ) => cb !== allCb ) ;
311+ const selected = individualCheckboxes . filter ( ( cb ) => cb . checked ) . map ( ( cb ) => cb . value ) ;
312+
313+ allCb . checked = individualCheckboxes . every ( ( cb ) => cb . checked ) ;
300314
301- // dispatch your action with either an array or
302- // a comma-joined string—whatever your action expects
303315 this . dispatcher . dispatch ( ChooseConstraintAction . create ( selected ) ) ;
304316 } ;
305317
@@ -312,15 +324,16 @@ export class ConstraintMenu extends AbstractUIExtension implements Switchable {
312324
313325 // optional: click-outside handler
314326 const onClickOutside = ( e : MouseEvent ) => {
315- if (
316- this . optionsMenu &&
317- ! this . optionsMenu . contains ( e . target as Node ) &&
318- ! ( e . target as Element ) . matches ( "#constraint-options-button" )
319- ) {
320- this . toggleOptionsMenu ( ) ;
321- document . removeEventListener ( "click" , onClickOutside ) ;
322- }
327+ const target = e . target as Node ;
328+ if ( ! this . optionsMenu || this . optionsMenu . contains ( target ) ) return ;
329+
330+ const button = document . getElementById ( "constraint-options-button" ) ;
331+ if ( button && button . contains ( target ) ) return ;
332+
333+ this . optionsMenu . remove ( ) ;
334+ this . optionsMenu = undefined ;
335+ document . removeEventListener ( "click" , onClickOutside ) ;
323336 } ;
324- setTimeout ( ( ) => document . addEventListener ( "click" , onClickOutside ) , 0 ) ;
337+ document . addEventListener ( "click" , onClickOutside ) ;
325338 }
326339}
0 commit comments