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 }