ulrich
2022-05-10 49e40b83644bf7e268572b0a4ea9be155b3d7089
commit | author | age
231393 1 /*
U 2     MonatsboxFabrik - a date component for the browser
3     Copyright (c) 2012, 2021  Ulrich Hilger
4
5     This program is free software: you can redistribute it and/or modify
6     it under the terms of the GNU Affero General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU Affero General Public License for more details.
14
15     You should have received a copy of the GNU Affero General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20  * Die MonatsboxFabrik liefert mit der Funktion
21  * monatsboxErzeugen eine Monatsbox
22  */
23 function MonatsboxFabrik() {
24   var self = this;
25   this.gewaehlteZelle = null;
26   this.j = -1;
27   this.m = -1;
0dce88 28   this.r = -1; // Ruhetag
231393 29   this.stilName = 'monatsboxRumpf';
0dce88 30   this.alterStilName = 'monatsboxRumpf';
231393 31
U 32   this.kwt = new Array(3, 4, 5, 6, 0, 1, 2);
33   
34 /**
35  * Eine Monatsbox zusammensetzen
36  * 
37  * @param {int} jahr ein beliebiges Jahr
38  * @param {int} monat 0=Januar .. 11=Dezember
39  * @param {int} starttag der Wochentag, mit dem eine Woche startet, 
40  *                  0=Sonntag .. 6=Samstag
41  * @param {int} ruhetag der Wochentag, der als Ruhetag markiert werden soll, 
42  *                  0=Sonntag .. 6=Montag
43  * @param {type} ereignisse eine Map, die fuer jeden Tag mit Ereignissen einen 
44  *                  Klassennamen zurueckgibt
45  * @param {type} lauscher die Funktion, die gerufen wird, wenn ein Tag 
46  *                   geklickt wird
47  * @returns {Element} die Monatsbox
48  */
49   this.monatsboxErzeugen = function(jahr, monat, starttag, ruhetag, ereignisse, lauscher) {
50
51     // Jahr und Monat merken
52     this.j = jahr;
53     this.m = monat;
54
55     // eine Tabelle nimmt die Monatsbox auf
56     var tabelle = document.createElement("table");
57     tabelle.className = "monatsbox";
58     tabelle.setAttribute('jahr', jahr);
59     tabelle.setAttribute('monat', monat);
60
61     // Ruhetagspalte abhaengig vom ersten Tag der Woche bestimmen
62     var ruhetagspalte = self.spalteBestimmen(ruhetag, starttag) + 1;
63     this.r = ruhetagspalte;
64
65     // Ueberschrift bilden
66     tabelle.appendChild(self.monatsboxKopf(starttag, ruhetagspalte));
67
68     // Startdatum setzen
69     var tagesDatum = 1;
70     var datum = new Date();
71     datum.setFullYear(jahr);
72     datum.setDate(tagesDatum);
73     datum.setMonth(this.m);
74
75     // Startspalte abhaengig vom ersten Tag der Woche bestimmen
76     var startspalte = self.spalteBestimmen(datum.getDay(), starttag) + 1;
77
78     // den Rumpf der Monatsbox erzeugen
79     var zeile = 0;
80     var spalte = 0;
81     var w = 0;
82     var tr = document.createElement("tr");
83     var td;
84     var stilName;
85     var letzterTag = self.letzterTagImMonat(jahr, monat);
86     while(tagesDatum <= letzterTag) {
87       stilName = null;
88       td = document.createElement("td");
89       td.onclick = lauscher;
90       if(spalte == ruhetagspalte) {
91         stilName = ereignisse.get(tagesDatum);
92         td.className = "monatsboxRumpfRuhetag";
93       } else if(spalte == 0) {
94         td.className = "monatsboxWoche";
95       } else {
96         stilName = ereignisse.get(tagesDatum);
97         td.className = "monatsboxRumpf";
98       }
99       if(zeile == 0 && spalte < startspalte) {
100         if(spalte == 0) {
101           w = self.kalenderwoche(jahr, monat, tagesDatum, starttag);
102           td.innerHTML = w;
103         }
104       } else if(spalte == 0) {
105         // woche schreiben
106         if(w > 51) {
107           //w = kalenderwoche(jahr, monat, tagesDatum + 1, starttag);
108           w = self.kalenderwoche(jahr, monat, tagesDatum, starttag);
109           td.innerHTML = w;
110         } else {
111           td.innerHTML = ++w;
112         }
113       } else {
114         if(stilName !== null && stilName  !== undefined && stilName.length > 0) {
115           td.className = stilName;
116         }
117         td.innerHTML = String(tagesDatum);
118         datum.setDate(++tagesDatum);
119       }
120       tr.appendChild(td);
121       if(++spalte > 7) {
122         spalte = 0;
123         ++zeile;
124         tabelle.appendChild(tr);
125         tr = document.createElement("tr");
126       } 
127     }
128     if(spalte > 0) {
129       tabelle.appendChild(tr);
130       ++zeile;
131     }
132     if(spalte == 0 && zeile == 5) {
133       self.zeileAnfuegen(tabelle);
134       ++zeile;
135     }
136     while(zeile < 6) {
137       self.zeileAnfuegen(tabelle);
138       zeile++;
139     }
140     return tabelle;
141   };
142
143   this.zeileAnfuegen = function(tabelle) {
144     var tr = document.createElement("tr");
145     var td = document.createElement("td");
146     td.innerHTML = '&nbsp;';
147     tr.appendChild(td);
148     tabelle.appendChild(tr);
149   };
150
151 /**
0dce88 152  * Anhand eines Klick-Ereignisses in die Monatsbox bestimmen, ob ein Tag 
U 153  * angeklickt wurde. Wenn ein Tag angeklickt wurde, diesen farblich 
154  * hervorheben und das Datum des geklickten Tages zurueckgeben. 
155  * Wenn kein Tag angeklickt wurde, null zurueckgeben.
231393 156  */
U 157   this.datum = function(Ereignis) {
158     var datum = null;
159     var td = Ereignis.target;
0dce88 160     var boxTab = td.parentNode.parentNode;    
231393 161     var spalte = td.cellIndex;
U 162     var tagesDatum = Number(td.innerHTML);
163     if(spalte > 0 && tagesDatum !== Number.NaN && tagesDatum > 0) {
164       if(this.gewaehlteZelle !== null) {
0dce88 165         this.gewaehlteZelle.className = this.alterStilName;
231393 166       }
U 167       this.gewaehlteZelle = td;
168       datum = new Date();
0dce88 169       this.alterStilName = td.className;
231393 170       td.className = 'monatsboxGewaehlt';
U 171       datum.setFullYear(this.j);
172       datum.setDate(tagesDatum);
173       datum.setMonth(boxTab.getAttribute('monat'));
174     }
175     return datum;
176   };
177
178 /**
179  * Die Spalte eines Wochentags abhaengig vom Tag bestimmen, 
180  * mit dem eine Woche startet
181  * 
182  * wochentag: Wochentag, dessenSpalte bestimmt werden soll
183  * starttag: Wochentag, mit dem eine Woche beginnt
184  * 
185  * Jeweils 0=Sonntag .. 6=Samstag
186  */
187   this.spalteBestimmen = function(wochentag, starttag) {
188     var spalte = wochentag - starttag;
189     if(spalte < 0) {
190       spalte = 7 + spalte;
191     }
192     return spalte;
193   };
194
195 /**
196  * Die Ueberschrift einer Monatsbox bestehend aus 
197  * Wochentagsnamen bilden
198  * 
199  * starttag: Wochentag, mit dem eine Woche beginnt
200  * ruhetagspalte: Spalte des Wochentages, der als Ruhetag markiert werden soll
201  * 
202  * Jeweils 0=Sonntag .. 6=Samstag
203  */
204   this.monatsboxKopf = function(starttag, ruhetagspalte) {
205     var tagesnamen = new Array("Sonntag", "Montag", "Dienstag", "Mittwoch", 
206       "Donnerstag", "Freitag", "Samstag");
207     var tr = document.createElement("tr");
208     var td;
209     td = document.createElement("td");
210     td.className = "monatsboxKopfWoche";    
211     td.innerHTML = "Kw";
212     tr.appendChild(td);
213     for(var index = 1; index < 8; index++) {
214       td = document.createElement("td");
215       if(index == ruhetagspalte) {
216         td.className = "monatsboxKopfRuhetag";    
217       } else {
218         td.className = "monatsboxKopf";
219       }
220       //console.log(starttag + ' ' + index);
221       if(Number(starttag) + Number(index) > 7) {
222         td.innerHTML = tagesnamen[Number(starttag) + Number(index) - 8].substring(0, 2); 
223       } else {
224         td.innerHTML = tagesnamen[Number(starttag) + Number(index) - 1].substring(0, 2);
225       }
226       tr.appendChild(td);
227     }
228     return tr;
229   };
230
231 /* ----------------- Datumsberechnungen ---------------------- */
232
233 /**
234  * Bestimmen, ob ein Jahr ein Schaltjahr ist
235  * j: Das Jahr, fuer das bestimmt werden soll,ob es ein Schaltjahr ist
236  * Rueckgabe: true, wenn das Jahr ein Schaltjahr ist, false wenn nicht
237  */
238   this.schaltjahr = function(j) {
239     var istSchalt = false;
240     if(((j % 4 == 0) && (j % 100 != 0)) || (j % 400 == 0)) {
241       istSchalt = true;
242     }
243     return istSchalt;
244   };
245
246 /**
247  * Den letzten Tag eines Monats im Gregorianischen Kalender bestimmen
248  *
249  * @param gJahr  das Jahr des Monats im Gregorianischen Kalender
250  * @param month  der Monat im Gregorianischen Kalender
251  * @return  Nummer des letzten Tages im betreffenden Monat (28, 29, 30 oder 31)
252  */
253   this.letzterTagImMonat = function(gJahr, month) {
254     var letzter = -1;
255     switch (month) {
256       case 3:
257       case 5:
258       case 8:
259       case 10:
260         letzter = 30;
261         break;
262       case 1:
263         if (self.schaltjahr(gJahr)) {
264           letzter = 29;
265         } else {
266           letzter = 28;
267         }
268         break;
269       default:
270         letzter = 31;
271         break;
272     }
273     return letzter;
274   };
275
276 /**
277  * Die Kalenderwoche für ein Datum ermitteln
278  * 
279  * @param {int} jahr
280  * @param {int} monat
281  * @param {int} tag
282  * @param {int} erster  der Wochentag, mit dem eine Woche beginnt (0=Sonntag .. 6=Samstag)
283  * @returns {int} die Nummer der Kalenderwoche
284  */
285   this.kalenderwoche = function(jahr, monat, tag, erster) {
286     var datum = new Date(jahr,monat,tag);
287     var ersterTagDieserẂoche = self.wochenbeginn(datum, erster);
288     var bkw1 = self.beginnKw1(jahr, erster);
289     var kw = Math.floor(1.5 + ( ersterTagDieserẂoche.getTime() - bkw1.getTime() ) / 86400000 / 7);
290     if(kw < 1) {
291       bkw1 = self.beginnKw1(jahr-1, erster);
292       kw = Math.floor(1.5 + ( ersterTagDieserẂoche.getTime() - bkw1.getTime() ) / 86400000 / 7);
293     } else if(kw > 52) {
294       if(ersterTagDieserẂoche.getDate() > 28) {
295         kw = 1;
296       }
297     }
298     return kw;
299   };
300
301 /**
302  * Das Datum des Wochenbeginns fuer die Woche ermitteln, in der 
303  * ein Datum liegt.
304  * 
305  * @param {Date} datum  das Datum, für das der Wochenbeginn gesucht wird
306  * @param {int} erster erster Tag der Woche (0 = Sonntag .. 6 = Samstag)
307  * @returns {Date}  das Datum des ersten Tages der Woche
308  */
309   this.wochenbeginn = function(datum, erster) {
310     var datumTag = datum.getDay();
311     var tagDatum = new Date();
312     tagDatum.setTime(datum.getTime());
313     while(datumTag !== erster) {
314       tagDatum.setTime(tagDatum.getTime() - 86400000);
315       datumTag = tagDatum.getDay();
316     }
317     return tagDatum;
318   };
319
320 /**
321  * Den Wochentag wotag ermitteln, der in der Woche liegt, die mit
322  * dem Datum erster beginnt.
323  * 
324  * Also: Ermittle den Mittwoch der Woche, die mit dem 7.9.2021 beginnt.
325  * 
326  * @param {type} erster Datum des ersten Tages der betreffenden Woche
327  * @param {type} wotag  gesuchter Wochentag (0=Sonntag .. 6=Samstag)
328  * @returns {Date|tagInWo.wtDatum} Datum den gesuchten Wochentags
329  */
330   this.tagInWo = function(erster, wotag) {
331     var wt = erster.getDay();
332     var wtDatum = new Date();
333     wtDatum.setTime(erster.getTime());
334     while(wt !== wotag) {
335       wtDatum.setTime(wtDatum.getTime() + 86400000);
336       wt = wtDatum.getDay();
337     }
338     return wtDatum;
339   };
340
341 /**
342  * Das Datum des ersten Tages der KW 1 eines Jahres 
343  * ermitteln
344  * 
345  * @param {int} jahr  das Jahr, für das der erste Tag der KW 1 ermittelt werden soll
346  * @param {int} erster  der Wochentag, mit dem eine Woche beginnt (0=Sonntag .. 6=Samstag)
347  * @returns {Date} das Datum des ersten Tages der KW 1 von [jahr]
348  */
349   this.beginnKw1 = function(jahr, erster) {
350     var wbJ1 = self.wochenbeginn(new Date(jahr, 0, 1), erster);
351     var ersterWt = self.tagInWo(wbJ1, self.kwt[erster]);
352     if(ersterWt.getFullYear() < jahr) {
353       ersterWt.setTime(ersterWt.getTime() + (7 * 86400000));
354     }
355     return self.wochenbeginn(ersterWt, erster);
356   };  
357   
358   
359 }