Author: jkuhnert
Date: Tue Jun 12 19:35:05 2007
New Revision: 546712
URL: http://svn.apache.org/viewvc?view=rev&rev=546712
Log:
Fixes TAPESTRY-1563 regression. LinkSubmit async operations were broken by
placing using a href="#" directive. Took the opportunity to refactor some and
now have the href="" pointing to a valid url (even if it would definitely give
you a stale link exception if that's all you sent to the server) and used the
attribute in the real onClick capture.
Removed:
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/LinkSubmit.script
Modified:
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/AbstractSubmit.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/LinkSubmit.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/LinkSubmit.jwc
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/Submit.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/json/JSONObject.java
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/util/text/MarkupCharacterTranslator.java
tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/form/LinkSubmitTest.java
Modified:
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/AbstractSubmit.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/AbstractSubmit.java?view=diff&rev=546712&r1=546711&r2=546712
==============================================================================
---
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/AbstractSubmit.java
(original)
+++
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/AbstractSubmit.java
Tue Jun 12 19:35:05 2007
@@ -84,7 +84,8 @@
if (listener != null)
listenerInvoker.invokeListener(listener, AbstractSubmit.this,
cycle);
- if (action != null) {
+ if (action != null)
+ {
Runnable notify = new Runnable()
{
public void run()
@@ -101,8 +102,10 @@
* Manages rendering of important submit client side bindings, like
invoking the right submit
* type or any of the optional [EMAIL PROTECTED] IDynamicInvoker}
parameters.
*
- * @param writer The writer to use to write content.
- * @param cycle The current request cycle.
+ * @param writer
+ * The writer to use to write content.
+ * @param cycle
+ * The current request cycle.
*/
protected void renderSubmitBindings(IMarkupWriter writer, IRequestCycle
cycle)
{
@@ -113,86 +116,60 @@
Defense.notNull(type, "submitType");
- Map parms = null;
- JSONObject json = null;
List update = getUpdateComponents();
+ boolean isAsync = isAsync() || update != null && update.size() > 0;
+
+ if (!isAsync && type.equals(FormConstants.SUBMIT_NORMAL))
+ return;
- if (isAsync() || (update != null && update.size() > 0)) {
-
+ JSONObject json = null;
+
+ // build async URL to form if async
+
+ if (isAsync)
+ {
IForm form = getForm();
- parms = new HashMap();
- parms.put("submit", this);
- parms.put("key", ScriptUtils.functionHash(type + this.hashCode()));
-
json = new JSONObject();
-
json.put("async", Boolean.TRUE);
json.put("json", isJson());
DirectServiceParameter dsp = new DirectServiceParameter(form,
null, this);
-
json.put("url", getDirectService().getLink(true, dsp).getURL());
}
+
+ // only if not async - otherwise we have to stop the client side event
to prevent normal form submission
+ // within the submitbindings client side generated function
- if (!type.equals(FormConstants.SUBMIT_NORMAL)) {
- if (!isParameterBound("onClick") && !isParameterBound("onclick")
- && (!isAsync() && (update == null || update.size() == 0))) {
-
- StringBuffer str = new StringBuffer();
-
- str.append("tapestry.form.").append(type);
- str.append("('").append(getForm().getClientId()).append("',");
- str.append("'").append(getName()).append("'");
-
- if (json != null){
- str.append(",").append(json.toString());
- }
-
- str.append(")");
-
- writer.attribute("onClick", str.toString());
- return;
- } else {
- if (parms == null) {
- parms = new HashMap();
-
- parms.put("submit", this);
- parms.put("key", ScriptUtils.functionHash(type +
this.hashCode()));
- }
-
- parms.put("type", type);
- }
- }
-
- if (parms != null) {
-
- if (json != null) {
- parms.put("parms", json.toString());
- }
-
- PageRenderSupport prs = TapestryUtils.getPageRenderSupport(cycle,
this);
- getSubmitScript().execute(this, cycle, prs, parms);
+ if (!isAsync && !isParameterBound("onClick") &&
!isParameterBound("onclick"))
+ {
+ StringBuffer str = new StringBuffer();
- setSubmitBindingBound(true);
+ str.append("tapestry.form.").append(type);
+ str.append("('").append(getForm().getClientId()).append("',");
+ str.append("'").append(getName()).append("'");
+
+ if (json != null)
+ str.append(",").append(json.toString());
+
+ str.append(")");
+
+ writer.attribute("onClick", str.toString());
+ return;
}
+
+ Map parms = new HashMap();
+ parms.put("submit", this);
+ parms.put("key", ScriptUtils.functionHash(type + this.hashCode()));
+ parms.put("type", type);
+
+ if (json != null)
+ parms.put("parms", json.toString());
+
+ PageRenderSupport prs = TapestryUtils.getPageRenderSupport(cycle,
this);
+ getSubmitScript().execute(this, cycle, prs, parms);
}
- /**
- * Used internall to track whether or not an async submit binding was
rendered
- * as a result of calling [EMAIL PROTECTED]
#renderSubmitBindings(org.apache.tapestry.IMarkupWriter,
org.apache.tapestry.IRequestCycle)}.
- *
- * <p>
- * Currently this is used to track javascript contributions between the
base and subclasses so that
- * duplicate client side bindings aren't created - such as the case with
[EMAIL PROTECTED] LinkSubmit} where
- * client side javascript is always bound to the click of the link - with
only the XHR behaviour
- * changing depending on the configuration of the component.
- * </p>
- *
- * @return True if submit bindings have been configured for this component
instance, false otherwise.
- */
- public abstract boolean isSubmitBindingBound();
- public abstract void setSubmitBindingBound(boolean value);
/** parameter. */
public abstract IActionListener getListener();
Modified:
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/LinkSubmit.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/LinkSubmit.java?view=diff&rev=546712&r1=546711&r2=546712
==============================================================================
---
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/LinkSubmit.java
(original)
+++
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/LinkSubmit.java
Tue Jun 12 19:35:05 2007
@@ -15,16 +15,21 @@
package org.apache.tapestry.form;
import org.apache.hivemind.ApplicationRuntimeException;
-import org.apache.tapestry.*;
-import org.apache.tapestry.util.ScriptUtils;
+import org.apache.hivemind.util.Defense;
+import org.apache.tapestry.IComponent;
+import org.apache.tapestry.IForm;
+import org.apache.tapestry.IMarkupWriter;
+import org.apache.tapestry.IRequestCycle;
+import org.apache.tapestry.engine.DirectServiceParameter;
+import org.apache.tapestry.json.JSONLiteral;
+import org.apache.tapestry.json.JSONObject;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.List;
/**
* Implements a component that submits its enclosing form via a JavaScript
link. [ <a
* href="../../../../../ComponentReference/LinkSubmit.html">Component
Reference </a>]
- *
+ *
* @author Richard Lewis-Shell
*/
@@ -37,7 +42,7 @@
*/
public static final String ATTRIBUTE_NAME =
"org.apache.tapestry.form.LinkSubmit";
-
+
/**
* Checks the submit name ([EMAIL PROTECTED]
FormConstants#SUBMIT_NAME_PARAMETER}) to see if it matches
* this LinkSubmit's assigned element name.
@@ -45,12 +50,10 @@
protected boolean isClicked(IRequestCycle cycle, String name)
{
String value = cycle.getParameter(FormConstants.SUBMIT_NAME_PARAMETER);
-
+
return name.equals(value);
}
- public abstract IScript getScript();
-
/**
* @see
org.apache.tapestry.form.AbstractFormComponent#renderFormComponent(org.apache.tapestry.IMarkupWriter,
* org.apache.tapestry.IRequestCycle)
@@ -60,33 +63,37 @@
boolean disabled = isDisabled();
IForm form = getForm();
- String name = getName();
+ String type = getSubmitType();
+
+ Defense.notNull(type, "submitType");
+
+ List update = getUpdateComponents();
+ boolean isAsync = isAsync() || update != null && update.size() > 0;
if (!disabled)
- {
+ {
writer.begin("a");
- writer.attribute("href", "#");
-
- renderIdAttribute(writer, cycle);
-
- renderInformalParameters(writer, cycle);
-
- renderSubmitBindings(writer, cycle);
- // only if superclass hasn't done it already
+ String js = "tapestry.form." + type + "('" + form.getClientId() +
"', '" + getName() + "'";
- if (!isSubmitBindingBound())
+ if (isAsync)
{
- PageRenderSupport pageRenderSupport =
TapestryUtils.getPageRenderSupport(cycle, this);
+ JSONObject json = new JSONObject();
+ json.put(new JSONLiteral("async"), Boolean.TRUE);
+ json.put(new JSONLiteral("json"), isJson());
+
+ DirectServiceParameter dsp = new DirectServiceParameter(form,
null, this);
+ json.put(new JSONLiteral("url"), new JSONLiteral("this.href"));
+
+ writer.attribute("href", getDirectService().getLink(true,
dsp).getURL());
+ writer.attribute("onClick", js + "," + json.toString() + ");
return false;");
+ } else {
- Map symbols = new HashMap();
- symbols.put("form", form);
- symbols.put("name", name);
- symbols.put("component", this);
- symbols.put("functionName", ScriptUtils.functionHash("onclick"
+ this.hashCode()));
-
- getScript().execute(this, cycle, pageRenderSupport, symbols);
+ writer.attribute("href", "javascript:" + js + ");");
}
+
+ renderIdAttribute(writer, cycle);
+ renderInformalParameters(writer, cycle);
}
renderBody(writer, cycle);
@@ -95,16 +102,18 @@
writer.end();
}
+
+
/**
* @see
org.apache.tapestry.AbstractComponent#prepareForRender(org.apache.tapestry.IRequestCycle)
*/
protected void prepareForRender(IRequestCycle cycle)
{
IComponent outer = (IComponent) cycle.getAttribute(ATTRIBUTE_NAME);
-
+
if (outer != null)
throw new
ApplicationRuntimeException(FormMessages.linkSubmitMayNotNest(this, outer),
- this, getLocation(), null);
+ this, getLocation(), null);
cycle.setAttribute(ATTRIBUTE_NAME, this);
}
Modified:
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/LinkSubmit.jwc
URL:
http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/LinkSubmit.jwc?view=diff&rev=546712&r1=546711&r2=546712
==============================================================================
---
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/LinkSubmit.jwc
(original)
+++
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/LinkSubmit.jwc
Tue Jun 12 19:35:05 2007
@@ -28,9 +28,7 @@
<parameter name="disabled"/>
<parameter name="selected"/>
<parameter name="tag"/>
-
- <parameter name="id" property="idParameter" default-value="id"/>
-
+
<parameter name="listener">
<description>
A listener that is notified if this component is triggered.
@@ -61,17 +59,13 @@
</parameter>
<parameter name="updateComponents" />
-
<parameter name="json" default-value="false" />
-
<parameter name="async" default-value="false" />
<reserved-parameter name="name"/>
<reserved-parameter name="href"/>
-
+
<inject property="directService" object="engine-service:direct" />
<inject property="listenerInvoker" object="infrastructure:listenerInvoker"/>
- <inject property="script" type="script" object="LinkSubmit.script"/>
- <inject property="submitScript" type="script"
object="SubmitBindings.script"/>
</component-specification>
Modified:
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/Submit.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/Submit.java?view=diff&rev=546712&r1=546711&r2=546712
==============================================================================
---
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/Submit.java
(original)
+++
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/Submit.java
Tue Jun 12 19:35:05 2007
@@ -39,6 +39,7 @@
// If the value isn't there, then this button wasn't
// selected.
+
return cycle.getParameter(name) != null;
}
Modified:
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/json/JSONObject.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/json/JSONObject.java?view=diff&rev=546712&r1=546711&r2=546712
==============================================================================
---
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/json/JSONObject.java
(original)
+++
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/json/JSONObject.java
Tue Jun 12 19:35:05 2007
@@ -25,11 +25,7 @@
*/
import java.text.ParseException;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.NoSuchElementException;
+import java.util.*;
/**
* A JSONObject is an unordered collection of name/value pairs. Its external
@@ -505,41 +501,44 @@
return o != null ? o.toString() : defaultValue;
}
- public JSONObject put(String key, boolean value)
+ public JSONObject put(Object key, boolean value)
{
put(key, Boolean.valueOf(value));
return this;
}
- public JSONObject put(String key, double value)
+ public JSONObject put(Object key, double value)
{
put(key, new Double(value));
return this;
}
- public JSONObject put(String key, long value)
+ public JSONObject put(Object key, long value)
{
put(key, new Long(value));
return this;
}
- public JSONObject put(String key, int value)
+ public JSONObject put(Object key, int value)
{
put(key, new Integer(value));
return this;
}
- public JSONObject put(String key, Object value)
+ public JSONObject put(Object key, Object value)
{
- if (key == null) { throw new NullPointerException("Null key."); }
+ if (key == null)
+ throw new NullPointerException("Null key.");
+
if (value != null)
{
this.myHashMap.put(key, value);
}
else
{
- remove(key);
+ remove(key.toString());
}
+
return this;
}
@@ -663,7 +662,7 @@
sb.append(',');
}
Object o = keys.next();
- sb.append(quote(o.toString()));
+ sb.append(valueToString(o));
sb.append(':');
sb.append(valueToString(this.myHashMap.get(o)));
}
Modified:
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/util/text/MarkupCharacterTranslator.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/util/text/MarkupCharacterTranslator.java?view=diff&rev=546712&r1=546711&r2=546712
==============================================================================
---
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/util/text/MarkupCharacterTranslator.java
(original)
+++
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/util/text/MarkupCharacterTranslator.java
Tue Jun 12 19:35:05 2007
@@ -18,24 +18,23 @@
* An object that encodes a character according to rules of the HTML
* specification, so that it will be properly parsed by a browser
irrespectively
* of the character encoding used in the HTML output.
- *
+ *
* @author mb
* @since 4.0
*/
-public class MarkupCharacterTranslator implements ICharacterTranslator
-{
+public class MarkupCharacterTranslator implements ICharacterTranslator {
private static final String SAFE_CHARACTERS = "01234567890"
- + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- + "\t\n\r !#$%'()*+,-./:;[EMAIL PROTECTED]|}~";
+ +
"abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ + "\t\n\r
!#$%'()*+,-./:;[EMAIL PROTECTED]|}~";
- private static final String[][] ENTITIES = { { "\"", """ },
- { "<", "<" }, { ">", ">" }, { "&", "&" } };
+ private static final String[][] ENTITIES = {
+ {"\"", """},
+ {"<", "<"}, {">", ">"}, {"&", "&"}
+ };
- private static final ICharacterMatcher SAFE_MATCHER = new
AsciiCharacterMatcher(
- SAFE_CHARACTERS);
- private static final ICharacterTranslator ENTITY_TRANSLATOR = new
AsciiCharacterTranslator(
- ENTITIES);
+ private static final ICharacterMatcher SAFE_MATCHER = new
AsciiCharacterMatcher(SAFE_CHARACTERS);
+ private static final ICharacterTranslator ENTITY_TRANSLATOR = new
AsciiCharacterTranslator(ENTITIES);
private boolean _encodeNonAscii;
private ICharacterMatcher _safeMatcher;
@@ -52,7 +51,7 @@
}
public MarkupCharacterTranslator(boolean encodeNonAscii,
- ICharacterMatcher safeMatcher, ICharacterTranslator
entityTranslator)
+ ICharacterMatcher safeMatcher,
ICharacterTranslator entityTranslator)
{
_encodeNonAscii = encodeNonAscii;
_safeMatcher = safeMatcher;
@@ -60,7 +59,7 @@
}
public MarkupCharacterTranslator(boolean encodeNonAscii,
- String safeCharacters, String[][] entities)
+ String safeCharacters, String[][]
entities)
{
_encodeNonAscii = encodeNonAscii;
_safeMatcher = new AsciiCharacterMatcher(safeCharacters);
@@ -74,12 +73,15 @@
{
// IE and Firefox do not handle characters between 128 and 159 well,
// so they have to be quoted as well
- if (ch >= 160 && !_encodeNonAscii) return null;
+ if (ch >= 160 && !_encodeNonAscii)
+ return null;
- if (_safeMatcher.matches(ch)) return null;
+ if (_safeMatcher.matches(ch))
+ return null;
String entity = _entityTranslator.translate(ch);
- if (entity != null) return entity;
+ if (entity != null)
+ return entity;
// needs to use a NumberFormat here to be fully compliant,
// but this is accepted fine by the browsers
Modified:
tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/form/LinkSubmitTest.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/form/LinkSubmitTest.java?view=diff&rev=546712&r1=546711&r2=546712
==============================================================================
---
tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/form/LinkSubmitTest.java
(original)
+++
tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/form/LinkSubmitTest.java
Tue Jun 12 19:35:05 2007
@@ -66,25 +66,26 @@
{
IMarkupWriter writer = newBufferWriter();
IRequestCycle cycle = newCycle();
- IScript script = new ScriptFixture();
- PageRenderSupport support = newPageRenderSupport();
-
IForm form = newForm();
- LinkSubmit linkSubmit = newInstance(LinkSubmit.class, "form", form,
"name", "fred_1", "script", script,
- "id", "fred_id", "clientId",
"fred_1", "submitType", "submit");
-
+ LinkSubmit linkSubmit = newInstance(LinkSubmit.class,
+ "form", form,
+ "name", "fred_1",
+ "id", "fred_id",
+ "clientId", "fred_1",
+ "submitType",
FormConstants.SUBMIT_NORMAL);
+
+ expect(form.getClientId()).andReturn("form");
+ trainResponseBuilder(cycle, writer);
linkSubmit.addBody(newBody());
- trainGetSupport(cycle, support);
- trainResponseBuilder(cycle, writer);
-
+
replay();
linkSubmit.renderFormComponent(writer, cycle);
verify();
- assertBuffer("<a href=\"#\" id=\"fred_1\">BODY</a>");
+ assertBuffer("<a href=\"javascript:tapestry.form.submit('form',
'fred_1');\" id=\"fred_1\">BODY</a>");
}
public void test_Render_Disabled()
@@ -94,7 +95,12 @@
IForm form = newForm();
- LinkSubmit linkSubmit = newInstance(LinkSubmit.class, "disabled",
Boolean.TRUE, "form", form, "name", "fred_1", "idParameter", "fred_id");
+ LinkSubmit linkSubmit = newInstance(LinkSubmit.class,
+ "disabled", Boolean.TRUE,
+ "form", form,
+ "name", "fred_1",
+ "id", "fred_id",
+ "submitType",
FormConstants.SUBMIT_NORMAL);
linkSubmit.addBody(newBody());
trainResponseBuilder(cycle, writer);
@@ -112,8 +118,6 @@
{
IMarkupWriter writer = newBufferWriter();
IRequestCycle cycle = newCycle();
- IScript script = new ScriptFixture();
- PageRenderSupport support = newPageRenderSupport();
IEngineService engine = newMock(IEngineService.class);
ILink link = newMock(ILink.class);
@@ -127,14 +131,14 @@
"name", "submitMe",
"clientId", "submitMe",
"submitType",
FormConstants.SUBMIT_NORMAL,
- "directService", engine,
- "submitScript", script);
+ "directService", engine);
+
+ expect(form.getClientId()).andReturn("form");
linkSubmit.addBody(newBody());
expect(engine.getLink(eq(true),
isA(DirectServiceParameter.class))).andReturn(link);
expect(link.getURL()).andReturn("http://submit");
- trainGetSupport(cycle, support);
trainResponseBuilder(cycle, writer);
replay();
@@ -143,7 +147,9 @@
verify();
- assertBuffer("<a href=\"#\" id=\"submitMe\">BODY</a>");
+ assertBuffer("<a href=\"http://submit\" " +
+ "onClick=\"tapestry.form.submit('form', 'submitMe'," +
+ "{async:true,json:false,url:this.href}); return false;\"
id=\"submitMe\">BODY</a>");
}
public void test_Prepare_Normal()