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

org.dominokit.domino.ui.cards.Card Maven / Gradle / Ivy

There is a newer version: 2.0.3
Show newest version
/*
 * Copyright © 2019 Dominokit
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.dominokit.domino.ui.cards;

import static java.util.Objects.nonNull;
import static org.dominokit.domino.ui.utils.Domino.*;
import static org.dominokit.domino.ui.utils.Domino.div;
import static org.dominokit.domino.ui.utils.Domino.dui_order_last;

import elemental2.dom.Element;
import elemental2.dom.HTMLDivElement;
import elemental2.dom.HTMLElement;
import elemental2.dom.HTMLImageElement;
import java.util.HashSet;
import java.util.Set;
import org.dominokit.domino.ui.IsElement;
import org.dominokit.domino.ui.config.CardConfig;
import org.dominokit.domino.ui.config.HasComponentConfig;
import org.dominokit.domino.ui.elements.DivElement;
import org.dominokit.domino.ui.elements.HeadingElement;
import org.dominokit.domino.ui.elements.ImageElement;
import org.dominokit.domino.ui.elements.SmallElement;
import org.dominokit.domino.ui.icons.Icon;
import org.dominokit.domino.ui.icons.ToggleIcon;
import org.dominokit.domino.ui.icons.ToggleMdiIcon;
import org.dominokit.domino.ui.style.BooleanCssClass;
import org.dominokit.domino.ui.utils.*;

/**
 * A container component to host other components and elements that provide some extended features
 * like, collapsible body, feature rich header that comes with logo area, title, description and
 * actions toolbar and more.
 *
 * @see BaseDominoElement
 */
public class Card extends BaseDominoElement
    implements CardStyles, CollapsibleElement, HasComponentConfig {
  private DivElement element;
  private DivElement body;

  private LazyChild header;

  private Set> collapseHandlers = new HashSet<>();
  private Set> expandHandlers = new HashSet<>();
  private LazyChild> collapseElement = NullLazyChild.of();

  private final ToggleIcon collapseIcon;

  /**
   * factory method to create an empty card without a header
   *
   * @return a {@link org.dominokit.domino.ui.cards.Card} object
   */
  public static Card create() {
    return new Card();
  }

  /**
   * Factory method to create a card with a title in the header
   *
   * @param title The card title text.
   * @return new Card instance
   */
  public static Card create(String title) {
    return new Card(title);
  }

  /**
   * Factory method to create a card with a title in the header and a description below the title
   *
   * @param title The card title text
   * @param description The card description text
   * @return new Card instance
   */
  public static Card create(String title, String description) {
    return new Card(title, description);
  }

  /**
   * Creates a card with title in the header
   *
   * @param title The card title text
   */
  public Card(String title) {
    this();
    setTitle(title);
  }

  /**
   * Creates a card with the title in the header and a description below the title
   *
   * @param title The card title text
   * @param description The card description text
   */
  public Card(String title, String description) {
    this(title);
    setDescription(description);
  }

  /** Creates an empty Card without a header. */
  public Card() {
    element = div().addCss(dui_card).appendChild(body = div().addCss(dui_card_body));
    header = LazyChild.of(CardHeader.create(), element);
    collapseIcon = getConfig().getCardCollapseExpandIcon().get();

    init(this);
  }

  /**
   * Calling this will assume the Header is needed to for customization and will initialize the
   * header and append it to the card if not already initialized.
   *
   * @return This {@link org.dominokit.domino.ui.cards.CardHeader} component instance for this card
   */
  public CardHeader getHeader() {
    return header.get();
  }

  /**
   * Use this to apply customization to the header of this card instance, this will initialize the
   * card header and append it to the card if not already initialized.
   *
   * @param handler The {@link org.dominokit.domino.ui.utils.ChildHandler} applying the
   *     customizations
   * @return same Card instance
   */
  public Card withHeader(ChildHandler handler) {
    handler.apply(this, header.get());
    return this;
  }

  /**
   * Initialize the card header and append it to the card if not already initialized.
   *
   * @return same Card instance
   */
  public Card withHeader() {
    header.get();
    return this;
  }

  /**
   * Calling this will assume the Header is needed to for customization and will initialize the
   * header and append it to the card if not already initialized. And will also initialize and
   * append the sub-header to the card header if not already initialized.
   *
   * @return The {@link org.dominokit.domino.ui.elements.DivElement} that represent this card
   *     sub-header, sub-header is part of the card header.
   */
  public DivElement getSubHeader() {
    return header.get().getSubHeader();
  }

  /**
   * Calling this will assume the Header is needed to for customization and will initialize the
   * header and append it to the card if not already initialized. And will also initialize and
   * append the sub-header to the card header if not already initialized.
   *
   * @return same Card instance
   */
  public Card withSubHeader() {
    header.get().getSubHeader();
    return this;
  }

  /**
   * Use to apply customization to the card sub-header, this will initialize both the CardHeader and
   * the sub-header and append them if not yet initialized.
   *
   * @param handler The {@link org.dominokit.domino.ui.utils.ChildHandler} applying the
   *     customization
   * @return same Card instance
   */
  public Card withSubHeader(ChildHandler handler) {
    handler.apply(header.get(), header.get().getSubHeader());
    return this;
  }

  /**
   * Sets the card title, this will initialize and append the card header if not yet initialized.
   *
   * @param title The card title text
   * @return same Card instance
   */
  public Card setTitle(String title) {
    header.get().setTitle(title);
    return this;
  }

  /**
   * Sets the card description, this will initialize and append the card header if not yet
   * initialized.
   *
   * @param text The card description text
   * @return same Card instance
   */
  public Card setDescription(String text) {
    header.get().setDescription(text);
    return this;
  }

  /**
   * This will initialize and append the card header if not yet initialized.
   *
   * @return The {@link org.dominokit.domino.ui.elements.DivElement} that holds both the card title
   *     and description.
   */
  public DivElement getTitleElement() {
    return header.get().getTitleElement();
  }

  /**
   * This will initialize and append the card header if not yet initialized.
   *
   * @return same Card instance
   */
  public Card withTitle() {
    header.get().withTitle();
    return this;
  }

  /**
   * Use to apply customization on the Card title element without breaking the fluent API chain.
   * This will initialize and append the card header if not yet initialized.
   *
   * @param handler The {@link org.dominokit.domino.ui.utils.ChildHandler} applying the
   *     customizations.
   * @return same Card instance
   */
  public Card withTitle(ChildHandler handler) {
    handler.apply(header.get(), header.get().getTitleElement());
    return this;
  }

  /**
   * This will initialize and append the card header if not yet initialized.
   *
   * @return The {@link org.dominokit.domino.ui.elements.HeadingElement} that holds the card main
   *     title text
   */
  public HeadingElement getMainTitleElement() {
    return header.get().getMainTitleElement();
  }

  /**
   * This will initialize and append the card header if not yet initialized.
   *
   * @return same Card instance
   */
  public Card withMainTitle() {
    header.get().withMainTitle();
    return this;
  }

  /**
   * Sets the card main title. This will initialize and append the card header if not yet
   * initialized.
   *
   * @param title The card main title text
   * @return same Card instance
   */
  public Card withMainTitle(String title) {
    header.get().setTitle(title);
    return this;
  }

  /**
   * Use to apply customization on the Card main title element without breaking the fluent API
   * chain. This will initialize and append the card header if not yet initialized.
   *
   * @param handler The {@link org.dominokit.domino.ui.utils.ChildHandler} applying the
   *     customizations.
   * @return same Card instance
   */
  public Card withMainTitle(ChildHandler handler) {
    handler.apply(header.get(), header.get().getMainTitleElement());
    return this;
  }

  /**
   * This will initialize and append the card header if not yet initialized.
   *
   * @return The element that represent the card description.
   */
  public SmallElement getDescriptionElement() {
    return header.get().getDescriptionElement();
  }

  /**
   * This will initialize and append the card header if not yet initialized.
   *
   * @return same Card instance
   */
  public Card withDescription() {
    header.get().withDescription();
    return this;
  }

  /**
   * Sets the card description This will initialize and append the card header if not yet
   * initialized.
   *
   * @return same Card instance
   */
  public Card withDescription(String description) {
    header.get().setDescription(description);
    return this;
  }

  /**
   * Use to apply customization on the Card description element without breaking the fluent API
   * chain. This will initialize and append the card header if not yet initialized.
   *
   * @param handler The {@link org.dominokit.domino.ui.utils.ChildHandler} applying the
   *     customizations.
   * @return same Card instance
   */
  public Card withDescription(ChildHandler handler) {
    handler.apply(header.get(), header.get().getDescriptionElement());
    return this;
  }

  /**
   * @return The {@link org.dominokit.domino.ui.elements.DivElement} that is the card body element.
   */
  public DivElement getBody() {
    return body;
  }

  /**
   * Use to apply customization on the Card body element without breaking the fluent API chain.
   *
   * @param handler The {@link org.dominokit.domino.ui.utils.ChildHandler} applying the
   *     customizations.
   * @return same Card instance
   */
  public Card withBody(ChildHandler handler) {
    handler.apply(this, body);
    return this;
  }

  /**
   * Sets the card logo This will initialize and append the card header if not yet initialized.
   *
   * @param img The {@link elemental2.dom.HTMLImageElement} to be used as card logo.
   * @return same Card instance
   */
  public Card setLogo(HTMLImageElement img) {
    header.get().setLogo(img);
    return this;
  }

  /**
   * Sets the card logo This will initialize and append the card header if not yet initialized.
   *
   * @param img The {@link ImageElement} to be used as card logo.
   * @return same Card instance
   */
  public Card setLogo(ImageElement img) {
    header.get().setLogo(img);
    return this;
  }

  /**
   * Sets the card logo This will initialize and append the card header if not yet initialized.
   *
   * @param img a {@link org.dominokit.domino.ui.IsElement} to be used as card logo.
   * @return same Card instance
   */
  public Card setLogo(IsElement img) {
    header.get().setLogo(img.element());
    return this;
  }

  /**
   * This will initialize and append the card header if not yet initialized.
   *
   * @return The {@link ImageElement} that represent the card logo.
   */
  public ImageElement getLogo() {
    return header.get().getLogo();
  }

  /**
   * Sets the card logo This will initialize and append the card header if not yet initialized.
   *
   * @param img a {@link HTMLImageElement} to be used as card logo.
   * @return same Card instance
   */
  public Card withLogo(HTMLImageElement img) {
    header.get().setLogo(img);
    return this;
  }

  /**
   * Sets the card logo This will initialize and append the card header if not yet initialized.
   *
   * @param img a {@link org.dominokit.domino.ui.IsElement} to be used as card logo.
   * @return same Card instance
   */
  public Card withLogo(IsElement img) {
    header.get().setLogo(img.element());
    return this;
  }

  /**
   * This will initialize and append the card header if not yet initialized.
   *
   * @return same Card instance
   */
  public Card withLogo() {
    header.get().withLogo();
    return this;
  }

  /**
   * Use to apply customization on the Card logo element without breaking the fluent API chain. This
   * will initialize and append the card header if not yet initialized.
   *
   * @param handler The {@link org.dominokit.domino.ui.utils.ChildHandler} applying the
   *     customizations.
   * @return same Card instance
   */
  public Card withLogo(ChildHandler handler) {
    handler.apply(header.get(), header.get().getLogo());
    return this;
  }

  /**
   * Sets the card icon, card icon fits between the logo and the title. This will initialize and
   * append the card header if not yet initialized.
   *
   * @param icon a {@link Icon} to be used as card logo.
   * @return same Card instance
   */
  public Card setIcon(Icon icon) {
    header.get().setIcon(icon);
    return this;
  }

  /**
   * This will initialize and append the card header if not yet initialized.
   *
   * @return The {@link Icon} of this card instance
   */
  public Icon getIcon() {
    return header.get().getIcon();
  }

  /**
   * Sets the card icon, card icon fits between the logo and the title. This will initialize and
   * append the card header if not yet initialized.
   *
   * @param icon a {@link Icon} to be used as card icon.
   * @return same Card instance
   */
  public Card withIcon(Icon icon) {
    setIcon(icon);
    return this;
  }

  /**
   * This will initialize and append the card header if not yet initialized.
   *
   * @return same Card instance
   */
  public Card withIcon() {
    header.get().withIcon();
    return this;
  }

  /**
   * Use to apply customization on the Card icon element without breaking the fluent API chain. This
   * will initialize and append the card header if not yet initialized.
   *
   * @param handler The {@link org.dominokit.domino.ui.utils.ChildHandler} applying the
   *     customizations.
   * @return same Card instance
   */
  public Card withIcon(ChildHandler> handler) {
    handler.apply(header.get(), header.get().getIcon());
    return this;
  }

  /**
   * Appends an element to the right side of the card header.
   *
   * @param postfix A {@link org.dominokit.domino.ui.utils.PostfixAddOn} wrapped element
   * @return same card instance
   */
  public Card appendChild(PostfixAddOn postfix) {
    header.get().appendChild(postfix);
    return this;
  }

  /**
   * Appends an element to the left side of the card header, between the logo and the title.
   *
   * @param prefix A {@link org.dominokit.domino.ui.utils.PrefixAddOn} wrapped element
   * @return same card instance
   */
  public Card appendChild(PrefixAddOn prefix) {
    header.get().appendChild(prefix);
    return this;
  }

  /**
   * Appends an element to the right side of the card header.
   *
   * @param postfix A {@link org.dominokit.domino.ui.utils.PostfixAddOn} wrapped element
   * @return same card instance
   */
  public Card withUtility(PostfixAddOn postfix) {
    header.get().appendChild(postfix);
    return this;
  }

  /**
   * Changes the position of the CardHeader to be at the top or bottom of the card.
   *
   * @param headerPosition The {@link org.dominokit.domino.ui.cards.HeaderPosition}
   * @return same card instance
   */
  public Card setHeaderPosition(HeaderPosition headerPosition) {
    addCss(BooleanCssClass.of(dui_card_header_bottom, HeaderPosition.BOTTOM == headerPosition));
    if (nonNull(collapseIcon) && collapseIcon instanceof ToggleMdiIcon) {
      if (HeaderPosition.BOTTOM == headerPosition) {
        ((ToggleMdiIcon) collapseIcon).flipV();
      }
    }
    return this;
  }

  /**
   * Toggle the card collapsible feature, collapsible card will show a collapse action button in the
   * card header, clicking the action will toggle the card body collapse state.
   *
   * @param collapsible boolean, true to enable card body collapse feature, false
   *     disable the card body collapse feature.
   * @return same card instance
   */
  @Override
  public Card setCollapsible(boolean collapsible) {
    collapseElement.remove();
    if (collapsible) {
      body.setCollapseStrategy(getConfig().getDefaultCardCollapseStrategySupplier().get());
      header
          .get()
          .withMainHeader(
              (header, mainHeader) -> {
                collapseElement =
                    LazyChild.of(
                        PostfixAddOn.of(collapseIcon.clickable())
                            .addCss(dui_order_last)
                            .setAttribute("tabindex", "0"),
                        mainHeader);
                collapseElement.whenInitialized(
                    () -> {
                      collapseElement.element().addClickListener(evt -> toggleCollapse());
                      collapseElement
                          .element()
                          .onKeyDown(keyEvents -> keyEvents.onEnter(evt -> toggleCollapse()));
                    });
              });
      collapseElement.get();
    } else {
      collapseElement.remove();
      body.getCollapsible().getStrategy().cleanup(body.element());
    }
    body.addCollapseListener(
        () -> collapseHandlers.forEach(handler -> handler.onCollapsed(Card.this)));
    body.addExpandListener(() -> expandHandlers.forEach(handler -> handler.onExpanded(Card.this)));

    return this;
  }

  /**
   * @return boolean, true if the card body is collapsed, false if the card body
   *     expanded.
   */
  @Override
  public boolean isCollapsed() {
    return body.isCollapsed();
  }

  /**
   * Toggle the card body collapse state, if collapsed it will be expanded, if expanded it will be
   * collapsed.
   *
   * @return same card instance
   */
  @Override
  public Card toggleCollapse() {
    toggleCollapse(!isCollapsed());
    return this;
  }

  /**
   * Toggle the card body collapse state based on provided flag.
   *
   * @param collapse boolean, true collapses the card body, false expands the card
   *     body
   * @return same card instance
   */
  @Override
  public Card toggleCollapse(boolean collapse) {
    if (collapse) {
      collapse();
    } else {
      expand();
    }
    return this;
  }

  /**
   * Expands the card body if collapsed.
   *
   * @return same card instance
   */
  @Override
  public Card expand() {
    body.getCollapsible().expand();
    collapseIcon.toggle();
    expandHandlers.forEach(handler -> handler.onExpanded(this));
    removeCss(() -> "dui-collapsed");
    return this;
  }

  /**
   * Collapses the card body if expanded.
   *
   * @return same card instance
   */
  @Override
  public Card collapse() {
    body.getCollapsible().collapse();
    collapseIcon.toggle();
    collapseHandlers.forEach(handler -> handler.onCollapsed(this));
    addCss(() -> "dui-collapsed");
    return this;
  }

  /** @dominokit-site-ignore {@inheritDoc} */
  @Override
  public Set> getCollapseHandlers() {
    return this.collapseHandlers;
  }

  /** @dominokit-site-ignore {@inheritDoc} */
  @Override
  public Set> getExpandHandlers() {
    return this.expandHandlers;
  }

  /** @dominokit-site-ignore {@inheritDoc} */
  @Override
  public HTMLElement getAppendTarget() {
    return body.element();
  }

  /** @dominokit-site-ignore {@inheritDoc} */
  @Override
  public HTMLDivElement element() {
    return element.element();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy