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.ajaxchildcombobox;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.myfaces.custom.ajax.api.AjaxRenderer;
24  import org.apache.myfaces.custom.dojo.DojoConfig;
25  import org.apache.myfaces.custom.dojo.DojoUtils;
26  import org.apache.myfaces.renderkit.html.ext.HtmlMenuRenderer;
27  import org.apache.myfaces.renderkit.html.util.AddResource;
28  import org.apache.myfaces.renderkit.html.util.AddResourceFactory;
29  import org.apache.myfaces.shared_tomahawk.renderkit.JSFAttr;
30  import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
31  import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
32  import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils;
33  
34  import javax.faces.component.UIComponent;
35  import javax.faces.component.UINamingContainer;
36  import javax.faces.context.FacesContext;
37  import javax.faces.context.ResponseWriter;
38  import javax.faces.el.MethodBinding;
39  import javax.faces.model.SelectItem;
40  import javax.servlet.ServletResponse;
41  import java.io.IOException;
42  import java.io.PrintWriter;
43  
44  /**
45   * Renderer for component HtmlAjaxChildComboBox
46   * 
47   * @JSFRenderer
48   *   renderKitId = "HTML_BASIC" 
49   *   family = "javax.faces.SelectOne"
50   *   type = "org.apache.myfaces.AjaxChildComboBox"
51   *
52   * @author Sharath Reddy
53   */
54  public class HtmlAjaxChildComboBoxRenderer extends HtmlMenuRenderer implements AjaxRenderer
55  {
56      private static final String BEGIN_OPTION = "<option>";
57      private static final String END_OPTION = "</option>";
58      private static final String BEGIN_OPTION_TEXT = "<optionText>";
59      private static final String END_OPTION_TEXT = "</optionText>";
60      private static final String BEGIN_OPTION_VALUE = "<optionValue>";
61      private static final String END_OPTION_VALUE = "</optionValue>";
62  
63      public static final int DEFAULT_MAX_SUGGESTED_ITEMS = 200;
64  
65      private static Log log = LogFactory.getLog(HtmlAjaxChildComboBoxRenderer.class);
66  
67      // Adds the javascript files needed by Dojo and the custom javascript for
68      // this
69      // component
70      private void encodeJavascript(FacesContext context, UIComponent component)
71          throws IOException
72      {
73          String javascriptLocation = (String) component.getAttributes().get(JSFAttr.JAVASCRIPT_LOCATION);
74          DojoUtils.addMainInclude(context, component, javascriptLocation, new DojoConfig());
75          DojoUtils.addRequire(context, component, "dojo.event.*");
76          // not required - and results in an error
77          // DojoUtils.addRequire(context, component, "dojo.io.bind");
78  
79          AddResource addResource = AddResourceFactory.getInstance(context);
80  
81          addResource.addJavaScriptAtPosition(context,
82              AddResource.HEADER_BEGIN, AjaxChildComboBox.class, "javascript/ajaxChildComboBox.js");
83      }
84  
85      public void encodeEnd(FacesContext context, UIComponent component) throws IOException
86      {
87          RendererUtils.checkParamValidity(context, component, AjaxChildComboBox.class);
88  
89          AjaxChildComboBox childComboBox = (AjaxChildComboBox) component;
90  
91          super.encodeEnd(context, component);
92  
93          String clientId = component.getClientId(context);
94  
95          UIComponent parentComboBox = this.getParentComboBox(childComboBox);
96          if (parentComboBox == null)
97          {
98              log.error("Could not find parent combo box for AjaxChildComboBox " +
99                  childComboBox.getClientId(context));
100             return;
101         }
102 
103         encodeJavascript(context, component);
104 
105         ResponseWriter writer = context.getResponseWriter();
106 
107         // Begin: Write out the javascript that hooks up this component with the
108         // parent combo-box
109         writer.startElement(HTML.SCRIPT_ELEM, component);
110         writer.writeAttribute(HTML.SCRIPT_TYPE_ATTR, HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT, null);
111 
112         writer.write("var parentCombo = document.getElementById('" +
113             parentComboBox.getClientId(context) + "');");
114         HtmlRendererUtils.writePrettyLineSeparator(context);
115         writer.write("dojo.event.connect(parentCombo, 'onchange', function(evt) { ");
116         HtmlRendererUtils.writePrettyLineSeparator(context);
117         writer.write("var targetElement = evt.target;");
118         writer.write("var targetValue = targetElement.options[targetElement.selectedIndex].value;");
119         HtmlRendererUtils.writePrettyLineSeparator(context);
120         writer.write("reloadChildComboBox('" + clientId + "', targetValue);");
121         HtmlRendererUtils.writePrettyLineSeparator(context);
122         writer.write("});");
123         writer.endElement(HTML.SCRIPT_ELEM);
124         // End: Javascript
125     }
126 
127 
128     // creates the XML response that is sent back to the browser
129     public void encodeAjax(FacesContext context, UIComponent uiComponent)
130         throws IOException
131     {
132 
133         String parentValue = (String) context.getExternalContext().
134             getRequestParameterMap().get("parentValue");
135 
136         ServletResponse response = (ServletResponse) context.getExternalContext().getResponse();
137         PrintWriter writer = response.getWriter();
138 
139         StringBuffer xml = new StringBuffer();
140 
141         MethodBinding mb = ((AjaxChildComboBox) uiComponent).getAjaxSelectItemsMethod();
142         SelectItem[] options = (SelectItem[])
143             mb.invoke(context, new Object[]{parentValue});
144 
145         xml.append("<?xml version=\"1.0\"?>\n");
146         xml.append("<response>\n");
147         for (int i = 0; i < options.length; i++)
148         {
149             xml.append(BEGIN_OPTION);
150             xml.append(BEGIN_OPTION_TEXT).append(options[i].getLabel()).append(END_OPTION_TEXT);
151             xml.append(BEGIN_OPTION_VALUE).append(options[i].getValue()).append(END_OPTION_VALUE);
152             xml.append(END_OPTION);
153         }
154         xml.append("</response>");
155 
156         writer.write(xml.toString());
157 
158     }
159 
160     private UIComponent getParentComboBox(AjaxChildComboBox comboBox)
161     {
162         String parentId = comboBox.getParentComboBox();
163 
164         UIComponent parentComboBox = comboBox.findComponent(parentId);
165         if (parentComboBox != null)
166         {
167             return parentComboBox;
168         }
169 
170         // try searching from the very root of the component tree
171         return comboBox.findComponent(UINamingContainer.SEPARATOR_CHAR + parentId);
172     }
173 }