package xapi.ui.api; import xapi.collect.api.IntTo; import xapi.event.api.IsEvent; import xapi.event.impl.EventTypes; import xapi.fu.In1Out1; import xapi.inject.X_Inject; import xapi.ui.api.event.UiEvent; import xapi.ui.api.event.UiEventHandler; import xapi.ui.impl.DelegateElementInjector; import xapi.ui.service.UiService; import javax.validation.constraints.NotNull; /** * @author James X. Nelson (james@wetheinter.net) * Created on 4/18/16. */ public interface UiElement <Node, Element extends Node, Base extends UiElement<Node, ? extends Node, Base>> extends ElementInjector<Node, Base> { Base getParent(); Base setParent(Base parent); IntTo<Base> getChildren(); String toSource(); Element element(); default Node getHost() { return (Node)UiService.getUiService().getHost(this); } <F extends UiFeature, Generic extends F> F getFeature(Class<Generic> cls); <F extends UiFeature, Generic extends F> F addFeature(Class<Generic> cls, F feature); default <F extends UiFeature, Generic extends F> F getOrAddFeature(Class<Generic> cls, In1Out1<Base, F> factory) { F f = getFeature(cls); if (f == null) { f = factory.io(ui()); // purposely not null checking. Will leave this to implementors to enforce. f.initialize(this, getUiService()); addFeature(cls, f); } return f; } default UiEventsFeature getEvents() { return getOrAddFeature(UiEventsFeature.class, i->createFeature(UiEventsFeature.class)); } default <F extends UiFeature, Generic extends F> F createFeature(Class<Generic> cls) { return X_Inject.instance(cls); } @SuppressWarnings("unchecked") default Base ui() { return (Base) this; } default UiWithAttributes<Node, Base> getAttributes() { return getOrAddFeature(UiWithAttributes.class, e->getUiService().newAttributes(e)); } default UiWithProperties<Node, Base> getProperties() { return getOrAddFeature(UiWithProperties.class, e->getUiService().newProperties(e)); } default UiService<Node, Base> getUiService() { return UiService.getUiService(); } @Override default void appendChild(Base newChild) { asInjector().appendChild(newChild); newChild.setParent(ui()); } @Override default void removeChild(Base child) { asInjector().removeChild(child); } void insertAdjacent(ElementPosition pos, Base child); default void insertBefore(Base newChild) { asInjector().insertBefore(newChild); } default void insertAtBegin(Base newChild) { asInjector().insertAtBegin(newChild); } default void insertAfter(Base newChild) { asInjector().insertAfter(newChild); } default void insertAtEnd(Base newChild) { asInjector().insertAtEnd(newChild); } default ElementInjector<Node, Base> asInjector() { // Platforms like Gwt might erase the type information off a // raw html / javascript type, so we return "real java objects" here. // This also allows implementors to insert control logic to the element attachment methods. return new DelegateElementInjector<>(ui()); } default boolean removeFromParent() { final Base parent = getParent(); if (parent != null) { parent.removeChild(ui()); assert getParent() == null : "Parent did not correctly detach child." + "\nChild " + toSource()+ "\nParent " + parent.toSource(); return true; } return false; } default boolean fireEventCapture(@NotNull IsEvent<?> event) { return getEvents().fireCapture(event); } default boolean handlesBubble(@NotNull IsEvent<?> event) { return getEvents().fireCapture(event); } default boolean handlesCapture(@NotNull IsEvent<?> event) { return getEvents().fireCapture(event); } default boolean fireEventBubble(@NotNull IsEvent<?> event) { return getEvents().fireBubble(event); } default <Payload> Base onEventBubble(EventTypes type, UiEventHandler<Payload, Node, Base, ? extends UiEvent<Payload, Node, Base>> handler) { getEvents().addBubbling(type, handler); return ui(); } default <Payload> Base onEvent(EventTypes type, UiEventHandler<Payload, Node, Base, ? extends UiEvent<Payload, Node, Base>> handler, boolean capture) { if (capture) { return onEventCapture(type, handler); } else { return onEventBubble(type, handler); } } default <Payload> Base onEventCapture(EventTypes type, UiEventHandler<Payload, Node, Base, ? extends UiEvent<Payload, Node, Base>> handler) { getEvents().addCapturing(type, handler); return ui(); } boolean addStyleName(String style); boolean removeStyleName(String style); }