Skip to content

Commit a6f6d2f

Browse files
committed
fix #1099 MatchHighlighter does not work for characters from all locales
1 parent 0500f77 commit a6f6d2f

File tree

4 files changed

+199
-5
lines changed

4 files changed

+199
-5
lines changed

domino-ui/pom.xml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,47 @@
1313
<packaging>gwt-lib</packaging>
1414

1515
<name>domino-ui</name>
16+
17+
<dependencyManagement>
18+
<dependencies>
19+
<dependency>
20+
<groupId>org.ow2.asm</groupId>
21+
<artifactId>asm-commons</artifactId>
22+
<version>9.6</version>
23+
<scope>test</scope>
24+
</dependency>
25+
<dependency>
26+
<groupId>org.ow2.asm</groupId>
27+
<artifactId>asm</artifactId>
28+
<version>9.6</version>
29+
<scope>test</scope>
30+
</dependency>
31+
<dependency>
32+
<groupId>commons-io</groupId>
33+
<artifactId>commons-io</artifactId>
34+
<version>2.10.0</version>
35+
<scope>test</scope>
36+
</dependency>
37+
<dependency>
38+
<groupId>org.apache.commons</groupId>
39+
<artifactId>commons-lang3</artifactId>
40+
<version>3.12.0</version>
41+
<scope>test</scope>
42+
</dependency>
43+
<dependency>
44+
<groupId>com.google.jsinterop</groupId>
45+
<artifactId>jsinterop-annotations</artifactId>
46+
<version>2.0.2</version>
47+
</dependency>
48+
<dependency>
49+
<groupId>com.google.code.findbugs</groupId>
50+
<artifactId>jsr305</artifactId>
51+
<version>3.0.2</version>
52+
<scope>test</scope>
53+
</dependency>
54+
</dependencies>
55+
</dependencyManagement>
56+
1657
<dependencies>
1758
<dependency>
1859
<groupId>org.dominokit</groupId>
@@ -64,6 +105,18 @@
64105
<groupId>com.google.elemental2</groupId>
65106
<artifactId>elemental2-webstorage</artifactId>
66107
</dependency>
108+
<dependency>
109+
<groupId>org.gwtproject</groupId>
110+
<artifactId>gwt-dev</artifactId>
111+
<version>${gwt.version}</version>
112+
<scope>test</scope>
113+
</dependency>
114+
<dependency>
115+
<groupId>org.gwtproject</groupId>
116+
<artifactId>gwt-user</artifactId>
117+
<version>${gwt.version}</version>
118+
<scope>test</scope>
119+
</dependency>
67120
<dependency>
68121
<groupId>junit</groupId>
69122
<artifactId>junit</artifactId>

domino-ui/src/main/java/org/dominokit/domino/ui/utils/MatchHighlighter.java

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818

1919
import static java.util.Objects.isNull;
2020

21+
import elemental2.core.JsRegExp;
22+
import elemental2.core.RegExpResult;
23+
2124
/**
2225
* The {@code MatchHighlighter} class provides utility methods for highlighting matching substrings
2326
* within a source string. It allows you to emphasize specific parts of the source string by
@@ -44,10 +47,13 @@ public static String highlight(String source, String part) {
4447
|| !containsPart(source, part)) {
4548
return sourceOrEmpty(source);
4649
}
47-
int startIndex = source.toLowerCase().indexOf(part.toLowerCase());
48-
String partInSource = source.substring(startIndex, startIndex + part.length());
49-
String result = source.replace(partInSource, prefix + partInSource + postfix);
50-
return result;
50+
JsRegExp regExp = new JsRegExp(escapeRegExp(part), "i");
51+
RegExpResult result = regExp.exec(source);
52+
if (isNull(result)) {
53+
return source;
54+
}
55+
String partInSource = result.getAt(0);
56+
return source.replace(partInSource, prefix + partInSource + postfix);
5157
}
5258

5359
/**
@@ -59,7 +65,8 @@ public static String highlight(String source, String part) {
5965
* {@code false}.
6066
*/
6167
private static boolean containsPart(String source, String part) {
62-
return source.toLowerCase().contains(part.toLowerCase());
68+
JsRegExp regExp = new JsRegExp(escapeRegExp(part), "i");
69+
return !isNull(regExp.exec(source));
6370
}
6471

6572
/**
@@ -71,4 +78,31 @@ private static boolean containsPart(String source, String part) {
7178
private static String sourceOrEmpty(String source) {
7279
return isNull(source) ? "" : source;
7380
}
81+
82+
private static String escapeRegExp(String text) {
83+
StringBuilder builder = new StringBuilder(text.length());
84+
for (int i = 0; i < text.length(); i++) {
85+
char ch = text.charAt(i);
86+
switch (ch) {
87+
case '\\':
88+
case '^':
89+
case '$':
90+
case '.':
91+
case '|':
92+
case '?':
93+
case '*':
94+
case '+':
95+
case '(':
96+
case ')':
97+
case '[':
98+
case ']':
99+
case '{':
100+
case '}':
101+
builder.append('\\');
102+
default:
103+
builder.append(ch);
104+
}
105+
}
106+
return builder.toString();
107+
}
74108
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright © 2019 Dominokit
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.dominokit.domino.ui.utils;
17+
18+
import com.google.gwt.junit.tools.GWTTestSuite;
19+
import junit.framework.Test;
20+
import junit.framework.TestSuite;
21+
22+
public class DominoUiTestSuite extends GWTTestSuite {
23+
public static Test suite() {
24+
TestSuite suite = new TestSuite("Tests for client domino-ui");
25+
suite.addTestSuite(MatchHighlighterTest.class);
26+
27+
return suite;
28+
}
29+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright © 2019 Dominokit
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.dominokit.domino.ui.utils;
17+
18+
import com.google.gwt.junit.client.GWTTestCase;
19+
20+
public class MatchHighlighterTest extends GWTTestCase {
21+
22+
@Override
23+
public String getModuleName() {
24+
return "org.dominokit.domino.ui.DominoUI";
25+
}
26+
27+
public void testShouldReturnEmptyStringWhenSourceIsNull() {
28+
assertEquals("", MatchHighlighter.highlight(null, "match"));
29+
}
30+
31+
public void testShouldReturnSourceWhenPartIsNull() {
32+
String source = "Domino UI";
33+
34+
assertEquals(source, MatchHighlighter.highlight(source, null));
35+
}
36+
37+
public void testShouldReturnSourceWhenPartIsEmpty() {
38+
String source = "Domino UI";
39+
40+
assertEquals(source, MatchHighlighter.highlight(source, ""));
41+
}
42+
43+
public void testShouldReturnSourceWhenSourceIsEmpty() {
44+
assertEquals("", MatchHighlighter.highlight("", "domino"));
45+
}
46+
47+
public void testShouldReturnSourceWhenNoMatchFound() {
48+
String source = "Domino UI";
49+
50+
assertEquals(source, MatchHighlighter.highlight(source, "test"));
51+
}
52+
53+
public void testShouldHighlightMatchWithSpecialCharacters() {
54+
String highlighted = MatchHighlighter.highlight("İrfan", "an");
55+
56+
assertEquals("İrf<mark>an</mark>", highlighted);
57+
}
58+
59+
public void testShouldHighlightMatchIgnoringCase() {
60+
String highlighted = MatchHighlighter.highlight("DominoUI", "dom");
61+
62+
assertEquals("<mark>Dom</mark>inoUI", highlighted);
63+
}
64+
65+
public void testShouldHighlightAllOccurrencesMatchingFirstDetectedCase() {
66+
String highlighted = MatchHighlighter.highlight("foo foo Foo foo", "foo");
67+
68+
assertEquals("<mark>foo</mark> <mark>foo</mark> Foo <mark>foo</mark>", highlighted);
69+
}
70+
71+
public void testShouldHighlightEntireSourceWhenPartEqualsSource() {
72+
assertEquals("<mark>match</mark>", MatchHighlighter.highlight("match", "match"));
73+
}
74+
75+
public void testShouldReturnSourceWhenPartLongerThanSource() {
76+
assertEquals("short", MatchHighlighter.highlight("short", "a bit longer"));
77+
}
78+
}

0 commit comments

Comments
 (0)