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    
015    package org.apache.tapestry5.corelib.components;
016    
017    import org.apache.tapestry5.*;
018    import org.apache.tapestry5.annotations.Parameter;
019    import org.apache.tapestry5.annotations.SupportsInformalParameters;
020    import org.apache.tapestry5.dom.Element;
021    import org.apache.tapestry5.ioc.annotations.Inject;
022    import org.apache.tapestry5.services.javascript.JavaScriptSupport;
023    
024    /**
025     * Renders an arbitrary element including informal parameters.
026     * 
027     * @tapestrydoc
028     */
029    @SupportsInformalParameters
030    public 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    }