From a7563799470ad8009908de46694091608d8c9f79 Mon Sep 17 00:00:00 2001
From: Thorsten Marx
Date: Wed, 9 Oct 2024 15:31:55 +0200
Subject: [PATCH 01/15] add jexl for expressions
---
cms-content/pom.xml | 4 ++
.../content/shortcodes/ShortCodeParser.java | 24 +++++---
.../cms/content/shortcodes/ShortCodes.java | 7 ++-
.../cms/content/ContentBaseTest.java | 45 ++++++++++++++
.../ShortCodeParserReplaceTest.java | 34 ++++++-----
.../shortcodes/ShortCodeParserTest.java | 15 ++---
.../content/shortcodes/ShortCodesTest.java | 10 ++--
...eeMarkerShortCodeTemplateFunctionTest.java | 15 +++--
.../PebbleShortCodeTemplateFunctionTest.java | 12 ++--
...hymeleafShortCodeTemplateFunctionTest.java | 13 +++--
cms-sandbox/pom.xml | 2 +-
cms-sandbox/tests/pom.xml | 22 +++++++
.../java/com/condation/cms/tests/Tests.java | 58 +++++++++++++++++++
.../cms/request/RequestContextFactory.java | 9 ++-
.../cms/server/configs/SiteModule.java | 7 +++
.../java/com/condation/cms/TestHelper.java | 5 +-
pom.xml | 6 ++
17 files changed, 232 insertions(+), 56 deletions(-)
create mode 100644 cms-content/src/test/java/com/condation/cms/content/ContentBaseTest.java
create mode 100644 cms-sandbox/tests/pom.xml
create mode 100644 cms-sandbox/tests/src/main/java/com/condation/cms/tests/Tests.java
diff --git a/cms-content/pom.xml b/cms-content/pom.xml
index 6ab4395dd..4f35b5428 100644
--- a/cms-content/pom.xml
+++ b/cms-content/pom.xml
@@ -35,6 +35,10 @@
org.jsoup
jsoup
+
+ org.apache.commons
+ commons-jexl3
+
org.freemarker
freemarker
diff --git a/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodeParser.java b/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodeParser.java
index c960a8dc2..2eddee9bd 100644
--- a/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodeParser.java
+++ b/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodeParser.java
@@ -29,15 +29,22 @@
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.jexl3.JexlEngine;
@Slf4j
public class ShortCodeParser {
+
+ JexlEngine engine;
public static final String SHORTCODE_REGEX = "\\[\\[(\\w+)([^\\]]*)\\]\\](.*?)\\[\\[\\/\\1\\]\\]|\\[\\[(\\w+)([^\\]]*)\\s*\\/\\]\\]";
public static final Pattern SHORTCODE_PATTERN = Pattern.compile(SHORTCODE_REGEX, Pattern.DOTALL);
public static final Pattern PARAM_PATTERN = Pattern.compile("(\\w+)=(\"[^\"]*\"|'[^']*')");
- public static List parseShortcodes(String text) {
+ public ShortCodeParser (JexlEngine engine) {
+ this.engine = engine;
+ }
+
+ public List parseShortcodes(String text) {
List shortcodes = new ArrayList<>();
Matcher matcher = SHORTCODE_PATTERN.matcher(text);
@@ -67,17 +74,16 @@ public static List parseShortcodes(String text) {
return shortcodes;
}
- public static String replace(String content, Codes codes) {
- String newContent = "";
-
+ public String replace(String content, Codes codes) {
+ StringBuilder newContent = new StringBuilder();
int lastPosition = 0;
var matches = parseShortcodes(content);
- for (var match : matches) {
- newContent += content.substring(lastPosition, match.getStart());
+ for (var match : matches) {
+ newContent.append(content, lastPosition, match.getStart());
try {
- newContent += codes.get(match.getName()).apply(match.getParameters());
+ newContent.append(codes.get(match.getName()).apply(match.getParameters()));
} catch (Exception e) {
log.error("error executing shortcode", e);
}
@@ -86,10 +92,10 @@ public static String replace(String content, Codes codes) {
}
if (content.length() > lastPosition) {
- newContent += content.substring(lastPosition);
+ newContent.append(content.substring(lastPosition));
}
- return newContent;
+ return newContent.toString();
}
@RequiredArgsConstructor
diff --git a/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java b/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
index 0a70b039d..27a8143dc 100644
--- a/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
+++ b/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
@@ -28,6 +28,7 @@
import java.util.function.Function;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.jexl3.JexlEngine;
/**
*
@@ -38,14 +39,16 @@
public class ShortCodes {
private final ShortCodeParser.Codes codes;
+ private final ShortCodeParser parser;
- public ShortCodes (Map> codes) {
+ public ShortCodes (Map> codes, ShortCodeParser shortCodeParser) {
+ this.parser = shortCodeParser;
this.codes = new ShortCodeParser.Codes();
this.codes.addAll(codes);
}
public String replace (final String content) {
- return ShortCodeParser.replace(content, codes);
+ return parser.replace(content, codes);
}
public String execute (String name, Map parameters) {
diff --git a/cms-content/src/test/java/com/condation/cms/content/ContentBaseTest.java b/cms-content/src/test/java/com/condation/cms/content/ContentBaseTest.java
new file mode 100644
index 000000000..883780f7f
--- /dev/null
+++ b/cms-content/src/test/java/com/condation/cms/content/ContentBaseTest.java
@@ -0,0 +1,45 @@
+package com.condation.cms.content;
+
+/*-
+ * #%L
+ * cms-content
+ * %%
+ * Copyright (C) 2023 - 2024 CondationCMS
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program. If not, see
+ * .
+ * #L%
+ */
+
+import com.condation.cms.content.shortcodes.ShortCodeParser;
+import org.apache.commons.jexl3.JexlBuilder;
+
+/**
+ *
+ * @author t.marx
+ */
+public abstract class ContentBaseTest {
+
+ private ShortCodeParser shortCodeParser;
+
+ public ShortCodeParser getShortCodeParser () {
+ if (shortCodeParser == null) {
+ shortCodeParser = new ShortCodeParser(
+ new JexlBuilder().cache(512).strict(true).silent(false).create()
+ );
+ }
+
+ return shortCodeParser;
+ }
+}
diff --git a/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodeParserReplaceTest.java b/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodeParserReplaceTest.java
index 133d5f070..743b6955b 100644
--- a/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodeParserReplaceTest.java
+++ b/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodeParserReplaceTest.java
@@ -23,20 +23,22 @@
*/
+import com.condation.cms.content.ContentBaseTest;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/**
*
* @author t.marx
*/
-public class ShortCodeParserReplaceTest {
+public class ShortCodeParserReplaceTest extends ContentBaseTest {
static ShortCodeParser.Codes tags;
- @BeforeAll
- public static void init () {
+ @BeforeEach
+ public void init () {
tags = new ShortCodeParser.Codes();
@@ -61,16 +63,16 @@ public static void init () {
@Test
void simpleTest () {
- var result = ShortCodeParser.replace("[[youtube /]]", tags);
+ var result = getShortCodeParser().replace("[[youtube /]]", tags);
Assertions.assertThat(result).isEqualTo(" ");
- result = ShortCodeParser.replace("[[youtube/]]", tags);
+ result = getShortCodeParser().replace("[[youtube/]]", tags);
Assertions.assertThat(result).isEqualTo(" ");
}
@Test
void simple_with_text_before_and_After () {
- var result = ShortCodeParser.replace("before [[youtube /]] after", tags);
+ var result = getShortCodeParser().replace("before [[youtube /]] after", tags);
Assertions.assertThat(result).isEqualTo("before after");
}
@@ -85,7 +87,7 @@ void complexTest () {
some text after
""";
- var result = ShortCodeParser.replace(content, tags);
+ var result = getShortCodeParser().replace(content, tags);
var expected = """
some text before
@@ -100,32 +102,32 @@ void complexTest () {
@Test
void unknown_tag () {
- var result = ShortCodeParser.replace("before [[vimeo id='TEST' /]] after", tags);
+ var result = getShortCodeParser().replace("before [[vimeo id='TEST' /]] after", tags);
Assertions.assertThat(result).isEqualToIgnoringWhitespace("before after");
}
@Test
void hello_from () {
- var result = ShortCodeParser.replace("[[hello_from name='Thorsten' from='Bochum' /]]", tags);
+ var result = getShortCodeParser().replace("[[hello_from name='Thorsten' from='Bochum' /]]", tags);
Assertions.assertThat(result).isEqualTo("
Thorsten from Bochum
");
- result = ShortCodeParser.replace("[[hello_from name='Thorsten' from='Bochum' /]]", tags);
+ result = getShortCodeParser().replace("[[hello_from name='Thorsten' from='Bochum' /]]", tags);
Assertions.assertThat(result).isEqualTo("
Thorsten from Bochum ");
- result = ShortCodeParser.replace("[[hello_from name='Thorsten' from='Bochum' /]]", tags);
+ result = getShortCodeParser().replace("[[hello_from name='Thorsten' from='Bochum' /]]", tags);
Assertions.assertThat(result).isEqualTo("
Thorsten from Bochum ");
}
@Test
void test_long () {
- var result = ShortCodeParser.replace("[[mark]]Important[[/mark]]", tags);
+ var result = getShortCodeParser().replace("[[mark]]Important[[/mark]]", tags);
Assertions.assertThat(result).isEqualTo("Important ");
}
@Test
void test_long_with_params () {
- var result = ShortCodeParser.replace("[[mark2 class='test-class']]Important[[/mark2]]", tags);
+ var result = getShortCodeParser().replace("[[mark2 class='test-class']]Important[[/mark2]]", tags);
Assertions.assertThat(result).isEqualTo("Important ");
}
@@ -141,7 +143,7 @@ void long_complex () {
some text after
""";
- var result = ShortCodeParser.replace(content,tags);
+ var result = getShortCodeParser().replace(content,tags);
var expected = """
some text before
@@ -162,7 +164,7 @@ void multiple_hello () {
var expected = """
Thorsten from Bochum
Thorsten from Bochum
""";
- var result = ShortCodeParser.replace(input, tags);
+ var result = getShortCodeParser().replace(input, tags);
Assertions.assertThat(result).isEqualTo(expected);
input = """
@@ -171,7 +173,7 @@ void multiple_hello () {
expected = """
Thorsten from Bochum
Thorsten from Bochum
""";
- result = ShortCodeParser.replace(input, tags);
+ result = getShortCodeParser().replace(input, tags);
Assertions.assertThat(result).isEqualTo(expected);
}
}
diff --git a/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodeParserTest.java b/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodeParserTest.java
index 157f5d8ac..30ea03983 100644
--- a/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodeParserTest.java
+++ b/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodeParserTest.java
@@ -23,17 +23,18 @@
*/
+import com.condation.cms.content.ContentBaseTest;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import java.util.List;
-public class ShortCodeParserTest {
+public class ShortCodeParserTest extends ContentBaseTest {
@Test
public void testParseShortcodes_singleShortcodeWithContent() {
String text = "This is a text with a shortcode [[code1 param1=\"value1\" param2=\"value2\"]]This is content[[/code1]].";
- List shortcodes = ShortCodeParser.parseShortcodes(text);
+ List shortcodes = getShortCodeParser().parseShortcodes(text);
assertEquals(1, shortcodes.size());
@@ -47,7 +48,7 @@ public void testParseShortcodes_singleShortcodeWithContent() {
@Test
public void testParseShortcodes_multipleShortcodes() {
String text = "This is a text with a shortcode [[code1 param1=\"value1\" param2=\"value2\"]]This is content[[/code1]] and another one [[code2 param1=\"value1\" param3=\"value3\" /]].";
- List shortcodes = ShortCodeParser.parseShortcodes(text);
+ List shortcodes = getShortCodeParser().parseShortcodes(text);
assertEquals(2, shortcodes.size());
@@ -67,7 +68,7 @@ public void testParseShortcodes_multipleShortcodes() {
@Test
public void testParseShortcodes_multipleShortcodes2() {
String text = "This is a text with a shortcode [[code1 param1=\"value1\" param2=\"value2\" ]]This is content[[/code1]] and another one [[code2 param1=\"value1\" param3=\"value3\"/]].";
- List shortcodes = ShortCodeParser.parseShortcodes(text);
+ List shortcodes = getShortCodeParser().parseShortcodes(text);
assertEquals(2, shortcodes.size());
@@ -87,7 +88,7 @@ public void testParseShortcodes_multipleShortcodes2() {
@Test
public void testParseShortcodes_noShortcodes() {
String text = "This text has no shortcodes.";
- List shortcodes = ShortCodeParser.parseShortcodes(text);
+ List shortcodes = getShortCodeParser().parseShortcodes(text);
assertEquals(0, shortcodes.size());
}
@@ -95,7 +96,7 @@ public void testParseShortcodes_noShortcodes() {
@Test
public void testParseShortcodes_emptyParameters() {
String text = "This is a text with a shortcode [[code1]][[/code1]] and another one [[code2 /]].";
- List shortcodes = ShortCodeParser.parseShortcodes(text);
+ List shortcodes = getShortCodeParser().parseShortcodes(text);
assertEquals(2, shortcodes.size());
@@ -111,7 +112,7 @@ public void testParseShortcodes_emptyParameters() {
@Test
public void testParseShortcodes_malformedShortcodes() {
String text = "This is a text with a malformed shortcode [[code1 param1=\"value1\" param2=\"value2\" .";
- List shortcodes = ShortCodeParser.parseShortcodes(text);
+ List shortcodes = getShortCodeParser().parseShortcodes(text);
assertEquals(0, shortcodes.size());
}
diff --git a/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java b/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java
index 2be9200af..8fff434a8 100644
--- a/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java
+++ b/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java
@@ -24,23 +24,25 @@
import com.condation.cms.api.model.Parameter;
+import com.condation.cms.content.ContentBaseTest;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/**
*
* @author t.marx
*/
-public class ShortCodesTest {
+public class ShortCodesTest extends ContentBaseTest {
static ShortCodes shortCodes;
- @BeforeAll
- public static void init () {
+ @BeforeEach
+ public void init () {
Map> tags = new HashMap<>();
tags.put(
"youtube",
@@ -59,7 +61,7 @@ public static void init () {
params -> "%s ".formatted(params.get("class"), params.get("content"))
);
- shortCodes = new ShortCodes(tags);
+ shortCodes = new ShortCodes(tags, getShortCodeParser());
}
diff --git a/cms-content/src/test/java/com/condation/cms/content/template/shortcode/FreeMarkerShortCodeTemplateFunctionTest.java b/cms-content/src/test/java/com/condation/cms/content/template/shortcode/FreeMarkerShortCodeTemplateFunctionTest.java
index 18bf04e1e..3d5fef036 100644
--- a/cms-content/src/test/java/com/condation/cms/content/template/shortcode/FreeMarkerShortCodeTemplateFunctionTest.java
+++ b/cms-content/src/test/java/com/condation/cms/content/template/shortcode/FreeMarkerShortCodeTemplateFunctionTest.java
@@ -23,6 +23,7 @@
*/
+import com.condation.cms.content.ContentBaseTest;
import com.condation.cms.content.template.functions.shortcode.ShortCodeTemplateFunction;
import com.condation.cms.content.shortcodes.ShortCodes;
import freemarker.template.Configuration;
@@ -34,29 +35,33 @@
import java.util.Map;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/**
*
* @author t.marx
*/
-public class FreeMarkerShortCodeTemplateFunctionTest {
+public class FreeMarkerShortCodeTemplateFunctionTest extends ContentBaseTest {
static Configuration cfg;
- static ShortCodes shortCodes;
+ ShortCodes shortCodes;
@BeforeAll
public static void setup() {
cfg = new Configuration(Configuration.VERSION_2_3_33);
cfg.setDefaultEncoding("UTF-8");
-
+ }
+
+ @BeforeEach
+ public void setupShortCodes() {
shortCodes = new ShortCodes(Map.of(
"echo", (params) -> "Hello world",
"greet", (params) -> "Hello " + params.get("name")
- ));
+ ), getShortCodeParser());
}
-
+
@Test
public void testSomeMethod() throws Exception {
String templateString = "${shortCode.call('echo')}";
diff --git a/cms-content/src/test/java/com/condation/cms/content/template/shortcode/PebbleShortCodeTemplateFunctionTest.java b/cms-content/src/test/java/com/condation/cms/content/template/shortcode/PebbleShortCodeTemplateFunctionTest.java
index d0c291b73..108e09e2d 100644
--- a/cms-content/src/test/java/com/condation/cms/content/template/shortcode/PebbleShortCodeTemplateFunctionTest.java
+++ b/cms-content/src/test/java/com/condation/cms/content/template/shortcode/PebbleShortCodeTemplateFunctionTest.java
@@ -23,6 +23,7 @@
*/
+import com.condation.cms.content.ContentBaseTest;
import com.condation.cms.content.template.functions.shortcode.ShortCodeTemplateFunction;
import com.condation.cms.content.shortcodes.ShortCodes;
import io.pebbletemplates.pebble.PebbleEngine;
@@ -34,15 +35,16 @@
import java.util.Map;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/**
*
* @author t.marx
*/
-public class PebbleShortCodeTemplateFunctionTest {
+public class PebbleShortCodeTemplateFunctionTest extends ContentBaseTest {
- static ShortCodes shortCodes;
+ ShortCodes shortCodes;
static PebbleEngine engine;
@@ -51,11 +53,13 @@ public static void setup() {
engine = new PebbleEngine.Builder()
.loader(new StringLoader())
.build();
-
+ }
+ @BeforeEach
+ public void setupShortCodes() {
shortCodes = new ShortCodes(Map.of(
"echo", (params) -> "Hello world",
"greet", (params) -> "Hello " + params.get("name")
- ));
+ ), getShortCodeParser());
}
@Test
diff --git a/cms-content/src/test/java/com/condation/cms/content/template/shortcode/ThymeleafShortCodeTemplateFunctionTest.java b/cms-content/src/test/java/com/condation/cms/content/template/shortcode/ThymeleafShortCodeTemplateFunctionTest.java
index 34b5e4ea0..1427a0b2b 100644
--- a/cms-content/src/test/java/com/condation/cms/content/template/shortcode/ThymeleafShortCodeTemplateFunctionTest.java
+++ b/cms-content/src/test/java/com/condation/cms/content/template/shortcode/ThymeleafShortCodeTemplateFunctionTest.java
@@ -23,11 +23,13 @@
*/
+import com.condation.cms.content.ContentBaseTest;
import com.condation.cms.content.template.functions.shortcode.ShortCodeTemplateFunction;
import com.condation.cms.content.shortcodes.ShortCodes;
import java.util.Map;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
@@ -37,9 +39,9 @@
*
* @author t.marx
*/
-public class ThymeleafShortCodeTemplateFunctionTest {
+public class ThymeleafShortCodeTemplateFunctionTest extends ContentBaseTest {
- static ShortCodes shortCodes;
+ ShortCodes shortCodes;
static TemplateEngine templateEngine;
@@ -51,11 +53,14 @@ public static void setup() {
templateEngine = new TemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
-
+ }
+
+ @BeforeEach
+ public void setupShortCodes() {
shortCodes = new ShortCodes(Map.of(
"echo", (params) -> "Hello world",
"greet", (params) -> "Hello " + params.get("name")
- ));
+ ), getShortCodeParser());
}
@Test
diff --git a/cms-sandbox/pom.xml b/cms-sandbox/pom.xml
index 5f0bd30e2..50662b7b8 100644
--- a/cms-sandbox/pom.xml
+++ b/cms-sandbox/pom.xml
@@ -9,6 +9,6 @@
cms-sandbox
pom
-
+ tests
\ No newline at end of file
diff --git a/cms-sandbox/tests/pom.xml b/cms-sandbox/tests/pom.xml
new file mode 100644
index 000000000..3a3b2487c
--- /dev/null
+++ b/cms-sandbox/tests/pom.xml
@@ -0,0 +1,22 @@
+
+
+ 4.0.0
+
+ com.condation.cms
+ cms-sandbox
+ 6.3.1
+
+ tests
+ jar
+
+ com.condation.cms.tests.Tests
+
+
+
+
+ org.apache.commons
+ commons-jexl3
+ 3.4.0
+
+
+
\ No newline at end of file
diff --git a/cms-sandbox/tests/src/main/java/com/condation/cms/tests/Tests.java b/cms-sandbox/tests/src/main/java/com/condation/cms/tests/Tests.java
new file mode 100644
index 000000000..b85c3ab54
--- /dev/null
+++ b/cms-sandbox/tests/src/main/java/com/condation/cms/tests/Tests.java
@@ -0,0 +1,58 @@
+package com.condation.cms.tests;
+
+/*-
+ * #%L
+ * tests
+ * %%
+ * Copyright (C) 2023 - 2024 CondationCMS
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program. If not, see
+ * .
+ * #L%
+ */
+
+import java.util.Arrays;
+import java.util.List;
+import org.apache.commons.jexl3.JexlBuilder;
+import org.apache.commons.jexl3.JexlContext;
+import org.apache.commons.jexl3.JexlEngine;
+import org.apache.commons.jexl3.MapContext;
+
+/**
+ *
+ * @author t.marx
+ */
+public class Tests {
+
+ private static final JexlEngine jexl = new JexlBuilder().cache(512).strict(true).silent(false).create();
+
+ public static void main(String[] args) throws Exception {
+ JexlContext context = new MapContext();
+ var expr = jexl.createExpression("[1, 2, 3]");
+
+ int[]value = (int[])expr.evaluate(context);
+
+ var list = Arrays.stream(value)
+ .boxed().toList();
+
+ list.forEach(System.out::println);
+
+
+ expr = jexl.createExpression("{'key' : 'value'}");
+
+ var map = expr.evaluate(context);
+
+ System.out.println(map);
+ }
+}
diff --git a/cms-server/src/main/java/com/condation/cms/request/RequestContextFactory.java b/cms-server/src/main/java/com/condation/cms/request/RequestContextFactory.java
index 3fe24525c..05450767c 100644
--- a/cms-server/src/main/java/com/condation/cms/request/RequestContextFactory.java
+++ b/cms-server/src/main/java/com/condation/cms/request/RequestContextFactory.java
@@ -53,6 +53,7 @@
import com.condation.cms.api.utils.HTTPUtil;
import com.condation.cms.api.utils.RequestUtil;
import com.condation.cms.content.RenderContext;
+import com.condation.cms.content.shortcodes.ShortCodeParser;
import com.condation.cms.content.shortcodes.ShortCodes;
import com.condation.cms.extensions.ExtensionManager;
import com.condation.cms.extensions.hooks.ContentHooks;
@@ -159,8 +160,10 @@ private ShortCodes initShortCodes(RequestContext requestContext) {
.forEach(extension -> codes.putAll(extension.shortCodes()));
var wrapper = requestContext.get(ContentHooks.class).getShortCodes(codes);
+
+ var parser = injector.getInstance(ShortCodeParser.class);
- return new ShortCodes(wrapper.getShortCodes());
+ return new ShortCodes(wrapper.getShortCodes(), parser);
}
public RequestContext create() throws IOException {
@@ -256,8 +259,8 @@ private ShortCodes createShortCodes(RequestContext requestContext) {
.forEach(extension -> codes.putAll(extension.shortCodes()));
var wrapper = requestContext.get(ContentHooks.class).getShortCodes(codes);
-
- return new ShortCodes(wrapper.getShortCodes());
+ var parser = injector.getInstance(ShortCodeParser.class);
+ return new ShortCodes(wrapper.getShortCodes(), parser);
}
}
diff --git a/cms-server/src/main/java/com/condation/cms/server/configs/SiteModule.java b/cms-server/src/main/java/com/condation/cms/server/configs/SiteModule.java
index add4c630f..763a05e80 100644
--- a/cms-server/src/main/java/com/condation/cms/server/configs/SiteModule.java
+++ b/cms-server/src/main/java/com/condation/cms/server/configs/SiteModule.java
@@ -59,6 +59,7 @@
import com.condation.cms.content.DefaultContentRenderer;
import com.condation.cms.content.TaxonomyResolver;
import com.condation.cms.content.ViewResolver;
+import com.condation.cms.content.shortcodes.ShortCodeParser;
import com.condation.cms.extensions.ExtensionManager;
import com.condation.cms.filesystem.FileDB;
import com.condation.cms.filesystem.MetaData;
@@ -109,6 +110,12 @@ public ContentNodeMapper contentNodeMapper (DB db, ContentParser contentParser)
return new ContentNodeMapper(db, contentParser);
}
+ @Provides
+ @Singleton
+ public ShortCodeParser shortCodeParser (DB db, ContentParser contentParser) {
+ return new ShortCodeParser(null);
+ }
+
@Provides
@Singleton
public ConfigurationManagement configurationManagement(DB db, Configuration configuration, SiteCronJobScheduler scheduler, EventBus eventBus) throws IOException {
diff --git a/cms-server/src/test/java/com/condation/cms/TestHelper.java b/cms-server/src/test/java/com/condation/cms/TestHelper.java
index 12f3f72e3..9dffb60ef 100644
--- a/cms-server/src/test/java/com/condation/cms/TestHelper.java
+++ b/cms-server/src/test/java/com/condation/cms/TestHelper.java
@@ -43,6 +43,7 @@
import com.condation.cms.api.markdown.MarkdownRenderer;
import com.condation.cms.api.request.RequestContext;
import com.condation.cms.content.RenderContext;
+import com.condation.cms.content.shortcodes.ShortCodeParser;
import com.condation.cms.content.shortcodes.ShortCodes;
import com.condation.cms.extensions.hooks.DBHooks;
import com.condation.cms.extensions.hooks.TemplateHooks;
@@ -71,10 +72,12 @@ public static RequestContext requestContext(String uri) {
var markdownRenderer = TestHelper.getRenderer();
RequestContext context = new RequestContext();
+ Jex
+ var shortCodeParser = new ShortCodeParser(null);
context.add(RequestFeature.class, new RequestFeature(uri, Map.of()));
context.add(RequestExtensions.class, new RequestExtensions(null));
- context.add(RenderContext.class, new RenderContext(markdownRenderer, new ShortCodes(Map.of()), DefaultTheme.EMPTY));
+ context.add(RenderContext.class, new RenderContext(markdownRenderer, new ShortCodes(Map.of(), shortCodeParser), DefaultTheme.EMPTY));
context.add(SiteMediaServiceFeature.class, new SiteMediaServiceFeature(new FileMediaService(null)));
context.add(InjectorFeature.class, new InjectorFeature(Mockito.mock(Injector.class)));
diff --git a/pom.xml b/pom.xml
index 5152ca620..b6d136236 100644
--- a/pom.xml
+++ b/pom.xml
@@ -111,6 +111,12 @@
${project.version}
+
+ org.apache.commons
+ commons-jexl3
+ 3.4.0
+
+
com.github.slugify
slugify
From 07b3073bf580d877890ae76ee9e84d99be5b5f56 Mon Sep 17 00:00:00 2001
From: Thorsten Marx
Date: Wed, 9 Oct 2024 15:32:16 +0200
Subject: [PATCH 02/15] remove error code
---
cms-server/src/test/java/com/condation/cms/TestHelper.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/cms-server/src/test/java/com/condation/cms/TestHelper.java b/cms-server/src/test/java/com/condation/cms/TestHelper.java
index 9dffb60ef..58c68421c 100644
--- a/cms-server/src/test/java/com/condation/cms/TestHelper.java
+++ b/cms-server/src/test/java/com/condation/cms/TestHelper.java
@@ -72,7 +72,6 @@ public static RequestContext requestContext(String uri) {
var markdownRenderer = TestHelper.getRenderer();
RequestContext context = new RequestContext();
- Jex
var shortCodeParser = new ShortCodeParser(null);
context.add(RequestFeature.class, new RequestFeature(uri, Map.of()));
From 103b9e05581075fc7f39c45839ab8743daf1e529 Mon Sep 17 00:00:00 2001
From: Thorsten Marx
Date: Thu, 10 Oct 2024 12:55:31 +0200
Subject: [PATCH 03/15] current
---
cms-sandbox/tests/pom.xml | 40 ++++-
.../cms/content/shortcodes/ShortCodes.java | 170 ++++++++++++++++++
.../java/com/condation/cms/tests/Tests.java | 1 -
.../cms/content/shortcodes/ShortCode.g4 | 35 ++++
.../cms/content/shortcodes/ShortCodeLexer.g4 | 12 ++
.../content/shortcodes/ShortCodesTest.java | 113 ++++++++++++
6 files changed, 366 insertions(+), 5 deletions(-)
create mode 100644 cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
create mode 100644 cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCode.g4
create mode 100644 cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeLexer.g4
create mode 100644 cms-sandbox/tests/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java
diff --git a/cms-sandbox/tests/pom.xml b/cms-sandbox/tests/pom.xml
index 3a3b2487c..ac3f80325 100644
--- a/cms-sandbox/tests/pom.xml
+++ b/cms-sandbox/tests/pom.xml
@@ -1,22 +1,54 @@
-
+
4.0.0
com.condation.cms
cms-sandbox
- 6.3.1
+ 6.4.0
tests
jar
com.condation.cms.tests.Tests
-
+
org.apache.commons
commons-jexl3
- 3.4.0
+
+
+ org.antlr
+ antlr4-runtime
+ 4.13.2
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+
+
+ org.antlr
+ antlr4-maven-plugin
+ 4.13.2
+
+ src/main/resources
+ target/generated-sources/antlr4
+
+
+
+
+ antlr4
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java b/cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
new file mode 100644
index 000000000..d7ff40390
--- /dev/null
+++ b/cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
@@ -0,0 +1,170 @@
+package com.condation.cms.content.shortcodes;
+
+/*-
+ * #%L
+ * tests
+ * %%
+ * Copyright (C) 2023 - 2024 CondationCMS
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program. If not, see
+ * .
+ * #L%
+ */
+
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.tree.*;
+import org.apache.commons.jexl3.*;
+import java.util.*;
+import java.util.function.Function;
+
+public class ShortCodes {
+
+ private static final JexlEngine jexl = new JexlBuilder().create(); // Initialisierung des JEXL-Engines
+
+ public static String parseShortcodes(String text, Codes codes) {
+ // ANTLR Setup
+ CharStream input = CharStreams.fromString(text);
+ ShortCodeLexer lexer = new ShortCodeLexer(input);
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+ ShortCodeParser parser = new ShortCodeParser(tokens);
+ ParseTree tree = parser.shortcodes(); // Parse the input
+
+ // Listener Setup
+ ShortCodeListenerImpl listener = new ShortCodeListenerImpl(codes);
+ ParseTreeWalker walker = new ParseTreeWalker();
+ walker.walk(listener, tree); // Walk the tree using the listener
+
+ // Return the modified text after processing all shortcodes
+ return listener.getResult();
+ }
+
+ // Listener class to process shortcodes
+ public static class ShortCodeListenerImpl extends ShortCodeBaseListener {
+ private final Codes codes;
+ private final StringBuilder result = new StringBuilder(); // Stores the final output
+
+ public ShortCodeListenerImpl(Codes codes) {
+ this.codes = codes;
+ }
+
+ @Override
+ public void enterText(ShortCodeParser.TextContext ctx) {
+ result.append(ctx.getText());
+ }
+
+ @Override
+ public void enterOpeningTag(ShortCodeParser.OpeningTagContext ctx) {
+ System.out.println("enterOpeningTag: " + ctx.NAME());
+ }
+
+ @Override
+ public void enterClosingTag(ShortCodeParser.ClosingTagContext ctx) {
+ System.out.println("enterClosingTag: " + ctx.NAME());
+ }
+
+ @Override
+ public void enterSelfClosingTag(ShortCodeParser.SelfClosingTagContext ctx) {
+ System.out.println("enterSelfClosingTag: " + ctx.NAME());
+ }
+
+ @Override
+ public void enterShortcodeWithContent(ShortCodeParser.ShortcodeWithContentContext ctx) {
+ System.out.println("enterShortcodeWithContent: " + ctx.openingTag().NAME());
+
+ String name = ctx.openingTag().NAME().getText();
+ Map parameters = parseParams(ctx.openingTag().params());
+ String content = ctx.content() != null ? ctx.content().getText() : "";
+
+ // Apply shortcode function if exists
+ if (codes.hasCode(name)) {
+ parameters.put("content", content); // Pass content as parameter
+ result.append(codes.get(name).apply(parameters));
+ } else {
+ result.append(ctx.getText()); // No shortcode function found, append raw text
+ }
+ }
+
+ @Override
+ public void enterSelfClosingShortcode(ShortCodeParser.SelfClosingShortcodeContext ctx) {
+ String name = ctx.selfClosingTag().NAME().getText();
+ Map parameters = parseParams(ctx.selfClosingTag().params());
+
+ // Apply shortcode function if exists
+ if (codes.hasCode(name)) {
+ result.append(codes.get(name).apply(parameters));
+ } else {
+ result.append(ctx.getText()); // No shortcode function found, append raw text
+ }
+ }
+
+ // Methode, um Parameter zu extrahieren
+ private Map parseParams(ShortCodeParser.ParamsContext ctx) {
+ Map params = new HashMap<>();
+ if (ctx != null) {
+ for (ShortCodeParser.ParamContext paramCtx : ctx.param()) {
+ String key = paramCtx.NAME().getText();
+ String rawValue = paramCtx.value().getText();
+ Object value = evaluateIfExpression(rawValue);
+ params.put(key, value);
+ }
+ }
+ return params;
+ }
+
+ // Methode, um Ausdrücke innerhalb von ${} zu erkennen und mit JEXL auszuwerten
+ private Object evaluateIfExpression(String rawValue) {
+ // Prüfen, ob der Wert im Format ${expression} vorliegt
+ if (rawValue.startsWith("${") && rawValue.endsWith("}")) {
+ String expression = rawValue.substring(2, rawValue.length() - 1);
+ return evaluateExpression(expression);
+ } else {
+ // Normaler Text
+ return rawValue.replace("\"", ""); // Entfernt eventuell vorhandene Anführungszeichen
+ }
+ }
+
+ // Methode, um einen JEXL-Ausdruck auszuwerten
+ private Object evaluateExpression(String expression) {
+ try {
+ JexlExpression jexlExpression = jexl.createExpression(expression);
+ JexlContext context = new MapContext(); // Leerer Kontext für einfache Auswertung
+ return jexlExpression.evaluate(context); // Ausdruck auswerten
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null; // Wenn die Auswertung fehlschlägt, gib null zurück
+ }
+ }
+
+ public String getResult() {
+ return result.toString(); // Gibt das finale Ergebnis nach dem Parsen zurück
+ }
+ }
+
+ // Codes class to store shortcode functions
+ public static class Codes {
+ private final Map, String>> codes = new HashMap<>();
+
+ public void add(String codeName, Function, String> function) {
+ codes.put(codeName, function);
+ }
+
+ public boolean hasCode(String codeName) {
+ return codes.containsKey(codeName);
+ }
+
+ public Function, String> get(String codeName) {
+ return codes.getOrDefault(codeName, (params) -> "");
+ }
+ }
+}
diff --git a/cms-sandbox/tests/src/main/java/com/condation/cms/tests/Tests.java b/cms-sandbox/tests/src/main/java/com/condation/cms/tests/Tests.java
index b85c3ab54..7743c392c 100644
--- a/cms-sandbox/tests/src/main/java/com/condation/cms/tests/Tests.java
+++ b/cms-sandbox/tests/src/main/java/com/condation/cms/tests/Tests.java
@@ -23,7 +23,6 @@
*/
import java.util.Arrays;
-import java.util.List;
import org.apache.commons.jexl3.JexlBuilder;
import org.apache.commons.jexl3.JexlContext;
import org.apache.commons.jexl3.JexlEngine;
diff --git a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCode.g4 b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCode.g4
new file mode 100644
index 000000000..b62d95359
--- /dev/null
+++ b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCode.g4
@@ -0,0 +1,35 @@
+grammar ShortCode;
+
+shortcodes: (shortcode | text)+ EOF;
+
+shortcode:
+ openingTag content? closingTag # shortcodeWithContent
+ | selfClosingTag # selfClosingShortcode
+ ;
+
+openingTag: OPENING_BRACKET NAME params? CLOSING_BRACKET ;
+closingTag: OPENING_BRACKET '/' NAME CLOSING_BRACKET ;
+selfClosingTag: OPENING_BRACKET NAME params? '/' CLOSING_BRACKET ;
+
+params: param (WS+ param)* ;
+param: NAME '=' value ;
+
+value: STRING | NUMBER;
+
+// Der Inhalt muss mindestens ein Zeichen sein, das nicht '[' ist
+//content: (text | shortcode)* ;
+content: (~'[' | ' ')+ ;
+//content: (~OPENING_BRACKET | ' ')+ ;
+
+//text: (~'[' | ' ')+ ;
+text: (~('[' | ']') | ' ' | '-')+ ;
+//text: (~OPENING_BRACKET)+ ;
+
+//TEXT: .;
+NAME: [a-zA-Z_][a-zA-Z0-9_]* ;
+STRING: '"' (~["])* '"' ;
+NUMBER: [0-9]+ ;
+WS: [ \t\r\n]+ ;
+
+OPENING_BRACKET: '[[' ;
+CLOSING_BRACKET: ']]' ;
\ No newline at end of file
diff --git a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeLexer.g4 b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeLexer.g4
new file mode 100644
index 000000000..743e42ec4
--- /dev/null
+++ b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeLexer.g4
@@ -0,0 +1,12 @@
+lexer grammar ShortCodes;
+
+TAG_OPENING_BRACKET: '[[' -> pushMode(TAG);
+
+mode TAG;
+TAG_CLOSING_BRACKET: ']]';
+TAG_CLOSING_CLOSING_BRACKET: '/]]' -> popMode;
+TAG_OPENING_CLOSING_BRACKET: '[[/' -> popMode;
+TAG_NAME: [a-zA-Z][a-zA-Z0-9]* ;
+TAG_STRING: '"' (~["])* '"' ;
+TAG_NUMBER: [0-9]+ ;
+TAG_WS: [ \t]+ ;
diff --git a/cms-sandbox/tests/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java b/cms-sandbox/tests/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java
new file mode 100644
index 000000000..971dfc152
--- /dev/null
+++ b/cms-sandbox/tests/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java
@@ -0,0 +1,113 @@
+package com.condation.cms.content.shortcodes;
+
+/*-
+ * #%L
+ * tests
+ * %%
+ * Copyright (C) 2023 - 2024 CondationCMS
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program. If not, see
+ * .
+ * #L%
+ */
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.RepeatedTest;
+
+/**
+ *
+ * @author t.marx
+ */
+public class ShortCodesTest {
+
+ ShortCodes shortCodes;
+ ShortCodes.Codes codes = new ShortCodes.Codes();
+
+ @BeforeEach
+ void setup() {
+ shortCodes = new ShortCodes();
+
+ codes.add("code", params -> {
+ // Verarbeitung der Parameter hier
+ return "Ausgabe des Shortcodes";
+ });
+ codes.add("content", params -> {
+ return (String)params.get("content");
+ });
+
+ codes.add("exp", params -> {
+ return "expression: " + params.get("value");
+ });
+
+ codes.add("param", params -> {
+ return "param: " + params.get("param1");
+ });
+ }
+
+ @Test
+ public void no_shortcode() {
+ String result = shortCodes.parseShortcodes("Dein Shortcode-Text hier", codes);
+ Assertions.assertThat(result).isEqualTo("Dein Shortcode-Text hier");
+ }
+
+ @Test
+ public void self_closing_tag() {
+ String result = shortCodes.parseShortcodes("[[code/]]", codes);
+ Assertions.assertThat(result).isEqualTo("Ausgabe des Shortcodes");
+ }
+
+ @Test
+ public void self_closing_tag_with_space() {
+ String result = shortCodes.parseShortcodes("[[code /]]", codes);
+ Assertions.assertThat(result).isEqualTo("Ausgabe des Shortcodes");
+ }
+
+ @Test
+ public void end_closing_tag() {
+ String result = shortCodes.parseShortcodes("[[code]][[/code]]", codes);
+ Assertions.assertThat(result).isEqualTo("Ausgabe des Shortcodes");
+ }
+
+ @Test
+ public void tag_with_content() {
+ String result = shortCodes.parseShortcodes("[[content]]Hello CondationCMS[[/content]]", codes);
+ Assertions.assertThat(result).isEqualTo("Hello CondationCMS");
+ }
+
+ @Test
+ public void expressions() {
+ String result = shortCodes.parseShortcodes("[[exp value=\"5\"/]]", codes);
+ Assertions.assertThat(result).isEqualTo("expression: 9");
+ }
+
+ @Test
+ public void parameters_string() {
+ String result = shortCodes.parseShortcodes("[[param param1=\"5\"/]]", codes);
+ Assertions.assertThat(result).isEqualTo("param: 5");
+ }
+
+ @Test
+ public void parameters_number() {
+ String result = shortCodes.parseShortcodes("[[param param1=5 /]]", codes);
+ Assertions.assertThat(result).isEqualTo("param: 5");
+ }
+
+ @Test
+ public void parameters_with_content() {
+ String result = shortCodes.parseShortcodes("[[param param1=\"5\"]]Hello[[/param]]", codes);
+ Assertions.assertThat(result).isEqualTo("param: 5");
+ }
+}
From 37a8cd9904b6c40dd6f7cd016ad07002405c5284 Mon Sep 17 00:00:00 2001
From: Thorsten Marx
Date: Thu, 10 Oct 2024 15:19:23 +0200
Subject: [PATCH 04/15] first jexl and antlr experiements
---
.../content/shortcodes/ShortCodeParser.java | 42 +++++++++++---
.../ShortCodeParserExpressionsTest.java | 55 +++++++++++++++++++
.../content/shortcodes/ShortCodesTest.java | 8 ++-
.../cms/content/shortcodes/ShortCodes.java | 2 +-
.../{ShortCode.g4 => ShortCode.g4-legacy} | 0
.../cms/content/shortcodes/ShortCodeLexer.g4 | 16 ++++--
.../cms/content/shortcodes/ShortCodeParser.g4 | 25 +++++++++
.../cms/server/configs/SiteModule.java | 17 +++++-
.../java/com/condation/cms/TestHelper.java | 3 +-
pom.xml | 1 -
10 files changed, 149 insertions(+), 20 deletions(-)
create mode 100644 cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodeParserExpressionsTest.java
rename cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/{ShortCode.g4 => ShortCode.g4-legacy} (100%)
create mode 100644 cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeParser.g4
diff --git a/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodeParser.java b/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodeParser.java
index 2eddee9bd..f5969d409 100644
--- a/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodeParser.java
+++ b/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodeParser.java
@@ -22,6 +22,7 @@
* #L%
*/
import com.condation.cms.api.model.Parameter;
+import java.lang.reflect.Array;
import java.util.*;
import java.util.function.Function;
import java.util.regex.*;
@@ -29,27 +30,30 @@
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.jexl3.JexlContext;
import org.apache.commons.jexl3.JexlEngine;
+import org.apache.commons.jexl3.JexlExpression;
+import org.apache.commons.jexl3.MapContext;
@Slf4j
public class ShortCodeParser {
-
+
JexlEngine engine;
public static final String SHORTCODE_REGEX = "\\[\\[(\\w+)([^\\]]*)\\]\\](.*?)\\[\\[\\/\\1\\]\\]|\\[\\[(\\w+)([^\\]]*)\\s*\\/\\]\\]";
public static final Pattern SHORTCODE_PATTERN = Pattern.compile(SHORTCODE_REGEX, Pattern.DOTALL);
- public static final Pattern PARAM_PATTERN = Pattern.compile("(\\w+)=(\"[^\"]*\"|'[^']*')");
+ //public static final Pattern PARAM_PATTERN = Pattern.compile("(\\w+)=(\"[^\"]*\"|'[^']*')");
+ public static final Pattern PARAM_PATTERN = Pattern.compile("(\\w+)=((\"[^\"]*\"|'[^']*'|\\[[^\\]]*\\]))");
- public ShortCodeParser (JexlEngine engine) {
+ public ShortCodeParser(JexlEngine engine) {
this.engine = engine;
}
-
+
public List parseShortcodes(String text) {
List shortcodes = new ArrayList<>();
Matcher matcher = SHORTCODE_PATTERN.matcher(text);
while (matcher.find()) {
-
String name = matcher.group(1) != null ? matcher.group(1) : matcher.group(4);
String params = matcher.group(2) != null ? matcher.group(2).trim() : matcher.group(5).trim();
String content = matcher.group(3) != null ? matcher.group(3).trim() : "";
@@ -63,9 +67,11 @@ public List parseShortcodes(String text) {
while (paramMatcher.find()) {
String key = paramMatcher.group(1);
String value = paramMatcher.group(2);
- // Remove the surrounding quotes
- value = value.substring(1, value.length() - 1);
- match.getParameters().put(key, value);
+ value = value.substring(1, value.length() - 1); // Entfernt die Anführungszeichen oder Klammern bei Arrays
+
+ // Prüfe, ob es ein Array ist und nutze JEXL zur Auswertung
+ Object evaluatedValue = evaluateExpression(value);
+ match.getParameters().put(key, evaluatedValue);
}
shortcodes.add(match);
@@ -74,6 +80,26 @@ public List parseShortcodes(String text) {
return shortcodes;
}
+ private Object evaluateExpression(String value) {
+ try {
+ JexlExpression expression = engine.createExpression(value);
+ JexlContext context = new MapContext();
+ var parsedValue = expression.evaluate(context);
+ if (parsedValue.getClass().isArray()) {
+ int length = Array.getLength(parsedValue);
+ List list = new ArrayList<>(length);
+ for (int i = 0; i < length; i++) {
+ list.add(Array.get(parsedValue, i)); // Holen des Elements am Index i
+ }
+ return list;
+ } else {
+ return parsedValue;
+ }
+ } catch (Exception e) {
+ return value;
+ }
+ }
+
public String replace(String content, Codes codes) {
StringBuilder newContent = new StringBuilder();
int lastPosition = 0;
diff --git a/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodeParserExpressionsTest.java b/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodeParserExpressionsTest.java
new file mode 100644
index 000000000..8e7855238
--- /dev/null
+++ b/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodeParserExpressionsTest.java
@@ -0,0 +1,55 @@
+package com.condation.cms.content.shortcodes;
+
+/*-
+ * #%L
+ * cms-content
+ * %%
+ * Copyright (C) 2023 - 2024 CondationCMS
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program. If not, see
+ * .
+ * #L%
+ */
+
+
+import com.condation.cms.content.ContentBaseTest;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.List;
+
+public class ShortCodeParserExpressionsTest extends ContentBaseTest {
+
+ @Test
+ public void test_numbers() {
+ String text = "[[code param1=\"12\" param2=\"12.5\"]][[/code]].";
+ List shortcodes = getShortCodeParser().parseShortcodes(text);
+
+ assertEquals(1, shortcodes.size());
+
+ var shortcode = shortcodes.get(0);
+ assertEquals(12, shortcode.getParameters().get("param1"));
+ assertEquals(12.5, shortcode.getParameters().get("param2"));
+ }
+
+ @Test
+ public void test_list() {
+ String text = "[[code param1=\"[12, 13, 14]\" param2=\"['12', '13', '14]\"]][[/code]].";
+ List shortcodes = getShortCodeParser().parseShortcodes(text);
+
+ var shortcode = shortcodes.get(0);
+ assertEquals(List.of(12, 13, 14), shortcode.getParameters().get("param1"));
+ assertEquals(List.of("12", "13", "14"), shortcode.getParameters().get("param2"));
+ }
+}
diff --git a/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java b/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java
index 8fff434a8..aea453676 100644
--- a/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java
+++ b/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java
@@ -29,7 +29,6 @@
import java.util.Map;
import java.util.function.Function;
import org.assertj.core.api.Assertions;
-import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -180,4 +179,11 @@ void multiple_hello () {
result = shortCodes.replace(input);
Assertions.assertThat(result).isEqualTo(expected);
}
+
+ @Test
+ void test_mismathc() {
+ var result = shortCodes.replace("[[mark1 class='test-class']]Important[[/mark2]]");
+
+ Assertions.assertThat(result).isEqualTo("[[mark1 class='test-class']]Important[[/mark2]]");
+ }
}
diff --git a/cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java b/cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
index d7ff40390..19459d1b3 100644
--- a/cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
+++ b/cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
@@ -50,7 +50,7 @@ public static String parseShortcodes(String text, Codes codes) {
}
// Listener class to process shortcodes
- public static class ShortCodeListenerImpl extends ShortCodeBaseListener {
+ public static class ShortCodeListenerImpl extends ShortCodeParserBaseListener {
private final Codes codes;
private final StringBuilder result = new StringBuilder(); // Stores the final output
diff --git a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCode.g4 b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCode.g4-legacy
similarity index 100%
rename from cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCode.g4
rename to cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCode.g4-legacy
diff --git a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeLexer.g4 b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeLexer.g4
index 743e42ec4..960cffefd 100644
--- a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeLexer.g4
+++ b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeLexer.g4
@@ -1,12 +1,16 @@
-lexer grammar ShortCodes;
+lexer grammar ShortCodeLexer;
+
+TAG_OPENING_BRACKET: '[[';
+
+EQUALS : '=' ;
+SPACE : ' ' ;
+SINGLE_OPEN_BRAKET : '[' ;
-TAG_OPENING_BRACKET: '[[' -> pushMode(TAG);
-mode TAG;
TAG_CLOSING_BRACKET: ']]';
-TAG_CLOSING_CLOSING_BRACKET: '/]]' -> popMode;
-TAG_OPENING_CLOSING_BRACKET: '[[/' -> popMode;
+TAG_CLOSING_CLOSING_BRACKET: '/]]' ;
+TAG_OPENING_CLOSING_BRACKET: '[[/';
TAG_NAME: [a-zA-Z][a-zA-Z0-9]* ;
TAG_STRING: '"' (~["])* '"' ;
TAG_NUMBER: [0-9]+ ;
-TAG_WS: [ \t]+ ;
+TAG_WS: [ \t]+ ;
\ No newline at end of file
diff --git a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeParser.g4 b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeParser.g4
new file mode 100644
index 000000000..d4afa662a
--- /dev/null
+++ b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeParser.g4
@@ -0,0 +1,25 @@
+parser grammar ShortCodeParser;
+
+options {
+ tokenVocab = ShortCodeLexer;
+}
+
+shortcodes: (shortcode)+ EOF;
+
+shortcode:
+ openingTag content? closingTag # shortcodeWithContent
+ | selfClosingTag # selfClosingShortcode
+ ;
+
+openingTag:
+ TAG_OPENING_BRACKET TAG_NAME TAG_CLOSING_BRACKET ;
+closingTag:
+ TAG_OPENING_CLOSING_BRACKET TAG_NAME TAG_CLOSING_BRACKET ;
+selfClosingTag:
+ TAG_OPENING_BRACKET TAG_NAME TAG_WS? TAG_CLOSING_CLOSING_BRACKET ;
+
+params: param (TAG_WS+ param)* ;
+param: TAG_NAME EQUALS value ;
+
+value: TAG_STRING | TAG_NUMBER;
+content: (~SINGLE_OPEN_BRAKET | SPACE)+ ;
diff --git a/cms-server/src/main/java/com/condation/cms/server/configs/SiteModule.java b/cms-server/src/main/java/com/condation/cms/server/configs/SiteModule.java
index 763a05e80..4d27f2e35 100644
--- a/cms-server/src/main/java/com/condation/cms/server/configs/SiteModule.java
+++ b/cms-server/src/main/java/com/condation/cms/server/configs/SiteModule.java
@@ -81,6 +81,7 @@
import java.nio.file.Path;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.jexl3.JexlBuilder;
import org.graalvm.polyglot.Engine;
/**
@@ -112,8 +113,20 @@ public ContentNodeMapper contentNodeMapper (DB db, ContentParser contentParser)
@Provides
@Singleton
- public ShortCodeParser shortCodeParser (DB db, ContentParser contentParser) {
- return new ShortCodeParser(null);
+ public ShortCodeParser shortCodeParser (Configuration configuration) {
+ var engine = new JexlBuilder()
+ .strict(true)
+ .cache(512);
+
+ boolean IS_DEV = configuration.get(ServerConfiguration.class).serverProperties().dev();
+
+ if (IS_DEV) {
+ engine.silent(false);
+ } else {
+ engine.silent(true);
+ }
+
+ return new ShortCodeParser(engine.create());
}
@Provides
diff --git a/cms-server/src/test/java/com/condation/cms/TestHelper.java b/cms-server/src/test/java/com/condation/cms/TestHelper.java
index 58c68421c..11f39eb21 100644
--- a/cms-server/src/test/java/com/condation/cms/TestHelper.java
+++ b/cms-server/src/test/java/com/condation/cms/TestHelper.java
@@ -52,6 +52,7 @@
import com.condation.cms.core.theme.DefaultTheme;
import com.google.inject.Injector;
import java.util.Map;
+import org.apache.commons.jexl3.JexlBuilder;
import org.mockito.Mockito;
/**
@@ -72,7 +73,7 @@ public static RequestContext requestContext(String uri) {
var markdownRenderer = TestHelper.getRenderer();
RequestContext context = new RequestContext();
- var shortCodeParser = new ShortCodeParser(null);
+ var shortCodeParser = new ShortCodeParser(new JexlBuilder().create());
context.add(RequestFeature.class, new RequestFeature(uri, Map.of()));
context.add(RequestExtensions.class, new RequestExtensions(null));
diff --git a/pom.xml b/pom.xml
index e5d42cac6..d1d087351 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,6 @@
cms-filesystem
cms-media
cms-git
- cms-sandbox
cms-content
cms-extensions
cms-auth
From 9835e04976fcfaaef897ad7cf6ee064ab0633bbe Mon Sep 17 00:00:00 2001
From: Thorsten Marx
Date: Thu, 10 Oct 2024 15:32:24 +0200
Subject: [PATCH 05/15] update antlr grammar
---
.../cms/content/shortcodes/ShortCodes.java | 74 ++++++++++---------
.../cms/content/shortcodes/ShortCodeLexer.g4 | 1 +
.../cms/content/shortcodes/ShortCodeParser.g4 | 10 ++-
.../content/shortcodes/ShortCodesTest.java | 1 -
4 files changed, 48 insertions(+), 38 deletions(-)
diff --git a/cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java b/cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
index 19459d1b3..8f4136f0c 100644
--- a/cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
+++ b/cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
@@ -62,42 +62,50 @@ public ShortCodeListenerImpl(Codes codes) {
public void enterText(ShortCodeParser.TextContext ctx) {
result.append(ctx.getText());
}
-
- @Override
- public void enterOpeningTag(ShortCodeParser.OpeningTagContext ctx) {
- System.out.println("enterOpeningTag: " + ctx.NAME());
- }
-
- @Override
- public void enterClosingTag(ShortCodeParser.ClosingTagContext ctx) {
- System.out.println("enterClosingTag: " + ctx.NAME());
- }
-
- @Override
- public void enterSelfClosingTag(ShortCodeParser.SelfClosingTagContext ctx) {
- System.out.println("enterSelfClosingTag: " + ctx.NAME());
- }
+//
+// @Override
+// public void enterOpeningTag(ShortCodeParser.OpeningTagContext ctx) {
+// System.out.println("enterOpeningTag: " + ctx.NAME());
+// }
+//
+// @Override
+// public void enterClosingTag(ShortCodeParser.ClosingTagContext ctx) {
+// System.out.println("enterClosingTag: " + ctx.NAME());
+// }
+
+// @Override
+// public void enterSelfClosingTag(ShortCodeParser.SelfClosingTagContext ctx) {
+// String name = ctx.TAG_NAME().getText();
+// Map parameters = parseParams(ctx.params());
+//
+// // Apply shortcode function if exists
+// if (codes.hasCode(name)) {
+// result.append(codes.get(name).apply(parameters));
+// } else {
+// result.append(ctx.getText()); // No shortcode function found, append raw text
+// }
+// }
- @Override
- public void enterShortcodeWithContent(ShortCodeParser.ShortcodeWithContentContext ctx) {
- System.out.println("enterShortcodeWithContent: " + ctx.openingTag().NAME());
-
- String name = ctx.openingTag().NAME().getText();
- Map parameters = parseParams(ctx.openingTag().params());
- String content = ctx.content() != null ? ctx.content().getText() : "";
-
- // Apply shortcode function if exists
- if (codes.hasCode(name)) {
- parameters.put("content", content); // Pass content as parameter
- result.append(codes.get(name).apply(parameters));
- } else {
- result.append(ctx.getText()); // No shortcode function found, append raw text
- }
- }
+// @Override
+// public void enterShortcodeWithContent(ShortCodeParser.ShortcodeWithContentContext ctx) {
+// System.out.println("enterShortcodeWithContent: " + ctx.openingTag().NAME());
+//
+// String name = ctx.openingTag().NAME().getText();
+// Map parameters = parseParams(ctx.openingTag().params());
+// String content = ctx.content() != null ? ctx.content().getText() : "";
+//
+// // Apply shortcode function if exists
+// if (codes.hasCode(name)) {
+// parameters.put("content", content); // Pass content as parameter
+// result.append(codes.get(name).apply(parameters));
+// } else {
+// result.append(ctx.getText()); // No shortcode function found, append raw text
+// }
+// }
@Override
public void enterSelfClosingShortcode(ShortCodeParser.SelfClosingShortcodeContext ctx) {
- String name = ctx.selfClosingTag().NAME().getText();
+ String name = ctx.selfClosingTag().TAG_NAME().getText();
Map parameters = parseParams(ctx.selfClosingTag().params());
// Apply shortcode function if exists
@@ -113,7 +121,7 @@ private Map parseParams(ShortCodeParser.ParamsContext ctx) {
Map params = new HashMap<>();
if (ctx != null) {
for (ShortCodeParser.ParamContext paramCtx : ctx.param()) {
- String key = paramCtx.NAME().getText();
+ String key = paramCtx.TAG_NAME().getText();
String rawValue = paramCtx.value().getText();
Object value = evaluateIfExpression(rawValue);
params.put(key, value);
diff --git a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeLexer.g4 b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeLexer.g4
index 960cffefd..b56c01c11 100644
--- a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeLexer.g4
+++ b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeLexer.g4
@@ -5,6 +5,7 @@ TAG_OPENING_BRACKET: '[[';
EQUALS : '=' ;
SPACE : ' ' ;
SINGLE_OPEN_BRAKET : '[' ;
+DASH : '-' ;
TAG_CLOSING_BRACKET: ']]';
diff --git a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeParser.g4 b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeParser.g4
index d4afa662a..7844367f7 100644
--- a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeParser.g4
+++ b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeParser.g4
@@ -4,7 +4,7 @@ options {
tokenVocab = ShortCodeLexer;
}
-shortcodes: (shortcode)+ EOF;
+shortcodes: (shortcode | text)+ EOF;
shortcode:
openingTag content? closingTag # shortcodeWithContent
@@ -12,14 +12,16 @@ shortcode:
;
openingTag:
- TAG_OPENING_BRACKET TAG_NAME TAG_CLOSING_BRACKET ;
+ TAG_OPENING_BRACKET TAG_NAME params? TAG_CLOSING_BRACKET ;
closingTag:
TAG_OPENING_CLOSING_BRACKET TAG_NAME TAG_CLOSING_BRACKET ;
selfClosingTag:
- TAG_OPENING_BRACKET TAG_NAME TAG_WS? TAG_CLOSING_CLOSING_BRACKET ;
+ TAG_OPENING_BRACKET TAG_NAME params? TAG_WS? TAG_CLOSING_CLOSING_BRACKET ;
params: param (TAG_WS+ param)* ;
param: TAG_NAME EQUALS value ;
value: TAG_STRING | TAG_NUMBER;
-content: (~SINGLE_OPEN_BRAKET | SPACE)+ ;
+content: (~SINGLE_OPEN_BRAKET | SPACE | DASH)+ ;
+
+text: (~SINGLE_OPEN_BRAKET | SPACE)+ ;
diff --git a/cms-sandbox/tests/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java b/cms-sandbox/tests/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java
index 971dfc152..55faac51e 100644
--- a/cms-sandbox/tests/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java
+++ b/cms-sandbox/tests/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java
@@ -25,7 +25,6 @@
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.RepeatedTest;
/**
*
From 42d134628e2d5d2f5567def5bd1258fa441a8a31 Mon Sep 17 00:00:00 2001
From: Thorsten Marx
Date: Thu, 10 Oct 2024 16:34:06 +0200
Subject: [PATCH 06/15] update antlr grammar
---
.../cms/content/shortcodes/ShortCodes.java | 49 +-
.../shortcodes/.antlr/ShortCodeLexer.interp | 53 ++
.../shortcodes/.antlr/ShortCodeLexer.java | 164 ++++
.../shortcodes/.antlr/ShortCodeLexer.tokens | 20 +
.../shortcodes/.antlr/ShortCodeParser.interp | 45 +
.../shortcodes/.antlr/ShortCodeParser.java | 797 ++++++++++++++++++
.../shortcodes/.antlr/ShortCodeParser.tokens | 20 +
.../6fbb63088f467e041b3797652b994d4b.atn | 1 +
.../cms/content/shortcodes/ShortCodeParser.g4 | 6 +-
.../content/shortcodes/ShortCodesTest.java | 8 +-
10 files changed, 1130 insertions(+), 33 deletions(-)
create mode 100644 cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeLexer.interp
create mode 100644 cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeLexer.java
create mode 100644 cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeLexer.tokens
create mode 100644 cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeParser.interp
create mode 100644 cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeParser.java
create mode 100644 cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeParser.tokens
create mode 100644 cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/cache/6fbb63088f467e041b3797652b994d4b.atn
diff --git a/cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java b/cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
index 8f4136f0c..612ac81bf 100644
--- a/cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
+++ b/cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
@@ -62,16 +62,6 @@ public ShortCodeListenerImpl(Codes codes) {
public void enterText(ShortCodeParser.TextContext ctx) {
result.append(ctx.getText());
}
-//
-// @Override
-// public void enterOpeningTag(ShortCodeParser.OpeningTagContext ctx) {
-// System.out.println("enterOpeningTag: " + ctx.NAME());
-// }
-//
-// @Override
-// public void enterClosingTag(ShortCodeParser.ClosingTagContext ctx) {
-// System.out.println("enterClosingTag: " + ctx.NAME());
-// }
// @Override
// public void enterSelfClosingTag(ShortCodeParser.SelfClosingTagContext ctx) {
@@ -86,22 +76,22 @@ public void enterText(ShortCodeParser.TextContext ctx) {
// }
// }
-// @Override
-// public void enterShortcodeWithContent(ShortCodeParser.ShortcodeWithContentContext ctx) {
-// System.out.println("enterShortcodeWithContent: " + ctx.openingTag().NAME());
-//
-// String name = ctx.openingTag().NAME().getText();
-// Map parameters = parseParams(ctx.openingTag().params());
-// String content = ctx.content() != null ? ctx.content().getText() : "";
-//
-// // Apply shortcode function if exists
-// if (codes.hasCode(name)) {
-// parameters.put("content", content); // Pass content as parameter
-// result.append(codes.get(name).apply(parameters));
-// } else {
-// result.append(ctx.getText()); // No shortcode function found, append raw text
-// }
-// }
+ @Override
+ public void enterShortcodeWithContent(ShortCodeParser.ShortcodeWithContentContext ctx) {
+ System.out.println("enterShortcodeWithContent: " + ctx.openingTag().TAG_NAME());
+
+ String name = ctx.openingTag().TAG_NAME().getText();
+ Map parameters = parseParams(ctx.openingTag().params());
+ String content = ctx.content() != null ? ctx.content().getText() : "";
+
+ // Apply shortcode function if exists
+ if (codes.hasCode(name)) {
+ parameters.put("content", content); // Pass content as parameter
+ result.append(codes.get(name).apply(parameters));
+ } else {
+ result.append(ctx.getText()); // No shortcode function found, append raw text
+ }
+ }
@Override
public void enterSelfClosingShortcode(ShortCodeParser.SelfClosingShortcodeContext ctx) {
@@ -133,12 +123,13 @@ private Map parseParams(ShortCodeParser.ParamsContext ctx) {
// Methode, um Ausdrücke innerhalb von ${} zu erkennen und mit JEXL auszuwerten
private Object evaluateIfExpression(String rawValue) {
// Prüfen, ob der Wert im Format ${expression} vorliegt
- if (rawValue.startsWith("${") && rawValue.endsWith("}")) {
- String expression = rawValue.substring(2, rawValue.length() - 1);
+ var testValue = rawValue.replace("\"", "");
+ if (testValue.startsWith("${") && testValue.endsWith("}")) {
+ String expression = testValue.substring(2, testValue.length() - 1);
return evaluateExpression(expression);
} else {
// Normaler Text
- return rawValue.replace("\"", ""); // Entfernt eventuell vorhandene Anführungszeichen
+ return testValue;// Entfernt eventuell vorhandene Anführungszeichen
}
}
diff --git a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeLexer.interp b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeLexer.interp
new file mode 100644
index 000000000..9b48d9b6c
--- /dev/null
+++ b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeLexer.interp
@@ -0,0 +1,53 @@
+token literal names:
+null
+'[['
+'='
+' '
+'['
+'-'
+']]'
+'/]]'
+'[[/'
+null
+null
+null
+null
+
+token symbolic names:
+null
+TAG_OPENING_BRACKET
+EQUALS
+SPACE
+SINGLE_OPEN_BRAKET
+DASH
+TAG_CLOSING_BRACKET
+TAG_CLOSING_CLOSING_BRACKET
+TAG_OPENING_CLOSING_BRACKET
+TAG_NAME
+TAG_STRING
+TAG_NUMBER
+TAG_WS
+
+rule names:
+TAG_OPENING_BRACKET
+EQUALS
+SPACE
+SINGLE_OPEN_BRAKET
+DASH
+TAG_CLOSING_BRACKET
+TAG_CLOSING_CLOSING_BRACKET
+TAG_OPENING_CLOSING_BRACKET
+TAG_NAME
+TAG_STRING
+TAG_NUMBER
+TAG_WS
+
+channel names:
+DEFAULT_TOKEN_CHANNEL
+HIDDEN
+
+mode names:
+DEFAULT_MODE
+
+atn:
+[4, 0, 12, 73, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 5, 8, 50, 8, 8, 10, 8, 12, 8, 53, 9, 8, 1, 9, 1, 9, 5, 9, 57, 8, 9, 10, 9, 12, 9, 60, 9, 9, 1, 9, 1, 9, 1, 10, 4, 10, 65, 8, 10, 11, 10, 12, 10, 66, 1, 11, 4, 11, 70, 8, 11, 11, 11, 12, 11, 71, 0, 0, 12, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 1, 0, 5, 2, 0, 65, 90, 97, 122, 3, 0, 48, 57, 65, 90, 97, 122, 1, 0, 34, 34, 1, 0, 48, 57, 2, 0, 9, 9, 32, 32, 76, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 1, 25, 1, 0, 0, 0, 3, 28, 1, 0, 0, 0, 5, 30, 1, 0, 0, 0, 7, 32, 1, 0, 0, 0, 9, 34, 1, 0, 0, 0, 11, 36, 1, 0, 0, 0, 13, 39, 1, 0, 0, 0, 15, 43, 1, 0, 0, 0, 17, 47, 1, 0, 0, 0, 19, 54, 1, 0, 0, 0, 21, 64, 1, 0, 0, 0, 23, 69, 1, 0, 0, 0, 25, 26, 5, 91, 0, 0, 26, 27, 5, 91, 0, 0, 27, 2, 1, 0, 0, 0, 28, 29, 5, 61, 0, 0, 29, 4, 1, 0, 0, 0, 30, 31, 5, 32, 0, 0, 31, 6, 1, 0, 0, 0, 32, 33, 5, 91, 0, 0, 33, 8, 1, 0, 0, 0, 34, 35, 5, 45, 0, 0, 35, 10, 1, 0, 0, 0, 36, 37, 5, 93, 0, 0, 37, 38, 5, 93, 0, 0, 38, 12, 1, 0, 0, 0, 39, 40, 5, 47, 0, 0, 40, 41, 5, 93, 0, 0, 41, 42, 5, 93, 0, 0, 42, 14, 1, 0, 0, 0, 43, 44, 5, 91, 0, 0, 44, 45, 5, 91, 0, 0, 45, 46, 5, 47, 0, 0, 46, 16, 1, 0, 0, 0, 47, 51, 7, 0, 0, 0, 48, 50, 7, 1, 0, 0, 49, 48, 1, 0, 0, 0, 50, 53, 1, 0, 0, 0, 51, 49, 1, 0, 0, 0, 51, 52, 1, 0, 0, 0, 52, 18, 1, 0, 0, 0, 53, 51, 1, 0, 0, 0, 54, 58, 5, 34, 0, 0, 55, 57, 8, 2, 0, 0, 56, 55, 1, 0, 0, 0, 57, 60, 1, 0, 0, 0, 58, 56, 1, 0, 0, 0, 58, 59, 1, 0, 0, 0, 59, 61, 1, 0, 0, 0, 60, 58, 1, 0, 0, 0, 61, 62, 5, 34, 0, 0, 62, 20, 1, 0, 0, 0, 63, 65, 7, 3, 0, 0, 64, 63, 1, 0, 0, 0, 65, 66, 1, 0, 0, 0, 66, 64, 1, 0, 0, 0, 66, 67, 1, 0, 0, 0, 67, 22, 1, 0, 0, 0, 68, 70, 7, 4, 0, 0, 69, 68, 1, 0, 0, 0, 70, 71, 1, 0, 0, 0, 71, 69, 1, 0, 0, 0, 71, 72, 1, 0, 0, 0, 72, 24, 1, 0, 0, 0, 5, 0, 51, 58, 66, 71, 0]
\ No newline at end of file
diff --git a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeLexer.java b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeLexer.java
new file mode 100644
index 000000000..e4eb39621
--- /dev/null
+++ b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeLexer.java
@@ -0,0 +1,164 @@
+// Generated from c:/entwicklung/workspaces/tma/cms/cms-server/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeLexer.g4 by ANTLR 4.13.1
+import org.antlr.v4.runtime.Lexer;
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.TokenStream;
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.atn.*;
+import org.antlr.v4.runtime.dfa.DFA;
+import org.antlr.v4.runtime.misc.*;
+
+@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue", "this-escape"})
+public class ShortCodeLexer extends Lexer {
+ static { RuntimeMetaData.checkVersion("4.13.1", RuntimeMetaData.VERSION); }
+
+ protected static final DFA[] _decisionToDFA;
+ protected static final PredictionContextCache _sharedContextCache =
+ new PredictionContextCache();
+ public static final int
+ TAG_OPENING_BRACKET=1, EQUALS=2, SPACE=3, SINGLE_OPEN_BRAKET=4, DASH=5,
+ TAG_CLOSING_BRACKET=6, TAG_CLOSING_CLOSING_BRACKET=7, TAG_OPENING_CLOSING_BRACKET=8,
+ TAG_NAME=9, TAG_STRING=10, TAG_NUMBER=11, TAG_WS=12;
+ public static String[] channelNames = {
+ "DEFAULT_TOKEN_CHANNEL", "HIDDEN"
+ };
+
+ public static String[] modeNames = {
+ "DEFAULT_MODE"
+ };
+
+ private static String[] makeRuleNames() {
+ return new String[] {
+ "TAG_OPENING_BRACKET", "EQUALS", "SPACE", "SINGLE_OPEN_BRAKET", "DASH",
+ "TAG_CLOSING_BRACKET", "TAG_CLOSING_CLOSING_BRACKET", "TAG_OPENING_CLOSING_BRACKET",
+ "TAG_NAME", "TAG_STRING", "TAG_NUMBER", "TAG_WS"
+ };
+ }
+ public static final String[] ruleNames = makeRuleNames();
+
+ private static String[] makeLiteralNames() {
+ return new String[] {
+ null, "'[['", "'='", "' '", "'['", "'-'", "']]'", "'/]]'", "'[[/'"
+ };
+ }
+ private static final String[] _LITERAL_NAMES = makeLiteralNames();
+ private static String[] makeSymbolicNames() {
+ return new String[] {
+ null, "TAG_OPENING_BRACKET", "EQUALS", "SPACE", "SINGLE_OPEN_BRAKET",
+ "DASH", "TAG_CLOSING_BRACKET", "TAG_CLOSING_CLOSING_BRACKET", "TAG_OPENING_CLOSING_BRACKET",
+ "TAG_NAME", "TAG_STRING", "TAG_NUMBER", "TAG_WS"
+ };
+ }
+ private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames();
+ public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
+
+ /**
+ * @deprecated Use {@link #VOCABULARY} instead.
+ */
+ @Deprecated
+ public static final String[] tokenNames;
+ static {
+ tokenNames = new String[_SYMBOLIC_NAMES.length];
+ for (int i = 0; i < tokenNames.length; i++) {
+ tokenNames[i] = VOCABULARY.getLiteralName(i);
+ if (tokenNames[i] == null) {
+ tokenNames[i] = VOCABULARY.getSymbolicName(i);
+ }
+
+ if (tokenNames[i] == null) {
+ tokenNames[i] = "";
+ }
+ }
+ }
+
+ @Override
+ @Deprecated
+ public String[] getTokenNames() {
+ return tokenNames;
+ }
+
+ @Override
+
+ public Vocabulary getVocabulary() {
+ return VOCABULARY;
+ }
+
+
+ public ShortCodeLexer(CharStream input) {
+ super(input);
+ _interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
+ }
+
+ @Override
+ public String getGrammarFileName() { return "ShortCodeLexer.g4"; }
+
+ @Override
+ public String[] getRuleNames() { return ruleNames; }
+
+ @Override
+ public String getSerializedATN() { return _serializedATN; }
+
+ @Override
+ public String[] getChannelNames() { return channelNames; }
+
+ @Override
+ public String[] getModeNames() { return modeNames; }
+
+ @Override
+ public ATN getATN() { return _ATN; }
+
+ public static final String _serializedATN =
+ "\u0004\u0000\fI\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002\u0001"+
+ "\u0007\u0001\u0002\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004"+
+ "\u0007\u0004\u0002\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007"+
+ "\u0007\u0007\u0002\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b"+
+ "\u0007\u000b\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0001\u0001\u0001"+
+ "\u0001\u0002\u0001\u0002\u0001\u0003\u0001\u0003\u0001\u0004\u0001\u0004"+
+ "\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0006\u0001\u0006\u0001\u0006"+
+ "\u0001\u0006\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\b\u0001"+
+ "\b\u0005\b2\b\b\n\b\f\b5\t\b\u0001\t\u0001\t\u0005\t9\b\t\n\t\f\t<\t\t"+
+ "\u0001\t\u0001\t\u0001\n\u0004\nA\b\n\u000b\n\f\nB\u0001\u000b\u0004\u000b"+
+ "F\b\u000b\u000b\u000b\f\u000bG\u0000\u0000\f\u0001\u0001\u0003\u0002\u0005"+
+ "\u0003\u0007\u0004\t\u0005\u000b\u0006\r\u0007\u000f\b\u0011\t\u0013\n"+
+ "\u0015\u000b\u0017\f\u0001\u0000\u0005\u0002\u0000AZaz\u0003\u000009A"+
+ "Zaz\u0001\u0000\"\"\u0001\u000009\u0002\u0000\t\t L\u0000\u0001\u0001"+
+ "\u0000\u0000\u0000\u0000\u0003\u0001\u0000\u0000\u0000\u0000\u0005\u0001"+
+ "\u0000\u0000\u0000\u0000\u0007\u0001\u0000\u0000\u0000\u0000\t\u0001\u0000"+
+ "\u0000\u0000\u0000\u000b\u0001\u0000\u0000\u0000\u0000\r\u0001\u0000\u0000"+
+ "\u0000\u0000\u000f\u0001\u0000\u0000\u0000\u0000\u0011\u0001\u0000\u0000"+
+ "\u0000\u0000\u0013\u0001\u0000\u0000\u0000\u0000\u0015\u0001\u0000\u0000"+
+ "\u0000\u0000\u0017\u0001\u0000\u0000\u0000\u0001\u0019\u0001\u0000\u0000"+
+ "\u0000\u0003\u001c\u0001\u0000\u0000\u0000\u0005\u001e\u0001\u0000\u0000"+
+ "\u0000\u0007 \u0001\u0000\u0000\u0000\t\"\u0001\u0000\u0000\u0000\u000b"+
+ "$\u0001\u0000\u0000\u0000\r\'\u0001\u0000\u0000\u0000\u000f+\u0001\u0000"+
+ "\u0000\u0000\u0011/\u0001\u0000\u0000\u0000\u00136\u0001\u0000\u0000\u0000"+
+ "\u0015@\u0001\u0000\u0000\u0000\u0017E\u0001\u0000\u0000\u0000\u0019\u001a"+
+ "\u0005[\u0000\u0000\u001a\u001b\u0005[\u0000\u0000\u001b\u0002\u0001\u0000"+
+ "\u0000\u0000\u001c\u001d\u0005=\u0000\u0000\u001d\u0004\u0001\u0000\u0000"+
+ "\u0000\u001e\u001f\u0005 \u0000\u0000\u001f\u0006\u0001\u0000\u0000\u0000"+
+ " !\u0005[\u0000\u0000!\b\u0001\u0000\u0000\u0000\"#\u0005-\u0000\u0000"+
+ "#\n\u0001\u0000\u0000\u0000$%\u0005]\u0000\u0000%&\u0005]\u0000\u0000"+
+ "&\f\u0001\u0000\u0000\u0000\'(\u0005/\u0000\u0000()\u0005]\u0000\u0000"+
+ ")*\u0005]\u0000\u0000*\u000e\u0001\u0000\u0000\u0000+,\u0005[\u0000\u0000"+
+ ",-\u0005[\u0000\u0000-.\u0005/\u0000\u0000.\u0010\u0001\u0000\u0000\u0000"+
+ "/3\u0007\u0000\u0000\u000002\u0007\u0001\u0000\u000010\u0001\u0000\u0000"+
+ "\u000025\u0001\u0000\u0000\u000031\u0001\u0000\u0000\u000034\u0001\u0000"+
+ "\u0000\u00004\u0012\u0001\u0000\u0000\u000053\u0001\u0000\u0000\u0000"+
+ "6:\u0005\"\u0000\u000079\b\u0002\u0000\u000087\u0001\u0000\u0000\u0000"+
+ "9<\u0001\u0000\u0000\u0000:8\u0001\u0000\u0000\u0000:;\u0001\u0000\u0000"+
+ "\u0000;=\u0001\u0000\u0000\u0000<:\u0001\u0000\u0000\u0000=>\u0005\"\u0000"+
+ "\u0000>\u0014\u0001\u0000\u0000\u0000?A\u0007\u0003\u0000\u0000@?\u0001"+
+ "\u0000\u0000\u0000AB\u0001\u0000\u0000\u0000B@\u0001\u0000\u0000\u0000"+
+ "BC\u0001\u0000\u0000\u0000C\u0016\u0001\u0000\u0000\u0000DF\u0007\u0004"+
+ "\u0000\u0000ED\u0001\u0000\u0000\u0000FG\u0001\u0000\u0000\u0000GE\u0001"+
+ "\u0000\u0000\u0000GH\u0001\u0000\u0000\u0000H\u0018\u0001\u0000\u0000"+
+ "\u0000\u0005\u00003:BG\u0000";
+ public static final ATN _ATN =
+ new ATNDeserializer().deserialize(_serializedATN.toCharArray());
+ static {
+ _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
+ for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
+ _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i);
+ }
+ }
+}
\ No newline at end of file
diff --git a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeLexer.tokens b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeLexer.tokens
new file mode 100644
index 000000000..e75993c9a
--- /dev/null
+++ b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeLexer.tokens
@@ -0,0 +1,20 @@
+TAG_OPENING_BRACKET=1
+EQUALS=2
+SPACE=3
+SINGLE_OPEN_BRAKET=4
+DASH=5
+TAG_CLOSING_BRACKET=6
+TAG_CLOSING_CLOSING_BRACKET=7
+TAG_OPENING_CLOSING_BRACKET=8
+TAG_NAME=9
+TAG_STRING=10
+TAG_NUMBER=11
+TAG_WS=12
+'[['=1
+'='=2
+' '=3
+'['=4
+'-'=5
+']]'=6
+'/]]'=7
+'[[/'=8
diff --git a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeParser.interp b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeParser.interp
new file mode 100644
index 000000000..57e5c636e
--- /dev/null
+++ b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeParser.interp
@@ -0,0 +1,45 @@
+token literal names:
+null
+'[['
+'='
+' '
+'['
+'-'
+']]'
+'/]]'
+'[[/'
+null
+null
+null
+null
+
+token symbolic names:
+null
+TAG_OPENING_BRACKET
+EQUALS
+SPACE
+SINGLE_OPEN_BRAKET
+DASH
+TAG_CLOSING_BRACKET
+TAG_CLOSING_CLOSING_BRACKET
+TAG_OPENING_CLOSING_BRACKET
+TAG_NAME
+TAG_STRING
+TAG_NUMBER
+TAG_WS
+
+rule names:
+shortcodes
+shortcode
+openingTag
+closingTag
+selfClosingTag
+params
+param
+value
+content
+text
+
+
+atn:
+[4, 1, 12, 96, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 1, 0, 1, 0, 4, 0, 23, 8, 0, 11, 0, 12, 0, 24, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 31, 8, 1, 1, 1, 1, 1, 1, 1, 3, 1, 36, 8, 1, 1, 2, 1, 2, 1, 2, 3, 2, 41, 8, 2, 1, 2, 3, 2, 44, 8, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 3, 4, 55, 8, 4, 1, 4, 3, 4, 58, 8, 4, 1, 4, 3, 4, 61, 8, 4, 1, 4, 1, 4, 1, 5, 1, 5, 4, 5, 67, 8, 5, 11, 5, 12, 5, 68, 1, 5, 5, 5, 72, 8, 5, 10, 5, 12, 5, 75, 9, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 4, 8, 86, 8, 8, 11, 8, 12, 8, 87, 1, 9, 1, 9, 4, 9, 92, 8, 9, 11, 9, 12, 9, 93, 1, 9, 0, 0, 10, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 0, 2, 1, 0, 10, 11, 1, 0, 4, 4, 101, 0, 22, 1, 0, 0, 0, 2, 35, 1, 0, 0, 0, 4, 37, 1, 0, 0, 0, 6, 47, 1, 0, 0, 0, 8, 51, 1, 0, 0, 0, 10, 64, 1, 0, 0, 0, 12, 76, 1, 0, 0, 0, 14, 80, 1, 0, 0, 0, 16, 85, 1, 0, 0, 0, 18, 91, 1, 0, 0, 0, 20, 23, 3, 2, 1, 0, 21, 23, 3, 18, 9, 0, 22, 20, 1, 0, 0, 0, 22, 21, 1, 0, 0, 0, 23, 24, 1, 0, 0, 0, 24, 22, 1, 0, 0, 0, 24, 25, 1, 0, 0, 0, 25, 26, 1, 0, 0, 0, 26, 27, 5, 0, 0, 1, 27, 1, 1, 0, 0, 0, 28, 30, 3, 4, 2, 0, 29, 31, 3, 16, 8, 0, 30, 29, 1, 0, 0, 0, 30, 31, 1, 0, 0, 0, 31, 32, 1, 0, 0, 0, 32, 33, 3, 6, 3, 0, 33, 36, 1, 0, 0, 0, 34, 36, 3, 8, 4, 0, 35, 28, 1, 0, 0, 0, 35, 34, 1, 0, 0, 0, 36, 3, 1, 0, 0, 0, 37, 38, 5, 1, 0, 0, 38, 40, 5, 9, 0, 0, 39, 41, 5, 12, 0, 0, 40, 39, 1, 0, 0, 0, 40, 41, 1, 0, 0, 0, 41, 43, 1, 0, 0, 0, 42, 44, 3, 10, 5, 0, 43, 42, 1, 0, 0, 0, 43, 44, 1, 0, 0, 0, 44, 45, 1, 0, 0, 0, 45, 46, 5, 6, 0, 0, 46, 5, 1, 0, 0, 0, 47, 48, 5, 8, 0, 0, 48, 49, 5, 9, 0, 0, 49, 50, 5, 6, 0, 0, 50, 7, 1, 0, 0, 0, 51, 52, 5, 1, 0, 0, 52, 54, 5, 9, 0, 0, 53, 55, 5, 12, 0, 0, 54, 53, 1, 0, 0, 0, 54, 55, 1, 0, 0, 0, 55, 57, 1, 0, 0, 0, 56, 58, 3, 10, 5, 0, 57, 56, 1, 0, 0, 0, 57, 58, 1, 0, 0, 0, 58, 60, 1, 0, 0, 0, 59, 61, 5, 12, 0, 0, 60, 59, 1, 0, 0, 0, 60, 61, 1, 0, 0, 0, 61, 62, 1, 0, 0, 0, 62, 63, 5, 7, 0, 0, 63, 9, 1, 0, 0, 0, 64, 73, 3, 12, 6, 0, 65, 67, 5, 12, 0, 0, 66, 65, 1, 0, 0, 0, 67, 68, 1, 0, 0, 0, 68, 66, 1, 0, 0, 0, 68, 69, 1, 0, 0, 0, 69, 70, 1, 0, 0, 0, 70, 72, 3, 12, 6, 0, 71, 66, 1, 0, 0, 0, 72, 75, 1, 0, 0, 0, 73, 71, 1, 0, 0, 0, 73, 74, 1, 0, 0, 0, 74, 11, 1, 0, 0, 0, 75, 73, 1, 0, 0, 0, 76, 77, 5, 9, 0, 0, 77, 78, 5, 2, 0, 0, 78, 79, 3, 14, 7, 0, 79, 13, 1, 0, 0, 0, 80, 81, 7, 0, 0, 0, 81, 15, 1, 0, 0, 0, 82, 86, 8, 1, 0, 0, 83, 86, 5, 3, 0, 0, 84, 86, 5, 5, 0, 0, 85, 82, 1, 0, 0, 0, 85, 83, 1, 0, 0, 0, 85, 84, 1, 0, 0, 0, 86, 87, 1, 0, 0, 0, 87, 85, 1, 0, 0, 0, 87, 88, 1, 0, 0, 0, 88, 17, 1, 0, 0, 0, 89, 92, 8, 1, 0, 0, 90, 92, 5, 3, 0, 0, 91, 89, 1, 0, 0, 0, 91, 90, 1, 0, 0, 0, 92, 93, 1, 0, 0, 0, 93, 91, 1, 0, 0, 0, 93, 94, 1, 0, 0, 0, 94, 19, 1, 0, 0, 0, 15, 22, 24, 30, 35, 40, 43, 54, 57, 60, 68, 73, 85, 87, 91, 93]
\ No newline at end of file
diff --git a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeParser.java b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeParser.java
new file mode 100644
index 000000000..c1e2303a9
--- /dev/null
+++ b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/.antlr/ShortCodeParser.java
@@ -0,0 +1,797 @@
+// Generated from c:/entwicklung/workspaces/tma/cms/cms-server/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeParser.g4 by ANTLR 4.13.1
+import org.antlr.v4.runtime.atn.*;
+import org.antlr.v4.runtime.dfa.DFA;
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.misc.*;
+import org.antlr.v4.runtime.tree.*;
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue"})
+public class ShortCodeParser extends Parser {
+ static { RuntimeMetaData.checkVersion("4.13.1", RuntimeMetaData.VERSION); }
+
+ protected static final DFA[] _decisionToDFA;
+ protected static final PredictionContextCache _sharedContextCache =
+ new PredictionContextCache();
+ public static final int
+ TAG_OPENING_BRACKET=1, EQUALS=2, SPACE=3, SINGLE_OPEN_BRAKET=4, DASH=5,
+ TAG_CLOSING_BRACKET=6, TAG_CLOSING_CLOSING_BRACKET=7, TAG_OPENING_CLOSING_BRACKET=8,
+ TAG_NAME=9, TAG_STRING=10, TAG_NUMBER=11, TAG_WS=12;
+ public static final int
+ RULE_shortcodes = 0, RULE_shortcode = 1, RULE_openingTag = 2, RULE_closingTag = 3,
+ RULE_selfClosingTag = 4, RULE_params = 5, RULE_param = 6, RULE_value = 7,
+ RULE_content = 8, RULE_text = 9;
+ private static String[] makeRuleNames() {
+ return new String[] {
+ "shortcodes", "shortcode", "openingTag", "closingTag", "selfClosingTag",
+ "params", "param", "value", "content", "text"
+ };
+ }
+ public static final String[] ruleNames = makeRuleNames();
+
+ private static String[] makeLiteralNames() {
+ return new String[] {
+ null, "'[['", "'='", "' '", "'['", "'-'", "']]'", "'/]]'", "'[[/'"
+ };
+ }
+ private static final String[] _LITERAL_NAMES = makeLiteralNames();
+ private static String[] makeSymbolicNames() {
+ return new String[] {
+ null, "TAG_OPENING_BRACKET", "EQUALS", "SPACE", "SINGLE_OPEN_BRAKET",
+ "DASH", "TAG_CLOSING_BRACKET", "TAG_CLOSING_CLOSING_BRACKET", "TAG_OPENING_CLOSING_BRACKET",
+ "TAG_NAME", "TAG_STRING", "TAG_NUMBER", "TAG_WS"
+ };
+ }
+ private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames();
+ public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
+
+ /**
+ * @deprecated Use {@link #VOCABULARY} instead.
+ */
+ @Deprecated
+ public static final String[] tokenNames;
+ static {
+ tokenNames = new String[_SYMBOLIC_NAMES.length];
+ for (int i = 0; i < tokenNames.length; i++) {
+ tokenNames[i] = VOCABULARY.getLiteralName(i);
+ if (tokenNames[i] == null) {
+ tokenNames[i] = VOCABULARY.getSymbolicName(i);
+ }
+
+ if (tokenNames[i] == null) {
+ tokenNames[i] = "";
+ }
+ }
+ }
+
+ @Override
+ @Deprecated
+ public String[] getTokenNames() {
+ return tokenNames;
+ }
+
+ @Override
+
+ public Vocabulary getVocabulary() {
+ return VOCABULARY;
+ }
+
+ @Override
+ public String getGrammarFileName() { return "ShortCodeParser.g4"; }
+
+ @Override
+ public String[] getRuleNames() { return ruleNames; }
+
+ @Override
+ public String getSerializedATN() { return _serializedATN; }
+
+ @Override
+ public ATN getATN() { return _ATN; }
+
+ public ShortCodeParser(TokenStream input) {
+ super(input);
+ _interp = new ParserATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
+ }
+
+ @SuppressWarnings("CheckReturnValue")
+ public static class ShortcodesContext extends ParserRuleContext {
+ public TerminalNode EOF() { return getToken(ShortCodeParser.EOF, 0); }
+ public List shortcode() {
+ return getRuleContexts(ShortcodeContext.class);
+ }
+ public ShortcodeContext shortcode(int i) {
+ return getRuleContext(ShortcodeContext.class,i);
+ }
+ public List text() {
+ return getRuleContexts(TextContext.class);
+ }
+ public TextContext text(int i) {
+ return getRuleContext(TextContext.class,i);
+ }
+ public ShortcodesContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_shortcodes; }
+ }
+
+ public final ShortcodesContext shortcodes() throws RecognitionException {
+ ShortcodesContext _localctx = new ShortcodesContext(_ctx, getState());
+ enterRule(_localctx, 0, RULE_shortcodes);
+ int _la;
+ try {
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(22);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ do {
+ {
+ setState(22);
+ _errHandler.sync(this);
+ switch ( getInterpreter().adaptivePredict(_input,0,_ctx) ) {
+ case 1:
+ {
+ setState(20);
+ shortcode();
+ }
+ break;
+ case 2:
+ {
+ setState(21);
+ text();
+ }
+ break;
+ }
+ }
+ setState(24);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ } while ( (((_la) & ~0x3f) == 0 && ((1L << _la) & 8174L) != 0) );
+ setState(26);
+ match(EOF);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ @SuppressWarnings("CheckReturnValue")
+ public static class ShortcodeContext extends ParserRuleContext {
+ public ShortcodeContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_shortcode; }
+
+ public ShortcodeContext() { }
+ public void copyFrom(ShortcodeContext ctx) {
+ super.copyFrom(ctx);
+ }
+ }
+ @SuppressWarnings("CheckReturnValue")
+ public static class ShortcodeWithContentContext extends ShortcodeContext {
+ public OpeningTagContext openingTag() {
+ return getRuleContext(OpeningTagContext.class,0);
+ }
+ public ClosingTagContext closingTag() {
+ return getRuleContext(ClosingTagContext.class,0);
+ }
+ public ContentContext content() {
+ return getRuleContext(ContentContext.class,0);
+ }
+ public ShortcodeWithContentContext(ShortcodeContext ctx) { copyFrom(ctx); }
+ }
+ @SuppressWarnings("CheckReturnValue")
+ public static class SelfClosingShortcodeContext extends ShortcodeContext {
+ public SelfClosingTagContext selfClosingTag() {
+ return getRuleContext(SelfClosingTagContext.class,0);
+ }
+ public SelfClosingShortcodeContext(ShortcodeContext ctx) { copyFrom(ctx); }
+ }
+
+ public final ShortcodeContext shortcode() throws RecognitionException {
+ ShortcodeContext _localctx = new ShortcodeContext(_ctx, getState());
+ enterRule(_localctx, 2, RULE_shortcode);
+ try {
+ setState(35);
+ _errHandler.sync(this);
+ switch ( getInterpreter().adaptivePredict(_input,3,_ctx) ) {
+ case 1:
+ _localctx = new ShortcodeWithContentContext(_localctx);
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(28);
+ openingTag();
+ setState(30);
+ _errHandler.sync(this);
+ switch ( getInterpreter().adaptivePredict(_input,2,_ctx) ) {
+ case 1:
+ {
+ setState(29);
+ content();
+ }
+ break;
+ }
+ setState(32);
+ closingTag();
+ }
+ break;
+ case 2:
+ _localctx = new SelfClosingShortcodeContext(_localctx);
+ enterOuterAlt(_localctx, 2);
+ {
+ setState(34);
+ selfClosingTag();
+ }
+ break;
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ @SuppressWarnings("CheckReturnValue")
+ public static class OpeningTagContext extends ParserRuleContext {
+ public TerminalNode TAG_OPENING_BRACKET() { return getToken(ShortCodeParser.TAG_OPENING_BRACKET, 0); }
+ public TerminalNode TAG_NAME() { return getToken(ShortCodeParser.TAG_NAME, 0); }
+ public TerminalNode TAG_CLOSING_BRACKET() { return getToken(ShortCodeParser.TAG_CLOSING_BRACKET, 0); }
+ public TerminalNode TAG_WS() { return getToken(ShortCodeParser.TAG_WS, 0); }
+ public ParamsContext params() {
+ return getRuleContext(ParamsContext.class,0);
+ }
+ public OpeningTagContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_openingTag; }
+ }
+
+ public final OpeningTagContext openingTag() throws RecognitionException {
+ OpeningTagContext _localctx = new OpeningTagContext(_ctx, getState());
+ enterRule(_localctx, 4, RULE_openingTag);
+ int _la;
+ try {
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(37);
+ match(TAG_OPENING_BRACKET);
+ setState(38);
+ match(TAG_NAME);
+ setState(40);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ if (_la==TAG_WS) {
+ {
+ setState(39);
+ match(TAG_WS);
+ }
+ }
+
+ setState(43);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ if (_la==TAG_NAME) {
+ {
+ setState(42);
+ params();
+ }
+ }
+
+ setState(45);
+ match(TAG_CLOSING_BRACKET);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ @SuppressWarnings("CheckReturnValue")
+ public static class ClosingTagContext extends ParserRuleContext {
+ public TerminalNode TAG_OPENING_CLOSING_BRACKET() { return getToken(ShortCodeParser.TAG_OPENING_CLOSING_BRACKET, 0); }
+ public TerminalNode TAG_NAME() { return getToken(ShortCodeParser.TAG_NAME, 0); }
+ public TerminalNode TAG_CLOSING_BRACKET() { return getToken(ShortCodeParser.TAG_CLOSING_BRACKET, 0); }
+ public ClosingTagContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_closingTag; }
+ }
+
+ public final ClosingTagContext closingTag() throws RecognitionException {
+ ClosingTagContext _localctx = new ClosingTagContext(_ctx, getState());
+ enterRule(_localctx, 6, RULE_closingTag);
+ try {
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(47);
+ match(TAG_OPENING_CLOSING_BRACKET);
+ setState(48);
+ match(TAG_NAME);
+ setState(49);
+ match(TAG_CLOSING_BRACKET);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ @SuppressWarnings("CheckReturnValue")
+ public static class SelfClosingTagContext extends ParserRuleContext {
+ public TerminalNode TAG_OPENING_BRACKET() { return getToken(ShortCodeParser.TAG_OPENING_BRACKET, 0); }
+ public TerminalNode TAG_NAME() { return getToken(ShortCodeParser.TAG_NAME, 0); }
+ public TerminalNode TAG_CLOSING_CLOSING_BRACKET() { return getToken(ShortCodeParser.TAG_CLOSING_CLOSING_BRACKET, 0); }
+ public List TAG_WS() { return getTokens(ShortCodeParser.TAG_WS); }
+ public TerminalNode TAG_WS(int i) {
+ return getToken(ShortCodeParser.TAG_WS, i);
+ }
+ public ParamsContext params() {
+ return getRuleContext(ParamsContext.class,0);
+ }
+ public SelfClosingTagContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_selfClosingTag; }
+ }
+
+ public final SelfClosingTagContext selfClosingTag() throws RecognitionException {
+ SelfClosingTagContext _localctx = new SelfClosingTagContext(_ctx, getState());
+ enterRule(_localctx, 8, RULE_selfClosingTag);
+ int _la;
+ try {
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(51);
+ match(TAG_OPENING_BRACKET);
+ setState(52);
+ match(TAG_NAME);
+ setState(54);
+ _errHandler.sync(this);
+ switch ( getInterpreter().adaptivePredict(_input,6,_ctx) ) {
+ case 1:
+ {
+ setState(53);
+ match(TAG_WS);
+ }
+ break;
+ }
+ setState(57);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ if (_la==TAG_NAME) {
+ {
+ setState(56);
+ params();
+ }
+ }
+
+ setState(60);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ if (_la==TAG_WS) {
+ {
+ setState(59);
+ match(TAG_WS);
+ }
+ }
+
+ setState(62);
+ match(TAG_CLOSING_CLOSING_BRACKET);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ @SuppressWarnings("CheckReturnValue")
+ public static class ParamsContext extends ParserRuleContext {
+ public List param() {
+ return getRuleContexts(ParamContext.class);
+ }
+ public ParamContext param(int i) {
+ return getRuleContext(ParamContext.class,i);
+ }
+ public List TAG_WS() { return getTokens(ShortCodeParser.TAG_WS); }
+ public TerminalNode TAG_WS(int i) {
+ return getToken(ShortCodeParser.TAG_WS, i);
+ }
+ public ParamsContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_params; }
+ }
+
+ public final ParamsContext params() throws RecognitionException {
+ ParamsContext _localctx = new ParamsContext(_ctx, getState());
+ enterRule(_localctx, 10, RULE_params);
+ int _la;
+ try {
+ int _alt;
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(64);
+ param();
+ setState(73);
+ _errHandler.sync(this);
+ _alt = getInterpreter().adaptivePredict(_input,10,_ctx);
+ while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
+ if ( _alt==1 ) {
+ {
+ {
+ setState(66);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ do {
+ {
+ {
+ setState(65);
+ match(TAG_WS);
+ }
+ }
+ setState(68);
+ _errHandler.sync(this);
+ _la = _input.LA(1);
+ } while ( _la==TAG_WS );
+ setState(70);
+ param();
+ }
+ }
+ }
+ setState(75);
+ _errHandler.sync(this);
+ _alt = getInterpreter().adaptivePredict(_input,10,_ctx);
+ }
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ @SuppressWarnings("CheckReturnValue")
+ public static class ParamContext extends ParserRuleContext {
+ public TerminalNode TAG_NAME() { return getToken(ShortCodeParser.TAG_NAME, 0); }
+ public TerminalNode EQUALS() { return getToken(ShortCodeParser.EQUALS, 0); }
+ public ValueContext value() {
+ return getRuleContext(ValueContext.class,0);
+ }
+ public ParamContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_param; }
+ }
+
+ public final ParamContext param() throws RecognitionException {
+ ParamContext _localctx = new ParamContext(_ctx, getState());
+ enterRule(_localctx, 12, RULE_param);
+ try {
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(76);
+ match(TAG_NAME);
+ setState(77);
+ match(EQUALS);
+ setState(78);
+ value();
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ @SuppressWarnings("CheckReturnValue")
+ public static class ValueContext extends ParserRuleContext {
+ public TerminalNode TAG_STRING() { return getToken(ShortCodeParser.TAG_STRING, 0); }
+ public TerminalNode TAG_NUMBER() { return getToken(ShortCodeParser.TAG_NUMBER, 0); }
+ public ValueContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_value; }
+ }
+
+ public final ValueContext value() throws RecognitionException {
+ ValueContext _localctx = new ValueContext(_ctx, getState());
+ enterRule(_localctx, 14, RULE_value);
+ int _la;
+ try {
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(80);
+ _la = _input.LA(1);
+ if ( !(_la==TAG_STRING || _la==TAG_NUMBER) ) {
+ _errHandler.recoverInline(this);
+ }
+ else {
+ if ( _input.LA(1)==Token.EOF ) matchedEOF = true;
+ _errHandler.reportMatch(this);
+ consume();
+ }
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ @SuppressWarnings("CheckReturnValue")
+ public static class ContentContext extends ParserRuleContext {
+ public List SPACE() { return getTokens(ShortCodeParser.SPACE); }
+ public TerminalNode SPACE(int i) {
+ return getToken(ShortCodeParser.SPACE, i);
+ }
+ public List DASH() { return getTokens(ShortCodeParser.DASH); }
+ public TerminalNode DASH(int i) {
+ return getToken(ShortCodeParser.DASH, i);
+ }
+ public List SINGLE_OPEN_BRAKET() { return getTokens(ShortCodeParser.SINGLE_OPEN_BRAKET); }
+ public TerminalNode SINGLE_OPEN_BRAKET(int i) {
+ return getToken(ShortCodeParser.SINGLE_OPEN_BRAKET, i);
+ }
+ public ContentContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_content; }
+ }
+
+ public final ContentContext content() throws RecognitionException {
+ ContentContext _localctx = new ContentContext(_ctx, getState());
+ enterRule(_localctx, 16, RULE_content);
+ int _la;
+ try {
+ int _alt;
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(85);
+ _errHandler.sync(this);
+ _alt = 1;
+ do {
+ switch (_alt) {
+ case 1:
+ {
+ setState(85);
+ _errHandler.sync(this);
+ switch ( getInterpreter().adaptivePredict(_input,11,_ctx) ) {
+ case 1:
+ {
+ setState(82);
+ _la = _input.LA(1);
+ if ( _la <= 0 || (_la==SINGLE_OPEN_BRAKET) ) {
+ _errHandler.recoverInline(this);
+ }
+ else {
+ if ( _input.LA(1)==Token.EOF ) matchedEOF = true;
+ _errHandler.reportMatch(this);
+ consume();
+ }
+ }
+ break;
+ case 2:
+ {
+ setState(83);
+ match(SPACE);
+ }
+ break;
+ case 3:
+ {
+ setState(84);
+ match(DASH);
+ }
+ break;
+ }
+ }
+ break;
+ default:
+ throw new NoViableAltException(this);
+ }
+ setState(87);
+ _errHandler.sync(this);
+ _alt = getInterpreter().adaptivePredict(_input,12,_ctx);
+ } while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER );
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ @SuppressWarnings("CheckReturnValue")
+ public static class TextContext extends ParserRuleContext {
+ public List SPACE() { return getTokens(ShortCodeParser.SPACE); }
+ public TerminalNode SPACE(int i) {
+ return getToken(ShortCodeParser.SPACE, i);
+ }
+ public List SINGLE_OPEN_BRAKET() { return getTokens(ShortCodeParser.SINGLE_OPEN_BRAKET); }
+ public TerminalNode SINGLE_OPEN_BRAKET(int i) {
+ return getToken(ShortCodeParser.SINGLE_OPEN_BRAKET, i);
+ }
+ public TextContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_text; }
+ }
+
+ public final TextContext text() throws RecognitionException {
+ TextContext _localctx = new TextContext(_ctx, getState());
+ enterRule(_localctx, 18, RULE_text);
+ int _la;
+ try {
+ int _alt;
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(91);
+ _errHandler.sync(this);
+ _alt = 1;
+ do {
+ switch (_alt) {
+ case 1:
+ {
+ setState(91);
+ _errHandler.sync(this);
+ switch ( getInterpreter().adaptivePredict(_input,13,_ctx) ) {
+ case 1:
+ {
+ setState(89);
+ _la = _input.LA(1);
+ if ( _la <= 0 || (_la==SINGLE_OPEN_BRAKET) ) {
+ _errHandler.recoverInline(this);
+ }
+ else {
+ if ( _input.LA(1)==Token.EOF ) matchedEOF = true;
+ _errHandler.reportMatch(this);
+ consume();
+ }
+ }
+ break;
+ case 2:
+ {
+ setState(90);
+ match(SPACE);
+ }
+ break;
+ }
+ }
+ break;
+ default:
+ throw new NoViableAltException(this);
+ }
+ setState(93);
+ _errHandler.sync(this);
+ _alt = getInterpreter().adaptivePredict(_input,14,_ctx);
+ } while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER );
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ public static final String _serializedATN =
+ "\u0004\u0001\f`\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+
+ "\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004\u0007\u0004\u0002"+
+ "\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007\u0007\u0007\u0002"+
+ "\b\u0007\b\u0002\t\u0007\t\u0001\u0000\u0001\u0000\u0004\u0000\u0017\b"+
+ "\u0000\u000b\u0000\f\u0000\u0018\u0001\u0000\u0001\u0000\u0001\u0001\u0001"+
+ "\u0001\u0003\u0001\u001f\b\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0003"+
+ "\u0001$\b\u0001\u0001\u0002\u0001\u0002\u0001\u0002\u0003\u0002)\b\u0002"+
+ "\u0001\u0002\u0003\u0002,\b\u0002\u0001\u0002\u0001\u0002\u0001\u0003"+
+ "\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0004\u0001\u0004\u0001\u0004"+
+ "\u0003\u00047\b\u0004\u0001\u0004\u0003\u0004:\b\u0004\u0001\u0004\u0003"+
+ "\u0004=\b\u0004\u0001\u0004\u0001\u0004\u0001\u0005\u0001\u0005\u0004"+
+ "\u0005C\b\u0005\u000b\u0005\f\u0005D\u0001\u0005\u0005\u0005H\b\u0005"+
+ "\n\u0005\f\u0005K\t\u0005\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006"+
+ "\u0001\u0007\u0001\u0007\u0001\b\u0001\b\u0001\b\u0004\bV\b\b\u000b\b"+
+ "\f\bW\u0001\t\u0001\t\u0004\t\\\b\t\u000b\t\f\t]\u0001\t\u0000\u0000\n"+
+ "\u0000\u0002\u0004\u0006\b\n\f\u000e\u0010\u0012\u0000\u0002\u0001\u0000"+
+ "\n\u000b\u0001\u0000\u0004\u0004e\u0000\u0016\u0001\u0000\u0000\u0000"+
+ "\u0002#\u0001\u0000\u0000\u0000\u0004%\u0001\u0000\u0000\u0000\u0006/"+
+ "\u0001\u0000\u0000\u0000\b3\u0001\u0000\u0000\u0000\n@\u0001\u0000\u0000"+
+ "\u0000\fL\u0001\u0000\u0000\u0000\u000eP\u0001\u0000\u0000\u0000\u0010"+
+ "U\u0001\u0000\u0000\u0000\u0012[\u0001\u0000\u0000\u0000\u0014\u0017\u0003"+
+ "\u0002\u0001\u0000\u0015\u0017\u0003\u0012\t\u0000\u0016\u0014\u0001\u0000"+
+ "\u0000\u0000\u0016\u0015\u0001\u0000\u0000\u0000\u0017\u0018\u0001\u0000"+
+ "\u0000\u0000\u0018\u0016\u0001\u0000\u0000\u0000\u0018\u0019\u0001\u0000"+
+ "\u0000\u0000\u0019\u001a\u0001\u0000\u0000\u0000\u001a\u001b\u0005\u0000"+
+ "\u0000\u0001\u001b\u0001\u0001\u0000\u0000\u0000\u001c\u001e\u0003\u0004"+
+ "\u0002\u0000\u001d\u001f\u0003\u0010\b\u0000\u001e\u001d\u0001\u0000\u0000"+
+ "\u0000\u001e\u001f\u0001\u0000\u0000\u0000\u001f \u0001\u0000\u0000\u0000"+
+ " !\u0003\u0006\u0003\u0000!$\u0001\u0000\u0000\u0000\"$\u0003\b\u0004"+
+ "\u0000#\u001c\u0001\u0000\u0000\u0000#\"\u0001\u0000\u0000\u0000$\u0003"+
+ "\u0001\u0000\u0000\u0000%&\u0005\u0001\u0000\u0000&(\u0005\t\u0000\u0000"+
+ "\')\u0005\f\u0000\u0000(\'\u0001\u0000\u0000\u0000()\u0001\u0000\u0000"+
+ "\u0000)+\u0001\u0000\u0000\u0000*,\u0003\n\u0005\u0000+*\u0001\u0000\u0000"+
+ "\u0000+,\u0001\u0000\u0000\u0000,-\u0001\u0000\u0000\u0000-.\u0005\u0006"+
+ "\u0000\u0000.\u0005\u0001\u0000\u0000\u0000/0\u0005\b\u0000\u000001\u0005"+
+ "\t\u0000\u000012\u0005\u0006\u0000\u00002\u0007\u0001\u0000\u0000\u0000"+
+ "34\u0005\u0001\u0000\u000046\u0005\t\u0000\u000057\u0005\f\u0000\u0000"+
+ "65\u0001\u0000\u0000\u000067\u0001\u0000\u0000\u000079\u0001\u0000\u0000"+
+ "\u00008:\u0003\n\u0005\u000098\u0001\u0000\u0000\u00009:\u0001\u0000\u0000"+
+ "\u0000:<\u0001\u0000\u0000\u0000;=\u0005\f\u0000\u0000<;\u0001\u0000\u0000"+
+ "\u0000<=\u0001\u0000\u0000\u0000=>\u0001\u0000\u0000\u0000>?\u0005\u0007"+
+ "\u0000\u0000?\t\u0001\u0000\u0000\u0000@I\u0003\f\u0006\u0000AC\u0005"+
+ "\f\u0000\u0000BA\u0001\u0000\u0000\u0000CD\u0001\u0000\u0000\u0000DB\u0001"+
+ "\u0000\u0000\u0000DE\u0001\u0000\u0000\u0000EF\u0001\u0000\u0000\u0000"+
+ "FH\u0003\f\u0006\u0000GB\u0001\u0000\u0000\u0000HK\u0001\u0000\u0000\u0000"+
+ "IG\u0001\u0000\u0000\u0000IJ\u0001\u0000\u0000\u0000J\u000b\u0001\u0000"+
+ "\u0000\u0000KI\u0001\u0000\u0000\u0000LM\u0005\t\u0000\u0000MN\u0005\u0002"+
+ "\u0000\u0000NO\u0003\u000e\u0007\u0000O\r\u0001\u0000\u0000\u0000PQ\u0007"+
+ "\u0000\u0000\u0000Q\u000f\u0001\u0000\u0000\u0000RV\b\u0001\u0000\u0000"+
+ "SV\u0005\u0003\u0000\u0000TV\u0005\u0005\u0000\u0000UR\u0001\u0000\u0000"+
+ "\u0000US\u0001\u0000\u0000\u0000UT\u0001\u0000\u0000\u0000VW\u0001\u0000"+
+ "\u0000\u0000WU\u0001\u0000\u0000\u0000WX\u0001\u0000\u0000\u0000X\u0011"+
+ "\u0001\u0000\u0000\u0000Y\\\b\u0001\u0000\u0000Z\\\u0005\u0003\u0000\u0000"+
+ "[Y\u0001\u0000\u0000\u0000[Z\u0001\u0000\u0000\u0000\\]\u0001\u0000\u0000"+
+ "\u0000][\u0001\u0000\u0000\u0000]^\u0001\u0000\u0000\u0000^\u0013\u0001"+
+ "\u0000\u0000\u0000\u000f\u0016\u0018\u001e#(+69
Date: Thu, 10 Oct 2024 16:37:24 +0200
Subject: [PATCH 07/15] update antlr grammar
---
.../condation/cms/content/shortcodes/ShortCodeParser.g4 | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeParser.g4 b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeParser.g4
index 771d20471..5461ead93 100644
--- a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeParser.g4
+++ b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeParser.g4
@@ -24,4 +24,9 @@ param: TAG_NAME EQUALS value ;
value: TAG_STRING | TAG_NUMBER;
content: (~SINGLE_OPEN_BRAKET | SPACE | DASH)+ ;
-text: (.)+? { _input.LA(1) != '[' || _input.LA(2) != '[' }? ;
+text2:
+ (.)+? { _input.LA(1) != '[' || _input.LA(2) != '[' }?
+ ;
+text
+ : (~'[' | ('[' { _input.LA(1) != '[' }?))+
+ ;
From 010c30c83128af107c461cda57bcd1a23d796b7d Mon Sep 17 00:00:00 2001
From: Thorsten Marx
Date: Thu, 10 Oct 2024 16:37:34 +0200
Subject: [PATCH 08/15] update antlr grammar
---
.../com/condation/cms/content/shortcodes/ShortCodeParser.g4 | 3 ---
1 file changed, 3 deletions(-)
diff --git a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeParser.g4 b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeParser.g4
index 5461ead93..937b237be 100644
--- a/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeParser.g4
+++ b/cms-sandbox/tests/src/main/resources/com/condation/cms/content/shortcodes/ShortCodeParser.g4
@@ -27,6 +27,3 @@ content: (~SINGLE_OPEN_BRAKET | SPACE | DASH)+ ;
text2:
(.)+? { _input.LA(1) != '[' || _input.LA(2) != '[' }?
;
-text
- : (~'[' | ('[' { _input.LA(1) != '[' }?))+
- ;
From 1a5592ed7a1b7c0664e281998978c29c9cce2edd Mon Sep 17 00:00:00 2001
From: Thorsten Marx
Date: Thu, 10 Oct 2024 21:11:45 +0200
Subject: [PATCH 09/15] new short code tag parser with expression support
---
.../content/shortcodes/ShortCodeParser.java | 30 +---
.../cms/content/shortcodes/ShortCodes.java | 19 +--
.../cms/content/shortcodes/TagMap.java | 53 ++++++
.../cms/content/shortcodes/TagParser.java | 157 ++++++++++++++++++
.../cms/content/ContentBaseTest.java | 14 +-
.../ShortCodeParserExpressionsTest.java | 55 ------
.../content/shortcodes/ShortCodesTest.java | 18 +-
.../cms/content/shortcodes/TagParserTest.java | 123 ++++++++++++++
...eeMarkerShortCodeTemplateFunctionTest.java | 2 +-
.../PebbleShortCodeTemplateFunctionTest.java | 2 +-
...hymeleafShortCodeTemplateFunctionTest.java | 2 +-
.../cms/content/shortcodes/TagParser.java | 151 +++++++++++++++++
.../cms/content/shortcodes/TagParserTest.java | 103 ++++++++++++
.../cms/request/RequestContextFactory.java | 6 +-
.../cms/server/configs/SiteModule.java | 6 +-
.../java/com/condation/cms/TestHelper.java | 3 +-
16 files changed, 631 insertions(+), 113 deletions(-)
create mode 100644 cms-content/src/main/java/com/condation/cms/content/shortcodes/TagMap.java
create mode 100644 cms-content/src/main/java/com/condation/cms/content/shortcodes/TagParser.java
delete mode 100644 cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodeParserExpressionsTest.java
create mode 100644 cms-content/src/test/java/com/condation/cms/content/shortcodes/TagParserTest.java
create mode 100644 cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/TagParser.java
create mode 100644 cms-sandbox/tests/src/test/java/com/condation/cms/content/shortcodes/TagParserTest.java
diff --git a/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodeParser.java b/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodeParser.java
index f5969d409..be7c57566 100644
--- a/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodeParser.java
+++ b/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodeParser.java
@@ -38,15 +38,12 @@
@Slf4j
public class ShortCodeParser {
- JexlEngine engine;
-
public static final String SHORTCODE_REGEX = "\\[\\[(\\w+)([^\\]]*)\\]\\](.*?)\\[\\[\\/\\1\\]\\]|\\[\\[(\\w+)([^\\]]*)\\s*\\/\\]\\]";
public static final Pattern SHORTCODE_PATTERN = Pattern.compile(SHORTCODE_REGEX, Pattern.DOTALL);
//public static final Pattern PARAM_PATTERN = Pattern.compile("(\\w+)=(\"[^\"]*\"|'[^']*')");
public static final Pattern PARAM_PATTERN = Pattern.compile("(\\w+)=((\"[^\"]*\"|'[^']*'|\\[[^\\]]*\\]))");
- public ShortCodeParser(JexlEngine engine) {
- this.engine = engine;
+ public ShortCodeParser() {
}
public List parseShortcodes(String text) {
@@ -68,10 +65,7 @@ public List parseShortcodes(String text) {
String key = paramMatcher.group(1);
String value = paramMatcher.group(2);
value = value.substring(1, value.length() - 1); // Entfernt die Anführungszeichen oder Klammern bei Arrays
-
- // Prüfe, ob es ein Array ist und nutze JEXL zur Auswertung
- Object evaluatedValue = evaluateExpression(value);
- match.getParameters().put(key, evaluatedValue);
+ match.getParameters().put(key, value);
}
shortcodes.add(match);
@@ -80,26 +74,6 @@ public List parseShortcodes(String text) {
return shortcodes;
}
- private Object evaluateExpression(String value) {
- try {
- JexlExpression expression = engine.createExpression(value);
- JexlContext context = new MapContext();
- var parsedValue = expression.evaluate(context);
- if (parsedValue.getClass().isArray()) {
- int length = Array.getLength(parsedValue);
- List list = new ArrayList<>(length);
- for (int i = 0; i < length; i++) {
- list.add(Array.get(parsedValue, i)); // Holen des Elements am Index i
- }
- return list;
- } else {
- return parsedValue;
- }
- } catch (Exception e) {
- return value;
- }
- }
-
public String replace(String content, Codes codes) {
StringBuilder newContent = new StringBuilder();
int lastPosition = 0;
diff --git a/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java b/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
index 27a8143dc..9d71e70c7 100644
--- a/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
+++ b/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
@@ -28,7 +28,6 @@
import java.util.function.Function;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.jexl3.JexlEngine;
/**
*
@@ -38,21 +37,21 @@
@RequiredArgsConstructor
public class ShortCodes {
- private final ShortCodeParser.Codes codes;
- private final ShortCodeParser parser;
+ private final TagMap tagMap;
+ private final TagParser parser;
- public ShortCodes (Map> codes, ShortCodeParser shortCodeParser) {
- this.parser = shortCodeParser;
- this.codes = new ShortCodeParser.Codes();
- this.codes.addAll(codes);
+ public ShortCodes (Map> codes, TagParser tagParser) {
+ this.parser = tagParser;
+ this.tagMap = new TagMap();
+ this.tagMap.putAll(codes);
}
public String replace (final String content) {
- return parser.replace(content, codes);
+ return parser.parse(content, tagMap);
}
public String execute (String name, Map parameters) {
- if (codes.get(name) == null) {
+ if (!tagMap.has(name)) {
return "";
}
try {
@@ -62,7 +61,7 @@ public String execute (String name, Map parameters) {
} else {
params = new Parameter();
}
- return codes.get(name).apply(params);
+ return tagMap.get(name).apply(params);
} catch (Exception e) {
log.error("",e);
}
diff --git a/cms-content/src/main/java/com/condation/cms/content/shortcodes/TagMap.java b/cms-content/src/main/java/com/condation/cms/content/shortcodes/TagMap.java
new file mode 100644
index 000000000..e503f067a
--- /dev/null
+++ b/cms-content/src/main/java/com/condation/cms/content/shortcodes/TagMap.java
@@ -0,0 +1,53 @@
+package com.condation.cms.content.shortcodes;
+
+/*-
+ * #%L
+ * cms-content
+ * %%
+ * Copyright (C) 2023 - 2024 CondationCMS
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program. If not, see
+ * .
+ * #L%
+ */
+
+import com.condation.cms.api.model.Parameter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+
+/**
+ *
+ * @author t.marx
+ */
+public class TagMap {
+
+ private final Map> tags = new HashMap<>();
+
+ public void put(String codeName, Function function) {
+ tags.put(codeName, function);
+ }
+
+ public void putAll(Map> tags) {
+ this.tags.putAll(tags);
+ }
+
+ public boolean has(String codeName) {
+ return tags.containsKey(codeName);
+ }
+
+ public Function get(String codeName) {
+ return tags.getOrDefault(codeName, (params) -> "");
+ }
+}
diff --git a/cms-content/src/main/java/com/condation/cms/content/shortcodes/TagParser.java b/cms-content/src/main/java/com/condation/cms/content/shortcodes/TagParser.java
new file mode 100644
index 000000000..82dec3038
--- /dev/null
+++ b/cms-content/src/main/java/com/condation/cms/content/shortcodes/TagParser.java
@@ -0,0 +1,157 @@
+package com.condation.cms.content.shortcodes;
+
+/*-
+ * #%L
+ * cms-content
+ * %%
+ * Copyright (C) 2023 - 2024 CondationCMS
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program. If not, see
+ * .
+ * #L%
+ */
+
+import com.condation.cms.api.model.Parameter;
+import java.util.*;
+import java.util.function.Function;
+import org.apache.commons.jexl3.JexlEngine;
+import org.apache.commons.jexl3.MapContext;
+
+public class TagParser {
+
+ private final JexlEngine engine;
+
+ public TagParser(JexlEngine engine) {
+ this.engine = engine;
+ }
+
+ public String parse(String text, TagMap tagHandlers) {
+ StringBuilder result = new StringBuilder();
+ int i = 0;
+ while (i < text.length()) {
+ if (text.charAt(i) == '[' && i + 1 < text.length() && text.charAt(i + 1) == '[') {
+ int tagStart = i;
+ i = parseTag(text, i, result, tagHandlers);
+ if (i == tagStart) { // Kein gültiger Tag gefunden, füge '[[' hinzu.
+ result.append("[[");
+ i += 2;
+ }
+ } else {
+ result.append(text.charAt(i));
+ i++;
+ }
+ }
+ return result.toString();
+ }
+
+ private int parseTag(String text, int index, StringBuilder result, TagMap tagHandlers) {
+ int endTagIndex = findTagEnd(text, index);
+ if (endTagIndex == -1) {
+ return index; // Kein schließendes ']]' gefunden
+ }
+
+ String tagContent = text.substring(index + 2, endTagIndex).trim();
+ boolean isSelfClosing = tagContent.endsWith("/");
+
+ if (isSelfClosing) {
+ tagContent = tagContent.substring(0, tagContent.length() - 1).trim();
+ }
+
+ int spaceIndex = tagContent.indexOf(' ');
+ String tagName = spaceIndex == -1 ? tagContent : tagContent.substring(0, spaceIndex);
+ Parameter attributes = spaceIndex == -1
+ ? new Parameter()
+ : parseAttributes(tagContent.substring(spaceIndex + 1));
+
+ int closingTagIndex = -1;
+ if (!isSelfClosing) {
+ closingTagIndex = text.indexOf("[[/" + tagName + "]]", endTagIndex + 2);
+ if (closingTagIndex != -1) {
+ // Verarbeite den Content für geöffnete und geschlossene Tags
+ String content = text.substring(endTagIndex + 2, closingTagIndex);
+ attributes.put("_content", content);
+ endTagIndex = closingTagIndex + ("[[/" + tagName + "]]").length() - 2;
+ }
+ }
+
+ if (tagHandlers.has(tagName)) {
+ Function handler = tagHandlers.get(tagName);
+ result.append(handler.apply(attributes));
+ // Setze den Index auf das Zeichen direkt nach dem schließenden Tag oder schließenden Tag mit Content
+ return endTagIndex + 2;
+ }
+
+ return index; // Tag nicht erkannt
+ }
+
+ private int findTagEnd(String text, int startIndex) {
+ for (int i = startIndex; i < text.length() - 1; i++) {
+ if (text.charAt(i) == ']' && text.charAt(i + 1) == ']') {
+ return i;
+ }
+ }
+ return -1; // Kein schließendes ']]' gefunden
+ }
+
+ private Parameter parseAttributes(String attributesString) {
+ Parameter attributes = new Parameter();
+ StringBuilder key = new StringBuilder();
+ StringBuilder value = new StringBuilder();
+ boolean inQuotes = false;
+ boolean readingKey = true;
+
+ for (int i = 0; i < attributesString.length(); i++) {
+ char c = attributesString.charAt(i);
+ if (c == '"' || c == '\'') {
+ inQuotes = !inQuotes;
+ } else if (!inQuotes && (c == '=' || c == ' ')) {
+ if (readingKey) {
+ readingKey = false;
+ } else {
+ attributes.put(key.toString().trim(), parseValue(value.toString().trim()));
+ key.setLength(0);
+ value.setLength(0);
+ readingKey = true;
+ }
+ } else {
+ if (readingKey) {
+ key.append(c);
+ } else {
+ value.append(c);
+ }
+ }
+ }
+
+ // Letztes Attribut verarbeiten
+ if (key.length() > 0 && value.length() > 0) {
+ attributes.put(key.toString().trim(), parseValue(value.toString().trim()));
+ }
+
+ return attributes;
+ }
+
+ private Object parseValue(String value) {
+ if (value.matches("\\d+")) {
+ return Integer.valueOf(value);
+ } else if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
+ return Boolean.valueOf(value);
+ } else if (value.startsWith("${") && value.endsWith("}")) {
+ String expressionString = value.substring(2, value.length() - 1);
+
+ var expression = engine.createExpression(expressionString);
+ return expression.evaluate(new MapContext());
+ }
+ return value;
+ }
+}
diff --git a/cms-content/src/test/java/com/condation/cms/content/ContentBaseTest.java b/cms-content/src/test/java/com/condation/cms/content/ContentBaseTest.java
index 883780f7f..a86307a41 100644
--- a/cms-content/src/test/java/com/condation/cms/content/ContentBaseTest.java
+++ b/cms-content/src/test/java/com/condation/cms/content/ContentBaseTest.java
@@ -23,6 +23,7 @@
*/
import com.condation.cms.content.shortcodes.ShortCodeParser;
+import com.condation.cms.content.shortcodes.TagParser;
import org.apache.commons.jexl3.JexlBuilder;
/**
@@ -33,10 +34,21 @@ public abstract class ContentBaseTest {
private ShortCodeParser shortCodeParser;
+ private TagParser tagParser;
+
+ public TagParser getTagParser () {
+ if (tagParser == null) {
+ tagParser = new TagParser(
+ new JexlBuilder().cache(512).strict(true).silent(false).create()
+ );
+ }
+
+ return tagParser;
+ }
+
public ShortCodeParser getShortCodeParser () {
if (shortCodeParser == null) {
shortCodeParser = new ShortCodeParser(
- new JexlBuilder().cache(512).strict(true).silent(false).create()
);
}
diff --git a/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodeParserExpressionsTest.java b/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodeParserExpressionsTest.java
deleted file mode 100644
index 8e7855238..000000000
--- a/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodeParserExpressionsTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.condation.cms.content.shortcodes;
-
-/*-
- * #%L
- * cms-content
- * %%
- * Copyright (C) 2023 - 2024 CondationCMS
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program. If not, see
- * .
- * #L%
- */
-
-
-import com.condation.cms.content.ContentBaseTest;
-import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.*;
-
-import java.util.List;
-
-public class ShortCodeParserExpressionsTest extends ContentBaseTest {
-
- @Test
- public void test_numbers() {
- String text = "[[code param1=\"12\" param2=\"12.5\"]][[/code]].";
- List shortcodes = getShortCodeParser().parseShortcodes(text);
-
- assertEquals(1, shortcodes.size());
-
- var shortcode = shortcodes.get(0);
- assertEquals(12, shortcode.getParameters().get("param1"));
- assertEquals(12.5, shortcode.getParameters().get("param2"));
- }
-
- @Test
- public void test_list() {
- String text = "[[code param1=\"[12, 13, 14]\" param2=\"['12', '13', '14]\"]][[/code]].";
- List shortcodes = getShortCodeParser().parseShortcodes(text);
-
- var shortcode = shortcodes.get(0);
- assertEquals(List.of(12, 13, 14), shortcode.getParameters().get("param1"));
- assertEquals(List.of("12", "13", "14"), shortcode.getParameters().get("param2"));
- }
-}
diff --git a/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java b/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java
index aea453676..f48142f27 100644
--- a/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java
+++ b/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java
@@ -52,15 +52,15 @@ public void init () {
tags.put(
"mark",
- params -> "%s ".formatted(params.get("content"))
+ params -> "%s ".formatted(params.get("_content"))
);
tags.put(
"mark2",
- params -> "%s ".formatted(params.get("class"), params.get("content"))
+ params -> "%s ".formatted(params.get("class"), params.get("_content"))
);
- shortCodes = new ShortCodes(tags, getShortCodeParser());
+ shortCodes = new ShortCodes(tags, getTagParser());
}
@@ -106,18 +106,18 @@ void complexTest () {
@Test
void unknown_tag () {
var result = shortCodes.replace("before [[vimeo id='TEST' /]] after");
- Assertions.assertThat(result).isEqualToIgnoringWhitespace("before after");
+ Assertions.assertThat(result).isEqualToIgnoringWhitespace("before [[vimeo id='TEST' /]] after");
}
@Test
void hello_from () {
- var result = shortCodes.replace("[[hello_from name='Thorsten',from='Bochum' /]]");
+ var result = shortCodes.replace("[[hello_from name=\"Thorsten\" from=\"Bochum\" /]]");
Assertions.assertThat(result).isEqualTo("
Thorsten from Bochum ");
- result = shortCodes.replace("[[hello_from name='Thorsten',from='Bochum' /]]");
+ result = shortCodes.replace("[[hello_from name='Thorsten' from='Bochum' /]]");
Assertions.assertThat(result).isEqualTo("
Thorsten from Bochum ");
- result = shortCodes.replace("[[hello_from name='Thorsten', from='Bochum' /]]");
+ result = shortCodes.replace("[[hello_from name='Thorsten' from='Bochum' /]]");
Assertions.assertThat(result).isEqualTo("
Thorsten from Bochum ");
}
@@ -162,7 +162,7 @@ void long_complex () {
@Test
void multiple_hello () {
var input = """
- [[hello_from name='Thorsten',from='Bochum']][[/hello_from]][[hello_from name='Thorsten',from='Bochum']][[/hello_from]]
+ [[hello_from name='Thorsten' from='Bochum']][[/hello_from]][[hello_from name='Thorsten' from='Bochum']][[/hello_from]]
""";
var expected = """
Thorsten from Bochum
Thorsten from Bochum
@@ -171,7 +171,7 @@ void multiple_hello () {
Assertions.assertThat(result).isEqualTo(expected);
input = """
- [[hello_from name='Thorsten',from='Bochum'/]][[hello_from name='Thorsten',from='Bochum'/]]
+ [[hello_from name='Thorsten' from='Bochum'/]][[hello_from name='Thorsten' from='Bochum'/]]
""";
expected = """
Thorsten from Bochum
Thorsten from Bochum
diff --git a/cms-content/src/test/java/com/condation/cms/content/shortcodes/TagParserTest.java b/cms-content/src/test/java/com/condation/cms/content/shortcodes/TagParserTest.java
new file mode 100644
index 000000000..41142f52b
--- /dev/null
+++ b/cms-content/src/test/java/com/condation/cms/content/shortcodes/TagParserTest.java
@@ -0,0 +1,123 @@
+package com.condation.cms.content.shortcodes;
+
+/*-
+ * #%L
+ * cms-content
+ * %%
+ * Copyright (C) 2023 - 2024 CondationCMS
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program. If not, see
+ * .
+ * #L%
+ */
+
+import org.apache.commons.jexl3.JexlBuilder;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.BeforeEach;
+
+/**
+ *
+ * @author t.marx
+ */
+public class TagParserTest {
+
+ TagParser tagParser;
+
+ TagMap tagMap;
+
+ @BeforeEach
+ void setup() {
+ tagMap = new TagMap();
+ tagMap.put("code", params -> {
+ // Verarbeitung der Parameter hier
+ return "Ausgabe des Shortcodes";
+ });
+ tagMap.put("content", params -> {
+ return (String)params.get("_content");
+ });
+
+ tagMap.put("exp", params -> {
+ return "expression: " + params.get("value");
+ });
+
+ tagMap.put("param", params -> {
+ return "param: " + params.get("param1");
+ });
+
+ this.tagParser = new TagParser(new JexlBuilder().create());
+ }
+
+ @Test
+ public void no_shortcode() {
+ String result = tagParser.parse("Dein Shortcode-Text hier", tagMap);
+ Assertions.assertThat(result).isEqualTo("Dein Shortcode-Text hier");
+ }
+
+ @Test
+ public void self_closing_tag() {
+ String result = tagParser.parse("[[code/]]", tagMap);
+ Assertions.assertThat(result).isEqualTo("Ausgabe des Shortcodes");
+ }
+
+ @Test
+ public void self_closing_tag_with_space() {
+ String result = tagParser.parse("[[code /]]", tagMap);
+ Assertions.assertThat(result).isEqualTo("Ausgabe des Shortcodes");
+ }
+
+ @Test
+ public void end_closing_tag() {
+ String result = tagParser.parse("[[code]][[/code]]", tagMap);
+ Assertions.assertThat(result).isEqualTo("Ausgabe des Shortcodes");
+ }
+
+ @Test
+ public void tag_with_content() {
+ String result = tagParser.parse("[[content]]Hello CondationCMS[[/content]]", tagMap);
+ Assertions.assertThat(result).isEqualTo("Hello CondationCMS");
+ }
+
+ @Test
+ public void expressions() {
+ String result = tagParser.parse("[[exp value=\"${5+4}\"/]]", tagMap);
+ Assertions.assertThat(result).isEqualTo("expression: 9");
+ }
+
+ @Test
+ public void parameters_string() {
+ String result = tagParser.parse("[[param param1=\"5\"/]]", tagMap);
+ Assertions.assertThat(result).isEqualTo("param: 5");
+ }
+
+ @Test
+ public void parameters_number() {
+ String result = tagParser.parse("[[param param1=5 /]]", tagMap);
+ Assertions.assertThat(result).isEqualTo("param: 5");
+ }
+
+ @Test
+ public void parameters_with_content() {
+ String result = tagParser.parse("[[param param1=\"5\"]]Hello[[/param]]", tagMap);
+ Assertions.assertThat(result).isEqualTo("param: 5");
+ }
+
+ @Test
+ public void shortCode_in_text() {
+ String result = tagParser.parse("Hello [[content]]CondationCMS[[/content]]!", tagMap);
+ Assertions.assertThat(result).isEqualTo("Hello CondationCMS!");
+ }
+
+}
diff --git a/cms-content/src/test/java/com/condation/cms/content/template/shortcode/FreeMarkerShortCodeTemplateFunctionTest.java b/cms-content/src/test/java/com/condation/cms/content/template/shortcode/FreeMarkerShortCodeTemplateFunctionTest.java
index 3d5fef036..5a47cf8c6 100644
--- a/cms-content/src/test/java/com/condation/cms/content/template/shortcode/FreeMarkerShortCodeTemplateFunctionTest.java
+++ b/cms-content/src/test/java/com/condation/cms/content/template/shortcode/FreeMarkerShortCodeTemplateFunctionTest.java
@@ -59,7 +59,7 @@ public void setupShortCodes() {
shortCodes = new ShortCodes(Map.of(
"echo", (params) -> "Hello world",
"greet", (params) -> "Hello " + params.get("name")
- ), getShortCodeParser());
+ ), getTagParser());
}
@Test
diff --git a/cms-content/src/test/java/com/condation/cms/content/template/shortcode/PebbleShortCodeTemplateFunctionTest.java b/cms-content/src/test/java/com/condation/cms/content/template/shortcode/PebbleShortCodeTemplateFunctionTest.java
index 108e09e2d..250c856f7 100644
--- a/cms-content/src/test/java/com/condation/cms/content/template/shortcode/PebbleShortCodeTemplateFunctionTest.java
+++ b/cms-content/src/test/java/com/condation/cms/content/template/shortcode/PebbleShortCodeTemplateFunctionTest.java
@@ -59,7 +59,7 @@ public void setupShortCodes() {
shortCodes = new ShortCodes(Map.of(
"echo", (params) -> "Hello world",
"greet", (params) -> "Hello " + params.get("name")
- ), getShortCodeParser());
+ ), getTagParser());
}
@Test
diff --git a/cms-content/src/test/java/com/condation/cms/content/template/shortcode/ThymeleafShortCodeTemplateFunctionTest.java b/cms-content/src/test/java/com/condation/cms/content/template/shortcode/ThymeleafShortCodeTemplateFunctionTest.java
index 1427a0b2b..31f902ae1 100644
--- a/cms-content/src/test/java/com/condation/cms/content/template/shortcode/ThymeleafShortCodeTemplateFunctionTest.java
+++ b/cms-content/src/test/java/com/condation/cms/content/template/shortcode/ThymeleafShortCodeTemplateFunctionTest.java
@@ -60,7 +60,7 @@ public void setupShortCodes() {
shortCodes = new ShortCodes(Map.of(
"echo", (params) -> "Hello world",
"greet", (params) -> "Hello " + params.get("name")
- ), getShortCodeParser());
+ ), getTagParser());
}
@Test
diff --git a/cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/TagParser.java b/cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/TagParser.java
new file mode 100644
index 000000000..65d52c578
--- /dev/null
+++ b/cms-sandbox/tests/src/main/java/com/condation/cms/content/shortcodes/TagParser.java
@@ -0,0 +1,151 @@
+package com.condation.cms.content.shortcodes;
+
+import java.util.*;
+import java.util.function.Function;
+import org.apache.commons.jexl3.JexlEngine;
+import org.apache.commons.jexl3.MapContext;
+
+public class TagParser {
+
+ private final Codes tagHandlers;
+ private final JexlEngine engine;
+
+ public TagParser(Codes tagHandlers, JexlEngine engine) {
+ this.tagHandlers = tagHandlers;
+ this.engine = engine;
+ }
+
+ public String parse(String text) {
+ StringBuilder result = new StringBuilder();
+ int i = 0;
+ while (i < text.length()) {
+ if (text.charAt(i) == '[' && i + 1 < text.length() && text.charAt(i + 1) == '[') {
+ int tagStart = i;
+ i = parseTag(text, i, result);
+ if (i == tagStart) { // Kein gültiger Tag gefunden, füge '[[' hinzu.
+ result.append("[[");
+ i += 2;
+ }
+ } else {
+ result.append(text.charAt(i));
+ i++;
+ }
+ }
+ return result.toString();
+ }
+
+ private int parseTag(String text, int index, StringBuilder result) {
+ int endTagIndex = findTagEnd(text, index);
+ if (endTagIndex == -1) {
+ return index; // Kein schließendes ']]' gefunden
+ }
+
+ String tagContent = text.substring(index + 2, endTagIndex).trim();
+ boolean isSelfClosing = tagContent.endsWith("/");
+
+ if (isSelfClosing) {
+ tagContent = tagContent.substring(0, tagContent.length() - 1).trim();
+ }
+
+ int spaceIndex = tagContent.indexOf(' ');
+ String tagName = spaceIndex == -1 ? tagContent : tagContent.substring(0, spaceIndex);
+ Map attributes = spaceIndex == -1 ? new HashMap<>() : parseAttributes(tagContent.substring(spaceIndex + 1));
+
+ int closingTagIndex = -1;
+ if (!isSelfClosing) {
+ closingTagIndex = text.indexOf("[[/" + tagName + "]]", endTagIndex + 2);
+ if (closingTagIndex != -1) {
+ // Verarbeite den Content für geöffnete und geschlossene Tags
+ String content = text.substring(endTagIndex + 2, closingTagIndex);
+ attributes.put("_content", content);
+ endTagIndex = closingTagIndex + ("[[/" + tagName + "]]").length() - 2;
+ }
+ }
+
+ if (tagHandlers.hasCode(tagName)) {
+ Function, String> handler = tagHandlers.get(tagName);
+ result.append(handler.apply(attributes));
+ // Setze den Index auf das Zeichen direkt nach dem schließenden Tag oder schließenden Tag mit Content
+ return endTagIndex + 2;
+ }
+
+ return index; // Tag nicht erkannt
+ }
+
+ private int findTagEnd(String text, int startIndex) {
+ for (int i = startIndex; i < text.length() - 1; i++) {
+ if (text.charAt(i) == ']' && text.charAt(i + 1) == ']') {
+ return i;
+ }
+ }
+ return -1; // Kein schließendes ']]' gefunden
+ }
+
+ private Map parseAttributes(String attributesString) {
+ Map attributes = new HashMap<>();
+ StringBuilder key = new StringBuilder();
+ StringBuilder value = new StringBuilder();
+ boolean inQuotes = false;
+ boolean readingKey = true;
+
+ for (int i = 0; i < attributesString.length(); i++) {
+ char c = attributesString.charAt(i);
+ if (c == '"' || c == '\'') {
+ inQuotes = !inQuotes;
+ } else if (!inQuotes && (c == '=' || c == ' ')) {
+ if (readingKey) {
+ readingKey = false;
+ } else {
+ attributes.put(key.toString().trim(), parseValue(value.toString().trim()));
+ key.setLength(0);
+ value.setLength(0);
+ readingKey = true;
+ }
+ } else {
+ if (readingKey) {
+ key.append(c);
+ } else {
+ value.append(c);
+ }
+ }
+ }
+
+ // Letztes Attribut verarbeiten
+ if (key.length() > 0 && value.length() > 0) {
+ attributes.put(key.toString().trim(), parseValue(value.toString().trim()));
+ }
+
+ return attributes;
+ }
+
+ private Object parseValue(String value) {
+ if (value.matches("\\d+")) {
+ return Integer.valueOf(value);
+ } else if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
+ return Boolean.valueOf(value);
+ } else if (value.startsWith("${") && value.endsWith("}")) {
+ String expressionString = value.substring(2, value.length() - 1);
+
+ var expression = engine.createExpression(expressionString);
+ return expression.evaluate(new MapContext());
+ }
+ return value;
+ }
+
+ public static class Codes {
+
+ private final Map, String>> codes = new HashMap<>();
+
+ public void add(String codeName, Function, String> function) {
+ codes.put(codeName, function);
+ }
+
+ public boolean hasCode(String codeName) {
+ return codes.containsKey(codeName);
+ }
+
+ public Function, String> get(String codeName) {
+ return codes.getOrDefault(codeName, (params) -> "");
+ }
+ }
+}
diff --git a/cms-sandbox/tests/src/test/java/com/condation/cms/content/shortcodes/TagParserTest.java b/cms-sandbox/tests/src/test/java/com/condation/cms/content/shortcodes/TagParserTest.java
new file mode 100644
index 000000000..ab7830f4c
--- /dev/null
+++ b/cms-sandbox/tests/src/test/java/com/condation/cms/content/shortcodes/TagParserTest.java
@@ -0,0 +1,103 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/UnitTests/JUnit5TestClass.java to edit this template
+ */
+package com.condation.cms.content.shortcodes;
+
+import org.apache.commons.jexl3.JexlBuilder;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.BeforeEach;
+
+/**
+ *
+ * @author t.marx
+ */
+public class TagParserTest {
+
+
+ TagParser tagParser;
+
+ @BeforeEach
+ void setup() {
+ TagParser.Codes codes = new TagParser.Codes();
+ codes.add("code", params -> {
+ // Verarbeitung der Parameter hier
+ return "Ausgabe des Shortcodes";
+ });
+ codes.add("content", params -> {
+ return (String)params.get("_content");
+ });
+
+ codes.add("exp", params -> {
+ return "expression: " + params.get("value");
+ });
+
+ codes.add("param", params -> {
+ return "param: " + params.get("param1");
+ });
+
+ this.tagParser = new TagParser(codes, new JexlBuilder().create());
+ }
+
+ @Test
+ public void no_shortcode() {
+ String result = tagParser.parse("Dein Shortcode-Text hier");
+ Assertions.assertThat(result).isEqualTo("Dein Shortcode-Text hier");
+ }
+
+ @Test
+ public void self_closing_tag() {
+ String result = tagParser.parse("[[code/]]");
+ Assertions.assertThat(result).isEqualTo("Ausgabe des Shortcodes");
+ }
+
+ @Test
+ public void self_closing_tag_with_space() {
+ String result = tagParser.parse("[[code /]]");
+ Assertions.assertThat(result).isEqualTo("Ausgabe des Shortcodes");
+ }
+
+ @Test
+ public void end_closing_tag() {
+ String result = tagParser.parse("[[code]][[/code]]");
+ Assertions.assertThat(result).isEqualTo("Ausgabe des Shortcodes");
+ }
+
+ @Test
+ public void tag_with_content() {
+ String result = tagParser.parse("[[content]]Hello CondationCMS[[/content]]");
+ Assertions.assertThat(result).isEqualTo("Hello CondationCMS");
+ }
+
+ @Test
+ public void expressions() {
+ String result = tagParser.parse("[[exp value=\"${5+4}\"/]]");
+ Assertions.assertThat(result).isEqualTo("expression: 9");
+ }
+
+ @Test
+ public void parameters_string() {
+ String result = tagParser.parse("[[param param1=\"5\"/]]");
+ Assertions.assertThat(result).isEqualTo("param: 5");
+ }
+
+ @Test
+ public void parameters_number() {
+ String result = tagParser.parse("[[param param1=5 /]]");
+ Assertions.assertThat(result).isEqualTo("param: 5");
+ }
+
+ @Test
+ public void parameters_with_content() {
+ String result = tagParser.parse("[[param param1=\"5\"]]Hello[[/param]]");
+ Assertions.assertThat(result).isEqualTo("param: 5");
+ }
+
+ @Test
+ public void shortCode_in_text() {
+ String result = tagParser.parse("Hello [[content]]CondationCMS[[/content]]!");
+ Assertions.assertThat(result).isEqualTo("Hello CondationCMS!");
+ }
+
+}
diff --git a/cms-server/src/main/java/com/condation/cms/request/RequestContextFactory.java b/cms-server/src/main/java/com/condation/cms/request/RequestContextFactory.java
index 05450767c..ff53c5e82 100644
--- a/cms-server/src/main/java/com/condation/cms/request/RequestContextFactory.java
+++ b/cms-server/src/main/java/com/condation/cms/request/RequestContextFactory.java
@@ -53,8 +53,8 @@
import com.condation.cms.api.utils.HTTPUtil;
import com.condation.cms.api.utils.RequestUtil;
import com.condation.cms.content.RenderContext;
-import com.condation.cms.content.shortcodes.ShortCodeParser;
import com.condation.cms.content.shortcodes.ShortCodes;
+import com.condation.cms.content.shortcodes.TagParser;
import com.condation.cms.extensions.ExtensionManager;
import com.condation.cms.extensions.hooks.ContentHooks;
import com.condation.cms.extensions.hooks.DBHooks;
@@ -161,7 +161,7 @@ private ShortCodes initShortCodes(RequestContext requestContext) {
var wrapper = requestContext.get(ContentHooks.class).getShortCodes(codes);
- var parser = injector.getInstance(ShortCodeParser.class);
+ var parser = injector.getInstance(TagParser.class);
return new ShortCodes(wrapper.getShortCodes(), parser);
}
@@ -259,7 +259,7 @@ private ShortCodes createShortCodes(RequestContext requestContext) {
.forEach(extension -> codes.putAll(extension.shortCodes()));
var wrapper = requestContext.get(ContentHooks.class).getShortCodes(codes);
- var parser = injector.getInstance(ShortCodeParser.class);
+ var parser = injector.getInstance(TagParser.class);
return new ShortCodes(wrapper.getShortCodes(), parser);
}
diff --git a/cms-server/src/main/java/com/condation/cms/server/configs/SiteModule.java b/cms-server/src/main/java/com/condation/cms/server/configs/SiteModule.java
index 4d27f2e35..c5e7cc0b6 100644
--- a/cms-server/src/main/java/com/condation/cms/server/configs/SiteModule.java
+++ b/cms-server/src/main/java/com/condation/cms/server/configs/SiteModule.java
@@ -59,7 +59,7 @@
import com.condation.cms.content.DefaultContentRenderer;
import com.condation.cms.content.TaxonomyResolver;
import com.condation.cms.content.ViewResolver;
-import com.condation.cms.content.shortcodes.ShortCodeParser;
+import com.condation.cms.content.shortcodes.TagParser;
import com.condation.cms.extensions.ExtensionManager;
import com.condation.cms.filesystem.FileDB;
import com.condation.cms.filesystem.MetaData;
@@ -113,7 +113,7 @@ public ContentNodeMapper contentNodeMapper (DB db, ContentParser contentParser)
@Provides
@Singleton
- public ShortCodeParser shortCodeParser (Configuration configuration) {
+ public TagParser tagParser (Configuration configuration) {
var engine = new JexlBuilder()
.strict(true)
.cache(512);
@@ -126,7 +126,7 @@ public ShortCodeParser shortCodeParser (Configuration configuration) {
engine.silent(true);
}
- return new ShortCodeParser(engine.create());
+ return new TagParser(engine.create());
}
@Provides
diff --git a/cms-server/src/test/java/com/condation/cms/TestHelper.java b/cms-server/src/test/java/com/condation/cms/TestHelper.java
index 11f39eb21..274ed3af2 100644
--- a/cms-server/src/test/java/com/condation/cms/TestHelper.java
+++ b/cms-server/src/test/java/com/condation/cms/TestHelper.java
@@ -45,6 +45,7 @@
import com.condation.cms.content.RenderContext;
import com.condation.cms.content.shortcodes.ShortCodeParser;
import com.condation.cms.content.shortcodes.ShortCodes;
+import com.condation.cms.content.shortcodes.TagParser;
import com.condation.cms.extensions.hooks.DBHooks;
import com.condation.cms.extensions.hooks.TemplateHooks;
import com.condation.cms.extensions.request.RequestExtensions;
@@ -73,7 +74,7 @@ public static RequestContext requestContext(String uri) {
var markdownRenderer = TestHelper.getRenderer();
RequestContext context = new RequestContext();
- var shortCodeParser = new ShortCodeParser(new JexlBuilder().create());
+ var shortCodeParser = new TagParser(new JexlBuilder().create());
context.add(RequestFeature.class, new RequestFeature(uri, Map.of()));
context.add(RequestExtensions.class, new RequestExtensions(null));
From 85e71458b5ebfc772c4ea853f321b0f1ece10bd3 Mon Sep 17 00:00:00 2001
From: Thorsten Marx
Date: Fri, 11 Oct 2024 08:47:32 +0200
Subject: [PATCH 10/15] fix feature test project
---
.../features/extensions/{theme.extension.js => theme.hooks.js} | 0
cms-server/themes/{test => parent}/extensions/parent.extension.js | 0
cms-server/themes/{parent => test}/extensions/theme.extension.js | 0
3 files changed, 0 insertions(+), 0 deletions(-)
rename cms-server/hosts/features/extensions/{theme.extension.js => theme.hooks.js} (100%)
rename cms-server/themes/{test => parent}/extensions/parent.extension.js (100%)
rename cms-server/themes/{parent => test}/extensions/theme.extension.js (100%)
diff --git a/cms-server/hosts/features/extensions/theme.extension.js b/cms-server/hosts/features/extensions/theme.hooks.js
similarity index 100%
rename from cms-server/hosts/features/extensions/theme.extension.js
rename to cms-server/hosts/features/extensions/theme.hooks.js
diff --git a/cms-server/themes/test/extensions/parent.extension.js b/cms-server/themes/parent/extensions/parent.extension.js
similarity index 100%
rename from cms-server/themes/test/extensions/parent.extension.js
rename to cms-server/themes/parent/extensions/parent.extension.js
diff --git a/cms-server/themes/parent/extensions/theme.extension.js b/cms-server/themes/test/extensions/theme.extension.js
similarity index 100%
rename from cms-server/themes/parent/extensions/theme.extension.js
rename to cms-server/themes/test/extensions/theme.extension.js
From 02ec9df09a7551638185144ed9a41d09a01a93fb Mon Sep 17 00:00:00 2001
From: Thorsten Marx
Date: Fri, 11 Oct 2024 08:51:45 +0200
Subject: [PATCH 11/15] remove unused code example for an expression
---
.../cms/content/DefaultContentRenderer.java | 12 ++----------
.../cms/content/pipeline/ContentPipeline.java | 8 --------
.../hosts/features/content/shortcodes/index.md | 2 +-
3 files changed, 3 insertions(+), 19 deletions(-)
diff --git a/cms-content/src/main/java/com/condation/cms/content/DefaultContentRenderer.java b/cms-content/src/main/java/com/condation/cms/content/DefaultContentRenderer.java
index e40c7a57d..d0e22bf58 100644
--- a/cms-content/src/main/java/com/condation/cms/content/DefaultContentRenderer.java
+++ b/cms-content/src/main/java/com/condation/cms/content/DefaultContentRenderer.java
@@ -120,15 +120,7 @@ public String renderView(final ReadOnlyFile viewFile, final View view, final Con
});
}
- private Object getFeatureValueOrDefault(RequestContext context,
- Class feature, Function valueFunction, Object defaultValue) {
- if (context.has(feature)) {
- return valueFunction.apply(context.get(feature));
- }
- return defaultValue;
- }
-
- private String renderMarkdown(final String rawContent, final RequestContext context, final TemplateEngine.Model model) {
+ private String renderContent(final String rawContent, final RequestContext context, final TemplateEngine.Model model) {
var pipeline = ContentPipelineFactory.create(context, model);
return pipeline.process(rawContent);
@@ -190,7 +182,7 @@ public String render(final ReadOnlyFile contentFile, final RequestContext contex
extendModel(model);
model.values.put("content",
- renderMarkdown(rawContent, context, model)
+ renderContent(rawContent, context, model)
);
return templates.get().render((String) meta.get("template"), model);
diff --git a/cms-content/src/main/java/com/condation/cms/content/pipeline/ContentPipeline.java b/cms-content/src/main/java/com/condation/cms/content/pipeline/ContentPipeline.java
index 852b03346..2d29e7d43 100644
--- a/cms-content/src/main/java/com/condation/cms/content/pipeline/ContentPipeline.java
+++ b/cms-content/src/main/java/com/condation/cms/content/pipeline/ContentPipeline.java
@@ -90,12 +90,4 @@ private String processTemplate(FilterContext context) {
return context.value();
}
}
-
- private Object getFeatureValueOrDefault(RequestContext context,
- Class feature, Function valueFunction, Object defaultValue) {
- if (context.has(feature)) {
- return valueFunction.apply(context.get(feature));
- }
- return defaultValue;
- }
}
diff --git a/cms-server/hosts/features/content/shortcodes/index.md b/cms-server/hosts/features/content/shortcodes/index.md
index 545ac4dac..bb55a5234 100644
--- a/cms-server/hosts/features/content/shortcodes/index.md
+++ b/cms-server/hosts/features/content/shortcodes/index.md
@@ -9,7 +9,7 @@ menu:
[[hello name='Thorsten'/]]
-[[name_age name='Thorsten' age="46" /]]
+[[name_age name='Thorsten' age="${40+6+1}" /]]
Or call a shortcode provided by the default theme
From 4be934d506dd93ee85a91bc51c37f80e4ac10851 Mon Sep 17 00:00:00 2001
From: Thorsten Marx
Date: Fri, 11 Oct 2024 09:43:09 +0200
Subject: [PATCH 12/15] add render model to shortcode processing
---
.../cms/content/pipeline/ContentPipeline.java | 7 +++---
.../cms/content/shortcodes/ShortCodes.java | 7 +++++-
.../cms/content/shortcodes/TagParser.java | 23 +++++++++++--------
.../content/shortcodes/ShortCodesTest.java | 18 ++++++++++++++-
4 files changed, 40 insertions(+), 15 deletions(-)
diff --git a/cms-content/src/main/java/com/condation/cms/content/pipeline/ContentPipeline.java b/cms-content/src/main/java/com/condation/cms/content/pipeline/ContentPipeline.java
index 2d29e7d43..edfa3066f 100644
--- a/cms-content/src/main/java/com/condation/cms/content/pipeline/ContentPipeline.java
+++ b/cms-content/src/main/java/com/condation/cms/content/pipeline/ContentPipeline.java
@@ -44,15 +44,14 @@
* @author thmar
*/
@Slf4j
-@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
+@RequiredArgsConstructor
public class ContentPipeline {
private final HookSystem hookSystem;
private final RequestContext requestContext;
-
private final TemplateEngine.Model model;
- void init() {
+ protected void init() {
List pipeline = requestContext.get(ConfigurationFeature.class)
.configuration().get(SiteConfiguration.class)
@@ -78,7 +77,7 @@ private String processMarkdown(FilterContext context) {
}
private String processShortCodes(FilterContext context) {
- return requestContext.get(RenderContext.class).shortCodes().replace(context.value());
+ return requestContext.get(RenderContext.class).shortCodes().replace(context.value(), model.values);
}
private String processTemplate(FilterContext context) {
diff --git a/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java b/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
index 9d71e70c7..33470aed2 100644
--- a/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
+++ b/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java
@@ -24,6 +24,7 @@
import com.condation.cms.api.model.Parameter;
+import java.util.Collections;
import java.util.Map;
import java.util.function.Function;
import lombok.RequiredArgsConstructor;
@@ -47,7 +48,11 @@ public ShortCodes (Map> codes, TagParser tag
}
public String replace (final String content) {
- return parser.parse(content, tagMap);
+ return replace(content, Collections.emptyMap());
+ }
+
+ public String replace (final String content, Map contextModel) {
+ return parser.parse(content, tagMap, contextModel);
}
public String execute (String name, Map parameters) {
diff --git a/cms-content/src/main/java/com/condation/cms/content/shortcodes/TagParser.java b/cms-content/src/main/java/com/condation/cms/content/shortcodes/TagParser.java
index 82dec3038..3cd099100 100644
--- a/cms-content/src/main/java/com/condation/cms/content/shortcodes/TagParser.java
+++ b/cms-content/src/main/java/com/condation/cms/content/shortcodes/TagParser.java
@@ -23,7 +23,8 @@
*/
import com.condation.cms.api.model.Parameter;
-import java.util.*;
+import java.util.Collections;
+import java.util.Map;
import java.util.function.Function;
import org.apache.commons.jexl3.JexlEngine;
import org.apache.commons.jexl3.MapContext;
@@ -37,12 +38,16 @@ public TagParser(JexlEngine engine) {
}
public String parse(String text, TagMap tagHandlers) {
+ return parse(text, tagHandlers, Collections.emptyMap());
+ }
+
+ public String parse(String text, TagMap tagHandlers, Map contextModel) {
StringBuilder result = new StringBuilder();
int i = 0;
while (i < text.length()) {
if (text.charAt(i) == '[' && i + 1 < text.length() && text.charAt(i + 1) == '[') {
int tagStart = i;
- i = parseTag(text, i, result, tagHandlers);
+ i = parseTag(text, i, result, tagHandlers, contextModel);
if (i == tagStart) { // Kein gültiger Tag gefunden, füge '[[' hinzu.
result.append("[[");
i += 2;
@@ -55,7 +60,7 @@ public String parse(String text, TagMap tagHandlers) {
return result.toString();
}
- private int parseTag(String text, int index, StringBuilder result, TagMap tagHandlers) {
+ private int parseTag(String text, int index, StringBuilder result, TagMap tagHandlers, Map contextModel) {
int endTagIndex = findTagEnd(text, index);
if (endTagIndex == -1) {
return index; // Kein schließendes ']]' gefunden
@@ -72,7 +77,7 @@ private int parseTag(String text, int index, StringBuilder result, TagMap tagHan
String tagName = spaceIndex == -1 ? tagContent : tagContent.substring(0, spaceIndex);
Parameter attributes = spaceIndex == -1
? new Parameter()
- : parseAttributes(tagContent.substring(spaceIndex + 1));
+ : parseAttributes(tagContent.substring(spaceIndex + 1), contextModel);
int closingTagIndex = -1;
if (!isSelfClosing) {
@@ -104,7 +109,7 @@ private int findTagEnd(String text, int startIndex) {
return -1; // Kein schließendes ']]' gefunden
}
- private Parameter parseAttributes(String attributesString) {
+ private Parameter parseAttributes(String attributesString, Map contextModel) {
Parameter attributes = new Parameter();
StringBuilder key = new StringBuilder();
StringBuilder value = new StringBuilder();
@@ -119,7 +124,7 @@ private Parameter parseAttributes(String attributesString) {
if (readingKey) {
readingKey = false;
} else {
- attributes.put(key.toString().trim(), parseValue(value.toString().trim()));
+ attributes.put(key.toString().trim(), parseValue(value.toString().trim(), contextModel));
key.setLength(0);
value.setLength(0);
readingKey = true;
@@ -135,13 +140,13 @@ private Parameter parseAttributes(String attributesString) {
// Letztes Attribut verarbeiten
if (key.length() > 0 && value.length() > 0) {
- attributes.put(key.toString().trim(), parseValue(value.toString().trim()));
+ attributes.put(key.toString().trim(), parseValue(value.toString().trim(), contextModel));
}
return attributes;
}
- private Object parseValue(String value) {
+ private Object parseValue(String value, Map contextModel) {
if (value.matches("\\d+")) {
return Integer.valueOf(value);
} else if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
@@ -150,7 +155,7 @@ private Object parseValue(String value) {
String expressionString = value.substring(2, value.length() - 1);
var expression = engine.createExpression(expressionString);
- return expression.evaluate(new MapContext());
+ return expression.evaluate(new MapContext(contextModel));
}
return value;
}
diff --git a/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java b/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java
index f48142f27..33de04a80 100644
--- a/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java
+++ b/cms-content/src/test/java/com/condation/cms/content/shortcodes/ShortCodesTest.java
@@ -60,6 +60,11 @@ public void init () {
params -> "%s ".formatted(params.get("class"), params.get("_content"))
);
+ tags.put(
+ "exp",
+ params -> "%s ".formatted(params.get("expression"))
+ );
+
shortCodes = new ShortCodes(tags, getTagParser());
}
@@ -181,9 +186,20 @@ void multiple_hello () {
}
@Test
- void test_mismathc() {
+ void test_mismach() {
var result = shortCodes.replace("[[mark1 class='test-class']]Important[[/mark2]]");
Assertions.assertThat(result).isEqualTo("[[mark1 class='test-class']]Important[[/mark2]]");
}
+
+ @Test
+ void test_expression() {
+ var result = shortCodes.replace("[[exp expression='${meta.title}' /]]",
+ Map.of(
+ "meta", Map.of("title", "CondationCMS")
+ )
+ );
+
+ Assertions.assertThat(result).isEqualTo("CondationCMS ");
+ }
}
From 264edcfa37022916393f3e7333508af2bf90e74a Mon Sep 17 00:00:00 2001
From: Thorsten Marx
Date: Fri, 11 Oct 2024 09:50:50 +0200
Subject: [PATCH 13/15] add more tests
---
.../cms/content/shortcodes/TagParserTest.java | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/cms-content/src/test/java/com/condation/cms/content/shortcodes/TagParserTest.java b/cms-content/src/test/java/com/condation/cms/content/shortcodes/TagParserTest.java
index 41142f52b..e1a05afb1 100644
--- a/cms-content/src/test/java/com/condation/cms/content/shortcodes/TagParserTest.java
+++ b/cms-content/src/test/java/com/condation/cms/content/shortcodes/TagParserTest.java
@@ -25,7 +25,6 @@
import org.apache.commons.jexl3.JexlBuilder;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeEach;
/**
@@ -108,6 +107,18 @@ public void parameters_number() {
Assertions.assertThat(result).isEqualTo("param: 5");
}
+ @Test
+ public void parameters_boolean_true() {
+ String result = tagParser.parse("[[param param1=true /]]", tagMap);
+ Assertions.assertThat(result).isEqualTo("param: true");
+ }
+
+ @Test
+ public void parameters_boolean_false() {
+ String result = tagParser.parse("[[param param1=false /]]", tagMap);
+ Assertions.assertThat(result).isEqualTo("param: false");
+ }
+
@Test
public void parameters_with_content() {
String result = tagParser.parse("[[param param1=\"5\"]]Hello[[/param]]", tagMap);
From 98f1c9d8e501c14492328ca566f90af651f02df6 Mon Sep 17 00:00:00 2001
From: Thorsten Marx
Date: Fri, 11 Oct 2024 12:42:22 +0200
Subject: [PATCH 14/15] update markdown renderer to use new TagParser
---
.../condation/cms/auth/AuthShortCodes.java | 3 +-
.../rules/block/ShortCodeBlockRule.java | 110 ++++---
.../inline/ShortCodeInlineBlockRule.java | 95 +++---
.../cms/content/shortcodes/TagParser.java | 282 ++++++++++--------
.../rules/block/ShortCodeBlockRuleTest.java | 47 +--
.../inline/ShortCodeInlineBlockRuleTest.java | 29 +-
.../cms/content/shortcodes/TagParserTest.java | 12 +
.../content/markdown/features.shortcodes.html | 8 +-
.../content/markdown/features.shortcodes.md | 6 +-
.../hosts/features/content/search/index.md | 2 +-
10 files changed, 336 insertions(+), 258 deletions(-)
diff --git a/cms-auth/src/main/java/com/condation/cms/auth/AuthShortCodes.java b/cms-auth/src/main/java/com/condation/cms/auth/AuthShortCodes.java
index 616792e7a..7f14f8e12 100644
--- a/cms-auth/src/main/java/com/condation/cms/auth/AuthShortCodes.java
+++ b/cms-auth/src/main/java/com/condation/cms/auth/AuthShortCodes.java
@@ -41,7 +41,8 @@ public class AuthShortCodes extends RegisterShortCodesExtensionPoint {
@Override
public Map> shortCodes() {
return Map.of(
- "username", this::getUserName
+ "username", this::getUserName,
+ "cms:username", this::getUserName
);
}
diff --git a/cms-content/src/main/java/com/condation/cms/content/markdown/rules/block/ShortCodeBlockRule.java b/cms-content/src/main/java/com/condation/cms/content/markdown/rules/block/ShortCodeBlockRule.java
index 2f1502632..eaab38343 100644
--- a/cms-content/src/main/java/com/condation/cms/content/markdown/rules/block/ShortCodeBlockRule.java
+++ b/cms-content/src/main/java/com/condation/cms/content/markdown/rules/block/ShortCodeBlockRule.java
@@ -21,14 +21,12 @@
* .
* #L%
*/
-
-
import com.condation.cms.content.markdown.Block;
import com.condation.cms.content.markdown.BlockElementRule;
import com.condation.cms.content.markdown.InlineRenderer;
-import com.condation.cms.content.shortcodes.ShortCodeParser;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import com.condation.cms.content.shortcodes.TagMap;
+import com.condation.cms.content.shortcodes.TagParser;
+import java.util.List;
/**
*
@@ -36,55 +34,77 @@
*/
public class ShortCodeBlockRule implements BlockElementRule {
- public static final Pattern TAG_PARAMS_PATTERN_SHORT = Pattern.compile("^(\\[{2})(?[a-z_A-Z0-9]+)( (?.*?))?\\p{Blank}*/\\]{2}",
- Pattern.MULTILINE | Pattern.DOTALL | Pattern.UNIX_LINES);
- public static final Pattern TAG_PARAMS_PATTERN_LONG = Pattern.compile("^(\\[{2})(?[a-z_A-Z0-9]+)( (?.*?))?\\]{2}(?.*)\\[{2}/\\k\\]{2}",
- Pattern.MULTILINE | Pattern.DOTALL | Pattern.UNIX_LINES);
-
- public static final Pattern SHORTCODE_PATTERN = Pattern.compile("^" + ShortCodeParser.SHORTCODE_REGEX,
- Pattern.DOTALL | Pattern.MULTILINE);
-
+ private static final TagParser tagParser = new TagParser(null);
+
@Override
public Block next(final String md) {
- /*
- Matcher matcher = TAG_PARAMS_PATTERN_SHORT.matcher(md);
- if (matcher.find()) {
- return new ShortCodeBlock(matcher.start(), matcher.end(),
- matcher.group("tag"), matcher.group("params"), ""
- );
- }
- matcher = TAG_PARAMS_PATTERN_LONG.matcher(md);
- if (matcher.find()) {
- return new ShortCodeBlock(matcher.start(), matcher.end(),
- matcher.group("tag"), matcher.group("params"), matcher.group("content")
- );
- }
- */
- Matcher matcher = SHORTCODE_PATTERN.matcher(md);
- if (matcher.matches()) {
- String name = matcher.group(1) != null ? matcher.group(1) : matcher.group(4);
- String params = matcher.group(2) != null ? matcher.group(2).trim() : matcher.group(5).trim();
- String content = matcher.group(3) != null ? matcher.group(3).trim() : "";
- ShortCodeParser.Match match = new ShortCodeParser.Match(name, matcher.start(), matcher.end());
- match.setContent(content);
- match.getParameters().put("content", content);
-
- return new ShortCodeBlock(matcher.start(), matcher.end(), name, params, content);
+ List tags = tagParser.findTags(md, new TagMap() {
+ @Override
+ public boolean has(String codeName) {
+ return true;
+ }
+ }).stream()
+ .filter(tag -> isStandaloneInLine(md, tag))
+ .toList();
+ if (tags.isEmpty()) {
+ return null;
}
-
- return null;
+ var tag = tags.getFirst();
+ return new ShortCodeBlock(
+ tag.startIndex(),
+ tag.endIndex(),
+ tag);
+
}
-
- public static record ShortCodeBlock (int start, int end, String tag, String params, String content) implements Block {
+ public static record ShortCodeBlock(int start, int end, TagParser.TagInfo tagInfo) implements Block {
@Override
public String render(InlineRenderer inlineRenderer) {
- return "[[%s %s]]%s[[/%s]]".formatted(tag, params, content, tag);
+ List params = tagInfo.rawAttributes()
+ .entrySet().stream()
+ .filter(entry -> !entry.getKey().equals("_content"))
+ .sorted((entry1, entry2) -> entry1.getKey().compareTo(entry2.getKey()))
+ .map(entry -> {
+ return "%s=%s".formatted(entry.getKey(), parseValue((String) entry.getValue()));
+ }).toList();
+ return "[[%s %s]]%s[[/%s]]"
+ .formatted(
+ tagInfo.name(),
+ String.join(" ", params),
+ tagInfo.rawAttributes().getOrDefault("_content", ""),
+ tagInfo.name()
+ );
+ }
+ }
+
+ private static Object parseValue(String value) {
+ if (value.matches("\\d+")) {
+ return value;
+ } else if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
+ return value;
+ }
+ return "\"" + value + "\"";
+ }
+
+ public boolean isStandaloneInLine(String text, TagParser.TagInfo tag) {
+ var startIndex = tag.startIndex();
+ var endIndex = tag.endIndex();
+ // Prüfe, ob die Indizes gültig sind
+ if (startIndex < 0 || endIndex > text.length() || startIndex >= endIndex) {
+ throw new IllegalArgumentException("Ungültige Indizes");
}
-
-
+
+ // Finde die Position des Textausschnitts
+ String before = text.substring(0, startIndex);
+ String after = text.substring(endIndex);
+
+ // Prüfe, ob vor und nach dem Ausschnitt ein Zeilenumbruch oder nichts steht
+ boolean beforeIsLineBreak = before.isEmpty() || before.endsWith("\n") || before.endsWith("\r\n");
+ boolean afterIsLineBreak = after.isEmpty() || after.startsWith("\n") || after.startsWith("\r\n");
+
+ return beforeIsLineBreak && afterIsLineBreak;
}
-
+
}
diff --git a/cms-content/src/main/java/com/condation/cms/content/markdown/rules/inline/ShortCodeInlineBlockRule.java b/cms-content/src/main/java/com/condation/cms/content/markdown/rules/inline/ShortCodeInlineBlockRule.java
index e09f20a96..62080ce1f 100644
--- a/cms-content/src/main/java/com/condation/cms/content/markdown/rules/inline/ShortCodeInlineBlockRule.java
+++ b/cms-content/src/main/java/com/condation/cms/content/markdown/rules/inline/ShortCodeInlineBlockRule.java
@@ -21,14 +21,11 @@
* .
* #L%
*/
-
-
import com.condation.cms.content.markdown.InlineBlock;
import com.condation.cms.content.markdown.InlineElementRule;
-import com.condation.cms.content.shortcodes.ShortCodeParser;
-import static com.condation.cms.content.shortcodes.ShortCodeParser.PARAM_PATTERN;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import com.condation.cms.content.shortcodes.TagMap;
+import com.condation.cms.content.shortcodes.TagParser;
+import java.util.List;
/**
*
@@ -36,65 +33,55 @@
*/
public class ShortCodeInlineBlockRule implements InlineElementRule {
- public static final Pattern TAG_PARAMS_PATTERN_SHORT = Pattern.compile("(\\[{2})(?[a-z_A-Z0-9]+)( (?.*?))?\\p{Blank}*/\\]{2}",
- Pattern.MULTILINE | Pattern.DOTALL | Pattern.UNIX_LINES);
- public static final Pattern TAG_PARAMS_PATTERN_LONG = Pattern.compile("^(\\[{2})(?[a-z_A-Z0-9]+)( (?.*?))?\\]{2}(?.*)\\[{2}/\\k\\]{2}",
- Pattern.MULTILINE | Pattern.DOTALL | Pattern.UNIX_LINES);
+ private static final TagParser tagParser = new TagParser(null);
@Override
public InlineBlock next(final String md) {
- /*
- Matcher matcher = TAG_PARAMS_PATTERN_SHORT.matcher(md);
- if (matcher.find()) {
- return new ShortCodeInlineBlock(matcher.start(), matcher.end(),
- matcher.group("tag"), matcher.group("params"), ""
- );
- }
- matcher = TAG_PARAMS_PATTERN_LONG.matcher(md);
- if (matcher.find()) {
- return new ShortCodeInlineBlock(matcher.start(), matcher.end(),
- matcher.group("tag"), matcher.group("params"), matcher.group("content")
- );
- }
- */
-
- Matcher matcher = ShortCodeParser.SHORTCODE_PATTERN.matcher(md);
- if (matcher.find()) {
- String name = matcher.group(1) != null ? matcher.group(1) : matcher.group(4);
- String params = matcher.group(2) != null ? matcher.group(2).trim() : matcher.group(5).trim();
- String content = matcher.group(3) != null ? matcher.group(3).trim() : "";
-
- ShortCodeParser.Match match = new ShortCodeParser.Match(name, matcher.start(), matcher.end());
- match.setContent(content);
- match.getParameters().put("content", content);
-
- /*
- Matcher paramMatcher = PARAM_PATTERN.matcher(params);
- while (paramMatcher.find()) {
- String key = paramMatcher.group(1);
- String value = paramMatcher.group(2);
- // Remove the surrounding quotes
- value = value.substring(1, value.length() - 1);
- match.getParameters().put(key, value);
+ List tags = tagParser.findTags(md, new TagMap() {
+ @Override
+ public boolean has(String codeName) {
+ return true;
}
- */
- return new ShortCodeInlineBlock(matcher.start(), matcher.end(), name, params, content);
+ }).stream().toList();
+ if (tags.isEmpty()) {
+ return null;
}
-
- return null;
+ var tag = tags.getFirst();
+ return new ShortCodeInlineBlock(
+ tag.startIndex(),
+ tag.endIndex(),
+ tag);
}
-
- public static record ShortCodeInlineBlock (int start, int end, String tag, String params, String content) implements InlineBlock {
+ public static record ShortCodeInlineBlock(int start, int end, TagParser.TagInfo tagInfo) implements InlineBlock {
@Override
public String render() {
- return "[[%s %s]]%s[[/%s]]".formatted(tag, params, content, tag);
+ List params = tagInfo.rawAttributes()
+ .entrySet().stream()
+ .filter(entry -> !entry.getKey().equals("_content"))
+ .sorted((entry1, entry2) -> entry1.getKey().compareTo(entry2.getKey()))
+ .map(entry -> {
+ return "%s=%s".formatted(entry.getKey(), parseValue((String) entry.getValue()));
+ }).toList();
+ return "[[%s %s]]%s[[/%s]]"
+ .formatted(
+ tagInfo.name(),
+ String.join(" ", params),
+ tagInfo.rawAttributes().getOrDefault("_content", ""),
+ tagInfo.name()
+ );
}
-
-
-
+
+ }
+
+ private static Object parseValue(String value) {
+ if (value.matches("\\d+")) {
+ return value;
+ } else if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
+ return value;
+ }
+ return "\"" + value + "\"";
}
-
}
diff --git a/cms-content/src/main/java/com/condation/cms/content/shortcodes/TagParser.java b/cms-content/src/main/java/com/condation/cms/content/shortcodes/TagParser.java
index 3cd099100..af357e1e6 100644
--- a/cms-content/src/main/java/com/condation/cms/content/shortcodes/TagParser.java
+++ b/cms-content/src/main/java/com/condation/cms/content/shortcodes/TagParser.java
@@ -23,140 +23,170 @@
*/
import com.condation.cms.api.model.Parameter;
-import java.util.Collections;
-import java.util.Map;
-import java.util.function.Function;
import org.apache.commons.jexl3.JexlEngine;
import org.apache.commons.jexl3.MapContext;
+import java.util.*;
+import java.util.function.Function;
+
public class TagParser {
- private final JexlEngine engine;
-
- public TagParser(JexlEngine engine) {
- this.engine = engine;
- }
+ private final JexlEngine engine;
+
+ public TagParser(JexlEngine engine) {
+ this.engine = engine;
+ }
+
+ // Klasse zur Speicherung der Tag-Informationen
+ public static record TagInfo (String name, Parameter rawAttributes, int startIndex, int endIndex) {}
+
+ // Erster Schritt: Alle Tags ermitteln und deren Positionen sowie Roh-Attribute speichern
+ public List findTags(String text, TagMap tagHandlers) {
+ List tags = new ArrayList<>();
+ int i = 0;
+
+ while (i < text.length()) {
+ if (text.charAt(i) == '[' && i + 1 < text.length() && text.charAt(i + 1) == '[') {
+ int tagStart = i;
+ int endTagIndex = findTagEnd(text, i);
+ if (endTagIndex != -1) {
+ String tagContent = text.substring(i + 2, endTagIndex).trim();
+ boolean isSelfClosing = tagContent.endsWith("/");
+
+ if (isSelfClosing) {
+ tagContent = tagContent.substring(0, tagContent.length() - 1).trim();
+ }
+
+ int spaceIndex = tagContent.indexOf(' ');
+ String tagName = spaceIndex == -1 ? tagContent : tagContent.substring(0, spaceIndex);
+ Parameter rawAttributes = spaceIndex == -1
+ ? new Parameter()
+ : parseRawAttributes(tagContent.substring(spaceIndex + 1));
+
+ int closingTagIndex = -1;
+ if (!isSelfClosing) {
+ closingTagIndex = text.indexOf("[[/" + tagName + "]]", endTagIndex + 2);
+ if (closingTagIndex != -1) {
+ String content = text.substring(endTagIndex + 2, closingTagIndex);
+ rawAttributes.put("_content", content);
+ endTagIndex = closingTagIndex + ("[[/" + tagName + "]]").length() - 2;
+ }
+ }
+
+ if (tagHandlers.has(tagName)) {
+ tags.add(new TagInfo(tagName, rawAttributes, tagStart, endTagIndex + 2));
+ i = endTagIndex + 2; // Zum nächsten Tag springen
+ } else {
+ i++;
+ }
+ } else {
+ i++;
+ }
+ } else {
+ i++;
+ }
+ }
+ return tags;
+ }
public String parse(String text, TagMap tagHandlers) {
return parse(text, tagHandlers, Collections.emptyMap());
}
- public String parse(String text, TagMap tagHandlers, Map contextModel) {
- StringBuilder result = new StringBuilder();
- int i = 0;
- while (i < text.length()) {
- if (text.charAt(i) == '[' && i + 1 < text.length() && text.charAt(i + 1) == '[') {
- int tagStart = i;
- i = parseTag(text, i, result, tagHandlers, contextModel);
- if (i == tagStart) { // Kein gültiger Tag gefunden, füge '[[' hinzu.
- result.append("[[");
- i += 2;
- }
- } else {
- result.append(text.charAt(i));
- i++;
- }
- }
- return result.toString();
- }
-
- private int parseTag(String text, int index, StringBuilder result, TagMap tagHandlers, Map contextModel) {
- int endTagIndex = findTagEnd(text, index);
- if (endTagIndex == -1) {
- return index; // Kein schließendes ']]' gefunden
- }
-
- String tagContent = text.substring(index + 2, endTagIndex).trim();
- boolean isSelfClosing = tagContent.endsWith("/");
-
- if (isSelfClosing) {
- tagContent = tagContent.substring(0, tagContent.length() - 1).trim();
- }
-
- int spaceIndex = tagContent.indexOf(' ');
- String tagName = spaceIndex == -1 ? tagContent : tagContent.substring(0, spaceIndex);
- Parameter attributes = spaceIndex == -1
- ? new Parameter()
- : parseAttributes(tagContent.substring(spaceIndex + 1), contextModel);
-
- int closingTagIndex = -1;
- if (!isSelfClosing) {
- closingTagIndex = text.indexOf("[[/" + tagName + "]]", endTagIndex + 2);
- if (closingTagIndex != -1) {
- // Verarbeite den Content für geöffnete und geschlossene Tags
- String content = text.substring(endTagIndex + 2, closingTagIndex);
- attributes.put("_content", content);
- endTagIndex = closingTagIndex + ("[[/" + tagName + "]]").length() - 2;
- }
- }
-
- if (tagHandlers.has(tagName)) {
- Function handler = tagHandlers.get(tagName);
- result.append(handler.apply(attributes));
- // Setze den Index auf das Zeichen direkt nach dem schließenden Tag oder schließenden Tag mit Content
- return endTagIndex + 2;
- }
-
- return index; // Tag nicht erkannt
- }
-
- private int findTagEnd(String text, int startIndex) {
- for (int i = startIndex; i < text.length() - 1; i++) {
- if (text.charAt(i) == ']' && text.charAt(i + 1) == ']') {
- return i;
- }
- }
- return -1; // Kein schließendes ']]' gefunden
- }
-
- private Parameter parseAttributes(String attributesString, Map contextModel) {
- Parameter attributes = new Parameter();
- StringBuilder key = new StringBuilder();
- StringBuilder value = new StringBuilder();
- boolean inQuotes = false;
- boolean readingKey = true;
-
- for (int i = 0; i < attributesString.length(); i++) {
- char c = attributesString.charAt(i);
- if (c == '"' || c == '\'') {
- inQuotes = !inQuotes;
- } else if (!inQuotes && (c == '=' || c == ' ')) {
- if (readingKey) {
- readingKey = false;
- } else {
- attributes.put(key.toString().trim(), parseValue(value.toString().trim(), contextModel));
- key.setLength(0);
- value.setLength(0);
- readingKey = true;
- }
- } else {
- if (readingKey) {
- key.append(c);
- } else {
- value.append(c);
- }
- }
- }
-
- // Letztes Attribut verarbeiten
- if (key.length() > 0 && value.length() > 0) {
- attributes.put(key.toString().trim(), parseValue(value.toString().trim(), contextModel));
- }
-
- return attributes;
- }
-
- private Object parseValue(String value, Map contextModel) {
- if (value.matches("\\d+")) {
- return Integer.valueOf(value);
- } else if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
- return Boolean.valueOf(value);
- } else if (value.startsWith("${") && value.endsWith("}")) {
- String expressionString = value.substring(2, value.length() - 1);
-
- var expression = engine.createExpression(expressionString);
- return expression.evaluate(new MapContext(contextModel));
- }
- return value;
- }
+ // Zweiter Schritt: Tags basierend auf den gespeicherten Positionen ersetzen
+ public String parse(String text, TagMap tagHandlers, Map contextModel) {
+ // Erster Schritt: Finde alle Tags
+ List tags = findTags(text, tagHandlers);
+
+ // Zweiter Schritt: Ersetze alle Tags im Text
+ StringBuilder result = new StringBuilder();
+ int lastIndex = 0;
+ for (TagInfo tag : tags) {
+ result.append(text, lastIndex, tag.startIndex); // Unveränderten Teil des Textes hinzufügen
+ Function handler = tagHandlers.get(tag.name);
+
+ // Im zweiten Schritt: Attribute auswerten
+ Parameter evaluatedAttributes = evaluateAttributes(tag.rawAttributes, contextModel);
+
+ result.append(handler.apply(evaluatedAttributes)); // Tag-Ersetzung
+ lastIndex = tag.endIndex; // Aktualisiere den Startpunkt für den nächsten Tag
+ }
+ result.append(text.substring(lastIndex)); // Füge den restlichen Text hinzu
+
+ return result.toString();
+ }
+
+ // Methode zum Finden des Endes eines Tags
+ private int findTagEnd(String text, int startIndex) {
+ for (int i = startIndex; i < text.length() - 1; i++) {
+ if (text.charAt(i) == ']' && text.charAt(i + 1) == ']') {
+ return i;
+ }
+ }
+ return -1; // Kein schließendes ']]' gefunden
+ }
+
+ // Methode zur Attribut-Analyse im ersten Schritt (Rohwerte als Strings speichern)
+ private Parameter parseRawAttributes(String attributesString) {
+ Parameter attributes = new Parameter();
+ StringBuilder key = new StringBuilder();
+ StringBuilder value = new StringBuilder();
+ boolean inQuotes = false;
+ boolean readingKey = true;
+
+ for (int i = 0; i < attributesString.length(); i++) {
+ char c = attributesString.charAt(i);
+ if (c == '"' || c == '\'') {
+ inQuotes = !inQuotes;
+ } else if (!inQuotes && (c == '=' || c == ' ')) {
+ if (readingKey) {
+ readingKey = false;
+ } else {
+ attributes.put(key.toString().trim(), value.toString().trim()); // Rohwert speichern
+ key.setLength(0);
+ value.setLength(0);
+ readingKey = true;
+ }
+ } else {
+ if (readingKey) {
+ key.append(c);
+ } else {
+ value.append(c);
+ }
+ }
+ }
+
+ // Letztes Attribut verarbeiten
+ if (key.length() > 0 && value.length() > 0) {
+ attributes.put(key.toString().trim(), value.toString().trim()); // Rohwert speichern
+ }
+
+ return attributes;
+ }
+
+ // Zweiter Schritt: Attribute auswerten
+ private Parameter evaluateAttributes(Parameter rawAttributes, Map contextModel) {
+ Parameter evaluatedAttributes = new Parameter();
+ for (Map.Entry entry : rawAttributes.entrySet()) {
+ String key = entry.getKey();
+ String rawValue = (String) entry.getValue(); // Rohwert als String
+ evaluatedAttributes.put(key, parseValue(rawValue, contextModel)); // Wert erst jetzt parsen
+ }
+ return evaluatedAttributes;
+ }
+
+ // Methode zur Auswertung von Attributwerten im zweiten Schritt
+ private Object parseValue(String value, Map contextModel) {
+ if (value.matches("\\d+")) {
+ return Integer.valueOf(value);
+ } else if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
+ return Boolean.valueOf(value);
+ } else if (value.startsWith("${") && value.endsWith("}")) {
+ String expressionString = value.substring(2, value.length() - 1);
+
+ var expression = engine.createExpression(expressionString);
+ return expression.evaluate(new MapContext(contextModel));
+ }
+ return value;
+ }
}
diff --git a/cms-content/src/test/java/com/condation/cms/content/markdown/rules/block/ShortCodeBlockRuleTest.java b/cms-content/src/test/java/com/condation/cms/content/markdown/rules/block/ShortCodeBlockRuleTest.java
index 09058224c..facd66f74 100644
--- a/cms-content/src/test/java/com/condation/cms/content/markdown/rules/block/ShortCodeBlockRuleTest.java
+++ b/cms-content/src/test/java/com/condation/cms/content/markdown/rules/block/ShortCodeBlockRuleTest.java
@@ -24,6 +24,7 @@
import com.condation.cms.content.markdown.Block;
+import java.util.Map;
import org.assertj.core.api.Assertions;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
@@ -45,13 +46,16 @@ void long_form() {
Assertions.assertThat(next)
.isNotNull()
- .isInstanceOf(ShortCodeBlockRule.ShortCodeBlock.class)
- .asInstanceOf(InstanceOfAssertFactories.type(ShortCodeBlockRule.ShortCodeBlock.class))
- .hasFieldOrPropertyWithValue("tag", "link")
- .hasFieldOrPropertyWithValue("params", "url=\"https://google.de/\"")
- .hasFieldOrPropertyWithValue("content", "Google")
- ;
-
+ .isInstanceOf(ShortCodeBlockRule.ShortCodeBlock.class);
+
+ var tag = (ShortCodeBlockRule.ShortCodeBlock)next;
+ Assertions.assertThat(tag.tagInfo())
+ .hasFieldOrPropertyWithValue("name", "link")
+ .hasFieldOrPropertyWithValue("rawAttributes", Map.of(
+ "url", "https://google.de/",
+ "_content", "Google"
+ ));
+
Assertions.assertThat(next.render((content) -> content)).isEqualTo("[[link url=\"https://google.de/\"]]Google[[/link]]");
}
@@ -64,12 +68,15 @@ void short_form() {
Assertions.assertThat(next)
.isNotNull()
- .isInstanceOf(ShortCodeBlockRule.ShortCodeBlock.class)
- .asInstanceOf(InstanceOfAssertFactories.type(ShortCodeBlockRule.ShortCodeBlock.class))
- .hasFieldOrPropertyWithValue("tag", "link")
- .hasFieldOrPropertyWithValue("params", "url=\"https://google.de/\"")
- ;
-
+ .isInstanceOf(ShortCodeBlockRule.ShortCodeBlock.class);
+
+ var tag = (ShortCodeBlockRule.ShortCodeBlock)next;
+ Assertions.assertThat(tag.tagInfo())
+ .hasFieldOrPropertyWithValue("name", "link")
+ .hasFieldOrPropertyWithValue("rawAttributes", Map.of(
+ "url", "https://google.de/"
+ ));
+
Assertions.assertThat(next.render((content) -> content)).isEqualTo("[[link url=\"https://google.de/\"]][[/link]]");
}
@@ -82,13 +89,19 @@ void test_issue () {
Assertions.assertThat(next)
.isNotNull()
.isInstanceOf(ShortCodeBlockRule.ShortCodeBlock.class)
- .asInstanceOf(InstanceOfAssertFactories.type(ShortCodeBlockRule.ShortCodeBlock.class))
- .hasFieldOrPropertyWithValue("tag", "video")
- .hasFieldOrPropertyWithValue("params", "type=\"youtube\" id=\"y0sF5xhGreA\" title=\"Everybody loves little cats\"")
;
+ var tag = (ShortCodeBlockRule.ShortCodeBlock)next;
+ Assertions.assertThat(tag.tagInfo())
+ .hasFieldOrPropertyWithValue("name", "video")
+ .hasFieldOrPropertyWithValue("rawAttributes", Map.of(
+ "type", "youtube",
+ "id", "y0sF5xhGreA",
+ "title", "Everybody loves little cats"
+ ));
+
Assertions.assertThat(next.render((content) -> content))
- .isEqualTo("[[video type=\"youtube\" id=\"y0sF5xhGreA\" title=\"Everybody loves little cats\"]][[/video]]");
+ .isEqualTo("[[video id=\"y0sF5xhGreA\" title=\"Everybody loves little cats\" type=\"youtube\"]][[/video]]");
}
}
diff --git a/cms-content/src/test/java/com/condation/cms/content/markdown/rules/inline/ShortCodeInlineBlockRuleTest.java b/cms-content/src/test/java/com/condation/cms/content/markdown/rules/inline/ShortCodeInlineBlockRuleTest.java
index 942046ac8..24bc99b31 100644
--- a/cms-content/src/test/java/com/condation/cms/content/markdown/rules/inline/ShortCodeInlineBlockRuleTest.java
+++ b/cms-content/src/test/java/com/condation/cms/content/markdown/rules/inline/ShortCodeInlineBlockRuleTest.java
@@ -25,6 +25,7 @@
import com.condation.cms.content.markdown.InlineBlock;
+import java.util.Map;
import org.assertj.core.api.Assertions;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
@@ -46,12 +47,15 @@ void long_form() {
Assertions.assertThat(next)
.isNotNull()
- .isInstanceOf(ShortCodeInlineBlockRule.ShortCodeInlineBlock.class)
- .asInstanceOf(InstanceOfAssertFactories.type(ShortCodeInlineBlockRule.ShortCodeInlineBlock.class))
- .hasFieldOrPropertyWithValue("tag", "link")
- .hasFieldOrPropertyWithValue("params", "url=\"https://google.de/\"")
- .hasFieldOrPropertyWithValue("content", "Google")
- ;
+ .isInstanceOf(ShortCodeInlineBlockRule.ShortCodeInlineBlock.class);
+
+ var tag = (ShortCodeInlineBlockRule.ShortCodeInlineBlock)next;
+ Assertions.assertThat(tag.tagInfo())
+ .hasFieldOrPropertyWithValue("name", "link")
+ .hasFieldOrPropertyWithValue("rawAttributes", Map.of(
+ "url", "https://google.de/",
+ "_content", "Google"
+ ));
Assertions.assertThat(next.render()).isEqualTo("[[link url=\"https://google.de/\"]]Google[[/link]]");
}
@@ -65,12 +69,15 @@ void short_form() {
Assertions.assertThat(next)
.isNotNull()
- .isInstanceOf(ShortCodeInlineBlockRule.ShortCodeInlineBlock.class)
- .asInstanceOf(InstanceOfAssertFactories.type(ShortCodeInlineBlockRule.ShortCodeInlineBlock.class))
- .hasFieldOrPropertyWithValue("tag", "link")
- .hasFieldOrPropertyWithValue("params", "url=\"https://google.de/\"")
- ;
+ .isInstanceOf(ShortCodeInlineBlockRule.ShortCodeInlineBlock.class);
+ var tag = (ShortCodeInlineBlockRule.ShortCodeInlineBlock)next;
+ Assertions.assertThat(tag.tagInfo())
+ .hasFieldOrPropertyWithValue("name", "link")
+ .hasFieldOrPropertyWithValue("rawAttributes", Map.of(
+ "url", "https://google.de/"
+ ));
+
Assertions.assertThat(next.render()).isEqualTo("[[link url=\"https://google.de/\"]][[/link]]");
}
diff --git a/cms-content/src/test/java/com/condation/cms/content/shortcodes/TagParserTest.java b/cms-content/src/test/java/com/condation/cms/content/shortcodes/TagParserTest.java
index e1a05afb1..4ebb118c1 100644
--- a/cms-content/src/test/java/com/condation/cms/content/shortcodes/TagParserTest.java
+++ b/cms-content/src/test/java/com/condation/cms/content/shortcodes/TagParserTest.java
@@ -56,6 +56,10 @@ void setup() {
return "param: " + params.get("param1");
});
+ tagMap.put("ns1:print", params -> {
+ return "message: " + params.get("message");
+ });
+
this.tagParser = new TagParser(new JexlBuilder().create());
}
@@ -131,4 +135,12 @@ public void shortCode_in_text() {
Assertions.assertThat(result).isEqualTo("Hello CondationCMS!");
}
+ @Test
+ public void namespace() {
+ String result = tagParser.parse("[[ns1:print message='Hello CondationCMS']][[/ns1:print]]", tagMap);
+ Assertions.assertThat(result).isEqualTo("message: Hello CondationCMS");
+
+ result = tagParser.parse("[[ns1:print message='Hello CondationCMS' /]]", tagMap);
+ Assertions.assertThat(result).isEqualTo("message: Hello CondationCMS");
+ }
}
diff --git a/cms-content/src/test/resources/com/condation/cms/content/markdown/features.shortcodes.html b/cms-content/src/test/resources/com/condation/cms/content/markdown/features.shortcodes.html
index 275a6b8e4..e780cd780 100644
--- a/cms-content/src/test/resources/com/condation/cms/content/markdown/features.shortcodes.html
+++ b/cms-content/src/test/resources/com/condation/cms/content/markdown/features.shortcodes.html
@@ -22,7 +22,11 @@
task list test
a paragraph with [[link id="google" title="Google"]][[/link]]
-
next
-
[[link id="apache" title="Apache"]][[/link]]
+
+ [[link id="apache" title="Apache"]][[/link]]
+
+
with namespace
+
+ [[ns:link id="apache" title="Apache"]][[/ns:link]]
diff --git a/cms-content/src/test/resources/com/condation/cms/content/markdown/features.shortcodes.md b/cms-content/src/test/resources/com/condation/cms/content/markdown/features.shortcodes.md
index abc97612b..345653e15 100644
--- a/cms-content/src/test/resources/com/condation/cms/content/markdown/features.shortcodes.md
+++ b/cms-content/src/test/resources/com/condation/cms/content/markdown/features.shortcodes.md
@@ -4,4 +4,8 @@ a paragraph with [[link id="google" title="Google" /]]
# next
-[[link id="apache" title="Apache" /]]
\ No newline at end of file
+[[link id="apache" title="Apache" /]]
+
+# with namespace
+
+[[ns:link id="apache" title="Apache" /]]
\ No newline at end of file
diff --git a/cms-server/hosts/features/content/search/index.md b/cms-server/hosts/features/content/search/index.md
index dde8342a2..d57562de0 100644
--- a/cms-server/hosts/features/content/search/index.md
+++ b/cms-server/hosts/features/content/search/index.md
@@ -8,4 +8,4 @@ menu:
## Search
-Hello [[username /]]
\ No newline at end of file
+Hello [[cms:username /]]
\ No newline at end of file
From 2bddb2f68177cf096c8327185318c5d032ecd894 Mon Sep 17 00:00:00 2001
From: Thorsten Marx
Date: Fri, 11 Oct 2024 13:10:03 +0200
Subject: [PATCH 15/15] fix cachehandler
---
.../configuration/ConfigurationManagement.java | 1 -
.../cms/server/handler/cache/CacheHandler.java | 16 ++++++++--------
2 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/cms-api/src/main/java/com/condation/cms/api/configuration/ConfigurationManagement.java b/cms-api/src/main/java/com/condation/cms/api/configuration/ConfigurationManagement.java
index 898424d29..edab3e92a 100644
--- a/cms-api/src/main/java/com/condation/cms/api/configuration/ConfigurationManagement.java
+++ b/cms-api/src/main/java/com/condation/cms/api/configuration/ConfigurationManagement.java
@@ -114,7 +114,6 @@ private List getConfigurations () {
public void update(CronJobContext jobContext) {
- System.out.println("update");
log.trace("check for modified configurations {}", db.getFileSystem().resolve(".").toString());
getConfigurations().forEach(config -> {
try {
diff --git a/cms-server/src/main/java/com/condation/cms/server/handler/cache/CacheHandler.java b/cms-server/src/main/java/com/condation/cms/server/handler/cache/CacheHandler.java
index 4950124e1..caeaf5dd6 100644
--- a/cms-server/src/main/java/com/condation/cms/server/handler/cache/CacheHandler.java
+++ b/cms-server/src/main/java/com/condation/cms/server/handler/cache/CacheHandler.java
@@ -96,7 +96,7 @@ public boolean handle(Request request, Response response, Callback callback) thr
return true;
}
- final MyResponse cacheResponse = new MyResponse(request, response);
+ final CacheResponseWrapper cacheResponse = new CacheResponseWrapper(request, response);
return super.handle(request, cacheResponse, new Callback.Nested(callback) {
@Override
public void succeeded() {
@@ -138,13 +138,13 @@ private record CachedResponse(String body, Map headers) implemen
}
- private class MyResponse extends Response.Wrapper {
+ private class CacheResponseWrapper extends Response.Wrapper {
final ByteArrayOutputStream bout = new ByteArrayOutputStream();
- final HttpFields.Mutable httpFields = HttpFields.build();
+// final HttpFields.Mutable httpFields = HttpFields.build();
- public MyResponse(Request request, Response wrapped) {
+ public CacheResponseWrapper(Request request, Response wrapped) {
super(request, wrapped);
}
@@ -152,10 +152,10 @@ public String getContent() {
return bout.toString(StandardCharsets.UTF_8);
}
- @Override
- public HttpFields.Mutable getHeaders() {
- return httpFields;
- }
+// @Override
+// public HttpFields.Mutable getHeaders() {
+// return httpFields;
+// }
@Override
public void write(boolean last, ByteBuffer byteBuffer, Callback callback) {