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.toggle;
20  
21  import java.io.IOException;
22  import java.lang.reflect.Method;
23  import java.util.Iterator;
24  import java.util.List;
25  
26  import javax.faces.component.UIComponent;
27  import javax.faces.context.FacesContext;
28  import javax.faces.context.ResponseWriter;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.myfaces.renderkit.html.util.AddResource;
33  import org.apache.myfaces.renderkit.html.util.AddResourceFactory;
34  import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
35  import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
36  import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlGroupRendererBase;
37  
38  /**
39   * 
40   * @JSFRenderer
41   *   renderKitId = "HTML_BASIC" 
42   *   family = "javax.faces.Panel"
43   *   type = "org.apache.myfaces.TogglePanel"
44   * 
45   */
46  public class TogglePanelRenderer extends HtmlGroupRendererBase {
47  
48      private static Log log = LogFactory.getLog(TogglePanelRenderer.class);
49  
50      public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
51          RendererUtils.checkParamValidity(context, component, TogglePanel.class);
52          addToggleLinkJavascript(context);
53          
54          TogglePanel togglePanel = (TogglePanel) component;
55          boolean toggleMode = togglePanel.isToggled();
56          toggleVisibility(togglePanel.getChildren(), toggleMode);
57          
58          // render the hidden input field
59          ResponseWriter writer = context.getResponseWriter();
60  
61          String hiddenFieldId = getHiddenFieldId(context, togglePanel);
62  
63          writer.startElement(HTML.INPUT_ELEM, component);
64          writer.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_HIDDEN, null);
65          writer.writeAttribute(HTML.ID_ATTR, hiddenFieldId, null);
66          writer.writeAttribute(HTML.NAME_ATTR, hiddenFieldId, null);
67  
68          writer.writeAttribute(HTML.VALUE_ATTR, toggleMode ? "1" : "", null);
69  
70          writer.endElement(HTML.INPUT_ELEM);
71  
72          super.encodeEnd(context, togglePanel);
73      }
74  
75      private void toggleVisibility(List children, boolean toggleMode) {
76          for(Iterator it = children.iterator(); it.hasNext(); ) {
77              UIComponent component = (UIComponent) it.next();
78              setComponentVisibility( component, toggleMode );
79          }
80      }
81  
82      // checks if this component has getStyle/setStyle methods
83      public static boolean hasStyleAttribute(UIComponent component) {
84          Method[] methods = component.getClass().getMethods();
85  
86          for (int i = 0; i < methods.length; i++) {
87              Method method = methods[i];
88              if (method.getName().equals("getStyle")) {
89                  return true;
90              }
91          }
92          return false;
93      }
94  
95      // hides component by appending 'display:none' to the 'style' attribute
96      public static void setComponentVisibility(UIComponent component, boolean toggleMode) {
97          FacesContext context = FacesContext.getCurrentInstance();
98  
99          if (!hasStyleAttribute(component)) {
100             log.info("style attribute expected, not found for component " + component.getClientId(context));
101             return;
102         }
103 
104         try {
105             Class c = component.getClass();
106             Method getStyle = c.getMethod("getStyle", new Class[] {});
107             Method setStyle = c.getMethod("setStyle", new Class[] { String.class });
108 
109             String style = (String) getStyle.invoke(component, new Object[] {});
110             
111             boolean display = toggleMode != isHiddenWhenToggled(component);
112             if( display ){
113                 if (style == null || style.length() == 0) {
114                     return;
115                 } else {
116                     int index = style.indexOf(";display:none;");
117                     if (index == -1)
118                         return;
119 
120                     if (index == 0) {
121                         style = null;
122                     } else {
123                         style = style.substring(0, index);
124                     }
125                 }
126             }else{ // hide
127                 if (style == null) {
128                     style = ";display:none;";
129                 } else if (style.indexOf("display:none;") == -1) {
130                     style = style.concat(";display:none;");
131                 }
132             }
133 
134             setStyle.invoke(component, new Object[] { style });
135         } catch (Throwable e) {
136             log.error("unable to set style attribute on component " + component.getClientId(context));
137         }
138     }
139 
140     public static boolean isHiddenWhenToggled(UIComponent component){
141         return component instanceof ToggleLink || component instanceof ToggleGroup;
142     }
143 
144     private String getHiddenFieldId(FacesContext context, TogglePanel togglePanel){
145         return togglePanel.getClientId(context) + "_hidden";
146     }
147 
148     static public String getToggleJavascriptFunctionName(FacesContext context, TogglePanel togglePanel) {
149         return "MyFacesToggleLinkUtils.toggle";
150     }
151     
152     public void addToggleLinkJavascript(FacesContext context)throws IOException {
153         AddResource addResource = AddResourceFactory.getInstance(context);
154         
155         addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN, AbstractTogglePanel.class, "MyFacesToggleLink.js");
156     }
157 }