Introduce a distinction between the core stack and all other stacks (and JavaScript) - allows more stacks/libraries to continue working under 5.4 without change
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/bbeca8f5 Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/bbeca8f5 Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/bbeca8f5 Branch: refs/heads/5.4-js-rewrite Commit: bbeca8f53e8ee4a8ba33d4c90622b659b87f209c Parents: 300494b Author: Howard M. Lewis Ship <hls...@apache.org> Authored: Mon Aug 20 10:51:01 2012 -0700 Committer: Howard M. Lewis Ship <hls...@apache.org> Committed: Mon Aug 20 10:51:01 2012 -0700 ---------------------------------------------------------------------- .../META-INF/modules/core/pageinit.coffee | 20 +++++--- .../internal/services/DocumentLinker.java | 24 ++++++++- .../internal/services/DocumentLinkerImpl.java | 13 +++++- .../services/PartialMarkupDocumentLinker.java | 7 +++ .../services/ajax/JavaScriptSupportImpl.java | 37 ++++++++------ .../services/javascript/ModuleManagerImpl.java | 3 +- .../services/javascript/ModuleManager.java | 11 +++-- .../resources/org/apache/tapestry5/core.properties | 2 +- .../resources/org/apache/tapestry5/t5-forceload.js | 9 ++-- .../services/DocumentLinkerImplTest.groovy | 20 ++++---- .../services/ajax/JavaScriptSupportImplTest.groovy | 5 +- 11 files changed, 102 insertions(+), 49 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bbeca8f5/tapestry-core/src/main/coffeescript/META-INF/modules/core/pageinit.coffee ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/coffeescript/META-INF/modules/core/pageinit.coffee b/tapestry-core/src/main/coffeescript/META-INF/modules/core/pageinit.coffee index bf1850b..4032d39 100644 --- a/tapestry-core/src/main/coffeescript/META-INF/modules/core/pageinit.coffee +++ b/tapestry-core/src/main/coffeescript/META-INF/modules/core/pageinit.coffee @@ -134,13 +134,19 @@ define ["_", "core/console", "core/spi", "core/events"], finalCallback.call null - # Loads all the libraries, in order. It then executes the immediate initializations. - # After that, it waits for the DOM to be ready and executes the other initializations. - loadLibrariesAndInitialize: (libraries, immediateInits, otherInits) -> - exports.loadLibraries libraries, -> - exports.initialize immediateInits - - spi.domReady -> exports.initialize otherInits + # Loads all the core libraries (the core JavaScript Stack), in order.It then ensures that some key modules have + # initialized, and loads all other libraries in order (this includes other stacks beyond core, and free-standing + # libraries). It then executes the immediate initializations. After that, it waits for the DOM to be ready and + # executes the other initializations. A lot of the complexity here is for compatibility with Tapestry 5.3 and + # earlier, where dependencies were exclusively defined in terms of load order (and there were lots of globals). + loadLibrariesAndInitialize: (coreLibraries, libraries, immediateInits, otherInits) -> + exports.loadLibraries coreLibraries, -> + require ["core/compat/t5-forceload"], -> + console.debug "Core libraries loaded." + exports.loadLibraries libraries, -> + exports.initialize immediateInits + + spi.domReady -> exports.initialize otherInits evalJavaScript: (js) -> require ["core/compat/tapestry"], -> http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bbeca8f5/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java index 34eafd3..eafddd6 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java @@ -1,4 +1,4 @@ -// Copyright 2007, 2008, 2010 The Apache Software Foundation +// Copyright 2007, 2008, 2010, 2012 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -21,12 +21,30 @@ import org.apache.tapestry5.services.javascript.StylesheetLink; /** * Responsible for injecting script and style links into the <head> and <body> element of the rendered HTML * document. + * + * @see org.apache.tapestry5.services.javascript.ModuleManager#writeInitialization(org.apache.tapestry5.dom.Element, java.util.List, java.util.List, java.util.List, java.util.List) + * @since 5.4 */ public interface DocumentLinker { /** - * Adds a link to load a JavaScript library. . The <script> elements will be added inside - * the document's <head>. + * Special handling for the + * {@linkplain org.apache.tapestry5.internal.services.javascript.CoreJavaScriptStack }core JavaScriptStack}, + * whose contents are loaded directly at page startup. This represents special treatment of the core JavaScriptStack, + * starting in release 5.4. It is necessary during the transition from JavaScript libraries (that make use of the + * client-side Tapestry and/or T5 globals) to modules. + * + * + * @param libraryURL + * @since 5.4 + */ + void addCoreLibrary(String libraryURL); + + /** + * Adds a link to load a non-core JavaScript library. These libraries are loaded, sequentially, only once + * the core libraries have loaded and initialized. Thus difference between core libraries and other libraries + * is new in 5.4, and represents a conflict between asynchronous loading of modules (introduced in 5.4) and + * sequential loading of libraries (in 5.3 and earlier). */ void addLibrary(String libraryURL); http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bbeca8f5/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java index 80235f3..4301b86 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 @@ -26,6 +26,8 @@ import java.util.List; public class DocumentLinkerImpl implements DocumentLinker { + private final List<String> coreLibraryURLs = CollectionFactory.newList(); + private final List<String> libraryURLs = CollectionFactory.newList(); private final ModuleInitsManager initsManager = new ModuleInitsManager(); @@ -62,6 +64,15 @@ public class DocumentLinkerImpl implements DocumentLinker includedStylesheets.add(sheet); } + + @Override + public void addCoreLibrary(String libraryURL) + { + coreLibraryURLs.add(libraryURL); + + hasScriptsOrInitializations = true; + } + public void addLibrary(String libraryURL) { libraryURLs.add(libraryURL); @@ -188,7 +199,7 @@ public class DocumentLinkerImpl implements DocumentLinker // (in <head> or at bottom of <body>). Switching to a module approach gives us a new chance to fix this. // Eventually, (nearly) everything will be loaded as modules. - moduleManager.writeInitialization(body, libraryURLs, + moduleManager.writeInitialization(body, coreLibraryURLs, libraryURLs, initsManager.forPriority(InitializationPriority.IMMEDIATE), initsManager.forPriority(InitializationPriority.EARLY, InitializationPriority.NORMAL, InitializationPriority.LATE)); } http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bbeca8f5/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java index fe64a04..a802339 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java @@ -28,6 +28,13 @@ public class PartialMarkupDocumentLinker implements DocumentLinker private final ModuleInitsManager initsManager = new ModuleInitsManager(); + @Override + public void addCoreLibrary(String libraryURL) + { + // Really, this will never happen. + throw new IllegalStateException("Core libraries may not be added during a partial page render."); + } + public void addLibrary(String libraryURL) { libraryURLs.put(libraryURL); http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bbeca8f5/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 c9c26ba..be9adee 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 @@ -44,9 +44,7 @@ public class JavaScriptSupportImpl implements JavaScriptSupport private final Map<String, Boolean> addedStacks = CollectionFactory.newCaseInsensitiveMap(); - private final List<String> stackLibraries = CollectionFactory.newList(); - - private final List<String> otherLibraries = CollectionFactory.newList(); + private final Set<String> otherLibraries = CollectionFactory.newSet(); private final Set<String> importedStylesheetURLs = CollectionFactory.newSet(); @@ -64,6 +62,8 @@ public class JavaScriptSupportImpl implements JavaScriptSupport private String focusFieldId; + private Map<String, String> libraryURLToStackName; + class InitializationImpl implements Initialization { InitializationPriority priority = InitializationPriority.NORMAL; @@ -163,17 +163,6 @@ public class JavaScriptSupportImpl implements JavaScriptSupport } }); - Worker<String> linkLibrary = new Worker<String>() - { - public void work(String value) - { - linker.addLibrary(value); - } - }; - - F.flow(stackLibraries).each(linkLibrary); - F.flow(otherLibraries).each(linkLibrary); - F.flow(inits).sort(new Comparator<InitializationImpl>() { @Override @@ -283,13 +272,14 @@ public class JavaScriptSupportImpl implements JavaScriptSupport if (!otherLibraries.contains(libraryURL)) { + linker.addLibrary(libraryURL); + otherLibraries.add(libraryURL); } return this; } - private Map<String, String> libraryURLToStackName; /** * Locates the name of the stack that includes the library URL. Returns the stack, @@ -326,7 +316,9 @@ public class JavaScriptSupportImpl implements JavaScriptSupport private void addAssetsFromStack(String stackName) { if (addedStacks.containsKey(stackName)) + { return; + } JavaScriptStack stack = javascriptStackSource.getStack(stackName); @@ -335,7 +327,18 @@ public class JavaScriptSupportImpl implements JavaScriptSupport addAssetsFromStack(dependentStackname); } - stackLibraries.addAll(stackPathConstructor.constructPathsForJavaScriptStack(stackName)); + List<String> libraryURLs = stackPathConstructor.constructPathsForJavaScriptStack(stackName); + + for (String libraryURL : libraryURLs) + { + if (stackName.equals(InternalConstants.CORE_STACK_NAME)) + { + linker.addCoreLibrary(libraryURL); + } else + { + linker.addLibrary(libraryURL); + } + } stylesheetLinks.addAll(stack.getStylesheets()); @@ -344,7 +347,9 @@ public class JavaScriptSupportImpl implements JavaScriptSupport String initialization = stack.getInitialization(); if (initialization != null) + { addScript(InitializationPriority.IMMEDIATE, initialization); + } } public JavaScriptSupport importStylesheet(Asset stylesheet) http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bbeca8f5/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/ModuleManagerImpl.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/ModuleManagerImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/ModuleManagerImpl.java index 3509f79..cfa2927 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/ModuleManagerImpl.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/ModuleManagerImpl.java @@ -139,7 +139,7 @@ public class ModuleManagerImpl implements ModuleManager tracker.clearOnInvalidation(cache); } - public void writeInitialization(Element body, List<String> libraryURLs, List<JSONArray> immediateInits, List<JSONArray> deferredInits) + public void writeInitialization(Element body, List<String> coreLibraryURLs, List<String> libraryURLs, List<JSONArray> immediateInits, List<JSONArray> deferredInits) { body.element("script", "src", requireJS.toClientURL()); @@ -150,6 +150,7 @@ public class ModuleManagerImpl implements ModuleManager StringBuilder content = new StringBuilder(1000); content.append(globalMessages.format("core-page-initialization-template", + convert(coreLibraryURLs), convert(libraryURLs), convert(immediateInits), convert(deferredInits))); http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bbeca8f5/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ModuleManager.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ModuleManager.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ModuleManager.java index a4dde1d..4913175 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ModuleManager.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ModuleManager.java @@ -42,14 +42,17 @@ public interface ModuleManager * * @param body * {@code <body>} element of the page, to which new {@code <script>>} element(s) will be added. - * @param libraryURLs + * @param coreLibraryURLs * list of static JavaScript library URLs that must be loaded on the page, prior to any initializations + * @param libraryURLs + * list of additional static JavaScript library URLs that must be loaded on the page, after the + * coreLibraryURLs, and before an initializations * @param immediateInits - * list of immediate initializations that occur as soon as the static JavaScript libraries are loaded + * list of immediate initializations that occur as soon as the static JavaScript libraries are loaded * @param deferredInits - * List of deferred initializations that occur once the page has loaded + * list of initializations that are deferred until after the browser document is ready * */ - void writeInitialization(Element body, List<String> libraryURLs, List<JSONArray> immediateInits, List<JSONArray> deferredInits); + void writeInitialization(Element body, List<String> coreLibraryURLs, List<String> libraryURLs, List<JSONArray> immediateInits, List<JSONArray> deferredInits); /** * Given a module name (which may be a path of names separated by slashes), locates the corresponding {@link Resource}. http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bbeca8f5/tapestry-core/src/main/resources/org/apache/tapestry5/core.properties ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/core.properties b/tapestry-core/src/main/resources/org/apache/tapestry5/core.properties index cdf5d6b..5488e7a 100644 --- a/tapestry-core/src/main/resources/org/apache/tapestry5/core.properties +++ b/tapestry-core/src/main/resources/org/apache/tapestry5/core.properties @@ -49,5 +49,5 @@ required=You must provide a value for %s. core-page-initialization-template=\ require(["core/pageinit"], function(pageinit) {\ - pageinit.loadLibrariesAndInitialize(%s, %s, %s); \ + pageinit.loadLibrariesAndInitialize(%s, %s, %s, %s); \ }); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bbeca8f5/tapestry-core/src/main/resources/org/apache/tapestry5/t5-forceload.js ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/t5-forceload.js b/tapestry-core/src/main/resources/org/apache/tapestry5/t5-forceload.js index 1ff8940..9bec9ee 100644 --- a/tapestry-core/src/main/resources/org/apache/tapestry5/t5-forceload.js +++ b/tapestry-core/src/main/resources/org/apache/tapestry5/t5-forceload.js @@ -19,12 +19,11 @@ * the loading of the other modules before older (and third party) JavaScript code attempts to make use * of methods inside the T5 and Tapestry namespace objects. */ -require([ +define("core/compat/t5-forceload", [ "core/compat/t5-alerts", "core/compat/t5-formfragment", "core/compat/tree", "core/compat/tapestry-messages"], - function () { - // Does nothing, but forces the other define()-ed "modules" to have their dependencies - // loaded, and to be loaded themselves. - }); + // Does nothing, but forces the other define()-ed "modules" to have their dependencies + // loaded, and to be loaded themselves. + null); http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bbeca8f5/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy ---------------------------------------------------------------------- diff --git a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy index f23f1ab..bab9659 100644 --- a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy +++ b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy @@ -93,12 +93,13 @@ class DocumentLinkerImplTest extends InternalBaseTestCase { document.newRootElement("html").element("body").element("p").text("Ready to be updated with scripts.") - def manager = mockModuleManager(["foo.js", "bar/baz.js"], [], [new JSONArray("core/pageinit:evalJavaScript", "pageInitialization();")]) + def manager = mockModuleManager(["core.js"], ["foo.js", "bar/baz.js"], [], [new JSONArray("core/pageinit:evalJavaScript", "pageInitialization();")]) DocumentLinkerImpl linker = new DocumentLinkerImpl(manager, true, "1.2.3") replay() + linker.addCoreLibrary("core.js") linker.addLibrary("foo.js") linker.addLibrary("bar/baz.js") linker.addScript(InitializationPriority.NORMAL, "pageInitialization();") @@ -196,7 +197,7 @@ class DocumentLinkerImplTest extends InternalBaseTestCase { document.newRootElement("html").element("body").element("p").text("Ready to be updated with scripts.") - def manager = mockModuleManager([], [new JSONArray("core/pageinit:evalJavaScript", "doSomething();")], []) + def manager = mockModuleManager([], [], [new JSONArray("core/pageinit:evalJavaScript", "doSomething();")], []) DocumentLinkerImpl linker = new DocumentLinkerImpl(manager, true, "1.2.3") @@ -222,7 +223,7 @@ class DocumentLinkerImplTest extends InternalBaseTestCase { document.newRootElement("html").element("notbody").element("p").text("Ready to be updated with scripts.") - def manager = mockModuleManager(["foo.js"], [], []) + def manager = mockModuleManager([], ["foo.js"], [], []) DocumentLinkerImpl linker = new DocumentLinkerImpl(manager, true, "1.2.3") @@ -249,7 +250,7 @@ class DocumentLinkerImplTest extends InternalBaseTestCase { head.element("meta") head.element("script") - def manager = mockModuleManager([], [new JSONArray("['immediate/module:myfunc', {'fred':'barney'}]")], []) + def manager = mockModuleManager([], [], [new JSONArray("['immediate/module:myfunc', {'fred':'barney'}]")], []) DocumentLinkerImpl linker = new DocumentLinkerImpl(manager, true, "1.2.3") @@ -276,7 +277,7 @@ class DocumentLinkerImplTest extends InternalBaseTestCase { head.element("meta") head.element("script") - def manager = mockModuleManager([], [], [new JSONArray("['my/module', 'barney']")]) + def manager = mockModuleManager([], [], [], [new JSONArray("['my/module', 'barney']")]) DocumentLinkerImpl linker = new DocumentLinkerImpl(manager, true, "1.2.3") @@ -340,7 +341,7 @@ class DocumentLinkerImplTest extends InternalBaseTestCase { head.element("meta") - def manager = mockModuleManager([], [], [new JSONArray("['my/module']"), + def manager = mockModuleManager([], [], [], [new JSONArray("['my/module']"), new JSONArray("my/other/module:normal", 111, 222), new JSONArray("my/other/module:late", 333, 444)]) @@ -369,7 +370,7 @@ class DocumentLinkerImplTest extends InternalBaseTestCase { head.element("meta") - def manager = mockModuleManager([], [], [new JSONArray("['my/module']"), + def manager = mockModuleManager([], [], [], [new JSONArray("['my/module']"), new JSONArray("my/other/module:normal", 111, 222)]) DocumentLinkerImpl linker = new DocumentLinkerImpl(manager, true, "1.2.3") @@ -389,12 +390,13 @@ class DocumentLinkerImplTest extends InternalBaseTestCase { verify() } - private ModuleManager mockModuleManager(scripts, immediateInits, deferredInits) { + private ModuleManager mockModuleManager(def coreLibraryURLs, def libraryURLs, def immediateInits, def deferredInits) { ModuleManager mock = newMock(ModuleManager); expect(mock.writeInitialization(isA(Element), - eq(scripts), + eq(coreLibraryURLs), + eq(libraryURLs), eq(immediateInits), eq(deferredInits))).andAnswer({ def body = EasyMock.currentArguments[0] http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bbeca8f5/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 e1aa596..3740f53 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 @@ -60,6 +60,7 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase { DocumentLinker linker = mockDocumentLinker() JavaScriptStackSource stackSource = mockJavaScriptStackSource() JavaScriptStackPathConstructor pathConstructor = mockJavaScriptStackPathConstructor() + trainForCoreStack(linker, stackSource, pathConstructor) linker.addScript(InitializationPriority.IMMEDIATE, "stackInit();") @@ -107,8 +108,8 @@ class JavaScriptSupportImplTest extends InternalBaseTestCase { expect(stack.stacks).andReturn([]) - linker.addLibrary("stack1.js") - linker.addLibrary("stack2.js") + linker.addCoreLibrary("stack1.js") + linker.addCoreLibrary("stack2.js") linker.addStylesheetLink(stylesheetLink) }