All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dominokit.domino.ui.utils.BodyObserver Maven / Gradle / Ivy

There is a newer version: 1.0.139
Show newest version
package org.dominokit.domino.ui.utils;

import elemental2.core.JsArray;
import elemental2.dom.*;
import jsinterop.base.Js;
import org.jboss.elemento.Elements;
import org.jboss.elemento.ObserverCallback;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

import static elemental2.dom.DomGlobal.document;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;

final class BodyObserver {

    private static String ATTACH_UID_KEY = "on-attach-uid";
    private static String DETACH_UID_KEY = "on-detach-uid";

    private static List detachObservers = new ArrayList<>();
    private static List attachObservers = new ArrayList<>();
    private static boolean ready = false;

    private static void startObserving() {
        MutationObserver mutationObserver = new MutationObserver(
                (MutationRecord[] records, MutationObserver observer) -> {
                    for (MutationRecord record : records) {
                        if (!record.removedNodes.asList().isEmpty()) {
                            onElementsRemoved(record);
                        }

                        if (!record.addedNodes.asList().isEmpty()) {
                            onElementsAppended(record);
                        }
                    }
                    return null;
                });

        MutationObserverInit mutationObserverInit = MutationObserverInit.create();
        mutationObserverInit.setChildList(true);
        mutationObserverInit.setSubtree(true);
        mutationObserver.observe(document.body, mutationObserverInit);
        ready = true;
    }

    private static void onElementsAppended(MutationRecord record) {
        List nodes = record.addedNodes.asList();
        List observed = new ArrayList<>();
        for (ElementObserver elementObserver : attachObservers) {
            if (isNull(elementObserver.observedElement())) {
                observed.add(elementObserver);
            } else {
                if (nodes.contains(elementObserver.observedElement()) || isChildOfAddedNode(record, elementObserver.attachId())) {
                    elementObserver.callback().onObserved(record);
                    observed.add(elementObserver);
                }
            }
        }

        attachObservers.removeAll(observed);
    }

    private static boolean isChildOfAddedNode(MutationRecord record, String attachId) {
        return isChildOfObservedNode(attachId, record.addedNodes.asList(), ATTACH_UID_KEY);
    }

    private static void onElementsRemoved(MutationRecord record) {
        List nodes = record.removedNodes.asList();
        List observed = new ArrayList<>();
        for (ElementObserver elementObserver : detachObservers) {
            if (isNull(elementObserver.observedElement())) {
                observed.add(elementObserver);
            } else {
                if (nodes.contains(elementObserver.observedElement()) || isChildOfRemovedNode(record, elementObserver.attachId())) {
                    elementObserver.callback().onObserved(record);
                    observed.add(elementObserver);
                }
            }
        }
        detachObservers.removeAll(observed);
    }

    private static boolean isChildOfRemovedNode(MutationRecord record, final String detachId) {
        return isChildOfObservedNode(detachId, record.removedNodes.asList(), DETACH_UID_KEY);
    }

    private static boolean isChildOfObservedNode(String attachId, List nodes, String attachUidKey) {

        for (int i = 0; i < nodes.size(); i++) {
            Node elementNode = Js.uncheckedCast(nodes.get(i));
            if (Node.ELEMENT_NODE == elementNode.nodeType) {
                if (nonNull(elementNode.querySelector("[" + attachUidKey + "='" + attachId + "']"))) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Check if the observer is already started, if not it will start it, then register and callback for when the
     * element is attached to the dom.
     */
    static ElementObserver addAttachObserver(HTMLElement element, ObserverCallback callback) {
        if (!ready) {
            startObserving();
        }
        ElementObserver observer = createObserver(element, callback, ATTACH_UID_KEY, elementObserver -> attachObservers.remove(elementObserver));
        attachObservers.add(observer);
        return observer;
    }

    /**
     * Check if the observer is already started, if not it will start it, then register and callback for when the
     * element is removed from the dom.
     */
    static ElementObserver addDetachObserver(HTMLElement element, ObserverCallback callback) {
        if (!ready) {
            startObserving();
        }
        ElementObserver observer = createObserver(element, callback, DETACH_UID_KEY, elementObserver -> detachObservers.remove(elementObserver));
        detachObservers.add(observer);

        return observer;
    }

    private static ElementObserver createObserver(HTMLElement element, ObserverCallback callback,
                                                  String idAttributeName, Consumer onRemoveHandler) {
        String elementId = element.getAttribute(idAttributeName);
        if (elementId == null) {
            element.setAttribute(idAttributeName, Elements.uniqueId());
        }

        return new ElementObserver() {
            @Override
            public String attachId() {
                return element.getAttribute(idAttributeName);
            }

            @Override
            public HTMLElement observedElement() {
                return element;
            }

            @Override
            public ObserverCallback callback() {
                return callback;
            }

            @Override
            public void remove() {
                onRemoveHandler.accept(this);
            }
        };
    }

    private BodyObserver() {
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy