diff --git a/web_src/css/modules/dropdown.css b/web_src/css/modules/dropdown.css index 9d3dc48ada..02957fe31d 100644 --- a/web_src/css/modules/dropdown.css +++ b/web_src/css/modules/dropdown.css @@ -80,6 +80,10 @@ border-top-width: 0; } +.ui.dropdown .menu .hidden { /* for hidden items and dividers */ + display: none; +} + .ui.dropdown .menu > .header { margin: 1rem 0 0.75rem; padding: 0 1.14285714rem; diff --git a/web_src/fomantic/build/components/dropdown.js b/web_src/fomantic/build/components/dropdown.js index b8f066db74..0faed1858c 100644 --- a/web_src/fomantic/build/components/dropdown.js +++ b/web_src/fomantic/build/components/dropdown.js @@ -308,12 +308,12 @@ $.fn.dropdown = function(parameters) { firstUnfiltered: function() { module.verbose('Selecting first non-filtered element'); module.remove.selectedItem(); - $item + const $selectable = $item .not(selector.unselectable) - .not(selector.addition + selector.hidden) - .eq(0) - .addClass(className.selected) - ; + .not(selector.addition + selector.hidden); + let $selectedItem = $selectable.filter(`[data-value="${CSS.escape($input.val())}"]`); // GITEA-PATCH: try to re-select the last selected item for single selection + if (!$selectedItem.length) $selectedItem = $item.eq(0); + $selectedItem.addClass(className.selected); }, nextAvailable: function($selected) { $selected = $selected.eq(0); @@ -772,11 +772,13 @@ $.fn.dropdown = function(parameters) { if(!Array.isArray(preSelected)) { preSelected = preSelected && preSelected!=="" ? preSelected.split(settings.delimiter) : []; } - $.each(preSelected,function(index,value){ - $item.filter('[data-value="'+CSS.escape(value)+'"]') // GITEA-PATCH: use "CSS.escape" for query selector + if (module.is.multiple()) { // GITEA-PATCH: only hide selected items when the dropdown is "multiple selection" + $.each(preSelected, function (index, value) { + $item.filter('[data-value="' + CSS.escape(value) + '"]') // GITEA-PATCH: use "CSS.escape" for query selector .addClass(className.filtered) - ; - }); + ; + }); + } afterFiltered(); }); } diff --git a/web_src/js/features/repo-new.ts b/web_src/js/features/repo-new.ts index b690ace0f7..8b1188f19f 100644 --- a/web_src/js/features/repo-new.ts +++ b/web_src/js/features/repo-new.ts @@ -47,7 +47,6 @@ function initRepoNewTemplateSearch(form: HTMLFormElement) { value: String(tmplRepo.repository.id), }); } - $repoTemplateDropdown.fomanticExt.onResponseKeepSelectedItem($repoTemplateDropdown, inputRepoTemplate.value); return {results}; }, cache: false, diff --git a/web_src/js/modules/fomantic/dropdown.test.ts b/web_src/js/modules/fomantic/dropdown.test.ts index dd3497c8fc..542cb854b8 100644 --- a/web_src/js/modules/fomantic/dropdown.test.ts +++ b/web_src/js/modules/fomantic/dropdown.test.ts @@ -13,13 +13,13 @@ test('hideScopedEmptyDividers-simple', () => { `); hideScopedEmptyDividers(container); expect(container.innerHTML).toEqual(` - +
a
- - + +
b
- + `); }); @@ -35,7 +35,7 @@ test('hideScopedEmptyDividers-items-all-filtered', () => { hideScopedEmptyDividers(container); expect(container.innerHTML).toEqual(`
- +
a
b
@@ -52,7 +52,7 @@ test('hideScopedEmptyDividers-hide-last', () => { hideScopedEmptyDividers(container); expect(container.innerHTML).toEqual(`
a
- +
b
`); }); @@ -68,9 +68,9 @@ test('hideScopedEmptyDividers-scoped-items', () => { hideScopedEmptyDividers(container); expect(container.innerHTML).toEqual(`
a
- +
b
- +
c
`); }); diff --git a/web_src/js/modules/fomantic/dropdown.ts b/web_src/js/modules/fomantic/dropdown.ts index e49c410682..a12b56d23d 100644 --- a/web_src/js/modules/fomantic/dropdown.ts +++ b/web_src/js/modules/fomantic/dropdown.ts @@ -8,7 +8,6 @@ const fomanticDropdownFn = $.fn.dropdown; export function initAriaDropdownPatch() { if ($.fn.dropdown === ariaDropdownFn) throw new Error('initAriaDropdownPatch could only be called once'); $.fn.dropdown = ariaDropdownFn; - $.fn.fomanticExt.onResponseKeepSelectedItem = onResponseKeepSelectedItem; $.fn.fomanticExt.onDropdownAfterFiltered = onDropdownAfterFiltered; (ariaDropdownFn as FomanticInitFunction).settings = fomanticDropdownFn.settings; } @@ -296,8 +295,8 @@ export function hideScopedEmptyDividers(container: Element) { let curScope: string = '', lastVisibleScope: string = ''; const isDivider = (item: Element) => item.classList.contains('divider'); const isScopedDivider = (item: Element) => isDivider(item) && item.hasAttribute('data-scope'); - const hideDivider = (item: Element) => item.classList.add('hidden', 'transition'); // dropdown has its own classes to hide items - const showDivider = (item: Element) => item.classList.remove('hidden', 'transition'); + const hideDivider = (item: Element) => item.classList.add('hidden'); // dropdown has its own classes to hide items + const showDivider = (item: Element) => item.classList.remove('hidden'); const isHidden = (item: Element) => item.classList.contains('hidden') || item.classList.contains('filtered') || item.classList.contains('tw-hidden'); const handleScopeSwitch = (itemScope: string) => { if (curScopeVisibleItems.length === 1 && isScopedDivider(curScopeVisibleItems[0])) { @@ -347,19 +346,3 @@ export function hideScopedEmptyDividers(container: Element) { if (visibleItems[i + 1].matches('.divider')) hideDivider(visibleItems[i]); } } - -function onResponseKeepSelectedItem(dropdown: typeof $ | HTMLElement, selectedValue: string) { - // There is a bug in fomantic dropdown when using "apiSettings" to fetch data - // * when there is a selected item, the dropdown insists on hiding the selected one from the list: - // * in the "filter" function: ('[data-value="'+value+'"]').addClass(className.filtered) - // - // When user selects one item, and click the dropdown again, - // then the dropdown only shows other items and will select another (wrong) one. - // It can't be easily fix by using setTimeout(patch, 0) in `onResponse` because the `onResponse` is called before another `setTimeout(..., timeLeft)` - // Fortunately, the "timeLeft" is controlled by "loadingDuration" which is always zero at the moment, so we can use `setTimeout(..., 10)` - const elDropdown = (dropdown instanceof HTMLElement) ? dropdown : (dropdown as any)[0]; - setTimeout(() => { - queryElems(elDropdown, `.menu .item[data-value="${CSS.escape(selectedValue)}"].filtered`, (el) => el.classList.remove('filtered')); - $(elDropdown).dropdown('set selected', selectedValue ?? ''); - }, 10); -}