import { Arr } from '@ephox/katamari'; import { Insert, Remove, SugarBody, type SugarElement, Traverse } from '@ephox/sugar'; import * as InternalAttachment from '../../system/InternalAttachment'; import type { AlloyComponent } from '../component/ComponentApi'; import type { GuiSystem } from './Gui'; const attach = (parent: AlloyComponent, child: AlloyComponent): void => { attachWith(parent, child, Insert.append); }; const attachWith = (parent: AlloyComponent, child: AlloyComponent, insertion: (parent: SugarElement, child: SugarElement) => void): void => { parent.getSystem().addToWorld(child); insertion(parent.element, child.element); if (SugarBody.inBody(parent.element)) { InternalAttachment.fireAttaching(child); } parent.syncComponents(); }; const doDetach = (component: AlloyComponent) => { InternalAttachment.fireDetaching(component); Remove.remove(component.element); component.getSystem().removeFromWorld(component); }; const detach = (component: AlloyComponent): void => { const parent = Traverse.parent(component.element).bind((p) => component.getSystem().getByDom(p).toOptional()); doDetach(component); parent.each((p) => { p.syncComponents(); }); }; const detachChildren = (component: AlloyComponent): void => { // This will not detach the component, but will detach its children and sync at the end. const subs = component.components(); Arr.each(subs, doDetach); // Clear the component also. Remove.empty(component.element); component.syncComponents(); }; const attachSystem = (element: SugarElement, guiSystem: GuiSystem): void => { attachSystemWith(element, guiSystem, Insert.append); }; const attachSystemAfter = (element: SugarElement, guiSystem: GuiSystem): void => { attachSystemWith(element, guiSystem, Insert.after); }; const attachSystemWith = (element: SugarElement, guiSystem: GuiSystem, inserter: (marker: SugarElement, element: SugarElement) => void): void => { inserter(element, guiSystem.element); const children = Traverse.children(guiSystem.element); Arr.each(children, (child) => { guiSystem.getByDom(child).each(InternalAttachment.fireAttaching); }); }; const detachSystem = (guiSystem: GuiSystem): void => { const children = Traverse.children(guiSystem.element); Arr.each(children, (child) => { guiSystem.getByDom(child).each(InternalAttachment.fireDetaching); }); Remove.remove(guiSystem.element); }; export { attach, attachWith, detach, detachChildren, attachSystem, attachSystemAfter, detachSystem };