import { Utility } from '../../core/utility'; const INTERACTIVE_FIELDSET_UTIL_TARGET_SELECTOR = '.interactive-fieldset__target'; const INTERACTIVE_FIELDSET_INITIALIZED_CLASS = 'interactive-fieldset--initialized'; const INTERACTIVE_FIELDSET_CHILD_SELECTOR = 'input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled])'; let fieldsetCounter = 0; @Utility({ selector: '[uw-interactive-fieldset]', }) export class InteractiveFieldset { fieldsetIdent = (fieldsetCounter++).toString(); _element; conditionalInput; conditionalValue; target; childInputs; negated; constructor(element) { if (!element) { throw new Error('Interactive Fieldset utility cannot be setup without an element!'); } this._element = element; if (this._element.classList.contains(INTERACTIVE_FIELDSET_INITIALIZED_CLASS)) { return false; } // if (this._element.querySelector('[uw-interactive-fieldset]')) { // return false; // } // param conditionalInput if (!this._element.dataset.conditionalInput) { throw new Error('Interactive Fieldset needs a selector for a conditional input!'); } this.conditionalInput = document.querySelector('#' + this._element.dataset.conditionalInput); if (!this.conditionalInput) { // abort if form has no required inputs throw new Error('Couldn\'t find the conditional input. Aborting setup for interactive fieldset.'); } // param conditionalValue if (!('conditionalValue' in this._element.dataset) && !this._isCheckbox()) { throw new Error('Interactive Fieldset needs a conditional value!'); } this.conditionalValue = this._element.dataset.conditionalValue; this.negated = 'conditionalNegated' in this._element.dataset; this.target = this._element.closest(INTERACTIVE_FIELDSET_UTIL_TARGET_SELECTOR); if (!this.target || this._element.matches(INTERACTIVE_FIELDSET_UTIL_TARGET_SELECTOR)) { this.target = this._element; } this.childInputs = Array.from(this._element.querySelectorAll(INTERACTIVE_FIELDSET_CHILD_SELECTOR)).filter(child => child.closest('[uw-interactive-fieldset]') === this._element); // add event listener const observer = new MutationObserver(this._updateVisibility.bind(this)); observer.observe(this.conditionalInput, { attributes: true, attributeFilter: ['data-interactive-fieldset-hidden'] }); this.conditionalInput.addEventListener('input', this._updateVisibility.bind(this)); // mark as initialized this._element.classList.add(INTERACTIVE_FIELDSET_INITIALIZED_CLASS); } start() { // initial visibility update this._updateVisibility(); } destroy() { // TODO } _updateVisibility() { const active = this._matchesConditionalValue() && !this.conditionalInput.dataset.interactiveFieldsetHidden; let hiddenBy = (this.target.dataset.interactiveFieldsetHiddenBy || '').split(',').filter(str => str.length !== 0); if (active) hiddenBy = hiddenBy.filter(ident => ident !== this.fieldsetIdent); else if (hiddenBy.every(ident => ident !== this.fieldsetIdent)) hiddenBy = [ ...hiddenBy, this.fieldsetIdent ]; if (hiddenBy.length !== 0) { this.target.dataset.interactiveFieldsetHiddenBy = hiddenBy.join(','); this.target.classList.add('hidden'); } else { delete this.target.dataset['interactiveFieldsetHiddenBy']; this.target.classList.remove('hidden'); } this.childInputs.forEach((el) => this._updateChildVisibility(el, active)); } _updateChildVisibility(el, active) { el.disabled = !active; if (active) { delete el.dataset.interactiveFieldsetHidden; } else { el.dataset.interactiveFieldsetHidden = true; } } _matchesConditionalValue() { var matches; if (this._isCheckbox()) { matches = this.conditionalInput.checked === true; } else if (this._isRadio()) { const radios = Array.from(this.conditionalInput.querySelectorAll('input[type=radio]')); matches = radios.some(radio => radio.checked && radio.value === this.conditionalValue); } else { matches = this.conditionalInput.value === this.conditionalValue; } if (this.negated) { return !matches; } else { return matches; } } _isCheckbox() { return this.conditionalInput.getAttribute('type') === 'checkbox'; } _isRadio() { return !!this.conditionalInput.querySelector('input[type=radio]'); } }