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

org.dominokit.domino.ui.tree.TreeItem Maven / Gradle / Ivy

package org.dominokit.domino.ui.tree;

import elemental2.dom.*;
import org.dominokit.domino.ui.collapsible.Collapsible;
import org.dominokit.domino.ui.icons.BaseIcon;
import org.dominokit.domino.ui.icons.Icons;
import org.dominokit.domino.ui.style.Style;
import org.dominokit.domino.ui.style.WaveColor;
import org.dominokit.domino.ui.style.WaveStyle;
import org.dominokit.domino.ui.style.WavesElement;
import org.dominokit.domino.ui.utils.*;
import org.jboss.gwt.elemento.core.EventType;

import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static org.dominokit.domino.ui.style.Unit.px;
import static org.jboss.gwt.elemento.core.Elements.*;

public class TreeItem extends WavesElement implements ParentTreeItem, CanActivate, CanDeactivate, HasClickableElement {

    private String title;
    private HTMLLIElement element;
    private DominoElement anchorElement;
    private List subItems = new LinkedList<>();
    private TreeItem activeTreeItem;
    private ParentTreeItem parent;
    private Collapsible collapsible;

    private HTMLUListElement childrenContainer;
    private BaseIcon icon;
    private BaseIcon activeIcon;
    private BaseIcon originalIcon;
    private HTMLElement titleElement;

    private BaseIcon expandIcon;

    private int nextLevel = 1;

    public TreeItem(String title, BaseIcon icon) {
        this.title = title;
        setIcon(icon);
        this.titleElement = span().css("title").textContent(title).asElement();
        this.anchorElement = DominoElement.of(a()
                .add(this.icon)
                .add(div().style("margin-top: 2px;").add(titleElement)));
        init();
    }

    public TreeItem(String title) {
        this(title, Icons.ALL.folder().styler(style -> style.setProperty("visibility", "hidden")));
    }

    public TreeItem(BaseIcon icon) {
        setIcon(icon);
        this.anchorElement = DominoElement.of(a()
                .add(this.icon));
        init();
    }

    public static TreeItem create(String title) {
        return new TreeItem(title);
    }

    public static TreeItem create(String title, BaseIcon icon) {
        return new TreeItem(title, icon);
    }

    public static TreeItem create(BaseIcon icon) {
        return new TreeItem(icon);
    }

    /**
     * @deprecated use {@link #appendChild(TreeItem)}
     */
    @Deprecated
    public TreeItem addTreeItem(TreeItem treeItem) {
        return appendChild(treeItem);
    }

    public TreeItem appendChild(TreeItem treeItem) {
        this.subItems.add(treeItem);
        childrenContainer.appendChild(treeItem.asElement());
        Style.of(anchorElement).add("tree-toggle");
        treeItem.parent = this;
        treeItem.setLevel(nextLevel);
        Style.of(treeItem).add("tree-leaf");
        Style.of(this.asElement()).remove("tree-leaf");
        return this;
    }

    public TreeItem addSeparator() {
        childrenContainer.appendChild(li().css("separator")
                .add(a())
                .asElement());
        return this;
    }

    private void init() {
        this.element = li().asElement();
        this.element.appendChild(anchorElement.asElement());
        childrenContainer = ul().css("ml-tree").asElement();
        asElement().appendChild(childrenContainer);
        collapsible = Collapsible.create(childrenContainer)
                .addHideHandler(() -> {
                    Style.of(anchorElement).remove("toggled");
                    restoreIcon();
                })
                .addShowHandler(() -> {
                    Style.of(anchorElement).add("toggled");
                    replaceIcon(expandIcon);
                })
                .hide();
        anchorElement.addEventListener("click", evt -> {
            if (isParent()) {
                collapsible.toggleDisplay();
            }
            parent.setActiveItem(TreeItem.this);
        });
        init(this);
        setWaveColor(WaveColor.THEME);
        applyWaveStyle(WaveStyle.BLOCK);
    }

    public TreeItem show() {
        return show(false);
    }

    public TreeItem show(boolean expandParent) {
        if (isParent()) {
            collapsible.show();
        }
        if (expandParent && nonNull(parent)) {
            parent.expand(expandParent);
        }
        return this;
    }

    /**
     * @deprecated use {@link #show(boolean)}
     */
    @Deprecated
    public TreeItem expand(boolean expandParent) {
        return show(expandParent);
    }

    public TreeItem hide() {
        if (isParent()) {
            collapsible.hide();
        }
        return this;
    }

    public TreeItem toggleDisplay() {
        if (isParent()) {
            collapsible.toggleDisplay();
        }
        return this;
    }

    @Override
    public boolean isHidden() {
        return collapsible.isHidden();
    }

    @Override
    public TreeItem addHideHandler(Collapsible.HideCompletedHandler handler) {
        collapsible.addHideHandler(handler);
        return this;
    }

    @Override
    public TreeItem removeHideHandler(Collapsible.HideCompletedHandler handler) {
        collapsible.removeHideHandler(handler);
        return this;
    }

    @Override
    public TreeItem addShowHandler(Collapsible.ShowCompletedHandler handler) {
        collapsible.addShowHandler(handler);
        return this;
    }

    @Override
    public TreeItem removeShowHandler(Collapsible.ShowCompletedHandler handler) {
        collapsible.removeShowHandler(handler);
        return this;
    }

    @Override
    public HTMLLIElement asElement() {
        return element;
    }

    @Override
    public TreeItem getActiveItem() {
        return activeTreeItem;
    }

    @Override
    public Tree getTreeRoot() {
        return parent.getTreeRoot();
    }

    @Override
    public void setActiveItem(TreeItem activeItem) {
        if (nonNull(activeItem)) {
            if (nonNull(this.activeTreeItem) && !this.activeTreeItem.equals(activeItem)) {
                this.activeTreeItem.deactivate();
            }
            this.activeTreeItem = activeItem;
            this.activeTreeItem.activate();
            parent.setActiveItem(this);
        }
    }

    @Override
    public void activate() {
        activate(false);
    }

    @Override
    public void activate(boolean activateParent) {
        Style.of(asElement()).add("active");
        if (isNull(expandIcon) || collapsible.isHidden() || !isParent()) {
            replaceIcon(this.activeIcon);
        }


        if (activateParent && nonNull(parent)) {
            parent.setActiveItem(this);

        }
    }

    private void replaceIcon(BaseIcon newIcon) {
        if (nonNull(newIcon)) {
            if (nonNull(icon)) {
                icon.remove();
            }
            anchorElement.insertFirst(newIcon);
            this.icon = newIcon;
        }
    }

    @Override
    public void deactivate() {
        Style.of(asElement()).remove("active");
        if (isNull(expandIcon) || collapsible.isHidden() || !isParent()) {
            restoreIcon();
        }
        if (isParent()) {
            subItems.forEach(TreeItem::deactivate);
            if (getTreeRoot().isAutoCollapse()) {
                collapsible.hide();
            }
        }
    }

    private void restoreIcon() {
        if (nonNull(originalIcon)) {
            icon.remove();
            anchorElement.insertFirst(originalIcon);
            this.icon = originalIcon;
        } else {
            if (nonNull(icon)) {
                icon.remove();
            }
        }
    }

    @Override
    public HTMLAnchorElement getClickableElement() {
        return anchorElement.asElement();
    }

    public TreeItem addClickListener(EventListener listener) {
        getClickableElement().addEventListener(EventType.click.getName(), listener);
        return this;
    }

    public TreeItem setIcon(BaseIcon icon) {
        this.icon = icon;
        this.originalIcon = icon.copy();
        if (icon.asElement().style.visibility.equals("hidden")) {
            this.originalIcon.styler(style -> style.setProperty("visibility", "hidden"));
        }
        return this;
    }

    public TreeItem setActiveIcon(BaseIcon activeIcon) {
        this.activeIcon = activeIcon;
        return this;
    }

    public TreeItem setExpandIcon(BaseIcon expandIcon) {
        this.expandIcon = expandIcon;
        return this;
    }

    boolean isParent() {
        return !subItems.isEmpty();
    }

    void setParent(ParentTreeItem parentMenu) {
        this.parent = parentMenu;
    }

    public String getTitle() {
        return title;
    }

    public boolean filter(String searchToken) {

        boolean found;
        if (isParent()) {
            found = title.toLowerCase().contains(searchToken.toLowerCase()) | filterChildren(searchToken);
        } else {
            found = title.toLowerCase().contains(searchToken.toLowerCase());
        }

        if (found) {
            Style.of(element).removeProperty("display");
            if (isParent() && isAutoExpandFound() && collapsible.isHidden()) {
                collapsible.show();
            }
            return true;
        } else {
            Style.of(element).setDisplay("none");
            return false;
        }
    }

    @Override
    public boolean isAutoExpandFound() {
        return parent.isAutoExpandFound();
    }

    public void clearFilter() {
        Style.of(element).removeProperty("display");
        subItems.forEach(TreeItem::clearFilter);
    }

    public boolean filterChildren(String searchToken) {
        return subItems.stream().filter(treeItem -> treeItem.filter(searchToken)).collect(Collectors.toList()).size() > 0;
    }

    public void collapseAll() {
        if (isParent() && !collapsible.isHidden()) {
            hide();
            subItems.forEach(TreeItem::collapseAll);
        }
    }

    public void expandAll() {
        if (isParent() && collapsible.isHidden()) {
            show();
            subItems.forEach(TreeItem::expandAll);
        }
    }

    public void setLevel(int level) {
        this.nextLevel = level + 1;
        if (isParent()) {
            subItems.forEach(treeItem -> treeItem.setLevel(nextLevel));
        }
        anchorElement.style().setPaddingLeft(px.of(nextLevel * 15));
    }

    @Override
    public HTMLElement getWavesElement() {
        return anchorElement.asElement();
    }

    public boolean isLeaf() {
        return subItems.isEmpty();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy