kosmas58-compass-jquery-plugin 0.2.0.3 → 0.2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.textile CHANGED
@@ -61,7 +61,6 @@ To use the localized stylesheets and javacripts include:
61
61
 
62
62
  <pre>
63
63
  = stylesheet_link_tag 'compiled/jquery.ui/jqGrid.css', :media => 'screen, projection'
64
- = stylesheet_link_tag 'fix_blueprint_jqgrid.css', :media => 'screen, projection'
65
64
  = jqgrid_javascripts I18n.locale</pre>
66
65
 
67
66
  jqGrid now uses the jQuery UI Themes. jqGrid has been included as a subproject. You do not need to check it out unless you want to use a different version.
@@ -80,9 +79,24 @@ To use the localized stylesheets and javacripts include:
80
79
 
81
80
  <pre>
82
81
  = stylesheet_link_tag 'compiled/jquery.ui/secret_sauce.css', :media => 'screen, projection'
83
- = stylesheet_link_tag 'fix_blueprint_jqgrid.css', :media => 'screen, projection'
84
82
  = javascript_include_tag :secret_sauce</pre>
85
83
 
84
+ h3. Calendar
85
+
86
+ Use compass to install the calendar javascript library into your project.
87
+
88
+ <pre>compass -f jquery -p calendar <project name></pre>
89
+
90
+ You will find all the stylesheets in easy-to-read Sass format.
91
+
92
+ <pre>stylesheets/jquery.ui</pre>
93
+
94
+ To use the (localized) stylesheets and javacripts include:
95
+
96
+ <pre>
97
+ = stylesheet_link_tag 'compiled/jquery.ui/calendar.css', :media => 'screen, projection'
98
+ = javascript_include_tag :calendar</pre>
99
+
86
100
  h2. Thanks to the Contributors:
87
101
 
88
102
  h3. Rails
@@ -101,3 +115,5 @@ h3. jQuery Plugins included
101
115
  * John Reisig et. al. for <b>"jQuery Form Plugin":http://malsup.com/jquery/form//</b>
102
116
  * Martin Wendt for <b>"jQuery Dynatree Plugin":http://www.wwwendt.de</b>
103
117
  * Tony Tomov for <b>"jQuery Grid Plugin":http://www.trirand.com/blog/</b>
118
+ * Rob Monie for <b>"jQuery.weekCalendar":http://www.redredred.com.au/</b>
119
+ * Kyle LeNeau for <b>"jMonthCalendar":http://www.bytecyclist.com/projects/jmonthcalendar</b>
@@ -0,0 +1,5 @@
1
+ module ActionView
2
+ module Helpers
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module ActionView
2
+ module Helpers
3
+
4
+ end
5
+ end
data/lib/jquery/jqgrid.rb CHANGED
@@ -365,7 +365,7 @@ module JqgridJson
365
365
  end
366
366
  json.chop! << "]},"
367
367
  end
368
- json.chop! << "]}"
368
+ json.chomp!(',') << "]}"
369
369
  end
370
370
  end
371
371
 
@@ -8,7 +8,7 @@ spec = Gem::Specification.new do |s|
8
8
  s.description = s.summary
9
9
  #s.executables = ["jqgrid", "jquery-ui"]
10
10
  s.files = %w[MIT-LICENSE Rakefile README.textile] + Dir["lib/**/*"] + Dir["templates/**/*"]
11
- s.add_dependency("chriseppstein-compass", [">= 0.8.8"])
11
+ s.add_dependency("chriseppstein-compass", [">= 0.8.16"])
12
12
  end
13
13
 
14
14
  Rake::GemPackageTask.new(spec) do |package|
@@ -210,8 +210,9 @@ module SecretSauce
210
210
  :edit => false,
211
211
  :add => false,
212
212
  :del => false
213
- }.merge(options[:nav]))
214
- render :partial => 'ui/ui_grid_for_without_block', :locals => {:options => mapped_options, :name => name_or_array, :nav => options[:nav], :actions => options[:actions]}
213
+ }.merge(options[:nav]))
214
+ #render(:partial => 'ui/ui_grid_for_without_block', :locals => {:options => mapped_options, :name => name_or_array, :nav => options[:nav], :actions => options[:actions]})
215
+ render(:file => 'ui/_ui_grid_for_without_block.js.haml', :locals => {:options => mapped_options, :name => name_or_array, :nav => options[:nav], :actions => options[:actions]})
215
216
  end
216
217
  end
217
218
  end
@@ -2,8 +2,8 @@ module CompassJqueryPlugin#:nodoc:
2
2
 
3
3
  class VERSION #:nodoc:
4
4
 
5
- PATCH = 3 # Set to nil for official release
6
- TINY = 0
5
+ PATCH = 0 # Set to nil for official release
6
+ TINY = 2
7
7
  MINOR = 2
8
8
  MAJOR = 0
9
9
 
@@ -0,0 +1,3 @@
1
+ require 'jquery/calendar'
2
+
3
+ ActionView::Helpers::AssetTagHelper.register_javascript_expansion :calendar => ['jquery.calendar.min']
@@ -0,0 +1,2047 @@
1
+ /*
2
+ * jQuery.weekCalendar v1.2.1
3
+ * http://www.redredred.com.au/
4
+ *
5
+ * Requires:
6
+ * - jquery.weekcalendar.css
7
+ * - jquery 1.3.x
8
+ * - jquery-ui 1.7.x (widget, drag, drop, resize)
9
+ *
10
+ * Copyright (c) 2009 Rob Monie
11
+ * Dual licensed under the MIT and GPL licenses:
12
+ * http://www.opensource.org/licenses/mit-license.php
13
+ * http://www.gnu.org/licenses/gpl.html
14
+ *
15
+ * If you're after a monthly calendar plugin, check out http://arshaw.com/fullcalendar/
16
+ */
17
+
18
+ (function($) {
19
+
20
+ $.widget("ui.weekCalendar", {
21
+
22
+ /***********************
23
+ * Initialise calendar *
24
+ ***********************/
25
+ _init : function() {
26
+ var self = this;
27
+ self._computeOptions();
28
+ self._setupEventDelegation();
29
+ self._renderCalendar();
30
+ self._loadCalEvents();
31
+ self._resizeCalendar();
32
+ //setTimeout(function() {
33
+ self._scrollToHour(self.options.date.getHours());
34
+ //}, 500);
35
+
36
+ $(window).unbind("resize.weekcalendar");
37
+ $(window).bind("resize.weekcalendar", function(){
38
+ self._resizeCalendar();
39
+ });
40
+
41
+ },
42
+
43
+ /********************
44
+ * public functions *
45
+ ********************/
46
+ /*
47
+ * Refresh the events for the currently displayed week.
48
+ */
49
+ refresh : function() {
50
+ this._clearCalendar();
51
+ this._loadCalEvents(this.element.data("startDate")); //reload with existing week
52
+ },
53
+
54
+ /*
55
+ * Clear all events currently loaded into the calendar
56
+ */
57
+ clear : function() {
58
+ this._clearCalendar();
59
+ },
60
+
61
+ /*
62
+ * Go to this week
63
+ */
64
+ today : function() {
65
+ this._clearCalendar();
66
+ this._loadCalEvents(new Date());
67
+ },
68
+
69
+ /*
70
+ * Go to the previous week relative to the currently displayed week
71
+ */
72
+ prevWeek : function() {
73
+ //minus more than 1 day to be sure we're in previous week - account for daylight savings or other anomolies
74
+ var newDate = new Date(this.element.data("startDate").getTime() - (MILLIS_IN_WEEK / 6));
75
+ this._clearCalendar();
76
+ this._loadCalEvents(newDate);
77
+ },
78
+
79
+ /*
80
+ * Go to the next week relative to the currently displayed week
81
+ */
82
+ nextWeek : function() {
83
+ //add 8 days to be sure of being in prev week - allows for daylight savings or other anomolies
84
+ var newDate = new Date(this.element.data("startDate").getTime() + MILLIS_IN_WEEK + (MILLIS_IN_WEEK / 7));
85
+ this._clearCalendar();
86
+ this._loadCalEvents(newDate);
87
+ },
88
+
89
+ /*
90
+ * Reload the calendar to whatever week the date passed in falls on.
91
+ */
92
+ gotoWeek : function(date) {
93
+ this._clearCalendar();
94
+ this._loadCalEvents(date);
95
+ },
96
+
97
+ /*
98
+ * Remove an event based on it's id
99
+ */
100
+ removeEvent : function(eventId) {
101
+ this.element.find(".cal-event").each(function(){
102
+ if($(this).data("calEvent").id === eventId) {
103
+ $(this).fadeOut(function(){
104
+ $(this).remove();
105
+ });
106
+ return false;
107
+ }
108
+ });
109
+ },
110
+
111
+ /*
112
+ * Removes any events that have been added but not yet saved (have no id).
113
+ * This is useful to call after adding a freshly saved new event.
114
+ */
115
+ removeUnsavedEvents : function() {
116
+ this.element.find(".new-cal-event").fadeOut(function(){
117
+ $(this).remove();
118
+ });
119
+ },
120
+
121
+ /*
122
+ * update an event in the calendar. If the event exists it refreshes
123
+ * it's rendering. If it's a new event that does not exist in the calendar
124
+ * it will be added.
125
+ */
126
+ updateEvent : function (calEvent) {
127
+ this._updateEventInCalendar(calEvent);
128
+ },
129
+
130
+ /*
131
+ * Returns an array of timeslot start and end times based on
132
+ * the configured grid of the calendar. Returns in both date and
133
+ * formatted time based on the 'timeFormat' config option.
134
+ */
135
+ getTimeslotTimes : function(date) {
136
+ var options = this.options;
137
+ var firstHourDisplayed = options.businessHours.limitDisplay ? options.businessHours.start : 0;
138
+ var startDate = new Date(date.getFullYear(), date.getMonth(), date.getDate(), firstHourDisplayed);
139
+
140
+ var times = []
141
+ var startMillis = startDate.getTime();
142
+ for(var i=0; i < options.timeslotsPerDay; i++) {
143
+ var endMillis = startMillis + options.millisPerTimeslot;
144
+ times[i] = {
145
+ start: new Date(startMillis),
146
+ startFormatted: this._formatDate(new Date(startMillis), options.timeFormat),
147
+ end: new Date(endMillis),
148
+ endFormatted: this._formatDate(new Date(endMillis), options.timeFormat)
149
+ };
150
+ startMillis = endMillis;
151
+ }
152
+ return times;
153
+ },
154
+
155
+ formatDate : function(date, format) {
156
+ if(format) {
157
+ return this._formatDate(date, format);
158
+ } else {
159
+ return this._formatDate(date, this.options.dateFormat);
160
+ }
161
+ },
162
+
163
+ formatTime : function(date, format) {
164
+ if(format) {
165
+ return this._formatDate(date, format);
166
+ } else {
167
+ return this._formatDate(date, this.options.timeFormat);
168
+ }
169
+ },
170
+
171
+ getData : function(key) {
172
+ return this._getData(key);
173
+ },
174
+
175
+ /*********************
176
+ * private functions *
177
+ *********************/
178
+ // compute dynamic options based on other config values
179
+ _computeOptions : function() {
180
+
181
+ var options = this.options;
182
+
183
+ if(options.businessHours.limitDisplay) {
184
+ options.timeslotsPerDay = options.timeslotsPerHour * (options.businessHours.end - options.businessHours.start);
185
+ options.millisToDisplay = (options.businessHours.end - options.businessHours.start) * 60 * 60 * 1000;
186
+ options.millisPerTimeslot = options.millisToDisplay / options.timeslotsPerDay;
187
+ } else {
188
+ options.timeslotsPerDay = options.timeslotsPerHour * 24;
189
+ options.millisToDisplay = MILLIS_IN_DAY;
190
+ options.millisPerTimeslot = MILLIS_IN_DAY / options.timeslotsPerDay;
191
+ }
192
+ },
193
+
194
+ /*
195
+ * Resize the calendar scrollable height based on the provided function in options.
196
+ */
197
+ _resizeCalendar : function () {
198
+
199
+ var options = this.options;
200
+ if(options && $.isFunction(options.height)) {
201
+ var calendarHeight = options.height(this.element);
202
+ var headerHeight = this.element.find(".week-calendar-header").outerHeight();
203
+ var navHeight = this.element.find(".calendar-nav").outerHeight();
204
+ this.element.find(".calendar-scrollable-grid").height(calendarHeight - navHeight - headerHeight);
205
+ }
206
+ },
207
+
208
+ /*
209
+ * configure calendar interaction events that are able to use event
210
+ * delegation for greater efficiency
211
+ */
212
+ _setupEventDelegation : function() {
213
+ var self = this;
214
+ var options = this.options;
215
+ this.element.click(function(event) {
216
+ var $target = $(event.target);
217
+ if($target.data("preventClick")) {
218
+ return;
219
+ }
220
+ if($target.hasClass("cal-event")) {
221
+ options.eventClick($target.data("calEvent"), $target, event);
222
+ } else if($target.parent().hasClass("cal-event")) {
223
+ options.eventClick($target.parent().data("calEvent"), $target.parent(), event);
224
+ }
225
+ }).mouseover(function(event){
226
+ var $target = $(event.target);
227
+
228
+ if(self._isDraggingOrResizing($target)) {
229
+ return;
230
+ }
231
+
232
+ if($target.hasClass("cal-event") ) {
233
+ options.eventMouseover($target.data("calEvent"), $target, event);
234
+ }
235
+ }).mouseout(function(event){
236
+ var $target = $(event.target);
237
+ if(self._isDraggingOrResizing($target)) {
238
+ return;
239
+ }
240
+ if($target.hasClass("cal-event")) {
241
+ if($target.data("sizing")) return;
242
+ options.eventMouseout($target.data("calEvent"), $target, event);
243
+
244
+ }
245
+ });
246
+ },
247
+
248
+ /*
249
+ * check if a ui draggable or resizable is currently being dragged or resized
250
+ */
251
+ _isDraggingOrResizing : function ($target) {
252
+ return $target.hasClass("ui-draggable-dragging") || $target.hasClass("ui-resizable-resizing");
253
+ },
254
+
255
+ /*
256
+ * Render the main calendar layout
257
+ */
258
+ _renderCalendar : function() {
259
+
260
+ var $calendarContainer, calendarNavHtml, calendarHeaderHtml, calendarBodyHtml, $weekDayColumns;
261
+ var self = this;
262
+ var options = this.options;
263
+
264
+ $calendarContainer = $("<div class=\"week-calendar\">").appendTo(self.element);
265
+
266
+ if(options.buttons) {
267
+ calendarNavHtml = "<div class=\"calendar-nav\">\
268
+ <button class=\"today\">" + options.buttonText.today + "</button>\
269
+ <button class=\"prev\">" + options.buttonText.lastWeek + "</button>\
270
+ <button class=\"next\">" + options.buttonText.nextWeek + "</button>\
271
+ </div>";
272
+
273
+ $(calendarNavHtml).appendTo($calendarContainer);
274
+
275
+ $calendarContainer.find(".calendar-nav .today").click(function(){
276
+ self.element.weekCalendar("today");
277
+ return false;
278
+ });
279
+
280
+ $calendarContainer.find(".calendar-nav .prev").click(function(){
281
+ self.element.weekCalendar("prevWeek");
282
+ return false;
283
+ });
284
+
285
+ $calendarContainer.find(".calendar-nav .next").click(function(){
286
+ self.element.weekCalendar("nextWeek");
287
+ return false;
288
+ });
289
+
290
+ }
291
+
292
+ //render calendar header
293
+ calendarHeaderHtml = "<table class=\"week-calendar-header\"><tbody><tr><td class=\"time-column-header\"></td>";
294
+ for(var i=1 ; i<=7; i++) {
295
+ calendarHeaderHtml += "<td class=\"day-column-header day-" + i + "\"></td>";
296
+ }
297
+ calendarHeaderHtml += "<td class=\"scrollbar-shim\"></td></tr></tbody></table>";
298
+
299
+ //render calendar body
300
+ calendarBodyHtml = "<div class=\"calendar-scrollable-grid\">\
301
+ <table class=\"week-calendar-time-slots\">\
302
+ <tbody>\
303
+ <tr>\
304
+ <td class=\"grid-timeslot-header\"></td>\
305
+ <td colspan=\"7\">\
306
+ <div class=\"time-slot-wrapper\">\
307
+ <div class=\"time-slots\">";
308
+
309
+ var start = options.businessHours.limitDisplay ? options.businessHours.start : 0;
310
+ var end = options.businessHours.limitDisplay ? options.businessHours.end : 24;
311
+
312
+ for(var i = start ; i < end; i++) {
313
+ for(var j=0;j<options.timeslotsPerHour - 1; j++) {
314
+ calendarBodyHtml += "<div class=\"time-slot\"></div>";
315
+ }
316
+ calendarBodyHtml += "<div class=\"time-slot hour-end\"></div>";
317
+ }
318
+
319
+ calendarBodyHtml += "</div></div></td></tr><tr><td class=\"grid-timeslot-header\">";
320
+
321
+ for(var i = start ; i < end; i++) {
322
+
323
+ var bhClass = (options.businessHours.start <= i && options.businessHours.end > i) ? "business-hours" : "";
324
+ calendarBodyHtml += "<div class=\"hour-header " + bhClass + "\">"
325
+ if(options.use24Hour) {
326
+ calendarBodyHtml += "<div class=\"time-header-cell\">" + self._24HourForIndex(i) + "</div>";
327
+ } else {
328
+ calendarBodyHtml += "<div class=\"time-header-cell\">" + self._hourForIndex(i) + "<span class=\"am-pm\">" + self._amOrPm(i) + "</span></div>";
329
+ }
330
+ calendarBodyHtml += "</div>";
331
+ }
332
+
333
+ calendarBodyHtml += "</td>";
334
+
335
+ for(var i=1 ; i<=7; i++) {
336
+ calendarBodyHtml += "<td class=\"day-column day-" + i + "\"><div class=\"day-column-inner\"></div></td>"
337
+ }
338
+
339
+ calendarBodyHtml += "</tr></tbody></table></div>";
340
+
341
+ //append all calendar parts to container
342
+ $(calendarHeaderHtml + calendarBodyHtml).appendTo($calendarContainer);
343
+
344
+ $weekDayColumns = $calendarContainer.find(".day-column-inner");
345
+ $weekDayColumns.each(function(i, val) {
346
+ $(this).height(options.timeslotHeight * options.timeslotsPerDay);
347
+ if(!options.readonly) {
348
+ self._addDroppableToWeekDay($(this));
349
+ self._setupEventCreationForWeekDay($(this));
350
+ }
351
+ });
352
+
353
+ $calendarContainer.find(".time-slot").height(options.timeslotHeight -1); //account for border
354
+
355
+ $calendarContainer.find(".time-header-cell").css({
356
+ height : (options.timeslotHeight * options.timeslotsPerHour) - 11,
357
+ padding: 5
358
+ });
359
+
360
+
361
+
362
+ },
363
+
364
+ /*
365
+ * setup mouse events for capturing new events
366
+ */
367
+ _setupEventCreationForWeekDay : function($weekDay) {
368
+ var self = this;
369
+ var options = this.options;
370
+ $weekDay.mousedown(function(event) {
371
+ var $target = $(event.target);
372
+ if($target.hasClass("day-column-inner")) {
373
+
374
+ var $newEvent = $("<div class=\"cal-event new-cal-event new-cal-event-creating\"></div>");
375
+
376
+ $newEvent.css({lineHeight: (options.timeslotHeight - 2) + "px", fontSize: (options.timeslotHeight / 2) + "px"});
377
+ $target.append($newEvent);
378
+
379
+ var columnOffset = $target.offset().top;
380
+ var clickY = event.pageY - columnOffset;
381
+ var clickYRounded = (clickY - (clickY % options.timeslotHeight)) / options.timeslotHeight;
382
+ var topPosition = clickYRounded * options.timeslotHeight;
383
+ $newEvent.css({top: topPosition});
384
+
385
+ $target.bind("mousemove.newevent", function(event){
386
+ $newEvent.show();
387
+ $newEvent.addClass("ui-resizable-resizing");
388
+ var height = Math.round(event.pageY - columnOffset - topPosition);
389
+ var remainder = height % options.timeslotHeight;
390
+ //snap to closest timeslot
391
+ if(remainder < (height / 2)) {
392
+ var useHeight = height - remainder;
393
+ $newEvent.css("height", useHeight < options.timeslotHeight ? options.timeslotHeight : useHeight);
394
+ } else {
395
+ $newEvent.css("height", height + (options.timeslotHeight - remainder));
396
+ }
397
+ }).mouseup(function(){
398
+ $target.unbind("mousemove.newevent");
399
+ $newEvent.addClass("ui-corner-all");
400
+ });
401
+ }
402
+
403
+ }).mouseup(function(event) {
404
+ var $target = $(event.target);
405
+
406
+ var $weekDay = $target.closest(".day-column-inner");
407
+ var $newEvent = $weekDay.find(".new-cal-event-creating");
408
+
409
+ if($newEvent.length) {
410
+ //if even created from a single click only, default height
411
+ if(!$newEvent.hasClass("ui-resizable-resizing")) {
412
+ $newEvent.css({height: options.timeslotHeight * options.defaultEventLength}).show();
413
+ }
414
+ var top = parseInt($newEvent.css("top"));
415
+ var eventDuration = self._getEventDurationFromPositionedEventElement($weekDay, $newEvent, top);
416
+
417
+ $newEvent.remove();
418
+ var newCalEvent = {start: eventDuration.start, end: eventDuration.end, title: options.newEventText};
419
+ var $renderedCalEvent = self._renderEvent(newCalEvent, $weekDay);
420
+
421
+ if(!options.allowCalEventOverlap) {
422
+ self._adjustForEventCollisions($weekDay, $renderedCalEvent, newCalEvent, newCalEvent);
423
+ self._positionEvent($weekDay, $renderedCalEvent);
424
+ } else {
425
+ self._adjustOverlappingEvents($weekDay);
426
+ }
427
+
428
+ options.eventNew(eventDuration, $renderedCalEvent);
429
+ }
430
+ });
431
+ },
432
+
433
+ /*
434
+ * load calendar events for the week based on the date provided
435
+ */
436
+ _loadCalEvents : function(dateWithinWeek) {
437
+
438
+ var date, weekStartDate, endDate, $weekDayColumns;
439
+ var self = this;
440
+ var options = this.options;
441
+ date = dateWithinWeek || options.date;
442
+ weekStartDate = self._dateFirstDayOfWeek(date);
443
+ weekEndDate = self._dateLastMilliOfWeek(date);
444
+
445
+ options.calendarBeforeLoad(self.element);
446
+
447
+ self.element.data("startDate", weekStartDate);
448
+ self.element.data("endDate", weekEndDate);
449
+
450
+ $weekDayColumns = self.element.find(".day-column-inner");
451
+
452
+ self._updateDayColumnHeader($weekDayColumns);
453
+
454
+ //load events by chosen means
455
+ if (typeof options.data == 'string') {
456
+ if (options.loading) options.loading(true);
457
+ var jsonOptions = {};
458
+ jsonOptions[options.startParam || 'start'] = Math.round(weekStartDate.getTime() / 1000);
459
+ jsonOptions[options.endParam || 'end'] = Math.round(weekEndDate.getTime() / 1000);
460
+ $.getJSON(options.data, jsonOptions, function(data) {
461
+ self._renderEvents(data, $weekDayColumns);
462
+ if (options.loading) options.loading(false);
463
+ });
464
+ }
465
+ else if ($.isFunction(options.data)) {
466
+ options.data(weekStartDate, weekEndDate,
467
+ function(data) {
468
+ self._renderEvents(data, $weekDayColumns);
469
+ });
470
+ }
471
+ else if (options.data) {
472
+ self._renderEvents(options.data, $weekDayColumns);
473
+ }
474
+
475
+ self._disableTextSelect($weekDayColumns);
476
+
477
+
478
+ },
479
+
480
+ /*
481
+ * update the display of each day column header based on the calendar week
482
+ */
483
+ _updateDayColumnHeader : function ($weekDayColumns) {
484
+ var self = this;
485
+ var options = this.options;
486
+ var currentDay = self._cloneDate(self.element.data("startDate"));
487
+
488
+ self.element.find(".week-calendar-header td.day-column-header").each(function(i, val) {
489
+
490
+ var dayName = options.useShortDayNames ? options.shortDays[currentDay.getDay()] : options.longDays[currentDay.getDay()];
491
+
492
+ $(this).html(dayName + "<br/>" + self._formatDate(currentDay, options.dateFormat));
493
+ if(self._isToday(currentDay)) {
494
+ $(this).addClass("today");
495
+ } else {
496
+ $(this).removeClass("today");
497
+ }
498
+ currentDay = self._addDays(currentDay, 1);
499
+
500
+ });
501
+
502
+ currentDay = self._dateFirstDayOfWeek(self._cloneDate(self.element.data("startDate")));
503
+
504
+ $weekDayColumns.each(function(i, val) {
505
+
506
+ $(this).data("startDate", self._cloneDate(currentDay));
507
+ $(this).data("endDate", new Date(currentDay.getTime() + (MILLIS_IN_DAY - 1)));
508
+ if(self._isToday(currentDay)) {
509
+ $(this).parent().addClass("today");
510
+ } else {
511
+ $(this).parent().removeClass("today");
512
+ }
513
+
514
+ currentDay = self._addDays(currentDay, 1);
515
+ });
516
+
517
+ },
518
+
519
+ /*
520
+ * Render the events into the calendar
521
+ */
522
+ _renderEvents : function (events, $weekDayColumns) {
523
+ var self = this;
524
+ var options = this.options;
525
+ var eventsToRender;
526
+
527
+ if($.isArray(events)) {
528
+ eventsToRender = self._cleanEvents(events);
529
+ } else if(events.events) {
530
+ eventsToRender = self._cleanEvents(events.events);
531
+ }
532
+ if(events.options) {
533
+
534
+ var updateLayout = false;
535
+ //update options
536
+ $.each(events.options, function(key, value){
537
+ if(value !== options[key]) {
538
+ options[key] = value;
539
+ updateLayout = true;
540
+ }
541
+ });
542
+
543
+ self._computeOptions();
544
+
545
+ if(updateLayout) {
546
+ self.element.empty();
547
+ self._renderCalendar();
548
+ $weekDayColumns = self.element.find(".week-calendar-time-slots .day-column-inner");
549
+ self._updateDayColumnHeader($weekDayColumns);
550
+ self._resizeCalendar();
551
+ }
552
+
553
+ }
554
+
555
+
556
+ $.each(eventsToRender, function(i, calEvent){
557
+
558
+ var $weekDay = self._findWeekDayForEvent(calEvent, $weekDayColumns);
559
+
560
+ if($weekDay) {
561
+ self._renderEvent(calEvent, $weekDay);
562
+ }
563
+ });
564
+
565
+ $weekDayColumns.each(function(){
566
+ self._adjustOverlappingEvents($(this));
567
+ });
568
+
569
+ options.calendarAfterLoad(self.element);
570
+
571
+ if(!eventsToRender.length) {
572
+ options.noEvents();
573
+ }
574
+
575
+ },
576
+
577
+ /*
578
+ * Render a specific event into the day provided. Assumes correct
579
+ * day for calEvent date
580
+ */
581
+ _renderEvent: function (calEvent, $weekDay) {
582
+ var self = this;
583
+ var options = this.options;
584
+ if(calEvent.start.getTime() > calEvent.end.getTime()) {
585
+ return; // can't render a negative height
586
+ }
587
+
588
+ var eventClass, eventHtml, $calEvent, $modifiedEvent;
589
+
590
+ eventClass = calEvent.id ? "cal-event" : "cal-event new-cal-event";
591
+ eventHtml = "<div class=\"" + eventClass + " ui-corner-all\">\
592
+ <div class=\"time ui-corner-all\"></div>\
593
+ <div class=\"title\"></div></div>";
594
+
595
+ $calEvent = $(eventHtml);
596
+ $modifiedEvent = options.eventRender(calEvent, $calEvent);
597
+ $calEvent = $modifiedEvent ? $modifiedEvent.appendTo($weekDay) : $calEvent.appendTo($weekDay);
598
+ $calEvent.css({lineHeight: (options.timeslotHeight - 2) + "px", fontSize: (options.timeslotHeight / 2) + "px"});
599
+
600
+ self._refreshEventDetails(calEvent, $calEvent);
601
+ self._positionEvent($weekDay, $calEvent);
602
+ $calEvent.show();
603
+
604
+ if(!options.readonly && options.resizable(calEvent, $calEvent)) {
605
+ self._addResizableToCalEvent(calEvent, $calEvent, $weekDay)
606
+ }
607
+ if(!options.readonly && options.draggable(calEvent, $calEvent)) {
608
+ self._addDraggableToCalEvent(calEvent, $calEvent);
609
+ }
610
+
611
+ options.eventAfterRender(calEvent, $calEvent);
612
+
613
+ return $calEvent;
614
+
615
+ },
616
+
617
+ /*
618
+ * If overlapping is allowed, check for overlapping events and format
619
+ * for greater readability
620
+ */
621
+ _adjustOverlappingEvents : function($weekDay) {
622
+ var self = this;
623
+ if(self.options.allowCalEventOverlap) {
624
+ var groups = self._groupOverlappingEventElements($weekDay);
625
+
626
+ $.each(groups, function(){
627
+ var groupAmount = this.length;
628
+ var curGroup = this;
629
+ // do we want events to be displayed as overlapping
630
+ if (self.options.overlapEventsSeparate){
631
+ var newWidth = 100/groupAmount;
632
+ var newLeftAdd = newWidth;
633
+ } else {
634
+ // TODO what happens when the group has more than 10 elements
635
+ var newWidth = (100 - (groupAmount*10));
636
+ var newLeftAdd = (100 - newWidth) / (groupAmount-1);
637
+ }
638
+ $.each(this, function(i){
639
+ var newLeft = (i * newLeftAdd);
640
+ // bring mouseovered event to the front
641
+ if(!self.options.overlapEventsSeparate){
642
+ $(this).bind("mouseover.z-index",function(){
643
+ var $elem = $(this);
644
+ $.each(curGroup, function() {
645
+ $(this).css({"z-index": "1"});
646
+ });
647
+ $elem.css({"z-index": "3"});
648
+ });
649
+ }
650
+ $(this).css({width: newWidth+"%", left: newLeft+"%", right: 0});
651
+ });
652
+ });
653
+ }
654
+ },
655
+
656
+
657
+ /*
658
+ * Find groups of overlapping events
659
+ */
660
+ _groupOverlappingEventElements : function($weekDay) {
661
+ var self = this;
662
+ var $events = $weekDay.find(".cal-event");
663
+ var sortedEvents = $events.sort(function(a, b){
664
+ return $(a).data("calEvent").start.getTime() - $(b).data("calEvent").start.getTime();
665
+ });
666
+
667
+ var $lastEvent;
668
+ var groups = [];
669
+ var currentGroup = [];
670
+ var $curEvent;
671
+ var currentGroupStartTime = 0;
672
+ var currentGroupEndTime = 0;
673
+ var lastGroupEndTime = 0;
674
+ $.each(sortedEvents, function(){
675
+
676
+ $curEvent = $(this);
677
+ currentGroupStartTime = $curEvent.data("calEvent").start.getTime();
678
+ currentGroupEndTime = $curEvent.data("calEvent").end.getTime();
679
+ $curEvent.css({width: "100%", left: "0%", right: "", "z-index": "1"});
680
+ $curEvent.unbind("mouseover.z-index");
681
+ // if current start time is lower than current endtime time than either this event is earlier than the group, or already within the group
682
+ if ($curEvent.data("calEvent").start.getTime() < lastGroupEndTime) {
683
+ return;
684
+ }
685
+ // loop through all current weekday events to check if they belong to the same group
686
+ $.each(sortedEvents, function() {
687
+ // check for same element and possibility to even be in the same group note: somehow ($curEvent == $(this) doens't work
688
+ if ($curEvent.data("calEvent").id == $(this).data("calEvent").id ||
689
+ currentGroupStartTime > $(this).data("calEvent").start.getTime()+1 ||
690
+ currentGroupEndTime < $(this).data("calEvent").start.getTime()+1) {
691
+ return;
692
+ }
693
+ //set new endtime of the group
694
+ if ($(this).data("calEvent").end.getTime() > currentGroupEndTime) {
695
+ currentGroupEndTime = $(this).data("calEvent").end.getTime();
696
+ }
697
+ // ain't we adding the same element
698
+ if ($.inArray($(this), currentGroup) == -1) {
699
+ currentGroup.push($(this));
700
+ }
701
+ // ain't we adding the same element
702
+ if ($.inArray($curEvent, currentGroup) == -1) {
703
+ currentGroup.push($curEvent);
704
+ }
705
+ });
706
+ if(currentGroup.length) {
707
+ currentGroup.sort(function(a,b){
708
+ if ($(a).data("calEvent").start.getTime() > $(b).data("calEvent").start.getTime()) {
709
+ return 1;
710
+ } else if ($(a).data("calEvent").start.getTime() < $(b).data("calEvent").start.getTime()) {
711
+ return -1;
712
+ } else {
713
+ return ($(a).data("calEvent").end.getTime() - $(a).data("calEvent").start.getTime())
714
+ - ($(b).data("calEvent").end.getTime() - $(b).data("calEvent").start.getTime());
715
+ }
716
+ });
717
+ groups.push(currentGroup);
718
+ currentGroup = [];
719
+ lastGroupEndTime = currentGroupEndTime;
720
+ }
721
+
722
+ });
723
+
724
+ return groups;
725
+
726
+ },
727
+ /*
728
+ * Check if two groups containt the same events. It assumes the groups are sorted NOTE: might be obsolete
729
+ */
730
+ _compareGroups: function(thisGroup, thatGroup){
731
+ if (thisGroup.length != thatGroup.length) {
732
+ return false;
733
+ }
734
+
735
+ for (var i = 0; i < thisGroup.length; i++) {
736
+ if (thisGroup[i].data("calEvent").id != thatGroup[i].data("calEvent").id) {
737
+ return false;
738
+ }
739
+ }
740
+
741
+ return true;
742
+ },
743
+
744
+
745
+
746
+ /*
747
+ * find the weekday in the current calendar that the calEvent falls within
748
+ */
749
+ _findWeekDayForEvent : function(calEvent, $weekDayColumns) {
750
+
751
+ var $weekDay;
752
+ $weekDayColumns.each(function(){
753
+ if($(this).data("startDate").getTime() <= calEvent.start.getTime() && $(this).data("endDate").getTime() >= calEvent.end.getTime()) {
754
+ $weekDay = $(this);
755
+ return false;
756
+ }
757
+ });
758
+ return $weekDay;
759
+ },
760
+
761
+ /*
762
+ * update the events rendering in the calendar. Add if does not yet exist.
763
+ */
764
+ _updateEventInCalendar : function (calEvent) {
765
+ var self = this;
766
+ var options = this.options;
767
+ self._cleanEvent(calEvent);
768
+
769
+ if(calEvent.id) {
770
+ self.element.find(".cal-event").each(function(){
771
+ if($(this).data("calEvent").id === calEvent.id || $(this).hasClass("new-cal-event")) {
772
+ $(this).remove();
773
+ return false;
774
+ }
775
+ });
776
+ }
777
+
778
+ var $weekDay = self._findWeekDayForEvent(calEvent, self.element.find(".week-calendar-time-slots .day-column-inner"));
779
+ if($weekDay) {
780
+ self._renderEvent(calEvent, $weekDay);
781
+ self._adjustOverlappingEvents($weekDay);
782
+ }
783
+ },
784
+
785
+ /*
786
+ * Position the event element within the weekday based on it's start / end dates.
787
+ */
788
+ _positionEvent : function($weekDay, $calEvent) {
789
+ var options = this.options;
790
+ var calEvent = $calEvent.data("calEvent");
791
+ var pxPerMillis = $weekDay.height() / options.millisToDisplay;
792
+ var firstHourDisplayed = options.businessHours.limitDisplay ? options.businessHours.start : 0;
793
+ var startMillis = calEvent.start.getTime() - new Date(calEvent.start.getFullYear(), calEvent.start.getMonth(), calEvent.start.getDate(), firstHourDisplayed).getTime();
794
+ var eventMillis = calEvent.end.getTime() - calEvent.start.getTime();
795
+ var pxTop = pxPerMillis * startMillis;
796
+ var pxHeight = pxPerMillis * eventMillis;
797
+ $calEvent.css({top: pxTop, height: pxHeight});
798
+ },
799
+
800
+ /*
801
+ * Determine the actual start and end times of a calevent based on it's
802
+ * relative position within the weekday column and the starting hour of the
803
+ * displayed calendar.
804
+ */
805
+ _getEventDurationFromPositionedEventElement : function($weekDay, $calEvent, top) {
806
+ var options = this.options;
807
+ var startOffsetMillis = options.businessHours.limitDisplay ? options.businessHours.start * 60 *60 * 1000 : 0;
808
+ var start = new Date($weekDay.data("startDate").getTime() + startOffsetMillis + Math.round(top / options.timeslotHeight) * options.millisPerTimeslot);
809
+ var end = new Date(start.getTime() + ($calEvent.height() / options.timeslotHeight) * options.millisPerTimeslot);
810
+ return {start: start, end: end};
811
+ },
812
+
813
+ /*
814
+ * If the calendar does not allow event overlap, adjust the start or end date if necessary to
815
+ * avoid overlapping of events. Typically, shortens the resized / dropped event to it's max possible
816
+ * duration based on the overlap. If no satisfactory adjustment can be made, the event is reverted to
817
+ * it's original location.
818
+ */
819
+ _adjustForEventCollisions : function($weekDay, $calEvent, newCalEvent, oldCalEvent, maintainEventDuration) {
820
+ var options = this.options;
821
+
822
+ if(options.allowCalEventOverlap) {
823
+ return;
824
+ }
825
+ var adjustedStart, adjustedEnd;
826
+ var self = this;
827
+
828
+ $weekDay.find(".cal-event").not($calEvent).each(function(){
829
+ var currentCalEvent = $(this).data("calEvent");
830
+
831
+ //has been dropped onto existing event overlapping the end time
832
+ if(newCalEvent.start.getTime() < currentCalEvent.end.getTime()
833
+ && newCalEvent.end.getTime() >= currentCalEvent.end.getTime()) {
834
+
835
+ adjustedStart = currentCalEvent.end;
836
+ }
837
+
838
+
839
+ //has been dropped onto existing event overlapping the start time
840
+ if(newCalEvent.end.getTime() > currentCalEvent.start.getTime()
841
+ && newCalEvent.start.getTime() <= currentCalEvent.start.getTime()) {
842
+
843
+ adjustedEnd = currentCalEvent.start;
844
+ }
845
+ //has been dropped inside existing event with same or larger duration
846
+ if(newCalEvent.end.getTime() <= currentCalEvent.end.getTime()
847
+ && newCalEvent.start.getTime() >= currentCalEvent.start.getTime()) {
848
+
849
+ adjustedStart = oldCalEvent.start;
850
+ adjustedEnd = oldCalEvent.end;
851
+ return false;
852
+ }
853
+
854
+ });
855
+
856
+
857
+ newCalEvent.start = adjustedStart || newCalEvent.start;
858
+
859
+ if(adjustedStart && maintainEventDuration) {
860
+ newCalEvent.end = new Date(adjustedStart.getTime() + (oldCalEvent.end.getTime() - oldCalEvent.start.getTime()));
861
+ self._adjustForEventCollisions($weekDay, $calEvent, newCalEvent, oldCalEvent);
862
+ } else {
863
+ newCalEvent.end = adjustedEnd || newCalEvent.end;
864
+ }
865
+
866
+
867
+
868
+ //reset if new cal event has been forced to zero size
869
+ if(newCalEvent.start.getTime() >= newCalEvent.end.getTime()) {
870
+ newCalEvent.start = oldCalEvent.start;
871
+ newCalEvent.end = oldCalEvent.end;
872
+ }
873
+
874
+ $calEvent.data("calEvent", newCalEvent);
875
+ },
876
+
877
+ /*
878
+ * Add draggable capabilities to an event
879
+ */
880
+ _addDraggableToCalEvent : function(calEvent, $calEvent) {
881
+ var self = this;
882
+ var options = this.options;
883
+ var $weekDay = self._findWeekDayForEvent(calEvent, self.element.find(".week-calendar-time-slots .day-column-inner"));
884
+ $calEvent.draggable({
885
+ handle : ".time",
886
+ containment: ".calendar-scrollable-grid",
887
+ revert: 'valid',
888
+ opacity: 0.5,
889
+ grid : [$calEvent.outerWidth() + 1, options.timeslotHeight ],
890
+ start : function(event, ui) {
891
+ var $calEvent = ui.draggable;
892
+ options.eventDrag(calEvent, $calEvent);
893
+ }
894
+ });
895
+
896
+ },
897
+
898
+ /*
899
+ * Add droppable capabilites to weekdays to allow dropping of calEvents only
900
+ */
901
+ _addDroppableToWeekDay : function($weekDay) {
902
+ var self = this;
903
+ var options = this.options;
904
+ $weekDay.droppable({
905
+ accept: ".cal-event",
906
+ drop: function(event, ui) {
907
+ var $calEvent = ui.draggable;
908
+ var top = Math.round(parseInt(ui.position.top));
909
+ var eventDuration = self._getEventDurationFromPositionedEventElement($weekDay, $calEvent, top);
910
+ var calEvent = $calEvent.data("calEvent");
911
+ var newCalEvent = $.extend(true, {start: eventDuration.start, end: eventDuration.end}, calEvent);
912
+ self._adjustForEventCollisions($weekDay, $calEvent, newCalEvent, calEvent, true);
913
+ var $weekDayColumns = self.element.find(".day-column-inner");
914
+ var $newEvent = self._renderEvent(newCalEvent, self._findWeekDayForEvent(newCalEvent, $weekDayColumns));
915
+ $calEvent.hide();
916
+
917
+ //trigger drop callback
918
+ options.eventDrop(newCalEvent, calEvent, $newEvent);
919
+ $calEvent.data("preventClick", true);
920
+ setTimeout(function(){
921
+ var $weekDayOld = self._findWeekDayForEvent($calEvent.data("calEvent"), self.element.find(".week-calendar-time-slots .day-column-inner"));
922
+ $calEvent.remove();
923
+ if ($weekDayOld.data("startDate") != $weekDay.data("startDate")) {
924
+ self._adjustOverlappingEvents($weekDayOld);
925
+ }
926
+ self._adjustOverlappingEvents($weekDay);
927
+ }, 500);
928
+
929
+ }
930
+ });
931
+ },
932
+
933
+ /*
934
+ * Add resizable capabilities to a calEvent
935
+ */
936
+ _addResizableToCalEvent : function(calEvent, $calEvent, $weekDay) {
937
+ var self = this;
938
+ var options = this.options;
939
+ $calEvent.resizable({
940
+ grid: options.timeslotHeight,
941
+ containment : $weekDay,
942
+ handles: "s",
943
+ minHeight: options.timeslotHeight,
944
+ stop :function(event, ui){
945
+ var $calEvent = ui.element;
946
+ var newEnd = new Date($calEvent.data("calEvent").start.getTime() + ($calEvent.height() / options.timeslotHeight) * options.millisPerTimeslot);
947
+ var newCalEvent = $.extend(true, {start: calEvent.start, end: newEnd}, calEvent);
948
+ self._adjustForEventCollisions($weekDay, $calEvent, newCalEvent, calEvent);
949
+
950
+ self._refreshEventDetails(newCalEvent, $calEvent);
951
+ self._positionEvent($weekDay, $calEvent);
952
+
953
+ //trigger resize callback
954
+ options.eventResize(newCalEvent, calEvent, $calEvent);
955
+ $calEvent.data("preventClick", true);
956
+ setTimeout(function(){
957
+ $calEvent.removeData("preventClick");
958
+ }, 500);
959
+ }
960
+ });
961
+ },
962
+
963
+ /*
964
+ * Refresh the displayed details of a calEvent in the calendar
965
+ */
966
+ _refreshEventDetails : function(calEvent, $calEvent) {
967
+ var self = this;
968
+ var options = this.options;
969
+ $calEvent.find(".time").text(self._formatDate(calEvent.start, options.timeFormat) + options.timeSeparator + self._formatDate(calEvent.end, options.timeFormat));
970
+ $calEvent.find(".title").text(calEvent.title);
971
+ $calEvent.data("calEvent", calEvent);
972
+ },
973
+
974
+ /*
975
+ * Clear all cal events from the calendar
976
+ */
977
+ _clearCalendar : function() {
978
+ this.element.find(".day-column-inner div").remove();
979
+ },
980
+
981
+ /*
982
+ * Scroll the calendar to a specific hour
983
+ */
984
+ _scrollToHour : function(hour) {
985
+ var self = this;
986
+ var options = this.options;
987
+ var $scrollable = this.element.find(".calendar-scrollable-grid");
988
+ var slot = hour;
989
+ if(self.options.businessHours.limitDisplay) {
990
+ if(hour < self.options.businessHours.start) {
991
+ slot = 0;
992
+ } else if(hour > self.options.businessHours.end) {
993
+ slot = self.options.businessHours.end - self.options.businessHours.start - 1;
994
+ }
995
+ }
996
+
997
+ var $target = this.element.find(".grid-timeslot-header .hour-header:eq(" + slot + ")");
998
+
999
+ $scrollable.animate({scrollTop: 0}, 0, function(){
1000
+ var targetOffset = $target.offset().top;
1001
+ var scroll = targetOffset - $scrollable.offset().top - $target.outerHeight();
1002
+ $scrollable.animate({scrollTop: scroll}, options.scrollToHourMillis);
1003
+ });
1004
+ },
1005
+
1006
+ /*
1007
+ * find the hour (12 hour day) for a given hour index
1008
+ */
1009
+ _hourForIndex : function(index) {
1010
+ if(index === 0 ) { //midnight
1011
+ return 12;
1012
+ } else if(index < 13) { //am
1013
+ return index;
1014
+ } else { //pm
1015
+ return index - 12;
1016
+ }
1017
+ },
1018
+
1019
+ _24HourForIndex : function(index) {
1020
+ if(index === 0 ) { //midnight
1021
+ return "00:00";
1022
+ } else if(index < 10) {
1023
+ return "0"+index+":00";
1024
+ } else {
1025
+ return index+":00";
1026
+ }
1027
+ },
1028
+
1029
+ _amOrPm : function (hourOfDay) {
1030
+ return hourOfDay < 12 ? "AM" : "PM";
1031
+ },
1032
+
1033
+ _isToday : function(date) {
1034
+ var clonedDate = this._cloneDate(date);
1035
+ this._clearTime(clonedDate);
1036
+ var today = new Date();
1037
+ this._clearTime(today);
1038
+ return today.getTime() === clonedDate.getTime();
1039
+ },
1040
+
1041
+ /*
1042
+ * Clean events to ensure correct format
1043
+ */
1044
+ _cleanEvents : function(events) {
1045
+ var self = this;
1046
+ $.each(events, function(i, event) {
1047
+ self._cleanEvent(event);
1048
+ });
1049
+ return events;
1050
+ },
1051
+
1052
+ /*
1053
+ * Clean specific event
1054
+ */
1055
+ _cleanEvent : function (event) {
1056
+ if (event.date) {
1057
+ event.start = event.date;
1058
+ }
1059
+ event.start = this._cleanDate(event.start);
1060
+ event.end = this._cleanDate(event.end);
1061
+ if (!event.end) {
1062
+ event.end = this._addDays(this._cloneDate(event.start), 1);
1063
+ }
1064
+ },
1065
+
1066
+ /*
1067
+ * Disable text selection of the elements in different browsers
1068
+ */
1069
+ _disableTextSelect : function($elements) {
1070
+ $elements.each(function(){
1071
+ if($.browser.mozilla){//Firefox
1072
+ $(this).css('MozUserSelect','none');
1073
+ }else if($.browser.msie){//IE
1074
+ $(this).bind('selectstart',function(){return false;});
1075
+ }else{//Opera, etc.
1076
+ $(this).mousedown(function(){return false;});
1077
+ }
1078
+ });
1079
+ },
1080
+
1081
+ /*
1082
+ * returns the date on the first millisecond of the week
1083
+ */
1084
+ _dateFirstDayOfWeek : function(date) {
1085
+ var self = this;
1086
+ var midnightCurrentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
1087
+ var millisToSubtract = self._getAdjustedDayIndex(midnightCurrentDate) * 86400000;
1088
+ return new Date(midnightCurrentDate.getTime() - millisToSubtract);
1089
+
1090
+ },
1091
+
1092
+ /*
1093
+ * returns the date on the first millisecond of the last day of the week
1094
+ */
1095
+ _dateLastDayOfWeek : function(date) {
1096
+ var self = this;
1097
+ var midnightCurrentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
1098
+ var millisToAdd = (6 - self._getAdjustedDayIndex(midnightCurrentDate)) * MILLIS_IN_DAY;
1099
+ return new Date(midnightCurrentDate.getTime() + millisToAdd);
1100
+ },
1101
+
1102
+ /*
1103
+ * gets the index of the current day adjusted based on options
1104
+ */
1105
+ _getAdjustedDayIndex : function(date) {
1106
+
1107
+ var midnightCurrentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
1108
+ var currentDayOfStandardWeek = midnightCurrentDate.getDay();
1109
+ var days = [0,1,2,3,4,5,6];
1110
+ this._rotate(days, this.options.firstDayOfWeek);
1111
+ return days[currentDayOfStandardWeek];
1112
+ },
1113
+
1114
+ /*
1115
+ * returns the date on the last millisecond of the week
1116
+ */
1117
+ _dateLastMilliOfWeek : function(date) {
1118
+ var lastDayOfWeek = this._dateLastDayOfWeek(date);
1119
+ return new Date(lastDayOfWeek.getTime() + (MILLIS_IN_DAY - 1));
1120
+
1121
+ },
1122
+
1123
+ /*
1124
+ * Clear the time components of a date leaving the date
1125
+ * of the first milli of day
1126
+ */
1127
+ _clearTime : function(d) {
1128
+ d.setHours(0);
1129
+ d.setMinutes(0);
1130
+ d.setSeconds(0);
1131
+ d.setMilliseconds(0);
1132
+ return d;
1133
+ },
1134
+
1135
+ /*
1136
+ * add specific number of days to date
1137
+ */
1138
+ _addDays : function(d, n, keepTime) {
1139
+ d.setDate(d.getDate() + n);
1140
+ if (keepTime) {
1141
+ return d;
1142
+ }
1143
+ return this._clearTime(d);
1144
+ },
1145
+
1146
+ /*
1147
+ * Rotate an array by specified number of places.
1148
+ */
1149
+ _rotate : function(a /*array*/, p /* integer, positive integer rotate to the right, negative to the left... */){
1150
+ for(var l = a.length, p = (Math.abs(p) >= l && (p %= l), p < 0 && (p += l), p), i, x; p; p = (Math.ceil(l / p) - 1) * p - l + (l = p)) {
1151
+ for(i = l; i > p; x = a[--i], a[i] = a[i - p], a[i - p] = x);
1152
+ }
1153
+ return a;
1154
+ },
1155
+
1156
+ _cloneDate : function(d) {
1157
+ return new Date(+d);
1158
+ },
1159
+
1160
+ /*
1161
+ * return a date for different representations
1162
+ */
1163
+ _cleanDate : function(d) {
1164
+ if (typeof d == 'string') {
1165
+ return $.weekCalendar.parseISO8601(d, true) || Date.parse(d) || new Date(parseInt(d));
1166
+ }
1167
+ if (typeof d == 'number') {
1168
+ return new Date(d);
1169
+ }
1170
+ return d;
1171
+ },
1172
+
1173
+ /*
1174
+ * date formatting is adapted from
1175
+ * http://jacwright.com/projects/javascript/date_format
1176
+ */
1177
+ _formatDate : function(date, format) {
1178
+ var options = this.options;
1179
+ var returnStr = '';
1180
+ for (var i = 0; i < format.length; i++) {
1181
+ var curChar = format.charAt(i);
1182
+ if ($.isFunction(this._replaceChars[curChar])) {
1183
+ returnStr += this._replaceChars[curChar](date, options);
1184
+ } else {
1185
+ returnStr += curChar;
1186
+ }
1187
+ }
1188
+ return returnStr;
1189
+ },
1190
+
1191
+ _replaceChars : {
1192
+
1193
+ // Day
1194
+ d: function(date) { return (date.getDate() < 10 ? '0' : '') + date.getDate(); },
1195
+ D: function(date, options) { return options.shortDays[date.getDay()]; },
1196
+ j: function(date) { return date.getDate(); },
1197
+ l: function(date, options) { return options.longDays[date.getDay()]; },
1198
+ N: function(date) { return date.getDay() + 1; },
1199
+ S: function(date) { return (date.getDate() % 10 == 1 && date.getDate() != 11 ? 'st' : (date.getDate() % 10 == 2 && date.getDate() != 12 ? 'nd' : (date.getDate() % 10 == 3 && date.getDate() != 13 ? 'rd' : 'th'))); },
1200
+ w: function(date) { return date.getDay(); },
1201
+ z: function(date) { return "Not Yet Supported"; },
1202
+ // Week
1203
+ W: function(date) { return "Not Yet Supported"; },
1204
+ // Month
1205
+ F: function(date, options) { return options.longMonths[date.getMonth()]; },
1206
+ m: function(date) { return (date.getMonth() < 9 ? '0' : '') + (date.getMonth() + 1); },
1207
+ M: function(date, options) { return options.shortMonths[date.getMonth()]; },
1208
+ n: function(date) { return date.getMonth() + 1; },
1209
+ t: function(date) { return "Not Yet Supported"; },
1210
+ // Year
1211
+ L: function(date) { return "Not Yet Supported"; },
1212
+ o: function(date) { return "Not Supported"; },
1213
+ Y: function(date) { return date.getFullYear(); },
1214
+ y: function(date) { return ('' + date.getFullYear()).substr(2); },
1215
+ // Time
1216
+ a: function(date) { return date.getHours() < 12 ? 'am' : 'pm'; },
1217
+ A: function(date) { return date.getHours() < 12 ? 'AM' : 'PM'; },
1218
+ B: function(date) { return "Not Yet Supported"; },
1219
+ g: function(date) { return date.getHours() % 12 || 12; },
1220
+ G: function(date) { return date.getHours(); },
1221
+ h: function(date) { return ((date.getHours() % 12 || 12) < 10 ? '0' : '') + (date.getHours() % 12 || 12); },
1222
+ H: function(date) { return (date.getHours() < 10 ? '0' : '') + date.getHours(); },
1223
+ i: function(date) { return (date.getMinutes() < 10 ? '0' : '') + date.getMinutes(); },
1224
+ s: function(date) { return (date.getSeconds() < 10 ? '0' : '') + date.getSeconds(); },
1225
+ // Timezone
1226
+ e: function(date) { return "Not Yet Supported"; },
1227
+ I: function(date) { return "Not Supported"; },
1228
+ O: function(date) { return (date.getTimezoneOffset() < 0 ? '-' : '+') + (date.getTimezoneOffset() / 60 < 10 ? '0' : '') + (date.getTimezoneOffset() / 60) + '00'; },
1229
+ T: function(date) { return "Not Yet Supported"; },
1230
+ Z: function(date) { return date.getTimezoneOffset() * 60; },
1231
+ // Full Date/Time
1232
+ c: function(date) { return "Not Yet Supported"; },
1233
+ r: function(date) { return date.toString(); },
1234
+ U: function(date) { return date.getTime() / 1000; }
1235
+ }
1236
+
1237
+ });
1238
+
1239
+ $.extend($.ui.weekCalendar, {
1240
+ version: '1.2.1',
1241
+ getter: ['getTimeslotTimes', 'getData', 'formatDate', 'formatTime'],
1242
+ defaults: {
1243
+ date: new Date(),
1244
+ timeFormat : "h:i a",
1245
+ dateFormat : "M d, Y",
1246
+ use24Hour : false,
1247
+ firstDayOfWeek : 0, // 0 = Sunday, 1 = Monday, 2 = Tuesday, ... , 6 = Saturday
1248
+ useShortDayNames: false,
1249
+ timeSeparator : " to ",
1250
+ startParam : "start",
1251
+ endParam : "end",
1252
+ businessHours : {start: 8, end: 18, limitDisplay : false},
1253
+ newEventText : "New Event",
1254
+ timeslotHeight: 20,
1255
+ defaultEventLength : 2,
1256
+ timeslotsPerHour : 4,
1257
+ buttons : true,
1258
+ buttonText : {
1259
+ today : "today",
1260
+ lastWeek : "&nbsp;&lt;&nbsp;",
1261
+ nextWeek : "&nbsp;&gt;&nbsp;"
1262
+ },
1263
+ scrollToHourMillis : 500,
1264
+ allowCalEventOverlap : false,
1265
+ overlapEventsSeparate: false,
1266
+ readonly: false,
1267
+ draggable : function(calEvent, element) { return true;},
1268
+ resizable : function(calEvent, element) { return true;},
1269
+ eventClick : function(){},
1270
+ eventRender : function(calEvent, element) { return element;},
1271
+ eventAfterRender : function(calEvent, element) { return element;},
1272
+ eventDrag : function(calEvent, element) {},
1273
+ eventDrop : function(calEvent, element){},
1274
+ eventResize : function(calEvent, element){},
1275
+ eventNew : function(calEvent, element) {},
1276
+ eventMouseover : function(calEvent, $event) {},
1277
+ eventMouseout : function(calEvent, $event) {},
1278
+ calendarBeforeLoad : function(calendar) {},
1279
+ calendarAfterLoad : function(calendar) {},
1280
+ noEvents : function() {},
1281
+ shortMonths : ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
1282
+ longMonths : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
1283
+ shortDays : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
1284
+ longDays : ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
1285
+ }
1286
+ });
1287
+
1288
+ var MILLIS_IN_DAY = 86400000;
1289
+ var MILLIS_IN_WEEK = MILLIS_IN_DAY * 7;
1290
+
1291
+ $.weekCalendar = function() {
1292
+ return {
1293
+ parseISO8601 : function(s, ignoreTimezone) {
1294
+
1295
+ // derived from http://delete.me.uk/2005/03/iso8601.html
1296
+ var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
1297
+ "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
1298
+ "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
1299
+ var d = s.match(new RegExp(regexp));
1300
+ if (!d) return null;
1301
+ var offset = 0;
1302
+ var date = new Date(d[1], 0, 1);
1303
+ if (d[3]) { date.setMonth(d[3] - 1); }
1304
+ if (d[5]) { date.setDate(d[5]); }
1305
+ if (d[7]) { date.setHours(d[7]); }
1306
+ if (d[8]) { date.setMinutes(d[8]); }
1307
+ if (d[10]) { date.setSeconds(d[10]); }
1308
+ if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
1309
+ if (!ignoreTimezone) {
1310
+ if (d[14]) {
1311
+ offset = (Number(d[16]) * 60) + Number(d[17]);
1312
+ offset *= ((d[15] == '-') ? 1 : -1);
1313
+ }
1314
+ offset -= date.getTimezoneOffset();
1315
+ }
1316
+ return new Date(Number(date) + (offset * 60 * 1000));
1317
+ }
1318
+ };
1319
+ }();
1320
+
1321
+
1322
+ })(jQuery);
1323
+
1324
+
1325
+ /*!
1326
+ * Title: jMonthCalendar 1.3.2-beta2
1327
+ * Dependencies: jQuery 1.3.0 +
1328
+ * Author: Kyle LeNeau
1329
+ * Email: kyle.leneau@gmail.com
1330
+ * Project Hompage: http://www.bytecyclist.com/projects/jmonthcalendar
1331
+ * Source: http://code.google.com/p/jmonthcalendar
1332
+ *
1333
+ */
1334
+ (function($) {
1335
+ var _boxes = [];
1336
+ var _eventObj = {};
1337
+
1338
+ var _workingDate = null;
1339
+ var _daysInMonth = 0;
1340
+ var _firstOfMonth = null;
1341
+ var _lastOfMonth = null;
1342
+ var _gridOffset = 0;
1343
+ var _totalDates = 0;
1344
+ var _gridRows = 0;
1345
+ var _totalBoxes = 0;
1346
+ var _dateRange = { startDate: null, endDate: null };
1347
+
1348
+
1349
+ var cEvents = [];
1350
+ var def = {
1351
+ containerId: "#jMonthCalendar",
1352
+ headerHeight: 50,
1353
+ firstDayOfWeek: 0,
1354
+ calendarStartDate:new Date(),
1355
+ dragableEvents: true,
1356
+ dragHoverClass: 'DateBoxOver',
1357
+ navLinks: {
1358
+ enableToday: true,
1359
+ enableNextYear: true,
1360
+ enablePrevYear: true,
1361
+ p:'&lsaquo; Prev',
1362
+ n:'Next &rsaquo;',
1363
+ t:'Today',
1364
+ showMore: 'Show More'
1365
+ },
1366
+ onMonthChanging: function() {},
1367
+ onMonthChanged: function() {},
1368
+ onEventLinkClick: function() {},
1369
+ onEventBlockClick: function() {},
1370
+ onEventBlockOver: function() {},
1371
+ onEventBlockOut: function() {},
1372
+ onDayLinkClick: function() {},
1373
+ onDayCellClick: function() {},
1374
+ onDayCellDblClick: function() {},
1375
+ onEventDropped: function() {},
1376
+ onShowMoreClick: function() {}
1377
+ };
1378
+
1379
+ $.jMonthCalendar = $.J = function() {};
1380
+
1381
+ var _getJSONDate = function(dateStr) {
1382
+ //check conditions for different types of accepted dates
1383
+ var tDt, k;
1384
+ if (typeof dateStr == "string") {
1385
+
1386
+ // "2008-12-28T00:00:00.0000000"
1387
+ var isoRegPlus = /^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2}).([0-9]{7})$/;
1388
+
1389
+ // "2008-12-28T00:00:00"
1390
+ var isoReg = /^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})$/;
1391
+
1392
+ //"2008-12-28"
1393
+ var yyyyMMdd = /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/;
1394
+
1395
+ // "new Date(2009, 1, 1)"
1396
+ // "new Date(1230444000000)
1397
+ var newReg = /^new/;
1398
+
1399
+ // "\/Date(1234418400000-0600)\/"
1400
+ var stdReg = /^\\\/Date\(([0-9]{13})-([0-9]{4})\)\\\/$/;
1401
+
1402
+ if (k = dateStr.match(isoRegPlus)) {
1403
+ return new Date(k[1],k[2]-1,k[3],k[4],k[5],k[6]);
1404
+ } else if (k = dateStr.match(isoReg)) {
1405
+ return new Date(k[1],k[2]-1,k[3],k[4],k[5],k[6]);
1406
+ } else if (k = dateStr.match(yyyyMMdd)) {
1407
+ return new Date(k[1],k[2]-1,k[3]);
1408
+ }
1409
+
1410
+ if (k = dateStr.match(stdReg)) {
1411
+ return new Date(k[1]);
1412
+ }
1413
+
1414
+ if (k = dateStr.match(newReg)) {
1415
+ return eval('(' + dateStr + ')');
1416
+ }
1417
+
1418
+ return tDt;
1419
+ }
1420
+ };
1421
+
1422
+ //This function will clean the JSON array, primaryly the dates and put the correct ones in the object. Intended to alwasy be called on event functions.
1423
+ var _filterEventCollection = function() {
1424
+ if (cEvents && cEvents.length > 0) {
1425
+ var multi = [];
1426
+ var single = [];
1427
+
1428
+ //Update and parse all the dates
1429
+ $.each(cEvents, function(){
1430
+ var ev = this;
1431
+ //Date Parse the JSON to create a new Date to work with here
1432
+ if(ev.StartDateTime) {
1433
+ if (typeof ev.StartDateTime == 'object' && ev.StartDateTime.getDate) { this.StartDateTime = ev.StartDateTime; }
1434
+ if (typeof ev.StartDateTime == 'string' && ev.StartDateTime.split) { this.StartDateTime = _getJSONDate(ev.StartDateTime); }
1435
+ } else if(ev.Date) { // DEPRECATED
1436
+ if (typeof ev.Date == 'object' && ev.Date.getDate) { this.StartDateTime = ev.Date; }
1437
+ if (typeof ev.Date == 'string' && ev.Date.split) { this.StartDateTime = _getJSONDate(ev.Date); }
1438
+ } else {
1439
+ return; //no start date, or legacy date. no event.
1440
+ }
1441
+
1442
+ if(ev.EndDateTime) {
1443
+ if (typeof ev.EndDateTime == 'object' && ev.EndDateTime.getDate) { this.EndDateTime = ev.EndDateTime; }
1444
+ if (typeof ev.EndDateTime == 'string' && ev.EndDateTime.split) { this.EndDateTime = _getJSONDate(ev.EndDateTime); }
1445
+ } else {
1446
+ this.EndDateTime = this.StartDateTime.clone();
1447
+ }
1448
+
1449
+ if (this.StartDateTime.clone().clearTime().compareTo(this.EndDateTime.clone().clearTime()) == 0) {
1450
+ single.push(this);
1451
+ } else if (this.StartDateTime.clone().clearTime().compareTo(this.EndDateTime.clone().clearTime()) == -1) {
1452
+ multi.push(this);
1453
+ }
1454
+ });
1455
+
1456
+ multi.sort(_eventSort);
1457
+ single.sort(_eventSort);
1458
+ cEvents = [];
1459
+ $.merge(cEvents, multi);
1460
+ $.merge(cEvents, single);
1461
+ }
1462
+ };
1463
+
1464
+ var _eventSort = function(a, b) {
1465
+ return a.StartDateTime.compareTo(b.StartDateTime);
1466
+ };
1467
+
1468
+ var _clearBoxes = function() {
1469
+ _clearBoxEvents();
1470
+ _boxes = [];
1471
+ };
1472
+
1473
+ var _clearBoxEvents = function() {
1474
+ for (var i = 0; i < _boxes.length; i++) {
1475
+ _boxes[i].clear();
1476
+ }
1477
+ _eventObj = {};
1478
+ };
1479
+
1480
+ var _initDates = function(dateIn) {
1481
+ var today = def.calendarStartDate;
1482
+ if(dateIn == undefined) {
1483
+ _workingDate = new Date(today.getFullYear(), today.getMonth(), 1);
1484
+ } else {
1485
+ _workingDate = dateIn;
1486
+ _workingDate.setDate(1);
1487
+ }
1488
+
1489
+ _daysInMonth = _workingDate.getDaysInMonth();
1490
+ _firstOfMonth = _workingDate.clone().moveToFirstDayOfMonth();
1491
+ _lastOfMonth = _workingDate.clone().moveToLastDayOfMonth();
1492
+ _gridOffset = _firstOfMonth.getDay() - def.firstDayOfWeek;
1493
+ _totalDates = _gridOffset + _daysInMonth;
1494
+ _gridRows = Math.ceil(_totalDates / 7);
1495
+ _totalBoxes = _gridRows * 7;
1496
+
1497
+ _dateRange.startDate = _firstOfMonth.clone().addDays((-1) * _gridOffset);
1498
+ _dateRange.endDate = _lastOfMonth.clone().addDays(_totalBoxes - (_daysInMonth + _gridOffset));
1499
+ };
1500
+
1501
+ var _initHeaders = function() {
1502
+ // Create Previous Month link for later
1503
+ var prevMonth = _workingDate.clone().addMonths(-1);
1504
+ var prevMLink = $('<div class="MonthNavPrev"><a class="link-prev">'+ def.navLinks.p +'</a></div>').click(function() {
1505
+ $.J.ChangeMonth(prevMonth);
1506
+ return false;
1507
+ });
1508
+
1509
+ //Create Next Month link for later
1510
+ var nextMonth = _workingDate.clone().addMonths(1);
1511
+ var nextMLink = $('<div class="MonthNavNext"><a class="link-next">'+ def.navLinks.n +'</a></div>').click(function() {
1512
+ $.J.ChangeMonth(nextMonth);
1513
+ return false;
1514
+ });
1515
+
1516
+ //Create Previous Year link for later
1517
+ var prevYear = _workingDate.clone().addYears(-1);
1518
+ var prevYLink;
1519
+ if(def.navLinks.enablePrevYear) {
1520
+ prevYLink = $('<div class="YearNavPrev"><a>'+ prevYear.getFullYear() +'</a></div>').click(function() {
1521
+ $.J.ChangeMonth(prevYear);
1522
+ return false;
1523
+ });
1524
+ }
1525
+
1526
+ //Create Next Year link for later
1527
+ var nextYear = _workingDate.clone().addYears(1);
1528
+ var nextYLink;
1529
+ if(def.navLinks.enableNextYear) {
1530
+ nextYLink = $('<div class="YearNavNext"><a>'+ nextYear.getFullYear() +'</a></div>').click(function() {
1531
+ $.J.ChangeMonth(nextYear);
1532
+ return false;
1533
+ });
1534
+ }
1535
+
1536
+ var todayLink;
1537
+ if(def.navLinks.enableToday) {
1538
+ //Create Today link for later
1539
+ todayLink = $('<div class="TodayLink"><a class="link-today">'+ def.navLinks.t +'</a></div>').click(function() {
1540
+ $.J.ChangeMonth(new Date());
1541
+ return false;
1542
+ });
1543
+ }
1544
+
1545
+ //Build up the Header first, Navigation
1546
+ var navRow = $('<tr><td colspan="7"><div class="FormHeader MonthNavigation"></div></td></tr>');
1547
+ var navHead = $('.MonthNavigation', navRow);
1548
+
1549
+ navHead.append(prevMLink, nextMLink);
1550
+ if(def.navLinks.enableToday) { navHead.append(todayLink); }
1551
+
1552
+ navHead.append($('<div class="MonthName"></div>').append(Date.CultureInfo.monthNames[_workingDate.getMonth()] + " " + _workingDate.getFullYear()));
1553
+
1554
+ if(def.navLinks.enablePrevYear) { navHead.append(prevYLink); }
1555
+ if(def.navLinks.enableNextYear) { navHead.append(nextYLink); }
1556
+
1557
+
1558
+ // Days
1559
+ var headRow = $("<tr></tr>");
1560
+ for (var i = def.firstDayOfWeek; i < def.firstDayOfWeek+7; i++) {
1561
+ var weekday = i % 7;
1562
+ var wordday = Date.CultureInfo.dayNames[weekday];
1563
+ headRow.append('<th title="' + wordday + '" class="DateHeader' + (weekday == 0 || weekday == 6 ? ' Weekend' : '') + '"><span>' + wordday + '</span></th>');
1564
+ }
1565
+
1566
+ headRow = $("<thead id=\"CalendarHead\"></thead>").css({ "height" : def.headerHeight + "px" }).append(headRow);
1567
+ headRow = headRow.prepend(navRow);
1568
+ return headRow;
1569
+ };
1570
+
1571
+
1572
+
1573
+ $.J.DrawCalendar = function(dateIn){
1574
+ var now = new Date();
1575
+ now.clearTime();
1576
+
1577
+ var today = def.calendarStartDate;
1578
+
1579
+ _clearBoxes();
1580
+
1581
+ _initDates(dateIn);
1582
+ var headerRow = _initHeaders();
1583
+
1584
+ //properties
1585
+ var isCurrentMonth = (_workingDate.getMonth() == today.getMonth() && _workingDate.getFullYear() == today.getFullYear());
1586
+ var containerHeight = $(def.containerId).outerHeight();
1587
+ var rowHeight = (containerHeight - def.headerHeight) / _gridRows;
1588
+ var row = null;
1589
+
1590
+ //Build up the Body
1591
+ var tBody = $('<tbody id="CalendarBody"></tbody>');
1592
+
1593
+ for (var i = 0; i < _totalBoxes; i++) {
1594
+ var currentDate = _dateRange.startDate.clone().addDays(i);
1595
+ if (i % 7 == 0 || i == 0) {
1596
+ row = $("<tr></tr>");
1597
+ row.css({ "height" : rowHeight + "px" });
1598
+ tBody.append(row);
1599
+ }
1600
+
1601
+ var weekday = (def.firstDayOfWeek + i) % 7;
1602
+ var atts = {'class':"DateBox" + (weekday == 0 || weekday == 6 ? ' Weekend ' : ''),
1603
+ 'date':currentDate.toString("M/d/yyyy")
1604
+ };
1605
+
1606
+ //dates outside of month range.
1607
+ if (currentDate.compareTo(_firstOfMonth) == -1 || currentDate.compareTo(_lastOfMonth) == 1) {
1608
+ atts['class'] += ' Inactive';
1609
+ }
1610
+
1611
+ //check to see if current date rendering is today
1612
+ if (currentDate.compareTo(now) == 0) {
1613
+ atts['class'] += ' Today';
1614
+ }
1615
+
1616
+ //DateBox Events
1617
+ var dateLink = $('<div class="DateLabel"><a>' + currentDate.getDate() + '</a></div>');
1618
+ dateLink.bind('click', { Date: currentDate.clone() }, def.onDayLinkClick);
1619
+
1620
+ var dateBox = $("<td></td>").attr(atts).append(dateLink);
1621
+ dateBox.bind('dblclick', { Date: currentDate.clone() }, def.onDayCellDblClick);
1622
+ dateBox.bind('click', { Date: currentDate.clone() }, def.onDayCellClick);
1623
+
1624
+ if (def.dragableEvents) {
1625
+ dateBox.droppable({
1626
+ hoverClass: def.dragHoverClass,
1627
+ tolerance: 'pointer',
1628
+ drop: function(ev, ui) {
1629
+ var eventId = ui.draggable.attr("eventid")
1630
+ var newDate = new Date($(this).attr("date")).clearTime();
1631
+
1632
+ var event;
1633
+ $.each(cEvents, function() {
1634
+ if (this.EventID == eventId) {
1635
+ var days = new TimeSpan(newDate - this.StartDateTime).days;
1636
+
1637
+ this.StartDateTime.addDays(days);
1638
+ this.EndDateTime.addDays(days);
1639
+
1640
+ event = this;
1641
+ }
1642
+ });
1643
+
1644
+ $.J.ClearEventsOnCalendar();
1645
+ _drawEventsOnCalendar();
1646
+
1647
+ def.onEventDropped.call(this, event, newDate);
1648
+ }
1649
+ });
1650
+ }
1651
+
1652
+ _boxes.push(new CalendarBox(i, currentDate, dateBox, dateLink));
1653
+ row.append(dateBox);
1654
+ }
1655
+ tBody.append(row);
1656
+
1657
+ var a = $(def.containerId);
1658
+ var cal = $('<table class="MonthlyCalendar" cellpadding="0" tablespacing="0"></table>').append(headerRow, tBody);
1659
+
1660
+ a.hide();
1661
+ a.html(cal);
1662
+ a.fadeIn("normal");
1663
+
1664
+ _drawEventsOnCalendar();
1665
+ }
1666
+
1667
+ var _drawEventsOnCalendar = function() {
1668
+ //filter the JSON array for proper dates
1669
+ _filterEventCollection();
1670
+ _clearBoxEvents();
1671
+
1672
+ if (cEvents && cEvents.length > 0) {
1673
+ var container = $(def.containerId);
1674
+
1675
+ $.each(cEvents, function(){
1676
+ var ev = this;
1677
+ //alert("eventID: " + ev.EventID + ", start: " + ev.StartDateTime + ",end: " + ev.EndDateTime);
1678
+
1679
+ var tempStartDT = ev.StartDateTime.clone().clearTime();
1680
+ var tempEndDT = ev.EndDateTime.clone().clearTime();
1681
+
1682
+ var startI = new TimeSpan(tempStartDT - _dateRange.startDate).days;
1683
+ var endI = new TimeSpan(tempEndDT - _dateRange.startDate).days;
1684
+ //alert("start I: " + startI + " end I: " + endI);
1685
+
1686
+ var istart = (startI < 0) ? 0 : startI;
1687
+ var iend = (endI > _boxes.length - 1) ? _boxes.length - 1 : endI;
1688
+ //alert("istart: " + istart + " iend: " + iend);
1689
+
1690
+
1691
+ for (var i = istart; i <= iend; i++) {
1692
+ var b = _boxes[i];
1693
+
1694
+ var startBoxCompare = tempStartDT.compareTo(b.date);
1695
+ var endBoxCompare = tempEndDT.compareTo(b.date);
1696
+
1697
+ var continueEvent = ((i != 0 && startBoxCompare == -1 && endBoxCompare >= 0 && b.weekNumber != _boxes[i - 1].weekNumber) || (i == 0 && startBoxCompare == -1));
1698
+ var toManyEvents = (startBoxCompare == 0 || (i == 0 && startBoxCompare == -1) ||
1699
+ continueEvent || (startBoxCompare == -1 && endBoxCompare >= 0)) && b.vOffset >= (b.getCellBox().height() - b.getLabelHeight() - 32);
1700
+
1701
+ //alert("b.vOffset: " + b.vOffset + ", cell height: " + (b.getCellBox().height() - b.getLabelHeight() - 32));
1702
+ //alert(continueEvent);
1703
+ //alert(toManyEvents);
1704
+
1705
+ if (toManyEvents) {
1706
+ if (!b.isTooManySet) {
1707
+ var moreDiv = $('<div class="MoreEvents" id="ME_' + i + '">' + def.navLinks.showMore + '</div>');
1708
+ var pos = b.getCellPosition();
1709
+ var index = i;
1710
+
1711
+ moreDiv.css({
1712
+ "top" : (pos.top + (b.getCellBox().height() - b.getLabelHeight())),
1713
+ "left" : pos.left,
1714
+ "width" : (b.getLabelWidth() - 7),
1715
+ "position" : "absolute" });
1716
+
1717
+ moreDiv.click(function(e) { _showMoreClick(e, index); });
1718
+
1719
+ _eventObj[moreDiv.attr("id")] = moreDiv;
1720
+ b.isTooManySet = true;
1721
+ } //else update the +more to show??
1722
+ b.events.push(ev);
1723
+ } else if (startBoxCompare == 0 || (i == 0 && startBoxCompare == -1) || continueEvent) {
1724
+ var block = _buildEventBlock(ev, b.weekNumber);
1725
+ var pos = b.getCellPosition();
1726
+
1727
+ block.css({
1728
+ "top" : (pos.top + b.getLabelHeight() + b.vOffset),
1729
+ "left" : pos.left,
1730
+ "width" : (b.getLabelWidth() - 7),
1731
+ "position" : "absolute" });
1732
+
1733
+ b.vOffset += 19;
1734
+
1735
+ if (continueEvent) {
1736
+ block.prepend($('<span />').addClass("ui-icon").addClass("ui-icon-triangle-1-w"));
1737
+
1738
+ var e = _eventObj['Event_' + ev.EventID + '_' + (b.weekNumber - 1)];
1739
+ if (e) { e.prepend($('<span />').addClass("ui-icon").addClass("ui-icon-triangle-1-e")); }
1740
+ }
1741
+
1742
+ _eventObj[block.attr("id")] = block;
1743
+
1744
+ b.events.push(ev);
1745
+ } else if (startBoxCompare == -1 && endBoxCompare >= 0) {
1746
+ var e = _eventObj['Event_' + ev.EventID + '_' + b.weekNumber];
1747
+ if (e) {
1748
+ var w = e.css("width")
1749
+ e.css({ "width" : (parseInt(w) + b.getLabelWidth() + 1) });
1750
+ b.vOffset += 19;
1751
+ b.events.push(ev);
1752
+ }
1753
+ }
1754
+
1755
+ //end of month continue
1756
+ if (i == iend && endBoxCompare > 0) {
1757
+ var e = _eventObj['Event_' + ev.EventID + '_' + b.weekNumber];
1758
+ if (e) { e.prepend($('<span />').addClass("ui-icon").addClass("ui-icon-triangle-1-e")); }
1759
+ }
1760
+ }
1761
+ });
1762
+
1763
+ for (var o in _eventObj) {
1764
+ _eventObj[o].hide();
1765
+ container.append(_eventObj[o]);
1766
+ _eventObj[o].show();
1767
+ }
1768
+ }
1769
+ }
1770
+
1771
+ var _buildEventBlock = function(ev, weekNumber) {
1772
+ var block = $('<div class="Event" id="Event_' + ev.EventID + '_' + weekNumber + '" eventid="' + ev.EventID +'"></div>');
1773
+
1774
+ if(ev.CssClass) { block.addClass(ev.CssClass) }
1775
+ block.bind('click', { Event: ev }, def.onEventBlockClick);
1776
+ block.bind('mouseover', { Event: ev }, def.onEventBlockOver);
1777
+ block.bind('mouseout', { Event: ev }, def.onEventBlockOut);
1778
+
1779
+ if (def.dragableEvents) {
1780
+ _dragableEvent(ev, block, weekNumber);
1781
+ }
1782
+
1783
+ var link;
1784
+ if (ev.URL && ev.URL.length > 0) {
1785
+ link = $('<a href="' + ev.URL + '">' + ev.Title + '</a>');
1786
+ } else {
1787
+ link = $('<a>' + ev.Title + '</a>');
1788
+ }
1789
+
1790
+ link.bind('click', { Event: ev }, def.onEventLinkClick);
1791
+ block.append(link);
1792
+ return block;
1793
+ }
1794
+
1795
+ var _dragableEvent = function(event, block, weekNumber) {
1796
+ block.draggable({
1797
+ zIndex: 4,
1798
+ delay: 50,
1799
+ opacity: 0.5,
1800
+ revertDuration: 1000,
1801
+ cursorAt: { left: 5 },
1802
+ start: function(ev, ui) {
1803
+ //hide any additional event parts
1804
+ for (var i = 0; i <= _gridRows; i++) {
1805
+ if (i == weekNumber) {
1806
+ continue;
1807
+ }
1808
+
1809
+ var e = _eventObj['Event_' + event.EventID + '_' + i];
1810
+ if (e) { e.hide(); }
1811
+ }
1812
+ }
1813
+ });
1814
+ }
1815
+
1816
+ var _showMoreClick = function(e, boxIndex) {
1817
+ var box = _boxes[boxIndex];
1818
+ def.onShowMoreClick.call(this, box.events);
1819
+ e.stopPropagation();
1820
+ }
1821
+
1822
+
1823
+ $.J.ClearEventsOnCalendar = function() {
1824
+ _clearBoxEvents();
1825
+ $(".Event", $(def.containerId)).remove();
1826
+ $(".MoreEvents", $(def.containerId)).remove();
1827
+ }
1828
+
1829
+ $.J.AddEvents = function(eventCollection) {
1830
+ if(eventCollection) {
1831
+ if(eventCollection.length > 0) {
1832
+ $.merge(cEvents, eventCollection);
1833
+ } else {
1834
+ cEvents.push(eventCollection);
1835
+ }
1836
+ $.J.ClearEventsOnCalendar();
1837
+ _drawEventsOnCalendar();
1838
+ }
1839
+ }
1840
+
1841
+ $.J.ReplaceEventCollection = function(eventCollection) {
1842
+ if(eventCollection) {
1843
+ cEvents = [];
1844
+ cEvents = eventCollection;
1845
+ }
1846
+
1847
+ $.J.ClearEventsOnCalendar();
1848
+ _drawEventsOnCalendar();
1849
+ }
1850
+
1851
+ $.J.ChangeMonth = function(dateIn) {
1852
+ var returned = def.onMonthChanging.call(this, dateIn);
1853
+ if (!returned) {
1854
+ $.J.DrawCalendar(dateIn);
1855
+ def.onMonthChanged.call(this, dateIn);
1856
+ }
1857
+ }
1858
+
1859
+ $.J.Initialize = function(options, events) {
1860
+ var today = new Date();
1861
+
1862
+ options = $.extend(def, options);
1863
+
1864
+ if (events) {
1865
+ $.J.ClearEventsOnCalendar();
1866
+ cEvents = events;
1867
+ }
1868
+
1869
+ $.J.DrawCalendar();
1870
+ };
1871
+
1872
+
1873
+ function CalendarBox(id, boxDate, cell, label) {
1874
+ this.id = id;
1875
+ this.date = boxDate;
1876
+ this.cell = cell;
1877
+ this.label = label;
1878
+ this.weekNumber = Math.floor(id / 7);
1879
+ this.events= [];
1880
+ this.isTooManySet = false;
1881
+ this.vOffset = 0;
1882
+
1883
+ this.echo = function() {
1884
+ alert("Date: " + this.date + " WeekNumber: " + this.weekNumber + " ID: " + this.id);
1885
+ }
1886
+
1887
+ this.clear = function() {
1888
+ this.events = [];
1889
+ this.isTooManySet = false;
1890
+ this.vOffset = 0;
1891
+ }
1892
+
1893
+ this.getCellPosition = function() {
1894
+ if (this.cell) {
1895
+ return this.cell.position();
1896
+ }
1897
+ return;
1898
+ }
1899
+
1900
+ this.getCellBox = function() {
1901
+ if (this.cell) {
1902
+ return this.cell;
1903
+ }
1904
+ return;
1905
+ }
1906
+
1907
+ this.getLabelWidth = function() {
1908
+ if (this.label) {
1909
+ return this.label.innerWidth();
1910
+ }
1911
+ return;
1912
+ }
1913
+
1914
+ this.getLabelHeight = function() {
1915
+ if (this.label) {
1916
+ return this.label.height();
1917
+ }
1918
+ return;
1919
+ }
1920
+
1921
+ this.getDate = function() {
1922
+ return this.date;
1923
+ }
1924
+ }
1925
+ })(jQuery);/**
1926
+ * Version: 1.0 Alpha-1
1927
+ * Build Date: 13-Nov-2007
1928
+ * Copyright (c) 2006-2007, Coolite Inc. (http://www.coolite.com/). All rights reserved.
1929
+ * License: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
1930
+ * Website: http://www.datejs.com/ or http://www.coolite.com/datejs/
1931
+ */
1932
+ Date.CultureInfo={name:"en-US",englishName:"English (United States)",nativeName:"English (United States)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\+|after|from)/i,subtract:/^(\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\.?m?\.?|p\.?m?\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt)/i,ordinalSuffix:/^\s*(st|nd|rd|th)/i,timeContext:/^\s*(\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
1933
+ Date.getMonthNumberFromName=function(name){var n=Date.CultureInfo.monthNames,m=Date.CultureInfo.abbreviatedMonthNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
1934
+ return-1;};Date.getDayNumberFromName=function(name){var n=Date.CultureInfo.dayNames,m=Date.CultureInfo.abbreviatedDayNames,o=Date.CultureInfo.shortestDayNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
1935
+ return-1;};Date.isLeapYear=function(year){return(((year%4===0)&&(year%100!==0))||(year%400===0));};Date.getDaysInMonth=function(year,month){return[31,(Date.isLeapYear(year)?29:28),31,30,31,30,31,31,30,31,30,31][month];};Date.getTimezoneOffset=function(s,dst){return(dst||false)?Date.CultureInfo.abbreviatedTimeZoneDST[s.toUpperCase()]:Date.CultureInfo.abbreviatedTimeZoneStandard[s.toUpperCase()];};Date.getTimezoneAbbreviation=function(offset,dst){var n=(dst||false)?Date.CultureInfo.abbreviatedTimeZoneDST:Date.CultureInfo.abbreviatedTimeZoneStandard,p;for(p in n){if(n[p]===offset){return p;}}
1936
+ return null;};Date.prototype.clone=function(){return new Date(this.getTime());};Date.prototype.compareTo=function(date){if(isNaN(this)){throw new Error(this);}
1937
+ if(date instanceof Date&&!isNaN(date)){return(this>date)?1:(this<date)?-1:0;}else{throw new TypeError(date);}};Date.prototype.equals=function(date){return(this.compareTo(date)===0);};Date.prototype.between=function(start,end){var t=this.getTime();return t>=start.getTime()&&t<=end.getTime();};Date.prototype.addMilliseconds=function(value){this.setMilliseconds(this.getMilliseconds()+value);return this;};Date.prototype.addSeconds=function(value){return this.addMilliseconds(value*1000);};Date.prototype.addMinutes=function(value){return this.addMilliseconds(value*60000);};Date.prototype.addHours=function(value){return this.addMilliseconds(value*3600000);};Date.prototype.addDays=function(value){return this.addMilliseconds(value*86400000);};Date.prototype.addWeeks=function(value){return this.addMilliseconds(value*604800000);};Date.prototype.addMonths=function(value){var n=this.getDate();this.setDate(1);this.setMonth(this.getMonth()+value);this.setDate(Math.min(n,this.getDaysInMonth()));return this;};Date.prototype.addYears=function(value){return this.addMonths(value*12);};Date.prototype.add=function(config){if(typeof config=="number"){this._orient=config;return this;}
1938
+ var x=config;if(x.millisecond||x.milliseconds){this.addMilliseconds(x.millisecond||x.milliseconds);}
1939
+ if(x.second||x.seconds){this.addSeconds(x.second||x.seconds);}
1940
+ if(x.minute||x.minutes){this.addMinutes(x.minute||x.minutes);}
1941
+ if(x.hour||x.hours){this.addHours(x.hour||x.hours);}
1942
+ if(x.month||x.months){this.addMonths(x.month||x.months);}
1943
+ if(x.year||x.years){this.addYears(x.year||x.years);}
1944
+ if(x.day||x.days){this.addDays(x.day||x.days);}
1945
+ return this;};Date._validate=function(value,min,max,name){if(typeof value!="number"){throw new TypeError(value+" is not a Number.");}else if(value<min||value>max){throw new RangeError(value+" is not a valid value for "+name+".");}
1946
+ return true;};Date.validateMillisecond=function(n){return Date._validate(n,0,999,"milliseconds");};Date.validateSecond=function(n){return Date._validate(n,0,59,"seconds");};Date.validateMinute=function(n){return Date._validate(n,0,59,"minutes");};Date.validateHour=function(n){return Date._validate(n,0,23,"hours");};Date.validateDay=function(n,year,month){return Date._validate(n,1,Date.getDaysInMonth(year,month),"days");};Date.validateMonth=function(n){return Date._validate(n,0,11,"months");};Date.validateYear=function(n){return Date._validate(n,1,9999,"seconds");};Date.prototype.set=function(config){var x=config;if(!x.millisecond&&x.millisecond!==0){x.millisecond=-1;}
1947
+ if(!x.second&&x.second!==0){x.second=-1;}
1948
+ if(!x.minute&&x.minute!==0){x.minute=-1;}
1949
+ if(!x.hour&&x.hour!==0){x.hour=-1;}
1950
+ if(!x.day&&x.day!==0){x.day=-1;}
1951
+ if(!x.month&&x.month!==0){x.month=-1;}
1952
+ if(!x.year&&x.year!==0){x.year=-1;}
1953
+ if(x.millisecond!=-1&&Date.validateMillisecond(x.millisecond)){this.addMilliseconds(x.millisecond-this.getMilliseconds());}
1954
+ if(x.second!=-1&&Date.validateSecond(x.second)){this.addSeconds(x.second-this.getSeconds());}
1955
+ if(x.minute!=-1&&Date.validateMinute(x.minute)){this.addMinutes(x.minute-this.getMinutes());}
1956
+ if(x.hour!=-1&&Date.validateHour(x.hour)){this.addHours(x.hour-this.getHours());}
1957
+ if(x.month!==-1&&Date.validateMonth(x.month)){this.addMonths(x.month-this.getMonth());}
1958
+ if(x.year!=-1&&Date.validateYear(x.year)){this.addYears(x.year-this.getFullYear());}
1959
+ if(x.day!=-1&&Date.validateDay(x.day,this.getFullYear(),this.getMonth())){this.addDays(x.day-this.getDate());}
1960
+ if(x.timezone){this.setTimezone(x.timezone);}
1961
+ if(x.timezoneOffset){this.setTimezoneOffset(x.timezoneOffset);}
1962
+ return this;};Date.prototype.clearTime=function(){this.setHours(0);this.setMinutes(0);this.setSeconds(0);this.setMilliseconds(0);return this;};Date.prototype.isLeapYear=function(){var y=this.getFullYear();return(((y%4===0)&&(y%100!==0))||(y%400===0));};Date.prototype.isWeekday=function(){return!(this.is().sat()||this.is().sun());};Date.prototype.getDaysInMonth=function(){return Date.getDaysInMonth(this.getFullYear(),this.getMonth());};Date.prototype.moveToFirstDayOfMonth=function(){return this.set({day:1});};Date.prototype.moveToLastDayOfMonth=function(){return this.set({day:this.getDaysInMonth()});};Date.prototype.moveToDayOfWeek=function(day,orient){var diff=(day-this.getDay()+7*(orient||+1))%7;return this.addDays((diff===0)?diff+=7*(orient||+1):diff);};Date.prototype.moveToMonth=function(month,orient){var diff=(month-this.getMonth()+12*(orient||+1))%12;return this.addMonths((diff===0)?diff+=12*(orient||+1):diff);};Date.prototype.getDayOfYear=function(){return Math.floor((this-new Date(this.getFullYear(),0,1))/86400000);};Date.prototype.getWeekOfYear=function(firstDayOfWeek){var y=this.getFullYear(),m=this.getMonth(),d=this.getDate();var dow=firstDayOfWeek||Date.CultureInfo.firstDayOfWeek;var offset=7+1-new Date(y,0,1).getDay();if(offset==8){offset=1;}
1963
+ var daynum=((Date.UTC(y,m,d,0,0,0)-Date.UTC(y,0,1,0,0,0))/86400000)+1;var w=Math.floor((daynum-offset+7)/7);if(w===dow){y--;var prevOffset=7+1-new Date(y,0,1).getDay();if(prevOffset==2||prevOffset==8){w=53;}else{w=52;}}
1964
+ return w;};Date.prototype.isDST=function(){console.log('isDST');return this.toString().match(/(E|C|M|P)(S|D)T/)[2]=="D";};Date.prototype.getTimezone=function(){return Date.getTimezoneAbbreviation(this.getUTCOffset,this.isDST());};Date.prototype.setTimezoneOffset=function(s){var here=this.getTimezoneOffset(),there=Number(s)*-6/10;this.addMinutes(there-here);return this;};Date.prototype.setTimezone=function(s){return this.setTimezoneOffset(Date.getTimezoneOffset(s));};Date.prototype.getUTCOffset=function(){var n=this.getTimezoneOffset()*-10/6,r;if(n<0){r=(n-10000).toString();return r[0]+r.substr(2);}else{r=(n+10000).toString();return"+"+r.substr(1);}};Date.prototype.getDayName=function(abbrev){return abbrev?Date.CultureInfo.abbreviatedDayNames[this.getDay()]:Date.CultureInfo.dayNames[this.getDay()];};Date.prototype.getMonthName=function(abbrev){return abbrev?Date.CultureInfo.abbreviatedMonthNames[this.getMonth()]:Date.CultureInfo.monthNames[this.getMonth()];};Date.prototype._toString=Date.prototype.toString;Date.prototype.toString=function(format){var self=this;var p=function p(s){return(s.toString().length==1)?"0"+s:s;};return format?format.replace(/dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?/g,function(format){switch(format){case"hh":return p(self.getHours()<13?self.getHours():(self.getHours()-12));case"h":return self.getHours()<13?self.getHours():(self.getHours()-12);case"HH":return p(self.getHours());case"H":return self.getHours();case"mm":return p(self.getMinutes());case"m":return self.getMinutes();case"ss":return p(self.getSeconds());case"s":return self.getSeconds();case"yyyy":return self.getFullYear();case"yy":return self.getFullYear().toString().substring(2,4);case"dddd":return self.getDayName();case"ddd":return self.getDayName(true);case"dd":return p(self.getDate());case"d":return self.getDate().toString();case"MMMM":return self.getMonthName();case"MMM":return self.getMonthName(true);case"MM":return p((self.getMonth()+1));case"M":return self.getMonth()+1;case"t":return self.getHours()<12?Date.CultureInfo.amDesignator.substring(0,1):Date.CultureInfo.pmDesignator.substring(0,1);case"tt":return self.getHours()<12?Date.CultureInfo.amDesignator:Date.CultureInfo.pmDesignator;case"zzz":case"zz":case"z":return"";}}):this._toString();};
1965
+ Date.now=function(){return new Date();};Date.today=function(){return Date.now().clearTime();};Date.prototype._orient=+1;Date.prototype.next=function(){this._orient=+1;return this;};Date.prototype.last=Date.prototype.prev=Date.prototype.previous=function(){this._orient=-1;return this;};Date.prototype._is=false;Date.prototype.is=function(){this._is=true;return this;};Number.prototype._dateElement="day";Number.prototype.fromNow=function(){var c={};c[this._dateElement]=this;return Date.now().add(c);};Number.prototype.ago=function(){var c={};c[this._dateElement]=this*-1;return Date.now().add(c);};(function(){var $D=Date.prototype,$N=Number.prototype;var dx=("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),mx=("january february march april may june july august september october november december").split(/\s/),px=("Millisecond Second Minute Hour Day Week Month Year").split(/\s/),de;var df=function(n){return function(){if(this._is){this._is=false;return this.getDay()==n;}
1966
+ return this.moveToDayOfWeek(n,this._orient);};};for(var i=0;i<dx.length;i++){$D[dx[i]]=$D[dx[i].substring(0,3)]=df(i);}
1967
+ var mf=function(n){return function(){if(this._is){this._is=false;return this.getMonth()===n;}
1968
+ return this.moveToMonth(n,this._orient);};};for(var j=0;j<mx.length;j++){$D[mx[j]]=$D[mx[j].substring(0,3)]=mf(j);}
1969
+ var ef=function(j){return function(){if(j.substring(j.length-1)!="s"){j+="s";}
1970
+ return this["add"+j](this._orient);};};var nf=function(n){return function(){this._dateElement=n;return this;};};for(var k=0;k<px.length;k++){de=px[k].toLowerCase();$D[de]=$D[de+"s"]=ef(px[k]);$N[de]=$N[de+"s"]=nf(de);}}());Date.prototype.toJSONString=function(){return this.toString("yyyy-MM-ddThh:mm:ssZ");};Date.prototype.toShortDateString=function(){return this.toString(Date.CultureInfo.formatPatterns.shortDatePattern);};Date.prototype.toLongDateString=function(){return this.toString(Date.CultureInfo.formatPatterns.longDatePattern);};Date.prototype.toShortTimeString=function(){return this.toString(Date.CultureInfo.formatPatterns.shortTimePattern);};Date.prototype.toLongTimeString=function(){return this.toString(Date.CultureInfo.formatPatterns.longTimePattern);};Date.prototype.getOrdinal=function(){switch(this.getDate()){case 1:case 21:case 31:return"st";case 2:case 22:return"nd";case 3:case 23:return"rd";default:return"th";}};
1971
+ (function(){Date.Parsing={Exception:function(s){this.message="Parse error at '"+s.substring(0,10)+" ...'";}};var $P=Date.Parsing;var _=$P.Operators={rtoken:function(r){return function(s){var mx=s.match(r);if(mx){return([mx[0],s.substring(mx[0].length)]);}else{throw new $P.Exception(s);}};},token:function(s){return function(s){return _.rtoken(new RegExp("^\s*"+s+"\s*"))(s);};},stoken:function(s){return _.rtoken(new RegExp("^"+s));},until:function(p){return function(s){var qx=[],rx=null;while(s.length){try{rx=p.call(this,s);}catch(e){qx.push(rx[0]);s=rx[1];continue;}
1972
+ break;}
1973
+ return[qx,s];};},many:function(p){return function(s){var rx=[],r=null;while(s.length){try{r=p.call(this,s);}catch(e){return[rx,s];}
1974
+ rx.push(r[0]);s=r[1];}
1975
+ return[rx,s];};},optional:function(p){return function(s){var r=null;try{r=p.call(this,s);}catch(e){return[null,s];}
1976
+ return[r[0],r[1]];};},not:function(p){return function(s){try{p.call(this,s);}catch(e){return[null,s];}
1977
+ throw new $P.Exception(s);};},ignore:function(p){return p?function(s){var r=null;r=p.call(this,s);return[null,r[1]];}:null;},product:function(){var px=arguments[0],qx=Array.prototype.slice.call(arguments,1),rx=[];for(var i=0;i<px.length;i++){rx.push(_.each(px[i],qx));}
1978
+ return rx;},cache:function(rule){var cache={},r=null;return function(s){try{r=cache[s]=(cache[s]||rule.call(this,s));}catch(e){r=cache[s]=e;}
1979
+ if(r instanceof $P.Exception){throw r;}else{return r;}};},any:function(){var px=arguments;return function(s){var r=null;for(var i=0;i<px.length;i++){if(px[i]==null){continue;}
1980
+ try{r=(px[i].call(this,s));}catch(e){r=null;}
1981
+ if(r){return r;}}
1982
+ throw new $P.Exception(s);};},each:function(){var px=arguments;return function(s){var rx=[],r=null;for(var i=0;i<px.length;i++){if(px[i]==null){continue;}
1983
+ try{r=(px[i].call(this,s));}catch(e){throw new $P.Exception(s);}
1984
+ rx.push(r[0]);s=r[1];}
1985
+ return[rx,s];};},all:function(){var px=arguments,_=_;return _.each(_.optional(px));},sequence:function(px,d,c){d=d||_.rtoken(/^\s*/);c=c||null;if(px.length==1){return px[0];}
1986
+ return function(s){var r=null,q=null;var rx=[];for(var i=0;i<px.length;i++){try{r=px[i].call(this,s);}catch(e){break;}
1987
+ rx.push(r[0]);try{q=d.call(this,r[1]);}catch(ex){q=null;break;}
1988
+ s=q[1];}
1989
+ if(!r){throw new $P.Exception(s);}
1990
+ if(q){throw new $P.Exception(q[1]);}
1991
+ if(c){try{r=c.call(this,r[1]);}catch(ey){throw new $P.Exception(r[1]);}}
1992
+ return[rx,(r?r[1]:s)];};},between:function(d1,p,d2){d2=d2||d1;var _fn=_.each(_.ignore(d1),p,_.ignore(d2));return function(s){var rx=_fn.call(this,s);return[[rx[0][0],r[0][2]],rx[1]];};},list:function(p,d,c){d=d||_.rtoken(/^\s*/);c=c||null;return(p instanceof Array?_.each(_.product(p.slice(0,-1),_.ignore(d)),p.slice(-1),_.ignore(c)):_.each(_.many(_.each(p,_.ignore(d))),px,_.ignore(c)));},set:function(px,d,c){d=d||_.rtoken(/^\s*/);c=c||null;return function(s){var r=null,p=null,q=null,rx=null,best=[[],s],last=false;for(var i=0;i<px.length;i++){q=null;p=null;r=null;last=(px.length==1);try{r=px[i].call(this,s);}catch(e){continue;}
1993
+ rx=[[r[0]],r[1]];if(r[1].length>0&&!last){try{q=d.call(this,r[1]);}catch(ex){last=true;}}else{last=true;}
1994
+ if(!last&&q[1].length===0){last=true;}
1995
+ if(!last){var qx=[];for(var j=0;j<px.length;j++){if(i!=j){qx.push(px[j]);}}
1996
+ p=_.set(qx,d).call(this,q[1]);if(p[0].length>0){rx[0]=rx[0].concat(p[0]);rx[1]=p[1];}}
1997
+ if(rx[1].length<best[1].length){best=rx;}
1998
+ if(best[1].length===0){break;}}
1999
+ if(best[0].length===0){return best;}
2000
+ if(c){try{q=c.call(this,best[1]);}catch(ey){throw new $P.Exception(best[1]);}
2001
+ best[1]=q[1];}
2002
+ return best;};},forward:function(gr,fname){return function(s){return gr[fname].call(this,s);};},replace:function(rule,repl){return function(s){var r=rule.call(this,s);return[repl,r[1]];};},process:function(rule,fn){return function(s){var r=rule.call(this,s);return[fn.call(this,r[0]),r[1]];};},min:function(min,rule){return function(s){var rx=rule.call(this,s);if(rx[0].length<min){throw new $P.Exception(s);}
2003
+ return rx;};}};var _generator=function(op){return function(){var args=null,rx=[];if(arguments.length>1){args=Array.prototype.slice.call(arguments);}else if(arguments[0]instanceof Array){args=arguments[0];}
2004
+ if(args){for(var i=0,px=args.shift();i<px.length;i++){args.unshift(px[i]);rx.push(op.apply(null,args));args.shift();return rx;}}else{return op.apply(null,arguments);}};};var gx="optional not ignore cache".split(/\s/);for(var i=0;i<gx.length;i++){_[gx[i]]=_generator(_[gx[i]]);}
2005
+ var _vector=function(op){return function(){if(arguments[0]instanceof Array){return op.apply(null,arguments[0]);}else{return op.apply(null,arguments);}};};var vx="each any all".split(/\s/);for(var j=0;j<vx.length;j++){_[vx[j]]=_vector(_[vx[j]]);}}());(function(){var flattenAndCompact=function(ax){var rx=[];for(var i=0;i<ax.length;i++){if(ax[i]instanceof Array){rx=rx.concat(flattenAndCompact(ax[i]));}else{if(ax[i]){rx.push(ax[i]);}}}
2006
+ return rx;};Date.Grammar={};Date.Translator={hour:function(s){return function(){this.hour=Number(s);};},minute:function(s){return function(){this.minute=Number(s);};},second:function(s){return function(){this.second=Number(s);};},meridian:function(s){return function(){this.meridian=s.slice(0,1).toLowerCase();};},timezone:function(s){return function(){var n=s.replace(/[^\d\+\-]/g,"");if(n.length){this.timezoneOffset=Number(n);}else{this.timezone=s.toLowerCase();}};},day:function(x){var s=x[0];return function(){this.day=Number(s.match(/\d+/)[0]);};},month:function(s){return function(){this.month=((s.length==3)?Date.getMonthNumberFromName(s):(Number(s)-1));};},year:function(s){return function(){var n=Number(s);this.year=((s.length>2)?n:(n+(((n+2000)<Date.CultureInfo.twoDigitYearMax)?2000:1900)));};},rday:function(s){return function(){switch(s){case"yesterday":this.days=-1;break;case"tomorrow":this.days=1;break;case"today":this.days=0;break;case"now":this.days=0;this.now=true;break;}};},finishExact:function(x){x=(x instanceof Array)?x:[x];var now=new Date();this.year=now.getFullYear();this.month=now.getMonth();this.day=1;this.hour=0;this.minute=0;this.second=0;for(var i=0;i<x.length;i++){if(x[i]){x[i].call(this);}}
2007
+ this.hour=(this.meridian=="p"&&this.hour<13)?this.hour+12:this.hour;if(this.day>Date.getDaysInMonth(this.year,this.month)){throw new RangeError(this.day+" is not a valid value for days.");}
2008
+ var r=new Date(this.year,this.month,this.day,this.hour,this.minute,this.second);if(this.timezone){r.set({timezone:this.timezone});}else if(this.timezoneOffset){r.set({timezoneOffset:this.timezoneOffset});}
2009
+ return r;},finish:function(x){x=(x instanceof Array)?flattenAndCompact(x):[x];if(x.length===0){return null;}
2010
+ for(var i=0;i<x.length;i++){if(typeof x[i]=="function"){x[i].call(this);}}
2011
+ if(this.now){return new Date();}
2012
+ var today=Date.today();var method=null;var expression=!!(this.days!=null||this.orient||this.operator);if(expression){var gap,mod,orient;orient=((this.orient=="past"||this.operator=="subtract")?-1:1);if(this.weekday){this.unit="day";gap=(Date.getDayNumberFromName(this.weekday)-today.getDay());mod=7;this.days=gap?((gap+(orient*mod))%mod):(orient*mod);}
2013
+ if(this.month){this.unit="month";gap=(this.month-today.getMonth());mod=12;this.months=gap?((gap+(orient*mod))%mod):(orient*mod);this.month=null;}
2014
+ if(!this.unit){this.unit="day";}
2015
+ if(this[this.unit+"s"]==null||this.operator!=null){if(!this.value){this.value=1;}
2016
+ if(this.unit=="week"){this.unit="day";this.value=this.value*7;}
2017
+ this[this.unit+"s"]=this.value*orient;}
2018
+ return today.add(this);}else{if(this.meridian&&this.hour){this.hour=(this.hour<13&&this.meridian=="p")?this.hour+12:this.hour;}
2019
+ if(this.weekday&&!this.day){this.day=(today.addDays((Date.getDayNumberFromName(this.weekday)-today.getDay()))).getDate();}
2020
+ if(this.month&&!this.day){this.day=1;}
2021
+ return today.set(this);}}};var _=Date.Parsing.Operators,g=Date.Grammar,t=Date.Translator,_fn;g.datePartDelimiter=_.rtoken(/^([\s\-\.\,\/\x27]+)/);g.timePartDelimiter=_.stoken(":");g.whiteSpace=_.rtoken(/^\s*/);g.generalDelimiter=_.rtoken(/^(([\s\,]|at|on)+)/);var _C={};g.ctoken=function(keys){var fn=_C[keys];if(!fn){var c=Date.CultureInfo.regexPatterns;var kx=keys.split(/\s+/),px=[];for(var i=0;i<kx.length;i++){px.push(_.replace(_.rtoken(c[kx[i]]),kx[i]));}
2022
+ fn=_C[keys]=_.any.apply(null,px);}
2023
+ return fn;};g.ctoken2=function(key){return _.rtoken(Date.CultureInfo.regexPatterns[key]);};g.h=_.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2]|[1-9])/),t.hour));g.hh=_.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2])/),t.hour));g.H=_.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3]|[0-9])/),t.hour));g.HH=_.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3])/),t.hour));g.m=_.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/),t.minute));g.mm=_.cache(_.process(_.rtoken(/^[0-5][0-9]/),t.minute));g.s=_.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/),t.second));g.ss=_.cache(_.process(_.rtoken(/^[0-5][0-9]/),t.second));g.hms=_.cache(_.sequence([g.H,g.mm,g.ss],g.timePartDelimiter));g.t=_.cache(_.process(g.ctoken2("shortMeridian"),t.meridian));g.tt=_.cache(_.process(g.ctoken2("longMeridian"),t.meridian));g.z=_.cache(_.process(_.rtoken(/^(\+|\-)?\s*\d\d\d\d?/),t.timezone));g.zz=_.cache(_.process(_.rtoken(/^(\+|\-)\s*\d\d\d\d/),t.timezone));g.zzz=_.cache(_.process(g.ctoken2("timezone"),t.timezone));g.timeSuffix=_.each(_.ignore(g.whiteSpace),_.set([g.tt,g.zzz]));g.time=_.each(_.optional(_.ignore(_.stoken("T"))),g.hms,g.timeSuffix);g.d=_.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1]|\d)/),_.optional(g.ctoken2("ordinalSuffix"))),t.day));g.dd=_.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1])/),_.optional(g.ctoken2("ordinalSuffix"))),t.day));g.ddd=g.dddd=_.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),function(s){return function(){this.weekday=s;};}));g.M=_.cache(_.process(_.rtoken(/^(1[0-2]|0\d|\d)/),t.month));g.MM=_.cache(_.process(_.rtoken(/^(1[0-2]|0\d)/),t.month));g.MMM=g.MMMM=_.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"),t.month));g.y=_.cache(_.process(_.rtoken(/^(\d\d?)/),t.year));g.yy=_.cache(_.process(_.rtoken(/^(\d\d)/),t.year));g.yyy=_.cache(_.process(_.rtoken(/^(\d\d?\d?\d?)/),t.year));g.yyyy=_.cache(_.process(_.rtoken(/^(\d\d\d\d)/),t.year));_fn=function(){return _.each(_.any.apply(null,arguments),_.not(g.ctoken2("timeContext")));};g.day=_fn(g.d,g.dd);g.month=_fn(g.M,g.MMM);g.year=_fn(g.yyyy,g.yy);g.orientation=_.process(g.ctoken("past future"),function(s){return function(){this.orient=s;};});g.operator=_.process(g.ctoken("add subtract"),function(s){return function(){this.operator=s;};});g.rday=_.process(g.ctoken("yesterday tomorrow today now"),t.rday);g.unit=_.process(g.ctoken("minute hour day week month year"),function(s){return function(){this.unit=s;};});g.value=_.process(_.rtoken(/^\d\d?(st|nd|rd|th)?/),function(s){return function(){this.value=s.replace(/\D/g,"");};});g.expression=_.set([g.rday,g.operator,g.value,g.unit,g.orientation,g.ddd,g.MMM]);_fn=function(){return _.set(arguments,g.datePartDelimiter);};g.mdy=_fn(g.ddd,g.month,g.day,g.year);g.ymd=_fn(g.ddd,g.year,g.month,g.day);g.dmy=_fn(g.ddd,g.day,g.month,g.year);g.date=function(s){return((g[Date.CultureInfo.dateElementOrder]||g.mdy).call(this,s));};g.format=_.process(_.many(_.any(_.process(_.rtoken(/^(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),function(fmt){if(g[fmt]){return g[fmt];}else{throw Date.Parsing.Exception(fmt);}}),_.process(_.rtoken(/^[^dMyhHmstz]+/),function(s){return _.ignore(_.stoken(s));}))),function(rules){return _.process(_.each.apply(null,rules),t.finishExact);});var _F={};var _get=function(f){return _F[f]=(_F[f]||g.format(f)[0]);};g.formats=function(fx){if(fx instanceof Array){var rx=[];for(var i=0;i<fx.length;i++){rx.push(_get(fx[i]));}
2024
+ return _.any.apply(null,rx);}else{return _get(fx);}};g._formats=g.formats(["yyyy-MM-ddTHH:mm:ss","ddd, MMM dd, yyyy H:mm:ss tt","ddd MMM d yyyy HH:mm:ss zzz","d"]);g._start=_.process(_.set([g.date,g.time,g.expression],g.generalDelimiter,g.whiteSpace),t.finish);g.start=function(s){try{var r=g._formats.call({},s);if(r[1].length===0){return r;}}catch(e){}
2025
+ return g._start.call({},s);};}());Date._parse=Date.parse;Date.parse=function(s){var r=null;if(!s){return null;}
2026
+ try{r=Date.Grammar.start.call({},s);}catch(e){return null;}
2027
+ return((r[1].length===0)?r[0]:null);};Date.getParseFunction=function(fx){var fn=Date.Grammar.formats(fx);return function(s){var r=null;try{r=fn.call({},s);}catch(e){return null;}
2028
+ return((r[1].length===0)?r[0]:null);};};Date.parseExact=function(s,fx){return Date.getParseFunction(fx)(s);};
2029
+ /**
2030
+ * Version: 1.0 Alpha-1
2031
+ * Build Date: 13-Nov-2007
2032
+ * Copyright (c) 2006-2007, Coolite Inc. (http://www.coolite.com/). All rights reserved.
2033
+ * License: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
2034
+ * Website: http://www.datejs.com/ or http://www.coolite.com/datejs/
2035
+ */
2036
+ TimeSpan=function(days,hours,minutes,seconds,milliseconds){this.days=0;this.hours=0;this.minutes=0;this.seconds=0;this.milliseconds=0;if(arguments.length==5){this.days=days;this.hours=hours;this.minutes=minutes;this.seconds=seconds;this.milliseconds=milliseconds;}
2037
+ else if(arguments.length==1&&typeof days=="number"){var orient=(days<0)?-1:+1;this.milliseconds=Math.abs(days);this.days=Math.floor(this.milliseconds/(24*60*60*1000))*orient;this.milliseconds=this.milliseconds%(24*60*60*1000);this.hours=Math.floor(this.milliseconds/(60*60*1000))*orient;this.milliseconds=this.milliseconds%(60*60*1000);this.minutes=Math.floor(this.milliseconds/(60*1000))*orient;this.milliseconds=this.milliseconds%(60*1000);this.seconds=Math.floor(this.milliseconds/1000)*orient;this.milliseconds=this.milliseconds%1000;this.milliseconds=this.milliseconds*orient;return this;}
2038
+ else{return null;}};TimeSpan.prototype.compare=function(timeSpan){var t1=new Date(1970,1,1,this.hours(),this.minutes(),this.seconds()),t2;if(timeSpan===null){t2=new Date(1970,1,1,0,0,0);}
2039
+ else{t2=new Date(1970,1,1,timeSpan.hours(),timeSpan.minutes(),timeSpan.seconds());}
2040
+ return(t1>t2)?1:(t1<t2)?-1:0;};TimeSpan.prototype.add=function(timeSpan){return(timeSpan===null)?this:this.addSeconds(timeSpan.getTotalMilliseconds()/1000);};TimeSpan.prototype.subtract=function(timeSpan){return(timeSpan===null)?this:this.addSeconds(-timeSpan.getTotalMilliseconds()/1000);};TimeSpan.prototype.addDays=function(n){return new TimeSpan(this.getTotalMilliseconds()+(n*24*60*60*1000));};TimeSpan.prototype.addHours=function(n){return new TimeSpan(this.getTotalMilliseconds()+(n*60*60*1000));};TimeSpan.prototype.addMinutes=function(n){return new TimeSpan(this.getTotalMilliseconds()+(n*60*1000));};TimeSpan.prototype.addSeconds=function(n){return new TimeSpan(this.getTotalMilliseconds()+(n*1000));};TimeSpan.prototype.addMilliseconds=function(n){return new TimeSpan(this.getTotalMilliseconds()+n);};TimeSpan.prototype.getTotalMilliseconds=function(){return(this.days()*(24*60*60*1000))+(this.hours()*(60*60*1000))+(this.minutes()*(60*1000))+(this.seconds()*(1000));};TimeSpan.prototype.get12HourHour=function(){return((h=this.hours()%12)?h:12);};TimeSpan.prototype.getDesignator=function(){return(this.hours()<12)?Date.CultureInfo.amDesignator:Date.CultureInfo.pmDesignator;};TimeSpan.prototype.toString=function(format){function _toString(){if(this.days()!==null&&this.days()>0){return this.days()+"."+this.hours()+":"+p(this.minutes())+":"+p(this.seconds());}
2041
+ else{return this.hours()+":"+p(this.minutes())+":"+p(this.seconds());}}
2042
+ function p(s){return(s.toString().length<2)?"0"+s:s;}
2043
+ var self=this;return format?format.replace(/d|dd|HH|H|hh|h|mm|m|ss|s|tt|t/g,function(format){switch(format){case"d":return self.days();case"dd":return p(self.days());case"H":return self.hours();case"HH":return p(self.hours());case"h":return self.get12HourHour();case"hh":return p(self.get12HourHour());case"m":return self.minutes();case"mm":return p(self.minutes());case"s":return self.seconds();case"ss":return p(self.seconds());case"t":return((this.hours()<12)?Date.CultureInfo.amDesignator:Date.CultureInfo.pmDesignator).substring(0,1);case"tt":return(this.hours()<12)?Date.CultureInfo.amDesignator:Date.CultureInfo.pmDesignator;}}):this._toString();};var TimePeriod=function(years,months,days,hours,minutes,seconds,milliseconds){this.years=0;this.months=0;this.days=0;this.hours=0;this.minutes=0;this.seconds=0;this.milliseconds=0;if(arguments.length==2&&arguments[0]instanceof Date&&arguments[1]instanceof Date){var date1=years.clone();var date2=months.clone();var temp=date1.clone();var orient=(date1>date2)?-1:+1;this.years=date2.getFullYear()-date1.getFullYear();temp.addYears(this.years);if(orient==+1){if(temp>date2){if(this.years!==0){this.years--;}}}else{if(temp<date2){if(this.years!==0){this.years++;}}}
2044
+ date1.addYears(this.years);if(orient==+1){while(date1<date2&&date1.clone().addDays(date1.getDaysInMonth())<date2){date1.addMonths(1);this.months++;}}
2045
+ else{while(date1>date2&&date1.clone().addDays(-date1.getDaysInMonth())>date2){date1.addMonths(-1);this.months--;}}
2046
+ var diff=date2-date1;if(diff!==0){var ts=new TimeSpan(diff);this.days=ts.days;this.hours=ts.hours;this.minutes=ts.minutes;this.seconds=ts.seconds;this.milliseconds=ts.milliseconds;}
2047
+ return this;}};