diff --git a/.idea/misc.xml b/.idea/misc.xml index 0ccb376..690120f 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -47,6 +47,7 @@ + diff --git a/README.md b/README.md index 1f96f6c..35a8bc0 100644 --- a/README.md +++ b/README.md @@ -21,17 +21,17 @@ This project provides a collection of useful template renderers. ## Encoding Renderers -| Renderer | Description | -|:--------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------| -| [rife.render.EncodeBase64](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeBase64) | Encodes a template value to Base64 | -| [rife.render.EncodeHtml](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeHtml) | Encodes a template value to HTML | -| [rife.render.EncodeHtmlEntities](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeHtmlEntities) | Encodes a template value to HTML decimal entities | -| [rife.render.EncodeJs](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeJs) | Encodes a template value to JavaScript/ECMAScript | -| [rife.render.EncodeJson](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeJson) | Encodes a template value to JSON | -| [rife.render.EncodeUnicode](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeUnicode) | Encodes a template value to Unicode escape codes | -| [rife.render.EncodeUrl](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeUrl) | URL-encodes a template value | -| [rife.render.EncodeXml](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeXml) | Encodes a template value to XML | - +| Renderer | Description | +|:--------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------| +| [rife.render.EncodeBase64](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeBase64) | Encodes a template value to Base64 | +| [rife.render.EncodeHtml](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeHtml) | Encodes a template value to HTML | +| [rife.render.EncodeHtmlEntities](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeHtmlEntities) | Encodes a template value to HTML decimal entities | +| [rife.render.EncodeJs](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeJs) | Encodes a template value to JavaScript/ECMAScript | +| [rife.render.EncodeJson](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeJson) | Encodes a template value to JSON | +| [rife.render.EncodeUnicode](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeUnicode) | Encodes a template value to Unicode escape codes | +| [rife.render.EncodeUrl](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeUrl) | URL-encodes a template value | +| [rife.render.EncodeXml](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.EncodeXml) | Encodes a template value to XML | +| [rife.render.Normalize](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Normalize) | Normalizes a template value for inclusion in a URL path. | ## Format Renderers | Renderer | Description | diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index f897576..976c72a 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -13,7 +13,7 @@ plugins { id("com.github.ben-manes.versions") version "0.46.0" } -val rifeVersion by rootProject.extra { "1.5.0-SNAPSHOT" } +val rifeVersion by rootProject.extra { "1.5.0" } group = "com.uwyn.rife2" version = "0.9.0-SNAPSHOT" diff --git a/lib/src/main/java/rife/render/Normalize.java b/lib/src/main/java/rife/render/Normalize.java new file mode 100644 index 0000000..2f1097d --- /dev/null +++ b/lib/src/main/java/rife/render/Normalize.java @@ -0,0 +1,45 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package rife.render; + +import rife.template.Template; +import rife.template.ValueRenderer; + +/** + *

Normalizes a template value for inclusion in URL path.

+ * + *

Usage:

+ * + *
+ *   <!--v render:rife.render.Normalize:valueId/-->
+ *   {{v render:rife.render.Normalize:valueId/}}
+ * 
+ * + * @author Erik C. Thauvin + * @see rife.render.Normalize + * @since 1.0 + */ +public class Normalize implements ValueRenderer { + /** + * {@inheritDoc} + */ + @Override + public String render(Template template, String valueId, String differentiator) { + return RenderUtils.normalize(template.getValueOrAttribute(differentiator)); + } +} diff --git a/lib/src/main/java/rife/render/RenderUtils.java b/lib/src/main/java/rife/render/RenderUtils.java index 6692c3d..3883f05 100644 --- a/lib/src/main/java/rife/render/RenderUtils.java +++ b/lib/src/main/java/rife/render/RenderUtils.java @@ -24,6 +24,7 @@ import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; +import java.text.Normalizer; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.temporal.ChronoField; @@ -121,6 +122,34 @@ public final class RenderUtils { return ""; } + /** + * Normalizes a String for inclusion in a URL path. + * + * @param src The source String + * @return The normalized String + */ + public static String normalize(String src) { + var sb = new StringBuilder(src.length()); + var normalized = Normalizer.normalize(src.trim(), Normalizer.Form.NFD); + boolean space = false; + for (var c : normalized.toCharArray()) { + if (c <= '\u007F') { // ascii only + if (!space && c == ' ') { + space = true; + sb.append('-'); + } else { + space = false; + if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z')) { + sb.append(c); + } else if (c >= 'A' && c <= 'Z') { + sb.append((char) (c + 32)); // lowercase + } + } + } + } + return sb.toString(); + } + /** * Returns the plural form of a word, if count > 1. * diff --git a/lib/src/test/java/rife/render/TestEncode.java b/lib/src/test/java/rife/render/TestEncode.java index 0ccf03e..fe54771 100644 --- a/lib/src/test/java/rife/render/TestEncode.java +++ b/lib/src/test/java/rife/render/TestEncode.java @@ -93,4 +93,13 @@ class TestEncode { t.setAttribute(TestCase.FOO, "a test &"); assertThat(t.getContent()).isEqualTo("\n a test &\n"); } + + @Test + void testNormalize() { + var t = TemplateFactory.HTML.get("normalize"); + var foo = "News for January 6, 2023 (Paris)"; + t.setValue(TestCase.FOO, foo); + assertThat(t.getContent()).isEqualTo("" + + foo + ""); + } } \ No newline at end of file diff --git a/lib/src/test/resources/templates/normalize.html b/lib/src/test/resources/templates/normalize.html new file mode 100644 index 0000000..3f40a91 --- /dev/null +++ b/lib/src/test/resources/templates/normalize.html @@ -0,0 +1 @@ + \ No newline at end of file