Skip to content

Commit 6b7f6ee

Browse files
committed
fix
1 parent 70746e7 commit 6b7f6ee

File tree

3 files changed

+43
-25
lines changed

3 files changed

+43
-25
lines changed

web_src/fomantic/build/components/dropdown.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,7 @@ $.fn.dropdown = function(parameters) {
752752
if(module.is.searchSelection() && module.can.show() && module.is.focusedOnSearch() ) {
753753
module.show();
754754
}
755+
settings.onAfterFiltered.call(element); // GITEA-PATCH: callback to correctly handle the filtered items
755756
}
756757
;
757758
if(settings.useLabels && module.has.maxSelections()) {
@@ -3992,6 +3993,8 @@ $.fn.dropdown.settings = {
39923993
onShow : function(){},
39933994
onHide : function(){},
39943995

3996+
onAfterFiltered: function(){}, // GITEA-PATCH: callback to correctly handle the filtered items
3997+
39953998
/* Component */
39963999
name : 'Dropdown',
39974000
namespace : 'dropdown',

web_src/js/modules/fomantic/dropdown.test.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,35 @@ test('hideScopedEmptyDividers-simple', () => {
1515
expect(container.innerHTML).toEqual(`
1616
<div class="divider hidden transition"></div>
1717
<div class="item">a</div>
18+
<div class="divider"></div>
1819
<div class="divider hidden transition"></div>
1920
<div class="divider hidden transition"></div>
20-
<div class="divider"></div>
2121
<div class="item">b</div>
2222
<div class="divider hidden transition"></div>
2323
`);
2424
});
2525

26-
test('hideScopedEmptyDividers-hidden1', () => {
26+
test('hideScopedEmptyDividers-items-all-filtered', () => {
27+
const container = createElementFromHTML(`<div>
28+
<div class="any"></div>
29+
<div class="divider"></div>
30+
<div class="item filtered">a</div>
31+
<div class="item filtered">b</div>
32+
<div class="divider"></div>
33+
<div class="any"></div>
34+
</div>`);
35+
hideScopedEmptyDividers(container);
36+
expect(container.innerHTML).toEqual(`
37+
<div class="any"></div>
38+
<div class="divider"></div>
39+
<div class="item filtered">a</div>
40+
<div class="item filtered">b</div>
41+
<div class="divider hidden transition"></div>
42+
<div class="any"></div>
43+
`);
44+
});
45+
46+
test('hideScopedEmptyDividers-hide-last', () => {
2747
const container = createElementFromHTML(`<div>
2848
<div class="item">a</div>
2949
<div class="divider" data-scope="b"></div>
@@ -37,7 +57,7 @@ test('hideScopedEmptyDividers-hidden1', () => {
3757
`);
3858
});
3959

40-
test('hideScopedEmptyDividers-hidden2', () => {
60+
test('hideScopedEmptyDividers-scoped-items', () => {
4161
const container = createElementFromHTML(`<div>
4262
<div class="item" data-scope="">a</div>
4363
<div class="divider" data-scope="b"></div>

web_src/js/modules/fomantic/dropdown.ts

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const fomanticDropdownFn = $.fn.dropdown;
99
// use our own `$().dropdown` function to patch Fomantic's dropdown module
1010
export function initAriaDropdownPatch() {
1111
if ($.fn.dropdown === ariaDropdownFn) throw new Error('initAriaDropdownPatch could only be called once');
12+
$.fn.dropdown.settings.onAfterFiltered = onAfterFiltered;
1213
$.fn.dropdown = ariaDropdownFn;
1314
$.fn.fomanticExt.onResponseKeepSelectedItem = onResponseKeepSelectedItem;
1415
(ariaDropdownFn as FomanticInitFunction).settings = fomanticDropdownFn.settings;
@@ -67,8 +68,9 @@ function updateSelectionLabel(label: HTMLElement) {
6768
}
6869
}
6970

70-
function processMenuItems($dropdown: any, dropdownCall: any) {
71-
const hideEmptyDividers = dropdownCall('setting', 'hideDividers') === 'empty';
71+
function onAfterFiltered(this: any) {
72+
const $dropdown = $(this);
73+
const hideEmptyDividers = $dropdown.dropdown('setting', 'hideDividers') === 'empty';
7274
const itemsMenu = $dropdown[0].querySelector('.scrolling.menu') || $dropdown[0].querySelector('.menu');
7375
if (hideEmptyDividers) hideScopedEmptyDividers(itemsMenu);
7476
}
@@ -77,18 +79,6 @@ function processMenuItems($dropdown: any, dropdownCall: any) {
7779
function delegateDropdownModule($dropdown: any) {
7880
const dropdownCall = fomanticDropdownFn.bind($dropdown);
7981

80-
const oldFilterItems = dropdownCall('internal', 'filterItems');
81-
dropdownCall('internal', 'filterItems', function (this: any, ...args: any[]) {
82-
oldFilterItems.call(this, ...args);
83-
processMenuItems($dropdown, dropdownCall);
84-
});
85-
86-
const oldShow = dropdownCall('internal', 'show');
87-
dropdownCall('internal', 'show', function (this: any, ...args: any[]) {
88-
oldShow.call(this, ...args);
89-
processMenuItems($dropdown, dropdownCall);
90-
});
91-
9282
// the "template" functions are used for dynamic creation (eg: AJAX)
9383
const dropdownTemplates = {...dropdownCall('setting', 'templates'), t: performance.now()};
9484
const dropdownTemplatesMenuOld = dropdownTemplates.menu;
@@ -301,9 +291,11 @@ export function hideScopedEmptyDividers(container: Element) {
301291
const visibleItems: Element[] = [];
302292
const curScopeVisibleItems: Element[] = [];
303293
let curScope: string = '', lastVisibleScope: string = '';
304-
const isScopedDivider = (item: Element) => item.matches('.divider') && item.hasAttribute('data-scope');
294+
const isDivider = (item: Element) => item.classList.contains('divider');
295+
const isScopedDivider = (item: Element) => isDivider(item) && item.hasAttribute('data-scope');
305296
const hideDivider = (item: Element) => item.classList.add('hidden', 'transition'); // dropdown has its own classes to hide items
306-
297+
const showDivider = (item: Element) => item.classList.remove('hidden', 'transition');
298+
const isHidden = (item: Element) => item.classList.contains('hidden') || item.classList.contains('filtered') || item.classList.contains('tw-hidden');
307299
const handleScopeSwitch = (itemScope: string) => {
308300
if (curScopeVisibleItems.length === 1 && isScopedDivider(curScopeVisibleItems[0])) {
309301
hideDivider(curScopeVisibleItems[0]);
@@ -319,34 +311,37 @@ export function hideScopedEmptyDividers(container: Element) {
319311
curScopeVisibleItems.length = 0;
320312
};
321313

314+
// reset hidden dividers
315+
queryElems(container, '.divider', showDivider);
316+
322317
// hide the scope dividers if the scope items are empty
323318
for (const item of container.children) {
324319
const itemScope = item.getAttribute('data-scope') || '';
325320
if (itemScope !== curScope) {
326321
handleScopeSwitch(itemScope);
327322
}
328-
if (!item.classList.contains('filtered') && !item.classList.contains('tw-hidden')) {
323+
if (!isHidden(item)) {
329324
curScopeVisibleItems.push(item as HTMLElement);
330325
}
331326
}
332327
handleScopeSwitch('');
333328

334329
// hide all leading and trailing dividers
335330
while (visibleItems.length) {
336-
if (!visibleItems[0].matches('.divider')) break;
331+
if (!isDivider(visibleItems[0])) break;
337332
hideDivider(visibleItems[0]);
338333
visibleItems.shift();
339334
}
340335
while (visibleItems.length) {
341-
if (!visibleItems[visibleItems.length - 1].matches('.divider')) break;
336+
if (!isDivider(visibleItems[visibleItems.length - 1])) break;
342337
hideDivider(visibleItems[visibleItems.length - 1]);
343338
visibleItems.pop();
344339
}
345340
// hide all duplicate dividers, hide current divider if next sibling is still divider
346341
// no need to update "visibleItems" array since this is the last loop
347-
for (const item of visibleItems) {
348-
if (!item.matches('.divider')) continue;
349-
if (item.nextElementSibling?.matches('.divider')) hideDivider(item);
342+
for (let i = 0; i < visibleItems.length - 1; i++) {
343+
if (!visibleItems[i].matches('.divider')) continue;
344+
if (visibleItems[i + 1].matches('.divider')) hideDivider(visibleItems[i + 1]);
350345
}
351346
}
352347

0 commit comments

Comments
 (0)