/* * � Copyright IBM Corp. 2014, 2015, 2016 * * 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. */ /* * Author: Brian Gleeson (brian.gleeson@ie.ibm.com) * Date: 29 Sep 2014 * DashboardRenderer.java */ package com.ibm.xsp.theme.bootstrap.renderkit.html.extlib.containers; import java.io.IOException; import java.util.List; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import com.ibm.commons.util.StringUtil; import com.ibm.xsp.extlib.renderkit.html_extended.FacesRendererEx; import com.ibm.xsp.extlib.util.ExtLibRenderUtil; import com.ibm.xsp.extlib.util.ExtLibUtil; import com.ibm.xsp.renderkit.html_basic.HtmlRendererUtil; import com.ibm.xsp.renderkit.html_extended.RenderUtil; import com.ibm.xsp.theme.bootstrap.components.responsive.DashNode; import com.ibm.xsp.theme.bootstrap.components.responsive.UIDashboard; import com.ibm.xsp.util.HtmlUtil; /** * * @author Brian Gleeson (brian.gleeson@ie.ibm.com) */ public class DashboardRenderer extends FacesRendererEx { //column class prefixes public static final String COLUMN_TINY = "col-xs-"; // $NON-NLS-1$ public static final String COLUMN_SMALL = "col-sm-"; // $NON-NLS-1$ public static final String COLUMN_MEDIUM = "col-md-"; // $NON-NLS-1$ public static final String COLUMN_LARGE = "col-lg-"; // $NON-NLS-1$ // Container protected static final int PROP_CONTAINER_CLASS = 1; protected static final int PROP_CONTAINER_STYLE = 2; protected static final int PROP_INNER_CLASS = 3; // Heading protected static final int PROP_HEADING_TAG = 10; protected static final int PROP_HEADING_STYLE = 11; protected static final int PROP_HEADING_CLASS = 12; // Dash Nodes protected static final int PROP_TOTALCOLUMNS = 20; protected static final int PROP_NODE_CONTAINER_TAG = 21; protected static final int PROP_NODE_CONTAINER_CLASS = 22; protected static final int PROP_NODE_CONTAINER_STYLE = 23; protected static final int PROP_NODE_TITLE_TAG = 24; protected static final int PROP_NODE_TITLE_STYLE = 25; protected static final int PROP_NODE_TITLE_CLASS = 26; protected static final int PROP_NODE_IMAGE_SRC = 27; protected static final int PROP_NODE_IMAGE_STYLE = 28; protected static final int PROP_NODE_IMAGE_CLASS = 29; protected static final int PROP_NODE_IMAGE_WIDTH_DEFAULT = 30; protected static final int PROP_NODE_IMAGE_HEIGHT_DEFAULT = 31; protected static final int PROP_NODE_DESCRIPTION_STYLECLASS = 32; protected static final int PROP_NODE_DEFAULT_GLYPH_SIZE = 33; protected static final int PROP_NODE_DEFAULT_GLYPH_TAG = 34; protected static final int PROP_NODE_DEFAULT_GLYPH_CLASS = 35; protected static final int PROP_NODE_DEFAULT_GLYPH_STYLE = 36; protected static final int PROP_NODE_DEFAULT_BADGE_TAG = 37; protected static final int PROP_NODE_DEFAULT_BADGE_STYLE = 38; protected static final int PROP_NODE_DEFAULT_BADGE_CLASS = 39; @Override protected Object getProperty(int prop) { switch(prop) { // Container div case PROP_CONTAINER_CLASS: return "row xspDashboard"; //$NON-NLS-1$ case PROP_CONTAINER_STYLE: return ""; //$NON-NLS-1$ case PROP_INNER_CLASS: return "xspDashboardInner"; //$NON-NLS-1$ // Heading case PROP_HEADING_TAG: return "h2"; // $NON-NLS-1$ case PROP_HEADING_STYLE: return "border-bottom: 1px solid #DDDDDD;"; //$NON-NLS-1$ case PROP_HEADING_CLASS: return ""; //$NON-NLS-1$ // Dash Nodes case PROP_TOTALCOLUMNS: return 12; case PROP_NODE_CONTAINER_TAG: return "div"; //$NON-NLS-1$ case PROP_NODE_CONTAINER_CLASS: return "xspDash"; //$NON-NLS-1$ case PROP_NODE_CONTAINER_STYLE: return ""; //$NON-NLS-1$ // Node Title case PROP_NODE_TITLE_TAG: return "h3"; // $NON-NLS-1$ case PROP_NODE_TITLE_STYLE: return ""; //$NON-NLS-1$ case PROP_NODE_TITLE_CLASS: return "xspDashTitle"; //$NON-NLS-1$ // Node Image case PROP_NODE_IMAGE_SRC: return ""; // $NON-NLS-1$ case PROP_NODE_IMAGE_STYLE: return "display:inline-block;"; //$NON-NLS-1$ case PROP_NODE_IMAGE_CLASS: return "img-responsive"; //$NON-NLS-1$ case PROP_NODE_IMAGE_WIDTH_DEFAULT: return "200px"; //$NON-NLS-1$ case PROP_NODE_IMAGE_HEIGHT_DEFAULT: return "200px"; //$NON-NLS-1$ //Node Description case PROP_NODE_DESCRIPTION_STYLECLASS: return "text-muted xspNodeDescription"; //$NON-NLS-1$ // Node Glyphicon case PROP_NODE_DEFAULT_GLYPH_TAG: return "div"; // $NON-NLS-1$ case PROP_NODE_DEFAULT_GLYPH_SIZE: return ""; //$NON-NLS-1$ case PROP_NODE_DEFAULT_GLYPH_CLASS: return "glyphicon "; //$NON-NLS-1$ case PROP_NODE_DEFAULT_GLYPH_STYLE: return ""; //$NON-NLS-1$ // Node Badge case PROP_NODE_DEFAULT_BADGE_TAG: return "span"; // $NON-NLS-1$ case PROP_NODE_DEFAULT_BADGE_CLASS: return "badge dashBadge"; //$NON-NLS-1$ case PROP_NODE_DEFAULT_BADGE_STYLE: return ""; //$NON-NLS-1$ } return super.getProperty(prop); } public void writeDashboard(FacesContext context, ResponseWriter w, UIDashboard c) throws IOException{ String containerStyle = ""; String containerStyleClass = ""; String headingText = ""; String headingStyle = ""; String headingStyleClass = ""; String boardTitle = ""; if(c != null) { containerStyle = c.getStyle(); containerStyleClass = c.getStyleClass(); headingText = c.getHeading(); headingStyle = c.getHeadingStyle(); headingStyleClass = c.getHeadingStyleClass(); boardTitle = c.getTitle(); } //Get the list of dash nodes List<DashNode> nodes = c.getDashNodes(); //write container div w.startElement("div", c); // $NON-NLS-1$ if(HtmlUtil.isUserId(c.getId())) { String clientId = c.getClientId(context); w.writeAttribute("id", clientId, null); // $NON-NLS-1$ $NON-NLS-2$ } String containerClazz = ExtLibUtil.concatStyleClasses((String)getProperty(PROP_CONTAINER_CLASS), containerStyleClass); if(StringUtil.isNotEmpty(containerClazz)) { w.writeAttribute("class", containerClazz, null); // $NON-NLS-1$ } String containerMixinStyle = ExtLibUtil.concatStyleClasses((String)getProperty(PROP_CONTAINER_STYLE), containerStyle); if(StringUtil.isNotEmpty(containerMixinStyle)) { w.writeAttribute("style", containerMixinStyle, null); // $NON-NLS-1$ } if(StringUtil.isNotEmpty(boardTitle)) { w.writeText(boardTitle, null); }else{ w.writeAttribute("title", "Dashboard", null); // $NON-NLS-1$ $NLS-DashboardRenderer.dashboard-2$ } String role = "presentation"; // $NON-NLS-1$ w.writeAttribute("role", role, null); // $NON-NLS-1$ //write title div if(StringUtil.isNotEmpty(headingText)) { w.startElement((String)getProperty(PROP_HEADING_TAG), c); String titleClazz = ExtLibUtil.concatStyleClasses((String)getProperty(PROP_HEADING_CLASS), headingStyleClass); if(StringUtil.isNotEmpty(titleClazz)) { w.writeAttribute("class", titleClazz, null); // $NON-NLS-1$ } String titleMixinStyle = ExtLibUtil.concatStyleClasses((String)getProperty(PROP_HEADING_STYLE), headingStyle); if(StringUtil.isNotEmpty(titleMixinStyle)) { w.writeAttribute("style", titleMixinStyle, null); // $NON-NLS-1$ } w.writeText(headingText, null); w.endElement((String)getProperty(PROP_HEADING_TAG)); } if(nodes != null && nodes.size() > 0) { //write inner div w.startElement("div", c); // $NON-NLS-1$ String innerClazz = (String)getProperty(PROP_INNER_CLASS); if(StringUtil.isNotEmpty(innerClazz)) { w.writeAttribute("class", innerClazz, null); // $NON-NLS-1$ } //write dash nodes writeDashNodes(context, w, c); //end inner div w.endElement("div"); // $NON-NLS-1$ } //end container div w.endElement("div"); // $NON-NLS-1$ } public void writeDashNodes(FacesContext context, ResponseWriter w, UIDashboard c) throws IOException{ //iterate through dash nodes, set their size and render them List<DashNode> nodes = c.getDashNodes(); if(null != nodes) { int size = nodes.size(); if(size > 0) { for(DashNode node : nodes) { writeNode(context, w, c, node, size); } } } } public void writeNode(FacesContext context, ResponseWriter w, UIDashboard c, DashNode node, int nodeCount) throws IOException{ String containerStyle = node.getStyle(); String containerStyleClass = node.getStyleClass(); boolean useGlyph = node.isIconEnabled(); //write node container div w.startElement((String)getProperty(PROP_NODE_CONTAINER_TAG), c); String clazz = ExtLibUtil.concatStyleClasses(getNodeContainerClass(node, nodeCount), containerStyleClass); if(StringUtil.isNotEmpty(clazz)) { w.writeAttribute("class", clazz, null); // $NON-NLS-1$ } String containerMixinStyle = ExtLibUtil.concatStyles((String)getProperty(PROP_NODE_CONTAINER_STYLE), containerStyle); if(StringUtil.isNotEmpty(containerMixinStyle)) { w.writeAttribute("style", containerMixinStyle, null); // $NON-NLS-1$ } //Start the enclosing link if a href exists String labelLink = node.getLabelHref(); boolean isLink = StringUtil.isNotEmpty(labelLink); boolean isDisplayAsLink = node.isDisplayNodeAsLink(); //Add link tag is href exists and node is set to be wrapped in a link if(isDisplayAsLink && isLink) { //add anchor tag for title link w.startElement("a", c); RenderUtil.writeLinkAttribute(context,w, labelLink); } //write the image or the glyphicon instead //write image + alt text + width + height if(useGlyph) { writeGlyphicon(context, w, c, node); }else{ writeNodeImage(context, w, c, node); } //write title writeNodeLabel(context, w, c, node); //Close link if(isDisplayAsLink && isLink) { w.endElement("a"); } //write description writeNodeDescription(context, w, c, node); //close container w.endElement((String)getProperty(PROP_NODE_CONTAINER_TAG)); } public void writeNodeLabel(FacesContext context, ResponseWriter w, UIDashboard c, DashNode node) throws IOException{ String labelText = node.getLabelText(); if(StringUtil.isNotEmpty(labelText)) { String labelLink = node.getLabelHref(); String labelStyle = node.getLabelStyle(); String labelClass = node.getLabelStyleClass(); boolean badgeEnabled = node.isBadgeEnabled(); boolean isLink = StringUtil.isNotEmpty(labelLink); boolean isDisplayAsLink = node.isDisplayNodeAsLink(); //Add link tag if href is set and node is not wrapped in a link if(!isDisplayAsLink && isLink) { //add anchor tag for title link w.startElement("a", c); RenderUtil.writeLinkAttribute(context,w, labelLink); } w.startElement((String)getProperty(PROP_NODE_TITLE_TAG), c); String titleClazz = ExtLibUtil.concatStyleClasses((String)getProperty(PROP_NODE_TITLE_CLASS), labelClass); if(StringUtil.isNotEmpty(titleClazz)) { w.writeAttribute("class", titleClazz, null); // $NON-NLS-1$ } String titleMixinStyle = ExtLibUtil.concatStyles((String)getProperty(PROP_NODE_TITLE_STYLE), labelStyle); if(StringUtil.isNotEmpty(titleMixinStyle)) { w.writeAttribute("style", titleMixinStyle, null); // $NON-NLS-1$ } w.writeText(labelText, null); if(badgeEnabled){ writeNodeBadge(context, w, c, node); } w.endElement((String)getProperty(PROP_NODE_TITLE_TAG)); if(!isDisplayAsLink && isLink) { w.endElement("a"); } } } public void writeNodeBadge(FacesContext context, ResponseWriter w, UIDashboard c, DashNode node) throws IOException{ String badgeLabel = node.getBadgeLabel(); String badgeStyle = node.getBadgeStyle(); String badgeClass = node.getBadgeStyleClass(); w.startElement((String)getProperty(PROP_NODE_DEFAULT_BADGE_TAG), c); String badgeClazz = ExtLibUtil.concatStyleClasses((String)getProperty(PROP_NODE_DEFAULT_BADGE_CLASS), badgeClass); if(StringUtil.isNotEmpty(badgeClazz)) { w.writeAttribute("class", badgeClazz, null); // $NON-NLS-1$ } String badgeMixinStyle = ExtLibUtil.concatStyles((String)getProperty(PROP_NODE_DEFAULT_BADGE_STYLE), badgeStyle); if(StringUtil.isNotEmpty(badgeMixinStyle)) { w.writeAttribute("style", badgeMixinStyle, null); // $NON-NLS-1$ } if(StringUtil.isNotEmpty(badgeLabel)) { w.writeText(badgeLabel, null); } w.endElement((String)getProperty(PROP_NODE_DEFAULT_BADGE_TAG)); } public void writeNodeDescription(FacesContext context, ResponseWriter w, UIDashboard c, DashNode node) throws IOException{ String descrText = node.getDescription(); if(StringUtil.isNotEmpty(descrText)) { String descrStyle = node.getDescriptionStyle(); String descrClass = node.getDescriptionStyleClass(); w.startElement("span", c); // $NON-NLS-1$ String descrClazz = ExtLibUtil.concatStyleClasses((String)getProperty(PROP_NODE_DESCRIPTION_STYLECLASS), descrClass); if(StringUtil.isNotEmpty(descrClazz)) { w.writeAttribute("class", descrClazz, null); // $NON-NLS-1$ } if(StringUtil.isNotEmpty(descrStyle)) { w.writeAttribute("style", descrStyle, null); // $NON-NLS-1$ } w.writeText(descrText, null); w.endElement("span"); // $NON-NLS-1$ } } public void writeGlyphicon(FacesContext context, ResponseWriter w, UIDashboard c, DashNode node) throws IOException{ String glyphicon = node.getIcon(); if(StringUtil.isNotEmpty(glyphicon)) { String glyphiconTag = node.getIconTag(); String glyphSize = node.getIconSize(); String glyphStyle = node.getIconStyle(); String glyphTitle = node.getIconTitle(); String tag = StringUtil.isNotEmpty(glyphiconTag) ? glyphiconTag : (String)getProperty(PROP_NODE_DEFAULT_GLYPH_TAG); String size = StringUtil.isNotEmpty(glyphSize) ? (glyphSize.contains("font-size:") ? glyphSize : "font-size:"+glyphSize) : (String)getProperty(PROP_NODE_DEFAULT_GLYPH_SIZE); // $NON-NLS-1$ $NON-NLS-2$ w.startElement(tag, c); String glyphClazz = ExtLibUtil.concatStyleClasses((String)getProperty(PROP_NODE_DEFAULT_GLYPH_CLASS), glyphicon); if(StringUtil.isNotEmpty(glyphClazz)) { w.writeAttribute("class", glyphClazz, null); // $NON-NLS-1$ } if(StringUtil.isNotEmpty(glyphTitle)) { w.writeAttribute("title", glyphTitle, null); // $NON-NLS-1$ } String iconStyle = StringUtil.isNotEmpty(glyphStyle) ? ExtLibUtil.concatStyles(size, glyphStyle) : size; if(StringUtil.isNotEmpty(iconStyle)) { w.writeAttribute("style", iconStyle, null); // $NON-NLS-1$ } w.endElement(tag); } } public void writeNodeImage(FacesContext context, ResponseWriter w, UIDashboard c, DashNode node) throws IOException{ String imageSrc = node.getImageSrc(); if(StringUtil.isNotEmpty(imageSrc)) { String imageWidth = node.getImageWidth(); String imageHeight = node.getImageHeight(); String imageStyle = node.getImageStyle(); String imageClass = node.getImageStyleClass(); String imageAlt = node.getImageAlt(); w.startElement("img", c); // $NON-NLS-1$ String imageClazz = ExtLibUtil.concatStyleClasses((String)getProperty(PROP_NODE_IMAGE_CLASS), imageClass); if(StringUtil.isNotEmpty(imageClazz)) { w.writeAttribute("class", imageClazz, null); // $NON-NLS-1$ } String imageMixinStyle = ExtLibUtil.concatStyles((String)getProperty(PROP_NODE_IMAGE_STYLE), imageStyle); String setImageWidth = StringUtil.isNotEmpty(imageWidth) ? imageWidth : (String)getProperty(PROP_NODE_IMAGE_WIDTH_DEFAULT); if(StringUtil.isNotEmpty(setImageWidth)) { imageMixinStyle = ExtLibUtil.concatStyles(imageMixinStyle, "width:" + setImageWidth); // $NON-NLS-1$ } String setImageHeight= StringUtil.isNotEmpty(imageHeight) ? imageHeight : (String)getProperty(PROP_NODE_IMAGE_HEIGHT_DEFAULT); if(StringUtil.isNotEmpty(setImageHeight)) { imageMixinStyle = ExtLibUtil.concatStyles(imageMixinStyle, "height:" + setImageHeight); // $NON-NLS-1$ } if(StringUtil.isNotEmpty(imageMixinStyle)) { w.writeAttribute("style", imageMixinStyle, null); // $NON-NLS-1$ } if(ExtLibRenderUtil.isAltPresent(imageAlt)) { w.writeAttribute("alt", imageAlt, null); // $NON-NLS-1$ } if(StringUtil.isNotEmpty(imageSrc)) { w.writeAttribute("src", HtmlRendererUtil.getImageURL(context, imageSrc), null); // $NON-NLS-1$ } w.endElement("img"); // $NON-NLS-1$ } } /* * Generate the CSS classes of the node container div */ protected String getNodeContainerClass(DashNode node, int nodeCount) { //Retrieve size properties from component int totalSize = (Integer)getProperty(PROP_TOTALCOLUMNS); //There are 12 available columns in bootstrap's grid system int largeSize = node.getSizeLarge(); int mediumSize = node.getSizeMedium(); int smallSize = node.getSizeSmall(); int xsmallSize = node.getSizeExtraSmall(); //Declare size variables int lgSize = 0; int mdSize = 0; int smSize = 0; int xsSize = 0; //Check if medium size, the most common size, has been set if(mediumSize > 0) { mdSize = mediumSize; }else{ //Default medium size //Under 7 nodes = total-grid-size/number-of-nodes //Except 5 nodes = total-grid-size/6 = 2 //Over 7 nodes = 1 mdSize = (nodeCount == 5) ? totalSize/6 : (nodeCount < 7) ? totalSize/nodeCount : 1; } //If large size has not been set, match it with medium size if(largeSize <= 0) { lgSize = mdSize; }else{ lgSize = largeSize; } //Set default smSize & xsSize if they are not defined switch (mdSize) { case 1: smSize = (smallSize <= 0) ? 4 : smallSize; xsSize = (xsmallSize <= 0) ? 4 : xsmallSize; break; case 2: smSize = (smallSize <= 0) ? 4 : smallSize; xsSize = (xsmallSize <= 0) ? 6 : xsmallSize; break; case 3: smSize = (smallSize <= 0) ? 3 : smallSize; xsSize = (xsmallSize <= 0) ? 6 : xsmallSize; break; case 4: smSize = (smallSize <= 0) ? 4 : smallSize; xsSize = (xsmallSize <= 0) ? 4 : xsmallSize; break; case 5: smSize = (smallSize <= 0) ? 4 : smallSize; xsSize = (xsmallSize <= 0) ? 6 : xsmallSize;; break; case 6: smSize = (smallSize <= 0) ? 6 : smallSize; xsSize = (xsmallSize <= 0) ? 12 : xsmallSize; break; default: smSize = (smallSize <= 0) ? 12 : smallSize; xsSize = (xsmallSize <= 0) ? 12 : xsmallSize; break; } String clazz = ""; clazz = COLUMN_TINY + xsSize + " " + COLUMN_SMALL + smSize + " " + COLUMN_MEDIUM + mdSize + " " + COLUMN_LARGE + lgSize + " " + getProperty(PROP_NODE_CONTAINER_CLASS); return clazz; } @Override public void decode(FacesContext context, UIComponent component) { // Nothing to decode here... } @Override public void encodeBegin(FacesContext context, UIComponent component) throws IOException { ResponseWriter w = context.getResponseWriter(); UIDashboard c = (UIDashboard) component; if (!c.isRendered()) { return; } writeDashboard(context, w, c); } @Override public void encodeEnd(FacesContext context, UIComponent component) throws IOException { //Nothing to do here, all handled in write dashboard } @Override public boolean getRendersChildren() { return true; } @Override public void encodeChildren(FacesContext context, UIComponent component) throws IOException { // Forget about the children, the dash children are rendered elsewhere } }