You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ha...@apache.org on 2008/06/11 14:14:46 UTC

svn commit: r666629 - in /myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/subform: ./ AbstractSubForm.java SubFormRenderer.java

Author: hazems
Date: Wed Jun 11 05:14:46 2008
New Revision: 666629

URL: http://svn.apache.org/viewvc?rev=666629&view=rev
Log:
([TOMAHAWK-1279] promoting the subform component to Tomahawk.)

Added:
    myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/subform/
    myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/subform/AbstractSubForm.java
    myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/subform/SubFormRenderer.java

Added: myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/subform/AbstractSubForm.java
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/subform/AbstractSubForm.java?rev=666629&view=auto
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/subform/AbstractSubForm.java (added)
+++ myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/subform/AbstractSubForm.java Wed Jun 11 05:14:46 2008
@@ -0,0 +1,303 @@
+/*
+ * 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.subform;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javax.faces.component.EditableValueHolder;
+import javax.faces.component.NamingContainer;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIComponentBase;
+import javax.faces.context.FacesContext;
+import javax.faces.event.ActionEvent;
+import javax.faces.event.FacesEvent;
+import javax.faces.event.PhaseId;
+
+import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
+
+/**
+ * A SubForm which will allow for partial validation
+ * and model update.
+ * <p>
+ * A subform to an existing form. Inputs in this form will only be 
+ * validated and updated, if a t:commandButton or t:commandLink 
+ * has been clicked with an actionFor attribute which references 
+ * the client-id of this subform. Optionally, the validation will 
+ * trigger if a commandButton or commandLink embedded in this 
+ * subform has been clicked, except if this command is a 
+ * t:commandButton or t:commandLink with an actionFor attribute 
+ * which doesn't reference the client-id of this subform.
+ * </p>
+ * <p>
+ * Components will be validated and updated only if
+ * either a child-component of this form caused
+ * the submit of the form, or an extended commandLink
+ * or commandButton with the actionFor attribute set
+ * to the client-id of this component was used.
+ * </p>
+ * <p>
+ * You can have several comma-separated entries in
+ * the actionFor-attribute - with this it's possible to
+ * validate and update more than one subForm at once.
+ * </p>
+ *
+ * @JSFComponent
+ *   name = "t:subform"
+ *   class = "org.apache.myfaces.custom.subform.SubForm"
+ *   tagClass = "org.apache.myfaces.custom.subform.SubFormTag"
+ *   implements = "javax.faces.component.NamingContainer"
+ *   
+ * @author Gerald Muellan
+ * @author Martin Marinschek
+ *         Date: 19.01.2006
+ *         Time: 13:58:18
+ */
+public abstract class AbstractSubForm extends UIComponentBase
+                     implements NamingContainer
+{
+
+    public static final String COMPONENT_TYPE = "org.apache.myfaces.SubForm";
+    public static final String DEFAULT_RENDERER_TYPE = "org.apache.myfaces.SubForm";
+    public static final String COMPONENT_FAMILY = "org.apache.myfaces.SubForm";
+
+    private static final String PARTIAL_ENABLED = "org.apache.myfaces.IsPartialPhaseExecutionEnabled";
+    private boolean _submitted;
+
+	public AbstractSubForm()
+    {
+        super.setRendererType(DEFAULT_RENDERER_TYPE);
+    }
+
+    public String getFamily()
+    {
+        return COMPONENT_FAMILY;
+    }
+
+    public boolean isSubmitted()
+    {
+        return _submitted;
+    }
+
+    public void setSubmitted(boolean submitted)
+    {
+        _submitted = submitted;
+    }
+
+    /**
+     * true|false - set to false if you submit other subforms and would like to 
+     * have your subform reflecting any model update. Default: true
+     * 
+     * @JSFProperty
+     * @return
+     */
+	public abstract Boolean getPreserveSubmittedValues();
+
+
+	public void processDecodes(FacesContext context)
+	{
+		super.processDecodes(context);
+		if (!isRendered()) return;
+
+		if (!_submitted && Boolean.FALSE.equals(getPreserveSubmittedValues()))
+		{
+			// didn't find any better way as we do not know if we are submitted before the
+			// decode phase, but then all the other components have the submitted value
+			// set already.
+			// so lets reset them again ... boring hack.
+			resetSubmittedValues(this, context);
+		}
+	}
+
+	public void processValidators(FacesContext context)
+    {
+		if (context == null) throw new NullPointerException("context");
+		if (!isRendered()) return;
+
+		boolean partialEnabled = isPartialEnabled(context, PhaseId.PROCESS_VALIDATIONS);
+
+		if(partialEnabled || (_submitted && isEmptyList(context)))
+		{
+			for (Iterator it = getFacetsAndChildren(); it.hasNext(); )
+			{
+				UIComponent childOrFacet = (UIComponent)it.next();
+				childOrFacet.processValidators(context);
+			}
+		}
+		else
+		{
+			processSubFormValidators(this,context);
+		}
+    }
+
+    public void processUpdates(FacesContext context)
+    {
+        if (context == null) throw new NullPointerException("context");
+        if (!isRendered()) return;
+
+        boolean partialEnabled = isPartialEnabled(context,PhaseId.UPDATE_MODEL_VALUES);
+
+        if(partialEnabled || _submitted)
+        {
+            for (Iterator it = getFacetsAndChildren(); it.hasNext(); )
+            {
+                UIComponent childOrFacet = (UIComponent)it.next();
+                childOrFacet.processUpdates(context);
+            }
+        }
+        else
+        {
+            processSubFormUpdates(this,context);
+        }
+    }
+
+	private static void resetSubmittedValues(UIComponent comp, FacesContext context)
+	{
+		for (Iterator it = comp.getFacetsAndChildren(); it.hasNext(); )
+		{
+			UIComponent childOrFacet = (UIComponent)it.next();
+			if (childOrFacet instanceof AbstractSubForm)
+			{
+				// we are not responsible for this subForm, are we?
+				continue;
+			}
+
+			if (childOrFacet instanceof EditableValueHolder)
+			{
+				((EditableValueHolder) childOrFacet).setSubmittedValue(null);
+			}
+
+			resetSubmittedValues(childOrFacet, context);
+		}
+	}
+
+	private static void processSubFormUpdates(UIComponent comp, FacesContext context)
+    {
+        for (Iterator it = comp.getFacetsAndChildren(); it.hasNext(); )
+        {
+            UIComponent childOrFacet = (UIComponent)it.next();
+
+            if(childOrFacet instanceof AbstractSubForm)
+            {
+                childOrFacet.processUpdates(context);
+            }
+            else
+            {
+                processSubFormUpdates(childOrFacet, context);
+            }
+        }
+    }
+
+    private static void processSubFormValidators(UIComponent comp, FacesContext context)
+    {
+        for (Iterator it = comp.getFacetsAndChildren(); it.hasNext(); )
+        {
+            UIComponent childOrFacet = (UIComponent)it.next();
+
+            if(childOrFacet instanceof AbstractSubForm)
+            {
+                childOrFacet.processValidators(context);
+            }
+            else
+            {
+                processSubFormValidators(childOrFacet, context);
+            }
+        }
+    }
+
+    public void queueEvent(FacesEvent event)
+    {
+        if(event instanceof ActionEvent)
+        {
+            _submitted = true;
+        }
+
+        // This idea is taken from ADF faces - my approach of checking for instanceof ActionEvent
+        // didn't go as far as necessary for dataTables.
+        // In the dataTable case, the ActionEvent is wrapped in an EventWrapper
+        //
+        // I still believe the second part of the if condition is a hack:
+        // If the event is being queued for anything *after* APPLY_REQUEST_VALUES,
+        // then this subform is active - IMHO there might be other events not relating
+        // to the action system which are queued after this phase.
+        if (PhaseId.APPLY_REQUEST_VALUES.compareTo(event.getPhaseId()) < 0)
+        {
+            setSubmitted(true);
+        }
+
+        super.queueEvent(event);
+    }
+
+    protected boolean isEmptyList(FacesContext context)
+    {
+        //get the list of (parent) client-ids for which a validation/model update should be performed
+        List li = (List) context.getExternalContext().getRequestMap().get(
+                RendererUtils.ACTION_FOR_LIST);
+
+        return li==null || li.size()==0;
+    }
+
+    /**Sets up information if this component is included in
+     * the group of components which are associated with the current action.
+     *
+     * @param context
+     * @return true if there has been a change by this setup which has to be undone after the phase finishes.
+     */
+    protected boolean isPartialEnabled(FacesContext context, PhaseId phaseId)
+    {
+        //we want to execute validation (and model update) only
+        //if certain conditions are met
+        //especially, we want to switch validation/update on/off depending on
+        //the attribute "actionFor" of a MyFaces extended button or link
+        //if you use commandButtons which don't set these
+        //request parameters, this won't cause any adverse effects
+
+        boolean partialEnabled = false;
+
+        //get the list of (parent) client-ids for which a validation/model update should be performed
+        List li = (List) context.getExternalContext().getRequestMap().get(
+                RendererUtils.ACTION_FOR_LIST);
+
+        //if there is a list, check if the current client id
+        //matches an entry of the list
+        if(li != null && li.contains(getClientId(context)))
+        {
+            if(!context.getExternalContext().getRequestMap().containsKey(PARTIAL_ENABLED))
+            {
+                partialEnabled=true;
+            }
+        }
+
+        if(partialEnabled)
+        {
+            //get the list of phases which should be executed
+            List phaseList = (List) context.getExternalContext().getRequestMap().get(
+                RendererUtils.ACTION_FOR_PHASE_LIST);
+
+            if(phaseList != null && !phaseList.isEmpty() && !phaseList.contains(phaseId))
+            {
+                partialEnabled=false;
+            }
+        }
+
+        return partialEnabled;
+    }
+
+
+}

Added: myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/subform/SubFormRenderer.java
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/subform/SubFormRenderer.java?rev=666629&view=auto
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/subform/SubFormRenderer.java (added)
+++ myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/subform/SubFormRenderer.java Wed Jun 11 05:14:46 2008
@@ -0,0 +1,103 @@
+/*
+ * 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.subform;
+
+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.HtmlRenderer;
+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 java.io.IOException;
+import java.util.Map;
+
+/**
+ * 
+ * @JSFRenderer
+ *   renderKitId = "HTML_BASIC" 
+ *   family = "org.apache.myfaces.SubForm"
+ *   type = "org.apache.myfaces.SubForm"
+ * 
+ * @author Gerald Muellan
+ *         Date: 19.01.2006
+ *         Time: 14:01:35
+ */
+public class SubFormRenderer extends HtmlRenderer
+{
+    private static final String SUBMIT_FUNCTION_SUFFIX = "_submit";
+    private static final String HIDDEN_PARAM_NAME = "org.apache.myfaces.custom.subform.submittedId";
+
+	
+    public void encodeBegin(FacesContext context, UIComponent component) throws IOException
+    {
+        super.encodeBegin(context, component);
+
+        ResponseWriter writer = context.getResponseWriter();
+
+        HtmlRendererUtils.writePrettyLineSeparator(context);
+        writer.startElement(HTML.SCRIPT_ELEM, null);
+        writer.writeAttribute(org.apache.myfaces.shared_tomahawk.renderkit.html.HTML.SCRIPT_TYPE_ATTR, org.apache.myfaces.shared_tomahawk.renderkit.html.HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT, null);
+
+		FormInfo parentFormInfo = RendererUtils.findNestingForm(component,context);
+        if(parentFormInfo!=null)
+        {
+            writer.writeText(createPartialSubmitJS(component.getId(), parentFormInfo.getFormName()), null);
+        }
+
+        writer.endElement(org.apache.myfaces.shared_tomahawk.renderkit.html.HTML.SCRIPT_ELEM);
+        HtmlRendererUtils.writePrettyLineSeparator(context);
+    }
+    
+
+    public void decode(FacesContext context, UIComponent component)
+    {
+        super.decode(context, component);
+
+        Map paramValuesMap = context.getExternalContext().getRequestParameterMap();
+        String reqValue = (String) paramValuesMap.get(HIDDEN_PARAM_NAME);
+        if (reqValue != null && component.getId().equals(reqValue))
+        {
+            ((SubForm) component).setSubmitted(true);
+        }
+    }
+
+    
+    protected String createPartialSubmitJS(String subFormId, String parentFormClientId)
+    {
+        StringBuffer script = new StringBuffer();
+        script.append("function ");
+        script.append(subFormId).append(SUBMIT_FUNCTION_SUFFIX + "()");
+        script.append(" {\n");
+        script.append("var form = document.forms['").append(parentFormClientId).append("'];\n");
+        script.append("var el = document.createElement(\"input\");\n");
+        script.append("el.type = \"hidden\";\n");
+        script.append("el.name = \"" + HIDDEN_PARAM_NAME + "\";\n");
+        script.append("el.value = \"").append(subFormId).append("\";\n");
+        script.append("form.appendChild(el);\n");
+        script.append("form.submit();\n");
+        script.append("}\n");
+
+        return script.toString();
+    }
+
+}