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 2013/11/02 01:53:10 UTC
[1/2] git commit: Support aggregation of modules into a JavaScript
Stack - move RequireJS into the core stack - include the core stack on all
pages - rewrite modules to add the module name to the JavaScript define()
function invocation
Updated Branches:
refs/heads/master 9c574e7a5 -> 65d31852d
Support aggregation of modules into a JavaScript Stack
- move RequireJS into the core stack
- include the core stack on all pages
- rewrite modules to add the module name to the JavaScript define() function invocation
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/65d31852
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/65d31852
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/65d31852
Branch: refs/heads/master
Commit: 65d31852d8b4a0691a19736c672fedea9e3179e0
Parents: 1ff0ae9
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Fri Nov 1 17:51:17 2013 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Fri Nov 1 17:51:35 2013 -0700
----------------------------------------------------------------------
.../internal/services/DocumentLinker.java | 8 ++
.../internal/services/DocumentLinkerImpl.java | 18 +++
.../services/PartialMarkupDocumentLinker.java | 15 +-
.../services/ajax/JavaScriptSupportImpl.java | 30 ++--
.../assets/JavaScriptStackAssemblerImpl.java | 136 ++++++++++++++-----
.../JavaScriptStackPathConstructorImpl.java | 16 ++-
.../services/javascript/ModuleManagerImpl.java | 31 ++---
.../tapestry5/modules/JavaScriptModule.java | 34 ++++-
.../services/javascript/StackExtensionType.java | 10 +-
.../ajax/JavaScriptSupportAutofocusTests.groovy | 5 +-
.../ajax/JavaScriptSupportImplTest.groovy | 74 ++++------
.../app1/pages/MultiZoneUpdateDemo.java | 13 +-
.../META-INF/modules/app/multi-zone-update.js | 5 +
.../app1/pages/MultiZoneUpdateDemo.js | 5 -
14 files changed, 263 insertions(+), 137 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/65d31852/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java
index a66b828..e380160 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java
@@ -37,6 +37,14 @@ public interface DocumentLinker
void addLibrary(String libraryURL);
/**
+ * A special case used only for the libraries that are part of the core stack, which itself contains RequireJS
+ * and is used to bootstrap up to adding non-core libraries.
+ *
+ * @since 5.4
+ */
+ void addCoreLibrary(String libraryURL);
+
+ /**
* Adds a link to load a CSS stylesheet.
*/
void addStylesheetLink(StylesheetLink stylesheet);
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/65d31852/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java
index 5263be6..0c41e82 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java
@@ -27,6 +27,8 @@ import java.util.List;
public class DocumentLinkerImpl implements DocumentLinker
{
+ private final List<String> coreLibraryURLs = CollectionFactory.newList();
+
private final List<String> libraryURLs = CollectionFactory.newList();
private final ModuleInitsManager initsManager = new ModuleInitsManager();
@@ -64,6 +66,13 @@ public class DocumentLinkerImpl implements DocumentLinker
}
+ public void addCoreLibrary(String libraryURL)
+ {
+ coreLibraryURLs.add(libraryURL);
+
+ hasScriptsOrInitializations = true;
+ }
+
public void addLibrary(String libraryURL)
{
libraryURLs.add(libraryURL);
@@ -153,7 +162,9 @@ public class DocumentLinkerImpl implements DocumentLinker
// use stylesheets?
if (!rootElementName.equals("html"))
+ {
throw new RuntimeException(String.format("The root element of the rendered document was <%s>, not <html>. A root element of <html> is needed when linking JavaScript and stylesheet resources.", rootElementName));
+ }
// TAPESTRY-2364
@@ -196,6 +207,13 @@ public class DocumentLinkerImpl implements DocumentLinker
*/
protected void addScriptsToEndOfBody(Element body)
{
+ for (String url : coreLibraryURLs)
+ {
+ body.element("script",
+ "type", "text/javascript",
+ "src", url);
+ }
+
// In prior releases of Tapestry, we've vacillated about where the <script> tags go
// (in <head> or at bottom of <body>). Switching to a module approach gives us a new chance to fix this.
// Eventually, (nearly) everything will be loaded as modules.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/65d31852/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java
index ddcde16..7927f20 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java
@@ -1,4 +1,4 @@
-// Copyright 2008, 2010, 2011, 2012 The Apache Software Foundation
+// Copyright 2008-2013 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.
@@ -30,6 +30,11 @@ public class PartialMarkupDocumentLinker implements DocumentLinker
private final ModuleInitsManager initsManager = new ModuleInitsManager();
+ public void addCoreLibrary(String libraryURL)
+ {
+ notImplemented("addCoreLibrary");
+ }
+
public void addLibrary(String libraryURL)
{
libraryURLs.put(libraryURL);
@@ -46,10 +51,14 @@ public class PartialMarkupDocumentLinker implements DocumentLinker
stylesheets.put(object);
}
+ private void notImplemented(String methodName)
+ {
+ throw new UnsupportedOperationException(String.format("DocumentLinker.%s() is not implemented for partial page renders.", methodName));
+ }
+
public void addScript(InitializationPriority priority, String script)
{
- throw new UnsupportedOperationException(
- "DocumentLinker.addScript() is not implemented for partial page renders.");
+ notImplemented("addScript");
}
public void addInitialization(InitializationPriority priority, String moduleName, String functionName, JSONArray arguments)
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/65d31852/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImpl.java
index 2d207b8..691872e 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImpl.java
@@ -198,6 +198,8 @@ public class JavaScriptSupportImpl implements JavaScriptSupport
assert parameter != null;
assert InternalUtils.isNonBlank(functionName);
+ addAssetsFromStack(InternalConstants.CORE_STACK_NAME);
+
require("t5/core/init").priority(priority).with(functionName, parameter);
}
@@ -221,6 +223,8 @@ public class JavaScriptSupportImpl implements JavaScriptSupport
assert priority != null;
assert InternalUtils.isNonBlank(format);
+ addAssetsFromStack(InternalConstants.CORE_STACK_NAME);
+
String newScript = arguments.length == 0 ? format : String.format(format, arguments);
if (partialMode)
@@ -257,6 +261,8 @@ public class JavaScriptSupportImpl implements JavaScriptSupport
public JavaScriptSupport importJavaScriptLibrary(String libraryURL)
{
+ addAssetsFromStack(InternalConstants.CORE_STACK_NAME);
+
String stackName = findStackForLibrary(libraryURL);
if (stackName != null)
@@ -322,24 +328,27 @@ public class JavaScriptSupportImpl implements JavaScriptSupport
addAssetsFromStack(dependentStackname);
}
+ addedStacks.put(stackName, true);
+
+ boolean addAsCoreLibrary = stackName.equals(InternalConstants.CORE_STACK_NAME);
+
List<String> libraryURLs = stackPathConstructor.constructPathsForJavaScriptStack(stackName);
for (String libraryURL : libraryURLs)
{
- linker.addLibrary(libraryURL);
+ if (addAsCoreLibrary)
+ {
+ linker.addCoreLibrary(libraryURL);
+ } else
+ {
+ linker.addLibrary(libraryURL);
+ }
}
// TAP5-2197: to avoid @Import'ed stylesheets to appear after the core ones,
// the latter ones are now always added in the head of stylesheetLinks, not the tail.
stylesheetLinks.addAll(0, stack.getStylesheets());
- for (String moduleName : stack.getModules())
- {
- require(moduleName);
- }
-
- addedStacks.put(stackName, true);
-
String initialization = stack.getInitialization();
if (initialization != null)
@@ -376,6 +385,8 @@ public class JavaScriptSupportImpl implements JavaScriptSupport
{
assert InternalUtils.isNonBlank(stackName);
+ addAssetsFromStack(InternalConstants.CORE_STACK_NAME);
+
addAssetsFromStack(stackName);
return this;
@@ -399,10 +410,13 @@ public class JavaScriptSupportImpl implements JavaScriptSupport
{
assert InternalUtils.isNonBlank(moduleName);
+ addAssetsFromStack(InternalConstants.CORE_STACK_NAME);
+
InitializationImpl init = new InitializationImpl(moduleName);
inits.add(init);
return init;
}
+
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/65d31852/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/JavaScriptStackAssemblerImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/JavaScriptStackAssemblerImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/JavaScriptStackAssemblerImpl.java
index b52ab09..5cce91b 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/JavaScriptStackAssemblerImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/JavaScriptStackAssemblerImpl.java
@@ -14,26 +14,20 @@
package org.apache.tapestry5.internal.services.assets;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
import org.apache.tapestry5.Asset;
import org.apache.tapestry5.ioc.Resource;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.services.ThreadLocale;
-import org.apache.tapestry5.json.JSONArray;
-import org.apache.tapestry5.services.assets.AssetChecksumGenerator;
-import org.apache.tapestry5.services.assets.CompressionStatus;
-import org.apache.tapestry5.services.assets.StreamableResource;
-import org.apache.tapestry5.services.assets.StreamableResourceProcessing;
-import org.apache.tapestry5.services.assets.StreamableResourceSource;
+import org.apache.tapestry5.services.assets.*;
import org.apache.tapestry5.services.javascript.JavaScriptStack;
import org.apache.tapestry5.services.javascript.JavaScriptStackSource;
+import org.apache.tapestry5.services.javascript.ModuleManager;
+
+import java.io.*;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Pattern;
public class JavaScriptStackAssemblerImpl implements JavaScriptStackAssembler
{
@@ -49,18 +43,20 @@ public class JavaScriptStackAssemblerImpl implements JavaScriptStackAssembler
private final AssetChecksumGenerator checksumGenerator;
+ private final ModuleManager moduleManager;
+
private final Map<String, StreamableResource> cache = CollectionFactory.newCaseInsensitiveMap();
- // TODO: Support for minimization
// TODO: Support for aggregated CSS as well as aggregated JavaScript
- public JavaScriptStackAssemblerImpl(ThreadLocale threadLocale, ResourceChangeTracker resourceChangeTracker, StreamableResourceSource streamableResourceSource, JavaScriptStackSource stackSource, AssetChecksumGenerator checksumGenerator)
+ public JavaScriptStackAssemblerImpl(ThreadLocale threadLocale, ResourceChangeTracker resourceChangeTracker, StreamableResourceSource streamableResourceSource, JavaScriptStackSource stackSource, AssetChecksumGenerator checksumGenerator, ModuleManager moduleManager)
{
this.threadLocale = threadLocale;
this.resourceChangeTracker = resourceChangeTracker;
this.streamableResourceSource = streamableResourceSource;
this.stackSource = stackSource;
this.checksumGenerator = checksumGenerator;
+ this.moduleManager = moduleManager;
resourceChangeTracker.clearOnInvalidation(cache);
}
@@ -102,31 +98,72 @@ public class JavaScriptStackAssemblerImpl implements JavaScriptStackAssembler
JavaScriptStack stack = stackSource.getStack(stackName);
- return assemble(locale.toString(), stackName, stack.getJavaScriptLibraries());
+ return assembleStreamableForStack(locale.toString(), stackName, stack.getJavaScriptLibraries(), stack.getModules());
}
+ interface StreamableReader
+ {
+ /**
+ * Reads the content of a StreamableResource as a UTF-8 string, and optionally transforms it in some way.
+ */
+ String read(StreamableResource resource) throws IOException;
+ }
- private StreamableResource assemble(String localeName, String stackName, List<Asset> libraries) throws IOException
+ static String getContent(StreamableResource resource) throws IOException
{
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
- OutputStreamWriter osw = new OutputStreamWriter(stream, "UTF-8");
- PrintWriter writer = new PrintWriter(osw, true);
- long lastModified = 0;
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream(resource.getSize());
+ resource.streamTo(bos);
- StringBuilder description = new StringBuilder(String.format("'%s' JavaScript stack, for locale %s, resources=", stackName, localeName));
- String sep = "";
+ return new String(bos.toByteArray(), "UTF-8");
+ }
- JSONArray paths = new JSONArray();
- for (Asset library : libraries)
+ final StreamableReader libraryReader = new StreamableReader()
+ {
+ public String read(StreamableResource resource) throws IOException
{
- String path = library.getResource().toString();
+ return getContent(resource);
+ }
+ };
- paths.put(path);
+ private final static Pattern DEFINE = Pattern.compile("\\bdefine\\s*\\(");
- writer.format("\n/* %s */;\n", path);
+ private class ModuleReader implements StreamableReader
+ {
+ final String moduleName;
- Resource resource = library.getResource();
+ private ModuleReader(String moduleName)
+ {
+ this.moduleName = moduleName;
+ }
+
+ public String read(StreamableResource resource) throws IOException
+ {
+ String content = getContent(resource);
+
+ return DEFINE.matcher(content).replaceFirst("define(\"" + moduleName + "\",");
+ }
+ }
+
+
+ private class Assembly
+ {
+ final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(2000);
+ final PrintWriter writer;
+ long lastModified = 0;
+ final StringBuilder description;
+ private String sep = "";
+
+ private Assembly(String description) throws UnsupportedEncodingException
+ {
+ writer = new PrintWriter(new OutputStreamWriter(outputStream, "UTF-8"));
+
+ this.description = new StringBuilder(description);
+ }
+
+ void add(Resource resource, StreamableReader reader) throws IOException
+ {
+ writer.format("\n/* %s */;\n", resource.toString());
description.append(sep).append(resource.toString());
sep = ", ";
@@ -134,18 +171,45 @@ public class JavaScriptStackAssemblerImpl implements JavaScriptStackAssembler
StreamableResource streamable = streamableResourceSource.getStreamableResource(resource,
StreamableResourceProcessing.FOR_AGGREGATION, resourceChangeTracker);
- streamable.streamTo(stream);
+ writer.print(reader.read(streamable));
lastModified = Math.max(lastModified, streamable.getLastModified());
}
- writer.close();
+ StreamableResource finish()
+ {
+ writer.close();
- return new StreamableResourceImpl(
- description.toString(),
- JAVASCRIPT_CONTENT_TYPE, CompressionStatus.COMPRESSABLE, lastModified,
- new BytestreamCache(stream), checksumGenerator);
+ return new StreamableResourceImpl(
+ description.toString(),
+ JAVASCRIPT_CONTENT_TYPE, CompressionStatus.COMPRESSABLE, lastModified,
+ new BytestreamCache(outputStream), checksumGenerator);
+ }
}
+ private StreamableResource assembleStreamableForStack(String localeName, String stackName, List<Asset> libraries, List<String> moduleNames) throws IOException
+ {
+ Assembly assembly = new Assembly(String.format("'%s' JavaScript stack, for locale %s, resources=", stackName, localeName));
+ for (Asset library : libraries)
+ {
+ Resource resource = library.getResource();
+
+ assembly.add(resource, libraryReader);
+ }
+
+ for (String moduleName : moduleNames)
+ {
+ Resource resource = moduleManager.findResourceForModule(moduleName);
+
+ if (resource == null)
+ {
+ throw new IllegalArgumentException(String.format("Could not identify a resource for module name '%s'.", moduleName));
+ }
+
+ assembly.add(resource, new ModuleReader(moduleName));
+ }
+
+ return assembly.finish();
+ }
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/65d31852/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavaScriptStackPathConstructorImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavaScriptStackPathConstructorImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavaScriptStackPathConstructorImpl.java
index 25c4288..ebb7af0 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavaScriptStackPathConstructorImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavaScriptStackPathConstructorImpl.java
@@ -58,8 +58,9 @@ public class JavaScriptStackPathConstructorImpl implements JavaScriptStackPathCo
public JavaScriptStackPathConstructorImpl(ThreadLocale threadLocale, AssetPathConstructor assetPathConstructor,
JavaScriptStackSource javascriptStackSource,
JavaScriptStackAssembler assembler,
- ResponseCompressionAnalyzer compressionAnalyzer, @Symbol(SymbolConstants.COMBINE_SCRIPTS)
- boolean combineScripts)
+ ResponseCompressionAnalyzer compressionAnalyzer,
+ @Symbol(SymbolConstants.COMBINE_SCRIPTS)
+ boolean combineScripts)
{
this.threadLocale = threadLocale;
this.assetPathConstructor = assetPathConstructor;
@@ -75,9 +76,16 @@ public class JavaScriptStackPathConstructorImpl implements JavaScriptStackPathCo
List<Asset> assets = stack.getJavaScriptLibraries();
- if (assets.size() > 1 && combineScripts)
+ // When combine scripts is true, we want to build the virtual aggregated JavaScript ... but only
+ // if there is more than one library asset, or any modules.
+ if (combineScripts)
{
- return combinedStackURL(stackName);
+ boolean needsVirtual = (assets.size() > 1) || (!stack.getModules().isEmpty());
+
+ if (needsVirtual)
+ {
+ return combinedStackURL(stackName);
+ }
}
return toPaths(assets);
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/65d31852/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/ModuleManagerImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/ModuleManagerImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/ModuleManagerImpl.java
index 95642ce..99ca34d 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/ModuleManagerImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/ModuleManagerImpl.java
@@ -14,9 +14,7 @@
package org.apache.tapestry5.internal.services.javascript;
-import org.apache.tapestry5.Asset;
import org.apache.tapestry5.SymbolConstants;
-import org.apache.tapestry5.annotations.Path;
import org.apache.tapestry5.dom.Element;
import org.apache.tapestry5.internal.services.assets.ResourceChangeTracker;
import org.apache.tapestry5.ioc.Messages;
@@ -43,10 +41,6 @@ public class ModuleManagerImpl implements ModuleManager
private final ResponseCompressionAnalyzer compressionAnalyzer;
- private final Asset requireJS;
-
- private final Map<String, JavaScriptModuleConfiguration> configuration;
-
private final Messages globalMessages;
private final boolean compactJSON;
@@ -60,14 +54,12 @@ public class ModuleManagerImpl implements ModuleManager
// Note: ConcurrentHashMap does not support null as a value, alas. We use classpathRoot as a null.
private final Map<String, Resource> cache = CollectionFactory.newConcurrentMap();
- private final boolean devMode;
+ private final JSONObject baseConfig;
private final AssetPathConstructor assetPathConstructor;
public ModuleManagerImpl(ResponseCompressionAnalyzer compressionAnalyzer,
AssetSource assetSource,
- @Path("${" + SymbolConstants.REQUIRE_JS + "}")
- Asset requireJS,
Map<String, JavaScriptModuleConfiguration> configuration,
Messages globalMessages,
StreamableResourceSource streamableResourceSource,
@@ -78,25 +70,29 @@ public class ModuleManagerImpl implements ModuleManager
AssetPathConstructor assetPathConstructor)
{
this.compressionAnalyzer = compressionAnalyzer;
- this.requireJS = requireJS;
- this.configuration = configuration;
this.globalMessages = globalMessages;
this.compactJSON = compactJSON;
this.assetPathConstructor = assetPathConstructor;
- this.devMode = !productionMode;
-
classpathRoot = assetSource.resourceForPath("");
extensions = CollectionFactory.newSet("js");
extensions.addAll(streamableResourceSource.fileExtensionsForContentType("text/javascript"));
+
+ baseConfig = buildBaseConfig(configuration, !productionMode);
}
private String buildRequireJSConfig()
{
- String baseURL = getBaseURL();
+ // This is the part that can vary from one request to another, based on the capabilities of the client.
+ JSONObject config = baseConfig.copy().put("baseUrl", getBaseURL());
- JSONObject config = new JSONObject("baseUrl", baseURL);
+ return String.format("requirejs.config(%s);\n", config.toString(compactJSON));
+ }
+
+ private JSONObject buildBaseConfig(Map<String, JavaScriptModuleConfiguration> configuration, boolean devMode)
+ {
+ JSONObject config = new JSONObject();
// In DevMode, wait up to five minutes for a script, as the developer may be using the debugger.
if (devMode)
@@ -119,8 +115,7 @@ public class ModuleManagerImpl implements ModuleManager
addModuleToConfig(config, name, module);
}
}
-
- return String.format("requirejs.config(%s);\n", config.toString(compactJSON));
+ return config;
}
private String getBaseURL()
@@ -173,8 +168,6 @@ public class ModuleManagerImpl implements ModuleManager
public void writeInitialization(Element body, List<String> libraryURLs, List<?> inits)
{
- body.element("script", "src", requireJS.toClientURL());
-
Element element = body.element("script", "type", "text/javascript");
// Build it each time because we don't know if the client supports GZip or not, and
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/65d31852/tapestry-core/src/main/java/org/apache/tapestry5/modules/JavaScriptModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/JavaScriptModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/JavaScriptModule.java
index 5bf0782..25e2f77 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/modules/JavaScriptModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/JavaScriptModule.java
@@ -77,10 +77,35 @@ public class JavaScriptModule
configuration.add(InternalConstants.CORE_STACK_NAME, coreStack);
}
+ private static final String[] bundledModules = new String[]{
+ "ajax", "dom", "events", "console", "exception-frame", "pageinit", "messages", "utils"
+ };
+
+ /**
+ * The core JavaScriptStack has a number of entries:
+ * <dl>
+ * <dt>requirejs</dt> <dd>The RequireJS AMD JavaScript library</dd>
+ * <dt>scriptaculous.js, effects.js</dt> <dd>Optional JavaScript libraries in compatibility mode (see {@link Trait#SCRIPTACULOUS})</dd>
+ * <dt>t53-compatibility.js</dt> <dd>Optional JavaScript library (see {@link Trait#INITIALIZERS})</dd>
+ * <dt>t5/core/init</dt> <dd>Optional module related to t53-compatibility.js</dd>
+ * <dt>bootstrap.css, tapestry.css, exception-frame.css, tapestry-console.css, tree.css</dt>
+ * <dd>CSS files</dd>
+ * <dt>t5/core/ajax, dom, events, console, exception-frame, pageinit, messages, utils</dt>
+ * <dd>Additional JavaScript modules</dd>
+ * </dl>
+ * <p/>
+ * User modules may replace or extend this list.
+ */
@Contribute(JavaScriptStack.class)
@Core
- public static void setupCoreJavaScriptStack(OrderedConfiguration<StackExtension> configuration, Compatibility compatibility, @Symbol(SymbolConstants.JAVASCRIPT_INFRASTRUCTURE_PROVIDER) String provider)
+ public static void setupCoreJavaScriptStack(OrderedConfiguration<StackExtension> configuration, Compatibility compatibility,
+ @Symbol(SymbolConstants.REQUIRE_JS)
+ String requireJS,
+ @Symbol(SymbolConstants.JAVASCRIPT_INFRASTRUCTURE_PROVIDER)
+ String provider)
{
+ configuration.add("requirejs", new StackExtension(StackExtensionType.LIBRARY, requireJS));
+
final String ROOT = "${tapestry.asset.root}";
if (provider.equals("prototype") && compatibility.enabled(Trait.SCRIPTACULOUS))
@@ -95,6 +120,7 @@ public class JavaScriptModule
add(configuration, StackExtensionType.LIBRARY,
ROOT + "/t53-compatibility.js"
);
+ configuration.add("t5/core/init", new StackExtension(StackExtensionType.MODULE, "t5/core/init"));
}
add(configuration, StackExtensionType.STYLESHEET,
@@ -107,6 +133,12 @@ public class JavaScriptModule
ROOT + "/tapestry-console.css",
ROOT + "/tree.css");
+
+ for (String name : bundledModules)
+ {
+ String full = "t5/core/" + name;
+ configuration.add(full, new StackExtension(StackExtensionType.MODULE, full));
+ }
}
private static void add(OrderedConfiguration<StackExtension> configuration, StackExtensionType type, String... paths)
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/65d31852/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtensionType.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtensionType.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtensionType.java
index 2848817..50594ae 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtensionType.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtensionType.java
@@ -55,7 +55,15 @@ public enum StackExtensionType
STYLESHEET,
/**
- * A module to load with the stack.
+ * A module to aggregate with the stack. The module's JavaScript is included after any libraries.
+ * In development mode (with aggregation disabled), the library will be included individually.
+ * Unlike the RequireJS {@code r.js} tool, this does not process
+ * dependencies and is based on a simple regular expression parser.
+ * <p/>
+ * Note that this only loads the module's <em>code</em> and defines the module as available;
+ * the module's function will not be invoked unless {@link JavaScriptSupport#require(String)} is invoked to establish
+ * a dependency.
+ *
* @since 5.4
*/
MODULE,
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/65d31852/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportAutofocusTests.groovy
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportAutofocusTests.groovy b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportAutofocusTests.groovy
index a0b7e00..ba023f8 100644
--- a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportAutofocusTests.groovy
+++ b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportAutofocusTests.groovy
@@ -1,4 +1,4 @@
-// Copyright 2010, 2012 The Apache Software Foundation
+// Copyright 2010-2013 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.
@@ -39,7 +39,8 @@ class JavaScriptSupportAutofocusTests extends InternalBaseTestCase {
replay()
- def jss = new JavaScriptSupportImpl(linker, stackSource, stackPathConstructor)
+ // Test in partial mode, to bypass the logic about importing the "core' stack.
+ def jss = new JavaScriptSupportImpl(linker, stackSource, stackPathConstructor, null, true)
cls jss
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/65d31852/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImplTest.groovy
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImplTest.groovy b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImplTest.groovy
index 5796285..2b8abd1 100644
--- a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImplTest.groovy
+++ b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImplTest.groovy
@@ -2,6 +2,7 @@ package org.apache.tapestry5.internal.services.ajax
import org.apache.tapestry5.Asset
import org.apache.tapestry5.ComponentResources
+import org.apache.tapestry5.internal.InternalConstants
import org.apache.tapestry5.internal.services.DocumentLinker
import org.apache.tapestry5.internal.services.javascript.JavaScriptStackPathConstructor
import org.apache.tapestry5.internal.test.InternalBaseTestCase
@@ -66,12 +67,27 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase {
return newMock(JavaScriptStackSource.class)
}
+ protected final train_for_empty_core_stack(stackSource, pathConstructor) {
+ JavaScriptStack stack = mockJavaScriptStack()
+
+ expect(stackSource.getStack(InternalConstants.CORE_STACK_NAME)).andReturn(stack)
+
+ expect(stack.initialization).andReturn(null)
+
+ expect(stack.stacks).andReturn([])
+ expect(stack.stylesheets).andReturn([])
+
+ expect(pathConstructor.constructPathsForJavaScriptStack(InternalConstants.CORE_STACK_NAME)).andReturn([])
+ }
+
@Test
void add_script_passes_thru_to_document_linker() {
DocumentLinker linker = mockDocumentLinker()
JavaScriptStackSource stackSource = mockJavaScriptStackSource()
JavaScriptStackPathConstructor pathConstructor = mockJavaScriptStackPathConstructor()
+ train_for_empty_core_stack stackSource, pathConstructor
+
linker.addScript(InitializationPriority.IMMEDIATE, "doSomething();")
replay()
@@ -97,7 +113,7 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase {
replay()
- JavaScriptSupportImpl jss = new JavaScriptSupportImpl(linker, stackSource, pathConstructor)
+ JavaScriptSupportImpl jss = new JavaScriptSupportImpl(linker, stackSource, pathConstructor, null, true)
jss.importJavaScriptLibrary(library)
@@ -121,7 +137,6 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase {
expect(stackSource.getStack("mystack")).andReturn(mystack).atLeastOnce()
expect(mystack.stacks).andReturn([])
- expect(mystack.modules).andReturn([])
expect(mystack.javaScriptLibraries).andReturn([library1, library2])
expect(pathConstructor.constructPathsForJavaScriptStack("mystack")).andReturn(["stacks/mystack.js"])
@@ -134,7 +149,7 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase {
replay()
- JavaScriptSupportImpl jss = new JavaScriptSupportImpl(linker, stackSource, pathConstructor)
+ JavaScriptSupportImpl jss = new JavaScriptSupportImpl(linker, stackSource, pathConstructor, null, true)
jss.importJavaScriptLibrary(library1)
@@ -155,6 +170,8 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase {
JavaScriptStackSource stackSource = mockJavaScriptStackSource()
JavaScriptStackPathConstructor pathConstructor = mockJavaScriptStackPathConstructor()
+ train_for_empty_core_stack stackSource, pathConstructor
+
JavaScriptStack stack = mockJavaScriptStack()
StylesheetLink stylesheetLink = new StylesheetLink("stack.css")
@@ -162,7 +179,6 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase {
expect(stackSource.getStack("custom")).andReturn(stack)
expect(pathConstructor.constructPathsForJavaScriptStack("custom")).andReturn(["stack.js"])
expect(stack.stylesheets).andReturn([stylesheetLink])
- expect(stack.modules).andReturn([])
expect(stack.initialization).andReturn "customInit();"
expect(stack.stacks).andReturn([])
@@ -187,47 +203,13 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase {
}
@Test
- void import_stack_with_modules() {
- DocumentLinker linker = mockDocumentLinker()
- JavaScriptStackSource stackSource = mockJavaScriptStackSource()
- JavaScriptStackPathConstructor pathConstructor = mockJavaScriptStackPathConstructor()
- JavaScriptStack mystack = mockJavaScriptStack()
-
- expect(stackSource.getStack("mystack")).andReturn(mystack).atLeastOnce()
-
- expect(mystack.stacks).andReturn([])
- expect(mystack.modules).andReturn(["foo/bar", "gnip/gnop"])
-
- expect(pathConstructor.constructPathsForJavaScriptStack("mystack")).andReturn(["stacks/mystack.js"])
-
- expect(mystack.stylesheets).andReturn([])
-
- expect(mystack.initialization).andReturn null
-
- linker.addLibrary("stacks/mystack.js")
- linker.addInitialization(InitializationPriority.NORMAL, "foo/bar", null, null)
- linker.addInitialization(InitializationPriority.NORMAL, "gnip/gnop", null, null)
-
- replay()
-
- JavaScriptSupportImpl jss = new JavaScriptSupportImpl(linker, stackSource, pathConstructor)
-
- jss.importStack("mystack")
-
-
-
- jss.commit()
-
- verify()
-
- }
-
- @Test
void import_stack_with_dependencies() {
DocumentLinker linker = mockDocumentLinker()
JavaScriptStackSource stackSource = mockJavaScriptStackSource()
JavaScriptStackPathConstructor pathConstructor = mockJavaScriptStackPathConstructor()
+ train_for_empty_core_stack stackSource, pathConstructor
+
JavaScriptStack child = mockJavaScriptStack()
JavaScriptStack parent = mockJavaScriptStack()
@@ -243,13 +225,11 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase {
expect(pathConstructor.constructPathsForJavaScriptStack("parent")).andReturn(["parent.js"])
expect(parent.stylesheets).andReturn([parentStylesheetLink])
- expect(parent.modules).andReturn([])
expect(parent.initialization).andReturn("parentInit();")
expect(pathConstructor.constructPathsForJavaScriptStack("child")).andReturn(["child.js"])
expect(child.stylesheets).andReturn([childStylesheetLink])
- expect(child.modules).andReturn([])
expect(child.getInitialization()).andReturn("childInit();")
@@ -291,7 +271,7 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase {
replay()
- JavaScriptSupportImpl jss = new JavaScriptSupportImpl(linker, stackSource, pathConstructor)
+ JavaScriptSupportImpl jss = new JavaScriptSupportImpl(linker, stackSource, pathConstructor, null, true)
jss.importJavaScriptLibrary(library1)
jss.importJavaScriptLibrary(library2)
@@ -313,7 +293,7 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase {
replay()
- JavaScriptSupportImpl jss = new JavaScriptSupportImpl(linker, stackSource, pathConstructor)
+ JavaScriptSupportImpl jss = new JavaScriptSupportImpl(linker, stackSource, pathConstructor, null, true)
jss.addInitializerCall(InitializationPriority.IMMEDIATE, "setup", "chuck")
jss.addInitializerCall(InitializationPriority.IMMEDIATE, "setup", "charley")
@@ -337,7 +317,7 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase {
replay()
- JavaScriptSupportImpl jss = new JavaScriptSupportImpl(linker, stackSource, pathConstructor)
+ JavaScriptSupportImpl jss = new JavaScriptSupportImpl(linker, stackSource, pathConstructor, null, true)
jss.addInitializerCall(InitializationPriority.IMMEDIATE, "setup", chuck)
jss.addInitializerCall(InitializationPriority.IMMEDIATE, "setup", buzz)
@@ -365,7 +345,7 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase {
replay()
- JavaScriptSupportImpl jss = new JavaScriptSupportImpl(linker, stackSource, pathConstructor)
+ JavaScriptSupportImpl jss = new JavaScriptSupportImpl(linker, stackSource, pathConstructor, null, true)
jss.addInitializerCall("setup", "chuck")
@@ -386,7 +366,7 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase {
replay()
- JavaScriptSupportImpl jss = new JavaScriptSupportImpl(linker, stackSource, pathConstructor)
+ JavaScriptSupportImpl jss = new JavaScriptSupportImpl(linker, stackSource, pathConstructor, null, true)
jss.addInitializerCall("setup", chuck)
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/65d31852/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MultiZoneUpdateDemo.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MultiZoneUpdateDemo.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MultiZoneUpdateDemo.java
index 3aaa1cb..7af7bcc 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MultiZoneUpdateDemo.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MultiZoneUpdateDemo.java
@@ -1,4 +1,4 @@
-// Copyright 2009, 2010 The Apache Software Foundation
+// Copyright 2009-2013 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,17 +14,14 @@
package org.apache.tapestry5.integration.app1.pages;
-import org.apache.tapestry5.Asset;
import org.apache.tapestry5.Block;
import org.apache.tapestry5.ValueEncoder;
import org.apache.tapestry5.ajax.MultiZoneUpdate;
import org.apache.tapestry5.annotations.InjectComponent;
-import org.apache.tapestry5.annotations.Path;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.corelib.components.Zone;
import org.apache.tapestry5.internal.services.StringValueEncoder;
import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.json.JSONObject;
import org.apache.tapestry5.services.ajax.AjaxResponseRenderer;
import org.apache.tapestry5.services.ajax.JavaScriptCallback;
import org.apache.tapestry5.services.javascript.JavaScriptSupport;
@@ -45,10 +42,6 @@ public class MultiZoneUpdateDemo
@Inject
private AjaxResponseRenderer ajaxResponseRenderer;
- @Inject
- @Path("MultiZoneUpdateDemo.js")
- private Asset library;
-
public Date getNow()
{
return new Date();
@@ -65,9 +58,7 @@ public class MultiZoneUpdateDemo
{
public void run(JavaScriptSupport javascriptSupport)
{
- javascriptSupport.importJavaScriptLibrary(library);
- javascriptSupport.addInitializerCall("writeMessageTo", new JSONObject("id", "message", "message",
- "Updated"));
+ javascriptSupport.require("app/multi-zone-update").with("message", "Updated");
}
});
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/65d31852/tapestry-core/src/test/resources/META-INF/modules/app/multi-zone-update.js
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/resources/META-INF/modules/app/multi-zone-update.js b/tapestry-core/src/test/resources/META-INF/modules/app/multi-zone-update.js
new file mode 100644
index 0000000..fe7f694
--- /dev/null
+++ b/tapestry-core/src/test/resources/META-INF/modules/app/multi-zone-update.js
@@ -0,0 +1,5 @@
+define(["t5/core/dom"], function (dom) {
+ return function (id, message) {
+ dom(id).update(message);
+ };
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/65d31852/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/MultiZoneUpdateDemo.js
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/MultiZoneUpdateDemo.js b/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/MultiZoneUpdateDemo.js
deleted file mode 100644
index cbf379b..0000000
--- a/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/MultiZoneUpdateDemo.js
+++ /dev/null
@@ -1,5 +0,0 @@
-T5.extendInitializers({
- writeMessageTo : function(spec) {
- $(spec.id).update(spec.message);
- }
-})
\ No newline at end of file
[2/2] git commit: Add a copy() method to JSONObject
Posted by hl...@apache.org.
Add a copy() method to JSONObject
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/1ff0ae9e
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/1ff0ae9e
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/1ff0ae9e
Branch: refs/heads/master
Commit: 1ff0ae9e21dd978e9df0e6854d009b0a6a032247
Parents: 9c574e7
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Wed Oct 16 18:09:28 2013 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Fri Nov 1 17:51:35 2013 -0700
----------------------------------------------------------------------
.../org/apache/tapestry5/json/JSONObject.java | 20 +++++++++++++++---
.../groovy/json/specs/JSONObjectSpec.groovy | 22 ++++++++++++++++++++
2 files changed, 39 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1ff0ae9e/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
----------------------------------------------------------------------
diff --git a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
index 8b78ad8..575d1ea 100644
--- a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
+++ b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
@@ -1,4 +1,4 @@
-// Copyright 2007, 2010, 2011, 2012 The Apache Software Foundation
+// Copyright 2007-2013 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.
@@ -150,10 +150,23 @@ public final class JSONObject extends JSONCollection
}
/**
+ * Returns a new JSONObject that is a shallow copy of this JSONObject.
+ *
+ * @since 5.4
+ */
+ public JSONObject copy()
+ {
+ JSONObject dupe = new JSONObject();
+ dupe.properties.putAll(properties);
+
+ return dupe;
+ }
+
+ /**
* Constructs a new JSONObject using a series of String keys and object values.
* Object values sholuld be compatible with {@link #put(String, Object)}. Keys must be strings
* (toString() will be invoked on each key).
- *
+ * <p/>
* Prior to release 5.4, keysAndValues was type String...; changing it to Object... makes
* it much easier to initialize a JSONObject in a single statement, which is more readable.
*
@@ -999,7 +1012,8 @@ public final class JSONObject extends JSONCollection
throw new IllegalStateException(String.format("JSONObject[%s] is not a JSONObject.", quote(key)));
}
- if (nested == null) {
+ if (nested == null)
+ {
nested = new JSONObject();
properties.put(key, nested);
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1ff0ae9e/tapestry-json/src/test/groovy/json/specs/JSONObjectSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-json/src/test/groovy/json/specs/JSONObjectSpec.groovy b/tapestry-json/src/test/groovy/json/specs/JSONObjectSpec.groovy
index 9500d33..4cdd50b 100644
--- a/tapestry-json/src/test/groovy/json/specs/JSONObjectSpec.groovy
+++ b/tapestry-json/src/test/groovy/json/specs/JSONObjectSpec.groovy
@@ -38,6 +38,28 @@ class JSONObjectSpec extends Specification {
fullCopy.toCompactString() == /{"fred":"flintstone","barney":"rubble"}/
}
+ def "copy all properties of JSONObject"() {
+ def master = new JSONObject("fred", "flintstone", "barney", "rubble")
+
+ when:
+
+ def fullCopy = master.copy()
+
+ then:
+
+ master == fullCopy
+
+ // And they are independent:
+
+ when:
+
+ master.put("wilma", "flintstone")
+
+ then:
+
+ master != fullCopy
+ }
+
def "unknown keys when copying a JSONObject are ignored"() {
def master = new JSONObject("fred", "flintstone", "barney", "rubble")
[2/2] git commit: Add a copy() method to JSONObject
Posted by hl...@apache.org.
Add a copy() method to JSONObject
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/1ff0ae9e
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/1ff0ae9e
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/1ff0ae9e
Branch: refs/heads/master
Commit: 1ff0ae9e21dd978e9df0e6854d009b0a6a032247
Parents: 9c574e7
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Wed Oct 16 18:09:28 2013 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Fri Nov 1 17:51:35 2013 -0700
----------------------------------------------------------------------
.../org/apache/tapestry5/json/JSONObject.java | 20 +++++++++++++++---
.../groovy/json/specs/JSONObjectSpec.groovy | 22 ++++++++++++++++++++
2 files changed, 39 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1ff0ae9e/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
----------------------------------------------------------------------
diff --git a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
index 8b78ad8..575d1ea 100644
--- a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
+++ b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
@@ -1,4 +1,4 @@
-// Copyright 2007, 2010, 2011, 2012 The Apache Software Foundation
+// Copyright 2007-2013 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.
@@ -150,10 +150,23 @@ public final class JSONObject extends JSONCollection
}
/**
+ * Returns a new JSONObject that is a shallow copy of this JSONObject.
+ *
+ * @since 5.4
+ */
+ public JSONObject copy()
+ {
+ JSONObject dupe = new JSONObject();
+ dupe.properties.putAll(properties);
+
+ return dupe;
+ }
+
+ /**
* Constructs a new JSONObject using a series of String keys and object values.
* Object values sholuld be compatible with {@link #put(String, Object)}. Keys must be strings
* (toString() will be invoked on each key).
- *
+ * <p/>
* Prior to release 5.4, keysAndValues was type String...; changing it to Object... makes
* it much easier to initialize a JSONObject in a single statement, which is more readable.
*
@@ -999,7 +1012,8 @@ public final class JSONObject extends JSONCollection
throw new IllegalStateException(String.format("JSONObject[%s] is not a JSONObject.", quote(key)));
}
- if (nested == null) {
+ if (nested == null)
+ {
nested = new JSONObject();
properties.put(key, nested);
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1ff0ae9e/tapestry-json/src/test/groovy/json/specs/JSONObjectSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-json/src/test/groovy/json/specs/JSONObjectSpec.groovy b/tapestry-json/src/test/groovy/json/specs/JSONObjectSpec.groovy
index 9500d33..4cdd50b 100644
--- a/tapestry-json/src/test/groovy/json/specs/JSONObjectSpec.groovy
+++ b/tapestry-json/src/test/groovy/json/specs/JSONObjectSpec.groovy
@@ -38,6 +38,28 @@ class JSONObjectSpec extends Specification {
fullCopy.toCompactString() == /{"fred":"flintstone","barney":"rubble"}/
}
+ def "copy all properties of JSONObject"() {
+ def master = new JSONObject("fred", "flintstone", "barney", "rubble")
+
+ when:
+
+ def fullCopy = master.copy()
+
+ then:
+
+ master == fullCopy
+
+ // And they are independent:
+
+ when:
+
+ master.put("wilma", "flintstone")
+
+ then:
+
+ master != fullCopy
+ }
+
def "unknown keys when copying a JSONObject are ignored"() {
def master = new JSONObject("fred", "flintstone", "barney", "rubble")