First pass at module-based initialization - traditional requests only - tests coming
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/95dcefc3 Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/95dcefc3 Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/95dcefc3 Branch: refs/heads/5.4-js-rewrite Commit: 95dcefc3d13a1b62e827313cd612a69366693712 Parents: f39aaf1 Author: Howard M. Lewis Ship <[email protected]> Authored: Wed Jun 27 15:13:04 2012 -0700 Committer: Howard M. Lewis Ship <[email protected]> Committed: Wed Jun 27 15:13:04 2012 -0700 ---------------------------------------------------------------------- .../corelib/modulejs/page-initialization.coffee | 11 -- .../tapestry5/corelib/modulejs/pageinit.coffee | 14 +++ .../internal/services/DocumentLinker.java | 30 +++++- .../internal/services/DocumentLinkerImpl.java | 53 ++++++++++- .../services/PartialMarkupDocumentLinker.java | 9 ++- .../services/ajax/JavaScriptSupportImpl.java | 79 +++++++++++++++ .../services/javascript/Initialization.java | 41 ++++++++ .../services/javascript/JavaScriptSupport.java | 11 ++ 8 files changed, 229 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/95dcefc3/tapestry-core/src/main/coffeescript/org/apache/tapestry5/corelib/modulejs/page-initialization.coffee ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/coffeescript/org/apache/tapestry5/corelib/modulejs/page-initialization.coffee b/tapestry-core/src/main/coffeescript/org/apache/tapestry5/corelib/modulejs/page-initialization.coffee deleted file mode 100644 index 21e9f4f..0000000 --- a/tapestry-core/src/main/coffeescript/org/apache/tapestry5/corelib/modulejs/page-initialization.coffee +++ /dev/null @@ -1,11 +0,0 @@ -define -> - - invokeInitializer = (name, argument) -> - require [name], (moduleLib) -> moduleLib(argument) - - # Handles the simple case, where the initializer name is just the name of a module, and - # an argument is always present. Later, we'll support an init that is just a string, - # and names that include a property within the module name. - (inits) -> - invokeInitializer name, argument for [name, argument] in inits - http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/95dcefc3/tapestry-core/src/main/coffeescript/org/apache/tapestry5/corelib/modulejs/pageinit.coffee ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/coffeescript/org/apache/tapestry5/corelib/modulejs/pageinit.coffee b/tapestry-core/src/main/coffeescript/org/apache/tapestry5/corelib/modulejs/pageinit.coffee new file mode 100644 index 0000000..a5ab345 --- /dev/null +++ b/tapestry-core/src/main/coffeescript/org/apache/tapestry5/corelib/modulejs/pageinit.coffee @@ -0,0 +1,14 @@ +define -> + + invokeInitializer = (qualifiedName, initArguments...) -> + + [moduleName, functionName] = qualifiedName.split ':' + + require [moduleName], (moduleLib) -> + fn = if functionName? then moduleLib[functionName] else moduleLib + fn.apply null, initArguments + + # Exports this single function: + (inits) -> + invokeInitializer.apply null, init for init in inits + http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/95dcefc3/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 d07f62b..9578167 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 @@ -14,6 +14,7 @@ package org.apache.tapestry5.internal.services; +import org.apache.tapestry5.json.JSONArray; import org.apache.tapestry5.json.JSONObject; import org.apache.tapestry5.services.javascript.InitializationPriority; import org.apache.tapestry5.services.javascript.StylesheetLink; @@ -40,13 +41,13 @@ public interface DocumentLinker * of the page (in a full page render) and collected as the "script" property of the partial page render response. * The JavaScript is executed after the page loads (or in an Ajax update, after external JavaScript libraries are * loaded and the DOM is updated). - * <p> + * <p/> * This method may be called multiple times for the same priority and the script will be accumulated. - * + * * @param priority - * when to execute the provided script + * when to execute the provided script * @param script - * statement to add to the block (a newline will be appended as well) + * statement to add to the block (a newline will be appended as well) */ void addScript(InitializationPriority priority, String script); @@ -54,10 +55,27 @@ public interface DocumentLinker * Adds a call to the Tapestry.init() function. This may be called multiple times and the init() calls will occur * in order. In a normal page render, the init() calls will be added to the main JavaScript block, but in a partial * page render Ajax response, the initialization will be property "init" of the partial page render response. - * <p> + * <p/> * This method should only be invoked at most once per priority. - * + * * @since 5.2.0 */ void setInitialization(InitializationPriority priority, JSONObject initialization); + + /** + * Page initialization based on JavaScript modules. + * + * @param priority + * priority at which to perform initialization + * @param moduleName + * name of module; the module exports a single function, or a map of functions + * @param functionName + * name of function exported by module, or null (if the module exports a single function) + * @param arguments + * arguments to pass to the function + */ + void setInitialization(InitializationPriority priority, + String moduleName, + String functionName, + JSONArray arguments); } http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/95dcefc3/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 0d8ffce..38cf54a 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 @@ -18,6 +18,8 @@ import org.apache.tapestry5.Asset; import org.apache.tapestry5.dom.Document; import org.apache.tapestry5.dom.Element; import org.apache.tapestry5.ioc.internal.util.CollectionFactory; +import org.apache.tapestry5.ioc.internal.util.InternalUtils; +import org.apache.tapestry5.json.JSONArray; import org.apache.tapestry5.json.JSONObject; import org.apache.tapestry5.services.javascript.InitializationPriority; import org.apache.tapestry5.services.javascript.ModuleManager; @@ -34,6 +36,8 @@ public class DocumentLinkerImpl implements DocumentLinker private final Map<InitializationPriority, JSONObject> priorityToInit = CollectionFactory.newMap(); + private final Map<InitializationPriority, List<JSONArray>> priorityToModuleInit = CollectionFactory.newMap(); + private final List<StylesheetLink> includedStylesheets = CollectionFactory.newList(); private final ModuleManager moduleManager; @@ -105,6 +109,28 @@ public class DocumentLinkerImpl implements DocumentLinker hasDynamicScript = true; } + @Override + public void setInitialization(InitializationPriority priority, String moduleName, String functionName, JSONArray arguments) + { + JSONArray init = new JSONArray(); + + String name = functionName == null ? moduleName : moduleName + ":" + functionName; + + init.put(name); + + if (arguments != null) + { + for (Object o : arguments) + { + init.put(o); + } + } + + InternalUtils.addToMapList(priorityToModuleInit, priority, init); + + hasDynamicScript = true; + } + /** * Updates the supplied Document, possibly adding <head> or <body> elements. * @@ -223,7 +249,9 @@ public class DocumentLinkerImpl implements DocumentLinker for (InitializationPriority p : InitializationPriority.values()) { if (p != InitializationPriority.IMMEDIATE && !wrapped - && (priorityToScript.containsKey(p) || priorityToInit.containsKey(p))) + && (priorityToScript.containsKey(p) || + priorityToInit.containsKey(p) || + priorityToModuleInit.containsKey(p))) { block.append("Tapestry.onDOMLoaded(function() {\n"); @@ -245,10 +273,33 @@ public class DocumentLinkerImpl implements DocumentLinker private void add(StringBuilder block, InitializationPriority priority) { + addModuleInits(block, priorityToModuleInit.get(priority)); + add(block, priorityToScript.get(priority)); add(block, priorityToInit.get(priority)); } + private void addModuleInits(StringBuilder block, List<JSONArray> moduleInits) + { + if (moduleInits == null) + { + return; + } + + block.append("require([\"core/pageinit\"], function (pageinit) {\n"); + block.append(" pageinit(["); + + String sep = ""; + + for (JSONArray init : moduleInits) { + block.append(sep); + block.append(init.toString(compactJSON)); + sep = ",\n "; + } + + block.append("]);\n});\n"); + } + private void add(StringBuilder block, JSONObject init) { if (init == null) http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/95dcefc3/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 1d08342..4e4879b 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 @@ -57,10 +57,17 @@ public class PartialMarkupDocumentLinker implements DocumentLinker priorityToInits.put(priority, initialization); } + @Override + public void setInitialization(InitializationPriority priority, String moduleName, String functionName, JSONArray arguments) + { + throw new IllegalStateException("not yet implemented"); + } + /** * Commits changes, adding one or more keys to the reply. * - * @param reply JSON Object to be sent to client + * @param reply + * JSON Object to be sent to client */ public void commit(JSONObject reply) { http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/95dcefc3/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 7181aaa..5aa59c7 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 @@ -29,6 +29,7 @@ import org.apache.tapestry5.json.JSONArray; import org.apache.tapestry5.json.JSONObject; import org.apache.tapestry5.services.javascript.*; +import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; @@ -53,6 +54,11 @@ public class JavaScriptSupportImpl implements JavaScriptSupport private final Map<InitializationPriority, JSONObject> inits = CollectionFactory.newMap(); + // Temporary name, as eventually 5.3-style inits will become a special case of + // 5.4 module-based initialization. + + private final List<InitializationImpl> moduleInits = CollectionFactory.newList(); + private final JavaScriptStackSource javascriptStackSource; private final JavaScriptStackPathConstructor stackPathConstructor; @@ -63,6 +69,48 @@ public class JavaScriptSupportImpl implements JavaScriptSupport private String focusFieldId; + class InitializationImpl implements Initialization + { + InitializationPriority priority = InitializationPriority.NORMAL; + + final String moduleName; + + String functionName; + + JSONArray arguments; + + InitializationImpl(String moduleName) + { + this.moduleName = moduleName; + } + + @Override + public Initialization invoke(String functionName) + { + assert InternalUtils.isNonBlank(functionName); + + this.functionName = functionName; + + return this; + } + + @Override + public Initialization priority(InitializationPriority priority) + { + assert priority != null; + + this.priority = priority; + + return this; + } + + @Override + public void with(Object... arguments) + { + this.arguments = new JSONArray(arguments); + } + } + public JavaScriptSupportImpl(DocumentLinker linker, JavaScriptStackSource javascriptStackSource, JavaScriptStackPathConstructor stackPathConstructor) { @@ -106,7 +154,9 @@ public class JavaScriptSupportImpl implements JavaScriptSupport public void commit() { if (focusFieldId != null) + { addInitializerCall("activate", focusFieldId); + } F.flow(stylesheetLinks).each(new Worker<StylesheetLink>() { @@ -132,8 +182,26 @@ public class JavaScriptSupportImpl implements JavaScriptSupport JSONObject init = inits.get(p); if (init != null) + { linker.setInitialization(p, init); + } } + + F.flow(moduleInits).sort(new Comparator<InitializationImpl>() + { + @Override + public int compare(InitializationImpl o1, InitializationImpl o2) + { + return o1.priority.compareTo(o2.priority); + } + }).each(new Worker<InitializationImpl>() + { + @Override + public void work(InitializationImpl element) + { + linker.setInitialization(element.priority, element.moduleName, element.functionName, element.arguments); + } + }); } public void addInitializerCall(InitializationPriority priority, String functionName, JSONObject parameter) @@ -358,4 +426,15 @@ public class JavaScriptSupportImpl implements JavaScriptSupport return this; } + @Override + public Initialization require(String moduleName) + { + assert InternalUtils.isNonBlank(moduleName); + + InitializationImpl init = new InitializationImpl(moduleName); + + moduleInits.add(init); + + return init; + } } http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/95dcefc3/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/Initialization.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/Initialization.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/Initialization.java new file mode 100644 index 0000000..9fafcf6 --- /dev/null +++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/Initialization.java @@ -0,0 +1,41 @@ +package org.apache.tapestry5.services.javascript; + +/** + * Provided by {@link JavaScriptSupport#require(String)} to allow additional, optional, details of the module-based page initialization + * to be configured. + * + * @since 5.4 + */ +public interface Initialization +{ + + /** + * Specifies the function to invoke. If not invoked, then the module is expected to export + * just a single function. + * + * @param functionName + * name of a function exported by the module. + * @return this Initialization, for further configuration + */ + Initialization invoke(String functionName); + + /** + * Changes the initialization priority of the initialization from its default, {@link InitializationPriority#NORMAL}. + * + * @param priority + * new priority + * @return this Initialization, for further configuration + */ + Initialization priority(InitializationPriority priority); + + /** + * Specifies the arguments to be passed to the function. Normally, just a single {@link org.apache.tapestry5.json.JSONObject} + * is passed. + * + * @param arguments + * any number of values. Each value may be one of: null, String, Boolean, Number, + * {@link org.apache.tapestry5.json.JSONObject}, {@link org.apache.tapestry5.json.JSONArray}, or + * {@link org.apache.tapestry5.json.JSONLiteral}. + */ + void with(Object... arguments); +} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/95dcefc3/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 b114b74..2fc30bc 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 @@ -224,4 +224,15 @@ public interface JavaScriptSupport */ JavaScriptSupport autofocus(FieldFocusPriority priority, String fieldId); + + /** + * Requires a JavaScript module by name. On the c + * + * @param moduleName + * the name of the module to require + * @return Initialization instance, used to configure function name, arguments, etc. + * @since 5.4 + */ + Initialization require(String moduleName); + }
