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

de.larmic.butterfaces.component.renderkit.html_basic.MojarraRenderUtils Maven / Gradle / Ivy

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

/*
 * Copied from com.sun.faces.renderkit.RenderKitUtils to release a myfaces version of butterfaces input components.
 * Mojarra dependencies are removed.
 **/

package de.larmic.butterfaces.component.renderkit.html_basic;

import javax.faces.component.ActionSource;
import javax.faces.component.UIComponent;
import javax.faces.component.UIForm;
import javax.faces.component.behavior.ClientBehavior;
import javax.faces.component.behavior.ClientBehaviorContext;
import javax.faces.component.behavior.ClientBehaviorHint;
import javax.faces.component.behavior.ClientBehaviorHolder;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.RenderKit;
import java.io.IOException;
import java.util.*;

/**
 * 

A set of utilities for use in {@link RenderKit}s.

*/ public class MojarraRenderUtils { private MojarraRenderUtils() { } public static void renderPassThruAttributes(ResponseWriter writer, UIComponent component, String attributeName, String eventName) throws IOException { final FacesContext context = FacesContext.getCurrentInstance(); Map> behaviors = Collections.emptyMap(); if (component instanceof ClientBehaviorHolder) { behaviors = ((ClientBehaviorHolder) component).getClientBehaviors(); } renderPassThruAttributesUnoptimized(context, writer, component, attributeName, eventName, behaviors); } // --------------------------------------------------------- Private Methods /** *

Loops over all known attributes and attempts to render each one. * * @param context the {@link FacesContext} of the current request * @param writer the current writer * @param component the component whose attributes we're rendering * @param behaviors the non-null behaviors map for this request. * @throws IOException if an error occurs during the write */ private static void renderPassThruAttributesUnoptimized(FacesContext context, ResponseWriter writer, UIComponent component, String attributeName, String eventName, Map> behaviors) throws IOException { Map attrMap = component.getAttributes(); boolean hasBehavior = ((eventName != null) && (behaviors.containsKey(eventName))); Object value = attrMap.get(attributeName); if (hasBehavior) { // If we've got a behavior for this attribute, // we may need to chain scripts together, so use // renderHandler(). renderHandler(context, component, attributeName, value, eventName); } } /** *

Utility method to return the client ID of the parent form.

* * @param component typically a command component * @param context the FacesContext for the current request * @return the client ID of the parent form, if any */ public static String getFormClientId(UIComponent component, FacesContext context) { UIForm form = getForm(component); if (form != null) { return form.getClientId(context); } return null; } /** *

Utility method to return the client ID of the parent form.

* * @param component typically a command component * @return the parent form, if any */ public static UIForm getForm(UIComponent component) { UIComponent parent = component.getParent(); while (parent != null) { if (parent instanceof UIForm) { break; } parent = parent.getParent(); } UIForm form = (UIForm) parent; if (form != null) { return form; } return null; } // --------------------------------------------------------- Private Methods // Appends a script to a jsf.util.chain() call private static void appendScriptToChain(StringBuilder builder, String script) { if ((script == null) || (script.length() == 0)) { return; } if (builder.length() == 0) { builder.append("butter.util.chain(this,event,"); } if (builder.charAt(builder.length() - 1) != ',') builder.append(','); appendQuotedValue(builder, script); } // Appends an name/value property pair to a JSON object. Assumes // object has already been opened by the caller. The value will // be quoted (ie. wrapped in single quotes and escaped appropriately). public static void appendProperty(StringBuilder builder, String name, Object value) { appendProperty(builder, name, value, true); } // Appends an name/value property pair to a JSON object. Assumes // object has already been opened by the caller. public static void appendProperty(StringBuilder builder, String name, Object value, boolean quoteValue) { if ((null == name) || (name.length() == 0)) throw new IllegalArgumentException(); char lastChar = builder.charAt(builder.length() - 1); if ((lastChar != ',') && (lastChar != '{')) builder.append(','); MojarraRenderUtils.appendQuotedValue(builder, name); builder.append(":"); if (value == null) { builder.append("''"); } else if (quoteValue) { MojarraRenderUtils.appendQuotedValue(builder, value.toString()); } else { builder.append(value.toString()); } } // Append a script to the chain, escaping any single quotes, since // our script content is itself nested within single quotes. private static void appendQuotedValue(StringBuilder builder, String script) { builder.append("'"); int length = script.length(); for (int i = 0; i < length; i++) { char c = script.charAt(i); if (c == '\'' || c == '\\') { builder.append('\\'); } builder.append(c); } builder.append("'"); } // Appends one or more behavior scripts a jsf.util.chain() call private static boolean appendBehaviorsToChain(StringBuilder builder, FacesContext context, UIComponent component, List behaviors, String behaviorEventName, Collection params) { if ((behaviors == null) || (behaviors.isEmpty())) { return false; } ClientBehaviorContext bContext = createClientBehaviorContext(context, component, behaviorEventName, params); boolean submitting = false; for (ClientBehavior behavior : behaviors) { String script = behavior.getScript(bContext); if ((script != null) && (script.length() > 0)) { appendScriptToChain(builder, script); if (isSubmitting(behavior)) { submitting = true; } } } return submitting; } // Ensures that the user-specified DOM event handler script // is non-empty, and trimmed if necessary. private static String getNonEmptyUserHandler(Object handlerObject) { String handler = null; if (null != handlerObject) { handler = handlerObject.toString(); handler = handler.trim(); if (handler.length() == 0) handler = null; } return handler; } // Returns the Behaviors for the specified component/event name, // or null if no Behaviors are available private static List getClientBehaviors(UIComponent component, String behaviorEventName) { if (component instanceof ClientBehaviorHolder) { ClientBehaviorHolder bHolder = (ClientBehaviorHolder) component; Map> behaviors = bHolder.getClientBehaviors(); if (null != behaviors) { return behaviors.get(behaviorEventName); } } return null; } // Returns a submit handler - ie. a script that calls // mojara.jsfcljs() private static String getSubmitHandler(FacesContext context, UIComponent component, Collection params, boolean preventDefault) { StringBuilder builder = new StringBuilder(256); String formClientId = getFormClientId(component, context); String componentClientId = component.getClientId(context); builder.append("mojarra.jsfcljs(document.getElementById('"); builder.append(formClientId); builder.append("'),{"); appendProperty(builder, componentClientId, componentClientId); if ((null != params) && (!params.isEmpty())) { for (ClientBehaviorContext.Parameter param : params) { appendProperty(builder, param.getName(), param.getValue()); } } builder.append("},'"); builder.append("')"); if (preventDefault) { builder.append(";return false"); } return builder.toString(); } // Chains together a number of Behavior scripts with a user handler // script. private static String getChainedHandler(FacesContext context, UIComponent component, List behaviors, Collection params, String behaviorEventName, String userHandler, boolean needsSubmit) { // Hard to pre-compute builder initial capacity StringBuilder builder = new StringBuilder(100); appendScriptToChain(builder, userHandler); boolean submitting = appendBehaviorsToChain(builder, context, component, behaviors, behaviorEventName, params); boolean hasParams = ((null != params) && !params.isEmpty()); // If we've got parameters but we didn't render a "submitting" // behavior script, we need to explicitly render a submit script. if (!submitting && (hasParams || needsSubmit)) { String submitHandler = getSubmitHandler(context, component, params, false); appendScriptToChain(builder, submitHandler); // We are now submitting since we've rendered a submit script. submitting = true; } if (builder.length() == 0) { return null; } builder.append(")"); // If we're submitting (either via a behavior, or by rendering // a submit script), we need to return false to prevent the // default button/link action. if (submitting && ("action".equals(behaviorEventName) || "click".equals(behaviorEventName))) { builder.append(";return false"); } return builder.toString(); } // Returns the script for a single Behavior private static String getSingleBehaviorHandler(FacesContext context, UIComponent component, ClientBehavior behavior, Collection params, String behaviorEventName, boolean needsSubmit) { final ClientBehaviorContext bContext = createClientBehaviorContext(context, component, behaviorEventName, params); String script = behavior.getScript(bContext); boolean preventDefault = ((needsSubmit || isSubmitting(behavior)) && (component instanceof ActionSource)); if (script == null) { if (needsSubmit) { script = getSubmitHandler(context, component, params, preventDefault); } } else if (preventDefault) { script = script + ";return false"; } return script; } // Creates a ClientBehaviorContext with the specified properties. private static ClientBehaviorContext createClientBehaviorContext(FacesContext context, UIComponent component, String behaviorEventName, Collection params) { return ClientBehaviorContext.createClientBehaviorContext(context, component, behaviorEventName, null, params); } // Tests whether the specified behavior is submitting private static boolean isSubmitting(ClientBehavior behavior) { return behavior.getHints().contains(ClientBehaviorHint.SUBMITTING); } /** * Renders a handler script, which may require chaining together * the user-specified event handler, any scripts required by attached * Behaviors, and also possibly the mojarra.jsfcljs() "submit" script. * * @param context the FacesContext for this request. * @param component the UIComponent that we are rendering * @param handlerName the name of the handler attribute to render (eg. * "onclick" or "ommouseover") * @param handlerValue the user-specified value for the handler attribute * @param behaviorEventName the name of the behavior event that corresponds * to this handler (eg. "action" or "mouseover"). */ private static void renderHandler(FacesContext context, UIComponent component, String handlerName, Object handlerValue, String behaviorEventName) throws IOException { ResponseWriter writer = context.getResponseWriter(); String userHandler = getNonEmptyUserHandler(handlerValue); List behaviors = getClientBehaviors(component, behaviorEventName); // Don't render behavior scripts if component is disabled if ((null != behaviors) && (behaviors.size() > 0) && componentIsDisabled(component)) { behaviors = null; } Collection params = Collections.emptyList(); String handler = null; switch (getHandlerType(behaviors, params, userHandler, false)) { case USER_HANDLER_ONLY: handler = userHandler; break; case SINGLE_BEHAVIOR_ONLY: handler = getSingleBehaviorHandler(context, component, behaviors.get(0), params, behaviorEventName, false); break; case SUBMIT_ONLY: handler = getSubmitHandler(context, component, params, true); break; case CHAIN: handler = getChainedHandler(context, component, behaviors, params, behaviorEventName, userHandler, false); break; default: assert (false); } writer.writeAttribute(handlerName, handler, null); } public static boolean componentIsDisabled(UIComponent component) { return (Boolean.valueOf(String.valueOf(component.getAttributes().get("disabled")))); } // Determines the type of handler to render based on what sorts of // scripts we need to render/chain. private static HandlerType getHandlerType(List behaviors, Collection params, String userHandler, boolean needsSubmit) { if ((behaviors == null) || (behaviors.isEmpty())) { // No behaviors and no params means user handler only, // if we have a param only because of includeExec while having // no behaviors, also, user handler only if ((params.isEmpty() && !needsSubmit)) return HandlerType.USER_HANDLER_ONLY; // We've got params. If we've also got a user handler, we need // to chain. Otherwise, we only render the submit script. return (userHandler == null) ? HandlerType.SUBMIT_ONLY : HandlerType.CHAIN; } // We've got behaviors. See if we can optimize for the single // behavior case. We can only do this if we don't have a user // handler. if ((behaviors.size() == 1) && (userHandler == null)) { ClientBehavior behavior = behaviors.get(0); // If we've got a submitting behavior, then it will handle // submitting the params. If not, then we need to use // a submit script to handle the params. if (isSubmitting(behavior) || ((params.isEmpty()) && !needsSubmit)) return HandlerType.SINGLE_BEHAVIOR_ONLY; } return HandlerType.CHAIN; } // Little utility enum that we use to identify the type of // handler that we are going to render. private enum HandlerType { // Indicates that we only have a user handler - nothing else USER_HANDLER_ONLY, // Indicates that we only have a single behavior - no chaining SINGLE_BEHAVIOR_ONLY, // Indicates that we only render the mojarra.jsfcljs() script SUBMIT_ONLY, // Indicates that we've got a chain CHAIN } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy