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