1 /*if(!window.LOG){
  2  window.LOG = {warn:function(){}};
  3  }*/
  4 
  5 // TODO: try to change RichFaces.$ to $$ if possible
  6 
  7 (function ($, rf) {
  8 
  9     rf.ui = rf.ui || {};
 10 
 11     //calendar templates
 12     var CalendarView = {
 13         getControl: function(text, attributes, functionName, paramsStr) {
 14             var attr = $.extend({
 15                     onclick: (functionName ? "RichFaces.$$('Calendar',this)." + functionName + "(" + (paramsStr ? paramsStr : "") + ");" : "") + "return true;"
 16                 }, attributes);
 17             return new E('div', attr, [new T(text)]);
 18         },
 19 
 20         getSelectedDateControl: function(calendar) {
 21 
 22             if (!calendar.selectedDate || calendar.options.showApplyButton) return "";
 23 
 24             var text = rf.calendarUtils.formatDate(calendar.selectedDate, (calendar.timeType ? calendar.datePattern : calendar.options.datePattern), calendar.options.monthLabels, calendar.options.monthLabelsShort);
 25             var onclick = "RichFaces.$$('Calendar',this).showSelectedDate(); return true;"
 26             var markup = ( calendar.options.disabled ?
 27                 new E('div', {'class': 'rf-cal-tl-btn-dis'}, [new ET(text)]) :
 28                 new E('div', {'class': 'rf-cal-tl-btn', 'onclick': onclick}, [new ET(text)]) );
 29 
 30             return markup;
 31         },
 32 
 33         getTimeControl: function(calendar) {
 34 
 35             if (!calendar.selectedDate || !calendar.timeType) return "";
 36 
 37             var text = rf.calendarUtils.formatDate(calendar.selectedDate, calendar.timePattern, calendar.options.monthLabels, calendar.options.monthLabelsShort);
 38 
 39             var onmouseover = "RichFaces.jQuery(this).removeClass('rf-cal-btn-press');";
 40             var onmouseout = "RichFaces.jQuery(this).addClass('rf-cal-btn-press');";
 41             var onclick = "RichFaces.$$('Calendar',this).showTimeEditor();return true;";
 42             var markup = calendar.options.disabled || calendar.options.readonly ?
 43                 new E('div', {'class': 'rf-cal-tl-btn-btn-dis'}, [new ET(text)]) :
 44                 new E('div', {'class': 'rf-cal-tl-btn rf-cal-tl-btn-hov rf-cal-btn-press', 'onclick': onclick,
 45                         'onmouseover': + onmouseover ,
 46                         'onmouseout' : + onmouseout}, [new ET(text)]);
 47 
 48             return markup;
 49         },
 50 
 51         toolButtonAttributes: {className: "rf-cal-tl-btn", onmouseover:"this.className='rf-cal-tl-btn rf-cal-tl-btn-hov'", onmouseout:"this.className='rf-cal-tl-btn'", onmousedown:"this.className='rf-cal-tl-btn rf-cal-tl-btn-hov rf-cal-tl-btn-btn-press'", onmouseup:"this.className='rf-cal-tl-btn rf-cal-tl-btn-hov'"},
 52         nextYearControl: function (context) {
 53             return (!context.calendar.options.disabled ? CalendarView.getControl(">>", CalendarView.toolButtonAttributes, "nextYear") : "");
 54         },
 55         previousYearControl: function (context) {
 56             return (!context.calendar.options.disabled ? CalendarView.getControl("<<", CalendarView.toolButtonAttributes, "prevYear") : "");
 57         },
 58         nextMonthControl: function (context) {
 59             return (!context.calendar.options.disabled ? CalendarView.getControl(">", CalendarView.toolButtonAttributes, "nextMonth") : "");
 60         },
 61         previousMonthControl: function (context) {
 62             return (!context.calendar.options.disabled ? CalendarView.getControl("<", CalendarView.toolButtonAttributes, "prevMonth") : "");
 63         },
 64         currentMonthControl: function (context) {
 65             var text = rf.calendarUtils.formatDate(context.calendar.getCurrentDate(), "MMMM, yyyy", context.monthLabels, context.monthLabelsShort);
 66             var markup = context.calendar.options.disabled ?
 67                 new E('div', {className: "rf-cal-tl-btn-dis"}, [new T(text)]) :
 68                 CalendarView.getControl(text, CalendarView.toolButtonAttributes, "showDateEditor");
 69             return markup;
 70         },
 71         todayControl: function (context) {
 72             return (!context.calendar.options.disabled && context.calendar.options.todayControlMode != 'hidden' ? CalendarView.getControl(context.controlLabels.today, CalendarView.toolButtonAttributes, "today") : "");
 73         },
 74         closeControl: function (context) {
 75             return (context.calendar.options.popup ? CalendarView.getControl(context.controlLabels.close, CalendarView.toolButtonAttributes, "close", "false") : "");
 76         },
 77         applyControl: function (context) {
 78             return (!context.calendar.options.disabled && !context.calendar.options.readonly && context.calendar.options.showApplyButton ? CalendarView.getControl(context.controlLabels.apply, CalendarView.toolButtonAttributes, "close", "true") : "");
 79         },
 80         cleanControl: function (context) {
 81             return (!context.calendar.options.disabled && !context.calendar.options.readonly && context.calendar.selectedDate ? CalendarView.getControl(context.controlLabels.clean, CalendarView.toolButtonAttributes, "__resetSelectedDate") : "");
 82         },
 83 
 84         selectedDateControl: function (context) {
 85             return CalendarView.getSelectedDateControl(context.calendar);
 86         },
 87         timeControl: function (context) {
 88             return CalendarView.getTimeControl(context.calendar);
 89         },
 90         timeEditorFields: function (context) {
 91             return context.calendar.timePatternHtml;
 92         },
 93 
 94         header: [
 95             new E('table', {'border': '0', 'cellpadding': '0', 'cellspacing': '0', 'width': '100%'},
 96                 [
 97                     new E('tbody', {},
 98                         [
 99                             new E('tr', {},
100                                 [
101                                     new E('td', {'class': 'rf-cal-tl'},
102                                         [
103                                             new ET(function (context) {
104                                                 return rf.calendarTemplates.evalMacro("previousYearControl", context)
105                                             })
106                                         ]),
107                                     new E('td', {'class': 'rf-cal-tl'},
108                                         [
109                                             new ET(function (context) {
110                                                 return rf.calendarTemplates.evalMacro("previousMonthControl", context)
111                                             })
112                                         ]),
113                                     new E('td', {'class': 'rf-cal-hdr-month'},
114                                         [
115                                             new ET(function (context) {
116                                                 return rf.calendarTemplates.evalMacro("currentMonthControl", context)
117                                             })
118                                         ]),
119                                     new E('td', {'class': 'rf-cal-tl'},
120                                         [
121                                             new ET(function (context) {
122                                                 return rf.calendarTemplates.evalMacro("nextMonthControl", context)
123                                             })
124                                         ]),
125                                     new E('td', {'class': 'rf-cal-tl'},
126                                         [
127                                             new ET(function (context) {
128                                                 return rf.calendarTemplates.evalMacro("nextYearControl", context)
129                                             })
130                                         ]),
131                                     new E('td', {'class': 'rf-cal-tl rf-cal-btn-close', 'style':function(context) {
132                                             return (this.isEmpty ? 'display:none;' : '');
133                                         }},
134                                         [
135                                             new ET(function (context) {
136                                                 return rf.calendarTemplates.evalMacro("closeControl", context)
137                                             })
138                                         ])
139                                 ])
140                         ])
141                 ]
142             )],
143 
144         footer: [
145             new E('table', {'border': '0', 'cellpadding': '0', 'cellspacing': '0', 'width': '100%'},
146                 [
147                     new E('tbody', {},
148                         [
149                             new E('tr', {},
150                                 [
151                                     new E('td', {'class': 'rf-cal-tl-ftr', 'style':function(context) {
152                                             return (this.isEmpty ? 'display:none;' : '');
153                                         }},
154                                         [
155                                             new ET(function (context) {
156                                                 return rf.calendarTemplates.evalMacro("selectedDateControl", context)
157                                             })
158                                         ]),
159                                     new E('td', {'class': 'rf-cal-tl-ftr', 'style':function(context) {
160                                             return (this.isEmpty ? 'display:none;' : '');
161                                         }},
162                                         [
163                                             new ET(function (context) {
164                                                 return rf.calendarTemplates.evalMacro("cleanControl", context)
165                                             })
166                                         ]),
167                                     new E('td', {'class': 'rf-cal-tl-ftr', 'style':function(context) {
168                                             return (this.isEmpty ? 'display:none;' : '');
169                                         }},
170                                         [
171                                             new ET(function (context) {
172                                                 return rf.calendarTemplates.evalMacro("timeControl", context)
173                                             })
174                                         ]),
175                                     new E('td', {'class': 'rf-cal-tl-ftr', 'style': 'background-image:none;', 'width': '100%'}, []),
176                                     new E('td', {'class': 'rf-cal-tl-ftr', 'style':function(context) {
177                                             return (this.isEmpty ? 'display:none;' : '') + (context.calendar.options.disabled || context.calendar.options.readonly || !context.calendar.options.showApplyButton ? 'background-image:none;' : '');
178                                         }},
179                                         [
180                                             new ET(function (context) {
181                                                 return rf.calendarTemplates.evalMacro("todayControl", context)
182                                             })
183                                         ]),
184                                     new E('td', {'class': 'rf-cal-tl-ftr', 'style':function(context) {
185                                             return (this.isEmpty ? 'display:none;' : '') + 'background-image:none;';
186                                         }},
187                                         [
188                                             new ET(function (context) {
189                                                 return rf.calendarTemplates.evalMacro("applyControl", context)
190                                             })
191                                         ])
192                                 ])
193                         ])
194                 ]
195             )],
196 
197         timeEditorLayout: [
198 
199             new E('table', {'id': function(context) {
200                     return context.calendar.TIME_EDITOR_LAYOUT_ID
201                 }, 'border': '0', 'cellpadding': '0', 'cellspacing': '0', 'class': 'rf-cal-timepicker-cnt'},
202                 [
203                     new E('tbody', {},
204                         [
205                             new E('tr', {},
206                                 [
207                                     new E('td', {'class': 'rf-cal-timepicker-inp', 'colspan': '2', 'align': 'center'},
208                                         [
209                                             new ET(function (context) {
210                                                 return rf.calendarTemplates.evalMacro("timeEditorFields", context)
211                                             })
212                                         ])
213                                 ]),
214                             new E('tr', {},
215                                 [
216                                     new E('td', {'class': 'rf-cal-timepicker-ok'},
217                                         [
218                                             new E('div', {'id': function(context) {
219                                                     return context.calendar.TIME_EDITOR_BUTTON_OK
220                                                 }, 'class': 'rf-cal-time-btn', 'style': 'float:right;', 'onmousedown': "RichFaces.jQuery(this).addClass('rf-cal-time-btn-press');", 'onmouseout': "RichFaces.jQuery(this).removeClass('rf-cal-time-btn-press');", 'onmouseup': "RichFaces.jQuery(this).removeClass('rf-cal-time-btn-press');", 'onclick': function(context) {
221                                                     return "RichFaces.component('" + context.calendar.id + "').hideTimeEditor(true)";
222                                                 }},
223                                                 [
224                                                     new E('span', {},
225                                                         [
226                                                             new ET(function (context) {
227                                                                 return context.controlLabels.ok;
228                                                             })
229                                                         ])
230                                                 ])
231                                         ])
232                                     ,
233                                     new E('td', {'class': 'rf-cal-timepicker-cancel'},
234                                         [
235                                             new E('div', {'id': function(context) {
236                                                     return context.calendar.TIME_EDITOR_BUTTON_CANCEL
237                                                 }, 'class': 'rf-cal-time-btn', 'style': 'float:left;', 'onmousedown': "RichFaces.jQuery(this).addClass('rf-cal-time-btn-press');", 'onmouseout': "RichFaces.jQuery(this).removeClass('rf-cal-time-btn-press');", 'onmouseup': "RichFaces.jQuery(this).removeClass('rf-cal-time-btn-press');", 'onclick': function(context) {
238                                                     return "RichFaces.component('" + context.calendar.id + "').hideTimeEditor(false)";
239                                                 }},
240                                                 [
241                                                     new E('span', {},
242                                                         [
243                                                             new ET(function (context) {
244                                                                 return context.controlLabels.cancel;
245                                                             })
246                                                         ])
247                                                 ])
248                                         ])
249                                 ])
250                         ])
251                 ]
252             )],
253 
254         dayList: [new ET(function (context) {
255             return context.day
256         })],
257         weekNumber: [new ET(function (context) {
258             return context.weekNumber
259         })],
260         weekDay: [new ET(function (context) {
261             return context.weekDayLabelShort
262         })]
263     };
264     // calendar templates end
265 
266     // calendar context
267     var CalendarContext = function(calendar) {
268         this.calendar = calendar;
269         this.monthLabels = calendar.options.monthLabels;
270         this.monthLabelsShort = calendar.options.monthLabelsShort;
271         this.weekDayLabels = calendar.options.weekDayLabels;
272         this.weekDayLabelsShort = calendar.options.weekDayLabelsShort;
273         this.controlLabels = calendar.options.labels;
274     };
275 
276     $.extend(CalendarContext.prototype, {
277             nextYearControl: CalendarView.nextYearControl,
278             previousYearControl: CalendarView.previousYearControl,
279             nextMonthControl: CalendarView.nextMonthControl,
280             previousMonthControl: CalendarView.previousMonthControl,
281             currentMonthControl: CalendarView.currentMonthControl,
282             selectedDateControl: CalendarView.selectedDateControl,
283             cleanControl: CalendarView.cleanControl,
284             timeControl: CalendarView.timeControl,
285             todayControl: CalendarView.todayControl,
286             closeControl: CalendarView.closeControl,
287             applyControl: CalendarView.applyControl,
288             timeEditorFields: CalendarView.timeEditorFields
289         });
290 
291     // must be :defaultTime, minDaysInFirstWeek, firstWeekday, weekDayLabels, weekDayLabelsShort, monthLabels, monthLabelsShort
292 
293     // defaults definition
294     var defaultOptions = {
295         showWeekDaysBar: true,
296         showWeeksBar: true,
297         datePattern: "MMM d, yyyy",
298         horizontalOffset: 0,
299         verticalOffset: 0,
300         dayListMarkup: CalendarView.dayList,
301         weekNumberMarkup: CalendarView.weekNumber,
302         weekDayMarkup: CalendarView.weekDay,
303         headerMarkup: CalendarView.header,
304         footerMarkup: CalendarView.footer,
305         isDayEnabled: function (context) {
306             return true;
307         },
308         dayStyleClass: function (context) {
309             return "";
310         },
311         showHeader: true,
312         showFooter: true,
313         direction: "AA",
314         jointPoint: "AA",
315         popup: true,
316         boundaryDatesMode: "inactive",
317         todayControlMode: "select",
318         style: "",
319         className: "",
320         disabled: false,
321         readonly: false,
322         enableManualInput: false,
323         showInput: true,
324         resetTimeOnDateSelect: false,
325         style: "z-index: 3;",
326         showApplyButton: false,
327         selectedDate: null,
328         currentDate: null,
329         defaultTime: {hours:12,minutes:0, seconds:0},
330         mode: "client",
331         hidePopupOnScroll: true,
332         defaultLabel:""
333     };
334 
335     var defaultLabels = {apply:'Apply', today:'Today', clean:'Clean', ok:'OK', cancel:'Cancel', close:'x'};
336 
337     var eventHandlerNames = ["change", "dateselect", "beforedateselect", "currentdateselect",
338         "beforecurrentdateselect", "currentdateselect", "clean", "complete", "collapse",
339         "datemouseout", "datemouseover", "show", "hide", "timeselect", "beforetimeselect"];
340 
341     var updateDefaultLabel = function (value) {
342         var field = rf.getDomElement(this.INPUT_DATE_ID);
343         if (
344             (field.value == this.options.defaultLabel && !value) ||
345                 (value == this.options.defaultLabel && !field.value)
346             ) {
347             field.value = value;
348             if (value) {
349                 $(field).addClass("rf-cal-dflt-lbl");
350             } else {
351                 $(field).removeClass("rf-cal-dflt-lbl");
352             }
353         }
354     }
355 
356     var onFocusBlur = function (event) {
357         this.isFocused = event.type == "focus";
358         if (!this.isFocused && this.isVisible) return;
359         updateDefaultLabel.call(this, (event.type == "focus" ? "" : this.options.defaultLabel));
360     }
361 
362     // Constructor definition
363     rf.ui.Calendar = function(componentId, locale, options, markups) {
364 
365         // dayListMarkup - day cell markup
366         //		context: {day, date, weekNumber, weekDayNumber, isWeekend, isCurrentMonth,  elementId, component}
367         // weekNumberMarkup - week number cell markup
368         //		context: {weekNumber, elementId, component}
369         // weekDayMarkup - week day cell markup
370         //		context: {weekDayLabel, weekDayLabelShort, weekDayNumber, isWeekend, elementId, component}
371 
372         // headerMarkup
373         // footerMarkup
374         // optionalHeaderMarkup - user defined header (optional)
375         // optionalFooterMarkup - user defined footer (optional)
376 
377         // currentDate - date to show month (day not used) (MM/yyyy)
378         // selectedDate - selected date (mm/dd/yyyy)
379         // weekDayLabels - collection of week day labels keyed by week day numbers
380         // weekDayLabelsShort - collection of week day short labels keyed by week day numbers
381         // minDaysInFirstWeek - locale-specific constant defining number of days in the first week
382         // firstWeekDay - (0..6) locale-specific constant defining number of the first week day
383         // showWeekDaysBar - show WeekDays Bar [default value is true]
384         // showWeeksBar - show Weeks numbers bar [default value is true]
385         // showApplyButton
386         // showHeader
387         // showFooter
388 
389         // POPUP description
390         // direction - [top-left, top-right, bottom-left, bottom-right, auto]
391         // jointPoint - [top-left, top-right, bottom-left, bottom-right]
392         // popup - true
393         // id+PopupButton, id+InputDate,
394 
395         // boundaryDatesMode - boundary dates onclick action:
396         // 						"inactive" or undefined - no action (default)
397         //						"scroll" - change current month
398         //						"select" - change current month and select date
399         //						"hidden" - does not render content for boundary dates
400         //
401         // todayControlMode - today control onclick action:
402         //						"scroll"
403         //						"select"
404         //						"hidden"
405 
406         // isDayEnabled - end-developer JS function
407         // dayStyleClass - end-developer JS function that provide style class for day's cells.
408 
409         // dayCellClass - add div to day cell with class 'rf-cal-c-cnt' and add this class to TD if defined
410         // style - table style
411         // styleClass - table class
412 
413         // disabled
414         // readonly
415 
416         //var _d = new Date();
417 
418         // call constructor of parent class
419         $super.constructor.call(this, componentId);
420 
421         this.namespace = "." + rf.Event.createNamespace(this.name, componentId);
422 
423         //create parameters
424         //this.options = $.extend(this.options, defaultOptions, options);
425         this.options = $.extend(this.options, defaultOptions, locales[locale], options, markups);
426 
427         // labels
428         var value = options.labels || {};
429         for (var name in defaultLabels) {
430             if (!value[name]) value[name] = defaultLabels[name];
431         }
432         this.options.labels = value;
433 
434         this.popupOffset = [this.options.horizontalOffset, this.options.verticalOffset];
435 
436         //
437         if (!this.options.popup) this.options.showApplyButton = false;
438 
439         //
440         this.options.boundaryDatesMode = this.options.boundaryDatesMode.toLowerCase();
441         this.hideBoundaryDatesContent = this.options.boundaryDatesMode == "hidden";
442         this.options.todayControlMode = this.options.todayControlMode.toLowerCase();
443 
444         // time
445         this.setTimeProperties();
446 
447         this.customDayListMarkup = (this.options.dayListMarkup != CalendarView.dayList);
448 
449         this.currentDate = this.options.currentDate ? this.options.currentDate : (this.options.selectedDate ? this.options.selectedDate : new Date());
450         this.currentDate.setDate(1);
451         this.selectedDate = this.options.selectedDate;
452 
453         this.todayDate = new Date();
454 
455         this.firstWeekendDayNumber = 6 - this.options.firstWeekDay;
456         this.secondWeekendDayNumber = (this.options.firstWeekDay > 0 ? 7 - this.options.firstWeekDay : 0);
457 
458         this.calendarContext = new CalendarContext(this);
459 
460         // TODO: move it from constructor
461         this.DATE_ELEMENT_ID = this.id + 'DayCell';
462         this.WEEKNUMBER_BAR_ID = this.id + "WeekNum";
463         this.WEEKNUMBER_ELEMENT_ID = this.WEEKNUMBER_BAR_ID + 'Cell';
464         this.WEEKDAY_BAR_ID = this.id + "WeekDay";
465         this.WEEKDAY_ELEMENT_ID = this.WEEKDAY_BAR_ID + 'Cell';
466         this.POPUP_ID = this.id + 'Popup';
467         this.POPUP_BUTTON_ID = this.id + 'PopupButton';
468         this.INPUT_DATE_ID = this.id + 'InputDate';
469         this.EDITOR_ID = this.id + 'Editor';
470         this.EDITOR_SHADOW_ID = this.id + 'EditorShadow';
471 
472         this.TIME_EDITOR_LAYOUT_ID = this.id + 'TimeEditorLayout';
473         this.DATE_EDITOR_LAYOUT_ID = this.id + 'DateEditorLayout';
474         this.EDITOR_LAYOUT_SHADOW_ID = this.id + 'EditorLayoutShadow';
475         this.TIME_EDITOR_BUTTON_OK = this.id + 'TimeEditorButtonOk';
476         this.TIME_EDITOR_BUTTON_CANCEL = this.id + 'TimeEditorButtonCancel';
477         this.DATE_EDITOR_BUTTON_OK = this.id + 'DateEditorButtonOk';
478         this.DATE_EDITOR_BUTTON_CANCEL = this.id + 'DateEditorButtonCancel';
479         this.CALENDAR_CONTENT = this.id + "Content";
480 
481         this.firstDateIndex = 0;
482 
483         this.daysData = {startDate:null, days:[]};
484         this.days = [];
485         this.todayCellId = null;
486         this.todayCellColor = "";
487 
488         this.selectedDateCellId = null;
489         this.selectedDateCellColor = "";
490 
491         var popupStyles = "";
492         this.isVisible = true;
493         if (this.options.popup == true) {
494             // popup mode initialisation
495             popupStyles = "display:none; position:absolute;"
496             this.isVisible = false;
497         }
498 
499         var tempStr = "RichFaces.component('" + this.id + "').";
500 
501         var htmlTextHeader = '<table id="' + this.CALENDAR_CONTENT + '" border="0" cellpadding="0" cellspacing="0" class="rf-cal-extr rf-cal-popup ' + this.options.styleClass + '" style="' + popupStyles + this.options.style + '" onclick="' + tempStr + 'skipEventOnCollapse=true;"><tbody>';
502         var colspan = (this.options.showWeeksBar ? "8" : "7");
503         var htmlHeaderOptional = (this.options.optionalHeaderMarkup) ? '<tr><td class="rf-cal-hdr-optnl" colspan="' + colspan + '" id="' + this.id + 'HeaderOptional"></td></tr>' : '';
504         var htmlFooterOptional = (this.options.optionalFooterMarkup) ? '<tr><td class="rf-cal-ftr-optl" colspan="' + colspan + '" id="' + this.id + 'FooterOptional"></td></tr>' : '';
505         var htmlControlsHeader = (this.options.showHeader ? '<tr><td class="rf-cal-hdr" colspan="' + colspan + '" id="' + this.id + 'Header"></td></tr>' : '');
506         var htmlControlsFooter = (this.options.showFooter ? '<tr><td class="rf-cal-ftr" colspan="' + colspan + '" id="' + this.id + 'Footer"></td></tr>' : '');
507         var htmlTextFooter = '</tbody></table>'
508 
509         // days bar creation
510         var styleClass;
511         var bottomStyleClass;
512         var htmlTextWeekDayBar = [];
513         var context;
514 
515         var eventsStr = this.options.disabled || this.options.readonly ? '' : 'onclick="' + tempStr + 'eventCellOnClick(event, this);" onmouseover="' + tempStr + 'eventCellOnMouseOver(event, this);" onmouseout="' + tempStr + 'eventCellOnMouseOut(event, this);"';
516         if (this.options.showWeekDaysBar) {
517             htmlTextWeekDayBar.push('<tr id="' + this.WEEKDAY_BAR_ID + '">');
518             if (this.options.showWeeksBar) htmlTextWeekDayBar.push('<td class="rf-cal-day-lbl"><br/></td>');
519             var weekDayCounter = this.options.firstWeekDay;
520             for (var i = 0; i < 7; i++) {
521                 context = {weekDayLabel: this.options.weekDayLabels[weekDayCounter], weekDayLabelShort: this.options.weekDayLabelsShort[weekDayCounter], weekDayNumber:weekDayCounter, isWeekend:this.isWeekend(i), elementId:this.WEEKDAY_ELEMENT_ID + i, component:this};
522                 var weekDayHtml = this.evaluateMarkup(this.options.weekDayMarkup, context);
523                 if (weekDayCounter == 6) weekDayCounter = 0; else weekDayCounter++;
524 
525                 styleClass = "rf-cal-day-lbl";
526                 if (context.isWeekend) {
527                     styleClass += " rf-cal-holliday-lbl";
528                 }
529                 if (i == 6) styleClass += " rf-cal-right-c";
530                 htmlTextWeekDayBar.push('<td class="' + styleClass + '" id="' + context.elementId + '">' + weekDayHtml + '</td>');
531             }
532             htmlTextWeekDayBar.push('</tr>\n');
533         }
534 
535         // week & weekNumber creation
536         var htmlTextWeek = [];
537         var p = 0;
538         this.dayCellClassName = [];
539 
540         for (k = 1; k < 7; k++) {
541             bottomStyleClass = (k == 6 ? "rf-btm-c " : "");
542             htmlTextWeek.push('<tr id="' + this.WEEKNUMBER_BAR_ID + k + '">');
543             if (this.options.showWeeksBar) {
544                 context = {weekNumber: k, elementId:this.WEEKNUMBER_ELEMENT_ID + k, component:this};
545                 var weekNumberHtml = this.evaluateMarkup(this.options.weekNumberMarkup, context);
546                 htmlTextWeek.push('<td class="rf-cal-week ' + bottomStyleClass + '" id="' + context.elementId + '">' + weekNumberHtml + '</td>');
547             }
548 
549             // day cells creation
550             for (var i = 0; i < 7; i++) {
551                 styleClass = bottomStyleClass + (!this.options.dayCellClass ? "rf-cal-c-cnt-overflow" : (!this.customDayListMarkup ? this.options.dayCellClass : "")) + " rf-cal-c";
552                 if (i == this.firstWeekendDayNumber || i == this.secondWeekendDayNumber) styleClass += " rf-cal-holiday";
553                 if (i == 6) styleClass += " rf-cal-right-c";
554 
555                 this.dayCellClassName.push(styleClass);
556                 htmlTextWeek.push('<td class="' + styleClass + '" id="' + this.DATE_ELEMENT_ID + p + '" ' +
557                     eventsStr +
558                     '>' + (this.customDayListMarkup ? '<div class="rf-cal-c-cnt' + (this.options.dayCellClass ? ' ' + this.options.dayCellClass : '') + '"></div>' : '') + '</td>');
559                 p++;
560             }
561             htmlTextWeek.push('</tr>');
562         }
563 
564         var div = rf.getDomElement(this.CALENDAR_CONTENT);
565         div = $(div).replaceWith(htmlTextHeader + htmlHeaderOptional + htmlControlsHeader + htmlTextWeekDayBar.join('') + htmlTextWeek.join('') + htmlControlsFooter + htmlFooterOptional + htmlTextFooter);
566         this.attachToDom(); // TODO: optimize double $
567 
568         // memory leaks fix // from old 3.3.x code, may be not needed now
569         div = null;
570 
571         // add onclick event handlers to input field and popup button
572         if (this.options.popup && !this.options.disabled) {
573             var handler = new Function('event', "RichFaces.component('" + this.id + "').switchPopup();");
574             rf.Event.bindById(this.POPUP_BUTTON_ID, "click" + this.namespace, handler, this);
575             if (!this.options.enableManualInput) {
576                 rf.Event.bindById(this.INPUT_DATE_ID, "click" + this.namespace, handler, this);
577             }
578             if (this.options.defaultLabel) {
579                 updateDefaultLabel.call(this, this.options.defaultLabel);
580                 rf.Event.bindById(this.INPUT_DATE_ID, "focus" + this.namespace + " blur" + this.namespace, onFocusBlur, this);
581             }
582         }
583 
584         this.scrollElements = null;
585 
586         //define isAjaxMode variable
587         this.isAjaxMode = this.options.mode == "ajax";
588 
589         //alert(new Date().getTime()-_d.getTime());
590     };
591 
592     // Extend component class and add protected methods from parent class to our container
593     rf.BaseComponent.extend(rf.ui.Calendar);
594 
595     // define super class link
596     var $super = rf.ui.Calendar.$super;
597 
598     // static methods definition
599     var locales = {};
600 
601     rf.ui.Calendar.addLocale = function (locale, symbols) {
602         if (!locales[locale]) {
603             locales[locale] = symbols;
604         }
605     };
606 
607     /*
608      * Prototype definition
609      */
610     $.extend(rf.ui.Calendar.prototype, {
611             name: "Calendar",
612             destroy: function() {
613                 if (this.options.popup && this.isVisible) {
614                     this.scrollElements && rf.Event.unbindScrollEventHandlers(this.scrollElements, this);
615                     this.scrollElements = null;
616                     rf.Event.unbind(window.document, "click" + this.namespace);
617                 }
618                 $super.destroy.call(this);
619             },
620 
621             dateEditorSelectYear: function(value) {
622                 if (this.dateEditorYearID) {
623                     $(rf.getDomElement(this.dateEditorYearID)).removeClass('rf-cal-edtr-btn-sel');
624                 }
625                 this.dateEditorYear = this.dateEditorStartYear + value;
626                 this.dateEditorYearID = this.DATE_EDITOR_LAYOUT_ID + 'Y' + value;
627                 $(rf.getDomElement(this.dateEditorYearID)).addClass('rf-cal-edtr-btn-sel');
628             },
629 
630             dateEditorSelectMonth: function(value) {
631                 this.dateEditorMonth = value;
632                 $(rf.getDomElement(this.dateEditorMonthID)).removeClass('rf-cal-edtr-btn-sel');
633                 this.dateEditorMonthID = this.DATE_EDITOR_LAYOUT_ID + 'M' + value;
634                 $(rf.getDomElement(this.dateEditorMonthID)).addClass('rf-cal-edtr-btn-sel');
635             },
636 
637             scrollEditorYear: function(value) {
638                 var element = rf.getDomElement(this.DATE_EDITOR_LAYOUT_ID + 'TR');
639 
640                 if (this.dateEditorYearID) {
641                     $(rf.getDomElement(this.dateEditorYearID)).removeClass('rf-cal-edtr-btn-sel');
642                     this.dateEditorYearID = '';
643                 }
644 
645                 if (!value) {
646                     // update month selection when open editor (value == 0)
647                     if (this.dateEditorMonth != this.getCurrentMonth()) {
648                         this.dateEditorMonth = this.getCurrentMonth();
649                         $(rf.getDomElement(this.dateEditorMonthID)).removeClass('rf-cal-edtr-btn-sel');
650                         this.dateEditorMonthID = this.DATE_EDITOR_LAYOUT_ID + 'M' + this.dateEditorMonth;
651                         $(rf.getDomElement(this.dateEditorMonthID)).addClass('rf-cal-edtr-btn-sel');
652                     }
653                 }
654 
655                 if (element) {
656                     var div;
657                     var year = this.dateEditorStartYear = this.dateEditorStartYear + value * 10;
658                     for (var i = 0; i < 5; i++) {
659                         element = element.nextSibling;
660                         div = element.firstChild.nextSibling.nextSibling;
661                         div.firstChild.innerHTML = year;
662                         if (year == this.dateEditorYear) {
663                             $(div.firstChild).addClass('rf-cal-edtr-btn-sel');
664                             this.dateEditorYearID = div.firstChild.id;
665                         }
666                         div = div.nextSibling;
667                         div.firstChild.innerHTML = year + 5;
668                         if (year + 5 == this.dateEditorYear) {
669                             $(div.firstChild).addClass('rf-cal-edtr-btn-sel');
670                             this.dateEditorYearID = div.firstChild.id;
671                         }
672                         year++;
673                     }
674                 }
675             },
676 
677             updateDateEditor: function() {
678                 this.dateEditorYear = this.getCurrentYear();
679                 this.dateEditorStartYear = this.getCurrentYear() - 4;
680                 this.scrollEditorYear(0);
681             },
682 
683             updateTimeEditor: function() {
684                 var th = rf.getDomElement(this.id + 'TimeHours');
685                 var ts = rf.getDomElement(this.id + 'TimeSign');
686                 var tm = rf.getDomElement(this.id + 'TimeMinutes');
687 
688                 var h = this.selectedDate.getHours();
689                 var m = this.selectedDate.getMinutes();
690                 if (this.timeType == 2) {
691                     var a = (h < 12 ? 'AM' : 'PM');
692                     ts.value = a;
693                     h = (h == 0 ? '12' : (h > 12 ? h - 12 : h));
694                 }
695                 th.value = (this.timeHoursDigits == 2 && h < 10 ? '0' + h : h);
696                 tm.value = (m < 10 ? '0' + m : m);
697 
698                 if (this.showSeconds) {
699                     var tsec = rf.getDomElement(this.id + 'TimeSeconds');
700                     var s = this.selectedDate.getSeconds();
701                     tsec.value = (s < 10 ? '0' + s : s);
702                 }
703             },
704 
705 
706             createEditor: function() {
707                 var element = $(rf.getDomElement(this.CALENDAR_CONTENT));
708                 var zindex = parseInt(element.css('z-index'), 10);
709                 var htmlBegin = '<div id="' + this.EDITOR_SHADOW_ID + '" class="rf-cal-edtr-shdw" style="position:absolute; display:none;z-index:' + zindex + '"></div><table border="0" cellpadding="0" cellspacing="0" id="' + this.EDITOR_ID + '" style="position:absolute; display:none;z-index:' + (zindex + 1) + '" onclick="RichFaces.component(\'' + this.id + '\').skipEventOnCollapse=true;"><tbody><tr><td class="rf-cal-edtr-cntr" align="center"><div style="position:relative; display:inline-block;">';
710                 var htmlContent = '<div id="' + this.EDITOR_LAYOUT_SHADOW_ID + '" class="rf-cal-edtr-layout-shdw"></div>';
711 
712                 var htmlEnd = '</div></td></tr></tbody></table>';
713                 element.after(htmlBegin + htmlContent + htmlEnd);
714 
715                 this.isEditorCreated = true;
716 
717                 return rf.getDomElement(this.EDITOR_ID);
718             },
719 
720             createTimeEditorLayout: function(editor) {
721                 $(rf.getDomElement(this.EDITOR_LAYOUT_SHADOW_ID)).after(this.evaluateMarkup(CalendarView.timeEditorLayout, this.calendarContext));
722 
723                 var th = rf.getDomElement(this.id + 'TimeHours');
724                 var ts;
725                 var tm = rf.getDomElement(this.id + 'TimeMinutes');
726                 if (this.timeType == 1) {
727                     sbjQuery(th).SpinButton({digits:this.timeHoursDigits,min:0,max:23});
728                 }
729                 else {
730                     sbjQuery(th).SpinButton({digits:this.timeHoursDigits,min:1,max:12});
731                     ts = rf.getDomElement(this.id + 'TimeSign');
732                     sbjQuery(ts).SpinButton({});
733                 }
734                 sbjQuery(tm).SpinButton({digits:2,min:0,max:59});
735                 if (this.showSeconds) {
736                     var tsec = rf.getDomElement(this.id + 'TimeSeconds');
737                     sbjQuery(tsec).SpinButton({digits:2,min:0,max:59});
738                 }
739 
740                 this.correctEditorButtons(editor, this.TIME_EDITOR_BUTTON_OK, this.TIME_EDITOR_BUTTON_CANCEL);
741 
742                 this.isTimeEditorLayoutCreated = true;
743             },
744 
745             correctEditorButtons: function(editor, buttonID1, buttonID2) {
746                 var button1 = rf.getDomElement(buttonID1);
747                 var button2 = rf.getDomElement(buttonID2);
748                 editor.style.visibility = "hidden";
749                 editor.style.display = "";
750                 var width1 = $(button1.firstChild).width();
751                 var width2 = $(button2.firstChild).width();
752                 editor.style.display = "none";
753                 editor.style.visibility = "";
754 
755                 if (width1 != width2) {
756                     button1.style.width = button2.style.width = (width1 > width2 ? width1 : width2) + "px";
757                 }
758             },
759 
760             createDECell: function(id, value, buttonType, param, className) {
761                 if (buttonType == 0) {
762                     return '<div id="' + id + '" class="rf-cal-edtr-btn' + (className ? ' ' + className : '') +
763                         '" onmouseover="this.className=\'rf-cal-edtr-btn rf-cal-edtr-tl-over\';" onmouseout="this.className=\'rf-cal-edtr-btn\';" onmousedown="this.className=\'rf-cal-edtr-btn rf-cal-edtr-tl-press\';" onmouseup="this.className=\'rf-cal-edtr-btn rf-cal-edtr-tl-over\';" onclick="RichFaces.component(\'' + this.id + '\').scrollEditorYear(' + param + ');">' + value + '</div>';
764                 }
765                 else {
766                     var onclick = (buttonType == 1 ? 'RichFaces.component(\'' + this.id + '\').dateEditorSelectMonth(' + param + ');' :
767                         'RichFaces.component(\'' + this.id + '\').dateEditorSelectYear(' + param + ');' );
768                     return '<div id="' + id + '" class="rf-cal-edtr-btn' + (className ? ' ' + className : '') +
769                         '" onmouseover="RichFaces.jQuery(this).addClass(\'rf-cal-edtr-btn-over\');" onmouseout="$(this).removeClass(\'rf-cal-edtr-btn-over\');" onclick="' + onclick + '">' + value + '</div>';
770                 }
771             },
772 
773             createDateEditorLayout: function(editor) {
774                 var htmlBegin = '<table id="' + this.DATE_EDITOR_LAYOUT_ID + '" class="rf-cal-monthpicker-cnt" border="0" cellpadding="0" cellspacing="0"><tbody><tr id="' + this.DATE_EDITOR_LAYOUT_ID + 'TR">';
775                 var htmlEnd = '</tr></tbody></table>';
776                 var month = 0;
777                 this.dateEditorYear = this.getCurrentYear();
778                 var year = this.dateEditorStartYear = this.dateEditorYear - 4;
779                 var htmlContent = '<td align="center">' + this.createDECell(this.DATE_EDITOR_LAYOUT_ID + 'M' + month, this.options.monthLabelsShort[month], 1, month) + '</td>'
780                     + '<td align="center" class="rf-cal-monthpicker-split">' + this.createDECell(this.DATE_EDITOR_LAYOUT_ID + 'M' + (month + 6), this.options.monthLabelsShort[month + 6], 1, month + 6) + '</td>'
781                     + '<td align="center">' + this.createDECell('', '<', 0, -1) + '</td>'
782                     + '<td align="center">' + this.createDECell('', '>', 0, 1) + '</td>';
783                 month++;
784 
785                 for (var i = 0; i < 5; i++) {
786                     htmlContent += '</tr><tr><td align="center">' + this.createDECell(this.DATE_EDITOR_LAYOUT_ID + 'M' + month, this.options.monthLabelsShort[month], 1, month) + '</td>'
787                         + '<td align="center" class="rf-cal-monthpicker-split">' + this.createDECell(this.DATE_EDITOR_LAYOUT_ID + 'M' + (month + 6), this.options.monthLabelsShort[month + 6], 1, month + 6) + '</td>'
788                         + '<td align="center">' + this.createDECell(this.DATE_EDITOR_LAYOUT_ID + 'Y' + i, year, 2, i, (i == 4 ? 'rf-cal-edtr-btn-sel' : '')) + '</td>'
789                         + '<td align="center">' + this.createDECell(this.DATE_EDITOR_LAYOUT_ID + 'Y' + (i + 5), year + 5, 2, i + 5) + '</td>';
790                     month++;
791                     year++;
792                 }
793                 this.dateEditorYearID = this.DATE_EDITOR_LAYOUT_ID + 'Y4';
794                 this.dateEditorMonth = this.getCurrentMonth();
795                 this.dateEditorMonthID = this.DATE_EDITOR_LAYOUT_ID + 'M' + this.dateEditorMonth;
796 
797                 htmlContent += '</tr><tr><td colspan="2" class="rf-cal-monthpicker-ok">' +
798                     '<div id="' + this.DATE_EDITOR_BUTTON_OK + '" class="rf-cal-time-btn" style="float:right;" onmousedown="RichFaces.jQuery(this).addClass(\'rf-cal-time-btn-press\');" onmouseout="RichFaces.jQuery(this).removeClass(\'rf-cal-time-btn-press\');" onmouseup="RichFaces.jQuery(this).removeClass(\'rf-cal-time-btn-press\');" onclick="RichFaces.component(\'' + this.id + '\').hideDateEditor(true);"><span>' + this.options.labels.ok + '</span></div>' +
799                     '</td><td colspan="2" class="rf-cal-monthpicker-cancel">' +
800                     '<div id="' + this.DATE_EDITOR_BUTTON_CANCEL + '" class="rf-cal-time-btn" style="float:left;" onmousedown="RichFaces.jQuery(this).addClass(\'rf-cal-time-btn-press\');" onmouseout="RichFaces.jQuery(this).removeClass(\'rf-cal-time-btn-press\');" onmouseup="RichFaces.jQuery(this).removeClass(\'rf-cal-time-btn-press\');" onclick="RichFaces.component(\'' + this.id + '\').hideDateEditor(false);"><span>' + this.options.labels.cancel + '</span></div>' +
801                     '</td>';
802 
803 
804                 $(rf.getDomElement(this.EDITOR_LAYOUT_SHADOW_ID)).after(htmlBegin + htmlContent + htmlEnd);
805 
806                 $(rf.getDomElement(this.dateEditorMonthID)).addClass('rf-cal-edtr-btn-sel');
807 
808                 this.correctEditorButtons(editor, this.DATE_EDITOR_BUTTON_OK, this.DATE_EDITOR_BUTTON_CANCEL);
809 
810                 this.isDateEditorLayoutCreated = true;
811             },
812 
813             createSpinnerTable: function(id) {
814                 return '<table cellspacing="0" cellpadding="0" border="0"><tbody><tr>' +
815                     '<td class="rf-cal-sp-inp-ctnr">' +
816                     '<input id="' + id + '" name="' + id + '" class="rf-cal-sp-inp" type="text" />' +
817                     '</td>' +
818                     '<td class="rf-cal-sp-btn">' +
819                     '<table border="0" cellspacing="0" cellpadding="0"><tbody>' +
820                     '<tr><td>' +
821                     '<div id="' + id + 'BtnUp" class="rf-cal-sp-up"' +
822                     ' onmousedown="this.className=\'rf-cal-sp-up rf-cal-sp-press\'"' +
823                     ' onmouseup="this.className=\'rf-cal-sp-up\'"' +
824                     ' onmouseout="this.className=\'rf-cal-sp-up\'"><span></span></div>' +
825                     '</td></tr>' +
826                     '<tr><td>' +
827                     '<div id="' + id + 'BtnDown" class="rf-cal-sp-down"' +
828                     ' onmousedown="this.className=\'rf-cal-sp-down rf-cal-sp-press\'"' +
829                     ' onmouseup="this.className=\'rf-cal-sp-down\'"' +
830                     ' onmouseout="this.className=\'rf-cal-sp-down\'"><span></span></div>' +
831                     '</td></tr>' +
832                     '</tbody></table>' +
833                     '</td>' +
834                     '</tr></tbody></table>';
835             },
836 
837             setTimeProperties: function() {
838                 this.timeType = 0;
839 
840                 var dateTimePattern = this.options.datePattern;
841                 var pattern = [];
842                 var re = /(\\\\|\\[yMdaHhms])|(y+|M+|d+|a|H{1,2}|h{1,2}|m{2}|s{2})/g;
843                 var r;
844                 while (r = re.exec(dateTimePattern))
845                     if (!r[1])
846                         pattern.push({str:r[0],marker:r[2],idx:r.index});
847 
848                 var datePattern = "";
849                 var timePattern = "";
850 
851                 var digits,h,hh,m,s,a;
852                 var id = this.id;
853 
854                 var getString = function (p) {
855                     return (p.length == 0 ? obj.marker : dateTimePattern.substring(pattern[i - 1].str.length + pattern[i - 1].idx, obj.idx + obj.str.length));
856                 };
857 
858                 for (var i = 0; i < pattern.length; i++) {
859                     var obj = pattern[i];
860                     var ch = obj.marker.charAt(0);
861                     if (ch == 'y' || ch == 'M' || ch == 'd') datePattern += getString(datePattern);
862                     else if (ch == 'a') {
863                         a = true;
864                         timePattern += getString(timePattern);
865                     }
866                     else if (ch == 'H') {
867                         h = true;
868                         digits = obj.marker.length;
869                         timePattern += getString(timePattern);
870                     }
871                     else if (ch == 'h') {
872                         hh = true;
873                         digits = obj.marker.length;
874                         timePattern += getString(timePattern);
875                     }
876                     else if (ch == 'm') {
877                         m = true;
878                         timePattern += getString(timePattern);
879                     }
880                     else if (ch == 's') {
881                         this.showSeconds = true;
882                         timePattern += getString(timePattern);
883                     }
884 
885 
886                 }
887                 this.datePattern = datePattern;
888                 this.timePattern = timePattern;
889 
890                 var calendar = this;
891 
892                 this.timePatternHtml = timePattern.replace(/(\\\\|\\[yMdaHhms])|(H{1,2}|h{1,2}|m{2}|s{2}|a)/g,
893                     function($1, $2, $3) {
894                         if ($2) return $2.charAt(1);
895                         switch ($3) {
896                             case 'a'  :
897                                 return '</td><td>' + calendar.createSpinnerTable(id + 'TimeSign') + '</td><td>';
898                             case 'H'  :
899                             case 'HH' :
900                             case 'h'  :
901                             case 'hh' :
902                                 return '</td><td>' + calendar.createSpinnerTable(id + 'TimeHours') + '</td><td>';
903                             case 'mm' :
904                                 return '</td><td>' + calendar.createSpinnerTable(id + 'TimeMinutes') + '</td><td>';
905                             case 'ss' :
906                                 return '</td><td>' + calendar.createSpinnerTable(id + 'TimeSeconds') + '</td><td>';
907                         }
908                     }
909                 );
910 
911                 this.timePatternHtml = '<table border="0" cellpadding="0"><tbody><tr><td>' + this.timePatternHtml + '</td></tr></tbody></table>';
912 
913                 if (m && h) {
914                     this.timeType = 1;
915                 }
916                 else if (m && hh && a) {
917                     this.timeType = 2;
918                 }
919                 this.timeHoursDigits = digits;
920             },
921 
922             eventOnScroll: function (e) {
923                 this.hidePopup();
924             },
925 
926             hidePopup: function() {
927 
928                 if (!this.options.popup || !this.isVisible) return;
929 
930                 if (this.invokeEvent("hide", rf.getDomElement(this.id))) {
931                     if (this.isEditorVisible) this.hideEditor();
932                     this.scrollElements && rf.Event.unbindScrollEventHandlers(this.scrollElements, this);
933                     this.scrollElements = null;
934                     rf.Event.unbind(window.document, "click" + this.namespace);
935 
936                     $(rf.getDomElement(this.CALENDAR_CONTENT)).hide();
937                     this.isVisible = false;
938                     if (this.options.defaultLabel && !this.isFocused) {
939                         updateDefaultLabel.call(this, this.options.defaultLabel);
940                     }
941                 }
942             },
943 
944             showPopup: function(e) {
945                 if (!this.isRendered) {
946                     this.isRendered = true;
947                     this.render();
948                 }
949                 this.skipEventOnCollapse = false;
950                 if (e && e.type == 'click') this.skipEventOnCollapse = true;
951                 if (!this.options.popup || this.isVisible) return;
952 
953                 var element = rf.getDomElement(this.id);
954 
955                 if (this.invokeEvent("show", element, e)) {
956                     var base = rf.getDomElement(this.POPUP_ID)
957                     var baseInput = base.firstChild;
958                     var baseButton = baseInput.nextSibling;
959 
960                     if (this.options.defaultLabel) {
961                         if (!this.isFocused) updateDefaultLabel.call(this, "");
962                     }
963                     if (baseInput.value) {
964                         this.__selectDate(baseInput.value, false, {event:e, element:element});
965                     }
966 
967                     //rect calculation
968 
969                     if (this.options.showInput) {
970                         base = base.children;
971                     } else {
972                         base = baseButton;
973                     }
974                     ;
975 
976                     $(rf.getDomElement(this.CALENDAR_CONTENT)).setPosition(base, {type:"DROPDOWN", from: this.options.jointPoint, to:this.options.direction, offset: this.popupOffset}).show();
977 
978                     this.isVisible = true;
979 
980                     rf.Event.bind(window.document, "click" + this.namespace, this.eventOnCollapse, this);
981 
982                     this.scrollElements && rf.Event.unbindScrollEventHandlers(this.scrollElements, this);
983                     this.scrollElements = null;
984                     if (this.options.hidePopupOnScroll) {
985                         this.scrollElements = rf.Event.bindScrollEventHandlers(element, this.eventOnScroll, this);
986                     }
987                 }
988             },
989 
990             switchPopup: function(e) {
991                 this.isVisible ? this.hidePopup() : this.showPopup(e);
992             },
993 
994             eventOnCollapse: function (e) {
995                 if (this.skipEventOnCollapse) {
996                     this.skipEventOnCollapse = false;
997                     return true;
998                 }
999 
1000                 if (e.target.id == this.POPUP_BUTTON_ID || (!this.options.enableManualInput && e.target.id == this.INPUT_DATE_ID)) return true;
1001 
1002                 this.hidePopup();
1003 
1004                 return true;
1005             },
1006 
1007             setInputField: function(dateStr, event) {
1008                 var field = rf.getDomElement(this.INPUT_DATE_ID);
1009                 if (field.value != dateStr) {
1010                     field.value = dateStr;
1011                     this.invokeEvent("change", rf.getDomElement(this.id), event, this.selectedDate);
1012                     $(rf.getDomElement(this.INPUT_DATE_ID)).blur();
1013                 }
1014             },
1015 
1016             getCurrentDate: function() {
1017                 return this.currentDate;
1018             },
1019             __getSelectedDate: function() {
1020                 if (!this.selectedDate) return null; else return this.selectedDate;
1021             },
1022             __getSelectedDateString: function(pattern) {
1023                 if (!this.selectedDate) return "";
1024                 if (!pattern) pattern = this.options.datePattern;
1025                 return rf.calendarUtils.formatDate(this.selectedDate, pattern, this.options.monthLabels, this.options.monthLabelsShort);
1026             },
1027 
1028             getPrevYear: function() {
1029                 var value = this.currentDate.getFullYear() - 1;
1030                 if (value < 0) value = 0;
1031                 return value;
1032             },
1033             getPrevMonth: function(asMonthLabel) {
1034                 var value = this.currentDate.getMonth() - 1;
1035                 if (value < 0) value = 11;
1036                 if (asMonthLabel) {
1037                     return this.options.monthLabels[value];
1038                 } else return value;
1039             },
1040             getCurrentYear: function() {
1041                 return this.currentDate.getFullYear();
1042             },
1043             getCurrentMonth: function(asMonthLabel) {
1044                 var value = this.currentDate.getMonth();
1045                 if (asMonthLabel) {
1046                     return this.options.monthLabels[value];
1047                 } else return value;
1048             },
1049             getNextYear: function() {
1050                 return this.currentDate.getFullYear() + 1;
1051             },
1052             getNextMonth: function(asMonthLabel) {
1053                 var value = this.currentDate.getMonth() + 1;
1054                 if (value > 11) value = 0;
1055                 if (asMonthLabel) {
1056                     return this.options.monthLabels[value];
1057                 } else return value;
1058             },
1059 
1060             isWeekend: function(weekday) {
1061                 return (weekday == this.firstWeekendDayNumber || weekday == this.secondWeekendDayNumber);
1062             },
1063 
1064             setupTimeForDate: function (date) {
1065                 var result = new Date(date);
1066                 if (this.selectedDate && (!this.options.resetTimeOnDateSelect ||
1067                     (this.selectedDate.getFullYear() == date.getFullYear() &&
1068                         this.selectedDate.getMonth() == date.getMonth() &&
1069                         this.selectedDate.getDate() == date.getDate()))) {
1070                     result = rf.calendarUtils.createDate(date.getFullYear(), date.getMonth(), date.getDate(), this.selectedDate.getHours(), this.selectedDate.getMinutes(), this.selectedDate.getSeconds());
1071                 } else {
1072                     result = rf.calendarUtils.createDate(date.getFullYear(), date.getMonth(), date.getDate(), this.options.defaultTime.hours, this.options.defaultTime.minutes, this.options.defaultTime.seconds);
1073                 }
1074                 return result;
1075             },
1076 
1077             eventCellOnClick: function (e, obj) {
1078                 var daydata = this.days[parseInt(obj.id.substr(this.DATE_ELEMENT_ID.length), 10)];
1079                 if (daydata.enabled && daydata._month == 0) {
1080                     var date = rf.calendarUtils.createDate(this.currentDate.getFullYear(), this.currentDate.getMonth(), daydata.day);
1081                     if (this.timeType) {
1082                         date = this.setupTimeForDate(date);
1083                     }
1084 
1085                     if (this.__selectDate(date, true, {event:e, element:obj}) && !this.options.showApplyButton) {
1086                         this.hidePopup();
1087                     }
1088 
1089                 } else if (daydata._month != 0) {
1090                     if (this.options.boundaryDatesMode == "scroll")
1091                         if (daydata._month == -1) this.prevMonth(); else this.nextMonth();
1092                     else if (this.options.boundaryDatesMode == "select") {
1093                         var date = new Date(daydata.date);
1094                         if (this.timeType) {
1095                             date = this.setupTimeForDate(date);
1096                         }
1097 
1098                         if (this.__selectDate(date, false, {event:e, element:obj}) && !this.options.showApplyButton) {
1099                             this.hidePopup();
1100                         }
1101                     }
1102                 }
1103             },
1104 
1105             eventCellOnMouseOver: function (e, obj) {
1106                 var daydata = this.days[parseInt(obj.id.substr(this.DATE_ELEMENT_ID.length), 10)];
1107                 if (this.invokeEvent("datemouseover", obj, e, daydata.date) && daydata.enabled) {
1108                     if (daydata._month == 0 && obj.id != this.selectedDateCellId && obj.id != this.todayCellId) {
1109                         $(obj).addClass('rf-cal-hov');
1110                     }
1111                 }
1112             },
1113 
1114             eventCellOnMouseOut: function (e, obj) {
1115                 var daydata = this.days[parseInt(obj.id.substr(this.DATE_ELEMENT_ID.length), 10)];
1116                 if (this.invokeEvent("datemouseout", obj, e, daydata.date) && daydata.enabled) {
1117                     if (daydata._month == 0 && obj.id != this.selectedDateCellId && obj.id != this.todayCellId) {
1118                         $(obj).removeClass('rf-cal-hov');
1119                     }
1120                 }
1121             },
1122 
1123             load:function(daysData, isAjaxMode) {
1124                 //	startDate,
1125                 //	daysData:array[]
1126                 //	{
1127                 //			day
1128                 //			enabled boolean
1129                 //			text1: 'Meeting...',
1130                 //			text2: 'Meeting...'
1131                 //			tooltip
1132                 //			hasTooltip
1133                 //			styleClass
1134                 //	}
1135 
1136 
1137                 if (daysData) {
1138                     this.daysData = this.indexData(daysData, isAjaxMode);
1139                 } else {
1140                     this.daysData = null;
1141                 }
1142 
1143                 this.isRendered = false;
1144                 if (this.isVisible) {
1145                     this.render();
1146                 }
1147                 ;
1148 
1149                 if (typeof this.afterLoad == 'function') {
1150                     this.afterLoad();
1151                     this.afterLoad = null;
1152                 }
1153             },
1154 
1155             indexData:function(daysData, isAjaxMode) {
1156 
1157                 var dateYear = daysData.startDate.year;
1158                 var dateMonth = daysData.startDate.month;
1159                 daysData.startDate = new Date(dateYear, dateMonth)
1160 
1161                 daysData.index = [];
1162                 daysData.index[dateYear + '-' + dateMonth] = 0;
1163                 if (isAjaxMode) {
1164                     this.currentDate = daysData.startDate;
1165                     this.currentDate.setDate(1);
1166                     return daysData;
1167                 }
1168                 var idx = rf.calendarUtils.daysInMonthByDate(daysData.startDate) - daysData.startDate.getDate() + 1;
1169 
1170                 while (daysData.days[idx]) {
1171                     if (dateMonth == 11) {
1172                         dateYear++;
1173                         dateMonth = 0;
1174                     } else dateMonth++;
1175                     daysData.index[dateYear + '-' + dateMonth] = idx;
1176                     idx += (32 - new Date(dateYear, dateMonth, 32).getDate());
1177                 }
1178                 return daysData;
1179             },
1180 
1181             getCellBackgroundColor: function(element) {
1182                 return $(element).css('background-color');
1183             },
1184 
1185             clearEffect: function (element_id, className, className1) {
1186                 if (element_id) {
1187                     var e = $(rf.getDomElement(element_id)).stop(true, true);
1188                     if (className) e.removeClass(className);
1189                     if (className1) e.addClass(className1);
1190                 }
1191                 return null;
1192             },
1193 
1194             render:function() {
1195                 //var _d=new Date();
1196                 this.isRendered = true;
1197                 this.todayDate = new Date();
1198 
1199                 var currentYear = this.getCurrentYear();
1200                 var currentMonth = this.getCurrentMonth();
1201 
1202                 var todayflag = (currentYear == this.todayDate.getFullYear() && currentMonth == this.todayDate.getMonth());
1203                 var todaydate = this.todayDate.getDate();
1204 
1205                 var selectedflag = this.selectedDate && (currentYear == this.selectedDate.getFullYear() && currentMonth == this.selectedDate.getMonth())
1206                 var selecteddate = this.selectedDate && this.selectedDate.getDate();
1207 
1208                 var wd = rf.calendarUtils.getDay(this.currentDate, this.options.firstWeekDay);
1209                 var currentMonthDays = rf.calendarUtils.daysInMonthByDate(this.currentDate);
1210                 var previousMonthDays = rf.calendarUtils.daysInMonth(currentYear, currentMonth - 1);
1211 
1212                 var p = 0;
1213                 var month = -1;
1214                 this.days = [];
1215                 var dayCounter = previousMonthDays - wd + 1;
1216 
1217                 // previuos month days
1218                 if (wd > 0) while (dayCounter <= previousMonthDays) {
1219                     this.days.push({day:dayCounter, isWeekend: this.isWeekend(p), _month:month});
1220                     dayCounter++;
1221                     p++;
1222                 }
1223 
1224                 dayCounter = 1;
1225                 month = 0;
1226 
1227                 this.firstDateIndex = p;
1228 
1229                 // current month days
1230                 if (this.daysData && this.daysData.index[currentYear + '-' + currentMonth] != undefined) {
1231                     var idx = this.daysData.index[currentYear + '-' + currentMonth];
1232                     if (this.daysData.startDate.getFullYear() == currentYear && this.daysData.startDate.getMonth() == currentMonth) {
1233                         var firstDay = firstDay = (this.daysData.days[idx].day ? this.daysData.days[idx].day : this.daysData.startDate.getDate());
1234                         while (dayCounter < firstDay) {
1235                             this.days.push({day:dayCounter, isWeekend:this.isWeekend(p % 7), _month:month});
1236 
1237                             dayCounter++;
1238                             p++;
1239                         }
1240                     }
1241 
1242                     var len = this.daysData.days.length;
1243                     var obj;
1244                     var flag;
1245                     while (idx < len && dayCounter <= currentMonthDays) {
1246                         flag = this.isWeekend(p % 7);
1247                         obj = this.daysData.days[idx];
1248                         obj.day = dayCounter;
1249                         obj.isWeekend = flag;
1250                         obj._month = month;
1251                         this.days.push(obj);
1252                         idx++;
1253                         dayCounter++;
1254                         p++;
1255                     }
1256                 }
1257                 while (p < 42) {
1258                     if (dayCounter > currentMonthDays) {
1259                         dayCounter = 1;
1260                         month = 1;
1261                     }
1262                     this.days.push({day:dayCounter, isWeekend: this.isWeekend(p % 7), _month:month});
1263                     dayCounter++;
1264                     p++;
1265                 }
1266 
1267                 // render
1268                 this.renderHF();
1269 
1270                 //days render
1271                 p = 0;
1272                 var element;
1273                 var dataobj;
1274                 var wn;
1275                 if (this.options.showWeeksBar) wn = rf.calendarUtils.weekNumber(currentYear, currentMonth, this.options.minDaysInFirstWeek, this.options.firstWeekDay); /// fix it
1276                 this.selectedDayElement = null;
1277                 var weekflag = true;
1278 
1279                 var e;
1280 
1281                 var boundaryDatesModeFlag = (this.options.boundaryDatesMode == "scroll" || this.options.boundaryDatesMode == "select");
1282 
1283                 this.todayCellId = this.clearEffect(this.todayCellId);
1284                 this.selectedDateCellId = this.clearEffect(this.selectedDateCellId);
1285 
1286                 //var _d=new Date();
1287                 var obj = rf.getDomElement(this.WEEKNUMBER_BAR_ID + "1");
1288                 for (var k = 1; k < 7; k++) {
1289                     //
1290                     dataobj = this.days[p];
1291 
1292                     element = obj.firstChild;
1293                     var weeknumber;
1294 
1295                     // week number update
1296                     if (this.options.showWeeksBar) {
1297                         // TODO: fix:  there is no weekNumber in dataobj if showWeeksBar == false;
1298                         if (weekflag && currentMonth == 11 &&
1299                             (k == 5 || k == 6) &&
1300                             (dataobj._month == 1 || (7 - (currentMonthDays - dataobj.day + 1)) >= this.options.minDaysInFirstWeek)) {
1301                             wn = 1;
1302                             weekflag = false;
1303                         }
1304                         weeknumber = wn;
1305                         element.innerHTML = this.evaluateMarkup(this.options.weekNumberMarkup, {weekNumber: wn++, elementId:element.id, component:this});
1306                         if (k == 1 && wn > 52) wn = 1;
1307                         element = element.nextSibling;
1308                     }
1309 
1310                     var weekdaycounter = this.options.firstWeekDay;
1311                     var contentElement = null;
1312 
1313                     while (element) {
1314                         dataobj.elementId = element.id;
1315                         dataobj.date = new Date(currentYear, currentMonth + dataobj._month, dataobj.day);
1316                         dataobj.weekNumber = weeknumber;
1317                         dataobj.component = this;
1318                         dataobj.isCurrentMonth = (dataobj._month == 0);
1319                         dataobj.weekDayNumber = weekdaycounter;
1320 
1321                         // call user function to get day state
1322                         if (dataobj.enabled != false) dataobj.enabled = this.options.isDayEnabled(dataobj);
1323                         // call user function to custom class style
1324                         if (!dataobj.styleClass) dataobj.customStyleClass = this.options.dayStyleClass(dataobj);
1325                         else {
1326                             var styleclass = this.options.dayStyleClass(dataobj);
1327                             dataobj.customStyleClass = dataobj.styleClass;
1328                             if (styleclass) dataobj.customStyleClass += " " + styleclass;
1329                         }
1330 
1331                         contentElement = (this.customDayListMarkup ? element.firstChild : element);
1332                         contentElement.innerHTML = this.hideBoundaryDatesContent && dataobj._month != 0 ? "" : this.evaluateMarkup(this.options.dayListMarkup, dataobj);
1333 
1334                         if (weekdaycounter == 6) weekdaycounter = 0; else weekdaycounter++;
1335 
1336                         var classNames = this.dayCellClassName[p];
1337 
1338                         // class styles
1339                         if (dataobj._month != 0) {
1340                             classNames += ' rf-cal-boundary-day';
1341                             if (!this.options.disabled && !this.options.readonly && boundaryDatesModeFlag) {
1342                                 classNames += ' rf-cal-btn';
1343                             }
1344                         }
1345                         else {
1346                             if (todayflag && dataobj.day == todaydate) {
1347                                 this.todayCellId = element.id;
1348                                 this.todayCellColor = this.getCellBackgroundColor(element);
1349                                 classNames += " rf-cal-today";
1350                             }
1351 
1352                             if (selectedflag && dataobj.day == selecteddate) {
1353                                 this.selectedDateCellId = element.id;
1354                                 this.selectedDateCellColor = this.getCellBackgroundColor(element);
1355                                 classNames += " rf-cal-sel";
1356                             }
1357                             else if (!this.options.disabled && !this.options.readonly && dataobj.enabled) classNames += ' rf-cal-btn';
1358 
1359                             // add custom style class
1360                             if (dataobj.customStyleClass) {
1361                                 classNames += ' ' + dataobj.customStyleClass;
1362                             }
1363                         }
1364                         element.className = classNames;
1365 
1366                         p++;
1367 
1368                         dataobj = this.days[p];
1369                         element = element.nextSibling;
1370                     }
1371                     obj = obj.nextSibling;
1372                 }
1373 
1374                 //alert(new Date().getTime()-_d.getTime());
1375 
1376             },
1377 
1378             renderHF: function() {
1379                 if (this.options.showHeader) this.renderMarkup(this.options.headerMarkup, this.id + "Header", this.calendarContext);
1380                 if (this.options.showFooter) this.renderMarkup(this.options.footerMarkup, this.id + "Footer", this.calendarContext);
1381 
1382                 this.renderHeaderOptional();
1383                 this.renderFooterOptional();
1384             },
1385 
1386             renderHeaderOptional: function() {
1387                 this.renderMarkup(this.options.optionalHeaderMarkup, this.id + "HeaderOptional", this.calendarContext);
1388             },
1389 
1390             renderFooterOptional: function() {
1391                 this.renderMarkup(this.options.optionalFooterMarkup, this.id + "FooterOptional", this.calendarContext);
1392             },
1393 
1394             renderMarkup: function (markup, elementId, context) {
1395                 if (!markup) return;
1396 
1397                 var e = rf.getDomElement(elementId);
1398                 if (!e) return;
1399 
1400                 e.innerHTML = this.evaluateMarkup(markup, context);
1401             },
1402 
1403             evaluateMarkup: function(markup, context) {
1404                 if (!markup) return "";
1405 
1406                 var result = [];
1407                 var m;
1408                 for (var i = 0; i < markup.length; i++) {
1409                     m = markup[i];
1410                     if (m['getContent']) {
1411                         result.push(m.getContent(context));
1412                     }
1413                 }
1414                 return result.join('');
1415             },
1416 
1417             onUpdate: function() {
1418                 var formattedDate = rf.calendarUtils.formatDate(this.getCurrentDate(), "MM/yyyy");
1419                 rf.getDomElement(this.id + 'InputCurrentDate').value = formattedDate;
1420 
1421                 if (this.isAjaxMode && this.callAjax)
1422                     this.callAjax.call(this, formattedDate);
1423                 else
1424                     this.render();
1425             },
1426 
1427             callAjax: function(calendar, date) {
1428                 var _this = this;
1429                 var ajaxSuccess = function (event) {
1430                     var dataDays = event && event.componentData && event.componentData[_this.id];
1431                     _this.load(dataDays, true);
1432                 }
1433                 var ajaxError = function (event) {
1434                     // do nothing
1435                 }
1436                 var params = {};
1437                 params[this.id + ".ajax"] = "1";
1438 
1439                 rf.ajax(this.id, null, {parameters: params, error: ajaxError, complete:ajaxSuccess});
1440 
1441             },
1442 
1443             nextMonth: function() {
1444                 this.changeCurrentDateOffset(0, 1);
1445             },
1446 
1447             prevMonth: function() {
1448                 this.changeCurrentDateOffset(0, -1);
1449             },
1450 
1451             nextYear: function() {
1452                 this.changeCurrentDateOffset(1, 0);
1453             },
1454 
1455             prevYear: function() {
1456                 this.changeCurrentDateOffset(-1, 0);
1457             },
1458 
1459             changeCurrentDate: function(year, month, noUpdate) {
1460                 if (this.getCurrentMonth() != month || this.getCurrentYear() != year) {
1461                     var date = new Date(year, month, 1);
1462                     if (this.invokeEvent("beforecurrentdateselect", rf.getDomElement(this.id), null, date)) {
1463                         // fix for RF-2450.
1464                         // Additional event is fired: after the hidden input with current date
1465                         // value is updated in function onUpdate() and then
1466                         // the "currentdateselected" Event is fired.
1467                         this.currentDate = date;
1468                         if (noUpdate) this.render(); else this.onUpdate();
1469                         this.invokeEvent("currentdateselect", rf.getDomElement(this.id), null, date);
1470                         return true;
1471                     }
1472                 }
1473                 return false;
1474             },
1475 
1476             changeCurrentDateOffset: function(yearOffset, monthOffset) {
1477                 var date = new Date(this.currentDate.getFullYear() + yearOffset, this.currentDate.getMonth() + monthOffset, 1);
1478 
1479                 if (this.invokeEvent("beforecurrentdateselect", rf.getDomElement(this.id), null, date)) {
1480                     // fix for RF-2450.
1481                     // Additional event is fired: after the hidden input with current date
1482                     // value is updated in function onUpdate() and then
1483                     // the "currentdateselected" Event is fired.
1484                     this.currentDate = date;
1485                     this.onUpdate();
1486                     this.invokeEvent("currentdateselect", rf.getDomElement(this.id), null, date);
1487                 }
1488             },
1489 
1490             today: function(noUpdate, noHighlight) {
1491 
1492                 var now = new Date();
1493 
1494                 var nowyear = now.getFullYear();
1495                 var nowmonth = now.getMonth();
1496                 var nowdate = now.getDate();
1497                 var updateflag = false;
1498 
1499                 if (nowdate != this.todayDate.getDate()) {
1500                     updateflag = true;
1501                     this.todayDate = now;
1502                 }
1503 
1504                 if (nowyear != this.currentDate.getFullYear() || nowmonth != this.currentDate.getMonth()) {
1505                     updateflag = true;
1506                     this.currentDate = new Date(nowyear, nowmonth, 1);
1507                 }
1508 
1509                 if (this.options.todayControlMode == 'select') {
1510                     noHighlight = true;
1511                 }
1512 
1513                 if (updateflag) {
1514                     if (noUpdate) this.render(); else this.onUpdate();
1515                 }
1516                 else {
1517                     // highlight today
1518 
1519                     if (this.isVisible && this.todayCellId && !noHighlight) {
1520                         this.clearEffect(this.todayCellId);
1521                         if (this.todayCellColor != "transparent") {
1522                             $(rf.getDomElement(this.todayCellId)).effect("highlight", {easing:'easeInOutSine', color: this.todayCellColor}, 300);
1523                         }
1524                     }
1525                 }
1526 
1527                 // todayControl select mode
1528                 if (this.options.todayControlMode == 'select' && !this.options.disabled && !this.options.readonly)
1529                     if (updateflag && !noUpdate && this.submitFunction) {
1530                         this.afterLoad = this.selectToday;
1531                     }
1532                     else this.selectToday();
1533 
1534             },
1535 
1536             selectToday: function() {
1537                 if (this.todayCellId) {
1538                     var daydata = this.days[parseInt(this.todayCellId.substr(this.DATE_ELEMENT_ID.length), 10)];
1539                     var today = new Date();
1540                     var date = new Date(today);
1541                     if (this.timeType) {
1542                         date = this.setupTimeForDate(date);
1543                     }
1544                     if (daydata.enabled && this.__selectDate(date, true) && !this.options.showApplyButton) {
1545                         this.hidePopup();
1546                     }
1547                 }
1548             },
1549 
1550             __selectDate: function(date, noUpdate, eventData, applySelection) {
1551 
1552                 if (!eventData) {
1553                     eventData = {event: null, element: null};
1554                 }
1555 
1556                 if (typeof applySelection === "undefined") {
1557                     applySelection = !this.options.showApplyButton
1558                 }
1559 
1560                 var oldSelectedDate = this.selectedDate;
1561                 var newSelectedDate;
1562                 if (date) {
1563                     if (typeof date == 'string') {
1564                         date = rf.calendarUtils.parseDate(date, this.options.datePattern, this.options.monthLabels, this.options.monthLabelsShort);
1565                     }
1566                     newSelectedDate = date;
1567                 }
1568                 else {
1569                     newSelectedDate = null;
1570                 }
1571 
1572                 // fire user event
1573                 var flag = true;
1574                 var isDateChange = false;
1575                 if ((oldSelectedDate - newSelectedDate) && (oldSelectedDate != null || newSelectedDate != null)) {
1576                     isDateChange = true;
1577                     flag = this.invokeEvent("beforedateselect", eventData.element, eventData.event, date);
1578                 }
1579 
1580                 if (flag) {
1581                     if (newSelectedDate != null) {
1582                         if (newSelectedDate.getMonth() == this.currentDate.getMonth() && newSelectedDate.getFullYear() == this.currentDate.getFullYear()) {
1583                             this.selectedDate = newSelectedDate;
1584                             if (!oldSelectedDate || (oldSelectedDate - this.selectedDate)) {
1585                                 // find cell and change style class
1586                                 var e = $(rf.getDomElement(this.DATE_ELEMENT_ID + (this.firstDateIndex + this.selectedDate.getDate() - 1)));
1587 
1588                                 this.clearEffect(this.selectedDateCellId, "rf-cal-sel", (this.options.disabled || this.options.readonly ? null : "rf-cal-btn"));
1589                                 this.selectedDateCellId = e.attr('id');
1590                                 this.selectedDateCellColor = this.getCellBackgroundColor(e);
1591 
1592                                 e.removeClass("rf-cal-btn");
1593                                 e.removeClass("rf-cal-hov");
1594                                 e.addClass("rf-cal-sel");
1595 
1596                                 this.renderHF();
1597                             }
1598                             else if (this.timeType != 0) this.renderHF();
1599                         }
1600                         else {
1601                             //RF-5600
1602                             this.selectedDate = newSelectedDate;
1603 
1604                             // change currentDate and call this.onUpdate();
1605                             if (this.changeCurrentDate(newSelectedDate.getFullYear(), newSelectedDate.getMonth(), noUpdate)) {
1606                                 //this.selectedDate = newSelectedDate;
1607                             } else {
1608                                 this.selectedDate = oldSelectedDate;
1609                                 isDateChange = false;
1610                             }
1611                         }
1612                     }
1613                     else {
1614                         this.selectedDate = null;
1615 
1616                         this.clearEffect(this.selectedDateCellId, "rf-cal-sel", (this.options.disabled || this.options.readonly ? null : "rf-cal-btn"));
1617 
1618                         if (this.selectedDateCellId) {
1619                             this.selectedDateCellId = null;
1620                             this.renderHF();
1621                         }
1622 
1623                         var date = new Date();
1624                         if (this.currentDate.getMonth() == date.getMonth() && this.currentDate.getFullYear() == date.getFullYear()) {
1625                             this.renderHF();
1626                         }
1627 
1628                         var todayControlMode = this.options.todayControlMode;
1629                         this.options.todayControlMode = '';
1630                         this.today(noUpdate, true);
1631                         this.options.todayControlMode = todayControlMode;
1632                     }
1633 
1634                     // call user event
1635                     if (isDateChange) {
1636                         this.invokeEvent("dateselect", eventData.element, eventData.event, this.selectedDate);
1637                         if (applySelection === true) {
1638                             this.setInputField(this.selectedDate != null ? this.__getSelectedDateString(this.options.datePattern) : "", eventData.event);
1639                         }
1640                     }
1641                 }
1642 
1643                 return isDateChange;
1644             },
1645 
1646             __resetSelectedDate: function() {
1647                 if (!this.selectedDate) return;
1648                 if (this.invokeEvent("beforedateselect", null, null, null)) {
1649                     this.selectedDate = null;
1650                     this.invokeEvent("dateselect", null, null, null);
1651 
1652                     this.selectedDateCellId = this.clearEffect(this.selectedDateCellId, "rf-cal-sel", (this.options.disabled || this.options.readonly ? null : "rf-cal-btn"));
1653                     this.invokeEvent("clean", null, null, null);
1654                     this.renderHF();
1655                     if (!this.options.showApplyButton) {
1656                         this.setInputField("", null);
1657                         this.hidePopup();
1658                     }
1659                 }
1660             },
1661 
1662             showSelectedDate: function() {
1663                 if (!this.selectedDate) return;
1664                 if (this.currentDate.getMonth() != this.selectedDate.getMonth() || this.currentDate.getFullYear() != this.selectedDate.getFullYear()) {
1665                     this.currentDate = new Date(this.selectedDate);
1666                     this.currentDate.setDate(1);
1667                     this.onUpdate();
1668                 }
1669                 else {
1670                     // highlight Selected Date
1671                     if (this.isVisible && this.selectedDateCellId) {
1672                         this.clearEffect(this.selectedDateCellId);
1673                         if (this.selectedDateCellColor != "transparent") {
1674                             $(rf.getDomElement(this.selectedDateCellId)).effect("highlight", {easing:'easeInOutSine', color: this.selectedDateCellColor}, 300);
1675 
1676                         }
1677                     }
1678                 }
1679             },
1680 
1681             close: function(updateDate) {
1682                 if (updateDate) {
1683                     this.setInputField(this.__getSelectedDateString(this.options.datePattern), null);
1684                 }
1685                 this.hidePopup();
1686             },
1687 
1688             clonePosition: function (source, elements, offset) {
1689                 var jqe = $(source);
1690                 if (!elements.length) elements = [elements];
1691                 offset = offset || {left:0,top:0};
1692                 var width = jqe.outerWidth() + "px", height = jqe.outerHeight() + "px";
1693                 var pos = jqe.position();
1694                 var left = Math.floor(pos.left) + offset.left + "px", top = Math.floor(pos.top) + offset.top + "px";
1695                 var element;
1696                 for (var i = 0; i < elements.length; i++) {
1697                     element = elements[i];
1698                     element.style.width = width;
1699                     element.style.height = height;
1700                     element.style.left = left;
1701                     element.style.top = top;
1702                 }
1703             },
1704 
1705             showTimeEditor: function() {
1706                 var editor;
1707                 if (this.timeType == 0) return;
1708                 if (!this.isEditorCreated) editor = this.createEditor();
1709                 else editor = rf.getDomElement(this.EDITOR_ID);
1710                 if (!this.isTimeEditorLayoutCreated) this.createTimeEditorLayout(editor);
1711 
1712                 $(rf.getDomElement(this.TIME_EDITOR_LAYOUT_ID)).show();
1713 
1714                 var editor_shadow = rf.getDomElement(this.EDITOR_SHADOW_ID);
1715 
1716                 this.clonePosition(rf.getDomElement(this.CALENDAR_CONTENT), [editor, editor_shadow]);
1717 
1718                 this.updateTimeEditor();
1719 
1720                 $(editor_shadow).show();
1721 
1722                 $(editor).show();
1723 
1724                 this.clonePosition(rf.getDomElement(this.TIME_EDITOR_LAYOUT_ID), rf.getDomElement(this.EDITOR_LAYOUT_SHADOW_ID), {left: 3, top: 3});
1725                 this.isEditorVisible = true;
1726             },
1727 
1728             hideEditor: function() {
1729                 if (this.isTimeEditorLayoutCreated) $(rf.getDomElement(this.TIME_EDITOR_LAYOUT_ID)).hide();
1730                 if (this.isDateEditorLayoutCreated) $(rf.getDomElement(this.DATE_EDITOR_LAYOUT_ID)).hide();
1731                 $(rf.getDomElement(this.EDITOR_ID)).hide();
1732                 $(rf.getDomElement(this.EDITOR_SHADOW_ID)).hide();
1733                 this.isEditorVisible = false;
1734             },
1735 
1736             hideTimeEditor: function(updateTime) {
1737                 this.hideEditor();
1738                 if (updateTime && this.selectedDate) {
1739                     var s = this.showSeconds ? parseInt(rf.getDomElement(this.id + 'TimeSeconds').value, 10) : this.options.defaultTime.seconds;
1740                     var m = parseInt(rf.getDomElement(this.id + 'TimeMinutes').value, 10);
1741                     var h = parseInt(rf.getDomElement(this.id + 'TimeHours').value, 10);
1742                     if (this.timeType == 2) {
1743                         if (rf.getDomElement(this.id + 'TimeSign').value.toLowerCase() == "am") {
1744                             if (h == 12) h = 0;
1745                         }
1746                         else {
1747                             if (h != 12) h += 12;
1748                         }
1749                     }
1750                     var date = rf.calendarUtils.createDate(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), this.selectedDate.getDate(), h, m, s);
1751                     if (date - this.selectedDate && this.invokeEvent("beforetimeselect", null, null, date)) {
1752                         this.selectedDate = date;
1753                         this.renderHF();
1754                         if (!this.options.popup || !this.options.showApplyButton) this.setInputField(this.__getSelectedDateString(this.options.datePattern), null);
1755                         this.invokeEvent("timeselect", null, null, this.selectedDate);
1756                     }
1757                 }
1758                 if (this.options.popup && !this.options.showApplyButton) this.close(false);
1759             },
1760 
1761             showDateEditor: function() {
1762                 var editor;
1763                 if (!this.isEditorCreated) editor = this.createEditor();
1764                 else editor = rf.getDomElement(this.EDITOR_ID);
1765                 if (!this.isDateEditorLayoutCreated) this.createDateEditorLayout(editor);
1766                 else this.updateDateEditor();
1767 
1768                 $(rf.getDomElement(this.DATE_EDITOR_LAYOUT_ID)).show();
1769 
1770                 var editor_shadow = rf.getDomElement(this.EDITOR_SHADOW_ID);
1771 
1772                 this.clonePosition(rf.getDomElement(this.CALENDAR_CONTENT), [editor, editor_shadow]);
1773 
1774                 $(editor_shadow).show();
1775                 $(editor).show();
1776 
1777                 this.clonePosition(rf.getDomElement(this.DATE_EDITOR_LAYOUT_ID), rf.getDomElement(this.EDITOR_LAYOUT_SHADOW_ID), {left: 3, top: 3});
1778 
1779                 this.isEditorVisible = true;
1780             },
1781 
1782             hideDateEditor: function(updateCurrentDate) {
1783                 this.hideEditor();
1784                 if (updateCurrentDate) {
1785                     this.changeCurrentDate(this.dateEditorYear, this.dateEditorMonth);
1786                 }
1787             },
1788 
1789             getValue: function() {
1790                 return this.__getSelectedDate();
1791             },
1792 
1793             getValueAsString: function(pattern) {
1794                 return this.__getSelectedDateString(pattern);
1795             },
1796 
1797             setValue: function(value) {
1798                 this.__selectDate(value, undefined, undefined, true);
1799             },
1800 
1801             resetValue: function() {
1802                 this.__resetSelectedDate();
1803                 if (this.options.defaultLabel && !this.isFocused) {
1804                     updateDefaultLabel.call(this, this.options.defaultLabel);
1805                 }
1806             },
1807 
1808             getNamespace: function () {
1809                 return this.namespace;
1810             }
1811         });
1812 })(RichFaces.jQuery, RichFaces);
1813