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.util.Iterator;
23  import java.util.List;
24  import java.util.Map;
25  
26  import javax.faces.component.UIComponent;
27  import javax.faces.component.UIOutput;
28  import javax.faces.component.behavior.ClientBehavior;
29  import javax.faces.context.FacesContext;
30  import javax.faces.context.ResponseWriter;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.apache.myfaces.component.UserRoleUtils;
35  import org.apache.myfaces.renderkit.html.ext.HtmlLinkRenderer;
36  import org.apache.myfaces.shared_tomahawk.renderkit.ClientBehaviorEvents;
37  import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
38  import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
39  import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils;
40  
41  /**
42   * Renderer for component HtmlAjaxChildComboBox
43   * 
44   * 
45   * @JSFRenderer
46   *   renderKitId = "HTML_BASIC" 
47   *   family = "javax.faces.Output"
48   *   type = "org.apache.myfaces.ToggleLink"
49   * 
50   * @author Sharath Reddy
51   */
52  public class ToggleLinkRenderer extends HtmlLinkRenderer {
53      public static final int DEFAULT_MAX_SUGGESTED_ITEMS = 200;
54  
55      protected void renderOutputLinkStart(FacesContext facesContext,
56              UIOutput output) throws IOException
57      {
58          ResponseWriter writer = facesContext.getResponseWriter();
59      
60          String clientId = output.getClientId(facesContext);
61          
62          ToggleLink toggleLink = (ToggleLink) output;
63  
64          //write anchor
65          writer.startElement(HTML.ANCHOR_ELEM, output);
66          writer.writeAttribute(HTML.ID_ATTR, clientId, null);
67          writer.writeAttribute(HTML.NAME_ATTR, clientId, null);
68          writer.writeURIAttribute(HTML.HREF_ATTR, "javascript:void(0);", null);
69  
70          Map<String, List<ClientBehavior>> behaviors = toggleLink.getClientBehaviors();        
71          if (behaviors != null && !behaviors.isEmpty())
72          {
73              HtmlRendererUtils.renderBehaviorizedEventHandlersWithoutOnclick(facesContext, writer, output, behaviors);
74              HtmlRendererUtils.renderBehaviorizedFieldEventHandlersWithoutOnchangeAndOnselect(facesContext, writer, output, behaviors);
75              HtmlRendererUtils
76                      .renderHTMLAttributes(
77                              writer,
78                              output,
79                              HTML.ANCHOR_PASSTHROUGH_ATTRIBUTES_WITHOUT_STYLE_AND_EVENTS);
80              HtmlRendererUtils.renderBehaviorizedAttribute(facesContext, writer, HTML.ONCLICK_ATTR, output,
81                      ClientBehaviorEvents.CLICK, null, behaviors, HTML.ONCLICK_ATTR, null, buildOnclickToggleFunction(facesContext,output));
82          }
83          else
84          {
85              HtmlRendererUtils
86                      .renderHTMLAttributes(
87                              writer,
88                              output,
89                              HTML.ANCHOR_PASSTHROUGH_ATTRIBUTES_WITHOUT_ONCLICK_WITHOUT_STYLE);
90              HtmlRendererUtils.renderHTMLAttribute(writer, HTML.ONCLICK_ATTR, HTML.ONCLICK_ATTR, 
91                      buildOnclickToggleFunction(facesContext,output));
92          }
93  
94          HtmlRendererUtils.renderHTMLAttribute(writer, HTML.STYLE_ATTR, HTML.STYLE_ATTR,
95                  output.getAttributes().get(HTML.STYLE_ATTR));
96          HtmlRendererUtils.renderHTMLAttribute(writer, HTML.STYLE_CLASS_ATTR, HTML.STYLE_CLASS_ATTR,
97                  output.getAttributes().get(HTML.STYLE_CLASS_ATTR));
98          
99          writer.flush();
100     }
101     
102     protected void renderOutputLinkEnd(FacesContext facesContext, UIComponent component)
103         throws IOException
104     {
105         ResponseWriter writer = facesContext.getResponseWriter();
106         // force separate end tag
107         writer.writeText("", null);
108         writer.endElement(HTML.ANCHOR_ELEM);
109     }
110     
111     private String buildOnclickToggleFunction(FacesContext facesContext,
112             UIOutput output) throws IOException
113     {
114         ToggleLink toggleLink = (ToggleLink) output;
115         TogglePanel togglePanel = getParentTogglePanel(facesContext, toggleLink);
116         String[] componentsToToggle = toggleLink.getFor().split(",");
117         String idsToHide = getIdsToHide(facesContext, togglePanel);
118         StringBuffer idsToShow = new StringBuffer();
119         for (int i = 0; i < componentsToToggle.length; i++) {
120             String componentId = componentsToToggle[i].trim();
121             UIComponent componentToShow = toggleLink.findComponent(componentId);
122             if (componentToShow == null) {
123                 Log log = LogFactory.getLog(ToggleLinkRenderer.class);
124                 log.error("Unable to find component with id " + componentId);
125                 continue;
126             }
127             if( idsToShow.length() > 0 )
128                 idsToShow.append( ',' );
129             idsToShow.append( componentToShow.getClientId(facesContext) );
130         }
131         
132         String outputOnclick = toggleLink.getOnclick();
133         StringBuffer onClick = new StringBuffer();
134         if(outputOnclick != null)
135         {
136             onClick.append("var cf = function(){");
137             onClick.append(outputOnclick);
138             onClick.append('}');
139             onClick.append(';');
140             onClick.append("var oamSF = function(){");            
141         }
142 
143         String onClickFocusClientId = toggleLink.getOnClickFocusId() != null ? toggleLink.findComponent(toggleLink.getOnClickFocusId()).getClientId(facesContext) : "";
144         onClick.append(getToggleJavascriptFunctionName(facesContext, toggleLink) + "('"+idsToShow+"','" + idsToHide + "','" + getHiddenFieldId(facesContext, togglePanel) + "','" + onClickFocusClientId + "');");
145                 
146         if (outputOnclick != null)
147         {
148             onClick.append('}');
149             onClick.append(';');
150             onClick.append("return (cf()==false)? false : oamSF();");        
151         }        
152 
153         return onClick.toString();
154     }
155             
156     public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
157         RendererUtils.checkParamValidity(context, component, ToggleLink.class);
158 
159         ToggleLink toggleLink = (ToggleLink) component;
160         if(isDisabled(context, toggleLink))
161             return;
162 
163         super.encodeEnd(context, component);
164     }
165 
166     public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
167         RendererUtils.checkParamValidity(context, component, ToggleLink.class);
168 
169         ToggleLink toggleLink = (ToggleLink) component;
170         if(isDisabled(context, toggleLink))
171             return;
172 
173 
174         super.encodeBegin(context, component);
175     }
176     
177     private String getToggleJavascriptFunctionName(FacesContext context,ToggleLink toggleLink){
178         for(UIComponent component = toggleLink.getParent(); component != null; component = component.getParent())
179             if( component instanceof TogglePanel )
180                 return TogglePanelRenderer.getToggleJavascriptFunctionName( context, (TogglePanel)component );
181 
182         Log log = LogFactory.getLog(ToggleLinkRenderer.class);
183         log.error("The ToggleLink component with id " + toggleLink.getClientId( context )+" isn't enclosed in a togglePanel.");
184         return null;
185     }
186     
187     private String getIdsToHide(FacesContext facesContext, TogglePanel togglePanel) {
188          StringBuffer idsToHide = new StringBuffer();
189          int idsToHideCount = 0;
190          for(Iterator it = togglePanel.getChildren().iterator(); it.hasNext(); ) {
191              UIComponent component = (UIComponent) it.next();
192              if ( TogglePanelRenderer.isHiddenWhenToggled( component ) ) {
193                  if( idsToHideCount > 0 )
194                      idsToHide.append( ',' );
195                  
196                  idsToHide.append( component.getClientId( facesContext ) );
197                  idsToHideCount++;
198              }
199          }
200          
201          return idsToHide.toString();
202     }
203     
204     private TogglePanel getParentTogglePanel(FacesContext facesContext, ToggleLink toggleLink) {
205          for(UIComponent component = toggleLink.getParent(); component != null; component = component.getParent()) {
206              if( component instanceof TogglePanel )
207                  return (TogglePanel) component;
208          }
209          
210          return null;
211     }
212     
213     private String getHiddenFieldId(FacesContext context, TogglePanel togglePanel){
214         return togglePanel.getClientId(context) + "_hidden";
215     }
216     
217     private boolean isDisabled(FacesContext facesContext, ToggleLink link) {
218         TogglePanel panel = getParentTogglePanel(facesContext, link);
219 
220         return panel.isDisabled() || link.isDisabled() || !UserRoleUtils.isEnabledOnUserRole(link);
221     }
222 }