1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.custom.calendar;
20
21 import org.apache.commons.lang.StringEscapeUtils;
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.apache.myfaces.component.UserRoleUtils;
25 import org.apache.myfaces.custom.inputTextHelp.HtmlInputTextHelp;
26 import org.apache.myfaces.custom.prototype.PrototypeResourceLoader;
27 import org.apache.myfaces.dateformat.SimpleDateFormatter;
28 import org.apache.myfaces.renderkit.html.util.AddResource;
29 import org.apache.myfaces.renderkit.html.util.AddResourceFactory;
30 import org.apache.myfaces.shared_tomahawk.renderkit.JSFAttr;
31 import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
32 import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
33 import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRenderer;
34 import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils;
35 import org.apache.myfaces.shared_tomahawk.renderkit.html.util.JavascriptUtils;
36 import org.apache.myfaces.shared_tomahawk.util.MessageUtils;
37 import org.apache.myfaces.tomahawk.util.Constants;
38
39 import javax.faces.application.Application;
40 import javax.faces.application.FacesMessage;
41 import javax.faces.component.EditableValueHolder;
42 import javax.faces.component.UIComponent;
43 import javax.faces.component.UIInput;
44 import javax.faces.component.UIParameter;
45 import javax.faces.component.html.HtmlCommandLink;
46 import javax.faces.component.html.HtmlOutputText;
47 import javax.faces.context.FacesContext;
48 import javax.faces.context.ResponseWriter;
49 import javax.faces.convert.Converter;
50 import javax.faces.convert.ConverterException;
51 import javax.faces.convert.DateTimeConverter;
52 import java.io.IOException;
53 import java.text.DateFormat;
54 import java.text.DateFormatSymbols;
55 import java.text.ParseException;
56 import java.text.SimpleDateFormat;
57 import java.util.*;
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102 public class HtmlCalendarRenderer
103 extends HtmlRenderer
104 {
105 private final Log log = LogFactory.getLog(HtmlCalendarRenderer.class);
106
107 private static final String JAVASCRIPT_ENCODED = "org.apache.myfaces.calendar.JAVASCRIPT_ENCODED";
108
109
110 private static final String RESOURCE_NONE = "none";
111
112 public void encodeEnd(FacesContext facesContext, UIComponent component)
113 throws IOException
114 {
115 RendererUtils.checkParamValidity(facesContext, component, HtmlInputCalendar.class);
116
117 HtmlInputCalendar inputCalendar = (HtmlInputCalendar) component;
118
119 Locale currentLocale = facesContext.getViewRoot().getLocale();
120 log.debug("current locale:" + currentLocale.toString());
121
122 String textValue;
123
124 Converter converter = inputCalendar.getConverter();
125 Object submittedValue = inputCalendar.getSubmittedValue();
126
127 Date value;
128
129 if (submittedValue != null)
130 {
131
132 textValue = (String) submittedValue;
133
134 if(textValue ==null || textValue.trim().length()==0 || textValue.equals(getHelperString(inputCalendar)))
135 {
136 value = null;
137 }
138 else
139 {
140 try
141 {
142 String formatStr = CalendarDateTimeConverter.createJSPopupFormat(facesContext, inputCalendar.getPopupDateFormat());
143 Calendar timeKeeper = Calendar.getInstance(currentLocale);
144 int firstDayOfWeek = timeKeeper.getFirstDayOfWeek() - 1;
145 org.apache.myfaces.dateformat.DateFormatSymbols symbols = new org.apache.myfaces.dateformat.DateFormatSymbols(currentLocale);
146
147 SimpleDateFormatter dateFormat = new SimpleDateFormatter(formatStr, symbols, firstDayOfWeek);
148 value = dateFormat.parse(textValue);
149 }
150 catch (IllegalArgumentException illegalArgumentException)
151 {
152 value = null;
153 }
154 }
155 }
156 else
157 {
158 if (converter == null)
159 {
160 CalendarDateTimeConverter defaultConverter = new CalendarDateTimeConverter();
161
162 value = (Date) getDateBusinessConverter(inputCalendar).getDateValue(facesContext, component, inputCalendar.getValue());
163
164 textValue = defaultConverter.getAsString(facesContext, inputCalendar, value);
165 }
166 else
167 {
168 Object componentValue = null;
169 boolean usedComponentValue = false;
170
171 if(converter instanceof DateConverter)
172 {
173 value = ((DateConverter) converter).getAsDate(facesContext, inputCalendar);
174 }
175 else
176 {
177 componentValue = inputCalendar.getValue();
178 if (componentValue instanceof Date)
179 {
180 value = (Date) componentValue;
181 }
182 else
183 {
184 usedComponentValue = true;
185 value = null;
186 }
187 }
188 textValue = converter.getAsString(facesContext, inputCalendar, usedComponentValue ? componentValue : value);
189 }
190 }
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237 Calendar timeKeeper = Calendar.getInstance(currentLocale);
238 timeKeeper.setTime(value!=null?value:new Date());
239
240 DateFormatSymbols symbols = new DateFormatSymbols(currentLocale);
241
242 if(inputCalendar.isRenderAsPopup())
243 {
244 renderPopup(facesContext, inputCalendar, textValue, timeKeeper, symbols);
245 }
246 else
247 {
248 renderInline(facesContext, inputCalendar, timeKeeper, symbols);
249 }
250
251 component.getChildren().removeAll(component.getChildren());
252 }
253
254 private void renderPopup(
255 FacesContext facesContext,
256 HtmlInputCalendar inputCalendar,
257 String value,
258 Calendar timeKeeper,
259 DateFormatSymbols symbols) throws IOException
260 {
261 if(inputCalendar.isAddResources())
262 addScriptAndCSSResources(facesContext, inputCalendar);
263
264
265 UIInput uiInput = (UIInput) inputCalendar;
266 Converter converter = uiInput.getConverter();
267 String dateFormat = null;
268 if (converter != null && converter instanceof DateTimeConverter) {
269 dateFormat = ((DateTimeConverter) converter).getPattern();
270 }
271 if (dateFormat == null) {
272 dateFormat = CalendarDateTimeConverter.createJSPopupFormat(facesContext,
273 inputCalendar.getPopupDateFormat());
274 }
275
276 Application application = facesContext.getApplication();
277
278 HtmlInputTextHelp inputText = getOrCreateInputTextChild(inputCalendar, application);
279
280 RendererUtils.copyHtmlInputTextAttributes(inputCalendar, inputText);
281
282 inputText.setConverter(null);
283 inputText.setTransient(true);
284 inputText.setHelpText(inputCalendar.getHelpText());
285 inputText.setSelectText(true);
286
287 inputText.setValue(value);
288
289
290
291
292
293
294
295
296
297
298 inputText.setDisabled(inputCalendar.isDisabled());
299 inputText.setReadonly(inputCalendar.isReadonly());
300 inputText.setEnabledOnUserRole(inputCalendar.getEnabledOnUserRole());
301 inputText.setVisibleOnUserRole(inputCalendar.getVisibleOnUserRole());
302
303
304
305
306 inputCalendar.setId(inputCalendar.getId()+"tempId");
307
308 inputCalendar.getChildren().add(inputText);
309
310 RendererUtils.renderChild(facesContext, inputText);
311
312 inputCalendar.getChildren().remove(inputText);
313
314
315 inputCalendar.setId(inputText.getId());
316
317 ResponseWriter writer = facesContext.getResponseWriter();
318
319 writer.startElement(HTML.SPAN_ELEM,inputCalendar);
320 writer.writeAttribute(HTML.ID_ATTR,inputCalendar.getClientId(facesContext)+"Span",
321 JSFAttr.ID_ATTR);
322 writer.endElement(HTML.SPAN_ELEM);
323
324 if (!isDisabled(facesContext, inputCalendar) && !inputCalendar.isReadonly())
325 {
326 writer.startElement(HTML.SCRIPT_ELEM, inputCalendar);
327 writer.writeAttribute(HTML.SCRIPT_TYPE_ATTR,HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT,null);
328
329 String calendarVar = JavascriptUtils.getValidJavascriptName(
330 inputCalendar.getClientId(facesContext)+"CalendarVar",false);
331
332 writer.writeText(calendarVar+"=new org_apache_myfaces_PopupCalendar();\n",null);
333 writer.writeText(getLocalizedLanguageScript(facesContext,symbols,
334 timeKeeper.getFirstDayOfWeek(),inputCalendar,calendarVar)+"\n",null);
335
336 StringBuffer script = new StringBuffer();
337 setStringVariable(script, calendarVar +".initData.selectMode",inputCalendar.getPopupSelectMode());
338 writer.writeText(script.toString(), null);
339
340 writer.writeText(calendarVar+".init(document.getElementById('"+
341 inputCalendar.getClientId(facesContext)+"Span"+"'));\n",null);
342 writer.endElement(HTML.SCRIPT_ELEM);
343 if(!inputCalendar.isDisplayValueOnly())
344 {
345 getScriptBtn(writer, facesContext, inputCalendar,
346 dateFormat,inputCalendar.getPopupButtonString(), new FunctionCallProvider(){
347 public String getFunctionCall(FacesContext facesContext, UIComponent uiComponent, String dateFormat)
348 {
349 String clientId = uiComponent.getClientId(facesContext);
350
351 String clientVar = JavascriptUtils.getValidJavascriptName(clientId+"CalendarVar",true);
352
353 return clientVar+"._popUpCalendar(this,document.getElementById('"+clientId+"'),'"+dateFormat+"')";
354 }
355 });
356 }
357 }
358 }
359
360 private void renderInline(
361 FacesContext facesContext,
362 HtmlInputCalendar inputCalendar,
363 Calendar timeKeeper,
364 DateFormatSymbols symbols) throws IOException
365 {
366 String[] weekdays = mapShortWeekdays(symbols);
367 String[] months = mapMonths(symbols);
368
369 int lastDayInMonth = timeKeeper.getActualMaximum(Calendar.DAY_OF_MONTH);
370
371 int currentDay = timeKeeper.get(Calendar.DAY_OF_MONTH);
372
373 if (currentDay > lastDayInMonth)
374 currentDay = lastDayInMonth;
375
376 timeKeeper.set(Calendar.DAY_OF_MONTH, 1);
377
378 int weekDayOfFirstDayOfMonth = mapCalendarDayToCommonDay(timeKeeper.get(Calendar.DAY_OF_WEEK));
379
380 int weekStartsAtDayIndex = mapCalendarDayToCommonDay(timeKeeper.getFirstDayOfWeek());
381
382 ResponseWriter writer = facesContext.getResponseWriter();
383
384 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
385 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
386
387 writer.startElement(HTML.TABLE_ELEM, inputCalendar);
388 HtmlRendererUtils.renderHTMLAttributes(writer, inputCalendar, HTML.UNIVERSAL_ATTRIBUTES);
389 HtmlRendererUtils.renderHTMLAttributes(writer, inputCalendar, HTML.EVENT_HANDLER_ATTRIBUTES);
390 HtmlRendererUtils.renderHTMLAttributes(writer, inputCalendar, HTML.COMMON_FIELD_EVENT_ATTRIBUTES_WITHOUT_ONSELECT_AND_ONCHANGE);
391 writer.flush();
392
393 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
394
395 writer.startElement(HTML.TR_ELEM, inputCalendar);
396
397 if(inputCalendar.getMonthYearRowClass() != null)
398 writer.writeAttribute(HTML.CLASS_ATTR, inputCalendar.getMonthYearRowClass(), null);
399
400 writeMonthYearHeader(facesContext, writer, inputCalendar, timeKeeper,
401 currentDay, weekdays, months);
402
403 writer.endElement(HTML.TR_ELEM);
404
405 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
406
407 writer.startElement(HTML.TR_ELEM, inputCalendar);
408
409 if(inputCalendar.getWeekRowClass() != null)
410 writer.writeAttribute(HTML.CLASS_ATTR, inputCalendar.getWeekRowClass(), null);
411
412 writeWeekDayNameHeader(weekStartsAtDayIndex, weekdays,
413 facesContext, writer, inputCalendar);
414
415 writer.endElement(HTML.TR_ELEM);
416
417 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
418
419 writeDays(facesContext, writer, inputCalendar, timeKeeper,
420 currentDay, weekStartsAtDayIndex, weekDayOfFirstDayOfMonth,
421 lastDayInMonth, weekdays);
422
423 writer.endElement(HTML.TABLE_ELEM);
424 }
425
426 private HtmlInputTextHelp getOrCreateInputTextChild(HtmlInputCalendar inputCalendar, Application application)
427 {
428 HtmlInputTextHelp inputText = null;
429
430 List li = inputCalendar.getChildren();
431
432 for (int i = 0; i < li.size(); i++)
433 {
434 UIComponent uiComponent = (UIComponent) li.get(i);
435
436 if(uiComponent instanceof HtmlInputTextHelp)
437 {
438 inputText = (HtmlInputTextHelp) uiComponent;
439 break;
440 }
441 }
442
443 if(inputText == null)
444 {
445 inputText = (HtmlInputTextHelp) application.createComponent(HtmlInputTextHelp.COMPONENT_TYPE);
446 }
447 return inputText;
448 }
449
450
451
452
453 static public void addScriptAndCSSResources(FacesContext facesContext, UIComponent component){
454
455
456
457
458
459 if (facesContext.getExternalContext().getRequestMap().containsKey(JAVASCRIPT_ENCODED))
460 {
461 return;
462 }
463
464 AddResource addresource = AddResourceFactory.getInstance(facesContext);
465
466
467 String styleLocation = HtmlRendererUtils.getStyleLocation(component);
468
469 if(styleLocation==null)
470 {
471 addresource.addStyleSheet(facesContext, AddResource.HEADER_BEGIN, HtmlCalendarRenderer.class, "WH/theme.css");
472 addresource.addStyleSheet(facesContext, AddResource.HEADER_BEGIN, HtmlCalendarRenderer.class, "DB/theme.css");
473 }
474 else if (!RESOURCE_NONE.equals(styleLocation))
475 {
476 addresource.addStyleSheet(facesContext, AddResource.HEADER_BEGIN, styleLocation+"/theme.css");
477 }
478 else
479 {
480
481 }
482
483 String javascriptLocation = HtmlRendererUtils.getJavascriptLocation(component);
484
485 if(javascriptLocation==null)
486 {
487 addresource.addJavaScriptAtPosition(facesContext, AddResource.HEADER_BEGIN, PrototypeResourceLoader.class, "prototype.js");
488 addresource.addJavaScriptAtPosition(facesContext, AddResource.HEADER_BEGIN, HtmlCalendarRenderer.class, "date.js");
489 addresource.addJavaScriptAtPosition(facesContext, AddResource.HEADER_BEGIN, HtmlCalendarRenderer.class, "popcalendar.js");
490 }
491 else if (!RESOURCE_NONE.equals(javascriptLocation))
492 {
493 addresource.addJavaScriptAtPosition(facesContext, AddResource.HEADER_BEGIN, javascriptLocation+ "/prototype.js");
494 addresource.addJavaScriptAtPosition(facesContext, AddResource.HEADER_BEGIN, javascriptLocation+ "/date.js");
495 addresource.addJavaScriptAtPosition(facesContext, AddResource.HEADER_BEGIN, javascriptLocation+ "/popcalendar.js");
496 }
497 else
498 {
499
500 }
501
502 facesContext.getExternalContext().getRequestMap().put(JAVASCRIPT_ENCODED, Boolean.TRUE);
503 }
504
505
506
507
508
509
510
511
512
513
514
515
516 public static String getLocalizedLanguageScript(FacesContext facesContext,
517 DateFormatSymbols symbols, int firstDayOfWeek, UIComponent uiComponent,
518 String popupCalendarVariable)
519 {
520
521
522
523 int realFirstDayOfWeek = firstDayOfWeek - 1;
524
525 String[] weekDays;
526
527 if (realFirstDayOfWeek == 0)
528 {
529
530 weekDays = mapShortWeekdaysStartingWithSunday(symbols);
531 }
532 else if (realFirstDayOfWeek == 1)
533 {
534
535 weekDays = mapShortWeekdays(symbols);
536 }
537 else if (realFirstDayOfWeek == 6)
538 {
539
540 weekDays = mapShortWeekdaysStartingWithSaturday(symbols);
541 }
542 else
543 {
544 throw new IllegalStateException("Week may only start with saturday, sunday or monday.");
545 }
546
547 StringBuffer script = new StringBuffer();
548 AddResource ar = AddResourceFactory.getInstance(facesContext);
549
550 if (uiComponent instanceof HtmlInputCalendar)
551 {
552 HtmlInputCalendar calendar = (HtmlInputCalendar) uiComponent;
553
554 String popupTheme = calendar.getPopupTheme();
555 if (popupTheme == null)
556 {
557 popupTheme = "DB";
558 }
559 setStringVariable(script, popupCalendarVariable + ".initData.themePrefix",
560 "jscalendar-" + popupTheme);
561
562
563
564 String imageLocation = HtmlRendererUtils.getImageLocation(uiComponent);
565 if (imageLocation == null)
566 {
567 String uri = ar.getResourceUri(facesContext, HtmlCalendarRenderer.class, popupTheme
568 + "/");
569 setStringVariable(script, popupCalendarVariable + ".initData.imgDir",
570 JavascriptUtils.encodeString(uri));
571 }
572 else
573 {
574 setStringVariable(script, popupCalendarVariable + ".initData.imgDir",
575 (JavascriptUtils.encodeString(AddResourceFactory.getInstance(facesContext)
576 .getResourceUri(facesContext, imageLocation + "/"))));
577 }
578 }
579 else
580 {
581 String imageLocation = HtmlRendererUtils.getImageLocation(uiComponent);
582 if (imageLocation == null)
583 {
584 String uri = ar.getResourceUri(facesContext, HtmlCalendarRenderer.class, "images/");
585 setStringVariable(script, popupCalendarVariable + ".initData.imgDir",
586 JavascriptUtils.encodeString(uri));
587 }
588 else
589 {
590 setStringVariable(script, popupCalendarVariable + ".initData.imgDir",
591 (JavascriptUtils.encodeString(AddResourceFactory.getInstance(facesContext)
592 .getResourceUri(facesContext, imageLocation + "/"))));
593 }
594 }
595 defineStringArray(script, popupCalendarVariable + ".initData.monthName", mapMonths(symbols));
596 defineStringArray(script, popupCalendarVariable + ".initData.dayName", weekDays);
597 setIntegerVariable(script, popupCalendarVariable + ".initData.startAt", realFirstDayOfWeek);
598
599 defineStringArray(script, popupCalendarVariable + ".dateFormatSymbols.weekdays",
600 mapWeekdaysStartingWithSunday(symbols));
601 defineStringArray(script, popupCalendarVariable + ".dateFormatSymbols.shortWeekdays",
602 mapShortWeekdaysStartingWithSunday(symbols));
603 defineStringArray(script, popupCalendarVariable + ".dateFormatSymbols.shortMonths",
604 mapShortMonths(symbols));
605 defineStringArray(script, popupCalendarVariable + ".dateFormatSymbols.months",
606 mapMonths(symbols));
607 defineStringArray(script, popupCalendarVariable + ".dateFormatSymbols.eras", symbols
608 .getEras());
609 defineStringArray(script, popupCalendarVariable + ".dateFormatSymbols.ampms", symbols
610 .getAmPmStrings());
611
612 if (uiComponent instanceof HtmlInputCalendar)
613 {
614
615 HtmlInputCalendar inputCalendar = (HtmlInputCalendar) uiComponent;
616
617 if (inputCalendar.getPopupGotoString() != null)
618 setStringVariable(script, popupCalendarVariable + ".initData.gotoString",
619 inputCalendar.getPopupGotoString());
620 if (inputCalendar.getPopupTodayString() != null)
621 setStringVariable(script, popupCalendarVariable + ".initData.todayString",
622 inputCalendar.getPopupTodayString());
623 if (inputCalendar.getPopupTodayDateFormat() != null)
624 setStringVariable(script, popupCalendarVariable + ".initData.todayDateFormat",
625 inputCalendar.getPopupTodayDateFormat());
626 else if (inputCalendar.getPopupDateFormat() != null)
627 setStringVariable(script, popupCalendarVariable + ".initData.todayDateFormat",
628 inputCalendar.getPopupDateFormat());
629 if (inputCalendar.getPopupWeekString() != null)
630 setStringVariable(script, popupCalendarVariable + ".initData.weekString",
631 inputCalendar.getPopupWeekString());
632 if (inputCalendar.getPopupScrollLeftMessage() != null)
633 setStringVariable(script, popupCalendarVariable + ".initData.scrollLeftMessage",
634 inputCalendar.getPopupScrollLeftMessage());
635 if (inputCalendar.getPopupScrollRightMessage() != null)
636 setStringVariable(script, popupCalendarVariable + ".initData.scrollRightMessage",
637 inputCalendar.getPopupScrollRightMessage());
638 if (inputCalendar.getPopupSelectMonthMessage() != null)
639 setStringVariable(script, popupCalendarVariable + ".initData.selectMonthMessage",
640 inputCalendar.getPopupSelectMonthMessage());
641 if (inputCalendar.getPopupSelectYearMessage() != null)
642 setStringVariable(script, popupCalendarVariable + ".initData.selectYearMessage",
643 inputCalendar.getPopupSelectYearMessage());
644 if (inputCalendar.getPopupSelectDateMessage() != null)
645 setStringVariable(script, popupCalendarVariable + ".initData.selectDateMessage",
646 inputCalendar.getPopupSelectDateMessage());
647 setBooleanVariable(script, popupCalendarVariable + ".initData.popupLeft", inputCalendar
648 .isPopupLeft());
649
650 }
651
652 return script.toString();
653 }
654
655 private static void setBooleanVariable(StringBuffer script, String name, boolean value)
656 {
657 script.append(name);
658 script.append(" = ");
659 script.append(value);
660 script.append(";\n");
661 }
662
663 private static void setIntegerVariable(StringBuffer script, String name, int value)
664 {
665 script.append(name);
666 script.append(" = ");
667 script.append(value);
668 script.append(";\n");
669 }
670
671 private static void setStringVariable(StringBuffer script, String name, String value)
672 {
673 script.append(name);
674 script.append(" = \"");
675 script.append(StringEscapeUtils.escapeJavaScript(value));
676 script.append("\";\n");
677 }
678
679 private static void defineStringArray(StringBuffer script, String arrayName, String[] array)
680 {
681 script.append(arrayName);
682 script.append(" = new Array(");
683
684 for(int i=0;i<array.length;i++)
685 {
686 if(i!=0)
687 script.append(",");
688
689 script.append("\"");
690 script.append(StringEscapeUtils.escapeJavaScript(array[i]));
691 script.append("\"");
692 }
693
694 script.append(");\n");
695 }
696
697 public static void getScriptBtn(ResponseWriter writer, FacesContext facesContext, UIComponent uiComponent,
698 String dateFormat, String popupButtonString, FunctionCallProvider prov)
699 throws IOException
700 {
701 boolean renderButtonAsImage = false;
702 String popupButtonStyle = null;
703 String popupButtonStyleClass = null;
704
705 if(uiComponent instanceof HtmlInputCalendar)
706 {
707 HtmlInputCalendar calendar = (HtmlInputCalendar)uiComponent;
708 renderButtonAsImage = calendar.isRenderPopupButtonAsImage();
709 popupButtonStyle = calendar.getPopupButtonStyle();
710 popupButtonStyleClass = calendar.getPopupButtonStyleClass();
711 }
712
713 if (!renderButtonAsImage) {
714
715 writer.startElement(HTML.INPUT_ELEM, uiComponent);
716 writer.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_BUTTON, null);
717
718 writer.writeAttribute(HTML.ONCLICK_ATTR,
719 prov.getFunctionCall(facesContext,uiComponent,dateFormat),
720 null);
721
722 if(popupButtonString==null)
723 popupButtonString="...";
724 writer.writeAttribute(HTML.VALUE_ATTR, StringEscapeUtils.escapeJavaScript(popupButtonString), null);
725
726 if(popupButtonStyle != null)
727 {
728 writer.writeAttribute(HTML.STYLE_ATTR, popupButtonStyle, null);
729 }
730
731 if(popupButtonStyleClass != null)
732 {
733 writer.writeAttribute(HTML.CLASS_ATTR, popupButtonStyleClass, null);
734 }
735
736 writer.endElement(HTML.INPUT_ELEM);
737 } else {
738
739 writer.startElement(HTML.IMG_ELEM, uiComponent);
740 AddResource addResource = AddResourceFactory.getInstance(facesContext);
741
742 String imgUrl = (String) uiComponent.getAttributes().get("popupButtonImageUrl");
743
744 if(imgUrl!=null)
745 {
746 writer.writeAttribute(HTML.SRC_ATTR, addResource.getResourceUri(facesContext, imgUrl), null);
747 }
748 else
749 {
750 writer.writeAttribute(HTML.SRC_ATTR, addResource.getResourceUri(facesContext, HtmlCalendarRenderer.class, "images/calendar.gif"), null);
751 }
752
753 if(popupButtonStyle != null)
754 {
755 writer.writeAttribute(HTML.STYLE_ATTR, popupButtonStyle, null);
756 }
757 else
758 {
759 writer.writeAttribute(HTML.STYLE_ATTR, "vertical-align:bottom;", null);
760 }
761
762 if(popupButtonStyleClass != null)
763 {
764 writer.writeAttribute(HTML.CLASS_ATTR, popupButtonStyleClass, null);
765 }
766
767 writer.writeAttribute(HTML.ONCLICK_ATTR, prov.getFunctionCall(facesContext, uiComponent, dateFormat),
768 null);
769
770 writer.endElement(HTML.IMG_ELEM);
771 }
772 }
773
774
775 private void writeMonthYearHeader(FacesContext facesContext, ResponseWriter writer, UIInput inputComponent, Calendar timeKeeper,
776 int currentDay, String[] weekdays,
777 String[] months)
778 throws IOException
779 {
780 Calendar cal = shiftMonth(facesContext, timeKeeper, currentDay, -1);
781
782 writeCell(facesContext, writer, inputComponent, "<", cal.getTime(), null);
783
784 writer.startElement(HTML.TD_ELEM, inputComponent);
785 writer.writeAttribute(HTML.COLSPAN_ATTR, new Integer(weekdays.length - 2), null);
786 writer.writeText(months[timeKeeper.get(Calendar.MONTH)] + " " + timeKeeper.get(Calendar.YEAR), null);
787 writer.endElement(HTML.TD_ELEM);
788
789 cal = shiftMonth(facesContext, timeKeeper, currentDay, 1);
790
791 writeCell(facesContext, writer, inputComponent, ">", cal.getTime(), null);
792 }
793
794 private Calendar shiftMonth(FacesContext facesContext,
795 Calendar timeKeeper, int currentDay, int shift)
796 {
797 Calendar cal = copyCalendar(facesContext, timeKeeper);
798
799 cal.set(Calendar.DAY_OF_MONTH, 1);
800 cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) + shift);
801
802 if(currentDay > cal.getActualMaximum(Calendar.DAY_OF_MONTH))
803 currentDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
804
805 cal.set(Calendar.DAY_OF_MONTH, currentDay);
806 return cal;
807 }
808
809 private Calendar copyCalendar(FacesContext facesContext, Calendar timeKeeper)
810 {
811 Calendar cal = Calendar.getInstance(facesContext.getViewRoot().getLocale());
812 cal.setTime(timeKeeper.getTime());
813 return cal;
814 }
815
816 private void writeWeekDayNameHeader(int weekStartsAtDayIndex, String[] weekdays, FacesContext facesContext, ResponseWriter writer, UIInput inputComponent)
817 throws IOException
818 {
819 for (int i = weekStartsAtDayIndex; i < weekdays.length; i++)
820 writeCell(facesContext,
821 writer, inputComponent, weekdays[i], null, null);
822
823 for (int i = 0; i < weekStartsAtDayIndex; i++)
824 writeCell(facesContext, writer,
825 inputComponent, weekdays[i], null, null);
826 }
827
828 private void writeDays(FacesContext facesContext, ResponseWriter writer,
829 HtmlInputCalendar inputComponent, Calendar timeKeeper, int currentDay, int weekStartsAtDayIndex,
830 int weekDayOfFirstDayOfMonth, int lastDayInMonth, String[] weekdays)
831 throws IOException
832 {
833 Calendar cal;
834
835 int space = (weekStartsAtDayIndex < weekDayOfFirstDayOfMonth) ? (weekDayOfFirstDayOfMonth - weekStartsAtDayIndex)
836 : (weekdays.length - weekStartsAtDayIndex + weekDayOfFirstDayOfMonth);
837
838 if (space == weekdays.length)
839 space = 0;
840
841 int columnIndexCounter = 0;
842
843 for (int i = 0; i < space; i++)
844 {
845 if (columnIndexCounter == 0)
846 {
847 writer.startElement(HTML.TR_ELEM, inputComponent);
848 }
849
850 writeCell(facesContext, writer, inputComponent, "",
851 null, inputComponent.getDayCellClass());
852 columnIndexCounter++;
853 }
854
855 for (int i = 0; i < lastDayInMonth; i++)
856 {
857 if (columnIndexCounter == 0)
858 {
859 writer.startElement(HTML.TR_ELEM, inputComponent);
860 }
861
862 cal = copyCalendar(facesContext, timeKeeper);
863 cal.set(Calendar.DAY_OF_MONTH, i + 1);
864
865 String cellStyle = inputComponent.getDayCellClass();
866
867 if((currentDay - 1) == i)
868 cellStyle = inputComponent.getCurrentDayCellClass();
869
870 writeCell(facesContext, writer,
871 inputComponent, String.valueOf(i + 1), cal.getTime(),
872 cellStyle);
873
874 columnIndexCounter++;
875
876 if (columnIndexCounter == weekdays.length)
877 {
878 writer.endElement(HTML.TR_ELEM);
879 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
880 columnIndexCounter = 0;
881 }
882 }
883
884 if (columnIndexCounter != 0)
885 {
886 for (int i = columnIndexCounter; i < weekdays.length; i++)
887 {
888 writeCell(facesContext, writer,
889 inputComponent, "", null, inputComponent.getDayCellClass());
890 }
891
892 writer.endElement(HTML.TR_ELEM);
893 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
894 }
895 }
896
897
898
899
900 private void writeCell(FacesContext facesContext,
901 ResponseWriter writer, UIInput component, String content,
902 Date valueForLink, String styleClass)
903 throws IOException
904 {
905 writer.startElement(HTML.TD_ELEM, component);
906
907 if (styleClass != null)
908 writer.writeAttribute(HTML.CLASS_ATTR, styleClass, null);
909
910 if (valueForLink == null)
911 writer.writeText(content, JSFAttr.VALUE_ATTR);
912 else
913 {
914 writeLink(content, component, facesContext, valueForLink);
915 }
916
917 writer.endElement(HTML.TD_ELEM);
918 }
919
920
921
922
923
924
925
926
927
928
929
930 private void writeLink(String content,
931 UIInput component,
932 FacesContext facesContext,
933 Date valueForLink)
934 throws IOException
935 {
936 Converter converter = getConverter(component);
937 Application application = facesContext.getApplication();
938
939 HtmlOutputText text
940 = (HtmlOutputText)application.createComponent(HtmlOutputText.COMPONENT_TYPE);
941 text.setValue(content);
942 text.setId(component.getId() + "_" + valueForLink.getTime() + "_text");
943 text.setTransient(true);
944
945 HtmlInputCalendar calendar = (HtmlInputCalendar)component;
946 if (isDisabled(facesContext, component) || calendar.isReadonly())
947 {
948 component.getChildren().add(text);
949
950 RendererUtils.renderChild(facesContext, text);
951 return;
952 }
953
954 HtmlCommandLink link
955 = (HtmlCommandLink)application.createComponent(HtmlCommandLink.COMPONENT_TYPE);
956 link.setId(component.getId() + "_" + valueForLink.getTime() + "_link");
957 link.setTransient(true);
958 link.setImmediate(component.isImmediate());
959
960 UIParameter parameter
961 = (UIParameter)application.createComponent(UIParameter.COMPONENT_TYPE);
962 parameter.setId(component.getId() + "_" + valueForLink.getTime() + "_param");
963 parameter.setTransient(true);
964 parameter.setName(component.getClientId(facesContext));
965 parameter.setValue(converter.getAsString(facesContext, component, valueForLink));
966
967 RendererUtils.addOrReplaceChild(component,link);
968 link.getChildren().add(parameter);
969 link.getChildren().add(text);
970
971 RendererUtils.renderChild(facesContext, link);
972 }
973
974 private Converter getConverter(UIInput component)
975 {
976 Converter converter = component.getConverter();
977
978 if (converter == null)
979 {
980 converter = new CalendarDateTimeConverter();
981 }
982 return converter;
983 }
984
985 private DateBusinessConverter getDateBusinessConverter(AbstractHtmlInputCalendar component)
986 {
987 DateBusinessConverter dateBusinessConverter = component.getDateBusinessConverter();
988 if (dateBusinessConverter == null)
989 {
990 dateBusinessConverter = new DefaultDateBusinessConverter();
991 }
992 return dateBusinessConverter;
993 }
994
995 private int mapCalendarDayToCommonDay(int day)
996 {
997 switch (day)
998 {
999 case Calendar.TUESDAY:
1000 return 1;
1001 case Calendar.WEDNESDAY:
1002 return 2;
1003 case Calendar.THURSDAY:
1004 return 3;
1005 case Calendar.FRIDAY:
1006 return 4;
1007 case Calendar.SATURDAY:
1008 return 5;
1009 case Calendar.SUNDAY:
1010 return 6;
1011 default:
1012 return 0;
1013 }
1014 }
1015
1016 private static String[] mapShortWeekdays(DateFormatSymbols symbols)
1017 {
1018 String[] weekdays = new String[7];
1019
1020 String[] localeWeekdays = symbols.getShortWeekdays();
1021
1022 weekdays[0] = localeWeekdays[Calendar.MONDAY];
1023 weekdays[1] = localeWeekdays[Calendar.TUESDAY];
1024 weekdays[2] = localeWeekdays[Calendar.WEDNESDAY];
1025 weekdays[3] = localeWeekdays[Calendar.THURSDAY];
1026 weekdays[4] = localeWeekdays[Calendar.FRIDAY];
1027 weekdays[5] = localeWeekdays[Calendar.SATURDAY];
1028 weekdays[6] = localeWeekdays[Calendar.SUNDAY];
1029
1030 return weekdays;
1031 }
1032
1033 private static String[] mapShortWeekdaysStartingWithSunday(DateFormatSymbols symbols)
1034 {
1035 String[] weekdays = new String[7];
1036
1037 String[] localeWeekdays = symbols.getShortWeekdays();
1038
1039 weekdays[0] = localeWeekdays[Calendar.SUNDAY];
1040 weekdays[1] = localeWeekdays[Calendar.MONDAY];
1041 weekdays[2] = localeWeekdays[Calendar.TUESDAY];
1042 weekdays[3] = localeWeekdays[Calendar.WEDNESDAY];
1043 weekdays[4] = localeWeekdays[Calendar.THURSDAY];
1044 weekdays[5] = localeWeekdays[Calendar.FRIDAY];
1045 weekdays[6] = localeWeekdays[Calendar.SATURDAY];
1046
1047 return weekdays;
1048 }
1049
1050
1051 private static String[] mapShortWeekdaysStartingWithSaturday(DateFormatSymbols symbols)
1052 {
1053 String[] weekdays = new String[7];
1054
1055 String[] localeWeekdays = symbols.getShortWeekdays();
1056
1057 weekdays[0] = localeWeekdays[Calendar.SATURDAY];
1058 weekdays[1] = localeWeekdays[Calendar.SUNDAY];
1059 weekdays[2] = localeWeekdays[Calendar.MONDAY];
1060 weekdays[3] = localeWeekdays[Calendar.TUESDAY];
1061 weekdays[4] = localeWeekdays[Calendar.WEDNESDAY];
1062 weekdays[5] = localeWeekdays[Calendar.THURSDAY];
1063 weekdays[6] = localeWeekdays[Calendar.FRIDAY];
1064
1065 return weekdays;
1066 }
1067
1068 private static String[] mapWeekdaysStartingWithSunday(DateFormatSymbols symbols)
1069 {
1070 String[] weekdays = new String[7];
1071
1072 String[] localeWeekdays = symbols.getWeekdays();
1073
1074 weekdays[0] = localeWeekdays[Calendar.SUNDAY];
1075 weekdays[1] = localeWeekdays[Calendar.MONDAY];
1076 weekdays[2] = localeWeekdays[Calendar.TUESDAY];
1077 weekdays[3] = localeWeekdays[Calendar.WEDNESDAY];
1078 weekdays[4] = localeWeekdays[Calendar.THURSDAY];
1079 weekdays[5] = localeWeekdays[Calendar.FRIDAY];
1080 weekdays[6] = localeWeekdays[Calendar.SATURDAY];
1081
1082 return weekdays;
1083 }
1084
1085 public static String[] mapMonths(DateFormatSymbols symbols)
1086 {
1087 String[] months = new String[12];
1088
1089 String[] localeMonths = symbols.getMonths();
1090
1091 months[0] = localeMonths[Calendar.JANUARY];
1092 months[1] = localeMonths[Calendar.FEBRUARY];
1093 months[2] = localeMonths[Calendar.MARCH];
1094 months[3] = localeMonths[Calendar.APRIL];
1095 months[4] = localeMonths[Calendar.MAY];
1096 months[5] = localeMonths[Calendar.JUNE];
1097 months[6] = localeMonths[Calendar.JULY];
1098 months[7] = localeMonths[Calendar.AUGUST];
1099 months[8] = localeMonths[Calendar.SEPTEMBER];
1100 months[9] = localeMonths[Calendar.OCTOBER];
1101 months[10] = localeMonths[Calendar.NOVEMBER];
1102 months[11] = localeMonths[Calendar.DECEMBER];
1103
1104 return months;
1105 }
1106
1107 public static String[] mapShortMonths(DateFormatSymbols symbols)
1108 {
1109 String[] months = new String[12];
1110
1111 String[] localeMonths = symbols.getShortMonths();
1112
1113 months[0] = localeMonths[Calendar.JANUARY];
1114 months[1] = localeMonths[Calendar.FEBRUARY];
1115 months[2] = localeMonths[Calendar.MARCH];
1116 months[3] = localeMonths[Calendar.APRIL];
1117 months[4] = localeMonths[Calendar.MAY];
1118 months[5] = localeMonths[Calendar.JUNE];
1119 months[6] = localeMonths[Calendar.JULY];
1120 months[7] = localeMonths[Calendar.AUGUST];
1121 months[8] = localeMonths[Calendar.SEPTEMBER];
1122 months[9] = localeMonths[Calendar.OCTOBER];
1123 months[10] = localeMonths[Calendar.NOVEMBER];
1124 months[11] = localeMonths[Calendar.DECEMBER];
1125
1126 return months;
1127 }
1128
1129
1130 public void decode(FacesContext facesContext, UIComponent component)
1131 {
1132 if(HtmlRendererUtils.isDisabledOrReadOnly(component))
1133 {
1134
1135 return;
1136 }
1137
1138 RendererUtils.checkParamValidity(facesContext, component, HtmlInputCalendar.class);
1139
1140
1141
1142 if (!(component instanceof EditableValueHolder)) {
1143 throw new IllegalArgumentException("Component "
1144 + component.getClientId(facesContext)
1145 + " is not an EditableValueHolder");
1146 }
1147 Map paramMap = facesContext.getExternalContext()
1148 .getRequestParameterMap();
1149 String clientId = component.getClientId(facesContext);
1150
1151 if(paramMap.containsKey(clientId))
1152 {
1153 String value = (String) paramMap.get(clientId);
1154
1155
1156
1157 ((EditableValueHolder) component).setSubmittedValue(value);
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169 }
1170 else
1171 {
1172 log.warn(HtmlRendererUtils.NON_SUBMITTED_VALUE_WARNING +
1173 " Component : "+
1174 RendererUtils.getPathToComponent(component));
1175 }
1176
1177 }
1178
1179 protected static boolean isDisabled(FacesContext facesContext, UIComponent uiComponent)
1180 {
1181 if (!UserRoleUtils.isEnabledOnUserRole(uiComponent))
1182 {
1183 return true;
1184 }
1185 else
1186 {
1187 if (uiComponent instanceof HtmlInputCalendar)
1188 {
1189 return ((HtmlInputCalendar)uiComponent).isDisabled();
1190 }
1191 else
1192 {
1193 return org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils.getBooleanAttribute(uiComponent, HTML.DISABLED_ATTR, false);
1194 }
1195 }
1196 }
1197
1198 public Object getConvertedValue(FacesContext facesContext, UIComponent uiComponent, Object submittedValue) throws ConverterException
1199 {
1200 RendererUtils.checkParamValidity(facesContext, uiComponent, HtmlInputCalendar.class);
1201
1202 AbstractHtmlInputCalendar uiInput = (AbstractHtmlInputCalendar) uiComponent;
1203
1204 Converter converter = uiInput.getConverter();
1205
1206 if (submittedValue != null && !(submittedValue instanceof String))
1207 {
1208 throw new IllegalArgumentException("Submitted value of type String expected");
1209 }
1210
1211
1212 if(submittedValue != null && submittedValue.equals(getHelperString(uiComponent)))
1213 return null;
1214
1215 if(converter==null)
1216 {
1217 converter = new CalendarDateTimeConverter();
1218
1219 Date date = (Date) converter.getAsObject(facesContext, uiComponent, (String) submittedValue);
1220
1221 return getDateBusinessConverter(uiInput).getBusinessValue(facesContext, uiComponent, date);
1222 }
1223 else
1224 {
1225 return converter.getAsObject(facesContext, uiComponent, (String) submittedValue);
1226 }
1227 }
1228
1229 public interface DateConverter extends Converter
1230 {
1231 public Date getAsDate(FacesContext facesContext, UIComponent uiComponent);
1232 }
1233
1234 private static String getHelperString(UIComponent uiComponent)
1235 {
1236 return uiComponent instanceof HtmlInputCalendar?((HtmlInputCalendar) uiComponent).getHelpText():null;
1237 }
1238
1239 public static class CalendarDateTimeConverter implements DateConverter
1240 {
1241 private static final String CONVERSION_MESSAGE_ID = "org.apache.myfaces.calendar.CONVERSION";
1242
1243 public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String s)
1244 {
1245 if(s==null || s.trim().length()==0 || s.equals(getHelperString(uiComponent)))
1246 return null;
1247
1248 if(uiComponent instanceof HtmlInputCalendar && ((HtmlInputCalendar) uiComponent).isRenderAsPopup())
1249 {
1250 HtmlInputCalendar calendar = (HtmlInputCalendar) uiComponent;
1251 String popupDateFormat = calendar.getPopupDateFormat();
1252 String formatStr = createJSPopupFormat(facesContext, popupDateFormat);
1253 Locale locale = facesContext.getViewRoot().getLocale();
1254 Calendar timeKeeper = Calendar.getInstance(locale);
1255 int firstDayOfWeek = timeKeeper.getFirstDayOfWeek() - 1;
1256 org.apache.myfaces.dateformat.DateFormatSymbols symbols = new org.apache.myfaces.dateformat.DateFormatSymbols(locale);
1257 SimpleDateFormatter dateFormat = new SimpleDateFormatter(formatStr, symbols, firstDayOfWeek);
1258
1259 Date date = dateFormat.parse(s);
1260 if (date != null) {
1261 return date;
1262 }
1263 FacesMessage msg = MessageUtils.getMessage(Constants.TOMAHAWK_DEFAULT_BUNDLE,FacesMessage.SEVERITY_ERROR,CONVERSION_MESSAGE_ID,new Object[]{
1264 uiComponent.getId(),s},facesContext);
1265 throw new ConverterException(msg);
1266 }
1267 else
1268 {
1269 DateFormat dateFormat = createStandardDateFormat(facesContext);
1270 dateFormat.setLenient(false);
1271 try
1272 {
1273 Date date = dateFormat.parse(s);
1274 return date;
1275 }
1276 catch (ParseException e)
1277 {
1278 FacesMessage msg = MessageUtils.getMessage(Constants.TOMAHAWK_DEFAULT_BUNDLE,FacesMessage.SEVERITY_ERROR,CONVERSION_MESSAGE_ID,new Object[]{
1279 uiComponent.getId(),s},facesContext);
1280 throw new ConverterException(msg,e);
1281 }
1282 }
1283 }
1284
1285 public Date getAsDate(FacesContext facesContext, UIComponent uiComponent)
1286 {
1287 return RendererUtils.getDateValue(uiComponent);
1288 }
1289
1290 public static String createJSPopupFormat(FacesContext facesContext, String popupDateFormat)
1291 {
1292
1293 if(popupDateFormat == null)
1294 {
1295 SimpleDateFormat defaultDateFormat = createStandardDateFormat(facesContext);
1296 popupDateFormat = defaultDateFormat.toPattern();
1297 }
1298
1299 return popupDateFormat;
1300 }
1301
1302 public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object o)
1303 {
1304 Date date = (Date) o;
1305
1306 if(date==null)
1307 return getHelperString(uiComponent);
1308
1309 if(uiComponent instanceof HtmlInputCalendar && ((HtmlInputCalendar) uiComponent).isRenderAsPopup())
1310 {
1311 HtmlInputCalendar calendar = (HtmlInputCalendar) uiComponent;
1312 String popupDateFormat = calendar.getPopupDateFormat();
1313 String formatStr = createJSPopupFormat(facesContext, popupDateFormat);
1314 Locale locale = facesContext.getViewRoot().getLocale();
1315 Calendar timeKeeper = Calendar.getInstance(locale);
1316 int firstDayOfWeek = timeKeeper.getFirstDayOfWeek() - 1;
1317 org.apache.myfaces.dateformat.DateFormatSymbols symbols = new org.apache.myfaces.dateformat.DateFormatSymbols(locale);
1318
1319 SimpleDateFormatter dateFormat = new SimpleDateFormatter(formatStr, symbols, firstDayOfWeek);
1320 return dateFormat.format(date);
1321 }
1322 else
1323 {
1324 DateFormat dateFormat = createStandardDateFormat(facesContext);
1325 dateFormat.setLenient(false);
1326 return dateFormat.format(date);
1327 }
1328 }
1329
1330 private static SimpleDateFormat createStandardDateFormat(FacesContext facesContext)
1331 {
1332 DateFormat dateFormat;
1333 dateFormat = DateFormat.getDateInstance(DateFormat.SHORT,
1334 facesContext.getViewRoot().getLocale());
1335
1336 if(dateFormat instanceof SimpleDateFormat)
1337 return (SimpleDateFormat) dateFormat;
1338 else
1339 return new SimpleDateFormat("dd.MM.yyyy", facesContext.getViewRoot().getLocale());
1340 }
1341 }
1342 }