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.renderkit.html.ext;
20  
21  import java.io.IOException;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.logging.Level;
25  import java.util.logging.Logger;
26  
27  import javax.faces.component.UIComponent;
28  import javax.faces.component.UIInput;
29  import javax.faces.component.UIOutput;
30  import javax.faces.component.UIViewRoot;
31  import javax.faces.component.behavior.ClientBehavior;
32  import javax.faces.component.behavior.ClientBehaviorHolder;
33  import javax.faces.component.html.HtmlOutputText;
34  import javax.faces.context.FacesContext;
35  import javax.faces.context.ResponseWriter;
36  
37  import org.apache.myfaces.component.UserRoleUtils;
38  import org.apache.myfaces.component.html.ext.HtmlInputText;
39  import org.apache.myfaces.shared_tomahawk.component.EscapeCapable;
40  import org.apache.myfaces.shared_tomahawk.renderkit.JSFAttr;
41  import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
42  import org.apache.myfaces.shared_tomahawk.renderkit.html.CommonEventUtils;
43  import org.apache.myfaces.shared_tomahawk.renderkit.html.CommonPropertyConstants;
44  import org.apache.myfaces.shared_tomahawk.renderkit.html.CommonPropertyUtils;
45  import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
46  import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils;
47  import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlTextRendererBase;
48  import org.apache.myfaces.shared_tomahawk.renderkit.html.util.JavascriptUtils;
49  
50  
51  /**
52   * @JSFRenderer
53   *   renderKitId = "HTML_BASIC"
54   *   family = "javax.faces.Input"
55   *   type = "org.apache.myfaces.Text"
56   *   
57   * @JSFRenderer
58   *   renderKitId = "HTML_BASIC"
59   *   family = "javax.faces.Output"
60   *   type = "org.apache.myfaces.Text"
61   * 
62   * @author Manfred Geiler (latest modification by $Author: lu4242 $)
63   * @version $Revision: 659874 $ $Date: 2008-05-24 15:59:15 -0500 (sáb, 24 may 2008) $
64   */
65  public class HtmlTextRenderer
66          extends HtmlTextRendererBase
67  {
68      private static final String ONCHANGE_PREFIX = "onChange_";
69      private static final String HIDDEN_SUFFIX   = "_hidden";
70       
71      //private static final Log log = LogFactory.getLog(HtmlTextRenderer.class);
72      private static final Logger log = Logger.getLogger(HtmlTextRenderer.class.getName());
73      
74      @Override
75      protected boolean isCommonPropertiesOptimizationEnabled(FacesContext facesContext)
76      {
77          return true;
78      }
79  
80      @Override
81      protected boolean isCommonEventsOptimizationEnabled(FacesContext facesContext)
82      {
83          return true;
84      }
85  
86      protected boolean isDisabled(FacesContext facesContext, UIComponent uiComponent)
87      {
88          if (!UserRoleUtils.isEnabledOnUserRole(uiComponent))
89          {
90              return true;
91          }
92          else
93          {
94              return super.isDisabled(facesContext, uiComponent);
95          }
96      }
97      /**
98       *
99       */
100     protected boolean isDisabledOnClientSide(FacesContext facesContext, UIComponent component)
101     {
102         if (component instanceof HtmlInputText)
103         {
104             return ((HtmlInputText)component).isDisabledOnClientSide();
105         }
106         
107         return false;
108     }      
109 
110     public void encodeEnd(FacesContext facesContext, UIComponent component)
111         throws IOException
112     {
113         if (HtmlRendererUtils.isDisplayValueOnly(component))
114         {
115             renderInputValueOnly(facesContext, component);
116         }
117         else
118         {
119             renderNormal(facesContext, component);
120         }
121     }
122     
123     @Override
124     protected void renderOutput(FacesContext facesContext, UIComponent component)
125         throws IOException
126     {
127         String text = org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils.getStringValue(facesContext, component);
128         if (log.isLoggable(Level.FINE)) log.fine("renderOutput '" + text + "'");
129         boolean escape;
130         if (component instanceof HtmlOutputText || component instanceof EscapeCapable)
131         {
132             escape = ((HtmlOutputText)component).isEscape();
133         }
134         else
135         {
136             escape = RendererUtils.getBooleanAttribute(component, org.apache.myfaces.shared_tomahawk.renderkit.JSFAttr.ESCAPE_ATTR,
137                                                        true); //default is to escape
138         }
139 
140         if (text != null)
141         {
142             ResponseWriter writer = facesContext.getResponseWriter();
143             boolean span = false;
144 
145             Map<String, List<ClientBehavior>> behaviors = null;
146             if (component instanceof ClientBehaviorHolder)
147             {
148                 behaviors = ((ClientBehaviorHolder) component).getClientBehaviors();
149             }
150             
151             if (behaviors != null && !behaviors.isEmpty())
152             {
153                 span = true;
154                 writer.startElement(HTML.SPAN_ELEM, component);
155                 writer.writeAttribute(HTML.ID_ATTR, component.getClientId(facesContext),null);
156                 if (isCommonPropertiesOptimizationEnabled(facesContext))
157                 {
158                     long commonPropertiesMarked = CommonPropertyUtils.getCommonPropertiesMarked(component);
159                     
160                     CommonPropertyUtils.renderUniversalProperties(writer, commonPropertiesMarked, component);
161                     CommonPropertyUtils.renderStyleProperties(writer, commonPropertiesMarked, component);
162 
163                     if (isCommonEventsOptimizationEnabled(facesContext))
164                     {
165                         Long commonEventsMarked = CommonEventUtils.getCommonEventsMarked(component);
166                         CommonEventUtils.renderBehaviorizedEventHandlers(facesContext, writer, 
167                                 commonPropertiesMarked, commonEventsMarked, component, behaviors);
168                     }
169                     else
170                     {
171                         HtmlRendererUtils.renderBehaviorizedEventHandlers(facesContext, writer, component, behaviors);
172                     }
173                 }
174                 else
175                 {
176                     HtmlRendererUtils.renderHTMLAttributes(writer, component, HTML.UNIVERSAL_ATTRIBUTES);
177                     HtmlRendererUtils.renderBehaviorizedEventHandlers(facesContext, writer, component, behaviors);
178                 }
179             }
180             else
181             {
182                 if (isCommonPropertiesOptimizationEnabled(facesContext))
183                 {
184                     long commonPropertiesMarked = CommonPropertyUtils.getCommonPropertiesMarked(component);
185                     if ( (commonPropertiesMarked & ~(CommonPropertyConstants.ESCAPE_PROP)) > 0)
186                     {
187                         span = true;
188                         writer.startElement(HTML.SPAN_ELEM, component);
189                         HtmlRendererUtils.writeIdIfNecessary(writer, component, facesContext);
190                     }
191                     else if (CommonPropertyUtils.isIdRenderingNecessary(component))
192                     {
193                         span = true;
194                         writer.startElement(HTML.SPAN_ELEM, component);
195                         writer.writeAttribute(HTML.ID_ATTR, component.getClientId(facesContext), null);
196                     }
197                     
198                     CommonPropertyUtils.renderUniversalProperties(writer, commonPropertiesMarked, component);
199                     CommonPropertyUtils.renderStyleProperties(writer, commonPropertiesMarked, component);
200                     
201                     if (isRenderOutputEventAttributes())
202                     {
203                         HtmlRendererUtils.renderHTMLAttributes(writer, component, HTML.EVENT_HANDLER_ATTRIBUTES);
204                     }
205                 }
206                 else
207                 {
208                     if(component.getId()!=null && !component.getId().startsWith(UIViewRoot.UNIQUE_ID_PREFIX))
209                     {
210                         span = true;
211         
212                         writer.startElement(HTML.SPAN_ELEM, component);
213         
214                         HtmlRendererUtils.writeIdIfNecessary(writer, component, facesContext);
215         
216                         HtmlRendererUtils.renderHTMLAttributes(writer, component, HTML.COMMON_PASSTROUGH_ATTRIBUTES);
217         
218                     }
219                     else
220                     {
221                         span = HtmlRendererUtils.renderHTMLAttributesWithOptionalStartElement(writer,component,
222                                 HTML.SPAN_ELEM,HTML.COMMON_PASSTROUGH_ATTRIBUTES);
223                     }
224                 }
225             }
226 
227             if (escape)
228             {
229                 Logger log = Logger.getLogger(HtmlTextRendererBase.class.getName());
230                 if (log.isLoggable(Level.FINE)) log.fine("renderOutputText writing '" + text + "'");
231                 writer.writeText(text, org.apache.myfaces.shared_tomahawk.renderkit.JSFAttr.VALUE_ATTR);
232             }
233             else
234             {
235                 writer.write(text);
236             }
237 
238             if(span)
239             {
240                 writer.endElement(org.apache.myfaces.shared_tomahawk.renderkit.html.HTML.SPAN_ELEM);
241             }
242         }
243     }
244     
245     @Override
246     protected void renderInput(FacesContext facesContext, UIComponent component) throws IOException 
247     {
248         if (!isDisabledOnClientSide(facesContext, component) || isDisabled(facesContext, component))
249         {
250             super.renderInput(facesContext, component);
251             return;
252         }               
253         
254         //render the input component as if it was disabled
255         ResponseWriter writer = facesContext.getResponseWriter();
256 
257         String clientId = component.getClientId(facesContext);
258         String value = RendererUtils.getStringValue(facesContext, component);
259 
260         writer.startElement(HTML.INPUT_ELEM, component);
261         writer.writeAttribute(HTML.ID_ATTR, clientId, null);
262         writer.writeAttribute(HTML.NAME_ATTR, clientId, null);
263         writer.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_TEXT, null);
264         if (value != null)
265         {
266             writer.writeAttribute(HTML.VALUE_ATTR, value, JSFAttr.VALUE_ATTR);
267         }
268 
269         HtmlRendererUtils.renderHTMLAttributes(writer, component, HTML.INPUT_PASSTHROUGH_ATTRIBUTES_WITHOUT_DISABLED);
270         //render as disabled on the client side
271         writer.writeAttribute(HTML.DISABLED_ATTR, Boolean.TRUE, null);
272         //render the JS function that will change the hidden input field's value when his changes        
273         writer.writeAttribute(HTML.ONCHANGE_ATTR, getOnChangeFunctionName(clientId)+"();", null);
274         
275         writer.endElement(HTML.INPUT_ELEM);
276         
277         //render the hidden input field that will hold this component's value
278         renderHiddenInput(facesContext, (UIInput)component);
279     }    
280     /**
281      *
282      */
283     protected void renderHiddenInput(FacesContext facesContext, UIComponent component) throws IOException
284     {
285         ResponseWriter writer = facesContext.getResponseWriter();
286         
287         String disabledInputClientId = component.getClientId(facesContext);
288         
289         HtmlRendererUtils.writePrettyLineSeparator(facesContext);
290         
291         writer.startElement(HTML.SCRIPT_ELEM, null);
292         writer.writeAttribute(HTML.SCRIPT_TYPE_ATTR, HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT, null);                        
293         writer.writeText(createOnChangeListenerJS(disabledInputClientId), null);        
294         writer.endElement(HTML.SCRIPT_ELEM);
295         
296         HtmlRendererUtils.writePrettyLineSeparator(facesContext);  
297         
298         writer.startElement(HTML.INPUT_ELEM, null);
299         writer.writeAttribute(HTML.ID_ATTR, disabledInputClientId + HIDDEN_SUFFIX, null);
300         writer.writeAttribute(HTML.NAME_ATTR, disabledInputClientId + HIDDEN_SUFFIX, null);
301         writer.writeAttribute(HTML.VALUE_ATTR, RendererUtils.getStringValue(facesContext, component), null);
302         writer.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_HIDDEN, null);        
303         writer.endElement(HTML.INPUT_ELEM);
304         
305         HtmlRendererUtils.writePrettyLineSeparator(facesContext);       
306     }
307 
308     protected void renderInputValueOnly(FacesContext facesContext, UIComponent component)
309         throws IOException
310     {
311             HtmlRendererUtils.renderDisplayValueOnly(facesContext,
312                                                      (UIInput) component);
313     }
314 
315     protected void renderNormal(FacesContext facesContext, UIComponent component)
316         throws IOException
317     {
318             super.encodeEnd(facesContext, component);
319     }    
320     
321     /**
322      *
323      */ 
324     protected String getOnChangeFunctionName(String inputDisabledClientId)
325     {
326         StringBuffer buf = new StringBuffer();
327         buf.append(ONCHANGE_PREFIX);
328         buf.append(JavascriptUtils.getValidJavascriptName(inputDisabledClientId, true));
329         
330         return buf.toString();
331     }     
332     /**
333      *
334      */
335     protected String createOnChangeListenerJS(String inputDisabledClientId)
336     {
337         StringBuffer script = new StringBuffer();
338         script.append("function ");
339         script.append(getOnChangeFunctionName(inputDisabledClientId));            
340         script.append("() {\n");                
341         script.append("var hiddenInput = document.getElementById(\"").append(inputDisabledClientId + HIDDEN_SUFFIX).append("\");\n");
342         script.append("var disabledInput = document.getElementById(\"").append(inputDisabledClientId).append("\");\n");
343         script.append("hiddenInput.value=disabledInput.value;\n");        
344         script.append("}\n");        
345         
346         return script.toString();
347     }
348 
349     public void decode(FacesContext facesContext, UIComponent component) 
350     {        
351         if (isDisabledOnClientSide(facesContext, component) && !isDisabled(facesContext, component))
352         {            
353             //in this case we don't need to check the request parameters validity, 
354             //the submitted value comes from the hidden input field
355             Map paramValuesMap = facesContext.getExternalContext().getRequestParameterMap();            
356             Object reqValue = paramValuesMap.get(component.getClientId(facesContext) + HIDDEN_SUFFIX);  
357                        
358             ((UIInput)component).setSubmittedValue(reqValue); 
359             return;
360         }
361         
362         if (!(component instanceof UIInput) && (component instanceof UIOutput))
363         {
364             HtmlRendererUtils.decodeClientBehaviors(facesContext, component);
365         }
366         super.decode(facesContext, component);        
367     }
368 }