All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.larmic.butterfaces.component.renderkit.html_basic.table.TableRenderer Maven / Gradle / Ivy

The newest version!
/*
 * Copyright Lars Michaelis and Stephan Zerhusen 2016.
 * Distributed under the MIT License.
 * (See accompanying file README.md file or copy at http://opensource.org/licenses/MIT)
 */
package de.larmic.butterfaces.component.renderkit.html_basic.table;

import de.larmic.butterfaces.component.base.renderer.HtmlBasicRenderer;
import de.larmic.butterfaces.component.behavior.JsfAjaxRequest;
import de.larmic.butterfaces.component.html.table.HtmlColumn;
import de.larmic.butterfaces.component.html.table.HtmlTable;
import de.larmic.butterfaces.component.partrenderer.RenderUtils;
import de.larmic.butterfaces.component.renderkit.html_basic.table.cache.TableColumnCache;
import de.larmic.butterfaces.event.TableSingleSelectionListener;
import de.larmic.butterfaces.model.table.SortType;
import de.larmic.butterfaces.resolver.ClientBehaviorResolver;
import de.larmic.butterfaces.resolver.WebXmlParameters;
import de.larmic.butterfaces.util.StringJoiner;
import de.larmic.butterfaces.util.StringUtils;

import javax.faces.component.UIComponent;
import javax.faces.component.UIData;
import javax.faces.component.behavior.AjaxBehavior;
import javax.faces.component.behavior.ClientBehavior;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Renderer for {@link HtmlTable}.
 *
 * @author Lars Michaelis
 */
@FacesRenderer(componentFamily = HtmlTable.COMPONENT_FAMILY, rendererType = HtmlTable.RENDERER_TYPE)
public class TableRenderer extends HtmlBasicRenderer {

    private boolean hasColumnWidthSet;
    private int rowIndex;
    private boolean foundSelectedRow;

    private WebXmlParameters webXmlParameters;

    @Override
    public void encodeBegin(final FacesContext context,
                            final UIComponent component) throws IOException {
        if (!component.isRendered()) {
            return;
        }

        final HtmlTable table = (HtmlTable) component;
        final TableColumnCache tableColumnCache = table.getTableColumnCache(context);
        this.hasColumnWidthSet = hasColumnWidthSet(tableColumnCache.getCachedColumns());
        this.rowIndex = 0;
        this.webXmlParameters = new WebXmlParameters(context.getExternalContext());
        this.foundSelectedRow = false;

        table.setRowIndex(-1);

        final ResponseWriter writer = context.getResponseWriter();

        renderTableStart(context, table, writer);
        renderHeader(context, table, writer);
    }

    @Override
    public void encodeChildren(FacesContext context, UIComponent component) throws IOException {
        if (!component.isRendered()) {
            return;
        }

        final HtmlTable table = (HtmlTable) component;
        final ResponseWriter writer = context.getResponseWriter();

        final int rows = table.getRows();
        int processed = 0;
        int rowIndex = table.getFirst() - 1;

        writer.startElement("tbody", component);

        while (true) {
            if ((rows > 0) && (++processed > rows)) {
                break;
            }

            table.setRowIndex(++rowIndex);

            if (!table.isRowAvailable()) {
                break;
            }

            renderRowStart(table, writer);
            renderRow(context, table, writer);
            renderRowEnd(writer);
        }

        writer.endElement("tbody");

        table.setRowIndex(-1);
    }

    @Override
    public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
        if (!component.isRendered()) {
            return;
        }

        ((HtmlTable) component).clearMetaInfo(context, component);
        ((UIData) component).setRowIndex(-1);

        renderTableEnd(context.getResponseWriter());
    }

    @Override
    public boolean getRendersChildren() {
        return true;
    }

    private void renderHeader(final FacesContext context,
                              final HtmlTable table,
                              final ResponseWriter writer) throws IOException {
        final TableColumnCache tableColumnCache = table.getTableColumnCache(context);

        if (hasColumnWidthSet) {
            writer.startElement("colgroup", table);

            int columnNumber = 0;

            for (HtmlColumn column : tableColumnCache.getCachedColumns()) {
                writer.startElement("col", table);
                writer.writeAttribute("class", "butter-table-colgroup", null);
                writer.writeAttribute("columnNumber", "" + columnNumber, null);

                final StringBuilder style = new StringBuilder();

                if (StringUtils.isNotEmpty(column.getColWidth())) {
                    style.append("width: ");
                    style.append(column.getColWidth());
                }
                if (table.isHideColumn(column)) {
                    if (style.length() > 0) {
                        style.append("; ");
                    }
                    style.append("display: none");
                }

                if (style.length() > 0) {
                    writer.writeAttribute("style", style.toString(), null);
                }
                writer.endElement("col");

                columnNumber++;
            }
            writer.endElement("colgroup");
        }

        writer.startElement("thead", table);
        writer.startElement("tr", table);

        int columnNumber = 0;

        for (HtmlColumn column : tableColumnCache.getCachedColumns()) {
            column.setWebXmlParameters(webXmlParameters);
            column.setColumnNumberUsedByTable(columnNumber);
            column.encodeBegin(context);
            column.encodeEnd(context);
            columnNumber++;
        }
        writer.endElement("tr");
        writer.endElement("thead");
    }

    private void renderTableStart(final FacesContext context,
                                  final HtmlTable table,
                                  final ResponseWriter writer) throws IOException {
        writer.startElement(HtmlBasicRenderer.ELEMENT_DIV, table);
        writer.writeAttribute("id", table.getClientId(context), "id");
        writer.writeAttribute("class", StringJoiner.on(' ').join("butter-table").join(StringUtils.getNullSafeValue(table.getStyleClass())).toString(), null);
        if (StringUtils.isNotEmpty(table.getStyle())) {
            writer.writeAttribute("style", table.getStyle(), null);
        }

        writer.startElement(HtmlBasicRenderer.ELEMENT_DIV, table);

        writer.writeAttribute("class", "table-responsive", "styleClass");

        writer.startElement("table", table);
        final StringBuilder tableStyleClass = new StringBuilder("table table-hover");

        if (this.hasColumnWidthSet) {
            tableStyleClass.append(" table-fixed");
        }
        if (table.isTableCondensed()) {
            tableStyleClass.append(" table-condensed");
        }
        if (table.isTableBordered()) {
            tableStyleClass.append(" table-bordered");
        }
        if (table.isTableStriped()) {
            tableStyleClass.append(" table-striped");
        }

        writer.writeAttribute("class", tableStyleClass.toString(), "styleClass");

        writer.writeText("\n", table, null);
    }

    private void renderTableEnd(final ResponseWriter writer) throws IOException {
        writer.endElement("table");
        writer.endElement(HtmlBasicRenderer.ELEMENT_DIV);
        writer.endElement(HtmlBasicRenderer.ELEMENT_DIV);
    }

    private void renderRowStart(final HtmlTable table,
                                final ResponseWriter writer) throws IOException {
        final String clientId = table.getClientId();
        final String baseClientId = clientId.substring(0, clientId.length() - (rowIndex + "").length() - 1);

        writer.startElement("tr", table);
        writer.writeAttribute("rowIndex", rowIndex, null);
        final String rowClass = StringUtils.isNotEmpty(table.getRowClass()) ? "butter-table-row " + table.getRowClass() : "butter-table-row";

        if (!foundSelectedRow && this.isRowSelected(table, rowIndex)) {
            writer.writeAttribute("class", rowClass + " butter-table-row-selected", null);
            foundSelectedRow = true;
        } else {
            writer.writeAttribute("class", rowClass, null);
        }

        final AjaxBehavior clickAjaxBehavior = ClientBehaviorResolver.resolveActiveAjaxBehavior(table, "click");

        if (clickAjaxBehavior != null && table.getSingleSelectionListener() != null) {
            final JsfAjaxRequest ajaxRequest = new JsfAjaxRequest(baseClientId, true)
                    .setEvent("click_" + rowIndex)
                    .setRender(table, "click")
                    .setBehaviorEvent("click_" + rowIndex);
            final String jQueryPluginCall = RenderUtils.createJQueryPluginCall(table.getClientId(), "selectTableRow({rowIndex:'" + rowIndex + "'})");
            writer.writeAttribute("onclick", ajaxRequest.toString() + ";" + jQueryPluginCall.replaceFirst(clientId, baseClientId), null);
        }

        writer.writeText("\n", table, null);

        rowIndex++;
    }

    private void renderRowEnd(final ResponseWriter writer) throws IOException {
        writer.endElement("tr");
    }

    private void renderRow(final FacesContext context,
                           final HtmlTable table,
                           final ResponseWriter writer) throws IOException {
        final TableColumnCache info = table.getTableColumnCache(context);

        int columnNumber = 0;

        for (HtmlColumn column : info.getCachedColumns()) {
            if (table.isHideColumn(column)) {
                continue;
            }

            // Render the beginning of this cell
            boolean isRowHeader = false;
            Object rowHeaderValue = column.getAttributes().get("rowHeader");
            if (null != rowHeaderValue) {
                isRowHeader = Boolean.valueOf(rowHeaderValue.toString());
            }
            if (isRowHeader) {
                writer.startElement("th", column);
                writer.writeAttribute("scope", "row", null);
            } else {
                writer.startElement("td", column);
                //********************************************** ADD butter style class
                StringBuilder sb = new StringBuilder("butter-component-table-column");
                if (StringUtils.isNotEmpty(column.getStyleClass())) {
                    sb.append(" ").append(column.getStyleClass());
                }
                writer.writeAttribute("class", sb.toString(), null);
                writer.writeAttribute("columnNumber", "" + columnNumber, null);

                //********************************************** hide column if models says that
                if (table.isHideColumn(column)) {
                    writer.writeAttribute("style", "display:none", null);
                } else {
                    if (StringUtils.isNotEmpty(column.getStyle())) {
                        writer.writeAttribute("style", column.getStyle(), null);
                    }
                }
            }

            for (Iterator gkids = getChildren(column); gkids.hasNext(); ) {
                encodeRecursive(context, gkids.next());
            }

            if (isRowHeader) {
                writer.endElement("th");
            } else {
                writer.endElement("td");
            }

            columnNumber++;
        }

    }

    @Override
    public void decode(final FacesContext context, final UIComponent component) {
        final HtmlTable table = (HtmlTable) component;
        final Map> behaviors = table.getClientBehaviors();

        if (behaviors.isEmpty()) {
            return;
        }

        final Object untypedTableValue = table.getValue();


        if (!(untypedTableValue instanceof Iterable)) {
            return;
        }

        final ExternalContext external = context.getExternalContext();
        final Map params = external.getRequestParameterMap();
        final String behaviorEvent = params.get("javax.faces.behavior.event");

        if (behaviorEvent != null && behaviorEvent.contains("_")) {
            final String[] split = behaviorEvent.split("_");
            final String event = split[0];
            try {
                final int eventNumber = Integer.valueOf(split[1]);
                if ("click".equals(event)) {
                    final Object rowObject = findRowObject(table, eventNumber);

                    if (rowObject != null) {
                        final TableSingleSelectionListener listener = table.getSingleSelectionListener();

                        if (listener != null) {
                            listener.processTableSelection(rowObject);
                        }

                    }
                } else if ("sort".equals(event) && table.getModel() != null) {
                    final TableColumnCache tableColumnCache = table.getTableColumnCache(context);
                    final HtmlColumn sortedColumn = tableColumnCache.getCachedColumns().get(eventNumber);
                    final String tableUniqueIdentifier = table.getModelUniqueIdentifier();
                    final String columnUniqueIdentifier = sortedColumn.getModelUniqueIdentifier();
                    if (table.getTableSortModel().getSortType(tableUniqueIdentifier, columnUniqueIdentifier) == SortType.ASCENDING) {
                        table.getTableSortModel().sortColumn(tableUniqueIdentifier, columnUniqueIdentifier, sortedColumn.getSortBy(), SortType.DESCENDING);
                    } else {
                        table.getTableSortModel().sortColumn(tableUniqueIdentifier, columnUniqueIdentifier, sortedColumn.getSortBy(), SortType.ASCENDING);
                    }
                }
            } catch (NumberFormatException e) {
                // event is not fired by table component
            }
        }
    }

    private boolean isRowSelected(final HtmlTable table, final int rowIndex) {
        if (table.getSingleSelectionListener() != null) {
            final Object rowObject = findRowObject(table, rowIndex);
            return table.getSingleSelectionListener().isValueSelected(rowObject);
        }

        return false;
    }

    private Object findRowObject(final HtmlTable table, final int row) {
        final Object value = table.getValue();

        if (value instanceof Iterable) {
            final Iterator iterator = ((Iterable) value).iterator();
            int actualRow = 0;

            while (iterator.hasNext()) {
                final Object value1 = iterator.next();

                if (actualRow == row) {
                    return value1;
                }

                actualRow++;
            }

            return null;
        }

        return null;
    }

    private boolean hasColumnWidthSet(final List columns) {
        for (HtmlColumn column : columns) {
            if (StringUtils.isNotEmpty(column.getColWidth())) {
                return true;
            }
        }

        return false;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy