001: /*
002: * $Id: HtmlHeaderSectionHandler.java 5857 2006-05-25 17:27:26 +0000 (Thu, 25
003: * May 2006) joco01 $ $Revision: 461655 $ $Date: 2006-05-25 17:27:26 +0000 (Thu,
004: * 25 May 2006) $
005: *
006: * ==============================================================================
007: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
008: * use this file except in compliance with the License. You may obtain a copy of
009: * the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
015: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
016: * License for the specific language governing permissions and limitations under
017: * the License.
018: */
019: package wicket.markup.parser.filter;
020:
021: import java.text.ParseException;
022:
023: import wicket.markup.ComponentTag;
024: import wicket.markup.Markup;
025: import wicket.markup.MarkupElement;
026: import wicket.markup.parser.AbstractMarkupFilter;
027: import wicket.markup.parser.XmlTag;
028:
029: /**
030: * This is a markup inline filter. It assumes that WicketTagIdentifier has been
031: * called first and search for a <head> tag (note: not wicket:head).
032: * Provided the markup contains a <body> tag it will automatically prepend
033: * a <head> tag if missing.
034: * <p>
035: * Note: This handler is only relevant for Pages (see
036: * MarkupParser.newFilterChain())
037: *
038: * @see wicket.markup.MarkupParser
039: * @author Juergen Donnerstag
040: */
041: public final class HtmlHeaderSectionHandler extends
042: AbstractMarkupFilter {
043: private static final String BODY = "body";
044: private static final String HEAD = "head";
045:
046: /** The automatically assigned wicket:id to >head< tag */
047: public static final String HEADER_ID = "<auto>_header";
048:
049: /** True if <head> has been found already */
050: private boolean foundHead = false;
051:
052: /** True if all the rest of the markup file can be ignored */
053: private boolean ignoreTheRest = false;
054:
055: /** The Markup available so far for the resource */
056: private final Markup markup;
057:
058: /**
059: * Construct.
060: *
061: * @param markup The Markup object being filled while reading the markup resource
062: */
063: public HtmlHeaderSectionHandler(final Markup markup) {
064: this .markup = markup;
065: }
066:
067: /**
068: * Get the next tag from the next MarkupFilter in the chain and search for
069: * Wicket specific tags.
070: * <p>
071: *
072: * @see wicket.markup.parser.IMarkupFilter#nextTag()
073: * @return The next tag from markup to be processed. If null, no more tags
074: * are available
075: */
076: public MarkupElement nextTag() throws ParseException {
077: // Get the next tag from the markup.
078: // If null, no more tags are available
079: final ComponentTag tag = nextComponentTag();
080: if (tag == null) {
081: return tag;
082: }
083:
084: // Whatever there is left in the markup, ignore it
085: if (ignoreTheRest == true) {
086: return tag;
087: }
088:
089: // if it is <head> or </head>
090: if (HEAD.equalsIgnoreCase(tag.getName())) {
091: if (tag.getNamespace() == null) {
092: // we found <head>
093: if (tag.isClose()) {
094: foundHead = true;
095: } else if (tag.getId() == null) {
096: tag.setId(HEADER_ID);
097: }
098:
099: // Usually <head> is not a wicket special tag. But because we want
100: // transparent header support we insert it automatically if missing
101: // and while rendering its content all child components are asked if
102: // they want to contribute something to the header. Thus we have to
103: // handle <head> accordingly.
104: tag.setInternalTag(true);
105: return tag;
106: } else {
107: // we found <wicket:head>
108: foundHead = true;
109: }
110: } else if (BODY.equalsIgnoreCase(tag.getName())
111: && (tag.getNamespace() == null)) {
112: // We found <body>
113: if (foundHead == false) {
114: insertHeadTag();
115: }
116:
117: // <head> must always be before <body>
118: ignoreTheRest = true;
119: return tag;
120: }
121:
122: return tag;
123: }
124:
125: /**
126: * Insert <head> open and close tag (with empty body) to the current
127: * position.
128: */
129: private void insertHeadTag() {
130: // Note: only the open-tag must be a AutoComponentTag
131: final ComponentTag openTag = new ComponentTag(HEAD, XmlTag.OPEN);
132: openTag.setId(HEADER_ID);
133:
134: final ComponentTag closeTag = new ComponentTag(HEAD,
135: XmlTag.CLOSE);
136: closeTag.setOpenTag(openTag);
137:
138: // insert the tags into the markup stream
139: this.markup.addMarkupElement(openTag);
140: this.markup.addMarkupElement(closeTag);
141: }
142: }
|