function calendarElementClass(prefix, year, month, day, linked) { this.__construct(prefix, year, month, day, linked); } /** * @var Array Die Namen der Monate. */ calendarElementClass.prototype._months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; /** * @var Array Die Namen der Wochentage. */ calendarElementClass.prototype._weekdays = [ 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su']; /** * @var string Das Prefix des Kalender Elements. */ calendarElementClass.prototype._prefix = ''; /** * @var string Das Suffix des Kalender Elements. */ calendarElementClass.prototype._suffix = ''; /** * @var string Der komplette Name des Kalender Elements. */ calendarElementClass.prototype._name = ''; /** * @var string Das Prefix für die CSS Klassen. */ calendarElementClass.prototype._CSSPrefix = 'calendar'; /** * @var boolean Gibt an ob der markierter Tag mit dem Select aktualisiert wird. */ calendarElementClass.prototype._linked = false; /** * @var integer Das Jahr in dem der markierte Tag ist. */ calendarElementClass.prototype._markedYear = -1; /** * @var integer Der Monat in dem der markierte Tag ist. */ calendarElementClass.prototype._markedMonth = -1; /** * @var integer Das aktuelle Jahr. */ calendarElementClass.prototype._year = -1; /** * @var integer Der aktuelle Monat. */ calendarElementClass.prototype._month = -1; /** * @var integer Der aktuelle Tag. */ calendarElementClass.prototype._day = -1; /** * @var integer Das niedrigste erlaubte Jahr. */ calendarElementClass.prototype._minYear = 2005; /** * @var integer Das höchste erlaubte Jahr. */ calendarElementClass.prototype._maxYear = 2020; /** * @var integer Wenn leere Elemente in den Selects sind 1 und sonst 0. */ calendarElementClass.prototype._offset = 0; /** * @var object Das DIV Element in dem der Kalender ist. */ calendarElementClass.prototype._div = ''; /** * @var string Die Funktion, die beim Klick auf einen Tag aufgerufen wird. */ calendarElementClass.prototype._onclickFunction = 'void'; /** * @var array Array mit den abhängigen Elementen. */ calendarElementClass.prototype._dependencies = new Array(); /** * @var Date Das aktuelle Datum in den Select Feldern. */ calendarElementClass.prototype._currentDate = new Date(); /** * Gibt den ersten Wochentag im Monat zurück. * * @return integer Der erste Wochentag im Monat. */ calendarElementClass.prototype._getFirstWeekday = function () { var date = new Date(this._year, this._month - 1, 1); var firstWeekday = date.getDay(); if (firstWeekday == 0) { firstWeekday = 7 } return firstWeekday; } /** * Gibt die Anzahl der Tage im aktuellen Monat zurück. * * @return integer Die Anzahl der Tage im aktuellem Monat. */ calendarElementClass.prototype._getDaysInMonth = function () { var days = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); if (this._month != 2) { return days[this._month - 1]; } else if ( ( this._year % 4 == 0 && this._year % 100 != 0 ) || this._year % 400 == 0 ) { return 29; } else { return 28; } } /** * Erstellt ein HTML Element für einen Tag und liefert es zurück. * * @param string text Der Text des Elementes. * @param string className Der Name der CSS Klasse. * * @return object Das HTML Element. */ calendarElementClass.prototype._createDay = function (text, className) { var textNode = document.createTextNode(text); var day = document.createElement('a'); day.appendChild(textNode); day.setAttribute('href', '#'); if (typeof className != 'undefined') { day.setAttribute('className', className); day.setAttribute('class', className); } if (this._onclickFunction != '' && text != '') { var attribute = 'javascript: ' + this._onclickFunction + '(' + this._year + ', ' + this._month + ', ' + text + ')'; day.setAttribute('href', attribute); } return day; } /** * Erstellt die HTML Elemente des Kalenders. */ calendarElementClass.prototype._createCalendar = function () { while (this._div.hasChildNodes()) { this._div.removeChild(this._div.firstChild); } /* * Monatsauswahl */ var div = document.createElement('div'); div.setAttribute('className', this._CSSPrefix + 'Title'); div.setAttribute('class', this._CSSPrefix + 'Title'); var element, option, year, month, i; /* * Zurück Link */ if (this._year > this._minYear || this._month > 1) { year = this._year; month = this._month - 1; if (month < 1) { year--; month = 12; } element = document.createElement('a'); element.setAttribute('href', 'javascript: ' + this._name + '.changeMonth(' + year + ', ' + month + ');'); element.appendChild(document.createTextNode('«')); div.appendChild(element); div.appendChild(document.createTextNode(' ')); } /* * Monatsauswahl */ element = document.createElement('select'); element.setAttribute('id', this._name + 'Month'); element.onchange = function () { window[this.id.substr(0, this.id.length - 5)].changeMonth(this.parentNode.getElementsByTagName('select')[1].value, this.value); } for (i = 0; i < this._months.length; i++) { option = document.createElement('option'); option.setAttribute('value', i + 1); option.appendChild(document.createTextNode(this._months[i])); if (option.value == this._month) { option.setAttribute('selected', 'selected'); } element.appendChild(option); } element.setAttribute('selectedIndex', this._month - 1); div.appendChild(element); /* * Jahresauswahl */ element = document.createElement('select'); element.setAttribute('id', this._name + 'Year'); element.onchange = function () { window[this.id.substr(0, this.id.length - 4)].changeMonth(this.value, this.parentNode.getElementsByTagName('select')[0].value); } for (i = this._minYear; i <= this._maxYear; i++) { option = document.createElement('option'); option.setAttribute('value', i); option.appendChild(document.createTextNode(option.value)); if (option.value == this._year) { option.setAttribute('selected', 'selected'); } element.appendChild(option); } element.setAttribute('selectedIndex', this._year - this._minYear); div.appendChild(element); /* * Weiter Link */ if (this._year < this._maxYear || this._month < 12) { div.appendChild(document.createTextNode(' ')); year = this._year; month = this._month + 1; if (month > 12) { year++; month = 1; } element = document.createElement('a'); element.setAttribute('href', 'javascript: ' + this._name + '.changeMonth(' + year + ', ' + month + ');'); element.appendChild(document.createTextNode('»')); div.appendChild(element); } /* * Umbruch */ element = document.createElement('br'); element.setAttribute('className', 'clear'); element.setAttribute('class', 'clear'); div.appendChild(element); this._div.appendChild(div); /* * Wochentage */ div = document.createElement('div'); div.setAttribute('className', this._CSSPrefix + 'Weekdays'); div.setAttribute('class', this._CSSPrefix + 'Weekdays'); for (i = 0; i < this._weekdays.length; i++) { element = document.createElement('div'); element.appendChild(document.createTextNode(this._weekdays[i])); div.appendChild(element); } this._div.appendChild(div); /* * Tage */ div = document.createElement('div'); div.setAttribute('className', this._CSSPrefix + 'Days'); div.setAttribute('class', this._CSSPrefix + 'Days'); if (this._getFirstWeekday() != 0) { for (i = 1; i < this._getFirstWeekday(); i++) { div.appendChild(this._createDay('', this._CSSPrefix + 'Empty')); } } var className = ''; for (i = 1; i <= this._getDaysInMonth(); i++) { if ( this._year == this._markedYear && this._month == this._markedMonth && this._day == i ) { className = 'active'; } else if ((i + this._getFirstWeekday() - 1) % 7 == 0) { className = this._CSSPrefix + 'Weekend'; } else { className = void(0); } div.appendChild(this._createDay(i, className)); } this._div.appendChild(div); /* * Umbruch */ element = document.createElement('br'); element.setAttribute('className', 'clear'); element.setAttribute('class', 'clear'); this._div.appendChild(element); } /** * Berechnet die Position des Mauszeigers und zeigt den Kalender an der * Position. */ calendarElementClass.prototype._display = function (event) { var xVisible, xScroll, yVisible, yScroll, posLeft, posTop; xScroll = document.getElementsByTagName('html')[0].scrollLeft; yScroll = document.getElementsByTagName('html')[0].scrollTop; if (window.opera) { xVisible = document.getElementsByTagName('body')[0].clientWidth; yVisible = document.getElementsByTagName('body')[0].clientHeight; } else { xVisible = document.getElementsByTagName('html')[0].clientWidth; yVisible = document.getElementsByTagName('html')[0].clientHeight; } if (typeof event.pageX != 'undefined') { posLeft = event.pageX; posTop = event.pageY; } else { var pos = getPos(event.srcElement); posLeft = pos[0] + window.event.offsetX; posTop = pos[1] + window.event.offsetY; } if (posLeft > xScroll + xVisible - this._div.offsetWidth) { posLeft = xScroll + xVisible - this._div.offsetWidth; } if (posTop > yScroll + yVisible - this._div.offsetHeight) { posTop = yScroll + yVisible - this._div.offsetHeight; } this._div.style.left = posLeft + 'px'; this._div.style.top = posTop + 'px'; this._div.style.display = 'block'; if (posLeft > xScroll + xVisible - this._div.offsetWidth) { posLeft = xScroll + xVisible - this._div.offsetWidth; } if (posTop > yScroll + yVisible - this._div.offsetHeight) { posTop = yScroll + yVisible - this._div.offsetHeight; } this._div.style.left = posLeft + 'px'; this._div.style.top = posTop + 'px'; checkMouseOut.addElement(this._div); } /** * Liefert ein Date Objekt mit dem aktuellem Datum der Select Felder. * * @return Date Das aktuelle Datum der Select Felder. */ calendarElementClass.prototype._getDate = function () { return new Date( this._minYear - this._offset + document.getElementsByName(this._prefix + '[Y]')[0].selectedIndex, document.getElementsByName(this._prefix + '[M]')[0].selectedIndex - this._offset, document.getElementsByName(this._prefix + '[d]')[0].selectedIndex + 1 - this._offset ); } /** * Setzt den Index eines Select Feldes anhand eines Wertes aus dem Select Feld. * * @param Object select Das Select Feld. * @param string value Der Wert aus dem Select Feld. */ calendarElementClass.prototype._setSelectIndexByValue = function (select, value) { var selectedIndex = undefined; for (var index in select.options) { if ( !isNaN(index) && select.options[index] != undefined && select.options[index].value == value ) { selectedIndex = index; break; } } select.selectedIndex = selectedIndex; } /** * Setzt das Datum bei den abhängigen Elementen. * * @param Date oldDate Das alte Datum. */ calendarElementClass.prototype._setDependantDates = function (oldDate) { var year, month, date; var diff = this._currentDate.getTime() - oldDate.getTime(); for (var index in this._dependencies) { if (document.getElementsByName(this._dependencies[index] + '[Y]').length == 0) { continue; } year = document.getElementsByName(this._dependencies[index] + '[Y]')[0]; month = document.getElementsByName(this._dependencies[index] + '[M]')[0]; day = document.getElementsByName(this._dependencies[index] + '[d]')[0]; dependantDate = new Date( year.value, month.value - 1, day.value ); dependantDate.setTime(dependantDate.getTime() + diff); this._setSelectIndexByValue(year, dependantDate.getFullYear()); this._setSelectIndexByValue(month, dependantDate.getMonth() + 1); this._setSelectIndexByValue(day, dependantDate.getDate()); if (year.onchange != undefined) { year.onchange(); } } } /** * Erstellt den Kalender und zeigt ihn an. */ calendarElementClass.prototype.show = function (event) { this._createCalendar(); this._display(event); } /** * Ändert das aktuelle Datum. * * @param integer year Das neue Jahr. * @param integer month Der neue Monat. * @param integer day Der neue Tag, wird nur gesetzt wenn das markierte * Datum mit den Select Felder aktualisiert wird. */ calendarElementClass.prototype.changeMonth = function (year, month, day) { if (year != '' && month != '') { this._year = parseInt(year); this._month = parseInt(month); if (this._linked && typeof day != 'undefined') { this._markedYear = this._year; this._markedMonth = this._month; if (day != '') { this._day = day; } } if (this._div.style.display != 'none') { this._createCalendar(); } } } /** * Überträgt das ausgewählte Datum in die Datumsfelder. * * @param integer year Das ausgewählte Jahr. * @param integer month Der ausgewählte Monat. * @param integer day Der ausgewählte Tag. */ calendarElementClass.prototype.setDate = function (year, month, day) { document.getElementsByName(this._prefix + '[Y]')[0].selectedIndex = year - this._minYear + this._offset; document.getElementsByName(this._prefix + '[M]')[0].selectedIndex = month - 1 + this._offset; document.getElementsByName(this._prefix + '[d]')[0].selectedIndex = day - 1 + this._offset; if (typeof document.getElementsByName(this._prefix + '[Y]')[0].onchange != 'undefined') { document.getElementsByName(this._prefix + '[Y]')[0].onchange(); } this._div.style.display = 'none'; checkMouseOut.removeElement(this._div); } /** * Setzt ein Element, dass vom Datum dieses Elements abhängig ist. * * @param string element Der Name des abhängigen Elements. */ calendarElementClass.prototype.setDependency = function (element) { if (!in_array(element, this._dependencies)) { this._dependencies.push(element); } } /** * Aktualisiert alle von den Select Feldern abhängigen Werte. */ calendarElementClass.prototype.update = function () { var oldDate = this._currentDate; this._currentDate = this._getDate(); this.changeMonth( this._currentDate.getFullYear(), this._currentDate.getMonth() + 1, this._currentDate.getDate() ); this._setDependantDates(oldDate); } /** * Initalisiert den Kalender. * * @param string prefix Das Prefix des Kalender Elements. * @param integer year Das Jahr für den Kalender. * @param integer month Der Monat für den Kalender. * @param integer day Der ausgewählte Tag für den Kalender. * @param boolean linked Markierter Tag wird mit dem Select aktualisiert. */ calendarElementClass.prototype.__construct = function (prefix, year, month, day, linked) { this._CSSPrefix = 'calendarElement'; this._prefix = prefix; this._name = this._prefix + 'CalendarElement'; this._linked = linked; if (document.getElementsByName(this._prefix + '[M]')[0].length == 13) { this._offset = 1; } var date = new Date(); this._year = parseInt(document.getElementsByName(this._prefix + '[Y]')[0].value); if (isNaN(this._year)) { if (typeof year != 'undefined') { this._year = year; } else { this._year = date.getFullYear(); } } if (linked) { this._markedYear = this._year; } else if (typeof year != 'undefined') { this._markedYear = year; } else { this._markedYear = date.getFullYear(); } this._month = parseInt(document.getElementsByName(this._prefix + '[M]')[0].value); if (isNaN(this._month)) { if (typeof month != 'undefined') { this._month = month; } else { this._month = date.getMonth() + 1; } } if (linked) { this._markedMonth = this._Month; } else if (typeof month != 'undefined') { this._markedMonth = month; } else { this._markedMonth = date.getMonth() + 1; } if (linked) { this._day = parseInt(document.getElementsByName(this._prefix + '[d]')[0].value); } if (!linked || isNaN(this._day)) { if (typeof day != 'undefined') { this._day = day; } else { this._day = date.getDate(); } } this._minYear = document.getElementsByName(this._prefix + '[Y]')[0].options[this._offset].value; this._maxYear = document.getElementsByName(this._prefix + '[Y]')[0].options[document.getElementsByName(this._prefix + '[Y]')[0].length - 1].value; this._currentDate = this._getDate(); this._div = document.createElement('div'); this._div.setAttribute('className', this._CSSPrefix); this._div.setAttribute('class', this._CSSPrefix); document.getElementsByName(this._prefix + '[d]')[0].parentNode.appendChild(this._div); this._onclickFunction = this._name + '.setDate'; if (typeof window.checkMouseOut == 'undefined') { window.checkMouseOut = new checkMouseOutClass(); } if (linked) { this.changeMonth(this._year, this._month, this._day); } this._dependencies = new Array(); } /* * CalendarTextClass extends calendarElementClass */ function calendarTextClass(prefix, year, month, day) { for (var property in calendarElementClass.prototype) { if (typeof this[property] == 'undefined') { this[property] = calendarElementClass.prototype[property]; } } this.__construct(prefix, year, month, day); } /* * Überschriebene Funktionen verfügbar machen. */ calendarTextClass.prototype._parentConstruct = calendarElementClass.prototype.__construct; calendarTextClass.prototype._parentSetDate = calendarElementClass.prototype.setDate; calendarTextClass.prototype._parentUpdate = calendarElementClass.prototype.update; /** * @var object Das Text Element mit dem Datum. */ calendarTextClass.prototype._text = ''; /** * Liefert ein Date Objekt mit dem aktuellem Datum der Select Felder. * * @return Date Das aktuelle Datum der Select Felder. */ calendarTextClass.prototype._getDate = function () { /* * Fix für Opera */ document.getElementsByName(this._prefix + '[Y]')[0].style.display = 'block'; document.getElementsByName(this._prefix + '[M]')[0].style.display = 'block'; document.getElementsByName(this._prefix + '[d]')[0].style.display = 'block'; var date = new Date( this._minYear - this._offset + document.getElementsByName(this._prefix + '[Y]')[0].selectedIndex, document.getElementsByName(this._prefix + '[M]')[0].selectedIndex - this._offset, document.getElementsByName(this._prefix + '[d]')[0].selectedIndex + 1 - this._offset ); document.getElementsByName(this._prefix + '[Y]')[0].style.display = 'none'; document.getElementsByName(this._prefix + '[M]')[0].style.display = 'none'; document.getElementsByName(this._prefix + '[d]')[0].style.display = 'none'; return date; } /** * Füllt einen String mit 0 auf zwei Stellen auf. * * @param string string Der zu formatierende String. * * @return string Der formatierte String. */ calendarTextClass.prototype._strPad = function (string) { string = String(string); while (string.length < 2) { string = ('0').concat(string); } return string; } /** * Überträgt das Ausgewählte Datum in das Textfeld und die Selectfelder. * * @param integer year Das ausgewählte Jahr. * @param integer month Der ausgewählte Monat. * @param integer day Der ausgewählte Tag. */ calendarTextClass.prototype.setDate = function (year, month, day) { this._parentSetDate(year, month, day); this._text.nodeValue = this._strPad(day) + '.' + this._strPad(month) + '.' + year; } /** * Aktualisiert alle von den Select Feldern abhängigen Werte. */ calendarTextClass.prototype.update = function () { this._parentUpdate(); this._text.nodeValue = this._strPad(this._currentDate.getDate()) + '.' + this._strPad(this._currentDate.getMonth() + 1) + '.' + this._currentDate.getFullYear(); } /** * Initalisiert den Kalender. * * @param string prefix Das Prefix des Kalender Elements. * @param integer year Das Jahr für den Kalender. * @param integer month Der Monat für den Kalender. * @param integer day Der ausgewählte Tag für den Kalender. */ calendarTextClass.prototype.__construct = function (prefix, year, month, day) { this._parentConstruct(prefix, year, month, day); year = document.getElementsByName(this._prefix + '[Y]')[0].value; month = document.getElementsByName(this._prefix + '[M]')[0].value; day = document.getElementsByName(this._prefix + '[d]')[0].value; this._text = document.createTextNode(this._strPad(day) + '.' + this._strPad(month) + '.' + year); document.getElementsByName(this._prefix + '[d]')[0].parentNode.insertBefore(this._text, document.getElementsByName(this._prefix + '[d]')[0]); } function checkMouseOutClass() { try { /* * Funktion gemäß DOM registrieren. */ document.addEventListener( 'mousemove', function (event) { checkMouseOut.check(event) }, true ); } catch (e) { /* * Funktion gemäß IE registrieren. */ document.attachEvent( 'onmousemove', function (event) { checkMouseOut.check(event); } ); } }; /** * @var Array Array mit den Elementen die überprüft werden. */ checkMouseOutClass.prototype._elements = new Array(); /** * Überprüft ob sich die Maus außerhalbe eines der zu überwachenden Elemente * befindet und blendet dieses gegebenen falls aus. */ checkMouseOutClass.prototype.check = function(event) { var posLeft, posTop; if (typeof event != 'undefined' && typeof event.pageX != 'undefined') { posLeft = event.pageX; posTop = event.pageY; } else { if (window.event.srcElement.disabled == undefined) { return undefined; } var element = window.event.srcElement; while ( element.parentNode != 'undefined' && element != document.getElementsByTagName('body')[0] && element != document.getElementsByTagName('html')[0] && ( !element.currentStyle.hasLayout ) ) { element = element.parentNode; } var pos = getPos(element); posLeft = pos[0] + window.event.offsetX; posTop = pos[1] + window.event.offsetY; } var index = 'parentNode'; var elementPos, currentElement, j; var tolerance = 5; for (var i in this._elements) { if (typeof this._elements[i] != 'object') { continue; } elementPos = getPos(this._elements[i]); if (typeof event.target != 'undefined') { currentElement = event.target; } else { currentElement = event.srcElement; index = 'srcElement'; } while (currentElement != this._elements[i]) { if (typeof currentElement[index] == 'undefined' || currentElement[index] == null) { break; } currentElement = currentElement[index]; } if ( currentElement != this._elements[i] && ( posLeft < elementPos[0] - tolerance || posLeft > elementPos[0] + this._elements[i].offsetWidth + tolerance || posTop < elementPos[1] - tolerance || posTop > elementPos[1] + this._elements[i].offsetHeight + tolerance ) ) { this._elements[i].style.display = 'none'; for (j = 0; j < this._elements[i].getElementsByTagName('select').length; j++) { this._elements[i].getElementsByTagName('select')[j].blur(); } this.removeElement(this._elements[i]); } } } /** * Fügt ein zu überwachendes Element hinzu. * * @param object Das zu überwachende Element. * * @return boolean true wenn das Element hinzugefügt wurde, false wenn das * Element bereits vorhanden ist. */ checkMouseOutClass.prototype.addElement = function(element) { for (var i in this._elements) { if (this._elements[i] == element) { return false; } } this._elements.push(element); return true; } /** * Entfernt ein zu überwachendes Element. * * @param object Das zu entfernende Element. * * @return boolean true wenn das Element entfernt wurde, false wenn kein * passendes Element gefunden wurde. */ checkMouseOutClass.prototype.removeElement = function(element) { for (var i in this._elements) { if (this._elements[i] == element) { this._elements.splice(i, 1); return true; } } return false; }