001// Copyright 2012 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007// http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.tapestry5.services.javascript;
016
017import org.apache.tapestry5.ioc.Resource;
018
019import java.util.Arrays;
020import java.util.List;
021
022/**
023 * Used to define a <a href="http://requirejs.org/docs/api.html#config-shim">module shim</a>, used to adapt non-AMD JavaScript libraries
024 * to operate like proper modules.  This information is used to build up a list of dependencies for the contributed JavaScript module,
025 * and to identify the resource to be streamed to the client.
026 * <p/>
027 * Instances of this class are contributed to the {@link ModuleManager} service;  the contribution key is the module name
028 * (typically, a single word).
029 * <p/>
030 * In some cases, an instance may be created and contributed to override a default module; if the module has no dependencies,
031 * exports, or initExpression (that is, if it is a proper AMD module, where such dependencies are provided inside
032 * the module itself), then no client-side shim configuration will be written for the module, but requests for the
033 * module will be satisfied by the resource.'
034 *
035 * @since 5.4
036 * @see AMDWrapper
037 */
038public final class JavaScriptModuleConfiguration
039{
040    /**
041     * The resource for this shim module.
042     */
043    public final Resource resource;
044
045    /**
046     * The names of other shim modules that should be loaded before this shim module.
047     */
048    private List<String> dependencies;
049
050    /**
051     * Optional (but desirable) value exported by the shim module.
052     */
053    private String exports;
054
055    private String initExpression;
056
057    private boolean needsConfiguration;
058
059    public JavaScriptModuleConfiguration(Resource resource)
060    {
061        assert resource != null;
062
063        this.resource = resource;
064    }
065
066    /**
067     * A list of other module names the shim depends on.
068     *
069     * @param moduleNames
070     * @return this JavaScriptModuleConfiguration for further configuration
071     */
072    public JavaScriptModuleConfiguration dependsOn(String... moduleNames)
073    {
074        assert moduleNames.length > 0;
075
076        dependencies = Arrays.asList(moduleNames);
077
078        needsConfiguration = true;
079
080        return this;
081    }
082
083    public List<String> getDependencies()
084    {
085        return dependencies;
086    }
087
088    /**
089     * The name of a global variable exported by the module. This will be the value injected into
090     * modules that depend on the shim.
091     *
092     * @return this JavaScriptModuleConfiguration for further configuration
093     */
094    public JavaScriptModuleConfiguration exports(String exports)
095    {
096        assert exports != null;
097
098        this.exports = exports;
099
100        needsConfiguration = true;
101
102        return this;
103    }
104
105    public String getExports()
106    {
107        return exports;
108    }
109
110    /**
111     * Used as an alternative to {@linkplain #exports(String)}, this allows a short expression to be specified; the
112     * expression is used to initialize, clean up, and (usually) return the module's export value. For Underscore, this
113     * would be "_.noConflict()".  If the expression returns null, then the exports value is used.
114     * <p/>
115     * In RequireJS 2.1.1 (the version shipped with Tapestry, currently), an init function is not invoked unless
116     * the shim also defines an exports. See <a href="https://github.com/jrburke/requirejs/issues/517">RequireJS issue 517</a>.
117     * At this time, you should specify {@link #exports} even if you provide a {@link #initializeWith(String)}}.
118     *
119     * @param expression
120     *         initialization expression
121     * @return this JavaScriptModuleConfiguration, for further configuration
122     */
123    public JavaScriptModuleConfiguration initializeWith(String expression)
124    {
125        assert expression != null;
126
127        this.initExpression = expression;
128
129        needsConfiguration = true;
130
131        return this;
132    }
133
134    public String getInitExpression()
135    {
136        return initExpression;
137    }
138
139    /**
140     * Returns true if the module contains any additional configuration beyond its {@link Resource}.
141     */
142    public boolean getNeedsConfiguration()
143    {
144        return needsConfiguration;
145    }
146}