Skip to content

Commit 82d2ba6

Browse files
committed
feat: initial implementation
1 parent 656a59c commit 82d2ba6

File tree

21 files changed

+677
-95
lines changed

21 files changed

+677
-95
lines changed

README.md

Lines changed: 15 additions & 12 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
```
@@ -69,7 +72,7 @@ Then, follow these steps for creating a contribution:
6972

7073
This add-on is distributed under Apache License 2.0. For license terms, see LICENSE.txt.
7174

72-
TEMPLATE_ADDON is written by Flowing Code S.A.
75+
Regular Expression Field Add-On is written by Flowing Code S.A.
7376

7477
# Developer Guide
7578

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: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*-
2+
* #%L
3+
* Regular Expression Field Add-on
4+
* %%
5+
* Copyright (C) 2025 Flowing Code
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* #L%
19+
*/
20+
package com.flowingcode.vaadin.addons.regex;
21+
22+
import static com.flowingcode.vaadin.addons.regex.RegularExpressionOperator.ADVANCED;
23+
import static com.flowingcode.vaadin.addons.regex.RegularExpressionOperator.CONTAINS;
24+
import static com.flowingcode.vaadin.addons.regex.RegularExpressionOperator.ENDS_WITH;
25+
import static com.flowingcode.vaadin.addons.regex.RegularExpressionOperator.STARTS_WITH;
26+
import java.util.regex.Pattern;
27+
import java.util.regex.PatternSyntaxException;
28+
import lombok.AccessLevel;
29+
import lombok.AllArgsConstructor;
30+
import lombok.EqualsAndHashCode;
31+
import lombok.Getter;
32+
import lombok.NonNull;
33+
import lombok.Setter;
34+
35+
@Getter
36+
@Setter
37+
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
38+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
39+
/**
40+
*
41+
* @author Javier Godoy
42+
*/
43+
public final class RegularExpression {
44+
45+
private static final String ANY = ".*";
46+
47+
@EqualsAndHashCode.Include
48+
private final RegularExpressionOperator operator;
49+
50+
@EqualsAndHashCode.Include
51+
private final String input;
52+
53+
private final Pattern pattern;
54+
55+
public RegularExpression(@NonNull RegularExpressionOperator operator, @NonNull String input)
56+
throws PatternSyntaxException {
57+
this.operator = operator;
58+
this.input = input;
59+
60+
String regex = switch (operator) {
61+
case ADVANCED -> input;
62+
case CONTAINS -> ANY + quote(input) + ANY;
63+
case ENDS_WITH -> ANY + quote(input);
64+
case STARTS_WITH -> quote(input) + ANY;
65+
};
66+
67+
pattern = Pattern.compile(regex);
68+
}
69+
70+
private final static String CHARS = ".?+*\\[({$^|\\\\";
71+
72+
private final static Pattern SIMPLE_PATTERN =
73+
Pattern.compile("(?:[^CHARS]|\\\\[CHARS])+".replace("CHARS", CHARS));
74+
75+
private final static Pattern ESCAPE_PATTERN =
76+
Pattern.compile("[CHARS]".replace("CHARS", CHARS));
77+
78+
private final static Pattern UNQUOTE_PATTERN =
79+
Pattern.compile("\\\\([CHARS])".replace("CHARS", CHARS));
80+
81+
private static String quote(String input) {
82+
String s1 = ESCAPE_PATTERN.matcher(input).replaceAll("\\\\$0");
83+
String s2 = "\\Q" + input.replace("\\E", "\\E\\\\E\\Q") + "\\E";
84+
return (s1.length() < s2.length()) ? s1 : s2;
85+
}
86+
87+
public static RegularExpression of(Pattern pattern) {
88+
89+
String regex = pattern.pattern();
90+
boolean notStartsWith = false;
91+
boolean notEndsWith = false;
92+
if (regex.startsWith(ANY)) {
93+
notStartsWith = true;
94+
regex = regex.substring(2);
95+
}
96+
97+
if (regex.endsWith(ANY)) {
98+
notEndsWith = true;
99+
regex = regex.substring(0, regex.length() - 2);
100+
}
101+
102+
String input = null;
103+
if (notStartsWith || notEndsWith) {
104+
if (SIMPLE_PATTERN.matcher(regex).matches()) {
105+
input = UNQUOTE_PATTERN.matcher(regex).replaceAll("$1");
106+
} else if (regex.startsWith("\\Q") && regex.endsWith("\\E")) {
107+
input = regex.substring(2, regex.length() - 2).replace("\\E\\\\E\\Q", "\\E");
108+
}
109+
}
110+
111+
if (input != null) {
112+
if (notStartsWith && notEndsWith) {
113+
return new RegularExpression(CONTAINS, input);
114+
} else if (notStartsWith) {
115+
return new RegularExpression(ENDS_WITH, input);
116+
} else if (notEndsWith) {
117+
return new RegularExpression(STARTS_WITH, input);
118+
}
119+
}
120+
121+
return new RegularExpression(ADVANCED, pattern.pattern(), pattern);
122+
}
123+
124+
@Override
125+
public String toString() {
126+
return operator + " " + input;
127+
}
128+
129+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*-
2+
* #%L
3+
* Regular Expression Field Add-on
4+
* %%
5+
* Copyright (C) 2025 Flowing Code
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* #L%
19+
*/
20+
package com.flowingcode.vaadin.addons.regex;
21+
22+
import com.vaadin.flow.component.customfield.CustomField;
23+
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
24+
import com.vaadin.flow.component.select.Select;
25+
import com.vaadin.flow.component.textfield.TextField;
26+
import java.util.Collection;
27+
import java.util.regex.PatternSyntaxException;
28+
29+
@SuppressWarnings("serial")
30+
/**
31+
*
32+
* @author Javier Godoy
33+
*/
34+
public class RegularExpressionField extends CustomField<RegularExpression> {
35+
36+
private final Select<RegularExpressionOperator> operatorField;
37+
38+
private final TextField inputField;
39+
40+
private final RegularExpressionTestField testField;
41+
42+
private boolean hasPatternSyntaxError;
43+
44+
private boolean testFieldEnabled;
45+
46+
public RegularExpressionField() {
47+
operatorField = new Select<>();
48+
operatorField.setItems(RegularExpressionOperator.values());
49+
inputField = new TextField();
50+
51+
testField = new RegularExpressionTestField();
52+
testField.setVisible(false);
53+
add(new HorizontalLayout(operatorField, inputField), testField);
54+
55+
operatorField.addValueChangeListener(ev -> setTestFieldEnabled(testFieldEnabled));
56+
addValueChangeListener(ev -> testField.setPattern(getValue()));
57+
}
58+
59+
@Override
60+
protected RegularExpression generateModelValue() {
61+
if (hasPatternSyntaxError) {
62+
onPatternSyntaxException(null, 0);
63+
hasPatternSyntaxError = false;
64+
}
65+
if (!inputField.isEmpty() && !operatorField.isEmpty()) {
66+
try {
67+
var r = new RegularExpression(operatorField.getValue(), inputField.getValue());
68+
return r;
69+
} catch (PatternSyntaxException e) {
70+
onPatternSyntaxException(e.getDescription(), e.getIndex());
71+
hasPatternSyntaxError = true;
72+
return null;
73+
}
74+
} else {
75+
return null;
76+
}
77+
}
78+
79+
private void onPatternSyntaxException(String description, int index) {
80+
String errorMessage = description;
81+
if (description != null && index >= 0) {
82+
errorMessage += " near index " + index;
83+
}
84+
setErrorMessage(errorMessage);
85+
inputField.setInvalid(errorMessage != null);
86+
setInvalid(errorMessage != null);
87+
}
88+
89+
@Override
90+
protected void setPresentationValue(RegularExpression newPresentationValue) {
91+
inputField.setValue(newPresentationValue.getInput());
92+
operatorField.setValue(newPresentationValue.getOperator());
93+
}
94+
95+
@Override
96+
public boolean isInvalid() {
97+
return super.isInvalid() || inputField.isInvalid();
98+
}
99+
100+
public void setTestFieldEnabled(boolean enabled) {
101+
testFieldEnabled = enabled;
102+
testField.setVisible(
103+
testFieldEnabled && operatorField.getValue() == RegularExpressionOperator.ADVANCED);
104+
}
105+
106+
public boolean isTestFieldEnabled() {
107+
return testFieldEnabled;
108+
}
109+
110+
public void setOperator(RegularExpressionOperator operator) {
111+
operatorField.setValue(operator);
112+
}
113+
114+
public void setTestStrings(String... strings) {
115+
testField.setItems(strings);
116+
}
117+
118+
public void setTestStrings(Collection<String> strings) {
119+
testField.setItems(strings);
120+
}
121+
122+
}

0 commit comments

Comments
 (0)