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: */
017: package org.apache.wicket.markup.parser.filter;
018:
019: import java.text.ParseException;
020:
021: import org.apache.wicket.markup.ComponentTag;
022: import org.apache.wicket.markup.Markup;
023: import org.apache.wicket.markup.MarkupElement;
024: import org.apache.wicket.markup.parser.AbstractMarkupFilter;
025: import org.apache.wicket.markup.parser.XmlTag;
026:
027: /**
028: * This is a markup inline filter. It assumes that WicketTagIdentifier has been
029: * called first and search for a <head> tag (note: not wicket:head).
030: * Provided the markup contains a <body> tag it will automatically prepend
031: * a <head> tag if missing.
032: * <p>
033: * Note: This handler is only relevant for Pages (see
034: * MarkupParser.newFilterChain())
035: *
036: * @see org.apache.wicket.markup.MarkupParser
037: * @author Juergen Donnerstag
038: */
039: public final class HtmlHeaderSectionHandler extends
040: AbstractMarkupFilter {
041: private static final String BODY = "body";
042: private static final String HEAD = "head";
043:
044: /** The automatically assigned wicket:id to >head< tag */
045: public static final String HEADER_ID = "_header_";
046:
047: /** True if <head> has been found already */
048: private boolean foundHead = false;
049:
050: /** True if all the rest of the markup file can be ignored */
051: private boolean ignoreTheRest = false;
052:
053: /** The Markup available so far for the resource */
054: private final Markup markup;
055:
056: /**
057: * Construct.
058: *
059: * @param markup
060: * The Markup object being filled while reading the markup
061: * 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 org.apache.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: tag.setAutoComponentTag(true);
098: tag.setModified(true);
099: }
100:
101: return tag;
102: } else {
103: // we found <wicket:head>
104: foundHead = true;
105: }
106: } else if (BODY.equalsIgnoreCase(tag.getName())
107: && (tag.getNamespace() == null)) {
108: // We found <body>
109: if (foundHead == false) {
110: insertHeadTag();
111: }
112:
113: // <head> must always be before <body>
114: ignoreTheRest = true;
115: return tag;
116: }
117:
118: return tag;
119: }
120:
121: /**
122: * Insert <head> open and close tag (with empty body) to the current
123: * position.
124: */
125: private void insertHeadTag() {
126: // Note: only the open-tag must be a AutoComponentTag
127: final ComponentTag openTag = new ComponentTag(HEAD, XmlTag.OPEN);
128: openTag.setId(HEADER_ID);
129: openTag.setAutoComponentTag(true);
130: openTag.setModified(true);
131:
132: final ComponentTag closeTag = new ComponentTag(HEAD,
133: XmlTag.CLOSE);
134: closeTag.setOpenTag(openTag);
135: closeTag.setModified(true);
136:
137: // insert the tags into the markup stream
138: markup.addMarkupElement(openTag);
139: markup.addMarkupElement(closeTag);
140: }
141: }
|