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    }