1 /**
  2  * @namespace Diese Klasse liefert Dienste zur Geolokalisierung.
  3  * @author Jan Kossick, jankossick@online.de
  4  * @version 2.0
  5  * @requires http://code.google.com/apis/gears/gears_init.js
  6  * @requires http://maps.google.com/maps/api/js
  7  */
  8 var Geo = {
  9 	/**
 10 	 * Zugriffspunkt f�r den Google-Geocoder.
 11 	 */
 12 	Geocoder : new google.maps.Geocoder(),
 13 	
 14 	/**
 15 	 * Speichert einen allgemeinen Standort.
 16 	 */
 17 	StandardPosition : null,
 18 	
 19 	/**
 20 	 * Versucht automatisch den Standort zu bestimmen.
 21 	 * @param {Function} callback Die Callback-Funktion mit einem Parameter.
 22 	 * 		Dem Parameter werden die Koordinaten als {google.maps.LatLng} 
 23 	 * 		�bergeben.
 24 	 */
 25 	getPosition : function(callback) {
 26 		if(navigator.geolocation) { // try W3C Geolocation (Preferred)
 27 			navigator.geolocation.getCurrentPosition(function(position) {
 28 				callback(new google.maps.LatLng(position.coords.latitude,position.coords.longitude));
 29     		}, function(msg) {
 30     			callback(false);
 31     		});
 32   		} else { // Browser doesn't support Geolocation
 33     		callback(false);
 34   		}
 35 	},
 36 	
 37 	/**
 38 	 * Sucht anhand einer Adresse Geokordinaten. Sollten mehrere Ergebnisse
 39 	 * vorliegen, wird das erste zur�ckgegeben.
 40 	 * @param {String} address Adresse
 41 	 * @param {Function} callback Callback-Funktion mit zwei Parametern: Der
 42 	 *		erste gibt ein {google.maps.LatLng} zur�ck und der zweite eine
 43 	 *		wohlformatierte Adresse.
 44 	 */
 45 	getLatLng : function(address, callback) {
 46 		if((!address) || address.length==0) {
 47 			callback(false, "Keine Adresse �bergeben.");
 48 			return;
 49 		}
 50 
 51 		if (this.Geocoder) {
 52 			this.Geocoder.geocode( { 'address': address, 'region': 'de'}, function(results, status) {
 53 				if (status == google.maps.GeocoderStatus.OK) {
 54 					callback(results[0].geometry.location, results[0].formatted_address);
 55 				} else {
 56 					callback(false, "Adresse aus folgendem Grund nicht gefunden: " + status);
 57 				}
 58 			});
 59 		} else {
 60 			callback(false, "Interner Fehler: Keinen Geocoder gefunden.");
 61 		}
 62 	},
 63 	
 64 	/**
 65 	 * Sucht anhand von Geokordinaten die n�chste visuell darstellbare
 66 	 * Adresse. Sollten mehrere Ergebnisse vorliegen, wird das erste
 67 	 * zur�ckgegeben.
 68 	 * @param {google.maps.LatLng} latlng Koordinaten
 69 	 * @param {Function} callback Callback-Funktion mit zwei Parametern: Im
 70 	 *		Erfolgsfall gibt der erste entweder ein {google.maps.LatLng} zur�ck
 71 	 *		und der zweite die wohlformatierte Adresse. Im Fehlerfall gibt der
 72 	 *		erste Parameter false zur�ck und der zweite die Fehlermeldung.
 73 	 */
 74 	getAddress : function(latlng, callback) {
 75 		if((!latlng) || latlng.length==0) {
 76 			callback(false, "Keine Koordinaten �bergeben.");
 77 			return;
 78 		}
 79 		
 80 		if (this.Geocoder) {
 81 			this.Geocoder.geocode({'latLng': latlng}, function(results, status) {
 82         		if (status == google.maps.GeocoderStatus.OK) {
 83 					callback(results[0].geometry.location, results[0].formatted_address);
 84         		} else {
 85           			callback(false, "Koordinaten aus folgendem Grund nicht gefunden: " + status);
 86         		}
 87 			});
 88 		} else {
 89 			callback(false, "Interner Fehler: Keinen Geocoder gefunden.");
 90 		} 
 91 	}
 92 };jQuery("head").append("<style id='infowindow_css'></style>");
 93 
 94 /**
 95  * @namespace Diese Klasse bietet ein Fenster um Informationen anzuzeigen.
 96  * @author Jan Kossick, jankossick@online.de
 97  * @version 2.0
 98  */
 99 var Infowindow = {
100 	/**
101 	 * Ersetzt den Inhalt des Infofensters.
102 	 * @param {String|Object} html DOM-Element, HTML-Zeichenfolge oder
103 	 *		jQuery-Objekt, das eingef�gt wird.
104 	 */
105 	setContent : function(html) {
106 		jQuery('#infowindow #content').empty();
107 		Infowindow.addContent(html);
108 	},
109 	
110 	/**
111 	 * Erg�nzt den Inhalt des Infofensters.
112 	 * @param {String|Object} html DOM-Element, HTML-Zeichenfolge oder
113 	 *		jQuery-Objekt, das eingef�gt wird.
114 	 */
115 	addContent : function(html) {
116 		jQuery('#infowindow #content').append(html);
117 	},
118 	
119 	/**
120 	 * L�dt CSS f�r den Content. �berschreibt die vorherigen Angaben.
121 	 * @param {String} css CSS-Zeichenfolge.
122 	 */
123 	setContentCSS : function(css) {
124 		try { //der IE<9 spinnt sonst rum
125 			jQuery('#infowindow_css').empty().append(css);
126 		} catch(ex) {}
127 	},
128 
129 	/**
130 	 * Setzt die CSS-Eigenschaften width, height, top, left, bottom, right
131 	 * des Infofensters.
132 	 * @param {Object|String} opt Ein Objekt oder JSON-formatierter String mit
133 	 *		den entsprechenden Angaben. Als Werte sind numerische CSS-Angaben
134 	 *		erlaubt.
135 	 * @example
136 	 * var props = {
137 	 *	"width":"200px","height":"400px","bottom":"1%","right":"1%"
138 	 * };
139 	 * Infowindow.setOptions(props);
140 	 */
141 	setOptions : function(opt) {
142 		if(typeof opt == "string") opt = jQuery.parseJSON(opt); 
143 		jQuery.each(opt, function(key, value) { 
144   			Infowindow.setCSS('', key, value); 
145 		});
146 	},
147 
148 	/**
149 	 * �ffnet das Infofenster.
150 	 */
151 	show : function() {
152 		jQuery("#infowindow").show();
153 	},
154 
155 	/**
156 	 * Schlie�t das Infofenster.
157 	 */
158 	hide : function() {
159 		jQuery("#infowindow").hide();
160 	},
161 	
162 	/** 
163 	 * Gibt Eigenschaften des Infofensters zur�ck.
164 	 * M�gliche Selektoren: 
165 	 *		#toolbar 
166 	 *		#toolbar img
167 	 *		#content
168 	 *		#content input
169 	 *		#content textarea
170 	 *		#content select
171 	 *		und eigene (mit @see{setContent}/@see{addContent} hinzugef�gte)
172 	 * @param {String} selektor CSS-Selektor. Ist der Selektor leer, wird die
173 	 *		Eigenschaft direkt vom Infowindow gelesen.
174 	 * @param {String} Name der Eigenschaft
175 	 * @returns {String} Wert der Eigenschaft
176 	*/
177 	getCSS : function(selektor, name) {
178 		return jQuery("#infowindow " + selektor).css(name);
179 	},
180 	
181 	/** 
182 	 * Kann die Eigenschaften des Infofensters anpassen.
183 	 * M�gliche Selektoren:
184 	 *		#content
185 	 *		#content input
186 	 *		#content textarea
187 	 *		#content select
188 	 *		und eigene (mit @see{setContent}/@see{addContent} hinzugef�gte)
189 	 * @param {String} selektor CSS-Selektor. Ist der Selektor leer, wird die
190 	 *		Eigenschaft direkt auf das Infowindow angewendet.
191 	 * @param {String} Name der Eigenschaft
192 	 * @param {String} Wert der Eigenschaft
193 	*/
194 	setCSS : function(selektor, name, value) {
195 		jQuery("#infowindow " + selektor).css(name, value);
196 	}
197 };/**
198  * Gibt einen als MySQL-Datum formatierten String des Datums zur�ck.
199  * @returns {String} Als MySQL-Datum formatierter String.
200  */
201 Date.prototype.toMySQLDate = function() {
202 	s = this.getFullYear() + "-"; 
203 	s += (this.getMonth()+1) + "-";
204 	s += this.getDate() + " ";
205 	s += this.getHours() + ":";
206 	s += this.getMinutes() + ":";
207 	s += this.getSeconds();
208 	return s;
209 };
210 
211 /**
212  * Setzt das Datum nach einem MySQL-formatierten Datumsstring.
213  */
214 Date.prototype.setMySQLDate = function(date) {
215 	var year = /^(\d{4})/i
216 	var r = year.exec(date);
217 	this.setFullYear(r[1]);
218 	
219 	var parts = /(\d{1,2}).(\d{1,2}).(\d{1,2}).(\d{1,2}).(\d{1,2})$/;
220 	r = parts.exec(date);
221 	this.setMonth(parseInt(r[1])-1);
222 	this.setDate(r[2]);
223 	this.setHours(r[3]);
224 	this.setMinutes(r[4]);
225 	this.setSeconds(r[5]);
226 };
227 
228 /**
229  * @namespace Diese Klasse liefert Veranstaltungen.
230  * @author Jan Kossick, jankossick@online.de
231  * @version 2.0
232  */
233 var Events = {
234 	/**
235 	 * Speichert das Start-Datum.
236 	 */
237 	DateStart : new Date(),
238 	
239 	/**
240 	 * Speichert das End-Datum.
241 	 */
242 	DateEnd : new Date(),
243 	
244 	/**
245 	 * Kategorien f�r die Events, die geladen werden.
246 	 * 	cinema
247 	 *	theatre
248 	 *	museum
249 	 *	art
250 	 *	other
251 	 *	yourbash
252 	 */
253 	EventCategories : {
254 		"cinema" : true,
255 		"theatre" : true,
256 		"museum" : true,
257 		"art" : true,
258 		"other" : true
259 	},
260 	
261 	/**
262 	 * Kategorien f�r die Yourbashs, die geladen werden.
263 	 *	concert
264 	 *	exhibition
265 	 *	theatre
266 	 *	sport
267 	 *	party
268 	 *	other
269 	 */
270 	YourbashCategories : {
271 		"concert" : true,
272 		"exhibition" : true,
273 		"theatre" : true,
274 		"sport" : true,
275 		"party" : true,
276 		"other" : true
277 	},
278 	
279 	/**
280 	 * W�hlt eine Kategorie der Events aus oder ab.
281 	 * @param {String} type Angabe, welche Kategorie aus- oder abgew�hlt werden
282 	 *		soll. {@see Events#EventCategories}
283 	 * @returns {Boolean} Ob die Kategorie aus- oder abgew�hlt wurde.
284 	 */
285 	toggleEventCategories : function(type) {
286 		Events.EventCategories[type] = !Events.EventCategories[type];
287 		Map.reload();
288 		return Events.EventCategories[type];
289 	},
290 	
291 	/**
292 	 * W�hlt eine Kategorie der Yourbashs aus oder ab.
293 	 * @param {String} type Angabe, welche Kategorie aus- oder abgew�hlt werden
294 	 *		soll. {@see Events#YourbashCategories}
295 	 * @returns {Boolean} Ob die Kategorie aus- oder abgew�hlt wurde.
296 	 */
297 	toggleYourbashCategories : function(type) {
298 		Events.YourbashCategories[type] = !Events.YourbashCategories[type];
299 		Map.reload();
300 		return Events.YourbashCategories[type];
301 	},
302 	
303 	/**
304 	 * Setzt das Startdatum neu.
305 	 * @param {Number} [hour] Stunde
306 	 * @param {Number} [minute] Minuten
307 	 * @param {Number} [day] Tag des Monats
308 	 * @param {Number} [month] Monat
309 	 * @param {Number} [year] vierstellige Jahreszahl
310 	 */
311 	setDateStart : function(hour, minute, day, month, year) {
312 		if(typeof year != "undefined") 
313 			this.DateStart.setFullYear(year);
314 		if(typeof month != "undefined")
315 			this.DateStart.setMonth(month-1);
316 		if(typeof day != "undefined")
317 			this.DateStart.setDate(day);
318 		if(typeof hour != "undefined")
319 			this.DateStart.setHours(hour);
320 		if(typeof minute != "undefined")		
321 			this.DateStart.setMinutes(minute);
322 		this.DateStart.setSeconds(0);	
323 	},
324 	
325 	/**
326 	 * Setzt das Enddatum neu.
327 	 * @param {Number} [hour] Stunde
328 	 * @param {Number} [minute] Minuten
329 	 * @param {Number} [day] Tag des Monats
330 	 * @param {Number} [month] Monat
331 	 * @param {Number} [year] vierstellige Jahreszahl
332 	 */
333 	setDateEnd : function(hour, minute, day, month, year) {
334 		if(typeof year != "undefined") 
335 			this.DateEnd.setFullYear(year);
336 		if(typeof month != "undefined")
337 			this.DateEnd.setMonth(month-1);
338 		if(typeof day != "undefined")
339 			this.DateEnd.setDate(day);
340 		if(typeof hour != "undefined")
341 			this.DateEnd.setHours(hour);
342 		if(typeof minute != "undefined")		
343 			this.DateEnd.setMinutes(minute);
344 		this.DateEnd.setSeconds(0);	
345 	},
346 	
347 	/**
348 	 * Liefert Orte in einer durch ein Rechteck begrenzten Region in denen zu
349 	 * einem Datum Veranstaltungen stattfinden.
350 	 * @param {google.maps.LatLngBounds} latlngBounds Ein geografisches
351 	 *		Rechteck.
352 	 * @param {Function} callback Callback-Funktion, die bei Erhalt der Daten
353 	 *		aufgerufen wird. �bergibt ein Array aus Orten mit
354 	 *		folgenden Eigenschaften:
355 	 *			loc_id, lat, lng, name, category
356 	 * @param {Number} [max=100] Maximale Anzahl an zur�ckzugebenden
357 	 *		Veranstaltungen.
358 	 * @example
359 	 * Events.getLocations(rect, function(orte) {
360 	 *	alert(orte[0].name);
361 	 * });
362 	 */
363 	getEvents : function(latlngBounds, callback, max) {
364 		if(typeof max == "undefined") var max=100;		
365 		jQuery.post("ajax", {
366 				"action": 			"get_events",
367 				"latlng_bounds": 	latlngBounds.toString(),
368 				"start": 	 		this.DateStart.toMySQLDate(),
369 				"end": 				this.DateEnd.toMySQLDate(),
370 				"categories": 		jQuery.toJSON(Events.EventCategories),
371 				"max": 				max },
372 				callback, "json"
373 		);
374 	},
375 	
376 	/**
377 	 * Liefert Yourbashs in einer durch ein Rechteck begrenzten Region in denen
378 	 * zu einem Datum Veranstaltungen stattfinden.
379 	 * @param {google.maps.LatLngBounds} latlngBounds Ein geografisches
380 	 *		Rechteck.
381 	 * @param {Function} callback Callback-Funktion, die bei Erhalt der Daten
382 	 *		aufgerufen wird.
383 	 * @param {Number} [max=100] Maximale Anzahl an zur�ckzugebenden
384 	 *		Veranstaltungen.
385 	 */
386 	getYourbashs : function(latlngBounds, callback, max) {
387 		if(typeof max == "undefined") var max=100;		
388 		jQuery.post("ajax", {
389 				"action": 			"get_yourbashs",
390 				"latlng_bounds": 	latlngBounds.toString(),
391 				"start": 			this.DateStart.toMySQLDate(),
392 				"end": 				this.DateEnd.toMySQLDate(),
393 				"categories": 		jQuery.toJSON(Events.YourbashCategories),
394 				"max": 				max },
395 				callback, "json"
396 		);
397 	},
398 	
399 	/**
400 	 * Liefert Orte in einer durch ein Rechteck begrenzten Region in denen zu
401 	 * einem Datum von Nutzern erstellte Doodles stattfinden.
402 	 * @param {String} vkeys Ein JSON-Array mit den Doodleschl�sseln.
403 	 * @param {google.maps.LatLngBounds} latlngBounds Ein geografisches
404 	 *		Rechteck.
405 	 * @param {Function} callback Callback-Funktion, die bei Erhalt der Daten
406 	 *		aufgerufen wird. �bergibt ein Array von Doodles mit
407 	 *		folgenden Eigenschaften:
408 	 *			doodle_id, lat, lng, name
409 	 * @param {Number} [max=100] Maximale Anzahl an zur�ckzugebenden
410 	 *		Doodles.
411 	 * @example
412 	 * Events.getDoodles(vkeys, rect, dt, function(doodles) {
413 	 *	alert(doodles[0].name);
414 	 * });
415 	 */
416 	getDoodles : function(latlngBounds, callback, max) {
417 		if(typeof max == "undefined") var max=100;		
418 		jQuery.post("ajax", {
419 				"action": "get_doodles",
420 				"start": Events.DateStart.toMySQLDate(),
421 				"end": Events.DateEnd.toMySQLDate(),
422 				"latlng_bounds": latlngBounds.toString(),
423 				"max": max,
424 				"vkeys": jQuery.toJSON(Events.getVisitkeys())},
425 				callback, "json"
426 		);
427 	},
428 	
429 	/**
430 	 * Liefert Schl�ssel von in Cookies gespeicherten Doodles zur�ck.
431 	 * @return Schl�ssel
432 	 */
433 	getVisitkeys : function() {
434 		var cookies = document.cookie.split(';');
435 		var vkeys = new Array();
436 		for(var i = 0; i<cookies.length; i++) {
437 			if(cookies[i].search(/[^=]*doodle/) != -1) {
438 				vkeys.push(cookies[i].split('=')[1]);
439 			}
440 		}
441 		return vkeys;
442 	},
443 	
444 	/**
445 	 * Gibt eine Veranstaltung als Objekt zur�ck.
446 	 * @param {Number} id Die ID der Veranstaltung.
447 	 * @param {Function} callback Callback-Funktion, die bei Erhalt der Daten
448 	 *		aufgerufen wird. �bergibt ein Objekt mit folgenden Eigenschaften:
449 	 *			id, userId, locationId, dateTime, readableDate, readableTime,
450 	 *			text, htmlText
451 	 *		ACHTUNG: dateTime ist ein MySQL-formatierter Datumsstring!
452 	 * @example
453 	 * Events.getEvent(id, function(ev) {
454 	 *	alert(ev.htmlText);
455 	 * });
456 	 */
457 	getEvent : function(id, callback) {
458 		jQuery.post("ajax",
459 			{ "action":"get_event", "id":id },
460 			callback, "json"	
461 		);
462 	},
463 	
464 	/**
465 	 * Gibt eine Location als Objekt zur�ck.
466 	 * @param {Number} id Die ID der Location.
467 	 * @param {Function} callback Callback-Funktion, die bei Erhalt der Daten
468 	 *		aufgerufen wird. �bergibt ein Objekt.
469 	 *		ACHTUNG: dateTime ist ein MySQL-formatierter Datumsstring.
470 	 * @example
471 	 * Events.getLocation(id, function(l) {
472 	 *	alert(l.Address);
473 	 * });
474 	 */
475 	getLocation : function(id, callback) {
476 		jQuery.post("ajax",
477 			{ "action":"get_location", "id":id },
478 			callback, "json"	
479 		);
480 	},
481 	
482 	/**
483 	 * Gibt ein Yourbash als Objekt zur�ck.
484 	 * @param {Number} id Die ID.
485 	 * @param {Function} callback Callback-Funktion, die bei Erhalt der Daten
486 	 *		aufgerufen wird. �bergibt ein Objekt mit folgenden Eigenschaften:
487 	 *			id, userId, address, lat, lng, dateTime, readableDate,
488 	 * 			readableTime, title, text, htmlText
489 	 *		ACHTUNG: dateTime ist ein MySQL-formatierter Datumsstring!
490 	 */
491 	getYourbash : function(id, callback) {
492 		jQuery.post("ajax",
493 			{ "action":"get_yourbash", "id":id },
494 			callback, "json"	
495 		);
496 	},
497 	
498 	/**
499 	 * Gibt einen Doodle als Objekt zur�ck.
500 	 * @param {String} vkey Der Schl�ssel des Doodles.
501 	 * @param {Function} callback Callback-Funktion, die bei Erhalt der Daten
502 	 *		aufgerufen wird. �bergibt ein Objekt mit folgenden Eigenschaften:
503 	 *			address, lat, lng, name, htmlName, text, htmlText, dateTime
504 	 *			readableDate, readableTime, visitKey
505 	 *		ACHTUNG: dateTime ist ein MySQL-formatierter Datumsstring und kann
506 	 *		mittels {@link Events#convertMySQLDateToJSDate()} in ein
507 	 *		Date-Objekt konvertiert werden.
508 	 * @example
509 	 * Events.getDoodle(vkey, function(doodle) {
510 	 *	alert(doodle.name);
511 	 * });
512 	 */
513 	getDoodle : function(key, callback) {
514 		jQuery.post("ajax", 
515 			{ "action":"get_doodle", "key":key },
516 			callback, "json"	
517 		);
518 	},
519 	
520 	/**
521 	 * Setzt ein neues Cookie mit den entsprechenden Doodledaten.
522 	 * @param {Object} d Ein Doodle.
523 	 */
524 	registerDoodle : function(d) {
525 		var date = new Date(d.Year, d.Month-1, d.Day+1);
526 		jQuery.cookie('doodle'+d.Id, d.VisitKey, 
527 			{ expires: date, path: '/' });
528 	},
529 	
530 	/**
531 	 * Setzt einen Ort �ber Cookies lokal als Favorit.
532 	 * @param {Number} locId Die ID des Ortes.
533 	 */
534 	setLocationAsFavorite : function(locId) {
535 		jQuery.cookie('loc'+locId, 1, { expires: 3650, path: "/"});
536 		Info.event(locId);
537 		Map.reload();
538 	},
539 	
540 	/**
541 	 * Entfernt die Markierung eines Ortes als Favorit lokal.
542 	 * @param {Number} locId Die ID des Ortes.
543 	 */
544 	unsetLocationAsFavorite : function(locId) {
545 		jQuery.cookie('loc'+locId, null, { expires: 3650, path: "/" });
546 		Info.event(locId);
547 		Map.reload();
548 	},
549 	
550 	/**
551 	 * Schaltet die Markierung eines Ortes als Favorit lokal um.
552 	 * @param {Number} locId Die ID des Ortes.
553 	 */
554 	toggleLocationAsFavorite : function(locId) {
555 		if(Events.isLocationFavorite(locId)) {
556 			Events.unsetLocationAsFavorite(locId);
557 		} else {
558 			Events.setLocationAsFavorite(locId);
559 		}
560 	},
561 	
562 	/**
563 	 * Gibt zur�ck, ob der Ort als Favorit eingestellt ist.
564 	 * @param {Number} locId Die ID des Ortes.
565 	 * @returns {Boolean} true oder false
566 	 */
567 	isLocationFavorite : function(locId) {
568 		return (jQuery.cookie('loc'+locId) == 1);
569 	},
570 	
571 	/**
572 	 * Bewertet einen Ort als positiv.
573 	 * @param {Number} locID Die ID des Ortes. 
574 	 */
575 	thumbUp : function(locId) {
576 		if(jQuery.cookie('thumb'+locId) == 1) return;
577 		jQuery.post("ajax", 
578 			{ "action":"thumb_up", "id":locId },
579 			function() {
580 				Info.event(locId);
581 				jQuery.cookie('thumb'+locId, 1, { expires: 3650, path: "/" });
582 			}, "json"	
583 		);
584 	},
585 	
586 	/**
587 	 * Bewertet einen Ort als negativ.
588 	 * @param {Number} locID Die ID des Ortes. 
589 	 */
590 	thumbDown : function(locId) {
591 		if(jQuery.cookie('thumb'+locId) == 1) return;
592 		jQuery.post("ajax", 
593 			{ "action":"thumb_down", "id":locId },
594 			function() {
595 				Info.event(locId);
596 				jQuery.cookie('thumb'+locId, 1, { expires: 3650, path: "/" });
597 			}, "json"	
598 		);
599 	}
600 };/**
601  * @namespace Diese Klasse zeigt die Map mit den Veranstaltungen an.
602  * @author Jan Kossick, jankossick@online.de
603  * @version 2.0
604  * @requires http://maps.google.com/maps/api/js
605  * @requires Geo
606  * @requires Info
607  * @requires Events
608  */
609 var Map = {
610 	/**
611 	 * Der Zugriffspunkt auf das map-Objekt von Google.
612 	 */
613 	Map : null,
614 	
615 	/**
616 	 * Die Legende der Karte.
617 	 */
618 	Legende : null,
619 	
620 	/**
621 	 * Enth�lt die auf der Karte befindlichen Marker.
622 	 */
623 	Markers : new Array(),
624 	
625 	/**
626 	 * Enth�lt den Index des derzeitig ausgew�hlten Markers.
627 	 * @see Map.Markers
628 	 */
629 	SelectedMarker : {
630 		EventType: null,
631 		Address: null, //f�r Doodles
632 		LocId: null //f�r Events
633 	},
634 	
635 	/**
636 	 * Der Marker der eine Position als Standort markiert.
637 	 */
638 	PositionMarker : null,
639 	
640 	/**
641 	 * Speichert die Daten des aktuell ausgew�hlten Markers um nach einem
642 	 * Refresh den Marker evtl. wieder ausw�hlen zu k�nnen.
643 	 * @param {Object} marker Der Marker der gespeichert werden soll.
644 	 */
645 	saveSelectedMarker : function(marker) {
646 		var locId = null;
647 		var address = null;
648 		if(typeof marker.EventType == 'undefined') marker.EventType = null;
649 		
650 		switch(marker.EventType) {
651 			case 'event': 	locId = marker.LocId; break;
652 			case 'yourbash':
653 			case 'doodle': 
654 				address = marker.Address;
655 				break;
656 		}
657 		Map.SelectedMarker.EventType = marker.EventType;
658 		Map.SelectedMarker.LocId = locId;
659 		Map.SelectedMarker.Address = address;
660 	},
661 	
662 	/**
663 	 * Selektiert einen Marker.
664 	 * @param {String} type Der Typ des Markers.
665 	 * @param {String} id Die Id des Markers.
666 	 */
667 	selectMarker : function(marker) {
668 		//altes Symbol deselektieren
669 		var sel = Map.indexOfMarker(Map.SelectedMarker);
670 		if(sel > -1) Map.Markers[sel].setShadow(null);
671 		
672 		//neues Symbol selektieren
673 		Map.saveSelectedMarker(marker);
674 		try { //falls tats�chlich ein google.maps.Marker
675 			marker.setShadow('img/selected.png');
676 		} catch(ex) { //sonst
677 			sel = Map.indexOfMarker(Map.SelectedMarker);
678 			if(sel > -1) Map.Markers[sel].setShadow('img/selected.png');
679 		}
680 	},
681 	
682 	/**
683 	 * Gibt den Index eines Markers im Array Markers zur�ck.
684 	 * @param {Object} m Der Marker, dessen Index gesucht wird.
685 	 * @see Map#Markers
686 	 */
687 	indexOfMarker : function(marker) {
688 		for(var i=0; i < Map.Markers.length; i++) {
689 			if(marker.EventType != Map.Markers[i].EventType) continue;
690 			switch(marker.EventType) {
691 				case 'event':
692 					if(Map.Markers[i].LocId == marker.LocId) return i;
693 					break;
694 				case 'yourbash':
695 				case 'doodle':
696 					if(Map.Markers[i].Address == marker.Address) return i;
697 					break;
698 			}
699 		}
700 		return -1;
701 	},
702 	
703 	/**
704 	 * Bindet eine Callback-Funktion an die einzelnen Marker. Der
705 	 * Callback-Funktion wird das selektierte Marker-Objekt �bergeben.
706 	 * @param {Function} callback Die aufzurufende Callback-Funktion.
707 	 */
708 	bind : function(callback) {
709 		for(var i=0; i < Map.Markers.length; i++) {
710   			google.maps.event.addListener(Map.Markers[i], 'click', function() {
711   				Map.selectMarker(this);				
712 				callback(this);
713 			});
714   		}
715 	},
716 	
717 	/**
718 	 * Initialisiert die Map und weist ihr einen Container zu.
719 	 * @param {google.maps.LatLng} [center] Gibt den Mittelpunkt der Karte an.
720 	 *		Falls nicht angegeben, wird die StandardPosition des Geo-Moduls
721 	 *		verwendet.
722 	 * @param {Object} [legende] Gibt die legende an, die am unteren linken
723 	 *		Bildrand eingeblendet werden kann. Falls nicht angegeben, wird
724 	 *		'#map_legende' verwendet.
725 	 * @param {Object} [container] Der Container, in dem die Karte angezeigt
726 	 *		wird. Falls nicht angegeben, wird '#map_canvas' verwendet.
727 	 * @see Geo#StandardPosition 
728 	 */
729 	setMap : function(center, zoom, legende, container) {
730 		if(typeof container == 'undefined')
731 			container = document.getElementById('map_canvas');
732 		if(typeof zoom == 'undefined')
733 			zoom = 15;
734 		if(typeof legende == 'undefined')
735 			legende = document.getElementById('map_legende');
736 		if(typeof center == 'undefined')
737 			center = Geo.StandardPosition.LatLng;
738 		
739 		Map.Map = new google.maps.Map(
740 			container,
741 			{ zoom: zoom, center: center, mapTypeId: google.maps.MapTypeId.ROADMAP }
742 		)
743 		
744 		// Das delay dient dazu, nicht bei jedem kurz hintereinander folgendem
745 		// bounds_changed-Ereignis alles neu zu laden.
746 		google.maps.event.addListener(Map.Map, 'bounds_changed', function() {
747 			try { window.clearTimeout(delayRefresh); } catch(ex) {}
748 			delayRefresh = window.setTimeout("Map.refresh()", 1000);
749 		});
750 
751 		Map.Legende = legende;
752 	},
753 	
754 	
755 	/**
756 	 * L�scht alle Elemente auf der Karte und l�dt dann neu.
757 	 */
758 	reload : function() {
759 		if(Map.Map == null) return;
760 		
761 		//Marker l�schen
762 		for(var i = 0; i < Map.Markers.length; i++) {
763 			Map.Markers[i].setMap(null);
764 		}
765 		Map.Markers = new Array();
766 				
767 		Map.refresh();
768 	},
769 	
770 	/**
771 	 * L�dt neue Elemente auf die Karte.
772 	 */
773 	refresh : function() {
774 		if(Map.Map == null) return;
775 				
776 		Events.getEvents(Map.Map.getBounds(), Map.setEventMarkers);
777 		Events.getYourbashs(Map.Map.getBounds(), Map.setYourbashMarkers);
778 		Events.getDoodles(Map.Map.getBounds(), Map.setDoodleMarkers);
779 	},
780 	
781 	/**
782 	 * Setzt Veranstaltungen auf die Karte.
783 	 */
784 	setEventMarkers : function(data) {
785 		if(Map.Map == null) return;
786 		if(data.length == 0) return;
787 		
788 		for(var i = 0; i < data.length; i++) {
789 			var marker = new google.maps.Marker();
790 			//LocationID, Typ setzen, Kategorie
791 			marker.LocId = data[i].loc_id;
792 			marker.EventType = 'event';
793 			//pr�fen, ob bereits gesetzt
794 			if(Map.indexOfMarker(marker) > -1) continue;
795 			
796 			//Kategorie, Position, Title setzen
797 			marker.Category = data[i].category;
798 			marker.setPosition(new google.maps.LatLng(data[i].lat, data[i].lng)),
799 			marker.setTitle(Encoder.htmlDecode(data[i].name));
800 			//Ort ist als Favorit markiert
801 			if(Events.isLocationFavorite(data[i].loc_id)) {
802 				marker.setIcon('img/favorite.png');
803 			} else { //Standardsymbol
804 				switch (data[i].category) {
805 					case 'cinema': marker.setIcon('img/cinema.png'); break;
806 					case 'theatre': marker.setIcon('img/theatre.png'); break;
807 					case 'museum': marker.setIcon('img/museum.png'); break;
808 					case 'arts': marker.setIcon('img/arts.png'); break;
809 					default: marker.setIcon('img/yb.png');
810 				}
811 			}
812 			//auf die Karte setzen
813 			marker.setMap(Map.Map);
814 			Map.Markers.push(marker);
815 		}
816 		
817 		//Events an die Marker binden
818 		Map.bind(function(marker) {
819 			if(marker.EventType == 'event') Info.event(marker.LocId);
820 			if(marker.EventType == 'yourbash') Info.yourbash(marker.Id);
821 			if(marker.EventType == 'doodle') Info.doodle(marker.Vkey);
822 		});
823 		
824 		//ausgew�hlten Marker setzen
825 		Map.selectMarker(Map.SelectedMarker);		
826 	},
827 	
828 	/**
829 	 * Setzt Yourbashs auf die Karte.
830 	 */
831 	setYourbashMarkers : function(data) {
832 		if(Map.Map == null) return;
833 		if(data.length == 0) return;
834 		
835 		for(i = 0; i < data.length; i++) {
836 			var marker = new google.maps.Marker();
837 			
838 			//YourbashID speichern
839 			marker.Id = data[i].id;
840 			marker.EventType = 'yourbash';
841 			
842 			//einf�gen, falls nicht schon vorhanden
843 			if(Map.indexOfMarker(marker) > -1) continue;
844 			
845 			marker.Group = data[i].group;
846 			marker.Category = data[i].category;
847 			marker.Address = data[i].address;
848 			marker.setPosition(new google.maps.LatLng(data[i].lat, data[i].lng));
849 			marker.setTitle(Encoder.htmlDecode(data[i].title));
850 			var icon = data[i].marker;
851 			switch (data[i].category) {
852 				case 'concert': marker.setIcon(icon); break;
853 				case 'exhibition': marker.setIcon(icon); break;
854 				case 'theatre': marker.setIcon(icon); break;
855 				case 'sport': marker.setIcon(icon); break;
856 				case 'party': marker.setIcon(icon); break;
857 				default: marker.setIcon(icon);
858 			}
859 			marker.setMap(Map.Map);
860 			Map.Markers.push(marker);
861 		}
862 		
863 		//Events an die Marker binden
864 		Map.bind(function(marker) {
865 			if(marker.EventType == 'event') Info.event(marker.LocId);
866 			if(marker.EventType == 'yourbash') Info.yourbash(marker.Id);
867 			if(marker.EventType == 'doodle') Info.doodle(marker.Vkey);
868 		});
869 		
870 		//ausgew�hlten Marker setzen
871 		Map.selectMarker(Map.SelectedMarker);		
872 	},
873 	
874 	/**
875 	 * Setzt Doodles auf die Karte.
876 	 */
877 	setDoodleMarkers : function(data) {
878 		if(Map.Map == null) return;
879 		if(data.length == 0) return;
880 
881 		for(i = 0; i < data.length; i++) {
882 			var marker = new google.maps.Marker();
883 			
884 			//DoodleID speichern
885 			marker.Id = data[i].id;
886 			marker.EventType = 'doodle';
887 			
888 			//einf�gen, falls nicht schon vorhanden
889 			if(Map.indexOfMarker(marker) > -1) continue;
890 			
891 			marker.Address = data[i].address;
892 			marker.Vkey = data[i].vkey;
893 			marker.setPosition(new google.maps.LatLng(data[i].lat, data[i].lng));
894 			marker.setTitle(Encoder.htmlDecode(data[i].name));
895 			marker.setIcon('img/doodle.png');
896 			marker.setMap(Map.Map);
897 			Map.Markers.push(marker);
898 		}
899 		
900 		//Events an die Marker binden
901 		Map.bind(function(marker) {
902 			if(marker.EventType == 'event') Info.event(marker.LocId);
903 			if(marker.EventType == 'yourbash') Info.yourbash(marker.Id);
904 			if(marker.EventType == 'doodle') Info.doodle(marker.Vkey);
905 		});
906 		
907 		//ausgew�hlten Marker setzen
908 		Map.selectMarker(Map.SelectedMarker);		
909 	},
910 	
911 	/**
912 	 * Setzt den Standort-Marker auf eine angegebene Position und zeigt ihn
913 	 * auf der entsprechenden Karte an.
914 	 * @param {google.maps.LatLng} [position] Die Position des Markers. Falls
915 	 *		nicht angegeben, wird versucht die vorherige Position
916 	 *		beizubehalten. Falls das auch nicht gelingt, wird die
917 	 *		StandardPosition des Geo-Moduls verwendet.
918 	 * @param {title} [title]
919 	 * @see Geo#StandardPosition 
920 	 */
921 	setPositionMarker : function(position, title) {
922 				if(Map.Map == null) return;
923 		
924 		if(typeof title == 'undefined')	title = '';
925 		if(typeof position == 'undefined') {
926 			if(Map.PositionMarker == null) {
927 				position = Geo.StandardPosition.LatLng;
928 				title = Geo.StandardPosition.Address;
929 			} else {
930 				position = Map.PositionMarker.getPosition();
931 				title = Map.PositionMarker.getTitle();
932 			}
933 		}
934 		if(Map.PositionMarker == null) {
935 			var image = new google.maps.MarkerImage('img/standort.png',
936 			  	new google.maps.Size(25, 38),
937 			  	new google.maps.Point(0,0),
938 			  	new google.maps.Point(25, 38)
939 			);
940 			Map.PositionMarker = new google.maps.Marker({
941 				position: position,
942 				title: title,
943 				icon: image,
944 				map: Map.Map
945 			});
946 		} else {
947 			Map.PositionMarker.setPosition(position);
948 			Map.PositionMarker.setTitle(title);
949 		}
950 	},
951 	
952 	/**
953 	 * Setzt das Zentrum der Karte auf den angegebenen Punkt.
954 	 * @param {google.maps.LatLng} latlng Die Koordinaten des Punktes.
955 	 * @param {String} [title] Der Titel des Markers.
956 	 */
957 	setLatLng : function(latlng, title) {
958 		if(Map.Map == null) return;
959 		
960 		if(latlng == false) {
961 			Info.message(title);
962 			return;
963 		}
964 		if(typeof title == 'undefined') title = '';
965 		Map.Map.setCenter(latlng);
966 		Map.setPositionMarker(latlng, title);
967 	},
968 	
969 	/**
970 	 * Setzt das Zentrum der Karte auf die angegebene Adresse.
971 	 * @param {String} address Die Adresse.
972 	 * @see Geo#getLatLng
973 	 */
974 	setAddress : function(address) {
975 		if(address == '' || typeof address == 'undefined') return;
976 		Geo.getLatLng(address, Map.setLatLng);
977 	},
978 	
979 	/**
980 	 * Zeigt die Legende an oder blendet diese aus.
981 	 * @param {Boolean} show Gibt an, ob die Legende sichtbar ist oder nicht.
982 	 */
983 	showLegende : function(show) {
984 		if(show) jQuery(Map.Legende).show();
985 		else jQuery(Map.Legende).hide();
986 	},
987 	
988 	/**
989 	 * �ndert das Yourbash-Icon in der Legende.
990 	 * ! Funktioniert nur mit der bereitgestellten Legende. 
991 	 */
992 	changeYourbashIcon : function(icon, name) {
993 		jQuery('#map_legende .symbol_yourbash').attr('src', icon);
994 		jQuery('#map_legende .yourbash').attr('src', icon);
995 		jQuery('#map_legende #yourbash .short_title').html(name);
996 	},
997 	
998 	/**
999 	 * �ndert CSS-Eigenschaften der Karte. Vor allem f�r Gr��en- und
1000 	 * Positions�nderungen gedacht.
1001 	 * @param {Object} opt Zu �ndernde CSS-Eigenschaften als Objekt, siehe
1002 	 *		{@link http://api.jquery.com/css/#css2}. 
1003 	 */
1004 	setCSS : function(opt) {
1005 		if(Map.Map == null) return;
1006 		jQuery(Map.Map.getDiv()).css(opt);
1007 	}
1008 };
1009 
1010 // Event-Listener f�r die Event-Symbole auf der Legende anmelden
1011 jQuery('#map_legende .symbol_event.clickable').click(function() {
1012 	if(Events.toggleEventCategories(jQuery(this).attr('alt')))
1013 		jQuery(this).css('opacity', 1);
1014 	else jQuery(this).css('opacity', 0.5);
1015 });
1016 
1017 // Event-Listener f�r die Yourbash-Symbole auf der Legende anmelden
1018 jQuery('#map_legende .symbol_yourbash.clickable').click(function() {
1019 	if(Events.toggleYourbashCategories(jQuery(this).attr('alt')))
1020 		jQuery(this).css('opacity', 1);
1021 	else jQuery(this).css('opacity', 0.5);
1022 });
1023 
1024 // Event-Listener f�r das allgemeine Yourbash-Symbol auf der Legende anmelden
1025 jQuery('#map_legende .yourbash.clickable').click(function() {
1026 	if(jQuery(this).css('opacity') == 1) {
1027 		for (var cat in Events.YourbashCategories) Events.YourbashCategories[cat] = false;
1028 		Map.reload();
1029 		jQuery(this).css('opacity', 0.5);
1030 		jQuery('#map_legende .symbol_yourbash.clickable').css('opacity', 0.5);
1031 	} else { 
1032 		for (var cat in Events.YourbashCategories) Events.YourbashCategories[cat] = true;
1033 		Map.reload();
1034 		jQuery(this).css('opacity', 1);
1035 		jQuery('#map_legende .symbol_yourbash.clickable').css('opacity', 1);
1036 	}
1037 });
1038 
1039 // Event-Listener f�r Standort anmelden
1040 jQuery('#map_legende .position.clickable').click(function() {
1041 	Geo.getPosition(function(latlng) {		
1042 		if(latlng == false) latlng = Geo.StandardPosition.LatLng;
1043 		Map.setLatLng(latlng);
1044 		Map.setPositionMarker(latlng);
1045 	});
1046 });
1047 
1048 // Event-Listener f�r toggelOptions anmelden
1049 jQuery('#map_legende #toggle_yourbashs').click(function() {
1050 	if(jQuery(this).hasClass('open')) {
1051 		jQuery(this).removeClass('open');
1052 		jQuery('#map_legende .container.yourbashs').hide();
1053 		jQuery('#map_legende #toggle_yourbashs').html('?<br />?<br />?');
1054 	} else {
1055 		jQuery(this).addClass('open');
1056 		jQuery('#map_legende .container.yourbashs').show();
1057 		jQuery('#map_legende #toggle_yourbashs').html('?<br />?<br />?');
1058 	}
1059 });/**
1060  * @namespace Diese Klasse stellt Eingabem�glichkeiten zur Verf�gung.
1061  * @author Jan Kossick, jankossick@online.de
1062  * @version 2.0
1063  * @requires http://maps.google.com/maps/api/js
1064  * @requires Info
1065  * @requires Events
1066  * @requires Map
1067  */
1068 var Input = {
1069 	/**
1070 	 * Interval, dass Zeit in Stunden zwischen Start- und Enddatum angibt beim
1071 	 * automatischen Setzen.
1072 	 */
1073 	Interval : 8,
1074 	
1075 	/**
1076 	 * �ndert den Datepicker und die Uhrzeit f�r das Startdatum.
1077 	 * Achtung! �ndert auch das Enddatum mit um {@see Input.Interval} Stunden.
1078 	 * @param date {Date} Das zu setzende Datum. 
1079 	 */
1080 	triggerStartDate : function(date) {
1081 		jQuery('#input #hour').val(date.getHours());
1082 		jQuery('#input #date').datepick('setDate', [date]);		
1083 	},
1084 	
1085 	/**
1086 	 * �ndert den Datepicker und die Uhrzeit f�r das Enddatum.
1087 	 * @param date {Date} Das zu setzende Datum. 
1088 	 */
1089 	triggerEndDate : function(date) {
1090 		jQuery('#input #hour_to').val(date.getHours());
1091 		jQuery('#input #date_to').datepick('setDate', [date]);
1092 	},
1093 	
1094 	/**
1095 	 * Gibt den Container des Inputbereiches als DOM-Element zur�ck.
1096 	 * @returns {Object} DOM-Element des Inputbereiches. 
1097 	 */
1098 	getContainer : function() {
1099 		return document.getElementById('input');
1100 	},
1101 	
1102 	/**
1103 	 * Zeigt den Eingabebereich an.
1104 	 */
1105 	show : function() {
1106 		jQuery('#input').show();
1107 	},
1108 	
1109 	/**
1110 	 * Blendet den Eingabebereich aus.
1111 	 */
1112 	hide : function() {
1113 		jQuery('#input').hide();
1114 	},
1115 	
1116 	/**
1117 	 * Setzt den Eingabefokus auf das Adressfeld.
1118 	 */
1119 	focus : function() {
1120 		jQuery('#input #address').focus();
1121 	},
1122 	
1123 	/** 
1124 	 * Gibt Eigenschaften des Inputbereiches zur�ck.
1125 	 * M�gliche Selektoren: 
1126 	 *		#nav		Navigationsbereich
1127 	 *		#search		Suchbereich
1128 	 *		#address	Adressfeld
1129 	 *		#date		Datumsfeld
1130 	 *		#hour		Stundenauswahl
1131 	 *		#find		Findenbutton
1132 	 *		#social		Social Media-Bereich
1133 	 * @param {String} selektor CSS-Selektor. Ist der Selektor leer, wird die
1134 	 *		Eigenschaft direkt vom Infowindow gelesen.
1135 	 * @param {String} Name der Eigenschaft
1136 	 * @returns {String} Wert der Eigenschaft
1137 	*/
1138 	getCSS : function(selektor, name) {
1139 		return jQuery("#input " + selektor).css(name);
1140 	},
1141 	
1142 	/** 
1143 	 * Kann die Eigenschaften des Inputbereiches anpassen.
1144 	 * M�gliche Selektoren: 
1145 	 *		#nav		Navigationsbereich
1146 	 *		#search		Suchbereich
1147 	 *		#address	Adressfeld
1148 	 *		#date		Datumsfeld
1149 	 *		#hour		Stundenauswahl
1150 	 *		#find		Findenbutton
1151 	 *		#social		Social Media-Bereich
1152 	 * @param {String} selektor CSS-Selektor. Ist der Selektor leer, wird die
1153 	 *		Eigenschaft direkt auf den Inputbereich angewendet.
1154 	 * @param {String} Name der Eigenschaft
1155 	 * @param {String} Wert der Eigenschaft
1156 	*/
1157 	setCSS : function(selektor, name, value) {
1158 		jQuery("#input " + selektor).css(name, value);
1159 	},
1160 	
1161 	/**
1162 	 * L�dt die SocialButtons. 
1163 	 */
1164 	loadSocials : function() {
1165 		jQuery(window).load(function() {
1166 			/* FLATTR */
1167 			(function() {
1168 	        	var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
1169 	        	s.type = 'text/javascript';
1170 	        	s.async = true;
1171 	        	s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
1172 	        	t.parentNode.insertBefore(s, t);
1173 	   		})();
1174    		
1175 			/* Facebook */
1176 			(function(d, s, id) {
1177 		  		var js, fjs = d.getElementsByTagName(s)[0];
1178 		  		if (d.getElementById(id)) return;
1179 		  		js = d.createElement(s); js.id = id;
1180 		  		js.src = "//connect.facebook.net/de_DE/all.js#xfbml=1";
1181 		  		fjs.parentNode.insertBefore(js, fjs);
1182 			}(document, 'script', 'facebook-jssdk'));
1183 			
1184 			/* Google+ */
1185 			window.___gcfg = {lang: 'de'};
1186 			(function() {
1187 		    	var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
1188 		    	po.src = 'https://apis.google.com/js/plusone.js';
1189 		    	var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
1190 		  	})();
1191 		  	
1192 		  	/* Twitter */
1193 		  	!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");
1194 		});
1195 	}
1196 };
1197 {
1198 	/* jQuery Datepicker */
1199 	jQuery('#input #date').datepick({
1200 		onSelect: function(dates) {
1201 			dates[0].setHours(jQuery('#input #hour').val());
1202 			Events.setDateStart(
1203 				dates[0].getHours(),
1204 				0,
1205 				dates[0].getDate(),
1206 				dates[0].getMonth()+1,
1207 				dates[0].getFullYear()
1208 			);
1209 			// Enddatum auf 8 Stunden sp�ter stellen.
1210 			// Dadurch entf�llt auch das Map.reload(), da es sowieso ausgef�hrt wird.
1211 			Input.triggerEndDate(new Date(Date.parse(dates[0])+(Input.Interval*60*60*1000)));
1212 	    }
1213 	});
1214 	jQuery('#input #date_to').datepick({
1215 		onSelect: function(dates) {
1216 			dates[0].setHours(jQuery('#input #hour_to').val());
1217 			Events.setDateEnd (
1218 				dates[0].getHours(),
1219 				0,
1220 				dates[0].getDate(),
1221 				dates[0].getMonth()+1,
1222 				dates[0].getFullYear()
1223 			);
1224 			Map.reload();
1225 	    }
1226 	});
1227 	/* Stunden */
1228 	jQuery('#input #hour').bind('change', function() {
1229 		Events.setDateStart(jQuery('#input #hour').val());
1230 		Input.triggerEndDate(new Date(Date.parse(Events.DateStart)+(Input.Interval*60*60*1000)));
1231 		Map.reload();
1232 	});
1233 	jQuery('#input #hour_to').bind('change', function() {
1234 		Events.setDateEnd(jQuery('#input #hour_to').val());
1235 		Map.reload();
1236 	});
1237 	/* Adressfeld */
1238 	jQuery('#input #address').bind('keyup', function(e) {
1239 		if(e.which==13) jQuery('#input #find').click();
1240 	});
1241 	jQuery('#input #find').bind('click', function() {
1242 		Map.setAddress(jQuery('#input #address').val());
1243 	});
1244 }
1245 /**
1246  * @namespace Diese Klasse liefert HTML-formatierte Seiten zur�ck.
1247  * @author Jan Kossick, jankossick@online.de
1248  * @version 2.0
1249  */
1250 var Info = {
1251 	/**
1252 	 * Zeigt Text-Informationen im {@link Infowindow} an.
1253 	 * @param {Object} data Ein Objekt mit den Attributen js, css, toolbar und
1254 	 *		content.
1255 	 */
1256 	message : function(data) {
1257 		Infowindow.setContentCSS(data.css);
1258 		Infowindow.setContent(data.content);
1259 		eval(data.js);
1260 	 	Infowindow.show();
1261 	},
1262 	
1263 	/**
1264 	 * L�dt eine HTML-Seite mit Informationen zum Ort und den Veranstaltungen,
1265 	 * basierend auf den Einstellungen von {@link Events} und zeigt diese im
1266 	 * {@link Infowindow} an.
1267 	 * @param {Number} locId Die ID des Ortes.
1268 	 */
1269 	event : function(locId) {
1270 		jQuery.post("ajax", {
1271 			"action": 		"get_info_event",
1272 			"loc_id": 		locId,
1273 			"is_favorite" : Events.isLocationFavorite(locId),
1274 			"categories_yourbash": 	jQuery.toJSON(Events.YourbashCategories),
1275 			"start": 		Events.DateStart.toMySQLDate(),
1276 			"end": 			Events.DateEnd.toMySQLDate() },
1277 			this.message, "json"
1278 		);
1279 	},
1280 	
1281 	/**
1282 	 * L�dt eine HTML-Seite mit Informationen zum Ort und den Yourbashs,
1283 	 * basierend auf den Einstellungen von {@link Events} und zeigt diese im
1284 	 * {@link Infowindow} an.
1285 	 * @param {Number} id Die ID des Yourbashs.
1286 	 */
1287 	yourbash : function(id, callback) {
1288 		if(typeof callback == 'undefined') callback = this.message;
1289 		 
1290 		jQuery.post("ajax", {
1291 			"action": 		"get_info_yourbash",
1292 			"id": 			id,
1293 			"categories_yourbash": 	jQuery.toJSON(Events.YourbashCategories),
1294 			"start": 		Events.DateStart.toMySQLDate(),
1295 			"end": 			Events.DateEnd.toMySQLDate() },
1296 			callback, "json"
1297 		);
1298 	},
1299 	
1300 	/**
1301 	 * L�dt eine HTML-Seite mit Informationen zu Doodles, basierend auf den
1302 	 * Einstellungen von {@link Events} und zeigt diese im {@link Infowindow}
1303 	 * an. Weitere Doodles an der selben Adresse werden automatisch geladen.
1304 	 * @param {String} vkey Der Schl�ssel des Doodles.
1305 	 */
1306 	doodle : function(vkey) {
1307 		jQuery.post("ajax", {
1308 			"action":"get_info_doodle",
1309 			'vkey' : vkey,
1310 			'vkeys' : jQuery.toJSON(Events.getVisitkeys()),
1311 			"start": Events.DateStart.toMySQLDate(),
1312 			"end": Events.DateEnd.toMySQLDate() },
1313 			this.message, "json"
1314 		);
1315 	},
1316 	
1317 	/**
1318 	 * L�dt eine HTML-Seite mit den News.
1319 	 */
1320 	news : function() {
1321 		jQuery.post("ajax", {
1322 			"action":"get_info_news" },
1323 			Info.message, "json"
1324 		);
1325 	},
1326 	
1327 	/**
1328 	 * L�dt eine HTML-Seite mit der Hilfe.
1329 	 */
1330 	hilfe : function() {
1331 		jQuery.post("ajax", {
1332 			"action":"get_info_hilfe" },
1333 			Info.message, "json"
1334 		);
1335 	},
1336 	
1337 	/**
1338 	 * L�dt eine HTML-Seite mit dem Impressum.
1339 	 */
1340 	impressum : function() {
1341 		jQuery.post("ajax", {
1342 			"action":"get_info_impressum" },
1343 			this.message, "json"
1344 		);
1345 	},
1346 	
1347 	/**
1348 	 * L�dt eine HTML-Seite mit dem Kontaktformular.
1349 	 */
1350 	kontakt : function() {
1351 		jQuery.post("ajax", {
1352 			"action":"get_info_kontakt" },
1353 			this.message, "json"
1354 		);
1355 	},
1356 	
1357 	/**
1358 	 * �bermittelt eine Kontaktnachricht und l�dt eine HTML-Seite mit dem
1359 	 * Status.
1360 	 * @param {String} data Serialisierte Formulardaten.
1361 	 */
1362 	kontaktSend : function(data) {
1363 		jQuery.post("ajax", data, this.message, "json");
1364 	},
1365 	
1366 	/**
1367 	 * L�dt eine HTML-Seite mit dem Fehlerformular.
1368 	 * @param {String} type Typ des Fehlers. location oder event.
1369 	 * @param {Number} id ID der entprechenden Location oder Veranstaltung. 
1370 	 */
1371 	fehler : function(type, id) {
1372 		jQuery.post("ajax", {
1373 			"action":"get_info_fehler",
1374 			"type":type,
1375 			"id":id },
1376 			this.message, "json"
1377 		);
1378 	},
1379 	
1380 	/**
1381 	 * �bermittelt eine Fehlernachricht und l�dt eine HTML-Seite mit dem
1382 	 * Status.
1383 	 * @param {String} data Serialisierte Formulardaten.
1384 	 */
1385 	fehlerSend : function(data) {
1386 		jQuery.post("ajax", data, this.message, "json");
1387 	}
1388 };/**
1389  * @namespace Diese Klasse bietet das Handling von allgemeinen AJAX-Events.
1390  * @author Jan Kossick, jankossick@online.de
1391  * @version 2.0
1392  */
1393 var Ajax = {
1394 	/**
1395 	 * Speichert den Container mit dem AjaxLoader.
1396 	 */
1397 	AjaxLoader : document.getElementById('ajax_loader'),
1398 	
1399 	/**
1400 	 * Wird aufgerufen, wenn das erste Ajax-Event beginnt.
1401 	 */
1402 	start : function() {
1403 		jQuery(Ajax.AjaxLoader).show();
1404 	},
1405 	
1406 	/**
1407 	 * Wird aufgerufen, wenn alle Ajax-Events beendet sind.
1408 	 */
1409 	stop : function() {
1410 		jQuery(Ajax.AjaxLoader).hide();
1411 	},
1412 	
1413 	/**
1414 	 * Wird aufgerufen, wenn ein Ajax-Fehler auftritt.
1415 	 */
1416 	error : function(e, jqxhr, settings, exception) {
1417 		jQuery(Ajax.AjaxLoader).hide();
1418 		var msg = "<h1>Interner Fehler</h1>\n\n" + exception;
1419 		try {
1420 			console.log(msg);
1421 			Info.message({"css": "", "js": "", "content": msg});
1422 			Support.message({"css": "", "js": "", "main": msg, "side": ""});
1423 		} catch(ex){}
1424 	}
1425 };
1426