/* * � Copyright IBM Corp. 2010, 2013 * * 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.List; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import javax.faces.model.DataModel; import com.ibm.commons.util.StringUtil; import com.ibm.xsp.application.XspPropertyConstants; import com.ibm.xsp.component.UIDataIterator; import com.ibm.xsp.component.UIScriptCollector; import com.ibm.xsp.context.FacesContextEx; import com.ibm.xsp.extlib.component.data.AbstractDataView; import com.ibm.xsp.extlib.component.data.CategoryColumn; import com.ibm.xsp.extlib.component.data.ExtraColumn; import com.ibm.xsp.extlib.component.data.IconColumn; import com.ibm.xsp.extlib.component.data.SummaryColumn; import com.ibm.xsp.extlib.component.data.UIDataSourceIterator; import com.ibm.xsp.extlib.component.data.UIDataView; import com.ibm.xsp.extlib.component.data.UIForumView; import com.ibm.xsp.extlib.util.ExtLibUtil; import com.ibm.xsp.util.FacesUtil; import com.ibm.xsp.util.JSUtil; import com.ibm.xsp.util.JavaScriptUtil; import com.ibm.xsp.util.TypedUtil; /** * Base renderer class for a Data View. * <p> * This renderer provides the common capability shared by the different * renderers, like the OneUI renderer and the mobile one. * </p> * {@link AbstractDataView} renderer. */ public abstract class AbstractDataViewRenderer extends DataSourceIteratorRenderer { protected static final String ID_SHOWHIDE = "_shimg"; // $NON-NLS-1$ protected static final String ID_SUMMARY = "_sum"; // $NON-NLS-1$ protected static final String ID_SUMMARY_LINK = "_sumLink"; // $NON-NLS-1$ protected static final String ID_DETAIL = "_detail"; // $NON-NLS-1$ protected static final String XSP_PROGRESSIVE_ENH = "xsp.progressive.enhancement"; // $NON-NLS-1$ protected static final String ENABLE = "enable"; // $NON-NLS-1$ protected static final String DISABLE = "disable"; // $NON-NLS-1$ protected static final String AUTO = "auto"; // $NON-NLS-1$ protected static final int PROP_MAINDIVCLASS = 38; protected static final int PROP_MAINDIVSTYLE = 39; protected static final int PROP_HASHEADERFACET = 40; protected static final int PROP_HEADER_PAGER_AREA_TAG = 41; protected static final int PROP_HEADERSTYLE = 42; protected static final int PROP_HEADERCLASS = 43; protected static final int PROP_HEADERDOJOTYPE = 44; protected static final int PROP_HASFOOTERFACET = 50; protected static final int PROP_FOOTER_PAGER_AREA_TAG = 51; protected static final int PROP_FOOTERSTYLE = 52; protected static final int PROP_FOOTERCLASS = 53; protected static final int PROP_FOOTERDOJOTYPE = 54; protected static final int PROP_FACETTAG = 60; protected static final int PROP_FACETDOJOTYPE = 61; protected static final int PROP_HEADERLEFTSTYLE = 62; protected static final int PROP_HEADERLEFTCLASS = 63; protected static final int PROP_HEADERMIDDLESTYLE = 64; protected static final int PROP_HEADERMIDDLECLASS = 65; protected static final int PROP_HEADERRIGHTSTYLE = 66; protected static final int PROP_HEADERRIGHTCLASS = 67; protected static final int PROP_FOOTERLEFTSTYLE = 72; protected static final int PROP_FOOTERLEFTCLASS = 73; protected static final int PROP_FOOTERMIDDLESTYLE = 74; protected static final int PROP_FOOTERMIDDLECLASS = 75; protected static final int PROP_FOOTERRIGHTSTYLE = 76; protected static final int PROP_FOOTERRIGHTCLASS = 77; protected static final int PROP_SHOWHIDEDOJOEFFECT = 80; protected static final int PROP_SHOWHIDEDOJODURATION = 81; protected static final int PROP_SHOWICONDETAILSCLASS = 82; protected static final int PROP_HIDEICONDETAILSCLASS = 83; protected static final int PROP_SHOWICONDETAILSTOOLTIP = 84; protected static final int PROP_HIDEICONDETAILSTOOLTIP = 85; protected static final int PROP_NOROWSCLASS = 90; @Override protected Object getProperty(int prop) { switch(prop) { case PROP_HASHEADERFACET: return true; case PROP_HEADER_PAGER_AREA_TAG: return "div"; // $NON-NLS-1$ case PROP_HASFOOTERFACET: return true; case PROP_FOOTER_PAGER_AREA_TAG: return "div"; // $NON-NLS-1$ case PROP_FACETTAG: return "div"; // $NON-NLS-1$ // TODO these styles should be in a .css file and referenced using a styleClass // TODO these styles have bidi problems case PROP_HEADERLEFTSTYLE: return "float:left;text-align:left;"; // $NON-NLS-1$ case PROP_HEADERRIGHTSTYLE: return "float:right;text-align:right;"; // $NON-NLS-1$ case PROP_FOOTERLEFTSTYLE: return "float:left;text-align:left;"; // $NON-NLS-1$ case PROP_FOOTERRIGHTSTYLE: return "float:right;text-align:right;"; // $NON-NLS-1$ case PROP_SHOWHIDEDOJOEFFECT: return true; case PROP_SHOWHIDEDOJODURATION: return "400"; // $NON-NLS-1$ case PROP_SHOWICONDETAILSTOOLTIP: return "Show details"; // $NLS-AbstractDataViewRenderer.Showdetails-1$ case PROP_HIDEICONDETAILSTOOLTIP: return "Hide details"; // $NLS-AbstractDataViewRenderer.Hidedetails-1$ } return super.getProperty(prop); } @Override public void encodeBegin(FacesContext context, UIComponent component) throws IOException { ResponseWriter w = context.getResponseWriter(); boolean rendered = component.isRendered(); if(!rendered) { return; } if(component instanceof AbstractDataView) { AbstractDataView c = (AbstractDataView)component; writeMainContainer(context, w, c); } if(component instanceof AbstractDataView.RowComponent) { AbstractDataView c = (AbstractDataView)component.getParent(); writeSingleRow(context, w, c); } } @Override public boolean getRendersChildren() { return true; } @Override public void encodeChildren(FacesContext context, UIComponent component) throws IOException { } @Override public void encodeEnd(FacesContext context, UIComponent component) throws IOException { //>tmg:a11y super.encodeEnd(context, component); //<tmg:a11y } /** * Object that caches the current data view parameters * @author priand * */ protected final class ViewDefinition { public AbstractDataView dataView; public DataModel dataModel; // Global properties public boolean showItemsFlat; public boolean columnTitles; public boolean collapsibleRows; public boolean collapsibleCategory; public boolean collapsibleDetails; public boolean detailsOnClient; public String showHideDetailFunctionName; public boolean hasCategoryRow; public int multiColumnCount; public int categoryCount; public List<CategoryColumn> categoryColumns; public boolean hasIconColumn; public IconColumn iconColumn; public UIComponent iconFacet; public boolean hasSummary; public SummaryColumn summaryColumn; public UIComponent summaryFacet; public boolean hasDetail; public UIComponent detailFacet; // Checkbox public boolean hasHeaderCheckBoxColumn; public boolean hasCheckBoxColumn; public String checkboxFieldName; // Input "checkbox" name public String checkboxFieldNamePrefix; // Input "checkbox" id/name prefix (for uniqueness) public String checkboxFieldNameSuffix; // Input "checkbox" id/name suffix (for uniqueness) // Extra columns public boolean hasExtraColumns; public List<ExtraColumn> extraColumns; public boolean summaryOrDetailVisible; public boolean expandedDetailDefault; // Row related properties public String rowPosition; public boolean rowDetailVisible; public boolean rowDisableHideRow; // Request properties public int first; public int rows; public int nColumns; // cached data public boolean viewRowRefresh; public boolean singleRowRefresh; // ==== rendering properties - depend on the renderer ===== // For multi column rendering public int currentColumn; // Indentation management public int indentLevel; public int initialIndentLevel; // ViewForum renderer -> define if we should use a table for rendering the data public boolean viewforumRenderAsTable; // ==== Temporary fix for 852 public int indentOffset; public boolean isInfiniteScroll = false; protected ViewDefinition(FacesContext context) { } } protected ViewDefinition createViewDefinition(FacesContext context) { ViewDefinition viewDef = new ViewDefinition(context); return viewDef; } protected void initViewDefinition(FacesContext context, AbstractDataView dataView, ViewDefinition viewDef) { List<UIComponent> children = TypedUtil.getChildren(dataView); viewDef.dataView = dataView; viewDef.dataModel = dataView.getDataModel(); viewDef.showItemsFlat = dataView.isShowItemsFlat(); viewDef.detailsOnClient = dataView.isDetailsOnClient() || (Boolean)getProperty(PROP_SHOWHIDEONCLIENT); viewDef.collapsibleDetails = dataView.isCollapsibleDetail(); viewDef.expandedDetailDefault = dataView.isExpandedDetail(); if(viewDef.collapsibleDetails) { viewDef.showHideDetailFunctionName = ExtLibUtil.encodeJSFunctionName(dataView.getClientId(context)); } viewDef.summaryColumn = dataView.getSummaryColumn(); if(!children.isEmpty()) { UIComponent row = children.get(0); viewDef.summaryFacet = row.getFacet(AbstractDataView.FACET_SUMMARY); // row facet viewDef.detailFacet = row.getFacet(AbstractDataView.FACET_DETAIL);// row facet } viewDef.hasSummary = viewDef.summaryColumn!=null || viewDef.summaryFacet!=null; viewDef.hasDetail = viewDef.detailFacet!=null; viewDef.nColumns = (viewDef.hasCheckBoxColumn?1:0) // CheckBox + 1 // Data - always + (viewDef.collapsibleDetails?1:0); // Collapsible details viewDef.viewRowRefresh = dataView.isRowRefresh(context); viewDef.rows = dataView.getRows(); } protected boolean getInfiniteScroll(String dataViewInfiniteScroll,FacesContext context ) { boolean isAuto = false; if(dataViewInfiniteScroll == null) { isAuto = true; } else { isAuto = dataViewInfiniteScroll.equalsIgnoreCase(AUTO); // $NON-NLS-1$ } if(isAuto) { if( context instanceof FacesContextEx ) { FacesContextEx contextEx = (FacesContextEx)context; //xsp.progressive.enhancement = enable | disable String progEnhancement = contextEx.getProperty(XSP_PROGRESSIVE_ENH); // $NON-NLS-1$ if(progEnhancement == null) { // is not set return false; } return progEnhancement.equalsIgnoreCase(ENABLE); } } return dataViewInfiniteScroll.equalsIgnoreCase(ENABLE); } // ================================================================ // Ajax Support // ================================================================ @Override public void encodeRows(FacesContext context, UIDataIterator iterator, int first, int rows) throws IOException { ResponseWriter w = context.getResponseWriter(); AbstractDataView c = (AbstractDataView)iterator; ViewDefinition viewDef = createViewDefinition(context); initViewDefinition(context, c, viewDef); writeRows(context, w, c, viewDef, first, rows); } // ================================================================ // Hidden field // ================================================================ protected void writeShowHide(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException { if(viewDef.detailsOnClient && viewDef.collapsibleDetails) { writeClientShowHideHiddenField(context, w, c, viewDef); addClientShowHideScript(context, w, c, viewDef); } } protected void addClientShowHideScript(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException { // TODO this code should be in a .js file, not inline in this renderer StringBuilder b = new StringBuilder(); //function view__id0_dataView1(idx,pos){ b.append("function "); // $NON-NLS-1$ b.append(viewDef.showHideDetailFunctionName); b.append("(idx,pos){\n"); // $NON-NLS-1$ //var id="view:_id0:dataView1"; b.append("var id="); // $NON-NLS-1$ JavaScriptUtil.addString(b, c.getClientId(context)); b.append(";\n"); // $NON-NLS-1$ //var img=id+":"+idx+"_shimg"; b.append("var img=id+"); // $NON-NLS-1$ JavaScriptUtil.addString(b, ":"); // $NON-NLS-1$ b.append("+idx+"); // $NON-NLS-1$ JavaScriptUtil.addString(b, ID_SHOWHIDE); // $NON-NLS-1$ b.append(";\n"); // $NON-NLS-1$ //var sum=id+":"+idx+"_sum"; b.append("var sum=id+"); // $NON-NLS-1$ JavaScriptUtil.addString(b, ":"); // $NON-NLS-1$ b.append("+idx+"); // $NON-NLS-1$ JavaScriptUtil.addString(b, ID_SUMMARY); b.append(";"); // $NON-NLS-1$ //var det=id+":"+idx+"_detail"; b.append("var det=id+"); // $NON-NLS-1$ JavaScriptUtil.addString(b, ":"); // $NON-NLS-1$ b.append("+idx+"); // $NON-NLS-1$ JavaScriptUtil.addString(b, ID_DETAIL); b.append(";\n"); // $NON-NLS-1$ //var inp=dojo.byId(id+"_shfld"); b.append("var inp=dojo.byId(id+"); // $NON-NLS-1$ JavaScriptUtil.addString(b, ID_HIDDEN); b.append(");\n"); // $NON-NLS-1$ //var a=inp.value?inp.value.split(","):[];\n b.append("var a=inp.value?inp.value.split("); // $NON-NLS-1$ JavaScriptUtil.addString(b, ","); // $NON-NLS-1$ b.append("):[];\n"); // $NON-NLS-1$ b.append("var ia=dojo.indexOf(a,pos);\n"); // $NON-NLS-1$ //b.append("alert('a='+a.toString()+', ia='+ia);\n"); b.append("if(ia>=0) a.splice(ia,1); else a.push(pos); inp.value=a.toString();\n"); // $NON-NLS-1$ //var vis=dojo.style(det,"display")!="none"; b.append("var vis=dojo.style(det,"); // $NON-NLS-1$ JavaScriptUtil.addString(b, "display"); // $NON-NLS-1$ b.append(")!="); // $NON-NLS-1$ JavaScriptUtil.addString(b, "none"); // $NON-NLS-1$ b.append(";\n"); // $NON-NLS-1$ //dojo.byId(img).className =vis?"lotusIcon16 lotusIconShow":"lotusIcon16 lotusIconHide"; // Set the icon class String hideClass = (String)getProperty(PROP_HIDEICONDETAILSCLASS); String showClass = (String)getProperty(PROP_SHOWICONDETAILSCLASS); b.append("dojo.byId(img).className =vis?"); // $NON-NLS-1$ JavaScriptUtil.addString(b, showClass); b.append(":"); //$NON-NLS-1$ JavaScriptUtil.addString(b, hideClass); b.append(";\n"); //$NON-NLS-1$ String hideLabel = (String)getProperty(PROP_HIDEICONDETAILSTOOLTIP); String showLabel = (String)getProperty(PROP_SHOWICONDETAILSTOOLTIP); if(StringUtil.isNotEmpty(showLabel) && StringUtil.isNotEmpty(hideLabel)) { //var toggleTitle = vis?"Show details":"Hide details"; b.append("var toggleTitle = vis?"); //$NON-NLS-1$ JSUtil.addString(b,showLabel); b.append(":"); //$NON-NLS-1$ JSUtil.addString(b,hideLabel); b.append(";\n"); //$NON-NLS-1$ //dojo.query(dojo.byId(img)).attr("title", toggleTitle).attr("alt", toggleTitle).attr("aria-label", toggleTitle); b.append("dojo.query(dojo.byId(img).parentNode).attr("); // $NON-NLS-1$ JavaScriptUtil.addString(b, "aria-label"); // $NON-NLS-1$ b.append(", toggleTitle).attr("); //$NON-NLS-1$ JavaScriptUtil.addString(b, "title"); // $NON-NLS-1$ b.append(", toggleTitle);\n"); //$NON-NLS-1$ } // Hide/Show the detail pane boolean dojoEffect = (Boolean)getProperty(PROP_SHOWHIDEDOJOEFFECT); if(dojoEffect) { String duration = (String)getProperty(PROP_SHOWHIDEDOJODURATION); if(viewDef.summaryOrDetailVisible) { //if(vis){dojo.style(det,'display','none');dojo.style(sum,'display','block') //}else{dojo.style(sum,'display','none'); dojo.style(det,{opacity: '0',display:'block'});dojo.fadeIn({node:dojo.byId(det),duration:400}).play();} b.append("if(vis){dojo.style(det,"); // $NON-NLS-1$ JavaScriptUtil.addString(b, "display"); // $NON-NLS-1$ b.append(","); // $NON-NLS-1$ JavaScriptUtil.addString(b, "none"); // $NON-NLS-1$ b.append(");dojo.style(sum,"); // $NON-NLS-1$ JavaScriptUtil.addString(b, "display"); // $NON-NLS-1$ b.append(","); // $NON-NLS-1$ JavaScriptUtil.addString(b, "block"); // $NON-NLS-1$ b.append(")}else{dojo.style(sum,"); // $NON-NLS-1$ JavaScriptUtil.addString(b, "display"); // $NON-NLS-1$ b.append(","); // $NON-NLS-1$ JavaScriptUtil.addString(b, "none"); // $NON-NLS-1$ b.append("); dojo.style(det,{opacity: "); // $NON-NLS-1$ JavaScriptUtil.addString(b, "0"); // $NON-NLS-1$ b.append(",display:"); // $NON-NLS-1$ JavaScriptUtil.addString(b, "block"); // $NON-NLS-1$ b.append("});dojo.fadeIn({node:dojo.byId(det),duration:"); // $NON-NLS-1$ JavaScriptUtil.addNumber(b, Integer.parseInt(duration)); b.append("}).play();}\n"); // $NON-NLS-1$ } else { //if(vis){dojo.style(det,'display','none'); //}else{dojo.style(det,{opacity: '0',display:'block'});dojo.fadeIn({node:dojo.byId(det),duration:400}).play();} b.append("if(vis){dojo.style(det,"); // $NON-NLS-1$ JavaScriptUtil.addString(b, "display"); // $NON-NLS-1$ b.append(","); // $NON-NLS-1$ JavaScriptUtil.addString(b, "none"); // $NON-NLS-1$ b.append(");}else{dojo.style(det,{opacity: "); // $NON-NLS-1$ JavaScriptUtil.addString(b, "0"); // $NON-NLS-1$ b.append(",display:"); // $NON-NLS-1$ JavaScriptUtil.addString(b, "block"); // $NON-NLS-1$ b.append("});dojo.fadeIn({node:dojo.byId(det),duration:"); // $NON-NLS-1$ JavaScriptUtil.addNumber(b, Integer.parseInt(duration)); b.append("}).play();}\n"); // $NON-NLS-1$ } } else { if(viewDef.summaryOrDetailVisible) { // if(vis){dojo.style(det,'display','none');dojo.style(sum,'display','block'); //}else{dojo.style(sum,'display','none');dojo.style(det,'display','block')} b.append("if(vis){dojo.style(det,"); // $NON-NLS-1$ JavaScriptUtil.addString(b, "display"); // $NON-NLS-1$ b.append(","); // $NON-NLS-1$ JavaScriptUtil.addString(b, "none"); // $NON-NLS-1$ b.append(");dojo.style(sum,"); // $NON-NLS-1$ JavaScriptUtil.addString(b, "display"); // $NON-NLS-1$ b.append(","); // $NON-NLS-1$ JavaScriptUtil.addString(b, "block"); // $NON-NLS-1$ b.append(");}else{dojo.style(sum,"); // $NON-NLS-1$ JavaScriptUtil.addString(b, "display"); // $NON-NLS-1$ b.append(","); // $NON-NLS-1$ JavaScriptUtil.addString(b, "none"); // $NON-NLS-1$ b.append(");dojo.style(det,"); // $NON-NLS-1$ JavaScriptUtil.addString(b, "display"); // $NON-NLS-1$ b.append(","); // $NON-NLS-1$ JavaScriptUtil.addString(b, "block"); // $NON-NLS-1$ b.append(")}\n"); // $NON-NLS-1$ } else { // if(vis){dojo.style(det,'display','none'); //}else{dojo.style(det,'display','block')} b.append("if(vis){dojo.style(det,"); // $NON-NLS-1$ JavaScriptUtil.addString(b, "display"); // $NON-NLS-1$ b.append(","); // $NON-NLS-1$ JavaScriptUtil.addString(b, "none"); // $NON-NLS-1$ b.append(");}else{dojo.style(det,"); // $NON-NLS-1$ JavaScriptUtil.addString(b, "display"); // $NON-NLS-1$ b.append(","); // $NON-NLS-1$ JavaScriptUtil.addString(b, "block"); // $NON-NLS-1$ b.append(")}\n"); // $NON-NLS-1$ } } b.append("}\n"); // $NON-NLS-1$ UIScriptCollector col = UIScriptCollector.find(); col.addScript(b.toString()); } protected void writeClientShowHideHiddenField(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException { String id = c.getClientId(context)+ID_HIDDEN; w.startElement("input",c); // this is for the uistate $NON-NLS-1$ w.writeAttribute("id",id,null); // $NON-NLS-1$ w.writeAttribute("name",id,null); // $NON-NLS-1$ w.writeAttribute("type","hidden",null); // $NON-NLS-1$ $NON-NLS-2$ w.writeAttribute("value","",null); // $NON-NLS-1$ w.endElement("input"); // $NON-NLS-1$ } // ================================================================ // Header // ================================================================ protected void writeHeader(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException { // container facets UIComponent header = c.getFacet(AbstractDataView.FACET_HEADER); if( null != header ){ writeHeaderFacet(context, w, c, viewDef, header); } UIComponent noRowsFacet = c.getFacet(AbstractDataView.FACET_NOROWS); if (!hasMoreRowsToRender(c) && noRowsFacet != null) { return; } UIComponent pagerTop = c.getFacet(AbstractDataView.FACET_PAGERTOP); UIComponent pagerTopLeft = c.getFacet(AbstractDataView.FACET_PAGERTOPLEFT); UIComponent pagerTopRight = c.getFacet(AbstractDataView.FACET_PAGERTOPRIGHT); if( null != pagerTop && !pagerTop.isRendered() ){ pagerTop = null; } if( null != pagerTopLeft && !pagerTopLeft.isRendered() ){ pagerTopLeft = null; } if( null != pagerTopRight && !pagerTopRight.isRendered() ){ pagerTopRight = null; } if( pagerTop !=null || pagerTopLeft!=null || pagerTopRight!=null) { writeHeaderPagerArea(context, w, c, viewDef, pagerTop, pagerTopLeft, pagerTopRight); } } protected void writeHeaderFacet(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef, UIComponent header) throws IOException { FacesUtil.renderComponent(context, header); } protected void writeHeaderPagerArea(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef, UIComponent pagerTop, UIComponent pagerTopLeft, UIComponent pagerTopRight) throws IOException { String tag = (String)getProperty(PROP_HEADER_PAGER_AREA_TAG); if(StringUtil.isNotEmpty(tag)) { startElement(w, tag, PROP_HEADERSTYLE, PROP_HEADERCLASS, PROP_HEADERDOJOTYPE); } writeHeaderLeft(context, w, c, viewDef, pagerTopLeft); writeHeaderMiddle(context, w, c, viewDef, pagerTop); writeHeaderRight(context, w, c, viewDef, pagerTopRight); if(StringUtil.isNotEmpty(tag)) { w.endElement(tag); } newLine(w); } protected void writeHeaderLeft(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef, UIComponent facet) throws IOException { if(facet!=null) { String tag = (String)getProperty(PROP_FACETTAG); if(StringUtil.isNotEmpty(tag)) { startElement(w, tag, PROP_HEADERLEFTSTYLE, PROP_HEADERLEFTCLASS, null); } FacesUtil.renderComponent(context, facet); if(StringUtil.isNotEmpty(tag)) { w.endElement(tag); } newLine(w); } } protected void writeHeaderMiddle(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef, UIComponent facet) throws IOException { if(facet!=null) { String tag = (String)getProperty(PROP_FACETTAG); if(StringUtil.isNotEmpty(tag)) { startElement(w, tag, PROP_HEADERMIDDLESTYLE, PROP_HEADERMIDDLECLASS, null); } FacesUtil.renderComponent(context, facet); if(StringUtil.isNotEmpty(tag)) { w.endElement(tag); } newLine(w); } } protected void writeHeaderRight(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef, UIComponent facet) throws IOException { if(facet!=null) { String tag = (String)getProperty(PROP_FACETTAG); if(StringUtil.isNotEmpty(tag)) { startElement(w, tag, PROP_HEADERRIGHTSTYLE, PROP_HEADERRIGHTCLASS, null); } FacesUtil.renderComponent(context, facet); if(StringUtil.isNotEmpty(tag)) { w.endElement(tag); } newLine(w); } } // ================================================================ // Footer // ================================================================ protected void writeFooter(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException { // container facets if (hasMoreRowsToRender(c)) { UIComponent pagerBottom = c.getFacet(AbstractDataView.FACET_PAGERBOTTOM); UIComponent pagerBottomLeft = c.getFacet(AbstractDataView.FACET_PAGERBOTTOMLEFT); UIComponent pagerBottomRight = c.getFacet(AbstractDataView.FACET_PAGERBOTTOMRIGHT); if( null != pagerBottom && !pagerBottom.isRendered() ){ pagerBottom = null; } if( null != pagerBottomLeft && !pagerBottomLeft.isRendered() ){ pagerBottomLeft = null; } if( null != pagerBottomRight && !pagerBottomRight.isRendered() ){ pagerBottomRight = null; } if(pagerBottom !=null || pagerBottomLeft!=null || pagerBottomRight!=null) { writeFooterPagerArea(context, w, c, viewDef, pagerBottom, pagerBottomLeft, pagerBottomRight); } } UIComponent footer = c.getFacet(AbstractDataView.FACET_FOOTER); if( null != footer ){ writeFooterFacet(context, w, c, viewDef, footer); } } protected void writeFooterFacet(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef, UIComponent footer) throws IOException { FacesUtil.renderComponent(context, footer); } protected void writeFooterPagerArea(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef, UIComponent pagerBottom, UIComponent pagerBottomLeft, UIComponent pagerBottomRight) throws IOException { String tag = (String)getProperty(PROP_FOOTER_PAGER_AREA_TAG); if(StringUtil.isNotEmpty(tag)) { startElement(w, tag, PROP_FOOTERSTYLE, PROP_FOOTERCLASS, PROP_FOOTERDOJOTYPE); } writeFooterLeft(context, w, c, viewDef, pagerBottomLeft); writeFooterMiddle(context, w, c, viewDef, pagerBottom); writeFooterRight(context, w, c, viewDef, pagerBottomRight); if(StringUtil.isNotEmpty(tag)) { w.endElement(tag); } newLine(w); } protected void writeFooterLeft(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef, UIComponent facet) throws IOException { if(facet!=null) { String tag = (String)getProperty(PROP_FACETTAG); if(StringUtil.isNotEmpty(tag)) { startElement(w, tag, PROP_FOOTERLEFTSTYLE, PROP_FOOTERLEFTCLASS, null); } FacesUtil.renderComponent(context, facet); if(StringUtil.isNotEmpty(tag)) { w.endElement(tag); } newLine(w); } } protected void writeFooterMiddle(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef, UIComponent facet) throws IOException { if(facet!=null) { String tag = (String)getProperty(PROP_FACETTAG); if(StringUtil.isNotEmpty(tag)) { startElement(w, tag, PROP_FOOTERMIDDLESTYLE, PROP_FOOTERMIDDLECLASS, null); } FacesUtil.renderComponent(context, facet); if(StringUtil.isNotEmpty(tag)) { w.endElement(tag); } newLine(w); } } protected void writeFooterRight(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef, UIComponent facet) throws IOException { if(facet!=null) { String tag = (String)getProperty(PROP_FACETTAG); if(StringUtil.isNotEmpty(tag)) { startElement(w, tag, PROP_FOOTERRIGHTSTYLE, PROP_FOOTERRIGHTCLASS, null); } FacesUtil.renderComponent(context, facet); if(StringUtil.isNotEmpty(tag)) { w.endElement(tag); } newLine(w); } } // ================================================================ // Write a single row - used by partial refresh // ================================================================ protected void writeSingleRow(FacesContext context, ResponseWriter w, AbstractDataView c) throws IOException { ViewDefinition viewDef = new ViewDefinition(context); initViewDefinition(context, c, viewDef); viewDef.singleRowRefresh = true; // The data iterator already put us on the right row beforeRow(context, w, c, viewDef); writeRow(context, w, c, viewDef); afterRow(context, w, c, viewDef); } // ================================================================ // Common implementation // ================================================================ @Override protected final void writeMainContainer(FacesContext context, ResponseWriter w, UIDataSourceIterator _c) throws IOException { AbstractDataView c = (AbstractDataView)_c; ViewDefinition viewDef = createViewDefinition(context); initViewDefinition(context, c, viewDef); writeDataView(context, w, c, viewDef); } protected void writeDataView(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException { // Start the main frame w.startElement("div",c); // $NON-NLS-1$ w.writeAttribute("id",c.getClientId(context),null); // $NON-NLS-1$ String style = c.getStyle(); if(StringUtil.isEmpty(style)) { style = (String)getProperty(PROP_MAINDIVSTYLE); } if(StringUtil.isNotEmpty(style)) { w.writeAttribute("style", style, null); // $NON-NLS-1$ } String styleClass = c.getStyleClass(); if(StringUtil.isEmpty(styleClass)) { styleClass = (String)getProperty(PROP_MAINDIVCLASS); } if(StringUtil.isNotEmpty(styleClass)) { w.writeAttribute("class", styleClass, null); // $NON-NLS-1$ } if (c instanceof UIDataView) { UIDataView dv = (UIDataView)c; String role = dv.getRole(); if(!StringUtil.isEmpty(role)) { w.writeAttribute("role", role, null); // $NON-NLS-1$ } } // Write the support field for show/hide writeShowHide(context, w, c, viewDef); // Write the header boolean hasHeader = (Boolean)getProperty(PROP_HASHEADERFACET); if(hasHeader) { writeHeader(context, w, c, viewDef); } // Write the body UIComponent noRowsFacet = c.getFacet(AbstractDataView.FACET_NOROWS); if (!hasMoreRowsToRender(c) && noRowsFacet != null) { writeNoRowsContent(context, w, c, viewDef); } else { writeContent(context, w, c, viewDef); } // Write the footer boolean hasFooter = (Boolean)getProperty(PROP_HASFOOTERFACET); if(hasFooter) { writeFooter(context, w, c, viewDef); } // Close the main container w.endElement("div"); // $NON-NLS-1$ newLine(w); } protected abstract void writeContent(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException; protected void writeNoRowsContent(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException { UIComponent noRowsFacet = c.getFacet(AbstractDataView.FACET_NOROWS); if( null != noRowsFacet) { String tag = (String)getProperty(PROP_FACETTAG); if(StringUtil.isNotEmpty(tag)) { startElement(w, tag, null, PROP_NOROWSCLASS, null); } FacesUtil.renderComponent(context, noRowsFacet); if(StringUtil.isNotEmpty(tag)) { w.endElement(tag); } newLine(w); } } protected void writeRows(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef, int first, int rows) throws IOException { try { // Initialize the view definition viewDef.first = first; viewDef.rows = rows; beforeRows(context, w, c, viewDef); // Horrible fix for 852... if(ExtLibUtil.isXPages852()) { // We use the offset that was previously stored when we read the very first row // This assumes that the view had been already read from the beginning. Object o = c.getAttributes().get("__view_indent_offset"); // $NON-NLS-1$ if(o instanceof Integer) { viewDef.indentOffset = (Integer)o; } } for(int i=0; i<rows; i++) { int index = first+i; c.setRowIndex(index); if(!c.isRowAvailable()) { if(index == 0 && c instanceof UIForumView){ w.startElement("li", null); //$NON-NLS-1$ w.writeComment("no content"); //$NON-NLS-1$ w.endElement("li"); //$NON-NLS-1$ } break; } if(ExtLibUtil.isXPages852()) { if(index==0) { // There is a bug in the view datamodel in 852 // When the view do start from the root level (ex: from a parent id), then viewDef.indentOffset = Math.max(0,calculateIndentOffset(context, c, viewDef)); if(viewDef.indentOffset>0) { TypedUtil.getAttributes(c).put("__view_indent_offset",Integer.valueOf(viewDef.indentOffset)); // $NON-NLS-1$ } } } beforeRow(context, w, c, viewDef); writeRow(context, w, c, viewDef); afterRow(context, w, c, viewDef); } afterRows(context, w, c, viewDef); } finally { //reset c.setRowIndex(-1); } } protected void beforeRows(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException { } protected void afterRows(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException { } protected void beforeRow(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException{ viewDef.rowPosition = getRowPosition(context, c, viewDef); viewDef.rowDisableHideRow = c.isDisableHideRow(); viewDef.rowDetailVisible = isRowDetailVisible(context, c, viewDef); } protected void afterRow(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException{ } protected abstract void writeRow(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException; protected boolean hasMoreRowsToRender(AbstractDataView c) { if (c.getFirst() > 0) return true; boolean more = false; // preserve old index int idx = c.getRowIndex(); // set index to first row for current page. If step 10, then first row for Page 1 is 0, first row for Page 2 is 10 c.setRowIndex(c.getFirst()); // calculate if more rows are available on current page boolean isRowAvailable = c.isRowAvailable(); more = c.getFirst() > 0 || isRowAvailable; // restore index c.setRowIndex(idx); // Navigation to previous page could be considered later, but right now we'll stay on the same page // if we are on a page > 1 and no more rows on it, then navigate to previous page // if (c.getFirst() > 0 && !isRowAvailable) c.gotoPreviousPage(); return more; } }