View Javadoc

1   /*
2    * Copyright 2004 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.nordija.tapestry.bayeux.link;
17  
18  import org.apache.hivemind.ApplicationRuntimeException;
19  import org.apache.tapestry.BaseComponent;
20  import org.apache.tapestry.IMarkupWriter;
21  import org.apache.tapestry.IRequestCycle;
22  import org.apache.tapestry.PageRenderSupport;
23  import org.apache.tapestry.TapestryUtils;
24  
25  import java.util.HashMap;
26  import java.util.Map;
27  
28  /**
29   * A base component used to render a LinkSubmit, DirectLink or ActionLink with a
30   * javascript onClick event handler that secures that the rendered component
31   * cannot be activated more than once. <p/> The component takes care of any user
32   * defined onClick eventhandler and secures that it is executed upon a user
33   * click. <p/> <b>Note</b> The component uses javascript statehandling to
34   * prevent more than one click, so be careful if you uses this component
35   * together with the <i>AJAX</i> technology.
36   *
37   * @author Jacob von Eyben www.nordija.com
38   * @version $Id: ClickOnce.java 93 2007-05-19 09:21:20Z jeyben $
39   * @since 1.3.0
40   */
41  public abstract class ClickOnce extends BaseComponent {
42  
43      public static final String DEFAULT_FUNCTION_NAME = "singleSubmit";
44  
45      public static final String SUBMITFLAG = "ongoingSubmit";
46  
47      public abstract String getOnclick();
48  
49      public abstract boolean getDisabled();
50  
51      public abstract void setFunctionName(String name);
52  
53      public abstract String getFunctionName();
54  
55      public abstract void setNestedFunctionCall(String nestedFunctionCall);
56  
57      public abstract String getNestedFunctionCall();
58  
59      public abstract void setIdParameter(String value);
60  
61      public abstract String getIdParameter();
62  
63      protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle) {
64          if (!cycle.isRewinding()) {
65              PageRenderSupport pageRenderSupport = TapestryUtils.getOptionalPageRenderSupport(cycle);
66              if (pageRenderSupport == null) {
67                  throw new ApplicationRuntimeException("SingleSubmit component[" + getId()
68                          + "] must be contained inside a body component", this, null, null);
69              }
70              if (getOnclick() == null || "".equals(getOnclick())) {
71                  setFunctionName(DEFAULT_FUNCTION_NAME);
72              } else {
73                  setFunctionName(pageRenderSupport.getUniqueString(DEFAULT_FUNCTION_NAME + "Nested"));
74              }
75              setNestedFunctionCall(extractOnclick(getOnclick()));
76          } else {
77              // when rewinding just use some string to prevent nullpointer
78              // exception in
79              setFunctionName(DEFAULT_FUNCTION_NAME);
80          }
81          super.renderComponent(writer, cycle);
82      }
83  
84      public Map getScriptSymbols() {
85          Map ret = new HashMap();
86          ret.put("disabled", Boolean.valueOf(getDisabled()));
87          ret.put("submitflagName", SUBMITFLAG);
88          ret.put("functionName", getFunctionName());
89          ret.put("nestedFunctionCall", "".equals(getNestedFunctionCall()) ? null : getNestedFunctionCall());
90          return ret;
91      }
92  
93      /**
94       * Finds the onClick function call defined by the user. If the function
95       * begins with 'return' this is removed
96       *
97       * @param onclick the javascript code to execute
98       * @return if onClick is <code>null</code> or empty, <code>null</code>
99       *         is returned, otherwise a string
100      */
101     protected static String extractOnclick(String onclick) {
102         String result = null;
103         if (onclick != null && !("".equals(onclick))) {
104             result = onclick.trim();
105             // remove eventual "return " in beginning of the onClick.
106             // done because we need to pick the returnvalue up in a variable in
107             // our javascript.
108             if (result.startsWith("return")) {
109                 result = result.replaceFirst("return", "");
110             }
111             result = result.trim();
112         }
113         return result;
114     }
115 
116 }