Structurally, adding a dynamic tabMenu to Morpheus limits the menu's customizability. Therefore, an additional intervention to Morpheus may not be welcomed by users. So I made some changes for you. You can integrate these changes into your project.
Code: Select all
/*
Copyright 2009-2021 PrimeTek.
Licensed under PrimeFaces Commercial License, Version 1.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under PrimeFaces Commercial License, Version 1.0 (the "License");
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.primefaces.morpheus.component;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import org.primefaces.component.api.AjaxSource;
import org.primefaces.component.api.UIOutcomeTarget;
import org.primefaces.component.menuitem.UIMenuItem;
import org.primefaces.component.submenu.UISubmenu;
import org.primefaces.expression.SearchExpressionFacade;
import org.primefaces.model.menu.MenuElement;
import org.primefaces.model.menu.MenuItem;
import org.primefaces.model.menu.MenuModel;
import org.primefaces.model.menu.Separator;
import org.primefaces.model.menu.Submenu;
import org.primefaces.renderkit.OutcomeTargetRenderer;
import org.primefaces.util.AjaxRequestBuilder;
import org.primefaces.util.ComponentTraversalUtils;
import org.primefaces.util.WidgetBuilder;
public class TabMenuRenderer extends OutcomeTargetRenderer {
@Override
public void decode(FacesContext context, UIComponent component) {
decodeBehaviors(context, component);
}
@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
TabMenu tabMenu = (TabMenu) component;
if (tabMenu.getModel() != null) {
encodeModel(context, component);
}
else {
encodeDefault(context, component);
}
encodeScript(context, component);
}
public void encodeModel(FacesContext context, UIComponent component) throws IOException {
TabMenu tabMenu = (TabMenu) component;
ResponseWriter writer = context.getResponseWriter();
List<TabMenuItem> model = tabMenu.getModel();
String clientId = tabMenu.getClientId(context);
writer.startElement("div", tabMenu);
writer.writeAttribute("id", clientId, "id");
writer.writeAttribute("class", "layout-tabmenu", null);
writer.startElement("ul", tabMenu);
writer.writeAttribute("class", "layout-tabmenu-nav", null);
for (TabMenuItem menuitem : model) {
writer.startElement("li", null);
writer.writeAttribute("id", menuitem.getId(), "id");
writer.startElement("a", null);
writer.writeAttribute("href", "#", null);
writer.startElement("i", null);
writer.writeAttribute("class", menuitem.getIcon(), null);
writer.endElement("i");
writer.startElement("div", null);
writer.writeAttribute("class", "layout-tabmenu-tooltip", null);
writer.startElement("div", null);
writer.writeAttribute("class", "layout-tabmenu-tooltip-arrow", null);
writer.endElement("div");
writer.startElement("div", null);
writer.writeAttribute("class", "layout-tabmenu-tooltip-text", null);
writer.writeText(menuitem.getTitle(), null);
writer.endElement("div");
writer.endElement("div");
writer.endElement("a");
writer.endElement("li");
}
writer.endElement("ul");
writer.startElement("div", tabMenu);
writer.writeAttribute("class", "layout-tabmenu-contents", null);
for (int i = 0; i < model.size(); i++) {
TabMenuItem menuitem = model.get(i);
writer.startElement("div", null);
writer.writeAttribute("class", "layout-tabmenu-content", null);
writer.startElement("div", null);
writer.writeAttribute("class", "layout-submenu-title clearfix", null);
writer.startElement("span", null);
writer.writeText(menuitem.getTitle(), null);
writer.endElement("span");
writer.endElement("div");
writer.startElement("div", tabMenu);
writer.writeAttribute("class", "layout-submenu-content", null);
writer.startElement("div", null);
writer.writeAttribute("class", "menu-scroll-content", null);
MenuModel menuModel = menuitem.getModel();
if (menuModel != null && menuModel.getElements() != null) {
String id = menuitem.getId() + "_" + i;
writer.startElement("ul", tabMenu);
writer.writeAttribute("id", id, "id");
writer.writeAttribute("class", "navigation-menu", null);
encodeElements(context, tabMenu, menuModel.getElements());
writer.endElement("ul");
WidgetBuilder wb = getWidgetBuilder(context);
wb.init("MorpheusMenu", "widget_" + id, id).finish();
}
writer.endElement("div");
writer.endElement("div");
writer.endElement("div");
}
writer.endElement("div");
writer.endElement("div");
}
public void encodeDefault(FacesContext context, UIComponent component) throws IOException {
TabMenu tabMenu = (TabMenu) component;
ResponseWriter writer = context.getResponseWriter();
List<UIComponent> children = tabMenu.getChildren();
String clientId = tabMenu.getClientId(context);
writer.startElement("div", tabMenu);
writer.writeAttribute("id", clientId, "id");
writer.writeAttribute("class", "layout-tabmenu", null);
writer.startElement("ul", tabMenu);
writer.writeAttribute("class", "layout-tabmenu-nav", null);
for (UIComponent child : children) {
if (child.isRendered() && child instanceof Tab) {
Tab tab = (Tab) child;
writer.startElement("li", tab);
writer.writeAttribute("id", tab.getClientId(context), "id");
writer.startElement("a", tab);
writer.writeAttribute("href", "#", null);
writer.startElement("i", tab);
writer.writeAttribute("class", tab.getIcon(), null);
writer.endElement("i");
writer.startElement("div", null);
writer.writeAttribute("class", "layout-tabmenu-tooltip", null);
writer.startElement("div", null);
writer.writeAttribute("class", "layout-tabmenu-tooltip-arrow", null);
writer.endElement("div");
writer.startElement("div", null);
writer.writeAttribute("class", "layout-tabmenu-tooltip-text", null);
writer.writeText(tab.getTitle(), null);
writer.endElement("div");
writer.endElement("div");
writer.endElement("a");
writer.endElement("li");
}
}
writer.endElement("ul");
writer.startElement("div", tabMenu);
writer.writeAttribute("class", "layout-tabmenu-contents", null);
for (int i = 0; i < children.size(); i++) {
Tab tab = (Tab) children.get(i);
if (tab.isRendered()) {
writer.startElement("div", tabMenu);
writer.writeAttribute("class", "layout-tabmenu-content", null);
writer.startElement("div", tabMenu);
writer.writeAttribute("class", "layout-submenu-title clearfix", null);
writer.startElement("span", tab);
writer.writeText(tab.getTitle(), null);
writer.endElement("span");
writer.endElement("div");
writer.startElement("div", tabMenu);
writer.writeAttribute("class", "layout-submenu-content", null);
writer.startElement("div", null);
writer.writeAttribute("class", "menu-scroll-content", null);
tab.encodeAll(context);
writer.endElement("div");
writer.endElement("div");
writer.endElement("div");
}
}
writer.endElement("div");
writer.endElement("div");
}
public void encodeScript(FacesContext context, UIComponent component) throws IOException {
TabMenu tabMenu = (TabMenu) component;
String clientId = tabMenu.getClientId(context);
WidgetBuilder wb = getWidgetBuilder(context);
wb.init("Morpheus", tabMenu.resolveWidgetVar(), clientId)
.attr("stateful", tabMenu.isStateful())
.attr("activeIndex", tabMenu.getActiveIndex());
encodeClientBehaviors(context, tabMenu);
wb.finish();
}
@Override
public void encodeChildren(FacesContext context, UIComponent component) throws IOException {
//Rendering happens on encodeEnd
}
@Override
public boolean getRendersChildren() {
return true;
}
protected void encodeElements(FacesContext context, TabMenu tabMenu, List<MenuElement> elements) throws IOException {
int size = elements.size();
for (int i = 0; i < size; i++) {
encodeElement(context, tabMenu, elements.get(i));
}
}
protected void encodeElement(FacesContext context, TabMenu tabMenu, MenuElement element) throws IOException {
ResponseWriter writer = context.getResponseWriter();
if (element.isRendered()) {
if (element instanceof MenuItem) {
MenuItem menuItem = (MenuItem) element;
String menuItemClientId = (menuItem instanceof UIComponent) ? menuItem.getClientId() : menuItem.getClientId();
String containerStyle = menuItem.getContainerStyle();
String containerStyleClass = menuItem.getContainerStyleClass();
writer.startElement("li", null);
writer.writeAttribute("id", menuItemClientId, null);
writer.writeAttribute("role", "menuitem", null);
if (containerStyle != null) {
writer.writeAttribute("style", containerStyle, null);
}
if (containerStyleClass != null) {
writer.writeAttribute("class", containerStyleClass, null);
}
encodeMenuItem(context, tabMenu, menuItem);
writer.endElement("li");
}
else if (element instanceof Submenu) {
Submenu submenu = (Submenu) element;
String submenuClientId = (submenu instanceof UIComponent) ? ((UIComponent) submenu).getClientId() : submenu.getId();
String style = submenu.getStyle();
String styleClass = submenu.getStyleClass();
writer.startElement("li", null);
writer.writeAttribute("id", submenuClientId, null);
writer.writeAttribute("role", "menuitem", null);
if (style != null) {
writer.writeAttribute("style", style, null);
}
if (styleClass != null) {
writer.writeAttribute("class", styleClass, null);
}
encodeSubmenu(context, tabMenu, submenu);
writer.endElement("li");
}
else if (element instanceof Separator) {
encodeSeparator(context, (Separator) element);
}
}
}
protected void encodeSubmenu(FacesContext context, TabMenu tabMenu, Submenu submenu) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String icon = submenu.getIcon();
String label = submenu.getLabel();
int childrenElementsCount = submenu.getElementsCount();
writer.startElement("a", null);
writer.writeAttribute("href", "#", null);
writer.writeAttribute("class", "ripplelink", null);
encodeItemIcon(context, icon);
if (label != null) {
writer.startElement("span", null);
writer.writeText(label, null);
writer.endElement("span");
writer.startElement("span", null);
writer.writeAttribute("class", "ink animate", null);
writer.endElement("span");
encodeToggleIcon(context, submenu, childrenElementsCount);
if (submenu instanceof UISubmenu) {
encodeBadge(context, ((UISubmenu) submenu).getAttributes().get("badge"));
}
}
writer.endElement("a");
//submenus and menuitems
if (childrenElementsCount > 0) {
writer.startElement("ul", null);
writer.writeAttribute("role", "menu", null);
encodeElements(context, tabMenu, submenu.getElements());
writer.endElement("ul");
}
}
protected void encodeItemIcon(FacesContext context, String icon) throws IOException {
if (icon != null) {
ResponseWriter writer = context.getResponseWriter();
writer.startElement("i", null);
writer.writeAttribute("class", "layout-menuitem-icon " + icon, null);
writer.endElement("i");
}
}
protected void encodeToggleIcon(FacesContext context, Submenu submenu, int childrenElementsCount) throws IOException {
if (childrenElementsCount > 0) {
ResponseWriter writer = context.getResponseWriter();
writer.startElement("i", null);
writer.writeAttribute("class", "pi pi-fw pi-angle-down layout-menuitem-toggler", null);
writer.endElement("i");
}
}
protected void encodeBadge(FacesContext context, Object value) throws IOException {
if (value != null) {
ResponseWriter writer = context.getResponseWriter();
writer.startElement("span", null);
writer.writeAttribute("class", "menuitem-badge", null);
writer.writeText(value.toString(), null);
writer.endElement("span");
}
}
protected void encodeSeparator(FacesContext context, Separator separator) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String style = separator.getStyle();
String styleClass = separator.getStyleClass();
styleClass = styleClass == null ? "Separator" : "Separator " + styleClass;
//title
writer.startElement("li", null);
writer.writeAttribute("class", styleClass, null);
if (style != null) {
writer.writeAttribute("style", style, null);
}
writer.endElement("li");
}
protected void encodeMenuItem(FacesContext context, TabMenu tabMenu, MenuItem menuitem) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String title = menuitem.getTitle();
boolean disabled = menuitem.isDisabled();
String style = menuitem.getStyle();
String styleClass = menuitem.getStyleClass();
writer.startElement("a", null);
if (title != null) {
writer.writeAttribute("title", title, null);
}
if (style != null) {
writer.writeAttribute("style", style, null);
}
if (styleClass != null) {
writer.writeAttribute("class", styleClass, null);
}
if (disabled) {
writer.writeAttribute("href", "#", null);
writer.writeAttribute("onclick", "return false;", null);
}
else {
String onclick = menuitem.getOnclick();
//GET
if (menuitem.getUrl() != null || menuitem.getOutcome() != null) {
String targetURL = getTargetURL(context, (UIOutcomeTarget) menuitem);
writer.writeAttribute("href", targetURL, null);
if (menuitem.getTarget() != null) {
writer.writeAttribute("target", menuitem.getTarget(), null);
}
}
//POST
else {
writer.writeAttribute("href", "#", null);
UIComponent form = ComponentTraversalUtils.closestForm(context, tabMenu);
if (form == null) {
throw new FacesException("MenuItem must be inside a form element");
}
String command;
if (menuitem.isDynamic()) {
String menuClientId = tabMenu.getClientId(context);
Map<String, List<String>> params = menuitem.getParams();
if (params == null) {
params = new LinkedHashMap<>();
}
List<String> idParams = new ArrayList<>();
idParams.add(menuitem.getId());
params.put(menuClientId + "_menuid", idParams);
command = menuitem.isAjax() ? createAjaxRequest(context, tabMenu, (AjaxSource) menuitem, form, params) : buildNonAjaxRequest(context, tabMenu, form, menuClientId, params, true);
}
else {
command = menuitem.isAjax() ? createAjaxRequest(context, (AjaxSource) menuitem, form) : buildNonAjaxRequest(context, ((UIComponent) menuitem), form, ((UIComponent) menuitem).getClientId(context), true);
}
onclick = (onclick == null) ? command : onclick + ";" + command;
}
if (onclick != null) {
writer.writeAttribute("onclick", onclick, null);
}
}
encodeMenuItemContent(context, menuitem);
writer.endElement("a");
}
protected void encodeMenuItemContent(FacesContext context, MenuItem menuitem) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String icon = menuitem.getIcon();
Object value = menuitem.getValue();
if (menuitem instanceof UIMenuItem) {
encodeBadge(context, ((UIMenuItem) menuitem).getAttributes().get("badge"));
}
encodeItemIcon(context, icon);
if (value != null) {
writer.startElement("span", null);
writer.writeText(value, "value");
writer.endElement("span");
}
}
protected String createAjaxRequest(FacesContext context, AjaxSource source, UIComponent form) {
UIComponent component = (UIComponent) source;
String clientId = component.getClientId(context);
AjaxRequestBuilder builder = getAjaxRequestBuilder();
builder.init()
.source(clientId)
.form(SearchExpressionFacade.resolveClientId(context, component, source.getForm()))
.process(component, source.getProcess())
.update(component, source.getUpdate())
.async(source.isAsync())
.global(source.isGlobal())
.delay(source.getDelay())
.timeout(source.getTimeout())
.partialSubmit(source.isPartialSubmit(), source.isPartialSubmitSet(), source.getPartialSubmitFilter())
.resetValues(source.isResetValues(), source.isResetValuesSet())
.ignoreAutoUpdate(source.isIgnoreAutoUpdate())
.onstart(source.getOnstart())
.onerror(source.getOnerror())
.onsuccess(source.getOnsuccess())
.oncomplete(source.getOncomplete())
.params(component);
if (form != null) {
builder.form(form.getClientId(context));
}
builder.preventDefault();
return builder.build();
}
protected String createAjaxRequest(FacesContext context, UIComponent menu, AjaxSource source, UIComponent form,
Map<String, List<String>> params) {
String clientId = menu.getClientId(context);
AjaxRequestBuilder builder = getAjaxRequestBuilder();
builder.init()
.source(clientId)
.process(menu, source.getProcess())
.update(menu, source.getUpdate())
.async(source.isAsync())
.global(source.isGlobal())
.delay(source.getDelay())
.timeout(source.getTimeout())
.partialSubmit(source.isPartialSubmit(), source.isPartialSubmitSet(), source.getPartialSubmitFilter())
.resetValues(source.isResetValues(), source.isResetValuesSet())
.ignoreAutoUpdate(source.isIgnoreAutoUpdate())
.onstart(source.getOnstart())
.onerror(source.getOnerror())
.onsuccess(source.getOnsuccess())
.oncomplete(source.getOncomplete())
.params(params);
if (form != null) {
builder.form(form.getClientId(context));
}
builder.preventDefault();
return builder.build();
}
protected AjaxRequestBuilder getAjaxRequestBuilder() {
Class rootContext;
Object requestContextInstance;
AjaxRequestBuilder builder;
try {
rootContext = Class.forName("org.primefaces.context.PrimeRequestContext");
} catch (ClassNotFoundException ex) {
try {
rootContext = Class.forName("org.primefaces.context.RequestContext");
} catch (ClassNotFoundException ex1) {
throw new RuntimeException(ex1);
}
}
try {
Method method = rootContext.getMethod("getCurrentInstance");
requestContextInstance = method.invoke(null);
method = requestContextInstance.getClass().getMethod("getAjaxRequestBuilder");
builder = (AjaxRequestBuilder) method.invoke(requestContextInstance);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
return builder;
}
}