You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by pr...@apache.org on 2006/04/07 01:15:34 UTC

svn commit: r392113 - in /myfaces/tomahawk/trunk: core/src/main/java/org/apache/myfaces/renderkit/html/util/ sandbox/core/src/main/java/org/apache/myfaces/custom/ajax/api/ sandbox/core/src/main/java/org/apache/myfaces/custom/ajax/util/ sandbox/core/src...

Author: prophecy
Date: Thu Apr  6 16:15:30 2006
New Revision: 392113

URL: http://svn.apache.org/viewcvs?rev=392113&view=rev
Log:
Added Listener component, that will listen for ajax events on components and call actions.  Currently only supports "update".

Added:
    myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/inputAjax/Listener.java
    myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/inputAjax/ListenerTag.java
Modified:
    myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/renderkit/html/util/ExtensionsPhaseListener.java
    myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/ajax/api/AjaxDecodePhaseListener.java
    myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/ajax/util/AjaxRendererUtils.java
    myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/inputAjax/HtmlInputTextAjax.java
    myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/suggestajax/tablesuggestajax/HtmlOutputText.java
    myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/util/ComponentUtils.java
    myfaces/tomahawk/trunk/sandbox/core/src/main/resources-facesconfig/META-INF/faces-config.xml
    myfaces/tomahawk/trunk/sandbox/core/src/main/tld/myfaces_sandbox.tld
    myfaces/tomahawk/trunk/sandbox/examples/src/main/java/org/apache/myfaces/examples/inputAjax/InputAjaxBean.java
    myfaces/tomahawk/trunk/sandbox/examples/src/main/webapp/inputAjax.jsp

Modified: myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/renderkit/html/util/ExtensionsPhaseListener.java
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/renderkit/html/util/ExtensionsPhaseListener.java?rev=392113&r1=392112&r2=392113&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/renderkit/html/util/ExtensionsPhaseListener.java (original)
+++ myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/renderkit/html/util/ExtensionsPhaseListener.java Thu Apr  6 16:15:30 2006
@@ -16,6 +16,8 @@
 package org.apache.myfaces.renderkit.html.util;
 
 import java.io.IOException;
+import java.util.List;
+import java.util.Map;
 
 import javax.faces.context.FacesContext;
 import javax.faces.context.ResponseWriter;
@@ -44,6 +46,7 @@
 
 
     private static final String ORG_APACHE_MYFACES_MY_FACES_JAVASCRIPT = "org.apache.myfaces.myFacesJavascript";
+    public static final String LISTENERS_MAP = "_MyFaces_inputAjax_listenersMap";
 
     public PhaseId getPhaseId()
     {
@@ -129,5 +132,40 @@
         {
             JavascriptUtils.renderAutoScrollFunction(facesContext, writer);
         }
-	}
+
+        // also write out listeners
+        // todo: change the get entry below to use the static field in Listener if/when the listeners move to Tomahawk from sandbox
+        try
+        {
+            List listeners = (List) facesContext.getExternalContext().getRequestMap().get("org.apache.myfaces.Listener");
+            //System.out.println("listeners: " + listeners);
+            if(listeners != null && listeners.size() > 0){
+                writer.startElement(HTML.SCRIPT_ELEM,null);
+                writer.writeAttribute("attr", HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT,null);
+                StringBuffer buff = new StringBuffer();
+                String mapName = LISTENERS_MAP;
+                buff.append("var ").append(mapName).append(" = new Object();\n");
+                for (int i = 0; i < listeners.size(); i++)
+                {
+                    Map listenerItem = (Map) listeners.get(i);
+                    String listenerId = (String) listenerItem.get("listenerId");
+                    String listenOn = (String) listenerItem.get("listenOn");
+                    // todo: Should use Listener object for more flexibility, but only when it moves to tomahawk
+                    buff.append("var _MyFaces_listenerItem = ").append(mapName).append("['").append(listenOn).append("'];\n");
+                    buff.append("if(!_MyFaces_listenerItem) {\n");
+                    buff.append("    _MyFaces_listenerItem = new Array();\n");
+                    buff.append("    ").append(mapName).append("['").append(listenOn).append("'] = _MyFaces_listenerItem;\n");
+                    buff.append("}\n");
+                    buff.append("_MyFaces_listenerItem[_MyFaces_listenerItem.length] = '").append(listenerId).append("';\n");
+                }
+                writer.write(buff.toString());
+                writer.endElement(HTML.SCRIPT_ELEM);
+            }
+        }
+        catch (Exception e)
+        {
+            System.err.println("CAUGHT");
+            e.printStackTrace();
+        }
+    }
 }

Modified: myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/ajax/api/AjaxDecodePhaseListener.java
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/ajax/api/AjaxDecodePhaseListener.java?rev=392113&r1=392112&r2=392113&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/ajax/api/AjaxDecodePhaseListener.java (original)
+++ myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/ajax/api/AjaxDecodePhaseListener.java Thu Apr  6 16:15:30 2006
@@ -66,31 +66,24 @@
     public PhaseId getPhaseId()
     {
         return PhaseId.APPLY_REQUEST_VALUES;
-
     }
 
     public void beforePhase(PhaseEvent event)
     {
         log.debug("In AjaxDecodePhaseListener beforePhase");
-
         FacesContext context = event.getFacesContext();
-
         Map externalRequestMap = context.getExternalContext().getRequestParameterMap();
 
         if (externalRequestMap.containsKey("affectedAjaxComponent"))
         {
             UIViewRoot root = context.getViewRoot();
-
             String affectedAjaxComponent = (String) context.getExternalContext()
                                                         .getRequestParameterMap().get("affectedAjaxComponent");
-
             UIComponent ajaxComponent = root.findComponent(affectedAjaxComponent);
-
             //checking if ajaxComp is inside a dataTable;
             if (ajaxComponent instanceof UIComponentPerspective)
             {
                 UIComponentPerspective componentPerspective = (UIComponentPerspective) ajaxComponent;
-
                 ajaxComponent = (UIComponent) componentPerspective.executeOn(context, new ExecuteOnCallback()
                 {
                     public Object execute(FacesContext facesContext, UIComponent ajaxComponent)
@@ -107,12 +100,10 @@
             }
 
             StateManager stateManager = context.getApplication().getStateManager();
-
             if (!stateManager.isSavingStateInClient(context))
             {
                 stateManager.saveSerializedView(context);
             }
-
             context.responseComplete();
         }
     }
@@ -120,18 +111,21 @@
 
     private void handleAjaxRequest(UIComponent ajaxComponent, FacesContext facesContext)
     {
-        decodeAjax(ajaxComponent, facesContext);
-
-        facesContext.getViewRoot().processApplication(facesContext);
-
+        String updateOnly = (String) facesContext.getExternalContext().getRequestParameterMap().get("updateOnly");
+        if(updateOnly == null) {
+            // then decode
+            decodeAjax(ajaxComponent, facesContext);
+            facesContext.getViewRoot().processApplication(facesContext);
+        }
+        // else only update
         encodeAjax(ajaxComponent, facesContext);
     }
 
     private void decodeAjax(UIComponent ajaxComponent, FacesContext context)
     {
+
         String affectedAjaxComponent = (String) context.getExternalContext()
                                                     .getRequestParameterMap().get("affectedAjaxComponent");
-
         if (ajaxComponent == null)
         {
             String msg = "Component with id [" + affectedAjaxComponent + "] not found in view tree.";
@@ -150,11 +144,14 @@
             if (form != null)
             {
                 form.processDecodes(context);
-                form.processValidators(context);
-                form.processUpdates(context);
+                //if(context.getRenderResponse())
+                    form.processValidators(context);
+                //else log.debug("Decode failed on Ajax Decode");
+                //if(context.getRenderResponse())
+                    form.processUpdates(context);
+                //else log.debug("Validation failed on Ajax Decode");
                 //System.out.println("DONE!");
             }
-
         }
         else if (ajaxComponent instanceof AjaxComponent)
         {
@@ -175,14 +172,11 @@
     }
 
 
-    private void encodeAjax(UIComponent ajaxComponent, FacesContext context)
+    private void encodeAjax(UIComponent component, FacesContext context)
     {
         Map requestMap = context.getExternalContext().getRequestParameterMap();
 
-        // NOW TRYING TO DO THE ENCODE THAT WAS IN AJAXPHASELISTENER RIGHT HERE, THEN ENDING RESPONSE
-        if (ajaxComponent instanceof AjaxComponent)
-        {
-            if (ajaxComponent instanceof SuggestAjax)
+            if (component instanceof SuggestAjax)
             {
                 try
                 {
@@ -193,7 +187,7 @@
                         PrintWriter htmlResponseWriter = response.getWriter();
                         context.setResponseWriter(new HtmlResponseWriterImpl(htmlResponseWriter, "text/html", "UTF-8"));
                     }
-                    ((AjaxComponent) ajaxComponent).encodeAjax(context);
+                    ((AjaxComponent) component).encodeAjax(context);
                 }
                 catch (IOException e)
                 {
@@ -227,12 +221,12 @@
                     PrintWriter out = response.getWriter();
                     out.print(buff);
 
-                    if (ajaxComponent instanceof HtmlCommandButtonAjax)
+                    if (component instanceof HtmlCommandButtonAjax)
                     {
                         // special treatment for this one, it will try to update the entire form
                         // 1. get surrounding form
                         //String elname = (String) requestMap.get("elname");
-                        FormInfo fi = _ComponentUtils.findNestingForm(ajaxComponent, context);
+                        FormInfo fi = _ComponentUtils.findNestingForm(component, context);
                         UIComponent form = fi.getForm();
                         //System.out.println("FOUND FORM: " + form);
                         if (form != null)
@@ -241,11 +235,14 @@
                             encodeChildren(form, context, requestMap);
                         }
                     }
-                    else
+                    else if (component instanceof AjaxComponent)
                     {
                         // let component render xml response
                         // NOTE: probably don't need an encodeAjax in each component, but leaving it in until that's for sure
-                        ((AjaxComponent) ajaxComponent).encodeAjax(context);
+                        ((AjaxComponent) component).encodeAjax(context);
+                    } else {
+                        // just get latest value
+                        AjaxRendererUtils.encodeAjax(context, component);
                     }
 
                     // end response
@@ -257,11 +254,11 @@
                     log.error("Exception while rendering ajax-response", e);
                 }
             }
-        }
+       /* }
         else
         {
-            log.error("Found component is no ajaxComponent : " + RendererUtils.getPathToComponent(ajaxComponent));
-        }
+            log.error("Found component is no AjaxComponent : " + RendererUtils.getPathToComponent(component));
+        }*/
     }
 
 
@@ -315,11 +312,8 @@
                                             .getRequestParameterMap().get("affectedAjaxComponent");
 
             log.debug("affectedAjaxComponent: " + possibleClientId);
-
             UIViewRoot root = context.getViewRoot();
-
             UIComponent ajaxComponent = root.findComponent(possibleClientId);
-
             if (ajaxComponent instanceof UIComponentPerspective)
             {
                 UIComponentPerspective componentPerspective = (UIComponentPerspective) ajaxComponent;

Modified: myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/ajax/util/AjaxRendererUtils.java
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/ajax/util/AjaxRendererUtils.java?rev=392113&r1=392112&r2=392113&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/ajax/util/AjaxRendererUtils.java (original)
+++ myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/ajax/util/AjaxRendererUtils.java Thu Apr  6 16:15:30 2006
@@ -24,7 +24,7 @@
 import javax.faces.application.FacesMessage;
 import javax.faces.application.ViewHandler;
 import javax.faces.component.UIComponent;
-import javax.faces.component.UIInput;
+import javax.faces.component.UIOutput;
 import javax.faces.context.FacesContext;
 import javax.faces.context.ResponseWriter;
 import javax.servlet.http.HttpServletRequest;
@@ -33,6 +33,7 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.myfaces.renderkit.html.util.AddResource;
+import org.apache.myfaces.renderkit.html.util.ExtensionsPhaseListener;
 import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
 import org.apache.myfaces.custom.ajax.AjaxCallbacks;
 import org.apache.myfaces.custom.prototype.PrototypeResourceLoader;
@@ -153,9 +154,10 @@
             buff = new StringBuffer();
             buff.append("\n")
                     .append("function ").append(jsNameSpace).append("notifyElement(originalRequest, successful)\n")
-                    .append("{\n")
-                    .append("    //alert(\"originalRequest: \" + originalRequest + \" - \" + successful + \"\\ntext: \" + originalRequest.responseText);\n")
-                    .append("    var errorArray = originalRequest.responseXML.getElementsByTagName(\"response\")[0].getElementsByTagName(\"error\");\n")
+                    .append("{\n");
+                            buff.append("            ").append(jsNameSpace).append("clearGlobalMessages();\n");
+                    //buff.append("    alert(\"originalRequest: \" + originalRequest + \" - \" + successful + \"\\ntext: \" + originalRequest.responseText);\n");
+                    buff.append("    var errorArray = originalRequest.responseXML.getElementsByTagName(\"response\")[0].getElementsByTagName(\"error\");\n")
                     .append("    if(errorArray && errorArray.length > 0){\n")
                     .append("      for(ierr = 0; ierr < errorArray.length; ierr++){\n")
                     .append("        var myObError = errorArray[ierr];\n")
@@ -183,15 +185,36 @@
                     .append("       var myObElement = myObElementArray[iob];\n")
                     .append("       var elname = myObElement.getAttribute(\"elname\");\n")
                     .append("       var elvalue = myObElement.getAttribute(\"elvalue\");\n")
-                    .append("       if (successful)\n")
-                    .append("       {\n");
+                    //.append("       alert('elname: ' + elname + ' elvalue: ' + elvalue + ' successful: ' + successful);\n")
+                    .append("       if(elvalue){\n")
+                    .append("           if (successful){\n");
             if (component.getOnSuccess() != null)
             {
-                buff.append("        ").append(AJAX_RESPONSE_MAP).append("['elname']['onSuccessFunction'](elname, elvalue, originalRequest);\n");
+                buff.append("            ").append(AJAX_RESPONSE_MAP).append("['elname']['onSuccessFunction'](elname, elvalue, originalRequest);\n");
             }
-            buff.append(jsNameSpace).append("clearErrorMessageAndFieldStyles(elname, myObElementArray);\n");
-            buff.append("        ").append(jsNameSpace).append("clearError(elname);\n");
-            buff.append("    }\n");
+
+            buff.append("            ").append(jsNameSpace).append("clearError(elname);\n");
+            // and update the component value if it changed
+            buff.append("            var elToUpdate = document.getElementById(elname + '_span');\n");
+            //buff.append("alert('span: ' + elname + '_span elToUpdate: ' + elToUpdate + ' - ' + elvalue);\n");
+            buff.append("            if(elToUpdate) elToUpdate.innerHTML = elvalue;\n"); // todo: need to use ".value" for form elements
+            // also check for any listeners
+            //buff.append("alert('listenersmap: ' + ").append(ExtensionsPhaseListener.LISTENERS_MAP).append(" + ' getting: ' + elname);\n");
+            buff.append("            if(").append(ExtensionsPhaseListener.LISTENERS_MAP).append("){\n")
+                    .append("            var _MyFaces_listenerArray = ").append(ExtensionsPhaseListener.LISTENERS_MAP).append("[elname];\n")
+                   // .append("alert('listenerarray: ' + _MyFaces_listenerArray);\n")
+                    .append("            if(_MyFaces_listenerArray){\n")
+                            // loop throough listeners in array
+                    .append("              for(ilaindex = 0; ilaindex < _MyFaces_listenerArray.length; ilaindex++){\n")
+                            .append("                var _MyFaces_listenerItem = _MyFaces_listenerArray[ilaindex];\n")
+                    // then call action on listener, just supporting "update" at first
+                    //.append("alert('listeneritem: ' + _MyFaces_listenerItem);\n")
+                    .append("                ").append(jsNameSpace).append("updateComponent(_MyFaces_listenerItem);\n")
+                    .append("               }\n")
+                    .append("            }\n")
+                    .append("         }\n");
+            buff.append("        }\n");
+            buff.append("     }\n");// end if(elvalue)
             if (component.getOnFailure() != null)
             {
                 buff.append("        else\n")
@@ -236,21 +259,9 @@
                     .append("    var msgSpan = document.getElementById(elname+\"_msgFor\");\n")
                     .append("    if(msgSpan){\n")
                     .append("        msgSpan.innerHTML = \"\";\n")
-                    .append("    }\n")
-                    .append("}\n");
-            //clearError function; same as above, but also for the htmlInputTextAjax field if using the messages comp
-            buff.append("function ").append(jsNameSpace).append("clearErrorMessageAndFieldStyles(elname, possibleUpdateTag){\n")
-                    .append("try\n")
-                    .append("    {\n")
-                    .append("        if(possibleUpdateTag[0].tagName == \"elementUpdated\")\n")
-                    .append("        {\n");
-            if (ajaxMessagesId != null)
-            {
-                buff.append("            var errorMessageSpan = document.getElementById(\"" + ajaxMessagesId + "\");\n")
-                        .append("            errorMessageSpan.innerHTML = \"\";\n");
-            }
-            //set ajaxinputField to default style or styleclass
+                    .append("    }\n");
             buff.append("            var errorField = document.getElementById(elname);\n");
+            buff.append("            if(errorField){\n");
             if (htmlInputTextAjax != null)
             {
                 if (htmlInputTextAjax.getStyleClass() != null)
@@ -264,15 +275,30 @@
                     buff.append("errorField.style.cssText = \"\";\n")
                             .append("errorField.className = \"\";\n");
                 }
+            }
+             buff.append("}\n");
+            buff.append("}\n");
 
 
+            //clearError function; same as above, but also for using the messages comp
+            buff.append("function ").append(jsNameSpace).append("clearGlobalMessages(){\n");
+                    /*.append("try\n")
+                    .append("    {\n")*/
+                    //.append("        if(possibleUpdateTag[0].tagName == \"elementUpdated\")\n")
+                    //.append("        {\n");
+            if (ajaxMessagesId != null)
+            {
+                buff.append("            var errorMessageSpan = document.getElementById(\"" + ajaxMessagesId + "\");\n")
+                        .append("            errorMessageSpan.innerHTML = \"\";\n");
             }
-            buff.append("        }\n")
-                    .append("    }catch(e)\n")
+            //set ajaxinputField to default style or styleclass
+
+            //buff.append("        }\n")
+                    /*.append("    }catch(e)\n")
                     .append("    {\n")
                     .append("        this.dispatchException(e);\n")
-                    .append("    }\n")
-                    .append("    }\n");
+                    .append("    }\n")*/
+                   buff.append("    }\n");
 
             buff.append("function ").append(jsNameSpace)
                     .append("notifyElementFailure(originalRequest){\n")
@@ -316,7 +342,7 @@
                     .append("}\n");
 
             // and now the actual function that will send the request
-            buff.append("function ").append(jsNameSpace).append("ajaxSubmit(elname, elvalue, el, extraParams){\n");
+            buff.append("function ").append(jsNameSpace).append("ajaxSubmit(elname, elvalue, el, extraParams, updateOnly){\n");
             if (component.getOnStart() != null)
                 buff.append("    ").append(AJAX_RESPONSE_MAP).append("[elname]").append("['onStartFunction'](elname, elvalue);\n");
             buff.append("    var pars = \"affectedAjaxComponent=\" + elname + \"&elname=\" + elname + \"&elvalue=\" + elvalue + \"");
@@ -327,10 +353,11 @@
             }
             buff.append("\";\n"); // end pars
             buff.append("    if(extraParams) pars += extraParams;\n");
-            buff.append("    pars += '&' + Form.serialize(el);\n");
+            buff.append("    if(updateOnly) pars += '&updateOnly=true';\n");
+            buff.append("    if(el) pars += '&' + Form.serialize(el);\n");
             //buff.append(" alert(pars);"); // can be used for debugging
             buff.append("    var " + "_ajaxRequest = new Ajax.Request(\n")
-                    .append("    ").append(AJAX_RESPONSE_MAP).append("[elname]['ajaxUrl'],\n")
+                    .append("    '").append(ajaxURL).append("',\n")//.append(AJAX_RESPONSE_MAP).append("[elname]['ajaxUrl'],\n")
                     .append("    {method: 'post'" + ", parameters: pars");
             buff.append(", onComplete: ").append(jsNameSpace).append("complete");
             buff.append(", onSuccess: ").append(jsNameSpace).append("notifyElementSuccess");
@@ -341,6 +368,16 @@
                             "}\n"
             );
 
+            // updateComponent will request latest value from server, basically just half of what ajaxSubmit does
+            buff.append("function ").append(jsNameSpace).append("updateComponent(elname){\n")
+                    //.append("    alert('updating component: ' + elname);\n")
+                    .append("    ").append(jsNameSpace).append("ajaxUpdate(elname);\n")
+                    .append("}\n");
+
+             buff.append("function ").append(jsNameSpace).append("ajaxUpdate(elname){\n")
+                    .append("    ").append(jsNameSpace).append("ajaxSubmit(elname, null, null, null, true);\n")
+                    .append("}\n");
+
             out.writeText(buff.toString(), null);
 
 
@@ -353,7 +390,7 @@
         out.startElement(HTML.SCRIPT_ELEM, null);
         out.writeAttribute(HTML.TYPE_ATTR, "text/javascript", null);
         out.writeText(AJAX_RESPONSE_MAP + "['" + clientId + "'] = new Object();\n", null);
-        out.writeText(AJAX_RESPONSE_MAP + "['" + clientId + "']['ajaxUrl'] = '" + ajaxURL + "';\n", null);
+        //out.writeText(AJAX_RESPONSE_MAP + "['" + clientId + "']['ajaxUrl'] = '" + ajaxURL + "';\n", null);
         if (component.getOnSuccess() != null)
             out.writeText(AJAX_RESPONSE_MAP + "['" + clientId + "']['onSuccessFunction'] = " + component.getOnSuccess() + ";\n", null);
         if (component.getOnFailure() != null)
@@ -413,7 +450,6 @@
                 //System.out.println("Looking for component: " + msgForId);
                 UIComponent msgComponent = context.getViewRoot().findComponent(msgForId);
                 String msgId = null;
-
                 if (msgComponent != null)
                 {
                     //System.out.println("Component found");
@@ -451,11 +487,11 @@
             {
                 // send elementUpdated messages
                 buff.append("<elementUpdated elname=\"").append(clientId).append("\"");
-                if(component instanceof UIInput){
-                    UIInput uiInput = (UIInput) component;
+                if(component instanceof UIOutput){
+                    UIOutput uiOutput = (UIOutput) component;
                     // todo: might have to make sure this value can be serialized like this
                     // todo: and should probably be in text block, rather than an attribute
-                        buff.append(" elvalue=\"").append(uiInput.getValue()).append("\"");
+                        buff.append(" elvalue=\"").append(uiOutput.getValue()).append("\"");
                 }
                 if (extraReturnAttributes != null)
                 {

Modified: myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/inputAjax/HtmlInputTextAjax.java
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/inputAjax/HtmlInputTextAjax.java?rev=392113&r1=392112&r2=392113&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/inputAjax/HtmlInputTextAjax.java (original)
+++ myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/inputAjax/HtmlInputTextAjax.java Thu Apr  6 16:15:30 2006
@@ -82,7 +82,6 @@
         if (context == null) throw new NullPointerException("context");
         if (!isRendered()) return;
         Renderer renderer = getRenderer(context);
-
         if (renderer != null && renderer instanceof AjaxRenderer)
         {
             ((AjaxRenderer) renderer).encodeAjax(context, this);

Added: myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/inputAjax/Listener.java
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/inputAjax/Listener.java?rev=392113&view=auto
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/inputAjax/Listener.java (added)
+++ myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/inputAjax/Listener.java Thu Apr  6 16:15:30 2006
@@ -0,0 +1,89 @@
+package org.apache.myfaces.custom.inputAjax;
+
+import javax.faces.component.UIComponentBase;
+import javax.faces.context.FacesContext;
+
+/**
+ * On is the id of the component you want to listen on.
+ * eventType is what happened to the component, for instance "onChange"
+ * action is what to do if the event occurs, default is "update".  Will be able to call arbitrary javascript functions too.
+ *
+ * NOTE: eventType and action are NOT implemented yet
+ *
+ * User: Travis Reeder
+ * Date: Apr 5, 2006
+ * Time: 4:33:10 PM
+ */
+public class Listener extends UIComponentBase
+{
+    public static final String FAMILY = "org.apache.myfaces.Listener";
+    public static final String COMPONENT_TYPE = "org.apache.myfaces.Listener";
+    public static final String LISTENER_MAP_ENTRY = "org.apache.myfaces.Listener";
+
+    private String _on;
+    private String _eventType;
+    private String _action;
+
+    public Listener()
+    {
+    }
+
+    public boolean isRendered()
+    {
+        return super.isRendered();
+    }
+
+    public String getFamily()
+    {
+        return FAMILY;
+    }
+
+    public Object saveState(FacesContext context)
+    {
+        Object values[] = new Object[4];
+        values[0] = super.saveState(context);
+        values[1] = _on;
+        values[2] = _eventType;
+        values[3] = _action;
+        return ((Object) (values));
+    }
+
+    public void restoreState(FacesContext context, Object state)
+    {
+        Object values[] = (Object[]) state;
+        super.restoreState(context, values[0]);
+        _on = (String) values[1];
+        _eventType = (String) values[2];
+        _action = (String) values[3];
+    }
+
+    public String getOn()
+    {
+        return _on;
+    }
+
+    public void setOn(String on)
+    {
+        _on = on;
+    }
+
+    public String getEventType()
+    {
+        return _eventType;
+    }
+
+    public void setEventType(String eventType)
+    {
+        _eventType = eventType;
+    }
+
+    public String getAction()
+    {
+        return _action;
+    }
+
+    public void setAction(String action)
+    {
+        _action = action;
+    }
+}

Added: myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/inputAjax/ListenerTag.java
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/inputAjax/ListenerTag.java?rev=392113&view=auto
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/inputAjax/ListenerTag.java (added)
+++ myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/inputAjax/ListenerTag.java Thu Apr  6 16:15:30 2006
@@ -0,0 +1,77 @@
+package org.apache.myfaces.custom.inputAjax;
+
+import org.apache.myfaces.component.UserRoleAware;
+import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
+import org.apache.myfaces.shared_impl.taglib.UIComponentTagUtils;
+
+import javax.servlet.jsp.tagext.Tag;
+import javax.faces.webapp.UIComponentTag;
+import javax.faces.component.UIComponent;
+
+/**
+ * User: Travis Reeder
+ * Date: Apr 5, 2006
+ * Time: 4:14:07 PM
+ */
+public class ListenerTag extends UIComponentTag
+{
+    private String _on;
+    private String _eventType;
+    private String _action;
+
+    public void release()
+    {
+        super.release();
+        _on = null;
+        _eventType = null;
+        _action = null;
+    }
+
+    public String getComponentType()
+    {
+        return Listener.COMPONENT_TYPE;
+    }
+
+    public String getRendererType()
+    {
+        return null;
+    }
+
+    protected void setProperties(UIComponent uiComponent)
+    {
+        super.setProperties(uiComponent);
+        UIComponentTagUtils.setStringProperty(getFacesContext(), uiComponent, "on", _on);
+        UIComponentTagUtils.setStringProperty(getFacesContext(), uiComponent, "eventType", _eventType);
+        UIComponentTagUtils.setStringProperty(getFacesContext(), uiComponent, "action", _action);
+    }
+
+    public String getOn()
+    {
+        return _on;
+    }
+
+    public void setOn(String on)
+    {
+        _on = on;
+    }
+
+    public String getEventType()
+    {
+        return _eventType;
+    }
+
+    public void setEventType(String eventType)
+    {
+        _eventType = eventType;
+    }
+
+    public String getAction()
+    {
+        return _action;
+    }
+
+    public void setAction(String action)
+    {
+        _action = action;
+    }
+}

Modified: myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/suggestajax/tablesuggestajax/HtmlOutputText.java
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/suggestajax/tablesuggestajax/HtmlOutputText.java?rev=392113&r1=392112&r2=392113&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/suggestajax/tablesuggestajax/HtmlOutputText.java (original)
+++ myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/suggestajax/tablesuggestajax/HtmlOutputText.java Thu Apr  6 16:15:30 2006
@@ -1,15 +1,29 @@
 package org.apache.myfaces.custom.suggestajax.tablesuggestajax;
 
 
+import org.apache.myfaces.custom.inputAjax.Listener;
+import org.apache.myfaces.custom.util.ComponentUtils;
+import org.apache.myfaces.shared_tomahawk.util._ComponentUtils;
+import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
+import org.apache.myfaces.shared_impl.renderkit.html.HTML;
+
 import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
 import javax.faces.el.ValueBinding;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIViewRoot;
+import java.io.IOException;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
 
 /**
- * @author Gerald Müllan
+ * @author Gerald M�llan
  *         Date: 15.02.2006
  *         Time: 13:30:43
  */
-public class HtmlOutputText extends javax.faces.component.html.HtmlOutputText
+public class HtmlOutputText extends org.apache.myfaces.component.html.ext.HtmlOutputText
 {
     public static final String COMPONENT_TYPE = "org.apache.myfaces.HtmlOutputTextFor";
 
@@ -21,7 +35,66 @@
     {
     }
 
-     public Object saveState(FacesContext context)
+    public void encodeBegin(FacesContext facesContext) throws IOException
+    {
+        super.encodeBegin(facesContext);
+    }
+
+    public void encodeEnd(FacesContext facesContext) throws IOException
+    {
+        ResponseWriter writer = facesContext.getResponseWriter();
+        writer.startElement(HTML.SPAN_ELEM, null);
+        writer.writeAttribute("id", this.getClientId(facesContext) + "_span", null);
+        super.encodeEnd(facesContext);
+        writer.endElement(HTML.SPAN_ELEM);
+    }
+
+    public boolean getRendersChildren()
+    {
+        return true;
+    }
+
+    public void encodeChildren(FacesContext facesContext) throws IOException
+    {
+        checkForListeners(facesContext, this);
+        super.encodeChildren(facesContext);
+    }
+
+    private void checkForListeners(FacesContext context, UIComponent component)
+    {
+        // TODO: MOVE THIS UP THE TREE OR TO SOME OTHER LEVEL SO IT CAN WORK ON ANY COMPONENT
+        List children = component.getChildren();
+        if(children != null){
+            for (int i=0; i<children.size(); i++)
+            {
+                UIComponent child = (UIComponent) children.get(i);
+                if(child instanceof Listener){
+                    Listener listener = (Listener) child;
+                    Map rmap = context.getExternalContext().getRequestMap();
+                    List listeners = (List) rmap.get(Listener.LISTENER_MAP_ENTRY);
+                    if(listeners == null){
+                        listeners = new ArrayList();
+                        rmap.put(Listener.LISTENER_MAP_ENTRY, listeners);
+                    }
+                    // find component
+                    UIViewRoot root = context.getViewRoot();
+                    UIComponent ajaxComponent; //= component.findComponent(listener.getOn());
+                    //System.out.println("FINDING COMPONENT TO LISTEN ON: " + ajaxComponent);
+                    ajaxComponent = ComponentUtils.findComponentById(context, root, listener.getOn());
+                    if(ajaxComponent != null){
+                        //System.out.println("FINDING COMPONENT TO LISTEN ON: " + ajaxComponent);
+                        Map listenerItem = new HashMap();
+                        listenerItem.put("listenOn", ajaxComponent.getClientId(context));
+                        listenerItem.put("listenerId", component.getClientId(context));
+                        listenerItem.put("action", "update");
+                        listeners.add(listenerItem);
+                    }
+                }
+            }
+        }
+    }
+
+    public Object saveState(FacesContext context)
     {
         Object values[] = new Object[4];
         values[0] = super.saveState(context);

Modified: myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/util/ComponentUtils.java
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/util/ComponentUtils.java?rev=392113&r1=392112&r2=392113&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/util/ComponentUtils.java (original)
+++ myfaces/tomahawk/trunk/sandbox/core/src/main/java/org/apache/myfaces/custom/util/ComponentUtils.java Thu Apr  6 16:15:30 2006
@@ -29,13 +29,71 @@
  */
 public class ComponentUtils
 {
+
+    /**
+     * TR- This was moved from AjaxPhaseListenere on checkin 344383
+     *
+     * @param context
+     * @param root
+     * @param clientId
+     * @return component referenced by clientId or null if not found
+     */
+    public static UIComponent findComponentByClientId(FacesContext context, UIComponent root, String clientId)
+    {
+        UIComponent component = null;
+        for (int i = 0; i < root.getChildCount() && component == null; i++)
+        {
+            UIComponent child = (UIComponent) root.getChildren().get(i);
+            component = findComponentByClientId(context, child, clientId);
+        }
+        if (root.getId() != null)
+        {
+            if (component == null && root.getClientId(context).equals(clientId))
+            {
+                component = root;
+            }
+        }
+        return component;
+    }
+
+    /**
+     * Useful if you don't know the clientId
+     * <p/>
+     * TR- This was moved from AjaxPhaseListenere on checkin 344383
+     * Seems like this could be made more efficient
+     *
+     * @param context
+     * @param root
+     * @param id
+     * @return component referenced by id or null if not found
+     */
+    public static UIComponent findComponentById(FacesContext context, UIComponent root, String id)
+    {
+        UIComponent component = null;
+        for (int i = 0; i < root.getChildCount() && component == null; i++)
+        {
+            UIComponent child = (UIComponent) root.getChildren().get(i);
+            component = findComponentById(context, child, id);
+        }
+        //System.out.println("component looking for: " + id + " - rootid: " + root.getId() + " " + root);
+        if (root.getId() != null)
+        {
+            if (component == null && root.getId().equals(id))
+            {
+                component = root;
+            }
+        }
+        return component;
+    }
+
+
     public static UIComponent findFirstMessagesComponent(FacesContext context, UIComponent base)
     {
-    	if (base == null)
-    	{
-    		return null;
-    	}
-    	
+        if (base == null)
+        {
+            return null;
+        }
+
         if (base instanceof HtmlMessages)
         {
             return base;
@@ -44,15 +102,15 @@
         Iterator iterChildren = base.getFacetsAndChildren();
         while (iterChildren.hasNext())
         {
-        	UIComponent child = (UIComponent) iterChildren.next();
-            
-        	UIComponent found = findFirstMessagesComponent(context, child);
-        	if (found != null)
-        	{
-        		return found;
-        	}
+            UIComponent child = (UIComponent) iterChildren.next();
+
+            UIComponent found = findFirstMessagesComponent(context, child);
+            if (found != null)
+            {
+                return found;
+            }
         }
-        
+
         return null;
     }
 }

Modified: myfaces/tomahawk/trunk/sandbox/core/src/main/resources-facesconfig/META-INF/faces-config.xml
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/resources-facesconfig/META-INF/faces-config.xml?rev=392113&r1=392112&r2=392113&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core/src/main/resources-facesconfig/META-INF/faces-config.xml (original)
+++ myfaces/tomahawk/trunk/sandbox/core/src/main/resources-facesconfig/META-INF/faces-config.xml Thu Apr  6 16:15:30 2006
@@ -65,6 +65,11 @@
   </component>
 
   <component>
+    <component-type>org.apache.myfaces.Listener</component-type>
+    <component-class>org.apache.myfaces.custom.inputAjax.Listener</component-class>
+  </component>
+
+  <component>
     <component-type>org.apache.myfaces.Planner</component-type>
     <component-class>org.apache.myfaces.custom.schedule.HtmlPlanner</component-class>
   </component>

Modified: myfaces/tomahawk/trunk/sandbox/core/src/main/tld/myfaces_sandbox.tld
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/core/src/main/tld/myfaces_sandbox.tld?rev=392113&r1=392112&r2=392113&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/core/src/main/tld/myfaces_sandbox.tld (original)
+++ myfaces/tomahawk/trunk/sandbox/core/src/main/tld/myfaces_sandbox.tld Thu Apr  6 16:15:30 2006
@@ -728,6 +728,34 @@
 		&ext_ajax_attributes;
 	</tag>
 
+    <tag>
+		<name>listener</name>
+		<tag-class>org.apache.myfaces.custom.inputAjax.ListenerTag</tag-class>
+		<body-content>JSP</body-content>
+		<description>Allows a component to listen for events on another component with AJAX input elements.</description>
+        <attribute>
+			<name>on</name>
+			<required>true</required>
+			<rtexprvalue>false</rtexprvalue>
+			<type>java.lang.String</type>
+			<description>Id of another component.</description>
+		</attribute>
+        <attribute>
+			<name>eventType</name>
+			<required>false</required>
+			<rtexprvalue>false</rtexprvalue>
+			<type>java.lang.String</type>
+			<description>NOT IMPLEMENTED - Type of event (ie: onchange, onclick) </description>
+		</attribute>
+        <attribute>
+			<name>action</name>
+			<required>false</required>
+			<rtexprvalue>false</rtexprvalue>
+			<type>java.lang.String</type>
+			<description>NOT IMPLEMENTED - Action to take (ie: update, submit, call (call a javascript function)) </description>
+		</attribute>
+    </tag>
+
 
     <tag>
 		<name>selectBooleanCheckboxAjax</name>

Modified: myfaces/tomahawk/trunk/sandbox/examples/src/main/java/org/apache/myfaces/examples/inputAjax/InputAjaxBean.java
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/examples/src/main/java/org/apache/myfaces/examples/inputAjax/InputAjaxBean.java?rev=392113&r1=392112&r2=392113&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/examples/src/main/java/org/apache/myfaces/examples/inputAjax/InputAjaxBean.java (original)
+++ myfaces/tomahawk/trunk/sandbox/examples/src/main/java/org/apache/myfaces/examples/inputAjax/InputAjaxBean.java Thu Apr  6 16:15:30 2006
@@ -46,6 +46,10 @@
 
     private String formText1;
     private String formText2;
+    private String waitingText1 = "I'm waaaaaiiiiiting...";
+    private String waitingText2 = new String(waitingText1);
+    private int counter1 = 0;
+    private int counter2 = 0;
 
     /**
      * Simple validator to show error handling messages in examples, returns an error if value string is
@@ -256,5 +260,33 @@
         System.out.println("setting formtext1");
         this.formText1 = formText1;
     }
+
+    public String getWaitingText1()
+    {
+        if(counter1 > 0){
+            waitingText1 = "I was listening " + counter1 + " times!";
+        }
+        counter1++;
+        return waitingText1;
+    }
+
+    public void setWaitingText1(String waitingText)
+    {
+        this.waitingText1 = waitingText;
+    }
+    public String getWaitingText2()
+    {
+        if(counter2 > 0){
+            waitingText2 = "I was listening " + counter2 + " times!";
+        }
+        counter2++;
+        return waitingText2;
+    }
+
+    public void setWaitingText2(String waitingText)
+    {
+        this.waitingText2 = waitingText;
+    }
+
 
 }

Modified: myfaces/tomahawk/trunk/sandbox/examples/src/main/webapp/inputAjax.jsp
URL: http://svn.apache.org/viewcvs/myfaces/tomahawk/trunk/sandbox/examples/src/main/webapp/inputAjax.jsp?rev=392113&r1=392112&r2=392113&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/sandbox/examples/src/main/webapp/inputAjax.jsp (original)
+++ myfaces/tomahawk/trunk/sandbox/examples/src/main/webapp/inputAjax.jsp Thu Apr  6 16:15:30 2006
@@ -207,7 +207,7 @@
 </f:facet>
 </t:panelLayout>
 
-
+<h:panelGrid columns="2">
 <h:form>
     <h:outputText styleClass="standard_bold" value="Form Submit via AJAX"/>
     <h:panelGrid columns="2">
@@ -226,8 +226,19 @@
     <f:verbatim>This component demonstrates submitting a form through ajax.  To see validation errors, put less than five
     characters in first box, and a string with a space in it in the second box.</f:verbatim>
 </h:panelGrid>
-
 </h:form>
+     <%-- Auto updating piece --%>
+    <h:panelGrid columns="1">
+    <h:outputText styleClass="standard_bold" value="Listener on the first textfield to the left"/>
+    <s:outputText value="#{inputAjaxBean.waitingText1}">
+        <s:listener on="formText1"/>
+    </s:outputText>
+    <h:outputText styleClass="standard_bold" value="Listener on the second textfield to the left"/>
+    <s:outputText value="#{inputAjaxBean.waitingText2}">
+        <s:listener on="formText2"/>
+    </s:outputText>
+    </h:panelGrid>
+</h:panelGrid>
 
 <h:outputLink value="inputAjax.jsf"><h:outputText value="Refresh"></h:outputText></h:outputLink>