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.clockpicker;
23
24 import java.io.IOException;
25 import java.text.DateFormatSymbols;
26 import java.time.LocalTime;
27 import java.time.format.DateTimeFormatter;
28 import java.util.Locale;
29 import java.util.Objects;
30
31 import javax.el.ValueExpression;
32 import javax.faces.component.UIComponent;
33 import javax.faces.context.FacesContext;
34 import javax.faces.context.ResponseWriter;
35 import javax.faces.convert.Converter;
36 import javax.faces.convert.ConverterException;
37
38 import org.primefaces.expression.SearchExpressionUtils;
39 import org.primefaces.extensions.util.Attrs;
40 import org.primefaces.renderkit.InputRenderer;
41 import org.primefaces.util.HTML;
42 import org.primefaces.util.LangUtils;
43 import org.primefaces.util.WidgetBuilder;
44
45 public class ClockPickerRenderer extends InputRenderer {
46
47 private static final DateTimeFormatter FORMATTER_24_HOUR = DateTimeFormatter.ofPattern("HH:mm");
48
49 @Override
50 public void decode(FacesContext context, UIComponent component) {
51
52 final ClockPicker clockPicker = (ClockPicker) component;
53
54 if (clockPicker.isDisabled() || clockPicker.isReadonly()) {
55 return;
56 }
57 final String param = clockPicker.getClientId(context) + "_input";
58 final String submittedValue = context.getExternalContext().getRequestParameterMap().get(param);
59
60 if (null != submittedValue) {
61 clockPicker.setSubmittedValue(submittedValue);
62 }
63 decodeBehaviors(context, component);
64 }
65
66 @Override
67 public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
68 final ClockPicker clockPicker = (ClockPicker) component;
69 final Locale locale = clockPicker.calculateLocale(context);
70 final DateFormatSymbols symbols = new DateFormatSymbols(locale);
71
72 final String value = getValueAsString(context, clockPicker);
73 encodeMarkup(context, clockPicker, value, symbols);
74 encodeScript(context, clockPicker, symbols);
75 }
76
77 private void encodeMarkup(FacesContext context, ClockPicker clockPicker, final String value, DateFormatSymbols symbols) throws IOException {
78 final ResponseWriter writer = context.getResponseWriter();
79 final String clientId = clockPicker.getClientId();
80 final String inputId = clientId + "_input";
81 final String[] ampm = symbols.getAmPmStrings();
82 final int inputSize = clockPicker.isTwelveHour() ? 5 + ampm[0].length() : 5;
83
84 writer.startElement("div", clockPicker);
85 writer.writeAttribute("id", clientId, null);
86 String containerClass = ClockPicker.CONTAINER_CLASS;
87 if (clockPicker.isShowOnButton()) {
88 containerClass += " ui-inputgroup";
89 }
90 writer.writeAttribute("class", containerClass, null);
91
92 writer.startElement("input", null);
93 writer.writeAttribute("id", inputId, null);
94 writer.writeAttribute("name", inputId, null);
95 writer.writeAttribute("type", "text", null);
96 writer.writeAttribute("size", inputSize, null);
97 writer.writeAttribute("maxlength", inputSize, null);
98
99 final String styleClass = createStyleClass(clockPicker, "ui-inputfield ui-widget ui-state-default ui-corner-all");
100 writer.writeAttribute(Attrs.CLASS, styleClass, null);
101
102 if (clockPicker.getStyle() != null) {
103 writer.writeAttribute(Attrs.STYLE, clockPicker.getStyle(), null);
104 }
105
106 if (LangUtils.isNotBlank(value)) {
107 writer.writeAttribute("value", value, null);
108 }
109
110 renderAccessibilityAttributes(context, clockPicker);
111 renderPassThruAttributes(context, clockPicker, HTML.INPUT_TEXT_ATTRS_WITHOUT_EVENTS);
112 renderDomEvents(context, clockPicker, HTML.INPUT_TEXT_EVENTS);
113 renderValidationMetadata(context, clockPicker);
114
115 writer.endElement("input");
116
117 if (clockPicker.isShowOnButton()) {
118 writer.startElement("button", null);
119 writer.writeAttribute(Attrs.CLASS, ClockPicker.BUTTON_TRIGGER_CLASS, null);
120 writer.writeAttribute("type", "button", null);
121 writer.writeAttribute("role", "button", null);
122
123 writer.startElement("span", null);
124 writer.writeAttribute(Attrs.CLASS, ClockPicker.BUTTON_TRIGGER_ICON_CLASS, null);
125 writer.endElement("span");
126
127 writer.startElement("span", null);
128 writer.writeAttribute(Attrs.CLASS, ClockPicker.BUTTON_TRIGGER_TEXT_CLASS, null);
129 writer.write("ui-button");
130 writer.endElement("span");
131 writer.endElement("button");
132 }
133
134 writer.endElement("div");
135 }
136
137 private void encodeScript(final FacesContext context, final ClockPicker clockPicker, DateFormatSymbols symbols) throws IOException {
138 final String[] ampm = symbols.getAmPmStrings();
139
140 final WidgetBuilder wb = getWidgetBuilder(context);
141 wb.init("ExtClockPicker", clockPicker);
142 wb.attr("appendTo", SearchExpressionUtils.resolveOptionalClientIdForClientSide(context, clockPicker, clockPicker.getAppendTo()));
143 wb.attr("placement", clockPicker.getPlacement(), "bottom");
144 wb.attr("align", clockPicker.getAlign(), "left");
145 wb.attr("autoclose", clockPicker.isAutoClose(), false);
146 wb.attr("vibrate", clockPicker.getVibrate(), true);
147 wb.attr("twelvehour", clockPicker.isTwelveHour(), false);
148 wb.attr("amtext", ampm[0], "AM");
149 wb.attr("pmtext", ampm[1], "PM");
150
151 if (clockPicker.getOnbeforehourselect() != null) {
152 wb.callback("beforeHourSelect", "function()", clockPicker.getOnbeforehourselect());
153 }
154 if (clockPicker.getOnbeforedone() != null) {
155 wb.callback("beforeDone", "function()", clockPicker.getOnbeforedone());
156 }
157 if (clockPicker.getOnbeforeshow() != null) {
158 wb.callback("beforeShow", "function()", clockPicker.getOnbeforeshow());
159 }
160 if (clockPicker.getOnbeforehide() != null) {
161 wb.callback("beforeHide", "function()", clockPicker.getOnbeforehide());
162 }
163 if (clockPicker.getOnafterhourselect() != null) {
164 wb.callback("afterHourSelect", "function()", clockPicker.getOnafterhourselect());
165 }
166 if (clockPicker.getOnafterdone() != null) {
167 wb.callback("afterDone", "function()", clockPicker.getOnafterdone());
168 }
169 if (clockPicker.getOnaftershow() != null) {
170 wb.callback("afterShow", "function()", clockPicker.getOnaftershow());
171 }
172 if (clockPicker.getOnafterhide() != null) {
173 wb.callback("afterHide", "function()", clockPicker.getOnafterhide());
174 }
175 if (clockPicker.getOnafterampmselect() != null) {
176 wb.callback("afterAmPmSelect", "function()", clockPicker.getOnafterampmselect());
177 }
178
179 encodeClientBehaviors(context, clockPicker);
180 wb.finish();
181 }
182
183 protected static String getValueAsString(final FacesContext context, final ClockPicker clockPicker) {
184 Object submittedValue = clockPicker.getSubmittedValue();
185 if (submittedValue != null) {
186 return submittedValue.toString();
187 }
188
189 Object value = clockPicker.getValue();
190 if (value == null) {
191 return null;
192 }
193
194 try {
195 if (clockPicker.getConverter() != null) {
196 return clockPicker.getConverter().getAsString(context, clockPicker, value);
197 }
198 else if (value instanceof LocalTime) {
199 return clockPicker.isTwelveHour()
200 ? ((LocalTime) value).format(DateTimeFormatter.ofPattern("hh:mma").withLocale(clockPicker.calculateLocale(context)))
201 : ((LocalTime) value).format(FORMATTER_24_HOUR);
202 }
203 }
204 catch (Exception e) {
205 return null;
206 }
207
208 return null;
209 }
210
211 @Override
212 public Object getConvertedValue(FacesContext context, UIComponent component,
213 Object value) throws ConverterException {
214 final ClockPicker clockPicker = (ClockPicker) component;
215 String submittedValue = Objects.toString(value, null);
216
217 if (isValueBlank(submittedValue)) {
218 return null;
219 }
220
221
222 try {
223 Converter converter = clockPicker.getConverter();
224 if (converter != null) {
225 return converter.getAsObject(context, clockPicker, submittedValue);
226 }
227 }
228 catch (ConverterException e) {
229 return submittedValue;
230 }
231
232
233 try {
234 ValueExpression ve = clockPicker.getValueExpression("value");
235 if (ve != null) {
236 Class<?> type = ve.getType(context.getELContext());
237 if (type != null && submittedValue != null && type.isAssignableFrom(LocalTime.class)) {
238
239 return clockPicker.isTwelveHour()
240 ? LocalTime.parse(submittedValue, DateTimeFormatter.ofPattern("hh:mma").withLocale(clockPicker.calculateLocale(context)))
241 : LocalTime.parse(submittedValue, FORMATTER_24_HOUR);
242 }
243 }
244 }
245 catch (Exception e) {
246 return submittedValue;
247 }
248 return submittedValue;
249 }
250 }