Skip to content

Commit 58ae78d

Browse files
committed
WIP: feat: initial implementation
1 parent 656a59c commit 58ae78d

File tree

21 files changed

+548
-90
lines changed

21 files changed

+548
-90
lines changed

README.md

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
1-
[![Published on Vaadin Directory](https://img.shields.io/badge/Vaadin%20Directory-published-00b4f0.svg)](https://vaadin.com/directory/component/template-add-on)
2-
[![Stars on vaadin.com/directory](https://img.shields.io/vaadin-directory/star/template-add-on.svg)](https://vaadin.com/directory/component/template-add-on)
3-
[![Build Status](https://jenkins.flowingcode.com/job/template-addon/badge/icon)](https://jenkins.flowingcode.com/job/template-addon)
4-
[![Maven Central](https://img.shields.io/maven-central/v/com.flowingcode.vaadin.addons/template-addon)](https://mvnrepository.com/artifact/com.flowingcode.vaadin.addons/template-addon)
5-
[![Javadoc](https://img.shields.io/badge/javadoc-00b4f0)](https://javadoc.flowingcode.com/artifact/com.flowingcode.vaadin.addons/template-addon)
1+
[![Published on Vaadin Directory](https://img.shields.io/badge/Vaadin%20Directory-published-00b4f0.svg)](https://vaadin.com/directory/component/regular-expression-field-add-on)
2+
[![Stars on vaadin.com/directory](https://img.shields.io/vaadin-directory/star/regular-expression-field-add-on.svg)](https://vaadin.com/directory/component/regular-expression-field-add-on)
3+
[![Build Status](https://jenkins.flowingcode.com/job/regular-expression-field-addon/badge/icon)](https://jenkins.flowingcode.com/job/regular-expression-field-addon)
4+
[![Maven Central](https://img.shields.io/maven-central/v/com.flowingcode.vaadin.addons/regular-expression-field-addon)](https://mvnrepository.com/artifact/com.flowingcode.vaadin.addons/regular-expression-field-addon)
5+
[![Javadoc](https://img.shields.io/badge/javadoc-00b4f0)](https://javadoc.flowingcode.com/artifact/com.flowingcode.vaadin.addons/regular-expression-field-addon)
66

7-
# Template Add-on
7+
# Regular Expression Field Add-on
88

9-
This is a template project for building new Vaadin 24 add-ons
9+
A field for Vaadin 24 that assists in creating regular expressions.
1010

1111
## Features
1212

13-
* List the features of your add-on in here
13+
* A ComboBox option for creating simple regular expressions, such as "contains."
14+
* Additional options for patterns like "starts with" and "ends with."
15+
* An advanced mode that assists in creating complex regular expressions with automatic validation.
16+
1417

1518
## Online demo
1619

17-
[Online demo here](http://addonsv24.flowingcode.com/template)
20+
[Online demo here](http://addonsv24.flowingcode.com/regular-expression-field)
1821

1922
## Download release
2023

21-
[Available in Vaadin Directory](https://vaadin.com/directory/component/template-add-on)
24+
[Available in Vaadin Directory](https://vaadin.com/directory/component/regular-expression-field-add-on)
2225

2326
### Maven install
2427

@@ -27,7 +30,7 @@ Add the following dependencies in your pom.xml file:
2730
```xml
2831
<dependency>
2932
<groupId>com.flowingcode.vaadin.addons</groupId>
30-
<artifactId>template-addon</artifactId>
33+
<artifactId>regular-expression-field-addon</artifactId>
3134
<version>X.Y.Z</version>
3235
</dependency>
3336
```
@@ -67,9 +70,18 @@ Then, follow these steps for creating a contribution:
6770

6871
## License & Author
6972

70-
This add-on is distributed under Apache License 2.0. For license terms, see LICENSE.txt.
73+
<!-- This add-on is distributed under Apache License 2.0. For license terms, see LICENSE.txt. -->
74+
75+
<!-- Regular Expression Field Add-On is written by Flowing Code S.A. -->
76+
77+
This repository contains Personal Intellectual Property that remains the sole property of the Author.
78+
79+
Ownership of this Intellectual Property is intended to be transferred to Flowing Code S.A. on March 29, 2025,
80+
contingent upon the Author's uninterrupted employment with the company until that date.
7181

72-
TEMPLATE_ADDON is written by Flowing Code S.A.
82+
The Author expressly reserves the right, at their sole discretion, to amend or revoke this intended transfer at any time.
83+
Until such transfer is effected, all rights, including but not limited to the rights of use, modification, and transfer,
84+
remain exclusively with the Author.
7385

7486
# Developer Guide
7587

pom.xml

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
<modelVersion>4.0.0</modelVersion>
66

77
<groupId>com.flowingcode.vaadin.addons</groupId>
8-
<artifactId>template-addon</artifactId>
8+
<artifactId>regular-expression-field-addon</artifactId>
99
<version>1.0.0-SNAPSHOT</version>
10-
<name>Template Add-on</name>
11-
<description>Template Add-on for Vaadin Flow</description>
10+
<name>Regular Expression Field Add-on</name>
11+
<description>Regular Expression Field Add-on for Vaadin Flow</description>
1212
<url>https://www.flowingcode.com/en/open-source/</url>
1313

1414
<properties>
15-
<vaadin.version>24.4.6</vaadin.version>
15+
<vaadin.version>24.7.0</vaadin.version>
1616
<selenium.version>4.10.0</selenium.version>
1717
<maven.compiler.source>17</maven.compiler.source>
1818
<maven.compiler.target>17</maven.compiler.target>
@@ -21,7 +21,6 @@
2121
<drivers.dir>${project.basedir}/drivers</drivers.dir>
2222
<jetty.version>11.0.20</jetty.version>
2323
<flowingcode.commons.demo.version>4.2.0</flowingcode.commons.demo.version>
24-
<frontend.hotdeploy>true</frontend.hotdeploy>
2524
</properties>
2625

2726
<organization>
@@ -122,6 +121,12 @@
122121
<artifactId>vaadin-core</artifactId>
123122
<optional>true</optional>
124123
</dependency>
124+
<dependency>
125+
<groupId>org.projectlombok</groupId>
126+
<artifactId>lombok</artifactId>
127+
<version>1.18.36</version>
128+
<scope>provided</scope>
129+
</dependency>
125130
<dependency>
126131
<groupId>com.flowingcode.vaadin.addons.demo</groupId>
127132
<artifactId>commons-demo</artifactId>
@@ -264,15 +269,12 @@
264269
<scan>3</scan>
265270
<!-- Use test scope because the UI/demo classes are in the test package. -->
266271
<useTestScope>true</useTestScope>
267-
<webApp>
268-
<resourceBases>
269-
<resourceBase>src/test/resources/META-INF/resources</resourceBase>
270-
<resourceBase>src/main/resources/META-INF/resources</resourceBase>
271-
</resourceBases>
272-
</webApp>
273272
<supportedPackagings>
274273
<supportedPackaging>jar</supportedPackaging>
275274
</supportedPackagings>
275+
<systemProperties>
276+
<vaadin.frontend.hotdeploy>true</vaadin.frontend.hotdeploy>
277+
</systemProperties>
276278
</configuration>
277279
</plugin>
278280
</plugins>
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package com.flowingcode.vaadin.addons.regex;
2+
3+
import static com.flowingcode.vaadin.addons.regex.RegularExpressionOperator.ADVANCED;
4+
import static com.flowingcode.vaadin.addons.regex.RegularExpressionOperator.CONTAINS;
5+
import static com.flowingcode.vaadin.addons.regex.RegularExpressionOperator.ENDS_WITH;
6+
import static com.flowingcode.vaadin.addons.regex.RegularExpressionOperator.STARTS_WITH;
7+
import java.util.regex.Pattern;
8+
import java.util.regex.PatternSyntaxException;
9+
import lombok.AccessLevel;
10+
import lombok.AllArgsConstructor;
11+
import lombok.EqualsAndHashCode;
12+
import lombok.Getter;
13+
import lombok.NonNull;
14+
import lombok.Setter;
15+
16+
@Getter
17+
@Setter
18+
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
19+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
20+
/**
21+
*
22+
* @author Javier Godoy
23+
*/
24+
public final class RegularExpression {
25+
26+
private static final String ANY = ".*";
27+
28+
@EqualsAndHashCode.Include
29+
private final RegularExpressionOperator operator;
30+
31+
@EqualsAndHashCode.Include
32+
private final String input;
33+
34+
private final Pattern pattern;
35+
36+
public RegularExpression(@NonNull RegularExpressionOperator operator, @NonNull String input)
37+
throws PatternSyntaxException {
38+
this.operator = operator;
39+
this.input = input;
40+
41+
String regex = switch (operator) {
42+
case ADVANCED -> input;
43+
case CONTAINS -> ANY + quote(input) + ANY;
44+
case ENDS_WITH -> ANY + quote(input);
45+
case STARTS_WITH -> quote(input) + ANY;
46+
};
47+
48+
pattern = Pattern.compile(regex);
49+
}
50+
51+
private final static String CHARS = ".?+*\\[({$^|\\\\";
52+
53+
private final static Pattern SIMPLE_PATTERN =
54+
Pattern.compile("(?:[^CHARS]|\\\\[CHARS])+".replace("CHARS", CHARS));
55+
56+
private final static Pattern ESCAPE_PATTERN =
57+
Pattern.compile("[CHARS]".replace("CHARS", CHARS));
58+
59+
private final static Pattern UNQUOTE_PATTERN =
60+
Pattern.compile("\\\\([CHARS])".replace("CHARS", CHARS));
61+
62+
private static String quote(String input) {
63+
String s1 = ESCAPE_PATTERN.matcher(input).replaceAll("\\\\$0");
64+
String s2 = "\\Q" + input.replace("\\E", "\\E\\\\E\\Q") + "\\E";
65+
return (s1.length() < s2.length()) ? s1 : s2;
66+
}
67+
68+
public static RegularExpression of(Pattern pattern) {
69+
70+
String regex = pattern.pattern();
71+
boolean notStartsWith = false;
72+
boolean notEndsWith = false;
73+
if (regex.startsWith(ANY)) {
74+
notStartsWith = true;
75+
regex = regex.substring(2);
76+
}
77+
78+
if (regex.endsWith(ANY)) {
79+
notEndsWith = true;
80+
regex = regex.substring(0, regex.length() - 2);
81+
}
82+
83+
String input = null;
84+
if (notStartsWith || notEndsWith) {
85+
if (SIMPLE_PATTERN.matcher(regex).matches()) {
86+
input = UNQUOTE_PATTERN.matcher(regex).replaceAll("$1");
87+
} else if (regex.startsWith("\\Q") && regex.endsWith("\\E")) {
88+
input = regex.substring(2, regex.length() - 2).replace("\\E\\\\E\\Q", "\\E");
89+
}
90+
}
91+
92+
if (input != null) {
93+
if (notStartsWith && notEndsWith) {
94+
return new RegularExpression(CONTAINS, input);
95+
} else if (notStartsWith) {
96+
return new RegularExpression(ENDS_WITH, input);
97+
} else if (notEndsWith) {
98+
return new RegularExpression(STARTS_WITH, input);
99+
}
100+
}
101+
102+
return new RegularExpression(ADVANCED, pattern.pattern(), pattern);
103+
}
104+
105+
@Override
106+
public String toString() {
107+
return operator + " " + input;
108+
}
109+
110+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package com.flowingcode.vaadin.addons.regex;
2+
3+
import com.vaadin.flow.component.customfield.CustomField;
4+
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
5+
import com.vaadin.flow.component.select.Select;
6+
import com.vaadin.flow.component.textfield.TextField;
7+
import java.util.Collection;
8+
import java.util.regex.PatternSyntaxException;
9+
10+
@SuppressWarnings("serial")
11+
/**
12+
*
13+
* @author Javier Godoy
14+
*/
15+
public class RegularExpressionField extends CustomField<RegularExpression> {
16+
17+
private final Select<RegularExpressionOperator> operatorField;
18+
19+
private final TextField inputField;
20+
21+
private final RegularExpressionTestField testField;
22+
23+
private boolean hasPatternSyntaxError;
24+
25+
private boolean testFieldEnabled;
26+
27+
public RegularExpressionField() {
28+
operatorField = new Select<>();
29+
operatorField.setItems(RegularExpressionOperator.values());
30+
inputField = new TextField();
31+
32+
testField = new RegularExpressionTestField();
33+
testField.setVisible(false);
34+
add(new HorizontalLayout(operatorField, inputField), testField);
35+
36+
operatorField.addValueChangeListener(ev -> setTestFieldEnabled(testFieldEnabled));
37+
addValueChangeListener(ev -> testField.setPattern(getValue()));
38+
}
39+
40+
@Override
41+
protected RegularExpression generateModelValue() {
42+
if (hasPatternSyntaxError) {
43+
onPatternSyntaxException(null, 0);
44+
hasPatternSyntaxError = false;
45+
}
46+
if (!inputField.isEmpty() && !operatorField.isEmpty()) {
47+
try {
48+
var r = new RegularExpression(operatorField.getValue(), inputField.getValue());
49+
return r;
50+
} catch (PatternSyntaxException e) {
51+
onPatternSyntaxException(e.getDescription(), e.getIndex());
52+
hasPatternSyntaxError = true;
53+
return null;
54+
}
55+
} else {
56+
return null;
57+
}
58+
}
59+
60+
private void onPatternSyntaxException(String description, int index) {
61+
String errorMessage = description;
62+
if (description != null && index >= 0) {
63+
errorMessage += " near index " + index;
64+
}
65+
setErrorMessage(errorMessage);
66+
inputField.setInvalid(errorMessage != null);
67+
setInvalid(errorMessage != null);
68+
}
69+
70+
@Override
71+
protected void setPresentationValue(RegularExpression newPresentationValue) {
72+
inputField.setValue(newPresentationValue.getInput());
73+
operatorField.setValue(newPresentationValue.getOperator());
74+
}
75+
76+
@Override
77+
public boolean isInvalid() {
78+
return super.isInvalid() || inputField.isInvalid();
79+
}
80+
81+
public void setTestFieldEnabled(boolean enabled) {
82+
testFieldEnabled = enabled;
83+
testField.setVisible(
84+
testFieldEnabled && operatorField.getValue() == RegularExpressionOperator.ADVANCED);
85+
}
86+
87+
public boolean isTestFieldEnabled() {
88+
return testFieldEnabled;
89+
}
90+
91+
public void setOperator(RegularExpressionOperator operator) {
92+
operatorField.setValue(operator);
93+
}
94+
95+
public void setTestStrings(String... strings) {
96+
testField.setItems(strings);
97+
}
98+
99+
public void setTestStrings(Collection<String> strings) {
100+
testField.setItems(strings);
101+
}
102+
103+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.flowingcode.vaadin.addons.regex;
2+
3+
/**
4+
*
5+
* @author Javier Godoy
6+
*/
7+
public enum RegularExpressionOperator {
8+
9+
STARTS_WITH, ENDS_WITH, CONTAINS, ADVANCED;
10+
11+
}

0 commit comments

Comments
 (0)