001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.markup.html.panel;
018
019import org.apache.wicket.Component;
020import org.apache.wicket.DequeueContext;
021import org.apache.wicket.IQueueRegion;
022import org.apache.wicket.MarkupContainer;
023import org.apache.wicket.markup.IMarkupFragment;
024import org.apache.wicket.markup.html.WebMarkupContainer;
025import org.apache.wicket.model.IModel;
026import org.apache.wicket.util.lang.Args;
027
028/**
029 * Usually you either have a markup file or a xml tag with wicket:id="myComponent" to associate
030 * markup with a component. However in some use cases, especially when working with small panels it
031 * is a bit awkward to maintain tiny pieces of markup in plenty of panel markup files. Use cases are
032 * for example list views where list items are different depending on a state.
033 * <p>
034 * Fragments provide a means to maintain the panels tiny piece of markup. Since it can be anywhere,
035 * the component whose markup contains the fragment's markup must be provided (markup provider).
036 * <p>
037 * 
038 * <pre>
039 *  &lt;span wicket:id=&quot;myPanel&quot;&gt;Example input (will be removed)&lt;/span&gt;
040 * 
041 *  &lt;wicket:fragment wicket:id=&quot;frag1&quot;&gt;panel 1&lt;/wicket:fragment&gt;
042 *  &lt;wicket:fragment wicket:id=&quot;frag2&quot;&gt;panel 2&lt;/wicket:fragment&gt;
043 * </pre>
044 * 
045 * <pre>
046 *  add(new Fragment(&quot;myPanel1&quot;, &quot;frag1&quot;, myPage);
047 * </pre>
048 * 
049 * @author Juergen Donnerstag
050 */
051public class Fragment extends WebMarkupContainer implements IQueueRegion
052{
053        private static final long serialVersionUID = 1L;
054
055        /** The wicket:id of the associated markup fragment */
056        private final String associatedMarkupId;
057
058        private final MarkupContainer markupProvider;
059
060        /**
061         * Constructor.
062         * 
063         * @see org.apache.wicket.Component#Component(String)
064         * 
065         * @param id
066         *            The component id
067         * @param markupId
068         *            The associated id of the associated markup fragment
069         * @param markupProvider
070         *            The component whose markup contains the fragment's markup
071         */
072        public Fragment(final String id, final String markupId, final MarkupContainer markupProvider)
073        {
074                this(id, markupId, markupProvider, null);
075        }
076
077        /**
078         * Constructor.
079         * 
080         * @see org.apache.wicket.Component#Component(String)
081         * 
082         * @param id
083         *            The component id
084         * @param markupId
085         *            The associated id of the associated markup fragment
086         * @param markupProvider
087         *            The component whose markup contains the fragment's markup
088         * @param model
089         *            The model for this fragment
090         */
091        public Fragment(final String id, final String markupId, final MarkupContainer markupProvider,
092                final IModel<?> model)
093        {
094                super(id, model);
095
096                associatedMarkupId = Args.notNull(markupId, "markupId");
097                this.markupProvider = markupProvider;
098        }
099
100        /**
101         * {@inheritDoc}
102         */
103        @Override
104        protected IMarkupSourcingStrategy newMarkupSourcingStrategy()
105        {
106                return new FragmentMarkupSourcingStrategy(associatedMarkupId, markupProvider)
107                {
108                        @Override
109                        public IMarkupFragment chooseMarkup(Component component)
110                        {
111                                return Fragment.this.chooseMarkup(getMarkupProvider(component));
112                        }
113                };
114        }
115
116        /**
117         * Get the markup stream which shall be used to search for the fragment
118         * 
119         * @param provider
120         * @return The markup stream to be used to find the fragment markup
121         */
122        protected IMarkupFragment chooseMarkup(final MarkupContainer provider)
123        {
124                return provider.getMarkup(null);
125        }
126
127        /**
128         * @return the markup id associated to this Fragment
129         */
130        public final String getAssociatedMarkupId()
131        {
132                return associatedMarkupId;
133        }
134
135
136        @Override
137        public DequeueContext newDequeueContext()
138        {
139                IMarkupFragment markup = getMarkupSourcingStrategy().getMarkup(this, null);
140                if (markup == null)
141                {
142                        return null;
143                }
144
145                return new DequeueContext(markup, this, true);
146        }
147}