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