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  
20  package org.apache.myfaces.tobago.renderkit.html.scarborough.standard.tag;
21  
22  import org.apache.myfaces.tobago.component.Attributes;
23  import org.apache.myfaces.tobago.component.Facets;
24  import org.apache.myfaces.tobago.component.RendererTypes;
25  import org.apache.myfaces.tobago.component.UIMenuCommand;
26  import org.apache.myfaces.tobago.component.UISelectBooleanCheckbox;
27  import org.apache.myfaces.tobago.context.Markup;
28  import org.apache.myfaces.tobago.context.ResourceManagerUtils;
29  import org.apache.myfaces.tobago.internal.util.AccessKeyMap;
30  import org.apache.myfaces.tobago.layout.Measure;
31  import org.apache.myfaces.tobago.renderkit.CommandRendererBase;
32  import org.apache.myfaces.tobago.renderkit.LabelWithAccessKey;
33  import org.apache.myfaces.tobago.renderkit.css.Classes;
34  import org.apache.myfaces.tobago.renderkit.css.Style;
35  import org.apache.myfaces.tobago.renderkit.html.DataAttributes;
36  import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
37  import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
38  import org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes;
39  import org.apache.myfaces.tobago.renderkit.html.util.CommandRendererHelper;
40  import org.apache.myfaces.tobago.renderkit.html.util.HtmlRendererUtils;
41  import org.apache.myfaces.tobago.renderkit.util.JQueryUtils;
42  import org.apache.myfaces.tobago.renderkit.util.RenderUtils;
43  import org.apache.myfaces.tobago.util.ComponentUtils;
44  import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
45  import org.slf4j.Logger;
46  import org.slf4j.LoggerFactory;
47  
48  import javax.faces.component.UIComponent;
49  import javax.faces.component.UISelectOne;
50  import javax.faces.context.FacesContext;
51  import javax.faces.model.SelectItem;
52  import java.io.IOException;
53  import java.util.List;
54  
55  /**
56   * Does the decoding with parent class CommandRendererBase.
57   *
58   * @see CommandRendererBase
59   */
60  public class MenuCommandRenderer extends CommandRendererBase {
61  
62    private static final Logger LOG = LoggerFactory.getLogger(MenuCommandRenderer.class);
63  
64    @Override
65    public void encodeBegin(FacesContext facesContext, UIComponent component) throws IOException {
66      UIMenuCommand menu = (UIMenuCommand) component;
67      TobagoResponseWriter writer = HtmlRendererUtils.getTobagoResponseWriter(facesContext);
68  
69      boolean disabled = menu.isDisabled();
70      boolean firstLevel = RendererTypes.MENU_BAR.equals(menu.getParent().getRendererType());
71      LabelWithAccessKey label = new LabelWithAccessKey(menu);
72      String clientId = menu.getClientId(facesContext);
73      String submit = HtmlRendererUtils.createSubmitAction(clientId, true, null, null);
74  
75      if (menu.getFacet(Facets.CHECKBOX) != null) {
76        // checkbox menu
77        UISelectBooleanCheckbox checkbox = (UISelectBooleanCheckbox) menu.getFacet(Facets.CHECKBOX);
78        boolean checked = ComponentUtils.getBooleanAttribute(checkbox, Attributes.VALUE);
79        String image = checked ? "image/MenuCheckmark.gif" : null;
80        String hiddenId = checkbox.getClientId(facesContext);
81        // the function toggles true <-> false
82        String setValue = JQueryUtils.selectId(hiddenId) 
83            + ".each(function(){jQuery(this).val(jQuery(this).val() == 'true' ? 'false' : 'true')}); ";
84        encodeItem(facesContext, writer, menu, label, setValue + submit, disabled, firstLevel, image);
85        encodeHidden(writer, hiddenId, checked);
86      } else if (menu.getFacet(Facets.RADIO) != null) {
87        // radio menu
88        UISelectOne radio = (UISelectOne) menu.getFacet(Facets.RADIO);
89        List<SelectItem> items = RenderUtils.getSelectItems(radio);
90        String hiddenId = radio.getClientId(facesContext);
91        for (SelectItem item : items) {
92          boolean checked = item.getValue().equals(radio.getValue());
93          String image = checked ? "image/MenuRadioChecked.gif" : null;
94          final String labelText = item.getLabel();
95          label.reset();
96          if (labelText != null) {
97            if (labelText.indexOf(LabelWithAccessKey.INDICATOR) > -1) {
98              label.setup(labelText);
99            } else {
100             label.setText(labelText);
101           }
102         } else {
103           LOG.warn("Menu item has label=null where clientId=" + clientId);
104         }
105         String formattedValue = RenderUtils.getFormattedValue(facesContext, radio, item.getValue());
106         String setValue = JQueryUtils.selectId(hiddenId) + ".val('" + JQueryUtils.escapeValue(formattedValue) + "'); ";
107         encodeItem(facesContext, writer, null, label, setValue + submit, disabled, firstLevel, image);
108       }
109       encodeHidden(writer, hiddenId, getCurrentValue(facesContext, radio));
110     } else {
111       // normal menu command
112       CommandRendererHelper helper = new CommandRendererHelper(facesContext, menu);
113       String onclick = helper.getOnclick();
114       String image = menu.getImage();
115       encodeItem(facesContext, writer, menu, label, onclick != null ? onclick : submit, disabled, firstLevel, image);
116     }
117   }
118 
119   private void encodeHidden(TobagoResponseWriter writer, String hiddenId, Object value) throws IOException {
120     writer.startElement(HtmlElements.INPUT, null);
121     writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN, false);
122     writer.writeIdAttribute(hiddenId);
123     writer.writeNameAttribute(hiddenId);
124     if (value != null) {
125       writer.writeAttribute(HtmlAttributes.VALUE, value.toString(), true);
126     }
127     writer.endElement(HtmlElements.INPUT);
128   }
129 
130   private void encodeItem(
131       FacesContext facesContext, TobagoResponseWriter writer, UIMenuCommand component, LabelWithAccessKey label,
132       String onclick, boolean disabled, boolean firstLevel, String image) throws IOException {
133 
134     writer.startElement(HtmlElements.LI, null);
135     if (component != null) {
136         writer.writeIdAttribute(component.getClientId(facesContext));
137     }
138     Markup markup = null;
139     if (component != null) {
140       markup = component.getCurrentMarkup();
141       if (firstLevel) {
142         markup = Markup.TOP.add(markup);
143       }
144     }
145     writer.writeClassAttribute(Classes.createWorkaround("menu", markup)); // todo: solve workaround
146     writer.writeAttribute(HtmlAttributes.ONCLICK, onclick, true);
147     if (component != null) {
148       HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
149     }
150 
151     if (image != null) {
152       if (firstLevel) {
153         Style iconStyle = new Style();
154         iconStyle.setLeft(Measure.valueOf(0));
155         iconStyle.setTop(Measure.valueOf(0));
156         iconStyle.setHeight(Measure.valueOf(16));
157         iconStyle.setWidth(Measure.valueOf(16));
158 
159         writer.startElement(HtmlElements.IMG, null);
160         String imageWithPath = ResourceManagerUtils.getImageWithPath(facesContext, image, true);
161         writer.writeAttribute(HtmlAttributes.SRC, imageWithPath, false);
162         String imageHover
163             = ResourceManagerUtils.getImageWithPath(facesContext, HtmlRendererUtils.createSrc(image, "Hover"), true);
164         if (imageHover != null) {
165           writer.writeAttribute(DataAttributes.SRCDEFAULT, imageWithPath, false);
166           writer.writeAttribute(DataAttributes.SRCHOVER, imageHover, false);
167         }
168 
169         writer.writeAttribute(HtmlAttributes.ALT, label.getText(), true);
170         writer.writeStyleAttribute(iconStyle);
171         writer.endElement(HtmlElements.IMG);
172       } else {
173         Style style = new Style();
174         style.setBackgroundImage("url("
175             + ResourceManagerUtils.getImageWithPath(facesContext, image)
176             + ")");
177         writer.writeStyleAttribute(style);
178       }
179     }
180 
181     writer.startElement(HtmlElements.A, null);
182     writer.writeAttribute(HtmlAttributes.HREF, "#", false);
183     if (image != null && firstLevel) {
184       writer.writeStyleAttribute("vertical-align:top");
185     }
186 //    writer.writeIdAttribute(clientId);
187 
188     if (label.getText() != null) {
189       if (label.getAccessKey() != null) {
190         if (LOG.isInfoEnabled()
191             && !AccessKeyMap.addAccessKey(facesContext, label.getAccessKey())) {
192           LOG.info("duplicated accessKey : " + label.getAccessKey());
193         }
194         if (!disabled && component != null && label.getAccessKey() != null) {
195           writer.writeAttribute(HtmlAttributes.ACCESSKEY, Character.toString(label.getAccessKey()), false);
196         }
197       }
198       HtmlRendererUtils.writeLabelWithAccessKey(writer, label);
199     }
200     writer.endElement(HtmlElements.A);
201     writer.endElement(HtmlElements.LI);
202   }
203 
204   public void encodeChildren(FacesContext facesContext, UIComponent component)
205       throws IOException {
206   }
207 
208   public boolean getRendersChildren() {
209     return true;
210   }
211   
212 
213 }