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