    001// Copyright 2010-2013 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.Asset;
    018import org.apache.tapestry5.ComponentResources;
    019import org.apache.tapestry5.FieldFocusPriority;
    020import org.apache.tapestry5.SymbolConstants;
    021import org.apache.tapestry5.annotations.Environmental;
    022import org.apache.tapestry5.internal.services.DocumentLinker;
    023import org.apache.tapestry5.json.JSONArray;
    024import org.apache.tapestry5.json.JSONObject;
    025import org.apache.tapestry5.services.EnvironmentalShadowBuilder;
    026
    027/**
    028 * The JavaScriptSupport environmental is very stateful, accumulating JavaScript stacks, libraries and initialization
    029 * code until the end of the main page render; it then updates the rendered DOM (adding &lt;script&gt; tags to the
    030 * &lt;head&gt; and &lt;body&gt;) before the document is streamed to the client.
    031 * <p/>
    032 * JavaScriptSupport is normally accessed within a component by using the {@link Environmental} annotation on a
    033 * component field. In addition, JavaScriptSupport may also be accessed as a service (the service
    034 * {@linkplain EnvironmentalShadowBuilder internally delegates to the current environmental instance}), which is useful
    035 * for service-layer objects.
    036 * <p/>
    037 * The term "import" is used on many methods to indicate that the indicated resource (stack, library or stylesheet) will
    038 * only be added to the final cocument once, even when there are repeated calls.
    039 * <p/>
    040 * The name is slightly a misnomer, since there's a side-line of {@linkplain #importStylesheet(StylesheetLink)} as well.
    041 * <p/>
    042 * JavaScriptSupport works equally well inside an Ajax request that produces a JSON-formatted partial page update response.
    043 *
    044 * @see org.apache.tapestry5.internal.services.DocumentLinker
    045 * @since 5.2.0
    046 */
    047public interface JavaScriptSupport
    048{
    049    /**
    050     * Allocates a unique id based on the component's id. In some cases, the return value will not precisely match the
    051     * input value (an underscore and a unique index value may be appended).
    052     *
    053     * @param id
    054     *         the component id from which a unique id will be generated
    055     * @return a unique id for this rendering of the page
    056     * @see org.apache.tapestry5.ioc.util.IdAllocator
    057     */
    058    String allocateClientId(String id);
    059
    060    /**
    061     * As with {@link #allocateClientId(String)} but uses the id of the component extracted from the resources.
    062     *
    063     * @param resources
    064     *         of the component which requires an id
    065     * @return a unique id for this rendering of the page
    066     */
    067    String allocateClientId(ComponentResources resources);
    068
    069    /**
    070     * Adds initialization script at {@link InitializationPriority#NORMAL} priority.
    071     *
    072     * @param format
    073     *         format string (as per {@link String#format(String, Object...)}
    074     * @param arguments
    075     *         arguments referenced by format specifiers
    076     * @deprecated Deprecated in 5.4; refactor to use {@linkplain #require(String) JavaScript modules} instead
    077     */
    078    void addScript(String format, Object... arguments);
    079
    080    /**
    081     * Adds initialization script at the specified priority.
    082     *
    083     * @param priority
    084     *         priority to use when adding the script
    085     * @param format
    086     *         format string (as per {@link String#format(String, Object...)}
    087     * @param arguments
    088     *         arguments referenced by format specifiers
    089     * @deprecated Deprecated in 5.4; refactor to use {@linkplain #require(String) JavaScript modules} instead
    090     */
    091    void addScript(InitializationPriority priority, String format, Object... arguments);
    092
    093    /**
    094     * Adds a call to a client-side function inside the Tapestry.Initializer namespace. Calls to this
    095     * method are aggregated into a call to the Tapestry.init() function. Initialization occurs at
    096     * {@link InitializationPriority#NORMAL} priority.
    097     *
    098     * @param functionName
    099     *         name of client-side function (within Tapestry.Initializer namespace) to execute
    100     * @param parameter
    101     *         object to pass to the client-side function
    102     * @deprecated Deprecated in 5.4; refactor to use {@linkplain #require(String) JavaScript modules} instead
    103     */
    104    void addInitializerCall(String functionName, JSONObject parameter);
    105
    106    /**
    107     * Adds a call to a client-side function inside the Tapestry.Initializer namespace. Calls to this
    108     * method are aggregated into a call to the Tapestry.init() function. Initialization occurs at
    109     * {@link InitializationPriority#NORMAL} priority.
    110     *
    111     * @param functionName
    112     *         name of client-side function (within Tapestry.Initializer namespace) to execute
    113     * @param parameter
    114     *         array of parameters to pass to the client-side function
    115     * @since 5.3
    116     * @deprecated Deprecated in 5.4; refactor to use {@linkplain #require(String) JavaScript modules} instead
    117     */
    118    void addInitializerCall(String functionName, JSONArray parameter);
    119
    120    /**
    121     * Adds a call to a client-side function inside the Tapestry.Initializer namespace. Calls to this
    122     * method are aggregated into a call to the Tapestry.init() function. Initialization occurs at
    123     * {@link InitializationPriority#NORMAL} priority.
    124     *
    125     * @param functionName
    126     *         name of client-side function (within Tapestry.Initializer namespace) to execute
    127     * @param parameter
    128     *         array of parameters to pass to the client-side function
    129     * @since 5.3
    130     * @deprecated Deprecated in 5.4; refactor to use {@linkplain #require(String) JavaScript modules} instead
    131     */
    132    void addInitializerCall(InitializationPriority priority, String functionName, JSONArray parameter);
    133
    134    /**
    135     * Adds a call to a client-side function inside the Tapestry.Initializer namespace. Calls to this
    136     * method are aggregated into a call to the Tapestry.init() function. Initialization occurs at
    137     * the specified priority.
    138     *
    139     * @param priority
    140     *         priority to use when adding the script
    141     * @param functionName
    142     *         name of client-side function (within Tapestry.Initializer namespace) to execute
    143     * @param parameter
    144     *         object to pass to the client-side function
    145     * @deprecated Deprecated in 5.4; refactor to use {@linkplain #require(String) JavaScript modules} instead
    146     */
    147    void addInitializerCall(InitializationPriority priority, String functionName, JSONObject parameter);
    148
    149    /**
    150     * Adds a call to a client-side function inside the Tapestry.Initializer namespace. Calls to this
    151     * method are aggregated into a call to the Tapestry.init() function. Initialization occurs at
    152     * {@link InitializationPriority#NORMAL} priority.
    153     *
    154     * @param functionName
    155     *         name of client-side function (within Tapestry.Initializer namespace) to execute
    156     * @param parameter
    157     *         string to pass to function (typically, a client id)
    158     * @deprecated Deprecated in 5.4; refactor to use {@linkplain #require(String) JavaScript modules} instead
    159     */
    160    void addInitializerCall(String functionName, String parameter);
    161
    162    /**
    163     * Adds a call to a client-side function inside the Tapestry.Initializer namespace. Calls to this
    164     * method are aggregated into a call to the Tapestry.init() function. Initialization occurs at
    165     * the specified priority.
    166     *
    167     * @param priority
    168     *         priority to use when adding the script
    169     * @param functionName
    170     *         name of client-side function (within Tapestry.Initializer namespace) to execute
    171     * @param parameter
    172     *         string to pass to function (typically, a client id)
    173     * @deprecated Deprecated in 5.4; refactor to use {@linkplain #require(String) JavaScript modules} instead
    174     */
    175    void addInitializerCall(InitializationPriority priority, String functionName, String parameter);
    176
    177    /**
    178     * Imports a JavaScript library as part of the rendered page. Libraries are added in the order
    179     * they are first imported; duplicate imports are ignored. Libraries are added to the page serially
    180     * (whereas modules may be loaded in parallel), and all libraries are added before any modules are loaded.
    181     * Because of this, it is preferrable to organize your JavaScript into modules, rather than libraries.
    182     *
    183     * @return this JavaScriptSupport, for further configuration
    184     * @see org.apache.tapestry5.annotations.Import
    185     */
    186    JavaScriptSupport importJavaScriptLibrary(Asset asset);
    187
    188    /**
    189     * A convenience method that wraps the Asset as a {@link StylesheetLink}.
    190     *
    191     * @param stylesheet
    192     *         asset for the stylesheet
    193     * @return this JavaScriptSupport, for further configuration
    194     * @see #importStylesheet(StylesheetLink)
    195     */
    196    JavaScriptSupport importStylesheet(Asset stylesheet);
    197
    198    /**
    199     * Imports a Cascading Style Sheet file as part of the rendered page. Stylesheets are added in the
    200     * order they are first imported; duplicate imports are ignored. Starting in 5.4, importing a stylesheet
    201     * imports the core stack as well (with its stylesheets); this ensures that the imported stylesheet(s) can
    202     * override rules from Tapestry's default stylesheets.
    203     *
    204     * @param stylesheetLink
    205     *         encapsulates the link URL plus any additional options
    206     * @return this JavaScriptSupport, for further configuration
    207     */
    208    JavaScriptSupport importStylesheet(StylesheetLink stylesheetLink);
    209
    210    /**
    211     * Imports a {@link JavaScriptStack} by name, a related set of JavaScript libraries and stylesheets.
    212     * Stacks are contributions to the {@link JavaScriptStackSource} service. When
    213     * {@linkplain SymbolConstants#COMBINE_SCRIPTS JavaScript aggregation} in enabled, the stack will be represented by
    214     * a single virtual URL; otherwise the individual asset URLs of the stack
    215     * will be added to the document.
    216     * <p/>
    217     * Please refer to the {@linkplain #importJavaScriptLibrary(Asset) notes about libraries vs. modules}.
    218     *
    219     * @param stackName
    220     *         the name of the stack (case is ignored); the stack must exist
    221     * @return this JavaScriptSupport, for further configuration
    222     */
    223    JavaScriptSupport importStack(String stackName);
    224
    225    /**
    226     * Import a Javascript library with an arbitrary URL.
    227     * <p/>
    228     * Please refer to the {@linkplain #importJavaScriptLibrary(Asset) notes about libraries vs. modules}.
    229     */
    230    JavaScriptSupport importJavaScriptLibrary(String libraryURL);
    231
    232    /**
    233     * Invoked to set focus on a rendered field. Takes into account priority, meaning that a field with errors will take
    234     * precedence over a merely required field, and over a field that is optional. The value
    235     * {@link org.apache.tapestry5.FieldFocusPriority#OVERRIDE} can be used to force a particular field to receive
    236     * focus.
    237     *
    238     * @param priority
    239     *         focus is set only if the provided priority is greater than the current priority
    240     * @param fieldId
    241     *         id of client-side element to take focus
    242     */
    243    JavaScriptSupport autofocus(FieldFocusPriority priority, String fieldId);
    244
    245
    246    /**
    247     * Requires a JavaScript module by name. On the client, this will <code>require()</code> the module and
    248     * (optionally) de-reference a function exported by the module (or, treat the module as exporting a single
    249     * implicit function). The function will be invoked. Use the returned {@link Initialization} to specify the function name
    250     * to invoke, and the parameters to pass to the function.
    251     * <p/>
    252     * In some cases, a module exports no functions, but performs some initialization (typically, adding document-level
    253     * event handlers), in which case a call to require() is sufficient. In cases where the module, or a function
    254     * within the module, are invoked with no parameters, the calls will be collapsed into a single invocation.
    255     * <p/>
    256     * If the module is part of a {@linkplain org.apache.tapestry5.services.javascript.JavaScriptStack#getModules() JavaScript stack},
    257     * then the stack will be imported; this is important when {@linkplain SymbolConstants#COMBINE_SCRIPTS JavaScript aggregation is enabled},
    258     * but also ensures that libraries in the stack are loaded before the module (for cases where the
    259     * module has dependencies on libraries not wrapped as AMD modules).
    260     *
    261     * @param moduleName
    262     *         the name of the module to require
    263     * @return Initialization instance, used to configure function name, arguments, etc.
    264     * @since 5.4
    265     */
    266    Initialization require(String moduleName);
    267
    268    /**
    269     * Adds a module configuration callback for this request.
    270     *
    271     * @param callback
    272     *         a {@link ModuleConfigurationCallback}. It cannot be null.
    273     * @see DocumentLinker#addModuleConfigurationCallback(ModuleConfigurationCallback)
    274     * @since 5.4
    275     */
    276    void addModuleConfigurationCallback(ModuleConfigurationCallback callback);
    277
    278}