import { Arr, Future, Result } from '@ephox/katamari'; import { Attribute, Class, Html, type SugarElement, SugarNode } from '@ephox/sugar'; import type { AlloyComponent } from '../../api/component/ComponentApi'; import type { Stateless } from '../common/BehaviourState'; import type { InvalidatingConfig } from './InvalidateTypes'; const ariaElements = [ 'input', 'textarea' ]; const isAriaElement = (elem: SugarElement): elem is SugarElement => { const name = SugarNode.name(elem); return Arr.contains(ariaElements, name); }; const markValid = (component: AlloyComponent, invalidConfig: InvalidatingConfig): void => { const elem = invalidConfig.getRoot(component).getOr(component.element); Class.remove(elem, invalidConfig.invalidClass); invalidConfig.notify.each((notifyInfo) => { if (isAriaElement(component.element)) { Attribute.set(component.element, 'aria-invalid', false); } notifyInfo.getContainer(component).each((container) => { Html.set(container, notifyInfo.validHtml); }); notifyInfo.onValid(component); }); }; const markInvalid = (component: AlloyComponent, invalidConfig: InvalidatingConfig, invalidState: Stateless, text: string): void => { const elem = invalidConfig.getRoot(component).getOr(component.element); Class.add(elem, invalidConfig.invalidClass); invalidConfig.notify.each((notifyInfo) => { if (isAriaElement(component.element)) { Attribute.set(component.element, 'aria-invalid', true); } notifyInfo.getContainer(component).each((container) => { // TODO: Should we just use Text here, not HTML? Html.set(container, text); }); notifyInfo.onInvalid(component, text); }); }; const query = (component: AlloyComponent, invalidConfig: InvalidatingConfig, _invalidState: Stateless): Future> => invalidConfig.validator.fold( () => Future.pure(Result.value(true)), (validatorInfo) => validatorInfo.validate(component) ); const run = (component: AlloyComponent, invalidConfig: InvalidatingConfig, invalidState: Stateless): Future> => { invalidConfig.notify.each((notifyInfo) => { notifyInfo.onValidate(component); }); return query(component, invalidConfig, invalidState).map((valid: Result) => { if (component.getSystem().isConnected()) { return valid.fold((err) => { markInvalid(component, invalidConfig, invalidState, err); return Result.error(err); }, (v) => { markValid(component, invalidConfig); return Result.value(v); }); } else { return Result.error('No longer in system'); } }); }; const isInvalid = (component: AlloyComponent, invalidConfig: InvalidatingConfig): boolean => { const elem = invalidConfig.getRoot(component).getOr(component.element); return Class.has(elem, invalidConfig.invalidClass); }; export { markValid, markInvalid, query, run, isInvalid };