/* * � Copyright IBM Corp. 2010, 2014 * * 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 com.ibm.xsp.extlib.renderkit.html_extended.data; import java.io.IOException; import java.util.Locale; import javax.faces.component.NamingContainer; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import lotus.domino.ViewEntry; import com.ibm.commons.util.StringUtil; import com.ibm.xsp.component.UIScriptCollector; import com.ibm.xsp.extlib.component.data.AbstractDataView; import com.ibm.xsp.extlib.component.data.UIDataSourceIterator; import com.ibm.xsp.extlib.component.data.UIDataView; import com.ibm.xsp.extlib.component.data.ValueColumn; import com.ibm.xsp.extlib.util.ExtLibRenderUtil; import com.ibm.xsp.extlib.util.ExtLibUtil; import com.ibm.xsp.model.ViewRowData; import com.ibm.xsp.renderkit.html_basic.HtmlRendererUtil; import com.ibm.xsp.renderkit.html_extended.RenderUtil; import com.ibm.xsp.util.FacesUtil; import com.ibm.xsp.util.HtmlUtil; import com.ibm.xsp.util.JSUtil; import com.ibm.xsp.util.JavaScriptUtil; /** * Base renderer class for a Data View for the web. * <p> * This renderer provides the common capability shared by the different * renderers, like the DataView or ForumView renderers for the web. * </p> */ public abstract class AbstractWebDataViewRenderer extends AbstractDataViewRenderer { protected static final int PROP_SUMMARYTITLETAG = 120; protected static final int PROP_SUMMARYTITLESTYLE = 121; protected static final int PROP_SUMMARYTITLECLASS = 122; protected static final int PROP_SUMMARYFACETTAG = 123; protected static final int PROP_SUMMARYFACETSTYLE = 124; protected static final int PROP_SUMMARYFACETCLASS = 125; protected static final int PROP_DETAILTAG = 130; protected static final int PROP_DETAILSTYLE = 131; protected static final int PROP_DETAILCLASS = 132; //>tmg:a11y @Override public void encodeEnd(FacesContext context, UIComponent component) throws IOException { super.encodeEnd(context, component); // only working with the actual source row of the action event in here... if(component instanceof AbstractDataView.RowComponent) { AbstractDataView c = (AbstractDataView)component.getParent(); String _toggleActionClientId = (String)HtmlUtil.readEncodeParameter(context, c, UIDataSourceIterator.TOGGLE_ACTION_CLIENT_ID, /*remove*/ true); if(null != _toggleActionClientId){ // flip the event client id... show vs hide... hide vs show... if(_toggleActionClientId.contains(HIDE_DELIMITER)){ _toggleActionClientId = _toggleActionClientId.replaceAll(HIDE_DELIMITER, SHOW_DELIMITER); }else if(_toggleActionClientId.contains(SHOW_DELIMITER)){ _toggleActionClientId = _toggleActionClientId.replaceAll(SHOW_DELIMITER, HIDE_DELIMITER); } StringBuilder js = new StringBuilder(); js.append("XSP.setFocus("); //$NON-NLS-1$ JavaScriptUtil.addString(js, _toggleActionClientId); js.append(");\n"); //$NON-NLS-1$ JavaScriptUtil.addScriptOnLoad(js.toString()); } } } //<tmg:a11y @Override protected Object getProperty(int prop) { switch(prop) { case PROP_DETAILTAG: return "div"; // $NON-NLS-1$ case PROP_SUMMARYTITLETAG: return "h4"; // $NON-NLS-1$ case PROP_SUMMARYFACETTAG: return "div"; // $NON-NLS-1$ } return super.getProperty(prop); } // ================================================================ // Summary column functions // ================================================================ protected void writeSummary(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException { if(!viewDef.hasSummary) { return; } boolean summaryVisible = !(viewDef.rowDetailVisible && viewDef.summaryOrDetailVisible); // If the summary should not be displayed, then leave if(!summaryVisible && !viewDef.detailsOnClient) { return; } String clientIdSummary = c.getClientId(context)+ID_SUMMARY; String hideStyle = null; if(!summaryVisible) { // We must have then detailsOnClient // Just renders it invisible hideStyle = "display: none"; // $NON-NLS-1$ } else { boolean dojoEffect = (Boolean)getProperty(PROP_SHOWHIDEDOJOEFFECT); if(dojoEffect && c.getToggledVisibleDetail()!=null && StringUtil.equals(c.getToggledVisibleDetail(), viewDef.rowPosition)) { hideStyle = "opacity: 0"; // $NON-NLS-1$ UIScriptCollector collector = UIScriptCollector.find(); String duration = (String)getProperty(PROP_SHOWHIDEDOJODURATION); StringBuilder b = new StringBuilder(); b.append("dojo.fadeIn({node:"); // $NON-NLS-1$ JavaScriptUtil.addString(b, clientIdSummary); b.append(", duration: "); // $NON-NLS-1$ JavaScriptUtil.addNumber(b, Integer.parseInt(duration)); b.append("}).play()"); // $NON-NLS-1$ collector.addScriptOnLoad(b.toString()); } } // Add the enclosing tag if(viewDef.summaryFacet==null) { String tagName = (String)getProperty(PROP_SUMMARYTITLETAG); w.startElement(tagName,c); w.writeAttribute("id",clientIdSummary,null); // $NON-NLS-1$ writeSummaryTitleStyles(context, w, c, viewDef, hideStyle); // Expand/collapse icon if(viewDef.collapsibleRows) { writeExpandCollapseIcon(context, w, c, viewDef); } // Write the content column w.startElement("a",c); String linkId = c.getClientId(context)+ID_SUMMARY_LINK; w.writeAttribute("id", linkId, null); // $NON-NLS-1$ String href = getSummaryColumnUrl(context, c, viewDef); if(StringUtil.isNotEmpty(href)) { RenderUtil.writeLinkAttribute(context,w,href); } else { w.writeAttribute("href","javascript:;",null); // $NON-NLS-1$ $NON-NLS-2$ //LHEY97CCSZ adding the role=button w.writeAttribute("role", "button", null); // $NON-NLS-1$ // $NON-NLS-2$ } String title = getTitle(context,c,viewDef,viewDef.summaryColumn); if(StringUtil.isNotEmpty(title)) { w.writeAttribute("title",title,null); // $NON-NLS-1$ } writeColumnValue(context, w, c, viewDef, viewDef.summaryColumn); w.endElement("a"); w.endElement(tagName); } else { String tagName = (String)getProperty(PROP_SUMMARYFACETTAG); w.startElement(tagName,c); w.writeAttribute("id",clientIdSummary,null); // $NON-NLS-1$ String style = viewDef.summaryColumn!=null ? viewDef.summaryColumn.getStyle() : null; if(StringUtil.isEmpty(style)) { style = (String)getProperty(PROP_SUMMARYFACETSTYLE); } style = ExtLibUtil.concatStyles(style, hideStyle); if(StringUtil.isNotEmpty(style)) { w.writeAttribute("style",style,null); // $NON-NLS-1$ } String styleClass = viewDef.summaryColumn!=null ? viewDef.summaryColumn.getStyleClass() : null; if(StringUtil.isEmpty(styleClass)) { styleClass = (String)getProperty(PROP_SUMMARYFACETCLASS); } if(StringUtil.isNotEmpty(styleClass)) { w.writeAttribute("class",styleClass,null); // $NON-NLS-1$ } // Expand/collapse icon if(viewDef.collapsibleRows) { writeExpandCollapseIcon(context, w, c, viewDef); } // Write the content column FacesUtil.renderChildren(context, viewDef.summaryFacet); w.endElement(tagName); } } protected void writeSummaryTitleStyles(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef, String hideStyle) throws IOException { String style = viewDef.summaryColumn.getStyle(); if(StringUtil.isEmpty(style)) { style = (String)getProperty(PROP_SUMMARYTITLESTYLE); } style = ExtLibUtil.concatStyles(style, hideStyle); String styleClass = viewDef.summaryColumn.getStyleClass(); if(StringUtil.isEmpty(styleClass)) { styleClass = (String)getProperty(PROP_SUMMARYTITLECLASS); } if(StringUtil.isNotEmpty(styleClass)) { w.writeAttribute("class",styleClass,null); // $NON-NLS-1$ } style = ExtLibUtil.concatStyles("margin: 0",style); // $NON-NLS-1$ w.writeAttribute("style",style,null); // $NON-NLS-1$ } protected void writeExpandCollapseIcon(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException { boolean leaf = isRowLeaf(context, c, viewDef); if(leaf) { String icon = (String)getProperty(PROP_EMPTYICON); if(icon!=null) { w.startElement("img",c); // $NON-NLS-1$ w.writeAttribute("src",HtmlRendererUtil.getImageURL(context,icon),null); // $NON-NLS-1$ String iconAlt = (String) getProperty(PROP_EMPTYICONALT); if( ExtLibRenderUtil.isAltPresent(iconAlt) ){ // "" - present but empty w.writeAttribute("alt",iconAlt,null); //$NON-NLS-1$ } String style = (String)getProperty(PROP_EMPTYICONSTYLE); if(StringUtil.isNotEmpty(style)) { w.writeAttribute("style",style,null); // $NON-NLS-1$ } String clazz = (String)getProperty(PROP_EMPTYICONCLASS); if(StringUtil.isNotEmpty(clazz)) { w.writeAttribute("class",clazz,null); // $NON-NLS-1$ } w.endElement("img"); // $NON-NLS-1$ } } else { boolean expanded = isRowExpanded(context, c, viewDef); String icon = (String)getProperty(expanded ? PROP_COLLAPSEICON : PROP_EXPANDICON); if(icon!=null) { String linkId = c.getClientId(context) + (expanded?SHRINK_DELIMITER:EXPAND_DELIMITER) + viewDef.rowPosition; w.startElement("a",c); w.writeAttribute("id",linkId,null); // $NON-NLS-1$ w.writeAttribute("href","javascript:;",null); // $NON-NLS-1$ $NON-NLS-2$ //LHEY97CCSZ adding the role=button w.writeAttribute("role", "button", null); // $NON-NLS-1$ // $NON-NLS-2$ String iconAlt = (String) getProperty(expanded? PROP_COLLAPSEICONALT : PROP_EXPANDICONALT); w.writeAttribute("title", iconAlt, null); //$NON-NLS-1$ w.writeAttribute("aria-label", iconAlt, null); //$NON-NLS-1$ w.startElement("img",c); // $NON-NLS-1$ w.writeAttribute("src",HtmlRendererUtil.getImageURL(context,icon),null); // $NON-NLS-1$ w.writeAttribute("alt", iconAlt, null); //$NON-NLS-1$ String style = (String)getProperty(expanded ? PROP_COLLAPSEICONSTYLE : PROP_EXPANDICONSTYLE); if(StringUtil.isNotEmpty(style)) { w.writeAttribute("style",style,null); // $NON-NLS-1$ } String clazz = (String)getProperty(expanded ? PROP_COLLAPSEICONCLASS : PROP_EXPANDICONCLASS); if(StringUtil.isNotEmpty(clazz)) { w.writeAttribute("class",clazz,null); // $NON-NLS-1$ } w.endElement("img"); // $NON-NLS-1$ w.endElement("a"); setupSubmitOnClick(context, c, linkId, linkId, null); } } } protected String getSummaryColumnUrl(FacesContext context, AbstractDataView c, ViewDefinition viewDef) { // Try a fixed href String href = getColumnUrl(context, c, viewDef, viewDef.summaryColumn); if(StringUtil.isNotEmpty(href)) { return href; } // Try a URL for the row Object row = viewDef.dataModel.getRowData(); if (row instanceof ViewRowData){ ViewRowData viewRowData = (ViewRowData)row; String pageName = c.getPageName(); boolean readOnly = c.isOpenDocAsReadonly(); // SPR#PHAN9BMHN6 was always casting to ViewEntry, which gave ClassCastException // with 3rd party viewRowData implementations. if( viewRowData instanceof ViewEntry ){ ViewRowDataOverride helper = new ViewRowDataOverride((ViewEntry)viewRowData); return helper.getOpenPageURL(pageName, readOnly); }else{ return viewRowData.getOpenPageURL(pageName, readOnly); } } return null; } protected String getTitle(FacesContext context, AbstractDataView c, ViewDefinition viewDef, ValueColumn col) { if(col!=null) { String title = col.getLinkTitle(); if(StringUtil.isNotEmpty(title)) { return title; } } return null; } protected String getColumnUrl(FacesContext context, AbstractDataView c, ViewDefinition viewDef, ValueColumn col) { if(col!=null) { String href = col.getHref(); if(StringUtil.isNotEmpty(href)) { return href; } } return null; } // ================================================================ // Show/Hide detail button // ================================================================ protected void writeShowHideDetailContent(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException { if(!viewDef.hasSummary || !viewDef.hasDetail) { return; } // In case this is diabled for this particular row if(viewDef.rowDisableHideRow) { return; } boolean detailsOnClient = viewDef.detailsOnClient; String linkId = c.getClientId(context) + (viewDef.rowDetailVisible?HIDE_DELIMITER:SHOW_DELIMITER) + viewDef.rowPosition; w.startElement("a",c); w.writeAttribute("id",linkId,null); // $NON-NLS-1$ w.writeAttribute("href","javascript:;",null); // $NON-NLS-1$ $NON-NLS-2$ //LHEY97CCSZ adding the role=button w.writeAttribute("role", "button", null); // $NON-NLS-1$ // $NON-NLS-2$ String label = (String)getProperty(viewDef.rowDetailVisible ? PROP_HIDEICONDETAILSTOOLTIP : PROP_SHOWICONDETAILSTOOLTIP); if(StringUtil.isNotEmpty(label)) { w.writeAttribute("title", label, null); // $NON-NLS-1$ w.writeAttribute("aria-label", label, null); // $NON-NLS-1$ } if(detailsOnClient) { StringBuilder b = new StringBuilder(); b.append(viewDef.showHideDetailFunctionName); b.append("("); JSUtil.addSingleQuoteString(b,Integer.toString(viewDef.dataModel.getRowIndex())); b.append(","); JSUtil.addSingleQuoteString(b,viewDef.rowPosition); b.append(")"); w.writeAttribute("onclick","javascript:"+b.toString(),null); // $NON-NLS-1$ $NON-NLS-2$ } w.startElement("img",c); // $NON-NLS-1$ String imgid = c.getClientId(context)+ID_SHOWHIDE; w.writeAttribute("id",imgid,null); // $NON-NLS-1$ String clazz = (String)getProperty(viewDef.rowDetailVisible?PROP_HIDEICONDETAILSCLASS:PROP_SHOWICONDETAILSCLASS); if(StringUtil.isNotEmpty(clazz)) { w.writeAttribute("class",clazz,null); // $NON-NLS-1$ } //fix for MLML8MXRVX in IE only boolean changeImageSize = false; if(viewDef.viewforumRenderAsTable){ Locale locale = context.getExternalContext().getRequestLocale(); if( null == locale ){ locale = context.getViewRoot().getLocale(); if( null == locale){ locale = Locale.getDefault(); } } String lang = locale.getLanguage(); if (StringUtil.isNotEmpty(lang) && lang.equals("ko") || lang.equals("zh") || lang.equals("ja") || lang.equals("zh-tw"))// $NON-NLS-1$ // $NON-NLS-2$ // $NON-NLS-3$ // $NON-NLS-4$ changeImageSize = true; } if(changeImageSize) w.writeAttribute("width","40",null); // $NON-NLS-1$ else w.writeAttribute("width","16",null); // $NON-NLS-1$ if(changeImageSize) w.writeAttribute("height","40",null); // $NON-NLS-1$ else w.writeAttribute("height","16",null); // $NON-NLS-1$ String bgif = (String)getProperty(PROP_BLANKIMG); if(StringUtil.isNotEmpty(bgif)) { w.writeAttribute("src",HtmlRendererUtil.getImageURL(context,bgif),null); // $NON-NLS-1$ } String blankImageAlt = (String)getProperty(PROP_BLANKIMGALT); if( ExtLibRenderUtil.isAltPresent(blankImageAlt) ){ w.writeAttribute("alt",blankImageAlt,null); // $NON-NLS-1$ } w.startElement("span",c); // $NON-NLS-1$ String altTextClass = (String)getProperty(PROP_ALTTEXTCLASS); if(StringUtil.isNotEmpty(bgif)) { w.writeAttribute("class",altTextClass,null); // $NON-NLS-1$ } if( viewDef.rowDetailVisible ){ w.writeText("Hide",null); // $NLS-AbstractWebDataViewRenderer.Hide_HideDetailIconAlt-1$ }else{ w.writeText("Show",null); // $NLS-AbstractWebDataViewRenderer.Show-1$ } w.endElement("span"); // $NON-NLS-1$ w.endElement("img"); // $NON-NLS-1$ w.endElement("a"); if(!detailsOnClient) { if(viewDef.viewRowRefresh) { String refreshId = c.getClientId(context)+NamingContainer.SEPARATOR_CHAR+UIDataView.ROW_ID; setupSubmitOnClick(context, c, linkId, linkId, refreshId); } else { setupSubmitOnClick(context, c, linkId, linkId, null); } } } // ================================================================ // Detail part // ================================================================ protected void writeDetail(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException { if(!viewDef.hasDetail) { return; } String id = c.getClientId(context)+ID_DETAIL; // If the detail should not be displayed, then leave boolean detailVisible = viewDef.rowDetailVisible; if(!detailVisible && !viewDef.detailsOnClient) { return; } String hideStyle = null; if(!detailVisible) { // We must have then detailsOnClient // Just renders it invisible hideStyle = "display: none"; // $NON-NLS-1$ } else { // TODO this fade effect doesn't change the tooltips and alt text from Show to Hide boolean dojoEffect = (Boolean)getProperty(PROP_SHOWHIDEDOJOEFFECT); if(dojoEffect && StringUtil.equals(c.getToggledVisibleDetail(), viewDef.rowPosition)) { hideStyle = "opacity: 0"; // $NON-NLS-1$ UIScriptCollector collector = UIScriptCollector.find(); String duration = (String)getProperty(PROP_SHOWHIDEDOJODURATION); StringBuilder b = new StringBuilder(); b.append("dojo.fadeIn({node:"); // $NON-NLS-1$ JavaScriptUtil.addString(b, id); b.append(", duration: "); // $NON-NLS-1$ JavaScriptUtil.addNumber(b, Integer.parseInt(duration)); b.append("}).play()"); // $NON-NLS-1$ collector.addScriptOnLoad(b.toString()); } } UIComponent detail = viewDef.detailFacet; if(detail!=null) { String tagName = (String)getProperty(PROP_DETAILTAG); w.startElement(tagName,c); w.writeAttribute("id",id,null); // $NON-NLS-1$ String style = (String)getProperty(PROP_DETAILSTYLE); String styleClass = (String)getProperty(PROP_DETAILCLASS); if(viewDef.collapsibleRows) { String collapsibleSize = "20px"; //(Boolean)getProperty(PROP_SHOWHIDEONCLIENT); $NON-NLS-1$ style = ExtLibUtil.concatStyles(style, "padding-left: "+collapsibleSize); // $NON-NLS-1$ } style = ExtLibUtil.concatStyles(style, hideStyle); if(StringUtil.isNotEmpty(style)) { w.writeAttribute("style",style,null); // $NON-NLS-1$ } if(StringUtil.isNotEmpty(styleClass)) { w.writeAttribute("class",styleClass,null); // $NON-NLS-1$ } FacesUtil.renderComponent(context, detail); w.endElement(tagName); } } }