org.patternfly.component.menu.MenuItem Maven / Gradle / Ivy
/*
* Copyright 2023 Red Hat
*
* 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
*
* https://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.patternfly.component.menu;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import org.jboss.elemento.Attachable;
import org.jboss.elemento.ButtonType;
import org.jboss.elemento.By;
import org.jboss.elemento.Elements;
import org.jboss.elemento.HTMLContainerBuilder;
import org.jboss.elemento.Id;
import org.jboss.elemento.logger.Logger;
import org.patternfly.component.IconPosition;
import org.patternfly.component.SelectionMode;
import org.patternfly.component.WithIcon;
import org.patternfly.component.WithIconAndText;
import org.patternfly.component.WithIdentifier;
import org.patternfly.component.WithText;
import org.patternfly.component.form.Checkbox;
import org.patternfly.core.Aria;
import org.patternfly.core.ComponentContext;
import org.patternfly.core.Dataset;
import org.patternfly.handler.ComponentHandler;
import org.patternfly.style.Classes;
import org.patternfly.style.Modifiers.Disabled;
import elemental2.dom.Element;
import elemental2.dom.HTMLAnchorElement;
import elemental2.dom.HTMLButtonElement;
import elemental2.dom.HTMLElement;
import elemental2.dom.MutationRecord;
import elemental2.promise.Promise;
import static elemental2.dom.DomGlobal.clearTimeout;
import static elemental2.dom.DomGlobal.setTimeout;
import static org.jboss.elemento.Elements.a;
import static org.jboss.elemento.Elements.button;
import static org.jboss.elemento.Elements.div;
import static org.jboss.elemento.Elements.failSafeRemoveFromParent;
import static org.jboss.elemento.Elements.insertFirst;
import static org.jboss.elemento.Elements.label;
import static org.jboss.elemento.Elements.li;
import static org.jboss.elemento.Elements.removeChildrenFrom;
import static org.jboss.elemento.Elements.span;
import static org.jboss.elemento.EventType.click;
import static org.patternfly.component.SelectionMode.group;
import static org.patternfly.component.SelectionMode.multi;
import static org.patternfly.component.SelectionMode.single;
import static org.patternfly.component.form.Checkbox.checkbox;
import static org.patternfly.component.menu.MenuItemAction.favoriteMenuItemAction;
import static org.patternfly.component.menu.MenuItemType.async;
import static org.patternfly.component.menu.MenuItemType.checkbox;
import static org.patternfly.component.menu.MenuItemType.link;
import static org.patternfly.component.spinner.Spinner.spinner;
import static org.patternfly.core.Attributes.role;
import static org.patternfly.core.Attributes.tabindex;
import static org.patternfly.core.Roles.menuitem;
import static org.patternfly.core.Roles.none;
import static org.patternfly.core.Roles.option;
import static org.patternfly.core.Timeouts.LOADING_TIMEOUT;
import static org.patternfly.icon.IconSets.fas.check;
import static org.patternfly.icon.IconSets.fas.externalLinkAlt;
import static org.patternfly.style.Classes.component;
import static org.patternfly.style.Classes.danger;
import static org.patternfly.style.Classes.description;
import static org.patternfly.style.Classes.disabled;
import static org.patternfly.style.Classes.externalIcon;
import static org.patternfly.style.Classes.favorite;
import static org.patternfly.style.Classes.icon;
import static org.patternfly.style.Classes.item;
import static org.patternfly.style.Classes.list;
import static org.patternfly.style.Classes.load;
import static org.patternfly.style.Classes.loading;
import static org.patternfly.style.Classes.main;
import static org.patternfly.style.Classes.modifier;
import static org.patternfly.style.Classes.screenReader;
import static org.patternfly.style.Classes.select;
import static org.patternfly.style.Size.lg;
public class MenuItem extends MenuSubComponent implements
ComponentContext,
Disabled,
WithIdentifier,
WithText,
WithIcon,
WithIconAndText,
Attachable {
// ------------------------------------------------------ factory
/**
* Create a new menu item with type {@link MenuItemType#action}.
*/
public static MenuItem menuItem(String identifier, String text) {
return new MenuItem(identifier, text, MenuItemType.action, null);
}
/**
* Create a new menu item with type {@link MenuItemType#link}.
*/
public static MenuItem linkMenuItem(String identifier, String text, String href) {
return new MenuItem(identifier, text, link, null).href(href);
}
/**
* Create a new menu item with type {@link MenuItemType#link}.
*/
public static MenuItem checkboxMenuItem(String identifier, String text) {
return new MenuItem(identifier, text, checkbox, null);
}
public static MenuItem asyncMenuItem(String identifier, String text,
Function>> loadItems) {
return new MenuItem(identifier, text, async, loadItems);
}
// ------------------------------------------------------ instance
private static final Logger logger = Logger.getLogger(MenuItem.class.getName());
static final String SUB_COMPONENT_NAME = "";
final MenuItemType itemType;
private final String identifier;
private final Map data;
private final HTMLElement itemElement;
private final HTMLElement mainElement;
private final HTMLElement textElement;
private final List> handler;
MenuItem sourceItem;
MenuItem favoriteItem;
MenuItemAction favoriteItemAction;
private String loadingText;
private double loadingTimeout;
private boolean initialSelection;
private Checkbox checkboxComponent;
private MenuItemAction itemAction;
private HTMLElement iconContainer;
private HTMLElement descriptionElement;
private HTMLElement selectIcon;
MenuItem(String identifier, String text, MenuItemType itemType, Function>> loadItems) {
super(SUB_COMPONENT_NAME, li().css(component(Classes.menu, list, item))
.attr(role, none)
.data(Dataset.identifier, identifier)
.element());
this.identifier = identifier;
this.itemType = itemType;
this.data = new HashMap<>();
this.handler = new ArrayList<>();
HTMLContainerBuilder extends HTMLElement> itemBuilder;
if (itemType == MenuItemType.action || itemType == link || itemType == async) {
itemBuilder = itemType == MenuItemType.action || itemType == async
? button(ButtonType.button).attr(tabindex, 0)
: a().attr(tabindex, -1);
itemBuilder.add(mainElement = span().css(component(Classes.menu, item, main))
.add(textElement = span().css(component(Classes.menu, item, Classes.text))
.element())
.element());
} else if (itemType == checkbox) {
String checkboxId = Id.unique(identifier, "check");
itemBuilder = label()
.apply(l -> l.htmlFor = checkboxId)
.add(mainElement = span().css(component(Classes.menu, item, main))
.add(span().css(component(Classes.menu, item, Classes.check))
.add(checkboxComponent = checkbox(checkboxId, checkboxId).standalone()))
.add(textElement = span().css(component(Classes.menu, item, Classes.text))
.element())
.element());
} else {
// create a pseudo-element but don't add it
itemBuilder = div()
.add(mainElement = div()
.add(textElement = div().element())
.element());
logger.error("Unknown menu item type %s for %o", itemType, element());
}
add(itemElement = itemBuilder.css(component(Classes.menu, item)).element());
if (text != null) {
textElement.textContent = text;
}
if (itemType == async) {
css(modifier(load));
if (loadItems == null) {
logger.error("No load items promise for menu item %o defined!", element());
} else {
loadItems(loadItems);
}
} else if (loadItems != null) {
logger.warn("Ignore load items promise for menu item %o with type '%s'", element(), itemType.name());
}
Attachable.register(this, this);
}
// constructor must only be used to clone an item as a favorite item!
MenuItem(Menu menu, MenuItem item, MenuItemType itemType) {
super(SUB_COMPONENT_NAME, ((HTMLElement) item.element().cloneNode(true)));
this.identifier = Id.build("fav", item.identifier);
this.data = new HashMap<>(item.data);
this.itemType = itemType;
this.favoriteItem = null;
this.initialSelection = item.initialSelection;
this.itemElement = find(By.classname(component(Classes.menu, Classes.item)));
this.mainElement = find(By.classname(component(Classes.menu, Classes.item, main)));
this.textElement = find(By.classname(component(Classes.menu, Classes.item, Classes.text)));
this.iconContainer = find(By.classname(component(Classes.menu, Classes.item, icon)));
this.descriptionElement = find(By.classname(component(Classes.menu, Classes.item, description)));
// checkbox must not be used for cloned favorite items!
this.handler = new ArrayList<>();
for (ComponentHandler
© 2015 - 2024 Weber Informatics LLC | Privacy Policy