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