Package org.openfaces.renderkit.select

Source Code of org.openfaces.renderkit.select.TabSetRenderer

/*
* OpenFaces - JSF Component Library 2.0
* Copyright (C) 2007-2012, TeamDev Ltd.
* licensing@openfaces.org
* Unless agreed in writing the contents of this file are subject to
* the GNU Lesser General Public License Version 2.1 (the "LGPL" License).
* This library 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.
* Please visit http://openfaces.org/licensing/ for more details.
*/
package org.openfaces.renderkit.select;

import org.openfaces.component.select.TabAlignment;
import org.openfaces.component.select.TabPlacement;
import org.openfaces.component.select.TabSet;
import org.openfaces.component.select.TabSetItem;
import org.openfaces.component.select.TabSetItems;
import org.openfaces.event.SelectionChangeEvent;
import org.openfaces.org.json.JSONArray;
import org.openfaces.util.AnonymousFunction;
import org.openfaces.util.HTML;
import org.openfaces.util.Rendering;
import org.openfaces.util.Resources;
import org.openfaces.util.ScriptBuilder;
import org.openfaces.util.Styles;
import org.openfaces.util.AjaxUtil;
import org.openfaces.util.Environment;
import org.openfaces.util.StyleGroup;

import javax.el.ELContext;
import javax.el.ValueExpression;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

/**
* @author Andrew Palval
*/
public class TabSetRenderer extends BaseTabSetRenderer {
    private static final String DEFAULT_EMPTY_SPACE_CLASS_PREFIX = "o_tabset_empty_space_";
    private static final String DEFAULT_CLASS_PREFIX = "o_tabset_";
    private static final String DEFAULT_ROLLOVER_CLASS_PREFIX = "o_tabset_rollover_";
    private static final MessageFormat DEFAULT_SELECTED_STYLE = new MessageFormat("background-color: transparent; border-{0}: #c9d8f5 3px solid;");
    private static final String DEFAULT_SELECTED_ROLLOVER_CLASS_PREFIX = "o_tabset_selected_rollover_";
    private static final String BACK_BORDER_CLASS_PREFIX = "o_tabset_back_border_";
    private static final String FRONT_BORDER_CLASS_PREFIX = "o_tabset_front_border_";
    public static final String ATTR_CONSIDER_TAB_NON_RENDERED = "o_considerTabNonRendered";

    protected void changeTabIndex(UIComponent component, int selectedIndex) {
        TabSet tabSet = (TabSet) component;
        int oldSelectedIndex = tabSet.getSelectedIndex();
        if (oldSelectedIndex != selectedIndex) {
            tabSet.setSelectedIndex(selectedIndex);
            tabSet.queueEvent(new SelectionChangeEvent(tabSet, oldSelectedIndex, selectedIndex));
        }

        List<Object> tabItems = getTabItems(tabSet);
        Object tabItem = tabItems.get(selectedIndex);
        Object tabValue = (tabItem instanceof TabSetItem) ? ((TabSetItem) tabItem).getItemValue() : null;
        tabSet.setSubmittedValue(tabValue);
    }

    protected String getSelectionHiddenFieldSuffix() {
        return SELECTED_INDEX_SUFFIX;
    }

    @Override
    public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
        if (AjaxUtil.getSkipExtraRenderingOnPortletsAjax(context))
            return;

        ResponseWriter writer = context.getResponseWriter();
        TabSet tabSet = (TabSet) component;

        writer.startElement("table", tabSet);
        writeIdAttribute(context, tabSet);
        writer.writeAttribute("border", "0", null);
        writer.writeAttribute("cellspacing", "0", null);
        writer.writeAttribute("cellpadding", "0", null);

        writeAttribute(writer, "style", tabSet.getStyle());
        writeAttribute(writer, "class", tabSet.getStyleClass());

        Rendering.writeStandardEvents(writer, tabSet);
    }

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

    @Override
    public void encodeChildren(FacesContext context, UIComponent component) throws IOException {
        if (AjaxUtil.getSkipExtraRenderingOnPortletsAjax(context))
            return;

        ResponseWriter writer = context.getResponseWriter();
        TabSet tabSet = (TabSet) component;
        List<UIComponent> tabChildren = tabSet.getChildren();

        TabPlacement tabPlacement = getTabPlacement(tabSet);
        boolean verticalTabs = tabPlacement.equals(TabPlacement.LEFT) || tabPlacement.equals(TabPlacement.RIGHT);

        TabAlignment tabAlign = tabSet.getAlignment();
        if (tabAlign == null) {
            tabAlign = TabAlignment.TOP_OR_LEFT;
        }

        List<Object> tabItems = getTabItems(tabSet);

        String emptySpaceClasses = getEmptySpaceClasses(tabSet, context);

        if (!verticalTabs) {
            writer.startElement("tr", tabSet);
            if (tabAlign.equals(TabAlignment.BOTTOM_OR_RIGHT)) {
                insertHorizontalSpacer(context, tabSet, emptySpaceClasses);
            }
        } else if (tabAlign.equals(TabAlignment.BOTTOM_OR_RIGHT)) {
            insertVerticalSpacer(context, tabSet, emptySpaceClasses);
        }

        String idPrefix = tabSet.getClientId(context) + Rendering.CLIENT_ID_SUFFIX_SEPARATOR;
        int gapWidth = tabSet.getGapWidth();

        int allTabCount = tabItems.size();
        List<Object> renderedTabItems = new ArrayList<Object>(allTabCount);
        int[] originalTabIndexes = new int[allTabCount];
        for (int i = 0, tabsAdded = 0; i < allTabCount; i++) {
            Object item = tabItems.get(i);
            if (isItemRendered(item)) {
                renderedTabItems.add(item);
                originalTabIndexes[tabsAdded++] = i;
            }
        }
        for (int i = 0, tabCount = renderedTabItems.size(); i < tabCount; i++) {

            Object item = renderedTabItems.get(i);
            if (!isItemRendered(item))
                continue;

            if (gapWidth > 0) {
                if (TabAlignment.TOP_OR_LEFT.equals(tabAlign)) {
                    if (verticalTabs) {
                        writeVerticalGap(writer, tabSet, gapWidth, emptySpaceClasses);
                    } else {
                        writeHorizontalGap(writer, tabSet, gapWidth, emptySpaceClasses);
                    }
                }
            }

            if (verticalTabs) {
                writer.startElement("tr", tabSet);
            }

            writer.startElement("td", tabSet);

            String attr = verticalTabs ? "align" : "valign";
            writer.writeAttribute(attr, tabPlacement.toString(), null);

            //        writer.startElement("div", tabSet);
            int absoluteTabIndex = originalTabIndexes[i];
            writer.writeAttribute("id", idPrefix + absoluteTabIndex, "id");

            if (tabSet.isFocusable()) {
                writer.startElement("div", tabSet);
                String defaultFocusedClass = Styles.getCSSClass(context, component,
                        !Environment.isExplorer6() ? "border: 1px solid transparent;" : "", StyleGroup.selectedStyleGroup(1));
                writer.writeAttribute("class", defaultFocusedClass, null);
            }
            /*...............*/
            if (item instanceof String) {
                writer.writeText(item, null);
            } else if (item instanceof UIComponent) {
                ((UIComponent) item).encodeAll(context);
            } else if (item != null) {
                writer.writeText(item.toString(), null);
            }
            /*                      */
            if (tabSet.isFocusable()) {
                writer.endElement("div");
            }
            //        writer.endElement("div");

            if (i == (tabCount - 1)) {
                encodeScriptsAndStyles(context, component);
            }

            writer.endElement("td");
            if (verticalTabs) {
                writer.endElement("tr");
            }

            if (gapWidth > 0) {
                if (TabAlignment.BOTTOM_OR_RIGHT.equals(tabAlign)) {
                    if (verticalTabs) {
                        writeVerticalGap(writer, tabSet, gapWidth, emptySpaceClasses);
                    } else {
                        writeHorizontalGap(writer, tabSet, gapWidth, emptySpaceClasses);
                    }
                }
            }
        }

        if (!verticalTabs) {
            if (tabAlign.equals(TabAlignment.TOP_OR_LEFT)) {
                insertHorizontalSpacer(context, tabSet, emptySpaceClasses);
            }
            writer.endElement("tr");
        } else if (tabAlign.equals(TabAlignment.TOP_OR_LEFT)) {
            insertVerticalSpacer(context, tabSet, emptySpaceClasses);
        }
    }


    private boolean isItemRendered(Object item) {
        if (!(item instanceof UIComponent))
            return true;
        UIComponent component = (UIComponent) item;
        boolean rendered = component.isRendered();
        if (!rendered)
            return false;
        return !component.getAttributes().containsKey(ATTR_CONSIDER_TAB_NON_RENDERED);
    }

    private void writeHorizontalGap(ResponseWriter writer, TabSet tabSet, int gapWidth, String emptySpaceClasses) throws IOException {
        writer.startElement("td", tabSet);
        writer.writeAttribute("width", gapWidth + "px", null);
        writer.writeAttribute("class", emptySpaceClasses, null);
        writer.writeAttribute("nowrap", "nowrap", null);
        writer.startElement("div", tabSet);
        writer.writeAttribute("style", "width: " + gapWidth + "px", null);
        writer.write(HTML.NBSP_ENTITY);
        writer.endElement("div");
        writer.endElement("td");
    }

    private void writeVerticalGap(ResponseWriter writer, TabSet tabSet, int gapWidth, String emptySpaceClasses) throws IOException {
        writer.startElement("tr", tabSet);
        writer.writeAttribute("style", "height: " + gapWidth + "px;", null);
        writer.startElement("td", tabSet);
        writer.writeAttribute("style", "height: " + gapWidth + "px;", null);
        writer.writeAttribute("class", emptySpaceClasses, null);
        writer.startElement("div", tabSet);
        writer.writeAttribute("style", "height: 1px; width: 1px; font-size: 1px;", null);
        writer.endElement("div");
        writer.endElement("td");
        writer.endElement("tr");
    }

    private void insertHorizontalSpacer(FacesContext context, TabSet tabSet, String emptySpaceClasses) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        writer.startElement("td", tabSet);
        writer.writeAttribute("class", emptySpaceClasses, null);
        if (tabSet.isFocusable()) {
            writer.writeAttribute("onmousedown", "O$.stopEvent(event);", null);
            writer.writeAttribute("onmouseup", "O$.stopEvent(event);", null);
            writer.writeAttribute("onclick", "O$.stopEvent(event);", null);
        }
        if (Environment.isMozilla()) { // the div is actually needed only for Mozilla running on Mac, to solve the width problem (JSFC-2713)
            writer.startElement("div", tabSet);
            writer.writeAttribute("class", "o_tabset_moz_empty_space", null);
            writer.endElement("div");
        } else {
            writer.write(HTML.NBSP_ENTITY);
        }
        writer.endElement("td");
    }

    private void insertVerticalSpacer(FacesContext context, TabSet tabSet, String emptySpaceClasses) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        writer.startElement("tr", tabSet);
        writer.writeAttribute("height", "100%", null);
        writer.startElement("td", tabSet);
        if (tabSet.isFocusable()) {
            writer.writeAttribute("onmousedown", "O$.stopEvent(event);", null);
            writer.writeAttribute("onmouseup", "O$.stopEvent(event);", null);
            writer.writeAttribute("onclick", "O$.stopEvent(event);", null);
        }
        writer.writeAttribute("height", "100%", null);
        writer.writeAttribute("class", emptySpaceClasses, null);
        writer.write(HTML.NBSP_ENTITY);
        writer.endElement("td");
        writer.endElement("tr");
    }

    private String getEmptySpaceClasses(TabSet tabSet, FacesContext context) {
        TabPlacement placement = getTabPlacement(tabSet);

        String borderStyle = tabSet.getFrontBorderStyle();
        String style = tabSet.getEmptySpaceStyle();
        if (borderStyle != null && borderStyle.length() > 0) {
            if (style == null) {
                style = "";
            }
            style += " border-" + placement.getOppositeValue() + ": " + borderStyle + ";";
        }
        String defaultClass = DEFAULT_EMPTY_SPACE_CLASS_PREFIX + placement;
        return Styles.getCSSClass(context, tabSet, style, defaultClass, tabSet.getEmptySpaceClass());
    }

    private TabPlacement getTabPlacement(TabSet tabSet) {
        TabPlacement placement = tabSet.getPlacement();
        if (placement == null) {
            placement = TabPlacement.TOP;
        }
        return placement;
    }

    @Override
    public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
        if (AjaxUtil.getSkipExtraRenderingOnPortletsAjax(context))
            return;

        ResponseWriter writer = context.getResponseWriter();
        writer.endElement("table");
        writer.flush();
    }

    private void encodeScriptsAndStyles(FacesContext context, UIComponent component) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        TabSet tabSet = (TabSet) component;

        List<Object> tabs = getTabItems(tabSet);
        int selectedIndex = getSelectedIndex(context, tabSet, tabs);

        Rendering.renderHiddenField(writer,
                component.getClientId(context) + SELECTED_INDEX_SUFFIX,
                String.valueOf(selectedIndex));

        TabPlacement placement = tabSet.getPlacement();
        if (placement == null) {
            placement = TabPlacement.TOP;
        }

        List<Object> borderSideNames = borderNames.getListWithFirst(placement, -1);
        String borderMask = "border-{0}: {4}; border-{1}: {4}; border-{2}: {4}; border-{3}: {5};";
        String frontBorderClass = FRONT_BORDER_CLASS_PREFIX + placement;

        int gapWidth = tabSet.getGapWidth();
        boolean hasGap = gapWidth > 0;

        String borderMaskPre;
        if (hasGap) {
            borderMaskPre = "border-{0}: {4}; border-{1}: {4}; border-{2}: {4}; border-{3}: {5};";
        } else {
            borderMaskPre = "border-{0}: {4}; border-{1}: {4}; border-{2}: 0px; border-{3}: {5};";
        }

        String backBorderClassPre = BACK_BORDER_CLASS_PREFIX + placement;

        String borderMaskPost;
        if (hasGap) {
            borderMaskPost = borderMaskPre;
        } else {
            borderMaskPost = "border-{0}: 0px;border-{1}: {4};border-{2}: {4};border-{3}: {5};";
        }
        String backBorderClassPost = backBorderClassPre;

        String frontBorderStyle = tabSet.getFrontBorderStyle();
        boolean frontBorderDefined = frontBorderStyle != null && frontBorderStyle.length() > 0;
        if (frontBorderDefined) {
            String frontBorder = formatBorderClassString(borderMask, borderSideNames, frontBorderStyle, "0px");
            frontBorderClass = Styles.getCSSClass(context, tabSet, frontBorder, frontBorderClass);
        }

        String backBorderStyle = tabSet.getBackBorderStyle();
        boolean backBorderDefined = backBorderStyle != null && backBorderStyle.length() > 0;
        if (backBorderDefined || frontBorderDefined) {
            String backBorderPre = formatBorderClassString(borderMaskPre, borderSideNames, backBorderStyle, frontBorderStyle);
            backBorderClassPre = Styles.getCSSClass(context, tabSet, backBorderPre, backBorderClassPre);

            String backBorderPost = formatBorderClassString(borderMaskPost, borderSideNames, backBorderStyle, frontBorderStyle);
            backBorderClassPost = Styles.getCSSClass(context, component, backBorderPost);
        }

        String defaultClass = DEFAULT_CLASS_PREFIX + placement;
        /**/
        String tabClass = Styles.getCSSClass(context, component, tabSet.getTabStyle(), defaultClass, tabSet.getTabClass());
        String defaultRolloverClass = DEFAULT_ROLLOVER_CLASS_PREFIX + placement;
        String rolloverClass = Styles.getCSSClass(context, component, tabSet.getRolloverTabStyle(), StyleGroup.rolloverStyleGroup(), tabSet.getRolloverTabClass(), defaultRolloverClass);
        String defaultSelectedClass = DEFAULT_SELECTED_STYLE.format(new Object[]{placement});
        String selectedClass = Styles.getStyleClassesStr(context, component, tabSet.getSelectedTabStyle(), tabSet.getSelectedTabClass(), defaultSelectedClass, StyleGroup.selectedStyleGroup());
        String defaultSelectedRolloverClass = DEFAULT_SELECTED_ROLLOVER_CLASS_PREFIX + placement.toString();
        String selectedRolloverClass = Styles.getCSSClass(context, component, tabSet.getRolloverSelectedTabStyle(), StyleGroup.selectedStyleGroup(1), tabSet.getRolloverSelectedTabClass(), defaultSelectedRolloverClass);
        String focusedTabClass = Styles.getStyleClassesStr(context, component, tabSet.getFocusedTabStyle(), tabSet.getFocusedTabClass(), null, StyleGroup.selectedStyleGroup(2));
        /// focus area style
        String defaultFocusedClass = Styles.getCSSClass(context, component, Rendering.DEFAULT_FOCUSED_STYLE, StyleGroup.selectedStyleGroup(1));
        String focusAreaClass = Styles.getCSSClass(context, component, tabSet.getFocusAreaStyle(),
                StyleGroup.selectedStyleGroup(2), tabSet.getFocusAreaClass(), defaultFocusedClass);

        String focusedClass = Styles.getCSSClass(context, tabSet,
                tabSet.getFocusedStyle(), StyleGroup.selectedStyleGroup(1), tabSet.getFocusedClass(), null);

        String onchange = tabSet.getOnchange();

        String defaultDisabledClass = DEFAULT_CLASS_PREFIX + "disabled";
             ScriptBuilder sb = new ScriptBuilder();
        sb.initScript(context, tabSet, "O$.TabSet._init",
                getTabIds(context, tabSet, tabs),
                selectedIndex,
                placement,
                new String[]{
                        tabClass,
                        selectedClass,
                        rolloverClass,
                        selectedRolloverClass,
                        focusedTabClass
                },
                new String[]{
                        frontBorderClass,
                        backBorderClassPre,
                        backBorderClassPost

                },
                tabSet.isFocusable(),
                focusAreaClass,
                focusedClass,
               onchange != null ? new AnonymousFunction(onchange, "event") : null);

        Rendering.renderInitScript(context, sb,
                Resources.utilJsURL(context),
                Resources.internalURL(context, "select/tabset.js"));

        Rendering.encodeClientActions(context, component);

        Styles.renderStyleClasses(context, tabSet);
    }

    private int getSelectedIndex(FacesContext context, TabSet tabSet, List<Object> allTabItems) {
        int selectedIndex;
        if (tabSet.isLocalValueSet()) {
            Object tabValue = tabSet.getLocalValue();
            selectedIndex = tabIndexByValue(allTabItems, tabValue);
        } else if (tabSet.getLocalSelectedIndex() != null) {
            selectedIndex = tabSet.getLocalSelectedIndex();
        } else {
            ValueExpression valueExpression = tabSet.getValueExpression("value");
            ValueExpression selectedIndexExpression = tabSet.getValueExpression("selectedIndex");
            ELContext elContext = context.getELContext();
            if (valueExpression != null) {
                Object tabValue = valueExpression.getValue(elContext);
                selectedIndex = tabIndexByValue(allTabItems, tabValue);
            } else {
                Integer indexObj;
                if (selectedIndexExpression != null)
                    indexObj = (Integer) selectedIndexExpression.getValue(elContext);
                else
                    indexObj = null;
                selectedIndex = indexObj != null
                        ? indexObj
                        : tabSet.getSelectedIndex();
            }
        }

        if (selectedIndex < 0 || selectedIndex >= allTabItems.size())
            selectedIndex = 0;

        Object selectedItem = allTabItems.get(selectedIndex);
        if (!isItemRendered(selectedItem)) {
            selectedIndex = -1;
            for (int tabIndex = 0; tabIndex < allTabItems.size(); tabIndex++) {
                Object item = allTabItems.get(tabIndex);
                if (isItemRendered(item)) {
                    selectedIndex = tabIndex;
                    break;
                }
            }
        }
        return selectedIndex;
    }

    private int tabIndexByValue(List<Object> allTabItems, Object tabValue) {
        for (int i = 0, count = allTabItems.size(); i < count; i++) {
            Object tabItem = allTabItems.get(i);
            if (tabItem instanceof TabSetItem) {
                Object itemValue = ((TabSetItem) tabItem).getItemValue();
                if ((tabValue == null && itemValue == null) || (tabValue != null && tabValue.equals(itemValue)))
                    return i;
            }
        }
        return -1;
    }

    private String formatBorderClassString(
            String borderMaskPre,
            List<Object> borderSideNames,
            String backBorderStyle,
            String frontBorderStyle) {
        if (Rendering.isNullOrEmpty(backBorderStyle))
            backBorderStyle = "none";
        if (Rendering.isNullOrEmpty(frontBorderStyle))
            frontBorderStyle = "none";
        String result = MessageFormat.format(borderMaskPre, borderSideNames.get(0),
                borderSideNames.get(1),
                borderSideNames.get(2),
                borderSideNames.get(3),
                backBorderStyle,
                frontBorderStyle);
        return result;
    }

    private List<Object> getTabItems(TabSet tabSet) {
        List<Object> itemsList = new ArrayList<Object>();

        List<UIComponent> children = tabSet.getChildren();
        for (Object child : children) {
            if (child instanceof TabSetItem) {
                itemsList.add(child);
            } else if (child instanceof TabSetItems) {
                Object value = ((TabSetItems) child).getValue();
                if (value != null && value instanceof Collection) {
                    itemsList.addAll((Collection<Object>) value);
                }
            }
        }

        return itemsList;
    }

    private JSONArray getTabIds(FacesContext context, TabSet tabSet, List<Object> tabs) {
        JSONArray result = new JSONArray();

        String clientId = tabSet.getClientId(context);
        for (int tabIndex = 0, tabCount = tabs.size(); tabIndex < tabCount; tabIndex++) {
            Object tabObj = tabs.get(tabIndex);
            if (!isItemRendered(tabObj))
                continue;

            result.put(clientId + Rendering.CLIENT_ID_SUFFIX_SEPARATOR + tabIndex);
        }
        return result;
    }
}
TOP

Related Classes of org.openfaces.renderkit.select.TabSetRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.