001// Copyright 2008, 2010, 2011 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.corelib.components;
016
017import org.apache.tapestry5.*;
018import org.apache.tapestry5.annotations.Parameter;
019import org.apache.tapestry5.annotations.SupportsInformalParameters;
020import org.apache.tapestry5.dom.Element;
021import org.apache.tapestry5.ioc.annotations.Inject;
022import org.apache.tapestry5.services.javascript.JavaScriptSupport;
023
024/**
025 * Renders an arbitrary element including informal parameters.
026 * 
027 * @tapestrydoc
028 */
029@SupportsInformalParameters
030public class Any implements ClientElement
031{
032    @Parameter(defaultPrefix = BindingConstants.LITERAL)
033    private String element;
034
035    /**
036     * The desired client id, which defaults to the components id.
037     */
038    @Parameter(value = "prop:componentResources.id", defaultPrefix = BindingConstants.LITERAL)
039    private String clientId;
040
041    private Element anyElement;
042
043    private String uniqueId;
044
045    @Inject
046    private ComponentResources resources;
047
048    @Inject
049    private JavaScriptSupport javascriptSupport;
050
051    String defaultElement()
052    {
053        return resources.getElementName("div");
054    }
055
056    void beginRender(MarkupWriter writer)
057    {
058        anyElement = writer.element(element);
059
060        uniqueId = null;
061
062        resources.renderInformalParameters(writer);
063    }
064
065    /**
066     * Returns the client id. This has side effects: this first time this is called (after the Any component renders
067     * its start tag), a unique id is allocated (based on, and typically the same as, the clientId parameter, which
068     * defaults to the component's id). The rendered element is updated, with its id attribute set to the unique client
069     * id, which is then returned.
070     * 
071     * @return unique client id for this component
072     */
073    public String getClientId()
074    {
075        if (anyElement == null)
076            throw new IllegalStateException(String.format(
077                    "Unable to provide client id for component %s as it has not yet rendered.", resources
078                            .getCompleteId()));
079
080        if (uniqueId == null)
081        {
082            uniqueId = javascriptSupport.allocateClientId(clientId);
083            anyElement.forceAttributes("id", uniqueId);
084        }
085
086        return uniqueId;
087    }
088
089    void afterRender(MarkupWriter writer)
090    {
091        writer.end(); // the element
092    }
093
094    void inject(JavaScriptSupport javascriptSupport, ComponentResources resources, String element, String clientId)
095    {
096        this.javascriptSupport = javascriptSupport;
097        this.resources = resources;
098        this.element = element;
099        this.clientId = clientId;
100    }
101}