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 2012/07/06 02:38:00 UTC
[5/16] git commit: Allow non-AMD libraries to be accessed -
ModuleManager now has configuration of ShimModule to define resources,
dependencies and exports - ResourceTransformer now defines content type of
transformed resources - StreamableResourceSource
Allow non-AMD libraries to be accessed
- ModuleManager now has configuration of ShimModule to define resources, dependencies and exports
- ResourceTransformer now defines content type of transformed resources
- StreamableResourceSource uses the transformed stream content type after transforming
- Documented new limitations of InitializationPriority due to asychronous behavior of RequireJS
- Extended core/pageinit module with new exported functions for different initializations
- JavaScriptSupport.addScript() now routed through an client-side initialization function based on eval()
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/e4503a4b
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/e4503a4b
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/e4503a4b
Branch: refs/heads/5.4-js-rewrite
Commit: e4503a4b8e4499a7d5efe6cf833bd122f6e81c5a
Parents: 949f9fb
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Thu Jul 5 16:33:59 2012 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Thu Jul 5 16:33:59 2012 -0700
----------------------------------------------------------------------
54_RELEASE_NOTES.txt | 3 +
.../tapestry5/corelib/modulejs/pageinit.coffee | 33 ++++-
.../java/org/apache/tapestry5/SymbolConstants.java | 2 +-
.../internal/services/DocumentLinkerImpl.java | 32 +----
.../assets/StreamableResourceSourceImpl.java | 2 +-
.../JavaScriptWrapperResourceTransformer.java | 5 +
.../services/javascript/ModuleManagerImpl.java | 59 +++++--
.../services/assets/ResourceTransformer.java | 7 +
.../javascript/InitializationPriority.java | 25 ++-
.../services/javascript/JavaScriptModule.java | 10 +-
.../services/javascript/ModuleManager.java | 10 +-
.../tapestry5/services/javascript/ShimModule.java | 58 +++++++
.../apache/tapestry5/corelib/modulejs/domReady.js | 125 +++++++++++++++
.../resources/org/apache/tapestry5/underscore.jsw | 4 -
.../services/DocumentLinkerImplTest.groovy | 35 +---
15 files changed, 317 insertions(+), 93 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e4503a4b/54_RELEASE_NOTES.txt
----------------------------------------------------------------------
diff --git a/54_RELEASE_NOTES.txt b/54_RELEASE_NOTES.txt
index 6e42455..f2de7a0 100644
--- a/54_RELEASE_NOTES.txt
+++ b/54_RELEASE_NOTES.txt
@@ -9,6 +9,9 @@ JavaScript Libraries (including stacks) are being replaced with modules. Note th
with RequireJS, which may mean that global values exported by the libraries are not visible; you should explicitly
attach properties to the global JavaScript window object, rather than assume that the context (this) is the window.
+The interface org.apache.tapestry5.services.assets.ResourceTransformer has had a new method added:
+getTransformedContentType().
+
Bugs fixed (in 5.4-js-rewrite branch):
TAP5-1965: Replace use of Request.getContextPath() with a symbol define at application startup
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e4503a4b/tapestry-core/src/main/coffeescript/org/apache/tapestry5/corelib/modulejs/pageinit.coffee
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/coffeescript/org/apache/tapestry5/corelib/modulejs/pageinit.coffee b/tapestry-core/src/main/coffeescript/org/apache/tapestry5/corelib/modulejs/pageinit.coffee
index abf8cf2..7c7a3b8 100644
--- a/tapestry-core/src/main/coffeescript/org/apache/tapestry5/corelib/modulejs/pageinit.coffee
+++ b/tapestry-core/src/main/coffeescript/org/apache/tapestry5/corelib/modulejs/pageinit.coffee
@@ -19,9 +19,8 @@
# The module name may also indicate the function exported by the module, as a suffix following a colon:
# e.g., "my/module:myfunc".
# Any additional values in the initializer are passed to the function. The context of the function (this) is null.
-define ->
+define ["_", "core/console"], (_, console) ->
invokeInitializer = (qualifiedName, initArguments...) ->
-
[moduleName, functionName] = qualifiedName.split ':'
require [moduleName], (moduleLib) ->
@@ -29,8 +28,34 @@ define ->
fn.apply null, initArguments
- # Exported function passed a list of initializers.
- initialize : (inits) ->
+ # Passed a list of initializers, executes each initializer in order. Due to asynchronous loading
+ # of modules, the exact order in which initializer functions are invoked is not predictable.
+ initialize: (inits) ->
# apply will split the first value from the rest for us, implicitly.
invokeInitializer.apply null, init for init in inits
+ # Pre-loads a number of scripts in order. When the last script is loaded,
+ # invokes the callback (with no parameters).
+ loadScripts: (scripts, callback) ->
+ reducer = (callback, script) -> ->
+ console.debug "Loading script #{script}"
+ require [script], callback
+
+ finalCallback = _.reduceRight scripts, reducer, callback
+
+ finalCallback.call(null)
+
+ # Loads all the scripts, in order. It then executes the immediate initializations.
+ # After that, it waits for the DOM to be ready and executes the other initializations.
+ loadScriptsAndInitialize: (scripts, immediateInits, otherInits) ->
+ this.loadScripts scripts, ->
+ this.initialize immediateInits
+ require ["core/domReady!"], -> this.initialize otherInits
+
+ evalJavaScript: (js) ->
+ console.debug "Evaluating: #{js}"
+ eval js
+
+
+
+
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e4503a4b/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java b/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java
index 07229bb..bcfa90b 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java
@@ -338,7 +338,7 @@ public class SymbolConstants
public static final String ASSET_URL_FULL_QUALIFIED = "tapestry.asset-url-fully-qualified";
/**
- * Prefix to be used for all asset paths, used to recognize which requests are for assets. This value
+ * Prefix to be used for all resource paths, used to recognize which requests are for assets. This value
* is appended to the context path and the (optional {@linkplain #APPLICATION_FOLDER application folder}.
* Its default is "assets". It may contain slashes, but should not begin or end with one.
*
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e4503a4b/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 e906680..1f529c5 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
@@ -30,8 +30,6 @@ public class DocumentLinkerImpl implements DocumentLinker
{
private final List<String> scriptURLs = CollectionFactory.newList();
- private final Map<InitializationPriority, StringBuilder> priorityToScript = CollectionFactory.newMap();
-
private final Map<InitializationPriority, List<JSONArray>> priorityToModuleInit = CollectionFactory.newMap();
private final List<StylesheetLink> includedStylesheets = CollectionFactory.newList();
@@ -80,20 +78,7 @@ public class DocumentLinkerImpl implements DocumentLinker
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");
-
- hasScriptsOrInitializations = true;
+ addInitialization(priority, "core/pageinit", "evalJavaScript", new JSONArray().put(script));
}
@Override
@@ -232,7 +217,7 @@ public class DocumentLinkerImpl implements DocumentLinker
body.element("script", "type", "text/javascript", "src", scriptURL);
}
- if (priorityToScript.isEmpty() && priorityToModuleInit.isEmpty())
+ if (priorityToModuleInit.isEmpty())
{
return;
}
@@ -244,8 +229,7 @@ public class DocumentLinkerImpl implements DocumentLinker
for (InitializationPriority p : InitializationPriority.values())
{
if (p != InitializationPriority.IMMEDIATE && !wrapped
- && (priorityToScript.containsKey(p) ||
- priorityToModuleInit.containsKey(p)))
+ && priorityToModuleInit.containsKey(p))
{
block.append("Tapestry.onDOMLoaded(function() {\n");
@@ -254,8 +238,6 @@ public class DocumentLinkerImpl implements DocumentLinker
}
addModuleInits(block, priorityToModuleInit.get(p));
-
- addDirectScriptInitialization(block, priorityToScript.get(p));
}
if (wrapped)
@@ -288,14 +270,6 @@ public class DocumentLinkerImpl implements DocumentLinker
block.append("]);\n});\n");
}
- private void addDirectScriptInitialization(StringBuilder block, StringBuilder content)
- {
- if (content == null)
- return;
-
- block.append(content);
- }
-
private static Element createTemporaryContainer(Element headElement, String existingElementName, String newElementName)
{
Element existingScript = headElement.find(existingElementName);
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e4503a4b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StreamableResourceSourceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StreamableResourceSourceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StreamableResourceSourceImpl.java
index 92e886e..b0bc641 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StreamableResourceSourceImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StreamableResourceSourceImpl.java
@@ -68,7 +68,7 @@ public class StreamableResourceSourceImpl implements StreamableResourceSource
transformed.close();
- String contentType = contentTypeAnalyzer.getContentType(baseResource);
+ String contentType = rt == null ? contentTypeAnalyzer.getContentType(baseResource) : rt.getTransformedContentType();
boolean compressable = compressionAnalyzer.isCompressable(contentType);
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e4503a4b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavaScriptWrapperResourceTransformer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavaScriptWrapperResourceTransformer.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavaScriptWrapperResourceTransformer.java
index 74502ad..e94f0c7 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavaScriptWrapperResourceTransformer.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/JavaScriptWrapperResourceTransformer.java
@@ -38,6 +38,11 @@ public class JavaScriptWrapperResourceTransformer implements ResourceTransformer
this.streamableResourceSource = streamableResourceSource;
}
+ public String getTransformedContentType()
+ {
+ return "text/javascript";
+ }
+
@Override
public InputStream transform(Resource source, ResourceDependencies dependencies) throws IOException
{
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e4503a4b/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 6f57358..7827151 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
@@ -23,11 +23,15 @@ import org.apache.tapestry5.func.Worker;
import org.apache.tapestry5.internal.services.assets.ResourceChangeTracker;
import org.apache.tapestry5.ioc.Resource;
import org.apache.tapestry5.ioc.annotations.PostInjection;
+import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.json.JSONObject;
import org.apache.tapestry5.services.AssetSource;
import org.apache.tapestry5.services.ComponentClassResolver;
import org.apache.tapestry5.services.assets.AssetPathConstructor;
import org.apache.tapestry5.services.javascript.ModuleManager;
+import org.apache.tapestry5.services.javascript.ShimModule;
import java.util.Comparator;
import java.util.List;
@@ -39,13 +43,13 @@ public class ModuleManagerImpl implements ModuleManager
private final Asset requireJS;
- private final Map<String, Resource> configuration;
-
// Library names, sorted by order of descending length.
private final List<String> libraryNames;
private final Map<String, List<String>> libraryNameToPackageNames = CollectionFactory.newMap();
+ private final Map<String, Resource> shimModuleNameToResource = CollectionFactory.newMap();
+
private final Resource classpathRoot;
// Note: ConcurrentHashMap does not support null as a value, alas. We use classpathRoot as a null.
@@ -54,14 +58,13 @@ public class ModuleManagerImpl implements ModuleManager
public ModuleManagerImpl(AssetPathConstructor constructor, final ComponentClassResolver resolver, AssetSource assetSource,
@Path("${" + SymbolConstants.REQUIRE_JS + "}")
Asset requireJS,
- Map<String, Resource> configuration)
+ Map<String, ShimModule> configuration,
+ @Symbol(SymbolConstants.COMPACT_JSON)
+ boolean compactJSON)
{
this.requireJS = requireJS;
- this.configuration = configuration;
- String baseURL = constructor.constructAssetPath("module-root", "");
- requireConfig = String.format("require.config({baseUrl:\"%s\"});\n",
- baseURL);
+ this.requireConfig = buildRequireJSConfig(constructor.constructAssetPath("module-root", ""), compactJSON, configuration);
classpathRoot = assetSource.resourceForPath("");
@@ -87,6 +90,39 @@ public class ModuleManagerImpl implements ModuleManager
libraryNameToPackageNames.put("app", resolver.getPackagesForLibrary(""));
}
+ private String buildRequireJSConfig(String baseURL, boolean compactJSON, Map<String, ShimModule> configuration)
+ {
+ JSONObject shims = new JSONObject();
+ JSONObject config = new JSONObject().put("baseUrl", baseURL).put("shim", shims);
+
+ for (String name : configuration.keySet())
+ {
+ ShimModule module = configuration.get(name);
+
+ shimModuleNameToResource.put(name, module.resource);
+
+ JSONObject shim = new JSONObject();
+
+ if (module.dependencies != null && !module.dependencies.isEmpty())
+ {
+ for (String dep : module.dependencies)
+ {
+ shim.accumulate("deps", dep);
+ }
+ }
+
+ if (InternalUtils.isNonBlank(module.exports))
+ {
+ shim.put("exports", module.exports);
+ }
+
+ shims.put(name, shim);
+ }
+
+ return String.format("require.config(%s);\n",
+ config.toString(compactJSON));
+ }
+
@PostInjection
public void setupInvalidation(ResourceChangeTracker tracker)
{
@@ -112,7 +148,6 @@ public class ModuleManagerImpl implements ModuleManager
cache.put(moduleName, resource);
}
-
// We're treating classpathRoot as a placeholder for null.
return resource == classpathRoot ? null : resource;
@@ -120,16 +155,10 @@ public class ModuleManagerImpl implements ModuleManager
private Resource resolveModuleNameToResource(String moduleName)
{
- Resource resource = configuration.get(moduleName);
+ Resource resource = shimModuleNameToResource.get(moduleName);
if (resource != null)
{
- if (!resource.exists())
- {
- throw new RuntimeException(String.format("Resource %s (mapped as module '%s') does not exist.",
- resource, moduleName));
- }
-
return resource;
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e4503a4b/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/ResourceTransformer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/ResourceTransformer.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/ResourceTransformer.java
index fb51c01..4eb517b 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/ResourceTransformer.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/ResourceTransformer.java
@@ -30,6 +30,13 @@ import java.io.InputStream;
public interface ResourceTransformer
{
/**
+ * Returns the MIME type of a transformed stream.
+ *
+ * @since 5.4
+ */
+ String getTransformedContentType();
+
+ /**
* Read the source input stream and provide a new input stream of the transformed content.
*
* @param source
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e4503a4b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/InitializationPriority.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/InitializationPriority.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/InitializationPriority.java
index d2d94b6..608efed 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/InitializationPriority.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/InitializationPriority.java
@@ -16,24 +16,35 @@ package org.apache.tapestry5.services.javascript;
/**
* Sets the priority for JavaScript initialization scripting. InitializationPriority allows coarse-grained control
- * over the order in which initialization occurs on the client. The default is normally {@link #NORMAL}.
- *
+ * over the order in which initialization occurs on the client. The default is normally {@link #NORMAL}. Starting in 5.4,
+ * these values have less meaning, as the {@linkplain JavaScriptSupport#require(String) dynamic loading of modules} may
+ * have unexpected effects on the exact order in which initialization occurs.
+ *
* @since 5.2.0
*/
public enum InitializationPriority
{
/**
- * 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.
+ * Provided JavaScript will be executed immediately (it is not deferred until the page loads). Execution occur via
+ * JavaScript's {@code eval}, and occurs once all {@linkplain JavaScriptSupport#importJavaScriptLibrary(org.apache.tapestry5.Asset) JavaScript libraries}
+ * (but not modules) for the page have been loaded.
+ * <p/>
+ * In an Ajax update, IMMEDIATE code is executed after the DOM is updated and before EARLY.
*/
IMMEDIATE,
- /** Execution is deferred until the page loads. All early execution occurs before {@link #NORMAL}. */
+ /**
+ * Execution is deferred until the page loads. All early execution occurs before {@link #NORMAL}.
+ */
EARLY,
- /** Execution is deferred until the page loads. This is the typical priority. */
+ /**
+ * Execution is deferred until the page loads. This is the typical priority.
+ */
NORMAL,
- /** Execution is deferred until the page loads. Execution occurs after {@link #NORMAL}. */
+ /**
+ * Execution is deferred until the page loads. Execution occurs after {@link #NORMAL}.
+ */
LATE
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e4503a4b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptModule.java
index 2de3a82..d8a0d79 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptModule.java
@@ -14,8 +14,10 @@
package org.apache.tapestry5.services.javascript;
+import org.apache.tapestry5.Asset;
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.RenderSupport;
+import org.apache.tapestry5.annotations.Path;
import org.apache.tapestry5.internal.InternalConstants;
import org.apache.tapestry5.internal.services.DocumentLinker;
import org.apache.tapestry5.internal.services.RenderSupportImpl;
@@ -23,8 +25,10 @@ import org.apache.tapestry5.internal.services.ajax.JavaScriptSupportImpl;
import org.apache.tapestry5.internal.services.javascript.*;
import org.apache.tapestry5.ioc.MappedConfiguration;
import org.apache.tapestry5.ioc.OrderedConfiguration;
+import org.apache.tapestry5.ioc.Resource;
import org.apache.tapestry5.ioc.ServiceBinder;
import org.apache.tapestry5.ioc.annotations.Contribute;
+import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.services.SymbolSource;
import org.apache.tapestry5.ioc.util.IdAllocator;
import org.apache.tapestry5.json.JSONObject;
@@ -227,9 +231,11 @@ public class JavaScriptModule
}
@Contribute(ModuleManager.class)
- public static void setupExtraModules(MappedConfiguration<String, Object> configuration)
+ public static void setupBaseModuleShims(MappedConfiguration<String, Object> configuration,
+ @Inject @Path("classpath:org/apache/tapestry5/underscore_1_3_3.js")
+ Resource underscore)
{
- configuration.add("_", "classpath:org/apache/tapestry5/underscore.jsw");
+ configuration.add("_", new ShimModule(underscore, null, "_"));
}
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e4503a4b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ModuleManager.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ModuleManager.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ModuleManager.java
index d534907..b7208ff 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ModuleManager.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ModuleManager.java
@@ -22,13 +22,12 @@ import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
* Responsible for managing access to the JavaScript modules.
* <p/>
* The configuration of the service allows overrides of the default search path; the configuration keys
- * are module names, and the configuration values are the resources for those module names. This is used to give
- * commonly-used modules a short module name (e.g., "_" for <a href="http://underscore.js">Underscore.js</a>),
- * <em>OR</em> to allow selective monkey-patching of default modules.
+ * are module names, and the configuration values are the {@link ShimModule} definitions for those module names.
+ * This is primarily used to wrap non-AMD compliant libraries for use with RequireJS (via contributed {@link ShimModule}s).
*
* @since 5.4
*/
-@UsesMappedConfiguration(Resource.class)
+@UsesMappedConfiguration(ShimModule.class)
public interface ModuleManager
{
/**
@@ -44,6 +43,9 @@ public interface ModuleManager
/**
* Given a module name (which may be a path of names separated by slashes), locates the corresponding {@link Resource}.
+ * First checks for {@linkplain ShimModule contributed shim modules}, then searches for possible matches among the
+ * {@linkplain org.apache.tapestry5.services.ComponentClassResolver#getLibraryNames() defined library names}. As a special
+ * case, the folder name "app" is mapped to the application's package.
*
* @param moduleName
* name of module to locate
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e4503a4b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ShimModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ShimModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ShimModule.java
new file mode 100644
index 0000000..9cd1150
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ShimModule.java
@@ -0,0 +1,58 @@
+// Copyright 2012 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.services.javascript;
+
+import org.apache.tapestry5.ioc.Resource;
+
+import java.util.List;
+
+/**
+ * Used to define a <a href="http://requirejs.org/docs/api.html#config-shim">module shim</a>, used to adapt non-AMD JavaScript libraries
+ * to operate like proper modules. This information is used to build up a list of dependencies for the contributed JavaScript module,
+ * and to identify the resource to be streamed to the client.
+ * <p/>
+ * Instances of this class are contributed to the {@link ModuleManager} service; the contribution key is the module name
+ * (typically, a single word).
+ * <p/>
+ * Tapestry contributes a single module, {@code _} for the <a href="http://underscore.js.org">Underscore</a> JavaScript library.
+ *
+ * @since 5.4
+ */
+public final class ShimModule
+{
+ /**
+ * The resource for this shim module.
+ */
+ public final Resource resource;
+
+ /**
+ * The names of other shim modules that should be loaded before this shim module.
+ */
+ public final List<String> dependencies;
+
+ /**
+ * Optional (but desirable) value exported by the shim module.
+ */
+ public final String exports;
+
+ public ShimModule(Resource resource, List<String> dependencies, String exports)
+ {
+ assert resource != null;
+
+ this.resource = resource;
+ this.dependencies = dependencies;
+ this.exports = exports;
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e4503a4b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/modulejs/domReady.js
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/modulejs/domReady.js b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/modulejs/domReady.js
new file mode 100644
index 0000000..6a79772
--- /dev/null
+++ b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/modulejs/domReady.js
@@ -0,0 +1,125 @@
+/**
+ * @license RequireJS domReady 2.0.0 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
+ * Available via the MIT or new BSD license.
+ * see: http://github.com/requirejs/domReady for details
+ */
+/*jslint */
+/*global require: false, define: false, requirejs: false,
+ window: false, clearInterval: false, document: false,
+ self: false, setInterval: false */
+
+
+define(function () {
+ 'use strict';
+
+ var isBrowser = typeof window !== "undefined" && window.document,
+ isPageLoaded = !isBrowser,
+ doc = isBrowser ? document : null,
+ readyCalls = [],
+ isTop, testDiv, scrollIntervalId;
+
+ function runCallbacks(callbacks) {
+ var i;
+ for (i = 0; i < callbacks.length; i++) {
+ callbacks[i](doc);
+ }
+ }
+
+ function callReady() {
+ var callbacks = readyCalls;
+
+ if (isPageLoaded) {
+ //Call the DOM ready callbacks
+ if (callbacks.length) {
+ readyCalls = [];
+ runCallbacks(callbacks);
+ }
+ }
+ }
+
+ /**
+ * Sets the page as loaded.
+ */
+ function pageLoaded() {
+ if (!isPageLoaded) {
+ isPageLoaded = true;
+ if (scrollIntervalId) {
+ clearInterval(scrollIntervalId);
+ }
+
+ callReady();
+ }
+ }
+
+ if (isBrowser) {
+ if (document.addEventListener) {
+ //Standards. Hooray! Assumption here that if standards based,
+ //it knows about DOMContentLoaded.
+ document.addEventListener("DOMContentLoaded", pageLoaded, false);
+ window.addEventListener("load", pageLoaded, false);
+ } else if (window.attachEvent) {
+ window.attachEvent("onload", pageLoaded);
+
+ testDiv = document.createElement('div');
+ try {
+ isTop = window.frameElement === null;
+ } catch(e) {}
+
+ //DOMContentLoaded approximation that uses a doScroll, as found by
+ //Diego Perini: http://javascript.nwbox.com/IEContentLoaded/,
+ //but modified by other contributors, including jdalton
+ if (testDiv.doScroll && isTop && window.external) {
+ scrollIntervalId = setInterval(function () {
+ try {
+ testDiv.doScroll();
+ pageLoaded();
+ } catch (e) {}
+ }, 30);
+ }
+ }
+
+ //Check if document already complete, and if so, just trigger page load
+ //listeners. Latest webkit browsers also use "interactive", and
+ //will fire the onDOMContentLoaded before "interactive" but not after
+ //entering "interactive" or "complete". More details:
+ //http://dev.w3.org/html5/spec/the-end.html#the-end
+ //http://stackoverflow.com/questions/3665561/document-readystate-of-interactive-vs-ondomcontentloaded
+ if (document.readyState === "complete" ||
+ document.readyState === "interactive") {
+ pageLoaded();
+ }
+ }
+
+ /** START OF PUBLIC API **/
+
+ /**
+ * Registers a callback for DOM ready. If DOM is already ready, the
+ * callback is called immediately.
+ * @param {Function} callback
+ */
+ function domReady(callback) {
+ if (isPageLoaded) {
+ callback(doc);
+ } else {
+ readyCalls.push(callback);
+ }
+ return domReady;
+ }
+
+ domReady.version = '2.0.0';
+
+ /**
+ * Loader Plugin API method
+ */
+ domReady.load = function (name, req, onLoad, config) {
+ if (config.isBuild) {
+ onLoad(null);
+ } else {
+ domReady(onLoad);
+ }
+ };
+
+ /** END OF PUBLIC API **/
+
+ return domReady;
+});
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e4503a4b/tapestry-core/src/main/resources/org/apache/tapestry5/underscore.jsw
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/underscore.jsw b/tapestry-core/src/main/resources/org/apache/tapestry5/underscore.jsw
deleted file mode 100644
index c9a287d..0000000
--- a/tapestry-core/src/main/resources/org/apache/tapestry5/underscore.jsw
+++ /dev/null
@@ -1,4 +0,0 @@
-define(function (require, exports, module) {
- @include("underscore_1_3_3.js")
- module.exports = _.noConflict();
-});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e4503a4b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy
index 121b365..3b592e4 100644
--- a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy
+++ b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy
@@ -103,9 +103,12 @@ class DocumentLinkerImplTest extends InternalBaseTestCase {
check document, '''
<?xml version="1.0"?>
<html><body><p>Ready to be updated with scripts.</p><!--MODULE-MANAGER-INITIALIZATION--><script src="foo.js" type="text/javascript"/><script src="bar/baz.js" type="text/javascript"/><script type="text/javascript">Tapestry.onDOMLoaded(function() {
-pageInitialization();
+require(["core/pageinit"], function (pageinit) {
+ pageinit.initialize([["core/pageinit:evalJavaScript","pageInitialization();"]]);
+});
});
-</script></body></html>'''
+</script></body></html>
+'''
verify()
}
@@ -203,8 +206,10 @@ pageInitialization();
linker.updateDocument(document)
check document, '''
-<html><body><p>Ready to be updated with scripts.</p><!--MODULE-MANAGER-INITIALIZATION--><script type="text/javascript">doSomething();
-doSomethingElse();
+<html><body><p>Ready to be updated with scripts.</p><!--MODULE-MANAGER-INITIALIZATION--><script type="text/javascript">require(["core/pageinit"], function (pageinit) {
+ pageinit.initialize([["core/pageinit:evalJavaScript","doSomething();"],
+ ["core/pageinit:evalJavaScript","doSomethingElse();"]]);
+});
</script></body></html>
'''
@@ -237,28 +242,6 @@ doSomethingElse();
}
@Test
- void script_written_raw() throws Exception {
- Document document = new Document()
-
- document.newRootElement("html").element("body").element("p").text("Ready to be updated with scripts.")
-
- DocumentLinkerImpl linker = new DocumentLinkerImpl(mockModuleManager(), true, "1.2.3", true)
-
- replay()
-
- linker.addScript(InitializationPriority.IMMEDIATE, "for (var i = 0; i < 5; i++) { doIt(i); }")
-
- linker.updateDocument(document)
-
- check document, '''
-<html><body><p>Ready to be updated with scripts.</p><!--MODULE-MANAGER-INITIALIZATION--><script type="text/javascript">for (var i = 0; i < 5; i++) { doIt(i); }
-</script></body></html>
-'''
-
- verify()
- }
-
- @Test
void non_asset_script_link_disables_aggregation() throws Exception {
Document document = new Document()