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.suggestajax.tablesuggestajax;
20  
21  import org.apache.commons.collections.map.HashedMap;
22  import org.apache.myfaces.component.html.ext.UIComponentPerspective;
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.custom.suggestajax.SuggestAjaxRenderer;
27  import org.apache.myfaces.shared_tomahawk.component.ExecuteOnCallback;
28  import org.apache.myfaces.shared_tomahawk.renderkit.JSFAttr;
29  import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
30  import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
31  
32  import javax.faces.component.UIColumn;
33  import javax.faces.component.UIComponent;
34  import javax.faces.component.UIViewRoot;
35  import javax.faces.context.FacesContext;
36  import javax.faces.context.ResponseWriter;
37  import java.io.IOException;
38  import java.util.Collection;
39  import java.util.Iterator;
40  import java.util.Map;
41  
42  /**
43   * 
44   * @JSFRenderer
45   *   renderKitId = "HTML_BASIC" 
46   *   family = "javax.faces.Input"
47   *   type = "org.apache.myfaces.TableSuggestAjax"
48   * 
49   * @author Gerald Muellan
50   *         Date: 25.03.2006
51   *         Time: 17:05:38
52   */
53  public class TableSuggestAjaxRenderer extends SuggestAjaxRenderer implements AjaxRenderer
54  {
55      public static final int DEFAULT_START_REQUEST = 0;
56      public static final int DEFAULT_BETWEEN_KEY_UP = 1000;
57      public static final String DEFAULT_AUTO_COMPLETE = "true";
58      
59     /**
60       * Encodes any stand-alone javascript functions that are needed.
61       * Uses either the extension filter, or a
62       * user-supplied location for the javascript files.
63       *
64       * @param context FacesContext
65       * @param component UIComponent
66       * @throws java.io.IOException
67       */
68      private void encodeJavascript(FacesContext context, UIComponent component) throws IOException
69      {
70  
71          String javascriptLocation = (String)component.getAttributes().get(JSFAttr.JAVASCRIPT_LOCATION);
72  
73          DojoConfig dojoConfig = new DojoConfig();
74          DojoUtils.addMainInclude(context, component, javascriptLocation, dojoConfig);
75          DojoUtils.addRequire(context, component, "extensions.FacesIO");
76          DojoUtils.addRequire(context, component, "extensions.widget.TableSuggest");
77          DojoUtils.addRequire(context, component, "dojo.event.*");
78      }
79  
80      public void encodeEnd(FacesContext context, UIComponent component) throws IOException
81      {
82          RendererUtils.checkParamValidity(context, component, TableSuggestAjax.class);
83  
84          TableSuggestAjax tableSuggestAjax = (TableSuggestAjax) component;
85  
86          encodeJavascript(context,component);
87  
88          //Disables browser auto completion
89          tableSuggestAjax.getAttributes().put("autocomplete","off");
90  
91          String clientId = component.getClientId(context);
92          String actionURL = getActionUrl(context);
93  
94          String charset = (tableSuggestAjax.getCharset() != null ? tableSuggestAjax.getCharset() : "");
95          String ajaxUrl = context.getExternalContext().encodeActionURL(addQueryString(actionURL, "affectedAjaxComponent=" + clientId +
96                  "&charset=" + charset + "&" + clientId + "=%{searchString}"));
97  
98          ResponseWriter out = context.getResponseWriter();
99  
100         String valueToRender = RendererUtils.getStringValue(context,tableSuggestAjax);
101         valueToRender = escapeQuotes(valueToRender);
102 
103         if (getChildren(tableSuggestAjax) != null
104                 && !getChildren(tableSuggestAjax).isEmpty())
105         {
106             StringBuffer divId = new StringBuffer();
107             divId.append(clientId).append(":::div");
108 
109             out.startElement(HTML.DIV_ELEM, component);
110             out.writeAttribute(HTML.ID_ATTR, divId , null);
111             out.endElement(HTML.DIV_ELEM);
112             super.encodeEnd(context, tableSuggestAjax);
113 
114             String tableSuggestComponentVar = DojoUtils.calculateWidgetVarName(divId.toString());
115 
116             Map attributes = new HashedMap();
117             String betweenKeyUp = "";
118             String startRequest = "";
119             String autoComplete = "";
120 
121             //General attributes
122             attributes.put("dataUrl", ajaxUrl);
123             attributes.put("mode", "remote");
124 
125             //BetweenKeyUp
126             if (tableSuggestAjax.getBetweenKeyUp() != null) {
127                 betweenKeyUp = tableSuggestAjax.getBetweenKeyUp().toString();
128             }
129             else {
130                 betweenKeyUp = Integer.toString(DEFAULT_BETWEEN_KEY_UP);
131             }
132             attributes.put("searchDelay", betweenKeyUp);
133 
134             //StartRequest
135             if (tableSuggestAjax.getStartRequest() != null) {
136                 startRequest = tableSuggestAjax.getStartRequest().toString();
137             }
138             else {
139                 startRequest = Integer.toString(DEFAULT_START_REQUEST);
140             }
141             attributes.put("startRequest", startRequest);
142 
143             //Autocomplete
144             if (tableSuggestAjax.getAutocomplete()!=null) {
145                 autoComplete = tableSuggestAjax.getAutocomplete();
146             }
147             else {
148                 autoComplete = DEFAULT_AUTO_COMPLETE;
149             }
150             attributes.put("autoComplete", autoComplete);
151 
152             //PopupId
153             if (tableSuggestAjax.getPopupId() != null) {
154                 attributes.put("popupId", tableSuggestAjax.getPopupId());
155             }
156 
157             //PopupStyleClass
158             if (tableSuggestAjax.getPopupStyleClass() != null) {
159                 attributes.put("popupStyleClass", tableSuggestAjax.getPopupStyleClass());
160             }
161 
162             //TableStyleClass
163             if (tableSuggestAjax.getTableStyleClass() != null) {
164                 attributes.put("tableStyleClass", tableSuggestAjax.getTableStyleClass());
165             }
166 
167             //ComboBoxStyleClass
168             if (tableSuggestAjax.getComboBoxStyleClass() != null) {
169                 attributes.put("comboBoxStyleClass", tableSuggestAjax.getComboBoxStyleClass());
170             }
171 
172             //RowStyleClass
173             if (tableSuggestAjax.getRowStyleClass() != null) {
174                 attributes.put("rowStyleClass", tableSuggestAjax.getRowStyleClass());
175             }
176 
177             //EvenRowStyleClass
178             if (tableSuggestAjax.getEvenRowStyleClass() != null) {
179                 attributes.put("evenRowStyleClass", tableSuggestAjax.getEvenRowStyleClass());
180             }
181 
182             //OddRowStyleClass
183             if (tableSuggestAjax.getOddRowStyleClass() != null) {
184                 attributes.put("oddRowStyleClass", tableSuggestAjax.getOddRowStyleClass());
185             }
186 
187             //HoverRowStyleClass
188             if (tableSuggestAjax.getHoverRowStyleClass() != null) {
189                 attributes.put("hoverRowStyleClass", tableSuggestAjax.getHoverRowStyleClass());
190             }
191 
192             //textInputId
193             attributes.put("textInputId", clientId);
194 
195             DojoUtils.renderWidgetInitializationCode(context.getResponseWriter(), component, "extensions:TableSuggest", attributes, divId.toString(), true);
196 
197             out.startElement(HTML.SCRIPT_ELEM, null);
198             out.writeAttribute(HTML.TYPE_ATTR, HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT, null);
199 
200             StringBuffer buffer = new StringBuffer();
201 
202             buffer.append("dojo.addOnLoad(function() {\n")
203                   .append(tableSuggestComponentVar).append(".comboBoxValue.value = \"").append(valueToRender).append("\";\n")
204                   .append(tableSuggestComponentVar).append(".onResize();\n")
205                   .append("});\n");
206 
207             out.write(buffer.toString());
208 
209             out.endElement(HTML.SCRIPT_ELEM);
210         }
211     }
212 
213     public void decode(FacesContext facesContext, UIComponent component)
214     {
215         super.decode(facesContext, component);
216     }
217 
218     public void encodeAjax(FacesContext context, UIComponent uiComponent)
219                                                                     throws IOException
220     {
221         String clientId = (String)context.getExternalContext()
222                                     .getRequestParameterMap().get("affectedAjaxComponent");
223 
224         UIViewRoot root = context.getViewRoot();
225 
226         UIComponent ajaxComp = root.findComponent(clientId);
227         
228         
229         //checking if ajaxComp is inside a dataTable; here needed for getting the correct ids
230         if (ajaxComp instanceof UIComponentPerspective)
231         {
232             UIComponentPerspective componentPerspective = (UIComponentPerspective) ajaxComp;
233 
234             componentPerspective.executeOn(context, new ExecuteOnCallback()
235             {
236                 public Object execute(FacesContext facesContext, UIComponent uiComponent)
237                 {
238                     try
239                     {
240                         renderResponse ( (TableSuggestAjax) uiComponent, facesContext);
241                     }
242                     catch (IOException e)
243                     {
244                         e.printStackTrace();
245                     }
246 
247                     return uiComponent;
248                 }
249             });
250         }
251         else
252         {
253             renderResponse ( (TableSuggestAjax) uiComponent, context);
254         }
255     }
256     
257     //renders the response data in an XML format
258     private void renderResponse(TableSuggestAjax tableSuggestAjax,
259             FacesContext context) throws IOException
260     {
261 
262         context.getResponseWriter().write("[");
263         renderColumnHeaders(tableSuggestAjax, context);
264         
265         StringBuffer response = new StringBuffer();
266         response.append("[");
267 
268         Collection suggestedItems =
269             getSuggestedItems(context, tableSuggestAjax);
270 
271         if (getChildren(tableSuggestAjax) == null
272                 || getChildren(tableSuggestAjax).isEmpty())
273         {
274             return;
275         }
276             
277         for (Iterator it = suggestedItems.iterator(); it.hasNext();) 
278         {
279             
280             Object addressEntryObject = it.next();
281             
282             context.getExternalContext().getRequestMap().put(
283                     tableSuggestAjax.getVar(), addressEntryObject);
284 
285             response.append("[");
286 
287             Iterator columns = tableSuggestAjax.getChildren().iterator();
288             while (columns.hasNext()) 
289             {
290                 UIComponent column = (UIComponent) columns.next();
291 
292                 Iterator columnChildren = column.getChildren().iterator(); 
293                 while (columnChildren.hasNext())
294                 {
295                     Object component = columnChildren.next();
296                     
297                     if (!(component instanceof HtmlOutputText)) 
298                     {
299                         continue;
300                     }
301                     
302                     HtmlOutputText htmlOutputText = 
303                         (HtmlOutputText) component;
304 
305                     response.append("{");
306                     
307                     //foreign-key field is a simple text field
308                     if (htmlOutputText.getFor() != null)
309                     {
310                         response.append("\"forText\": ");
311                         String forText = RendererUtils.getClientId(context,
312                                 tableSuggestAjax,
313                                 htmlOutputText.getFor());
314                         response.append("\"").append(forText).append("\",");
315                         response.append("\"label\": ");
316                         response.append("\"").append(escapeQuotes(htmlOutputText.getLabel())).append("\"");
317                     }
318                     //foreign-key field is a combo-box field 
319                     else if (htmlOutputText.getForValue() != null)
320                     {
321                         response.append("\"forValue\": ");
322                         String forValue = RendererUtils.getClientId(context,
323                                 tableSuggestAjax,
324                                 htmlOutputText.getForValue());
325                         response.append("\"").append(forValue).append("\",");
326                         response.append("\"label\": ");
327                         response.append("\"").append(escapeQuotes(htmlOutputText.getLabel())).append("\",");
328                         response.append("\"value\": ");
329                         response.append("\"").append(escapeQuotes(htmlOutputText.getValue().toString())).append("\"");
330                     } else {
331                         response.append("\"label\": ");
332                         response.append("\"").append(escapeQuotes(htmlOutputText.getValue().toString())).append("\"");
333                     }
334                     response.append("}");
335                     if (columnChildren.hasNext() || columns.hasNext()) {
336                         response.append(",");
337                     }
338                 }
339             }
340             response.append("]");
341             if (it.hasNext()) {
342                 response.append(",");
343             }
344         }
345         
346         context.getExternalContext().getRequestMap().remove(tableSuggestAjax.getVar());
347         response.append("]");
348         context.getResponseWriter().write(response.toString());
349         context.getResponseWriter().write("]");
350         
351     }
352 
353 
354 
355     //renders column names in the XML response
356     private void renderColumnHeaders(TableSuggestAjax tableSuggestAjax,
357             FacesContext context) throws IOException
358     {
359         StringBuffer columnHeaders = new StringBuffer();
360         columnHeaders.append("[");
361 
362         Iterator it = tableSuggestAjax.getChildren().iterator();
363         
364         while (it.hasNext())
365         {
366             UIComponent column = (UIComponent) it.next();
367 
368             if (column instanceof UIColumn)
369             {
370                 UIComponent tableHeader = (UIComponent) column.getFacet("header");
371 
372                 if (tableHeader != null && tableHeader instanceof HtmlOutputText)
373                 {
374                     HtmlOutputText htmlOutputText = (HtmlOutputText) tableHeader;
375                     columnHeaders.append("\"").append(htmlOutputText.getValue()).append("\"");
376                     if (it.hasNext()) {
377                         columnHeaders.append(",");
378                     }
379                 }
380             }
381         }
382         columnHeaders.append("],");
383         context.getResponseWriter().write(columnHeaders.toString());
384     }
385 
386     private String escapeQuotes(String input)
387     {
388            return input != null ? input.replaceAll("\"", "\\\\\"") : "";
389     }
390 
391 }
392 
393