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