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 }