org.richfaces.renderkit.CollapsibleSubTableRenderer Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source
* Copyright ${year}, Red Hat, Inc. and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.richfaces.renderkit;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.faces.application.ResourceDependencies;
import javax.faces.application.ResourceDependency;
import javax.faces.component.UIColumn;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.AbortProcessingException;
import org.ajax4jsf.javascript.JSFunction;
import org.richfaces.cdk.annotations.JsfRenderer;
import org.richfaces.component.AbstractCollapsibleSubTable;
import org.richfaces.component.AbstractDataTable;
import org.richfaces.component.Row;
import org.richfaces.component.UIDataTableBase;
import org.richfaces.event.CollapsibleSubTableToggleEvent;
import org.richfaces.renderkit.util.AjaxRendererUtils;
/**
* @author Anton Belevich
*
*/
@JsfRenderer(type = "org.richfaces.CollapsibleSubTableRenderer", family = AbstractCollapsibleSubTable.COMPONENT_FAMILY)
@ResourceDependencies({ @ResourceDependency(library = "javax.faces", name = "jsf.js"),
@ResourceDependency(library = "org.richfaces", name = "jquery.js"),
@ResourceDependency(library = "org.richfaces", name = "richfaces.js"),
@ResourceDependency(library = "org.richfaces", name = "richfaces-base-component.js"),
@ResourceDependency(library = "org.richfaces", name = "collapsible-subtable.js"),
@ResourceDependency(library = "org.richfaces", name = "collapsible-subtable.ecss") })
public class CollapsibleSubTableRenderer extends AbstractTableRenderer {
public static final String TB_ROW = ":c";
private static final String STATE = ":state";
private static final String OPTIONS = ":options";
private static final String DISPLAY_NONE = "display: none;";
private class CollapsibleSubTableHiddenEncodeStrategy implements EncodeStrategy {
public void begin(ResponseWriter writer, FacesContext context, UIComponent component, Object[] params)
throws IOException {
AbstractCollapsibleSubTable subTable = (AbstractCollapsibleSubTable) component;
writer.startElement(HtmlConstants.TR_ELEMENT, subTable);
writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, subTable.getContainerClientId(context) + HIDDEN_CONTAINER_ID,
null);
writer.writeAttribute(HtmlConstants.STYLE_ATTRIBUTE, DISPLAY_NONE, null);
writer.startElement(HtmlConstants.TD_ELEM, subTable);
}
public void end(ResponseWriter writer, FacesContext context, UIComponent component, Object[] params) throws IOException {
writer.endElement(HtmlConstants.TD_ELEM);
writer.endElement(HtmlConstants.TR_ELEMENT);
if (params != null && params.length == 1) {
boolean endTbody = (Boolean) params[0];
if (endTbody) {
encodeTableBodyEnd(writer);
}
}
}
}
;
protected void doDecode(FacesContext facesContext, UIComponent component) {
super.doDecode(facesContext, component);
AbstractCollapsibleSubTable subTable = (AbstractCollapsibleSubTable) component;
String clientId = subTable.getClientId(facesContext);
Map requestMap = facesContext.getExternalContext().getRequestParameterMap();
String optionsId = clientId + OPTIONS;
String togglerId = requestMap.get(optionsId);
String stateId = clientId + STATE;
String state = (String) requestMap.get(stateId);
boolean isExpanded = true;
if (state != null) {
int newValue = Integer.parseInt(state);
if (newValue < 1) {
isExpanded = false;
}
if (subTable.isExpanded() != isExpanded) {
new CollapsibleSubTableToggleEvent(subTable, isExpanded, togglerId).queue();
}
}
}
@Override
protected void decodeFiltering(FacesContext context, UIDataTableBase dataTableBase, String value) {
super.decodeFiltering(context, dataTableBase, value);
dataTableBase.clearExtendedDataModel();
}
@Override
protected void decodeSorting(FacesContext context, UIDataTableBase dataTableBase, String value) {
super.decodeSorting(context, dataTableBase, value);
dataTableBase.clearExtendedDataModel();
}
@Override
public void encodeFirstRowStart(ResponseWriter writer, FacesContext context, String parentId, int currentRow,
UIComponent component) throws IOException {
writer.startElement(HtmlConstants.TR_ELEMENT, component);
writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, parentId + ":" + currentRow + ":b", null);
String styleClass = concatClasses(getRowClass(context, parentId), getFirstRowClass(context, parentId), component
.getAttributes().get(ROW_CLASS));
encodeStyleClass(writer, context, component, HtmlConstants.STYLE_CLASS_ATTR, styleClass);
UIComponent parent = component.getParent();
if (parent instanceof AbstractCollapsibleSubTable && Boolean.TRUE.equals(parent.getAttributes().get("isNested"))) {
AbstractCollapsibleSubTable subTable = (AbstractCollapsibleSubTable) parent;
if (!subTable.isExpanded()) {
writer.writeAttribute(HtmlConstants.STYLE_ATTRIBUTE, DISPLAY_NONE, null);
}
}
}
@Override
public void encodeRowStart(ResponseWriter writer, FacesContext context, String parentId, int currentRow,
UIComponent component) throws IOException {
writer.startElement(HtmlConstants.TR_ELEMENT, component);
writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, parentId + ":" + currentRow + ":b", null);
String styleClass = concatClasses(getRowClass(context, parentId), component.getAttributes().get(ROW_CLASS));
encodeStyleClass(writer, context, component, HtmlConstants.STYLE_CLASS_ATTR, styleClass);
UIComponent parent = component.getParent();
if (parent instanceof AbstractCollapsibleSubTable && Boolean.TRUE.equals(parent.getAttributes().get("isNested"))) {
AbstractCollapsibleSubTable subTable = (AbstractCollapsibleSubTable) parent;
if (!subTable.isExpanded()) {
writer.writeAttribute(HtmlConstants.STYLE_ATTRIBUTE, DISPLAY_NONE, null);
}
}
}
public void encodeTableFacets(ResponseWriter writer, FacesContext context, UIDataTableBase dataTable) throws IOException {
AbstractCollapsibleSubTable subTable = (AbstractCollapsibleSubTable) dataTable;
encodeStyle(writer, context, subTable, null);
encodeHeaderFacet(writer, context, subTable, false);
String rowClass = getRowSkinClass();
String cellClass = getCellSkinClass();
String firstClass = getFirstRowSkinClass();
rowClass = mergeStyleClasses("rowClass", rowClass, subTable);
cellClass = mergeStyleClasses("cellClass", cellClass, subTable);
firstClass = mergeStyleClasses("firstRowClass", firstClass, subTable);
saveRowStyles(context, subTable.getContainerClientId(context), firstClass, rowClass, cellClass);
}
@Override
public void encodeTableBodyStart(ResponseWriter writer, FacesContext facesContext, UIDataTableBase dataTableBase)
throws IOException {
AbstractCollapsibleSubTable subTable = (AbstractCollapsibleSubTable) dataTableBase;
UIDataTableBase parent = findParent(subTable);
if (parent instanceof AbstractDataTable) {
writer.startElement(HtmlConstants.TBODY_ELEMENT, null);
writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE,
parent.getRelativeClientId(facesContext) + ":" + subTable.getId() + TB_ROW, null);
writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, getTableSkinClass(), null);
String predefinedStyles = !subTable.isExpanded() ? DISPLAY_NONE : null;
encodeStyle(writer, facesContext, subTable, predefinedStyles);
}
// stash whether or not this subTable is nested in the attribute map for later retrieval
subTable.getAttributes().put("isNested", (parent instanceof AbstractCollapsibleSubTable));
}
@Override
public void encodeBeforeRows(ResponseWriter writer, FacesContext facesContext, UIDataTableBase dataTableBase,
boolean encodeParentTBody, boolean partialUpdate) throws IOException {
AbstractCollapsibleSubTable subTable = (AbstractCollapsibleSubTable) dataTableBase;
encodeTableBodyStart(writer, facesContext, subTable);
encodeSubTableDomElement(writer, facesContext, subTable);
encodeHeaderFacet(writer, facesContext, subTable, false);
}
private void encodeSubTableDomElement(ResponseWriter writer, FacesContext facesContext, AbstractCollapsibleSubTable subTable)
throws IOException {
writer.startElement(HtmlConstants.TR_ELEMENT, subTable);
writer.writeAttribute(HtmlConstants.STYLE_ATTRIBUTE, DISPLAY_NONE, null);
writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, subTable.getContainerClientId(facesContext), null);
writer.startElement(HtmlConstants.TD_ELEM, subTable);
writer.endElement(HtmlConstants.TD_ELEM);
writer.endElement(HtmlConstants.TR_ELEMENT);
}
public void encodeRow(ResponseWriter writer, FacesContext facesContext, RowHolderBase holder) throws IOException {
RowHolder rowHolder = (RowHolder) holder;
Row row = rowHolder.getRow();
putRowStylesIntoContext(facesContext, rowHolder);
rowHolder.setRowStart(true);
Iterator components = row.columns();
if (rowHolder.isUpdatePartial()) {
partialStart(facesContext, ((AbstractCollapsibleSubTable) row).getRelativeClientId(facesContext) + ":b");
}
int columnNumber = 0;
boolean rowEnded = false;
while (components.hasNext()) {
UIComponent component = components.next();
if (component.isRendered()) {
if (component instanceof UIColumn) {
component.getAttributes().put(COLUMN_CLASS, getColumnClass(rowHolder, columnNumber));
encodeColumn(facesContext, writer, (UIColumn) component, rowHolder);
columnNumber++;
} else if (component instanceof AbstractCollapsibleSubTable) {
if (component.isRendered()) {
rowEnded = true;
encodeRowEnd(writer);
}
component.encodeAll(facesContext);
rowHolder.setRowStart(true);
}
}
}
if (!rowEnded) {
encodeRowEnd(writer);
}
if (rowHolder.isUpdatePartial()) {
partialEnd(facesContext);
}
}
@Override
public void encodeAfterRows(ResponseWriter writer, FacesContext facesContext, UIDataTableBase dataTableBase,
boolean encodeParentTBody, boolean partialUpdate) throws IOException {
AbstractCollapsibleSubTable subTable = (AbstractCollapsibleSubTable) dataTableBase;
encodeFooterFacet(writer, facesContext, subTable, false);
}
@Override
public boolean encodeParentTBody(UIDataTableBase dataTableBase) {
UIDataTableBase parent = findParent((AbstractCollapsibleSubTable) dataTableBase);
return (parent instanceof AbstractDataTable);
}
public void encodeHiddenInput(ResponseWriter writer, FacesContext facesContext, UIDataTableBase dataTableBase)
throws IOException {
AbstractCollapsibleSubTable subTable = (AbstractCollapsibleSubTable) dataTableBase;
String stateId = subTable.getClientId(facesContext) + STATE;
writer.startElement(HtmlConstants.INPUT_ELEM, subTable);
writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, stateId, null);
writer.writeAttribute(HtmlConstants.NAME_ATTRIBUTE, stateId, null);
writer.writeAttribute(HtmlConstants.TYPE_ATTR, HtmlConstants.INPUT_TYPE_HIDDEN, null);
int state = subTable.isExpanded() ? AbstractCollapsibleSubTable.EXPANDED_STATE
: AbstractCollapsibleSubTable.COLLAPSED_STATE;
writer.writeAttribute(HtmlConstants.VALUE_ATTRIBUTE, state, null);
writer.endElement(HtmlConstants.INPUT_ELEM);
String optionsId = subTable.getClientId(facesContext) + OPTIONS;
writer.startElement(HtmlConstants.INPUT_ELEM, subTable);
writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, optionsId, null);
writer.writeAttribute(HtmlConstants.NAME_ATTRIBUTE, optionsId, null);
writer.writeAttribute(HtmlConstants.TYPE_ATTR, HtmlConstants.INPUT_TYPE_HIDDEN, null);
writer.endElement(HtmlConstants.INPUT_ELEM);
}
public boolean containsThead() {
return false;
}
public EncodeStrategy getHeaderEncodeStrategy(UIComponent column, String tableFacetName) {
// TODO: anton -> use RichHeaderEncodeStrategy for our columns ???
return new SimpleHeaderEncodeStrategy();
}
public void encodeClientScript(ResponseWriter writer, FacesContext facesContext, UIDataTableBase component)
throws IOException {
AbstractCollapsibleSubTable subTable = (AbstractCollapsibleSubTable) component;
String id = subTable.getClientId(facesContext);
UIComponent nestingForm = getUtils().getNestingForm(subTable);
String formId = nestingForm != null ? nestingForm.getClientId(facesContext) : "";
AjaxOptions ajaxOptions = AjaxRendererUtils.buildEventOptions(facesContext, subTable);
Map options = new HashMap();
options.put("ajaxEventOptions", ajaxOptions.getParameters());
options.put("stateInput", subTable.getClientId(facesContext) + STATE);
options.put("optionsInput", subTable.getClientId(facesContext) + OPTIONS);
boolean isNested = Boolean.TRUE.equals(subTable.getAttributes().get("isNested"));
String expandMode = isNested ? "client" : subTable.getExpandMode();
options.put("expandMode", expandMode);
options.put("isNested", isNested);
options.put("eventOptions", AjaxRendererUtils.buildEventOptions(facesContext, subTable));
JSFunction jsFunction = new JSFunction("new RichFaces.ui.CollapsibleSubTable");
jsFunction.addParameter(id);
jsFunction.addParameter(formId);
jsFunction.addParameter(options);
writer.startElement(HtmlConstants.SCRIPT_ELEM, subTable);
writer.writeAttribute(HtmlConstants.TYPE_ATTR, HtmlConstants.JAVASCRIPT_TYPE, null);
writer.writeText(jsFunction.toScript(), null);
writer.endElement(HtmlConstants.SCRIPT_ELEM);
}
public String getTableSkinClass() {
return "rf-cst";
}
public String getRowSkinClass() {
return "rf-cst-r";
}
public String getFirstRowSkinClass() {
return "rf-cst-fst-r";
}
public String getHeaderRowSkinClass() {
return "rf-cst-hdr-r";
}
public String getHeaderFirstRowSkinClass() {
return "rf-cst-hdr-fst-r";
}
public String getCellSkinClass() {
return "rf-cst-c";
}
public String getHeaderCellSkinClass() {
return "rf-cst-hdr-c";
}
public String getColumnHeaderCellSkinClass() {
return "rf-cst-shdr-c";
}
public String getColumnHeaderSkinClass() {
return "rf-cst-shdr";
}
public String getFooterSkinClass() {
return "rf-cst-ftr";
}
public String getFooterCellSkinClass() {
return "rf-cst-ftr-c";
}
public String getFooterFirstRowSkinClass() {
return "rf-cst-ftr-fst";
}
public String getColumnFooterCellSkinClass() {
return "rf-cst-sftr-c";
}
public String getColumnFooterSkinClass() {
return "rf-cst-sftr";
}
public String getColumnFooterFirstSkinClass() {
return "rf-cst-sftr-fst";
}
public String getColumnHeaderFirstSkinClass() {
return "rf-cst-shdr-fst";
}
public String getFooterFirstSkinClass() {
return "rf-cst-ftr-fst";
}
public String getHeaderFirstSkinClass() {
return "rf-cst-hdr-fst";
}
public String getHeaderSkinClass() {
return "rf-cst-hdr";
}
public String getNoDataClass() {
return "rf-cst-nd";
}
@Override
public String getNoDataCellClass() {
return "rf-cst-nd-c";
}
@Override
public String getTableBodySkinClass() {
// AbstractSubTable doesn't have tbody
return null;
}
@Override
public void encodeMetaComponent(FacesContext facesContext, UIComponent component, String metaComponentId)
throws IOException {
AbstractCollapsibleSubTable subTable = (AbstractCollapsibleSubTable) component;
if (AbstractCollapsibleSubTable.BODY.equals(metaComponentId)) {
ResponseWriter writer = facesContext.getResponseWriter();
UIDataTableBase dataTableBase = findParent(subTable);
String updateId = dataTableBase.getRelativeClientId(facesContext) + ":" + subTable.getId() + TB_ROW;
partialStart(facesContext, updateId);
encodeTableRows(writer, facesContext, subTable, false);
partialEnd(facesContext);
}
}
@Override
public EncodeStrategy getHiddenContainerStrategy(UIDataTableBase dataTableBase) {
return new CollapsibleSubTableHiddenEncodeStrategy();
}
protected UIDataTableBase findParent(AbstractCollapsibleSubTable subTable) {
UIComponent parent = subTable.getParent();
while (parent != null && !(parent instanceof UIDataTableBase)) {
parent = parent.getParent();
}
if (parent == null) {
// TODO: anton -> do we need this?
throw new AbortProcessingException("UISubTable should be a child of UIDataTable or UISubTable");
}
return (UIDataTableBase) parent;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy