aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Vitaly Takmazov2024-04-27 19:54:16 +0300
committerGravatar Vitaly Takmazov2024-04-27 21:45:00 +0300
commitf2421c1e8ed0a0c8392b179435d638ff55fe1551 (patch)
treec95ec31b18ec23498408b4c34a351dcfbb4c2cdd
parent57fae6b2d4e2f94e49a3b809a47ef4abc2a1ef80 (diff)
Fix text truncation in reply quotes and Twitter posts
-rw-r--r--src/main/java/com/juick/service/TwitterService.java3
-rw-r--r--src/main/java/com/juick/util/MessageUtils.java3
-rw-r--r--src/main/java/com/juick/util/formatters/PlainTextFormatter.java25
-rw-r--r--src/test/java/com/juick/server/tests/ServerTests.java7
4 files changed, 35 insertions, 3 deletions
diff --git a/src/main/java/com/juick/service/TwitterService.java b/src/main/java/com/juick/service/TwitterService.java
index d0c105f2..ffcaca13 100644
--- a/src/main/java/com/juick/service/TwitterService.java
+++ b/src/main/java/com/juick/service/TwitterService.java
@@ -27,6 +27,7 @@ import com.github.scribejava.core.model.Verb;
import com.github.scribejava.core.oauth.OAuth20Service;
import com.juick.model.Message;
import com.juick.util.MessageUtils;
+import com.juick.util.formatters.PlainTextFormatter;
import jakarta.annotation.PostConstruct;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
@@ -67,7 +68,7 @@ public class TwitterService {
userService.getTwitterToken(jmsg.getUser().getUid()).ifPresent(t -> {
String status = MessageUtils.getMessageHashTags(jmsg) + StringUtils.defaultString(jmsg.getText());
if (status.length() > 253) {
- status = status.substring(0, 252) + "…";
+ status = PlainTextFormatter.truncateText(status, 252) + "…";
}
status += " http://juick.com/" + jmsg.getMid();
try {
diff --git a/src/main/java/com/juick/util/MessageUtils.java b/src/main/java/com/juick/util/MessageUtils.java
index a4407f17..308d144b 100644
--- a/src/main/java/com/juick/util/MessageUtils.java
+++ b/src/main/java/com/juick/util/MessageUtils.java
@@ -21,6 +21,7 @@ import com.juick.model.Message;
import com.juick.model.Tag;
import com.juick.model.User;
import com.juick.model.Entity;
+import com.juick.util.formatters.PlainTextFormatter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.util.UriComponentsBuilder;
@@ -52,7 +53,7 @@ public class MessageUtils {
if (quote != null) {
if (quote.length() > 50) {
- result = ">" + quote.substring(0, 47).replace('\n', ' ') + "...\n";
+ result = ">" + PlainTextFormatter.truncateText(quote, 47).replace('\n', ' ') + "…\n";
} else if (!quote.isEmpty()) {
result = ">" + quote.replace('\n', ' ') + "\n";
}
diff --git a/src/main/java/com/juick/util/formatters/PlainTextFormatter.java b/src/main/java/com/juick/util/formatters/PlainTextFormatter.java
index 9a885bca..2e7722e7 100644
--- a/src/main/java/com/juick/util/formatters/PlainTextFormatter.java
+++ b/src/main/java/com/juick/util/formatters/PlainTextFormatter.java
@@ -22,6 +22,7 @@ import com.juick.util.MessageUtils;
import org.apache.commons.lang3.StringUtils;
import org.ocpsoft.prettytime.PrettyTime;
+import java.text.BreakIterator;
import java.util.Date;
import java.util.Locale;
@@ -62,7 +63,7 @@ public class PlainTextFormatter {
sb.append(attachmentUrl).append("\n");
}
if (txt.length() >= cropLength) {
- sb.append(StringUtils.substring(txt, 0, cropLength)).append(" [...]");
+ sb.append(PlainTextFormatter.truncateText(txt, cropLength)).append(" [...]");
} else {
sb.append(txt);
}
@@ -97,4 +98,26 @@ public class PlainTextFormatter {
public static String formatTwitterCard(Message jmsg) {
return MessageUtils.getMessageHashTags(jmsg) + StringUtils.defaultString(jmsg.getText());
}
+ /**
+ * Truncate text to the nearest word, up to a maximum length specified.
+ *
+ * @param text
+ * @param maxLength
+ * @return
+ */
+ public static String truncateText(String text, int maxLength) {
+ if(text != null && text.length() > maxLength) {
+ BreakIterator bi = BreakIterator.getWordInstance();
+ bi.setText(text);
+
+ if(bi.isBoundary(maxLength-1)) {
+ return text.substring(0, maxLength-2);
+ } else {
+ int preceding = bi.preceding(maxLength-1);
+ return text.substring(0, preceding-1);
+ }
+ } else {
+ return text;
+ }
+ }
}
diff --git a/src/test/java/com/juick/server/tests/ServerTests.java b/src/test/java/com/juick/server/tests/ServerTests.java
index a728ac2b..d61725e6 100644
--- a/src/test/java/com/juick/server/tests/ServerTests.java
+++ b/src/test/java/com/juick/server/tests/ServerTests.java
@@ -2693,4 +2693,11 @@ public class ServerTests {
.with(httpBasic(ugnichName, ugnichPassword)))
.andExpect(status().isBadRequest());
}
+ @Test
+ public void textTruncationShouldNotBreakEmojis() {
+ var text = "Так ты же написал, чтоб я сам поправил отступ \uD83D\uDE00\n";
+ var expected = "Так ты же написал, чтоб я сам поправил отступ";
+ var truncated = PlainTextFormatter.truncateText(text, 47);
+ assertThat(truncated, is(expected));
+ }
}