TAP5-2238: When require-ing a module that is part of a JavaScript Stack, the entire stack should be imported
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/ee695314 Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/ee695314 Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/ee695314 Branch: refs/heads/master Commit: ee695314fab6794edeeda80bbc9875b6114cfc2a Parents: e514e7f Author: Howard M. Lewis Ship <[email protected]> Authored: Wed Nov 27 13:25:13 2013 -0800 Committer: Howard M. Lewis Ship <[email protected]> Committed: Wed Nov 27 13:25:13 2013 -0800 ---------------------------------------------------------------------- .../services/ajax/JavaScriptSupportImpl.java | 56 ++++++++++++------ .../services/javascript/JavaScriptSupport.java | 14 +++-- .../ajax/JavaScriptSupportAutofocusTests.groovy | 2 + .../ajax/JavaScriptSupportImplTest.groovy | 62 +++++++++++++++++++- 4 files changed, 112 insertions(+), 22 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ee695314/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImpl.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImpl.java index bcce095..eb8defb 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 @@ -14,13 +14,6 @@ package org.apache.tapestry5.internal.services.ajax; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.Set; - import org.apache.tapestry5.Asset; import org.apache.tapestry5.ComponentResources; import org.apache.tapestry5.FieldFocusPriority; @@ -34,13 +27,9 @@ 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.Initialization; -import org.apache.tapestry5.services.javascript.InitializationPriority; -import org.apache.tapestry5.services.javascript.JavaScriptStack; -import org.apache.tapestry5.services.javascript.JavaScriptStackSource; -import org.apache.tapestry5.services.javascript.JavaScriptSupport; -import org.apache.tapestry5.services.javascript.ModuleConfigurationCallback; -import org.apache.tapestry5.services.javascript.StylesheetLink; +import org.apache.tapestry5.services.javascript.*; + +import java.util.*; public class JavaScriptSupportImpl implements JavaScriptSupport { @@ -70,7 +59,7 @@ public class JavaScriptSupportImpl implements JavaScriptSupport private String focusFieldId; - private Map<String, String> libraryURLToStackName; + private Map<String, String> libraryURLToStackName, moduleNameToStackName; class InitializationImpl implements Initialization { @@ -246,7 +235,7 @@ public class JavaScriptSupportImpl implements JavaScriptSupport { addScript(InitializationPriority.NORMAL, format, arguments); } - + public void addModuleConfigurationCallback(ModuleConfigurationCallback callback) { linker.addModuleConfigurationCallback(callback); @@ -301,6 +290,7 @@ public class JavaScriptSupportImpl implements JavaScriptSupport return getLibraryURLToStackName().get(libraryURL); } + private Map<String, String> getLibraryURLToStackName() { if (libraryURLToStackName == null) @@ -319,6 +309,31 @@ public class JavaScriptSupportImpl implements JavaScriptSupport return libraryURLToStackName; } + private String findStackForModule(String moduleName) + { + return getModuleNameToStackName().get(moduleName); + } + + private Map<String, String> getModuleNameToStackName() + { + + if (moduleNameToStackName == null) + { + moduleNameToStackName = CollectionFactory.newMap(); + + for (String stackName : javascriptStackSource.getStackNames()) + { + for (String moduleName : javascriptStackSource.getStack(stackName).getModules()) + { + moduleNameToStackName.put(moduleName, stackName); + } + } + } + + return moduleNameToStackName; + } + + private void addAssetsFromStack(String stackName) { if (addedStacks.containsKey(stackName)) @@ -333,7 +348,7 @@ public class JavaScriptSupportImpl implements JavaScriptSupport // end, avoiding the TAP5-2197 bug. final List<String> reversedStacks = new ArrayList<String>(stack.getStacks()); Collections.reverse(reversedStacks); - + for (String dependentStackname : reversedStacks) { addAssetsFromStack(dependentStackname); @@ -423,6 +438,13 @@ public class JavaScriptSupportImpl implements JavaScriptSupport addAssetsFromStack(InternalConstants.CORE_STACK_NAME); + String stackName = findStackForModule(moduleName); + + if (stackName != null) + { + importStack(stackName); + } + InitializationImpl init = new InitializationImpl(moduleName); inits.add(init); http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ee695314/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java index 1b24e1b..caff985 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java @@ -1,4 +1,4 @@ -// Copyright 2010, 2011, 2012 The Apache Software Foundation +// Copyright 2010-2013 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -250,6 +250,11 @@ public interface JavaScriptSupport * In some cases, a module exports no functions, but performs some initialization (typically, adding document-level * event handlers), in which case a call to require() is sufficient. In cases where the module, or a function * within the module, are invoked with no parameters, the calls will be collapsed into a single invocation. + * <p/> + * If the module is part of a {@linkplain org.apache.tapestry5.services.javascript.JavaScriptStack#getModules() JavaScript stack}, + * then the stack will be imported; this is important when {@linkplain SymbolConstants#COMBINE_SCRIPTS JavaScript aggregation is enabled}, + * but also ensures that libraries in the stack are loaded before the module (for cases where the + * module has dependencies on libraries not wrapped as AMD modules). * * @param moduleName * the name of the module to require @@ -257,11 +262,12 @@ public interface JavaScriptSupport * @since 5.4 */ Initialization require(String moduleName); - + /** * Adds a module configuration callback for this request. - * - * @param callback a {@link ModuleConfigurationCallback}. It cannot be null. + * + * @param callback + * a {@link ModuleConfigurationCallback}. It cannot be null. * @see DocumentLinker#addModuleConfigurationCallback(ModuleConfigurationCallback) * @since 5.4 */ http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ee695314/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportAutofocusTests.groovy ---------------------------------------------------------------------- diff --git a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportAutofocusTests.groovy b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportAutofocusTests.groovy index ba023f8..afd7279 100644 --- a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportAutofocusTests.groovy +++ b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportAutofocusTests.groovy @@ -34,6 +34,8 @@ class JavaScriptSupportAutofocusTests extends InternalBaseTestCase { def stackSource = newMock(JavaScriptStackSource.class) def stackPathConstructor = newMock(JavaScriptStackPathConstructor.class) + expect(stackSource.stackNames).andReturn([]) + linker.addInitialization(InitializationPriority.NORMAL, "t5/core/pageinit", "focus", JSONArray.from([expectedFieldId])) http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ee695314/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImplTest.groovy ---------------------------------------------------------------------- diff --git a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImplTest.groovy b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImplTest.groovy index 2b8abd1..b8947d4 100644 --- a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImplTest.groovy +++ b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportImplTest.groovy @@ -40,13 +40,16 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase { @Test void partial_mode_add_script() { DocumentLinker linker = mockDocumentLinker() + def stackSource = mockJavaScriptStackSource() + + train_for_just_core_stack stackSource linker.addInitialization(InitializationPriority.NORMAL, "t5/core/pageinit", "evalJavaScript", new JSONArray().put("doSomething();")) replay() - JavaScriptSupportImpl jss = new JavaScriptSupportImpl(linker, null, null, new IdAllocator(), true) + JavaScriptSupportImpl jss = new JavaScriptSupportImpl(linker, stackSource, null, new IdAllocator(), true) jss.addScript("doSomething();") @@ -158,6 +161,44 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase { verify() } + @Test + void requireing_a_module_may_import_a_stack() { + DocumentLinker linker = mockDocumentLinker() + JavaScriptStackSource stackSource = mockJavaScriptStackSource() + JavaScriptStackPathConstructor pathConstructor = mockJavaScriptStackPathConstructor() + + JavaScriptStack mystack = mockJavaScriptStack() + + expect(stackSource.stackNames).andReturn(["mystack"]) + expect(stackSource.getStack("mystack")).andReturn(mystack).atLeastOnce() + + expect(mystack.modules).andReturn(["foo/bar"]) + + expect(mystack.stacks).andReturn([]) + + expect(pathConstructor.constructPathsForJavaScriptStack("mystack")).andReturn(["stacks/mystack.js"]) + + expect(mystack.stylesheets).andReturn([]) + + expect(mystack.initialization).andReturn null + + linker.addLibrary("stacks/mystack.js") + + linker.addInitialization(InitializationPriority.NORMAL, "foo/bar", null, null) + + replay() + + JavaScriptSupportImpl jss = new JavaScriptSupportImpl(linker, stackSource, pathConstructor, null, true) + + jss.require("foo/bar") + + jss.commit() + + verify() + + } + + private void trainForNoStackNames(JavaScriptStackSource stackSource) { // This is slightly odd, as it would normally return "core" at a minimum, but we test for that separately. @@ -288,6 +329,8 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase { JavaScriptStackSource stackSource = mockJavaScriptStackSource() JavaScriptStackPathConstructor pathConstructor = mockJavaScriptStackPathConstructor() + train_for_just_core_stack stackSource + train_init(linker, InitializationPriority.IMMEDIATE, "setup", "chuck") train_init(linker, InitializationPriority.IMMEDIATE, "setup", "charley") @@ -312,6 +355,8 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase { JSONArray chuck = new JSONArray("chuck", "yeager") JSONArray buzz = new JSONArray("buzz", "aldrin") + train_for_just_core_stack stackSource + train_init(linker, InitializationPriority.IMMEDIATE, "setup", chuck) train_init(linker, InitializationPriority.IMMEDIATE, "setup", buzz) @@ -341,6 +386,8 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase { JavaScriptStackSource stackSource = mockJavaScriptStackSource() JavaScriptStackPathConstructor pathConstructor = mockJavaScriptStackPathConstructor() + train_for_just_core_stack stackSource + train_init(linker, InitializationPriority.NORMAL, "setup", "chuck") replay() @@ -354,6 +401,17 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase { verify() } + def train_for_just_core_stack(stackSource) { + def coreStack = mockJavaScriptStack() + + expect(stackSource.stackNames).andReturn(["core"]) + + expect(stackSource.getStack("core")).andReturn(coreStack) + + expect(coreStack.modules).andReturn([]) + } + + @Test void default_for_init_array_is_normal_priority() { DocumentLinker linker = mockDocumentLinker() @@ -362,6 +420,8 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase { JSONArray chuck = new JSONArray("chuck", "yeager") + train_for_just_core_stack stackSource + train_init(linker, InitializationPriority.NORMAL, "setup", chuck) replay()
