001 package org.apache.myfaces.tobago.renderkit.html; 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.commons.logging.Log; 021 import org.apache.commons.logging.LogFactory; 022 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_ACTION_LINK; 023 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_ACTION_ONCLICK; 024 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_DEFAULT_COMMAND; 025 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_DISABLED; 026 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_POPUP_CLOSE; 027 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_TARGET; 028 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_TRANSITION; 029 import static org.apache.myfaces.tobago.TobagoConstants.FACET_POPUP; 030 import static org.apache.myfaces.tobago.TobagoConstants.FACET_CONFIRMATION; 031 import org.apache.myfaces.tobago.component.ComponentUtil; 032 import org.apache.myfaces.tobago.component.UIPopup; 033 import org.apache.myfaces.tobago.event.PopupActionListener; 034 import org.apache.myfaces.tobago.context.ClientProperties; 035 036 import javax.faces.context.FacesContext; 037 import javax.faces.component.UIComponent; 038 import javax.faces.component.ValueHolder; 039 import javax.faces.component.UIParameter; 040 import javax.faces.component.UICommand; 041 import javax.faces.application.Application; 042 import javax.faces.application.ViewHandler; 043 import java.util.List; 044 import java.util.Arrays; 045 import java.net.URLDecoder; 046 047 /** 048 * User: lofwyr 049 * Date: 19.03.2007 17:54:59 050 */ 051 public class CommandRendererHelper { 052 053 private static final Log LOG = LogFactory.getLog(CommandRendererHelper.class); 054 055 private String onclick; 056 private boolean disabled; 057 private String href; 058 private String target; 059 060 public CommandRendererHelper(FacesContext facesContext, UICommand component) { 061 initOnclick(facesContext, component, null); 062 } 063 064 public CommandRendererHelper(FacesContext facesContext, UICommand component, Tag tag) { 065 initOnclick(facesContext, component, tag); 066 } 067 068 private void initOnclick(FacesContext facesContext, UICommand command, Tag tag) { 069 070 disabled = ComponentUtil.getBooleanAttribute(command, ATTR_DISABLED); 071 href = getEmptyHref(facesContext); 072 073 if (disabled) { 074 onclick = ""; 075 href = ""; 076 } else { 077 078 UIPopup popup = (UIPopup) command.getFacet(FACET_POPUP); 079 if (popup != null) { 080 if (!ComponentUtil.containsPopupActionListener(command)) { 081 command.addActionListener(new PopupActionListener(popup)); 082 } 083 } 084 085 String clientId = command.getClientId(facesContext); 086 boolean defaultCommand = ComponentUtil.getBooleanAttribute(command, ATTR_DEFAULT_COMMAND); 087 boolean transition = ComponentUtil.getBooleanAttribute(command, ATTR_TRANSITION); 088 089 if (command.getAttributes().get(ATTR_ACTION_LINK) != null) { 090 String url = generateUrl(facesContext, command); 091 if (tag == Tag.ANCHOR) { 092 onclick = null; 093 href = url; 094 target = ComponentUtil.getStringAttribute(command, ATTR_TARGET); 095 } else { 096 onclick = "Tobago.navigateToUrl('" + url + "');"; 097 } 098 } else if (command.getAttributes().get(ATTR_ACTION_ONCLICK) != null) { 099 onclick = prepareOnClick(facesContext, command); 100 } else if (command instanceof org.apache.myfaces.tobago.component.UICommand 101 && ((org.apache.myfaces.tobago.component.UICommand) command).getRenderedPartially().length > 0) { 102 103 String[] componentId = ((org.apache.myfaces.tobago.component.UICommand) command).getRenderedPartially(); 104 105 if (componentId != null && componentId.length == 1) { 106 // TODO find a better way 107 boolean popupAction = ComponentUtil.containsPopupActionListener(command); 108 if (popupAction) { 109 onclick = "Tobago.openPopupWithAction('" 110 + HtmlRendererUtil.getComponentId(facesContext, command, componentId[0]) + "', '" + clientId + "')"; 111 } else { 112 onclick = "Tobago.reloadComponent('" 113 + HtmlRendererUtil.getComponentId(facesContext, command, componentId[0]) + "','" + clientId + "', {});"; 114 } 115 } else { 116 LOG.error("more than one parially rendered component is currently not supported " 117 + Arrays.toString(componentId)); 118 onclick = "Tobago.submitAction('" + clientId + "', " + transition + ");"; 119 } 120 121 } else if (defaultCommand) { 122 ComponentUtil.findPage(facesContext, command).setDefaultActionId(clientId); 123 onclick = null; 124 } else { 125 String target = ComponentUtil.getStringAttribute(command, ATTR_TARGET); 126 if (target == null) { 127 onclick = "Tobago.submitAction('" + clientId + "', " + transition + ");"; 128 } else { 129 onclick = "Tobago.submitAction('" + clientId + "', " + transition + ", '" + target + "');"; 130 } 131 } 132 133 if (command.getAttributes().get(ATTR_POPUP_CLOSE) != null 134 && ComponentUtil.isInPopup(command)) { 135 String value = (String) command.getAttributes().get(ATTR_POPUP_CLOSE); 136 if (value.equals("immediate")) { 137 onclick = "Tobago.closePopup(this);"; 138 } else if (value.equals("afterSubmit") 139 && command instanceof org.apache.myfaces.tobago.component.UICommand 140 && ((org.apache.myfaces.tobago.component.UICommand) command).getRenderedPartially().length > 0) { 141 onclick += "Tobago.closePopup(this);"; 142 } 143 144 } 145 146 onclick = appendConfirmationScript(onclick, command); 147 } 148 } 149 150 private String getEmptyHref(FacesContext facesContext) { 151 ClientProperties clientProperties = ClientProperties.getInstance(facesContext); 152 return clientProperties.getUserAgent().isMsie() ? "#" : "javascript:;"; 153 } 154 155 private String prepareOnClick(FacesContext facesContext, UIComponent component) { 156 String onclick; 157 onclick = (String) component.getAttributes().get(ATTR_ACTION_ONCLICK); 158 if (onclick.contains("@autoId")) { 159 onclick = onclick.replace("@autoId", component.getClientId(facesContext)); 160 } 161 return onclick; 162 } 163 164 private String appendConfirmationScript(String onclick, UIComponent component) { 165 ValueHolder confirmation = (ValueHolder) component.getFacet(FACET_CONFIRMATION); 166 if (confirmation != null) { 167 StringBuilder script = new StringBuilder(); 168 script.append("return confirm('"); 169 script.append(confirmation.getValue()); 170 script.append("')"); 171 if (onclick != null) { 172 script.append(" && "); 173 script.append(onclick); 174 } 175 onclick = script.toString(); 176 } 177 return onclick; 178 } 179 180 private String generateUrl(FacesContext facesContext, UIComponent component) { 181 String url; 182 Application application = facesContext.getApplication(); 183 ViewHandler viewHandler = application.getViewHandler(); 184 185 String link = (String) component.getAttributes().get(ATTR_ACTION_LINK); 186 if (link.startsWith("/")) { // internal URL 187 url = viewHandler.getActionURL(facesContext, link); 188 } else { // external URL 189 url = link; 190 } 191 192 url = facesContext.getExternalContext().encodeActionURL(url); 193 194 StringBuilder builder = new StringBuilder(url); 195 boolean firstParameter = !url.contains("?"); 196 for (UIComponent child : (List<UIComponent>) component.getChildren()) { 197 if (child instanceof UIParameter) { 198 UIParameter parameter = (UIParameter) child; 199 if (firstParameter) { 200 builder.append("?"); 201 firstParameter = false; 202 } else { 203 builder.append("&"); 204 } 205 builder.append(parameter.getName()); 206 builder.append("="); 207 Object value = parameter.getValue(); 208 // TODO encoding 209 builder.append(value != null ? URLDecoder.decode(value.toString()) : null); 210 } 211 } 212 url = builder.toString(); 213 214 return url; 215 } 216 217 218 public String getOnclick() { 219 return onclick; 220 } 221 222 public String getOnclickDoubleQuoted() { 223 return onclick.replaceAll("'", "\""); 224 } 225 226 public boolean isDisabled() { 227 return disabled; 228 } 229 230 public String getHref() { 231 return href; 232 } 233 234 public String getTarget() { 235 return target; 236 } 237 238 public static enum Tag { 239 ANCHOR, BUTTON 240 } 241 }