1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.primefaces.extensions.component.inputotp;
23
24 import java.io.IOException;
25
26 import javax.faces.FacesException;
27 import javax.faces.component.UIComponent;
28 import javax.faces.context.FacesContext;
29 import javax.faces.context.ResponseWriter;
30
31 import org.primefaces.extensions.util.Attrs;
32 import org.primefaces.renderkit.InputRenderer;
33 import org.primefaces.util.ComponentUtils;
34 import org.primefaces.util.Constants;
35 import org.primefaces.util.FacetUtils;
36 import org.primefaces.util.HTML;
37 import org.primefaces.util.LangUtils;
38 import org.primefaces.util.WidgetBuilder;
39
40
41
42
43
44
45 public class InputOtpRenderer extends InputRenderer {
46
47 @Override
48 public void decode(final FacesContext context, final UIComponent component) {
49 final InputOtp inputOtp = (InputOtp) component;
50
51 if (!shouldDecode(inputOtp)) {
52 return;
53 }
54
55 final String inputId = inputOtp.getClientId(context) + InputOtp.HIDDEN_SUFFIX;
56 final String submittedValue = context.getExternalContext().getRequestParameterMap().get(inputId);
57
58 if (submittedValue != null) {
59 inputOtp.setSubmittedValue(submittedValue);
60 }
61
62 decodeBehaviors(context, inputOtp);
63 }
64
65 @Override
66 public void encodeEnd(final FacesContext context, final UIComponent component) throws IOException {
67 final InputOtp inputOtp = (InputOtp) component;
68
69 if (inputOtp.getLength() < 1) {
70 throw new FacesException("InputOtp length property should be > 0");
71 }
72
73 String valueToRender = ComponentUtils.getValueToRender(context, inputOtp, inputOtp.getValue());
74 if (valueToRender == null) {
75 valueToRender = Constants.EMPTY_STRING;
76 }
77
78 encodeMarkup(context, inputOtp, valueToRender);
79 encodeScript(context, inputOtp);
80 }
81
82 protected void encodeMarkup(final FacesContext context, final InputOtp inputOtp, final String valueToRender)
83 throws IOException {
84 final ResponseWriter writer = context.getResponseWriter();
85 final String clientId = inputOtp.getClientId(context);
86 final String styleClass = getStyleClassBuilder(context)
87 .add(InputOtp.STYLE_CLASS, inputOtp.getStyleClass())
88 .add(ComponentUtils.isRTL(context, inputOtp), InputOtp.RTL_STYLE_CLASS)
89 .build();
90
91 writer.startElement("span", inputOtp);
92 writer.writeAttribute("id", clientId, null);
93 writer.writeAttribute(Attrs.CLASS, styleClass, "styleClass");
94
95 if (inputOtp.getStyle() != null) {
96 writer.writeAttribute(Attrs.STYLE, inputOtp.getStyle(), Attrs.STYLE);
97 }
98
99 encodeInput(context, inputOtp, clientId, valueToRender);
100 encodeHiddenInput(context, inputOtp, clientId, valueToRender);
101
102 writer.endElement("span");
103 }
104
105 protected void encodeInput(final FacesContext context, final InputOtp inputOtp, final String clientId,
106 final String valueToRender)
107 throws IOException {
108
109 final ResponseWriter writer = context.getResponseWriter();
110 final String inputStyle = inputOtp.getInputStyle();
111 final String inputStyleClass = createStyleClass(inputOtp, InputOtp.PropertyKeys.inputStyleClass.name(), InputOtp.CELL_STYLE_CLASS);
112 final char[] chars = valueToRender.toCharArray();
113 final boolean hasSeparatorFacet = FacetUtils.shouldRenderFacet(inputOtp.getFacet("separator"));
114 for (int i = 1; i <= inputOtp.getLength(); i++) {
115
116 if (i > 1 && (LangUtils.isNotBlank(inputOtp.getSeparator()) || hasSeparatorFacet)) {
117 writer.startElement("div", null);
118 writer.writeAttribute(Attrs.CLASS, InputOtp.SEPARATOR_STYLE_CLASS, null);
119 if (hasSeparatorFacet) {
120 inputOtp.getFacet("separator").encodeAll(context);
121 }
122 else {
123 writer.writeText(inputOtp.getSeparator(), InputOtp.PropertyKeys.separator.name());
124 }
125 writer.endElement("div");
126 }
127
128 final String inputId = clientId + InputOtp.INPUT_SUFFIX + i;
129 final String inputValue = chars.length >= i ? String.valueOf(chars[i - 1]) : "";
130
131 writer.startElement("input", null);
132 writer.writeAttribute("id", inputId, null);
133 writer.writeAttribute("name", inputId, null);
134 writer.writeAttribute("value", inputValue, null);
135 writer.writeAttribute("size", 1, null);
136 writer.writeAttribute("maxlength", inputOtp.getLength(), null);
137 writer.writeAttribute(Attrs.CLASS, inputStyleClass, null);
138
139 if (LangUtils.isNotBlank(inputStyle)) {
140 writer.writeAttribute(Attrs.STYLE, inputStyle, null);
141 }
142
143 if (inputOtp.isMask()) {
144 writer.writeAttribute("type", "password", null);
145 }
146
147 if (inputOtp.isIntegerOnly() && LangUtils.isBlank(inputOtp.getInputmode())) {
148 inputOtp.setInputmode("numeric");
149 }
150
151 if (LangUtils.isNotBlank(inputOtp.getPlaceholder())) {
152 char placeholder = inputOtp.getPlaceholder().charAt((i - 1) % inputOtp.getPlaceholder().length());
153 writer.writeAttribute("placeholder", placeholder, null);
154 }
155
156 renderAccessibilityAttributes(context, inputOtp);
157 renderRTLDirection(context, inputOtp);
158 renderPassThruAttributes(context, inputOtp, InputOtp.INPUT_OTP_ATTRIBUTES_WITHOUT_EVENTS);
159 renderDomEvents(context, inputOtp, HTML.INPUT_TEXT_EVENTS);
160 renderValidationMetadata(context, inputOtp);
161
162 writer.endElement("input");
163 }
164 }
165
166 protected void encodeHiddenInput(final FacesContext context, final InputOtp inputOtp, final String clientId, final String valueToRender)
167 throws IOException {
168 renderHiddenInput(context, clientId + InputOtp.HIDDEN_SUFFIX, valueToRender, inputOtp.isDisabled());
169 }
170
171 protected void encodeScript(final FacesContext context, final InputOtp inputOtp) throws IOException {
172 final WidgetBuilder wb = getWidgetBuilder(context);
173 wb.init("ExtInputOtp", inputOtp);
174 wb.attr("integerOnly", inputOtp.isIntegerOnly(), false);
175 if (LangUtils.isNotBlank(inputOtp.getAriaLabel())) {
176 wb.attr("ariaLabel", inputOtp.getAriaLabel());
177 }
178
179 encodeClientBehaviors(context, inputOtp);
180
181 wb.finish();
182 }
183
184 }