001    package org.apache.myfaces.tobago.renderkit.html.scarborough.standard.tag;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one or more
005     * contributor license agreements.  See the NOTICE file distributed with
006     * this work for additional information regarding copyright ownership.
007     * The ASF licenses this file to You under the Apache License, Version 2.0
008     * (the "License"); you may not use this file except in compliance with
009     * the License.  You may obtain a copy of the License at
010     *
011     *      http://www.apache.org/licenses/LICENSE-2.0
012     *
013     * Unless required by applicable law or agreed to in writing, software
014     * distributed under the License is distributed on an "AS IS" BASIS,
015     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016     * See the License for the specific language governing permissions and
017     * limitations under the License.
018     */
019    
020    import org.apache.myfaces.tobago.component.RendererTypes;
021    import org.apache.myfaces.tobago.component.UIMenu;
022    import org.apache.myfaces.tobago.context.Markup;
023    import org.apache.myfaces.tobago.internal.util.AccessKeyMap;
024    import org.apache.myfaces.tobago.renderkit.LabelWithAccessKey;
025    import org.apache.myfaces.tobago.renderkit.LayoutComponentRendererBase;
026    import org.apache.myfaces.tobago.renderkit.css.Classes;
027    import org.apache.myfaces.tobago.renderkit.css.Style;
028    import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
029    import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
030    import org.apache.myfaces.tobago.renderkit.html.util.HtmlRendererUtils;
031    import org.apache.myfaces.tobago.util.ComponentUtils;
032    import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
033    import org.slf4j.Logger;
034    import org.slf4j.LoggerFactory;
035    
036    import javax.faces.component.UIComponent;
037    import javax.faces.context.FacesContext;
038    import java.io.IOException;
039    import java.util.List;
040    
041    public class MenuRenderer extends LayoutComponentRendererBase {
042    
043      private static final Logger LOG = LoggerFactory.getLogger(MenuRenderer.class);
044    
045      private static final String MENU_ACCELERATOR_KEYS = "menuAcceleratorKeys";
046    
047      @Override
048      public void prepareRender(FacesContext facesContext, UIComponent component) throws IOException {
049        super.prepareRender(facesContext, component);
050    
051        final UIMenu menu = (UIMenu) component;
052        final boolean firstLevel = !RendererTypes.MENU.equals(menu.getParent().getRendererType());
053        if (firstLevel) {
054          menu.setCurrentMarkup(menu.getCurrentMarkup().add(Markup.TOP));
055        }
056      }
057    
058      @Override
059      public void encodeBegin(FacesContext facesContext, UIComponent component) throws IOException {
060    
061        final UIMenu menu = (UIMenu) component;
062        TobagoResponseWriter writer = HtmlRendererUtils.getTobagoResponseWriter(facesContext);
063    
064        final boolean disabled = menu.isDisabled();
065        final boolean firstLevel = !RendererTypes.MENU.equals(menu.getParent().getRendererType());
066        final boolean isParentMenu = menu.getChildCount() > 0; // todo: may be not correct
067        final String clientId = menu.getClientId(facesContext);
068    
069        writer.startElement(HtmlElements.LI, menu);
070        writer.writeClassAttribute(Classes.create(menu, firstLevel ? Markup.TOP : null));
071        if (menu.getImage() != null) {
072          Style style = new Style();
073          style.setBackgroundImage("url(" + menu.getImage() + ")");
074          writer.writeStyleAttribute(style);
075        }
076        writer.startElement(HtmlElements.A, menu);
077        writer.writeAttribute(HtmlAttributes.HREF, "#", false);
078        writer.writeIdAttribute(clientId);
079    
080        LabelWithAccessKey label = new LabelWithAccessKey(menu);
081        if (label.getText() != null) {
082          if (label.getAccessKey() != null) {
083            if (LOG.isInfoEnabled()
084                && !AccessKeyMap.addAccessKey(facesContext, label.getAccessKey())) {
085              LOG.info("duplicated accessKey : " + label.getAccessKey());
086            }
087            if (!disabled) {
088              addAcceleratorKey(facesContext, menu, label.getAccessKey());
089            }
090          }
091          HtmlRendererUtils.writeLabelWithAccessKey(writer, label);
092        }
093        writer.endElement(HtmlElements.A);
094        if (isParentMenu) {
095          writer.startElement(HtmlElements.OL, menu);
096          writer.writeIdAttribute(clientId + ComponentUtils.SUB_SEPARATOR + "menu");
097        }
098      }
099    
100      @Override
101      public void encodeEnd(FacesContext facesContext, UIComponent component) throws IOException {
102    
103        UIMenu menu = (UIMenu) component;
104        TobagoResponseWriter writer = HtmlRendererUtils.getTobagoResponseWriter(facesContext);
105    
106        boolean isParentMenu = menu.getChildCount() > 0; // todo: may be not correct
107        if (isParentMenu) {
108          writer.endElement(HtmlElements.OL);
109        }
110        writer.endElement(HtmlElements.LI);
111      }
112    
113      private void addAcceleratorKey(FacesContext facesContext, UIComponent component, Character accessKey) {
114        String clientId = component.getClientId(facesContext);
115        while (component != null && !component.getAttributes().containsKey(MENU_ACCELERATOR_KEYS)) {
116          component = component.getParent();
117        }
118        if (component != null) {
119          List<String> keys = (List<String>) component.getAttributes().get(MENU_ACCELERATOR_KEYS);
120          String jsStatement = HtmlRendererUtils.createOnclickAcceleratorKeyJsStatement(clientId, accessKey, null);
121          keys.add(jsStatement);
122        } else {
123          LOG.warn("Can't find menu root component!");
124        }
125      }
126    }