You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by jd...@apache.org on 2006/11/04 14:47:08 UTC

svn commit: r471185 [1/2] - in /incubator/wicket/trunk/wicket/src: main/java/wicket/ main/java/wicket/ajax/ main/java/wicket/markup/ main/java/wicket/markup/html/ main/java/wicket/markup/html/border/ main/java/wicket/markup/html/internal/ main/java/wic...

Author: jdonnerstag
Date: Sat Nov  4 05:47:06 2006
New Revision: 471185

URL: http://svn.apache.org/viewvc?view=rev&rev=471185
Log:
Changed <wicket:head> to make use of MarkupFragments.
Public API is unchanged.

Added:
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/WicketHeadContainer.java
      - copied, changed from r464848, incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HeaderPartContainer.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/onLoadListener/
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/onLoadListener/IMarkupLoadListener.java   (with props)
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/onLoadListener/WicketHeaderLoader.java   (with props)
    incubator/wicket/trunk/wicket/src/test/java/wicket/util/tester/apps_7/
    incubator/wicket/trunk/wicket/src/test/java/wicket/util/tester/apps_7/EmailPage.html   (with props)
    incubator/wicket/trunk/wicket/src/test/java/wicket/util/tester/apps_7/EmailPage.java   (with props)
    incubator/wicket/trunk/wicket/src/test/java/wicket/util/tester/apps_7/ExpectedResult-1.html   (with props)
    incubator/wicket/trunk/wicket/src/test/java/wicket/util/tester/apps_7/ExpectedResult-2.html   (with props)
    incubator/wicket/trunk/wicket/src/test/java/wicket/util/tester/apps_7/FormTesterTest.java   (with props)
    incubator/wicket/trunk/wicket/src/test/java/wicket/util/tester/apps_7/MyPanel.html   (with props)
    incubator/wicket/trunk/wicket/src/test/java/wicket/util/tester/apps_7/MyPanel.java   (with props)
Removed:
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HeaderPartContainer.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/resolver/HtmlHeaderResolver.java
Modified:
    incubator/wicket/trunk/wicket/src/main/java/wicket/Application.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/Component.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/MarkupContainer.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/Page.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/ajax/AjaxRequestTarget.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/MarkupCache.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/MarkupFragment.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/MarkupParser.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/WebMarkupContainerWithAssociatedMarkup.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/WebPage.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/border/Border.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HeaderContainer.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HeaderResponse.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HtmlHeaderContainer.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/PortletHeaderContainer.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/panel/Panel.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/loader/DefaultMarkupLoader.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/loader/InheritedMarkupMarkupLoader.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/loader/MarkupFragmentUtils.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/filter/HtmlHeaderSectionHandler.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/filter/TagTypeHandler.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/filter/WicketTagIdentifier.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/protocol/http/portlet/PortletPage.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/response/StringResponse.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/settings/IMarkupSettings.java
    incubator/wicket/trunk/wicket/src/main/java/wicket/settings/Settings.java
    incubator/wicket/trunk/wicket/src/test/java/wicket/ajax/AjaxRequestTargetTest.java
    incubator/wicket/trunk/wicket/src/test/java/wicket/markup/MarkupInheritanceExpectedResult_10.html
    incubator/wicket/trunk/wicket/src/test/java/wicket/markup/MarkupInheritanceExpectedResult_11.html
    incubator/wicket/trunk/wicket/src/test/java/wicket/markup/MarkupInheritanceExpectedResult_12.html
    incubator/wicket/trunk/wicket/src/test/java/wicket/markup/html/debug/WicketComponentTreeTestPage_ExpectedResult.html
    incubator/wicket/trunk/wicket/src/test/java/wicket/markup/html/header/testing4/Panel1.html
    incubator/wicket/trunk/wicket/src/test/java/wicket/markup/html/header/testing4/TestPage_ExpectedResult-1.html
    incubator/wicket/trunk/wicket/src/test/java/wicket/markup/parser/filter/HeaderSectionMyLabel.java
    incubator/wicket/trunk/wicket/src/test/java/wicket/markup/parser/filter/HeaderSectionMyLabel2.java
    incubator/wicket/trunk/wicket/src/test/java/wicket/markup/parser/filter/HeaderSectionPageExpectedResult_14.html
    incubator/wicket/trunk/wicket/src/test/java/wicket/markup/parser/filter/HeaderSectionPageExpectedResult_9.html
    incubator/wicket/trunk/wicket/src/test/java/wicket/markup/parser/filter/HeaderSectionPageExpectedResult_9a.html
    incubator/wicket/trunk/wicket/src/test/java/wicket/markup/parser/filter/HeaderSectionPage_19.java
    incubator/wicket/trunk/wicket/src/test/java/wicket/protocol/http/portlet/MockPortletPage.java

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/Application.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/Application.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/Application.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/Application.java Sat Nov  4 05:47:06 2006
@@ -35,9 +35,9 @@
 import wicket.application.IComponentInstantiationListener;
 import wicket.markup.MarkupCache;
 import wicket.markup.html.image.resource.DefaultButtonImageResourceFactory;
+import wicket.markup.parser.onLoadListener.WicketHeaderLoader;
 import wicket.markup.resolver.AutoComponentResolver;
 import wicket.markup.resolver.FragmentResolver;
-import wicket.markup.resolver.HtmlHeaderResolver;
 import wicket.markup.resolver.MarkupInheritanceResolver;
 import wicket.markup.resolver.ParentResolver;
 import wicket.markup.resolver.WicketLinkResolver;
@@ -719,14 +719,16 @@
 	{
 		settingsAccessible = true;
 		IPageSettings pageSettings = getPageSettings();
+		
 		// Install default component resolvers
 		pageSettings.addComponentResolver(new ParentResolver());
-		pageSettings.addComponentResolver(new AutoComponentResolver());
 		pageSettings.addComponentResolver(new MarkupInheritanceResolver());
-		pageSettings.addComponentResolver(new HtmlHeaderResolver());
 		pageSettings.addComponentResolver(new WicketLinkResolver());
 		pageSettings.addComponentResolver(new WicketMessageResolver());
 		pageSettings.addComponentResolver(new FragmentResolver());
+		pageSettings.addComponentResolver(new AutoComponentResolver());
+
+		getMarkupSettings().addMarkupLoadListener(new WicketHeaderLoader());
 
 		// Install button image resource factory
 		getResourceSettings().addResourceFactory("buttonFactory",

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/Component.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/Component.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/Component.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/Component.java Sat Nov  4 05:47:06 2006
@@ -47,7 +47,7 @@
 import wicket.markup.MarkupNotFoundException;
 import wicket.markup.MarkupStream;
 import wicket.markup.html.IHeaderContributor;
-import wicket.markup.html.internal.HeaderContainer;
+import wicket.markup.html.IHeaderResponse;
 import wicket.model.IAssignmentAwareModel;
 import wicket.model.IInheritableModel;
 import wicket.model.IModel;
@@ -711,8 +711,14 @@
 	}
 
 	/**
-	 * Gets the markup fragment associated with the component. Except for Pages
-	 * it is assumed that the first markup element of the fragment is a tag.
+	 * Gets the markup fragment associated with the component. Except for Pages,
+	 * Panels and Borders, it is assumed that the first markup element of the 
+	 * fragment is a tag.
+	 * <p>
+	 * If the markup fragment has been determined previously, the transient cache
+	 * of the Component is returned. Else, the parent container will be asked to 
+	 * provide the markup for its child and the object returned will be cached
+	 * for later re-use.
 	 * 
 	 * @return markup fragment.
 	 */
@@ -730,17 +736,17 @@
 					+ getId());
 		}
 
-		MarkupFragment markupFragment = parent.getMarkupFragment(getId());
-		if (markupFragment == null)
+		this.markupFragment = parent.getMarkupFragment(getId());
+		if (this.markupFragment == null)
 		{
 			throw new MarkupNotFoundException("Unable to find markup for Component: " + getId());
 		}
 
 		// Attached behaviors provided by the ComponentTag which
 		// one of the markup handlers might have added.
-		if (markupFragment.size() > 0)
+		if (this.markupFragment.size() > 0)
 		{
-			final ComponentTag tag = markupFragment.getTag();
+			final ComponentTag tag = this.markupFragment.getTag();
 
 			// add any behaviors attached to the component tag
 			if ((tag != null) && tag.hasBehaviors())
@@ -1955,30 +1961,22 @@
 	 * the head section. Make sure that all attached behaviors are asked as
 	 * well.
 	 * 
-	 * @param container
-	 *            The HtmlHeaderContainer
+	 * @param response
+	 *            The response object to write the output to
 	 */
-	public void renderHead(final HeaderContainer container)
+	public void renderHead(final IHeaderResponse response)
 	{
-		if (isHeadRendered() == false)
+		if ((isVisible() == true) && (isHeadRendered() == false))
 		{
-			// first try whether the component can contribute something?
-			if (this instanceof IHeaderContributor)
-			{
-				((IHeaderContributor)this).renderHead(container.getHeaderResponse());
-			}
-
 			// Ask all behaviors if they have something to contribute to the
 			// header or body onLoad tag.
 			if (this.behaviors != null)
 			{
-				final Iterator<IBehavior> iter = this.behaviors.iterator();
-				while (iter.hasNext())
+				for (IBehavior behavior : this.behaviors)
 				{
-					IBehavior behavior = iter.next();
 					if (behavior instanceof IHeaderContributor)
 					{
-						((IHeaderContributor)behavior).renderHead(container.getHeaderResponse());
+						((IHeaderContributor)behavior).renderHead(response);
 					}
 				}
 			}

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/MarkupContainer.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/MarkupContainer.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/MarkupContainer.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/MarkupContainer.java Sat Nov  4 05:47:06 2006
@@ -29,6 +29,7 @@
 import org.apache.commons.logging.LogFactory;
 
 import wicket.annot.AnnotationUtils;
+import wicket.annot.OnAfterRender;
 import wicket.feedback.IFeedback;
 import wicket.markup.ComponentTag;
 import wicket.markup.MarkupElement;
@@ -36,6 +37,8 @@
 import wicket.markup.MarkupFragment;
 import wicket.markup.MarkupNotFoundException;
 import wicket.markup.MarkupStream;
+import wicket.markup.html.IHeaderResponse;
+import wicket.markup.parser.onLoadListener.IMarkupLoadListener;
 import wicket.markup.resolver.IComponentResolver;
 import wicket.model.IInheritableModel;
 import wicket.model.IModel;
@@ -91,7 +94,7 @@
  * @see MarkupStream
  * @author Jonathan Locke
  */
-public abstract class MarkupContainer<T> extends Component<T>
+public abstract class MarkupContainer<T> extends Component<T> implements Iterable<Component>
 {
 	private static final long serialVersionUID = 1L;
 
@@ -408,12 +411,8 @@
 		AnnotationUtils.invokeOnDetachListeners(this);
 
 		// Loop through child components
-		final Iterator iter = iterator();
-		while (iter.hasNext())
+		for (Component child : this)
 		{
-			// Get next child
-			final Component child = (Component)iter.next();
-
 			// Call end request on the child
 			child.internalDetach();
 		}
@@ -844,6 +843,18 @@
 
 		return this.associatedMarkup;
 	}
+	
+	/**
+	 * Make sure changes to the locale and style are handled properly
+	 * 
+	 * @see wicket.Component#onAfterRender()
+	 */
+	@OnAfterRender
+	protected void onAfterRender()
+	{
+		this.associatedMarkup = null;
+		super.onAfterRender();
+	}
 
 	/**
 	 * Components which whish to analyze the markup and automatically add
@@ -857,6 +868,11 @@
 	 */
 	protected void onAssociatedMarkupLoaded(final MarkupFragment markup)
 	{
+		// Call all register load listeners
+		for (IMarkupLoadListener listener : getApplication().getMarkupSettings().getMarkupLoadListeners())
+		{
+			listener.onAssociatedMarkupLoaded(this, markup);
+		}
 	}
 
 	/**
@@ -1384,5 +1400,22 @@
 	public boolean isTransparentResolver()
 	{
 		return false;
+	}
+
+	/**
+	 * @see wicket.Component#renderHead(wicket.markup.html.IHeaderResponse)
+	 */
+	@Override
+	public void renderHead(final IHeaderResponse response)
+	{
+		if (isVisible())
+		{
+			super.renderHead(response);
+
+			for (Component child : this)
+			{
+				child.renderHead(response);
+			}
+		}
 	}
 }

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/Page.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/Page.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/Page.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/Page.java Sat Nov  4 05:47:06 2006
@@ -365,7 +365,7 @@
 				throw new MarkupException(
 						"The component "
 								+ component
-								+ " has the same wicket:id as another component already added at the same level");
+								+ " has the same wicket:id as another component already rendered at the same level");
 			}
 			if (log.isDebugEnabled())
 			{

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/ajax/AjaxRequestTarget.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/ajax/AjaxRequestTarget.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/ajax/AjaxRequestTarget.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/ajax/AjaxRequestTarget.java Sat Nov  4 05:47:06 2006
@@ -18,13 +18,10 @@
  */
 package wicket.ajax;
 
-import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -32,15 +29,13 @@
 import wicket.Application;
 import wicket.Component;
 import wicket.IRequestTarget;
-import wicket.MarkupContainer;
 import wicket.Page;
 import wicket.RequestCycle;
 import wicket.Response;
-import wicket.markup.html.internal.HeaderContainer;
-import wicket.markup.html.internal.HtmlHeaderContainer;
-import wicket.markup.parser.filter.HtmlHeaderSectionHandler;
+import wicket.markup.html.IHeaderResponse;
+import wicket.markup.html.internal.HeaderResponse;
 import wicket.protocol.http.WebResponse;
-import wicket.util.string.AppendingStringBuffer;
+import wicket.response.StringResponse;
 import wicket.util.string.Strings;
 
 /**
@@ -56,8 +51,8 @@
  * an id attribute in the generated markup that is equal to the value retrieved
  * from Component#getMarkupId(). This can be accomplished by either setting the
  * id attribute in the html template, or using an attribute modifier that will
- * add the attribute with value Component#getMarkupId() to the tag ( such as
- * MarkupIdSetter )
+ * add the attribute with value Component#getMarkupId() to the tag (such as
+ * MarkupIdSetter)
  * <p>
  * Any javascript that needs to be evaluater on the client side can be added
  * using AjaxRequestTarget#addJavascript(String). For example, this feature can
@@ -70,130 +65,24 @@
  */
 public class AjaxRequestTarget implements IRequestTarget
 {
-	/**
-	 * Response that uses an encoder to encode its contents
-	 * 
-	 * @author Igor Vaynberg (ivaynberg)
-	 */
-	private final class EncodingResponse extends WebResponse
-	{
-		private final AppendingStringBuffer buffer = new AppendingStringBuffer(256);
-
-		private boolean escaped = false;
-
-		private final Response originalResponse;
-
-		/**
-		 * Construct.
-		 * 
-		 * @param originalResponse
-		 */
-		public EncodingResponse(Response originalResponse)
-		{
-			this.originalResponse = originalResponse;
-		}
-
-		/**
-		 * @see wicket.Response#encodeURL(CharSequence)
-		 */
-		@Override
-		public CharSequence encodeURL(CharSequence url)
-		{
-			return originalResponse.encodeURL(url);
-		}
-
-		/**
-		 * @return contents of the response
-		 */
-		public CharSequence getContents()
-		{
-			return buffer;
-		}
-
-		/**
-		 * NOTE: this method is not supported
-		 * 
-		 * @see wicket.Response#getOutputStream()
-		 */
-		@Override
-		public OutputStream getOutputStream()
-		{
-			throw new UnsupportedOperationException("Cannot get output stream on StringResponse");
-		}
-
-		/**
-		 * @return true if any escaping has been performed, false otherwise
-		 */
-		public boolean isContentsEncoded()
-		{
-			return escaped;
-		}
-
-		/**
-		 * Resets the response to a clean state so it can be reused to save on
-		 * garbage.
-		 */
-		@Override
-		public void reset()
-		{
-			buffer.clear();
-			escaped = false;
-
-		}
-
-		/**
-		 * @see wicket.Response#write(CharSequence)
-		 */
-		@Override
-		public void write(CharSequence cs)
-		{
-			String string = cs.toString();
-			if (needsEncoding(string))
-			{
-				string = encode(string);
-				escaped = true;
-				buffer.append(string);
-			}
-			else
-			{
-				buffer.append(cs);
-			}
-		}
-
-	}
-
-	private static final Log LOG = LogFactory.getLog(AjaxRequestTarget.class);
+	private static final Log Log = LogFactory.getLog(AjaxRequestTarget.class);
 
+	/** */
 	private final List<String> appendJavascripts = new ArrayList<String>();
 
-	/**
-	 * create a response for component body and javascript that will escape
-	 * output to make it safe to use inside a CDATA block
-	 */
-	private final EncodingResponse encodingBodyResponse;
-
-	/**
-	 * Response for header contributon that will escape output to make it safe
-	 * to use inside a CDATA block
-	 */
-	private final EncodingResponse encodingHeaderResponse;
+	/** */
+	private final List<String> prependJavascripts = new ArrayList<String>();
 
 	/** the component instances that will be rendered */
 	private final Map<String, Component> markupIdToComponent = new HashMap<String, Component>();
 
-	private final List<String> prependJavascripts = new ArrayList<String>();
-
 	/**
 	 * Constructor
 	 */
 	public AjaxRequestTarget()
 	{
-		Response response = RequestCycle.get().getResponse();
-		encodingBodyResponse = new EncodingResponse(response);
-		encodingHeaderResponse = new EncodingResponse(response);
 	}
 
-
 	/**
 	 * Adds a component to the list of components to be rendered
 	 * 
@@ -255,7 +144,6 @@
 	{
 	}
 
-
 	/**
 	 * @see java.lang.Object#equals(java.lang.Object)
 	 */
@@ -272,7 +160,6 @@
 		return false;
 	}
 
-
 	/**
 	 * @see wicket.IRequestTarget#getLock(RequestCycle)
 	 */
@@ -315,6 +202,7 @@
 	 */
 	public final void respond(final RequestCycle requestCycle)
 	{
+		final WebResponse response = (WebResponse)requestCycle.getResponse();
 		try
 		{
 			final Application app = Application.get();
@@ -323,7 +211,6 @@
 			final String encoding = app.getRequestCycleSettings().getResponseRequestEncoding();
 
 			// Set content type based on markup type for page
-			WebResponse response = (WebResponse)requestCycle.getResponse();
 			response.setCharacterEncoding(encoding);
 			response.setContentType("text/xml; charset=" + encoding);
 
@@ -344,13 +231,12 @@
 				respondInvocation(response, js);
 			}
 
-			Iterator<Entry<String, Component>> it = markupIdToComponent.entrySet().iterator();
-			while (it.hasNext())
+			for (Map.Entry<String, Component> entry : markupIdToComponent.entrySet())
 			{
-				final Map.Entry<String, Component> entry = it.next();
 				final Component component = entry.getValue();
 				final String markupId = entry.getKey();
-				
+
+				// render the component
 				respondComponent(response, markupId, component);
 			}
 
@@ -366,9 +252,11 @@
 			// log the error but output nothing in the response, parse failure
 			// of response will cause any javascript failureHandler to be
 			// invoked
-			LOG.error("Error while responding to an AJAX request: " + toString(), ex);
-			System.out.println(ex.getMessage());
-			ex.printStackTrace();
+			Log.error("Error while responding to an AJAX request: " + toString(), ex);
+		}
+		finally
+		{
+			requestCycle.setResponse(response);
 		}
 	}
 
@@ -442,13 +330,7 @@
 		}
 
 		component.setOutputMarkupId(true);
-
-		// substitute our encoding response for the real one so we can capture
-		// component's markup in a manner safe for transport inside CDATA block
-		final Response originalResponse = response;
-		encodingBodyResponse.reset();
-		RequestCycle.get().setResponse(encodingBodyResponse);
-
+	
 		// Initialize temporary variables
 		final Page page = component.getPage();
 		if (page == null)
@@ -461,37 +343,40 @@
 		page.setVersioned(false);
 
 		page.startComponentRender(component);
-		component.renderComponent();
 		
+		// render any associated headers of the component
 		respondHeaderContribution(response, component);
-		
-		page.endComponentRender(component);
 
-		page.setVersioned(versioned);
+		Response encodingResponse = new StringResponse();
+		try
+		{
+			RequestCycle.get().setResponse(encodingResponse);
+			
+			component.renderComponent();
+		}
+		finally
+		{
+			// Restore original response
+			RequestCycle.get().setResponse(response);
+		}
 
-		// Restore original response
-		RequestCycle.get().setResponse(originalResponse);
+		page.endComponentRender(component);
+		page.setVersioned(versioned);
 
 		response.write("<component id=\"");
 		response.write(markupId);
 		response.write("\" ");
-		if (encodingBodyResponse.isContentsEncoded())
+		if (needsEncoding(encodingResponse.toString()))
 		{
 			response.write(" encoding=\"");
 			response.write(getEncodingName());
 			response.write("\" ");
 		}
 		response.write("><![CDATA[");
-		response.write(encodingBodyResponse.getContents());
+		response.write(encodingResponse.toString());
 		response.write("]]></component>");
-
-		encodingBodyResponse.reset();
-
-
 	}
 
-	private HeaderContainer header = null;
-
 	/**
 	 * 
 	 * @param response
@@ -499,45 +384,24 @@
 	 */
 	private void respondHeaderContribution(final Response response, final Component component)
 	{
-		if (header == null)
+		Response encodingResponse = new StringResponse();
+		
+		try
 		{
-			header = new HtmlHeaderContainer(component.getPage(),
-					HtmlHeaderSectionHandler.HEADER_ID);
+			final IHeaderResponse headerResponse = new HeaderResponse(encodingResponse);
+			RequestCycle.get().setResponse(headerResponse.getResponse());
+			component.renderHead(headerResponse);
 		}
-
-		Response oldResponse = RequestCycle.get().setResponse(encodingHeaderResponse);
-
-		encodingHeaderResponse.reset();
-
-		component.renderHead(header);		
-		
-		if (component instanceof MarkupContainer)
+		finally
 		{
-			((MarkupContainer)component).visitChildren(new Component.IVisitor()
-			{
-				public Object component(Component component)
-				{
-					if (component.isVisible())
-					{
-						component.renderHead(header);						
-						
-						return CONTINUE_TRAVERSAL;
-					}
-					else
-					{
-						return CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
-					}
-				}
-			});
+			RequestCycle.get().setResponse(response);
 		}
 
-		RequestCycle.get().setResponse(oldResponse);
-
-		if (encodingHeaderResponse.getContents().length() != 0)
+		if (encodingResponse.toString().length() != 0)
 		{
 			response.write("<header-contribution");
 
-			if (encodingHeaderResponse.isContentsEncoded())
+			if (needsEncoding(encodingResponse.toString()))
 			{
 				response.write(" encoding=\"");
 				response.write(getEncodingName());
@@ -545,14 +409,10 @@
 			}
 
 			// we need to write response as CDATA and parse it on client,
-			// because
-			// konqueror crashes when there is a <script> element
+			// because konqueror crashes when there is a <script> element
 			response.write("><![CDATA[<head xmlns:wicket=\"http://wicket.sourceforge.net\">");
-
-			response.write(encodingHeaderResponse.getContents());
-
+			response.write(encodingResponse.toString());
 			response.write("</head>]]>");
-
 			response.write("</header-contribution>");
 		}
 	}
@@ -586,7 +446,5 @@
 		response.write(javascript);
 		response.write("]]>");
 		response.write("</evaluate>");
-
-		encodingBodyResponse.reset();
 	}
 }

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/MarkupCache.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/MarkupCache.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/MarkupCache.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/MarkupCache.java Sat Nov  4 05:47:06 2006
@@ -331,6 +331,7 @@
 			// add the markup to the cache
 			if (markupResourceStream.getCacheKey() != null)
 			{
+				markup.makeImmutable();
 				markupCache.put(markupResourceStream.getCacheKey(), markup);
 			}
 

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/MarkupFragment.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/MarkupFragment.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/MarkupFragment.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/MarkupFragment.java Sat Nov  4 05:47:06 2006
@@ -322,6 +322,12 @@
 	 */
 	public final void addMarkupElement(final int pos, final MarkupElement markupElement)
 	{
+//		if ((markupElement instanceof ComponentTag) && (pos > 0) && (pos < size()))
+//		{
+//			throw new WicketRuntimeException(
+//					"ComponentTag's within a MarkupFragment can only be at the first or last position: "
+//							+ markupElement.toUserDebugString());
+//		}
 		this.markupElements.add(pos, markupElement);
 	}
 
@@ -334,6 +340,17 @@
 	public final MarkupElement removeMarkupElement(final int index)
 	{
 		return this.markupElements.remove(index);
+	}
+
+	/**
+	 * Remove the element from the list
+	 * 
+	 * @param element
+	 * @return true, if removed
+	 */
+	public final boolean removeMarkupElement(final MarkupElement element)
+	{
+		return this.markupElements.remove(element);
 	}
 
 	/**

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/MarkupParser.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/MarkupParser.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/MarkupParser.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/MarkupParser.java Sat Nov  4 05:47:06 2006
@@ -75,6 +75,9 @@
 	/** The root markup fragment of the markup being parsed */
 	private final MarkupFragment rootFragment;
 
+	/** The current markup fragment in process */
+	private MarkupFragment currentFragment;
+
 	/** True if comments are to be removed */
 	private boolean stripComments;
 
@@ -165,11 +168,9 @@
 	}
 
 	/**
-	 * Like internal filters, user provided filters might need access to the
-	 * markup as well.
+	 * Gets the Markup of the resource
 	 * 
 	 * @return The markup resource stream
-	 * @deprecated Since 2.0 please use getMarkupFragment().getMarkup() instead
 	 */
 	public final IMarkup getMarkup()
 	{
@@ -178,13 +179,14 @@
 
 	/**
 	 * Like internal filters, user provided filters might need access to the
-	 * markup as well.
+	 * markup as well. But be careful, out of the fragment tree it is always the
+	 * one currently in process.
 	 * 
 	 * @return The markup resource stream
 	 */
-	public final MarkupFragment getMarkupFragment()
+	public final MarkupFragment getCurrentMarkupFragment()
 	{
-		return this.rootFragment;
+		return this.currentFragment;
 	}
 
 	/**
@@ -196,28 +198,27 @@
 		// Chain together all the different markup filters and configure them
 		this.markupFilterChain = xmlParser;
 
-		registerMarkupFilter(new WicketTagIdentifier(markup));
+		registerMarkupFilter(new WicketTagIdentifier(this.markup));
 		registerMarkupFilter(new TagTypeHandler());
 		registerMarkupFilter(new HtmlHandler());
 		registerMarkupFilter(new WicketRemoveTagHandler());
 		registerMarkupFilter(new WicketLinkTagHandler());
-		registerMarkupFilter(new WicketNamespaceHandler(markup));
+		registerMarkupFilter(new WicketNamespaceHandler(this.markup));
 
 		// Provided the wicket component requesting the markup is known ...
-		final MarkupResourceStream resource = markup.getResource();
+		final MarkupResourceStream resource = this.markup.getResource();
 		if (resource != null)
 		{
 			final ContainerInfo containerInfo = resource.getContainerInfo();
 			if (containerInfo != null)
 			{
 				registerMarkupFilter(new WicketMessageTagHandler());
-
 				registerMarkupFilter(new BodyOnLoadHandler());
 
 				// Pages require additional handlers
 				if (Page.class.isAssignableFrom(containerInfo.getContainerClass()))
 				{
-					registerMarkupFilter(new HtmlHeaderSectionHandler(this.rootFragment));
+					registerMarkupFilter(new HtmlHeaderSectionHandler(this));
 				}
 
 				registerMarkupFilter(new HeadForceTagIdHandler(containerInfo.getContainerClass()));
@@ -285,12 +286,12 @@
 	private MarkupFragment parseMarkup()
 	{
 		final Stack<MarkupFragment> fragmentStack = new Stack<MarkupFragment>();
-		MarkupFragment fragment = this.rootFragment;
-		
+		this.currentFragment = this.rootFragment;
+
 		try
 		{
 			// allways remember the latest index (size)
-			int size = fragment.size();
+			int size = currentFragment.size();
 
 			// Loop through tags
 			for (ComponentTag tag; null != (tag = (ComponentTag)this.markupFilterChain.nextTag());)
@@ -324,7 +325,7 @@
 
 						// Make sure you add it at the correct location.
 						// IMarkupFilters might have added elements as well.
-						fragment.addMarkupElement(size, new RawMarkup(rawMarkup));
+						currentFragment.addMarkupElement(size, new RawMarkup(rawMarkup));
 					}
 
 					if (add)
@@ -335,29 +336,29 @@
 						{
 							if (tag.isOpen() || tag.isOpenClose())
 							{
-								fragmentStack.push(fragment);
+								fragmentStack.push(currentFragment);
 								MarkupFragment newFragment = new MarkupFragment(this.markup);
-								fragment.addMarkupElement(newFragment);
-								fragment = newFragment;
+								currentFragment.addMarkupElement(newFragment);
+								currentFragment = newFragment;
 							}
-							
-							fragment.addMarkupElement(tag);
+
+							currentFragment.addMarkupElement(tag);
 							if (tag.isClose() || tag.isOpenClose() || tag.hasNoCloseTag())
 							{
-								fragment = fragmentStack.pop();
+								currentFragment = fragmentStack.pop();
 							}
 						}
 					}
 					else if (tag.isModified())
 					{
-						fragment.addMarkupElement(new RawMarkup(tag.toCharSequence()));
+						currentFragment.addMarkupElement(new RawMarkup(tag.toCharSequence()));
 					}
 
 					this.xmlParser.setPositionMarker();
 				}
 
 				// allways remember the latest index (size)
-				size = fragment.size();
+				size = currentFragment.size();
 			}
 		}
 		catch (final ParseException ex)
@@ -366,14 +367,14 @@
 			final CharSequence text = this.xmlParser.getInputFromPositionMarker(-1);
 			if (text.length() > 0)
 			{
-				fragment.addMarkupElement(new RawMarkup(text));
+				currentFragment.addMarkupElement(new RawMarkup(text));
 			}
 
 			this.markup.setEncoding(this.xmlParser.getEncoding());
 			this.markup.setXmlDeclaration(this.xmlParser.getXmlDeclaration());
 
 			// Create a MarkupStream and position it at the error location
-			MarkupElement element = fragment.get(fragment.size() - 1);
+			MarkupElement element = currentFragment.get(currentFragment.size() - 1);
 			MarkupStream markupStream = new MarkupStream(this.rootFragment);
 			while (markupStream.hasMore())
 			{
@@ -382,7 +383,7 @@
 					break;
 				}
 			}
-			
+
 			throw new MarkupException(markupStream, ex.getMessage(), ex);
 		}
 
@@ -402,26 +403,23 @@
 				rawMarkup = compressWhitespace(rawMarkup);
 			}
 
-			fragment.addMarkupElement(new RawMarkup(rawMarkup));
+			currentFragment.addMarkupElement(new RawMarkup(rawMarkup));
 		}
 
-		// Do we have unclosed tags in the markup? Re-balance the markup tree 
+		// Do we have unclosed tags in the markup? Re-balance the markup tree
 		if (fragmentStack.size() > 0)
 		{
-			fragment.handleUnclosedTags();
-			fragment = this.rootFragment;
+			currentFragment.handleUnclosedTags();
+			currentFragment = this.rootFragment;
 		}
-		
+
 		// remove "empty" root fragment
-		if ((fragment.size() == 1) && (fragment.get(0) instanceof MarkupFragment))
+		if ((currentFragment.size() == 1) && (currentFragment.get(0) instanceof MarkupFragment))
 		{
-			fragment = (MarkupFragment)fragment.get(0);
+			currentFragment = (MarkupFragment)currentFragment.get(0);
 		}
 		
-		// Make all tags immutable and the list of elements unmodifable
-		fragment.makeImmutable();
-
-		return fragment;
+		return currentFragment;
 	}
 
 	/**

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/WebMarkupContainerWithAssociatedMarkup.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/WebMarkupContainerWithAssociatedMarkup.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/WebMarkupContainerWithAssociatedMarkup.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/WebMarkupContainerWithAssociatedMarkup.java Sat Nov  4 05:47:06 2006
@@ -18,20 +18,15 @@
  */
 package wicket.markup.html;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
 import wicket.Component;
 import wicket.MarkupContainer;
-import wicket.Response;
-import wicket.WicketRuntimeException;
-import wicket.markup.ComponentTag;
-import wicket.markup.MarkupElement;
-import wicket.markup.MarkupException;
 import wicket.markup.MarkupFragment;
 import wicket.markup.MarkupStream;
-import wicket.markup.html.internal.HeaderContainer;
-import wicket.markup.html.internal.HeaderPartContainer;
+import wicket.markup.html.internal.WicketHeadContainer;
 import wicket.model.IModel;
-import wicket.response.NullResponse;
-import wicket.util.lang.Classes;
 
 /**
  * A WebMarkupContainer, such as Panel or Border, with an associated markup
@@ -44,6 +39,8 @@
  */
 public class WebMarkupContainerWithAssociatedMarkup<T> extends WebMarkupContainer<T>
 {
+	private static final Log log = LogFactory.getLog(WebMarkupContainerWithAssociatedMarkup.class);
+
 	private static final long serialVersionUID = 1L;
 
 	/** True if body onLoad attribute modifiers have been attached */
@@ -52,12 +49,15 @@
 	/** <wicket:head> is only allowed before <body>, </head>, <wicket:panel> etc. */
 	private boolean noMoreWicketHeadTagsAllowed = false;
 
+	/** True, if headers have been added */
+	private transient boolean headersInitialized;
+
 	/**
 	 * @see Component#Component(MarkupContainer,String)
 	 */
 	public WebMarkupContainerWithAssociatedMarkup(MarkupContainer parent, final String id)
 	{
-		super(parent, id);
+		this(parent, id, null);
 	}
 
 	/**
@@ -67,6 +67,8 @@
 			IModel<T> model)
 	{
 		super(parent, id, model);
+
+		getAssociatedMarkup(true);
 	}
 
 	/**
@@ -75,264 +77,38 @@
 	 * @param id
 	 * @return MarkupFragment
 	 */
+	@Override
 	public MarkupFragment getMarkupFragment(final String id)
 	{
-		return getMarkupFragment().getChildFragment(id, true);
-	}
-
-	/**
-	 * Create a new HeaderPartContainer. Users may wish to do that to
-	 * implemented more sophisticated header scoping stragegies.
-	 * 
-	 * @param parent
-	 *            The parent of this component
-	 * 
-	 * @param id
-	 *            The header component's id
-	 * @param scope
-	 *            The default scope of the header
-	 * @return The new HeaderPartContainer
-	 */
-	public HeaderPartContainer newHeaderPartContainer(MarkupContainer parent, final String id,
-			final String scope)
-	{
-		return new HeaderPartContainer(parent, id, this, scope);
-	}
-
-	/**
-	 * Called by components like Panel and Border which have associated Markup
-	 * and which may have a &lt;wicket:head&gt; tag.
-	 * <p>
-	 * Whereas 'this' might be a Panel or Border, the HtmlHeaderContainer
-	 * parameter has been added to the Page as a container for all headers any
-	 * of its components might wish to contribute.
-	 * <p>
-	 * The headers contributed are rendered in the standard way.
-	 * 
-	 * @param htmlContainer
-	 *            The HtmlHeaderContainer added to the Page
-	 */
-	protected final void renderHeadFromAssociatedMarkupFile(final HeaderContainer htmlContainer)
-	{
-		// Gracefully getAssociateMarkupStream. Throws no exception in case
-		// markup is not found
-		final MarkupFragment markupFragment = getAssociatedMarkup(false);
-
-		// No associated markup => no header section
-		if (markupFragment == null)
-		{
-			return;
-		}
-
-		final MarkupStream markupStream = new MarkupStream(markupFragment);
-
-		// Position pointer at current (first) header
-		this.noMoreWicketHeadTagsAllowed = false;
-		while (nextHeaderMarkup(markupStream) != -1)
-		{
-			Class markupClass = markupStream.getTag().getMarkupClass();
-			if (markupClass == null)
-			{
-				markupClass = markupStream.getContainerClass();
-			}
-			// Create a HeaderPartContainer and associate the markup
-			final HeaderPartContainer headerPart = getHeaderPart(htmlContainer, markupClass,
-					markupStream.getCurrentIndex());
-			if (headerPart != null)
-			{
-				// A component's header section must only be added once,
-				// no matter how often the same Component has been added
-				// to the page or any other container in the hierachy.
-				if (htmlContainer.okToRenderComponent(headerPart.getScope(), headerPart.getId()))
-				{
-					headerPart.autoAdded();
-
-					// Check if the Panel/Border requires some <body
-					// onload=".."> attribute to be copied to the page's body
-					// tag.
-					if (checkedBody == false)
-					{
-						checkedBody = true;
-						checkBodyOnLoad();
-					}
-				}
-				else
-				{
-					// TODO Performance: I haven't found a more efficient
-					// solution yet.
-					// Already added but all the components in this header part
-					// must be touched (that they are rendered)
-					Response response = getRequestCycle().getResponse();
-					try
-					{
-						getRequestCycle().setResponse(NullResponse.getInstance());
-						headerPart.autoAdded();
-					}
-					finally
-					{
-						getRequestCycle().setResponse(response);
-					}
-				}
-			}
-
-			// Position the stream after <wicket:head>
-			markupStream.skipComponent();
-		}
-	}
-
-	/**
-	 * Check if the Panel/Border requires some <body onload=".."> attribute to
-	 * be copied to the page's body tag.
-	 */
-	private void checkBodyOnLoad()
-	{
-		// Gracefully getAssociateMarkupStream. Throws no exception in case
-		// markup is not found
-		final MarkupStream associatedMarkupStream = new MarkupStream(getAssociatedMarkup(false));
-
-		// No associated markup => no body tag
-		if (associatedMarkupStream == null)
-		{
-			return;
-		}
-
-		// Remember the current position within markup, where we need to
-		// go back to, at the end.
-		int index = associatedMarkupStream.getCurrentIndex();
-
-		try
+		MarkupFragment fragment = getMarkupFragment().getChildFragment(id, false);
+		if (fragment != null)
 		{
-			associatedMarkupStream.setCurrentIndex(0);
-			while (associatedMarkupStream.hasMoreComponentTags())
-			{
-				final ComponentTag tag = associatedMarkupStream.getTag();
-				if (tag.isBodyTag())
-				{
-					final CharSequence onLoad = tag.getString("onload");
-					if (onLoad != null)
-					{
-						// Attach an AttributeModifier to the body container
-						// which appends the new value to the onLoad
-						// attribute
-						getWebPage().getBodyContainer().addOnLoadModifier(onLoad, this);
-					}
-
-					// There can only be one body tag
-					break;
-				}
-			}
-		}
-		finally
-		{
-			// Make sure we return to the orginal position in the markup
-			associatedMarkupStream.setCurrentIndex(index);
+			return fragment;
 		}
+		
+		return getAssociatedMarkup(true).getChildFragment(id, true);
 	}
 
 	/**
-	 * Gets the header part of the Panel/Border. Returns null if it doesn't have
-	 * a header tag.
-	 * 
-	 * @param parent
-	 *            The parent of this component
-	 * 
-	 * @param index
-	 *            A unique index
-	 * @param markupClass
-	 *            The java class the wicket:head tag is directly associated with
-	 * @return the header part for this panel/border or null if it doesn't have
-	 *         a wicket:head tag.
+	 * @see wicket.Component#renderHead(wicket.markup.html.IHeaderResponse)
 	 */
-	private final HeaderPartContainer getHeaderPart(MarkupContainer parent,
-			final Class markupClass, final int index)
+	@Override
+	public void renderHead(final IHeaderResponse response)
 	{
-		// Gracefully getAssociateMarkupStream. Throws no exception in case
-		// markup is not found
-		final MarkupStream markupStream = new MarkupStream(getAssociatedMarkup(false));
-
-		// Position markup stream at beginning of header tag
-		markupStream.setCurrentIndex(index);
-
-		// Create a HtmlHeaderContainer for the header tag found
-		final ComponentTag tag = markupStream.getTag(false);
-		if ((tag != null) && tag.isWicketHeadTag())
+		if (isVisible())
 		{
-			// found <wicket:head>. Create a unique id for the
-			// HtmlHeaderContainer to be created
-			final String headerId = Component.AUTO_COMPONENT_PREFIX
-					+ Classes.simpleName(markupClass) + getVariation() + "Header" + index;
-
-			// Create the header container and associate the markup with
-			// it
-			String scope = tag.getAttributes().getString(
-					markupStream.getWicketNamespace() + ":scope");
-			final HeaderPartContainer headerContainer = newHeaderPartContainer(parent, headerId,
-					scope);
-			headerContainer.setMyMarkupStream(markupStream);
-			headerContainer.setRenderBodyOnly(true);
-
-			// The container does have a header component
-			return headerContainer;
-		}
-
-		throw new WicketRuntimeException("Programming error: expected a WicketTag: "
-				+ markupStream.toString());
-	}
-
-	/**
-	 * 
-	 * @param associatedMarkupStream
-	 * @return xxx
-	 */
-	private final int nextHeaderMarkup(final MarkupStream associatedMarkupStream)
-	{
-		// No associated markup => no header section
-		if (associatedMarkupStream == null)
-		{
-			return -1;
-		}
-
-		// Scan the markup for <wicket:head>.
-		MarkupElement elem = associatedMarkupStream.get();
-		while (elem != null)
-		{
-			if (elem instanceof ComponentTag)
+			// Load the markup and create the header containers if necessary
+			getAssociatedMarkup(true);
+			
+			for (Component child : this)
 			{
-				ComponentTag tag = (ComponentTag)elem;
-				if (tag.isOpen() && tag.isWicketHeadTag())
-				{
-					if (this.noMoreWicketHeadTagsAllowed == true)
-					{
-						throw new MarkupException(
-								"<wicket:head> tags are only allowed before <body>, </head>, <wicket:panel> etc. tag. Component: "
-										+ this.toString());
-					}
-					return associatedMarkupStream.getCurrentIndex();
-				}
-				else if (this.noMoreWicketHeadTagsAllowed == false)
+				if (child instanceof WicketHeadContainer)
 				{
-					// wicket:head must be before border, panel or extend
-					if (tag.isOpen()
-							&& (tag.isPanelTag() || tag.isBorderTag() || tag.isExtendTag()))
-					{
-						this.noMoreWicketHeadTagsAllowed = true;
-					}
-					// wicket:head must be before </head>
-					else if (tag.isClose() && tag.isHeadTag())
-					{
-						this.noMoreWicketHeadTagsAllowed = true;
-					}
-					// wicket:head must be before <body>
-					else if (tag.isOpen() && tag.isBodyTag())
-					{
-						this.noMoreWicketHeadTagsAllowed = true;
-					}
+					child.render(new MarkupStream(child.getMarkupFragment()));
 				}
 			}
-			elem = associatedMarkupStream.next();
+			
+			super.renderHead(response);
 		}
-
-		// No (more) wicket:head found
-		return -1;
 	}
 }

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/WebPage.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/WebPage.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/WebPage.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/WebPage.java Sat Nov  4 05:47:06 2006
@@ -37,11 +37,13 @@
 import wicket.markup.ComponentTag;
 import wicket.markup.MarkupFragment;
 import wicket.markup.MarkupStream;
+import wicket.markup.html.internal.HeaderContainer;
 import wicket.markup.html.internal.HtmlBodyContainer;
 import wicket.markup.html.internal.HtmlHeaderContainer;
 import wicket.markup.html.link.BookmarkablePageLink;
 import wicket.markup.parser.filter.BodyOnLoadHandler;
 import wicket.markup.parser.filter.HtmlHeaderSectionHandler;
+import wicket.markup.parser.filter.WicketTagIdentifier;
 import wicket.model.IModel;
 import wicket.model.Model;
 import wicket.protocol.http.WebRequest;
@@ -86,6 +88,12 @@
 	/** log. */
 	private static final Log log = LogFactory.getLog(WebPage.class);
 
+	static
+	{
+		// register "wicket:head"
+		WicketTagIdentifier.registerWellKnownTagName("head");
+	}
+
 	/** meta data key for missing body tags logging. */
 	private static final MetaDataKey PAGEMAP_ACCESS_MDK = new MetaDataKey(
 			PageMapAccessMetaData.class)
@@ -172,12 +180,23 @@
 	 * 
 	 * @return The body container
 	 */
-	public BodyContainer getBodyContainer()
+	public final BodyContainer getBodyContainer()
 	{
 		return bodyContainer;
 	}
 
 	/**
+	 * Gets the container for the &lt;head&gt; tag, which will also render
+	 * the &lt;wicket:head&gt; tags.
+	 * 
+	 * @return The header container
+	 */
+	public final HeaderContainer getHeaderContainer()
+	{
+		return (HeaderContainer)get(HtmlHeaderSectionHandler.HEADER_ID);
+	}
+	
+	/**
 	 * Gets the markup type for a WebPage, which is "html" by default. Support
 	 * for pages in another markup language, such as VXML, would require the
 	 * creation of a different Page subclass in an appropriate package under
@@ -264,48 +283,40 @@
 	 */
 	protected void onAssociatedMarkupLoaded(final MarkupFragment markup)
 	{
-		// Add a Body container if the associated markup contains a <body> tag
-		// get markup stream gracefully
-		MarkupStream markupStream = new MarkupStream(markup);
-		
-		// The <body> container. It can be accessed, replaced
-		// and attribute modifiers can be attached. <body> tags without
-		// wicket:id get automatically a wicket:id assigned.
-		while (markupStream.hasMoreComponentTags())
+		if (get(HtmlHeaderSectionHandler.HEADER_ID) == null)
 		{
-			final ComponentTag tag = markupStream.getTag();
-			if (tag.isOpen() && tag.isBodyTag())
+			// Add a Body container if the associated markup contains a <body> tag
+			// get markup stream gracefully
+			MarkupStream markupStream = new MarkupStream(markup);
+			
+			// The <body> container. It can be accessed, replaced
+			// and attribute modifiers can be attached. <body> tags without
+			// wicket:id get automatically a wicket:id assigned.
+			while (markupStream.hasMoreComponentTags())
 			{
-				// Add a default container if the tag has the default
-				// name. If the tag has a wicket:id, than the user
-				// must create the component.
-				if (BodyOnLoadHandler.BODY_ID.equals(tag.getId()))
+				final ComponentTag tag = markupStream.getTag();
+				if (tag.isOpen() && tag.isBodyTag())
 				{
-					new HtmlBodyContainer(this, tag.getId());
+					// Add a default container if the tag has the default
+					// name. If the tag has a wicket:id, than the user
+					// must create the component.
+					if (BodyOnLoadHandler.BODY_ID.equals(tag.getId()))
+					{
+						new HtmlBodyContainer(this, tag.getId());
+					}
+					// remember the id of the tag
+					bodyContainer = new BodyContainer(this, tag.getId());
+					break;
 				}
-				// remember the id of the tag
-				bodyContainer = new BodyContainer(this, tag.getId());
-				break;
 			}
 		}
-
+		
 		// The <head> container. It can be accessed, replaced
 		// and attribute modifiers can be attached.
-		markupStream.setCurrentIndex(0);
-		while (markupStream.hasMoreComponentTags())
+		// HtmlHeaderSectionHandler guarantees the <head> tag does exist.
+		if (get(HtmlHeaderSectionHandler.HEADER_ID) == null)
 		{
-			final ComponentTag tag = markupStream.getTag();
-			if (tag.isOpen() && tag.isHeadTag())
-			{
-				// Add a default container if the tag has the default
-				// name. If the tag has a wicket:id, than the user
-				// must create the component.
-				if (HtmlHeaderSectionHandler.HEADER_ID.equals(tag.getId()))
-				{
-					new HtmlHeaderContainer(this, tag.getId());
-				}
-				break;
-			}
+			new HtmlHeaderContainer(this, HtmlHeaderSectionHandler.HEADER_ID);
 		}
 
 		// if automatic multi window support is on, add a page checker instance
@@ -313,6 +324,9 @@
 		{
 			add(new PageMapChecker());
 		}
+		
+		// Do all the default staff
+		super.onAssociatedMarkupLoaded(markup);
 	}
 
 	/**

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/border/Border.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/border/Border.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/border/Border.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/border/Border.java Sat Nov  4 05:47:06 2006
@@ -27,7 +27,7 @@
 import wicket.markup.MarkupStream;
 import wicket.markup.html.WebMarkupContainer;
 import wicket.markup.html.WebMarkupContainerWithAssociatedMarkup;
-import wicket.markup.html.internal.HeaderContainer;
+import wicket.markup.html.internal.WicketHeadContainer;
 import wicket.markup.parser.XmlTag;
 import wicket.markup.parser.filter.WicketTagIdentifier;
 import wicket.markup.resolver.IComponentResolver;
@@ -184,7 +184,7 @@
 	{
 		// If, and only if, a body container exists, than redirect new
 		// components to become children of the body.
-		return (this.body != null ? this.body : this);
+		return ((this.body == null) || WicketHeadContainer.class.isInstance(childClass) ? this : this.body);
 	}
 
 	/**
@@ -219,8 +219,16 @@
 	public MarkupFragment getMarkupFragment(final String id)
 	{
 		// Find the tag in the associated markup
-		return getAssociatedMarkup(true).getWicketFragment(BORDER, true)
+		MarkupFragment fragment = getAssociatedMarkup(true).getWicketFragment(BORDER, true)
 				.getChildFragment(id, false);
+		
+		if (fragment != null)
+		{
+			return fragment;
+		}
+		
+		// wicket:head must be search for outside wicket:border
+		return getAssociatedMarkup(true).getChildFragment(id, true);
 	}
 
 	/**
@@ -269,20 +277,6 @@
 
 		// Unable to resolve the request
 		return false;
-	}
-
-	/**
-	 * 
-	 * @see wicket.Component#renderHead(wicket.markup.html.internal.HeaderContainer)
-	 */
-	@Override
-	public void renderHead(final HeaderContainer container)
-	{
-		if (isHeadRendered() == false)
-		{
-			this.renderHeadFromAssociatedMarkupFile(container);
-		}
-		super.renderHead(container);
 	}
 
 	/**

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HeaderContainer.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HeaderContainer.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HeaderContainer.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HeaderContainer.java Sat Nov  4 05:47:06 2006
@@ -18,20 +18,20 @@
  */
 package wicket.markup.html.internal;
 
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 import wicket.Component;
 import wicket.MarkupContainer;
 import wicket.Page;
+import wicket.annot.OnBeforeRender;
+import wicket.annot.OnDetach;
 import wicket.markup.html.IHeaderResponse;
 import wicket.markup.html.WebMarkupContainer;
 
 /**
  * HeaderContainer is a base class for {@link HtmlHeaderContainer} and
- * {$link PortletHeaderContainer}
+ * {@link PortletHeaderContainer}
  * 
  * @author Juergen Donnerstag
  * @author Janne Hietam&auml;ki
@@ -47,12 +47,14 @@
 	 * markup which contains the wicket:head. It can be modified by means of the
 	 * scope attribute.
 	 */
-	private Map<String, List<String>> renderedComponentsPerScope;
+	private transient Map<String, Map<Class, MarkupContainer>> componentsPerScope;
 
 	/**
-	 * Header response that is responsible for filtering duplicate contributions.
+	 * Header response that is responsible for filtering duplicate
+	 * contributions.
 	 */
-	private transient IHeaderResponse headerResponse = null;	
+	private transient IHeaderResponse headerResponse = null;
+
 	/**
 	 * Construct
 	 * 
@@ -68,46 +70,23 @@
 		// including the page does have a <head> or <wicket:head> tag.
 		setRenderBodyOnly(true);
 	}
-
+	
 	/**
 	 * Ask all child components of the Page if they have something to contribute
 	 * to the &lt;head&gt; section of the HTML output. Every component
-	 * interested must implement IHeaderContributor.
+	 * interested must subclass Component.renderHead().
 	 * <p>
 	 * Note: HtmlHeaderContainer will be removed from the component hierachie at
 	 * the end of the request (@see #onEndRequest()) and thus can not transport
 	 * status from one request to the next. This is true for all components
-	 * added to the header.
+	 * added to the header as well.
 	 * 
 	 * @param page
 	 *            The page object
-	 * @param container
-	 *            The header component container
 	 */
-	protected final void renderHeaderSections(final Page page, final HeaderContainer container)
+	protected final void renderHeaderSections(final Page page)
 	{
-		// Make sure all Components interested in contributing to the header
-		// and there attached behaviors are asked.
-		page.visitChildren(new IVisitor()
-		{
-			/**
-			 * @see wicket.Component.IVisitor#component(wicket.Component)
-			 */
-			public Object component(Component component)
-			{
-				if (component.isVisible())
-				{
-					component.renderHead(container);
-					return IVisitor.CONTINUE_TRAVERSAL;
-				}
-				else
-				{
-					return IVisitor.CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
-				}
-			}
-		});
-
-		page.renderHead(container);
+		page.renderHead(new HeaderResponse(getResponse()));
 	}
 
 	/**
@@ -122,58 +101,58 @@
 	/**
 	 * Check if the header component is ok to render within the scope given.
 	 * 
-	 * @param scope
-	 *            The scope of the header component
-	 * @param id
-	 *            The component's id
-	 * @return true, if the component ok to render
+	 * @param header
+	 *            The header part container to check
+	 * @return true, if the component is eligable to create and render
 	 */
-	public final boolean okToRenderComponent(final String scope, final String id)
+	public boolean okToRender(final WicketHeadContainer header)
 	{
-		if (this.renderedComponentsPerScope == null)
+		if (this.componentsPerScope == null)
 		{
-			this.renderedComponentsPerScope = new HashMap<String, List<String>>();
+			this.componentsPerScope = new HashMap<String, Map<Class, MarkupContainer>>();
 		}
 
-		// if (scope == null)
-		// {
-		// scope = header.getMarkupStream().getContainerClass().getName();
-		// }
-
-		List<String> componentScope = this.renderedComponentsPerScope.get(scope);
+		String scope = header.getScope();
+		Map<Class, MarkupContainer> componentScope = this.componentsPerScope.get(scope);
 		if (componentScope == null)
 		{
-			componentScope = new ArrayList<String>();
-			this.renderedComponentsPerScope.put(scope, componentScope);
+			componentScope = new HashMap<Class, MarkupContainer>();
+			this.componentsPerScope.put(scope, componentScope);
 		}
 
-		if (componentScope.contains(id))
+		Class markupClass = header.getMarkupFragment().getMarkup().getResource().getMarkupClass();
+		Component creator = componentScope.get(markupClass);
+		if (creator != null)
 		{
+			if (creator == header.getParent())
+			{
+				return true;
+			}
 			return false;
 		}
-		componentScope.add(id);
+
+		componentScope.put(markupClass, header.getParent());
 		return true;
 	}
 
-	@Override
-	protected void onDetach()
+	/**
+	 * 
+	 * @see wicket.Component#onBeforeRender()
+	 */
+	@OnBeforeRender
+	protected void onBeforeRender()
 	{
-		super.onDetach();
-
-		this.renderedComponentsPerScope = null;
-		this.headerResponse = null;
+		// not needed anymore, which is why it can be transient
+		this.componentsPerScope = null;
 	}
 
 	/**
-	 * Returns the header response. 
-	 * 
-	 * @return header response
+	 * @see wicket.Component#onDetach()
 	 */
-	public IHeaderResponse getHeaderResponse() {
-		if (this.headerResponse == null)
-		{
-			headerResponse = new HeaderResponse(getResponse());
-		}
-		return headerResponse;
+	@OnDetach
+	protected void onDetach()
+	{
+		this.componentsPerScope = null;
+		this.headerResponse = null;
 	}
 }

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HeaderResponse.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HeaderResponse.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HeaderResponse.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HeaderResponse.java Sat Nov  4 05:47:06 2006
@@ -34,7 +34,7 @@
  * 
  * @author Matej Knopp
  */
-class HeaderResponse implements IHeaderResponse
+public class HeaderResponse implements IHeaderResponse
 {
 	private static final long serialVersionUID = 1L;
 

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HtmlHeaderContainer.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HtmlHeaderContainer.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HtmlHeaderContainer.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HtmlHeaderContainer.java Sat Nov  4 05:47:06 2006
@@ -104,7 +104,7 @@
 			// with the markup
 			super.onComponentTagBody(markupStream, openTag);
 
-			renderHeaderSections(getPage(), this);
+			renderHeaderSections(getPage());
 
 			// Automatically add <head> if necessary
 			CharSequence output = response.getBuffer();

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/PortletHeaderContainer.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/PortletHeaderContainer.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/PortletHeaderContainer.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/PortletHeaderContainer.java Sat Nov  4 05:47:06 2006
@@ -84,7 +84,7 @@
 		// must be a Page
 		if (parent instanceof Page)
 		{
-			renderHeaderSections((Page)parent, this);
+			renderHeaderSections((Page)parent);
 		}
 		else
 		{

Copied: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/WicketHeadContainer.java (from r464848, incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HeaderPartContainer.java)
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/WicketHeadContainer.java?view=diff&rev=471185&p1=incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HeaderPartContainer.java&r1=464848&p2=incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/WicketHeadContainer.java&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/HeaderPartContainer.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/internal/WicketHeadContainer.java Sat Nov  4 05:47:06 2006
@@ -18,46 +18,65 @@
  */
 package wicket.markup.html.internal;
 
-import wicket.Component;
 import wicket.MarkupContainer;
-import wicket.markup.ComponentTag;
+import wicket.Response;
+import wicket.markup.MarkupFragment;
 import wicket.markup.MarkupStream;
 import wicket.markup.html.WebMarkupContainer;
-import wicket.markup.resolver.IComponentResolver;
+import wicket.response.NullResponse;
 
 /**
- * For each wicket:head tag a HeaderPartContainer is created and added to the
+ * For each wicket:head tag a WicketHeadContainer is created and added to the
  * HtmlHeaderContainer which has been added to the Page.
  * 
  * @author Juergen Donnerstag
  */
-public final class HeaderPartContainer extends WebMarkupContainer implements IComponentResolver
+public final class WicketHeadContainer extends WebMarkupContainer
 {
 	private static final long serialVersionUID = 1L;
 
-	/** The panel or bordered page the header part is associated with */
-	private final MarkupContainer container;
+	/** The scope attribute of the wicket:head tag */
+	private String scope;
 
-	/** <wicket:head scope="...">. A kind of namespace */
-	private final String scope;
+	private boolean enable = true;
 
 	/**
 	 * @param parent
-	 *            The parent of this component
+	 *            The owner parent of this component
 	 * @param id
 	 *            The component id
-	 * @param container
-	 *            The Panel (or bordered page) the header part is associated
-	 *            with
-	 * @param scope
-	 *            The scope of the wicket:head tag
+	 * @param fragment
+	 *            The markup fragment associated with the wicket:head
 	 */
-	public HeaderPartContainer(MarkupContainer parent, final String id,
-			final MarkupContainer container, final String scope)
+	public WicketHeadContainer(final MarkupContainer parent, final String id,
+			final MarkupFragment fragment)
 	{
 		super(parent, id);
-		this.container = container;
-		this.scope = scope;
+
+		// It is an auto component; make sure the markup loads properly
+		getMarkupFragment();
+		
+		setRenderBodyOnly(true);
+	}
+
+	/**
+	 * Enable/disable the header part and its childs. It is very similar to
+	 * setVisible() but as childs are added to the parent (Panel, Border) and
+	 * not the HeaderContainer, does setVisible() not work.
+	 * 
+	 * @param enable
+	 */
+	public final void setEnable(final boolean enable)
+	{
+		this.enable = enable;
+	}
+
+	/**
+	 * @return True, if header part and it childs are to be rendered.
+	 */
+	public final boolean isEnable()
+	{
+		return this.enable;
 	}
 
 	/**
@@ -67,35 +86,43 @@
 	 */
 	public final String getScope()
 	{
+		if (this.scope == null)
+		{
+			String namespace = getMarkupFragment().getMarkup().getWicketNamespace();
+			this.scope = getMarkupFragment().getTag().getAttributes().getString(namespace + ":scope");
+		}
+
 		return this.scope;
 	}
 
 	/**
-	 * @see IComponentResolver#resolve(MarkupContainer, MarkupStream,
-	 *      ComponentTag)
+	 * @see wicket.MarkupContainer#isTransparentResolver()
 	 */
-	public final boolean resolve(final MarkupContainer container, final MarkupStream markupStream,
-			final ComponentTag tag)
+	@Override
+	public boolean isTransparentResolver()
 	{
-		// The tag must be resolved against the panel and not against the
-		// page
-		Component component = this.container.get(tag.getId());
-		if (component != null)
-		{
-			component.render(markupStream);
-			return true;
-		}
-
-		return false;
+		return true;
 	}
 
 	/**
-	 * @see #setMarkupStream(MarkupStream)
-	 * 
-	 * @param markupStream
+	 * @see wicket.MarkupContainer#onRender(wicket.markup.MarkupStream)
 	 */
-	public final void setMyMarkupStream(final MarkupStream markupStream)
+	@Override
+	protected void onRender(final MarkupStream markupStream)
 	{
-		super.setMarkupStream(markupStream);
+		Response response = getRequestCycle().getResponse();
+		try
+		{
+			if (this.enable == false)
+			{
+				getRequestCycle().setResponse(NullResponse.getInstance());
+			}
+			super.onRender(new MarkupStream(getMarkupFragment()));
+		}
+		finally
+		{
+			markupStream.skipComponent();
+			getRequestCycle().setResponse(response);
+		}
 	}
 }

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/panel/Panel.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/panel/Panel.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/panel/Panel.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/html/panel/Panel.java Sat Nov  4 05:47:06 2006
@@ -22,7 +22,6 @@
 import wicket.markup.MarkupFragment;
 import wicket.markup.MarkupStream;
 import wicket.markup.html.WebMarkupContainerWithAssociatedMarkup;
-import wicket.markup.html.internal.HeaderContainer;
 import wicket.markup.parser.XmlTag;
 import wicket.markup.parser.filter.WicketTagIdentifier;
 import wicket.model.IModel;
@@ -97,8 +96,19 @@
 	 * @param id
 	 * @return MarkupFragment
 	 */
+	@Override
 	public MarkupFragment getMarkupFragment(final String id)
 	{
+		// Find the tag in the associated markup
+		MarkupFragment fragment = getAssociatedMarkup(true).getWicketFragment(PANEL, true)
+				.getChildFragment(id, false);
+		
+		if (fragment != null)
+		{
+			return fragment;
+		}
+		
+		// wicket:head must be searched for outside wicket:panel
 		return getAssociatedMarkup(true).getChildFragment(id, true);
 	}
 
@@ -137,20 +147,5 @@
 			// Skip any raw markup in the body
 			markupStream.skipRawMarkup();
 		}
-	}
-
-	/**
-	 * Check the associated markup file for a wicket header tag
-	 * 
-	 * @see wicket.Component#renderHead(wicket.markup.html.internal.HeaderContainer)
-	 */
-	@Override
-	public void renderHead(HeaderContainer container)
-	{
-		if (isHeadRendered() == false)
-		{
-			this.renderHeadFromAssociatedMarkupFile(container);
-		}
-		super.renderHead(container);
 	}
 }

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/loader/DefaultMarkupLoader.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/loader/DefaultMarkupLoader.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/loader/DefaultMarkupLoader.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/loader/DefaultMarkupLoader.java Sat Nov  4 05:47:06 2006
@@ -22,6 +22,7 @@
 
 import wicket.Application;
 import wicket.MarkupContainer;
+import wicket.markup.MarkupElement;
 import wicket.markup.MarkupFragment;
 import wicket.markup.MarkupResourceStream;
 import wicket.util.resource.ResourceStreamNotFoundException;
@@ -59,6 +60,42 @@
 		MarkupFragment markup = application.getMarkupSettings().getMarkupParserFactory()
 				.newMarkupParser(markupResourceStream).readAndParse();
 
+		checkHeaders(markup);
+
 		return markup;
+	}
+
+	/**
+	 * On Pages with wicket:head and automatically added head tag, move the
+	 * wicket:head tags inside the head tag.
+	 * 
+	 * @param markup
+	 */
+	private void checkHeaders(final MarkupFragment markup)
+	{
+		final MarkupFragment header = MarkupFragmentUtils.getHeadTag(markup);
+		if (header != null)
+		{
+			markup.visitChildren(MarkupFragment.class, new MarkupFragment.IVisitor()
+			{
+				public Object visit(final MarkupElement element, final MarkupFragment parent)
+				{
+					if (element == header)
+					{
+						return CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
+					}
+
+					if (((MarkupFragment)element).getTag().isWicketHeadTag())
+					{
+						if (parent.removeMarkupElement(element) == true)
+						{
+							header.addMarkupElement(header.size() - 1, element);
+						}
+					}
+
+					return CONTINUE_TRAVERSAL;
+				}
+			});
+		}
 	}
 }

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/loader/InheritedMarkupMarkupLoader.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/loader/InheritedMarkupMarkupLoader.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/loader/InheritedMarkupMarkupLoader.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/loader/InheritedMarkupMarkupLoader.java Sat Nov  4 05:47:06 2006
@@ -25,6 +25,7 @@
 import org.apache.commons.logging.LogFactory;
 
 import wicket.Application;
+import wicket.Component;
 import wicket.MarkupContainer;
 import wicket.Page;
 import wicket.markup.ComponentTag;
@@ -433,6 +434,24 @@
 			{
 				ComponentTag tag = (ComponentTag)element;
 				tag.setMarkupClass(parent.getMarkup().getResource().getMarkupClass());
+				return CONTINUE_TRAVERSAL;
+			}
+		});
+		
+		// Make sure that wicket:head tags don't have doublicate ids.
+		mergedMarkup.visitChildren(MarkupFragment.class, new MarkupFragment.IVisitor()
+		{
+			private int index = 0;
+			
+			public Object visit(final MarkupElement element, final MarkupFragment parent)
+			{
+				MarkupFragment fragment = (MarkupFragment) element;
+				ComponentTag tag = fragment.getTag();
+				if ((tag != null) && tag.isWicketHeadTag())
+				{
+					String id = Component.AUTO_COMPONENT_PREFIX + tag.getName() + index++;
+					tag.setId(id);
+				}
 				return CONTINUE_TRAVERSAL;
 			}
 		});

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/loader/MarkupFragmentUtils.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/loader/MarkupFragmentUtils.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/loader/MarkupFragmentUtils.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/loader/MarkupFragmentUtils.java Sat Nov  4 05:47:06 2006
@@ -119,9 +119,10 @@
 	}
 
 	/**
+	 * Gets the &lt;head&gt; fragment
 	 * 
 	 * @param fragment
-	 * @return True, if &lt;head&gt; was found
+	 * @return Null, if not found
 	 */
 	public static final MarkupFragment getHeadTag(final MarkupFragment fragment)
 	{
@@ -147,6 +148,8 @@
 	}
 
 	/**
+	 * Gets the parent fragment of &lt;head&gt; and the position of the
+	 * &lt;head&gt; tag
 	 * 
 	 * @param fragment
 	 * @return Null, if no &lt;head&gt; was found
@@ -260,6 +263,7 @@
 	}
 
 	/**
+	 * Gets the &lt;wicket:head&gt; markup
 	 * 
 	 * @param fragment
 	 * @return Null, if no wicket:head found

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/filter/HtmlHeaderSectionHandler.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/filter/HtmlHeaderSectionHandler.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/filter/HtmlHeaderSectionHandler.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/filter/HtmlHeaderSectionHandler.java Sat Nov  4 05:47:06 2006
@@ -24,6 +24,7 @@
 import wicket.markup.ComponentTag;
 import wicket.markup.MarkupElement;
 import wicket.markup.MarkupFragment;
+import wicket.markup.MarkupParser;
 import wicket.markup.parser.AbstractMarkupFilter;
 import wicket.markup.parser.XmlTag;
 
@@ -41,29 +42,26 @@
  */
 public final class HtmlHeaderSectionHandler extends AbstractMarkupFilter
 {
-	private static final String BODY = "body";
 	private static final String HEAD = "head";
 
 	/** The automatically assigned wicket:id to &gt;head&lt; tag */
-	public static final String HEADER_ID = Component.AUTO_COMPONENT_PREFIX + "<header>";
-
-	/** True if <head> has been found already */
-	private boolean foundHead = false;
+	public static final String HEADER_ID = Component.AUTO_COMPONENT_PREFIX + "header";
 
 	/** True if all the rest of the markup file can be ignored */
 	private boolean ignoreTheRest = false;
-	
-	/** The Markup available so far for the resource */
-	private final MarkupFragment markup;
-	
+
+	/** The markup parser */
+	private final MarkupParser parser;
+
 	/**
 	 * Construct.
 	 * 
-	 * @param markup The Markup object being filled while reading the markup resource
+	 * @param parser
+	 *            The markup parser
 	 */
-	public HtmlHeaderSectionHandler(final MarkupFragment markup)
+	public HtmlHeaderSectionHandler(final MarkupParser parser)
 	{
-		this.markup = markup;
+		this.parser = parser;
 	}
 
 	/**
@@ -92,41 +90,26 @@
 		}
 
 		// if it is <head> or </head>
-		if (HEAD.equalsIgnoreCase(tag.getName()))
+		if (tag.isHeadTag())
 		{
-			if (tag.getNamespace() == null)
-			{
-				// we found <head>
-				if (tag.isClose())
-				{
-					foundHead = true;
-				}
-				else if (tag.getId() == null)
-				{
-					tag.setId(HEADER_ID);
-				}
-	
-				// Usually <head> is not a wicket special tag. But because we want
-				// transparent header support we insert it automatically if missing
-				// and while rendering its content all child components are asked if
-				// they want to contribute something to the header. Thus we have to
-				// handle <head> accordingly.
-				tag.setInternalTag(true);
-				return tag;
-			}
-			else 
+			ignoreTheRest = true;
+
+			if (tag.getId() == null)
 			{
-				// we found <wicket:head>
-				foundHead = true;
+				tag.setId(HEADER_ID);
 			}
+
+			// Usually <head> is not a wicket special tag. But because we want
+			// transparent header support we insert it automatically if missing
+			// and while rendering its content all child components are asked if
+			// they want to contribute something to the header. Thus we have to
+			// handle <head> accordingly.
+			tag.setInternalTag(true);
+			return tag;
 		}
-		else if (BODY.equalsIgnoreCase(tag.getName()) && (tag.getNamespace() == null))
+		else if (tag.isBodyTag())
 		{
-			// We found <body>
-			if (foundHead == false)
-			{
-				insertHeadTag();
-			}
+			insertHeadTag();
 
 			// <head> must always be before <body>
 			ignoreTheRest = true;
@@ -145,12 +128,14 @@
 		// Note: only the open-tag must be a AutoComponentTag
 		final ComponentTag openTag = new ComponentTag(HEAD, XmlTag.Type.OPEN);
 		openTag.setId(HEADER_ID);
-		
+
 		final ComponentTag closeTag = new ComponentTag(HEAD, XmlTag.Type.CLOSE);
 		closeTag.setOpenTag(openTag);
 
 		// insert the tags into the markup stream
-		this.markup.addMarkupElement(openTag);
-		this.markup.addMarkupElement(closeTag);
+		MarkupFragment fragment = new MarkupFragment(parser.getMarkup());
+		fragment.addMarkupElement(openTag);
+		fragment.addMarkupElement(closeTag);
+		this.parser.getCurrentMarkupFragment().addMarkupElement(fragment);
 	}
 }

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/filter/TagTypeHandler.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/filter/TagTypeHandler.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/filter/TagTypeHandler.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/filter/TagTypeHandler.java Sat Nov  4 05:47:06 2006
@@ -46,7 +46,7 @@
 	static
 	{
 		// Tags which require open-body-close
-		requireOpenBodyCloseTag.put("select", Boolean.TRUE);
+		registerOpenBodyCloseTag("select");
 	}
 
 	/**
@@ -54,6 +54,17 @@
 	 */
 	public TagTypeHandler()
 	{
+	}
+
+	/**
+	 * Register the tags which will be converted from open-close to
+	 * open-blody-close if necessary.
+	 * 
+	 * @param name
+	 */
+	public static final void registerOpenBodyCloseTag(final String name)
+	{
+		requireOpenBodyCloseTag.put(name, Boolean.TRUE);
 	}
 
 	/**

Modified: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/filter/WicketTagIdentifier.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/filter/WicketTagIdentifier.java?view=diff&rev=471185&r1=471184&r2=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/filter/WicketTagIdentifier.java (original)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/filter/WicketTagIdentifier.java Sat Nov  4 05:47:06 2006
@@ -44,11 +44,23 @@
 public final class WicketTagIdentifier extends AbstractMarkupFilter
 {
 	/** List of well known wicket tag namses */
-	private static List<String> wellKnownTagNames;
+	private static List<String> wellKnownTagNames = new ArrayList<String>();
 
+	/** wicket tag which require unique ids */
+	private static List<String> requiresUniqueId = new ArrayList<String>();
+
+	static
+	{
+		// register wicket:head
+		registerTagWhichRequiresUniqueId("head");
+	}
+	
 	/** The current markup needed to get the markups namespace */
 	private final IMarkup markup;
 
+	/** auto increment to create unique ids */
+	private int index;
+	
 	/**
 	 * Construct.
 	 * 
@@ -59,7 +71,7 @@
 	{
 		this.markup = markup;
 	}
-
+	
 	/**
 	 * Get the next tag from the next MarkupFilter in the chain and search for
 	 * Wicket specific tags.
@@ -94,7 +106,12 @@
 			tag.setWicketTag(true);
 
 			// Make it a wicket component. Otherwise it would be RawMarkup
-			tag.setId(Component.AUTO_COMPONENT_PREFIX + tag.getName());
+			String id = Component.AUTO_COMPONENT_PREFIX + tag.getName();
+			if (requiresUniqueId.contains(tag.getName()))
+			{
+				id = id + this.index++;
+			}
+			tag.setId(id);
 
 			if (wellKnownTagNames.contains(xmlTag.getName()) == false)
 			{
@@ -129,14 +146,19 @@
 	 */
 	public final static void registerWellKnownTagName(final String name)
 	{
-		if (wellKnownTagNames == null)
-		{
-			wellKnownTagNames = new ArrayList<String>();
-		}
-
 		if (wellKnownTagNames.contains(name) == false)
 		{
 			wellKnownTagNames.add(name);
 		}
+	}
+
+	/**
+	 * Register tags, such as wicket:head, which require unique ids.
+	 * 
+	 * @param tag
+	 */
+	public final static void registerTagWhichRequiresUniqueId(final String tag)
+	{
+		requiresUniqueId.add(tag);
 	}
 }

Added: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/onLoadListener/IMarkupLoadListener.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/onLoadListener/IMarkupLoadListener.java?view=auto&rev=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/onLoadListener/IMarkupLoadListener.java (added)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/onLoadListener/IMarkupLoadListener.java Sat Nov  4 05:47:06 2006
@@ -0,0 +1,46 @@
+/*
+ * $Id: org.eclipse.jdt.ui.prefs 5004 2006-03-17 20:47:08 -0800 (Fri, 17 Mar 2006) eelco12 $
+ * $Revision$
+ * $Date: 2006-03-17 20:47:08 -0800 (Fri, 17 Mar 2006) $
+ * 
+ * ==============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package wicket.markup.parser.onLoadListener;
+
+import wicket.MarkupContainer;
+import wicket.markup.MarkupFragment;
+import wicket.markup.html.WebMarkupContainerWithAssociatedMarkup;
+
+/**
+ * Markup load listeners can be registered with the application and are invoked
+ * after Markup has been loaded from disk. As Wicket will internally cache the
+ * markup it is really only called when loaded.
+ * 
+ * @see WebMarkupContainerWithAssociatedMarkup#getAssociatedMarkup(boolean)
+ * 
+ * @author Juergen Donnerstag
+ */
+public interface IMarkupLoadListener
+{
+	/**
+	 * Invoked after a markup file has been loaded.
+	 * 
+	 * @param container
+	 *            The container which is associated with the markup
+	 * 
+	 * @param markup
+	 *            The markup
+	 */
+	void onAssociatedMarkupLoaded(final MarkupContainer container, final MarkupFragment markup);
+}

Propchange: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/onLoadListener/IMarkupLoadListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/onLoadListener/IMarkupLoadListener.java
------------------------------------------------------------------------------
    svn:keywords = "LastChangedDate LastChangedRevision URL"

Added: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/onLoadListener/WicketHeaderLoader.java
URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/onLoadListener/WicketHeaderLoader.java?view=auto&rev=471185
==============================================================================
--- incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/onLoadListener/WicketHeaderLoader.java (added)
+++ incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/onLoadListener/WicketHeaderLoader.java Sat Nov  4 05:47:06 2006
@@ -0,0 +1,164 @@
+/*
+ * $Id: org.eclipse.jdt.ui.prefs 5004 2006-03-17 20:47:08 -0800 (Fri, 17 Mar 2006) eelco12 $
+ * $Revision$
+ * $Date: 2006-03-17 20:47:08 -0800 (Fri, 17 Mar 2006) $
+ * 
+ * ==============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package wicket.markup.parser.onLoadListener;
+
+import wicket.Component;
+import wicket.MarkupContainer;
+import wicket.Page;
+import wicket.Component.IVisitor;
+import wicket.markup.ComponentTag;
+import wicket.markup.MarkupElement;
+import wicket.markup.MarkupException;
+import wicket.markup.MarkupFragment;
+import wicket.markup.MarkupStream;
+import wicket.markup.html.WebPage;
+import wicket.markup.html.internal.HeaderContainer;
+import wicket.markup.html.internal.WicketHeadContainer;
+import wicket.markup.parser.filter.HtmlHeaderSectionHandler;
+
+/**
+ * Add a markup load listener which adds the wicket:head containers to Page,
+ * Panel, Border etc.
+ * 
+ * @author Juergen Donnerstag
+ */
+public class WicketHeaderLoader implements IMarkupLoadListener
+{
+	/** body tag attribute */
+	private static final String ONUNLOAD = "onunload";
+
+	/** body tag attribute */
+	private static final String ONLOAD = "onload";
+
+	/**
+	 * @see wicket.markup.parser.onLoadListener.IMarkupLoadListener#onAssociatedMarkupLoaded(wicket.MarkupContainer,
+	 *      wicket.markup.MarkupFragment)
+	 */
+	public void onAssociatedMarkupLoaded(final MarkupContainer container,
+			final MarkupFragment fragment)
+	{
+		// Remove any wicket header container
+		container.visitChildren(WicketHeadContainer.class, new IVisitor()
+		{
+			public Object component(final Component<?> component)
+			{
+				component.remove();
+				return CONTINUE_TRAVERSAL;
+			}
+		});
+		
+		// Get the container for the headers from the page
+		final Page page = container.getPage();
+		final HeaderContainer headerContainer;
+		if (container instanceof WebPage)
+		{
+			headerContainer = ((WebPage)page).getHeaderContainer();
+		}
+		else
+		{
+			headerContainer = (HeaderContainer)page.get(HtmlHeaderSectionHandler.HEADER_ID);
+		}
+
+		// Search for wicket:head in the associated markup and copy the body
+		// onload and onunload attributes
+		fragment.visitChildren(MarkupFragment.class, new MarkupFragment.IVisitor()
+		{
+			private boolean foundBody = false;
+
+			/**
+			 * @see wicket.markup.MarkupFragment.IVisitor#visit(wicket.markup.MarkupElement,
+			 *      wicket.markup.MarkupFragment)
+			 */
+			public Object visit(final MarkupElement element, final MarkupFragment parent)
+			{
+				final MarkupFragment frag = (MarkupFragment)element;
+				final ComponentTag tag = frag.getTag();
+				if (tag.isWicketHeadTag())
+				{
+					if (foundBody == true)
+					{
+						// Create a MarkupStream and position it at the error
+						// location
+						MarkupStream markupStream = new MarkupStream(fragment);
+						while (markupStream.hasMore())
+						{
+							if (markupStream.next() == tag)
+							{
+								break;
+							}
+						}
+						throw new MarkupException(
+								"<wicket:head> must be before the <body>, <wicket:panel> ... tag");
+					}
+
+					WicketHeadContainer header = newWicketHeaderContainer(container, frag);
+					// TODO check again why setVisible() doesn't work here
+					header.setEnable(headerContainer.okToRender(header));
+
+					return CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
+				}
+				else if (tag.isBodyTag())
+				{
+					foundBody = true;
+					if (page instanceof WebPage)
+					{
+						WebPage webPage = (WebPage)page;
+						final CharSequence onLoad = tag.getString(ONLOAD);
+						if (onLoad != null)
+						{
+							// Attach an AttributeModifier to the body container
+							// which appends the new value to the onLoad
+							// attribute
+							webPage.getBodyContainer().addOnLoadModifier(onLoad, container);
+						}
+
+						final CharSequence onUnLoad = tag.getString(ONUNLOAD);
+						if (onUnLoad != null)
+						{
+							// Same for unload
+							webPage.getBodyContainer().addOnUnLoadModifier(onUnLoad, container);
+						}
+					}
+				}
+				else if (tag.isMajorWicketComponentTag())
+				{
+					foundBody = true;
+				}
+
+				return CONTINUE_TRAVERSAL;
+			}
+		});
+	}
+
+	/**
+	 * Create a new WicketHeadContainer. Users may wish subclass the method to
+	 * implemented more sophisticated header scoping stragegies.
+	 * 
+	 * @param parent
+	 *            The parent for the header
+	 * @param fragment
+	 *            The markup fragment associated with the wicket:head
+	 * @return The new header part container s
+	 */
+	public WicketHeadContainer newWicketHeaderContainer(final MarkupContainer parent,
+			final MarkupFragment fragment)
+	{
+		return new WicketHeadContainer(parent, fragment.getTag().getId(), fragment);
+	}
+}

Propchange: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/onLoadListener/WicketHeaderLoader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/wicket/trunk/wicket/src/main/java/wicket/markup/parser/onLoadListener/WicketHeaderLoader.java
------------------------------------------------------------------------------
    svn:keywords = "LastChangedDate LastChangedRevision URL"