001: /*
002: * $Id: org.eclipse.jdt.ui.prefs 5004 2006-03-17 20:47:08 -0800 (Fri, 17 Mar
003: * 2006) eelco12 $ $Revision: 5004 $ $Date: 2006-03-17 20:47:08 -0800 (Fri, 17
004: * Mar 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.MarkupElement;
025: import wicket.markup.WicketTag;
026: import wicket.markup.parser.AbstractMarkupFilter;
027: import wicket.util.string.AppendingStringBuffer;
028:
029: /**
030: * Handler that sets unique tag id for every inline script and style element in
031: * <wicket:head>, unless the element already has one. <br/> This is needed
032: * to be able to dedect multiple ajax header contribution. Tags that are not
033: * inline (stript with src attribute set and link with href attribute set) do
034: * not require id, because the detection is done by comparing URLs.
035: * <p>
036: * Tags with wicket:id are <strong>not processed</strong>. To
037: * setOutputWicketId(true) on attached component is developer's responsibility.
038: * FIXME: Really? And if so, document properly
039: *
040: * @author Matej Knopp
041: */
042: public class HeadForceTagIdHandler extends AbstractMarkupFilter {
043: /** Common prefix for all id's generated by this filter */
044: private final String headElementIdPrefix;
045:
046: /** Unique value per markup file */
047: private int counter = 0;
048:
049: /** we are in wicket:head */
050: private boolean inHead = false;
051:
052: /**
053: * Construct.
054: *
055: * @param parent
056: * @param markupFileClass Used to generated the a common prefix for the id
057: */
058: public HeadForceTagIdHandler(final Class markupFileClass) {
059: // generate the prefix from class name
060: final AppendingStringBuffer buffer = new AppendingStringBuffer(
061: markupFileClass.getName());
062: for (int i = 0; i < buffer.getValue().length; ++i) {
063: if (Character.isLetterOrDigit(buffer.getValue()[i]) == false) {
064: buffer.getValue()[i] = '-';
065: }
066: }
067:
068: buffer.append("-");
069: this .headElementIdPrefix = buffer.toString();
070: }
071:
072: /**
073: * @see wicket.markup.parser.IMarkupFilter#nextTag()
074: */
075: public MarkupElement nextTag() throws ParseException {
076: final ComponentTag tag = (ComponentTag) getParent().nextTag();
077:
078: if (tag != null) {
079: // is it a <wicket:head> tag?
080: if (tag instanceof WicketTag
081: && ((WicketTag) tag).isHeadTag()) {
082: this .inHead = tag.isOpen();
083: }
084: // no, it's not. Are we in <wicket:head> ?
085: else if (this .inHead == true) {
086: // is the tag open and has empty wicket:id?
087: if ((tag instanceof WicketTag == false)
088: && (tag.getId() == null)
089: && (tag.isOpen() || tag.isOpenClose())
090: && needId(tag)) {
091: if (tag.getAttributes().get("id") == null) {
092: tag.getAttributes().put("id",
093: headElementIdPrefix + nextValue());
094: tag.setModified(true);
095: }
096: }
097: }
098: }
099:
100: return tag;
101: }
102:
103: /**
104: *
105: * @param tag
106: * @return true, if id is needed
107: */
108: private final boolean needId(final ComponentTag tag) {
109: final String name = tag.getName().toLowerCase();
110: if (name.equals("script")
111: && tag.getAttributes().containsKey("src") == false) {
112: return true;
113: } else if (name.equals("style")
114: && tag.getAttributes().containsKey("href") == false) {
115: return true;
116: }
117:
118: return false;
119: }
120:
121: /**
122: *
123: * @return The next value
124: */
125: private final int nextValue() {
126: return counter++;
127: }
128: }
|