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.MarkupContainer;
020import org.apache.wicket.Page;
021import org.apache.wicket.WicketRuntimeException;
022import org.apache.wicket.markup.ComponentTag;
023import org.apache.wicket.markup.IMarkupFragment;
024import org.apache.wicket.markup.MarkupResourceStream;
025import org.apache.wicket.markup.MarkupStream;
026import org.apache.wicket.markup.WicketTag;
027import org.apache.wicket.util.lang.Args;
028import org.apache.wicket.util.visit.IVisit;
029import org.apache.wicket.util.visit.IVisitor;
030
031/**
032 * HTML5 helper
033 * 
034 * @author Juergen Donnerstag
035 */
036public class MarkupUtil
037{
038        /**
039         * 
040         * @param container
041         * @return True if the Page and all it's Panels, Borders etc. have HTML5 compliant markup. HTML5
042         *         markup is identified by <DOCTYPE html>
043         */
044        public static boolean isMarkupHtml5Compliant(final MarkupContainer container)
045        {
046                Args.notNull(container, "container");
047
048                Page page = container.getPage();
049
050                final boolean rtn[] = new boolean[] { true };
051                page.visitChildren(MarkupContainer.class, new IVisitor<MarkupContainer, Void>()
052                {
053                        @Override
054                        public void component(final MarkupContainer comp, final IVisit<Void> visit)
055                        {
056                                IMarkupFragment associatedMarkup = comp.getAssociatedMarkup();
057                                if (associatedMarkup != null)
058                                {
059                                        MarkupResourceStream rs = associatedMarkup.getMarkupResourceStream();
060                                        if (rs.isHtml5() == false)
061                                        {
062                                                rtn[0] = false;
063                                                visit.stop();
064                                        }
065                                }
066                        }
067                });
068
069                return rtn[0];
070        }
071        
072        /**
073         * Searches for {@code tagName} in the given {@code markup}.
074         * 
075         * @param markup
076         * @param tagName
077         * @return The {@link IMarkupFragment} corresponding to {@code tagName}. Null, if such {@code tagName} is not found
078         */
079        public static IMarkupFragment findStartTag(final IMarkupFragment markup, final String tagName)
080        {
081                MarkupStream stream = new MarkupStream(markup);
082
083                while (stream.skipUntil(WicketTag.class))
084                {
085                        ComponentTag tag = stream.getTag();
086                        if (tag.isOpen() || tag.isOpenClose())
087                        {
088                                WicketTag wtag = (WicketTag)tag;
089                                if (tagName.equalsIgnoreCase(wtag.getName()))
090                                {
091                                        return stream.getMarkupFragment();
092                                }
093
094                                stream.skipToMatchingCloseTag(tag);
095                        }
096
097                        stream.next();
098                }
099
100                return null;
101        }
102}