1 (function ($, rf) {
  2 
  3     rf.calendarUtils = rf.calendarUtils || {};
  4 
  5     var getDefaultMonthNames = function(shortNames) {
  6         return (shortNames
  7             ? ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
  8             : ['January','February','March','April','May','June','July','August','September','October','November','December']);
  9     };
 10 
 11     $.extend(rf.calendarUtils, {
 12             // TODO: rewrite this function or use the same function if exists
 13             /*clonePosition: function (elements, source)
 14              {
 15              if (!elements.length) elements = [elements];
 16              var offset = Position.cumulativeOffset(source);
 17              offset = {left:offset[0], top:offset[1]};
 18              var offsetTemp;
 19              if (source.style.position!='absolute')
 20              {
 21              offsetTemp = Position.realOffset(source);
 22              offset.left -= offsetTemp.left;
 23              offset.top -= offsetTemp.top;
 24              offsetTemp = Richfaces.Calendar.getWindowScrollOffset();
 25              offset.left += offsetTemp.left;
 26              offset.top += offsetTemp.top;
 27              }
 28 
 29              for (var i=0;i<elements.length;i++)
 30              {
 31              offsetTemp = Richfaces.Calendar.getParentOffset(elements[i]);
 32              elements[i].style.left = (offset.left - offsetTemp.left) + 'px';
 33              elements[i].style.top = (offset.top - offsetTemp.top) + 'px';
 34              }
 35              return offset;
 36              }*/
 37 
 38             //TODO: not used
 39             /*Object.extend(Event, {
 40              findElementByAttr : function(event, tagName, attribute, value, flag) {
 41              var element = Event.findElement(event, tagName);
 42              while (!element[attribute] || (flag ? element[attribute].indexOf(value)!=0 : element[attribute]!=value) )
 43              {
 44              element = element.parentNode;
 45              }
 46              return element;
 47              }
 48              });
 49 
 50              Object.extend(Element, {
 51              replaceClassName : function (element, whichClassName, toClassName) {
 52              if (!(element = $(element))) return;
 53              var e = Element.classNames(element);
 54              e.remove(whichClassName);
 55              e.add(toClassName);
 56              return element;
 57              }
 58              });*/
 59 
 60             // TODO: move joinArray to richfaces utils
 61             joinArray: function(array, begin, end, separator) {
 62                 var value = '';
 63                 if (array.length != 0) value = begin + array.pop() + end;
 64                 while (array.length)
 65                     value = begin + array.pop() + end + separator + value;
 66                 return value;
 67             },
 68 
 69             getMonthByLabel: function (monthLabel, monthNames) {
 70                 var toLowerMonthLabel = monthLabel.toLowerCase();
 71                 var i = 0;
 72                 while (i < monthNames.length) {
 73                     if (monthNames[i].toLowerCase() == toLowerMonthLabel) {
 74                         return i;
 75                     }
 76 
 77                     i++;
 78                 }
 79             },
 80 
 81             createDate: function (yy, mm, dd, h, m, s) {
 82                 h = h || 0;
 83                 m = m || 0;
 84                 s = s || 0;
 85                 var date = new Date(yy, mm, dd, h, m, s);
 86                 if (date.getDate() != dd) {
 87                     date = new Date(yy, mm);
 88                     date.setHours(h);
 89                     date.setMinutes(m);
 90                     date.setSeconds(s);
 91                     date.setUTCDate(dd);
 92                 }
 93                 return date;
 94             },
 95 
 96             /* Year:
 97              *	y,yy - 00-99
 98              *	yyy+ - 1999
 99              * Month:
100              *	M - 1-12
101              *	MM - 01-12
102              *	MMM - short (Jul)
103              *	MMMM+ - long (July)
104              * Date:
105              *	d - 1-31
106              *	dd+ - 01-31 */
107             parseDate: function(dateString, pattern, monthNames, monthNamesShort) {
108                 var re = /([.*+?^<>=!:${}()\[\]\/\\])/g;
109                 var monthNamesStr
110                 var monthNamesShortStr;
111                 if (!monthNames) {
112                     monthNames = getDefaultMonthNames();
113                     monthNamesStr = monthNames.join('|');
114                 } else {
115                     monthNamesStr = monthNames.join('|').replace(re, '\\$1');
116                 }
117 
118                 if (!monthNamesShort) {
119                     monthNamesShort = getDefaultMonthNames(true);
120                     monthNamesShortStr = monthNamesShort.join('|');
121                 } else {
122                     monthNamesShortStr = monthNamesShort.join('|').replace(re, '\\$1');
123                 }
124 
125                 var counter = 1;
126                 var y,m,d;
127                 var a,h,min,s;
128                 var shortLabel = false;
129 
130                 pattern = pattern.replace(/([.*+?^<>=!:${}()|\[\]\/\\])/g, '\\$1');
131                 pattern = pattern.replace(/(y+|M+|d+|a|H{1,2}|h{1,2}|m{2}|s{2})/g,
132                     function($1) {
133                         switch ($1) {
134                             case 'y'  :
135                             case 'yy' :
136                                 y = counter;
137                                 counter++;
138                                 return '(\\d{2})';
139                             case 'MM' :
140                                 m = counter;
141                                 counter++;
142                                 return '(\\d{2})';
143                             case 'M'  :
144                                 m = counter;
145                                 counter++;
146                                 return '(\\d{1,2})';
147                             case 'd'  :
148                                 d = counter;
149                                 counter++;
150                                 return '(\\d{1,2})';
151                             case 'MMM':
152                                 m = counter;
153                                 counter++;
154                                 shortLabel = true;
155                                 return '(' + monthNamesShortStr + ')';
156                             case 'a'  :
157                                 a = counter;
158                                 counter++;
159                                 return '(AM|am|PM|pm)?';
160                             case 'HH' :
161                             case 'hh' :
162                                 h = counter;
163                                 counter++;
164                                 return '(\\d{2})?';
165                             case 'H'  :
166                             case 'h'  :
167                                 h = counter;
168                                 counter++;
169                                 return '(\\d{1,2})?';
170                             case 'mm' :
171                                 min = counter;
172                                 counter++;
173                                 return '(\\d{2})?';
174                             case 'ss' :
175                                 s = counter;
176                                 counter++;
177                                 return '(\\d{2})?';
178 
179                         }
180                         // y+,M+,d+
181                         var ch = $1.charAt(0);
182                         if (ch == 'y') {
183                             y = counter;
184                             counter++;
185                             return '(\\d{3,4})'
186                         }
187                         ;
188                         if (ch == 'M') {
189                             m = counter;
190                             counter++;
191                             return '(' + monthNamesStr + ')'
192                         }
193                         ;
194                         if (ch == 'd') {
195                             d = counter;
196                             counter++;
197                             return '(\\d{2})'
198                         }
199                         ;
200                     }
201                 );
202 
203                 var re = new RegExp(pattern, 'i');
204                 var match = dateString.match(re);
205                 if (match != null && y != undefined && m != undefined) {
206                     // set default century start
207                     var correctYear = false;
208                     var defaultCenturyStart = new Date();
209                     defaultCenturyStart.setFullYear(defaultCenturyStart.getFullYear() - 80);
210 
211                     var yy = parseInt(match[y], 10);
212                     if (isNaN(yy)) return null;
213                     else if (yy < 100) {
214                         // calculate full year if year has only two digits
215                         var defaultCenturyStartYear = defaultCenturyStart.getFullYear();
216                         var ambiguousTwoDigitYear = defaultCenturyStartYear % 100;
217                         correctYear = yy == ambiguousTwoDigitYear;
218                         yy += Math.floor(defaultCenturyStartYear / 100) * 100 + (yy < ambiguousTwoDigitYear ? 100 : 0);
219                     }
220 
221                     var mm = parseInt(match[m], 10);
222                     if (isNaN(mm)) mm = this.getMonthByLabel(match[m], shortLabel ? monthNamesShort : monthNames); else if (--mm < 0 || mm > 11) return null;
223                     var addDay = correctYear ? 1 : 0;
224                     var dd;
225                     if (d != undefined) {
226                         dd = parseInt(match[d], 10);
227                     } else {
228                         dd = 1; // default to the first of the month when the date is not selected
229                     }
230                     if (isNaN(dd) || dd < 1 || dd > this.daysInMonth(yy, mm) + addDay) return null;
231 
232                     var date;
233 
234                     // time parsing
235                     if (min != undefined && h != undefined) {
236                         var hh,mmin,aa;
237                         mmin = parseInt(match[min], 10);
238                         if (isNaN(mmin) || mmin < 0 || mmin > 59) return null;
239                         hh = parseInt(match[h], 10);
240                         if (isNaN(hh)) return null;
241                         if (a != undefined) {
242                             aa = match[a];
243                             if (!aa) return null;
244                             aa = aa.toLowerCase();
245                             if ((aa != 'am' && aa != 'pm') || hh < 1 || hh > 12) return null;
246                             if (aa == 'pm') {
247                                 if (hh != 12) hh += 12;
248                             } else if (hh == 12) hh = 0;
249                         }
250                         else if (hh < 0 || hh > 23) return null;
251 
252                         date = this.createDate(yy, mm, dd, hh, mmin);
253                         if (s != undefined) {
254                             sec = parseInt(match[s], 10);
255                             if (isNaN(sec) || sec < 0 || sec > 59) return null;
256                             date.setSeconds(sec);
257                         }
258                     } else {
259                         date = this.createDate(yy, mm, dd);
260                     }
261 
262                     if (correctYear) {
263                         if (date.getTime() < defaultCenturyStart.getTime()) {
264                             date.setFullYear(yy + 100);
265                         }
266                         if (date.getMonth() != mm) return null;
267                     }
268 
269                     return date;
270                 }
271                 return null;
272             },
273 
274             formatDate: function(date, pattern, monthNames, monthNamesShort) {
275                 if (!monthNames) monthNames = getDefaultMonthNames();
276                 if (!monthNamesShort) monthNamesShort = getDefaultMonthNames(true);
277                 var mm,dd,hh,min,sec;
278                 var result = pattern.replace(/(\\\\|\\[yMdaHhms])|(y+|M+|d+|a|H{1,2}|h{1,2}|m{2}|s{2})/g,
279                     function($1, $2, $3) {
280                         if ($2) return $2.charAt(1);
281                         switch ($3) {
282                             case 'y':
283                             case 'yy':
284                                 return date.getYear().toString().slice(-2);
285                             case 'M':
286                                 return (date.getMonth() + 1);
287                             case 'MM':
288                                 return ((mm = date.getMonth() + 1) < 10 ? '0' + mm : mm);
289                             case 'MMM':
290                                 return monthNamesShort[date.getMonth()];
291                             case 'd':
292                                 return date.getDate();
293                             case 'a'  :
294                                 return (date.getHours() < 12 ? 'AM' : 'PM');
295                             case 'HH' :
296                                 return ((hh = date.getHours()) < 10 ? '0' + hh : hh);
297                             case 'H'  :
298                                 return date.getHours();
299                             case 'hh' :
300                                 return ((hh = date.getHours()) == 0 ? '12' : (hh < 10 ? '0' + hh : (hh > 21 ? hh - 12 : (hh > 12) ? '0' + (hh - 12) : hh)));
301                             case 'h'  :
302                                 return ((hh = date.getHours()) == 0 ? '12' : (hh > 12 ? hh - 12 : hh));
303                             case 'mm' :
304                                 return ((min = date.getMinutes()) < 10 ? '0' + min : min);
305                             case 'ss' :
306                                 return ((sec = date.getSeconds()) < 10 ? '0' + sec : sec);
307                         }
308                         // y+,M+,d+
309                         var ch = $3.charAt(0);
310                         if (ch == 'y') return date.getFullYear();
311                         if (ch == 'M') return monthNames[date.getMonth()];
312                         if (ch == 'd') return ((dd = date.getDate()) < 10 ? '0' + dd : dd);
313                     }
314                 );
315                 return result;
316             },
317 
318             isLeapYear: function(year) {
319                 return new Date(year, 1, 29).getDate() == 29;
320             },
321 
322             daysInMonth: function(year, month) {
323                 return 32 - new Date(year, month, 32).getDate();
324             },
325 
326             daysInMonthByDate: function(date) {
327                 return 32 - new Date(date.getFullYear(), date.getMonth(), 32).getDate();
328             },
329 
330             getDay: function(date, firstWeekDay) {
331                 var value = date.getDay() - firstWeekDay;
332                 if (value < 0) value = 7 + value;
333                 return value;
334             },
335 
336             getFirstWeek: function(year, mdifw, fdow) {
337                 var date = new Date(year, 0, 1);
338                 var firstday = this.getDay(date, fdow);
339 
340                 var weeknumber = (7 - firstday < mdifw) ? 0 : 1;
341 
342                 return {date:date, firstDay:firstday, weekNumber:weeknumber, mdifw:mdifw, fdow:fdow};
343             },
344 
345             getLastWeekOfPrevYear: function(o) {
346                 var year = o.date.getFullYear() - 1;
347                 var days = (this.isLeapYear(year) ? 366 : 365);
348                 var obj = this.getFirstWeek(year, o.mdifw, o.fdow);
349                 days = (days - 7 + o.firstDay);
350                 var weeks = Math.ceil(days / 7);
351 
352                 return  weeks + obj.weekNumber;
353             },
354 
355             weekNumber: function(year, month, mdifw, fdow) {
356 
357                 var o = this.getFirstWeek(year, mdifw, fdow);
358 
359                 if (month == 0) {
360                     if (o.weekNumber == 1) return 1;
361                     return this.getLastWeekOfPrevYear(o);
362                 }
363                 var oneweek = 604800000;
364                 var d = new Date(year, month, 1);
365                 d.setDate(1 + o.firstDay + (this.getDay(d, fdow) == 0 ? 1 : 0));
366 
367                 weeknumber = o.weekNumber + Math.floor((d.getTime() - o.date.getTime()) / oneweek);
368 
369                 return weeknumber;
370             }
371 
372         });
373 
374     rf.calendarTemplates = rf.calendarTemplates || {};
375 
376     $.extend(rf.calendarTemplates, (function () {
377 
378         var VARIABLE_NAME_PATTERN = /^\s*[_,A-Z,a-z][\w,_\.]*\s*$/;
379 
380         var getObjectValue = function (str, object) {
381             var a = str.split(".");
382             var value = object[a[0]];
383             var c = 1;
384             while (value && c < a.length) value = value[a[c++]];
385             return (value ? value : "");
386         };
387 
388         return  {
389             evalMacro: function(template, object) {
390                 var _value_ = "";
391                 // variable evaluation
392                 if (VARIABLE_NAME_PATTERN.test(template)) {
393                     if (template.indexOf('.') == -1) {
394                         _value_ = object[template];
395                         if (!_value_)    _value_ = window[template];
396                     }
397                     // object's variable evaluation
398                     else {
399                         _value_ = getObjectValue(template, object);
400                         if (!_value_) _value_ = getObjectValue(template, window);
401                     }
402                     if (_value_ && typeof _value_ == 'function') _value_ = _value_(object);
403                     if (!_value_) _value_ = "";
404                 }
405                 //js string evaluation
406                 else {
407                     try {
408                         if (object.eval) {
409                             _value_ = object.eval(template);
410                         }
411                         else with (object) {
412                             _value_ = eval(template);
413                         }
414 
415                         if (typeof _value_ == 'function') {
416                             _value_ = _value_(object);
417                         }
418                     } catch (e) {
419                         LOG.warn("Exception: " + e.Message + "\n[" + template + "]");
420                     }
421                 }
422                 return _value_;
423             }
424         };
425     })());
426 
427 })(RichFaces.jQuery, RichFaces);