InputTextarea extends standard InputTextarea with autoComplete, autoResize, remaining characters counter and theming features.
<p:growl id="growl" showSummary="true" showDetail="true" keepAlive="true" life="3000">
<p:autoUpdate/>
</p:growl>
<div class="card">
<h:form>
<h5>AutoResize + AJAX Events</h5>
<p:inputTextarea rows="6" cols="33" value="#{inputTextareaView.value}">
<p:ajax listener="#{inputTextareaView.onChange}"/>
</p:inputTextarea>
<h5>Remaining Chars</h5>
<p:inputTextarea rows="5" cols="30" counter="display" maxlength="10"
counterTemplate="{0} characters remaining." autoResize="false"/>
<h:outputText id="display" class="block" />
<h5>AutoComplete</h5>
<p>Following inputTextarea send a query for each word that has at least 4 characters to the complete method. Try typing "PrimeFaces".</p>
<p:inputTextarea rows="10" cols="50" completeMethod="#{inputTextareaView.completeArea}" queryDelay="750"
minQueryLength="4">
<p:ajax event="itemSelect" listener="#{inputTextareaView.onSelect}"/>
</p:inputTextarea>
</h:form>
</div>
package org.primefaces.showcase.view.input;
import org.primefaces.component.inputtextarea.InputTextarea;
import org.primefaces.event.SelectEvent;
import org.primefaces.showcase.util.taglib.TagLibProvider;
import java.util.ArrayList;
import java.util.List;
import jakarta.enterprise.context.RequestScoped;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.context.FacesContext;
import jakarta.faces.event.AjaxBehaviorEvent;
import jakarta.inject.Inject;
import jakarta.inject.Named;
@Named
@RequestScoped
public class InputTextareaView {
@Inject
private TagLibProvider tagLibProvider;
private String value;
public List<String> completeArea(String query) {
List<String> results = new ArrayList<>();
if ("PrimeFaces".equals(query)) {
results.add("PrimeFaces Rocks!!!");
results.add("PrimeFaces has " + tagLibProvider.getComponentCount() + " components.");
results.add("PrimeFaces is lightweight.");
results.add("PrimeFaces is easy to use.");
results.add("PrimeFaces is developed with passion!");
}
else {
for (int i = 0; i < 10; i++) {
results.add(query + i);
}
}
return results;
}
public void onSelect(SelectEvent<String> event) {
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "select", event.getObject()));
}
public void onChange(AjaxBehaviorEvent event) {
FacesContext facesContext = FacesContext.getCurrentInstance();
InputTextarea inputTextarea = (InputTextarea) event.getComponent();
String newValue = (String) inputTextarea.getValue();
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "change", newValue));
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
package org.primefaces.showcase.util.taglib;
import org.primefaces.cdk.spi.taglib.TagType;
import org.primefaces.cdk.spi.taglib.Taglib;
import org.primefaces.cdk.spi.taglib.TaglibParser;
import org.primefaces.util.LangUtils;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.faces.FacesException;
import jakarta.inject.Named;
import lombok.Getter;
@Named
@ApplicationScoped
@Getter
public class TagLibProvider {
private Taglib taglib;
private Map<String, TagInfo> tags;
private List<TagInfo> tagsSorted;
private List<FunctionInfo> functionsSorted;
private int componentCount;
@PostConstruct
public void init() {
TaglibParser taglibParser = new TaglibParser();
try {
taglib = taglibParser.parse(this.getClass().getResourceAsStream("/META-INF/primefaces.taglib.xml"));
tags = taglib.getTags().stream().collect(
Collectors.toMap(t -> t.getTagName(), t -> new TagInfo(t)));
tagsSorted = tags.values().stream()
.sorted(Comparator.comparing(o -> o.getTag().getTagName()))
.collect(Collectors.toList());
functionsSorted = taglib.getFunctions().stream()
.map(f -> new FunctionInfo(f))
.sorted(Comparator.comparing(o -> o.getFunction().getName()))
.collect(Collectors.toList());
// rendered components only: no child-only tags like p:tab or p:menuitem
componentCount = (int) taglib.getTags().stream()
.filter(t -> t.getType() == TagType.COMPONENT && LangUtils.isNotBlank(t.getRendererType()))
.count();
}
catch (Exception e) {
throw new FacesException("Could not parse taglib!", e);
}
}
}
package org.primefaces.showcase.util.taglib;
import org.primefaces.cdk.api.PrimeClientBehaviorEventKeys;
import org.primefaces.cdk.api.PrimeFacetKeys;
import org.primefaces.cdk.api.PrimePropertyKeys;
import org.primefaces.cdk.api.Property;
import org.primefaces.cdk.api.behavior.PrimeClientBehavior;
import org.primefaces.cdk.api.component.PrimeClientBehaviorHolder;
import org.primefaces.cdk.api.component.PrimeComponent;
import org.primefaces.cdk.api.converter.PrimeConverter;
import org.primefaces.cdk.api.utils.ReflectionUtils;
import org.primefaces.cdk.api.validator.PrimeValidator;
import org.primefaces.cdk.spi.taglib.Tag;
import org.primefaces.cdk.spi.taglib.TagType;
import org.primefaces.util.LangUtils;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import jakarta.faces.component.UIComponent;
import jakarta.faces.context.FacesContext;
import jakarta.faces.render.RenderKit;
import jakarta.faces.render.Renderer;
import lombok.Getter;
@Getter
public class TagInfo {
private Tag tag;
private List<PrimePropertyKeys> properties;
private String componentClass;
private String componentFamily;
private String rendererClass;
private List<PrimeFacetKeys> facets;
private List<PrimeClientBehaviorEventKeys> clientBehaviorsEvents;
private String behaviorClass;
private String converterClass;
private String validatorClass;
private List<ResourceDependency> resourceDependencies;
public TagInfo(Tag tag) {
try {
this.tag = tag;
FacesContext context = FacesContext.getCurrentInstance();
if (tag.getType() == TagType.COMPONENT) {
PrimeComponent instance = (PrimeComponent) context.getApplication().createComponent(tag.getComponentType());
properties = Arrays.asList(instance.getPropertyKeys());
componentClass = instance.getClass().getName();
componentFamily = ((UIComponent) instance).getFamily();
if (LangUtils.isNotBlank(tag.getRendererType())) {
RenderKit renderKit = context.getRenderKit();
Renderer<?> renderer = renderKit.getRenderer(componentFamily, tag.getRendererType());
rendererClass = renderer.getClass().getName();
}
facets = Arrays.asList(instance.getFacetKeys());
if (instance instanceof PrimeClientBehaviorHolder) {
clientBehaviorsEvents = Arrays.asList(((PrimeClientBehaviorHolder) instance).getClientBehaviorEventKeys());
}
resourceDependencies = Arrays.stream(
instance.getClass().getAnnotationsByType(jakarta.faces.application.ResourceDependency.class))
.map(r -> new ResourceDependency(r.name(), r.library(), r.target()))
.collect(Collectors.toList());
}
else if (tag.getType() == TagType.BEHAVIOR) {
PrimeClientBehavior instance = (PrimeClientBehavior) context.getApplication().createBehavior(tag.getBehaviorId());
properties = Arrays.asList(instance.getPropertyKeys());
behaviorClass = instance.getClass().getName();
resourceDependencies = Arrays.stream(
instance.getClass().getAnnotationsByType(jakarta.faces.application.ResourceDependency.class))
.map(r -> new ResourceDependency(r.name(), r.library(), r.target()))
.collect(Collectors.toList());
}
else if (tag.getType() == TagType.CONVERTER) {
PrimeConverter<?> instance = (PrimeConverter<?>) context.getApplication().createConverter(tag.getConverterId());
properties = Arrays.asList(instance.getPropertyKeys());
converterClass = instance.getClass().getName();
}
else if (tag.getType() == TagType.VALIDATOR) {
PrimeValidator<?> instance = (PrimeValidator<?>) context.getApplication().createValidator(tag.getValidatorId());
properties = Arrays.asList(instance.getPropertyKeys());
validatorClass = instance.getClass().getName();
}
else if (tag.getType() == TagType.TAG_HANDLER) {
Class<?> tagHandler = ReflectionUtils.tryToLoadClassForName(tag.getHandlerClass());
properties = Arrays.stream(tagHandler.getDeclaredFields())
.filter(f -> f.isAnnotationPresent(Property.class))
.map(f -> PrimePropertyKeys.Literal.of(f.getName(), f.getAnnotation(Property.class)))
.collect(Collectors.toList());
}
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
public boolean isComponent() {
return tag.getType() == TagType.COMPONENT;
}
public boolean isBehavior() {
return tag.getType() == TagType.BEHAVIOR;
}
public boolean isConverter() {
return tag.getType() == TagType.CONVERTER;
}
public boolean isValidator() {
return tag.getType() == TagType.VALIDATOR;
}
}
package org.primefaces.showcase.util.taglib;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class ResourceDependency {
private String name;
private String library;
private String target;
}
package org.primefaces.showcase.util.taglib;
import org.primefaces.cdk.api.utils.ReflectionUtils;
import org.primefaces.cdk.spi.taglib.Function;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.stream.Collectors;
import lombok.Getter;
@Getter
public class FunctionInfo {
private Function function;
private String signature;
public FunctionInfo(Function function) {
this.function = function;
try {
Class<?> clazz = ReflectionUtils.loadClassForName(function.getFunctionClass());
Method method = Arrays.stream(clazz.getMethods()).filter(m -> {
org.primefaces.cdk.api.Function func = m.getAnnotation(org.primefaces.cdk.api.Function.class);
if (func == null) return false;
String annotationName = func.name().isEmpty() ? m.getName() : func.name();
return annotationName.equals(function.getName());
})
.findFirst()
.orElse(null);
if (method == null) {
Class<?>[] paramTypes = extractParamTypes(function.getFunctionSignature());
method = clazz.getMethod(function.getName(), paramTypes);
}
signature = formatMethodSignature(function.getName(), method);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
public Class<?>[] extractParamTypes(String signature) throws ClassNotFoundException {
int start = signature.indexOf('(');
int end = signature.indexOf(')');
String inside = signature.substring(start + 1, end).trim();
if (inside.isEmpty()) return new Class<?>[0];
String[] typeNames = inside.split("\\s*,\\s*");
Class<?>[] types = new Class<?>[typeNames.length];
for (int i = 0; i < typeNames.length; i++) {
types[i] = resolveType(typeNames[i].trim());
}
return types;
}
private Class<?> resolveType(String typeName) throws ClassNotFoundException {
switch (typeName) {
case "int": return int.class;
case "long": return long.class;
case "double": return double.class;
case "float": return float.class;
case "boolean": return boolean.class;
case "byte": return byte.class;
case "short": return short.class;
case "char": return char.class;
case "void": return void.class;
default:
try {
return ReflectionUtils.loadClassForName(typeName);
}
catch (ClassNotFoundException e) {
return ReflectionUtils.loadClassForName("java.lang." + typeName);
}
}
}
public String formatMethodSignature(String name, Method method) {
String returnType = method.getReturnType().getSimpleName();
String params = Arrays.stream(method.getParameters())
.map(p -> p.getType().getSimpleName() + " " + p.getName())
.collect(Collectors.joining(", "));
return returnType + " " + name + "(" + params + ")";
}
}