You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2010/10/10 19:27:44 UTC

svn commit: r1006321 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry5/internal/services/ main/java/org/apache/tapestry5/internal/services/ajax/ main/resources/org/apache/tapestry5/ test/java/org/apache/tapestry5/internal...

Author: hlship
Date: Sun Oct 10 17:27:43 2010
New Revision: 1006321

URL: http://svn.apache.org/viewvc?rev=1006321&view=rev
Log:
TAP5-1300: Make use of a special CSS class name of forms to prevent submission (when using Ajax updates)
Also, some simplifications to how JavaScript initializations occur in an Ajax update

Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinkerTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImplTest.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java?rev=1006321&r1=1006320&r2=1006321&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java Sun Oct 10 17:27:43 2010
@@ -28,8 +28,6 @@ public class PartialMarkupDocumentLinker
 
     private final JSONArray stylesheets = new JSONArray();
 
-    private final Map<InitializationPriority, StringBuilder> priorityToScript = CollectionFactory.newMap();
-
     private final Map<InitializationPriority, JSONObject> priorityToInits = CollectionFactory.newMap();
 
     public void addScriptLink(String scriptURL)
@@ -50,16 +48,8 @@ public class PartialMarkupDocumentLinker
 
     public void addScript(InitializationPriority priority, String script)
     {
-        StringBuilder builder = priorityToScript.get(priority);
-
-        if (builder == null)
-        {
-            builder = new StringBuilder();
-            priorityToScript.put(priority, builder);
-        }
-
-        builder.append(script);
-        builder.append("\n");
+        throw new UnsupportedOperationException(
+                "DocumentLinker.addScript() is not implemented for partial page renders.");
     }
 
     public void setInitialization(InitializationPriority priority, JSONObject initialization)
@@ -81,25 +71,16 @@ public class PartialMarkupDocumentLinker
         if (stylesheets.length() > 0)
             reply.put("stylesheets", stylesheets);
 
-        StringBuilder master = new StringBuilder();
         JSONArray inits = new JSONArray();
 
         for (InitializationPriority p : InitializationPriority.values())
         {
-            StringBuilder builder = priorityToScript.get(p);
-
-            if (builder != null)
-                master.append(builder);
-
             JSONObject init = priorityToInits.get(p);
 
             if (init != null)
                 inits.put(init);
         }
 
-        if (master.length() > 0)
-            reply.put("script", master.toString());
-
         if (inits.length() > 0)
             reply.put("inits", inits);
     }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImpl.java?rev=1006321&r1=1006320&r2=1006321&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImpl.java Sun Oct 10 17:27:43 2010
@@ -61,6 +61,8 @@ public class JavaScriptSupportImpl imple
 
     private final JavaScriptStackPathConstructor stackPathConstructor;
 
+    private final boolean partialMode;
+
     private FieldFocusPriority focusPriority;
 
     private String focusFieldId;
@@ -71,6 +73,24 @@ public class JavaScriptSupportImpl imple
         this(linker, javascriptStackSource, stackPathConstructor, new IdAllocator(), false);
     }
 
+    /**
+     * @param linker
+     *            responsible for assembling all the information gathered by JavaScriptSupport and
+     *            attaching it to the Document (for a full page render) or to the JSON response (in a partial render)
+     * @param javascriptStackSource
+     *            source of information about {@link JavaScriptStack}s, used when handling the import
+     *            of libraries and stacks (often, to handle transitive dependencies)
+     * @param stackPathConstructor
+     *            encapsulates the knowledge of how to represent a stack (which may be converted
+     *            from a series of JavaScript libraries into a single virtual JavaScript library)
+     * @param idAllocator
+     *            used when allocating unique ids (it is usually pre-initialized in an Ajax request to ensure
+     *            that newly allocated ids do not conflict with previous renders and partial updates)
+     * @param partialMode
+     *            if true, then the JSS configures itself for a partial page render (part of an Ajax request)
+     *            which automatically assumes the "core" library has been added (to the original page render)
+     *            and makes other minor changes to behavior.
+     */
     public JavaScriptSupportImpl(DocumentLinker linker, JavaScriptStackSource javascriptStackSource,
             JavaScriptStackPathConstructor stackPathConstructor, IdAllocator idAllocator, boolean partialMode)
     {
@@ -78,6 +98,7 @@ public class JavaScriptSupportImpl imple
         this.idAllocator = idAllocator;
         this.javascriptStackSource = javascriptStackSource;
         this.stackPathConstructor = stackPathConstructor;
+        this.partialMode = partialMode;
 
         // In partial mode, assume that the infrastructure stack is already present
         // (from the original page render).
@@ -167,13 +188,21 @@ public class JavaScriptSupportImpl imple
 
     public void addScript(InitializationPriority priority, String format, Object... arguments)
     {
-        addCoreStackIfNeeded();
         assert priority != null;
         assert InternalUtils.isNonBlank(format);
 
+        addCoreStackIfNeeded();
+
         String newScript = arguments.length == 0 ? format : String.format(format, arguments);
 
-        linker.addScript(priority, newScript);
+        if (partialMode)
+        {
+            addInitializerCall(priority, "evalScript", newScript);
+        }
+        else
+        {
+            linker.addScript(priority, newScript);
+        }
     }
 
     public void addScript(String format, Object... arguments)
@@ -266,12 +295,12 @@ public class JavaScriptSupportImpl imple
 
         stylesheetLinks.addAll(stack.getStylesheets());
 
+        addedStacks.put(stackName, true);
+
         String initialization = stack.getInitialization();
 
         if (initialization != null)
-            linker.addScript(InitializationPriority.IMMEDIATE, initialization);
-
-        addedStacks.put(stackName, true);
+            addScript(InitializationPriority.IMMEDIATE, initialization);
     }
 
     public void importStylesheet(Asset stylesheet)

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js?rev=1006321&r1=1006320&r2=1006321&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js Sun Oct 10 17:27:43 2010
@@ -89,6 +89,11 @@ var Tapestry = {
 	/** Time, in seconds, that console messages are visible. */
 	CONSOLE_DURATION : 10,
 
+	/** CSS Class added to a <form> element that directs Tapestry to prevent normal
+	 *  (HTTP POST) form submission, in favor of Ajax (XmlHttpRequest) submission.
+	 */
+	PREVENT_SUBMISSION : "t-prevent-submission",
+	
 	/** Initially, false, set to true once the page is fully loaded. */
 	pageLoaded : false,
 
@@ -153,7 +158,7 @@ var Tapestry = {
 
 	},
 
-	/*
+	/**
 	 * Adds a callback function that will be invoked when the DOM is loaded
 	 * (which occurs *before* window.onload, which has to wait for images and
 	 * such to load first. This simply observes the dom:loaded event on the
@@ -297,8 +302,9 @@ var Tapestry = {
 	 * <dl>
 	 * <dt>redirectURL</dt>
 	 * <dd>URL to redirect to (in which case, the callback is not invoked)</dd>
-	 * <dt>scripts</dt>
-	 * <dd>Array of strings (URIs of scripts)</dd>
+	 * <dt>inits</dt>
+	 * <dd>Defines a set of calls to Tapestry.init() to perform initialization after the DOM
+	 * has been updated.</dd>
 	 * <dt>stylesheets</dt>
 	 * <dd>Array of hashes, each hash has key href and optional key media</dd>
 	 * 
@@ -325,34 +331,31 @@ var Tapestry = {
 			/* Let the caller do its thing first (i.e., modify the DOM). */
 			callback.call(this);
 
-			Tapestry.executeReplyScripts(reply.script, reply.inits);
+			/* And handle the scripts after the DOM is updated. */
+			Tapestry.executeInits(reply.inits);
 		});
 	},
 
 	/**
-	 * Called from Tapestry.loadScriptsInReply to load the script block and any
+	 * Called from Tapestry.loadScriptsInReply to load  any
 	 * initializations from the Ajax partial page render response. Calls
-	 * Tapestry.onDomLoadedCallback() last.
+	 * Tapestry.onDomLoadedCallback() last. This logic must be deferred
+	 * until after the DOM is fully updated, as initialization often
+	 * refer to DOM elements.
 	 * 
-	 * @param scriptBlock
-	 *            block of JavaScript to evaluate (may be null)
 	 * @param initializations
 	 *            array of parameters to pass to Tapestry.init(), one invocation
 	 *            per element (may be null)
 	 */
-	executeReplyScripts : function(scriptBlock, initializations) {
+	executeInits : function(initializations) {
 
-		if (scriptBlock)
-			eval(scriptBlock);
-
-		if (initializations)
-			$A(initializations).each(function(spec) {
-				Tapestry.init(spec);
-			});
+		$A(initializations).each(function(spec) {
+			Tapestry.init(spec);
+		});
 
 		Tapestry.onDomLoadedCallback();
-
 	},
+	
 
 	/**
 	 * Default function for handling a communication error during an Ajax
@@ -917,6 +920,13 @@ Tapestry.Initializer = {
 		$(id).activate();
 	},
 
+	/**
+	 * evalScript is a synonym for the JavaScript eval function. It is used
+	 * in Ajax requests to handle any setup code that does not
+	 * fit into a standard Tapestry.Initializer call.
+	 */
+	evalScript : eval,
+	
 	ajaxFormLoop : function(spec) {
 		var rowInjector = $(spec.rowInjector);
 
@@ -1012,8 +1022,8 @@ Tapestry.Initializer = {
 
 		if (element.tagName == "FORM") {
 
-			element.getFormEventManager().preventSubmission = true;
-
+			element.addClassName(Tapestry.PREVENT_SUBMISSION);
+			
 			/*
 			 * After the form is validated and prepared, this code will process
 			 * the form submission via an Ajax call. The original submit event
@@ -1477,7 +1487,7 @@ Tapestry.FormEventManager = Class.create
 
 	handleSubmit : function(domevent) {
 
-		/**
+		/*
 		 * Necessary because we set the onsubmit property of the form, rather
 		 * than observing the event. But that's because we want to specfically
 		 * overwrite any other handlers.
@@ -1527,7 +1537,7 @@ Tapestry.FormEventManager = Class.create
 		 * via Ajax.Request.
 		 */
 
-		if (this.preventSubmission) {
+		if (this.form.hasClassName(Tapestry.PREVENT_SUBMISSION)) {
 			domevent.stop();
 
 			/*
@@ -2081,9 +2091,9 @@ Tapestry.ScriptManager = {
  * In the spirit of $(), $T() exists to access a hash of extra data about an
  * element. In release 5.1 and prior, a hash attached to the element by Tapestry
  * was returned. In 5.2, Prototype's storage object is returned, which is less
- * like to cause memory leaks in IE.
+ * likely to cause memory leaks in IE.
  * 
- * @deprecated With no specific replacement
+ * @deprecated With no specific replacement. To be removed after Tapestry 5.2.
  * @param element
  *            an element instance or element id
  * @return object Prototype storage object for the element

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinkerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinkerTest.java?rev=1006321&r1=1006320&r2=1006321&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinkerTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinkerTest.java Sun Oct 10 17:27:43 2010
@@ -24,36 +24,14 @@ import org.testng.annotations.Test;
 
 public class PartialMarkupDocumentLinkerTest extends Assert
 {
-    @Test
+    @Test(expectedExceptions = UnsupportedOperationException.class)
     public void script()
     {
         PartialMarkupDocumentLinker linker = new PartialMarkupDocumentLinker();
 
         linker.addScript(InitializationPriority.NORMAL, "foo();");
-        linker.addScript(InitializationPriority.NORMAL, "bar();");
-
-        JSONObject reply = new JSONObject();
-
-        linker.commit(reply);
-
-        assertEquals(reply.get("script"), "foo();\nbar();\n");
-    }
-
-    @Test
-    public void script_with_priorty()
-    {
-        PartialMarkupDocumentLinker linker = new PartialMarkupDocumentLinker();
-
-        linker.addScript(InitializationPriority.LATE, "late();");
-        linker.addScript(InitializationPriority.NORMAL, "normal();");
-        linker.addScript(InitializationPriority.IMMEDIATE, "immediate();");
-        linker.addScript(InitializationPriority.EARLY, "early();");
-
-        JSONObject reply = new JSONObject();
-
-        linker.commit(reply);
 
-        assertEquals(reply.get("script"), "immediate();\nearly();\nnormal();\nlate();\n");
+        throw new IllegalStateException("Unreachable code.");
     }
 
     @Test

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImplTest.java?rev=1006321&r1=1006320&r2=1006321&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImplTest.java Sun Oct 10 17:27:43 2010
@@ -65,11 +65,12 @@ public class JavaScriptSupportImplTest e
     }
 
     @Test
-    public void no_stack_or_dom_loading_callback_in_partial_mode()
+    public void partial_mode_add_script()
     {
         DocumentLinker linker = mockDocumentLinker();
 
-        linker.addScript(InitializationPriority.NORMAL, "doSomething();");
+        linker.setInitialization(InitializationPriority.NORMAL, new JSONObject(
+                "{ 'evalScript' : [ 'doSomething();' ] }"));
 
         replay();