org.apache.myfaces.custom.fisheye.HtmlFishEyeNavigationMenuRenderer.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.myfaces.custom.fisheye.HtmlFishEyeNavigationMenuRenderer.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.myfaces.custom.fisheye;

import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.myfaces.custom.dojo.DojoUtils;
import org.apache.myfaces.custom.navmenu.UINavigationMenuItem;
import org.apache.myfaces.renderkit.html.ext.HtmlLinkRenderer;
import org.apache.myfaces.shared_tomahawk.renderkit.JSFAttr;
import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils;
import org.apache.myfaces.shared_tomahawk.renderkit.html.util.FormInfo;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.ActionEvent;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;

/**
 * Renderer for the FishEyeList component
 * 
 * @JSFRenderer
 *   renderKitId = "HTML_BASIC" 
 *   family = "javax.faces.Data"
 *   type = "org.apache.myfaces.FishEyeList"
 * @JSFRenderer
 *   renderKitId = "HTML_BASIC" 
 *   family = "javax.faces.Command"
 *   type = "org.apache.myfaces.FishEyeCommandLink"
 *
 * @author Jurgen Lust (latest modification by $Author$)
 * @version $Revision$ $Date$
 */
public class HtmlFishEyeNavigationMenuRenderer extends HtmlLinkRenderer {

    private static final String ON_CLICK_ATTR = "onClick";
    private static final String DOJO_COMPONENT_TYPE = "ScrollableFisheyeList";
    private static final String DOJO_ITEM_TYPE = "ScrollableFisheyeListItem";
    public static final String ATTACH_EDGE_ATTR = "attachEdge";
    public static final String CAPTION_ATTR = "caption";
    public static final String EFFECT_UNITS_ATTR = "effectUnits";
    public static final String ICON_SRC_ATTR = "iconSrc";
    public static final String ITEM_HEIGHT_ATTR = "itemHeight";
    public static final String ITEM_MAX_HEIGHT_ATTR = "itemMaxHeight";
    public static final String ITEM_MAX_WIDTH_ATTR = "itemMaxWidth";
    public static final String ITEM_PADDING_ATTR = "itemPadding";
    public static final String ITEM_WIDTH_ATTR = "itemWidth";
    public static final String LABEL_EDGE_ATTR = "labelEdge";
    public static final String ORIENTATION_ATTR = "orientation";
    public static final String CONSERVATIVE_TRIGGER_ATTR = "conservativeTrigger";
    public static final String RENDERER_TYPE = "org.apache.myfaces.FishEyeList";

    private Log log = LogFactory.getLog(HtmlFishEyeNavigationMenuRenderer.class);

    /**
     * @see javax.faces.render.Renderer#decode(javax.faces.context.FacesContext,
     *      javax.faces.component.UIComponent)
     */
    public void decode(FacesContext context, UIComponent component) {
        FormInfo nestingForm = findNestingForm(component, context);
        if (nestingForm != null) {
            String fieldName = HtmlRendererUtils.getHiddenCommandLinkFieldName(nestingForm);
            String reqValue = (String) context.getExternalContext().getRequestParameterMap().get(fieldName);
            if (reqValue != null && reqValue.length() > 0) {
                if (component instanceof FishEyeCommandLink && reqValue.equals(component.getClientId(context))) {
                    component.queueEvent(new ActionEvent(component));
                } else {
                    // deprecated : the old UINavigationMenuItem way
                    UIComponent source = context.getViewRoot().findComponent(reqValue);
                    if (source instanceof UINavigationMenuItem) {
                        source.queueEvent(new ActionEvent(source));
                    }

                }
            }
        }
    }

    /**
     * @see javax.faces.render.Renderer#encodeBegin(javax.faces.context.FacesContext,
     *      javax.faces.component.UIComponent)
     */
    public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
        if (component.isRendered()) {
            HtmlFishEyeNavigationMenu fisheye = (HtmlFishEyeNavigationMenu) component;
            ResponseWriter writer = context.getResponseWriter();
            // initialize DOJO
            String javascriptLocation = (String) component.getAttributes().get(JSFAttr.JAVASCRIPT_LOCATION);
            DojoUtils.addMainInclude(context, component, javascriptLocation,
                    DojoUtils.getDjConfigInstance(context));
            DojoUtils.addRequire(context, component, "dojo.widget.myfaces.ScrollableFisheyeList");
            DojoUtils.addRequire(context, component, "dojo.widget.html.myfaces.ScrollableFisheyeListItem");
            DojoUtils.addRequire(context, component, "dojo.widget.Button");
            String leftName = "";
            if (fisheye.getVisibleWindow() != null) {
                writer.startElement(HTML.TABLE_ELEM, component);
                writer.startElement(HTML.TR_ELEM, component);
                writer.startElement(HTML.TD_ELEM, component);
                writer.writeAttribute(HTML.WIDTH_ATTR, "30", null);
                writer.startElement(HTML.DIV_ELEM, component);
                writer.writeAttribute(HTML.ID_ATTR, component.getClientId(context) + "_left", null);
                writer.write("<<");
                writer.endElement(HTML.DIV_ELEM);

                Map paramMap = new TreeMap();
                paramMap.put("id", DojoUtils.calculateWidgetVarName(component.getClientId(context) + "_left"));
                leftName = DojoUtils.renderWidgetInitializationCode(writer, component, "Button", paramMap,
                        component.getClientId(context) + "_left", true);
                // render the onclick
                writer.endElement(HTML.TD_ELEM);
                writer.startElement(HTML.TD_ELEM, component);
            }

            writer.startElement(HTML.DIV_ELEM, fisheye);
            writer.writeAttribute(HTML.ID_ATTR, component.getClientId(context), null);

            writer.endElement(HTML.DIV_ELEM);
            String rightName = "";
            if (fisheye.getVisibleWindow() != null) {
                writer.endElement(HTML.TD_ELEM);
                writer.startElement(HTML.TD_ELEM, component);
                writer.writeAttribute(HTML.WIDTH_ATTR, "30", null);
                writer.startElement(HTML.DIV_ELEM, component);
                writer.writeAttribute(HTML.ID_ATTR, component.getClientId(context) + "_right", null);
                writer.write(">>");
                writer.endElement(HTML.DIV_ELEM);
                Map paramMap = new TreeMap();
                paramMap.put("id", DojoUtils.calculateWidgetVarName(component.getClientId(context) + "_right"));
                rightName = DojoUtils.renderWidgetInitializationCode(writer, component, "Button", paramMap,
                        component.getClientId(context) + "_right", true);

                writer.endElement(HTML.TD_ELEM);
                writer.endElement(HTML.TR_ELEM);
                writer.endElement(HTML.TABLE_ELEM);
            }

            Map paramMap = new HashedMap();

            if (fisheye.getVisibleWindow() != null) {
                paramMap.put("visibleWindow", fisheye.getVisibleWindow());
            } else {
                HtmlFishEyeNavigationMenu menu = (HtmlFishEyeNavigationMenu) component;
                int visibleWindow = calculateVisbleWindow(component, menu);
                paramMap.put("visibleWindow", new Integer(visibleWindow)); //lets expand, the fisheye will shrink it as needed
            }

            paramMap.put(ITEM_WIDTH_ATTR, fisheye.getItemWidth());
            paramMap.put(ITEM_HEIGHT_ATTR, fisheye.getItemHeight());
            paramMap.put(ITEM_MAX_WIDTH_ATTR, fisheye.getItemMaxWidth());
            paramMap.put(ITEM_MAX_HEIGHT_ATTR, fisheye.getItemMaxHeight());
            paramMap.put(ORIENTATION_ATTR, fisheye.getOrientation());
            paramMap.put(EFFECT_UNITS_ATTR, fisheye.getEffectUnits());
            paramMap.put(ITEM_PADDING_ATTR, fisheye.getItemPadding());
            paramMap.put(ATTACH_EDGE_ATTR, fisheye.getAttachEdge());
            paramMap.put(LABEL_EDGE_ATTR, fisheye.getLabelEdge());
            paramMap.put(CONSERVATIVE_TRIGGER_ATTR, fisheye.getConservativeTrigger());

            DojoUtils.renderWidgetInitializationCode(context, component, DOJO_COMPONENT_TYPE, paramMap);

            if (fisheye.getVisibleWindow() != null) {
                writer.startElement(HTML.SCRIPT_ELEM, component);
                writer.writeAttribute(HTML.TYPE_ATTR, HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT, null);
                writer.write(leftName + ".onClick = function(e) {"
                        + DojoUtils.calculateWidgetVarName(component.getClientId(context)) + ".onLeftScroll();};");
                writer.write(rightName + ".onClick = function(e) {"
                        + DojoUtils.calculateWidgetVarName(component.getClientId(context)) + ".onRightScroll();};");
                writer.endElement(HTML.SCRIPT_ELEM);
            }

        }

    }

    private int calculateVisbleWindow(UIComponent component, HtmlFishEyeNavigationMenu menu) {
        int visibleWindow = 0;
        if (menu.getChildCount() == 1 && menu.getChildren().get(0) instanceof FishEyeCommandLink) {
            visibleWindow = menu.getRowCount();
        } else {
            List children = component.getChildren();

            for (Iterator cit = children.iterator(); cit.hasNext();) {
                UIComponent child = (UIComponent) cit.next();
                if (!child.isRendered())
                    continue;
                if (child instanceof UINavigationMenuItem) {
                    visibleWindow += 1;
                }
            }
        }
        return visibleWindow;
    }

    private Stack getChildsMenuStack(FacesContext context, UIComponent component) {
        //Stack menuStack = (Stack) ((HttpServletRequest) context.getExternalContext().getRequest()).getAttribute(component.getClientId(context)
        //        + "_FishEyeMenuAttr");
        Stack menuStack = (Stack) context.getExternalContext().getRequestMap()
                .get(component.getClientId(context) + "_FishEyeMenuAttr");
        if (menuStack != null)
            return menuStack;

        menuStack = new Stack();
        //((HttpServletRequest) context.getExternalContext().getRequest()).setAttribute(component.getClientId(context) + "_FishEyeMenuAttr", menuStack);
        context.getExternalContext().getRequestMap().put(component.getClientId(context) + "_FishEyeMenuAttr",
                menuStack);

        return menuStack;
    }

    /**
     * @see javax.faces.render.Renderer#encodeChildren(javax.faces.context.FacesContext,
     *      javax.faces.component.UIComponent)
     */
    public void encodeChildren(FacesContext context, UIComponent component) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        List children = component.getChildren();
        Stack menuStack = getChildsMenuStack(context, component);
        HtmlFishEyeNavigationMenu menu = (HtmlFishEyeNavigationMenu) component;
        if (menu.getChildCount() == 1 && menu.getChildren().get(0) instanceof FishEyeCommandLink) {
            FishEyeCommandLink link = (FishEyeCommandLink) menu.getChildren().get(0);
            for (int i = 0; i < menu.getRowCount(); i++) {
                menu.setRowIndex(i);
                if (!menu.isRowAvailable()) {
                    log.error("Model is not available. Rowindex = " + i);
                    break;
                }
                renderMenuItem(context, writer, component, link, menuStack);
            }
        } else {
            for (Iterator cit = children.iterator(); cit.hasNext();) {
                UIComponent child = (UIComponent) cit.next();
                if (!child.isRendered())
                    continue;
                if (child instanceof UINavigationMenuItem) {
                    renderMenuItem(context, writer, component, (UINavigationMenuItem) child, menuStack);
                }
            }
        }
    }

    /**
     * @see javax.faces.render.Renderer#encodeEnd(javax.faces.context.FacesContext,
     *      javax.faces.component.UIComponent)
     */
    public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
        if (component.isRendered()) {
            ResponseWriter writer = context.getResponseWriter();
            Stack menuStack = getChildsMenuStack(context, component);
            String jsMenuVar = DojoUtils.calculateWidgetVarName(component.getClientId(context));

            writer.startElement(HTML.SCRIPT_ELEM, component);
            writer.writeAttribute(HTML.TYPE_ATTR, HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT, null);
            while (!menuStack.isEmpty()) {
                String item = (String) menuStack.pop();
                writer.write(jsMenuVar);
                writer.write(".addChild(");
                writer.write(item);
                writer.write(");\n");
            }
            writer.write(jsMenuVar + ".postCreate(['programmaticdone'],null);\n");
            writer.endElement(HTML.SCRIPT_ELEM);
        }
    }

    /**
     * @see javax.faces.render.Renderer#getRendersChildren()
     */
    public boolean getRendersChildren() {
        // always render the menu items
        return true;
    }

    protected void renderMenuItem(FacesContext context, ResponseWriter writer, UIComponent menu, UIComponent item,
            Stack childsMenuStack) throws IOException {
        // find the enclosing form
        FormInfo formInfo = findNestingForm(item, context);
        String clientId = item.getClientId(context);
        if (formInfo == null) {
            throw new IllegalArgumentException("Component " + clientId + " must be embedded in an form");
        }
        UIComponent nestingForm = formInfo.getForm();
        String formName = formInfo.getFormName();

        StringBuffer onClick = new StringBuffer();

        String jsForm = "document.forms['" + formName + "']";
        if (RendererUtils.isAdfOrTrinidadForm(formInfo.getForm())) {
            onClick.append("submitForm('");
            onClick.append(formInfo.getForm().getClientId(context));
            onClick.append("',1,{source:'");
            onClick.append(clientId);
            onClick.append("'});return false;");
        } else {
            // call the clear_<formName> method
            onClick.append(HtmlRendererUtils.getClearHiddenCommandFormParamsFunctionName(formName)).append("();");

            //if (MyfacesConfig.getCurrentInstance(context.getExternalContext()).isAutoScroll()) {
            //HtmlRendererUtils.appendAutoScrollAssignment(onClick, formName);
            //}

            // add id parameter for decode
            String hiddenFieldName = HtmlRendererUtils.getHiddenCommandLinkFieldName(formInfo);
            onClick.append(jsForm);
            onClick.append(".elements['").append(hiddenFieldName).append("']");
            onClick.append(".value='").append(clientId).append("';");
            addHiddenCommandParameter(context, nestingForm, hiddenFieldName);
        }
        String target;
        String caption;
        String iconSrc;
        if (item instanceof UINavigationMenuItem) {
            target = ((UINavigationMenuItem) item).getTarget();
            caption = ((UINavigationMenuItem) item).getItemLabel();
            iconSrc = ((UINavigationMenuItem) item).getIcon();
        } else if (item instanceof FishEyeCommandLink) {
            target = ((FishEyeCommandLink) item).getTarget();
            caption = ((FishEyeCommandLink) item).getCaption();
            iconSrc = ((FishEyeCommandLink) item).getIconSrc();
        } else {
            throw new IllegalArgumentException("expected UINavigationMenuItem or FisheyCommandLink");
        }

        // add the target window
        if (target != null && target.trim().length() > 0) {
            onClick.append(jsForm);
            onClick.append(".target='");
            onClick.append(target);
            onClick.append("';");
        }

        // onSubmit
        onClick.append("if(").append(jsForm).append(".onsubmit){var result=").append(jsForm).append(
                ".onsubmit();  if( (typeof result == 'undefined') || result ) {" + jsForm + ".submit();}}else{");

        // submit
        onClick.append(jsForm);
        onClick.append(".submit();}return false;"); // return false, so that
                                                    // browser does not handle
                                                    // the click

        Map paramMap = new HashMap();
        paramMap.put(CAPTION_ATTR, caption);
        paramMap.put(ICON_SRC_ATTR, iconSrc);
        paramMap.put(ON_CLICK_ATTR, new StringBuffer("function () {").append(onClick).append("}"));
        // push the onclick as lambda and use a stringbuffer so that we do not
        // get enclosing quotes
        String menuItemId = DojoUtils.renderWidgetInitializationCode(writer, item, DOJO_ITEM_TYPE, paramMap,
                item.getClientId(context), false);
        childsMenuStack.push(menuItemId);
        // we have to revert the elements,
        // hence a stack
    }

    protected void writeAttribute(ResponseWriter writer, HtmlFishEyeNavigationMenu fisheye, String name,
            Object value) throws IOException {
        if (name != null && value != null) {
            writer.writeAttribute(name, value, null);
        }
    }

}