/**
* 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.dropMenu;
import java.io.IOException;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;
import net.bootsfaces.component.dropButton.DropButton;
import net.bootsfaces.component.flyOutMenu.FlyOutMenu;
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.pillLinks.PillLinks;
import net.bootsfaces.component.tabLinks.TabLinks;
import net.bootsfaces.render.CoreRenderer;
import net.bootsfaces.render.Responsive;
import net.bootsfaces.render.Tooltip;
/** This class generates the HTML code of <b:dropMenu />. */
@FacesRenderer(componentFamily = "net.bootsfaces.component", rendererType = "net.bootsfaces.component.dropMenu.DropMenu")
public class DropMenuRenderer extends CoreRenderer {
/**
* This methods generates the HTML code of the current b:dropMenu. <code>encodeBegin</code> generates the start of
* the component. After the, the JSF framework calls <code>encodeChildren()</code> to generate the HTML code between
* the beginning and the end of the component. For instance, in the case of a panel component the content of the
* panel is generated by <code>encodeChildren()</code>. After that, <code>encodeEnd()</code> is called to generate
* the rest of the HTML code.
*
* @param context
* the FacesContext.
* @param component
* the current b:dropMenu.
* @throws IOException
* thrown if something goes wrong when writing the HTML code.
*/
@Override
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
if (!component.isRendered()) {
return;
}
DropMenu dropMenu = (DropMenu) component;
ResponseWriter rw = context.getResponseWriter();
String clientId = dropMenu.getClientId();
boolean isFlyOutMenu = isFlyOutMenu(component);
String htmlTag = determineHtmlTag(component, isFlyOutMenu);
rw.startElement(htmlTag, dropMenu);
rw.writeAttribute("id", clientId, "id");
rw.writeAttribute("class", getStyleClass(dropMenu, isFlyOutMenu), "class");
if (dropMenu.getStyle() != null) {
rw.writeAttribute("style", dropMenu.getStyle(), "style");
}
Tooltip.generateTooltip(context, dropMenu, rw);
{
rw.startElement("a", dropMenu);
rw.writeAttribute("id", "dtL" + clientId, "id");
if (isFlyOutMenu)
rw.writeAttribute("class", "dropdown-submenu", "class");
else
rw.writeAttribute("class", "dropdown-toggle", "class");
if (dropMenu.getStyle() != null) {
rw.writeAttribute("style", dropMenu.getStyle(), "style");
}
if ("a".equals("button")) {
rw.writeAttribute("type", "button", null);
} else {
rw.writeAttribute("href", "#", null);
}
rw.writeAttribute("role", "button", null);
if (!isFlyOutMenu)
rw.writeAttribute("data-toggle", "dropdown", null);
// Encode value
String value = (String) dropMenu.getAttributes().get("value");
String icon = dropMenu.getIcon();
String faicon = dropMenu.getIconAwesome();
boolean fa = false; // flag to indicate wether the selected icon
// set is
// Font Awesome or not.
if (faicon != null) {
icon = faicon;
fa = true;
}
if (icon != null) {
Object ialign = dropMenu.getIconAlign();
if (ialign != null && ialign.equals("right")) {
rw.writeText(value + " ", null);
IconRenderer.encodeIcon(rw, dropMenu, icon, fa, dropMenu.getIconSize(), dropMenu.getIconRotate(),
dropMenu.getIconFlip(), dropMenu.isIconSpin(), null, null, false, false, false, false);
} else {
IconRenderer.encodeIcon(rw, dropMenu, icon, fa, dropMenu.getIconSize(), dropMenu.getIconRotate(),
dropMenu.getIconFlip(), dropMenu.isIconSpin(), null, null, false, false, false, false);
// !//R.encodeIcon(rw, this, icon, white);
rw.writeText(" " + value, null);
}
} else {
rw.writeText(value, null);
}
// Encode Caret
if ((!isFlyOutMenu) && (!(dropMenu.getParent() instanceof DropMenu))) {
rw.startElement("b", dropMenu);
rw.writeAttribute("class", "caret", "class");
rw.endElement("b");
}
}
rw.endElement("a");
encodeDropMenuStart(dropMenu, rw, "dtL" + clientId);
}
private String determineHtmlTag(UIComponent component, boolean isFlyOutMenu) {
String htmlTag = "span";
if (isFlyOutMenu) {
htmlTag = "li";
} else {
UIComponent parent = component.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) {
htmlTag = "li";
}
}
}
return htmlTag;
}
private boolean isFlyOutMenu(UIComponent component) {
while (component != null && (!(component instanceof UIViewRoot))) {
if (component instanceof FlyOutMenu)
return true;
component = component.getParent();
}
return false;
}
private String getStyleClass(DropMenu dropMenu, boolean isFlyOutMenu) {
String userClass = dropMenu.getStyleClass();
if (null == userClass)
userClass = "";
userClass += Responsive.getResponsiveStyleClass(dropMenu, false);
String direction = dropMenu.getDrop();
if (direction == null) {
direction = "down";
}
if (!direction.equals("up") && !direction.equals("down")) {
direction = "down";
}
if (isFlyOutMenu) {
userClass += "dropdown-submenu" + " ";
return userClass;
} else if (dropMenu.getParent() instanceof DropMenu) {
userClass += "dropdown-submenu" + " ";
}
return (userClass + "drop" + direction).trim();
}
/**
* Renders the Drop Menu.
*
* @param c
* @param rw
* @param l
* @throws IOException
*/
public static void encodeDropMenuStart(DropMenu c, ResponseWriter rw, String l) throws IOException {
rw.startElement("ul", c);
if (c.getContentClass() != null)
rw.writeAttribute("class", "dropdown-menu " + c.getContentClass(), "class");
else
rw.writeAttribute("class", "dropdown-menu", "class");
if (null != c.getContentStyle())
rw.writeAttribute("style", c.getContentStyle(), "style");
rw.writeAttribute("role", "menu", null);
rw.writeAttribute("aria-labelledby", l, null);
}
/**
* This methods generates the HTML code of the current b:dropMenu. <code>encodeBegin</code> generates the start of
* the component. After the, the JSF framework calls <code>encodeChildren()</code> to generate the HTML code between
* the beginning and the end of the component. For instance, in the case of a panel component the content of the
* panel is generated by <code>encodeChildren()</code>. After that, <code>encodeEnd()</code> is called to generate
* the rest of the HTML code.
*
* @param context
* the FacesContext.
* @param component
* the current b:dropMenu.
* @throws IOException
* thrown if something goes wrong when writing the HTML code.
*/
@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
if (!component.isRendered()) {
return;
}
DropMenu dropMenu = (DropMenu) component;
ResponseWriter rw = context.getResponseWriter();
rw.endElement("ul");
boolean isFlyOutMenu = isFlyOutMenu(component);
String htmlTag = determineHtmlTag(component, isFlyOutMenu);
rw.endElement(htmlTag);
Tooltip.activateTooltips(context, dropMenu);
}
}