1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.custom.date;
20
21 import java.io.IOException;
22 import java.text.DateFormatSymbols;
23 import java.text.ParseException;
24 import java.util.Calendar;
25 import java.util.Date;
26 import java.util.Locale;
27 import java.util.Map;
28 import java.util.StringTokenizer;
29
30 import javax.faces.application.FacesMessage;
31 import javax.faces.component.UIComponent;
32 import javax.faces.context.FacesContext;
33 import javax.faces.context.ResponseWriter;
34 import javax.faces.convert.ConverterException;
35
36 import org.apache.myfaces.component.UserRoleUtils;
37 import org.apache.myfaces.custom.calendar.DateBusinessConverter;
38 import org.apache.myfaces.custom.calendar.DefaultDateBusinessConverter;
39 import org.apache.myfaces.custom.calendar.FunctionCallProvider;
40 import org.apache.myfaces.custom.calendar.HtmlCalendarRenderer;
41 import org.apache.myfaces.custom.calendar.HtmlCalendarRenderer.CalendarDateTimeConverter;
42 import org.apache.myfaces.custom.date.AbstractHtmlInputDate.UserData;
43 import org.apache.myfaces.shared_tomahawk.renderkit.JSFAttr;
44 import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
45 import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
46 import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRenderer;
47 import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils;
48 import org.apache.myfaces.shared_tomahawk.renderkit.html.util.JavascriptUtils;
49 import org.apache.myfaces.shared_tomahawk.util.MessageUtils;
50 import org.apache.myfaces.tomahawk.util.Constants;
51
52
53
54
55
56
57
58
59
60
61 public class HtmlDateRenderer extends HtmlRenderer {
62
63
64
65
66 public static final String DATE_MESSAGE_ID = "org.apache.myfaces.Date.INVALID";
67
68 private static final String ID_DAY_POSTFIX = ".day";
69 private static final String ID_MONTH_POSTFIX = ".month";
70 private static final String ID_YEAR_POSTFIX = ".year";
71 private static final String ID_HOURS_POSTFIX = ".hours";
72 private static final String ID_MINUTES_POSTFIX = ".minutes";
73 private static final String ID_SECONDS_POSTFIX = ".seconds";
74 private static final String ID_AMPM_POSTFIX = ".ampm";
75
76 static public String getClientIdForDaySubcomponent(String clientId)
77 {
78 return clientId + ID_DAY_POSTFIX;
79 }
80
81 protected boolean isDisabled(FacesContext facesContext, HtmlInputDate inputDate) {
82 if( !UserRoleUtils.isEnabledOnUserRole(inputDate) )
83 return false;
84
85 return inputDate.isDisabled();
86 }
87
88 public void encodeEnd(FacesContext facesContext, UIComponent uiComponent) throws IOException {
89 RendererUtils.checkParamValidity(facesContext, uiComponent, HtmlInputDate.class);
90
91 HtmlInputDate inputDate = (HtmlInputDate) uiComponent;
92 Locale currentLocale = facesContext.getViewRoot().getLocale();
93 UserData userData = null;
94 String type = inputDate.getType();
95 boolean ampm = inputDate.isAmpm();
96 String clientId = uiComponent.getClientId(facesContext);
97
98 if (null == inputDate.getConverter())
99 {
100 userData = (UserData) inputDate.getSubmittedValue();
101 if( userData == null )
102 userData = inputDate.getUserData(currentLocale);
103 }
104 else
105 {
106
107
108 String value = org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils.getStringValue(facesContext, inputDate);
109
110
111 userData = inputDate.getUserData(currentLocale);
112
113 if (null != value)
114 {
115 StringTokenizer st = new StringTokenizer(value,"\n");
116 while(st.hasMoreTokens())
117 {
118 String token = st.nextToken();
119 if (token.startsWith("year="))
120 {
121 userData.setYear(token.substring(5));
122 }
123 if (token.startsWith("month="))
124 {
125 userData.setMonth(token.substring(6));
126 }
127 if (token.startsWith("day="))
128 {
129 userData.setDay(token.substring(4));
130 }
131 if (token.startsWith("hours="))
132 {
133 userData.setHours(token.substring(6));
134 }
135 if (token.startsWith("minutes="))
136 {
137 userData.setMinutes(token.substring(8));
138 }
139 if (token.startsWith("seconds="))
140 {
141 userData.setSeconds(token.substring(8));
142 }
143 if (token.startsWith("ampm="))
144 {
145 userData.setAmpm(token.substring(5));
146 }
147 }
148 }
149 }
150
151 boolean disabled = isDisabled(facesContext, inputDate);
152 boolean readonly = inputDate.isReadonly();
153
154 ResponseWriter writer = facesContext.getResponseWriter();
155
156 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
157
158 writer.startElement(HTML.SPAN_ELEM, uiComponent);
159 writer.writeAttribute(HTML.ID_ATTR, clientId, null);
160
161 if( ! (type.equals("time") || type.equals("short_time"))){
162 encodeInputDay(inputDate, writer, clientId, userData, disabled, readonly);
163 encodeInputMonth(inputDate, writer, clientId, userData, currentLocale, disabled, readonly);
164 encodeInputYear(inputDate, writer, clientId, userData, disabled, readonly);
165
166 if( inputDate.isPopupCalendar() && ! disabled && ! readonly )
167 encodePopupCalendarButton(facesContext, uiComponent, writer, clientId, currentLocale);
168 }
169 if( type.equals("both") || type.equals("full")){
170 writer.write(" ");
171 }
172 if( ! type.equals("date")){
173 encodeInputHours(uiComponent, writer, clientId, userData, disabled, readonly);
174 writer.write(":");
175 encodeInputMinutes(uiComponent, writer, clientId, userData, disabled, readonly);
176 if (type.equals("full")|| type.equals("time")) {
177 writer.write(":");
178 encodeInputSeconds(uiComponent, writer, clientId, userData, disabled, readonly);
179 }
180 if (ampm) {
181 encodeInputAmpm(uiComponent, writer, clientId, userData, disabled, readonly, currentLocale);
182 }
183 }
184
185 writer.endElement(HTML.SPAN_ELEM);
186 }
187
188 protected void encodeInputField(UIComponent uiComponent, ResponseWriter writer, String id,
189 String value, int size, boolean disabled, boolean readonly) throws IOException {
190 writer.startElement(HTML.INPUT_ELEM, uiComponent);
191 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.UNIVERSAL_ATTRIBUTES);
192 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.EVENT_HANDLER_ATTRIBUTES);
193 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.INPUT_ATTRIBUTES);
194 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.COMMON_FIELD_EVENT_ATTRIBUTES);
195
196 if (disabled) {
197 writer.writeAttribute(HTML.DISABLED_ATTR, Boolean.TRUE, null);
198 }
199 if( readonly ) {
200 writer.writeAttribute(HTML.READONLY_ATTR, Boolean.TRUE, null);
201 }
202
203 writer.writeAttribute(HTML.ID_ATTR, id, null);
204 writer.writeAttribute(HTML.NAME_ATTR, id, null);
205 writer.writeAttribute(HTML.SIZE_ATTR, Integer.toString(size), null);
206 writer.writeAttribute(HTML.MAXLENGTH_ATTR, Integer.toString(size), null);
207 if (value != null) {
208 writer.writeAttribute(HTML.VALUE_ATTR, value, null);
209 }
210 writer.endElement(HTML.INPUT_ELEM);
211 }
212
213 protected void encodeInputDay(UIComponent uiComponent, ResponseWriter writer, String clientId,
214 UserData userData, boolean disabled, boolean readonly) throws IOException {
215 encodeInputField(uiComponent, writer, getClientIdForDaySubcomponent(clientId), userData.getDay(), 2, disabled, readonly);
216 }
217
218 protected void encodeInputMonth(UIComponent uiComponent, ResponseWriter writer, String clientId, UserData userData, Locale currentLocale,
219 boolean disabled, boolean readonly) throws IOException {
220 writer.startElement(HTML.SELECT_ELEM, uiComponent);
221 writer.writeAttribute(HTML.ID_ATTR, clientId + ID_MONTH_POSTFIX, null);
222 writer.writeAttribute(HTML.NAME_ATTR, clientId + ID_MONTH_POSTFIX, null);
223 writer.writeAttribute(HTML.SIZE_ATTR, "1", null);
224 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.UNIVERSAL_ATTRIBUTES);
225 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.EVENT_HANDLER_ATTRIBUTES);
226 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.COMMON_FIELD_EVENT_ATTRIBUTES);
227
228 if (disabled) {
229 writer.writeAttribute(HTML.DISABLED_ATTR, Boolean.TRUE, null);
230 }
231 if (readonly) {
232 writer.writeAttribute(HTML.READONLY_ATTR, Boolean.TRUE, null);
233 }
234
235 int selectedMonth = userData.getMonth() == null ? -1 : Integer.parseInt(userData.getMonth())-1;
236
237 String[] months = HtmlCalendarRenderer.mapMonths(new DateFormatSymbols(currentLocale));
238 encodeEmptyInputMonthSelection(uiComponent, writer, selectedMonth);
239 for (int i = 0; i < months.length; i++) {
240 String monthName = months[i];
241 String monthNumber = Integer.toString(i+1);
242
243 writer.write("\t\t");
244 writer.startElement(HTML.OPTION_ELEM, uiComponent);
245 writer.writeAttribute(HTML.VALUE_ATTR, monthNumber, null);
246
247 if (i == selectedMonth)
248 writer.writeAttribute(HTML.SELECTED_ATTR, HTML.SELECTED_ATTR, null);
249
250 writer.writeText(monthName, null);
251
252 writer.endElement(HTML.OPTION_ELEM);
253 }
254
255
256 writer.writeText("", null);
257 writer.endElement(HTML.SELECT_ELEM);
258 }
259
260 protected void encodeEmptyInputMonthSelection(UIComponent component, ResponseWriter writer, int selectedMonth) throws IOException{
261 writer.startElement(HTML.OPTION_ELEM, component);
262 writer.writeAttribute(HTML.VALUE_ATTR, "-1", null);
263
264 if(selectedMonth == -1)
265 writer.writeAttribute(HTML.SELECTED_ATTR, HTML.SELECTED_ATTR, null);
266
267 writer.writeText(((HtmlInputDate)component).getEmptyMonthSelection(), null);
268 writer.endElement(HTML.OPTION_ELEM);
269 }
270
271 protected void encodeInputYear(UIComponent uiComponent, ResponseWriter writer, String clientId,
272 UserData userData, boolean disabled, boolean readonly) throws IOException {
273 encodeInputField(uiComponent, writer, clientId + ID_YEAR_POSTFIX, userData.getYear(), 4, disabled, readonly);
274 }
275
276 protected void encodeInputHours(UIComponent uiComponent, ResponseWriter writer, String clientId,
277 UserData userData, boolean disabled, boolean readonly) throws IOException {
278 encodeInputField(uiComponent, writer, clientId + ID_HOURS_POSTFIX, userData.getHours(), 2, disabled, readonly);
279 }
280
281 protected void encodeInputMinutes(UIComponent uiComponent, ResponseWriter writer, String clientId,
282 UserData userData, boolean disabled, boolean readonly) throws IOException {
283 encodeInputField(uiComponent, writer, clientId + ID_MINUTES_POSTFIX, userData.getMinutes(), 2, disabled, readonly);
284 }
285
286 protected void encodeInputSeconds(UIComponent uiComponent, ResponseWriter writer, String clientId,
287 UserData userData, boolean disabled, boolean readonly) throws IOException {
288 encodeInputField(uiComponent, writer, clientId + ID_SECONDS_POSTFIX, userData.getSeconds(), 2, disabled, readonly);
289 }
290
291 protected void encodeAmpmChoice(DateFormatSymbols symbols, UIComponent uiComponent, ResponseWriter writer, int calendar_ampm, int selected) throws IOException {
292 String[] ampm_choices = symbols.getAmPmStrings();
293 writer.write("\t\t");
294 writer.startElement(HTML.OPTION_ELEM, uiComponent);
295 writer.writeAttribute(HTML.VALUE_ATTR, new Integer(calendar_ampm), null);
296 if (calendar_ampm == selected)
297 writer.writeAttribute(HTML.SELECTED_ATTR, HTML.SELECTED_ATTR, null);
298 writer.writeText(ampm_choices[calendar_ampm], null);
299 writer.endElement(HTML.OPTION_ELEM);
300 }
301
302 protected void encodeInputAmpm(UIComponent uiComponent, ResponseWriter writer, String clientId,
303 UserData userData, boolean disabled, boolean readonly, Locale currentLocale) throws IOException {
304 writer.startElement(HTML.SELECT_ELEM, uiComponent);
305 writer.writeAttribute(HTML.ID_ATTR, clientId + ID_AMPM_POSTFIX, null);
306 writer.writeAttribute(HTML.NAME_ATTR, clientId + ID_AMPM_POSTFIX, null);
307 writer.writeAttribute(HTML.SIZE_ATTR, "1", null);
308 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.UNIVERSAL_ATTRIBUTES);
309 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.EVENT_HANDLER_ATTRIBUTES);
310 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.COMMON_FIELD_EVENT_ATTRIBUTES);
311
312 if (disabled) {
313 writer.writeAttribute(HTML.DISABLED_ATTR, Boolean.TRUE, null);
314 }
315 if (readonly) {
316 writer.writeAttribute(HTML.READONLY_ATTR, Boolean.TRUE, null);
317 }
318
319 DateFormatSymbols symbols = new DateFormatSymbols(currentLocale);
320
321 int selectedAmpm = userData.getAmpm() == null ? -1 : Integer.parseInt(userData.getAmpm());
322 encodeEmtypAmpmChoice(uiComponent, writer, selectedAmpm);
323 encodeAmpmChoice(symbols, uiComponent, writer, Calendar.AM, selectedAmpm);
324 encodeAmpmChoice(symbols, uiComponent, writer, Calendar.PM, selectedAmpm);
325
326
327
328 writer.writeText("", null);
329 writer.endElement(HTML.SELECT_ELEM);
330 }
331
332 protected void encodeEmtypAmpmChoice(UIComponent component, ResponseWriter writer, int selectedAmpm) throws IOException{
333 writer.startElement(HTML.OPTION_ELEM, component);
334 writer.writeAttribute(HTML.VALUE_ATTR, "-1", null);
335
336 if(selectedAmpm == -1)
337 writer.writeAttribute(HTML.SELECTED_ATTR, HTML.SELECTED_ATTR, null);
338
339 writer.writeText(((HtmlInputDate)component).getEmptyAmpmSelection(), null);
340 writer.endElement(HTML.OPTION_ELEM);
341 }
342
343 protected void encodePopupCalendarButton(FacesContext facesContext, UIComponent uiComponent, ResponseWriter writer, String clientId, Locale currentLocale) throws IOException{
344
345 DateFormatSymbols symbols = new DateFormatSymbols(currentLocale);
346
347 HtmlCalendarRenderer.addScriptAndCSSResources(facesContext,uiComponent);
348
349 String calendarVar = JavascriptUtils.getValidJavascriptName(
350 uiComponent.getClientId(facesContext)+"CalendarVar",false);
351 String dateFormat = CalendarDateTimeConverter.createJSPopupFormat(facesContext, null);
352
353 String localizedLanguageScript = HtmlCalendarRenderer.getLocalizedLanguageScript(facesContext,
354 symbols,Calendar.getInstance(currentLocale).getFirstDayOfWeek(),
355 uiComponent,calendarVar);
356
357 writer.startElement(HTML.SPAN_ELEM,uiComponent);
358 writer.writeAttribute(HTML.ID_ATTR,uiComponent.getClientId(facesContext)+"Span",
359 JSFAttr.ID_ATTR);
360 writer.endElement(HTML.SPAN_ELEM);
361
362 writer.startElement(HTML.SCRIPT_ELEM,uiComponent);
363 writer.writeAttribute(HTML.SCRIPT_TYPE_ATTR,HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT,null);
364
365 writer.writeText("var "+calendarVar+"=new org_apache_myfaces_PopupCalendar();\n",null);
366 writer.write(localizedLanguageScript);
367 writer.writeText(calendarVar+".init(document.getElementById('"+
368 uiComponent.getClientId(facesContext)+"Span"+"'));\n",null);
369
370
371 writer.endElement(HTML.SCRIPT_ELEM);
372 HtmlCalendarRenderer.getScriptBtn(writer, facesContext, uiComponent,
373 dateFormat,"...",new FunctionCallProvider(){
374 public String getFunctionCall(FacesContext facesContext, UIComponent uiComponent, String dateFormat)
375 {
376 String clientId = uiComponent.getClientId(facesContext);
377
378 String clientVar = JavascriptUtils.getValidJavascriptName(clientId+"CalendarVar",true);
379
380 return clientVar+"._popUpCalendarForInputDate('"+clientId+"','"+dateFormat+"');";
381
382 }
383 });
384 }
385
386 public void decode(FacesContext facesContext, UIComponent uiComponent) {
387 RendererUtils.checkParamValidity(facesContext, uiComponent, HtmlInputDate.class);
388
389 HtmlInputDate inputDate = (HtmlInputDate) uiComponent;
390
391 if( isDisabled(facesContext, inputDate) )
392 return;
393
394 if (null != inputDate.getConverter())
395 {
396
397
398
399
400 String clientId = inputDate.getClientId(facesContext);
401 String type = inputDate.getType();
402 Map requestMap = facesContext.getExternalContext().getRequestParameterMap();
403 StringBuffer submittedValue = new StringBuffer();
404 if( ! (type.equals( "time" ) || type.equals( "short_time" )) )
405 {
406 submittedValue.append("year=");
407 submittedValue.append((String) requestMap.get(clientId + ID_YEAR_POSTFIX) );
408 submittedValue.append("\n");
409
410 submittedValue.append("month=");
411 submittedValue.append((String) requestMap.get(clientId + ID_MONTH_POSTFIX));
412 submittedValue.append("\n");
413
414 submittedValue.append("day=");
415 submittedValue.append((String) requestMap.get(getClientIdForDaySubcomponent(clientId)) );
416 submittedValue.append("\n");
417 }
418
419 if( ! type.equals( "date" ) )
420 {
421 submittedValue.append("hours=");
422 submittedValue.append((String) requestMap.get(clientId + ID_HOURS_POSTFIX) );
423 submittedValue.append("\n");
424
425 submittedValue.append("minutes=");
426 submittedValue.append((String) requestMap.get(clientId + ID_MINUTES_POSTFIX) );
427 submittedValue.append("\n");
428
429 if (type.equals("full") || type.equals("time"))
430 {
431 submittedValue.append("seconds=");
432 submittedValue.append((String) requestMap.get(clientId + ID_SECONDS_POSTFIX) );
433 submittedValue.append("\n");
434 }
435
436 if (inputDate.isAmpm())
437 {
438 submittedValue.append("ampm=");
439 submittedValue.append((String) requestMap.get(clientId + ID_AMPM_POSTFIX) );
440 submittedValue.append("\n");
441 }
442 }
443 if (submittedValue.charAt(submittedValue.length()-1) == '\n' )
444 {
445 submittedValue.deleteCharAt(submittedValue.length()-1);
446 }
447
448 inputDate.setSubmittedValue( submittedValue.toString() );
449 }
450 else
451 {
452
453 Locale currentLocale = facesContext.getViewRoot().getLocale();
454 UserData userData = (UserData) inputDate.getSubmittedValue();
455 if( userData == null )
456 userData = inputDate.getUserData(currentLocale);
457
458 String clientId = inputDate.getClientId(facesContext);
459 String type = inputDate.getType();
460 Map requestMap = facesContext.getExternalContext().getRequestParameterMap();
461
462 if( ! (type.equals( "time" ) || type.equals( "short_time" )) ){
463 userData.setDay( (String) requestMap.get(getClientIdForDaySubcomponent(clientId)) );
464 userData.setMonth( (String) requestMap.get(clientId + ID_MONTH_POSTFIX) );
465 userData.setYear( (String) requestMap.get(clientId + ID_YEAR_POSTFIX) );
466 }
467
468 if( ! type.equals( "date" ) ){
469 userData.setHours( (String) requestMap.get(clientId + ID_HOURS_POSTFIX) );
470 userData.setMinutes( (String) requestMap.get(clientId + ID_MINUTES_POSTFIX) );
471 if (type.equals("full") || type.equals("time"))
472 userData.setSeconds( (String) requestMap.get(clientId + ID_SECONDS_POSTFIX) );
473
474 if (inputDate.isAmpm()) {
475 userData.setAmpm( (String) requestMap.get(clientId + ID_AMPM_POSTFIX) );
476 }
477 }
478 inputDate.setSubmittedValue( userData );
479 }
480 }
481
482 private DateBusinessConverter getDateBusinessConverter(AbstractHtmlInputDate component)
483 {
484 DateBusinessConverter dateBusinessConverter = component.getDateBusinessConverter();
485 if (dateBusinessConverter == null)
486 {
487 dateBusinessConverter = new DefaultDateBusinessConverter();
488 }
489 return dateBusinessConverter;
490 }
491
492 public Object getConvertedValue(FacesContext context, UIComponent uiComponent, Object submittedValue) throws ConverterException {
493
494 HtmlInputDate inputDate = (HtmlInputDate) uiComponent;
495
496 if (inputDate.getConverter() == null)
497 {
498 UserData userData = (UserData) submittedValue;
499 Date date = null;
500 try {
501 date = userData.parse();
502 } catch (ParseException e) {
503 Object[] args = {uiComponent.getId()};
504 throw new ConverterException(MessageUtils.getMessage(Constants.TOMAHAWK_DEFAULT_BUNDLE, FacesMessage.SEVERITY_ERROR, DATE_MESSAGE_ID, args, context));
505 }
506
507 return getDateBusinessConverter(inputDate).getBusinessValue(context, inputDate, date);
508 }
509 else
510 {
511 if (submittedValue != null && !(submittedValue instanceof String))
512 {
513 if (RendererUtils.NOTHING.equals(submittedValue))
514 {
515 return null;
516 }
517 throw new IllegalArgumentException("Submitted value of type String for component : "
518 + RendererUtils.getPathToComponent(inputDate) + "expected");
519 }
520
521 return inputDate.getConverter().getAsObject(context, inputDate, (String) submittedValue);
522 }
523 }
524 }