View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.custom.jslistener;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.myfaces.renderkit.html.util.AddResource;
24  import org.apache.myfaces.renderkit.html.util.AddResourceFactory;
25  import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRenderer;
26  import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
27  
28  import javax.faces.application.Application;
29  import javax.faces.component.UIComponent;
30  import javax.faces.component.UINamingContainer;
31  import javax.faces.context.FacesContext;
32  import java.io.IOException;
33  
34  /**
35   * @JSFRenderer
36   *   renderKitId = "HTML_BASIC" 
37   *   family = "javax.faces.Output"
38   *   type = "org.apache.myfaces.JsValueChangeListener"
39   * 
40   * @author Martin Marinschek (latest modification by $Author: skitching $)
41   * @version $Revision: 673833 $ $Date: 2008-07-03 16:58:05 -0500 (Thu, 03 Jul 2008) $
42   */
43  public class JsValueChangeListenerRenderer
44          extends HtmlRenderer
45  {
46      private static Log log = LogFactory.getLog(JsValueChangeListenerRenderer.class);
47  
48      public void encodeEnd(FacesContext facesContext, UIComponent component)
49              throws IOException
50      {
51          RendererUtils.checkParamValidity(facesContext, component, JsValueChangeListener.class);
52  
53          UIComponent parent = component.getParent();
54  
55          JsValueChangeListener jsValueChangeListener = (JsValueChangeListener) component;
56  
57  
58          String aFor = jsValueChangeListener.getFor();
59          String expressionValue = jsValueChangeListener.getExpressionValue();
60          String property = jsValueChangeListener.getProperty();
61  
62          AddResourceFactory.getInstance(facesContext).addJavaScriptAtPosition(
63                  facesContext, AddResource.HEADER_BEGIN, JsValueChangeListenerRenderer.class,
64                  "JSListener.js");
65  
66          if(aFor!=null)
67          {
68              UIComponent forComponent = component.findComponent(aFor);
69  
70              String forComponentId = null;
71  
72              if (forComponent == null)
73              {
74                  if (log.isInfoEnabled())
75                  {
76                      log.info("Unable to find component '" + aFor + "' (calling findComponent on component '" + component.getClientId(getFacesContext()) + "') - will try to render component id based on the parent-id (on same level)");
77                  }
78                  if (aFor.length() > 0 && aFor.charAt(0) == UINamingContainer.SEPARATOR_CHAR)
79                  {
80                      //absolute id path
81                      forComponentId = aFor.substring(1);
82                  }
83                  else
84                  {
85                      //relative id path, we assume a component on the same level as the label component
86                      String labelClientId = component.getClientId(getFacesContext());
87                      int colon = labelClientId.lastIndexOf(UINamingContainer.SEPARATOR_CHAR);
88                      if (colon == -1)
89                      {
90                          forComponentId = aFor;
91                      }
92                      else
93                      {
94                          forComponentId = labelClientId.substring(0, colon + 1) + aFor;
95                      }
96                  }
97              }
98              else
99              {
100                 forComponentId = forComponent.getClientId(getFacesContext());
101             }
102 
103             expressionValue = expressionValue.replaceAll("\\'","\\\\'");
104             expressionValue = expressionValue.replaceAll("\"","\\\"");
105 
106 
107             String methodCall = "orgApacheMyfacesJsListenerSetExpressionProperty('"+
108                     parent.getClientId(getFacesContext())+"','"+
109                     forComponentId+"',"+
110                     (property==null?"null":"'"+property+"'")+
111                     ",'"+expressionValue+"');";
112 
113 
114             callMethod(facesContext, jsValueChangeListener, "onchange",methodCall);
115 
116             if (jsValueChangeListener.getBodyTagEvent() != null)
117             {
118                 callMethod(facesContext, jsValueChangeListener, jsValueChangeListener.getBodyTagEvent(), methodCall);
119             }
120 
121         }
122     }
123 
124     private void callMethod(FacesContext context, JsValueChangeListener jsValueChangeListener, String propName, String value)
125     {
126         UIComponent parent = jsValueChangeListener.getParent();
127 
128         Object oldValue = parent.getAttributes().get(propName);
129         
130         if(oldValue != null)
131         {
132             String oldValueStr = oldValue.toString().trim();
133 
134             // render the jsValueChangeListener script only for each parent component 
135             if(oldValueStr.indexOf(parent.getClientId(FacesContext.getCurrentInstance())) < 0
136                     && oldValueStr.length() > 0)
137             {
138                 oldValueStr = "";
139             }
140 
141             if(oldValueStr.length()>0 && !oldValueStr.endsWith(";"))
142                 oldValueStr +=";";
143 
144             value = oldValueStr + value;
145 
146         }
147 
148         if (!propName.equals("onchange") && value != null)
149         {
150             //TODO: this should be refactored to register a javascript-event-wrapper the java-script way
151             //in the current version of AddResource, this would not work anymore
152             /*AddResourceFactory.getInstance(context).
153                     addJavaScriptToBodyTag(context,jsValueChangeListener.getBodyTagEvent(), value);*/
154         }
155         else if(value != null)
156         {
157             parent.getAttributes().put(propName, value);
158         }
159         else
160         {
161             try
162             {
163                 parent.getAttributes().remove(propName);
164             }
165             catch(Exception ex)
166             {
167                 log.error("the value could not be removed : ",ex);
168             }
169         }
170     }
171 
172 
173     protected Application getApplication()
174     {
175         return getFacesContext().getApplication();
176     }
177 
178     protected FacesContext getFacesContext()
179     {
180         return FacesContext.getCurrentInstance();
181     }
182 
183 }