Created
March 7, 2025 11:07
-
-
Save TatuLund/e4a66e42a00cb0e4173d770ee5f870e8 to your computer and use it in GitHub Desktop.
Vaadin's RichTextEditor does not have label, errorText, invalid styles and helperText. CustomField is the simplest way to add those, here is example RteField
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.application.views; | |
import org.jsoup.Jsoup; | |
import org.jsoup.nodes.Document; | |
import com.vaadin.flow.component.Html; | |
import com.vaadin.flow.component.checkbox.Checkbox; | |
import com.vaadin.flow.component.customfield.CustomField; | |
import com.vaadin.flow.component.orderedlayout.VerticalLayout; | |
import com.vaadin.flow.component.richtexteditor.RichTextEditor; | |
import com.vaadin.flow.data.binder.Binder; | |
import com.vaadin.flow.router.Route; | |
@Route(value = "rich-text", layout = MainLayout.class) | |
public class RichTextEditorView extends VerticalLayout { | |
public RichTextEditorView() { | |
setMargin(true); | |
setSpacing(true); | |
var rteField = new RteField(); | |
rteField.setLabel("Html"); | |
rteField.setHelperText("Input something"); | |
var binder = new Binder<Data>(); | |
binder.forField(rteField).asRequired("Required") | |
.withValidator( | |
value -> Jsoup.parse(value).select("strong").size() > 0, | |
"Bold required") | |
.withValidator( | |
value -> Jsoup.parse(value).select("h1").size() > 0, | |
"H1 required") | |
.bind(Data::getHtml, Data::setHtml); | |
var html = new Html("<div></div>"); | |
binder.addValueChangeListener(e -> { | |
html.setHtmlContent( | |
String.format("<div>%s</div>", rteField.getValue())); | |
}); | |
var readOnly = new Checkbox("ReadOnly"); | |
readOnly.addValueChangeListener( | |
e -> rteField.setReadOnly(e.getValue())); | |
var disabled = new Checkbox("Disabled"); | |
disabled.addValueChangeListener( | |
e -> rteField.setEnabled(!e.getValue())); | |
add(readOnly, disabled, rteField, html); | |
} | |
public class Data { | |
private String html; | |
public String getHtml() { | |
return html; | |
} | |
public void setHtml(String html) { | |
this.html = html; | |
} | |
} | |
public class RteField extends CustomField<String> { | |
private RichTextEditor rte; | |
public RteField() { | |
rte = new RichTextEditor(); | |
add(rte); | |
} | |
@Override | |
public void setReadOnly(boolean readOnly) { | |
rte.setReadOnly(readOnly); | |
} | |
@Override | |
public void onEnabledStateChanged(boolean enabled) { | |
rte.setEnabled(enabled); | |
} | |
@Override | |
public void setInvalid(boolean invalid) { | |
// Use these in styles.css: | |
// | |
// vaadin-rich-text-editor[invalid] { | |
// border: 1px solid var(--lumo-error-color); | |
// background: var(--lumo-error-color-10pct); | |
// } | |
super.setInvalid(invalid); | |
if (invalid) { | |
rte.getElement().setAttribute("invalid", ""); | |
} else { | |
rte.getElement().removeAttribute("invalid"); | |
} | |
} | |
@Override | |
public boolean isEmpty() { | |
Document document = Jsoup.parse(getValue()); | |
// Get non-normalized text including spaces and newlines | |
// Note that <br>s count as newlines | |
String text = document.body().wholeText(); | |
// Remove first newline occurrence as Quill editor adds a single | |
// <br> in | |
// every element even without the user having typed anything | |
text = text.replaceFirst("\n", ""); | |
boolean hasText = !text.isEmpty(); | |
boolean hasImages = document.selectFirst("img") != null; | |
return !hasText && !hasImages; | |
} | |
@Override | |
public String getEmptyValue() { | |
// If current value is satisfying isEmpty condition, use it to | |
// satisfy Binder's asRequired. | |
return isEmpty() ? getValue() : ""; | |
} | |
@Override | |
protected String generateModelValue() { | |
return rte.getValue(); | |
} | |
@Override | |
protected void setPresentationValue(String newPresentationValue) { | |
rte.setValue(newPresentationValue); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment