blob: f2c2738f3d7ff874cf3e9a157a08d08e1fbf16b0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2015 Tasktop Technologies and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* David Green - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.wikitext.html;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.mylyn.wikitext.html.internal.FontElementStrategy;
import org.eclipse.mylyn.wikitext.html.internal.HtmlSubsetLanguage;
import org.eclipse.mylyn.wikitext.html.internal.LiteralHtmlDocumentHandler;
import org.eclipse.mylyn.wikitext.html.internal.SpanHtmlElementStrategy;
import org.eclipse.mylyn.wikitext.parser.Attributes;
import org.eclipse.mylyn.wikitext.parser.DocumentBuilder;
import org.eclipse.mylyn.wikitext.parser.DocumentBuilder.BlockType;
import org.eclipse.mylyn.wikitext.parser.DocumentBuilder.SpanType;
import org.eclipse.mylyn.wikitext.parser.builder.HtmlDocumentBuilder;
import org.eclipse.mylyn.wikitext.parser.builder.HtmlDocumentHandler;
import org.eclipse.mylyn.wikitext.parser.markup.MarkupLanguage;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
/**
* Provides a way to build HTML languages that support a specific set of HTML tags.
*
* @author david.green
* @see HtmlLanguage#builder()
* @since 3.0
*/
public class HtmlLanguageBuilder {
private String name;
private final Set<BlockType> blockTypes = Sets.newHashSet();
private final Set<SpanType> spanTypes = Sets.newHashSet();
private final Map<SpanType, String> spanTypeToElementNameSubstitution = Maps.newHashMap();
private final List<SpanHtmlElementStrategy> spanElementStrategies = new ArrayList<>();
private int headingLevel;
private LiteralHtmlDocumentHandler documentHandler;
private boolean xhtmlStrict;
private boolean supportsImages = true;
HtmlLanguageBuilder() {
// prevent direct instantiation
}
/**
* Sets the {@link MarkupLanguage#getName() name} of the markup language.
*
* @param name
* the name
* @return this builder
*/
public HtmlLanguageBuilder name(String name) {
requireNonNull(name, "Must provide a name"); //$NON-NLS-1$
checkArgument(!Strings.isNullOrEmpty(name), "Name must not be empty"); //$NON-NLS-1$
checkArgument(!name.equalsIgnoreCase(HtmlLanguage.NAME_HTML), "Name must not be equal to %s", //$NON-NLS-1$
HtmlLanguage.NAME_HTML);
checkArgument(name.equals(name.trim()), "Name must not have leading or trailing whitespace"); //$NON-NLS-1$
this.name = name;
return this;
}
/**
* Adds the given {@link BlockType} to the supported syntax of the language created by this builder.
* <p>
* Adding {@link BlockType#TABLE}, {@link BlockType#BULLETED_LIST}, {@link BlockType#NUMERIC_LIST} or
* {@link BlockType#DEFINITION_LIST} will cause the corresponding related blocks to be added. For example, adding
* {@link BlockType#BULLETED_LIST} also adds {@link BlockType#LIST_ITEM}.
* </p>
*
* @param blockType
* the block type
* @return this builder
*/
public HtmlLanguageBuilder add(BlockType blockType) {
blockTypes.add(requireNonNull(blockType, "Must provide a blockType")); //$NON-NLS-1$
return this;
}
/**
* Adds the given {@link SpanType} to the supported syntax of the language created by this builder.
*
* @param spanType
* the span type
* @return this builder
*/
public HtmlLanguageBuilder add(SpanType spanType) {
spanTypes.add(requireNonNull(spanType, "Must provide a spanType")); //$NON-NLS-1$
return this;
}
/**
* Adds to the syntax of the language created by this builder an {@code alternativeTagName} to be used when the
* given {@link SpanType} is {@link DocumentBuilder#beginSpan(SpanType, Attributes) started}.
*
* @param spanType
* the span type
* @param alternativeTagName
* the tag name to be used
* @return this builder
* @see HtmlDocumentBuilder#setElementNameOfSpanType(SpanType, String)
*/
public HtmlLanguageBuilder addSubstitution(SpanType spanType, String alternativeTagName) {
requireNonNull(spanType, "Must provide a spanType"); //$NON-NLS-1$
requireNonNull(alternativeTagName, "Must provide an alternativeTagName"); //$NON-NLS-1$
spanTypeToElementNameSubstitution.put(spanType, alternativeTagName);
return this;
}
/**
* Adds support for headings up to and including the specified level.
*
* @param level
* the level which must be a number between 1 and 6 inclusive
* @return this builder
*/
public HtmlLanguageBuilder addHeadings(int level) {
checkArgument(level > 0 && level <= 6, "Heading level must be between 1 and 6"); //$NON-NLS-1$
headingLevel = level;
return this;
}
/**
* Adds support for the {@code <font>} HTML tag as a {@link SpanType#SPAN}. The resulting document builder will
* convert {@link SpanType#SPAN} with {@code size} or {@code colour} CSS rules to {@code <font>} when generating
* HTML.
*
* @return
*/
public HtmlLanguageBuilder addSpanFont() {
spanElementStrategies.add(new FontElementStrategy());
return this;
}
/**
* Indicate if the resulting document builder should attempt to conform to strict XHTML rules. The default is false.
*
* @param xhtmlStrict
* true if the language should attempt to conform to XHTML strict rules, otherwise false
* @return this builder
*/
public HtmlLanguageBuilder setXhtmlStrict(boolean xhtmlStrict) {
this.xhtmlStrict = xhtmlStrict;
return this;
}
/**
* Provides a prefix and suffix which are emitted as literals at the start and end of content created using the
* {@link MarkupLanguage#createDocumentBuilder(java.io.Writer, boolean) document builder}.
*
* @param prefix
* the prefix which is an HTML literal value that precedes the content, for example {@code "<div>"} or
* {@code "<html><body>"}. May be empty.
* @param suffix
* the prefix which is an HTML literal value that precedes the content, for example {@code "</div>"} or
* {@code "</body></html>"}. May be empty.
* @return this builder
* @see HtmlDocumentHandler
*/
public HtmlLanguageBuilder document(String prefix, String suffix) {
requireNonNull(prefix, "Must provide a prefix"); //$NON-NLS-1$
requireNonNull(suffix, "Must provide a suffix"); //$NON-NLS-1$
documentHandler = new LiteralHtmlDocumentHandler(prefix, suffix);
return this;
}
/**
* Indicate if the resulting document builder should support HTML img tags or strip them out. The default is true.
*
* @param supportsImages
* true if the language should support HTML image tags, false if they are to be stripped out
* @return this builder
*/
public HtmlLanguageBuilder setSupportsImages(boolean supportsImages) {
this.supportsImages = supportsImages;
return this;
}
public HtmlLanguage create() {
checkState(name != null, "Name must be provided to create an HtmlLanguage"); //$NON-NLS-1$
return new HtmlSubsetLanguage(name, documentHandler, headingLevel, blockTypes, spanTypes,
spanTypeToElementNameSubstitution, spanElementStrategies, xhtmlStrict, supportsImages);
}
}