| /* |
| * Copyright 2009 Google Inc. |
| * |
| * Licensed 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 com.google.gwt.safehtml.rebind; |
| |
| import com.google.gwt.thirdparty.guava.common.base.Preconditions; |
| |
| import java.util.Collections; |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| /** |
| * A representation of a parsed HTML template. |
| * |
| * <p>A parsed template is represented as a sequence of template chunks. |
| * |
| * <p>A chunk may correspond to a literal string or to a formal template |
| * parameter. |
| * |
| * <p>Parameter chunks have an attribute that refers to the index of the |
| * corresponding template method parameter, as well as an attribute that |
| * represents the HTML context the template parameter appeared in. |
| */ |
| final class ParsedHtmlTemplate { |
| |
| /** |
| * A representation of the context of a point within a HTML document. A |
| * context consists of a type (such as "plain text", "attribute"), as well as |
| * a HTML tag and attribute name where applicable. |
| */ |
| static final class HtmlContext { |
| /** |
| * The possible types of HTML context. |
| */ |
| static enum Type { |
| /** |
| * Regular inner text HTML context. |
| */ |
| TEXT, |
| /** |
| * Value of a HTML attribute. |
| */ |
| ATTRIBUTE_VALUE, |
| /** |
| * At the very start of a URL-valued attribute. |
| */ |
| URL_ATTRIBUTE_START, |
| /** |
| * A template parameter that comprises an entire URL-valued attribute. |
| */ |
| URL_ATTRIBUTE_ENTIRE, |
| /** |
| * CSS (style) context. |
| */ |
| CSS, |
| /** |
| * CSS (style) attribute context. |
| */ |
| CSS_ATTRIBUTE, |
| /** |
| * At the very start of a CSS (style) attribute context. |
| */ |
| CSS_ATTRIBUTE_START |
| } |
| |
| private final Type type; |
| private final String tag; |
| private final String attribute; |
| |
| /** |
| * Creates a HTML context. |
| * |
| * @param type the {@link Type} of this context |
| */ |
| public HtmlContext(Type type) { |
| this(type, null, null); |
| } |
| |
| /** |
| * Creates a HTML context. |
| * |
| * @param type the {@link Type} of this context |
| * @param tag the HTML tag this context corresponds to, if applicable; null |
| * otherwise |
| * @param attribute the HTML attribute this context corresponds to, if |
| * applicable; null otherwise |
| */ |
| public HtmlContext(Type type, String tag, String attribute) { |
| Preconditions.checkArgument((type != Type.TEXT) |
| || ((tag == null) && (attribute == null)), |
| "tag and attribute must be null for context \"TEXT\""); |
| this.type = type; |
| this.tag = tag; |
| this.attribute = attribute; |
| } |
| |
| /** |
| * Returns the attribute of this HTML context. |
| */ |
| public String getAttribute() { |
| return attribute; |
| } |
| |
| /** |
| * Returns the tag of this HTML context. |
| */ |
| public String getTag() { |
| return tag; |
| } |
| |
| /** |
| * Returns the type of this HTML context. |
| */ |
| public Type getType() { |
| return type; |
| } |
| |
| @Override |
| public String toString() { |
| return "(" + getType() + "," + getTag() + "," + getAttribute() + ")"; |
| } |
| } |
| |
| /** |
| * Represents a template chunk corresponding to a literal string. |
| */ |
| static final class LiteralChunk implements TemplateChunk { |
| private final StringBuilder chunk; |
| |
| /** |
| * Creates a literal chunk corresponding to an empty string. |
| */ |
| public LiteralChunk() { |
| chunk = new StringBuilder(); |
| } |
| |
| /** |
| * Creates a literal chunk corresponding to the provided string. |
| */ |
| public LiteralChunk(String literal) { |
| chunk = new StringBuilder(literal); |
| } |
| |
| public Kind getKind() { |
| return Kind.LITERAL; |
| } |
| |
| public String getLiteral() { |
| return chunk.toString(); |
| } |
| |
| @Override |
| public String toString() { |
| return String.format("L(%s)", getLiteral()); |
| } |
| |
| void append(String s) { |
| chunk.append(s); |
| } |
| } |
| |
| /** |
| * Represents a template chunk corresponding to a template parameter. |
| */ |
| static final class ParameterChunk implements TemplateChunk { |
| |
| private final HtmlContext context; |
| private final int parameterIndex; |
| |
| /** |
| * Creates a parameter chunk. |
| * |
| * @param context the HTML context this parameter appears in |
| * @param parameterIndex the index of the template parameter that this chunk |
| * refers to |
| */ |
| public ParameterChunk(HtmlContext context, int parameterIndex) { |
| this.context = context; |
| this.parameterIndex = parameterIndex; |
| } |
| |
| /** |
| * Returns the HTML context this parameter appears in. |
| */ |
| public HtmlContext getContext() { |
| return context; |
| } |
| |
| public Kind getKind() { |
| return Kind.PARAMETER; |
| } |
| |
| /** |
| * Returns the index of the template parameter that this chunk refers to. |
| */ |
| public int getParameterIndex() { |
| return parameterIndex; |
| } |
| |
| @Override |
| public String toString() { |
| return String.format("P(%s,%d)", getContext(), getParameterIndex()); |
| } |
| } |
| |
| /** |
| * Represents a parsed chunk of a template. |
| * |
| * <p>There are two kinds of chunks: Those representing literal strings and |
| * those representing template parameters. |
| */ |
| interface TemplateChunk { |
| /** |
| * Distinguishes different kinds of {@link TemplateChunk}. |
| */ |
| public static enum Kind { |
| LITERAL, PARAMETER, |
| } |
| |
| /** |
| * Returns the {@link Kind} of this template chunk. |
| */ |
| Kind getKind(); |
| } |
| |
| /* |
| * The chunks of this parsed template. |
| */ |
| private final LinkedList<TemplateChunk> chunks; |
| |
| /** |
| * Initializes an empty parsed HTML template. |
| */ |
| public ParsedHtmlTemplate() { |
| chunks = new LinkedList<TemplateChunk>(); |
| } |
| |
| /** |
| * Adds a literal string to the template. |
| * |
| * If the currently last chunk of the parsed template is a literal chunk, the |
| * provided string literal will be appended to that chunk. I.e., consecutive |
| * literal chunks are automatically coalesced. |
| |
| * @param literal the string to be added as a literal chunk |
| */ |
| public void addLiteral(String literal) { |
| if (chunks.isEmpty() |
| || (chunks.getLast().getKind() != TemplateChunk.Kind.LITERAL)) { |
| chunks.add(new LiteralChunk(literal)); |
| } else { |
| ((LiteralChunk) chunks.getLast()).append(literal); |
| } |
| } |
| |
| /** |
| * Adds a parameter chunk to the template. |
| * |
| * @param chunk the chunk to be added |
| */ |
| public void addParameter(ParameterChunk chunk) { |
| chunks.add(chunk); |
| } |
| |
| /** |
| * Returns the chunks of this parsed template. |
| * |
| * <p>The returned list is unmodifiable. |
| */ |
| public List<TemplateChunk> getChunks() { |
| return Collections.unmodifiableList(chunks); |
| } |
| |
| @Override |
| public String toString() { |
| return chunks.toString(); |
| } |
| } |