All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.wicket.markup.MergedMarkup Maven / Gradle / Ivy

Go to download

Pax Wicket Service is an OSGi extension of the Wicket framework, allowing for dynamic loading and unloading of Wicket components and pageSources.

There is a newer version: 5.0.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.wicket.markup;

import org.apache.wicket.Page;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.markup.parser.XmlTag;
import org.apache.wicket.markup.parser.filter.HtmlHeaderSectionHandler;
import org.apache.wicket.util.string.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * A Markup class which represents merged markup, as it is required for markup inheritance.
 * 

* The Markups are merged at load time. Deep markup hierarchies are supported. Multiple inheritance * is not. *

* The markup resource file, which is associated with the markup, will be the resource of the * requested markup file. The base markup resources are not. *

* Base Markup must have a <wicket:child/> tag at the position where the derived markup should * be inserted. From the derived markup all tags in between <wicket:extend> and * </wicket:extend> will be inserted. *

* In addition, all <wicket:head> regions are copied as well. This allows to develop completely * self-contained plug & play components including javascript etc. * * @author Juergen Donnerstag */ public class MergedMarkup extends Markup { private final static Logger log = LoggerFactory.getLogger(MergedMarkup.class); /** * Merge inherited and base markup. * * @param markup * The inherited markup * @param baseMarkup * The base markup * @param extendIndex * Index where has been found */ public MergedMarkup(final Markup markup, final Markup baseMarkup, int extendIndex) { super(new MarkupResourceData()); // Copy settings from derived markup getMarkupResourceData().setResource(markup.getMarkupResourceData().getResource()); getMarkupResourceData().setXmlDeclaration( markup.getMarkupResourceData().getXmlDeclaration()); getMarkupResourceData().setEncoding(markup.getMarkupResourceData().getEncoding()); getMarkupResourceData().setWicketNamespace( markup.getMarkupResourceData().getWicketNamespace()); getMarkupResourceData().setBaseMarkup(baseMarkup); if (log.isDebugEnabled()) { String derivedResource = Strings.afterLast(markup.getMarkupResourceData() .getResource() .toString(), '/'); String baseResource = Strings.afterLast(baseMarkup.getMarkupResourceData() .getResource() .toString(), '/'); log.debug("Merge markup: derived markup: " + derivedResource + "; base markup: " + baseResource); } // Merge derived and base markup merge(markup, baseMarkup, extendIndex); // Initialize internals based on new markup initialize(); if (log.isDebugEnabled()) { log.debug("Merge markup: " + toString()); } } /** * @see org.apache.wicket.markup.Markup#locationAsString() */ @Override public String locationAsString() { /* * Uses both resource locations so that if the child does not have a style and the parent * does, the location is unique to this combination (or vice versa) SEE WICKET-1507 (Jeremy * Thomerson) */ String l1 = getMarkupResourceData().getBaseMarkup().locationAsString(); String l2 = getMarkupResourceData().getResource().locationAsString(); if ((l1 == null) && (l2 == null)) { return null; } return l1 + ":" + l2; } /** * Merge inherited and base markup. * * @param markup * The inherited markup * @param baseMarkup * The base markup * @param extendIndex * Index where has been found */ private void merge(final Markup markup, final Markup baseMarkup, int extendIndex) { // True if either or has been processed boolean wicketHeadProcessed = false; // True, if was found boolean foundHeadTag = false; // Add all elements from the base markup to the new list // until is found. Convert // into and add it as well. WicketTag childTag = null; int baseIndex = 0; for (; baseIndex < baseMarkup.size(); baseIndex++) { MarkupElement element = baseMarkup.get(baseIndex); if (element instanceof RawMarkup) { // Add the element to the merged list addMarkupElement(element); continue; } final ComponentTag tag = (ComponentTag)element; // Make sure all tags of the base markup remember where they are // from if ((baseMarkup.getMarkupResourceData().getResource() != null) && (tag.getMarkupClass() == null)) { tag.setMarkupClass(baseMarkup.getMarkupResourceData() .getResource() .getMarkupClass()); } if (element instanceof WicketTag) { WicketTag wtag = (WicketTag)element; // Found org.apache.wicket.child in base markup. In case of 3+ // level inheritance make sure the child tag is not from one of // the deeper levels if (wtag.isChildTag() && (tag.getMarkupClass() == baseMarkup.getMarkupResourceData() .getResource() .getMarkupClass())) { if (wtag.isOpenClose()) { // => ... childTag = wtag; WicketTag childOpenTag = (WicketTag)wtag.mutable(); childOpenTag.getXmlTag().setType(XmlTag.OPEN); childOpenTag.setMarkupClass(baseMarkup.getMarkupResourceData() .getResource() .getMarkupClass()); addMarkupElement(childOpenTag); break; } else if (wtag.isOpen()) { // addMarkupElement(wtag); break; } else { throw new WicketRuntimeException( "Did not expect a tag in " + baseMarkup.toString()); } } // Process the head of the extended markup only once if (wicketHeadProcessed == false) { // if in base markup and no if (wtag.isClose() && wtag.isHeadTag() && (foundHeadTag == false)) { wicketHeadProcessed = true; // Add the current close tag addMarkupElement(wtag); // Add the body from the derived markup. copyWicketHead(markup, extendIndex); // Do not add the current tag. It has already been // added. continue; } // if or ... in base markup if (wtag.isOpen() && wtag.isMajorWicketComponentTag()) { wicketHeadProcessed = true; // Add the body from the derived markup. copyWicketHead(markup, extendIndex); } } } // Process the head of the extended markup only once if (wicketHeadProcessed == false) { // Remember that we found in the base markup if (tag.isOpen() && TagUtils.isHeadTag(tag)) { foundHeadTag = true; } // if in base markup if ((tag.isClose() && TagUtils.isHeadTag(tag)) || (tag.isOpen() && TagUtils.isBodyTag(tag))) { wicketHeadProcessed = true; // Add the body from the derived markup. copyWicketHead(markup, extendIndex); } } // Add the element to the merged list addMarkupElement(element); } if (baseIndex == baseMarkup.size()) { throw new WicketRuntimeException("Expected to find in base markup: " + baseMarkup.toString()); } // Now append all elements from the derived markup starting with // until to the list for (; extendIndex < markup.size(); extendIndex++) { MarkupElement element = markup.get(extendIndex); addMarkupElement(element); if (element instanceof WicketTag) { WicketTag wtag = (WicketTag)element; if (wtag.isExtendTag() && wtag.isClose()) { break; } } } if (extendIndex == markup.size()) { throw new WicketRuntimeException( "Missing close tag in derived markup: " + markup.toString()); } // If than skip the body and find if (((ComponentTag)baseMarkup.get(baseIndex)).isOpen()) { for (baseIndex++; baseIndex < baseMarkup.size(); baseIndex++) { MarkupElement element = baseMarkup.get(baseIndex); if (element instanceof WicketTag) { WicketTag tag = (WicketTag)element; if (tag.isChildTag() && tag.isClose()) { // Ok, skipped the childs content tag.setMarkupClass(baseMarkup.getMarkupResourceData() .getResource() .getMarkupClass()); addMarkupElement(tag); break; } else { throw new WicketRuntimeException( "Wicket tags like are not allowed in between and tags: " + markup.toString()); } } else if (element instanceof ComponentTag) { throw new WicketRuntimeException( "Wicket tags identified by wicket:id are not allowed in between and tags: " + markup.toString()); } } // not found if (baseIndex == baseMarkup.size()) { throw new WicketRuntimeException( "Expected to find in base markup: " + baseMarkup.toString()); } } else { // And now all remaining elements from the derived markup. // But first add WicketTag childCloseTag = (WicketTag)childTag.mutable(); childCloseTag.getXmlTag().setType(XmlTag.CLOSE); childCloseTag.setMarkupClass(baseMarkup.getMarkupResourceData() .getResource() .getMarkupClass()); addMarkupElement(childCloseTag); } for (baseIndex++; baseIndex < baseMarkup.size(); baseIndex++) { MarkupElement element = baseMarkup.get(baseIndex); addMarkupElement(element); // Make sure all tags of the base markup remember where they are // from if ((element instanceof ComponentTag) && (baseMarkup.getMarkupResourceData().getResource() != null)) { ComponentTag tag = (ComponentTag)element; tag.setMarkupClass(baseMarkup.getMarkupResourceData() .getResource() .getMarkupClass()); } } // Automatically add if missing and required. On a Page // it must enclose ALL of the tags. // Note: HtmlHeaderSectionHandler does something similar, but because // markup filters are not called for merged markup again, ... if (Page.class.isAssignableFrom(markup.getMarkupResourceData() .getResource() .getMarkupClass())) { // Find the position inside the markup for first , // last and int hasOpenWicketHead = -1; int hasCloseWicketHead = -1; int hasHead = -1; for (int i = 0; i < size(); i++) { MarkupElement element = get(i); if ((hasOpenWicketHead == -1) && (element instanceof WicketTag) && ((WicketTag)element).isHeadTag()) { hasOpenWicketHead = i; } else if ((element instanceof WicketTag) && ((WicketTag)element).isHeadTag() && ((WicketTag)element).isClose()) { hasCloseWicketHead = i; } else if ((hasHead == -1) && (element instanceof ComponentTag) && TagUtils.isHeadTag((ComponentTag)element)) { hasHead = i; } else if ((hasHead != -1) && (hasOpenWicketHead != -1)) { break; } } // If a tag is missing, insert it automatically if ((hasOpenWicketHead != -1) && (hasHead == -1)) { final XmlTag headOpenTag = new XmlTag(); headOpenTag.setName("head"); headOpenTag.setType(XmlTag.OPEN); final ComponentTag openTag = new ComponentTag(headOpenTag); openTag.setId(HtmlHeaderSectionHandler.HEADER_ID); openTag.setAutoComponentTag(true); final XmlTag headCloseTag = new XmlTag(); headCloseTag.setName(headOpenTag.getName()); headCloseTag.setType(XmlTag.CLOSE); final ComponentTag closeTag = new ComponentTag(headCloseTag); closeTag.setOpenTag(openTag); closeTag.setId(HtmlHeaderSectionHandler.HEADER_ID); addMarkupElement(hasOpenWicketHead, openTag); addMarkupElement(hasCloseWicketHead + 2, closeTag); } } } /** * Append the wicket:head regions from the extended markup to the current markup * * @param markup * @param extendIndex */ private void copyWicketHead(final Markup markup, int extendIndex) { boolean copy = false; for (int i = 0; i < extendIndex; i++) { MarkupElement elem = markup.get(i); if (elem instanceof WicketTag) { WicketTag etag = (WicketTag)elem; if (etag.isHeadTag()) { if (etag.isOpen()) { copy = true; } else { addMarkupElement(elem); break; } } } if (copy == true) { addMarkupElement(elem); } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy