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