diff --git a/src/bundle/Resources/public/js/scripts/core/dropdown.js b/src/bundle/Resources/public/js/scripts/core/dropdown.js index 17ea6646bd..0ec81781aa 100644 --- a/src/bundle/Resources/public/js/scripts/core/dropdown.js +++ b/src/bundle/Resources/public/js/scripts/core/dropdown.js @@ -179,6 +179,10 @@ const stringifiedValue = JSON.stringify(String(value)); const optionToSelect = this.itemsListContainer.querySelector(`.ibexa-dropdown__item[data-value=${stringifiedValue}]`); + if (optionToSelect?.classList.contains('ibexa-dropdown__item--disabled')) { + return; + } + return this.onSelect(optionToSelect, true); } @@ -243,6 +247,10 @@ } onSelect(element, selected) { + if (!element || element.classList.contains('ibexa-dropdown__item--disabled')) { + return; + } + if (this.canSelectOnlyOne && selected) { this.hideOptions(); this.clearCurrentSelection(false); @@ -294,6 +302,11 @@ onOptionClick({ target }) { const option = target.closest('.ibexa-dropdown__item'); + + if (!option || option.classList.contains('ibexa-dropdown__item--disabled')) { + return; + } + const isSelected = this.canSelectOnlyOne || !option.classList.contains('ibexa-dropdown__item--selected'); return this.onSelect(option, isSelected); @@ -455,7 +468,7 @@ }); optionsToRecreate.forEach((option) => { - this.createOption(option.value, option.innerHTML); + this.createOption(option.value, option.innerHTML, option.disabled); }); const selectedItems = this.getSelectedItems(); @@ -479,7 +492,7 @@ optionNode.remove(); } - createOption(value, label) { + createOption(value, label, isDisabled = false) { const container = doc.createElement('div'); const itemRendered = this.itemTemplate.replaceAll('{{ value }}', escapeHTMLAttribute(value)).replaceAll('{{ label }}', label); @@ -487,6 +500,11 @@ const optionNode = container.firstElementChild; + if (isDisabled) { + optionNode.classList.add('ibexa-dropdown__item--disabled'); + optionNode.setAttribute('aria-disabled', 'true'); + } + optionNode.addEventListener('click', this.onOptionClick, false); this.itemsListContainer.append(optionNode); } @@ -578,7 +596,7 @@ this.itemsPopover._element.addEventListener('shown.bs.popover', this.onPopoverShow); this.itemsPopover._element.addEventListener('hidden.bs.popover', this.onPopoverHide); this.itemsListContainer - .querySelectorAll('.ibexa-dropdown__item:not([disabled])') + .querySelectorAll('.ibexa-dropdown__item:not(.ibexa-dropdown__item--disabled)') .forEach((option) => option.addEventListener('click', this.onOptionClick, false)); if (this.itemsFilterInput) { @@ -626,6 +644,43 @@ selectedItems.forEach((selectedItem) => this.attachSelectedItemEvents(selectedItem)); } + + disableOption(value) { + const stringifiedValue = JSON.stringify(String(value)); + const item = this.itemsListContainer.querySelector(`[data-value=${stringifiedValue}]`); + const option = this.sourceInput.querySelector(`[value=${stringifiedValue}]`); + + if (item) { + item.classList.add('ibexa-dropdown__item--disabled'); + item.setAttribute('aria-disabled', 'true'); + } + + if (option) { + option.disabled = true; + } + } + + enableOption(value) { + const stringifiedValue = JSON.stringify(String(value)); + const item = this.itemsListContainer.querySelector(`[data-value=${stringifiedValue}]`); + const option = this.sourceInput.querySelector(`[value=${stringifiedValue}]`); + + if (item) { + item.classList.remove('ibexa-dropdown__item--disabled'); + item.removeAttribute('aria-disabled'); + } + + if (option) { + option.disabled = false; + } + } + + isOptionDisabled(value) { + const stringifiedValue = JSON.stringify(String(value)); + const option = this.sourceInput.querySelector(`[value=${stringifiedValue}]`); + + return option.disabled; + } } ibexa.addConfig('core.Dropdown', Dropdown); diff --git a/src/bundle/Resources/public/scss/_dropdown.scss b/src/bundle/Resources/public/scss/_dropdown.scss index dabe32511a..94585e622c 100644 --- a/src/bundle/Resources/public/scss/_dropdown.scss +++ b/src/bundle/Resources/public/scss/_dropdown.scss @@ -557,3 +557,12 @@ margin: calculateRem(5px) calculateRem(8px); } } + +.ibexa-dropdown__item--disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.ibexa-dropdown__item--disabled * { + pointer-events: none; +}