/** * Copyright 2014-2017 Riccardo Massera (TheCoder4.Eu) and Stephan Rauh (http://www.beyondjava.net). * * This file is part of BootsFaces. * * 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 net.bootsfaces.component.navLink; import java.io.IOException; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.faces.application.ConfigurableNavigationHandler; import javax.faces.application.NavigationCase; import javax.faces.application.ProjectStage; import javax.faces.component.UIComponent; import javax.faces.component.UIParameter; import javax.faces.component.behavior.ClientBehaviorHolder; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import javax.faces.render.FacesRenderer; import net.bootsfaces.component.ajax.AJAXRenderer; import net.bootsfaces.component.dropButton.DropButton; import net.bootsfaces.component.dropMenu.DropMenu; import net.bootsfaces.component.flyOutMenu.FlyOutMenu; import net.bootsfaces.component.kebab.Kebab; import net.bootsfaces.component.icon.IconRenderer; import net.bootsfaces.component.listLinks.ListLinks; import net.bootsfaces.component.navBar.NavBar; import net.bootsfaces.component.navBarLinks.NavBarLinks; import net.bootsfaces.component.navCommandLink.NavCommandLink; import net.bootsfaces.component.pillLinks.PillLinks; import net.bootsfaces.component.tabLinks.TabLinks; import net.bootsfaces.render.CoreRenderer; import net.bootsfaces.render.H; import net.bootsfaces.render.R; import net.bootsfaces.render.Responsive; import net.bootsfaces.render.Tooltip; /** This class generates the HTML code of <b:navLink />. */ @FacesRenderer(componentFamily = "net.bootsfaces.component", rendererType = "net.bootsfaces.component.navLink.NavLink") public class NavLinkRenderer extends CoreRenderer { @Override public void decode(FacesContext context, UIComponent component) { if (componentIsDisabledOrReadonly(component)) { return; } String param = component.getClientId(context); if (context.getExternalContext().getRequestParameterMap().containsKey(param)) { new AJAXRenderer().decode(context, component); } } /** * This methods generates the HTML code of the current b:navLink. * * @param context * the FacesContext. * @param component * the current b:navLink. * @throws IOException * thrown if something goes wrong when writing the HTML code. */ @Override public void encodeBegin(FacesContext context, UIComponent component) throws IOException { AbstractNavLink navlink = (AbstractNavLink) component; if (!navlink.isRendered()) { return; } // If there is the header attribute, we only render a Header String head = navlink.getHeader(); if (head != null) { encodeHeader(context, head, (UIComponent) navlink); } else { // if there is no href, no outcome, no child and no value we render // a divider if ((navlink.getValue() == null) && (((UIComponent) navlink).getChildCount() == 0) && navlink.getIcon() == null && navlink.getIconAwesome()==null) { encodeDivider(context, navlink); } else { encodeHTML(context, (UIComponent) navlink); } } // if header Tooltip.activateTooltips(context, component); } public void encodeHeader(FacesContext context, String h, UIComponent navlink) throws IOException { ResponseWriter rw = context.getResponseWriter(); String htmlTag = "span"; UIComponent parent = navlink.getParent(); if (parent != null) { if (parent.getClass().getSimpleName().equals("UIRepeat")) { parent = parent.getParent(); } if (parent instanceof DropButton || parent instanceof NavBar || parent instanceof TabLinks || parent instanceof PillLinks || parent instanceof ListLinks || parent instanceof NavBarLinks || parent instanceof DropMenu || parent instanceof FlyOutMenu || parent instanceof Kebab) { htmlTag = "li"; } } rw.startElement(htmlTag, navlink); writeAttribute(rw, "id", navlink.getClientId(context), "id"); String styleClass = ((AbstractNavLink) navlink).getStyleClass(); if (null == styleClass) { styleClass = ""; } styleClass = "dropdown-header " + styleClass + " " + Responsive.getResponsiveStyleClass((AbstractNavLink) navlink, false); writeAttribute(rw, "class", styleClass.trim(), "class"); writeAttribute(rw, "style", ((AbstractNavLink) navlink).getStyle(), "style"); writeAttribute(rw, "role", "presentation", null); rw.writeText(h, null); rw.endElement(htmlTag); } public void encodeDivider(FacesContext context, AbstractNavLink navlink) throws IOException { ResponseWriter rw = context.getResponseWriter(); rw.startElement("li", (UIComponent) navlink); Tooltip.generateTooltip(context, (UIComponent) navlink, rw); String styleClass = navlink.getStyleClass(); if (null == styleClass) styleClass = ""; else styleClass += " "; if (((UIComponent) navlink).getParent().getClass().equals(NavBarLinks.class)) { writeAttribute(rw, "class", styleClass + "divider-vertical", "class"); } else { writeAttribute(rw, "class", styleClass + "divider", "class"); } writeAttribute(rw, "style", navlink.getStyle(), "style"); writeAttribute(rw, "role", "presentation", null); rw.endElement("li"); } public void encodeHTML(FacesContext context, UIComponent navlink) throws IOException { ResponseWriter rw = context.getResponseWriter(); Object _value = ((AbstractNavLink) navlink).getValue(); String value = null; if (_value != null) { value = String.valueOf(_value); } String htmlTag = "span"; UIComponent parent = navlink.getParent(); Boolean useAjax = ((AbstractNavLink) navlink).isAjax(); useAjax = useAjax == null ? true : useAjax; // by default, behave like before if (parent != null) { if (parent.getClass().getSimpleName().equals("UIRepeat")) { parent = parent.getParent(); } if (parent instanceof DropButton || parent instanceof NavBar || parent instanceof TabLinks || parent instanceof PillLinks || parent instanceof ListLinks || parent instanceof NavBarLinks || parent instanceof DropMenu || parent instanceof FlyOutMenu) { htmlTag = "li"; } } rw.startElement(htmlTag, navlink); writeAttribute(rw, "id", navlink.getClientId(context), "id"); if (((AbstractNavLink) navlink).isDisabled()) { writeAttribute(rw, "class", "disabled"); } Tooltip.generateTooltip(context, navlink, rw); if (!((AbstractNavLink)navlink).isDisabled()) { if (useAjax) { AJAXRenderer.generateBootsFacesAJAXAndJavaScript(context, (ClientBehaviorHolder) navlink, rw, false); } else { AJAXRenderer.generateBootsFacesAJAXAndJavaScript(context, (ClientBehaviorHolder) navlink, rw, true); } } R.encodeHTML4DHTMLAttrs(rw, navlink.getAttributes(), H.ALLBUTTON); String style = "cursor:pointer;"; if (((AbstractNavLink) navlink).getStyle()!=null) { style += ((AbstractNavLink) navlink).getStyle(); } writeAttribute(rw, "class", getStyleClasses(((AbstractNavLink) navlink))); writeAttribute(rw, "style", style); rw.startElement("a", navlink); writeAttribute(rw, "style", ((AbstractNavLink) navlink).getContentStyle(), "style"); writeAttribute(rw, "class", (navlink instanceof NavCommandLink ? "commandLink " : "") + (((AbstractNavLink) navlink).getContentClass() != null ? ((AbstractNavLink) navlink).getContentClass() : ""), "class"); boolean hasActionExpression = false; if (!((AbstractNavLink) navlink).isDisabled()) { if (navlink instanceof NavCommandLink) if (((NavCommandLink) navlink).getActionExpression() != null) hasActionExpression = true; if (((AbstractNavLink) navlink).getUpdate() == null && (!useAjax) && (!hasActionExpression)) { String url = encodeHref(context, ((AbstractNavLink) navlink)); if (url == null) { /* * If we cannot get an outcome we use the Bootstrap Framework to * give a feedback to the developer if this build is in the * Development Stage */ if (FacesContext.getCurrentInstance().getApplication().getProjectStage() .equals(ProjectStage.Development)) { writeAttribute(rw, "data-toggle", "tooltip", null); writeAttribute(rw, "title", FacesContext.getCurrentInstance().getApplication().getProjectStage() + "WARNING! " + "This link is disabled because a navigation case could not be matched.", null); } url = "#"; } writeAttribute(rw, "href", url, null); String target=((AbstractNavLink)navlink).getTarget(); writeAttribute(rw, "target", target, null); } } writeAttribute(rw, "role", "menuitem", null); writeAttribute(rw, "tabindex", "-1", null); String icon = ((AbstractNavLink) navlink).getIcon(); String faicon = ((AbstractNavLink) navlink).getIconAwesome(); boolean fa = false; // flag to indicate whether the selected icon set is // Font Awesome or not. if (faicon != null) { icon = faicon; fa = true; } if (icon != null) { AbstractNavLink link = (AbstractNavLink) navlink; Object ialign = link.getIconAlign(); // Default // Left if (ialign != null && ialign.equals("right")) { if (value != null) rw.writeText(value + " ", null); if (navlink.getChildCount() > 0) { for (UIComponent c : navlink.getChildren()) { c.encodeAll(context); } } IconRenderer.encodeIcon(rw, navlink, icon, fa, link.getIconSize(), link.getIconRotate(), link.getIconFlip(), link.isIconSpin(), null, null, false, false, false, false); } else { IconRenderer.encodeIcon(rw, navlink, icon, fa, link.getIconSize(), link.getIconRotate(), link.getIconFlip(), link.isIconSpin(), null, null, false, false, false, false); if (navlink.getChildCount() > 0) { for (UIComponent c : navlink.getChildren()) { c.encodeAll(context); } } if (value != null) rw.writeText(" " + value, null); } } else { if (value != null) rw.writeText(value, null); if (navlink.getChildCount() > 0) { for (UIComponent c : navlink.getChildren()) { c.encodeAll(context); } } } rw.endElement("a"); rw.endElement(htmlTag); } private String getStyleClasses(AbstractNavLink navlink) { String c = ""; boolean active = navlink.isActive(); if (active) { c += "active"; } String styleClass = navlink.getStyleClass(); if (null != styleClass) c += " " + styleClass; c += " " + Responsive.getResponsiveStyleClass((AbstractNavLink) navlink, false); return c.trim(); } private String encodeHref(FacesContext context, AbstractNavLink navlink) { String href = navlink.getHref(); String url; if (href != null) { url = getResourceURL(context, href); return url; } else { String outcome = navlink.getOutcome(); if (outcome==null) { return null; } ConfigurableNavigationHandler cnh = (ConfigurableNavigationHandler) context.getApplication() .getNavigationHandler(); NavigationCase navCase = cnh.getNavigationCase(context, null, outcome); if (navCase == null) { return null; } String vId = navCase.getToViewId(context); Map<String, List<String>> params = getParams(navCase, navlink); url = context.getApplication().getViewHandler().getBookmarkableURL(context, vId, params, navlink.isIncludeViewParams() || navCase.isIncludeViewParams()); if (url != null) { String frag = navlink.getFragment(); if (frag != null) { url += "#" + frag; } return url; } else { return "#"; } } } protected String getResourceURL(FacesContext fc, String url) { if (url.startsWith("http://")) { return url; } return fc.getExternalContext().encodeResourceURL(url); } /** * Find all parameters to include by looking at nested uiparams and params * of navigation case */ protected Map<String, List<String>> getParams(NavigationCase navCase, AbstractNavLink button) { Map<String, List<String>> params = new LinkedHashMap<String, List<String>>(); // UIParams for (UIComponent child : ((UIComponent) button).getChildren()) { if (child.isRendered() && (child instanceof UIParameter)) { UIParameter uiParam = (UIParameter) child; if (!uiParam.isDisable()) { List<String> paramValues = params.get(uiParam.getName()); if (paramValues == null) { paramValues = new ArrayList<String>(); params.put(uiParam.getName(), paramValues); } paramValues.add(String.valueOf(uiParam.getValue())); } } } // NavCase Params Map<String, List<String>> navCaseParams = navCase.getParameters(); if (navCaseParams != null && !navCaseParams.isEmpty()) { for (Map.Entry<String, List<String>> entry : navCaseParams.entrySet()) { String key = entry.getKey(); // UIParams take precedence if (!params.containsKey(key)) { params.put(key, entry.getValue()); } } } return params; } @Override public void encodeChildren(FacesContext context, UIComponent component) throws IOException { // this component rendered it's children itself } }