1 if ( typeof Dataface == 'undefined' ) Dataface = {};
  2 Dataface.Calendar = function(id, date){
  3 	if ( !id ) id = 'df-calendar-'+Math.random();
  4 	if ( !date ) date = new Date();
  5 	if ( typeof date != 'Date' ){
  6 		var d = new Date();
  7 		d.setTime(date);
  8 		date = d;
  9 	}
 10 	this.selectedDate = date;
 11 	this.id = id;
 12 	Dataface.Calendar.addInstance(this);
 13 	
 14 };
 15 
 16 Dataface.Calendar.instances = {};
 17 Dataface.Calendar.addInstance = function(calendar){
 18 	this.instances[calendar.id] = calendar;
 19 };
 20 Dataface.Calendar.getInstance = function(id){
 21 	return this.instances[id];
 22 };
 23 
 24 Dataface.Calendar.prototype = {
 25 	'selectedEvent': null,
 26 	'selectedDate': new Date(),
 27 	'defaultStartTime': 8,
 28 	'defaultEndTime': 22,
 29 	'monthPanel':null,
 30 	'weekPanel':null,
 31 	'dayPanel':null,
 32 	'detailsPanel':null,
 33 
 34 	
 35 	'handleSelectDay': function(date){
 36 		if ( typeof date != 'Date' ){
 37 			date = new Date(date);
 38 		}
 39 		this.selectedDate = date;
 40 		if ( this.dayPanel ){
 41 			document.getElementById(this.dayPanel).innerHTML = this.drawDay(9,21,0.25);
 42 		}
 43 		
 44 	},
 45 	
 46 	'handleSelectEvent': function(event){
 47 		if ( this.selectedEvent ){
 48 			var eventDiv = document.getElementById('event-preview-'+this.selectedEvent.id);
 49 			
 50 			var cls = eventDiv.className; //eventDiv.getAttribute('class');
 51 			if ( !cls ) cls = '';
 52 			eventDiv.className =  cls.replace(/Dataface-Calendar-selected-event/, ''); //eventDiv.setAttribute('class', cls.replace(/Dataface-Calendar-selected-event/, ''));
 53 		
 54 		}
 55 		this.selectedEvent = Dataface.Calendar.Event.getInstance(event);
 56 		if ( this.detailsPanel ){
 57 			document.getElementById(this.detailsPanel).innerHTML = this.selectedEvent.showDetails();
 58 			
 59 			
 60 		}
 61 		var div = document.getElementById('event-preview-'+this.selectedEvent.id);
 62 		var cls2 = div.className; //div.getAttribute('class');
 63 		if ( !cls2 ) cls2 = '';
 64 		if ( div ) div.className =  cls2+' Dataface-Calendar-selected-event'; //div.setAttribute('class', cls2+' Dataface-Calendar-selected-event');
 65 
 66 	}
 67 	
 68 };
 69 
 70 Dataface.Calendar.Event = function(id, data){
 71 	this.id = 'event-'+Math.random();
 72 	for ( var key in data){
 73 		if ( (key == 'date' || key == 'endTime') && typeof data[key] != 'Date' ){
 74 			var d = new Date();
 75 			d.setTime(data[key]+d.getTimezoneOffset()*60*1000);
 76 			data[key] = d;
 77 			
 78 		}
 79 		this[key] = data[key];
 80 	}
 81 	Dataface.Calendar.Event.addInstance(this);
 82 };
 83 
 84 Dataface.Calendar.Event.instances = {};
 85 Dataface.Calendar.Event.addInstance = function(event){
 86 	this.instances[event.id] = event;
 87 };
 88 Dataface.Calendar.Event.getInstance = function(id){
 89 	return this.instances[id];
 90 };
 91 
 92 
 93 
 94 Dataface.Calendar.Event.prototype = {
 95 	'title': null,
 96 	'date': null,
 97 	'endTime': null,
 98 	'description': null,
 99 	'url': null,
100 	'showDetails': function(){
101 		var out = '<div "Dataface-Calendar-details">';
102 		out += '<h3 class="Dataface-Calendar-details-title">'+this.title+'</h3>';
103 		out += '<table class="Dataface-Calendar-details-data"><tbody>';
104 		out += '<tr><th>from</th><td>'+this.date.asString('%Y-%m-%d')+' at '+this.date.asString('%H:%i')+'</td></tr>';
105 		if ( this.endTime ) {
106 			out += '<tr><th>to</th><td>'+this.endTime.asString('%Y-%m-%d')+' at '+this.endTime.asString('%H:%i')+'</td></tr>';
107 		}
108 		out += '</table>';
109 		out += '<div class="Dataface-Calendar-details-description">'+this.getDescription()+'</div>';
110 	
111 		out += '	</div>';
112 		return out;
113 	},
114 	'getDescription': function(){
115 		return this.description;
116 	}
117 };
118 
119 
120 
121 
122 Dataface.Calendar.prototype.events = {
123 	'list': [],
124 	'sorted': false,
125 	
126 	'add': function(e){
127 		this.list[this.list.length] = e;
128 		this.sorted = false;
129 	},
130 	
131 	'compare': function(a,b){
132 		return (a.date.getTime() < a.date.getTime());
133 	},
134 	
135 	'sort': function(){
136 		if ( !this.sorted ){
137 			this.list.sort(this.compare);
138 		}
139 	},
140 	
141 	'month': function(date){
142 		this.sort();
143 		var out = [];
144 		for ( var i=0; i<this.list.length; i++){
145 			var e = this.list[i];
146 			if ( (e.date.getFullYear() == date.getFullYear()) && (e.date.getMonth() == date.getMonth()) ){
147 				out[out.length] = this.list[i];
148 			}
149 		}
150 		return out;
151 	},
152 	
153 	'day': function(date){
154 		this.sort();
155 		var out = [];
156 		for ( var i=0; i<this.list.length; i++){
157 			var e = this.list[i];
158 			if ( (e.date.getFullYear() == date.getFullYear()) && 
159 				 ( e.date.getMonth() == date.getMonth() ) && 
160 				 ( e.date.getDate() == date.getDate() ) ){
161 				out[out.length] = this.list[i];
162 			}
163 		}
164 		return out;
165 	},
166 	
167 	'week': function(date){
168 		this.sort();
169 		var firstDay = date.getDate() - date.getDay();
170 		var lastDay = date.getDate() + ( 6 - date.getDay() );
171 		
172 		var out = [];
173 		for ( var i=0; i<this.list.length; i++){
174 			var e = this.list[i];
175 			if ( (e.date.getFullYear() == date.getFullYear()) && 
176 				 ( e.date.getMonth() == date.getMonth() ) && 
177 				 ( e.date.getDate() >= firstDay ) &&
178 				 ( e.date.getDate() <= lastDay ) ){
179 				out[out.length] = this.list[i];
180 			}
181 		}
182 		return out;
183 		
184 	},
185 	
186 	'range': function(start,end){
187 		this.sort();
188 		var out = [];
189 		for ( var i =0; i<this.list.length; i++ ){
190 			var e = this.list[i];
191 			
192 			if ( (start.getTime() <= e.date.getTime()) && (end.getTime() > e.date.getTime()) ){
193 				out[ out.length ] = e;
194 			}
195 		}
196 		return out;
197 	}
198 	
199 
200 };
201 
202 
203 Date.daysOfWeek = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
204 Date.monthsOfYear = ['January','February','March','April','May','June','July','August','September','October','November','December'];
205 
206 
207 Date.prototype.daysInMonth = function(/*iMonth, iYear*/){
208 	return 32 - new Date(this.getFullYear(), this.getMonth(), 32).getDate();
209 }
210 
211 Dataface.Calendar.prototype.drawMonth = function(){
212 	var firstDay = new Date(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), 1);
213 	
214 	var out = '<table class="Dataface-Calendar-month" cellspacing="0"><thead><tr><th>'+Date.daysOfWeek.join('</th><th>')+'</th></tr></thead>';
215 	out += '<tbody>';
216 	
217 	var day = -1;
218 	for ( var i=0; i<5; i++ ){
219 		out += '<tr>';
220 
221 		for ( var j=0; j<7; j++ ){
222 			
223 			
224 			if ( (day == -1) && ( firstDay.getDay() ==  j ) ){
225 				// We have arrived at the first day of the month so we can start the day counter
226 				day = 0;
227 			}
228 			
229 			if ( day == this.selectedDate.daysInMonth() ){
230 				day = -1;
231 			}
232 			var cls = '';
233 			if ( day >= 0 ) cls = 'Dataface-Calendar-day';
234 			else cls = 'Dataface-Calendar-empty-day';
235 			
236 			out += '<td class="'+cls+'"><div class="day-wrapper"';
237 			
238 			if ( day >= 0 ){
239 				var currDay = this.selectedDate.clone();
240 				currDay.setDate(day+1);
241 				out += '<div class="day-number"><a href="javascript:Dataface.Calendar.getInstance(\''+this.id+'\').handleSelectDay(\''+currDay.toString()+'\')">'+(day+1)+'</a></div>';
242 				
243 				
244 				//var events = Date.events.range(startTime, endTime);
245 				var events = this.events.day(currDay);
246 				
247 				for ( var k=0; k<events.length; k++){
248 					out += '<div class="Dataface-Calendar-event" id="event-preview-'+events[k].id+'"><a href="javascript:Dataface.Calendar.getInstance(\''+this.id+'\').handleSelectEvent(\''+events[k].id+'\');">'+events[k].title+'</a></div>';
249 				}
250 				
251 				day++;
252 			}
253 			
254 			out += '</div></td>';
255 			
256 		}
257 		out += '</tr>';
258 		
259 	}
260 	out += '</tbody></table>';
261 	return out;
262 };
263 
264 Dataface.Calendar.prototype.drawWeek = function(startHour, endHour){
265 
266 	if ( !startHour ) startHour = 8;
267 	if ( !endHour ) endHour = 20;
268 
269 	var thisDayOfWeek = this.selectedDate.getDay();
270 	var thisWeeksFirstDay = this.selectedDate.getDate()-this.selectedDate.getDay();
271 	
272 	var headings = [];
273 	
274 	for ( var i=0; i<Date.daysOfWeek.length; i++){
275 		var date = new Date(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), thisWeeksFirstDay+i);
276 		headings[headings.length] = Date.daysOfWeek[i]+' '+Date.monthsOfYear[ date.getMonth() ]+' '+date.getDate()+', '+date.getFullYear();
277 	}
278 	var out = '<table class="jsCalendar-week"><thead><tr><th></th><th>'+headings.join('</th><th>')+'</th></tr></thead>';
279 	out += '<tbody>';
280 	for ( var hour=startHour; hour<=endHour; hour++ ){
281 		out += '<tr><th>'+(hour+1)+':00</th>';
282 		for ( var j=0; j<Date.daysOfWeek.length; j++){
283 			out += '<td></td>';
284 		}
285 		out += '</tr>';
286 	}
287 	out += '</tbody></table>';
288 	
289 	return out;
290 	
291 	
292 };
293 
294 Dataface.Calendar.prototype.drawDay = function(startHour, endHour, precision){
295 	if ( !startHour ) startHour = 8;
296 	if ( !endHour ) endHour = 20;
297 	if ( !precision ) precision = 1.0;
298 
299 	var thisDayOfWeek = this.selectedDate.getDay();
300 	var thisWeeksFirstDay = this.selectedDate.getDate()-this.selectedDate.getDay();
301 	
302 	var headings = [];
303 	
304 	for ( var i=0; i<Date.daysOfWeek.length; i++){
305 		var date = new Date(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), thisWeeksFirstDay+i);
306 		headings[headings.length] = Date.daysOfWeek[i]+' '+Date.monthsOfYear[ date.getMonth() ]+' '+date.getDate()+', '+date.getFullYear();
307 	}
308 	var out = '<table class="jsCalendar-week"><thead><tr><th></th><th>'+headings[this.selectedDate.getDay()]+'</th></thead>';
309 	out += '<tbody>';
310 	var startTimems = this.selectedDate.clone();
311 	startTimems.setHours(startHour);
312 	startTimems.setMinutes(0);
313 	startTimems.setSeconds(0);
314 	
315 	var endTimems = this.selectedDate.clone();
316 	endTimems.setHours(endHour);
317 	endTimems.setMinutes(0);
318 	endTimems.setSeconds(0);
319 	
320 	//for ( var hour=startHour; hour<=endHour; hour++ ){
321 	for ( var time=startTimems.getTime(); time <= endTimems; time += (precision*60*60*1000) ){
322 		
323 		var startTime = this.selectedDate.clone();
324 		startTime.setTime(time);
325 		var minutes = startTime.getMinutes() + "";
326 		if ( minutes.length == 1 ) minutes = '0'+minutes;
327 		out += '<tr><th>'+(startTime.getHours())+':'+minutes+'</th>';
328 		//startTime.setHours(hour);
329 		//startTime.setMinutes(0);
330 		//startTime.setSeconds(0);
331 		
332 		var endTime = this.selectedDate.clone();
333 		endTime.setTime(time + (precision*60*60*1000) );
334 		//endTime.setHours(hour+1);
335 		//endTime.setMinutes(0);
336 		//endTime.setSeconds(0);
337 		
338 		//var events = Date.events.range(startTime, endTime);
339 		var events = this.events.range(startTime, endTime);
340 		out += '<td>';
341 		for ( var j=0; j<events.length; j++){
342 			out += '<div class="jsCalendar-event"><a href="javascript:Dataface.Calendar.getInstance(\''+this.id+'\').handleSelectEvent(\''+events[j].id+'\');">'+events[j].title+'</a></div>';
343 		}
344 		out += '</td></tr>';
345 	}
346 	out += '</tbody></table>';
347 	
348 	return out;
349 };
350 
351 Date.prototype.clone = function(){
352 	return new Date(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(), this.getSeconds());
353 };
354 
355 Date.prototype.asString = function (format){
356 	var out = format.replace(/%Y/, this.getFullYear());
357 	out = out.replace(/%m/, pad(this.getMonth()+1,2));
358 	out = out.replace(/%d/, pad(this.getDate(),2));
359 	out = out.replace(/%H/, pad(this.getHours(),2));
360 	out = out.replace(/%i/, pad(this.getMinutes(),2));
361 	return out;
362 };
363 
364 function pad(number, length) {
365    
366     var str = '' + number;
367     while (str.length < length) {
368         str = '0' + str;
369     }
370 
371     return str;
372 
373 }
374 
375 
376 
377