You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2010/05/17 07:37:27 UTC

svn commit: r944978 [1/2] - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry5/corelib/components/ main/java/org/apache/tapestry5/internal/services/ main/java/org/apache/tapestry5/internal/services/ajax/ main/java/org/apache...

Author: hlship
Date: Mon May 17 05:37:26 2010
New Revision: 944978

URL: http://svn.apache.org/viewvc?rev=944978&view=rev
Log:
TAP5-1155: JavaScript initialization inside the partial page render Ajax response should be unquoted

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/json/JSONCollection.java   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/immediate_initialization.txt   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/other_initialization.txt   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/pretty_print_initialization.txt   (with props)
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Palette.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java
    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/java/org/apache/tapestry5/internal/translator/NumericTranslatorSupportImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/json/JSONArray.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/json/JSONObject.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/InitializationPriority.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/DocumentLinkerImplTest.java
    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
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/json/JSONObjectTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/add_script.txt
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/add_script_links.txt
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/add_script_links_at_top.txt
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/added_scripts_go_before_existing_script.txt
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/empty_document_with_scripts_at_top.txt
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/no_body_element.txt
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/script_written_raw.txt

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Palette.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Palette.java?rev=944978&r1=944977&r2=944978&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Palette.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Palette.java Mon May 17 05:37:26 2010
@@ -1,10 +1,10 @@
-// Copyright 2007, 2008, 2009 The Apache Software Foundation
+// Copyright 2007, 2008, 2009, 2010 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -22,23 +22,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import org.apache.tapestry5.Asset;
-import org.apache.tapestry5.Binding;
-import org.apache.tapestry5.BindingConstants;
-import org.apache.tapestry5.Block;
-import org.apache.tapestry5.ComponentResources;
-import org.apache.tapestry5.FieldValidationSupport;
-import org.apache.tapestry5.FieldValidator;
-import org.apache.tapestry5.MarkupWriter;
-import org.apache.tapestry5.OptionGroupModel;
-import org.apache.tapestry5.OptionModel;
-import org.apache.tapestry5.RenderSupport;
-import org.apache.tapestry5.Renderable;
-import org.apache.tapestry5.SelectModel;
-import org.apache.tapestry5.SelectModelVisitor;
-import org.apache.tapestry5.ValidationException;
-import org.apache.tapestry5.ValidationTracker;
-import org.apache.tapestry5.ValueEncoder;
+import org.apache.tapestry5.*;
 import org.apache.tapestry5.annotations.Environmental;
 import org.apache.tapestry5.annotations.IncludeJavaScriptLibrary;
 import org.apache.tapestry5.annotations.Parameter;
@@ -46,10 +30,12 @@ import org.apache.tapestry5.annotations.
 import org.apache.tapestry5.corelib.base.AbstractField;
 import org.apache.tapestry5.internal.util.SelectModelRenderer;
 import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.annotations.Symbol;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.json.JSONArray;
 import org.apache.tapestry5.services.ComponentDefaultProvider;
 import org.apache.tapestry5.services.Request;
+import org.apache.tapestry5.services.javascript.JavascriptSupport;
 
 /**
  * Multiple selection component. Generates a UI consisting of two <select> elements configured for multiple
@@ -68,8 +54,9 @@ import org.apache.tapestry5.services.Req
  * buttons appear to move items up and down within the selected list.
  * <p/>
  * Much of the look and feel is driven by CSS, the default Tapestry CSS is used to set up the columns, etc. By default,
- * the &lt;select&gt; element's widths are 200px, and  it is common to override this to a specific value:
+ * the &lt;select&gt; element's widths are 200px, and it is common to override this to a specific value:
  * <p/>
+ * 
  * <pre>
  * &lt;style&gt;
  * DIV.t-palette SELECT { width: 300px; }
@@ -92,11 +79,8 @@ public class Palette extends AbstractFie
     {
         public void render(MarkupWriter writer)
         {
-            writer.element("select",
-                           "id", getClientId() + "-avail",
-                           "multiple", "multiple",
-                           "size", getSize(),
-                           "name", getControlName() + "-avail");
+            writer.element("select", "id", getClientId() + "-avail", "multiple", "multiple", "size", getSize(), "name",
+                    getControlName() + "-avail");
 
             writeDisabled(writer, isDisabled());
 
@@ -156,18 +140,15 @@ public class Palette extends AbstractFie
     {
         public void render(MarkupWriter writer)
         {
-            writer.element("select",
-                           "id", getClientId(),
-                           "multiple", "multiple",
-                           "size", getSize(),
-                           "name", getControlName());
+            writer.element("select", "id", getClientId(), "multiple", "multiple", "size", getSize(), "name",
+                    getControlName());
 
             writeDisabled(writer, isDisabled());
-            
+
             putPropertyNameIntoBeanValidationContext("selected");
-            
+
             Palette.this.validate.render(writer);
-            
+
             removePropertyNameFromBeanValidationContext();
 
             for (Object value : getSelected())
@@ -210,8 +191,7 @@ public class Palette extends AbstractFie
      * conditionals and components. The default is the text "Available".
      */
     @Property(write = false)
-    @Parameter(required = true, allowNull = false, value = "message:available-label",
-               defaultPrefix = BindingConstants.LITERAL)
+    @Parameter(required = true, allowNull = false, value = "message:available-label", defaultPrefix = BindingConstants.LITERAL)
     private Block availableLabel;
 
     /**
@@ -219,8 +199,7 @@ public class Palette extends AbstractFie
      * conditionals and components. The default is the text "Available".
      */
     @Property(write = false)
-    @Parameter(required = true, allowNull = false, value = "message:selected-label",
-               defaultPrefix = BindingConstants.LITERAL)
+    @Parameter(required = true, allowNull = false, value = "message:selected-label", defaultPrefix = BindingConstants.LITERAL)
     private Block selectedLabel;
 
     /**
@@ -241,8 +220,8 @@ public class Palette extends AbstractFie
      * Used to include scripting code in the rendered page.
      */
     @Environmental
-    private RenderSupport renderSupport;
-    
+    private JavascriptSupport javascriptSupport;
+
     @Environmental
     private ValidationTracker tracker;
 
@@ -251,17 +230,16 @@ public class Palette extends AbstractFie
      */
     @Inject
     private Request request;
-    
+
     @Inject
     private ComponentDefaultProvider defaultProvider;
 
     @Inject
     private ComponentResources componentResources;
-    
+
     @Inject
     private FieldValidationSupport fieldValidationSupport;
 
-
     private SelectModelRenderer renderer;
 
     /**
@@ -299,17 +277,21 @@ public class Palette extends AbstractFie
      */
     @Parameter(value = "10")
     private int size;
-    
+
     /**
      * The object that will perform input validation. The validate binding prefix is generally used to provide
      * this object in a declarative fashion.
      * 
-     * @since 5.2.0.0
+     * @since 5.2.0
      */
     @Parameter(defaultPrefix = BindingConstants.VALIDATE)
     @SuppressWarnings("unchecked")
     private FieldValidator<Object> validate;
 
+    @Inject
+    @Symbol(SymbolConstants.COMPACT_JSON)
+    private boolean compactJSON;
+
     /**
      * The natural order of elements, in terms of their client ids.
      */
@@ -329,7 +311,7 @@ public class Palette extends AbstractFie
     protected void processSubmission(String elementName)
     {
         String parameterValue = request.getParameter(elementName + "-values");
-        
+
         this.tracker.recordInput(this, parameterValue);
 
         JSONArray values = new JSONArray(parameterValue);
@@ -338,12 +320,13 @@ public class Palette extends AbstractFie
 
         List<Object> selected = this.selected;
 
-        if (selected == null) selected = newList();
-        else selected.clear();
+        if (selected == null)
+            selected = newList();
+        else
+            selected.clear();
 
         ValueEncoder encoder = this.encoder;
 
-
         int count = values.length();
         for (int i = 0; i < count; i++)
         {
@@ -355,24 +338,25 @@ public class Palette extends AbstractFie
         }
 
         putPropertyNameIntoBeanValidationContext("selected");
-        
-        try 
+
+        try
         {
             this.fieldValidationSupport.validate(selected, this.componentResources, this.validate);
-            
+
             this.selected = selected;
-        } 
-        catch (final ValidationException e) 
+        }
+        catch (final ValidationException e)
         {
             this.tracker.recordError(this, e.getMessage());
         }
-        
+
         removePropertyNameFromBeanValidationContext();
     }
 
     private void writeDisabled(MarkupWriter writer, boolean disabled)
     {
-        if (disabled) writer.attributes("disabled", "disabled");
+        if (disabled)
+            writer.attributes("disabled", "disabled");
     }
 
     void beginRender(MarkupWriter writer)
@@ -397,13 +381,11 @@ public class Palette extends AbstractFie
 
         String clientId = getClientId();
 
-        renderSupport.addScript("new Tapestry.Palette('%s', %s, %s);", clientId, reorder, naturalOrder);
+        javascriptSupport.addScript("new Tapestry.Palette('%s', %s, %s);", clientId, reorder, naturalOrder
+                .toString(compactJSON));
 
-        writer.element("input",
-                       "type", "hidden",
-                       "id", clientId + "-values",
-                       "name", getControlName() + "-values",
-                       "value", selectedValues);
+        writer.element("input", "type", "hidden", "id", clientId + "-values", "name", getControlName() + "-values",
+                "value", selectedValues);
         writer.end();
     }
 
@@ -461,17 +443,16 @@ public class Palette extends AbstractFie
 
         model.visit(visitor);
     }
-    
+
     /**
      * Computes a default value for the "validate" parameter using
      * {@link org.apache.tapestry5.services.FieldValidatorDefaultSource}.
      */
-    Binding defaultValidate() 
+    Binding defaultValidate()
     {
-       return this.defaultProvider.defaultValidatorBinding("selected", this.componentResources);
+        return this.defaultProvider.defaultValidatorBinding("selected", this.componentResources);
     }
 
-
     // Avoids a strange Javassist bytecode error, c'est lavie!
     int getSize()
     {
@@ -485,11 +466,12 @@ public class Palette extends AbstractFie
 
     List<Object> getSelected()
     {
-        if (selected == null) return Collections.emptyList();
+        if (selected == null)
+            return Collections.emptyList();
 
         return selected;
     }
-    
+
     @Override
     public boolean isRequired()
     {

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java?rev=944978&r1=944977&r2=944978&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java Mon May 17 05:37:26 2010
@@ -1,10 +1,10 @@
-// Copyright 2007, 2008, 2009 The Apache Software Foundation
+// Copyright 2007, 2008, 2009, 2010 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -41,22 +41,29 @@ public class AjaxPartialResponseRenderer
 
     private final String outputEncoding;
 
+    private final boolean compactJSON;
+
     public AjaxPartialResponseRendererImpl(MarkupWriterFactory factory,
 
-                                           Request request,
+    Request request,
+
+    Response response,
 
-                                           Response response,
+    PartialMarkupRenderer partialMarkupRenderer,
 
-                                           PartialMarkupRenderer partialMarkupRenderer,
+    @Inject
+    @Symbol(SymbolConstants.CHARSET)
+    String outputEncoding,
 
-                                           @Inject @Symbol(SymbolConstants.CHARSET)
-                                           String outputEncoding)
+    @Symbol(SymbolConstants.COMPACT_JSON)
+    boolean compactJSON)
     {
         this.factory = factory;
         this.request = request;
         this.response = response;
         this.partialMarkupRenderer = partialMarkupRenderer;
         this.outputEncoding = outputEncoding;
+        this.compactJSON = compactJSON;
     }
 
     public void renderPartialPageMarkup() throws IOException
@@ -65,8 +72,7 @@ public class AjaxPartialResponseRenderer
         // separated, and trying to keep stateless and stateful (i.e., perthread scope) services
         // separated. So we inform the stateful queue service what it needs to do here ...
 
-        ContentType pageContentType =
-                (ContentType) request.getAttribute(InternalConstants.CONTENT_TYPE_ATTRIBUTE_NAME);
+        ContentType pageContentType = (ContentType) request.getAttribute(InternalConstants.CONTENT_TYPE_ATTRIBUTE_NAME);
 
         ContentType contentType = new ContentType(InternalConstants.JSON_MIME_TYPE, outputEncoding);
 
@@ -80,7 +86,10 @@ public class AjaxPartialResponseRenderer
 
         PrintWriter pw = response.getPrintWriter(contentType.toString());
 
-        pw.print(reply);
+        if (compactJSON)
+            reply.print(pw);
+        else
+            reply.prettyPrint(pw);
 
         pw.close();
     }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java?rev=944978&r1=944977&r2=944978&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java Mon May 17 05:37:26 2010
@@ -1,4 +1,4 @@
-// Copyright 2007, 2008 The Apache Software Foundation
+// Copyright 2007, 2008, 2010 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -14,6 +14,9 @@
 
 package org.apache.tapestry5.internal.services;
 
+import org.apache.tapestry5.json.JSONObject;
+import org.apache.tapestry5.services.javascript.InitializationPriority;
+
 /**
  * Responsible for injecting script and style links into the &lt;head&gt; and &lt;body&gt; element of the rendered HTML
  * document.
@@ -38,10 +41,27 @@ public interface DocumentLinker
 
     /**
      * Adds JavaScript code. The code is collected into a single block that is injected just before the close body tag
-     * of the page.
+     * of the page (in a full page render) and collected as the "script" property of the partial page render response.
+     * The JavaScript is executed after the page loads (or in an Ajax update, after external JavaScript libraries are
+     * loaded and the DOM is updated).
+     * <p>
+     * This method may be called multiple times for the same priority and the script will be accumulated.
      * 
+     * @param priority
+     *            when to execute the provided script
      * @param script
      *            statement to add to the block (a newline will be appended as well)
      */
-    void addScript(String script);
+    void addScript(InitializationPriority priority, String script);
+
+    /**
+     * Adds a call to the Tapestry.init() function. This may be called multiple times and the init() calls will occur
+     * in order. In a normal page render, the init() calls will be added to the main JavaScript block, but in a partial
+     * page render Ajax response, the initialization will be property "init" of the partial page render response.
+     * <p>
+     * This method should only be invoked at most once per priority.
+     * 
+     * @since 5.2.0
+     */
+    void setInitialization(InitializationPriority priority, JSONObject initialization);
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java?rev=944978&r1=944977&r2=944978&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java Mon May 17 05:37:26 2010
@@ -15,6 +15,8 @@
 package org.apache.tapestry5.internal.services;
 
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import org.apache.tapestry5.dom.Document;
 import org.apache.tapestry5.dom.Element;
@@ -22,30 +24,42 @@ import org.apache.tapestry5.dom.Node;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.Func;
 import org.apache.tapestry5.ioc.internal.util.Operation;
+import org.apache.tapestry5.json.JSONObject;
+import org.apache.tapestry5.services.javascript.InitializationPriority;
 
 public class DocumentLinkerImpl implements DocumentLinker
 {
     private final List<String> scripts = CollectionFactory.newList();
 
-    private final StringBuilder scriptBlock = new StringBuilder();
+    private final Map<InitializationPriority, StringBuilder> priorityToScript = CollectionFactory.newMap();
+
+    private final Map<InitializationPriority, JSONObject> priorityToInit = CollectionFactory.newMap();
 
     private final List<IncludedStylesheet> includedStylesheets = CollectionFactory.newList();
 
+    private final boolean compactJSON;
+
     private final boolean omitGeneratorMetaTag;
 
     private final String tapestryBanner;
 
+    private boolean hasDynamicScript;
+
     /**
      * @param omitGeneratorMetaTag
      *            via symbol configuration
      * @param tapestryVersion
      *            version of Tapestry framework (for meta tag)
+     * @param compactJSON
+     *            should JSON content be compact or pretty printed?
      */
-    public DocumentLinkerImpl(boolean omitGeneratorMetaTag, String tapestryVersion)
+    public DocumentLinkerImpl(boolean omitGeneratorMetaTag, String tapestryVersion, boolean compactJSON)
     {
         this.omitGeneratorMetaTag = omitGeneratorMetaTag;
 
         tapestryBanner = String.format("Apache Tapestry Framework (version %s)", tapestryVersion);
+
+        this.compactJSON = compactJSON;
     }
 
     public void addStylesheetLink(String styleURL, String media)
@@ -58,9 +72,29 @@ public class DocumentLinkerImpl implemen
         scripts.add(scriptURL);
     }
 
-    public void addScript(String script)
+    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");
+
+        hasDynamicScript = true;
+    }
+
+    public void setInitialization(InitializationPriority priority, JSONObject initialization)
     {
-        scriptBlock.append(script);
+        priorityToInit.put(priority, initialization);
+
+        hasDynamicScript = true;
     }
 
     /**
@@ -95,7 +129,7 @@ public class DocumentLinkerImpl implemen
 
     private void addScriptElements(Element root)
     {
-        if (scripts.isEmpty() && scriptBlock.length() == 0)
+        if (scripts.isEmpty() && !hasDynamicScript)
             return;
 
         // This only applies when the document is an HTML document. This may need to change in the
@@ -113,7 +147,8 @@ public class DocumentLinkerImpl implemen
 
         addScriptLinksForIncludedScripts(container, scripts);
 
-        addDynamicScriptBlock(findOrCreateElement(root, "body", false));
+        if (hasDynamicScript)
+            addDynamicScriptBlock(findOrCreateElement(root, "body", false));
     }
 
     private Element findOrCreateElement(Element root, String childElement, boolean atTop)
@@ -136,12 +171,55 @@ public class DocumentLinkerImpl implemen
      */
     protected void addDynamicScriptBlock(Element body)
     {
-        if (scriptBlock.length() == 0)
-            return;
+        StringBuilder block = new StringBuilder();
+
+        boolean wrapped = false;
+
+        for (InitializationPriority p : InitializationPriority.values())
+        {
+            if (p != InitializationPriority.IMMEDIATE && !wrapped
+                    && (priorityToScript.containsKey(p) || priorityToInit.containsKey(p)))
+            {
+
+                block.append("Tapestry.onDOMLoaded(function() {\n");
+
+                wrapped = true;
+            }
+
+            add(block, p);
+        }
+
+        if (wrapped)
+            block.append("});\n");
 
         Element e = body.element("script", "type", "text/javascript");
 
-        e.raw(scriptBlock.toString());
+        e.raw(block.toString());
+
+    }
+
+    private void add(StringBuilder block, InitializationPriority priority)
+    {
+        add(block, priorityToScript.get(priority));
+        add(block, priorityToInit.get(priority));
+    }
+
+    private void add(StringBuilder block, JSONObject init)
+    {
+        if (init == null)
+            return;
+
+        block.append("Tapestry.init(");
+        block.append(init.toString(compactJSON));
+        block.append(");\n");
+    }
+
+    private void add(StringBuilder block, StringBuilder content)
+    {
+        if (content == null)
+            return;
+
+        block.append(content);
     }
 
     /**

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=944978&r1=944977&r2=944978&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 Mon May 17 05:37:26 2010
@@ -14,17 +14,23 @@
 
 package org.apache.tapestry5.internal.services;
 
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.json.JSONArray;
 import org.apache.tapestry5.json.JSONObject;
+import org.apache.tapestry5.services.javascript.InitializationPriority;
 
 public class PartialMarkupDocumentLinker implements DocumentLinker
 {
-    private final StringBuilder buffer = new StringBuilder(1000);
-
     private final JSONArray scripts = new JSONArray();
 
     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)
     {
         scripts.put(scriptURL);
@@ -41,10 +47,23 @@ public class PartialMarkupDocumentLinker
         stylesheets.put(object);
     }
 
-    public void addScript(String script)
+    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");
+    }
+
+    public void setInitialization(InitializationPriority priority, JSONObject initialization)
     {
-        buffer.append(script);
-        buffer.append("\n");
+        priorityToInits.put(priority, initialization);
     }
 
     /**
@@ -55,14 +74,32 @@ public class PartialMarkupDocumentLinker
      */
     public void commit(JSONObject reply)
     {
-        if (buffer.length() > 0)
-            reply.put("script", buffer.toString());
-
         if (scripts.length() > 0)
             reply.put("scripts", scripts);
 
         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=944978&r1=944977&r2=944978&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 Mon May 17 05:37:26 2010
@@ -55,10 +55,6 @@ public class JavascriptSupportImpl imple
 
     private final DocumentLinker linker;
 
-    private final boolean partialMode;
-
-    private final boolean compactMode;
-
     // Using a Map as a case-insensitive set of stack names.
 
     private final Map<String, Boolean> addedStacks = CollectionFactory.newCaseInsensitiveMap();
@@ -73,8 +69,6 @@ public class JavascriptSupportImpl imple
 
     private final List<Stylesheet> otherStylesheets = CollectionFactory.newList();
 
-    private final Map<InitializationPriority, StringBuilder> scripts = CollectionFactory.newMap();
-
     private final Map<InitializationPriority, JSONObject> inits = CollectionFactory.newMap();
 
     private final JavascriptStackSource javascriptStackSource;
@@ -90,20 +84,17 @@ public class JavascriptSupportImpl imple
     };
 
     public JavascriptSupportImpl(DocumentLinker linker, JavascriptStackSource javascriptStackSource,
-            JavascriptStackPathConstructor stackPathConstructor, boolean compactMode)
+            JavascriptStackPathConstructor stackPathConstructor)
     {
-        this(linker, javascriptStackSource, stackPathConstructor, new IdAllocator(), false, compactMode);
+        this(linker, javascriptStackSource, stackPathConstructor, new IdAllocator(), false);
     }
 
     public JavascriptSupportImpl(DocumentLinker linker, JavascriptStackSource javascriptStackSource,
-            JavascriptStackPathConstructor stackPathConstructor, IdAllocator idAllocator, boolean partialMode,
-            boolean compactMode)
+            JavascriptStackPathConstructor stackPathConstructor, IdAllocator idAllocator, boolean partialMode)
     {
         this.linker = linker;
         this.idAllocator = idAllocator;
         this.javascriptStackSource = javascriptStackSource;
-        this.partialMode = partialMode;
-        this.compactMode = compactMode | partialMode;
         this.stackPathConstructor = stackPathConstructor;
 
         // In partial mode, assume that the infrastructure stack is already present
@@ -142,65 +133,15 @@ public class JavascriptSupportImpl imple
         Func.each(linkLibrary, stackLibraries);
         Func.each(linkLibrary, otherLibraries);
 
-        convertInitsToScriptBlocks();
-
-        if (scripts.isEmpty())
-            return;
-
-        String masterBlock = assembleMasterScriptBlock();
-
-        linker.addScript(masterBlock);
-    }
-
-    private String assembleMasterScriptBlock()
-    {
-        StringBuilder master = new StringBuilder();
-
-        addIfNonNull(master, InitializationPriority.IMMEDIATE);
-
-        addDomLoadedScriptBlocks(master);
-
-        return master.toString();
-    }
-
-    private void addDomLoadedScriptBlocks(StringBuilder master)
-    {
-        if (scripts.containsKey(InitializationPriority.EARLY) || scripts.containsKey(InitializationPriority.NORMAL)
-                || scripts.containsKey(InitializationPriority.LATE))
-        {
-            if (!partialMode)
-                master.append("Tapestry.onDOMLoaded(function() {\n");
-
-            addIfNonNull(master, InitializationPriority.EARLY);
-            addIfNonNull(master, InitializationPriority.NORMAL);
-            addIfNonNull(master, InitializationPriority.LATE);
-
-            if (!partialMode)
-                master.append("});");
-        }
-    }
-
-    private void convertInitsToScriptBlocks()
-    {
         for (InitializationPriority p : InitializationPriority.values())
         {
             JSONObject init = inits.get(p);
 
             if (init != null)
-            {
-                String printed = compactMode ? init.toCompactString() : init.toString();
-
-                addScript(p, "Tapestry.init(%s);", printed);
-            }
+                linker.setInitialization(p, init);
         }
     }
 
-    private void addIfNonNull(StringBuilder builder, InitializationPriority priority)
-    {
-        if (scripts.containsKey(priority))
-            builder.append(scripts.get(priority).toString());
-    }
-
     public void addInitializerCall(InitializationPriority priority, String functionName, JSONObject parameter)
     {
         storeInitializerCall(priority, functionName, parameter);
@@ -257,21 +198,7 @@ public class JavascriptSupportImpl imple
 
         String newScript = arguments.length == 0 ? format : String.format(format, arguments);
 
-        appendScript(priority, newScript);
-    }
-
-    private void appendScript(InitializationPriority priority, String newScript)
-    {
-        StringBuilder script = scripts.get(priority);
-
-        if (script == null)
-        {
-            script = new StringBuilder();
-            scripts.put(priority, script);
-        }
-
-        script.append(newScript);
-        script.append("\n");
+        linker.addScript(priority, newScript);
     }
 
     public void addScript(String format, Object... arguments)
@@ -327,7 +254,7 @@ public class JavascriptSupportImpl imple
         String initialization = stack.getInitialization();
 
         if (initialization != null)
-            appendScript(InitializationPriority.IMMEDIATE, initialization);
+            linker.addScript(InitializationPriority.IMMEDIATE, initialization);
 
         addedStacks.put(stackName, true);
     }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/translator/NumericTranslatorSupportImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/translator/NumericTranslatorSupportImpl.java?rev=944978&r1=944977&r2=944978&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/translator/NumericTranslatorSupportImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/translator/NumericTranslatorSupportImpl.java Mon May 17 05:37:26 2010
@@ -1,10 +1,10 @@
-// Copyright 2009 The Apache Software Foundation
+// Copyright 2009, 2010 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,15 +14,6 @@
 
 package org.apache.tapestry5.internal.translator;
 
-import org.apache.tapestry5.Field;
-import org.apache.tapestry5.RenderSupport;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.services.ThreadLocale;
-import org.apache.tapestry5.ioc.services.TypeCoercer;
-import org.apache.tapestry5.json.JSONObject;
-import org.apache.tapestry5.services.ClientBehaviorSupport;
-import org.apache.tapestry5.services.Request;
-
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.text.DecimalFormat;
@@ -33,6 +24,18 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.tapestry5.Field;
+import org.apache.tapestry5.SymbolConstants;
+import org.apache.tapestry5.ioc.annotations.Symbol;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.services.ThreadLocale;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+import org.apache.tapestry5.json.JSONObject;
+import org.apache.tapestry5.services.ClientBehaviorSupport;
+import org.apache.tapestry5.services.Request;
+import org.apache.tapestry5.services.javascript.InitializationPriority;
+import org.apache.tapestry5.services.javascript.JavascriptSupport;
+
 public class NumericTranslatorSupportImpl implements NumericTranslatorSupport
 {
     private final TypeCoercer typeCoercer;
@@ -41,10 +44,12 @@ public class NumericTranslatorSupportImp
 
     private final Request request;
 
-    private final RenderSupport renderSupport;
+    private final JavascriptSupport javascriptSupport;
 
     private final ClientBehaviorSupport clientBehaviorSupport;
 
+    private final boolean compactJSON;
+
     private final Map<Locale, DecimalFormatSymbols> symbolsCache = CollectionFactory.newConcurrentMap();
 
     private final Set<Class> integerTypes = CollectionFactory.newSet();
@@ -52,17 +57,19 @@ public class NumericTranslatorSupportImp
     private static final String DECIMAL_FORMAT_SYMBOLS_PROVIDED = "tapestry.decimal-format-symbols-provided";
 
     public NumericTranslatorSupportImpl(TypeCoercer typeCoercer, ThreadLocale threadLocale, Request request,
-                                        RenderSupport renderSupport, ClientBehaviorSupport clientBehaviorSupport)
+            JavascriptSupport javascriptSupport, ClientBehaviorSupport clientBehaviorSupport, 
+            @Symbol(SymbolConstants.COMPACT_JSON)
+            boolean compactJSON)
     {
         this.typeCoercer = typeCoercer;
         this.threadLocale = threadLocale;
         this.request = request;
-        this.renderSupport = renderSupport;
+        this.javascriptSupport = javascriptSupport;
         this.clientBehaviorSupport = clientBehaviorSupport;
+        this.compactJSON = compactJSON;
 
-        Class[] integerTypes = {
-                Byte.class, Short.class, Integer.class, Long.class, BigInteger.class
-        };
+        Class[] integerTypes =
+        { Byte.class, Short.class, Integer.class, Long.class, BigInteger.class };
 
         for (Class c : integerTypes)
             this.integerTypes.add(c);
@@ -73,7 +80,8 @@ public class NumericTranslatorSupportImp
     {
         if (request.getAttribute(DECIMAL_FORMAT_SYMBOLS_PROVIDED) == null)
         {
-            renderSupport.addScript("Tapestry.decimalFormatSymbols = %s;", createJSONDecimalFormatSymbols());
+            javascriptSupport.addScript(InitializationPriority.IMMEDIATE, "Tapestry.decimalFormatSymbols = %s;",
+                    createJSONDecimalFormatSymbols().toString(compactJSON));
 
             request.setAttribute(DECIMAL_FORMAT_SYMBOLS_PROVIDED, true);
         }
@@ -167,7 +175,6 @@ public class NumericTranslatorSupportImp
         if (type.equals(BigDecimal.class))
             return new BigDecimalNumericFormatter(symbols);
 
-
         // We don't cache the rest of these, because they are built on DecimalFormat which is
         // not thread safe.
 
@@ -190,9 +197,7 @@ public class NumericTranslatorSupportImp
 
     public <T extends Number> String getMessageKey(Class<T> type)
     {
-        return isIntegerType(type)
-               ? "integer-format-exception"
-               : "number-format-exception";
+        return isIntegerType(type) ? "integer-format-exception" : "number-format-exception";
     }
 
     private static String toString(char ch)

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/json/JSONArray.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/json/JSONArray.java?rev=944978&r1=944977&r2=944978&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/json/JSONArray.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/json/JSONArray.java Mon May 17 05:37:26 2010
@@ -1,4 +1,4 @@
-// Copyright 2007, 2008 The Apache Software Foundation
+// Copyright 2007, 2008, 2010 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -34,7 +34,6 @@ package org.apache.tapestry5.json;
  * SOFTWARE.
  */
 
-import java.io.PrintWriter;
 import java.util.List;
 
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
@@ -74,7 +73,7 @@ import org.apache.tapestry5.ioc.internal
  * @author JSON.org
  * @version 2
  */
-public final class JSONArray
+public final class JSONArray extends JSONCollection
 {
 
     /**
@@ -380,21 +379,6 @@ public final class JSONArray
         return this;
     }
 
-    /**
-     * Make a JSON text of this JSONArray.
-     * <p/>
-     * Warning: This method assumes that the data structure is acyclical.
-     * <p>
-     * Starting in release 5.2, the result will be pretty printed for readability.
-     * 
-     * @return a printable, displayable, transmittable representation of the array.
-     */
-    @Override
-    public String toString()
-    {
-        return JSONObject.toString(this);
-    }
-
     /** Used for testing. */
     Object[] toArray()
     {
@@ -442,28 +426,4 @@ public final class JSONArray
 
         session.printSymbol(']');
     }
-
-    /**
-     * Prints the JSONArray to the writer compactly (with no extra whitespace).
-     * 
-     * @since 5.2.0
-     */
-    public JSONArray print(PrintWriter writer)
-    {
-        print(new CompactSession(writer));
-
-        return this;
-    }
-
-    /**
-     * Prints the JSONArray to the writer using indentation (two spaces per indentation level).
-     * 
-     * @since 5.2.0
-     */
-    public JSONArray prettyPrint(PrintWriter writer)
-    {
-        print(new PrettyPrintSession(writer));
-
-        return this;
-    }
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/json/JSONCollection.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/json/JSONCollection.java?rev=944978&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/json/JSONCollection.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/json/JSONCollection.java Mon May 17 05:37:26 2010
@@ -0,0 +1,103 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.json;
+
+import java.io.CharArrayWriter;
+import java.io.PrintWriter;
+
+/**
+ * Base class for {@link JSONArray} and {@link JSONObject} that exists to organize the code
+ * for printing such objects (either compact or pretty).
+ * 
+ * @since 5.2.0
+ */
+public abstract class JSONCollection
+{
+    /**
+     * Converts this JSON collection into a parsable string representation.
+     * <p/>
+     * Warning: This method assumes that the data structure is acyclical.
+     * <p>
+     * Starting in release 5.2, the result will be pretty printed for readability.
+     * 
+     * @return a printable, displayable, portable, transmittable representation of the object, beginning with
+     *         <code>{</code>&nbsp;<small>(left brace)</small> and ending with <code>}</code>&nbsp;<small>(right
+     *         brace)</small>.
+     */
+    @Override
+    public String toString()
+    {
+        CharArrayWriter caw = new CharArrayWriter();
+        PrintWriter pw = new PrintWriter(caw);
+
+        JSONPrintSession session = new PrettyPrintSession(pw);
+
+        print(session);
+
+        pw.close();
+
+        return caw.toString();
+    }
+
+    /**
+     * Converts the JSONObject to a compact or pretty-print string representation
+     * 
+     * @param compact
+     *            if true, return minimal format string.
+     * @since 5.2.0
+     */
+    public String toString(boolean compact)
+    {
+        return compact ? toCompactString() : toString();
+    }
+
+    /**
+     * Prints the JSONObject as a compact string (not extra punctuation). This is, essentially, what
+     * Tapestry 5.1 did inside {@link #toString()}.
+     */
+    public String toCompactString()
+    {
+        CharArrayWriter caw = new CharArrayWriter();
+        PrintWriter pw = new PrintWriter(caw);
+
+        print(pw);
+
+        pw.close();
+
+        return caw.toString();
+    }
+
+    /**
+     * Prints the JSONObject to the writer compactly (with no extra whitespace).
+     */
+    public void print(PrintWriter writer)
+    {
+        print(new CompactSession(writer));
+    }
+
+    /**
+     * Prints the JSONObject to the writer using indentation (two spaces per indentation level).
+     */
+    public void prettyPrint(PrintWriter writer)
+    {
+        print(new PrettyPrintSession(writer));
+    }
+
+    /**
+     * Print the collection in a parsable format using the session to (optionally) inject extra
+     * whitespace (for "pretty printing").
+     */
+    abstract void print(JSONPrintSession session);
+}

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/json/JSONCollection.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/json/JSONObject.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/json/JSONObject.java?rev=944978&r1=944977&r2=944978&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/json/JSONObject.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/json/JSONObject.java Mon May 17 05:37:26 2010
@@ -34,15 +34,13 @@ package org.apache.tapestry5.json;
  * SOFTWARE.
  */
 
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-
-import java.io.CharArrayWriter;
-import java.io.PrintWriter;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+
 /**
  * A JSONObject is an unordered collection of name/value pairs. Its external form is a string wrapped in curly braces
  * with colons between the names and values, and commas between the values and names. The internal form is an object
@@ -99,7 +97,7 @@ import java.util.Set;
  */
 @SuppressWarnings(
 { "CloneDoesntCallSuperClone" })
-public final class JSONObject
+public final class JSONObject extends JSONCollection
 {
 
     /**
@@ -805,85 +803,6 @@ public final class JSONObject
     }
 
     /**
-     * Make a JSON text of this JSONObject. For compactness, no whitespace is added. If this would not result in a
-     * syntactically correct JSON text, then null will be returned instead
-     * <p/>
-     * Warning: This method assumes that the data structure is acyclical.
-     * <p>
-     * Starting in release 5.2, the result will be pretty printed for readability.
-     * 
-     * @return a printable, displayable, portable, transmittable representation of the object, beginning with
-     *         <code>{</code>&nbsp;<small>(left brace)</small> and ending with <code>}</code>&nbsp;<small>(right
-     *         brace)</small>.
-     */
-    @Override
-    public String toString()
-    {
-        return toString(this);
-    }
-
-    /**
-     * Prints the JSONArray as a compact string (not extra punctuation). This is, essentially, what
-     * Tapestry 5.1 did inside {@link #toString()}.
-     * 
-     * @since 5.2.0
-     */
-    public String toCompactString()
-    {
-        CharArrayWriter caw = new CharArrayWriter();
-        PrintWriter pw = new PrintWriter(caw);
-
-        print(pw);
-
-        pw.close();
-
-        return caw.toString();
-    }
-
-    /**
-     * Creates a {@link PrettyPrintSession} to print the value (a JSONArray or JSONObject).
-     * 
-     * @since 5.2.0
-     */
-    static String toString(Object value)
-    {
-        CharArrayWriter caw = new CharArrayWriter();
-        PrintWriter pw = new PrintWriter(caw);
-
-        JSONPrintSession session = new PrettyPrintSession(pw);
-
-        printValue(session, value);
-
-        pw.close();
-
-        return caw.toString();
-    }
-
-    /**
-     * Prints the JSONObject to the writer compactly (with no extra whitespace).
-     * 
-     * @since 5.2.0
-     */
-    public JSONObject print(PrintWriter writer)
-    {
-        print(new CompactSession(writer));
-
-        return this;
-    }
-
-    /**
-     * Prints the JSONObject to the writer using indentation (two spaces per indentation level).
-     * 
-     * @since 5.2.0
-     */
-    public JSONObject prettyPrint(PrintWriter writer)
-    {
-        print(new PrettyPrintSession(writer));
-
-        return this;
-    }
-
-    /**
      * Prints the JSONObject using the session.
      * 
      * @since 5.2.0

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java?rev=944978&r1=944977&r2=944978&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java Mon May 17 05:37:26 2010
@@ -1951,7 +1951,7 @@ public final class TapestryModule
         {
             public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer)
             {
-                DocumentLinkerImpl linker = new DocumentLinkerImpl(omitGeneratorMeta, tapestryVersion);
+                DocumentLinkerImpl linker = new DocumentLinkerImpl(omitGeneratorMeta, tapestryVersion, compactJSON);
 
                 environment.push(DocumentLinker.class, linker);
 
@@ -1970,7 +1970,7 @@ public final class TapestryModule
                 DocumentLinker linker = environment.peekRequired(DocumentLinker.class);
 
                 JavascriptSupportImpl support = new JavascriptSupportImpl(linker, javascriptStackSource,
-                        javascriptStackPathConstructor, compactJSON);
+                        javascriptStackPathConstructor);
 
                 environment.push(JavascriptSupport.class, support);
 
@@ -2133,7 +2133,7 @@ public final class TapestryModule
                 DocumentLinker linker = environment.peekRequired(DocumentLinker.class);
 
                 JavascriptSupportImpl support = new JavascriptSupportImpl(linker, javascriptStackSource,
-                        javascriptStackPathConstructor, idAllocator, true, true);
+                        javascriptStackPathConstructor, idAllocator, true);
 
                 environment.push(JavascriptSupport.class, support);
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/InitializationPriority.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/InitializationPriority.java?rev=944978&r1=944977&r2=944978&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/InitializationPriority.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/InitializationPriority.java Mon May 17 05:37:26 2010
@@ -22,7 +22,10 @@ package org.apache.tapestry5.services.ja
  */
 public enum InitializationPriority
 {
-    /** Provided JavaScript will be executed immediately (it is not deferred until the page loads). */
+    /**
+     * Provided JavaScript will be executed immediately (it is not deferred until the page loads). In an Ajax
+     * update, IMMEDIATE code executed after the DOM is updated and before EARLY.
+     */
     IMMEDIATE,
 
     /** Execution is deferred until the page loads. All early execution occurs before {@link #NORMAL}. */

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=944978&r1=944977&r2=944978&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 Mon May 17 05:37:26 2010
@@ -314,19 +314,36 @@ var Tapestry = {
 		Tapestry.ScriptManager.addStylesheets(reply.stylesheets);
 
 		Tapestry.ScriptManager.addScripts(reply.scripts, function() {
+			/* Let the caller do its thing first (i.e., modify the DOM). */
 			callback.call(this);
 
-			/*
-			 * After the callback updates the DOM (presumably), continue on with
-			 * evaluating the reply.script and other final steps.
-			 */
+			Tapestry.executeReplyScripts(reply.script, reply.inits);
+		});
+	},
 
-			if (reply.script)
-				eval(reply.script);
+	/**
+	 * Called from Tapestry.loadScriptsInReply to load the script block and any
+	 * initializations from the Ajax partial page render response. Calls
+	 * Tapestry.onDomLoadedCallback() last.
+	 * 
+	 * @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) {
 
-			Tapestry.onDomLoadedCallback();
+		if (scriptBlock)
+			eval(scriptBlock);
+
+		if (initializations)
+			$A(initializations).each(function(spec) {
+				Tapestry.init(spec);
+			});
+
+		Tapestry.onDomLoadedCallback();
 
-		});
 	},
 
 	/**
@@ -2019,9 +2036,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.
+ * 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.
  * 
  * @deprecated With no specific replacement
  * @param element

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.java?rev=944978&r1=944977&r2=944978&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.java Mon May 17 05:37:26 2010
@@ -18,21 +18,13 @@ import org.apache.tapestry5.dom.Document
 import org.apache.tapestry5.dom.Element;
 import org.apache.tapestry5.dom.XMLMarkupModel;
 import org.apache.tapestry5.internal.test.InternalBaseTestCase;
-import org.apache.tapestry5.services.URLEncoder;
-import org.testng.annotations.BeforeClass;
+import org.apache.tapestry5.json.JSONArray;
+import org.apache.tapestry5.json.JSONObject;
+import org.apache.tapestry5.services.javascript.InitializationPriority;
 import org.testng.annotations.Test;
 
 public class DocumentLinkerImplTest extends InternalBaseTestCase
 {
-
-    private URLEncoder urlEncoder;
-
-    @BeforeClass
-    public void setup()
-    {
-        urlEncoder = getService(URLEncoder.class);
-    }
-
     private void check(Document document, String file) throws Exception
     {
         assertEquals(document.toString(), readFile(file));
@@ -45,12 +37,12 @@ public class DocumentLinkerImplTest exte
 
         document.newRootElement("not-html").text("not an HTML document");
 
-        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3");
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3", true);
 
         // Only checked if there's something to link.
 
-        linker.addScript("foo.js");
-        linker.addScript("doSomething();");
+        linker.addScriptLink("foo.js");
+        linker.addScript(InitializationPriority.NORMAL, "doSomething();");
 
         try
         {
@@ -72,7 +64,7 @@ public class DocumentLinkerImplTest exte
 
         document.newRootElement("not-html").text("not an HTML document");
 
-        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3");
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3", true);
 
         // Only checked if there's something to link.
 
@@ -94,10 +86,10 @@ public class DocumentLinkerImplTest exte
     {
         Document document = new Document();
 
-        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3");
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3", true);
 
-        linker.addScript("foo.js");
-        linker.addScript("doSomething();");
+        linker.addScriptLink("foo.js");
+        linker.addScript(InitializationPriority.NORMAL, "doSomething();");
 
         // No root element is not an error, even though there's work to do.
         // The failure to render is reported elsewhere.
@@ -111,11 +103,11 @@ public class DocumentLinkerImplTest exte
 
         document.newRootElement("html").element("body").element("p").text("Ready to be updated with scripts.");
 
-        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3");
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3", true);
 
         linker.addScriptLink("foo.js");
         linker.addScriptLink("bar/baz.js");
-        linker.addScript("pageInitialization();");
+        linker.addScript(InitializationPriority.NORMAL, "pageInitialization();");
 
         linker.updateDocument(document);
 
@@ -132,7 +124,7 @@ public class DocumentLinkerImplTest exte
 
         document.newRootElement("html").element("body").element("p").text("Ready to be marked with generator meta.");
 
-        DocumentLinkerImpl linker = new DocumentLinkerImpl(false, "1.2.3");
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(false, "1.2.3", true);
 
         linker.updateDocument(document);
 
@@ -149,7 +141,7 @@ public class DocumentLinkerImplTest exte
 
         document.newRootElement("no_html").text("Generator meta only added if root is html tag.");
 
-        DocumentLinkerImpl linker = new DocumentLinkerImpl(false, "1.2.3");
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(false, "1.2.3", true);
 
         linker.updateDocument(document);
 
@@ -163,12 +155,12 @@ public class DocumentLinkerImplTest exte
 
         document.newRootElement("html");
 
-        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3");
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3", true);
 
         linker.addStylesheetLink("style.css", "print");
         linker.addScriptLink("foo.js");
         linker.addScriptLink("bar/baz.js");
-        linker.addScript("pageInitialization();");
+        linker.addScript(InitializationPriority.IMMEDIATE, "pageInitialization();");
 
         linker.updateDocument(document);
 
@@ -182,11 +174,11 @@ public class DocumentLinkerImplTest exte
 
         document.newRootElement("html").element("body").element("p").text("Ready to be updated with scripts at top.");
 
-        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3");
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3", true);
 
         linker.addScriptLink("foo.js");
         linker.addScriptLink("bar/baz.js");
-        linker.addScript("pageInitialization();");
+        linker.addScript(InitializationPriority.NORMAL, "pageInitialization();");
 
         linker.updateDocument(document);
 
@@ -200,7 +192,7 @@ public class DocumentLinkerImplTest exte
 
         document.newRootElement("html").element("body").element("p").text("Ready to be updated with styles.");
 
-        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3");
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3", true);
 
         linker.addStylesheetLink("foo.css", null);
         linker.addStylesheetLink("bar/baz.css", "print");
@@ -218,7 +210,7 @@ public class DocumentLinkerImplTest exte
         document.newRootElement("html").element("head").comment(" existing head ").getParent().element("body").text(
                 "body content");
 
-        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3");
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3", true);
 
         linker.addStylesheetLink("foo.css", null);
 
@@ -234,10 +226,10 @@ public class DocumentLinkerImplTest exte
 
         document.newRootElement("html").element("body").element("p").text("Ready to be updated with scripts.");
 
-        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3");
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3", true);
 
-        linker.addScript("doSomething();");
-        linker.addScript("doSomethingElse();");
+        linker.addScript(InitializationPriority.IMMEDIATE, "doSomething();");
+        linker.addScript(InitializationPriority.IMMEDIATE, "doSomethingElse();");
 
         linker.updateDocument(document);
 
@@ -254,7 +246,7 @@ public class DocumentLinkerImplTest exte
 
         document.newRootElement("html").element("notbody").element("p").text("Ready to be updated with scripts.");
 
-        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3");
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3", true);
 
         linker.addScriptLink("foo.js");
 
@@ -270,9 +262,9 @@ public class DocumentLinkerImplTest exte
 
         document.newRootElement("html").element("body").element("p").text("Ready to be updated with scripts.");
 
-        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3");
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3", true);
 
-        linker.addScript("for (var i = 0; i < 5; i++)  { doIt(i); }");
+        linker.addScript(InitializationPriority.IMMEDIATE, "for (var i = 0; i < 5; i++)  { doIt(i); }");
 
         linker.updateDocument(document);
 
@@ -286,7 +278,7 @@ public class DocumentLinkerImplTest exte
 
         document.newRootElement("html").element("body").element("p").text("Ready to be updated with scripts.");
 
-        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3");
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3", true);
 
         linker.addScriptLink("/context/foo.js");
 
@@ -309,13 +301,70 @@ public class DocumentLinkerImplTest exte
         head.element("meta");
         head.element("script");
 
-        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3");
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3", true);
 
         linker.addScriptLink("/foo.js");
 
         linker.updateDocument(document);
 
         assertEquals(document.toString(), readFile("added_scripts_go_before_existing_script.txt"));
+    }
+
+    @Test
+    public void immediate_initialization() throws Exception
+    {
+        Document document = new Document();
+
+        Element head = document.newRootElement("html").element("head");
+
+        head.element("meta");
+        head.element("script");
+
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3", true);
+
+        linker.setInitialization(InitializationPriority.IMMEDIATE, new JSONObject("fred", "barney"));
+
+        linker.updateDocument(document);
+
+        assertEquals(document.toString(), readFile("immediate_initialization.txt"));
+    }
+
+    @Test
+    public void pretty_print_initialization() throws Exception
+    {
+        Document document = new Document();
+
+        Element head = document.newRootElement("html").element("head");
+
+        head.element("meta");
+        head.element("script");
+
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3", false);
+
+        linker.setInitialization(InitializationPriority.IMMEDIATE, new JSONObject().put("fred", new JSONArray("barney",
+                "wilma", "betty")));
+
+        linker.updateDocument(document);
+
+        assertEquals(document.toString(), readFile("pretty_print_initialization.txt"));
+    }
+
+    @Test
+    public void other_initialization() throws Exception
+    {
+        Document document = new Document();
+
+        Element head = document.newRootElement("html").element("head");
+
+        head.element("meta");
+        head.element("script");
+
+        DocumentLinkerImpl linker = new DocumentLinkerImpl(true, "1.2.3", true);
+
+        linker.setInitialization(InitializationPriority.NORMAL, new JSONObject("fred", "barney"));
+
+        linker.updateDocument(document);
 
+        assertEquals(document.toString(), readFile("other_initialization.txt"));
     }
 }

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=944978&r1=944977&r2=944978&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 Mon May 17 05:37:26 2010
@@ -14,7 +14,9 @@
 
 package org.apache.tapestry5.internal.services;
 
+import org.apache.tapestry5.json.JSONArray;
 import org.apache.tapestry5.json.JSONObject;
+import org.apache.tapestry5.services.javascript.InitializationPriority;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -25,8 +27,8 @@ public class PartialMarkupDocumentLinker
     {
         PartialMarkupDocumentLinker linker = new PartialMarkupDocumentLinker();
 
-        linker.addScript("foo();");
-        linker.addScript("bar();");
+        linker.addScript(InitializationPriority.NORMAL, "foo();");
+        linker.addScript(InitializationPriority.NORMAL, "bar();");
 
         JSONObject reply = new JSONObject();
 
@@ -36,6 +38,23 @@ public class PartialMarkupDocumentLinker
     }
 
     @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");
+    }
+
+    @Test
     public void script_link()
     {
         PartialMarkupDocumentLinker linker = new PartialMarkupDocumentLinker();
@@ -67,6 +86,25 @@ public class PartialMarkupDocumentLinker
                 "{\"stylesheets\":[{\"href\":\"foo.css\",\"media\":\"print\"},{\"href\":\"bar.css\"}]}");
 
         assertEquals(reply, expected);
+    }
 
+    @Test
+    public void set_initialization()
+    {
+        PartialMarkupDocumentLinker linker = new PartialMarkupDocumentLinker();
+
+        JSONObject spec1 = new JSONObject("order", "immediate");
+        JSONObject spec2 = new JSONObject("order", "normal");
+
+        JSONObject reply = new JSONObject();
+
+        linker.setInitialization(InitializationPriority.NORMAL, spec2);
+        linker.setInitialization(InitializationPriority.IMMEDIATE, spec1);
+
+        linker.commit(reply);
+
+        JSONObject expected = new JSONObject().put("inits", new JSONArray(spec1, spec2));
+
+        assertEquals(reply, expected);
     }
 }

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=944978&r1=944977&r2=944978&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 Mon May 17 05:37:26 2010
@@ -25,6 +25,7 @@ import org.apache.tapestry5.internal.ser
 import org.apache.tapestry5.internal.test.InternalBaseTestCase;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.IdAllocator;
+import org.apache.tapestry5.json.JSONArray;
 import org.apache.tapestry5.json.JSONObject;
 import org.apache.tapestry5.services.javascript.InitializationPriority;
 import org.apache.tapestry5.services.javascript.JavascriptStack;
@@ -43,7 +44,7 @@ public class JavascriptSupportImplTest e
 
         replay();
 
-        JavascriptSupport jss = new JavascriptSupportImpl(null, null, null, true);
+        JavascriptSupport jss = new JavascriptSupportImpl(null, null, null);
 
         assertEquals(jss.allocateClientId(resources), "tracy");
         assertEquals(jss.allocateClientId(resources), "tracy_0");
@@ -55,7 +56,7 @@ public class JavascriptSupportImplTest e
     @Test
     public void commit_with_no_javascript()
     {
-        JavascriptSupportImpl jss = new JavascriptSupportImpl(null, null, null, true);
+        JavascriptSupportImpl jss = new JavascriptSupportImpl(null, null, null);
 
         jss.commit();
     }
@@ -65,11 +66,11 @@ public class JavascriptSupportImplTest e
     {
         DocumentLinker linker = mockDocumentLinker();
 
-        linker.addScript("doSomething();\n");
+        linker.addScript(InitializationPriority.NORMAL, "doSomething();");
 
         replay();
 
-        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, null, null, new IdAllocator(), true, true);
+        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, null, null, new IdAllocator(), true);
 
         jss.addScript("doSomething();");
 
@@ -86,11 +87,12 @@ public class JavascriptSupportImplTest e
         JavascriptStackPathConstructor pathConstructor = mockJavascriptStackPathConstructor();
         trainForCoreStack(linker, stackSource, pathConstructor);
 
-        linker.addScript("stackInit();\nTapestry.onDOMLoaded(function() {\ndoSomething();\n});");
+        linker.addScript(InitializationPriority.IMMEDIATE, "stackInit();");
+        linker.addScript(InitializationPriority.NORMAL, "doSomething();");
 
         replay();
 
-        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor, true);
+        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor);
 
         jss.addScript("doSomething();");
 
@@ -150,71 +152,21 @@ public class JavascriptSupportImplTest e
     }
 
     @Test
-    public void only_immediate_script_added()
+    public void add_script_passes_thru_to_document_linker()
     {
         DocumentLinker linker = mockDocumentLinker();
         JavascriptStackSource stackSource = mockJavascriptStackSource();
         JavascriptStackPathConstructor pathConstructor = mockJavascriptStackPathConstructor();
         trainForEmptyCoreStack(linker, stackSource, pathConstructor);
 
-        linker.addScript("doSomething();\n");
+        linker.addScript(InitializationPriority.IMMEDIATE, "doSomething();");
 
         replay();
 
-        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor, true);
+        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor);
 
         jss.addScript(InitializationPriority.IMMEDIATE, "doSomething();");
 
-        jss.commit();
-
-        verify();
-    }
-
-    @Test
-    public void script_within_priority_accumulates()
-    {
-        DocumentLinker linker = mockDocumentLinker();
-        JavascriptStackSource stackSource = mockJavascriptStackSource();
-        JavascriptStackPathConstructor pathConstructor = mockJavascriptStackPathConstructor();
-        trainForEmptyCoreStack(linker, stackSource, pathConstructor);
-
-        linker
-                .addScript("immediate1();\nimmediate2();\nTapestry.onDOMLoaded(function() {\nnormal1();\nnormal2();\n});");
-
-        replay();
-
-        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor, true);
-
-        jss.addScript(InitializationPriority.IMMEDIATE, "immediate1();");
-        jss.addScript("normal1();");
-        jss.addScript(InitializationPriority.IMMEDIATE, "immediate2();");
-        jss.addScript("normal2();");
-
-        jss.commit();
-
-        verify();
-    }
-
-    @Test
-    public void priority_order()
-    {
-        DocumentLinker linker = mockDocumentLinker();
-        JavascriptStackSource stackSource = mockJavascriptStackSource();
-        JavascriptStackPathConstructor pathConstructor = mockJavascriptStackPathConstructor();
-        trainForCoreStack(linker, stackSource, pathConstructor);
-
-        linker.addScript("stackInit();\nTapestry.onDOMLoaded(function() {\nearly();\nnormal();\nlate();\n});");
-
-        replay();
-
-        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor, true);
-
-        jss.addScript(InitializationPriority.EARLY, "early();");
-        jss.addScript(InitializationPriority.NORMAL, "normal();");
-        jss.addScript(InitializationPriority.LATE, "late();");
-
-        jss.commit();
-
         verify();
     }
 
@@ -232,7 +184,7 @@ public class JavascriptSupportImplTest e
 
         replay();
 
-        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor, true);
+        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor);
 
         jss.importJavascriptLibrary(library);
 
@@ -264,14 +216,15 @@ public class JavascriptSupportImplTest e
         linker.addScriptLink("stack.js");
         linker.addStylesheetLink("stack.css", null);
 
-        linker.addScript("stackInit();\ncustomInit();\n");
+        linker.addScript(InitializationPriority.IMMEDIATE, "stackInit();");
+        linker.addScript(InitializationPriority.IMMEDIATE, "customInit();");
 
         replay();
 
-        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor, true);
+        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor);
 
         jss.importStack("custom");
-        
+
         // Duplicate calls are ignored.
         jss.importStack("Custom");
 
@@ -296,7 +249,7 @@ public class JavascriptSupportImplTest e
 
         replay();
 
-        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor, true);
+        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor);
 
         jss.importJavascriptLibrary(library1);
         jss.importJavascriptLibrary(library2);
@@ -308,22 +261,26 @@ public class JavascriptSupportImplTest e
     }
 
     @Test
-    public void init_once()
+    public void initialize_calls_are_aggregated_within_priority()
     {
         DocumentLinker linker = mockDocumentLinker();
         JavascriptStackSource stackSource = mockJavascriptStackSource();
         JavascriptStackPathConstructor pathConstructor = mockJavascriptStackPathConstructor();
         trainForEmptyCoreStack(linker, stackSource, pathConstructor);
 
-        JSONObject spec = new JSONObject("clientId", "chuck");
+        JSONObject spec1 = new JSONObject("clientId", "chuck");
+        JSONObject spec2 = new JSONObject("clientId", "fred");
+
+        JSONObject aggregated = new JSONObject().put("setup", new JSONArray(spec1, spec2));
 
-        linker.addScript("Tapestry.init({\"setup\":[{\"clientId\":\"chuck\"}]});\n");
+        linker.setInitialization(InitializationPriority.IMMEDIATE, aggregated);
 
         replay();
 
-        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor, true);
+        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor);
 
-        jss.addInitializerCall(InitializationPriority.IMMEDIATE, "setup", spec);
+        jss.addInitializerCall(InitializationPriority.IMMEDIATE, "setup", spec1);
+        jss.addInitializerCall(InitializationPriority.IMMEDIATE, "setup", spec2);
 
         jss.commit();
 
@@ -339,35 +296,16 @@ public class JavascriptSupportImplTest e
         JavascriptStackPathConstructor pathConstructor = mockJavascriptStackPathConstructor();
         trainForEmptyCoreStack(linker, stackSource, pathConstructor);
 
-        linker.addScript("Tapestry.init({\"setup\":[\"chuck\"]});\n");
-
-        replay();
-
-        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor, true);
-
-        jss.addInitializerCall(InitializationPriority.IMMEDIATE, "setup", "chuck");
-
-        jss.commit();
-
-        verify();
-    }
+        JSONObject aggregated = new JSONObject().put("setup", new JSONArray("chuck", "charley"));
 
-    @Test
-    public void init_with_string_multiple()
-    {
-        DocumentLinker linker = mockDocumentLinker();
-        JavascriptStackSource stackSource = mockJavascriptStackSource();
-        JavascriptStackPathConstructor pathConstructor = mockJavascriptStackPathConstructor();
-        trainForEmptyCoreStack(linker, stackSource, pathConstructor);
-
-        linker.addScript("Tapestry.init({\"setup\":[\"chuck\",\"pat\"]});\n");
+        linker.setInitialization(InitializationPriority.IMMEDIATE, aggregated);
 
         replay();
 
-        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor, true);
+        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor);
 
         jss.addInitializerCall(InitializationPriority.IMMEDIATE, "setup", "chuck");
-        jss.addInitializerCall(InitializationPriority.IMMEDIATE, "setup", "pat");
+        jss.addInitializerCall(InitializationPriority.IMMEDIATE, "setup", "charley");
 
         jss.commit();
 
@@ -382,64 +320,15 @@ public class JavascriptSupportImplTest e
         JavascriptStackPathConstructor pathConstructor = mockJavascriptStackPathConstructor();
         trainForEmptyCoreStack(linker, stackSource, pathConstructor);
 
-        linker.addScript("Tapestry.onDOMLoaded(function() {\nTapestry.init({\"setup\":[\"chuck\"]});\n});");
-
-        replay();
-
-        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor, true);
+        JSONObject aggregated = new JSONObject().put("setup", new JSONArray().put("chuck"));
 
-        jss.addInitializerCall("setup", "chuck");
-
-        jss.commit();
-
-        verify();
-    }
-
-    @Test
-    public void init_multiple()
-    {
-        DocumentLinker linker = mockDocumentLinker();
-        JavascriptStackSource stackSource = mockJavascriptStackSource();
-        JavascriptStackPathConstructor pathConstructor = mockJavascriptStackPathConstructor();
-        trainForEmptyCoreStack(linker, stackSource, pathConstructor);
-
-        JSONObject spec1 = new JSONObject("clientId", "chuck");
-        JSONObject spec2 = new JSONObject("clientId", "tony");
-
-        linker.addScript("Tapestry.init({\"setup\":[{\"clientId\":\"chuck\"},{\"clientId\":\"tony\"}]});\n");
-
-        replay();
-
-        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor, true);
-
-        jss.addInitializerCall(InitializationPriority.IMMEDIATE, "setup", spec1);
-        jss.addInitializerCall(InitializationPriority.IMMEDIATE, "setup", spec2);
-
-        jss.commit();
-
-        verify();
-    }
-
-    @Test
-    public void init_default_is_normal()
-    {
-
-        DocumentLinker linker = mockDocumentLinker();
-        JavascriptStackSource stackSource = mockJavascriptStackSource();
-        JavascriptStackPathConstructor pathConstructor = mockJavascriptStackPathConstructor();
-        trainForEmptyCoreStack(linker, stackSource, pathConstructor);
-
-        linker.addScript("Tapestry.onDOMLoaded(function() {\nTapestry.init({\"early\":[{\"id\":\"foo\"}]});\n"
-                + "Tapestry.init({\"normal\":[{\"id\":\"bar\"}]});\n"
-                + "Tapestry.init({\"late\":[{\"id\":\"baz\"}]});\n" + "});");
+        linker.setInitialization(InitializationPriority.NORMAL, aggregated);
 
         replay();
 
-        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor, true);
+        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, stackSource, pathConstructor);
 
-        jss.addInitializerCall(InitializationPriority.EARLY, "early", new JSONObject("id", "foo"));
-        jss.addInitializerCall("normal", new JSONObject("id", "bar"));
-        jss.addInitializerCall(InitializationPriority.LATE, "late", new JSONObject("id", "baz"));
+        jss.addInitializerCall("setup", "chuck");
 
         jss.commit();
 
@@ -456,7 +345,7 @@ public class JavascriptSupportImplTest e
 
         replay();
 
-        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, null, null, true);
+        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, null, null);
 
         jss.importStylesheet(stylesheet, "print");
 
@@ -474,7 +363,7 @@ public class JavascriptSupportImplTest e
 
         replay();
 
-        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, null, null, true);
+        JavascriptSupportImpl jss = new JavascriptSupportImpl(linker, null, null);
 
         jss.importStylesheet("style.css", "print");
         jss.importStylesheet("style.css", "screen");

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/json/JSONObjectTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/json/JSONObjectTest.java?rev=944978&r1=944977&r2=944978&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/json/JSONObjectTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/json/JSONObjectTest.java Mon May 17 05:37:26 2010
@@ -45,8 +45,7 @@ public class JSONObjectTest extends Asse
 
         JSONObject fullCopy = new JSONObject(master, "fred", "barney");
 
-        assertEquals(fullCopy.toString(), "{\n  \"fred\" : \"flintstone\",\n  \"barney\" : \"rubble\"\n"
-                + "}");
+        assertEquals(fullCopy.toString(), "{\n  \"fred\" : \"flintstone\",\n  \"barney\" : \"rubble\"\n" + "}");
 
         JSONObject limitedCopy2 = new JSONObject(master, "fred", "wilma");
         assertEquals(limitedCopy2.keys().size(), 1);
@@ -144,8 +143,7 @@ public class JSONObjectTest extends Asse
         object.accumulate(key, "beta");
         object.accumulate(key, "gamma");
 
-        assertEquals(object.toString(), "{\n  \"key\" : [\n    \"alpha\",\n    \"beta\",\n"
-                + "    \"gamma\"\n  ]\n}");
+        assertEquals(object.toString(), "{\n  \"key\" : [\n    \"alpha\",\n    \"beta\",\n" + "    \"gamma\"\n  ]\n}");
 
         JSONArray array = object.getJSONArray(key);
 
@@ -168,8 +166,7 @@ public class JSONObjectTest extends Asse
 
         array.put("gamma");
 
-        assertEquals(object.toString(), "{\n  \"key\" : [\n    \"alpha\",\n    \"beta\",\n"
-                + "    \"gamma\"\n  ]\n}");
+        assertEquals(object.toString(), "{\n  \"key\" : [\n    \"alpha\",\n    \"beta\",\n" + "    \"gamma\"\n  ]\n}");
     }
 
     @Test
@@ -198,8 +195,7 @@ public class JSONObjectTest extends Asse
 
         object.append(key, "beta");
 
-        assertEquals(object.toString(), "{\n  \"fubar\" : [\n    \"alpha\",\n    \"beta\"\n  ]\n"
-                + "}");
+        assertEquals(object.toString(), "{\n  \"fubar\" : [\n    \"alpha\",\n    \"beta\"\n  ]\n" + "}");
     }
 
     @Test
@@ -922,15 +918,8 @@ public class JSONObjectTest extends Asse
     {
         JSONObject o = new JSONObject("fred", "flintstone", "barney", "rubble");
 
-        CharArrayWriter caw = new CharArrayWriter();
-        PrintWriter pw = new PrintWriter(caw);
-
-        o.prettyPrint(pw);
-
-        String pretty = caw.toString();
-
-        assertEquals(o.toCompactString(), "{\"fred\":\"flintstone\",\"barney\":\"rubble\"}");
-        assertEquals(pretty, "{\n  \"fred\" : \"flintstone\",\n  \"barney\" : \"rubble\"\n}");
+        assertEquals(o.toString(true), "{\"fred\":\"flintstone\",\"barney\":\"rubble\"}");
+        assertEquals(o.toString(false), "{\n  \"fred\" : \"flintstone\",\n  \"barney\" : \"rubble\"\n}");
     }
 
     @Test
@@ -954,4 +943,12 @@ public class JSONObjectTest extends Asse
         assertEquals(compact, "[\"fred\",\"barney\"]");
         assertEquals(pretty, "[\n  \"fred\",\n  \"barney\"\n]");
     }
+
+    @Test
+    public void nested_collection()
+    {
+        JSONObject outer = new JSONObject().put("coll", new JSONArray("fred", "barney"));
+
+        assertEquals(outer.toCompactString(), "{\"coll\":[\"fred\",\"barney\"]}");
+    }
 }