TMP
authorKai Moritz <kai@juplo.de>
Wed, 24 Apr 2019 14:27:47 +0000 (16:27 +0200)
committerKai Moritz <kai@juplo.de>
Wed, 24 Apr 2019 14:27:47 +0000 (16:27 +0200)
src/main/java/de/juplo/thymeleaf/AbstractSubstituteAttrProcessor.java
src/main/java/de/juplo/thymeleaf/ActiveAttrProcessor.java
src/main/java/de/juplo/thymeleaf/InactiveAttrProcessor.java
src/main/java/de/juplo/thymeleaf/JuploDialect.java

index 6274016..09b30d1 100644 (file)
@@ -1,14 +1,20 @@
 package de.juplo.thymeleaf;
 
 
-import org.thymeleaf.Arguments;
-import org.thymeleaf.Configuration;
-import org.thymeleaf.dom.Element;
-import org.thymeleaf.processor.ProcessorResult;
-import org.thymeleaf.processor.attr.AbstractAttrProcessor;
-import org.thymeleaf.standard.expression.IStandardExpression;
-import org.thymeleaf.standard.expression.IStandardExpressionParser;
-import org.thymeleaf.standard.expression.StandardExpressions;
+import java.util.HashMap;
+import java.util.Map;
+import org.thymeleaf.context.ITemplateContext;
+import org.thymeleaf.engine.AttributeName;
+import org.thymeleaf.engine.EngineEventUtils;
+import org.thymeleaf.model.IAttribute;
+import org.thymeleaf.model.ICloseElementTag;
+import org.thymeleaf.model.IModel;
+import org.thymeleaf.model.IModelFactory;
+import org.thymeleaf.model.IProcessableElementTag;
+import org.thymeleaf.model.ITemplateEvent;
+import org.thymeleaf.processor.element.AbstractAttributeModelProcessor;
+import org.thymeleaf.processor.element.IElementModelStructureHandler;
+import org.thymeleaf.templatemode.TemplateMode;
 
 
 /**
@@ -16,74 +22,119 @@ import org.thymeleaf.standard.expression.StandardExpressions;
  *
  * @author kai
  */
-public abstract class AbstractSubstituteAttrProcessor extends AbstractAttrProcessor
+public abstract class AbstractSubstituteAttrProcessor
+    extends
+      AbstractAttributeModelProcessor
 {
   public static final int ATTR_PRECEDENCE = 100;
 
+
+  private final String attributeName;
   private final String substituteName;
 
 
-  public AbstractSubstituteAttrProcessor(String attribute, String substitute)
+  public AbstractSubstituteAttrProcessor(
+      final String prefix,
+      final String attribute,
+      final String substitute
+      )
   {
-    super(attribute);
+    super(
+        TemplateMode.HTML,
+        prefix,
+        null,
+        false,
+        attribute,
+        true,
+        ATTR_PRECEDENCE,
+        false
+        );
+    this.attributeName = attribute;
     this.substituteName = substitute;
   }
 
 
   @Override
-  protected final ProcessorResult processAttribute(
-      Arguments arguments,
-      Element element,
-      String name
+  protected void doProcess(
+      final ITemplateContext context,
+      final IModel model,
+      final AttributeName attributeName,
+      final String attributeValue,
+      final IElementModelStructureHandler handler
       )
   {
-    Configuration configuration = arguments.getConfiguration();
-    IStandardExpressionParser parser =
-        StandardExpressions.getExpressionParser(configuration);
-    String value = element.getAttributeValue(name);
-    IStandardExpression expression =
-        parser.parseExpression(configuration, arguments, value);
-    element.removeAttribute(name);
-    if ((Boolean)expression.execute(configuration, arguments))
+    final IProcessableElementTag element = (IProcessableElementTag) model.get(0);
+    final Object result =
+        EngineEventUtils.computeAttributeExpression(
+            context,
+            element,
+            attributeName,
+            attributeValue
+            )
+            .execute(context);
+
+    if (result == null || !(result instanceof Boolean))
     {
-      // We must not clone the processors, because we remove attributes
-      Element substituteElement =
-          element.cloneElementNodeWithNewName(element, substituteName, false);
-      // Remove attributes, that are not allowed for <span> or <strong>
-      substituteElement.removeAttribute("charset");
-      substituteElement.removeAttribute("th:charset");
-      substituteElement.removeAttribute("coords");
-      substituteElement.removeAttribute("href");
-      substituteElement.removeAttribute("th:href");
-      substituteElement.removeAttribute("hreflang");
-      substituteElement.removeAttribute("th:hreflang");
-      substituteElement.removeAttribute("media");
-      substituteElement.removeAttribute("th:media");
-      substituteElement.removeAttribute("name");
-      substituteElement.removeAttribute("th:name");
-      substituteElement.removeAttribute("rel");
-      substituteElement.removeAttribute("th:rel");
-      substituteElement.removeAttribute("ref");
-      substituteElement.removeAttribute("th:ref");
-      substituteElement.removeAttribute("shape");
-      substituteElement.removeAttribute("target");
-      substituteElement.removeAttribute("th:target");
-      substituteElement.removeAttribute("type");
-      substituteElement.removeAttribute("th:type");
-      // Also remove the title-attribute, because the mouse-over is confusing
-      substituteElement.removeAttribute("title");
-      substituteElement.removeAttribute("th:title");
-      // Replace the element
-      element.clearChildren();
-      element.addChild(substituteElement);
-      element.getParent().extractChild(element);
+      return;
     }
-    return ProcessorResult.OK;
-  }
 
-  @Override
-  public final int getPrecedence()
-  {
-    return ATTR_PRECEDENCE;
+
+    IModelFactory factory = context.getModelFactory();
+
+    if ((Boolean)result)
+    {
+      Map<String, String> attributes = new HashMap<>();
+
+      for (IAttribute attribute : element.getAllAttributes())
+      {
+        String name =
+            attribute
+                .getAttributeDefinition()
+                .getAttributeName()
+                .getAttributeName()
+                .toLowerCase();
+        switch (name)
+        {
+          case "charset":
+          case "coords":
+          case "href":
+          case "hreflang":
+          case "media":
+          case "name":
+          case "rel":
+          case "ref":
+          case "shape":
+          case "target":
+          case "type":
+          // Also remove the title-attribute, because the mouse-over is confusing
+          case "title":
+            break;
+          default:
+            if (name.equals(this.attributeName))
+              continue;
+            attributes.put(attribute.getAttributeCompleteName(), attribute.getValue());
+        }
+      }
+
+      ITemplateEvent tag;
+      tag = factory.createOpenElementTag(substituteName, attributes, null, false);
+      model.replace(0, tag);
+      for (int i = model.size(); i > 0; --i)
+      {
+        tag = model.get(i);
+        if (!(tag instanceof ICloseElementTag))
+          continue;
+        ICloseElementTag close = (ICloseElementTag)tag;
+        if (close.isUnmatched())
+          continue;
+        if (close.getElementCompleteName().equals(element.getElementCompleteName()))
+        {
+          model.replace(i, factory.createCloseElementTag(substituteName, close.isSynthetic(), close.isUnmatched()));
+          break;
+        }
+      }
+    }
+    else
+      model.replace(0, factory.removeAttribute(element, attributeName));
   }
 }
index ef17d00..7392bf9 100644 (file)
@@ -6,10 +6,10 @@ package de.juplo.thymeleaf;
  * marked as active.
  * @author Kai Moritz
  */
-public class ActiveAttrProcessor extends AbstractSubstituteAttrProcessor
+public class ActiveAttrProcessor extends AbstractSubstituteAttrrocessor
 {
-  public ActiveAttrProcessor()
+  public ActiveAttrProcessor(final String prefix)
   {
-    super("active", "strong");
+    super(prefix, "active", "strong");
   }
 }
index f04074c..6c6ca4b 100644 (file)
@@ -8,8 +8,8 @@ package de.juplo.thymeleaf;
  */
 public class InactiveAttrProcessor extends AbstractSubstituteAttrProcessor
 {
-  public InactiveAttrProcessor()
+  public InactiveAttrProcessor(final String prefix)
   {
-    super("inactive", "span");
+    super(prefix, "inactive", "span");
   }
 }
index e4d2d5b..21cf8ac 100644 (file)
@@ -2,8 +2,10 @@ package de.juplo.thymeleaf;
 
 
 import java.util.HashSet;
+import java.util.Locale;
 import java.util.Set;
-import org.thymeleaf.dialect.AbstractDialect;
+import org.springframework.context.MessageSource;
+import org.thymeleaf.dialect.AbstractProcessorDialect;
 import org.thymeleaf.processor.IProcessor;
 
 
@@ -11,29 +13,34 @@ import org.thymeleaf.processor.IProcessor;
  * A collection of usefull tools.
  * @author Kai Moritz
  */
-public class JuploDialect extends AbstractDialect
+public class JuploDialect extends AbstractProcessorDialect
 {
+  public static final String DIALECT_NAME = "juplo-Dialect";
   public static final String DIALECT_PREFIX = "juplo";
+  public static final int DIALECT_PRECEDENCE = 200;
 
 
-  public JuploDialect()
-  {
-    super();
-  }
+  final MessageSource messageSource;
+  final Locale defaultLocale;
 
 
-  @Override
-  public String getPrefix()
+  public JuploDialect(
+      final MessageSource messageSource,
+      final Locale defaultLocale
+      )
   {
-    return DIALECT_PREFIX;
+    super(DIALECT_NAME, DIALECT_PREFIX, DIALECT_PRECEDENCE);
+    this.messageSource = messageSource;
+    this.defaultLocale = defaultLocale;
   }
 
+
   @Override
-  public Set<IProcessor> getProcessors()
+  public Set<IProcessor> getProcessors(String prefix)
   {
     final Set<IProcessor> processors = new HashSet<>();
-    processors.add(new ActiveAttrProcessor());
-    processors.add(new InactiveAttrProcessor());
+    processors.add(new ActiveAttributeProcessor(prefix));
+    processors.add(new InactiveAttributeProcessor(prefix));
     processors.add(new ImportVariablesAttrProcessor());
     return processors;
   }