@@ -59,6 +59,12 @@ function updateSelectionLabel(label: HTMLElement) {
59
59
}
60
60
}
61
61
62
+ function processMenuItems ( $dropdown , dropdownCall ) {
63
+ const hideEmptyDividers = dropdownCall ( 'setting' , 'hideDividers' ) === 'empty' ;
64
+ const itemsMenu = $dropdown [ 0 ] . querySelector ( '.scrolling.menu' ) || $dropdown [ 0 ] . querySelector ( '.menu' ) ;
65
+ if ( hideEmptyDividers ) hideScopedEmptyDividers ( itemsMenu ) ;
66
+ }
67
+
62
68
// delegate the dropdown's template functions and callback functions to add aria attributes.
63
69
function delegateOne ( $dropdown : any ) {
64
70
const dropdownCall = fomanticDropdownFn . bind ( $dropdown ) ;
@@ -72,6 +78,18 @@ function delegateOne($dropdown: any) {
72
78
// * If the "dropdown icon" is clicked again when the menu is visible, Fomantic calls "blurSearch", so hide the menu
73
79
dropdownCall ( 'internal' , 'blurSearch' , function ( ) { oldBlurSearch . call ( this ) ; dropdownCall ( 'hide' ) } ) ;
74
80
81
+ const oldFilterItems = dropdownCall ( 'internal' , 'filterItems' ) ;
82
+ dropdownCall ( 'internal' , 'filterItems' , function ( ...args : any [ ] ) {
83
+ oldFilterItems . call ( this , ...args ) ;
84
+ processMenuItems ( $dropdown , dropdownCall ) ;
85
+ } ) ;
86
+
87
+ const oldShow = dropdownCall ( 'internal' , 'show' ) ;
88
+ dropdownCall ( 'internal' , 'show' , function ( ...args : any [ ] ) {
89
+ oldShow . call ( this , ...args ) ;
90
+ processMenuItems ( $dropdown , dropdownCall ) ;
91
+ } ) ;
92
+
75
93
// the "template" functions are used for dynamic creation (eg: AJAX)
76
94
const dropdownTemplates = { ...dropdownCall ( 'setting' , 'templates' ) , t : performance . now ( ) } ;
77
95
const dropdownTemplatesMenuOld = dropdownTemplates . menu ;
@@ -271,3 +289,65 @@ function attachDomEvents(dropdown: HTMLElement, focusable: HTMLElement, menu: HT
271
289
ignoreClickPreEvents = ignoreClickPreVisible = 0 ;
272
290
} , true ) ;
273
291
}
292
+
293
+ // Although Fomantic Dropdown supports "hideDividers", it doesn't really work with our "scoped dividers"
294
+ // At the moment, "label dropdown items" use scopes, a sample case is:
295
+ // * a-label
296
+ // * divider
297
+ // * scope/1
298
+ // * scope/2
299
+ // * divider
300
+ // * z-label
301
+ // when the "scope/*" are filtered out, we'd like to see "a-label" and "z-label" without the divider.
302
+ export function hideScopedEmptyDividers ( container : Element ) {
303
+ const visibleItems : Element [ ] = [ ] ;
304
+ const curScopeVisibleItems : Element [ ] = [ ] ;
305
+ let curScope : string = '' , lastVisibleScope : string = '' ;
306
+ const isScopedDivider = ( item : Element ) => item . matches ( '.divider' ) && item . hasAttribute ( 'data-scope' ) ;
307
+ const hideDivider = ( item : Element ) => item . classList . add ( 'hidden' , 'transition' ) ; // dropdown has its own classes to hide items
308
+
309
+ const handleScopeSwitch = ( itemScope : string ) => {
310
+ if ( curScopeVisibleItems . length === 1 && isScopedDivider ( curScopeVisibleItems [ 0 ] ) ) {
311
+ hideDivider ( curScopeVisibleItems [ 0 ] ) ;
312
+ } else if ( curScopeVisibleItems . length ) {
313
+ if ( isScopedDivider ( curScopeVisibleItems [ 0 ] ) && lastVisibleScope === curScope ) {
314
+ hideDivider ( curScopeVisibleItems [ 0 ] ) ;
315
+ curScopeVisibleItems . shift ( ) ;
316
+ }
317
+ visibleItems . push ( ...curScopeVisibleItems ) ;
318
+ lastVisibleScope = curScope ;
319
+ }
320
+ curScope = itemScope ;
321
+ curScopeVisibleItems . length = 0 ;
322
+ } ;
323
+
324
+ // hide the scope dividers if the scope items are empty
325
+ for ( const item of container . children ) {
326
+ const itemScope = item . getAttribute ( 'data-scope' ) || '' ;
327
+ if ( itemScope !== curScope ) {
328
+ handleScopeSwitch ( itemScope ) ;
329
+ }
330
+ if ( ! item . classList . contains ( 'filtered' ) && ! item . classList . contains ( 'tw-hidden' ) ) {
331
+ curScopeVisibleItems . push ( item as HTMLElement ) ;
332
+ }
333
+ }
334
+ handleScopeSwitch ( '' ) ;
335
+
336
+ // hide all leading and trailing dividers
337
+ while ( visibleItems . length ) {
338
+ if ( ! visibleItems [ 0 ] . matches ( '.divider' ) ) break ;
339
+ hideDivider ( visibleItems [ 0 ] ) ;
340
+ visibleItems . shift ( ) ;
341
+ }
342
+ while ( visibleItems . length ) {
343
+ if ( ! visibleItems [ visibleItems . length - 1 ] . matches ( '.divider' ) ) break ;
344
+ hideDivider ( visibleItems [ visibleItems . length - 1 ] ) ;
345
+ visibleItems . pop ( ) ;
346
+ }
347
+ // hide all duplicate dividers, hide current divider if next sibling is still divider
348
+ // no need to update "visibleItems" array since this is the last loop
349
+ for ( const item of visibleItems ) {
350
+ if ( ! item . matches ( '.divider' ) ) continue ;
351
+ if ( item . nextElementSibling ?. matches ( '.divider' ) ) hideDivider ( item ) ;
352
+ }
353
+ }
0 commit comments