This is an automated email from the ASF dual-hosted git repository.
thiagohp pushed a commit to branch feature/requirejs-less
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
The following commit(s) were added to refs/heads/feature/requirejs-less by this
push:
new ead827a04 TAP5-2810: More needed support code for Require.js-less mode
ead827a04 is described below
commit ead827a0425863649f03697fbfffc6bb84ee9940
Author: Thiago H. de Paula Figueiredo <[email protected]>
AuthorDate: Sat Jul 26 12:24:23 2025 -0300
TAP5-2810: More needed support code for Require.js-less mode
---
5_10_RELEASE_NOTES.md | 11 +-
.../apache/tapestry5/corelib/components/Zone.java | 8 +-
.../internal/services/DocumentLinkerImpl.java | 29 +-
.../internal/services/ajax/BaseInitialization.java | 10 +
.../services/ajax/EsModuleInitializationImpl.java | 12 +-
.../internal/services/ajax/EsShimManagerImpl.java | 66 ++
.../services/ajax/JavaScriptSupportImpl.java | 27 +-
.../services/javascript/EsModuleManagerImpl.java | 58 +-
.../services/javascript/EsShimDispatcher.java | 31 +-
.../apache/tapestry5/modules/JavaScriptModule.java | 189 ++--
.../apache/tapestry5/modules/TapestryModule.java | 7 +-
.../services/javascript/EsModuleManager.java | 14 +-
.../tapestry5/services/javascript/EsShim.java | 91 +-
.../services/javascript/EsShimManager.java | 49 +
.../javascript/ExtensibleJavaScriptStack.java | 18 +-
.../services/javascript/JavaScriptStack.java | 8 +
.../services/javascript/StackExtension.java | 10 +
.../services/javascript/StackExtensionType.java | 7 +
.../META-INF/assets/es-modules/t5/underscore.js | 5 -
.../typescript/src/t5/core/t53-compatibility.ts | 56 +
.../integration/app1/components/Border.java | 14 +-
.../tapestry5/integration/app1/pages/Index.java | 1150 ++++++++++----------
.../META-INF/assets/es-modules/app/test-support.js | 14 +
23 files changed, 1118 insertions(+), 766 deletions(-)
diff --git a/5_10_RELEASE_NOTES.md b/5_10_RELEASE_NOTES.md
index b893fdec3..4a942b709 100644
--- a/5_10_RELEASE_NOTES.md
+++ b/5_10_RELEASE_NOTES.md
@@ -31,13 +31,10 @@ Scratch pad for changes destined for the 5.10.0 release
notes page.
# Notes about Require.js disabled mode
-* When using Bootstrap 3, the `t5/bootstrap/*` modules had automatic dependency
- management (for example, if you `bootstrap/tooltip`, `bootstrap/transition`
- would automatically be included too through Require.js). This doesn't happen
- when Require.js is disabled. So, for example, when importing
`bootstrap/tooltip`,
- you should import `bootstrap/trasition` first. Notice Bootstrap 3 JavaScript
- files don't have any module management code on it (Require.js nor ES modules)
-
+* Underscore.js, jQuery and Require.js are not included in the default stack
+ (i.e. the set of JavaScript files which are included in pages by default).
+ If you need to use Underscore.js or jQuery, they're automatically available
for
+ import as `underscore` and `jquery`, respectively.
# Overall notes
diff --git
a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Zone.java
b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Zone.java
index b4e9b0282..7bfd9b720 100644
---
a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Zone.java
+++
b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Zone.java
@@ -20,6 +20,7 @@ import
org.apache.tapestry5.corelib.internal.FormSupportAdapter;
import org.apache.tapestry5.corelib.internal.HiddenFieldPositioner;
import org.apache.tapestry5.dom.Element;
import org.apache.tapestry5.internal.services.RequestConstants;
+import org.apache.tapestry5.internal.services.ajax.RequireJsModeHelper;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.json.JSONObject;
@@ -68,7 +69,6 @@ import org.slf4j.Logger;
* @see FormFragment
*/
@SupportsInformalParameters
-@Import(module = "t5/core/zone")
public class Zone implements ClientBodyElement
{
/**
@@ -144,6 +144,9 @@ public class Zone implements ClientBodyElement
@Inject
private HiddenFieldLocationRules rules;
+
+ @Inject
+ private RequireJsModeHelper requireJsModeHelper;
private String clientId;
@@ -175,6 +178,9 @@ public class Zone implements ClientBodyElement
void beginRender(MarkupWriter writer)
{
+
+ requireJsModeHelper.importModule("t5/core/zone");
+
clientId = resources.isBound("id") ? idParameter :
javascriptSupport.allocateClientId(resources);
Element e = writer.element(elementName,
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 8814e7faf..fd885ce87 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
@@ -53,6 +53,8 @@ public class DocumentLinkerImpl implements DocumentLinker
private final boolean omitGeneratorMetaTag, enablePageloadingMask;
private final String tapestryBanner;
+
+ private final boolean requireJsEnabled;
// Initially false; set to true when a scriptURL or any kind of
initialization is added.
private boolean hasScriptsOrInitializations;
@@ -66,12 +68,14 @@ public class DocumentLinkerImpl implements DocumentLinker
* @param tapestryVersion
*/
public DocumentLinkerImpl(ModuleManager moduleManager, EsModuleManager
esModuleManager,
- boolean omitGeneratorMetaTag, boolean enablePageloadingMask,
String tapestryVersion)
+ boolean omitGeneratorMetaTag, boolean enablePageloadingMask,
String tapestryVersion,
+ boolean requireJsEnabled)
{
this.moduleManager = moduleManager;
this.esModuleManager = esModuleManager;
this.omitGeneratorMetaTag = omitGeneratorMetaTag;
this.enablePageloadingMask = enablePageloadingMask;
+ this.requireJsEnabled = requireJsEnabled;
tapestryBanner = "Apache Tapestry Framework (version " +
tapestryVersion + ')';
}
@@ -149,8 +153,6 @@ public class DocumentLinkerImpl implements DocumentLinker
addElementBefore(head, existingMeta, "meta", "name", "generator",
"content", tapestryBanner);
}
-
- addScriptElements(root);
final List<EsModuleInitialization> esModuleInits =
esModulesinitsManager.getInits();
if (isHtmlRoot && !esModuleInits.isEmpty())
@@ -158,6 +160,8 @@ public class DocumentLinkerImpl implements DocumentLinker
esModuleManager.writeImportMap(root.find("head"),
esModuleConfigurationCallbacks);
esModuleManager.writeImports(root, esModuleInits);
}
+
+ addScriptElements(root);
}
@@ -252,8 +256,11 @@ public class DocumentLinkerImpl implements DocumentLinker
script.moveToTop(body);
}
-
- moduleManager.writeConfiguration(body, moduleConfigurationCallbacks);
+
+ if (requireJsEnabled)
+ {
+ moduleManager.writeConfiguration(body,
moduleConfigurationCallbacks);
+ }
// Write the core libraries, which includes RequireJS:
@@ -264,9 +271,15 @@ public class DocumentLinkerImpl implements DocumentLinker
"src", url);
}
- // Write the initialization at this point.
-
- moduleManager.writeInitialization(body, libraryURLs,
initsManager.getSortedInits());
+ if (requireJsEnabled)
+ {
+ // Write the initialization at this point.
+ moduleManager.writeInitialization(body, libraryURLs,
initsManager.getSortedInits());
+ }
+ else
+ {
+ esModuleManager.writeInitialization(body, libraryURLs);
+ }
}
private static Element createTemporaryContainer(Element headElement,
String existingElementName, String newElementName)
diff --git
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/BaseInitialization.java
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/BaseInitialization.java
index 589a8850a..7714dc461 100644
---
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/BaseInitialization.java
+++
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/BaseInitialization.java
@@ -1,3 +1,13 @@
+// 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
package org.apache.tapestry5.internal.services.ajax;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
diff --git
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/EsModuleInitializationImpl.java
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/EsModuleInitializationImpl.java
index 3b3bfeb4a..eb4e32137 100644
---
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/EsModuleInitializationImpl.java
+++
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/EsModuleInitializationImpl.java
@@ -1,3 +1,13 @@
+// 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
package org.apache.tapestry5.internal.services.ajax;
import java.util.Collections;
@@ -14,7 +24,7 @@ public class EsModuleInitializationImpl extends
BaseInitialization<EsModuleIniti
private ImportPlacement placement = ImportPlacement.BODY_BOTTOM;
private Object[] arguments;
- EsModuleInitializationImpl(String moduleName)
+ public EsModuleInitializationImpl(String moduleName)
{
super(moduleName);
}
diff --git
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/EsShimManagerImpl.java
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/EsShimManagerImpl.java
new file mode 100644
index 000000000..f8a8c0dd8
--- /dev/null
+++
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/EsShimManagerImpl.java
@@ -0,0 +1,66 @@
+// 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.internal.services.ajax;
+
+import java.util.Map;
+
+import org.apache.tapestry5.SymbolConstants;
+import org.apache.tapestry5.commons.Resource;
+import org.apache.tapestry5.ioc.annotations.Symbol;
+import org.apache.tapestry5.services.PathConstructor;
+import org.apache.tapestry5.services.javascript.EsShimManager;
+
+public class EsShimManagerImpl implements EsShimManager
+{
+
+ private static final String ES_SUBPATH = "es-shims";
+
+ private final Map<String, Resource> shims;
+
+ private final PathConstructor pathConstructor;
+
+ private final String assetPrefix;
+
+ public EsShimManagerImpl(Map<String, Resource> shims,
+ PathConstructor pathConstructor,
+ @Symbol(SymbolConstants.ASSET_PATH_PREFIX)
+ String assetPrefix)
+ {
+ super();
+ this.shims = shims;
+ this.assetPrefix = assetPrefix;
+ this.pathConstructor = pathConstructor;
+ }
+
+ /**
+ * Returns the shims as a (module name, module resource) map.
+ * @return a {@code Map<String, Resource>}
+ */
+ @Override
+ public Map<String, Resource> getShims()
+ {
+ return shims;
+ }
+
+ @Override
+ public String getRequestPrefix(boolean compress)
+ {
+ return pathConstructor.constructDispatchPath(assetPrefix + "/" +
(compress ? ES_SUBPATH + ".gz" : ES_SUBPATH) + "/");
+ }
+
+ @Override
+ public String getUrl(String moduleName) {
+ return getRequestPrefix(true) + moduleName + ".js";
+ }
+
+}
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 a065b4b6c..db44db661 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
@@ -34,6 +34,7 @@ import org.apache.tapestry5.ioc.internal.util.InternalUtils;
import org.apache.tapestry5.ioc.util.IdAllocator;
import org.apache.tapestry5.json.JSONArray;
import org.apache.tapestry5.json.JSONObject;
+import org.apache.tapestry5.services.javascript.AbstractInitialization;
import org.apache.tapestry5.services.javascript.EsModuleConfigurationCallback;
import org.apache.tapestry5.services.javascript.EsModuleInitialization;
import org.apache.tapestry5.services.javascript.Initialization;
@@ -46,6 +47,8 @@ import
org.apache.tapestry5.services.javascript.StylesheetLink;
public class JavaScriptSupportImpl implements JavaScriptSupport
{
+ private static final String PAGEINIT_MODULE_NAME = "t5/core/pageinit";
+
private final IdAllocator idAllocator;
private final DocumentLinker linker;
@@ -133,10 +136,21 @@ public class JavaScriptSupportImpl implements
JavaScriptSupport
public void commit()
{
+ final String pageInitModuleName = PAGEINIT_MODULE_NAME;
// TODO make no Require.js version of this
if (focusFieldId != null)
{
- require("t5/core/pageinit").invoke("focus").with(focusFieldId);
+ final AbstractInitialization<?> initialization;
+
+ if (requireJsEnabled)
+ {
+ initialization = require(pageInitModuleName);
+ }
+ else
+ {
+ initialization = importEsModule(pageInitModuleName);
+ }
+ initialization.invoke("focus").with(focusFieldId);
}
F.flow(stylesheetLinks).each(new Worker<StylesheetLink>()
@@ -224,7 +238,16 @@ public class JavaScriptSupportImpl implements
JavaScriptSupport
if (partialMode)
{
-
require("t5/core/pageinit").invoke("evalJavaScript").with(newScript);
+ final AbstractInitialization<?> initialization;
+ if (requireJsEnabled)
+ {
+ initialization = require(PAGEINIT_MODULE_NAME);
+ }
+ else
+ {
+ initialization = importEsModule(PAGEINIT_MODULE_NAME);
+ }
+ initialization.invoke("evalJavaScript").with(newScript);
} else
{
linker.addScript(priority, newScript);
diff --git
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/EsModuleManagerImpl.java
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/EsModuleManagerImpl.java
index a73a2fe64..5cfebf058 100644
---
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/EsModuleManagerImpl.java
+++
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/EsModuleManagerImpl.java
@@ -17,6 +17,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.stream.Collectors;
import org.apache.tapestry5.Asset;
import org.apache.tapestry5.SymbolConstants;
@@ -31,15 +32,18 @@ import
org.apache.tapestry5.internal.services.assets.ResourceChangeTracker;
import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.ioc.services.ClasspathMatcher;
import org.apache.tapestry5.ioc.services.ClasspathScanner;
+import org.apache.tapestry5.json.JSONArray;
import org.apache.tapestry5.json.JSONCollection;
import org.apache.tapestry5.json.JSONLiteral;
import org.apache.tapestry5.json.JSONObject;
import org.apache.tapestry5.services.AssetSource;
+import org.apache.tapestry5.services.Core;
import org.apache.tapestry5.services.assets.StreamableResourceSource;
import org.apache.tapestry5.services.javascript.EsModuleConfigurationCallback;
import org.apache.tapestry5.services.javascript.EsModuleInitialization;
import org.apache.tapestry5.services.javascript.EsModuleManager;
import org.apache.tapestry5.services.javascript.ImportPlacement;
+import org.apache.tapestry5.services.javascript.JavaScriptStack;
public class EsModuleManagerImpl implements EsModuleManager
{
@@ -60,6 +64,8 @@ public class EsModuleManagerImpl implements EsModuleManager
private final Set<String> extensions;
private final AssetSource assetSource;
+
+ private final List<EsModuleInitialization> coreStackInits;
// Note: ConcurrentHashMap does not support null as a value, alas. We use
classpathRoot as a null.
private final Map<String, String> cache =
CollectionFactory.newConcurrentMap();
@@ -74,6 +80,8 @@ public class EsModuleManagerImpl implements EsModuleManager
private final List<EsModuleConfigurationCallback>
globalPerRequestCallbacks;
+ private final String infraProvider;
+
public EsModuleManagerImpl(
List<EsModuleManagerContribution> contributions,
AssetSource assetSource,
@@ -82,14 +90,24 @@ public class EsModuleManagerImpl implements EsModuleManager
boolean compactJSON,
@Symbol(TapestryHttpSymbolConstants.PRODUCTION_MODE)
boolean productionMode,
+
@Symbol(SymbolConstants.JAVASCRIPT_INFRASTRUCTURE_PROVIDER)
+ String infraProvider,
ClasspathScanner classpathScanner,
- ResourceChangeTracker resourceChangeTracker)
+ ResourceChangeTracker resourceChangeTracker,
+ @Core JavaScriptStack javaScriptStack)
{
this.compactJSON = compactJSON;
this.assetSource = assetSource;
this.classpathScanner = classpathScanner;
this.productionMode = productionMode;
this.resourceChangeTracker = resourceChangeTracker;
+ this.infraProvider = infraProvider;
+
+ final List<String> coreStackEsModules = javaScriptStack.getEsModules();
+
+ coreStackInits = coreStackEsModules.stream()
+ .map(i -> new EsModuleInitializationImpl(i))
+ .collect(Collectors.toList());
baseCallbacks = new ArrayList<>();
globalPerRequestCallbacks = new ArrayList<>();
@@ -151,12 +169,22 @@ public class EsModuleManagerImpl implements
EsModuleManager
final Set<String> scan = classpathScanner.scan(CLASSPATH_ROOT,
matcher);
for (String file : scan)
{
- String id = file.replace(CLASSPATH_ROOT, "");
- id = id.substring(0, id.lastIndexOf('.'));
+ String moduleName = file.replace(CLASSPATH_ROOT, "");
+ moduleName = moduleName.substring(0,
moduleName.lastIndexOf('.'));
+
+ if (moduleName.startsWith("t5/core/t5-core-dom-"))
+ {
+ // They're treated specially.
+ continue;
+ }
+ else if (moduleName.equals("t5/core/dom"))
+ {
+ file = file.replace("t5/core/dom", "t5/core/t5-core-dom-"
+ infraProvider);
+ }
final Asset asset = assetSource.getClasspathAsset(file);
resourceChangeTracker.trackResource(asset.getResource());
- imports.put(id, asset.toClientURL());
+ imports.put(moduleName, asset.toClientURL());
}
} catch (IOException e)
{
@@ -192,7 +220,11 @@ public class EsModuleManagerImpl implements EsModuleManager
String functionName;
Object[] arguments;
- for (EsModuleInitialization i : inits)
+ List<EsModuleInitialization> allInits = new
ArrayList<>(coreStackInits.size() + inits.size());
+ allInits.addAll(coreStackInits);
+ allInits.addAll(inits);
+
+ for (EsModuleInitialization i : allInits)
{
init = (EsModuleInitializationImpl) i;
@@ -281,6 +313,22 @@ public class EsModuleManagerImpl implements EsModuleManager
}
+ @Override
+ public void writeInitialization(Element body, List<String> libraryURLs)
+ {
+
+ Element element = body.element("script", "type", "module");
+
+ element.raw(String.format("import pageinit from
\"t5/core/pageinit\";\npageinit(%s, []);",
+ convert(libraryURLs)));
+ }
+
+ private String convert(List<?> input)
+ {
+ return new JSONArray().putAll(input).toString(compactJSON);
+ }
+
+
static String convertToJsFunctionParameters(Object[] arguments, boolean
compactJSON)
{
String result;
diff --git
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/EsShimDispatcher.java
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/EsShimDispatcher.java
index fb1a24da9..03ec9874a 100644
---
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/EsShimDispatcher.java
+++
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/EsShimDispatcher.java
@@ -16,7 +16,6 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
-import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.commons.Resource;
import org.apache.tapestry5.http.services.Dispatcher;
import org.apache.tapestry5.http.services.Request;
@@ -26,13 +25,11 @@ import
org.apache.tapestry5.internal.services.ResourceStreamer;
import org.apache.tapestry5.internal.services.assets.ResourceChangeTracker;
import org.apache.tapestry5.ioc.IOOperation;
import org.apache.tapestry5.ioc.OperationTracker;
-import org.apache.tapestry5.ioc.annotations.Symbol;
-import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
-import org.apache.tapestry5.services.PathConstructor;
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.javascript.EsShim;
+import org.apache.tapestry5.services.javascript.EsShimManager;
import jakarta.servlet.http.HttpServletResponse;
@@ -43,12 +40,9 @@ import jakarta.servlet.http.HttpServletResponse;
*
* @see EsShim
*/
-@UsesMappedConfiguration(Resource.class)
public class EsShimDispatcher implements Dispatcher
{
- private static final String ES_SUBPATH = "es-shims";
-
private final ResourceStreamer streamer;
private final OperationTracker tracker;
@@ -59,27 +53,26 @@ public class EsShimDispatcher implements Dispatcher
private Map<String, StreamableResource> shimMap;
- public EsShimDispatcher(Map<String, Resource> configuration,
+ public EsShimDispatcher(EsShimManager esShimManager,
StreamableResourceSource streamableResourceSource,
ResourceChangeTracker resourceChangeTracker,
ResourceStreamer streamer,
OperationTracker tracker,
- PathConstructor pathConstructor,
- @Symbol(SymbolConstants.ASSET_PATH_PREFIX)
- String assetPrefix,
boolean compress)
{
this.streamer = streamer;
this.tracker = tracker;
this.compress = compress;
- this.shimMap = new HashMap<>(configuration.size());
+
+ final Map<String, Resource> shims = esShimManager.getShims();
+ this.shimMap = new HashMap<>(shims.size());
try
{
- for (String moduleName : configuration.keySet())
+ for (String moduleName : shims.keySet())
{
shimMap.put(moduleName,
streamableResourceSource.getStreamableResource(
- configuration.get(moduleName),
StreamableResourceProcessing.COMPRESSION_ENABLED, resourceChangeTracker));
+ shims.get(moduleName),
StreamableResourceProcessing.COMPRESSION_ENABLED, resourceChangeTracker));
}
}
catch (IOException e)
@@ -87,7 +80,7 @@ public class EsShimDispatcher implements Dispatcher
throw new RuntimeException(e);
}
- requestPrefix = pathConstructor.constructDispatchPath(assetPrefix +
"/" + (compress ? ES_SUBPATH + ".gz" : ES_SUBPATH) + "/");
+ requestPrefix = esShimManager.getRequestPrefix(compress);
}
public boolean dispatch(Request request, Response response) throws
IOException
@@ -110,11 +103,6 @@ public class EsShimDispatcher implements Dispatcher
}
- public String getUrl(String moduleName)
- {
- return requestPrefix + moduleName;
- }
-
private boolean handleModuleRequest(String extraPath, Response response)
throws IOException
{
int dotx = extraPath.lastIndexOf('.');
@@ -141,7 +129,8 @@ public class EsShimDispatcher implements Dispatcher
if (resource != null)
{
- return streamer.streamResource(resource,
resource.getChecksum(), ResourceStreamer.DEFAULT_OPTIONS);
+ final String checksum = resource.getChecksum();
+ return streamer.streamResource(resource, checksum,
ResourceStreamer.DEFAULT_OPTIONS);
}
return false;
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 8b6bf81a0..3ea83348c 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
@@ -14,7 +14,6 @@ package org.apache.tapestry5.modules;
import java.util.Locale;
-import org.apache.tapestry5.Asset;
import org.apache.tapestry5.BooleanHook;
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.SymbolConstants;
@@ -29,6 +28,7 @@ import org.apache.tapestry5.http.services.Request;
import org.apache.tapestry5.internal.InternalConstants;
import org.apache.tapestry5.internal.services.DocumentLinker;
import org.apache.tapestry5.internal.services.ResourceStreamer;
+import org.apache.tapestry5.internal.services.ajax.EsShimManagerImpl;
import org.apache.tapestry5.internal.services.ajax.JavaScriptSupportImpl;
import org.apache.tapestry5.internal.services.ajax.RequireJsModeHelper;
import org.apache.tapestry5.internal.services.ajax.RequireJsModeHelperImpl;
@@ -50,7 +50,6 @@ import org.apache.tapestry5.ioc.annotations.Primary;
import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.ioc.services.FactoryDefaults;
import org.apache.tapestry5.ioc.services.SymbolProvider;
-import org.apache.tapestry5.ioc.services.SymbolSource;
import org.apache.tapestry5.ioc.util.IdAllocator;
import org.apache.tapestry5.json.JSONObject;
import org.apache.tapestry5.services.AssetSource;
@@ -64,13 +63,15 @@ import org.apache.tapestry5.services.MarkupRendererFilter;
import org.apache.tapestry5.services.PartialMarkupRenderer;
import org.apache.tapestry5.services.PartialMarkupRendererFilter;
import org.apache.tapestry5.services.PathConstructor;
+import org.apache.tapestry5.services.assets.StreamableResourceSource;
import org.apache.tapestry5.services.compatibility.Compatibility;
import org.apache.tapestry5.services.compatibility.Trait;
import org.apache.tapestry5.services.javascript.AMDWrapper;
-import org.apache.tapestry5.services.javascript.EsShim;
import org.apache.tapestry5.services.javascript.EsModuleConfigurationCallback;
import org.apache.tapestry5.services.javascript.EsModuleManager;
import
org.apache.tapestry5.services.javascript.EsModuleManager.EsModuleManagerContribution;
+import org.apache.tapestry5.services.javascript.EsShim;
+import org.apache.tapestry5.services.javascript.EsShimManager;
import org.apache.tapestry5.services.javascript.ExtensibleJavaScriptStack;
import org.apache.tapestry5.services.javascript.JavaScriptModuleConfiguration;
import org.apache.tapestry5.services.javascript.JavaScriptStack;
@@ -108,7 +109,7 @@ public class JavaScriptModule
binder.bind(JavaScriptStack.class,
ExtensibleJavaScriptStack.class).withMarker(Core.class).withId("CoreJavaScriptStack");
binder.bind(JavaScriptStack.class,
ExtensibleJavaScriptStack.class).withMarker(Internal.class).withId("InternalJavaScriptStack");
binder.bind(RequireJsModeHelper.class, RequireJsModeHelperImpl.class);
- binder.bind(EsShimDispatcher.class);
+ binder.bind(EsShimManager.class, EsShimManagerImpl.class);
}
/**
@@ -135,15 +136,15 @@ public class JavaScriptModule
/**
* The core JavaScriptStack has a number of entries:
* <dl>
- * <dt>requirejs</dt> <dd>The RequireJS AMD JavaScript library</dd>
+ * <dt>requirejs</dt> <dd>The RequireJS AMD JavaScript library (if
Require.js is enabled)</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>underscore-library, underscore-module</dt>
+ * <dt>underscore-library, underscore-module (if Require.js is enabled. An
ES module version of it is provided by Tapestry)</dt>
* <dt>The Underscore JavaScript library, and the shim that allows
underscore to be injected</dt>
* <dt>t5/core/init</dt> <dd>Optional module related to
t53-compatibility.js</dd>
- * <dt>jquery-library</dt> <dd>The jQuery library</dd>
- * <dt>jquery-noconflict</dt> <dd>Switches jQuery to no-conflict mode
(only present when the infrastructure is "prototype").</dd>
- * <dt>jquery</dt> <dd>A module shim that allows jQuery to be injected
(and also switches jQuery to no-conflict mode)</dd>
+ * <dt>jquery-library</dt> <dd>The jQuery library (if Require.js is
enabled. An ES module version of it is provided by Tapestry)</dd>
+ * <dt>jquery-noconflict</dt> <dd>Switches jQuery to no-conflict mode
(only present when the infrastructure is "prototype" and Require.js is
enabled).</dd>
+ * <dt>jquery</dt> <dd>A module shim that allows jQuery to be injected
(and also switches jQuery to no-conflict mode) (if Require.js is enabled. An ES
module version of it is provided by Tapestry)</dd>
* <dt>bootstrap.css, tapestry.css, exception-frame.css,
tapestry-console.css, tree.css</dt>
* <dd>CSS files</dd>
* <dt>t5/core/[...]</dt>
@@ -159,10 +160,14 @@ public class JavaScriptModule
public static void
setupCoreJavaScriptStack(OrderedConfiguration<StackExtension> configuration,
Compatibility compatibility,
@Symbol(SymbolConstants.JAVASCRIPT_INFRASTRUCTURE_PROVIDER)
- String provider)
+ String provider,
+
@Symbol(SymbolConstants.REQUIRE_JS_ENABLED) boolean requireJsEnabled)
{
- configuration.add("requirejs", StackExtension.library(ROOT +
"/require.js"));
- configuration.add("underscore-library", StackExtension.library(ROOT +
"/underscore-1.13.7.js"));
+ if (requireJsEnabled)
+ {
+ configuration.add("requirejs", StackExtension.library(ROOT +
"/require.js"));
+ configuration.add("underscore-library",
StackExtension.library(ROOT + "/underscore-1.13.7.js"));
+ }
if (provider.equals("prototype"))
{
@@ -180,18 +185,32 @@ public class JavaScriptModule
if (compatibility.enabled(Trait.INITIALIZERS))
{
- add(configuration, StackExtensionType.LIBRARY, ROOT +
"/t53-compatibility.js");
- configuration.add("t5/core/init", new
StackExtension(StackExtensionType.MODULE, "t5/core/init"));
+ if (requireJsEnabled)
+ {
+ add(configuration, StackExtensionType.LIBRARY, ROOT +
"/t53-compatibility.js");
+ configuration.add("t5/core/init", new
StackExtension(StackExtensionType.MODULE, "t5/core/init"));
+ }
+ else
+ {
+ add(configuration, StackExtensionType.ES_MODULE,
"t5/core/t53-compatibility");
+ add(configuration, StackExtensionType.ES_MODULE,
"t5/core/init");
+ }
}
- configuration.add("jquery-library", StackExtension.library(ROOT +
"/jquery.js"));
+ if (requireJsEnabled)
+ {
+ configuration.add("jquery-library", StackExtension.library(ROOT +
"/jquery.js"));
+ }
- if (provider.equals("prototype"))
+ if (provider.equals("prototype") && requireJsEnabled)
{
configuration.add("jquery-noconflict", StackExtension.library(ROOT
+ "/jquery-noconflict.js"));
}
- add(configuration, StackExtensionType.MODULE, "jquery");
+ if (requireJsEnabled)
+ {
+ add(configuration, StackExtensionType.MODULE, "jquery");
+ }
add(configuration, StackExtensionType.STYLESHEET, "${" +
SymbolConstants.FONT_AWESOME_ROOT + "}/css/font-awesome.css");
@@ -289,11 +308,13 @@ public class JavaScriptModule
JavaScriptStackSource
javaScriptStackSource,
JavaScriptStackPathConstructor
javaScriptStackPathConstructor,
LocalizationSetter
localizationSetter,
+ EsShimManager esShimManager,
+ StreamableResourceSource
streamableResourceSource,
+ ResourceChangeTracker
resourceChangeTracker,
@Symbol(SymbolConstants.MODULE_PATH_PREFIX)
String modulePathPrefix,
@Symbol(SymbolConstants.ASSET_PATH_PREFIX)
- String assetPathPrefix,
- EsShimDispatcher
esShimDispatcher)
+ String assetPathPrefix)
{
configuration.add("Modules",
new ModuleDispatcher(moduleManager, resourceStreamer, tracker,
pathConstructor,
@@ -307,7 +328,13 @@ public class JavaScriptModule
assetPathPrefix, true),
"after:Modules", "before:ComponentEvent");
- configuration.add("EsShims", esShimDispatcher, "after:Asset",
"before:ComponentEvent");
+ configuration.add("EsShims", new EsShimDispatcher(esShimManager,
streamableResourceSource, resourceChangeTracker,
+ resourceStreamer, tracker, false),
+ "before:Asset", "before:ComponentEvent");
+
+ configuration.add("CompressedEsShims", new
EsShimDispatcher(esShimManager, streamableResourceSource,
resourceChangeTracker,
+ resourceStreamer, tracker, true),
+ "after:EsShims", "before:Asset", "before:ComponentEvent");
}
@@ -552,7 +579,7 @@ public class JavaScriptModule
}
- @Contribute(EsShimDispatcher.class)
+ @Contribute(EsShimManager.class)
public static void setupBaseEsShims(
MappedConfiguration<String, Resource> configuration,
@Path("${tapestry.asset.root}/bootstrap/js/transition.js")
@@ -560,11 +587,14 @@ public class JavaScriptModule
@Path("${tapestry.asset.root}/bootstrap4/js/bootstrap-util.js")
Resource bootstrapUtil,
Compatibility compatibility,
- AssetSource assetSource,
- EsShimDispatcher esShimDispatcher)
+ AssetSource assetSource)
{
-// configuration.add("jquery", new
JavaScriptModuleConfiguration(jqueryShim));
+ final Resource jQuery =
assetSource.getClasspathAsset("/META-INF/assets/tapestry5/jquery.js")
+ .getResource();
+ configuration.add("jquery", new EsShim(jQuery)
+ .defaultExport("jQuery.noConflict()")
+ .getResource());
if (compatibility.enabled(Trait.BOOTSTRAP_3))
{
@@ -576,25 +606,23 @@ public class JavaScriptModule
final String popoverModuleName = "bootstrap/popover";
configuration.add(popoverModuleName,
- EsModuleManagerContribution.base(
- new
EsShim(popover).importModule("bootstrap/tooltip"),
- createCallback(popoverModuleName,
esShimDispatcher)));
+ new EsShim(popover)
+ .importModule("jquery")
+ .importModule("bootstrap/tooltip")
+ .getResource());
}
if (compatibility.enabled(Trait.BOOTSTRAP_4))
{
final String bootstrapUtilModuleName = "bootstrap/bootstrap-util";
configuration.add(bootstrapUtilModuleName,
- EsModuleManagerContribution.base(
- new EsShim(bootstrapUtil),
- createCallback(bootstrapUtilModuleName,
esShimDispatcher)));
+ new EsShim(bootstrapUtil)
+ .getResource());
final String popperModuleName = "bootstrap/popper";
final Resource popper = bootstrapUtil.forFile("popper.js");
configuration.add(popperModuleName,
- EsModuleManagerContribution.base(
- new EsShim(popper),
- createCallback(popperModuleName,
esShimDispatcher)));
+ new EsShim(popper).getResource());
for (String name : new String[]{"alert", "button", "carousel",
"collapse", "dropdown", "modal",
"scrollspy", "tab", "tooltip"})
@@ -604,11 +632,10 @@ public class JavaScriptModule
{
final String moduleName = "bootstrap/" + name;
configuration.add(moduleName,
- EsModuleManagerContribution.base(
- new EsShim(lib)
- .importModule(bootstrapUtilModuleName)
- .importModule(popperModuleName),
- createCallback(popperModuleName,
esShimDispatcher)));
+ new EsShim(lib)
+ .importModule(bootstrapUtilModuleName)
+ .importModule(popperModuleName)
+ .getResource());
}
}
}
@@ -622,78 +649,16 @@ public class JavaScriptModule
}
}
-// @Contribute(EsModuleManager.class)
-// public static void setupBaseEsModules(
-// OrderedConfiguration<EsModuleManagerContribution> configuration,
-// @Path("${tapestry.asset.root}/bootstrap/js/transition.js")
-// Resource transition,
-// @Path("${tapestry.asset.root}/bootstrap4/js/bootstrap-util.js")
-// Resource bootstrapUtil,
-// Compatibility compatibility,
-// AssetSource assetSource,
-// EsShimDispatcher esShimDispatcher)
-// {
-//
-//// configuration.add("jquery", new
JavaScriptModuleConfiguration(jqueryShim));
-//
-// if (compatibility.enabled(Trait.BOOTSTRAP_3))
-// {
-// final String[] modules = new String[]{"affix", "alert",
"button", "carousel", "collapse", "dropdown", "modal",
-// "scrollspy", "tab", "tooltip"};
-// addBootstrap3EsShims(configuration, modules, transition);
-//
-// Resource popover = transition.forFile("popover.js");
-//
-// final String popoverModuleName = "bootstrap/popover";
-// configuration.add(popoverModuleName,
-// EsModuleManagerContribution.base(
-// new
EsShim(popover).importModule("bootstrap/tooltip"),
-// createCallback(popoverModuleName,
esShimDispatcher)));
-// }
-//
-// if (compatibility.enabled(Trait.BOOTSTRAP_4))
-// {
-// final String bootstrapUtilModuleName =
"bootstrap/bootstrap-util";
-// configuration.add(bootstrapUtilModuleName,
-// EsModuleManagerContribution.base(
-// new EsShim(bootstrapUtil),
-// createCallback(bootstrapUtilModuleName,
esShimDispatcher)));
-//
-// final String popperModuleName = "bootstrap/popper";
-// final Resource popper = bootstrapUtil.forFile("popper.js");
-// configuration.add(popperModuleName,
-// EsModuleManagerContribution.base(
-// new EsShim(popper),
-// createCallback(popperModuleName,
esShimDispatcher)));
-//
-// for (String name : new String[]{"alert", "button", "carousel",
"collapse", "dropdown", "modal",
-// "scrollspy", "tab", "tooltip"})
-// {
-// Resource lib = bootstrapUtil.forFile(name + ".js");
-// if (lib.exists())
-// {
-// final String moduleName = "bootstrap/" + name;
-// configuration.add(moduleName,
-// EsModuleManagerContribution.base(
-// new EsShim(lib)
-//
.importModule(bootstrapUtilModuleName)
-// .importModule(popperModuleName),
-// createCallback(popperModuleName,
esShimDispatcher)));
-// }
-// }
-// }
-//
-// // Just the minimum to have alerts and AJAX validation working when
Bootstrap
-// // is completely disabled
-// if (!compatibility.enabled(Trait.BOOTSTRAP_3) &&
!compatibility.enabled(Trait.BOOTSTRAP_4))
-// {
-// final String[] modules = new String[]{"alert", "dropdown",
"collapse"};
-// addBootstrap3EsShims(configuration, modules, transition);
-// }
-// }
-
- private static EsModuleConfigurationCallback createCallback(final String
moduleName, EsShimDispatcher esShimDispatcher) {
- return c -> EsModuleConfigurationCallback.setImport(c, moduleName,
esShimDispatcher.getUrl(moduleName));
+ @Contribute(EsModuleManager.class)
+ public static void setupBaseEsModules(
+ OrderedConfiguration<EsModuleManagerContribution> configuration,
+ EsShimManager esShimManager)
+ {
+ for (String moduleName : esShimManager.getShims().keySet())
+ {
+ configuration.add(moduleName, EsModuleManagerContribution.base(
+ c -> EsModuleConfigurationCallback.setImport(c,
moduleName, esShimManager.getUrl(moduleName))));
+ }
}
private static void addBootstrap3EsShims(
@@ -707,7 +672,9 @@ public class JavaScriptModule
final Resource resource = reference.forFile(module + ".js");
if (resource.exists())
{
- configuration.add(moduleId, resource);
+ configuration.add(moduleId, new EsShim(resource)
+ .importModule("jquery")
+ .getResource());
}
}
}
diff --git
a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
index 73a69419e..0709fd572 100644
---
a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
+++
b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
@@ -1810,6 +1810,9 @@ public final class TapestryModule
@Symbol(SymbolConstants.ENABLE_PAGELOADING_MASK)
final boolean enablePageloadingMask,
+
+
@Symbol(SymbolConstants.REQUIRE_JS_ENABLED)
+ final boolean requireJsEnabled,
final ValidationDecoratorFactory
validationDecoratorFactory)
{
@@ -1817,7 +1820,9 @@ public final class TapestryModule
{
public void renderMarkup(MarkupWriter writer, MarkupRenderer
renderer)
{
- DocumentLinkerImpl linker = new
DocumentLinkerImpl(moduleManager, esModuleManager, omitGeneratorMeta,
enablePageloadingMask, tapestryVersion);
+ DocumentLinkerImpl linker = new
DocumentLinkerImpl(moduleManager,
+ esModuleManager, omitGeneratorMeta,
enablePageloadingMask,
+ tapestryVersion, requireJsEnabled);
environment.push(DocumentLinker.class, linker);
diff --git
a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsModuleManager.java
b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsModuleManager.java
index edd3dfbb0..277d02d99 100644
---
a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsModuleManager.java
+++
b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsModuleManager.java
@@ -45,7 +45,7 @@ public interface EsModuleManager
/**
* Invoked by the internal {@link
org.apache.tapestry5.internal.services.DocumentLinker} service to write the
* ES module imports (as per {@link
JavaScriptSupport#importEsModule(String)} into the page.
- * this occurs after the ES module infrastructure
+ * This occurs after the ES module infrastructure
* has been written into the page, along with the core libraries.
*
* @param root
@@ -55,6 +55,18 @@ public interface EsModuleManager
*/
void writeImports(Element root, List<EsModuleInitialization> inits);
+
+ /**
+ * Invoked by the internal {@link
org.apache.tapestry5.internal.services.DocumentLinker} service to write the
+ * calls to {@code t5/core/pageinit} module.
+ * this occurs after the ES module infrastructure
+ * has been written into the page, along with the core libraries.
+ *
+ * @param root
+ * {@code <root>} element of the page.
+ */
+ void writeInitialization(Element body, List<String> libraryURLs);
+
/**
* Encapsulates a contribution to {@linkplain EsModuleManager}.
*
diff --git
a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsShim.java
b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsShim.java
index ca20f71b4..89a2cde2d 100644
---
a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsShim.java
+++
b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsShim.java
@@ -17,8 +17,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.net.URL;
-import java.util.LinkedHashMap;
+import java.util.HashMap;
import java.util.Map;
+import java.util.Vector;
import org.apache.tapestry5.commons.Resource;
import org.apache.tapestry5.internal.util.VirtualResource;
@@ -29,7 +30,8 @@ import org.apache.tapestry5.internal.util.VirtualResource;
*
* @since 5.10.0
*/
-public class EsShim {
+public class EsShim
+{
/**
* The underlying resource, usually a JavaScript library
@@ -41,9 +43,15 @@ public class EsShim {
* the values being the respective parameter names for the module's factory
* function.
*/
- private final Map<String, String> importConfig = new LinkedHashMap<String,
String>();
+ private final Map<String, String> importConfig = new HashMap<String,
String>();
+
+ /**
+ * The default export.
+ */
+ private String defaultExport;
- public EsShim(final Resource resource) {
+ public EsShim(final Resource resource)
+ {
this.resource = resource;
}
@@ -54,10 +62,11 @@ public class EsShim {
* the name of the required module, e.g. <code>jQuery</code>
* @param variableName
* the module's corresponding variable name
- * @return this ESWrapper for further configuration
+ * @return this EsShim for further configuration
*/
public EsShim importModule(final String moduleName,
- final String variableName) {
+ final String variableName)
+ {
importConfig.put(moduleName, variableName);
return this;
}
@@ -70,72 +79,104 @@ public class EsShim {
* @param moduleName
* the name of the required module, e.g.
* <code>bootstrap/transition</code>
- * @return this ESWrapper for further configuration
+ * @return this EsShim for further configuration
*/
- public EsShim importModule(final String moduleName) {
+ public EsShim importModule(final String moduleName)
+ {
importConfig.put(moduleName, null);
return this;
}
+
+ /**
+ * Defines the default export of this module.
+ * @param defaultExport the variable or expression to be the
+ * default export of the module
+ * @return this EsShim for further configuration
+ */
+ public EsShim defaultExport(final String defaultExport)
+ {
+ this.defaultExport = defaultExport;
+ return this;
+ }
/**
- * Returns a virtual resource representing this wrapper.
+ * Returns a virtual resource representing this shim.
* @return a {@linkplain Resource}.
*/
- public Resource getResource() {
- return new ESModuleWrapperResource(resource, importConfig);
+ public Resource getResource()
+ {
+ return new ESModuleWrapperResource(resource, importConfig,
defaultExport);
}
/**
- * A virtual resource that wraps a plain JavaScript library as an AMD
+ * A virtual resource that wraps a plain JavaScript library as an ES
* module.
- *
*/
private final static class ESModuleWrapperResource extends VirtualResource
{
private final Resource resource;
private final Map<String, String> importConfig;
+ private final String defaultExport;
public ESModuleWrapperResource(final Resource resource,
- final Map<String, String> importConfig)
+ final Map<String, String> importConfig,
+ final String defaultExport)
{
this.resource = resource;
this.importConfig = importConfig;
+ this.defaultExport = defaultExport;
}
@Override
public InputStream openStream() throws IOException
{
- StringBuilder sb = new StringBuilder();
+ StringBuilder imports = new StringBuilder();
for (String module : importConfig.keySet())
{
final String variableName = importConfig.get(module);
- sb.append("import ");
+ imports.append("import ");
if (variableName != null)
{
- sb.append(variableName);
- sb.append(" from ");
+ imports.append(variableName);
+ imports.append(" from ");
}
- sb.append("\"");
- sb.append(module);
- sb.append("\";\n");
+ imports.append("\"");
+ imports.append(module);
+ imports.append("\";\n");
}
- return new SequenceInputStream(toInputStream(sb),
resource.openStream());
+
+ // Vector since SequenceInputStream doesn't have a varargs
constructor
+ // nor something better than an Enumeration when you have more
than
+ // 2 InputStreams to join.
+ Vector<InputStream> v = new Vector<>();
+ v.add(toInputStream(imports));
+ v.add(resource.openStream());
+ if (defaultExport != null)
+ {
+ v.add(toInputStream(String.format("\n export default %s;\n",
+ defaultExport)));
+ }
+
+ return new SequenceInputStream(v.elements());
}
@Override
- public String getFile() {
+ public String getFile()
+ {
return "generated-module-for-" + resource.getFile();
}
@Override
- public URL toURL() {
+ public URL toURL()
+ {
return null;
}
@Override
- public String toString() {
+ public String toString()
+ {
return "ES module wrapper for " + resource.toString();
}
diff --git
a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsShimManager.java
b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsShimManager.java
new file mode 100644
index 000000000..f9d5c5f13
--- /dev/null
+++
b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsShimManager.java
@@ -0,0 +1,49 @@
+// 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 java.util.Map;
+
+import org.apache.tapestry5.commons.Resource;
+import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
+
+/**
+ * Service managing the ES shims.
+ *
+ * @since 5.10.0
+ */
+@UsesMappedConfiguration(Resource.class)
+public interface EsShimManager
+{
+
+ /**
+ * Returns the shims as a (module name, module resource) map.
+ * @return a {@code Map<String, Resource>}
+ */
+ Map<String, Resource> getShims();
+
+ /**
+ * Returns the request prefix to be used for ES shim URLs.
+ * @param compress a {@code boolean} to inform whether it's the compressed
asset URL or not.
+ * @return the request prefix.
+ */
+ String getRequestPrefix(boolean compress);
+
+ /**
+ * Returns the full URL of a module.
+ * @param moduleName a module name.
+ * @return its URL.
+ */
+ String getUrl(String moduleName);
+
+}
diff --git
a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ExtensibleJavaScriptStack.java
b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ExtensibleJavaScriptStack.java
index 8fa030fe5..0845431dd 100644
---
a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ExtensibleJavaScriptStack.java
+++
b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ExtensibleJavaScriptStack.java
@@ -12,6 +12,8 @@
package org.apache.tapestry5.services.javascript;
+import java.util.List;
+
import org.apache.tapestry5.Asset;
import org.apache.tapestry5.func.F;
import org.apache.tapestry5.func.Flow;
@@ -23,8 +25,6 @@ import
org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
import org.apache.tapestry5.services.AssetSource;
-import java.util.List;
-
/**
* An extensible implementation of {@link JavaScriptStack} that can be used as
the implementation of a service.
* The contributions to the service are used to supply the libraries,
stylesheets, and initialization for a
@@ -50,6 +50,8 @@ public class ExtensibleJavaScriptStack implements
JavaScriptStack
private final List<String> stacks;
private final List<String> modules;
+
+ private final List<String> esModules;
private final String initialization;
@@ -116,6 +118,8 @@ public class ExtensibleJavaScriptStack implements
JavaScriptStack
stacks =
extensions.filter(by(StackExtensionType.STACK)).map(extractValue).toList();
modules =
extensions.filter(by(StackExtensionType.MODULE)).map(extractValue).toList();
+
+ esModules =
extensions.filter(by(StackExtensionType.ES_MODULE)).map(extractValue).toList();
stylesheets =
extensions.filter(by(StackExtensionType.STYLESHEET)).map(extractValue).map(stringToAsset)
.map(assetToStylesheetLink).toList();
@@ -147,31 +151,41 @@ public class ExtensibleJavaScriptStack implements
JavaScriptStack
}
}
+ @Override
public List<String> getStacks()
{
return stacks;
}
+ @Override
public List<Asset> getJavaScriptLibraries()
{
return libraries;
}
+ @Override
public List<StylesheetLink> getStylesheets()
{
return stylesheets;
}
+ @Override
public String getInitialization()
{
return initialization;
}
+ @Override
public List<String> getModules()
{
return modules;
}
+ @Override
+ public List<String> getEsModules() {
+ return esModules;
+ }
+
@Override
public JavaScriptAggregationStrategy getJavaScriptAggregationStrategy()
{
diff --git
a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptStack.java
b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptStack.java
index 777c7a118..25555e396 100644
---
a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptStack.java
+++
b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptStack.java
@@ -72,6 +72,14 @@ public interface JavaScriptStack
* @since 5.4
*/
List<String> getModules();
+
+ /**
+ * Returns a list of ES modules to be automatically included in all pages.
+ *
+ * @see EsModuleManager
+ * @since 5.10.0
+ */
+ List<String> getEsModules();
/**
* Identifies how to aggregate JavaScript within the stack.
diff --git
a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtension.java
b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtension.java
index 67cc22d7b..42c463f38 100644
---
a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtension.java
+++
b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtension.java
@@ -62,6 +62,16 @@ public class StackExtension
return new StackExtension(StackExtensionType.MODULE, name);
}
+ /**
+ * Convenience for defining an ES_MODULE.
+ *
+ * @since 5.10.0
+ */
+ public static StackExtension esModule(String name)
+ {
+ return new StackExtension(StackExtensionType.ES_MODULE, name);
+ }
+
/**
* Convenience for defining a STYLESHEET.
*
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 a4f0d7b48..0dccf2e44 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
@@ -69,6 +69,13 @@ public enum StackExtensionType
* @since 5.4
*/
MODULE,
+
+ /**
+ * An ES module to be automatically imported.
+ *
+ * @since 5.10.0
+ */
+ ES_MODULE,
/**
* Overrides the {@linkplain
JavaScriptStack#getJavaScriptAggregationStrategy() JavaScript aggregation
strategy}
diff --git
a/tapestry-core/src/main/resources/META-INF/assets/es-modules/t5/underscore.js
b/tapestry-core/src/main/resources/META-INF/assets/es-modules/t5/underscore.js
deleted file mode 100644
index dd5899219..000000000
---
a/tapestry-core/src/main/resources/META-INF/assets/es-modules/t5/underscore.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// Underscore.js 1.13.7
-// https://underscorejs.org
-// (c) 2009-2024 Jeremy Ashkenas, Julian Gonggrijp, and DocumentCloud and
Investigative Reporters & Editors
-// Underscore may be freely distributed under the MIT license.
-var VERSION="1.13.7",root="object"==typeof
self&&self.self===self&&self||"object"==typeof
global&&global.global===global&&global||Function("return
this")()||{},ArrayProto=Array.prototype,ObjProto=Object.prototype,SymbolProto="undefined"!=typeof
Symbol?Symbol.prototype:null,push=ArrayProto.push,slice=ArrayProto.slice,toString=ObjProto.toString,hasOwnProperty=ObjProto.hasOwnProperty,supportsArrayBuffer="undefined"!=typeof
ArrayBuffer,supportsDataView="undefined"!=typeof DataView,nativeIsAr [...]
\ No newline at end of file
diff --git a/tapestry-core/src/main/typescript/src/t5/core/t53-compatibility.ts
b/tapestry-core/src/main/typescript/src/t5/core/t53-compatibility.ts
new file mode 100644
index 000000000..5edf150a1
--- /dev/null
+++ b/tapestry-core/src/main/typescript/src/t5/core/t53-compatibility.ts
@@ -0,0 +1,56 @@
+// Copyright 2012, 2015 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.
+
+// Provides a small amount of backwards compatibility to the Tapestry 5.3
approach.
+// This provides placeholders for the following:
+//
+// * `T5` namespace, including `extend`, `define`, and `initializers`,
`extendInitializers`, and `_` properties
+//
+// * `Tapestry` namespace: just the `Initializer` property, as an alias of
`T5.initializers`
+
+import _ from "underscore";
+
+// @ts-ignore
+var T5, Tapestry;
+T5 = {
+ _: _,
+ // @ts-ignore
+ extend: function(destination, source) {
+ if (_.isFunction(source)) {
+ source = source();
+ }
+ return _.extend(destination, source);
+ },
+ // @ts-ignore
+ define: function(name, source) {
+ var namespace;
+ namespace = {};
+ T5[name] = namespace;
+ // @ts-ignore
+ return T5.extend(namespace, source);
+ },
+ initializers: {},
+ // @ts-ignore
+ extendInitializers: function(source) {
+ // @ts-ignore
+ return T5.extend(T5.initializers, source);
+ }
+};
+Tapestry = {
+ Initializer: T5.initializers
+};
+// @ts-ignore
+window.T5 = T5;
+// @ts-ignore
+window.Tapestry = Tapestry;
diff --git
a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/Border.java
b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/Border.java
index b5a6d8e13..5ffe581ea 100644
---
a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/Border.java
+++
b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/Border.java
@@ -13,9 +13,11 @@
package org.apache.tapestry5.integration.app1.components;
import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.annotations.BeginRender;
import org.apache.tapestry5.annotations.Import;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.http.services.Request;
+import org.apache.tapestry5.internal.services.ajax.RequireJsModeHelper;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.pageload.PageClassLoaderContextManager;
@@ -25,7 +27,7 @@ import java.util.Calendar;
* Here's a component with a template, including a t:body element. Really
should rename this to "Layout" as that's the
* T5 naming.
*/
-@Import(stylesheet = "context:css/app.css", module = {"bootstrap/collapse",
"app/test-support"})
+@Import(stylesheet = "context:css/app.css")
public class Border
{
@Inject
@@ -37,6 +39,9 @@ public class Border
@Inject @Property
private PageClassLoaderContextManager pccm;
+
+ @Inject
+ private RequireJsModeHelper requireJsModeHelper;
public static final int year;
@@ -67,4 +72,11 @@ public class Border
return version + " from " + System.getProperty("java.vendor");
}
+ @BeginRender
+ void beginRender()
+ {
+ requireJsModeHelper.importModule("bootstrap/collapse");
+ requireJsModeHelper.importModule("app/test-support");
+ }
+
}
diff --git
a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
index 42338f94a..fcad59e0a 100644
---
a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
+++
b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
@@ -58,581 +58,581 @@ public class Index
private static final List<Item> ITEMS = CollectionFactory
.newList(
-// new Item("PublishEventDemo", "@PublishEvent Demo",
"Publishing server-side events to client-side code (JavaScript)"),
-//
-// new Item("StaticActivationContextValueDemo",
"@StaticActivationContextValue Demo", "Demonstrates the usage of
@StaticActivationContextValue"),
-//
-// new Item("rest/RestWithOnEventDemo", "REST with @OnEvent
Demo", "Demonstrates the usage of @OnEvent to handle REST requests"),
-//
-// new Item("rest/RestWithEventHandlerMethodNameDemo",
"REST with Event Handler Method Name Demo", "Demonstrates the usage of event
handler method names to handle REST requests"),
-//
-// new Item("Html5DateFieldDemo", "Html5DateField Demo",
"Choosing dates using the native HTML5 date picker"),
-//
-//// new Item("ZoneFormDemo", "Zone Form Decoration",
"Fields inside an Ajax-updatd Form are still decorated properly."),
-//
-// new Item("AjaxValidationDemo", "Ajax Validation",
"Demonstrated proper integration of server-side validation and client-side
field decoration."),
-//
-// new Item("OverrideEventHandlerDemo", "Event Handler
Override Demo", "Event Handler methods overridden by sub-classes invoke
base-class correctly."),
-//
-// new Item("LogoSubclass", "Base class Assets in
sub-classes", "Assets are resolved for the parent class if that's where the
annotations are."),
-//
-// new Item("MissingRequiredARP", "Missing Query Parameter
for @ActivationRequestParameter", "Activating a page with a required
@ActivationRequestParameter, but no matching query parameter, is an error."),
-//
-//// new Item("DateFieldValidationDemo", "DateField
Validation Demo",
-//// "Use of DateField component when client
validation is disabled."),
-//
-// new Item("MixinParameters54", "Strict Mixin Parameters",
"In the 5.4 DTD, Parameter Mixins must be qualified with the mixin id."),
-//
-// new Item("AsyncDemo", "Async Links and Forms Demo",
"Async (XHR) Updates without a containing Zone."),
-//
-// new Item("FormCancelActionDemo", "Form Cancel Action
Demo", "FormSupport.addCancel() support"),
-//
-// new Item("AjaxRadioDemo", "Ajax Radio Demo", "Radio
components inside an Ajax form"),
-//
-// new Item("TimeIntervalDemo", "TimeInterval Demo",
"Interval component, based on Moment.js"),
-//
-// new Item("LocalDateDemo", "LocalDate Demo", "LocalDate
component, based on Moment.js"),
-//
-// new Item("EmptyIfDemo", "Empty If Demo", "Ensure an
empty If can still render."),
-//
-// new Item("MissingAssetDemo", "Missing Asset Demo",
"Error when injecting an asset that does not exist."),
-//
-// new Item("ConfirmDemo", "Confirm Mixin Demo", "Confirm
an action when clicking it."),
-//
-// new Item("SingleErrorDemo", "Single Error", "Using Error
component to customize where the errors for a field will be displayed."),
-//
-// new Item("JavaScriptTests", "JavaScript Tests",
"Client-side tests using Mocha and Chai"),
-//
-// new Item("ModuleInitDemo", "Module-based Initialization
Demo", "Invoke a module function to perform page initialization"),
-//
-// new Item("OperationWorkerDemo", "Operation Worker Demo",
"Demonstrate use of @Operation annotation on component methods"),
-//
-// new Item("MixinParameterDefault", "Mixin Parameter with
Default", "Ensure that a mixin parameter with a default value is not reported
as unbound."),
-//
-// new Item("MixinVsInformalParameter", "Mixin Parameter
vs. Informal Parameter", "Informal Paramters vs. Mixin parameter of same name"),
-//
-// new Item("inherit/childa", "TAP5-1656 Demo", "Test a
reported bug in component inheritance"),
-//
-// new Item("ComponentInsideBlockDemo", "Component Inside
Block Demo", "Verify that a component, inside a block, is still an embedded "),
-//
-// new Item("EventMethodUnmatchedComponentId", "Unmatched
Component Id in Event Method Demo", "Show that referencing a component that
does not exist in an event handler method name is an error."),
-//
-// new Item("AlertsDemo", "Alerts Demo", "Managing alerts
both traditional and Ajax"),
-//
-// new Item("ClientConsoleDemo", "Client Console Demo",
"Demo for the JavaScript client-side console"),
-//
-// new Item("InvalidFormalParameterDemo", "Unmatched Formal
Parameter with @Component", "Parameters specified with @Component annotation
must match formal parameters"),
-//
-// new Item("NullBindingToPrimitive", "Null Bound to
Primitive Demo", "Correct exception when a primitive parameter is bound to
null"),
-//
-// new Item("TreeDemo", "Tree Component Demo", "Demo of
Tree Component"),
-//
-// new Item("TreeSelectionDemo", "Tree Component Selection
Demo", "Demo of Selection with Tree Component"),
-//
-// new Item("TreeNoRootsDemo", "Tree Component No Roots
Demo", "Demo of No Roots with Tree Component"),
-//
-// new Item("InvalidExpressionInDynamicTemplate", "Invalid
Dynamic Expression",
-// "Invalid expression in a Dynamic Template"),
-//
-// new Item("DynamicDemo", "Dynamic Demo", "Basic Dynamic
component tests"),
-//
-// new Item("DynamicExpansionsDemo", "Expansions in Dynamic
Templates",
-// "Expansions inside Dynamic component content and
attributes"),
-//
-// new Item("PACAnnotationDemo", "PageActivationContext
Demo",
-// "Shows that @PageActivationContext fields are
set before calls to the activate event handler."),
-//
-// new Item("PACMultipleAnnotationDemo",
"PageActivationContext Multiple Demo",
-// "Demonstrates multiple @PageActivationContext
fields."),
-//
-// new Item("PublicFieldAccessDemo", "Public Field Access
Demo", "Demonstrates TAP5-1222 fix"),
-//
-// new Item("ActivationRequestParameterDemo",
"ActivationRequestParameter Annotation Demo",
-// "Use of @ActivationRequestParameter to encode
page state into query parameters"),
-//
-// new Item("LibraryMessagesDemo", "Library Messages Demo",
-// "Demo ability to contribute additional message
catalog resources to the application global catalog."),
-//
-// new Item("MultiZoneUpdateInsideForm", "MultiZone Update
inside a Form",
-// "Update multiple zones within a single Form."),
-//
-// new Item("ZoneFormUpdateDemo", "Zone/Form Update Demo",
"Updating a Zone inside a Form"),
-//
-// new Item("MultiZoneStringBodyDemo", "MultiZone String
Body Demo",
-// "Multi-zone updates in a loop using strings
coerced into blocks"),
-//
-// new Item("RenderNotificationDemo", "RenderNotification
Demo", "Use of RenderNotification mixin"),
-//
-// new Item("InjectMessagesDemo", "Inject Global Messages
into Service Demo",
-// "Ensure that it is possible to inject the
application global message catalog into a service"),
-//
-// new Item("ReloadDemo", "Reloadable Service
Implementation Demo",
-// "Used when manually testing service reloads"),
-//
-// new Item("RequestParameterDemo", "RequestParameter
Annotation Demo",
-// "Use of @RequestParameter annotation on event
handler method parameters"),
-//
-// new Item("CancelDemo", "Cancel Demo", "Use of the cancel
option with Submit"),
-//
-// new Item("CanceledEventDemo", "Canceled Event Demo",
"Triggering of the canceled event from a form."),
-//
-// new Item("PageResetDemo", "PageReset Annotation Demo",
-// "Use of PageReset annotation to re-initialize
page state"),
-//
-// new Item("TestOnlyServiceDemo", "Test Only Service Demo",
-// "IoC module available via web.xml
configuration"),
-//
-// new Item("RenderObjectExceptionDemo", "RenderObject
Exception Demo",
-// "Demonstrate how exceptions when rendering
default objects are displayed."),
-//
-// new Item("MultiLevelInheritDemo", "Multi-Level Inherit
Demo",
-// "Use of inherit: binding prefix across three
levels"),
-//
-// new Item("HiddenDemo", "Hidden Demo", "Demo the use of
the Hidden component."),
-//
-// new Item("FormZoneDemo", "Form Zone Demo", "Use a form
to update a zone."),
-//
-// new Item("ZoneUpdateNamespace", "Zone/Namespace
Interaction", "Prove that TAP5-573 is fixed"),
-//
-// new Item("AbstractComponentDemo", "Abstract Component
Demo", "Error when a component is abstract"),
-//
-// new Item("TemplateOverrideDemo", "Template Override
Demo",
-// "Child component extends and overrides parent
template."),
-//
-// new Item("MultiZoneUpdateDemo", "Multiple Zone Update
Demo",
-// "A single request can now update multiple
Zones"),
-//
-// new Item("LinkSubmitInZoneDemo", "LinkSubmit inside
Zone",
-// "Ensure that a LinkSubmit works correctly when
its containing Form updates a Zone"),
-//
-// new Item("ProgressiveDemo", "ProgressiveDisplay Demo",
"Progressive Enhancement via a component"),
-//
-// new Item("ClientNumericValidationDemo", "Client-Side
Numeric Validation",
-// "Client-side locale-specific validation"),
-//
-// new Item("PublishParametersDemo", "Publish Parameters
Demo",
-// "Use of @Component.publishParameters
attribute."),
-//
-// new Item("LinkSubmitDemo", "LinkSubmit Demo",
"JavaScript LinkSubmit component"),
-//
-// new Item("LinkSubmitWithoutValidatorDemo", "LinkSubmit
Without Validator Demo",
-// "Demonstrates that the LinkSubmit component is
working without a validator on any of fields in the form"),
-//
-// new Item("PerFormValidationMessageDemo", "Per-Form
Validation Messages",
-// "Per-form configuration of validation messages
and constraints."),
-//
-// new Item("EmptyLoopDemo", "Empty Loop Demo", "Use of
empty parameter with the Loop component."),
-//
-// new Item("GenericLoopDemo", "Generic Loop Demo",
-// "Use of generic parameters with the Loop
component."),
-//
-// new Item("LoopWithMixinDemo", "Loop With Mixin Demo",
-// "Use a mixin with a Loop component."),
-//
-// new Item("BlankPasswordDemo", "Blank Password Demo",
-// "Show that a blank value in a PasswordField does
not update the server side value."),
-//
-// new Item("GridFormEncoderDemo", "Grid Form Encoder Demo",
-// "Grid inside a Form using the ValueEncoder
option"),
-//
-// new Item("GridFormWithInitialSortMixinDemo", "Grid Form
With Initial Sort Mixin Demo",
-// "Grid inside a Form using the InitialSort
mixin"),
-//
-// new Item("DateFieldAjaxFormLoop", "DateField inside
AjaxFormLoop",
-// "Show that DateField component works correctly
inside AjaxFormLoop"),
-//
-// new Item("NestedForm", "Nested Form Demo", "Error when a
Form is nested inside another Form."),
-//
-// new Item("UnhandledEventDemo", "Unhandled Event Demo",
-// "Events that don't have matching event handlers
cause exceptions"),
-//
-// new Item("PrimitiveDefaultDemo", "Primitive Default
Demo",
-// "Primitive value returned from parameter default
method"),
-//
-// new Item("ValidateFormValidationExceptionDemo",
"ValidationForm ValidationException Demo",
-// "Throwing a ValidationException from the
validateForm event handler."),
-//
-// new Item("ClientFormatDemo", "Client Format Validation",
"Client-side input format validation"),
-//
-// new Item("ShortGrid", "Short Grid",
-// "Grid where the number of claimed rows is less
than the number of actual rows"),
-//
-// new Item("NullParameterDemo", "Null Parameter Demo",
"Binding a not-null parameter to null."),
-//
-// new Item("nestedbeaneditor", "Nested BeanEditor",
-// "BeanEditor as override for property editor in
BeanEditForm"),
-//
-// new Item("actionpage", "Action Page", "tests fixture for
ActionLink component"),
-//
-// new Item("cleancachedemo", "Clean Cache Demo", "cache
cleared properly during Ajax calls"),
-//
-// new Item("numberbeaneditordemo", "Number BeanEditor
Demo",
-// "use of nulls and wrapper types with
BeanEditor"),
-//
-// new Item("forminjectordemo", "FormInjector Demo",
"extending a form dynamically via Ajax"),
-//
-// new Item("music", "Music Page", "demo handling of edge
cases of page naming"),
-//
-// new Item("PersistentDemo", "Persistent Demo", "storing
and clearing persistent properties"),
-//
-// new Item("ActionViaLinkDemo", "Action via Link Demo",
"tests creating an action link explicitly"),
-//
-// new Item("FormFragmentDemo", "Form Fragment Demo", "page
with dynamic form sections"),
-//
-// new Item("BooleanDemo", "Boolean Property Demo",
-// "demo boolean properties using both is and get
prefixes"),
-//
-// new Item("DeleteFromGridDemo", "Delete From Grid", "demo
deleting items form a Grid"),
-//
-// new Item("RenderErrorDemo", "Render Error Demo",
"reporting of errors while rendering"),
-//
-// new Item("nested/AssetDemo", "AssetDemo", "declaring an
image using Assets"),
-//
-// new Item("nested/ActionDemo", "Action With Context Demo",
-// "using action links with context on page with
activation context"),
-//
-// new Item("blockdemo", "BlockDemo", "use of blocks to
control rendering"),
-//
-// new Item("countdown", "Countdown Page", "defining
component using @Component annotation"),
-//
-// new Item("injectdemo", "Inject Demo", "use of various
kinds of injection"),
-//
-// new Item("instancemixin", "InstanceMixin", "mixin added
to a particular component instance"),
-//
-// new Item("TextFieldWrapperTypeDemo", "TextField Wrapper
Types",
-// "use of TextField to edit numeric wrapper types
(not primitives) "),
-//
-// new Item("EnvironmentalDemo", "Environmental Annotation
Usage",
-// "Storing and retrieving Environmental values"),
-//
-// new Item("Expansion", "Expansion Page", "Use of
expansions in templates"),
-//
-// new Item("ExpansionSubclass", "ExpansionSubclass",
-// "components can inherit templates from base
classes"),
-//
-// new Item("Localization", "Localization", "access
localized messages from the component catalog"),
-//
-// new Item("NumberSelect", "NumberSelect",
"passivate/activate page context demo"),
-//
-// new Item("ParameterConflict", "Template Overridden by
Class Page",
-// "Parameters in the class override those in the
template"),
-//
-// new Item("ParameterDefault", "ParameterDefault",
"defaulter methods for component parameters"),
-//
-// new Item("passwordfielddemo", "PasswordFieldDemo", "test
for the PasswordField component"),
-//
-// new Item("rendercomponentdemo", "RenderComponentDemo",
-// "components that \"nominate\" other components
to render"),
-//
-// new Item("renderphaseorder", "RenderPhaseOrder",
-// "order of operations when invoking render phase
methods"),
-//
-// new Item("simpleform", "SimpleForm", "first pass at
writing Form and TextField components"),
-//
-// new Item("OptionGroupForm", "OptionGroupForm Demo",
"Select with Option Group"),
-//
-// new Item("validform", "ValidForm", "server-side input
validation"),
-//
-// new Item("ToDoListVolatile", "ToDo List (Volatile)",
"Loops and Submit inside Form, volatile mode"),
-//
-// new Item("MissingTemplate", "Missing Template Demo",
-// "Demo for what happens when a template is not
found for a page"),
-//
-// new Item("nested/zonedemo", "Zone Demo", "dynamic
updates within a page"),
-//
-// new Item("todolist", "ToDo List", "Loops and Submit
inside Form using primary key encoder"),
-//
-// new Item("flashdemo", "FlashDemo", "demonstrate 'flash'
persistence"),
-//
-// new Item("beaneditordemo", "BeanEditor Demo",
"demonstrate the BeanEditor mega-component"),
-//
-// new Item("pageloadeddemo", "PageLoaded Demo", "shows
that page lifecycle methods are invoked"),
-//
-// new Item("griddemo", "Grid Demo", "default Grid
component"),
-//
-// new Item("GridInLoopDemo", "Grid In Loop Demo", "Grid
inside loop with different model on each iteration"),
-//
-// new Item("nullgrid", "Null Grid", "handling of null
source for Grid"),
-//
-// new Item("gridsetdemo", "Grid Set Demo", "handling of
Set sources for Grid"),
-//
-// new Item("gridenumdemo", "Grid Enum Demo", "handling of
enum types in the Grid"),
-//
-// new Item("GridRemoveReorderDemo", "Grid Remove/Reorder
Demo",
-// "handling of remove and reorder parameters"),
-//
-// new Item("EmptyGrid", "Empty Grid Demo", "show table for
empty data sources"),
-//
-// new Item("GridEarlyPagingDemo", "Grid Early Paging",
"set a Grid's current page before rendering"),
-//
-// new Item("protected", "Protected Page",
-// "Demonstrate result of non-void return from a
page's activate method"),
-//
-// new Item("Kicker", "Kicker", "demos complex page and
component context in links"),
-//
-// new Item("simpletrackgriddemo", "SimpleTrack Grid Demo",
-// "customizing the model for a Grid around an
interface"),
-//
-// new Item("pagelinkcontext", "PageLink Context Demo",
-// "passing explicit context in a page render
link"),
-//
-// new Item("pagecontextinform", "Page Context in Form",
"passivate/activate page context in Form",
-// "betty", "wilma", "context with spaces",
"context/with/slashes"),
-//
-// new Item("ValidBeanEditorDemo", "Client Validation
Demo", "BeanEditor with validation enabled"),
-//
-// new Item("Unreachable", "Unreachable Page", "page not
reachable due to IgnoredPathsFilter"),
-//
-// new Item("renderabledemo", "Renderable Demo",
-// "shows that render phase methods can return a
Renderable"),
-//
-// new Item("inheritedbindingsdemo", "Inherited Bindings
Demo",
-// "Tests for components that inherit bindings from
containing components"),
-//
-// new Item("ClientPersistenceDemo", "Client Persistence
Demo",
-// "component field values persisted on the client
side"),
-//
-// new Item("attributeExpansionsDemo", "Attribute
Expansions Demo",
-// "use expansions inside attributes of ordinary
elements"),
-//
-// new Item("PaletteDemo", "Palette Demo", "multiple
selection component"),
-// new Item("PaletteGroupedDemo", "Palette Grouped Demo",
"multiple selection component (grouped)"),
-//
-// new Item("ReturnTypes", "Return Types", "tests various
event handler return types"),
-//
-// new Item("FormEncodingType", "Form Encoding Type",
-// "Test ability to set an encoding type for a
Form"),
-//
-// new Item("RadioDemo", "RadioDemo", "Use of the
RadioGroup and Radio components"),
-//
-// new Item("RegexpDemo", "Regexp Demo", "Use of the Regexp
validator"),
-//
-// new Item("BeanEditRemoveReorder", "BeanEdit
Remove/Reorder",
-// "Use of the remove and reorder parameters with
BeanEditForm"),
-//
-// new Item("MultiBeanEditDemo", "MultiBeanEdit Demo",
-// "Multiple BeanEditor components in a single
form"),
-//
-// new Item("GridFormDemo", "Grid Form Demo", "Grid
operating inside a Form"),
-//
-// new Item("DateFieldDemo", "DateField Demo", "using
DateField by itself on a page"),
-//
-// new Item("BeanEditDateDemo", "BeanEditor / Date Demo",
-// "Use of date properties inside BeanEditor and
BeanDisplay"),
-//
-// new Item("eventmethodtranslate", "EventMethod
Translator",
-// "Demo ability to provide toclient and
parseclient event handler methods"),
-//
-// new Item("autocompletedemo", "Autocomplete Mixin Demo",
-// "Demo the autocomplete mixin for text fields"),
-//
-// new Item("componentparameter", "ComponentParameter Demo",
-// " Demo using a component type as a parameter
type and succesfully passing a component"),
-//
-// new Item("inheritinformalsdemo", "Inherit Informal
Parameters Demo",
-// "Demo a component which inherits informal
parameters from its container"),
-//
-// new Item("disabledfields", "Disabled Fields",
-// "Demonstrate a bunch of disabled fields, to
verify that the RenderDisabled mixin works and is being used properly"),
-//
-// new Item("BeanEditorOverride", "BeanEditor Override",
-// "Property editor overrides work for the
BeanEditor component itself (not just the BeanEditForm component)"),
-//
-// new Item("varbindingdemo", "Var Binding Demo", "use of
the var: binding prefix"),
-//
-// new Item("leangriddemo", "Lean Grid Demo",
-// "Grid component with lean parameter turned on,
to eliminate CSS class attributes in TD and TH elements"),
-//
-// new Item("blockcaller", "Action Links off of Active
Page",
-// "Actions can exist on pages other than the
active page, via Blocks."),
-//
-// new Item("unlessdemo", "Unless Demo", "use of the Unless
component"),
-//
-// new Item("delegateinline", "Inline Delegate",
-// "Using the delegate component to create inline
components"),
-//
-// new Item("MagicValueEncoder", "Magic ValueEncoder Demo",
-// "Automatic creation of ValueEncoder using the
TypeCoercer"),
-//
-// new Item("NullStrategyDemo", "Null Field Strategy Demo",
"use of the nulls parameter of TextField"),
-//
-// new Item("OverrideValidationDecorator", "Override
Validation Decorator",
-// "override the default validation decorator"),
-//
-// new Item("ExceptionEventDemo", "Exception Event Demo",
"handling component event exceptions"),
-//
-// new Item("AddedGridColumnsDemo", "Added Grid Columns
Demo", "programatically adding grid columns"),
-//
-// new Item("PrimitiveArrayParameterDemo", "Primitive Array
Parameter Demo",
-// "use primitive array as parameter type"),
-//
-// new Item("RenderPhaseMethodExceptionDemo", "Render Phase
Method Exception Demo",
-// "render phase methods may throw checked
exceptions"),
-//
-// new Item("TrackEditor", "Generic Page Class Demo",
-// "demo use of generics with component classes
and, particularily, with property types"),
-//
-// new Item("IndirectProtectedFields", "Protected Fields
Demo",
-// "demo exception when component class contains
protected fields"),
-//
-// new Item("injectcomponentdemo", "Inject Component Demo",
"inject component defined in template"),
-//
-// new Item("cachedpage", "Cached Annotation", "Caching
method return values"),
-//
-// new Item("cachedpage2", "Cached Annotation2", "Caching
method return values w/ inheritence"),
-//
-// new Item("inplacegriddemo", "In-Place Grid Demo", "Grid
that updates in-place using Ajax"),
-//
-// new Item("methodadvicedemo", "Method Advice Demo",
"Advising component methods."),
-//
-// new Item("HasBodyDemo", "Has Body Demo", "Verify the
hasBody() method of ComponentResources"),
-//
-// new Item("BeanEditorBeanEditContext", "BeanEditor
BeanEditContext",
-// "BeanEditContext is pushed into enviroment by
BeanEditor."),
-//
-// new Item("InformalParametersDemo", "Informal Parameters
Demo",
-// "Access to informal parameters names and
values"),
-//
-// new Item("FormFieldOutsideForm", "Form Field Outside
Form",
-// "Nice exception message for common problem of
form fields outside forms"),
-//
-// new Item("SubmitWithContext", "Submit With Context",
"Providing a context for Submit component"),
-//
-// new Item("MessageConstraintGeneratorDemo", "Validation
Constraints From Messages",
-// "Providing validators to apply from a properties
file"),
-//
-// new Item("RenderClientIdDemo", "RenderClientId Mixin",
-// "Force render of client-side id of a client
element via the RenderClientId mixin"),
-//
-// new Item("BindParameterDemo", "BindParameter mixin
annotation",
-// "Accessing component parameter values from a
mixin"),
-//
-// new Item("BindParameterNoSuchParameter", "BindParameter
error handling",
-// "BindParameter throws exception if the
containing component doesn't have a matching parameter"),
-//
-// new Item("BindParameterOnComponent", "BindParameter on
component",
-// "Verify that BindParameter can only be used on
mixin fields"),
-//
-// new Item("MixinOrderingDemo", "Mixin Ordering Demo",
"Various mixin-ordering scenarios"),
-//
-// new Item(
-// "MissingComponentClassException",
-// "Missing Component Class Exception",
-// "Meaningful exception message thrown when
component class can't be determined from template or field in containing
component."),
-//
-// new Item("SessionAttributeDemo", "SessionAttribute Demo",
-// "Annotation to map a field to a specific session
attribute"),
-//
-// new Item("BeanEditCalendarDemo", "BeanEditor / Calendar
Demo",
-// "Use of calendar properties inside BeanEditor
and BeanDisplay"),
-//
-// new Item("TriggerDemo", "Trigger Demo", "Use of Trigger
component"),
-//
-// new Item("ImageSubmitDemo", "Submit with an Image Demo",
-// "Make sure that submit with the image parameter
set triggers the 'selected' event."),
-//
-// new Item("SelectZoneDemo", "Select Zone Demo", "Use a
Select component to update a zone."),
-//
-// new Item("AssetProtectionDemo", "Asset Protection Demo",
-// "AssetProtectionDispatcher is properly
contributed and functioning"),
-//
-// new Item("BeanDisplayEnumDemo", "BeanDisplay Enum Demo",
-// "User represenation of enum values is correctly
read from messages"),
-//
-// new Item("unavailablecomponentdemo", "Report Location of
Unavailable Component",
-// "Report Location of Unavailable Component"),
-//
-// new Item("discardafterdemo", "@DiscardAfter Demo", "Demo
using @DiscardAfter annotation"),
-//
-// new Item("SelectDemo", "Select Demo", "Validation
decoration for Select"),
-//
-// new Item("SelectModelFromObjectsAndPropertyNameDemo",
"SelectModel from objects and property name",
-// "Creating a SelectModel from a list of objects
and a label property name"),
-//
-// new Item("SelectModelFromObjectsDemo", "SelectModel from
objects",
-// "Creating a SelectModel from a list of objects"),
-//
-// new Item("SelectModelCoercionDemo", "SelectModel
coercion",
-// "Creating a SelectModel from a list of objects
using coercion"),
-//
-// new Item("DecoratePageRenderLinkDemo", "Decorate Page
Render Link Demo",
-// "Decorating page render links"),
-//
-// new Item("DecorateComponentEventLinkDemo", "Decorate
Component Event Link Demo",
-// "Decorating event links"),
-//
-// new Item("ValidatorMacroDemo", "Validator Macro Demo",
"Using validator macros"),
-//
-// new Item("AtInjectDemo", "@jakarta.inject.Inject Demo",
"Using @jakarta.inject.Inject for injection"),
-//
-// new Item("LinkQueryParameters", "Link Query Parameters
Demo",
-// "Providing Query Parameters directly to link
components as a map of key=parameter name, value=parameter values"),
-//
-// new Item("ChecklistDemo", "Checklist Demo", "Use
Checklist component"),
-//
-// new Item("BeanEditFormPrepareBubbling", "BeanEditor
Prepare Bubbling Demo", "Prepare event bubbling"),
-//
-// new Item("NestedFormFragment", "Nested Form Fragment
Demo", "Nesting Form Fragments work properly"),
-//
-// new Item("MapExpressionInExpansions", "Map Expressions
in Expansions Demo", "Maps can be used in expansions"),
-//
-// new Item("ExpressionInJsFunction", "Expressions in JS
Functions Demo", "Expressions can be used inside javascript functions"),
-//
-// new Item("FormFieldFocusDemo", "FormFieldFocus
(DEPRECATED) Demo", "Setting the Form focus on a specific field"),
-//
-// new Item("FormFragmentExplicitVisibleBoundsDemo", "Form
Fragment Explicit Visible Bounds Demo", "Check for form fragment parent
visibility can be bounded to"),
-//
-// new Item("OverrideFieldFocusDemo", "OverrideFieldFocus
Demo", "Setting the focus in a form to a specific field"),
-//
-// new Item("OverrideLabelClassDemo", "Override Label Class
Demo", "Setting class attribute on Label component"),
-//
-// new Item("FormLinkParameters", "FormLinkParameters
Demo", "Form link parameters should be unescaped for a hidden field"),
-//
-// new Item("KnownActivationContextDemo", "Known Activation
Context Demo", "Page is displayed normally if called without context
(TAP5-2070)",
-// "Exact"),
-//
-// new Item("UnknownActivationContextDemo", "Unknown
Activation Context Demo", "Page refuse to serve if called with an unknown
activation context (TAP5-2070)",
-// "Unwanted", "context"),
-//
-// new Item("ModuleConfigurationCallbackDemo",
"ModuleConfigurationCallback Demo", "Shows an example of changing the
Require.js configuration using JavaScriptSupport.addModuleConfigurationDemo()"),
-//
-// new Item("PartialTemplateRendererDemo",
"PartialTemplateRenderer Demo", "Shows some examples of rendering blocks and
components to a String using PartialTemplateRenderer"),
-//
-// new Item("nested/PageThatThrowsException", "Reload on
nested page", "Tests a page reload from a nested page's exception report"),
-//
-// new Item("inplacegridinloopdemo", "In-Place Grid in a
Loop Demo", "In-place grid in a loop"),
-//
-// new Item("GenericTypeDemo", "Generic bound type demo",
"Tests that generic type info is available for generic bindings"),
-//
-// new Item("FormFieldClientIdParameterDemo", "Form Field
clientId Parameter Demo", "Shows and tests how to explicitly set the id of a
form field component"),
-//
-// new Item("gridwithsubmitwithcontextdemo", "Grid with
Submit with context", "A grid whose rows contain a Submit component with
context"),
-//
-// new Item("textfieldwithnullvalidateparameter",
"TextField with null validate parameter", "A TextField whose validate parameter
is bound to null"),
-//
-// new Item("validateCheckboxMustBeChecked", "Validate
Checkbox Must Be Checked", "A form that trigger validate in " +
-// "error event on submit when checkbox is not
checked"),
-//
-// new Item("validateCheckboxMustBeUnchecked", "Validate
Checkbox Must Be Unchecked", "A form that trigger validate in " +
-// "error event on submit when checkbox is
checked"),
-//
-// new Item("validateInErrorEvent", "Validate in error
Event", "A form that trigger validate in " +
-// "error event on submit when textfield is empty"),
-//
-// new Item("onactivateredirect", "OnActivateRedirect
Demo", "A page that redirects to itself from"
-// + " its activation method"),
-//
-// new Item("BeanEditorWithFormFragmentDemo", "Bean Editor
With Form Fragment Demo", "TriggerFragment mixin used inside a BeanEditor"),
-//
-// new Item("ObjectEditorDemo","Object Editor Demo","Edit
Bean with address objects"),
-//
-// new Item("IfDemo","If Demo","If component with all its
options"),
-//
-// new Item("RecursiveDemo","Recursive Demo","Recursive
component example"),
-//
-// new Item("SelfRecursiveDemo", "Self-Recursive Demo",
"check for handling of self-recursive components"),
-//
-// new Item("EsModuleDemo", "ES Module Demo", "tests and
demonstrations for the ES module support")
+ new Item("PublishEventDemo", "@PublishEvent Demo",
"Publishing server-side events to client-side code (JavaScript)"),
+
+ new Item("StaticActivationContextValueDemo",
"@StaticActivationContextValue Demo", "Demonstrates the usage of
@StaticActivationContextValue"),
+
+ new Item("rest/RestWithOnEventDemo", "REST with @OnEvent
Demo", "Demonstrates the usage of @OnEvent to handle REST requests"),
+
+ new Item("rest/RestWithEventHandlerMethodNameDemo", "REST
with Event Handler Method Name Demo", "Demonstrates the usage of event handler
method names to handle REST requests"),
+
+ new Item("Html5DateFieldDemo", "Html5DateField Demo",
"Choosing dates using the native HTML5 date picker"),
+
+// new Item("ZoneFormDemo", "Zone Form Decoration", "Fields
inside an Ajax-updatd Form are still decorated properly."),
+
+ new Item("AjaxValidationDemo", "Ajax Validation",
"Demonstrated proper integration of server-side validation and client-side
field decoration."),
+
+ new Item("OverrideEventHandlerDemo", "Event Handler
Override Demo", "Event Handler methods overridden by sub-classes invoke
base-class correctly."),
+
+ new Item("LogoSubclass", "Base class Assets in
sub-classes", "Assets are resolved for the parent class if that's where the
annotations are."),
+
+ new Item("MissingRequiredARP", "Missing Query Parameter
for @ActivationRequestParameter", "Activating a page with a required
@ActivationRequestParameter, but no matching query parameter, is an error."),
+
+// new Item("DateFieldValidationDemo", "DateField
Validation Demo",
+// "Use of DateField component when client
validation is disabled."),
+
+ new Item("MixinParameters54", "Strict Mixin Parameters",
"In the 5.4 DTD, Parameter Mixins must be qualified with the mixin id."),
+
+ new Item("AsyncDemo", "Async Links and Forms Demo", "Async
(XHR) Updates without a containing Zone."),
+
+ new Item("FormCancelActionDemo", "Form Cancel Action
Demo", "FormSupport.addCancel() support"),
+
+ new Item("AjaxRadioDemo", "Ajax Radio Demo", "Radio
components inside an Ajax form"),
+
+ new Item("TimeIntervalDemo", "TimeInterval Demo",
"Interval component, based on Moment.js"),
+
+ new Item("LocalDateDemo", "LocalDate Demo", "LocalDate
component, based on Moment.js"),
+
+ new Item("EmptyIfDemo", "Empty If Demo", "Ensure an empty
If can still render."),
+
+ new Item("MissingAssetDemo", "Missing Asset Demo", "Error
when injecting an asset that does not exist."),
+
+ new Item("ConfirmDemo", "Confirm Mixin Demo", "Confirm an
action when clicking it."),
+
+ new Item("SingleErrorDemo", "Single Error", "Using Error
component to customize where the errors for a field will be displayed."),
+
+ new Item("JavaScriptTests", "JavaScript Tests",
"Client-side tests using Mocha and Chai"),
+
+ new Item("ModuleInitDemo", "Module-based Initialization
Demo", "Invoke a module function to perform page initialization"),
+
+ new Item("OperationWorkerDemo", "Operation Worker Demo",
"Demonstrate use of @Operation annotation on component methods"),
+
+ new Item("MixinParameterDefault", "Mixin Parameter with
Default", "Ensure that a mixin parameter with a default value is not reported
as unbound."),
+
+ new Item("MixinVsInformalParameter", "Mixin Parameter vs.
Informal Parameter", "Informal Paramters vs. Mixin parameter of same name"),
+
+ new Item("inherit/childa", "TAP5-1656 Demo", "Test a
reported bug in component inheritance"),
+
+ new Item("ComponentInsideBlockDemo", "Component Inside
Block Demo", "Verify that a component, inside a block, is still an embedded "),
+
+ new Item("EventMethodUnmatchedComponentId", "Unmatched
Component Id in Event Method Demo", "Show that referencing a component that
does not exist in an event handler method name is an error."),
+
+ new Item("AlertsDemo", "Alerts Demo", "Managing alerts
both traditional and Ajax"),
+
+ new Item("ClientConsoleDemo", "Client Console Demo", "Demo
for the JavaScript client-side console"),
+
+ new Item("InvalidFormalParameterDemo", "Unmatched Formal
Parameter with @Component", "Parameters specified with @Component annotation
must match formal parameters"),
+
+ new Item("NullBindingToPrimitive", "Null Bound to
Primitive Demo", "Correct exception when a primitive parameter is bound to
null"),
+
+ new Item("TreeDemo", "Tree Component Demo", "Demo of Tree
Component"),
+
+ new Item("TreeSelectionDemo", "Tree Component Selection
Demo", "Demo of Selection with Tree Component"),
+
+ new Item("TreeNoRootsDemo", "Tree Component No Roots
Demo", "Demo of No Roots with Tree Component"),
+
+ new Item("InvalidExpressionInDynamicTemplate", "Invalid
Dynamic Expression",
+ "Invalid expression in a Dynamic Template"),
+
+ new Item("DynamicDemo", "Dynamic Demo", "Basic Dynamic
component tests"),
+
+ new Item("DynamicExpansionsDemo", "Expansions in Dynamic
Templates",
+ "Expansions inside Dynamic component content and
attributes"),
+
+ new Item("PACAnnotationDemo", "PageActivationContext Demo",
+ "Shows that @PageActivationContext fields are set
before calls to the activate event handler."),
+
+ new Item("PACMultipleAnnotationDemo",
"PageActivationContext Multiple Demo",
+ "Demonstrates multiple @PageActivationContext
fields."),
+
+ new Item("PublicFieldAccessDemo", "Public Field Access
Demo", "Demonstrates TAP5-1222 fix"),
+
+ new Item("ActivationRequestParameterDemo",
"ActivationRequestParameter Annotation Demo",
+ "Use of @ActivationRequestParameter to encode page
state into query parameters"),
+
+ new Item("LibraryMessagesDemo", "Library Messages Demo",
+ "Demo ability to contribute additional message
catalog resources to the application global catalog."),
+
+ new Item("MultiZoneUpdateInsideForm", "MultiZone Update
inside a Form",
+ "Update multiple zones within a single Form."),
+
+ new Item("ZoneFormUpdateDemo", "Zone/Form Update Demo",
"Updating a Zone inside a Form"),
+
+ new Item("MultiZoneStringBodyDemo", "MultiZone String Body
Demo",
+ "Multi-zone updates in a loop using strings
coerced into blocks"),
+
+ new Item("RenderNotificationDemo", "RenderNotification
Demo", "Use of RenderNotification mixin"),
+
+ new Item("InjectMessagesDemo", "Inject Global Messages
into Service Demo",
+ "Ensure that it is possible to inject the
application global message catalog into a service"),
+
+ new Item("ReloadDemo", "Reloadable Service Implementation
Demo",
+ "Used when manually testing service reloads"),
+
+ new Item("RequestParameterDemo", "RequestParameter
Annotation Demo",
+ "Use of @RequestParameter annotation on event
handler method parameters"),
+
+ new Item("CancelDemo", "Cancel Demo", "Use of the cancel
option with Submit"),
+
+ new Item("CanceledEventDemo", "Canceled Event Demo",
"Triggering of the canceled event from a form."),
+
+ new Item("PageResetDemo", "PageReset Annotation Demo",
+ "Use of PageReset annotation to re-initialize page
state"),
+
+ new Item("TestOnlyServiceDemo", "Test Only Service Demo",
+ "IoC module available via web.xml configuration"),
+
+ new Item("RenderObjectExceptionDemo", "RenderObject
Exception Demo",
+ "Demonstrate how exceptions when rendering default
objects are displayed."),
+
+ new Item("MultiLevelInheritDemo", "Multi-Level Inherit
Demo",
+ "Use of inherit: binding prefix across three
levels"),
+
+ new Item("HiddenDemo", "Hidden Demo", "Demo the use of the
Hidden component."),
+
+ new Item("FormZoneDemo", "Form Zone Demo", "Use a form to
update a zone."),
+
+ new Item("ZoneUpdateNamespace", "Zone/Namespace
Interaction", "Prove that TAP5-573 is fixed"),
+
+ new Item("AbstractComponentDemo", "Abstract Component
Demo", "Error when a component is abstract"),
+
+ new Item("TemplateOverrideDemo", "Template Override Demo",
+ "Child component extends and overrides parent
template."),
+
+ new Item("MultiZoneUpdateDemo", "Multiple Zone Update
Demo",
+ "A single request can now update multiple Zones"),
+
+ new Item("LinkSubmitInZoneDemo", "LinkSubmit inside Zone",
+ "Ensure that a LinkSubmit works correctly when its
containing Form updates a Zone"),
+
+ new Item("ProgressiveDemo", "ProgressiveDisplay Demo",
"Progressive Enhancement via a component"),
+
+ new Item("ClientNumericValidationDemo", "Client-Side
Numeric Validation",
+ "Client-side locale-specific validation"),
+
+ new Item("PublishParametersDemo", "Publish Parameters
Demo",
+ "Use of @Component.publishParameters attribute."),
+
+ new Item("LinkSubmitDemo", "LinkSubmit Demo", "JavaScript
LinkSubmit component"),
+
+ new Item("LinkSubmitWithoutValidatorDemo", "LinkSubmit
Without Validator Demo",
+ "Demonstrates that the LinkSubmit component is
working without a validator on any of fields in the form"),
+
+ new Item("PerFormValidationMessageDemo", "Per-Form
Validation Messages",
+ "Per-form configuration of validation messages and
constraints."),
+
+ new Item("EmptyLoopDemo", "Empty Loop Demo", "Use of empty
parameter with the Loop component."),
+
+ new Item("GenericLoopDemo", "Generic Loop Demo",
+ "Use of generic parameters with the Loop
component."),
+
+ new Item("LoopWithMixinDemo", "Loop With Mixin Demo",
+ "Use a mixin with a Loop component."),
+
+ new Item("BlankPasswordDemo", "Blank Password Demo",
+ "Show that a blank value in a PasswordField does
not update the server side value."),
+
+ new Item("GridFormEncoderDemo", "Grid Form Encoder Demo",
+ "Grid inside a Form using the ValueEncoder
option"),
+
+ new Item("GridFormWithInitialSortMixinDemo", "Grid Form
With Initial Sort Mixin Demo",
+ "Grid inside a Form using the InitialSort mixin"),
+
+ new Item("DateFieldAjaxFormLoop", "DateField inside
AjaxFormLoop",
+ "Show that DateField component works correctly
inside AjaxFormLoop"),
+
+ new Item("NestedForm", "Nested Form Demo", "Error when a
Form is nested inside another Form."),
+
+ new Item("UnhandledEventDemo", "Unhandled Event Demo",
+ "Events that don't have matching event handlers
cause exceptions"),
+
+ new Item("PrimitiveDefaultDemo", "Primitive Default Demo",
+ "Primitive value returned from parameter default
method"),
+
+ new Item("ValidateFormValidationExceptionDemo",
"ValidationForm ValidationException Demo",
+ "Throwing a ValidationException from the
validateForm event handler."),
+
+ new Item("ClientFormatDemo", "Client Format Validation",
"Client-side input format validation"),
+
+ new Item("ShortGrid", "Short Grid",
+ "Grid where the number of claimed rows is less
than the number of actual rows"),
+
+ new Item("NullParameterDemo", "Null Parameter Demo",
"Binding a not-null parameter to null."),
+
+ new Item("nestedbeaneditor", "Nested BeanEditor",
+ "BeanEditor as override for property editor in
BeanEditForm"),
+
+ new Item("actionpage", "Action Page", "tests fixture for
ActionLink component"),
+
+ new Item("cleancachedemo", "Clean Cache Demo", "cache
cleared properly during Ajax calls"),
+
+ new Item("numberbeaneditordemo", "Number BeanEditor Demo",
+ "use of nulls and wrapper types with BeanEditor"),
+
+ new Item("forminjectordemo", "FormInjector Demo",
"extending a form dynamically via Ajax"),
+
+ new Item("music", "Music Page", "demo handling of edge
cases of page naming"),
+
+ new Item("PersistentDemo", "Persistent Demo", "storing and
clearing persistent properties"),
+
+ new Item("ActionViaLinkDemo", "Action via Link Demo",
"tests creating an action link explicitly"),
+
+ new Item("FormFragmentDemo", "Form Fragment Demo", "page
with dynamic form sections"),
+
+ new Item("BooleanDemo", "Boolean Property Demo",
+ "demo boolean properties using both is and get
prefixes"),
+
+ new Item("DeleteFromGridDemo", "Delete From Grid", "demo
deleting items form a Grid"),
+
+ new Item("RenderErrorDemo", "Render Error Demo",
"reporting of errors while rendering"),
+
+ new Item("nested/AssetDemo", "AssetDemo", "declaring an
image using Assets"),
+
+ new Item("nested/ActionDemo", "Action With Context Demo",
+ "using action links with context on page with
activation context"),
+
+ new Item("blockdemo", "BlockDemo", "use of blocks to
control rendering"),
+
+ new Item("countdown", "Countdown Page", "defining
component using @Component annotation"),
+
+ new Item("injectdemo", "Inject Demo", "use of various
kinds of injection"),
+
+ new Item("instancemixin", "InstanceMixin", "mixin added to
a particular component instance"),
+
+ new Item("TextFieldWrapperTypeDemo", "TextField Wrapper
Types",
+ "use of TextField to edit numeric wrapper types
(not primitives) "),
+
+ new Item("EnvironmentalDemo", "Environmental Annotation
Usage",
+ "Storing and retrieving Environmental values"),
+
+ new Item("Expansion", "Expansion Page", "Use of expansions
in templates"),
+
+ new Item("ExpansionSubclass", "ExpansionSubclass",
+ "components can inherit templates from base
classes"),
+
+ new Item("Localization", "Localization", "access localized
messages from the component catalog"),
+
+ new Item("NumberSelect", "NumberSelect",
"passivate/activate page context demo"),
+
+ new Item("ParameterConflict", "Template Overridden by
Class Page",
+ "Parameters in the class override those in the
template"),
+
+ new Item("ParameterDefault", "ParameterDefault",
"defaulter methods for component parameters"),
+
+ new Item("passwordfielddemo", "PasswordFieldDemo", "test
for the PasswordField component"),
+
+ new Item("rendercomponentdemo", "RenderComponentDemo",
+ "components that \"nominate\" other components to
render"),
+
+ new Item("renderphaseorder", "RenderPhaseOrder",
+ "order of operations when invoking render phase
methods"),
+
+ new Item("simpleform", "SimpleForm", "first pass at
writing Form and TextField components"),
+
+ new Item("OptionGroupForm", "OptionGroupForm Demo",
"Select with Option Group"),
+
+ new Item("validform", "ValidForm", "server-side input
validation"),
+
+ new Item("ToDoListVolatile", "ToDo List (Volatile)",
"Loops and Submit inside Form, volatile mode"),
+
+ new Item("MissingTemplate", "Missing Template Demo",
+ "Demo for what happens when a template is not
found for a page"),
+
+ new Item("nested/zonedemo", "Zone Demo", "dynamic updates
within a page"),
+
+ new Item("todolist", "ToDo List", "Loops and Submit inside
Form using primary key encoder"),
+
+ new Item("flashdemo", "FlashDemo", "demonstrate 'flash'
persistence"),
+
+ new Item("beaneditordemo", "BeanEditor Demo", "demonstrate
the BeanEditor mega-component"),
+
+ new Item("pageloadeddemo", "PageLoaded Demo", "shows that
page lifecycle methods are invoked"),
+
+ new Item("griddemo", "Grid Demo", "default Grid
component"),
+
+ new Item("GridInLoopDemo", "Grid In Loop Demo", "Grid
inside loop with different model on each iteration"),
+
+ new Item("nullgrid", "Null Grid", "handling of null source
for Grid"),
+
+ new Item("gridsetdemo", "Grid Set Demo", "handling of Set
sources for Grid"),
+
+ new Item("gridenumdemo", "Grid Enum Demo", "handling of
enum types in the Grid"),
+
+ new Item("GridRemoveReorderDemo", "Grid Remove/Reorder
Demo",
+ "handling of remove and reorder parameters"),
+
+ new Item("EmptyGrid", "Empty Grid Demo", "show table for
empty data sources"),
+
+ new Item("GridEarlyPagingDemo", "Grid Early Paging", "set
a Grid's current page before rendering"),
+
+ new Item("protected", "Protected Page",
+ "Demonstrate result of non-void return from a
page's activate method"),
+
+ new Item("Kicker", "Kicker", "demos complex page and
component context in links"),
+
+ new Item("simpletrackgriddemo", "SimpleTrack Grid Demo",
+ "customizing the model for a Grid around an
interface"),
+
+ new Item("pagelinkcontext", "PageLink Context Demo",
+ "passing explicit context in a page render link"),
+
+ new Item("pagecontextinform", "Page Context in Form",
"passivate/activate page context in Form",
+ "betty", "wilma", "context with spaces",
"context/with/slashes"),
+
+ new Item("ValidBeanEditorDemo", "Client Validation Demo",
"BeanEditor with validation enabled"),
+
+ new Item("Unreachable", "Unreachable Page", "page not
reachable due to IgnoredPathsFilter"),
+
+ new Item("renderabledemo", "Renderable Demo",
+ "shows that render phase methods can return a
Renderable"),
+
+ new Item("inheritedbindingsdemo", "Inherited Bindings
Demo",
+ "Tests for components that inherit bindings from
containing components"),
+
+ new Item("ClientPersistenceDemo", "Client Persistence
Demo",
+ "component field values persisted on the client
side"),
+
+ new Item("attributeExpansionsDemo", "Attribute Expansions
Demo",
+ "use expansions inside attributes of ordinary
elements"),
+
+ new Item("PaletteDemo", "Palette Demo", "multiple
selection component"),
+ new Item("PaletteGroupedDemo", "Palette Grouped Demo",
"multiple selection component (grouped)"),
+
+ new Item("ReturnTypes", "Return Types", "tests various
event handler return types"),
+
+ new Item("FormEncodingType", "Form Encoding Type",
+ "Test ability to set an encoding type for a Form"),
+
+ new Item("RadioDemo", "RadioDemo", "Use of the RadioGroup
and Radio components"),
+
+ new Item("RegexpDemo", "Regexp Demo", "Use of the Regexp
validator"),
+
+ new Item("BeanEditRemoveReorder", "BeanEdit
Remove/Reorder",
+ "Use of the remove and reorder parameters with
BeanEditForm"),
+
+ new Item("MultiBeanEditDemo", "MultiBeanEdit Demo",
+ "Multiple BeanEditor components in a single form"),
+
+ new Item("GridFormDemo", "Grid Form Demo", "Grid operating
inside a Form"),
+
+ new Item("DateFieldDemo", "DateField Demo", "using
DateField by itself on a page"),
+
+ new Item("BeanEditDateDemo", "BeanEditor / Date Demo",
+ "Use of date properties inside BeanEditor and
BeanDisplay"),
+
+ new Item("eventmethodtranslate", "EventMethod Translator",
+ "Demo ability to provide toclient and parseclient
event handler methods"),
+
+ new Item("autocompletedemo", "Autocomplete Mixin Demo",
+ "Demo the autocomplete mixin for text fields"),
+
+ new Item("componentparameter", "ComponentParameter Demo",
+ " Demo using a component type as a parameter type
and succesfully passing a component"),
+
+ new Item("inheritinformalsdemo", "Inherit Informal
Parameters Demo",
+ "Demo a component which inherits informal
parameters from its container"),
+
+ new Item("disabledfields", "Disabled Fields",
+ "Demonstrate a bunch of disabled fields, to verify
that the RenderDisabled mixin works and is being used properly"),
+
+ new Item("BeanEditorOverride", "BeanEditor Override",
+ "Property editor overrides work for the BeanEditor
component itself (not just the BeanEditForm component)"),
+
+ new Item("varbindingdemo", "Var Binding Demo", "use of the
var: binding prefix"),
+
+ new Item("leangriddemo", "Lean Grid Demo",
+ "Grid component with lean parameter turned on, to
eliminate CSS class attributes in TD and TH elements"),
+
+ new Item("blockcaller", "Action Links off of Active Page",
+ "Actions can exist on pages other than the active
page, via Blocks."),
+
+ new Item("unlessdemo", "Unless Demo", "use of the Unless
component"),
+
+ new Item("delegateinline", "Inline Delegate",
+ "Using the delegate component to create inline
components"),
+
+ new Item("MagicValueEncoder", "Magic ValueEncoder Demo",
+ "Automatic creation of ValueEncoder using the
TypeCoercer"),
+
+ new Item("NullStrategyDemo", "Null Field Strategy Demo",
"use of the nulls parameter of TextField"),
+
+ new Item("OverrideValidationDecorator", "Override
Validation Decorator",
+ "override the default validation decorator"),
+
+ new Item("ExceptionEventDemo", "Exception Event Demo",
"handling component event exceptions"),
+
+ new Item("AddedGridColumnsDemo", "Added Grid Columns
Demo", "programatically adding grid columns"),
+
+ new Item("PrimitiveArrayParameterDemo", "Primitive Array
Parameter Demo",
+ "use primitive array as parameter type"),
+
+ new Item("RenderPhaseMethodExceptionDemo", "Render Phase
Method Exception Demo",
+ "render phase methods may throw checked
exceptions"),
+
+ new Item("TrackEditor", "Generic Page Class Demo",
+ "demo use of generics with component classes and,
particularily, with property types"),
+
+ new Item("IndirectProtectedFields", "Protected Fields
Demo",
+ "demo exception when component class contains
protected fields"),
+
+ new Item("injectcomponentdemo", "Inject Component Demo",
"inject component defined in template"),
+
+ new Item("cachedpage", "Cached Annotation", "Caching
method return values"),
+
+ new Item("cachedpage2", "Cached Annotation2", "Caching
method return values w/ inheritence"),
+
+ new Item("inplacegriddemo", "In-Place Grid Demo", "Grid
that updates in-place using Ajax"),
+
+ new Item("methodadvicedemo", "Method Advice Demo",
"Advising component methods."),
+
+ new Item("HasBodyDemo", "Has Body Demo", "Verify the
hasBody() method of ComponentResources"),
+
+ new Item("BeanEditorBeanEditContext", "BeanEditor
BeanEditContext",
+ "BeanEditContext is pushed into enviroment by
BeanEditor."),
+
+ new Item("InformalParametersDemo", "Informal Parameters
Demo",
+ "Access to informal parameters names and values"),
+
+ new Item("FormFieldOutsideForm", "Form Field Outside Form",
+ "Nice exception message for common problem of form
fields outside forms"),
+
+ new Item("SubmitWithContext", "Submit With Context",
"Providing a context for Submit component"),
+
+ new Item("MessageConstraintGeneratorDemo", "Validation
Constraints From Messages",
+ "Providing validators to apply from a properties
file"),
+
+ new Item("RenderClientIdDemo", "RenderClientId Mixin",
+ "Force render of client-side id of a client
element via the RenderClientId mixin"),
+
+ new Item("BindParameterDemo", "BindParameter mixin
annotation",
+ "Accessing component parameter values from a
mixin"),
+
+ new Item("BindParameterNoSuchParameter", "BindParameter
error handling",
+ "BindParameter throws exception if the containing
component doesn't have a matching parameter"),
+
+ new Item("BindParameterOnComponent", "BindParameter on
component",
+ "Verify that BindParameter can only be used on
mixin fields"),
+
+ new Item("MixinOrderingDemo", "Mixin Ordering Demo",
"Various mixin-ordering scenarios"),
+
+ new Item(
+ "MissingComponentClassException",
+ "Missing Component Class Exception",
+ "Meaningful exception message thrown when
component class can't be determined from template or field in containing
component."),
+
+ new Item("SessionAttributeDemo", "SessionAttribute Demo",
+ "Annotation to map a field to a specific session
attribute"),
+
+ new Item("BeanEditCalendarDemo", "BeanEditor / Calendar
Demo",
+ "Use of calendar properties inside BeanEditor and
BeanDisplay"),
+
+ new Item("TriggerDemo", "Trigger Demo", "Use of Trigger
component"),
+
+ new Item("ImageSubmitDemo", "Submit with an Image Demo",
+ "Make sure that submit with the image parameter
set triggers the 'selected' event."),
+
+ new Item("SelectZoneDemo", "Select Zone Demo", "Use a
Select component to update a zone."),
+
+ new Item("AssetProtectionDemo", "Asset Protection Demo",
+ "AssetProtectionDispatcher is properly contributed
and functioning"),
+
+ new Item("BeanDisplayEnumDemo", "BeanDisplay Enum Demo",
+ "User represenation of enum values is correctly
read from messages"),
+
+ new Item("unavailablecomponentdemo", "Report Location of
Unavailable Component",
+ "Report Location of Unavailable Component"),
+
+ new Item("discardafterdemo", "@DiscardAfter Demo", "Demo
using @DiscardAfter annotation"),
+
+ new Item("SelectDemo", "Select Demo", "Validation
decoration for Select"),
+
+ new Item("SelectModelFromObjectsAndPropertyNameDemo",
"SelectModel from objects and property name",
+ "Creating a SelectModel from a list of objects and
a label property name"),
+
+ new Item("SelectModelFromObjectsDemo", "SelectModel from
objects",
+ "Creating a SelectModel from a list of objects"),
+
+ new Item("SelectModelCoercionDemo", "SelectModel coercion",
+ "Creating a SelectModel from a list of objects
using coercion"),
+
+ new Item("DecoratePageRenderLinkDemo", "Decorate Page
Render Link Demo",
+ "Decorating page render links"),
+
+ new Item("DecorateComponentEventLinkDemo", "Decorate
Component Event Link Demo",
+ "Decorating event links"),
+
+ new Item("ValidatorMacroDemo", "Validator Macro Demo",
"Using validator macros"),
+
+ new Item("AtInjectDemo", "@jakarta.inject.Inject Demo",
"Using @jakarta.inject.Inject for injection"),
+
+ new Item("LinkQueryParameters", "Link Query Parameters
Demo",
+ "Providing Query Parameters directly to link
components as a map of key=parameter name, value=parameter values"),
+
+ new Item("ChecklistDemo", "Checklist Demo", "Use Checklist
component"),
+
+ new Item("BeanEditFormPrepareBubbling", "BeanEditor
Prepare Bubbling Demo", "Prepare event bubbling"),
+
+ new Item("NestedFormFragment", "Nested Form Fragment
Demo", "Nesting Form Fragments work properly"),
+
+ new Item("MapExpressionInExpansions", "Map Expressions in
Expansions Demo", "Maps can be used in expansions"),
+
+ new Item("ExpressionInJsFunction", "Expressions in JS
Functions Demo", "Expressions can be used inside javascript functions"),
+
+ new Item("FormFieldFocusDemo", "FormFieldFocus
(DEPRECATED) Demo", "Setting the Form focus on a specific field"),
+
+ new Item("FormFragmentExplicitVisibleBoundsDemo", "Form
Fragment Explicit Visible Bounds Demo", "Check for form fragment parent
visibility can be bounded to"),
+
+ new Item("OverrideFieldFocusDemo", "OverrideFieldFocus
Demo", "Setting the focus in a form to a specific field"),
+
+ new Item("OverrideLabelClassDemo", "Override Label Class
Demo", "Setting class attribute on Label component"),
+
+ new Item("FormLinkParameters", "FormLinkParameters Demo",
"Form link parameters should be unescaped for a hidden field"),
+
+ new Item("KnownActivationContextDemo", "Known Activation
Context Demo", "Page is displayed normally if called without context
(TAP5-2070)",
+ "Exact"),
+
+ new Item("UnknownActivationContextDemo", "Unknown
Activation Context Demo", "Page refuse to serve if called with an unknown
activation context (TAP5-2070)",
+ "Unwanted", "context"),
+
+ new Item("ModuleConfigurationCallbackDemo",
"ModuleConfigurationCallback Demo", "Shows an example of changing the
Require.js configuration using JavaScriptSupport.addModuleConfigurationDemo()"),
+
+ new Item("PartialTemplateRendererDemo",
"PartialTemplateRenderer Demo", "Shows some examples of rendering blocks and
components to a String using PartialTemplateRenderer"),
+
+ new Item("nested/PageThatThrowsException", "Reload on
nested page", "Tests a page reload from a nested page's exception report"),
+
+ new Item("inplacegridinloopdemo", "In-Place Grid in a Loop
Demo", "In-place grid in a loop"),
+
+ new Item("GenericTypeDemo", "Generic bound type demo",
"Tests that generic type info is available for generic bindings"),
+
+ new Item("FormFieldClientIdParameterDemo", "Form Field
clientId Parameter Demo", "Shows and tests how to explicitly set the id of a
form field component"),
+
+ new Item("gridwithsubmitwithcontextdemo", "Grid with
Submit with context", "A grid whose rows contain a Submit component with
context"),
+
+ new Item("textfieldwithnullvalidateparameter", "TextField
with null validate parameter", "A TextField whose validate parameter is bound
to null"),
+
+ new Item("validateCheckboxMustBeChecked", "Validate
Checkbox Must Be Checked", "A form that trigger validate in " +
+ "error event on submit when checkbox is not
checked"),
+
+ new Item("validateCheckboxMustBeUnchecked", "Validate
Checkbox Must Be Unchecked", "A form that trigger validate in " +
+ "error event on submit when checkbox is
checked"),
+
+ new Item("validateInErrorEvent", "Validate in error
Event", "A form that trigger validate in " +
+ "error event on submit when textfield is empty"),
+
+ new Item("onactivateredirect", "OnActivateRedirect Demo",
"A page that redirects to itself from"
+ + " its activation method"),
+
+ new Item("BeanEditorWithFormFragmentDemo", "Bean Editor
With Form Fragment Demo", "TriggerFragment mixin used inside a BeanEditor"),
+
+ new Item("ObjectEditorDemo","Object Editor Demo","Edit
Bean with address objects"),
+
+ new Item("IfDemo","If Demo","If component with all its
options"),
+
+ new Item("RecursiveDemo","Recursive Demo","Recursive
component example"),
+
+ new Item("SelfRecursiveDemo", "Self-Recursive Demo",
"check for handling of self-recursive components"),
+
+ new Item("EsModuleDemo", "ES Module Demo", "tests and
demonstrations for the ES module support")
);
static
diff --git
a/tapestry-core/src/test/resources/META-INF/assets/es-modules/app/test-support.js
b/tapestry-core/src/test/resources/META-INF/assets/es-modules/app/test-support.js
new file mode 100644
index 000000000..7728ef0c1
--- /dev/null
+++
b/tapestry-core/src/test/resources/META-INF/assets/es-modules/app/test-support.js
@@ -0,0 +1,14 @@
+// Provide test support functions that can be addressed via Selenium.
+
+// TODO: Maybe move this to main, for external re-use?
+
+import dom from "t5/core/dom";
+
+const exports = {
+ findCSSMatchCount(selector) { return dom.body.find(selector).length; },
+ doesNotExist(elementId) { return (dom(elementId)) === null; }
+};
+
+window.testSupport = exports;
+
+export default exports;