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.accordion;
20  
21  import org.apache.myfaces.renderkit.html.util.AddResource;
22  import org.apache.myfaces.renderkit.html.util.AddResourceFactory;
23  import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
24  import org.apache.myfaces.custom.tabbedpane.HtmlPanelTab;
25  import org.apache.myfaces.shared_tomahawk.renderkit.JSFAttr;
26  import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
27  import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils;
28  import org.apache.myfaces.renderkit.html.ext.HtmlGroupRenderer;
29  
30  import javax.faces.component.UIComponent;
31  import javax.faces.context.FacesContext;
32  import javax.faces.context.ResponseWriter;
33  import java.io.IOException;
34  import java.util.Iterator;
35  import java.util.List;
36  import java.util.Map;
37  
38  
39  /**
40   * @author Martin Marinschek
41   *
42   * @JSFRenderer
43   *   renderKitId = "HTML_BASIC" 
44   *   family = "javax.faces.Panel"
45   *   type = "org.apache.myfaces.AccordionPanel"
46   *
47   * @version $Revision: $ $Date: $
48   *          <p/>
49   */
50  public class HtmlAccordionPanelRenderer extends HtmlGroupRenderer
51  {
52      public void encodeBegin(FacesContext context, UIComponent component) throws IOException
53      {
54          encodeJavascript(context, component);
55  
56          super.encodeBegin(context, component);
57      }
58  
59      public void encodeChildren(FacesContext context, UIComponent component) throws IOException
60      {
61      }
62  
63      public void encodeEnd(FacesContext context, UIComponent component) throws IOException
64      {
65          RendererUtils.checkParamValidity(context, component, HtmlAccordionPanel.class);
66  
67          HtmlAccordionPanel panel = (HtmlAccordionPanel) component;
68  
69          ResponseWriter writer = context.getResponseWriter();
70  
71          writer.startElement(HTML.DIV_ELEM, component);
72          writer.writeAttribute(HTML.ID_ATTR,component.getClientId(context), JSFAttr.ID_ATTR);
73          HtmlRendererUtils.renderHTMLAttributes(writer, component, HTML.COMMON_PASSTROUGH_ATTRIBUTES);
74  
75          List childExpanded = panel.getChildExpanded();
76  
77          if (component.getChildCount() > 0)
78          {
79              int i = 0;
80              for (Iterator it = component.getChildren().iterator(); it.hasNext(); i++)
81              {
82                  UIComponent child = (UIComponent)it.next();
83  
84                  if(child instanceof HtmlPanelTab)
85                  {
86                      HtmlPanelTab pane = (HtmlPanelTab) child;
87                      writer.startElement(HTML.DIV_ELEM, child);
88                      writer.writeAttribute(HTML.ID_ATTR,
89                                            child.getClientId(context) + "_MAIN_DIV",
90                                            JSFAttr.ID_ATTR);
91  
92                      writer.startElement(HTML.DIV_ELEM, child);
93                      writer.writeAttribute(HTML.ID_ATTR,
94                                            child.getClientId(context) + "_HEADER_DIV",
95                                            JSFAttr.ID_ATTR);
96                      if(pane.getLabel() != null)
97                      {
98                          writer.writeText(pane.getLabel(), JSFAttr.LABEL_ATTR);
99                      }
100                     else
101                     {
102                         UIComponent header = pane.getFacet("header");
103 
104                         if(header == null)
105                         {
106                             throw new IllegalStateException("You need to set a label on the tab or include a facet with name 'header' into it.");
107                         }
108 
109                         RendererUtils.renderChild(context, header);
110                     }
111                     writer.endElement(HTML.DIV_ELEM);
112 
113                     UIComponent closedContent = pane.getFacet("closedContent");
114 
115                     if(closedContent != null)
116                     {
117                         writer.startElement(HTML.DIV_ELEM, child);
118                         writer.writeAttribute(HTML.ID_ATTR,
119                                               child.getClientId(context) + "_CLOSED_CONTENT_DIV",
120                                               JSFAttr.ID_ATTR);
121                         RendererUtils.renderChild(context, closedContent);
122                         writer.endElement(HTML.DIV_ELEM);
123                     }
124 
125                     writer.startElement(HTML.DIV_ELEM, child);
126                     writer.writeAttribute(HTML.ID_ATTR,
127                                           child.getClientId(context) + "_CONTENT_DIV",
128                                           JSFAttr.ID_ATTR);
129                     RendererUtils.renderChildren(context, child);
130                     writer.endElement(HTML.DIV_ELEM);
131 
132                     //stateholder hidden input
133                     String stateID = child.getClientId(context) + HtmlAccordionPanel.EXPAND_STATEHOLDER_ID;
134                     writer.startElement(HTML.INPUT_ELEM, child);
135                     writer.writeAttribute(HTML.ID_ATTR,
136                                           stateID,
137                                           JSFAttr.ID_ATTR);
138                     //must be setted, else not included in requestmap
139                     writer.writeAttribute(HTML.NAME_ATTR,
140                                           stateID,
141                                           null);
142                     writer.writeAttribute(HTML.TYPE_ATTR,
143                                           HTML.INPUT_TYPE_HIDDEN,
144                                           JSFAttr.TYPE_ATTR);
145                     Object o = childExpanded.get(i);
146                     if(o instanceof Integer)
147                     {
148                         writer.writeAttribute(HTML.VALUE_ATTR,
149                                               o,
150                                               JSFAttr.VALUE_ATTR);
151                     }
152                     writer.endElement(HTML.INPUT_ELEM);
153 
154                     writer.endElement(HTML.DIV_ELEM);
155 
156                 }
157                 else
158                 {
159                     throw new IllegalStateException("no other children accepted");
160                 }
161             }
162         }
163 
164         writer.endElement(HTML.DIV_ELEM);
165 
166         writer.startElement(HTML.SCRIPT_ELEM, component);
167         writer.writeAttribute(HTML.SCRIPT_TYPE_ATTR,
168                               HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT,
169                               null);
170 
171         String jsObjectName = "options";
172         encodeOptions(writer, panel, jsObjectName);
173 
174         String id = component.getClientId(context);
175 
176         if(panel.getLayout().equals(HtmlAccordionPanel.ACCORDION_LAYOUT))
177         {
178             writer.writeText("new Rico.Accordion.Custom('"+ id +"', " + jsObjectName + ");",
179                              null);
180         }
181         else if(panel.getLayout().equals(HtmlAccordionPanel.TOGGLING_LAYOUT))
182         {
183             writer.writeText("new Rico.Toggler.Custom('" + id + "', " + jsObjectName + ");",
184                              null);
185         }
186         else
187         {
188             throw new IllegalStateException("nothing known about layout : " +
189                                             panel.getLayout());
190         }
191 
192         writer.endElement(HTML.SCRIPT_ELEM);
193     }
194 
195 
196     public void decode(FacesContext context, UIComponent component)
197     {
198         super.decode(context, component);
199 
200         RendererUtils.checkParamValidity(context, component, HtmlAccordionPanel.class);
201 
202         HtmlAccordionPanel panel = (HtmlAccordionPanel) component;
203 
204         Map requestParams = context.getExternalContext().getRequestParameterMap();
205 
206         if(panel.getChildCount() > 0)
207         {
208             int i = 0;
209             List list = panel.getChildExpanded();
210 
211             for (Iterator it = component.getChildren().iterator(); it.hasNext(); i++)
212             {
213                 UIComponent child = (UIComponent)it.next();
214 
215                 if(child instanceof HtmlPanelTab)
216                 {
217                     String stateID = child.getClientId(context) + HtmlAccordionPanel.EXPAND_STATEHOLDER_ID;
218                     String stateValue = (String)requestParams.get(stateID);
219 
220                     try
221                     {
222                         Integer cur = Integer.valueOf(stateValue);
223                         list.set(i, cur);
224                     }
225                     catch(NumberFormatException e)
226                     {
227                         e.printStackTrace();
228                     }
229                 }
230             }
231             panel.setChildExpanded(list);
232         }
233     }
234 
235 
236     /**
237      * Encodes any stand-alone javascript functions that are needed.
238      * Uses either the extension filter, or a
239      * user-supplied location for the javascript files.
240      *
241      * @param context FacesContext
242      * @param component UIComponent
243      */
244     private void encodeJavascript(FacesContext context, UIComponent component)
245     {
246         // AddResource takes care to add only one reference to the same script
247         String javascriptLocation = (String)component.getAttributes().get(JSFAttr.JAVASCRIPT_LOCATION);
248         AddResource addResource = AddResourceFactory.getInstance(context);
249         if(javascriptLocation != null)
250         {
251             // add user defined javascripts
252             addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN, javascriptLocation + "/dpdump.js");
253             addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN, javascriptLocation + "/prototype.js");
254             addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN, javascriptLocation + "/rico.js");
255             addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN, javascriptLocation + "/toggler.js");
256             addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN, javascriptLocation + "/customRico.js");
257         }
258         else
259         {
260             addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN, HtmlAccordionPanelRenderer.class, "dpdump.js");
261             addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN, HtmlAccordionPanelRenderer.class, "prototype.js");
262             addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN, HtmlAccordionPanelRenderer.class, "rico.js");
263             addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN, HtmlAccordionPanelRenderer.class, "toggler.js");
264             addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN, HtmlAccordionPanelRenderer.class, "customRico.js");
265         }
266     }
267 
268 
269     /**
270      * Writes the style options for the given {@link HtmlAccordionPanel}.
271      *
272      * @param writer the {@link ResponseWriter} of the current {@link FacesContext}.
273      * @param panel the {@link HtmlAccordionPanel} to encode.
274      *
275      * @throws IOException
276      */
277 
278     private void encodeOptions(ResponseWriter writer,
279                                HtmlAccordionPanel panel,
280                                String jsObjectName)
281                                 throws IOException
282     {
283         writer.writeText("var " + jsObjectName + " = new Object();", null);
284 
285         if(panel.getExpandedBackColor() != null)
286         {
287             String statement;
288             statement = getJSPropertySetString(jsObjectName,
289                                                HtmlAccordionPanel.EXPANDED_BACK_COLOR,
290                                                panel.getExpandedBackColor());
291 
292             writer.writeText(statement, null);
293         }
294         if(panel.getExpandedTextColor() != null)
295         {
296             String statement;
297             statement = getJSPropertySetString(jsObjectName,
298                                                HtmlAccordionPanel.EXPANDED_TEXT_COLOR,
299                                                panel.getExpandedTextColor());
300 
301             writer.writeText(statement, null);
302         }
303         if(panel.getExpandedFontWeight() != null)
304         {
305             String statement;
306             statement = getJSPropertySetString(jsObjectName,
307                                                HtmlAccordionPanel.EXPANDED_FONT_WEIGHT,
308                                                panel.getExpandedFontWeight());
309 
310             writer.writeText(statement, null);
311         }
312 
313         if(panel.getCollapsedBackColor() != null)
314         {
315             String statement;
316             statement = getJSPropertySetString(jsObjectName,
317                                                HtmlAccordionPanel.COLLAPSED_BACK_COLOR,
318                                                panel.getCollapsedBackColor());
319 
320             writer.writeText(statement, null);
321         }
322         if(panel.getCollapsedTextColor() != null)
323         {
324             String statement;
325             statement = getJSPropertySetString(jsObjectName,
326                                                HtmlAccordionPanel.COLLAPSED_TEXT_COLOR,
327                                                panel.getCollapsedTextColor());
328 
329             writer.writeText(statement, null);
330         }
331         if(panel.getCollapsedFontWeight() != null)
332         {
333             String statement;
334             statement = getJSPropertySetString(jsObjectName,
335                                                HtmlAccordionPanel.COLLAPSED_FONT_WEIGHT,
336                                                panel.getCollapsedFontWeight());
337 
338             writer.writeText(statement, null);
339         }
340 
341         if(panel.getHoverBackColor() != null)
342         {
343             String statement;
344             statement = getJSPropertySetString(jsObjectName,
345                                                HtmlAccordionPanel.HOVER_BACK_COLOR,
346                                                panel.getHoverBackColor());
347 
348             writer.writeText(statement, null);
349         }
350         if(panel.getHoverTextColor() != null)
351         {
352             String statement;
353             statement = getJSPropertySetString(jsObjectName,
354                                                HtmlAccordionPanel.HOVER_TEXT_COLOR,
355                                                panel.getHoverTextColor());
356 
357             writer.writeText(statement, null);
358         }
359 
360         if(panel.getBorderColor() != null)
361         {
362             String statement;
363             statement = getJSPropertySetString(jsObjectName,
364                                                HtmlAccordionPanel.BORDER_COLOR,
365                                                panel.getBorderColor());
366 
367             writer.writeText(statement, null);
368         }
369     }
370 
371 
372     /**
373      * Builds a set statement for a property of an Javascript Object.
374      *
375      * @param object the name of the Javascript object.
376      * @param property the name of the object's property.
377      * @param value the new value of the property.
378      *
379      * @return a set statement for a Javascript object.
380      */
381 
382     private String getJSPropertySetString(String object,
383                                           String property,
384                                           String value)
385     {
386         StringBuffer sb = new StringBuffer();
387         sb.append(object);
388         sb.append(".");
389         sb.append(property);
390         sb.append("='");
391         sb.append(value);
392         sb.append("';");
393         return sb.toString();
394     }
395 }