Refactor sidebar label selector (#32460)

Introduce `issueSidebarLabelsData` to handle all sidebar labels related data.
This commit is contained in:
wxiaoguang 2024-11-10 16:26:42 +08:00 committed by GitHub
parent b55a31eb6a
commit 58c634b854
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 276 additions and 233 deletions

View file

@ -1,6 +1,6 @@
import {fomanticQuery} from '../modules/fomantic/base.ts';
import {POST} from '../modules/fetch.ts';
import {queryElemChildren, toggleElem} from '../utils/dom.ts';
import {queryElemChildren, queryElems, toggleElem} from '../utils/dom.ts';
// if there are draft comments, confirm before reloading, to avoid losing comments
export function issueSidebarReloadConfirmDraftComment() {
@ -27,20 +27,37 @@ function collectCheckedValues(elDropdown: HTMLElement) {
}
export function initIssueSidebarComboList(container: HTMLElement) {
if (!container) return;
const updateUrl = container.getAttribute('data-update-url');
const elDropdown = container.querySelector<HTMLElement>(':scope > .ui.dropdown');
const elList = container.querySelector<HTMLElement>(':scope > .ui.list');
const elComboValue = container.querySelector<HTMLInputElement>(':scope > .combo-value');
const initialValues = collectCheckedValues(elDropdown);
let initialValues = collectCheckedValues(elDropdown);
elDropdown.addEventListener('click', (e) => {
const elItem = (e.target as HTMLElement).closest('.item');
if (!elItem) return;
e.preventDefault();
if (elItem.getAttribute('data-can-change') !== 'true') return;
elItem.classList.toggle('checked');
if (elItem.hasAttribute('data-can-change') && elItem.getAttribute('data-can-change') !== 'true') return;
if (elItem.matches('.clear-selection')) {
queryElems(elDropdown, '.menu > .item', (el) => el.classList.remove('checked'));
elComboValue.value = '';
return;
}
const scope = elItem.getAttribute('data-scope');
if (scope) {
// scoped items could only be checked one at a time
const elSelected = elDropdown.querySelector<HTMLElement>(`.menu > .item.checked[data-scope="${CSS.escape(scope)}"]`);
if (elSelected === elItem) {
elItem.classList.toggle('checked');
} else {
queryElems(elDropdown, `.menu > .item[data-scope="${CSS.escape(scope)}"]`, (el) => el.classList.remove('checked'));
elItem.classList.toggle('checked', true);
}
} else {
elItem.classList.toggle('checked');
}
elComboValue.value = collectCheckedValues(elDropdown).join(',');
});
@ -61,29 +78,28 @@ export function initIssueSidebarComboList(container: HTMLElement) {
if (changed) issueSidebarReloadConfirmDraftComment();
};
const syncList = (changedValues) => {
const syncUiList = (changedValues) => {
const elEmptyTip = elList.querySelector('.item.empty-list');
queryElemChildren(elList, '.item:not(.empty-list)', (el) => el.remove());
for (const value of changedValues) {
const el = elDropdown.querySelector<HTMLElement>(`.menu > .item[data-value="${value}"]`);
const el = elDropdown.querySelector<HTMLElement>(`.menu > .item[data-value="${CSS.escape(value)}"]`);
const listItem = el.cloneNode(true) as HTMLElement;
listItem.querySelector('svg.octicon-check')?.remove();
queryElems(listItem, '.item-check-mark, .item-secondary-info', (el) => el.remove());
elList.append(listItem);
}
const hasItems = Boolean(elList.querySelector('.item:not(.empty-list)'));
toggleElem(elEmptyTip, !hasItems);
};
fomanticQuery(elDropdown).dropdown({
fomanticQuery(elDropdown).dropdown('setting', {
action: 'nothing', // do not hide the menu if user presses Enter
fullTextSearch: 'exact',
async onHide() {
// TODO: support "Esc" to cancel the selection. Use partial page loading to avoid losing inputs.
const changedValues = collectCheckedValues(elDropdown);
if (updateUrl) {
await updateToBackend(changedValues); // send requests to backend and reload the page
} else {
syncList(changedValues); // only update the list in the sidebar
}
syncUiList(changedValues);
if (updateUrl) await updateToBackend(changedValues);
initialValues = changedValues;
},
});
}