      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