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();
+ }
+
+}