/* * ============================================================================= * * Copyright (c) 2011-2016, The THYMELEAF team (http://www.thymeleaf.org) * * 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 org.thymeleaf.engine; import java.io.IOException; import java.io.Writer; import java.util.Arrays; import org.thymeleaf.model.AttributeValueQuotes; import org.thymeleaf.model.IAttribute; import org.thymeleaf.model.IModelVisitor; import org.thymeleaf.model.IOpenElementTag; import org.thymeleaf.templatemode.TemplateMode; /** * * @author Daniel Fernández * @since 3.0.0 * */ final class OpenElementTag extends AbstractProcessableElementTag implements IOpenElementTag, IEngineTemplateEvent { OpenElementTag( final TemplateMode templateMode, final ElementDefinition elementDefinition, final String elementCompleteName, final Attributes attributes, final boolean synthetic) { super(templateMode, elementDefinition, elementCompleteName, attributes, synthetic); } OpenElementTag( final TemplateMode templateMode, final ElementDefinition elementDefinition, final String elementCompleteName, final Attributes attributes, final boolean synthetic, final String templateName, final int line, final int col) { super(templateMode, elementDefinition, elementCompleteName, attributes, synthetic, templateName, line, col); } OpenElementTag setAttribute( final AttributeDefinitions attributeDefinitions, final AttributeDefinition attributeDefinition, final String completeName, final String value, final AttributeValueQuotes valueQuotes) { final Attributes oldAttributes = (this.attributes != null? this.attributes : Attributes.EMPTY_ATTRIBUTES); final Attributes newAttributes = oldAttributes.setAttribute(attributeDefinitions, this.templateMode, attributeDefinition, completeName, value, valueQuotes); return new OpenElementTag(this.templateMode, this.elementDefinition, this.elementCompleteName, newAttributes, this.synthetic, this.templateName, this.line, this.col); } OpenElementTag replaceAttribute( final AttributeDefinitions attributeDefinitions, final AttributeName oldName, final AttributeDefinition newAttributeDefinition, final String completeNewName, final String value, final AttributeValueQuotes valueQuotes) { final Attributes oldAttributes = (this.attributes != null? this.attributes : Attributes.EMPTY_ATTRIBUTES); final Attributes newAttributes = oldAttributes.replaceAttribute(attributeDefinitions, this.templateMode, oldName, newAttributeDefinition, completeNewName, value, valueQuotes); return new OpenElementTag(this.templateMode, this.elementDefinition, this.elementCompleteName, newAttributes, this.synthetic, this.templateName, this.line, this.col); } OpenElementTag removeAttribute(final String prefix, final String name) { final Attributes oldAttributes = (this.attributes != null? this.attributes : Attributes.EMPTY_ATTRIBUTES); final Attributes newAttributes = oldAttributes.removeAttribute(this.templateMode, prefix, name); if (oldAttributes == newAttributes) { return this; } return new OpenElementTag(this.templateMode, this.elementDefinition, this.elementCompleteName, newAttributes, this.synthetic, this.templateName, this.line, this.col); } OpenElementTag removeAttribute(final String completeName) { final Attributes oldAttributes = (this.attributes != null? this.attributes : Attributes.EMPTY_ATTRIBUTES); final Attributes newAttributes = oldAttributes.removeAttribute(this.templateMode, completeName); if (oldAttributes == newAttributes) { return this; } return new OpenElementTag(this.templateMode, this.elementDefinition, this.elementCompleteName, newAttributes, this.synthetic, this.templateName, this.line, this.col); } OpenElementTag removeAttribute(final AttributeName attributeName) { final Attributes oldAttributes = (this.attributes != null? this.attributes : Attributes.EMPTY_ATTRIBUTES); final Attributes newAttributes = oldAttributes.removeAttribute(attributeName); if (oldAttributes == newAttributes) { return this; } return new OpenElementTag(this.templateMode, this.elementDefinition, this.elementCompleteName, newAttributes, this.synthetic, this.templateName, this.line, this.col); } public void accept(final IModelVisitor visitor) { visitor.visit(this); } public void write(final Writer writer) throws IOException { if (this.synthetic) { // Nothing to be written... synthetic elements were not present at the original template! return; } if (this.templateMode.isText()) { writer.write("[#"); writer.write(this.elementCompleteName); if (this.attributes != null) { this.attributes.write(writer); } writer.write("]"); return; } writer.write('<'); writer.write(this.elementCompleteName); if (this.attributes != null) { this.attributes.write(writer); } writer.write('>'); } // Meant to be called only from within the engine static OpenElementTag asEngineOpenElementTag(final IOpenElementTag openElementTag) { if (openElementTag instanceof OpenElementTag) { return (OpenElementTag) openElementTag; } final IAttribute[] originalAttributeArray = openElementTag.getAllAttributes(); final Attributes attributes; if (originalAttributeArray == null || originalAttributeArray.length == 0) { attributes = null; } else { // We will perform a deep cloning of the attributes into objects of the Attribute class, so that // we make sure absolutely all Attributes in the new event are under the engine's control final Attribute[] newAttributeArray = new Attribute[originalAttributeArray.length]; for (int i = 0; i < originalAttributeArray.length; i++) { final IAttribute originalAttribute = originalAttributeArray[i]; newAttributeArray[i] = new Attribute( originalAttribute.getAttributeDefinition(), originalAttribute.getAttributeCompleteName(), originalAttribute.getOperator(), originalAttribute.getValue(), originalAttribute.getValueQuotes(), originalAttribute.getTemplateName(), originalAttribute.getLine(), originalAttribute.getCol()); } final String[] newInnerWhiteSpaces; if (newAttributeArray.length == 1) { newInnerWhiteSpaces = Attributes.DEFAULT_WHITE_SPACE_ARRAY; } else { newInnerWhiteSpaces = new String[newAttributeArray.length]; Arrays.fill(newInnerWhiteSpaces, Attributes.DEFAULT_WHITE_SPACE); } attributes = new Attributes(newAttributeArray, newInnerWhiteSpaces); } return new OpenElementTag( openElementTag.getTemplateMode(), openElementTag.getElementDefinition(), openElementTag.getElementCompleteName(), attributes, openElementTag.isSynthetic(), openElementTag.getTemplateName(), openElementTag.getLine(), openElementTag.getCol()); } @Override public void beHandled(final ITemplateHandler handler) { handler.handleOpenElement(this); } }