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; 018 019import org.apache.wicket.Component; 020import org.apache.wicket.MarkupContainer; 021import org.apache.wicket.markup.ComponentTag; 022import org.apache.wicket.markup.MarkupElement; 023import org.apache.wicket.markup.MarkupStream; 024import org.apache.wicket.markup.WicketTag; 025import org.apache.wicket.markup.html.internal.HtmlHeaderContainer; 026import org.apache.wicket.markup.resolver.ComponentResolvers; 027import org.apache.wicket.markup.resolver.IComponentResolver; 028import org.apache.wicket.request.Request; 029import org.apache.wicket.request.cycle.RequestCycle; 030import org.apache.wicket.request.http.WebRequest; 031 032/** 033 * A simple "transparent" markup container. 034 * 035 * @author Juergen Donnerstag 036 */ 037public class TransparentWebMarkupContainer extends WebMarkupContainer implements IComponentResolver 038{ 039 private static final long serialVersionUID = 1L; 040 041 /** 042 * Construct. 043 * 044 * @param id 045 * The component id 046 */ 047 public TransparentWebMarkupContainer(String id) 048 { 049 super(id); 050 } 051 052 /** 053 * @see org.apache.wicket.markup.resolver.IComponentResolver#resolve(org.apache.wicket.MarkupContainer, 054 * org.apache.wicket.markup.MarkupStream, org.apache.wicket.markup.ComponentTag) 055 */ 056 @Override 057 public Component resolve(MarkupContainer container, MarkupStream markupStream, ComponentTag tag) 058 { 059 if (tag instanceof WicketTag && ((WicketTag)tag).isFragmentTag()) 060 { 061 // even having a wicket:id it isn't a component's markup 062 return null; 063 } 064 065 Component resolvedComponent = getParent().get(tag.getId()); 066 if (resolvedComponent != null && getPage().wasRendered(resolvedComponent)) 067 { 068 /* 069 * Means that parent container has an associated homonymous tag to this grandchildren 070 * tag in markup. The parent container wants render it and it should be not resolved to 071 * their grandchildren. 072 */ 073 return null; 074 } 075 return resolvedComponent; 076 } 077 078 @Override 079 public void internalRenderHead(HtmlHeaderContainer container) 080 { 081 /* 082 * https://issues.apache.org/jira/browse/WICKET-5941 083 * 084 * if this component is updated via AJAX and is the root 085 * one, then render head also for embedded components. 086 */ 087 if (isAjaxRequest() && !isParentRendering()) 088 { 089 renderHeadForInnerSiblings(container); 090 } 091 092 super.internalRenderHead(container); 093 } 094 095 /** 096 * Says if parent container is rendering or not. 097 * 098 * @return true if parent is rendering, false otherwise. 099 */ 100 private boolean isParentRendering() 101 { 102 MarkupContainer parent = getParent(); 103 104 return parent != null && parent.isRendering(); 105 } 106 107 /** 108 * Says if the current request is an AJAX one. 109 * 110 * @return true if the current request is an AJAX one, false otherwise. 111 */ 112 private boolean isAjaxRequest() 113 { 114 Request request = RequestCycle.get().getRequest(); 115 116 if (request instanceof WebRequest) 117 { 118 WebRequest webRequest = (WebRequest)request; 119 return webRequest.isAjax(); 120 } 121 122 return false; 123 } 124 125 /** 126 * Renders head for embedded component, i.e. those who are not added 127 * directly to this container but have the markup inside it. 128 * 129 * @param container 130 * The HtmlHeaderContainer 131 */ 132 private void renderHeadForInnerSiblings(HtmlHeaderContainer container) 133 { 134 MarkupStream stream = new MarkupStream(getMarkup()); 135 136 while (stream.isCurrentIndexInsideTheStream()) 137 { 138 MarkupElement childOpenTag = stream.nextOpenTag(); 139 140 if ((childOpenTag instanceof ComponentTag) && !stream.atCloseTag()) 141 { 142 // Get element as tag 143 final ComponentTag tag = (ComponentTag)childOpenTag; 144 145 // Get component id 146 final String id = tag.getId(); 147 148 Component component = null; 149 150 if (get(id) == null) 151 { 152 component = ComponentResolvers.resolveByComponentHierarchy(this, stream, tag); 153 } 154 155 if (component != null) 156 { 157 component.internalRenderHead(container); 158 } 159 160 //consider just direct children 161 stream.skipToMatchingCloseTag(tag); 162 } 163 } 164 } 165 166 @Override 167 protected Component findChildComponent(ComponentTag tag) 168 { 169 Component childComponent = super.findChildComponent(tag); 170 171 return childComponent != null ? childComponent : resolve(this, null, tag); 172 } 173}