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

org.icefaces.ace.component.datatable.DataTableHeadRenderer Maven / Gradle / Ivy

There is a newer version: 4.3.0
Show newest version
/*
 * Copyright 2004-2013 ICEsoft Technologies Canada Corp.
 *
 * 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 org.icefaces.ace.component.datatable;

import org.icefaces.ace.component.column.Column;
import org.icefaces.ace.component.columngroup.ColumnGroup;
import org.icefaces.ace.component.row.Row;
import org.icefaces.ace.component.tableconfigpanel.TableConfigPanel;
import org.icefaces.ace.renderkit.CoreRenderer;
import org.icefaces.ace.util.HTML;
import org.icefaces.ace.util.JSONBuilder;

import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.model.SelectItem;
import java.io.IOException;
import java.util.*;

public class DataTableHeadRenderer {
    protected static void encodeTableHead(FacesContext context, DataTableRenderingContext tableContext) throws IOException {
        DataTable table = tableContext.getTable();

        if (!table.hasHeaders()) return;

        List headContainer = tableContext.getColumns();
        ResponseWriter writer = context.getResponseWriter();
        ColumnGroup group = table.getColumnGroup("header");
        if (group != null) headContainer = group.getChildren();

        if (tableContext.isStaticHeaders() && !table.isInDuplicateSegment()) {
            writer.startElement(HTML.DIV_ELEM, null);
            writer.writeAttribute(HTML.CLASS_ATTR, DataTableConstants.SCROLLABLE_HEADER_CLASS, null);
            writer.startElement(HTML.TABLE_ELEM, null);
        }

        writer.startElement(HTML.THEAD_ELEM, null);

        if (table.isInDuplicateSegment())
            writer.writeAttribute(HTML.STYLE_ATTR, "display:none;", null);

        // For each row of a col group, or child of a datatable
        boolean firstHeadElement = true;
        boolean subRows = false;
        Iterator headElementIterator = headContainer.iterator();

        do {
            UIComponent headerElem = headElementIterator.next();
            List headerRowChildren = new ArrayList();
            int i = 0;

            // If its a row, get the row children, else add the column as a pseduo child,
            // if not column, break.
            if (headerElem.isRendered() && (headerElem instanceof Row || headerElem instanceof Column)) {
                if (headerElem instanceof Row) {
                    Row headerRow = (Row) headerElem;
                    headerRowChildren = headerRow.getChildren();
                    subRows = true;
                } else headerRowChildren.add(headerElem);

                // If the element was a row of a col-group render another row for a subrow
                // of the header
                if (subRows || firstHeadElement) writer.startElement(HTML.TR_ELEM, null);

                // Either loop through row children or render the single column/columns
                Iterator componentIterator = headerRowChildren.iterator();
                boolean firstComponent = true;
                tableContext.setInHeaderSubrows(subRows);
                List siblings = (subRows) ? headerRowChildren : headContainer;
                while (componentIterator.hasNext()) {
                    UIComponent headerRowChild = componentIterator.next();

                    tableContext.setFirstColumn(firstComponent && firstHeadElement);
                    tableContext.setLastColumn(!headElementIterator.hasNext() && !componentIterator.hasNext());

                    if (headerRowChild.isRendered() && headerRowChild instanceof Column)
                        encodeColumn(context, tableContext, (Column) headerRowChild, siblings);

                    firstComponent = false;
                }

                firstHeadElement = false;

                if (subRows) writer.endElement(HTML.TR_ELEM);
            }
        } while (headElementIterator.hasNext());

        if (!subRows) writer.endElement(HTML.TR_ELEM);

        writer.endElement(HTML.THEAD_ELEM);

        if (tableContext.isStaticHeaders() && !table.isInDuplicateSegment()) {
            writer.endElement(HTML.TABLE_ELEM);
            writer.endElement(HTML.DIV_ELEM);
        }
    }

    private static void encodeColumn(FacesContext context, DataTableRenderingContext tableContext, Column column, List columnSiblings) throws IOException {
        DataTable table = tableContext.getTable();
        ResponseWriter writer = context.getResponseWriter();
        String clientId = column.getClientId(context);

        tableContext.setColumnSortable(column.getValueExpression("sortBy") != null);
        tableContext.setColumnFilterable(column.getValueExpression("filterBy") != null);

        Column nextColumn = DataTableRendererUtil.getNextColumn(column, columnSiblings);
        boolean isCurrStacked = DataTableRendererUtil.isCurrColumnStacked(columnSiblings, column);
        boolean isNextStacked = (nextColumn == null) ? false
                : (nextColumn.isRendered() && nextColumn.isStacked());

        if (!isCurrStacked) {
            String style = column.getStyle();
            String styleClass = column.getStyleClass();
            String columnClass = DataTableConstants.COLUMN_HEADER_CLASS;

            columnClass = (tableContext.isReorderableColumns() && column.isReorderable())
                    ? columnClass + " " + DataTableConstants.REORDERABLE_COL_CLASS
                    : columnClass;
            columnClass = styleClass != null
                    ? columnClass + " " + styleClass
                    : columnClass;
            columnClass = (column.hasSortPriority() && !isNextStacked)
                    ? columnClass + " ui-state-active"
                    : columnClass;

            writer.startElement(HTML.TH_ELEM, null);
            writer.writeAttribute(HTML.CLASS_ATTR, columnClass, null);

            if (style != null)
                writer.writeAttribute(HTML.STYLE_ELEM, style, null);
            if (column.getRowspan() != 1)
                writer.writeAttribute(HTML.ROWSPAN_ATTR, column.getRowspan(), null);
            if (column.getColspan() != 1)
                writer.writeAttribute(HTML.COLSPAN_ATTR, column.getColspan(), null);
        }

        else {
            writer.startElement("hr", null);
            writer.endElement("hr");
        }

        //Container
        writer.startElement(HTML.DIV_ELEM, null);
        writer.writeAttribute(HTML.ID_ATTR, clientId, null);

        if (tableContext.isResizableColumns())
            writer.writeAttribute(HTML.STYLE_ATTR, "position:relative;", null);

        String columnClass = DataTableConstants.COLUMN_HEADER_CONTAINER_CLASS;
        columnClass = tableContext.isColumnSortable() ? columnClass + " " + DataTableConstants.SORTABLE_COLUMN_CLASS : columnClass;
        columnClass = table.isClickableHeaderSorting() ? columnClass + " clickable" : columnClass;
        // Add style class to div in stacking case, else style th
        columnClass = (column.hasSortPriority() && (isCurrStacked || isNextStacked)) ? columnClass + " ui-state-active" : columnClass;

        writer.writeAttribute(HTML.CLASS_ATTR, columnClass, null);

        TableConfigPanel panel = table.findTableConfigPanel(context);

        if (panelTargetsColumn(panel, column,
                tableContext.isFirstColumn(),
                tableContext.isLastColumn(), true))
            encodeLeftSideControls(writer, table,
                    tableContext.isFirstColumn());

        writer.startElement(HTML.SPAN_ELEM, null);

        writer.startElement(HTML.SPAN_ELEM, null);
        writer.writeAttribute(HTML.ID_ATTR, clientId+"_text", null);
        writer.writeAttribute(HTML.CLASS_ATTR, DataTableConstants.HEAD_TEXT_CLASS, null);

        //Header content
        UIComponent header = column.getFacet("header");
        String headerText = column.getHeaderText();

        if (header != null) header.encodeAll(context);
        else if (headerText != null) writer.write(headerText);
        else if (tableContext.isInHeaderSubrows())
            for (UIComponent c : column.getChildren())
                c.encodeAll(context);


        writer.endElement(HTML.SPAN_ELEM);
        writer.endElement(HTML.SPAN_ELEM);

        boolean configButton = panelTargetsColumn(panel, column, tableContext.isFirstColumn(),
                tableContext.isLastColumn(), false);

        if (tableContext.isColumnSortable() || tableContext.isColumnPinningEnabled() || configButton)
            encodeRightSideControls(writer, context, tableContext, column, configButton);

        //Filter
        if (tableContext.isColumnFilterable())
            encodeFilter(context, tableContext, column);

        writer.endElement(HTML.DIV_ELEM);

        if (!isNextStacked) {
            writer.endElement("th");
        } else if (tableContext.isInHeaderSubrows()) {
            // If in a multirow header case, and using stacked, enforce these restrictions
            if (!DataTableRendererUtil.areBothSingleColumnSpan(column, nextColumn))
                throw new FacesException("DataTable : \"" + table.getClientId(context) + "\" must not have stacked header columns, with colspan values greater than 1.");
            if (!DataTableRendererUtil.isNextColumnRowSpanEqual(column, nextColumn))
                throw new FacesException("DataTable : \"" + table.getClientId(context) + "\" must not have stacked header columns, with unequal rowspan values.");
        }
    }

    private static boolean panelTargetsColumn(TableConfigPanel panel, Column column, boolean firstColumn, boolean lastColumn, boolean left) {
        if (panel == null) return false;
        String type = panel.getType();
        if (type.equals("first-col") && firstColumn && left) {
            return true;
        } else if (type.equals("last-col") && lastColumn && !left)  {
            return true;
        } else if (type.equals("in-col-left") && left && panel.getInColumnId().equals(column.getId())) {
            return true;
        } else if (type.equals("in-col-right") && !left && panel.getInColumnId().equals(column.getId())) {
            return true;
        }
        return false;
    }

    private static void encodeLeftSideControls(ResponseWriter writer, DataTable table, boolean first) throws IOException {
        writer.startElement(HTML.SPAN_ELEM, null);
        writer.writeAttribute(HTML.CLASS_ATTR, DataTableConstants.HEADER_LEFT_CLASS, null);

        encodeConfigPanelLaunchButton(writer, table, first);

        writer.endElement(HTML.SPAN_ELEM);
    }

    private static void encodeRightSideControls(ResponseWriter writer, FacesContext context, DataTableRenderingContext tableContext, Column column, boolean renderConfButton) throws IOException {
        writer.write(" ");

        writer.startElement(HTML.SPAN_ELEM, null);
        writer.writeAttribute(HTML.CLASS_ATTR, DataTableConstants.HEADER_RIGHT_CLASS, null);

        //Sort icon
        if (tableContext.isColumnSortable())
            encodeSortControl(writer, context, tableContext, column);

        if (tableContext.isColumnPinningEnabled() && tableContext.showPinningControls())
            encodePinningControl(writer, context, tableContext, column);

        //Configurable last-col controls
        if (renderConfButton)
            encodeConfigPanelLaunchButton(writer, tableContext.getTable(), false);

        writer.endElement(HTML.SPAN_ELEM);
    }

    private static void encodePinningControl(ResponseWriter writer, FacesContext context, DataTableRenderingContext tableContext, Column column) throws IOException {
        writer.startElement(HTML.SPAN_ELEM, null);
        writer.writeAttribute(HTML.CLASS_ATTR, DataTableConstants.PIN_COLUMN_CONTROL_CLASS, null);
        writer.startElement(HTML.ANCHOR_ELEM, null);

        writer.writeAttribute(HTML.CLASS_ATTR, "ui-state-default ui-corner-all", null);
        writer.writeAttribute(HTML.HREF_ATTR, "#", null);
        writer.writeAttribute(HTML.ONCLICK_ATTR,
                CoreRenderer.resolveWidgetVar(tableContext.getTable())+".pinThisColumn(event)", null);
        writer.startElement(HTML.SPAN_ELEM, null);

        writer.writeAttribute(HTML.CLASS_ATTR, "ui-icon", null);

        writer.endElement(HTML.SPAN_ELEM);
        writer.endElement(HTML.ANCHOR_ELEM);
        writer.endElement(HTML.SPAN_ELEM);

    }

    private static void encodeSortControl(ResponseWriter writer, FacesContext context, DataTableRenderingContext tableContext, Column column) throws IOException {
        writer.startElement(HTML.SPAN_ELEM, null);
        writer.writeAttribute(HTML.CLASS_ATTR, DataTableConstants.SORTABLE_COLUMN_CONTROL_CLASS, null);

        // Write carats
        writer.startElement(HTML.SPAN_ELEM, null);
        writer.writeAttribute(HTML.CLASS_ATTR, DataTableConstants.SORTABLE_COLUMN_ICON_CONTAINER, null);

        writer.startElement(HTML.ANCHOR_ELEM, null);
        writer.writeAttribute(HTML.TABINDEX_ATTR, tableContext.getTabIndex(), null);
        if (column.hasSortPriority() && column.isSortAscending())
            writer.writeAttribute(HTML.CLASS_ATTR, DataTableConstants.SORTABLE_COLUMN_ICON_UP_CLASS + " ui-toggled", null);
        else writer.writeAttribute(HTML.CLASS_ATTR, DataTableConstants.SORTABLE_COLUMN_ICON_UP_CLASS, null);
        writer.endElement(HTML.ANCHOR_ELEM);

        writer.startElement(HTML.ANCHOR_ELEM, null);
        writer.writeAttribute(HTML.TABINDEX_ATTR, tableContext.getTabIndex(), null);
        if (column.hasSortPriority() && !column.isSortAscending())
            writer.writeAttribute(HTML.CLASS_ATTR, DataTableConstants.SORTABLE_COLUMN_ICON_DOWN_CLASS + " ui-toggled", null);
        else writer.writeAttribute(HTML.CLASS_ATTR, DataTableConstants.SORTABLE_COLUMN_ICON_DOWN_CLASS, null);
        writer.endElement(HTML.ANCHOR_ELEM);

        writer.endElement(HTML.SPAN_ELEM);


        // Write Sort Order Integer
        writer.startElement(HTML.SPAN_ELEM, null);
        writer.writeAttribute(HTML.CLASS_ATTR, DataTableConstants.SORTABLE_COLUMN_ORDER_CLASS, null);

        if (tableContext.getTable().isSingleSort())
            writer.writeAttribute(HTML.STYLE_ATTR, "display:none;", null);
        else if (column.hasSortPriority()) writer.writeText(column.getSortPriority(), null);

        writer.endElement(HTML.SPAN_ELEM);

        writer.endElement(HTML.SPAN_ELEM);
    }

    private static void encodeFilter(FacesContext context, DataTableRenderingContext tableContext, Column column) throws IOException {
        Map params = context.getExternalContext().getRequestParameterMap();
        ResponseWriter writer = context.getResponseWriter();
        DataTable table = tableContext.getTable();

        String widgetVar = CoreRenderer.resolveWidgetVar(table);
        String filterId = column.getClientId(context) + "_filter";
        String filterFunction = widgetVar + ".filter(event)";
        String filterStyleClass = column.getFilterStyleClass();
        String filterEvent = table.getFilterEvent();
        filterStyleClass = filterStyleClass == null
                ? DataTableConstants.COLUMN_FILTER_CLASS
                : DataTableConstants.COLUMN_FILTER_CLASS + " " + filterStyleClass;

        if (column.getValueExpression("filterOptions") == null) {
            String filterValue = column.getFilterValue() != null ? column.getFilterValue() : "";

            writer.startElement(HTML.INPUT_ELEM, null);
            writer.writeAttribute(HTML.ID_ATTR, filterId, null);
            writer.writeAttribute(HTML.NAME_ATTR, filterId, null);
            writer.writeAttribute(HTML.TABINDEX_ATTR, tableContext.getTabIndex(), null);
            writer.writeAttribute(HTML.CLASS_ATTR, filterStyleClass, null);
            writer.writeAttribute("size", "1", null); // Webkit requires none zero/null size value to use CSS width correctly.
            writer.writeAttribute("value", filterValue , null);

            if (filterEvent.equals("keyup") || filterEvent.equals("blur"))
                writer.writeAttribute("on"+filterEvent, filterFunction , null);

            if (column.getFilterStyle() != null)
                writer.writeAttribute(HTML.STYLE_ELEM, column.getFilterStyle(), null);

            writer.endElement(HTML.INPUT_ELEM);
        }
        else {
            writer.startElement("select", null);
            writer.writeAttribute(HTML.ID_ATTR, filterId, null);
            writer.writeAttribute(HTML.NAME_ATTR, filterId, null);
            writer.writeAttribute(HTML.TABINDEX_ATTR, tableContext.getTabIndex(), null);
            writer.writeAttribute(HTML.CLASS_ATTR, filterStyleClass, null);
            writer.writeAttribute("onchange", filterFunction, null);

            SelectItem[] itemsArray = (SelectItem[]) getFilterOptions(column);
            Object filterVal = column.getFilterValue();

            for (SelectItem item : itemsArray) {
                writer.startElement("option", null);
                writer.writeAttribute("value", item.getValue(), null);

                Object itemVal = item.getValue();

                if ((filterVal == null && itemVal == null)
                        || itemVal.toString().equals(filterVal)) {
                    writer.writeAttribute("selected", "true", null);
                }

                writer.write(item.getLabel());
                writer.endElement("option");
            }

            writer.endElement("select");
        }

    }

    protected static void encodeConfigPanelLaunchButton(ResponseWriter writer, DataTable component, boolean first) throws IOException {
        String jsId = CoreRenderer.resolveWidgetVar(component);

        String panelJsId = CoreRenderer
                .resolveWidgetVar(component.findTableConfigPanel(FacesContext.getCurrentInstance()));

        TableConfigPanel configPanel = component.findTableConfigPanel(FacesContext.getCurrentInstance());

        if (configPanel.isRendered()) {
            String clientId = configPanel.getClientId();

            JSONBuilder json = JSONBuilder.create().beginFunction("ice.ace.lazy")
                    .item("TableConfLauncher")
                    .beginArray()
                    .item(clientId + "_tableconf_launch")
                    .item(panelJsId, false)
                    .endArray()
                    .endFunction();

            String script = json.toString();

            writer.startElement(HTML.SPAN_ELEM, null);
            writer.writeAttribute(HTML.CLASS_ATTR, "ui-tableconf-button", null);
            writer.writeAttribute(HTML.STYLE_ELEM, (first) ? "left:0;" : "right:0;", null);

            writer.startElement(HTML.ANCHOR_ELEM, null);
            writer.writeAttribute(HTML.CLASS_ATTR, "ui-state-default ui-corner-all", null);
            writer.writeAttribute(HTML.ONMOUSEOVER_ATTR, script, null);
            writer.writeAttribute(HTML.ONFOCUS_ATTR, script, null);
            writer.writeAttribute(HTML.TABINDEX_ATTR, 0, null);
            writer.writeAttribute(HTML.ID_ATTR, clientId +"_tableconf_launch", null);

            writer.startElement(HTML.SPAN_ELEM, null);
            writer.writeAttribute(HTML.CLASS_ATTR, "ui-icon ui-icon-gear", null);

            writer.endElement(HTML.SPAN_ELEM);
            writer.endElement(HTML.ANCHOR_ELEM);
            writer.endElement(HTML.SPAN_ELEM);
        }
    }

    /* Util Methods */

    private static SelectItem[] getFilterOptions(Column column) {
        Object options = column.getFilterOptions();
        if (options instanceof SelectItem[]) return (SelectItem[]) options;
        else if (options instanceof Collection) return ((Collection) column.getFilterOptions()).toArray(new SelectItem[] {});
        else throw new FacesException("Filter options for column " + column.getClientId() + " should be a SelectItem array or collection");
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy